├── .github ├── FUNDING.yml └── workflows │ └── make.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── images ├── lpc_winter_preview.png └── perlin.png ├── samples ├── sample-bench.c ├── sample-blend.c ├── sample-effect.c ├── sample-framebuffer.c ├── sample-primitives.c ├── sample-rectangle.c ├── sample-sdf.c └── sample-shell.html ├── shaders ├── sample-effect.glsl ├── sample-effect.glsl.h ├── sample-sdf.glsl ├── sample-sdf.glsl.h ├── sokol_gp.glsl └── sokol_gp.glsl.h ├── sokol_gp.h └── thirdparty ├── sokol_app.h ├── sokol_gfx.h ├── sokol_glue.h ├── sokol_log.h ├── sokol_time.h └── stb_image.h /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: edubart 2 | -------------------------------------------------------------------------------- /.github/workflows/make.yml: -------------------------------------------------------------------------------- 1 | name: Make 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | pull_request: 7 | branches: ["master"] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Install dependencies 16 | run: | 17 | sudo apt-get update 18 | sudo apt-get install -y libgl-dev libxi-dev libxcursor-dev 19 | - name: lint 20 | run: make lint 21 | - name: make 22 | run: make all 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /scratch 2 | /build 3 | /build.* 4 | /play 5 | *.TODO 6 | *.exe 7 | *.dll 8 | *.o 9 | *.log 10 | *.dxvk-cache 11 | .luamonrc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2024 Eduardo Bart (https://github.com/edubart/sokol_gp) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 16 | SOFTWARE. 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-std=c99 2 | CFLAGS+=-Wall -Wextra -Wshadow -Wno-unused-function -Wno-missing-field-initializers 3 | DEFS= 4 | CC=gcc 5 | INCS=-I. -Ithirdparty -Ishaders 6 | OUTDIR=build 7 | OUTEXT= 8 | SHDC=sokol-shdc 9 | SHDCFLAGS=--format sokol_impl --slang glsl410:glsl300es:hlsl4:metal_macos:metal_ios:wgsl 10 | SHADERS=\ 11 | shaders/sample-effect.glsl.h \ 12 | shaders/sample-sdf.glsl.h \ 13 | shaders/sokol_gp.glsl.h 14 | 15 | # platform 16 | ifndef platform 17 | platform=linux 18 | endif 19 | ifeq ($(platform), windows) 20 | CC=x86_64-w64-mingw32-gcc 21 | LIBS+=-lkernel32 -luser32 -lshell32 -lgdi32 -ld3d11 -ldxgi 22 | OUTEXT=.exe 23 | else ifeq ($(platform), linux) 24 | DEFS+=-D_GNU_SOURCE 25 | CFLAGS+=-pthread 26 | LIBS+=-lX11 -lXi -lXcursor -lGL -ldl -lm 27 | ifeq ($(backend), gles3) 28 | LIBS+=-lEGL 29 | endif 30 | else ifeq ($(platform), macos) 31 | LIBS+=-framework Cocoa -framework QuartzCore -framework Metal -framework MetalKit 32 | CFLAGS+=-ObjC -x objective-c 33 | else ifeq ($(platform), web) 34 | LIBS+=-sFULL_ES3 35 | CC=emcc 36 | OUTEXT=.html 37 | CFLAGS+=--shell-file=samples/sample-shell.html --embed-file images 38 | endif 39 | 40 | # build type 41 | ifndef build 42 | build=debug 43 | endif 44 | ifeq ($(platform), web) 45 | ifeq ($(build), debug) 46 | CFLAGS+=-Og -g 47 | else 48 | CFLAGS+=-O3 -g0 -s 49 | endif 50 | else ifeq ($(build), debug) 51 | CFLAGS+=-Og -ffast-math -g 52 | else ifeq ($(build), release) 53 | CFLAGS+=-Ofast -fno-plt -g 54 | DEFS+=-DNDEBUG 55 | endif 56 | 57 | ifeq ($(build), debug) 58 | DEFS+=-DSOKOL_DEBUG 59 | endif 60 | 61 | # backend 62 | ifndef backend 63 | ifeq ($(platform), windows) 64 | backend=d3d11 65 | else ifeq ($(platform), macos) 66 | backend=metal 67 | else ifeq ($(platform), web) 68 | backend=gles3 69 | else 70 | backend=glcore 71 | endif 72 | endif 73 | ifeq ($(backend), glcore) 74 | DEFS+=-DSOKOL_GLCORE 75 | else ifeq ($(backend), gles3) 76 | DEFS+=-DSOKOL_GLES3 77 | else ifeq ($(backend), d3d11) 78 | DEFS+=-DSOKOL_D3D11 79 | else ifeq ($(backend), metal) 80 | DEFS+=-DSOKOL_METAL 81 | else ifeq ($(backend), dummy) 82 | DEFS+=-DSOKOL_DUMMY_BACKEND 83 | endif 84 | 85 | SAMPLES=\ 86 | build/sample-rectangle$(OUTEXT) \ 87 | build/sample-primitives$(OUTEXT) \ 88 | build/sample-blend$(OUTEXT) \ 89 | build/sample-framebuffer$(OUTEXT) \ 90 | build/sample-bench$(OUTEXT) \ 91 | build/sample-sdf$(OUTEXT) \ 92 | build/sample-effect$(OUTEXT) 93 | 94 | all: $(SAMPLES) 95 | 96 | shaders: $(SHADERS) 97 | 98 | clean: 99 | rm -rf $(OUTDIR) 100 | 101 | clean-shaders: 102 | rm -f $(SHADERS) 103 | 104 | $(OUTDIR)/%$(OUTEXT): samples/%.c shaders/*.h thirdparty/*.h sokol_gp.h 105 | @mkdir -p $(OUTDIR) 106 | $(CC) -o $@ $< $(INCS) $(DEFS) $(CFLAGS) $(LIBS) 107 | 108 | shaders/%.glsl.h: shaders/%.glsl 109 | $(SHDC) $(SHDCFLAGS) -i $^ -o $@ 110 | 111 | lint: 112 | clang-tidy sokol_gp.h -- $(INCS) $(DEFS) $(CFLAGS) -DSOKOL_IMPL -include sokol_gfx.h 113 | 114 | update-thirdparty: 115 | wget -O thirdparty/sokol_app.h https://raw.githubusercontent.com/floooh/sokol/master/sokol_app.h 116 | wget -O thirdparty/sokol_gfx.h https://raw.githubusercontent.com/floooh/sokol/master/sokol_gfx.h 117 | wget -O thirdparty/sokol_glue.h https://raw.githubusercontent.com/floooh/sokol/master/sokol_glue.h 118 | wget -O thirdparty/sokol_time.h https://raw.githubusercontent.com/floooh/sokol/master/sokol_time.h 119 | wget -O thirdparty/sokol_log.h https://raw.githubusercontent.com/floooh/sokol/master/sokol_log.h 120 | wget -O thirdparty/stb_image.h https://raw.githubusercontent.com/nothings/stb/master/stb_image.h 121 | 122 | .PHONY: all shaders clean clean-shaders lint update-thirdparty 123 | 124 | test: all 125 | ./build/sample-rectangle$(OUTEXT) 126 | ./build/sample-blend$(OUTEXT) 127 | ./build/sample-primitives$(OUTEXT) 128 | ./build/sample-effect$(OUTEXT) 129 | ./build/sample-framebuffer$(OUTEXT) 130 | ./build/sample-sdf$(OUTEXT) 131 | ./build/sample-bench$(OUTEXT) 132 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sokol GP 2 | 3 | Minimal efficient cross platform 2D graphics painter in pure C 4 | using modern graphics API through the excellent [Sokol GFX](https://github.com/floooh/sokol) library. 5 | 6 | Sokol GP, or in short SGP, stands for Sokol Graphics Painter. 7 | 8 | [![sample-primitives](https://edubart.github.io/sokol_gp/sample-primitives.png)](https://edubart.github.io/sokol_gp/sample-primitives.html) 9 | 10 | ## Features 11 | 12 | * Made and optimized only for **2D rendering only**, no 3D support. 13 | * Minimal, in a pure single C header. 14 | * Use modern unfixed pipeline graphics APIs for more efficiency. 15 | * Cross platform (backed by Sokol GFX). 16 | * D3D11/OpenGL 3.3/Metal/WebGPU graphics backends (through Sokol GFX). 17 | * **Automatic batching** (merge recent draw calls into batches automatically). 18 | * **Batch optimizer** (rearranges the ordering of draw calls to batch more). 19 | * Batch draw calls even when using different color states. **\*NEW\*** 20 | * Uses preallocated memory (no allocations at runtime). 21 | * Supports drawing basic 2D primitives (rectangles, triangles, lines and points). 22 | * Supports the classic 2D color blending modes (color blend, add, modulate, multiply). 23 | * Supports 2D space transformations and changing 2D space coordinate systems. 24 | * Supports drawing the basic primitives (rectangles, triangles, lines and points). 25 | * Supports multiple texture bindings. 26 | * Supports custom fragment shaders with 2D primitives. 27 | * Can be mixed with projects that are already using Sokol GFX. 28 | 29 | ## Why? 30 | 31 | Sokol GFX is an excellent library for rendering using unfixed pipelines 32 | of modern graphics cards, but it is too complex to use for simple 2D drawing, 33 | and it's API is too generic and specialized for 3D rendering. To draw 2D stuff, the programmer 34 | usually needs to setup custom shaders when using Sokol GFX, or use its Sokol GL 35 | extra library, but Sokol GL also has an API with 3D design in mind, which 36 | incurs some costs and limitations. 37 | 38 | This library was created to draw 2D primitives through Sokol GFX with ease, 39 | and by not considering 3D usage it is optimized for 2D rendering only, 40 | furthermore it features an **automatic batch optimizer**, more details of it will be described below. 41 | 42 | ## Automatic batch optimizer 43 | 44 | When drawing the library creates a draw command queue of all primitives yet to be drawn, 45 | every time a new draw command is added the batch optimizer looks back up to the last 46 | 8 recent draw commands (this is adjustable), and try to rearrange and merge drawing commands 47 | if it finds a previous draw command that meets the following criteria: 48 | 49 | * The new draw command and previous command uses the *same primitive pipeline* 50 | * The new draw command and previous command uses the *same shader uniforms* 51 | * The new draw command and previous command uses the *same texture bindings* 52 | * The new draw command and previous command does not have another intermediary 53 | draw command *that overlaps* in-between them. 54 | 55 | By doing this the batch optimizer is able for example to merge textured draw calls, 56 | even if they were drawn with other intermediary different textures draws between them. 57 | The effect is more efficiency when drawing, because less draw calls will be dispatched 58 | to the GPU, 59 | 60 | This library can avoid a lot of work of making an efficient 2D drawing batching system, 61 | by automatically merging draw calls behind the scenes at runtime, 62 | thus the programmer does not need to manage batched draw calls manually, 63 | nor he needs to sort batched texture draw calls, 64 | the library will do this seamlessly behind the scenes. 65 | 66 | The batching algorithm is fast, but it has `O(n)` CPU complexity for every new draw command added, 67 | where `n` is the `SGP_BATCH_OPTIMIZER_DEPTH` configuration. 68 | In experiments using `8` as the default is a good default, 69 | but you may want to try out different values depending on your case. 70 | Using values that are too high is not recommended, because the algorithm may take too long 71 | scanning previous draw commands, and that may consume more CPU resources. 72 | 73 | The batch optimizer can be disabled by setting `SGP_BATCH_OPTIMIZER_DEPTH` to 0, 74 | you can use that to measure its impact. 75 | 76 | In the samples directory of this repository there is a 77 | benchmark example that tests drawing with the bath optimizer enabled/disabled. 78 | On my machine that benchmark was able to increase performance in a 2.2x factor when it is enabled. 79 | In some private game projects the gains of the batch optimizer proved to increase FPS performance 80 | above 1.5x by just replacing the graphics backend with this library, with no internal 81 | changes to the game itself. 82 | 83 | ## Design choices 84 | 85 | The library has some design choices with performance in mind that will be discussed briefly here. 86 | 87 | Like Sokol GFX, Sokol GP will never do any allocation in the draw loop, 88 | so when initializing you must configure beforehand the maximum size of the 89 | draw command queue buffer and the vertices buffer. 90 | 91 | All the 2D space transformation (functions like `sgp_rotate`) are done by the CPU and not by the GPU, 92 | this is intentionally to avoid adding extra overhead in the GPU, because typically the number 93 | of vertices of 2D applications are not that large, and it is more efficient to perform 94 | all the transformation with the CPU right away rather than pushing extra buffers to the GPU 95 | that ends up using more bandwidth of the CPU<->GPU bus. 96 | In contrast 3D applications usually dispatches vertex transformations to the GPU using a vertex shader, 97 | they do this because the amount of vertices of 3D objects can be very large 98 | and it is usually the best choice, but this is not true for 2D rendering. 99 | 100 | Many APIs to transform the 2D space before drawing a primitive are available, such as 101 | translate, rotate and scale. They can be used as similarly as the ones available in 3D graphics APIs, 102 | but they are crafted for 2D only, for example when using 2D we don't need to use a 4x4 or 3x3 matrix 103 | to perform vertex transformation, instead the code is specialized for 2D and can use a 2x3 matrix, 104 | saving extra CPU float computations. 105 | 106 | All pipelines always use a texture associated with it, even when drawing non textured primitives, 107 | because this minimizes graphics pipeline changes when mixing textured calls and non textured calls, 108 | improving efficiency. 109 | 110 | The library is coded in the style of Sokol GFX headers, reusing many macros from there, 111 | you can change some of its semantics such as custom allocator, custom log function, and some 112 | other details, read `sokol_gfx.h` documentation for more on that. 113 | 114 | ## Usage 115 | 116 | Copy `sokol_gp.h` along with other Sokol headers to the same folder. Setup Sokol GFX 117 | as you usually would, then add call to `sgp_setup(desc)` just after `sg_setup(desc)`, and 118 | call to `sgp_shutdown()` just before `sg_shutdown()`. Note that you should usually check if 119 | SGP is valid after its creation with `sgp_is_valid()` and exit gracefully with an error if not. 120 | 121 | In your frame draw function add `sgp_begin(width, height)` before calling any SGP 122 | draw function, then draw your primitives. At the end of the frame (or framebuffer) you 123 | should **ALWAYS call** `sgp_flush()` between a Sokol GFX begin/end render pass, 124 | the `sgp_flush()` will dispatch all draw commands to Sokol GFX. Then call `sgp_end()` immediately 125 | to discard the draw command queue. 126 | 127 | An actual example of this setup will be shown below. 128 | 129 | ## Quick usage example 130 | 131 | The following is a quick example on how to this library with Sokol GFX and Sokol APP: 132 | 133 | ```c 134 | // This is an example on how to set up and use Sokol GP to draw a filled rectangle. 135 | 136 | // Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations. 137 | #define SOKOL_IMPL 138 | #include "sokol_gfx.h" 139 | #include "sokol_gp.h" 140 | #include "sokol_app.h" 141 | #include "sokol_glue.h" 142 | #include "sokol_log.h" 143 | 144 | #include // for fprintf() 145 | #include // for exit() 146 | #include // for sinf() and cosf() 147 | 148 | // Called on every frame of the application. 149 | static void frame(void) { 150 | // Get current window size. 151 | int width = sapp_width(), height = sapp_height(); 152 | float ratio = width/(float)height; 153 | 154 | // Begin recording draw commands for a frame buffer of size (width, height). 155 | sgp_begin(width, height); 156 | // Set frame buffer drawing region to (0,0,width,height). 157 | sgp_viewport(0, 0, width, height); 158 | // Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1). 159 | sgp_project(-ratio, ratio, 1.0f, -1.0f); 160 | 161 | // Clear the frame buffer. 162 | sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); 163 | sgp_clear(); 164 | 165 | // Draw an animated rectangle that rotates and changes its colors. 166 | float time = sapp_frame_count() * sapp_frame_duration(); 167 | float r = sinf(time)*0.5+0.5, g = cosf(time)*0.5+0.5; 168 | sgp_set_color(r, g, 0.3f, 1.0f); 169 | sgp_rotate_at(time, 0.0f, 0.0f); 170 | sgp_draw_filled_rect(-0.5f, -0.5f, 1.0f, 1.0f); 171 | 172 | // Begin a render pass. 173 | sg_pass pass = {.swapchain = sglue_swapchain()}; 174 | sg_begin_pass(&pass); 175 | // Dispatch all draw commands to Sokol GFX. 176 | sgp_flush(); 177 | // Finish a draw command queue, clearing it. 178 | sgp_end(); 179 | // End render pass. 180 | sg_end_pass(); 181 | // Commit Sokol render. 182 | sg_commit(); 183 | } 184 | 185 | // Called when the application is initializing. 186 | static void init(void) { 187 | // Initialize Sokol GFX. 188 | sg_desc sgdesc = { 189 | .environment = sglue_environment(), 190 | .logger.func = slog_func 191 | }; 192 | sg_setup(&sgdesc); 193 | if (!sg_isvalid()) { 194 | fprintf(stderr, "Failed to create Sokol GFX context!\n"); 195 | exit(-1); 196 | } 197 | 198 | // Initialize Sokol GP, adjust the size of command buffers for your own use. 199 | sgp_desc sgpdesc = {0}; 200 | sgp_setup(&sgpdesc); 201 | if (!sgp_is_valid()) { 202 | fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); 203 | exit(-1); 204 | } 205 | } 206 | 207 | // Called when the application is shutting down. 208 | static void cleanup(void) { 209 | // Cleanup Sokol GP and Sokol GFX resources. 210 | sgp_shutdown(); 211 | sg_shutdown(); 212 | } 213 | 214 | // Implement application main through Sokol APP. 215 | sapp_desc sokol_main(int argc, char* argv[]) { 216 | (void)argc; 217 | (void)argv; 218 | return (sapp_desc){ 219 | .init_cb = init, 220 | .frame_cb = frame, 221 | .cleanup_cb = cleanup, 222 | .window_title = "Rectangle (Sokol GP)", 223 | .logger.func = slog_func, 224 | }; 225 | } 226 | ``` 227 | 228 | To run this example, first copy the `sokol_gp.h` header alongside with other Sokol headers 229 | to the same folder, then compile with any C compiler using the proper linking flags (read `sokol_gfx.h`). 230 | 231 | ## Complete Examples 232 | 233 | In folder `samples` you can find the following complete examples covering all APIs of the library: 234 | 235 | * [sample-primitives.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-primitives.c): This is an example showing all drawing primitives and transformations APIs. 236 | * [sample-blend.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-blend.c): This is an example showing all blend modes between 3 rectangles. 237 | * [sample-framebuffer.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-framebuffer.c): This is an example showing how to use multiple `sgp_begin()` with frame buffers. 238 | * [sample-sdf.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-sdf.c): This is an example on how to create custom shaders. 239 | * [sample-effect.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-effect.c): This is an example on how to use custom shaders for 2D drawing. 240 | * [sample-bench.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-bench.c): This is a heavy example used for benchmarking purposes. 241 | 242 | These examples are used as the test suite for the library, you can build them by typing `make`. 243 | 244 | ## Error handling 245 | 246 | It is possible that after many draw calls the command or vertex buffer may overflow, 247 | in that case the library will set an error error state and will continue to operate normally, 248 | but when flushing the drawing command queue with `sgp_flush()` no draw command will be dispatched. 249 | This can happen because the library uses pre allocated buffers, in such 250 | cases the issue can be fixed by increasing the prefixed command queue buffer and the vertices buffer 251 | when calling `sgp_setup()`. 252 | 253 | Making invalid number of push/pops of `sgp_push_transform()` and `sgp_pop_transform()`, 254 | or nesting too many `sgp_begin()` and `sgp_end()` may also lead to errors, that 255 | is a usage mistake. 256 | 257 | You can enable the `SOKOL_DEBUG` macro in such cases to debug, or handle 258 | the error programmatically by reading `sgp_get_last_error()` after calling `sgp_end()`. 259 | It is also advised to leave `SOKOL_DEBUG` enabled when developing with Sokol, so you can 260 | catch mistakes early. 261 | 262 | ## Blend modes 263 | 264 | The library supports the most usual blend modes used in 2D, which are the following: 265 | 266 | - `SGP_BLENDMODE_NONE` - No blending (`dstRGBA = srcRGBA`). 267 | - `SGP_BLENDMODE_BLEND` - Alpha blending (`dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))` and `dstA = srcA + (dstA * (1-srcA))`) 268 | - `SGP_BLENDMODE_BLEND_PREMULTIPLIED` - Pre-multiplied alpha blending (`dstRGBA = srcRGBA + (dstRGBA * (1-srcA))`) 269 | - `SGP_BLENDMODE_ADD` - Additive blending (`dstRGB = (srcRGB * srcA) + dstRGB` and `dstA = dstA`) 270 | - `SGP_BLENDMODE_ADD_PREMULTIPLIED` - Pre-multiplied additive blending (`dstRGB = srcRGB + dstRGB` and `dstA = dstA`) 271 | - `SGP_BLENDMODE_MOD` - Color modulate (`dstRGB = srcRGB * dstRGB` and `dstA = dstA`) 272 | - `SGP_BLENDMODE_MUL` - Color multiply (`dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))` and `dstA = (srcA * dstA) + (dstA * (1-srcA))`) 273 | 274 | ## Changing 2D coordinate system 275 | 276 | You can change the screen area to draw by calling `sgp_viewport(x, y, width, height)`. 277 | You can change the coordinate system of the 2D space by calling `sgp_project(left, right, top, bottom)`, 278 | with it. 279 | 280 | ## Transforming 2D space 281 | 282 | You can translate, rotate or scale the 2D space before a draw call, by using the transformation 283 | functions the library provides, such as `sgp_translate(x, y)`, `sgp_rotate(theta)`, etc. 284 | Check the cheat sheet or the header for more. 285 | 286 | To save and restore the transformation state you should call `sgp_push_transform()` and 287 | later `sgp_pop_transform()`. 288 | 289 | ## Drawing primitives 290 | 291 | The library provides drawing functions for all the basic primitives, that is, 292 | for points, lines, triangles and rectangles, such as `sgp_draw_line()` and `sgp_draw_filled_rect()`. 293 | Check the cheat sheet or the header for more. 294 | All of them have batched variations. 295 | 296 | ## Drawing textured primitives 297 | 298 | To draw textured rectangles you can use `sgp_set_image(0, img)` and then `sgp_draw_filled_rect()`, 299 | this will draw an entire texture into a rectangle. 300 | You should later reset the image with `sgp_reset_image(0)` to restore the bound image to default white image, 301 | otherwise you will have glitches when drawing a solid color. 302 | 303 | In case you want to draw a specific source from the texture, 304 | you should use `sgp_draw_textured_rect()` instead. 305 | 306 | By default textures are drawn using a simple nearest filter sampler, 307 | you can change the sampler with `sgp_set_sampler(0, smp)` before drawing a texture, 308 | it's recommended to restore the default sampler using `sgp_reset_sampler(0)`. 309 | 310 | ## Color modulation 311 | 312 | All common pipelines have color modulation, and you can modulate 313 | a color before a draw by setting the current state color with `sgp_set_color(r,g,b,a)`, 314 | later you should reset the color to default (white) with `sgp_reset_color()`. 315 | 316 | ## Custom shaders 317 | 318 | When using a custom shader, you must create a pipeline for it with `sgp_make_pipeline(desc)`, 319 | using shader, blend mode and a draw primitive associated with it. Then you should 320 | call `sgp_set_pipeline()` before the shader draw call. You are responsible for using 321 | the same blend mode and drawing primitive as the created pipeline. 322 | 323 | Custom uniforms can be passed to the shader with `sgp_set_uniform(vs_data, vs_size, fs_data, fs_size)`, 324 | where you should always pass a pointer to a struct with exactly the same schema and size 325 | as the one defined in the vertex and fragment shaders. 326 | 327 | Although you can create custom shaders for each graphics backend manually, 328 | it is advised should use the Sokol shader compiler [SHDC](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md), 329 | because it can generate shaders for multiple backends from a single `.glsl` file, 330 | and this usually works well. 331 | 332 | By default the library uniform buffer per draw call has just 8 float uniforms 333 | (`SGP_UNIFORM_CONTENT_SLOTS` configuration), and that may be too low to use with custom shaders. 334 | This is the default because typically newcomers may not want to use custom 2D shaders, 335 | and increasing a larger value means more overhead. 336 | If you are using custom shaders please increase this value to be large enough to hold 337 | the number of uniforms of your largest shader. 338 | 339 | ## Library configuration 340 | 341 | The following macros can be defined before including to change the library behavior: 342 | 343 | - `SGP_BATCH_OPTIMIZER_DEPTH` - Number of draw commands that the batch optimizer looks back at. Default is 8. 344 | - `SGP_UNIFORM_CONTENT_SLOTS` - Maximum number of floats that can be stored in each draw call uniform buffer. Default is 8. 345 | - `SGP_TEXTURE_SLOTS` - Maximum number of textures that can be bound per draw call. Default is 4. 346 | 347 | ## License 348 | 349 | MIT, see LICENSE file or the end of `sokol_gp.h` file. 350 | 351 | ## Cheat sheet 352 | 353 | Here is a quick list of all library functions for quick reference: 354 | 355 | ```c 356 | /* Initialization and de-initialization. */ 357 | void sgp_setup(const sgp_desc* desc); /* Initializes the SGP context, and should be called after `sg_setup`. */ 358 | void sgp_shutdown(void); /* Destroys the SGP context. */ 359 | bool sgp_is_valid(void); /* Checks if SGP context is valid, should be checked after `sgp_setup`. */ 360 | 361 | /* Error handling. */ 362 | sgp_error sgp_get_last_error(void); /* Returns last SGP error. */ 363 | const char* sgp_get_error_message(sgp_error error); /* Returns a message with SGP error description. */ 364 | 365 | /* Custom pipeline creation. */ 366 | sg_pipeline sgp_make_pipeline(const sgp_pipeline_desc* desc); /* Creates a custom shader pipeline to be used with SGP. */ 367 | 368 | /* Draw command queue management. */ 369 | void sgp_begin(int width, int height); /* Begins a new SGP draw command queue. */ 370 | void sgp_flush(void); /* Dispatch current Sokol GFX draw commands. */ 371 | void sgp_end(void); /* End current draw command queue, discarding it. */ 372 | 373 | /* 2D coordinate space projection */ 374 | void sgp_project(float left, float right, float top, float bottom); /* Set the coordinate space boundary in the current viewport. */ 375 | void sgp_reset_project(void); /* Resets the coordinate space to default (coordinate of the viewport). */ 376 | 377 | /* 2D coordinate space transformation. */ 378 | void sgp_push_transform(void); /* Saves current transform matrix, to be restored later with a pop. */ 379 | void sgp_pop_transform(void); /* Restore transform matrix to the same value of the last push. */ 380 | void sgp_reset_transform(void); /* Resets the transform matrix to identity (no transform). */ 381 | void sgp_translate(float x, float y); /* Translates the 2D coordinate space. */ 382 | void sgp_rotate(float theta); /* Rotates the 2D coordinate space around the origin. */ 383 | void sgp_rotate_at(float theta, float x, float y); /* Rotates the 2D coordinate space around a point. */ 384 | void sgp_scale(float sx, float sy); /* Scales the 2D coordinate space around the origin. */ 385 | void sgp_scale_at(float sx, float sy, float x, float y); /* Scales the 2D coordinate space around a point. */ 386 | 387 | /* State change for custom pipelines. */ 388 | void sgp_set_pipeline(sg_pipeline pipeline); /* Sets current draw pipeline. */ 389 | void sgp_reset_pipeline(void); /* Resets to the current draw pipeline to default (builtin pipelines). */ 390 | void sgp_set_uniform(const void* vs_data, uint32_t vs_size, const void *fs_data, uint32_t fs_size); /* Sets uniform buffer for a custom pipeline. */ 391 | void sgp_reset_uniform(void); /* Resets uniform buffer to default (current state color). */ 392 | 393 | /* State change functions for the common pipelines. */ 394 | void sgp_set_blend_mode(sgp_blend_mode blend_mode); /* Sets current blend mode. */ 395 | void sgp_reset_blend_mode(void); /* Resets current blend mode to default (no blending). */ 396 | void sgp_set_color(float r, float g, float b, float a); /* Sets current color modulation. */ 397 | void sgp_reset_color(void); /* Resets current color modulation to default (white). */ 398 | void sgp_set_image(int channel, sg_image image); /* Sets current bound image in a texture channel. */ 399 | void sgp_unset_image(int channel); /* Remove current bound image in a texture channel (no texture). */ 400 | void sgp_reset_image(int channel); /* Resets current bound image in a texture channel to default (white texture). */ 401 | void sgp_set_sampler(int channel, sg_sampler sampler); /* Sets current bound sampler in a texture channel. */ 402 | void sgp_unset_sampler(int channel); /* Remove current bound sampler in a texture channel (no sampler). */ 403 | void sgp_reset_sampler(int channel); /* Resets current bound sampler in a texture channel to default (nearest sampler). */ 404 | 405 | /* State change functions for all pipelines. */ 406 | void sgp_viewport(int x, int y, int w, int h); /* Sets the screen area to draw into. */ 407 | void sgp_reset_viewport(void); /* Reset viewport to default values (0, 0, width, height). */ 408 | void sgp_scissor(int x, int y, int w, int h); /* Set clip rectangle in the viewport. */ 409 | void sgp_reset_scissor(void); /* Resets clip rectangle to default (viewport bounds). */ 410 | void sgp_reset_state(void); /* Reset all state to default values. */ 411 | 412 | /* Drawing functions. */ 413 | void sgp_clear(void); /* Clears the current viewport using the current state color. */ 414 | void sgp_draw(sg_primitive_type primitive_type, const sgp_vertex* vertices, uint32_t count); /* Low level drawing function, capable of drawing any primitive. */ 415 | void sgp_draw_points(const sgp_point* points, uint32_t count); /* Draws points in a batch. */ 416 | void sgp_draw_point(float x, float y); /* Draws a single point. */ 417 | void sgp_draw_lines(const sgp_line* lines, uint32_t count); /* Draws lines in a batch. */ 418 | void sgp_draw_line(float ax, float ay, float bx, float by); /* Draws a single line. */ 419 | void sgp_draw_lines_strip(const sgp_point* points, uint32_t count); /* Draws a strip of lines. */ 420 | void sgp_draw_filled_triangles(const sgp_triangle* triangles, uint32_t count); /* Draws triangles in a batch. */ 421 | void sgp_draw_filled_triangle(float ax, float ay, float bx, float by, float cx, float cy); /* Draws a single triangle. */ 422 | void sgp_draw_filled_triangles_strip(const sgp_point* points, uint32_t count); /* Draws strip of triangles. */ 423 | void sgp_draw_filled_rects(const sgp_rect* rects, uint32_t count); /* Draws a batch of rectangles. */ 424 | void sgp_draw_filled_rect(float x, float y, float w, float h); /* Draws a single rectangle. */ 425 | void sgp_draw_textured_rects(int channel, const sgp_textured_rect* rects, uint32_t count); /* Draws a batch textured rectangle, each from a source region. */ 426 | void sgp_draw_textured_rect(int channel, sgp_rect dest_rect, sgp_rect src_rect); /* Draws a single textured rectangle from a source region. */ 427 | 428 | /* Querying functions. */ 429 | sgp_state* sgp_query_state(void); /* Returns the current draw state. */ 430 | sgp_desc sgp_query_desc(void); /* Returns description of the current SGP context. */ 431 | ``` 432 | 433 | ## Robustness 434 | 435 | This library has been tested since 2020 in private projects, 436 | and has proved to be stable. 437 | 438 | ## Sponsorships 439 | 440 | This library has been originally sponsored by the MMORPG game [Medivia Online](https://medivia.online/), 441 | I would like to thank them for supporting my work. 442 | 443 | Thanks @kkukshtel for sponsoring batching draw calls with different colors feature. 444 | 445 | ## Related projects 446 | 447 | Make sure to checkout the excellent [Sokol](https://github.com/floooh/sokol) project by @floooh, 448 | it features many useful single header C libraries made with quality that can be used for game development. 449 | 450 | You may also want to check my other single header C library 451 | [Minicoro](https://github.com/edubart/minicoro), 452 | it brings stackful coroutines for C, 453 | very useful for simplifying finite state machines in game devlopment. 454 | 455 | ## Updates 456 | 457 | * **06-Dec-2024**: Update to latest Sokol, resulting breaking changes in `sgp_set_uniform` API, 458 | added new pre-multiplied blend modes. 459 | * **27-Jul-2024**: Update to latest Sokol, the OpenGL backend requires now at least GL 4.1. 460 | * **22-Mar-2024**: Update to latest Sokol, added support for iOS simulator backend. 461 | * **18-Jan-2024**: Fix shader leaking when creating custom SGP pipelines. 462 | * **07-Jan-2024**: Make possible to set custom depth format and sample count in pipelines, batch draw calls even when using different colors, introduce low level primitive drawing function, format source files. 463 | * **31-Oct-2023**: Update to latest Sokol, introduced new WebGPU backend. 464 | * **30-Sep-2023**: Update to latest Sokol, deprecated GLES2 backend, add image sampler APIs, changes in draw textured APIs. 465 | * **31-Dec-2021**: The library was open sourced. 466 | * **05-Aug-2020**: Added support for custom shaders. 467 | * **03-Jun-2020**: Added the batch optimizer. 468 | * **29-May-2020**: The library was created. 469 | 470 | ## Screenshots 471 | 472 | Here are some screenshots of all samples in `samples` directory. 473 | Click on any of the images to view it actually being rendered in realtime in your browser. 474 | 475 | Primitives sample: 476 | 477 | [![sample-primitives](https://edubart.github.io/sokol_gp/sample-primitives.png)](https://edubart.github.io/sokol_gp/sample-primitives.html) 478 | 479 | Blending modes samples: 480 | 481 | [![sample-blend](https://edubart.github.io/sokol_gp/sample-blend.png)](https://edubart.github.io/sokol_gp/sample-blend.html) 482 | 483 | Frame buffer sample: 484 | 485 | [![sample-framebuffer](https://edubart.github.io/sokol_gp/sample-framebuffer.png)](https://edubart.github.io/sokol_gp/sample-framebuffer.html) 486 | 487 | Rectangle sample: 488 | 489 | [![sample-rectangle](https://edubart.github.io/sokol_gp/sample-rectangle.png)](https://edubart.github.io/sokol_gp/sample-rectangle.html) 490 | 491 | Effect sample: 492 | 493 | [![sample-effect](https://edubart.github.io/sokol_gp/sample-effect.png)](https://edubart.github.io/sokol_gp/sample-effect.html) 494 | 495 | SDF sample: 496 | 497 | [![sample-sdf](https://edubart.github.io/sokol_gp/sample-sdf.png)](https://edubart.github.io/sokol_gp/sample-sdf.html) 498 | 499 | ## Donation 500 | 501 | I'm a full-time open source developer, any amount of the donation through my GitHub will be appreciated and could bring me encouragement to keep supporting this and other open source projects. 502 | I may accept one-time sponsorships for small features or minor enhancements aligned with the project goals, in this case contact me. 503 | -------------------------------------------------------------------------------- /images/lpc_winter_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edubart/sokol_gp/d2af9f4ef58850b6599a9aea6edaa7bd79ce67b4/images/lpc_winter_preview.png -------------------------------------------------------------------------------- /images/perlin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edubart/sokol_gp/d2af9f4ef58850b6599a9aea6edaa7bd79ce67b4/images/perlin.png -------------------------------------------------------------------------------- /samples/sample-bench.c: -------------------------------------------------------------------------------- 1 | /* 2 | This sample is used to benchmark, it intentionally draws lots of primitives 3 | with interleaved textures or pipelines, to measure then gains of the batch optimizer. 4 | 5 | In my latest tests on my computer (edubart) with batch optimizer active 6 | there is a 2.2x in FPS gains. 7 | */ 8 | 9 | // Uncomment this to disable the batch optimizer. 10 | // #define SGP_BATCH_OPTIMIZER_DEPTH 0 11 | 12 | #define SOKOL_IMPL 13 | #include "sokol_gfx.h" 14 | #include "sokol_gp.h" 15 | #include "sokol_app.h" 16 | #include "sokol_glue.h" 17 | #include "sokol_time.h" 18 | #include "sokol_log.h" 19 | 20 | #include 21 | #include 22 | 23 | static sg_image image1; 24 | static sg_image image2; 25 | static float image_ratio; 26 | 27 | static const int count = 48; 28 | static const int rect_count = 4; 29 | 30 | static void bench_repeated_textured(void) { 31 | sgp_reset_color(); 32 | sgp_set_image(0, image1); 33 | for (int y=0;y= 0 && x < count; --y, ++x) { 99 | if (x % 3 == 0) { 100 | sgp_set_color(1.0f, 0, 0, 1.0f); 101 | } else if (x % 3 == 1) { 102 | sgp_set_color(0, 1.0f, 0, 1.0f); 103 | } else { 104 | sgp_set_color(0, 0, 1.0f, 1.0f); 105 | } 106 | if ((x+y) % 2 == 0) { 107 | sgp_draw_filled_rect(x*rect_count*2, y*rect_count*2, rect_count, rect_count); 108 | } else { 109 | sgp_set_image(0, image1); 110 | sgp_draw_filled_rect(x*rect_count*2, y*rect_count*2, rect_count, rect_count); 111 | sgp_reset_image(0); 112 | } 113 | } 114 | } 115 | } 116 | 117 | static void bench_sync_mixed(void) { 118 | sgp_set_image(0, image1); 119 | sgp_reset_color(); 120 | for (int y=0;y= 1.0) { 198 | printf("FPS: %d\n", fps); 199 | last = now; 200 | fps = 0; 201 | } 202 | } 203 | 204 | static sg_image create_image(int width, int height) { 205 | size_t num_pixels = (size_t)(width * height * 4); 206 | unsigned char* data = (unsigned char*)malloc(num_pixels); 207 | assert(data); 208 | for (int y=0;y 16 | #include 17 | 18 | static void draw_3rects(float brightness, float alpha) { 19 | sgp_translate(2.5f, 2.5f); 20 | sgp_set_color(brightness, 0.0f, 0.0f, alpha); 21 | sgp_draw_filled_rect(0, 0, 10, 10); 22 | sgp_set_color(0.0f, brightness, 0.0f, alpha); 23 | sgp_draw_filled_rect(0, 5, 10, 10); 24 | sgp_set_color(0.0f, 0.0f, brightness, alpha); 25 | sgp_draw_filled_rect(5, 2.5f, 10, 10); 26 | } 27 | 28 | static void draw_rects(float ratio) { 29 | sgp_project(0, 60*ratio, 0, 60); 30 | sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); 31 | 32 | // none 33 | sgp_set_blend_mode(SGP_BLENDMODE_NONE); 34 | sgp_push_transform(); 35 | sgp_translate(0, 0); 36 | draw_3rects(1.0f, 0.5f); 37 | sgp_pop_transform(); 38 | 39 | // blend 40 | sgp_set_blend_mode(SGP_BLENDMODE_BLEND); 41 | sgp_push_transform(); 42 | sgp_translate(20, 0); 43 | draw_3rects(1.0f, 0.5f); 44 | sgp_pop_transform(); 45 | 46 | // blend premultiplied 47 | sgp_set_blend_mode(SGP_BLENDMODE_BLEND_PREMULTIPLIED); 48 | sgp_push_transform(); 49 | sgp_translate(40, 0); 50 | draw_3rects(1.0f, 0.5f); 51 | sgp_pop_transform(); 52 | 53 | // add 54 | sgp_set_blend_mode(SGP_BLENDMODE_ADD); 55 | sgp_push_transform(); 56 | sgp_translate(20, 20); 57 | draw_3rects(1.0f, 0.5f); 58 | sgp_pop_transform(); 59 | 60 | // add premultiplied 61 | sgp_set_blend_mode(SGP_BLENDMODE_ADD_PREMULTIPLIED); 62 | sgp_push_transform(); 63 | sgp_translate(40, 20); 64 | draw_3rects(1.0f, 0.5f); 65 | sgp_pop_transform(); 66 | 67 | // mod 68 | sgp_set_blend_mode(SGP_BLENDMODE_MOD); 69 | sgp_push_transform(); 70 | sgp_translate(20, 40); 71 | draw_3rects(1.0f, 0.5f); 72 | sgp_pop_transform(); 73 | 74 | // mul 75 | sgp_set_blend_mode(SGP_BLENDMODE_MUL); 76 | sgp_push_transform(); 77 | sgp_translate(40, 40); 78 | draw_3rects(1.0f, 0.5f); 79 | sgp_pop_transform(); 80 | } 81 | 82 | static void draw_checkboard(int width, int height) { 83 | sgp_set_color(0.2f, 0.2f, 0.2f, 1.0f); 84 | sgp_clear(); 85 | sgp_set_color(0.4f, 0.4f, 0.4f, 1.0f); 86 | for (int y=0;y= image_ratio) ? window_width : image_ratio*window_height; 53 | float height = (window_ratio >= image_ratio) ? window_width/image_ratio : window_height; 54 | sgp_draw_filled_rect(0, 0, width, height); 55 | sgp_reset_image(IMG_iTexChannel0); 56 | sgp_reset_image(IMG_iTexChannel1); 57 | sgp_reset_sampler(SMP_iSmpChannel0); 58 | sgp_reset_sampler(SMP_iSmpChannel1); 59 | sgp_reset_pipeline(); 60 | 61 | // dispatch draw commands 62 | sg_pass pass = {.swapchain = sglue_swapchain()}; 63 | sg_begin_pass(&pass); 64 | sgp_flush(); 65 | sgp_end(); 66 | sg_end_pass(); 67 | sg_commit(); 68 | } 69 | 70 | static sg_image load_image(const char *filename) { 71 | int width, height, channels; 72 | uint8_t* data = stbi_load(filename, &width, &height, &channels, 4); 73 | sg_image img = {SG_INVALID_ID}; 74 | if (!data) { 75 | return img; 76 | } 77 | sg_image_desc image_desc = {0}; 78 | image_desc.width = width; 79 | image_desc.height = height; 80 | image_desc.data.subimage[0][0].ptr = data; 81 | image_desc.data.subimage[0][0].size = (size_t)(width * height * 4); 82 | img = sg_make_image(&image_desc); 83 | stbi_image_free(data); 84 | return img; 85 | } 86 | 87 | static void init(void) { 88 | // initialize Sokol GFX 89 | sg_desc sgdesc = { 90 | .environment = sglue_environment(), 91 | .logger.func = slog_func 92 | }; 93 | sg_setup(&sgdesc); 94 | if (!sg_isvalid()) { 95 | fprintf(stderr, "Failed to create Sokol GFX context!\n"); 96 | exit(-1); 97 | } 98 | 99 | // initialize Sokol GP 100 | sgp_desc sgpdesc = {0}; 101 | sgp_setup(&sgpdesc); 102 | if (!sgp_is_valid()) { 103 | fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); 104 | exit(-1); 105 | } 106 | 107 | // load image 108 | image = load_image("images/lpc_winter_preview.png"); 109 | perlin_image = load_image("images/perlin.png"); 110 | if (sg_query_image_state(image) != SG_RESOURCESTATE_VALID || sg_query_image_state(perlin_image) != SG_RESOURCESTATE_VALID) { 111 | fprintf(stderr, "failed to load images"); 112 | exit(-1); 113 | } 114 | 115 | // create linear sampler 116 | sg_sampler_desc linear_sampler_desc = { 117 | .min_filter = SG_FILTER_LINEAR, 118 | .mag_filter = SG_FILTER_LINEAR, 119 | .wrap_u = SG_WRAP_REPEAT, 120 | .wrap_v = SG_WRAP_REPEAT, 121 | }; 122 | linear_sampler = sg_make_sampler(&linear_sampler_desc); 123 | if (sg_query_sampler_state(linear_sampler) != SG_RESOURCESTATE_VALID) { 124 | fprintf(stderr, "failed to create linear sampler"); 125 | exit(-1); 126 | } 127 | 128 | // initialize shader 129 | shd = sg_make_shader(effect_program_shader_desc(sg_query_backend())); 130 | if (sg_query_shader_state(shd) != SG_RESOURCESTATE_VALID) { 131 | fprintf(stderr, "failed to make custom pipeline shader\n"); 132 | exit(-1); 133 | } 134 | sgp_pipeline_desc pip_desc = {0}; 135 | pip_desc.shader = shd; 136 | pip_desc.has_vs_color = true; 137 | pip = sgp_make_pipeline(&pip_desc); 138 | if (sg_query_pipeline_state(pip) != SG_RESOURCESTATE_VALID) { 139 | fprintf(stderr, "failed to make custom pipeline\n"); 140 | exit(-1); 141 | } 142 | } 143 | 144 | static void cleanup(void) { 145 | sg_destroy_image(image); 146 | sg_destroy_image(perlin_image); 147 | sg_destroy_pipeline(pip); 148 | sg_destroy_shader(shd); 149 | sgp_shutdown(); 150 | sg_shutdown(); 151 | } 152 | 153 | sapp_desc sokol_main(int argc, char* argv[]) { 154 | (void)argc; 155 | (void)argv; 156 | return (sapp_desc){ 157 | .init_cb = init, 158 | .frame_cb = frame, 159 | .cleanup_cb = cleanup, 160 | .window_title = "SDF (Sokol GP)", 161 | .logger.func = slog_func, 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /samples/sample-framebuffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | This sample showcases how to use Sokol GP to draw inside frame buffers (render targets). 3 | */ 4 | 5 | #define SOKOL_IMPL 6 | #include "sokol_gfx.h" 7 | #include "sokol_gp.h" 8 | #include "sokol_app.h" 9 | #include "sokol_glue.h" 10 | #include "sokol_log.h" 11 | 12 | #include 13 | #include 14 | 15 | static sg_image fb_color_image; 16 | static sg_image fb_resolve_image; 17 | static sg_image fb_depth_image; 18 | static sg_attachments fb_attachments; 19 | static sg_sampler linear_sampler; 20 | 21 | static void draw_triangles(void) { 22 | const float PI = 3.14159265f; 23 | static sgp_vec2 points_buffer[4096]; 24 | 25 | sgp_irect viewport = sgp_query_state()->viewport; 26 | int width = viewport.w, height = viewport.h; 27 | float hw = width * 0.5f; 28 | float hh = height * 0.5f; 29 | float w = height*0.3f; 30 | unsigned int count = 0; 31 | float step = (2.0f*PI)/6.0f; 32 | for (float theta = 0.0f; theta <= 2.0f*PI + step*0.5f; theta+=step) { 33 | sgp_vec2 v = {hw*1.33f + w*cosf(theta), hh*1.33f - w*sinf(theta)}; 34 | points_buffer[count++] = v; 35 | if (count % 3 == 1) { 36 | sgp_vec2 u = {hw, hh}; 37 | points_buffer[count++] = u; 38 | } 39 | } 40 | sgp_set_color(1.0f, 0.0f, 1.0f, 1.0f); 41 | sgp_draw_filled_triangles_strip(points_buffer, count); 42 | } 43 | 44 | static void draw_fbo(void) { 45 | sgp_begin(128, 128); 46 | sgp_project(0, 128, 128, 0); 47 | draw_triangles(); 48 | 49 | sg_pass_action pass_action = {0}; 50 | pass_action.colors[0].load_action = SG_LOADACTION_CLEAR; 51 | pass_action.colors[0].store_action = SG_STOREACTION_DONTCARE; 52 | pass_action.colors[0].clear_value.r = 1.0f; 53 | pass_action.colors[0].clear_value.g = 1.0f; 54 | pass_action.colors[0].clear_value.b = 1.0f; 55 | pass_action.colors[0].clear_value.a = 0.2f; 56 | sg_pass pass = { 57 | .action = pass_action, 58 | .attachments = fb_attachments 59 | }; 60 | sg_begin_pass(&pass); 61 | sgp_flush(); 62 | sgp_end(); 63 | sg_end_pass(); 64 | } 65 | 66 | static void frame(void) { 67 | // begin draw commands queue 68 | int width = sapp_width(), height = sapp_height(); 69 | sgp_begin(width, height); 70 | 71 | // draw background 72 | sgp_set_color(0.05f, 0.05f, 0.05f, 1.0f); 73 | sgp_clear(); 74 | sgp_reset_color(); 75 | 76 | float time = sapp_frame_count() / 60.0f; 77 | sgp_set_blend_mode(SGP_BLENDMODE_BLEND); 78 | draw_fbo(); 79 | int i = 0; 80 | for (int y=0;y 13 | #include 14 | 15 | static const float PI = 3.14159265358979323846264338327f; 16 | 17 | static void draw_rects(void) { 18 | sgp_irect viewport = sgp_query_state()->viewport; 19 | int width = viewport.w, height = viewport.h; 20 | int size = 64; 21 | int hsize = size / 2; 22 | float time = sapp_frame_count() / 60.0f; 23 | float t = (1.0f+sinf(time))/2.0f; 24 | 25 | // left 26 | sgp_push_transform(); 27 | sgp_translate(width*0.25f - hsize, height*0.5f - hsize); 28 | sgp_translate(0.0f, 2*size*t - size); 29 | sgp_set_color(t, 0.3f, 1.0f-t, 1.0f); 30 | sgp_draw_filled_rect(0, 0, size, size); 31 | sgp_pop_transform(); 32 | 33 | // middle 34 | sgp_push_transform(); 35 | sgp_translate(width*0.5f - hsize, height*0.5f - hsize); 36 | sgp_rotate_at(time, hsize, hsize); 37 | sgp_set_color(t, 1.0f - t, 0.3f, 1.0f); 38 | sgp_draw_filled_rect(0, 0, size, size); 39 | sgp_pop_transform(); 40 | 41 | // right 42 | sgp_push_transform(); 43 | sgp_translate(width*0.75f - hsize, height*0.5f - hsize); 44 | sgp_scale_at(t + 0.25f, t + 0.5f, hsize, hsize); 45 | sgp_set_color(0.3f, t, 1.0f - t, 1.0f); 46 | sgp_draw_filled_rect(0, 0, size, size); 47 | sgp_pop_transform(); 48 | } 49 | 50 | static void draw_points(void) { 51 | // point grid 52 | sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); 53 | sgp_irect viewport = sgp_query_state()->viewport; 54 | int width = viewport.w, height = viewport.h; 55 | static sgp_vec2 points_buffer[4096]; 56 | unsigned int count = 0; 57 | for (int y=64;yviewport; 70 | sgp_vec2 c = {viewport.w / 2.0f, viewport.h / 2.0f}; 71 | static sgp_vec2 points_buffer[4096]; 72 | unsigned int count = 0; 73 | points_buffer[count++] = c; 74 | for (float theta = 0.0f; theta <= PI*8.0f; theta+=PI/16.0f) { 75 | float r = 10.0f*theta; 76 | sgp_vec2 v = {c.x + r*cosf(theta), c.y + r*sinf(theta)}; 77 | points_buffer[count++] = v; 78 | } 79 | sgp_draw_lines_strip(points_buffer, count); 80 | 81 | // x 82 | sgp_push_transform(); 83 | sgp_translate(viewport.w/2, viewport.h/2); 84 | int x_size = 32; 85 | sgp_line x_line[2] = { 86 | {{-x_size, -x_size}, { x_size, x_size}}, 87 | {{ x_size, -x_size}, {-x_size, x_size}}, 88 | }; 89 | sgp_draw_lines(x_line, 2); 90 | sgp_pop_transform(); 91 | } 92 | 93 | static void draw_triangles(void) { 94 | float time = sapp_frame_count() / 60.0f; 95 | sgp_irect viewport = sgp_query_state()->viewport; 96 | int width = viewport.w, height = viewport.h; 97 | 98 | // triangle 99 | float hw = width * 0.5f; 100 | float hh = height * 0.5f; 101 | float w = height*0.2f; 102 | float ax = hw - w, ay = hh + w; 103 | float bx = hw, by = hh - w; 104 | float cx = hw + w, cy = hh + w; 105 | sgp_set_color(1.0f, 0.0f, 1.0f, 1.0f); 106 | sgp_push_transform(); 107 | sgp_translate(-w*1.5f, 0.0f); 108 | sgp_draw_filled_triangle(ax, ay, bx, by, cx, cy); 109 | 110 | // hexagon 111 | sgp_translate(w*3.0f, -hh*0.5f); 112 | sgp_set_color(0.0f, 1.0f, 1.0f, 1.0f); 113 | { 114 | float step = (2.0f*PI)/6.0f; 115 | unsigned int count = 0; 116 | static sgp_vec2 points_buffer[4096]; 117 | for (float theta = 0.0f; theta <= 2.0f*PI + step*0.5f; theta+=step) { 118 | sgp_vec2 v = {hw + w*cosf(theta), hh - w*sinf(theta)}; 119 | points_buffer[count++] = v; 120 | if (count % 3 == 1) { 121 | sgp_vec2 u = {hw, hh}; 122 | points_buffer[count++] = u; 123 | } 124 | } 125 | sgp_draw_filled_triangles_strip(points_buffer, count); 126 | } 127 | 128 | // color wheel 129 | sgp_translate(0.0f, hh); 130 | sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); 131 | { 132 | float step = (2.0f*PI)/64.0f; 133 | unsigned int count = 0; 134 | static sgp_vertex vertex_buffer[4096]; 135 | for (float theta = 0.0f; theta <= 2.0f*PI + step*0.5f; theta+=step) { 136 | sgp_vec2 v = {hw + w*cosf(theta), hh - w*sinf(theta)}; 137 | vertex_buffer[count].position = v; 138 | vertex_buffer[count].color = (sgp_color_ub4){(sinf(theta + time*1) + 1.0f) * 0.5f * 255.0f, 139 | (sinf(theta + time*2) + 1.0f) * 0.5f * 255.0f, 140 | (sinf(theta + time*4) + 1.0f) * 0.5f * 255.0f, 255}; 141 | count++; 142 | if (count % 3 == 1) { 143 | sgp_vec2 u = {hw, hh}; 144 | vertex_buffer[count].position = u; 145 | vertex_buffer[count].color = (sgp_color_ub4){255, 255, 255, 255}; 146 | count++; 147 | } 148 | } 149 | sgp_draw(SG_PRIMITIVETYPE_TRIANGLE_STRIP, vertex_buffer, count); 150 | } 151 | sgp_pop_transform(); 152 | } 153 | 154 | static void frame(void) { 155 | // begin draw commands queue 156 | int width = sapp_width(), height = sapp_height(); 157 | sgp_begin(width, height); 158 | 159 | int hw = width / 2; 160 | int hh = height / 2; 161 | 162 | // draw background 163 | sgp_set_color(0.05f, 0.05f, 0.05f, 1.0f); 164 | sgp_clear(); 165 | sgp_reset_color(); 166 | 167 | // top left 168 | sgp_viewport(0, 0, hw, hh); 169 | sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); 170 | sgp_clear(); 171 | sgp_reset_color(); 172 | sgp_push_transform(); 173 | sgp_translate(0.0f, -hh / 4.0f); 174 | draw_rects(); 175 | sgp_pop_transform(); 176 | sgp_push_transform(); 177 | sgp_translate(0.0f, hh / 4.0f); 178 | sgp_scissor(0, 0, hw, 3.0f*hh / 4.0f); 179 | draw_rects(); 180 | sgp_reset_scissor(); 181 | sgp_pop_transform(); 182 | 183 | // top right 184 | sgp_viewport(hw, 0, hw, hh); 185 | draw_triangles(); 186 | 187 | // bottom left 188 | sgp_viewport(0, hh, hw, hh); 189 | draw_points(); 190 | 191 | // bottom right 192 | sgp_viewport(hw, hh, hw, hh); 193 | sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); 194 | sgp_clear(); 195 | sgp_reset_color(); 196 | draw_lines(); 197 | 198 | // dispatch draw commands 199 | sg_pass pass = {.swapchain = sglue_swapchain()}; 200 | sg_begin_pass(&pass); 201 | sgp_flush(); 202 | sgp_end(); 203 | sg_end_pass(); 204 | sg_commit(); 205 | } 206 | 207 | static void init(void) { 208 | // initialize Sokol GFX 209 | sg_desc sgdesc = { 210 | .environment = sglue_environment(), 211 | .logger.func = slog_func 212 | }; 213 | sg_setup(&sgdesc); 214 | if (!sg_isvalid()) { 215 | fprintf(stderr, "Failed to create Sokol GFX context!\n"); 216 | exit(-1); 217 | } 218 | 219 | // initialize Sokol GP 220 | sgp_desc sgpdesc = {0}; 221 | sgp_setup(&sgpdesc); 222 | if (!sgp_is_valid()) { 223 | fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); 224 | exit(-1); 225 | } 226 | } 227 | 228 | static void cleanup(void) { 229 | sgp_shutdown(); 230 | sg_shutdown(); 231 | } 232 | 233 | sapp_desc sokol_main(int argc, char* argv[]) { 234 | (void)argc; 235 | (void)argv; 236 | return (sapp_desc){ 237 | .init_cb = init, 238 | .frame_cb = frame, 239 | .cleanup_cb = cleanup, 240 | .window_title = "Primitives (Sokol GP)", 241 | .logger.func = slog_func, 242 | .sample_count = 4, 243 | }; 244 | } 245 | -------------------------------------------------------------------------------- /samples/sample-rectangle.c: -------------------------------------------------------------------------------- 1 | // This is an example on how to set up and use Sokol GP to draw a filled rectangle. 2 | 3 | // Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations. 4 | #define SOKOL_IMPL 5 | #include "sokol_gfx.h" 6 | #include "sokol_gp.h" 7 | #include "sokol_app.h" 8 | #include "sokol_glue.h" 9 | #include "sokol_log.h" 10 | 11 | #include // for fprintf() 12 | #include // for exit() 13 | #include // for sinf() and cosf() 14 | 15 | // Called on every frame of the application. 16 | static void frame(void) { 17 | // Get current window size. 18 | int width = sapp_width(), height = sapp_height(); 19 | float ratio = width/(float)height; 20 | 21 | // Begin recording draw commands for a frame buffer of size (width, height). 22 | sgp_begin(width, height); 23 | // Set frame buffer drawing region to (0,0,width,height). 24 | sgp_viewport(0, 0, width, height); 25 | // Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1). 26 | sgp_project(-ratio, ratio, 1.0f, -1.0f); 27 | 28 | // Clear the frame buffer. 29 | sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); 30 | sgp_clear(); 31 | 32 | // Draw an animated rectangle that rotates and changes its colors. 33 | float time = sapp_frame_count() * sapp_frame_duration(); 34 | float r = sinf(time)*0.5+0.5, g = cosf(time)*0.5+0.5; 35 | sgp_set_color(r, g, 0.3f, 1.0f); 36 | sgp_rotate_at(time, 0.0f, 0.0f); 37 | sgp_draw_filled_rect(-0.5f, -0.5f, 1.0f, 1.0f); 38 | 39 | // Begin a render pass. 40 | sg_pass pass = {.swapchain = sglue_swapchain()}; 41 | sg_begin_pass(&pass); 42 | // Dispatch all draw commands to Sokol GFX. 43 | sgp_flush(); 44 | // Finish a draw command queue, clearing it. 45 | sgp_end(); 46 | // End render pass. 47 | sg_end_pass(); 48 | // Commit Sokol render. 49 | sg_commit(); 50 | } 51 | 52 | // Called when the application is initializing. 53 | static void init(void) { 54 | // Initialize Sokol GFX. 55 | sg_desc sgdesc = { 56 | .environment = sglue_environment(), 57 | .logger.func = slog_func 58 | }; 59 | sg_setup(&sgdesc); 60 | if (!sg_isvalid()) { 61 | fprintf(stderr, "Failed to create Sokol GFX context!\n"); 62 | exit(-1); 63 | } 64 | 65 | // Initialize Sokol GP, adjust the size of command buffers for your own use. 66 | sgp_desc sgpdesc = {0}; 67 | sgp_setup(&sgpdesc); 68 | if (!sgp_is_valid()) { 69 | fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); 70 | exit(-1); 71 | } 72 | } 73 | 74 | // Called when the application is shutting down. 75 | static void cleanup(void) { 76 | // Cleanup Sokol GP and Sokol GFX resources. 77 | sgp_shutdown(); 78 | sg_shutdown(); 79 | } 80 | 81 | // Implement application main through Sokol APP. 82 | sapp_desc sokol_main(int argc, char* argv[]) { 83 | (void)argc; 84 | (void)argv; 85 | return (sapp_desc){ 86 | .init_cb = init, 87 | .frame_cb = frame, 88 | .cleanup_cb = cleanup, 89 | .window_title = "Rectangle (Sokol GP)", 90 | .logger.func = slog_func, 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /samples/sample-sdf.c: -------------------------------------------------------------------------------- 1 | /* 2 | This examples shows how to create 2D shaders, 3 | in this case the shader is a SDF (signed distance field) animation. 4 | */ 5 | 6 | #define SOKOL_IMPL 7 | #include "sokol_gfx.h" 8 | #include "sokol_gp.h" 9 | #include "sokol_app.h" 10 | #include "sokol_glue.h" 11 | #include "sokol_log.h" 12 | 13 | #define SOKOL_SHDC_IMPL 14 | #include "sample-sdf.glsl.h" 15 | 16 | #include 17 | #include 18 | 19 | static sg_pipeline pip; 20 | static sg_shader shd; 21 | 22 | static void frame(void) { 23 | // begin draw commands queue 24 | int width = sapp_width(), height = sapp_height(); 25 | sgp_begin(width, height); 26 | 27 | // draw using the custom shader pipeline 28 | sgp_set_pipeline(pip); 29 | sdf_vs_uniforms_t vs_uniform = {0}; 30 | vs_uniform.iResolution.x = width; 31 | vs_uniform.iResolution.y = height; 32 | sdf_fs_uniforms_t fs_uniform = {0}; 33 | fs_uniform.iTime = sapp_frame_count() / 60.0f; 34 | sgp_set_uniform(&vs_uniform, sizeof(sdf_vs_uniforms_t), &fs_uniform, sizeof(sdf_fs_uniforms_t)); 35 | sgp_unset_image(0); 36 | sgp_draw_filled_rect(0, 0, width, height); 37 | sgp_reset_image(0); 38 | sgp_reset_pipeline(); 39 | 40 | // dispatch draw commands 41 | sg_pass pass = {.swapchain = sglue_swapchain()}; 42 | sg_begin_pass(&pass); 43 | sgp_flush(); 44 | sgp_end(); 45 | sg_end_pass(); 46 | sg_commit(); 47 | } 48 | 49 | static void init(void) { 50 | // initialize Sokol GFX 51 | sg_desc sgdesc = { 52 | .environment = sglue_environment(), 53 | .logger.func = slog_func 54 | }; 55 | sg_setup(&sgdesc); 56 | if (!sg_isvalid()) { 57 | fprintf(stderr, "Failed to create Sokol GFX context!\n"); 58 | exit(-1); 59 | } 60 | 61 | // initialize Sokol GP 62 | sgp_desc sgpdesc = {0}; 63 | sgp_setup(&sgpdesc); 64 | if (!sgp_is_valid()) { 65 | fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error())); 66 | exit(-1); 67 | } 68 | 69 | // initialize shader 70 | shd = sg_make_shader(sdf_program_shader_desc(sg_query_backend())); 71 | if (sg_query_shader_state(shd) != SG_RESOURCESTATE_VALID) { 72 | fprintf(stderr, "failed to make custom pipeline shader\n"); 73 | exit(-1); 74 | } 75 | sgp_pipeline_desc pip_desc = {0}; 76 | pip_desc.shader = shd; 77 | pip_desc.has_vs_color = true; 78 | pip = sgp_make_pipeline(&pip_desc); 79 | if (sg_query_pipeline_state(pip) != SG_RESOURCESTATE_VALID) { 80 | fprintf(stderr, "failed to make custom pipeline\n"); 81 | exit(-1); 82 | } 83 | } 84 | 85 | static void cleanup(void) { 86 | sg_destroy_pipeline(pip); 87 | sg_destroy_shader(shd); 88 | sgp_shutdown(); 89 | sg_shutdown(); 90 | } 91 | 92 | sapp_desc sokol_main(int argc, char* argv[]) { 93 | (void)argc; 94 | (void)argv; 95 | return (sapp_desc){ 96 | .init_cb = init, 97 | .frame_cb = frame, 98 | .cleanup_cb = cleanup, 99 | .window_title = "SDF (Sokol GP)", 100 | .logger.func = slog_func, 101 | }; 102 | } 103 | -------------------------------------------------------------------------------- /samples/sample-shell.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | sokol_gp 7 | 29 | 30 | 31 | 32 | 62 | {{{ SCRIPT }}} 63 | 64 | 65 | -------------------------------------------------------------------------------- /shaders/sample-effect.glsl: -------------------------------------------------------------------------------- 1 | @module effect 2 | @ctype vec2 sgp_vec2 3 | @ctype float float 4 | 5 | @vs vs 6 | layout(location=0) in vec4 coord; 7 | layout(location=1) in vec4 color; 8 | layout(location=0) out vec2 texUV; 9 | layout(location=1) out vec4 iColor; 10 | void main() { 11 | gl_Position = vec4(coord.xy, 0.0, 1.0); 12 | texUV = coord.zw; 13 | iColor = color; 14 | } 15 | @end 16 | 17 | @fs fs 18 | layout(binding=0) uniform texture2D iTexChannel0; 19 | layout(binding=1) uniform texture2D iTexChannel1; 20 | layout(binding=0) uniform sampler iSmpChannel0; 21 | layout(binding=1) uniform sampler iSmpChannel1; 22 | layout(binding=1) uniform fs_uniforms { 23 | vec2 iVelocity; 24 | float iPressure; 25 | float iTime; 26 | float iWarpiness; 27 | float iRatio; 28 | float iZoom; 29 | float iLevel; 30 | }; 31 | layout(location=0) in vec2 texUV; 32 | layout(location=1) in vec4 iColor; 33 | layout(location=0) out vec4 fragColor; 34 | float noise(vec2 p) { 35 | return texture(sampler2D(iTexChannel1, iSmpChannel1), p).r; 36 | } 37 | void main() { 38 | vec3 tex_col = texture(sampler2D(iTexChannel0, iSmpChannel0), texUV).rgb; 39 | vec2 fog_uv = (texUV * vec2(iRatio, 1.0)) * iZoom; 40 | float f = noise(fog_uv - iVelocity*iTime); 41 | f = noise(fog_uv + f*iWarpiness); 42 | vec3 col = mix(tex_col, vec3(f) * iColor.rgb, iPressure); 43 | fragColor = vec4(col, 1.0); 44 | } 45 | @end 46 | 47 | @program program vs fs 48 | -------------------------------------------------------------------------------- /shaders/sample-sdf.glsl: -------------------------------------------------------------------------------- 1 | @module sdf 2 | @ctype vec2 sgp_vec2 3 | @ctype float float 4 | 5 | @vs vs 6 | layout(binding=0) uniform vs_uniforms { 7 | vec2 iResolution; 8 | }; 9 | layout(location=0) in vec4 coord; 10 | layout(location=0) out vec2 texUV; 11 | layout(location=1) out vec2 fragPos; 12 | void main() { 13 | gl_Position = vec4(coord.xy, 0.0, 1.0); 14 | fragPos = vec2(coord.x * (iResolution.x/iResolution.y), coord.y); 15 | texUV = coord.zw; 16 | } 17 | @end 18 | 19 | @fs fs 20 | layout(binding=1) uniform fs_uniforms { 21 | float iTime; 22 | }; 23 | layout(location=0) in vec2 texUV; 24 | layout(location=1) in vec2 fragPos; 25 | layout(location=0) out vec4 fragColor; 26 | 27 | #line 0 28 | #define PI 3.141592653589793238 29 | 30 | float sd_circle(vec2 p, float r) { 31 | return length(p) - r; 32 | } 33 | 34 | float length_n(vec2 p, float n) { p=pow(abs(p), vec2(n)); return pow(p.x+p.y, 1.0/n); } 35 | 36 | float sd_ellipsoid(vec2 p, vec2 r, float roundness){ 37 | float k1 = length_n(p/r, roundness); 38 | float k2 = length_n(p/(r*r), roundness); 39 | return k1*(k1-1.0)/k2; 40 | } 41 | 42 | float sd_vesica(vec2 p, float r, float d) { 43 | p = abs(p); 44 | float b = sqrt(r*r-d*d); 45 | return ((p.y-b)*d>p.x*b) ? length(p-vec2(0.0,b)) 46 | : length(p-vec2(-d,0.0))-r; 47 | } 48 | 49 | float sd_arc(vec2 p, float ta, float tb, float ra, float rb) { 50 | vec2 sca = vec2(cos(ta), sin(ta)); 51 | vec2 scb = vec2(cos(tb), sin(tb)); 52 | p *= mat2(sca.x,sca.y,-sca.y,sca.x); 53 | p.x = abs(p.x); 54 | float k = (scb.y*p.x>scb.x*p.y) ? dot(p.xy,scb) : length(p.xy); 55 | return sqrt( dot(p,p) + ra*ra - 2.0*ra*k ) - rb; 56 | } 57 | 58 | float sd_line(vec2 p, vec2 a, vec2 b){ 59 | vec2 pa = p-a, ba = b-a; 60 | float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); 61 | return length( pa - ba*h ); 62 | } 63 | 64 | vec2 rotate(vec2 p, float theta) { 65 | float cost = cos(theta); 66 | float sint = sin(theta); 67 | return vec2(p.x*cost - p.y*sint, p.x*sint + p.y*cost); 68 | } 69 | 70 | float smin(float a, float b, float k) { 71 | float h = max(k - abs(a-b), 0.0)/k; 72 | return min(a, b) - h*h*k*(1.0/4.0); 73 | } 74 | 75 | vec3 background(vec2 uv) { 76 | vec2 q = abs(floor(uv)); 77 | vec3 col = vec3(0.39); 78 | col += vec3(0.17)*mod(q.x+q.y, 2.0); 79 | return col; 80 | } 81 | 82 | vec3 blend(vec3 col, vec3 ocol, float d) { 83 | return mix(ocol, col, smoothstep(0.5, 0.0, d)); 84 | } 85 | 86 | vec3 map(vec2 p) { 87 | float d, d2; 88 | vec2 q; 89 | p *= 100.0; 90 | p.y -= 30.0; 91 | vec2 sp = vec2(abs(p.x), p.y); 92 | 93 | // background 94 | vec3 ocol = background(p*0.3); 95 | 96 | // water 97 | d = sd_ellipsoid(p - vec2(0.0, -97.0), vec2(55.0, 20.0), 2.0); 98 | ocol = blend(vec3(0.61,0.85,0.94), ocol, d); 99 | 100 | // head 101 | q = sp; 102 | d = sd_ellipsoid(q, vec2(55.0, 45.0), 2.4); 103 | 104 | // moustache 1 105 | q -= vec2(45.0, -15.0); 106 | q.y += q.x*q.x*0.003*sin(iTime*1.0); 107 | d2 = sd_line(q, vec2(0.0,0.0), vec2(45.0,0.0)) - 0.2; 108 | d = min(d, d2); 109 | 110 | // moustache 2 111 | q.y += 6.0; 112 | q.y += q.x*q.x*0.003*sin(iTime*2.0); 113 | d2 = sd_line(q, vec2(0.0,0.0), vec2(45.0,0.0)) - 0.2; 114 | d = min(d, d2); 115 | 116 | // ears 117 | q = sp - vec2(32.0,30.0); 118 | q = rotate(q, 0.7+sin(iTime)*0.3); 119 | d2 = sd_vesica(q, 30.0, 15.0); 120 | d = min(d, d2); 121 | ocol = blend(vec3(0.12), ocol, d); 122 | 123 | // body 124 | q = sp; 125 | d = sd_ellipsoid(q - vec2(0.0,-60.0), vec2(27.0, 20.0), 2.0); 126 | d2 = sd_ellipsoid(q - vec2(0.0,-70.0), vec2(20.0, 16.0), 2.0); 127 | d = max(-d2, d); 128 | 129 | // middle legs 130 | q = sp - vec2(6.0, -50.0); 131 | q = rotate(q, -(0.5+0.5*sin(iTime))*0.1); 132 | q.x -= pow(max(-45.0-q.y, 0.0), 1.9)*0.1; 133 | d2 = sd_line(q, vec2(0.0,-50.0), vec2(0.0,0.0)) - 5.0; 134 | d = smin(d, d2, 1.0); 135 | 136 | // outer legs 137 | q = sp - vec2(22.0, -60.0); 138 | q = rotate(q, -(0.5+0.5*cos(iTime))*0.1); 139 | q.x -= pow(max(-29.0-q.y, 0.0), 1.9)*0.1; 140 | d2 = sd_line(q, vec2(0.0,-35.0), vec2(0.0,0.0)) - 5.0; 141 | d = smin(d, d2, 1.0); 142 | 143 | // tail 144 | q = p - vec2(-26.0, -60.0); 145 | q = rotate(q, PI*0.7); 146 | q.x -= sin(q.y*0.123+3.0)*4.0 + sin(q.y*0.1+iTime*10.0); 147 | d2 = sd_line(q, vec2(0.0,-40.0), vec2(0.0,0.0)) - 5.0 * smoothstep(-60.0, 0.0, q.y); 148 | d = smin(d, d2, 1.0); 149 | ocol = blend(vec3(0.12), ocol, d); 150 | 151 | // tail skin 152 | d = sd_circle(q - vec2(-2.0, -4.0), 1.3); 153 | d = min(d, sd_circle(q - vec2(-2.0, -9.0), 1.2)); 154 | d = min(d, sd_circle(q - vec2(-2.0, -15.0), 1.1)); 155 | d = min(d, sd_circle(q - vec2(-2.0, -20.0), 1.0)); 156 | d = min(d, sd_circle(q - vec2(-1.6, -25.0), 0.9)); 157 | d = min(d, sd_circle(q - vec2(-1.3, -29.0), 0.8)); 158 | d = min(d, sd_circle(q - vec2(-0.9, -33.0), 0.7)); 159 | d = min(d, sd_circle(q - vec2(-0.8, -37.0), 0.6)); 160 | ocol = blend(vec3(0.61,0.85,0.94), ocol, d); 161 | 162 | // face 163 | q = sp; 164 | q.y -= -11.0; 165 | d = sd_ellipsoid(q - vec2(0.0,-5.0), vec2(40.0, 20.0), 2.9); 166 | d = smin(d, sd_circle(q - vec2(21.0,0.0), 20.0), 5.0); 167 | ocol = blend(vec3(0.98, 0.79, 0.69), ocol, d); 168 | 169 | // nose 170 | d = sd_circle(q - vec2(0.0,-12.0+sin(iTime)*0.5), 2.0); 171 | 172 | // mouth 173 | d2 = sd_arc(q - vec2(0.0,-18.0), PI+sin(iTime)*0.3, 0.3, 4.0, 0.4); 174 | d = min(d, d2); 175 | ocol = blend(vec3(0.67, 0.36, 0.32), ocol, d); 176 | 177 | // eye white ball 178 | q = sp; 179 | q.y -= -12.0; 180 | q.y /= 1.0 - smoothstep(0.98,1.0,sin(iTime*3.0)); 181 | d = sd_ellipsoid(q - vec2(20.0,0.0), vec2(9.0, 12.0), 2.0); 182 | ocol = blend(vec3(1.0), ocol, d); 183 | 184 | // eye retina 185 | d = sd_ellipsoid(q - vec2(19.5,0.0), vec2(5.0, 8.0), 2.0); 186 | ocol = blend(vec3(0.67, 0.36, 0.32), ocol, d); 187 | 188 | // eye reflection 189 | q = p - vec2(-2.0, 0.0); 190 | q.x = abs(q.x); 191 | d = sd_circle(q - vec2(19.5,-8.0), 1.3); 192 | ocol = blend(vec3(1.0), ocol, d); 193 | 194 | return ocol; 195 | } 196 | 197 | void main() { 198 | vec3 col = map(fragPos); 199 | fragColor = vec4(col,1.0); 200 | } 201 | 202 | @end 203 | 204 | @program program vs fs 205 | -------------------------------------------------------------------------------- /shaders/sokol_gp.glsl: -------------------------------------------------------------------------------- 1 | /* This is the shader used by the default SGP pipeline */ 2 | @module sgp 3 | 4 | @vs vs 5 | layout(location=0) in vec4 coord; 6 | layout(location=1) in vec4 color; 7 | layout(location=0) out vec2 texUV; 8 | layout(location=1) out vec4 iColor; 9 | void main() { 10 | gl_Position = vec4(coord.xy, 0.0, 1.0); 11 | gl_PointSize = 1.0; 12 | texUV = coord.zw; 13 | iColor = color; 14 | } 15 | @end 16 | 17 | @fs fs 18 | layout(binding=0) uniform texture2D iTexChannel0; 19 | layout(binding=0) uniform sampler iSmpChannel0; 20 | layout(location=0) in vec2 texUV; 21 | layout(location=1) in vec4 iColor; 22 | layout(location=0) out vec4 fragColor; 23 | void main() { 24 | fragColor = texture(sampler2D(iTexChannel0, iSmpChannel0), texUV) * iColor; 25 | } 26 | @end 27 | 28 | @program program vs fs 29 | -------------------------------------------------------------------------------- /shaders/sokol_gp.glsl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /* 3 | #version:1# (machine generated, don't edit!) 4 | 5 | Generated by sokol-shdc (https://github.com/floooh/sokol-tools) 6 | 7 | Cmdline: 8 | sokol-shdc --format sokol_impl --slang glsl410:glsl300es:hlsl4:metal_macos:metal_ios:wgsl -i shaders/sokol_gp.glsl -o shaders/sokol_gp.glsl.h 9 | 10 | Overview: 11 | ========= 12 | Shader program: 'program': 13 | Get shader desc: sgp_program_shader_desc(sg_query_backend()); 14 | Vertex Shader: vs 15 | Fragment Shader: fs 16 | Attributes: 17 | ATTR_program_coord => 0 18 | ATTR_program_color => 1 19 | Bindings: 20 | Image 'iTexChannel0': 21 | Image type: SG_IMAGETYPE_2D 22 | Sample type: SG_IMAGESAMPLETYPE_FLOAT 23 | Multisampled: false 24 | Bind slot: IMG_iTexChannel0 => 0 25 | Sampler 'iSmpChannel0': 26 | Type: SG_SAMPLERTYPE_FILTERING 27 | Bind slot: SMP_iSmpChannel0 => 0 28 | */ 29 | #if !defined(SOKOL_GFX_INCLUDED) 30 | #error "Please include sokol_gfx.h before sokol_gp.glsl.h" 31 | #endif 32 | #if !defined(SOKOL_SHDC_ALIGN) 33 | #if defined(_MSC_VER) 34 | #define SOKOL_SHDC_ALIGN(a) __declspec(align(a)) 35 | #else 36 | #define SOKOL_SHDC_ALIGN(a) __attribute__((aligned(a))) 37 | #endif 38 | #endif 39 | const sg_shader_desc* sgp_program_shader_desc(sg_backend backend); 40 | #define ATTR_program_coord (0) 41 | #define ATTR_program_color (1) 42 | #define IMG_iTexChannel0 (0) 43 | #define SMP_iSmpChannel0 (0) 44 | #if defined(SOKOL_SHDC_IMPL) 45 | /* 46 | #version 410 47 | 48 | layout(location = 0) in vec4 coord; 49 | layout(location = 0) out vec2 texUV; 50 | layout(location = 1) out vec4 iColor; 51 | layout(location = 1) in vec4 color; 52 | 53 | void main() 54 | { 55 | gl_Position = vec4(coord.xy, 0.0, 1.0); 56 | gl_PointSize = 1.0; 57 | texUV = coord.zw; 58 | iColor = color; 59 | } 60 | 61 | */ 62 | static const uint8_t sgp_vs_source_glsl410[290] = { 63 | 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x6c,0x61, 64 | 0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20, 65 | 0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6f,0x72,0x64, 66 | 0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f, 67 | 0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20, 68 | 0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f, 69 | 0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x6f,0x75,0x74,0x20, 70 | 0x76,0x65,0x63,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79, 71 | 0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31, 72 | 0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b, 73 | 0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a, 74 | 0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20, 75 | 0x3d,0x20,0x76,0x65,0x63,0x34,0x28,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x2c, 76 | 0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, 77 | 0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x31, 78 | 0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20, 79 | 0x63,0x6f,0x6f,0x72,0x64,0x2e,0x7a,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x69,0x43, 80 | 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a, 81 | 0x0a,0x00, 82 | }; 83 | /* 84 | #version 410 85 | 86 | uniform sampler2D iTexChannel0_iSmpChannel0; 87 | 88 | layout(location = 0) out vec4 fragColor; 89 | layout(location = 0) in vec2 texUV; 90 | layout(location = 1) in vec4 iColor; 91 | 92 | void main() 93 | { 94 | fragColor = texture(iTexChannel0_iSmpChannel0, texUV) * iColor; 95 | } 96 | 97 | */ 98 | static const uint8_t sgp_fs_source_glsl410[261] = { 99 | 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x34,0x31,0x30,0x0a,0x0a,0x75,0x6e, 100 | 0x69,0x66,0x6f,0x72,0x6d,0x20,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x32,0x44,0x20, 101 | 0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x5f,0x69,0x53,0x6d, 102 | 0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f, 103 | 0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29, 104 | 0x20,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f, 105 | 0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61, 106 | 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63, 107 | 0x32,0x20,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28, 108 | 0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e, 109 | 0x20,0x76,0x65,0x63,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76, 110 | 0x6f,0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20, 111 | 0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78, 112 | 0x74,0x75,0x72,0x65,0x28,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c, 113 | 0x30,0x5f,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2c,0x20, 114 | 0x74,0x65,0x78,0x55,0x56,0x29,0x20,0x2a,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b, 115 | 0x0a,0x7d,0x0a,0x0a,0x00, 116 | }; 117 | /* 118 | #version 300 es 119 | 120 | layout(location = 0) in vec4 coord; 121 | out vec2 texUV; 122 | out vec4 iColor; 123 | layout(location = 1) in vec4 color; 124 | 125 | void main() 126 | { 127 | gl_Position = vec4(coord.xy, 0.0, 1.0); 128 | gl_PointSize = 1.0; 129 | texUV = coord.zw; 130 | iColor = color; 131 | } 132 | 133 | */ 134 | static const uint8_t sgp_vs_source_glsl300es[251] = { 135 | 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 136 | 0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, 137 | 0x20,0x3d,0x20,0x30,0x29,0x20,0x69,0x6e,0x20,0x76,0x65,0x63,0x34,0x20,0x63,0x6f, 138 | 0x6f,0x72,0x64,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x32,0x20,0x74,0x65, 139 | 0x78,0x55,0x56,0x3b,0x0a,0x6f,0x75,0x74,0x20,0x76,0x65,0x63,0x34,0x20,0x69,0x43, 140 | 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63, 141 | 0x61,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x31,0x29,0x20,0x69,0x6e,0x20,0x76,0x65, 142 | 0x63,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20, 143 | 0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f, 144 | 0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x28, 145 | 0x63,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x2c,0x20,0x30,0x2e,0x30,0x2c,0x20,0x31, 146 | 0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e, 147 | 0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20,0x31,0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20, 148 | 0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x7a, 149 | 0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20, 150 | 0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, 151 | }; 152 | /* 153 | #version 300 es 154 | precision mediump float; 155 | precision highp int; 156 | 157 | uniform highp sampler2D iTexChannel0_iSmpChannel0; 158 | 159 | layout(location = 0) out highp vec4 fragColor; 160 | in highp vec2 texUV; 161 | in highp vec4 iColor; 162 | 163 | void main() 164 | { 165 | fragColor = texture(iTexChannel0_iSmpChannel0, texUV) * iColor; 166 | } 167 | 168 | */ 169 | static const uint8_t sgp_fs_source_glsl300es[292] = { 170 | 0x23,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x30,0x30,0x20,0x65,0x73,0x0a, 171 | 0x70,0x72,0x65,0x63,0x69,0x73,0x69,0x6f,0x6e,0x20,0x6d,0x65,0x64,0x69,0x75,0x6d, 172 | 0x70,0x20,0x66,0x6c,0x6f,0x61,0x74,0x3b,0x0a,0x70,0x72,0x65,0x63,0x69,0x73,0x69, 173 | 0x6f,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x69,0x6e,0x74,0x3b,0x0a,0x0a,0x75, 174 | 0x6e,0x69,0x66,0x6f,0x72,0x6d,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x73,0x61,0x6d, 175 | 0x70,0x6c,0x65,0x72,0x32,0x44,0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e, 176 | 0x65,0x6c,0x30,0x5f,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30, 177 | 0x3b,0x0a,0x0a,0x6c,0x61,0x79,0x6f,0x75,0x74,0x28,0x6c,0x6f,0x63,0x61,0x74,0x69, 178 | 0x6f,0x6e,0x20,0x3d,0x20,0x30,0x29,0x20,0x6f,0x75,0x74,0x20,0x68,0x69,0x67,0x68, 179 | 0x70,0x20,0x76,0x65,0x63,0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72, 180 | 0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20,0x76,0x65,0x63,0x32,0x20, 181 | 0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x69,0x6e,0x20,0x68,0x69,0x67,0x68,0x70,0x20, 182 | 0x76,0x65,0x63,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x76,0x6f, 183 | 0x69,0x64,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, 184 | 0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x74,0x65,0x78,0x74, 185 | 0x75,0x72,0x65,0x28,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30, 186 | 0x5f,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2c,0x20,0x74, 187 | 0x65,0x78,0x55,0x56,0x29,0x20,0x2a,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, 188 | 0x7d,0x0a,0x0a,0x00, 189 | }; 190 | /* 191 | static float4 gl_Position; 192 | static float gl_PointSize; 193 | static float4 coord; 194 | static float2 texUV; 195 | static float4 iColor; 196 | static float4 color; 197 | 198 | struct SPIRV_Cross_Input 199 | { 200 | float4 coord : TEXCOORD0; 201 | float4 color : TEXCOORD1; 202 | }; 203 | 204 | struct SPIRV_Cross_Output 205 | { 206 | float2 texUV : TEXCOORD0; 207 | float4 iColor : TEXCOORD1; 208 | float4 gl_Position : SV_Position; 209 | }; 210 | 211 | void vert_main() 212 | { 213 | gl_Position = float4(coord.xy, 0.0f, 1.0f); 214 | gl_PointSize = 1.0f; 215 | texUV = coord.zw; 216 | iColor = color; 217 | } 218 | 219 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) 220 | { 221 | coord = stage_input.coord; 222 | color = stage_input.color; 223 | vert_main(); 224 | SPIRV_Cross_Output stage_output; 225 | stage_output.gl_Position = gl_Position; 226 | stage_output.texUV = texUV; 227 | stage_output.iColor = iColor; 228 | return stage_output; 229 | } 230 | */ 231 | static const uint8_t sgp_vs_source_hlsl4[810] = { 232 | 0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c, 233 | 0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69, 234 | 0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74, 235 | 0x53,0x69,0x7a,0x65,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f, 236 | 0x61,0x74,0x34,0x20,0x63,0x6f,0x6f,0x72,0x64,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69, 237 | 0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a, 238 | 0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x69,0x43, 239 | 0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f, 240 | 0x61,0x74,0x34,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75, 241 | 0x63,0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x49, 242 | 0x6e,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, 243 | 0x34,0x20,0x63,0x6f,0x6f,0x72,0x64,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f,0x4f, 244 | 0x52,0x44,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, 245 | 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44, 246 | 0x31,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x53,0x50, 247 | 0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75,0x74, 248 | 0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65, 249 | 0x78,0x55,0x56,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x30,0x3b, 250 | 0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x69,0x43,0x6f,0x6c, 251 | 0x6f,0x72,0x20,0x3a,0x20,0x54,0x45,0x58,0x43,0x4f,0x4f,0x52,0x44,0x31,0x3b,0x0a, 252 | 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f, 253 | 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x53,0x56,0x5f,0x50,0x6f,0x73,0x69, 254 | 0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x6f,0x69,0x64,0x20,0x76, 255 | 0x65,0x72,0x74,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20, 256 | 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66, 257 | 0x6c,0x6f,0x61,0x74,0x34,0x28,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x2c,0x20, 258 | 0x30,0x2e,0x30,0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x20, 259 | 0x20,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x3d,0x20, 260 | 0x31,0x2e,0x30,0x66,0x3b,0x0a,0x20,0x20,0x20,0x20,0x74,0x65,0x78,0x55,0x56,0x20, 261 | 0x3d,0x20,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x7a,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20, 262 | 0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, 263 | 0x7d,0x0a,0x0a,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f, 264 | 0x75,0x74,0x70,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x28,0x53,0x50,0x49,0x52,0x56, 265 | 0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x49,0x6e,0x70,0x75,0x74,0x20,0x73,0x74,0x61, 266 | 0x67,0x65,0x5f,0x69,0x6e,0x70,0x75,0x74,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20, 267 | 0x63,0x6f,0x6f,0x72,0x64,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e, 268 | 0x70,0x75,0x74,0x2e,0x63,0x6f,0x6f,0x72,0x64,0x3b,0x0a,0x20,0x20,0x20,0x20,0x63, 269 | 0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70, 270 | 0x75,0x74,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x76,0x65, 271 | 0x72,0x74,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20,0x53, 272 | 0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75, 273 | 0x74,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x3b,0x0a, 274 | 0x20,0x20,0x20,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74, 275 | 0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x67, 276 | 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x3b,0x0a,0x20,0x20,0x20,0x20, 277 | 0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x74,0x65,0x78, 278 | 0x55,0x56,0x20,0x3d,0x20,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x20,0x20,0x20,0x20, 279 | 0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x69,0x43,0x6f, 280 | 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20, 281 | 0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f, 282 | 0x75,0x74,0x70,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x00, 283 | }; 284 | /* 285 | Texture2D iTexChannel0 : register(t0); 286 | SamplerState iSmpChannel0 : register(s0); 287 | 288 | static float4 fragColor; 289 | static float2 texUV; 290 | static float4 iColor; 291 | 292 | struct SPIRV_Cross_Input 293 | { 294 | float2 texUV : TEXCOORD0; 295 | float4 iColor : TEXCOORD1; 296 | }; 297 | 298 | struct SPIRV_Cross_Output 299 | { 300 | float4 fragColor : SV_Target0; 301 | }; 302 | 303 | void frag_main() 304 | { 305 | fragColor = iTexChannel0.Sample(iSmpChannel0, texUV) * iColor; 306 | } 307 | 308 | SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) 309 | { 310 | texUV = stage_input.texUV; 311 | iColor = stage_input.iColor; 312 | frag_main(); 313 | SPIRV_Cross_Output stage_output; 314 | stage_output.fragColor = fragColor; 315 | return stage_output; 316 | } 317 | */ 318 | static const uint8_t sgp_fs_source_hlsl4[650] = { 319 | 0x54,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x44,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x34, 320 | 0x3e,0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x20,0x3a, 321 | 0x20,0x72,0x65,0x67,0x69,0x73,0x74,0x65,0x72,0x28,0x74,0x30,0x29,0x3b,0x0a,0x53, 322 | 0x61,0x6d,0x70,0x6c,0x65,0x72,0x53,0x74,0x61,0x74,0x65,0x20,0x69,0x53,0x6d,0x70, 323 | 0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x20,0x3a,0x20,0x72,0x65,0x67,0x69,0x73, 324 | 0x74,0x65,0x72,0x28,0x73,0x30,0x29,0x3b,0x0a,0x0a,0x73,0x74,0x61,0x74,0x69,0x63, 325 | 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f, 326 | 0x72,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32, 327 | 0x20,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x73,0x74,0x61,0x74,0x69,0x63,0x20,0x66, 328 | 0x6c,0x6f,0x61,0x74,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x0a,0x73, 329 | 0x74,0x72,0x75,0x63,0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73, 330 | 0x73,0x5f,0x49,0x6e,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c, 331 | 0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3a,0x20,0x54,0x45,0x58, 332 | 0x43,0x4f,0x4f,0x52,0x44,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61, 333 | 0x74,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x54,0x45,0x58,0x43, 334 | 0x4f,0x4f,0x52,0x44,0x31,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63, 335 | 0x74,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x4f,0x75, 336 | 0x74,0x70,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74, 337 | 0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x53,0x56, 338 | 0x5f,0x54,0x61,0x72,0x67,0x65,0x74,0x30,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x6f, 339 | 0x69,0x64,0x20,0x66,0x72,0x61,0x67,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x0a,0x7b, 340 | 0x0a,0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d, 341 | 0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2e,0x53,0x61, 342 | 0x6d,0x70,0x6c,0x65,0x28,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c, 343 | 0x30,0x2c,0x20,0x74,0x65,0x78,0x55,0x56,0x29,0x20,0x2a,0x20,0x69,0x43,0x6f,0x6c, 344 | 0x6f,0x72,0x3b,0x0a,0x7d,0x0a,0x0a,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f, 345 | 0x73,0x73,0x5f,0x4f,0x75,0x74,0x70,0x75,0x74,0x20,0x6d,0x61,0x69,0x6e,0x28,0x53, 346 | 0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73,0x5f,0x49,0x6e,0x70,0x75,0x74, 347 | 0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x70,0x75,0x74,0x29,0x0a,0x7b,0x0a, 348 | 0x20,0x20,0x20,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20,0x73,0x74,0x61,0x67, 349 | 0x65,0x5f,0x69,0x6e,0x70,0x75,0x74,0x2e,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x20, 350 | 0x20,0x20,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x73,0x74,0x61,0x67, 351 | 0x65,0x5f,0x69,0x6e,0x70,0x75,0x74,0x2e,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, 352 | 0x20,0x20,0x20,0x20,0x66,0x72,0x61,0x67,0x5f,0x6d,0x61,0x69,0x6e,0x28,0x29,0x3b, 353 | 0x0a,0x20,0x20,0x20,0x20,0x53,0x50,0x49,0x52,0x56,0x5f,0x43,0x72,0x6f,0x73,0x73, 354 | 0x5f,0x4f,0x75,0x74,0x70,0x75,0x74,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f,0x75, 355 | 0x74,0x70,0x75,0x74,0x3b,0x0a,0x20,0x20,0x20,0x20,0x73,0x74,0x61,0x67,0x65,0x5f, 356 | 0x6f,0x75,0x74,0x70,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72, 357 | 0x20,0x3d,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20, 358 | 0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x73,0x74,0x61,0x67,0x65,0x5f,0x6f, 359 | 0x75,0x74,0x70,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x00, 360 | }; 361 | /* 362 | #include 363 | #include 364 | 365 | using namespace metal; 366 | 367 | struct main0_out 368 | { 369 | float2 texUV [[user(locn0)]]; 370 | float4 iColor [[user(locn1)]]; 371 | float4 gl_Position [[position]]; 372 | float gl_PointSize [[point_size]]; 373 | }; 374 | 375 | struct main0_in 376 | { 377 | float4 coord [[attribute(0)]]; 378 | float4 color [[attribute(1)]]; 379 | }; 380 | 381 | vertex main0_out main0(main0_in in [[stage_in]]) 382 | { 383 | main0_out out = {}; 384 | out.gl_Position = float4(in.coord.xy, 0.0, 1.0); 385 | out.gl_PointSize = 1.0; 386 | out.texUV = in.coord.zw; 387 | out.iColor = in.color; 388 | return out; 389 | } 390 | 391 | */ 392 | static const uint8_t sgp_vs_source_metal_macos[564] = { 393 | 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 394 | 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 395 | 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, 396 | 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, 397 | 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, 398 | 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, 399 | 0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x5b,0x5b,0x75,0x73, 400 | 0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, 401 | 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x5b, 402 | 0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a, 403 | 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f, 404 | 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, 405 | 0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x67, 406 | 0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x70,0x6f, 407 | 0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, 408 | 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a, 409 | 0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6f, 410 | 0x72,0x64,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30, 411 | 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, 412 | 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, 413 | 0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74, 414 | 0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, 415 | 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, 416 | 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, 417 | 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, 418 | 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, 419 | 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f, 420 | 0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x2c, 421 | 0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, 422 | 0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65, 423 | 0x20,0x3d,0x20,0x31,0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, 424 | 0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6f,0x72,0x64, 425 | 0x2e,0x7a,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x69,0x43,0x6f, 426 | 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, 427 | 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, 428 | 0x7d,0x0a,0x0a,0x00, 429 | }; 430 | /* 431 | #include 432 | #include 433 | 434 | using namespace metal; 435 | 436 | struct main0_out 437 | { 438 | float4 fragColor [[color(0)]]; 439 | }; 440 | 441 | struct main0_in 442 | { 443 | float2 texUV [[user(locn0)]]; 444 | float4 iColor [[user(locn1)]]; 445 | }; 446 | 447 | fragment main0_out main0(main0_in in [[stage_in]], texture2d iTexChannel0 [[texture(0)]], sampler iSmpChannel0 [[sampler(0)]]) 448 | { 449 | main0_out out = {}; 450 | out.fragColor = iTexChannel0.sample(iSmpChannel0, in.texUV) * in.iColor; 451 | return out; 452 | } 453 | 454 | */ 455 | static const uint8_t sgp_fs_source_metal_macos[478] = { 456 | 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 457 | 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 458 | 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, 459 | 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, 460 | 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, 461 | 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, 462 | 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20, 463 | 0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, 464 | 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, 465 | 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74, 466 | 0x65,0x78,0x55,0x56,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, 467 | 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, 468 | 0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, 469 | 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61, 470 | 0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, 471 | 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, 472 | 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, 473 | 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e, 474 | 0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x20,0x5b,0x5b, 475 | 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61, 476 | 0x6d,0x70,0x6c,0x65,0x72,0x20,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65, 477 | 0x6c,0x30,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d, 478 | 0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, 479 | 0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20, 480 | 0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d, 481 | 0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2e,0x73,0x61, 482 | 0x6d,0x70,0x6c,0x65,0x28,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c, 483 | 0x30,0x2c,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x55,0x56,0x29,0x20,0x2a,0x20,0x69, 484 | 0x6e,0x2e,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65, 485 | 0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, 486 | }; 487 | /* 488 | #include 489 | #include 490 | 491 | using namespace metal; 492 | 493 | struct main0_out 494 | { 495 | float2 texUV [[user(locn0)]]; 496 | float4 iColor [[user(locn1)]]; 497 | float4 gl_Position [[position]]; 498 | float gl_PointSize [[point_size]]; 499 | }; 500 | 501 | struct main0_in 502 | { 503 | float4 coord [[attribute(0)]]; 504 | float4 color [[attribute(1)]]; 505 | }; 506 | 507 | vertex main0_out main0(main0_in in [[stage_in]]) 508 | { 509 | main0_out out = {}; 510 | out.gl_Position = float4(in.coord.xy, 0.0, 1.0); 511 | out.gl_PointSize = 1.0; 512 | out.texUV = in.coord.zw; 513 | out.iColor = in.color; 514 | return out; 515 | } 516 | 517 | */ 518 | static const uint8_t sgp_vs_source_metal_ios[564] = { 519 | 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 520 | 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 521 | 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, 522 | 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, 523 | 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, 524 | 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, 525 | 0x6c,0x6f,0x61,0x74,0x32,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x5b,0x5b,0x75,0x73, 526 | 0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20, 527 | 0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x5b, 528 | 0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a, 529 | 0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x67,0x6c,0x5f,0x50,0x6f, 530 | 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x5b,0x5b,0x70,0x6f,0x73,0x69,0x74,0x69,0x6f, 531 | 0x6e,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x20,0x67, 532 | 0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,0x20,0x5b,0x5b,0x70,0x6f, 533 | 0x69,0x6e,0x74,0x5f,0x73,0x69,0x7a,0x65,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a, 534 | 0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x0a, 535 | 0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20,0x63,0x6f,0x6f, 536 | 0x72,0x64,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x28,0x30, 537 | 0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34,0x20, 538 | 0x63,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x61,0x74,0x74,0x72,0x69,0x62,0x75,0x74, 539 | 0x65,0x28,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x76,0x65,0x72,0x74, 540 | 0x65,0x78,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6d,0x61,0x69, 541 | 0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69,0x6e,0x20,0x5b, 542 | 0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x29,0x0a,0x7b,0x0a,0x20, 543 | 0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20,0x6f,0x75,0x74, 544 | 0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x67, 545 | 0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x66,0x6c,0x6f, 546 | 0x61,0x74,0x34,0x28,0x69,0x6e,0x2e,0x63,0x6f,0x6f,0x72,0x64,0x2e,0x78,0x79,0x2c, 547 | 0x20,0x30,0x2e,0x30,0x2c,0x20,0x31,0x2e,0x30,0x29,0x3b,0x0a,0x20,0x20,0x20,0x20, 548 | 0x6f,0x75,0x74,0x2e,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65, 549 | 0x20,0x3d,0x20,0x31,0x2e,0x30,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e, 550 | 0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6f,0x72,0x64, 551 | 0x2e,0x7a,0x77,0x3b,0x0a,0x20,0x20,0x20,0x20,0x6f,0x75,0x74,0x2e,0x69,0x43,0x6f, 552 | 0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x6e,0x2e,0x63,0x6f,0x6c,0x6f,0x72,0x3b,0x0a, 553 | 0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a, 554 | 0x7d,0x0a,0x0a,0x00, 555 | }; 556 | /* 557 | #include 558 | #include 559 | 560 | using namespace metal; 561 | 562 | struct main0_out 563 | { 564 | float4 fragColor [[color(0)]]; 565 | }; 566 | 567 | struct main0_in 568 | { 569 | float2 texUV [[user(locn0)]]; 570 | float4 iColor [[user(locn1)]]; 571 | }; 572 | 573 | fragment main0_out main0(main0_in in [[stage_in]], texture2d iTexChannel0 [[texture(0)]], sampler iSmpChannel0 [[sampler(0)]]) 574 | { 575 | main0_out out = {}; 576 | out.fragColor = iTexChannel0.sample(iSmpChannel0, in.texUV) * in.iColor; 577 | return out; 578 | } 579 | 580 | */ 581 | static const uint8_t sgp_fs_source_metal_ios[478] = { 582 | 0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x6d,0x65,0x74,0x61,0x6c,0x5f, 583 | 0x73,0x74,0x64,0x6c,0x69,0x62,0x3e,0x0a,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65, 584 | 0x20,0x3c,0x73,0x69,0x6d,0x64,0x2f,0x73,0x69,0x6d,0x64,0x2e,0x68,0x3e,0x0a,0x0a, 585 | 0x75,0x73,0x69,0x6e,0x67,0x20,0x6e,0x61,0x6d,0x65,0x73,0x70,0x61,0x63,0x65,0x20, 586 | 0x6d,0x65,0x74,0x61,0x6c,0x3b,0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d, 587 | 0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66, 588 | 0x6c,0x6f,0x61,0x74,0x34,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20, 589 | 0x5b,0x5b,0x63,0x6f,0x6c,0x6f,0x72,0x28,0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b, 590 | 0x0a,0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69, 591 | 0x6e,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x32,0x20,0x74, 592 | 0x65,0x78,0x55,0x56,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c,0x6f,0x63,0x6e, 593 | 0x30,0x29,0x5d,0x5d,0x3b,0x0a,0x20,0x20,0x20,0x20,0x66,0x6c,0x6f,0x61,0x74,0x34, 594 | 0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x5b,0x5b,0x75,0x73,0x65,0x72,0x28,0x6c, 595 | 0x6f,0x63,0x6e,0x31,0x29,0x5d,0x5d,0x3b,0x0a,0x7d,0x3b,0x0a,0x0a,0x66,0x72,0x61, 596 | 0x67,0x6d,0x65,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f,0x75,0x74,0x20, 597 | 0x6d,0x61,0x69,0x6e,0x30,0x28,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x69,0x6e,0x20,0x69, 598 | 0x6e,0x20,0x5b,0x5b,0x73,0x74,0x61,0x67,0x65,0x5f,0x69,0x6e,0x5d,0x5d,0x2c,0x20, 599 | 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x32,0x64,0x3c,0x66,0x6c,0x6f,0x61,0x74,0x3e, 600 | 0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x20,0x5b,0x5b, 601 | 0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x28,0x30,0x29,0x5d,0x5d,0x2c,0x20,0x73,0x61, 602 | 0x6d,0x70,0x6c,0x65,0x72,0x20,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65, 603 | 0x6c,0x30,0x20,0x5b,0x5b,0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x28,0x30,0x29,0x5d, 604 | 0x5d,0x29,0x0a,0x7b,0x0a,0x20,0x20,0x20,0x20,0x6d,0x61,0x69,0x6e,0x30,0x5f,0x6f, 605 | 0x75,0x74,0x20,0x6f,0x75,0x74,0x20,0x3d,0x20,0x7b,0x7d,0x3b,0x0a,0x20,0x20,0x20, 606 | 0x20,0x6f,0x75,0x74,0x2e,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d, 607 | 0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2e,0x73,0x61, 608 | 0x6d,0x70,0x6c,0x65,0x28,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c, 609 | 0x30,0x2c,0x20,0x69,0x6e,0x2e,0x74,0x65,0x78,0x55,0x56,0x29,0x20,0x2a,0x20,0x69, 610 | 0x6e,0x2e,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x3b,0x0a,0x20,0x20,0x20,0x20,0x72,0x65, 611 | 0x74,0x75,0x72,0x6e,0x20,0x6f,0x75,0x74,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, 612 | }; 613 | /* 614 | diagnostic(off, derivative_uniformity); 615 | 616 | var coord : vec4f; 617 | 618 | var texUV : vec2f; 619 | 620 | var iColor : vec4f; 621 | 622 | var color : vec4f; 623 | 624 | var gl_Position : vec4f; 625 | 626 | fn main_1() { 627 | let x_19 : vec4f = coord; 628 | let x_20 : vec2f = vec2f(x_19.x, x_19.y); 629 | gl_Position = vec4f(x_20.x, x_20.y, 0.0f, 1.0f); 630 | let x_33 : vec4f = coord; 631 | texUV = vec2f(x_33.z, x_33.w); 632 | let x_37 : vec4f = color; 633 | iColor = x_37; 634 | return; 635 | } 636 | 637 | struct main_out { 638 | @builtin(position) 639 | gl_Position : vec4f, 640 | @location(0) 641 | texUV_1 : vec2f, 642 | @location(1) 643 | iColor_1 : vec4f, 644 | } 645 | 646 | @vertex 647 | fn main(@location(0) coord_param : vec4f, @location(1) color_param : vec4f) -> main_out { 648 | coord = coord_param; 649 | color = color_param; 650 | main_1(); 651 | return main_out(gl_Position, texUV, iColor); 652 | } 653 | 654 | */ 655 | static const uint8_t sgp_vs_source_wgsl[790] = { 656 | 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 657 | 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 658 | 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 659 | 0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f,0x6f,0x72,0x64,0x20,0x3a,0x20,0x76,0x65, 660 | 0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74, 661 | 0x65,0x3e,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66, 662 | 0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20, 663 | 0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, 664 | 0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x63,0x6f, 665 | 0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x76,0x61, 666 | 0x72,0x3c,0x70,0x72,0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x67,0x6c,0x5f,0x50,0x6f, 667 | 0x73,0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a, 668 | 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29,0x20,0x7b,0x0a,0x20, 669 | 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x31,0x39,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, 670 | 0x66,0x20,0x3d,0x20,0x63,0x6f,0x6f,0x72,0x64,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74, 671 | 0x20,0x78,0x5f,0x32,0x30,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20, 672 | 0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x31,0x39,0x2e,0x78,0x2c,0x20,0x78,0x5f, 673 | 0x31,0x39,0x2e,0x79,0x29,0x3b,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69, 674 | 0x74,0x69,0x6f,0x6e,0x20,0x3d,0x20,0x76,0x65,0x63,0x34,0x66,0x28,0x78,0x5f,0x32, 675 | 0x30,0x2e,0x78,0x2c,0x20,0x78,0x5f,0x32,0x30,0x2e,0x79,0x2c,0x20,0x30,0x2e,0x30, 676 | 0x66,0x2c,0x20,0x31,0x2e,0x30,0x66,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20, 677 | 0x78,0x5f,0x33,0x33,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63, 678 | 0x6f,0x6f,0x72,0x64,0x3b,0x0a,0x20,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3d,0x20, 679 | 0x76,0x65,0x63,0x32,0x66,0x28,0x78,0x5f,0x33,0x33,0x2e,0x7a,0x2c,0x20,0x78,0x5f, 680 | 0x33,0x33,0x2e,0x77,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x33, 681 | 0x37,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f, 682 | 0x72,0x3b,0x0a,0x20,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x78,0x5f, 683 | 0x33,0x37,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a, 684 | 0x0a,0x73,0x74,0x72,0x75,0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74, 685 | 0x20,0x7b,0x0a,0x20,0x20,0x40,0x62,0x75,0x69,0x6c,0x74,0x69,0x6e,0x28,0x70,0x6f, 686 | 0x73,0x69,0x74,0x69,0x6f,0x6e,0x29,0x0a,0x20,0x20,0x67,0x6c,0x5f,0x50,0x6f,0x73, 687 | 0x69,0x74,0x69,0x6f,0x6e,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x0a,0x20, 688 | 0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20, 689 | 0x74,0x65,0x78,0x55,0x56,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c, 690 | 0x0a,0x20,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x0a, 691 | 0x20,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, 692 | 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x76,0x65,0x72,0x74,0x65,0x78,0x0a,0x66, 693 | 0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e, 694 | 0x28,0x30,0x29,0x20,0x63,0x6f,0x6f,0x72,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x20, 695 | 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, 696 | 0x6f,0x6e,0x28,0x31,0x29,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61,0x72,0x61, 697 | 0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e,0x20,0x6d,0x61, 698 | 0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x63,0x6f,0x6f,0x72,0x64, 699 | 0x20,0x3d,0x20,0x63,0x6f,0x6f,0x72,0x64,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a, 700 | 0x20,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x63,0x6f,0x6c,0x6f,0x72,0x5f, 701 | 0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28, 702 | 0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x6d,0x61,0x69,0x6e, 703 | 0x5f,0x6f,0x75,0x74,0x28,0x67,0x6c,0x5f,0x50,0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e, 704 | 0x2c,0x20,0x74,0x65,0x78,0x55,0x56,0x2c,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x29, 705 | 0x3b,0x0a,0x7d,0x0a,0x0a,0x00, 706 | }; 707 | /* 708 | diagnostic(off, derivative_uniformity); 709 | 710 | var fragColor : vec4f; 711 | 712 | @group(1) @binding(64) var iTexChannel0 : texture_2d; 713 | 714 | @group(1) @binding(80) var iSmpChannel0 : sampler; 715 | 716 | var texUV : vec2f; 717 | 718 | var iColor : vec4f; 719 | 720 | fn main_1() { 721 | let x_23 : vec2f = texUV; 722 | let x_24 : vec4f = textureSample(iTexChannel0, iSmpChannel0, x_23); 723 | let x_27 : vec4f = iColor; 724 | fragColor = (x_24 * x_27); 725 | return; 726 | } 727 | 728 | struct main_out { 729 | @location(0) 730 | fragColor_1 : vec4f, 731 | } 732 | 733 | @fragment 734 | fn main(@location(0) texUV_param : vec2f, @location(1) iColor_param : vec4f) -> main_out { 735 | texUV = texUV_param; 736 | iColor = iColor_param; 737 | main_1(); 738 | return main_out(fragColor); 739 | } 740 | 741 | */ 742 | static const uint8_t sgp_fs_source_wgsl[682] = { 743 | 0x64,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x28,0x6f,0x66,0x66,0x2c,0x20, 744 | 0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x5f,0x75,0x6e,0x69,0x66,0x6f, 745 | 0x72,0x6d,0x69,0x74,0x79,0x29,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69, 746 | 0x76,0x61,0x74,0x65,0x3e,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20, 747 | 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70, 748 | 0x28,0x31,0x29,0x20,0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x36,0x34,0x29, 749 | 0x20,0x76,0x61,0x72,0x20,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c, 750 | 0x30,0x20,0x3a,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x5f,0x32,0x64,0x3c,0x66, 751 | 0x33,0x32,0x3e,0x3b,0x0a,0x0a,0x40,0x67,0x72,0x6f,0x75,0x70,0x28,0x31,0x29,0x20, 752 | 0x40,0x62,0x69,0x6e,0x64,0x69,0x6e,0x67,0x28,0x38,0x30,0x29,0x20,0x76,0x61,0x72, 753 | 0x20,0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x20,0x3a,0x20, 754 | 0x73,0x61,0x6d,0x70,0x6c,0x65,0x72,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72, 755 | 0x69,0x76,0x61,0x74,0x65,0x3e,0x20,0x74,0x65,0x78,0x55,0x56,0x20,0x3a,0x20,0x76, 756 | 0x65,0x63,0x32,0x66,0x3b,0x0a,0x0a,0x76,0x61,0x72,0x3c,0x70,0x72,0x69,0x76,0x61, 757 | 0x74,0x65,0x3e,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3a,0x20,0x76,0x65,0x63, 758 | 0x34,0x66,0x3b,0x0a,0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x31,0x28,0x29, 759 | 0x20,0x7b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x33,0x20,0x3a,0x20, 760 | 0x76,0x65,0x63,0x32,0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x55,0x56,0x3b,0x0a,0x20, 761 | 0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x34,0x20,0x3a,0x20,0x76,0x65,0x63,0x34, 762 | 0x66,0x20,0x3d,0x20,0x74,0x65,0x78,0x74,0x75,0x72,0x65,0x53,0x61,0x6d,0x70,0x6c, 763 | 0x65,0x28,0x69,0x54,0x65,0x78,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2c,0x20, 764 | 0x69,0x53,0x6d,0x70,0x43,0x68,0x61,0x6e,0x6e,0x65,0x6c,0x30,0x2c,0x20,0x78,0x5f, 765 | 0x32,0x33,0x29,0x3b,0x0a,0x20,0x20,0x6c,0x65,0x74,0x20,0x78,0x5f,0x32,0x37,0x20, 766 | 0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x20,0x3d,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72, 767 | 0x3b,0x0a,0x20,0x20,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20, 768 | 0x28,0x78,0x5f,0x32,0x34,0x20,0x2a,0x20,0x78,0x5f,0x32,0x37,0x29,0x3b,0x0a,0x20, 769 | 0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x3b,0x0a,0x7d,0x0a,0x0a,0x73,0x74,0x72,0x75, 770 | 0x63,0x74,0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20, 771 | 0x40,0x6c,0x6f,0x63,0x61,0x74,0x69,0x6f,0x6e,0x28,0x30,0x29,0x0a,0x20,0x20,0x66, 772 | 0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,0x72,0x5f,0x31,0x20,0x3a,0x20,0x76,0x65,0x63, 773 | 0x34,0x66,0x2c,0x0a,0x7d,0x0a,0x0a,0x40,0x66,0x72,0x61,0x67,0x6d,0x65,0x6e,0x74, 774 | 0x0a,0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x40,0x6c,0x6f,0x63,0x61,0x74,0x69, 775 | 0x6f,0x6e,0x28,0x30,0x29,0x20,0x74,0x65,0x78,0x55,0x56,0x5f,0x70,0x61,0x72,0x61, 776 | 0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x32,0x66,0x2c,0x20,0x40,0x6c,0x6f,0x63,0x61, 777 | 0x74,0x69,0x6f,0x6e,0x28,0x31,0x29,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x5f,0x70, 778 | 0x61,0x72,0x61,0x6d,0x20,0x3a,0x20,0x76,0x65,0x63,0x34,0x66,0x29,0x20,0x2d,0x3e, 779 | 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x20,0x7b,0x0a,0x20,0x20,0x74,0x65, 780 | 0x78,0x55,0x56,0x20,0x3d,0x20,0x74,0x65,0x78,0x55,0x56,0x5f,0x70,0x61,0x72,0x61, 781 | 0x6d,0x3b,0x0a,0x20,0x20,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x20,0x3d,0x20,0x69,0x43, 782 | 0x6f,0x6c,0x6f,0x72,0x5f,0x70,0x61,0x72,0x61,0x6d,0x3b,0x0a,0x20,0x20,0x6d,0x61, 783 | 0x69,0x6e,0x5f,0x31,0x28,0x29,0x3b,0x0a,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e, 784 | 0x20,0x6d,0x61,0x69,0x6e,0x5f,0x6f,0x75,0x74,0x28,0x66,0x72,0x61,0x67,0x43,0x6f, 785 | 0x6c,0x6f,0x72,0x29,0x3b,0x0a,0x7d,0x0a,0x0a,0x00, 786 | }; 787 | const sg_shader_desc* sgp_program_shader_desc(sg_backend backend) { 788 | if (backend == SG_BACKEND_GLCORE) { 789 | static sg_shader_desc desc; 790 | static bool valid; 791 | if (!valid) { 792 | valid = true; 793 | desc.vertex_func.source = (const char*)sgp_vs_source_glsl410; 794 | desc.vertex_func.entry = "main"; 795 | desc.fragment_func.source = (const char*)sgp_fs_source_glsl410; 796 | desc.fragment_func.entry = "main"; 797 | desc.attrs[0].glsl_name = "coord"; 798 | desc.attrs[1].glsl_name = "color"; 799 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 800 | desc.images[0].image_type = SG_IMAGETYPE_2D; 801 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 802 | desc.images[0].multisampled = false; 803 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 804 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 805 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 806 | desc.image_sampler_pairs[0].image_slot = 0; 807 | desc.image_sampler_pairs[0].sampler_slot = 0; 808 | desc.image_sampler_pairs[0].glsl_name = "iTexChannel0_iSmpChannel0"; 809 | desc.label = "sgp_program_shader"; 810 | } 811 | return &desc; 812 | } 813 | if (backend == SG_BACKEND_GLES3) { 814 | static sg_shader_desc desc; 815 | static bool valid; 816 | if (!valid) { 817 | valid = true; 818 | desc.vertex_func.source = (const char*)sgp_vs_source_glsl300es; 819 | desc.vertex_func.entry = "main"; 820 | desc.fragment_func.source = (const char*)sgp_fs_source_glsl300es; 821 | desc.fragment_func.entry = "main"; 822 | desc.attrs[0].glsl_name = "coord"; 823 | desc.attrs[1].glsl_name = "color"; 824 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 825 | desc.images[0].image_type = SG_IMAGETYPE_2D; 826 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 827 | desc.images[0].multisampled = false; 828 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 829 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 830 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 831 | desc.image_sampler_pairs[0].image_slot = 0; 832 | desc.image_sampler_pairs[0].sampler_slot = 0; 833 | desc.image_sampler_pairs[0].glsl_name = "iTexChannel0_iSmpChannel0"; 834 | desc.label = "sgp_program_shader"; 835 | } 836 | return &desc; 837 | } 838 | if (backend == SG_BACKEND_D3D11) { 839 | static sg_shader_desc desc; 840 | static bool valid; 841 | if (!valid) { 842 | valid = true; 843 | desc.vertex_func.source = (const char*)sgp_vs_source_hlsl4; 844 | desc.vertex_func.d3d11_target = "vs_4_0"; 845 | desc.vertex_func.entry = "main"; 846 | desc.fragment_func.source = (const char*)sgp_fs_source_hlsl4; 847 | desc.fragment_func.d3d11_target = "ps_4_0"; 848 | desc.fragment_func.entry = "main"; 849 | desc.attrs[0].hlsl_sem_name = "TEXCOORD"; 850 | desc.attrs[0].hlsl_sem_index = 0; 851 | desc.attrs[1].hlsl_sem_name = "TEXCOORD"; 852 | desc.attrs[1].hlsl_sem_index = 1; 853 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 854 | desc.images[0].image_type = SG_IMAGETYPE_2D; 855 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 856 | desc.images[0].multisampled = false; 857 | desc.images[0].hlsl_register_t_n = 0; 858 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 859 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 860 | desc.samplers[0].hlsl_register_s_n = 0; 861 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 862 | desc.image_sampler_pairs[0].image_slot = 0; 863 | desc.image_sampler_pairs[0].sampler_slot = 0; 864 | desc.label = "sgp_program_shader"; 865 | } 866 | return &desc; 867 | } 868 | if (backend == SG_BACKEND_METAL_MACOS) { 869 | static sg_shader_desc desc; 870 | static bool valid; 871 | if (!valid) { 872 | valid = true; 873 | desc.vertex_func.source = (const char*)sgp_vs_source_metal_macos; 874 | desc.vertex_func.entry = "main0"; 875 | desc.fragment_func.source = (const char*)sgp_fs_source_metal_macos; 876 | desc.fragment_func.entry = "main0"; 877 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 878 | desc.images[0].image_type = SG_IMAGETYPE_2D; 879 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 880 | desc.images[0].multisampled = false; 881 | desc.images[0].msl_texture_n = 0; 882 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 883 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 884 | desc.samplers[0].msl_sampler_n = 0; 885 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 886 | desc.image_sampler_pairs[0].image_slot = 0; 887 | desc.image_sampler_pairs[0].sampler_slot = 0; 888 | desc.label = "sgp_program_shader"; 889 | } 890 | return &desc; 891 | } 892 | if (backend == SG_BACKEND_METAL_IOS) { 893 | static sg_shader_desc desc; 894 | static bool valid; 895 | if (!valid) { 896 | valid = true; 897 | desc.vertex_func.source = (const char*)sgp_vs_source_metal_ios; 898 | desc.vertex_func.entry = "main0"; 899 | desc.fragment_func.source = (const char*)sgp_fs_source_metal_ios; 900 | desc.fragment_func.entry = "main0"; 901 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 902 | desc.images[0].image_type = SG_IMAGETYPE_2D; 903 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 904 | desc.images[0].multisampled = false; 905 | desc.images[0].msl_texture_n = 0; 906 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 907 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 908 | desc.samplers[0].msl_sampler_n = 0; 909 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 910 | desc.image_sampler_pairs[0].image_slot = 0; 911 | desc.image_sampler_pairs[0].sampler_slot = 0; 912 | desc.label = "sgp_program_shader"; 913 | } 914 | return &desc; 915 | } 916 | if (backend == SG_BACKEND_WGPU) { 917 | static sg_shader_desc desc; 918 | static bool valid; 919 | if (!valid) { 920 | valid = true; 921 | desc.vertex_func.source = (const char*)sgp_vs_source_wgsl; 922 | desc.vertex_func.entry = "main"; 923 | desc.fragment_func.source = (const char*)sgp_fs_source_wgsl; 924 | desc.fragment_func.entry = "main"; 925 | desc.images[0].stage = SG_SHADERSTAGE_FRAGMENT; 926 | desc.images[0].image_type = SG_IMAGETYPE_2D; 927 | desc.images[0].sample_type = SG_IMAGESAMPLETYPE_FLOAT; 928 | desc.images[0].multisampled = false; 929 | desc.images[0].wgsl_group1_binding_n = 64; 930 | desc.samplers[0].stage = SG_SHADERSTAGE_FRAGMENT; 931 | desc.samplers[0].sampler_type = SG_SAMPLERTYPE_FILTERING; 932 | desc.samplers[0].wgsl_group1_binding_n = 80; 933 | desc.image_sampler_pairs[0].stage = SG_SHADERSTAGE_FRAGMENT; 934 | desc.image_sampler_pairs[0].image_slot = 0; 935 | desc.image_sampler_pairs[0].sampler_slot = 0; 936 | desc.label = "sgp_program_shader"; 937 | } 938 | return &desc; 939 | } 940 | return 0; 941 | } 942 | #endif // SOKOL_SHDC_IMPL -------------------------------------------------------------------------------- /thirdparty/sokol_glue.h: -------------------------------------------------------------------------------- 1 | #if defined(SOKOL_IMPL) && !defined(SOKOL_GLUE_IMPL) 2 | #define SOKOL_GLUE_IMPL 3 | #endif 4 | #ifndef SOKOL_GLUE_INCLUDED 5 | /* 6 | sokol_glue.h -- glue helper functions for sokol headers 7 | 8 | Project URL: https://github.com/floooh/sokol 9 | 10 | Do this: 11 | #define SOKOL_IMPL or 12 | #define SOKOL_GLUE_IMPL 13 | before you include this file in *one* C or C++ file to create the 14 | implementation. 15 | 16 | ...optionally provide the following macros to override defaults: 17 | 18 | SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) 19 | SOKOL_GLUE_API_DECL - public function declaration prefix (default: extern) 20 | SOKOL_API_DECL - same as SOKOL_GLUE_API_DECL 21 | SOKOL_API_IMPL - public function implementation prefix (default: -) 22 | 23 | If sokol_glue.h is compiled as a DLL, define the following before 24 | including the declaration or implementation: 25 | 26 | SOKOL_DLL 27 | 28 | On Windows, SOKOL_DLL will define SOKOL_GLUE_API_DECL as __declspec(dllexport) 29 | or __declspec(dllimport) as needed. 30 | 31 | OVERVIEW 32 | ======== 33 | sokol_glue.h provides glue helper functions between sokol_gfx.h and sokol_app.h, 34 | so that sokol_gfx.h doesn't need to depend on sokol_app.h but can be 35 | used with different window system glue libraries. 36 | 37 | PROVIDED FUNCTIONS 38 | ================== 39 | 40 | sg_environment sglue_environment(void) 41 | 42 | Returns an sg_environment struct initialized by calling sokol_app.h 43 | functions. Use this in the sg_setup() call like this: 44 | 45 | sg_setup(&(sg_desc){ 46 | .environment = sglue_environment(), 47 | ... 48 | }); 49 | 50 | sg_swapchain sglue_swapchain(void) 51 | 52 | Returns an sg_swapchain struct initialized by calling sokol_app.h 53 | functions. Use this in sg_begin_pass() for a 'swapchain pass' like 54 | this: 55 | 56 | sg_begin_pass(&(sg_pass){ .swapchain = sglue_swapchain(), ... }); 57 | 58 | LICENSE 59 | ======= 60 | zlib/libpng license 61 | 62 | Copyright (c) 2018 Andre Weissflog 63 | 64 | This software is provided 'as-is', without any express or implied warranty. 65 | In no event will the authors be held liable for any damages arising from the 66 | use of this software. 67 | 68 | Permission is granted to anyone to use this software for any purpose, 69 | including commercial applications, and to alter it and redistribute it 70 | freely, subject to the following restrictions: 71 | 72 | 1. The origin of this software must not be misrepresented; you must not 73 | claim that you wrote the original software. If you use this software in a 74 | product, an acknowledgment in the product documentation would be 75 | appreciated but is not required. 76 | 77 | 2. Altered source versions must be plainly marked as such, and must not 78 | be misrepresented as being the original software. 79 | 80 | 3. This notice may not be removed or altered from any source 81 | distribution. 82 | */ 83 | #define SOKOL_GLUE_INCLUDED 84 | 85 | #if defined(SOKOL_API_DECL) && !defined(SOKOL_GLUE_API_DECL) 86 | #define SOKOL_GLUE_API_DECL SOKOL_API_DECL 87 | #endif 88 | #ifndef SOKOL_GLUE_API_DECL 89 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GLUE_IMPL) 90 | #define SOKOL_GLUE_API_DECL __declspec(dllexport) 91 | #elif defined(_WIN32) && defined(SOKOL_DLL) 92 | #define SOKOL_GLUE_API_DECL __declspec(dllimport) 93 | #else 94 | #define SOKOL_GLUE_API_DECL extern 95 | #endif 96 | #endif 97 | 98 | #ifndef SOKOL_GFX_INCLUDED 99 | #error "Please include sokol_gfx.h before sokol_glue.h" 100 | #endif 101 | 102 | #ifdef __cplusplus 103 | extern "C" { 104 | #endif 105 | 106 | SOKOL_GLUE_API_DECL sg_environment sglue_environment(void); 107 | SOKOL_GLUE_API_DECL sg_swapchain sglue_swapchain(void); 108 | 109 | #ifdef __cplusplus 110 | } /* extern "C" */ 111 | #endif 112 | #endif /* SOKOL_GLUE_INCLUDED */ 113 | 114 | /*-- IMPLEMENTATION ----------------------------------------------------------*/ 115 | #ifdef SOKOL_GLUE_IMPL 116 | #define SOKOL_GLUE_IMPL_INCLUDED (1) 117 | #include /* memset */ 118 | 119 | #ifndef SOKOL_APP_INCLUDED 120 | #error "Please include sokol_app.h before the sokol_glue.h implementation" 121 | #endif 122 | 123 | #ifndef SOKOL_API_IMPL 124 | #define SOKOL_API_IMPL 125 | #endif 126 | 127 | 128 | SOKOL_API_IMPL sg_environment sglue_environment(void) { 129 | sg_environment env; 130 | memset(&env, 0, sizeof(env)); 131 | env.defaults.color_format = (sg_pixel_format) sapp_color_format(); 132 | env.defaults.depth_format = (sg_pixel_format) sapp_depth_format(); 133 | env.defaults.sample_count = sapp_sample_count(); 134 | env.metal.device = sapp_metal_get_device(); 135 | env.d3d11.device = sapp_d3d11_get_device(); 136 | env.d3d11.device_context = sapp_d3d11_get_device_context(); 137 | env.wgpu.device = sapp_wgpu_get_device(); 138 | return env; 139 | } 140 | 141 | SOKOL_API_IMPL sg_swapchain sglue_swapchain(void) { 142 | sg_swapchain swapchain; 143 | memset(&swapchain, 0, sizeof(swapchain)); 144 | swapchain.width = sapp_width(); 145 | swapchain.height = sapp_height(); 146 | swapchain.sample_count = sapp_sample_count(); 147 | swapchain.color_format = (sg_pixel_format)sapp_color_format(); 148 | swapchain.depth_format = (sg_pixel_format)sapp_depth_format(); 149 | swapchain.metal.current_drawable = sapp_metal_get_current_drawable(); 150 | swapchain.metal.depth_stencil_texture = sapp_metal_get_depth_stencil_texture(); 151 | swapchain.metal.msaa_color_texture = sapp_metal_get_msaa_color_texture(); 152 | swapchain.d3d11.render_view = sapp_d3d11_get_render_view(); 153 | swapchain.d3d11.resolve_view = sapp_d3d11_get_resolve_view(); 154 | swapchain.d3d11.depth_stencil_view = sapp_d3d11_get_depth_stencil_view(); 155 | swapchain.wgpu.render_view = sapp_wgpu_get_render_view(); 156 | swapchain.wgpu.resolve_view = sapp_wgpu_get_resolve_view(); 157 | swapchain.wgpu.depth_stencil_view = sapp_wgpu_get_depth_stencil_view(); 158 | swapchain.gl.framebuffer = sapp_gl_get_framebuffer(); 159 | return swapchain; 160 | } 161 | 162 | #endif /* SOKOL_GLUE_IMPL */ 163 | -------------------------------------------------------------------------------- /thirdparty/sokol_log.h: -------------------------------------------------------------------------------- 1 | #if defined(SOKOL_IMPL) && !defined(SOKOL_LOG_IMPL) 2 | #define SOKOL_LOG_IMPL 3 | #endif 4 | #ifndef SOKOL_LOG_INCLUDED 5 | /* 6 | sokol_log.h -- common logging callback for sokol headers 7 | 8 | Project URL: https://github.com/floooh/sokol 9 | 10 | Example code: https://github.com/floooh/sokol-samples 11 | 12 | Do this: 13 | #define SOKOL_IMPL or 14 | #define SOKOL_LOG_IMPL 15 | before you include this file in *one* C or C++ file to create the 16 | implementation. 17 | 18 | Optionally provide the following defines when building the implementation: 19 | 20 | SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) 21 | SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false)) 22 | SOKOL_LOG_API_DECL - public function declaration prefix (default: extern) 23 | SOKOL_API_DECL - same as SOKOL_GFX_API_DECL 24 | SOKOL_API_IMPL - public function implementation prefix (default: -) 25 | 26 | Optionally define the following for verbose output: 27 | 28 | SOKOL_DEBUG - by default this is defined if _DEBUG is defined 29 | 30 | 31 | OVERVIEW 32 | ======== 33 | sokol_log.h provides a default logging callback for other sokol headers. 34 | 35 | To use the default log callback, just include sokol_log.h and provide 36 | a function pointer to the 'slog_func' function when setting up the 37 | sokol library: 38 | 39 | For instance with sokol_audio.h: 40 | 41 | #include "sokol_log.h" 42 | ... 43 | saudio_setup(&(saudio_desc){ .logger.func = slog_func }); 44 | 45 | Logging output goes to stderr and/or a platform specific logging subsystem 46 | (which means that in some scenarios you might see logging messages duplicated): 47 | 48 | - Windows: stderr + OutputDebugStringA() 49 | - macOS/iOS/Linux: stderr + syslog() 50 | - Emscripten: console.info()/warn()/error() 51 | - Android: __android_log_write() 52 | 53 | On Windows with sokol_app.h also note the runtime config items to make 54 | stdout/stderr output visible on the console for WinMain() applications 55 | via sapp_desc.win32_console_attach or sapp_desc.win32_console_create, 56 | however when running in a debugger on Windows, the logging output should 57 | show up on the debug output UI panel. 58 | 59 | In debug mode, a log message might look like this: 60 | 61 | [sspine][error][id:12] /Users/floh/projects/sokol/util/sokol_spine.h:3472:0: 62 | SKELETON_DESC_NO_ATLAS: no atlas object provided in sspine_skeleton_desc.atlas 63 | 64 | The source path and line number is formatted like compiler errors, in some IDEs (like VSCode) 65 | such error messages are clickable. 66 | 67 | In release mode, logging is less verbose as to not bloat the executable with string data, but you still get 68 | enough information to identify the type and location of an error: 69 | 70 | [sspine][error][id:12][line:3472] 71 | 72 | RULES FOR WRITING YOUR OWN LOGGING FUNCTION 73 | =========================================== 74 | - must be re-entrant because it might be called from different threads 75 | - must treat **all** provided string pointers as optional (can be null) 76 | - don't store the string pointers, copy the string data instead 77 | - must not return for log level panic 78 | 79 | LICENSE 80 | ======= 81 | zlib/libpng license 82 | 83 | Copyright (c) 2023 Andre Weissflog 84 | 85 | This software is provided 'as-is', without any express or implied warranty. 86 | In no event will the authors be held liable for any damages arising from the 87 | use of this software. 88 | 89 | Permission is granted to anyone to use this software for any purpose, 90 | including commercial applications, and to alter it and redistribute it 91 | freely, subject to the following restrictions: 92 | 93 | 1. The origin of this software must not be misrepresented; you must not 94 | claim that you wrote the original software. If you use this software in a 95 | product, an acknowledgment in the product documentation would be 96 | appreciated but is not required. 97 | 98 | 2. Altered source versions must be plainly marked as such, and must not 99 | be misrepresented as being the original software. 100 | 101 | 3. This notice may not be removed or altered from any source 102 | distribution. 103 | */ 104 | #define SOKOL_LOG_INCLUDED (1) 105 | #include 106 | 107 | #if defined(SOKOL_API_DECL) && !defined(SOKOL_LOG_API_DECL) 108 | #define SOKOL_LOG_API_DECL SOKOL_API_DECL 109 | #endif 110 | #ifndef SOKOL_LOG_API_DECL 111 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_LOG_IMPL) 112 | #define SOKOL_LOG_API_DECL __declspec(dllexport) 113 | #elif defined(_WIN32) && defined(SOKOL_DLL) 114 | #define SOKOL_LOG_API_DECL __declspec(dllimport) 115 | #else 116 | #define SOKOL_LOG_API_DECL extern 117 | #endif 118 | #endif 119 | 120 | #ifdef __cplusplus 121 | extern "C" { 122 | #endif 123 | 124 | /* 125 | Plug this function into the 'logger.func' struct item when initializing any of the sokol 126 | headers. For instance for sokol_audio.h it would loom like this: 127 | 128 | saudio_setup(&(saudio_desc){ 129 | .logger = { 130 | .func = slog_func 131 | } 132 | }); 133 | */ 134 | SOKOL_LOG_API_DECL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data); 135 | 136 | #ifdef __cplusplus 137 | } // extern "C" 138 | #endif 139 | #endif // SOKOL_LOG_INCLUDED 140 | 141 | // ██ ███ ███ ██████ ██ ███████ ███ ███ ███████ ███ ██ ████████ █████ ████████ ██ ██████ ███ ██ 142 | // ██ ████ ████ ██ ██ ██ ██ ████ ████ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ 143 | // ██ ██ ████ ██ ██████ ██ █████ ██ ████ ██ █████ ██ ██ ██ ██ ███████ ██ ██ ██ ██ ██ ██ ██ 144 | // ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 145 | // ██ ██ ██ ██ ███████ ███████ ██ ██ ███████ ██ ████ ██ ██ ██ ██ ██ ██████ ██ ████ 146 | // 147 | // >>implementation 148 | #ifdef SOKOL_LOG_IMPL 149 | #define SOKOL_LOG_IMPL_INCLUDED (1) 150 | 151 | #ifndef SOKOL_API_IMPL 152 | #define SOKOL_API_IMPL 153 | #endif 154 | #ifndef SOKOL_DEBUG 155 | #ifndef NDEBUG 156 | #define SOKOL_DEBUG 157 | #endif 158 | #endif 159 | #ifndef SOKOL_ASSERT 160 | #include 161 | #define SOKOL_ASSERT(c) assert(c) 162 | #endif 163 | 164 | #ifndef _SOKOL_PRIVATE 165 | #if defined(__GNUC__) || defined(__clang__) 166 | #define _SOKOL_PRIVATE __attribute__((unused)) static 167 | #else 168 | #define _SOKOL_PRIVATE static 169 | #endif 170 | #endif 171 | 172 | #ifndef _SOKOL_UNUSED 173 | #define _SOKOL_UNUSED(x) (void)(x) 174 | #endif 175 | 176 | // platform detection 177 | #if defined(__APPLE__) 178 | #define _SLOG_APPLE (1) 179 | #elif defined(__EMSCRIPTEN__) 180 | #define _SLOG_EMSCRIPTEN (1) 181 | #elif defined(_WIN32) 182 | #define _SLOG_WINDOWS (1) 183 | #elif defined(__ANDROID__) 184 | #define _SLOG_ANDROID (1) 185 | #elif defined(__linux__) || defined(__unix__) 186 | #define _SLOG_LINUX (1) 187 | #else 188 | #error "sokol_log.h: unknown platform" 189 | #endif 190 | 191 | #include // abort 192 | #include // fputs 193 | #include // size_t 194 | 195 | #if defined(_SLOG_EMSCRIPTEN) 196 | #include 197 | #elif defined(_SLOG_WINDOWS) 198 | #ifndef WIN32_LEAN_AND_MEAN 199 | #define WIN32_LEAN_AND_MEAN 200 | #endif 201 | #ifndef NOMINMAX 202 | #define NOMINMAX 203 | #endif 204 | #include 205 | #elif defined(_SLOG_ANDROID) 206 | #include 207 | #elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE) 208 | #include 209 | #endif 210 | 211 | // size of line buffer (on stack!) in bytes including terminating zero 212 | #define _SLOG_LINE_LENGTH (512) 213 | 214 | _SOKOL_PRIVATE char* _slog_append(const char* str, char* dst, char* end) { 215 | if (str) { 216 | char c; 217 | while (((c = *str++) != 0) && (dst < (end - 1))) { 218 | *dst++ = c; 219 | } 220 | } 221 | *dst = 0; 222 | return dst; 223 | } 224 | 225 | _SOKOL_PRIVATE char* _slog_itoa(uint32_t x, char* buf, size_t buf_size) { 226 | const size_t max_digits_and_null = 11; 227 | if (buf_size < max_digits_and_null) { 228 | return 0; 229 | } 230 | char* p = buf + max_digits_and_null; 231 | *--p = 0; 232 | do { 233 | *--p = '0' + (x % 10); 234 | x /= 10; 235 | } while (x != 0); 236 | return p; 237 | } 238 | 239 | #if defined(_SLOG_EMSCRIPTEN) 240 | EM_JS(void, slog_js_log, (uint32_t level, const char* c_str), { 241 | const str = UTF8ToString(c_str); 242 | switch (level) { 243 | case 0: console.error(str); break; 244 | case 1: console.error(str); break; 245 | case 2: console.warn(str); break; 246 | default: console.info(str); break; 247 | } 248 | }); 249 | #endif 250 | 251 | SOKOL_API_IMPL void slog_func(const char* tag, uint32_t log_level, uint32_t log_item, const char* message, uint32_t line_nr, const char* filename, void* user_data) { 252 | _SOKOL_UNUSED(user_data); 253 | 254 | const char* log_level_str; 255 | switch (log_level) { 256 | case 0: log_level_str = "panic"; break; 257 | case 1: log_level_str = "error"; break; 258 | case 2: log_level_str = "warning"; break; 259 | default: log_level_str = "info"; break; 260 | } 261 | 262 | // build log output line 263 | char line_buf[_SLOG_LINE_LENGTH]; 264 | char* str = line_buf; 265 | char* end = line_buf + sizeof(line_buf); 266 | char num_buf[32]; 267 | if (tag) { 268 | str = _slog_append("[", str, end); 269 | str = _slog_append(tag, str, end); 270 | str = _slog_append("]", str, end); 271 | } 272 | str = _slog_append("[", str, end); 273 | str = _slog_append(log_level_str, str, end); 274 | str = _slog_append("]", str, end); 275 | str = _slog_append("[id:", str, end); 276 | str = _slog_append(_slog_itoa(log_item, num_buf, sizeof(num_buf)), str, end); 277 | str = _slog_append("]", str, end); 278 | // if a filename is provided, build a clickable log message that's compatible with compiler error messages 279 | if (filename) { 280 | str = _slog_append(" ", str, end); 281 | #if defined(_MSC_VER) 282 | // MSVC compiler error format 283 | str = _slog_append(filename, str, end); 284 | str = _slog_append("(", str, end); 285 | str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); 286 | str = _slog_append("): ", str, end); 287 | #else 288 | // gcc/clang compiler error format 289 | str = _slog_append(filename, str, end); 290 | str = _slog_append(":", str, end); 291 | str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); 292 | str = _slog_append(":0: ", str, end); 293 | #endif 294 | } 295 | else { 296 | str = _slog_append("[line:", str, end); 297 | str = _slog_append(_slog_itoa(line_nr, num_buf, sizeof(num_buf)), str, end); 298 | str = _slog_append("] ", str, end); 299 | } 300 | if (message) { 301 | str = _slog_append("\n\t", str, end); 302 | str = _slog_append(message, str, end); 303 | } 304 | str = _slog_append("\n\n", str, end); 305 | if (0 == log_level) { 306 | str = _slog_append("ABORTING because of [panic]\n", str, end); 307 | (void)str; 308 | } 309 | 310 | // print to stderr? 311 | #if defined(_SLOG_LINUX) || defined(_SLOG_WINDOWS) || defined(_SLOG_APPLE) 312 | fputs(line_buf, stderr); 313 | #endif 314 | 315 | // platform specific logging calls 316 | #if defined(_SLOG_WINDOWS) 317 | OutputDebugStringA(line_buf); 318 | #elif defined(_SLOG_ANDROID) 319 | int prio; 320 | switch (log_level) { 321 | case 0: prio = ANDROID_LOG_FATAL; break; 322 | case 1: prio = ANDROID_LOG_ERROR; break; 323 | case 2: prio = ANDROID_LOG_WARN; break; 324 | default: prio = ANDROID_LOG_INFO; break; 325 | } 326 | __android_log_write(prio, "SOKOL", line_buf); 327 | #elif defined(_SLOG_EMSCRIPTEN) 328 | slog_js_log(log_level, line_buf); 329 | #elif defined(_SLOG_LINUX) || defined(_SLOG_APPLE) 330 | int prio; 331 | switch (log_level) { 332 | case 0: prio = LOG_CRIT; break; 333 | case 1: prio = LOG_ERR; break; 334 | case 2: prio = LOG_WARNING; break; 335 | default: prio = LOG_INFO; break; 336 | } 337 | syslog(prio, "%s", line_buf); 338 | #endif 339 | if (0 == log_level) { 340 | abort(); 341 | } 342 | } 343 | #endif // SOKOL_LOG_IMPL 344 | -------------------------------------------------------------------------------- /thirdparty/sokol_time.h: -------------------------------------------------------------------------------- 1 | #if defined(SOKOL_IMPL) && !defined(SOKOL_TIME_IMPL) 2 | #define SOKOL_TIME_IMPL 3 | #endif 4 | #ifndef SOKOL_TIME_INCLUDED 5 | /* 6 | sokol_time.h -- simple cross-platform time measurement 7 | 8 | Project URL: https://github.com/floooh/sokol 9 | 10 | Do this: 11 | #define SOKOL_IMPL or 12 | #define SOKOL_TIME_IMPL 13 | before you include this file in *one* C or C++ file to create the 14 | implementation. 15 | 16 | Optionally provide the following defines with your own implementations: 17 | SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) 18 | SOKOL_TIME_API_DECL - public function declaration prefix (default: extern) 19 | SOKOL_API_DECL - same as SOKOL_TIME_API_DECL 20 | SOKOL_API_IMPL - public function implementation prefix (default: -) 21 | 22 | If sokol_time.h is compiled as a DLL, define the following before 23 | including the declaration or implementation: 24 | 25 | SOKOL_DLL 26 | 27 | On Windows, SOKOL_DLL will define SOKOL_TIME_API_DECL as __declspec(dllexport) 28 | or __declspec(dllimport) as needed. 29 | 30 | void stm_setup(); 31 | Call once before any other functions to initialize sokol_time 32 | (this calls for instance QueryPerformanceFrequency on Windows) 33 | 34 | uint64_t stm_now(); 35 | Get current point in time in unspecified 'ticks'. The value that 36 | is returned has no relation to the 'wall-clock' time and is 37 | not in a specific time unit, it is only useful to compute 38 | time differences. 39 | 40 | uint64_t stm_diff(uint64_t new, uint64_t old); 41 | Computes the time difference between new and old. This will always 42 | return a positive, non-zero value. 43 | 44 | uint64_t stm_since(uint64_t start); 45 | Takes the current time, and returns the elapsed time since start 46 | (this is a shortcut for "stm_diff(stm_now(), start)") 47 | 48 | uint64_t stm_laptime(uint64_t* last_time); 49 | This is useful for measuring frame time and other recurring 50 | events. It takes the current time, returns the time difference 51 | to the value in last_time, and stores the current time in 52 | last_time for the next call. If the value in last_time is 0, 53 | the return value will be zero (this usually happens on the 54 | very first call). 55 | 56 | uint64_t stm_round_to_common_refresh_rate(uint64_t duration) 57 | This oddly named function takes a measured frame time and 58 | returns the closest "nearby" common display refresh rate frame duration 59 | in ticks. If the input duration isn't close to any common display 60 | refresh rate, the input duration will be returned unchanged as a fallback. 61 | The main purpose of this function is to remove jitter/inaccuracies from 62 | measured frame times, and instead use the display refresh rate as 63 | frame duration. 64 | NOTE: for more robust frame timing, consider using the 65 | sokol_app.h function sapp_frame_duration() 66 | 67 | Use the following functions to convert a duration in ticks into 68 | useful time units: 69 | 70 | double stm_sec(uint64_t ticks); 71 | double stm_ms(uint64_t ticks); 72 | double stm_us(uint64_t ticks); 73 | double stm_ns(uint64_t ticks); 74 | Converts a tick value into seconds, milliseconds, microseconds 75 | or nanoseconds. Note that not all platforms will have nanosecond 76 | or even microsecond precision. 77 | 78 | Uses the following time measurement functions under the hood: 79 | 80 | Windows: QueryPerformanceFrequency() / QueryPerformanceCounter() 81 | MacOS/iOS: mach_absolute_time() 82 | emscripten: emscripten_get_now() 83 | Linux+others: clock_gettime(CLOCK_MONOTONIC) 84 | 85 | zlib/libpng license 86 | 87 | Copyright (c) 2018 Andre Weissflog 88 | 89 | This software is provided 'as-is', without any express or implied warranty. 90 | In no event will the authors be held liable for any damages arising from the 91 | use of this software. 92 | 93 | Permission is granted to anyone to use this software for any purpose, 94 | including commercial applications, and to alter it and redistribute it 95 | freely, subject to the following restrictions: 96 | 97 | 1. The origin of this software must not be misrepresented; you must not 98 | claim that you wrote the original software. If you use this software in a 99 | product, an acknowledgment in the product documentation would be 100 | appreciated but is not required. 101 | 102 | 2. Altered source versions must be plainly marked as such, and must not 103 | be misrepresented as being the original software. 104 | 105 | 3. This notice may not be removed or altered from any source 106 | distribution. 107 | */ 108 | #define SOKOL_TIME_INCLUDED (1) 109 | #include 110 | 111 | #if defined(SOKOL_API_DECL) && !defined(SOKOL_TIME_API_DECL) 112 | #define SOKOL_TIME_API_DECL SOKOL_API_DECL 113 | #endif 114 | #ifndef SOKOL_TIME_API_DECL 115 | #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_TIME_IMPL) 116 | #define SOKOL_TIME_API_DECL __declspec(dllexport) 117 | #elif defined(_WIN32) && defined(SOKOL_DLL) 118 | #define SOKOL_TIME_API_DECL __declspec(dllimport) 119 | #else 120 | #define SOKOL_TIME_API_DECL extern 121 | #endif 122 | #endif 123 | 124 | #ifdef __cplusplus 125 | extern "C" { 126 | #endif 127 | 128 | SOKOL_TIME_API_DECL void stm_setup(void); 129 | SOKOL_TIME_API_DECL uint64_t stm_now(void); 130 | SOKOL_TIME_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks); 131 | SOKOL_TIME_API_DECL uint64_t stm_since(uint64_t start_ticks); 132 | SOKOL_TIME_API_DECL uint64_t stm_laptime(uint64_t* last_time); 133 | SOKOL_TIME_API_DECL uint64_t stm_round_to_common_refresh_rate(uint64_t frame_ticks); 134 | SOKOL_TIME_API_DECL double stm_sec(uint64_t ticks); 135 | SOKOL_TIME_API_DECL double stm_ms(uint64_t ticks); 136 | SOKOL_TIME_API_DECL double stm_us(uint64_t ticks); 137 | SOKOL_TIME_API_DECL double stm_ns(uint64_t ticks); 138 | 139 | #ifdef __cplusplus 140 | } /* extern "C" */ 141 | #endif 142 | #endif // SOKOL_TIME_INCLUDED 143 | 144 | /*-- IMPLEMENTATION ----------------------------------------------------------*/ 145 | #ifdef SOKOL_TIME_IMPL 146 | #define SOKOL_TIME_IMPL_INCLUDED (1) 147 | #include /* memset */ 148 | 149 | #ifndef SOKOL_API_IMPL 150 | #define SOKOL_API_IMPL 151 | #endif 152 | #ifndef SOKOL_ASSERT 153 | #include 154 | #define SOKOL_ASSERT(c) assert(c) 155 | #endif 156 | #ifndef _SOKOL_PRIVATE 157 | #if defined(__GNUC__) || defined(__clang__) 158 | #define _SOKOL_PRIVATE __attribute__((unused)) static 159 | #else 160 | #define _SOKOL_PRIVATE static 161 | #endif 162 | #endif 163 | 164 | #if defined(_WIN32) 165 | #ifndef WIN32_LEAN_AND_MEAN 166 | #define WIN32_LEAN_AND_MEAN 167 | #endif 168 | #include 169 | typedef struct { 170 | uint32_t initialized; 171 | LARGE_INTEGER freq; 172 | LARGE_INTEGER start; 173 | } _stm_state_t; 174 | #elif defined(__APPLE__) && defined(__MACH__) 175 | #include 176 | typedef struct { 177 | uint32_t initialized; 178 | mach_timebase_info_data_t timebase; 179 | uint64_t start; 180 | } _stm_state_t; 181 | #elif defined(__EMSCRIPTEN__) 182 | #include 183 | typedef struct { 184 | uint32_t initialized; 185 | double start; 186 | } _stm_state_t; 187 | #else /* anything else, this will need more care for non-Linux platforms */ 188 | #ifdef ESP8266 189 | // On the ESP8266, clock_gettime ignores the first argument and CLOCK_MONOTONIC isn't defined 190 | #define CLOCK_MONOTONIC 0 191 | #endif 192 | #include 193 | typedef struct { 194 | uint32_t initialized; 195 | uint64_t start; 196 | } _stm_state_t; 197 | #endif 198 | static _stm_state_t _stm; 199 | 200 | /* prevent 64-bit overflow when computing relative timestamp 201 | see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3 202 | */ 203 | #if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) 204 | _SOKOL_PRIVATE int64_t _stm_int64_muldiv(int64_t value, int64_t numer, int64_t denom) { 205 | int64_t q = value / denom; 206 | int64_t r = value % denom; 207 | return q * numer + r * numer / denom; 208 | } 209 | #endif 210 | 211 | SOKOL_API_IMPL void stm_setup(void) { 212 | memset(&_stm, 0, sizeof(_stm)); 213 | _stm.initialized = 0xABCDABCD; 214 | #if defined(_WIN32) 215 | QueryPerformanceFrequency(&_stm.freq); 216 | QueryPerformanceCounter(&_stm.start); 217 | #elif defined(__APPLE__) && defined(__MACH__) 218 | mach_timebase_info(&_stm.timebase); 219 | _stm.start = mach_absolute_time(); 220 | #elif defined(__EMSCRIPTEN__) 221 | _stm.start = emscripten_get_now(); 222 | #else 223 | struct timespec ts; 224 | clock_gettime(CLOCK_MONOTONIC, &ts); 225 | _stm.start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec; 226 | #endif 227 | } 228 | 229 | SOKOL_API_IMPL uint64_t stm_now(void) { 230 | SOKOL_ASSERT(_stm.initialized == 0xABCDABCD); 231 | uint64_t now; 232 | #if defined(_WIN32) 233 | LARGE_INTEGER qpc_t; 234 | QueryPerformanceCounter(&qpc_t); 235 | now = (uint64_t) _stm_int64_muldiv(qpc_t.QuadPart - _stm.start.QuadPart, 1000000000, _stm.freq.QuadPart); 236 | #elif defined(__APPLE__) && defined(__MACH__) 237 | const uint64_t mach_now = mach_absolute_time() - _stm.start; 238 | now = (uint64_t) _stm_int64_muldiv((int64_t)mach_now, (int64_t)_stm.timebase.numer, (int64_t)_stm.timebase.denom); 239 | #elif defined(__EMSCRIPTEN__) 240 | double js_now = emscripten_get_now() - _stm.start; 241 | now = (uint64_t) (js_now * 1000000.0); 242 | #else 243 | struct timespec ts; 244 | clock_gettime(CLOCK_MONOTONIC, &ts); 245 | now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm.start; 246 | #endif 247 | return now; 248 | } 249 | 250 | SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) { 251 | if (new_ticks > old_ticks) { 252 | return new_ticks - old_ticks; 253 | } 254 | else { 255 | return 1; 256 | } 257 | } 258 | 259 | SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) { 260 | return stm_diff(stm_now(), start_ticks); 261 | } 262 | 263 | SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) { 264 | SOKOL_ASSERT(last_time); 265 | uint64_t dt = 0; 266 | uint64_t now = stm_now(); 267 | if (0 != *last_time) { 268 | dt = stm_diff(now, *last_time); 269 | } 270 | *last_time = now; 271 | return dt; 272 | } 273 | 274 | // first number is frame duration in ns, second number is tolerance in ns, 275 | // the resulting min/max values must not overlap! 276 | static const uint64_t _stm_refresh_rates[][2] = { 277 | { 16666667, 1000000 }, // 60 Hz: 16.6667 +- 1ms 278 | { 13888889, 250000 }, // 72 Hz: 13.8889 +- 0.25ms 279 | { 13333333, 250000 }, // 75 Hz: 13.3333 +- 0.25ms 280 | { 11764706, 250000 }, // 85 Hz: 11.7647 +- 0.25 281 | { 11111111, 250000 }, // 90 Hz: 11.1111 +- 0.25ms 282 | { 10000000, 500000 }, // 100 Hz: 10.0000 +- 0.5ms 283 | { 8333333, 500000 }, // 120 Hz: 8.3333 +- 0.5ms 284 | { 6944445, 500000 }, // 144 Hz: 6.9445 +- 0.5ms 285 | { 4166667, 1000000 }, // 240 Hz: 4.1666 +- 1ms 286 | { 0, 0 }, // keep the last element always at zero 287 | }; 288 | 289 | SOKOL_API_IMPL uint64_t stm_round_to_common_refresh_rate(uint64_t ticks) { 290 | uint64_t ns; 291 | int i = 0; 292 | while (0 != (ns = _stm_refresh_rates[i][0])) { 293 | uint64_t tol = _stm_refresh_rates[i][1]; 294 | if ((ticks > (ns - tol)) && (ticks < (ns + tol))) { 295 | return ns; 296 | } 297 | i++; 298 | } 299 | // fallthrough: didn't fit into any buckets 300 | return ticks; 301 | } 302 | 303 | SOKOL_API_IMPL double stm_sec(uint64_t ticks) { 304 | return (double)ticks / 1000000000.0; 305 | } 306 | 307 | SOKOL_API_IMPL double stm_ms(uint64_t ticks) { 308 | return (double)ticks / 1000000.0; 309 | } 310 | 311 | SOKOL_API_IMPL double stm_us(uint64_t ticks) { 312 | return (double)ticks / 1000.0; 313 | } 314 | 315 | SOKOL_API_IMPL double stm_ns(uint64_t ticks) { 316 | return (double)ticks; 317 | } 318 | #endif /* SOKOL_TIME_IMPL */ 319 | 320 | --------------------------------------------------------------------------------