forked from edubart/sokol_gp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sokol_gp.h
2362 lines (2063 loc) · 98.2 KB
/
sokol_gp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Minimal efficient cross platform 2D graphics painter for Sokol GFX.
sokol_gp - v0.1.0 - 31/Dec/2021
Eduardo Bart - [email protected]
https://github.com/edubart/sokol_gp
# Sokol GP
Minimal efficient cross platform 2D graphics painter in pure C
using modern graphics API through the excellent [Sokol GFX](https://github.com/floooh/sokol) library.
Sokol GP, or in short SGP, stands for Sokol Graphics Painter.
![sample-primitives](https://raw.githubusercontent.com/edubart/sokol_gp/master/screenshots/sample-primitives.png)
## Features
* Made and optimized only for **2D rendering only**, no 3D support.
* Minimal, in a pure single C header.
* Use modern unfixed pipeline graphics APIs for more efficiency.
* Cross platform (backed by Sokol GFX).
* D3D11/OpenGL 3.3/Metal/WebGPU graphics backends (through Sokol GFX).
* **Automatic batching** (merge recent draw calls into batches automatically).
* **Batch optimizer** (rearranges the ordering of draw calls to batch more).
* Uses preallocated memory (no allocations at runtime).
* Supports drawing basic 2D primitives (rectangles, triangles, lines and points).
* Supports the classic 2D color blending modes (color blend, add, modulate, multiply).
* Supports 2D space transformations and changing 2D space coordinate systems.
* Supports drawing the basic primitives (rectangles, triangles, lines and points).
* Supports multiple texture bindings.
* Supports custom fragment shaders with 2D primitives.
* Can be mixed with projects that are already using Sokol GFX.
## Why?
Sokol GFX is an excellent library for rendering using unfixed pipelines
of modern graphics cards, but it is too complex to use for simple 2D drawing,
and it's API is too generic and specialized for 3D rendering. To draw 2D stuff, the programmer
usually needs to setup custom shaders when using Sokol GFX, or use its Sokol GL
extra library, but Sokol GL also has an API with 3D design in mind, which
incurs some costs and limitations.
This library was created to draw 2D primitives through Sokol GFX with ease,
and by not considering 3D usage it is optimized for 2D rendering only,
furthermore it features an **automatic batch optimizer**, more details of it will be described below.
## Automatic batch optimizer
When drawing the library creates a draw command queue of all primitives yet to be drawn,
every time a new draw command is added the batch optimizer looks back up to the last
8 recent draw commands (this is adjustable), and try to rearrange and merge drawing commands
if it finds a previous draw command that meets the following criteria:
* The new draw command and previous command uses the *same primitive pipeline*
* The new draw command and previous command uses the *same shader uniforms*
* The new draw command and previous command uses the *same texture bindings*
* The new draw command and previous command does not have another intermediary
draw command *that overlaps* in-between them.
By doing this the batch optimizer is able for example to merge textured draw calls,
even if they were drawn with other intermediary different textures draws between them.
The effect is more efficiency when drawing, because less draw calls will be dispatched
to the GPU,
This library can avoid a lot of work of making an efficient 2D drawing batching system,
by automatically merging draw calls behind the scenes at runtime,
thus the programmer does not need to manage batched draw calls manually,
nor he needs to sort batched texture draw calls,
the library will do this seamlessly behind the scenes.
The batching algorithm is fast, but it has `O(n)` CPU complexity for every new draw command added,
where `n` is the `SGP_BATCH_OPTIMIZER_DEPTH` configuration.
In experiments using `8` as the default is a good default,
but you may want to try out different values depending on your case.
Using values that are too high is not recommended, because the algorithm may take too long
scanning previous draw commands, and that may consume more CPU resources.
The batch optimizer can be disabled by setting `SGP_BATCH_OPTIMIZER_DEPTH` to 0,
you can use that to measure its impact.
In the samples directory of this repository there is a
benchmark example that tests drawing with the bath optimizer enabled/disabled.
On my machine that benchmark was able to increase performance in a 2.2x factor when it is enabled.
In some private game projects the gains of the batch optimizer proved to increase FPS performance
above 1.5x by just replacing the graphics backend with this library, with no internal
changes to the game itself.
## Design choices
The library has some design choices with performance in mind that will be discussed briefly here.
Like Sokol GFX, Sokol GP will never do any allocation in the draw loop,
so when initializing you must configure beforehand the maximum size of the
draw command queue buffer and the vertices buffer.
All the 2D space transformation (functions like `sgp_rotate`) are done by the CPU and not by the GPU,
this is intentionally to avoid adding extra overhead in the GPU, because typically the number
of vertices of 2D applications are not that large, and it is more efficient to perform
all the transformation with the CPU right away rather than pushing extra buffers to the GPU
that ends up using more bandwidth of the CPU<->GPU bus.
In contrast 3D applications usually dispatches vertex transformations to the GPU using a vertex shader,
they do this because the amount of vertices of 3D objects can be very large
and it is usually the best choice, but this is not true for 2D rendering.
Many APIs to transform the 2D space before drawing a primitive are available, such as
translate, rotate and scale. They can be used as similarly as the ones available in 3D graphics APIs,
but they are crafted for 2D only, for example when using 2D we don't need to use a 4x4 or 3x3 matrix
to perform vertex transformation, instead the code is specialized for 2D and can use a 2x3 matrix,
saving extra CPU float computations.
All pipelines always use a texture associated with it, even when drawing non textured primitives,
because this minimizes graphics pipeline changes when mixing textured calls and non textured calls,
improving efficiency.
The library is coded in the style of Sokol GFX headers, reusing many macros from there,
you can change some of its semantics such as custom allocator, custom log function, and some
other details, read `sokol_gfx.h` documentation for more on that.
## Usage
Copy `sokol_gp.h` along with other Sokol headers to the same folder. Setup Sokol GFX
as you usually would, then add call to `sgp_setup(desc)` just after `sg_setup(desc)`, and
call to `sgp_shutdown()` just before `sg_shutdown()`. Note that you should usually check if
SGP is valid after its creation with `sgp_is_valid()` and exit gracefully with an error if not.
In your frame draw function add `sgp_begin(width, height)` before calling any SGP
draw function, then draw your primitives. At the end of the frame (or framebuffer) you
should **ALWAYS call** `sgp_flush()` between a Sokol GFX begin/end render pass,
the `sgp_flush()` will dispatch all draw commands to Sokol GFX. Then call `sgp_end()` immediately
to discard the draw command queue.
An actual example of this setup will be shown below.
## Quick usage example
The following is a quick example on how to this library with Sokol GFX and Sokol APP:
```c
// This is an example on how to set up and use Sokol GP to draw a filled rectangle.
// Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations.
#define SOKOL_IMPL
#include "sokol_gfx.h"
#include "sokol_gp.h"
#include "sokol_app.h"
#include "sokol_glue.h"
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for exit()
#include <math.h> // for sinf() and cosf()
// Called on every frame of the application.
static void frame(void) {
// Get current window size.
int width = sapp_width(), height = sapp_height();
float ratio = width/(float)height;
// Begin recording draw commands for a frame buffer of size (width, height).
sgp_begin(width, height);
// Set frame buffer drawing region to (0,0,width,height).
sgp_viewport(0, 0, width, height);
// Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1).
sgp_project(-ratio, ratio, 1.0f, -1.0f);
// Clear the frame buffer.
sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f);
sgp_clear();
// Draw an animated rectangle that rotates and changes its colors.
float time = sapp_frame_count() * sapp_frame_duration();
float r = sinf(time)*0.5+0.5, g = cosf(time)*0.5+0.5;
sgp_set_color(r, g, 0.3f, 1.0f);
sgp_rotate_at(time, 0.0f, 0.0f);
sgp_draw_filled_rect(-0.5f, -0.5f, 1.0f, 1.0f);
// Begin a render pass.
sg_pass_action pass_action = {0};
sg_begin_default_pass(&pass_action, width, height);
// Dispatch all draw commands to Sokol GFX.
sgp_flush();
// Finish a draw command queue, clearing it.
sgp_end();
// End render pass.
sg_end_pass();
// Commit Sokol render.
sg_commit();
}
// Called when the application is initializing.
static void init(void) {
// Initialize Sokol GFX.
sg_desc sgdesc = {.context = sapp_sgcontext()};
sg_setup(&sgdesc);
if(!sg_isvalid()) {
fprintf(stderr, "Failed to create Sokol GFX context!\n");
exit(-1);
}
// Initialize Sokol GP, adjust the size of command buffers for your own use.
sgp_desc sgpdesc = {0};
sgp_setup(&sgpdesc);
if(!sgp_is_valid()) {
fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error()));
exit(-1);
}
}
// Called when the application is shutting down.
static void cleanup(void) {
// Cleanup Sokol GP and Sokol GFX resources.
sgp_shutdown();
sg_shutdown();
}
// Implement application main through Sokol APP.
sapp_desc sokol_main(int argc, char* argv[]) {
(void)argc;
(void)argv;
return (sapp_desc){
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.window_title = "Triangle (Sokol GP)",
.sample_count = 4, // Enable anti aliasing.
};
}
```
To run this example, first copy the `sokol_gp.h` header alongside with other Sokol headers
to the same folder, then compile with any C compiler using the proper linking flags (read `sokol_gfx.h`).
## Complete Examples
In folder `samples` you can find the following complete examples covering all APIs of the library:
* [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.
* [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.
* [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.
* [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.
* [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.
* [sample-bench.c](https://github.com/edubart/sokol_gp/blob/master/samples/sample-bench.c): This is a heavy example used for benchmarking purposes.
These examples are used as the test suite for the library, you can build them by typing `make`.
## Error handling
It is possible that after many draw calls the command or vertex buffer may overflow,
in that case the library will set an error error state and will continue to operate normally,
but when flushing the drawing command queue with `sgp_flush()` no draw command will be dispatched.
This can happen because the library uses pre allocated buffers, in such
cases the issue can be fixed by increasing the prefixed command queue buffer and the vertices buffer
when calling `sgp_setup()`.
Making invalid number of push/pops of `sgp_push_transform()` and `sgp_pop_transform()`,
or nesting too many `sgp_begin()` and `sgp_end()` may also lead to errors, that
is a usage mistake.
You can enable the `SOKOL_DEBUG` macro in such cases to debug, or handle
the error programmatically by reading `sgp_get_last_error()` after calling `sgp_end()`.
It is also advised to leave `SOKOL_DEBUG` enabled when developing with Sokol, so you can
catch mistakes early.
## Blend modes
The library supports the most usual blend modes used in 2D, which are the following:
- `SGP_BLENDMODE_NONE` - No blending (`dstRGBA = srcRGBA`).
- `SGP_BLENDMODE_BLEND` - Alpha blending (`dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))` and `dstA = srcA + (dstA * (1-srcA))`)
- `SGP_BLENDMODE_ADD` - Color add (`dstRGB = (srcRGB * srcA) + dstRGB` and `dstA = dstA`)
- `SGP_BLENDMODE_MOD` - Color modulate (`dstRGB = srcRGB * dstRGB` and `dstA = dstA`)
- `SGP_BLENDMODE_MUL` - Color multiply (`dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))` and `dstA = (srcA * dstA) + (dstA * (1-srcA))`)
## Changing 2D coordinate system
You can change the screen area to draw by calling `sgp_viewport(x, y, width, height)`.
You can change the coordinate system of the 2D space by calling `sgp_project(left, right, top, bottom)`,
with it.
## Transforming 2D space
You can translate, rotate or scale the 2D space before a draw call, by using the transformation
functions the library provides, such as `sgp_translate(x, y)`, `sgp_rotate(theta)`, etc.
Check the cheat sheet or the header for more.
To save and restore the transformation state you should call `sgp_push_transform()` and
later `sgp_pop_transform()`.
## Drawing primitives
The library provides drawing functions for all the basic primitives, that is,
for points, lines, triangles and rectangles, such as `sgp_draw_line()` and `sgp_draw_filled_rect()`.
Check the cheat sheet or the header for more.
All of them have batched variations.
## Color modulation
All common pipelines have color modulation, and you can modulate
a color before a draw by setting the current state color with `sgp_set_color(r,g,b,a)`,
later you should reset the color to default (white) with `sgp_reset_color()`.
## Custom shaders
When using a custom shader, you must create a pipeline for it with `sgp_make_pipeline(desc)`,
using shader, blend mode and a draw primitive associated with it. Then you should
call `sgp_set_pipeline()` before the shader draw call. You are responsible for using
the same blend mode and drawing primitive as the created pipeline.
Custom uniforms can be passed to the shader with `sgp_set_uniform(data, size)`,
where you should always pass a pointer to a struct with exactly the same schema and size
as the one defined in the shader.
Although you can create custom shaders for each graphics backend manually,
it is advised should use the Sokol shader compiler [SHDC](https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md),
because it can generate shaders for multiple backends from a single `.glsl` file,
and this usually works well.
By default the library uniform buffer per draw call has just 4 float uniforms
(`SGP_UNIFORM_CONTENT_SLOTS` configuration), and that may be too low to use with custom shaders.
This is the default because typically newcomers may not want to use custom 2D shaders,
and increasing a larger value means more overhead.
If you are using custom shaders please increase this value to be large enough to hold
the number of uniforms of your largest shader.
## Library configuration
The following macros can be defined before including to change the library behavior:
- `SGP_BATCH_OPTIMIZER_DEPTH` - Number of draw commands that the batch optimizer looks back at. Default is 8.
- `SGP_UNIFORM_CONTENT_SLOTS` - Maximum number of floats that can be stored in each draw call uniform buffer. Default is 4.
- `SGP_TEXTURE_SLOTS` - Maximum number of textures that can be bound per draw call. Default is 4.
## License
MIT, see LICENSE file or the end of `sokol_gp.h` file.
*/
#if defined(SOKOL_IMPL) && !defined(SOKOL_GP_IMPL)
#define SOKOL_GP_IMPL
#endif
#ifndef SOKOL_GP_INCLUDED
#define SOKOL_GP_INCLUDED 1
#ifndef SOKOL_GFX_INCLUDED
#error "Please include sokol_gfx.h before sokol_gp.h"
#endif
/* Number of draw commands that the batch optimizer looks back at.
8 is a fair default value, but could be tuned per application.
1 makes the batch optimizer try to merge only the very last draw call.
0 disables the batch optimizer
*/
#ifndef SGP_BATCH_OPTIMIZER_DEPTH
#define SGP_BATCH_OPTIMIZER_DEPTH 8
#endif
/* Number of draw commands that the batch optimizer looks back. */
#ifndef SGP_UNIFORM_CONTENT_SLOTS
#define SGP_UNIFORM_CONTENT_SLOTS 4
#endif
/* Number of texture slots that can be bound in a pipeline. */
#ifndef SGP_TEXTURE_SLOTS
#define SGP_TEXTURE_SLOTS 4
#endif
#if defined(SOKOL_API_DECL) && !defined(SOKOL_GP_API_DECL)
#define SOKOL_GP_API_DECL SOKOL_API_DECL
#endif
#ifndef SOKOL_GP_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GP_IMPL)
#define SOKOL_GP_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_GP_API_DECL __declspec(dllimport)
#else
#define SOKOL_GP_API_DECL extern
#endif
#endif
#ifndef SOKOL_LOG
#ifdef SOKOL_DEBUG
#include <stdio.h>
#define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
#else
#define SOKOL_LOG(s)
#endif
#endif
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* List of possible error codes. */
typedef enum sgp_error {
SGP_NO_ERROR = 0,
SGP_ERROR_SOKOL_INVALID,
SGP_ERROR_VERTICES_FULL,
SGP_ERROR_UNIFORMS_FULL,
SGP_ERROR_COMMANDS_FULL,
SGP_ERROR_VERTICES_OVERFLOW,
SGP_ERROR_TRANSFORM_STACK_OVERFLOW,
SGP_ERROR_TRANSFORM_STACK_UNDERFLOW,
SGP_ERROR_STATE_STACK_OVERFLOW,
SGP_ERROR_STATE_STACK_UNDERFLOW,
SGP_ERROR_ALLOC_FAILED,
SGP_ERROR_MAKE_VERTEX_BUFFER_FAILED,
SGP_ERROR_MAKE_WHITE_IMAGE_FAILED,
SGP_ERROR_MAKE_COMMON_SHADER_FAILED,
SGP_ERROR_MAKE_COMMON_PIPELINE_FAILED,
} sgp_error;
/* Blend modes. */
typedef enum sgp_blend_mode {
SGP_BLENDMODE_NONE = 0, /* No blending.
dstRGBA = srcRGBA */
SGP_BLENDMODE_BLEND, /* Alpha blending.
dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
dstA = srcA + (dstA * (1-srcA)) */
SGP_BLENDMODE_ADD, /* Color add.
dstRGB = (srcRGB * srcA) + dstRGB
dstA = dstA */
SGP_BLENDMODE_MOD, /* Color modulate.
dstRGB = srcRGB * dstRGB
dstA = dstA */
SGP_BLENDMODE_MUL, /* Color multiply.
dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA))
dstA = (srcA * dstA) + (dstA * (1-srcA)) */
_SGP_BLENDMODE_NUM
} sgp_blend_mode;
typedef struct sgp_isize {
int w, h;
} sgp_isize;
typedef struct sgp_irect {
int x, y, w, h;
} sgp_irect;
typedef struct sgp_rect {
float x, y, w, h;
} sgp_rect;
typedef struct sgp_textured_rect {
sgp_rect dst;
sgp_rect src;
} sgp_textured_rect;
typedef struct sgp_vec2 {
float x, y;
} sgp_vec2;
typedef sgp_vec2 sgp_point;
typedef struct sgp_line {
sgp_point a, b;
} sgp_line;
typedef struct sgp_triangle {
sgp_point a, b, c;
} sgp_triangle;
typedef struct sgp_mat2x3 {
float v[2][3];
} sgp_mat2x3;
typedef struct sgp_color {
float r, g, b, a;
} sgp_color;
typedef struct sgp_uniform {
uint32_t size;
float content[SGP_UNIFORM_CONTENT_SLOTS];
} sgp_uniform;
typedef struct sgp_images_uniform {
uint32_t count;
sg_image images[SGP_TEXTURE_SLOTS];
} sgp_images_uniform;
/* SGP draw state. */
typedef struct sgp_state {
sgp_isize frame_size;
sgp_irect viewport;
sgp_irect scissor;
sgp_mat2x3 proj;
sgp_mat2x3 transform;
sgp_mat2x3 mvp;
float thickness;
sgp_color color;
sgp_images_uniform images;
sgp_uniform uniform;
sgp_blend_mode blend_mode;
sg_pipeline pipeline;
uint32_t _base_vertex;
uint32_t _base_uniform;
uint32_t _base_command;
} sgp_state;
/* Structure that defines SGP setup parameters. */
typedef struct sgp_desc {
uint32_t max_vertices;
uint32_t max_commands;
} sgp_desc;
/* Structure that defines SGP custom pipeline creation parameters. */
typedef struct sgp_pipeline_desc {
sg_shader_desc shader; /* Sokol shader description. */
sg_primitive_type primitive_type; /* Draw primitive type (triangles, lines, points, etc). Default is triangles. */
sgp_blend_mode blend_mode; /* Color blend mode. Default is no blend. */
} sgp_pipeline_desc;
/* Initialization and de-initialization. */
SOKOL_GP_API_DECL void sgp_setup(const sgp_desc* desc); /* Initializes the SGP context, and should be called after `sg_setup`. */
SOKOL_GP_API_DECL void sgp_shutdown(void); /* Destroys the SGP context. */
SOKOL_GP_API_DECL bool sgp_is_valid(void); /* Checks if SGP context is valid, should be checked after `sgp_setup`. */
/* Error handling. */
SOKOL_GP_API_DECL sgp_error sgp_get_last_error(void); /* Returns last SGP error. */
SOKOL_GP_API_DECL const char* sgp_get_error_message(sgp_error error); /* Returns a message with SGP error description. */
/* Custom pipeline creation. */
SOKOL_GP_API_DECL sg_pipeline sgp_make_pipeline(const sgp_pipeline_desc* desc); /* Creates a custom shader pipeline to be used with SGP. */
/* Draw command queue management. */
SOKOL_GP_API_DECL void sgp_begin(int width, int height); /* Begins a new SGP draw command queue. */
SOKOL_GP_API_DECL void sgp_flush(void); /* Dispatch current Sokol GFX draw commands. */
SOKOL_GP_API_DECL void sgp_end(void); /* End current draw command queue, discarding it. */
/* 2D coordinate space projection */
SOKOL_GP_API_DECL void sgp_project(float left, float right, float top, float bottom); /* Set the coordinate space boundary in the current viewport. */
SOKOL_GP_API_DECL void sgp_reset_project(void); /* Resets the coordinate space to default (coordinate of the viewport). */
/* 2D coordinate space transformation. */
SOKOL_GP_API_DECL void sgp_push_transform(void); /* Saves current transform matrix, to be restored later with a pop. */
SOKOL_GP_API_DECL void sgp_pop_transform(void); /* Restore transform matrix to the same value of the last push. */
SOKOL_GP_API_DECL void sgp_reset_transform(void); /* Resets the transform matrix to identity (no transform). */
SOKOL_GP_API_DECL void sgp_translate(float x, float y); /* Translates the 2D coordinate space. */
SOKOL_GP_API_DECL void sgp_rotate(float theta); /* Rotates the 2D coordinate space around the origin. */
SOKOL_GP_API_DECL void sgp_rotate_at(float theta, float x, float y); /* Rotates the 2D coordinate space around a point. */
SOKOL_GP_API_DECL void sgp_scale(float sx, float sy); /* Scales the 2D coordinate space around the origin. */
SOKOL_GP_API_DECL void sgp_scale_at(float sx, float sy, float x, float y); /* Scales the 2D coordinate space around a point. */
/* State change for custom pipelines. */
SOKOL_GP_API_DECL void sgp_set_pipeline(sg_pipeline pipeline); /* Sets current draw pipeline. */
SOKOL_GP_API_DECL void sgp_reset_pipeline(void); /* Resets to the current draw pipeline to default (builtin pipelines). */
SOKOL_GP_API_DECL void sgp_set_uniform(const void* data, uint32_t size); /* Sets uniform buffer for a custom pipeline. */
SOKOL_GP_API_DECL void sgp_reset_uniform(void); /* Resets uniform buffer to default (current state color). */
/* State change functions for the common pipelines. */
SOKOL_GP_API_DECL void sgp_set_blend_mode(sgp_blend_mode blend_mode); /* Sets current blend mode. */
SOKOL_GP_API_DECL void sgp_reset_blend_mode(void); /* Resets current blend mode to default (no blending). */
SOKOL_GP_API_DECL void sgp_set_color(float r, float g, float b, float a); /* Sets current color modulation. */
SOKOL_GP_API_DECL void sgp_reset_color(void); /* Resets current color modulation to default (white). */
SOKOL_GP_API_DECL void sgp_set_image(int channel, sg_image image); /* Sets current bound texture in a texture channel. */
SOKOL_GP_API_DECL void sgp_unset_image(int channel); /* Remove current bound texture in a texture channel (no texture). */
SOKOL_GP_API_DECL void sgp_reset_image(int channel); /* Resets current bound texture in a channel to default (white texture). */
/* State change functions for all pipelines. */
SOKOL_GP_API_DECL void sgp_viewport(int x, int y, int w, int h); /* Sets the screen area to draw into. */
SOKOL_GP_API_DECL void sgp_reset_viewport(void); /* Reset viewport to default values (0, 0, width, height). */
SOKOL_GP_API_DECL void sgp_scissor(int x, int y, int w, int h); /* Set clip rectangle in the viewport. */
SOKOL_GP_API_DECL void sgp_reset_scissor(void); /* Resets clip rectangle to default (viewport bounds). */
SOKOL_GP_API_DECL void sgp_reset_state(void); /* Reset all state to default values. */
/* Drawing functions. */
SOKOL_GP_API_DECL void sgp_clear(void); /* Clears the current viewport using the current state color. */
SOKOL_GP_API_DECL void sgp_draw_points(const sgp_point* points, uint32_t count); /* Draws points in a batch. */
SOKOL_GP_API_DECL void sgp_draw_point(float x, float y); /* Draws a single point. */
SOKOL_GP_API_DECL void sgp_draw_lines(const sgp_line* lines, uint32_t count); /* Draws lines in a batch. */
SOKOL_GP_API_DECL void sgp_draw_line(float ax, float ay, float bx, float by); /* Draws a single line. */
SOKOL_GP_API_DECL void sgp_draw_lines_strip(const sgp_point* points, uint32_t count); /* Draws a strip of lines. */
SOKOL_GP_API_DECL void sgp_draw_filled_triangles(const sgp_triangle* triangles, uint32_t count); /* Draws triangles in a batch. */
SOKOL_GP_API_DECL void sgp_draw_filled_triangle(float ax, float ay, float bx, float by, float cx, float cy); /* Draws a single triangle. */
SOKOL_GP_API_DECL void sgp_draw_filled_triangles_strip(const sgp_point* points, uint32_t count); /* Draws strip of triangles. */
SOKOL_GP_API_DECL void sgp_draw_filled_rects(const sgp_rect* rects, uint32_t count); /* Draws a batch of rectangles. */
SOKOL_GP_API_DECL void sgp_draw_filled_rect(float x, float y, float w, float h); /* Draws a single rectangle. */
SOKOL_GP_API_DECL void sgp_draw_textured_rects(const sgp_rect* rects, uint32_t count); /* Draws a batch of textured rectangles. */
SOKOL_GP_API_DECL void sgp_draw_textured_rect(float x, float y, float w, float h); /* Draws a single textured rectangle. */
SOKOL_GP_API_DECL void sgp_draw_textured_rects_ex(int channel, const sgp_textured_rect* rects, uint32_t count); /* Draws a batch textured rectangle, each from a source region. */
SOKOL_GP_API_DECL void sgp_draw_textured_rect_ex(int channel, sgp_rect dest_rect, sgp_rect src_rect); /* Draws a single textured rectangle from a source region. */
/* Querying functions. */
SOKOL_GP_API_DECL sgp_state* sgp_query_state(void); /* Returns the current draw state. */
SOKOL_GP_API_DECL sgp_desc sgp_query_desc(void); /* Returns description of the current SGP context. */
#ifdef __cplusplus
} // extern "C"
#endif
#endif // SOKOL_GP_INCLUDED
#ifdef SOKOL_GP_IMPL
#ifndef SOKOL_GP_IMPL_INCLUDED
#define SOKOL_GP_IMPL_INCLUDED
#ifndef SOKOL_GFX_IMPL_INCLUDED
#error "Please include sokol_gfx.h implementation before sokol_gp.h implementation"
#endif
#include <string.h>
#include <math.h>
#include <stddef.h>
#ifndef SOKOL_LIKELY
#ifdef __GNUC__
#define SOKOL_LIKELY(x) __builtin_expect(x, 1)
#define SOKOL_UNLIKELY(x) __builtin_expect(x, 0)
#else
#define SOKOL_LIKELY(x) (x)
#define SOKOL_UNLIKELY(x) (x)
#endif
#endif
enum {
_SGP_INIT_COOKIE = 0xCAFED0D,
_SGP_DEFAULT_MAX_VERTICES = 65536,
_SGP_DEFAULT_MAX_COMMANDS = 16384,
_SGP_MAX_STACK_DEPTH = 64
};
typedef struct _sgp_vertex {
sgp_vec2 position;
sgp_vec2 texcoord;
} _sgp_vertex;
typedef struct _sgp_region {
float x1, y1, x2, y2;
} _sgp_region;
typedef struct _sgp_draw_args {
sg_pipeline pip;
sgp_images_uniform images;
_sgp_region region;
uint32_t uniform_index;
uint32_t vertex_index;
uint32_t num_vertices;
} _sgp_draw_args;
typedef union _sgp_command_args {
_sgp_draw_args draw;
sgp_irect viewport;
sgp_irect scissor;
} _sgp_command_args;
typedef enum _sgp_command_type {
SGP_COMMAND_NONE = 0,
SGP_COMMAND_DRAW,
SGP_COMMAND_VIEWPORT,
SGP_COMMAND_SCISSOR
} _sgp_command_type;
typedef struct _sgp_command {
_sgp_command_type cmd;
_sgp_command_args args;
} _sgp_command;
typedef struct _sgp_context {
uint32_t init_cookie;
sgp_error last_error;
sgp_desc desc;
// resources
sg_shader shader;
sg_buffer vertex_buf;
sg_image white_img;
sg_pipeline pipelines[_SG_PRIMITIVETYPE_NUM*_SGP_BLENDMODE_NUM];
// command queue
uint32_t cur_vertex;
uint32_t cur_uniform;
uint32_t cur_command;
uint32_t num_vertices;
uint32_t num_uniforms;
uint32_t num_commands;
_sgp_vertex* vertices;
sgp_uniform* uniforms;
_sgp_command* commands;
// state tracking
sgp_state state;
// matrix stack
uint32_t cur_transform;
uint32_t cur_state;
sgp_mat2x3 transform_stack[_SGP_MAX_STACK_DEPTH];
sgp_state state_stack[_SGP_MAX_STACK_DEPTH];
} _sgp_context;
static _sgp_context _sgp;
static const sgp_mat2x3 _sgp_mat3_identity = {{
{1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f}
}};
static const sgp_color _sgp_white_color = {1.0f, 1.0f, 1.0f, 1.0f};
static void _sgp_set_error(sgp_error error) {
_sgp.last_error = error;
SOKOL_LOG(sgp_get_error_message(error));
}
#if defined(SOKOL_GLCORE33)
static const char* _sgp_vs_source =
"#version 330\n"
"layout(location=0) in vec4 coord;\n"
"out vec2 texUV;\n"
"void main() {\n"
" gl_Position = vec4(coord.xy, 0.0, 1.0);\n"
" texUV = coord.zw;\n"
"}\n";
static const char* _sgp_fs_source =
"#version 330\n"
"uniform sampler2D iChannel0;\n"
"uniform vec4 iColor;\n"
"in vec2 texUV;\n"
"out vec4 fragColor;\n"
"void main() {\n"
" fragColor = texture(iChannel0, texUV) * iColor;\n"
"}\n";
#elif defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
static const char* _sgp_vs_source =
"attribute vec4 coord;\n"
"varying vec2 texUV;\n"
"void main() {\n"
" gl_Position = vec4(coord.xy, 0.0, 1.0);\n"
" texUV = coord.zw;\n"
"}\n";
static const char* _sgp_fs_source =
"precision mediump float;\n"
"uniform sampler2D iChannel0;\n"
"uniform vec4 iColor;\n"
"varying vec2 texUV;\n"
"void main() {\n"
" gl_FragColor = texture2D(iChannel0, texUV) * iColor;\n"
"}\n";
#elif defined(SOKOL_D3D11)
static const char* _sgp_vs_source =
"struct vs_out {\n"
" float2 texUV: TEXCOORD0;\n"
" float4 pos: SV_Position;\n"
"};\n"
"vs_out main(float4 coord: POSITION) {\n"
" vs_out outp;\n"
" outp.pos = float4(coord.xy, 0.0f, 1.0f);\n"
" outp.texUV = coord.zw;\n"
" return outp;\n"
"}\n";
static const char* _sgp_fs_source =
"Texture2D<float4> iChannel0: register(t0);\n"
"SamplerState smp: register(s0);\n"
"uniform float4 iColor;\n"
"float4 main(float2 texUV: TEXCOORD0): SV_Target0 {\n"
" return iChannel0.Sample(smp, texUV) * iColor;\n"
"}\n";
#elif defined(SOKOL_METAL)
static const char* _sgp_vs_source =
"#include <metal_stdlib>\n"
"#include <simd/simd.h>\n"
"using namespace metal;\n"
"struct main0_out {\n"
" float2 texUV [[user(locn0)]];\n"
" float4 gl_Position [[position]];\n"
"};\n"
"struct main0_in {\n"
" float4 coord [[attribute(0)]];\n"
"};\n"
"vertex main0_out _main(main0_in in [[stage_in]]) {\n"
" main0_out out = {};\n"
" out.gl_Position = float4(in.coord.xy, 0.0, 1.0);\n"
" out.texUV = in.coord.zw;\n"
" return out;\n"
"}\n";
static const char* _sgp_fs_source =
"#include <metal_stdlib>\n"
"#include <simd/simd.h>\n"
"using namespace metal;\n"
"struct main0_out {\n"
" float4 fragColor [[color(0)]];\n"
"};\n"
"struct main0_in {\n"
" float2 texUV [[user(locn0)]];\n"
"};\n"
"fragment main0_out _main(main0_in in [[stage_in]], constant float4& iColor [[buffer(0)]], texture2d<float> iChannel0 [[texture(0)]], sampler texSmplr [[sampler(0)]]) {\n"
" main0_out out = {};\n"
" out.fragColor = iChannel0.sample(texSmplr, in.texUV) * iColor;\n"
" return out;\n"
"}\n";
#elif defined(SOKOL_WGPU)
#define _SGP_BYTECODE
/*
#version 450
layout(location = 0) in vec4 coord;
layout(location = 0) out vec2 texUV;
void main() {
gl_Position = vec4(coord.xy, 0.0, 1.0);
texUV = coord.zw;
}
*/
static const uint8_t _sgp_vs_bytecode[1160] = {
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x22,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00,
0x02,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30,
0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x0f,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,
0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
0x07,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x08,0x00,
0x07,0x00,0x00,0x00,0x73,0x6f,0x6b,0x6f,0x6c,0x5f,0x67,0x70,0x5f,0x73,0x68,0x61,
0x64,0x65,0x72,0x73,0x2e,0x67,0x6c,0x73,0x6c,0x00,0x00,0x00,0x03,0x00,0x37,0x00,
0x02,0x00,0x00,0x00,0xc2,0x01,0x00,0x00,0x01,0x00,0x00,0x00,0x2f,0x2f,0x20,0x4f,
0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,
0x20,0x63,0x6c,0x69,0x65,0x6e,0x74,0x20,0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x30,
0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,
0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x63,0x6c,0x69,0x65,0x6e,0x74,0x20,0x6f,0x70,
0x65,0x6e,0x67,0x6c,0x31,0x30,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,
0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x74,0x61,0x72,
0x67,0x65,0x74,0x2d,0x65,0x6e,0x76,0x20,0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x2e,
0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,
0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2d,0x65,0x6e,
0x76,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,
0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x65,0x6e,
0x74,0x72,0x79,0x2d,0x70,0x6f,0x69,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x0a,0x23,
0x6c,0x69,0x6e,0x65,0x20,0x31,0x0a,0x00,0x05,0x00,0x04,0x00,0x05,0x00,0x00,0x00,
0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,0x05,0x00,0x06,0x00,0x0d,0x00,0x00,0x00,
0x67,0x6c,0x5f,0x50,0x65,0x72,0x56,0x65,0x72,0x74,0x65,0x78,0x00,0x00,0x00,0x00,
0x06,0x00,0x06,0x00,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,
0x6f,0x73,0x69,0x74,0x69,0x6f,0x6e,0x00,0x06,0x00,0x07,0x00,0x0d,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x67,0x6c,0x5f,0x50,0x6f,0x69,0x6e,0x74,0x53,0x69,0x7a,0x65,
0x00,0x00,0x00,0x00,0x06,0x00,0x07,0x00,0x0d,0x00,0x00,0x00,0x02,0x00,0x00,0x00,
0x67,0x6c,0x5f,0x43,0x6c,0x69,0x70,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00,
0x06,0x00,0x07,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x67,0x6c,0x5f,0x43,
0x75,0x6c,0x6c,0x44,0x69,0x73,0x74,0x61,0x6e,0x63,0x65,0x00,0x05,0x00,0x03,0x00,
0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x13,0x00,0x00,0x00,
0x63,0x6f,0x6f,0x72,0x64,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x1f,0x00,0x00,0x00,
0x74,0x65,0x78,0x55,0x56,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0d,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,
0x0d,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x48,0x00,0x05,0x00,0x0d,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,
0x03,0x00,0x00,0x00,0x48,0x00,0x05,0x00,0x0d,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
0x0b,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x47,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x13,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,0x1f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x13,0x00,0x02,0x00,0x03,0x00,0x00,0x00,0x21,0x00,0x03,0x00,
0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x16,0x00,0x03,0x00,0x08,0x00,0x00,0x00,
0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,0x09,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
0x04,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x0a,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x1c,0x00,0x04,0x00,0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
0x0b,0x00,0x00,0x00,0x1e,0x00,0x06,0x00,0x0d,0x00,0x00,0x00,0x09,0x00,0x00,0x00,
0x08,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x0e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x15,0x00,0x04,0x00,
0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,
0x10,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x04,0x00,
0x14,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,
0x08,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,
0x08,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x80,0x3f,0x20,0x00,0x04,0x00,
0x1c,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x1e,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x1e,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x36,0x00,0x05,0x00,
0x03,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
0xf8,0x00,0x02,0x00,0x06,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x07,0x00,0x00,0x00,
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x09,0x00,0x00,0x00,
0x15,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x51,0x00,0x05,0x00,0x08,0x00,0x00,0x00,
0x19,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0x00,0x05,0x00,
0x08,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x50,0x00,0x07,0x00,0x09,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x19,0x00,0x00,0x00,
0x1a,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x41,0x00,0x05,0x00,
0x1c,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x11,0x00,0x00,0x00,
0x3e,0x00,0x03,0x00,0x1d,0x00,0x00,0x00,0x1b,0x00,0x00,0x00,0x4f,0x00,0x07,0x00,
0x14,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x3e,0x00,0x03,0x00,0x1f,0x00,0x00,0x00,
0x21,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,0x38,0x00,0x01,0x00,
};
/*
#version 450
layout(set = 0, binding = 4, std140) uniform fs_in {
vec4 iColor;
} in;
layout(location = 0, set = 2, binding = 0) uniform sampler2D iChannel0;
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 texUV;
void main() {
fragColor = texture(iChannel0, texUV) * in.iColor;
}
*/
static const uint8_t _sgp_fs_bytecode[1060] = {
0x03,0x02,0x23,0x07,0x00,0x00,0x01,0x00,0x08,0x00,0x08,0x00,0x1f,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x11,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0b,0x00,0x06,0x00,
0x02,0x00,0x00,0x00,0x47,0x4c,0x53,0x4c,0x2e,0x73,0x74,0x64,0x2e,0x34,0x35,0x30,
0x00,0x00,0x00,0x00,0x0e,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
0x0f,0x00,0x07,0x00,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,
0x00,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x10,0x00,0x03,0x00,
0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x03,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x07,0x00,0x08,0x00,0x07,0x00,0x00,0x00,0x73,0x6f,0x6b,0x6f,
0x6c,0x5f,0x67,0x70,0x5f,0x73,0x68,0x61,0x64,0x65,0x72,0x73,0x2e,0x67,0x6c,0x73,
0x6c,0x00,0x00,0x00,0x03,0x00,0x37,0x00,0x02,0x00,0x00,0x00,0xc2,0x01,0x00,0x00,
0x01,0x00,0x00,0x00,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,
0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x63,0x6c,0x69,0x65,0x6e,0x74,0x20,
0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x30,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,
0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x63,
0x6c,0x69,0x65,0x6e,0x74,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c,0x31,0x30,0x30,0x0a,
0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,
0x73,0x73,0x65,0x64,0x20,0x74,0x61,0x72,0x67,0x65,0x74,0x2d,0x65,0x6e,0x76,0x20,
0x76,0x75,0x6c,0x6b,0x61,0x6e,0x31,0x2e,0x30,0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,
0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,0x65,0x73,0x73,0x65,0x64,0x20,0x74,
0x61,0x72,0x67,0x65,0x74,0x2d,0x65,0x6e,0x76,0x20,0x6f,0x70,0x65,0x6e,0x67,0x6c,
0x0a,0x2f,0x2f,0x20,0x4f,0x70,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x50,0x72,0x6f,0x63,
0x65,0x73,0x73,0x65,0x64,0x20,0x65,0x6e,0x74,0x72,0x79,0x2d,0x70,0x6f,0x69,0x6e,
0x74,0x20,0x6d,0x61,0x69,0x6e,0x0a,0x23,0x6c,0x69,0x6e,0x65,0x20,0x31,0x0a,0x00,
0x05,0x00,0x04,0x00,0x05,0x00,0x00,0x00,0x6d,0x61,0x69,0x6e,0x00,0x00,0x00,0x00,
0x05,0x00,0x05,0x00,0x0b,0x00,0x00,0x00,0x66,0x72,0x61,0x67,0x43,0x6f,0x6c,0x6f,
0x72,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x0f,0x00,0x00,0x00,0x69,0x43,0x68,0x61,
0x6e,0x6e,0x65,0x6c,0x30,0x00,0x00,0x00,0x05,0x00,0x04,0x00,0x13,0x00,0x00,0x00,
0x74,0x65,0x78,0x55,0x56,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x16,0x00,0x00,0x00,
0x66,0x73,0x5f,0x70,0x61,0x72,0x61,0x6d,0x73,0x00,0x00,0x00,0x06,0x00,0x05,0x00,
0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x69,0x43,0x6f,0x6c,0x6f,0x72,0x00,0x00,
0x05,0x00,0x03,0x00,0x18,0x00,0x00,0x00,0x5f,0x32,0x34,0x00,0x47,0x00,0x04,0x00,
0x0b,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x0f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x0f,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x0f,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x13,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x00,0x05,0x00,
0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x47,0x00,0x03,0x00,0x16,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x18,0x00,0x00,0x00,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x00,0x04,0x00,
0x18,0x00,0x00,0x00,0x21,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x13,0x00,0x02,0x00,
0x03,0x00,0x00,0x00,0x21,0x00,0x03,0x00,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
0x16,0x00,0x03,0x00,0x08,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x17,0x00,0x04,0x00,
0x09,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x0a,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x0a,0x00,0x00,0x00,0x0b,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x19,0x00,0x09,0x00,
0x0c,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x1b,0x00,0x03,0x00,0x0d,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x0e,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x00,0x04,0x00,
0x11,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x20,0x00,0x04,0x00,
0x12,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x11,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,
0x12,0x00,0x00,0x00,0x13,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x1e,0x00,0x03,0x00,
0x16,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x17,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,0x16,0x00,0x00,0x00,0x3b,0x00,0x04,0x00,0x17,0x00,0x00,0x00,
0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x15,0x00,0x04,0x00,0x19,0x00,0x00,0x00,
0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x2b,0x00,0x04,0x00,0x19,0x00,0x00,0x00,
0x1a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x04,0x00,0x1b,0x00,0x00,0x00,
0x02,0x00,0x00,0x00,0x09,0x00,0x00,0x00,0x36,0x00,0x05,0x00,0x03,0x00,0x00,0x00,
0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xf8,0x00,0x02,0x00,
0x06,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x07,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x0d,0x00,0x00,0x00,0x10,0x00,0x00,0x00,
0x0f,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,0x11,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
0x13,0x00,0x00,0x00,0x57,0x00,0x05,0x00,0x09,0x00,0x00,0x00,0x15,0x00,0x00,0x00,
0x10,0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x41,0x00,0x05,0x00,0x1b,0x00,0x00,0x00,
0x1c,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x1a,0x00,0x00,0x00,0x3d,0x00,0x04,0x00,
0x09,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,0x1c,0x00,0x00,0x00,0x85,0x00,0x05,0x00,
0x09,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x15,0x00,0x00,0x00,0x1d,0x00,0x00,0x00,
0x3e,0x00,0x03,0x00,0x0b,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0xfd,0x00,0x01,0x00,
0x38,0x00,0x01,0x00,
};
#elif defined(SOKOL_DUMMY_BACKEND)
static const char _sgp_vs_source[] = "";
static const char _sgp_fs_source[] = "";
#else
#error "Please define one of SOKOL_GLCORE33, SOKOL_GLES2, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND!"
#endif
static sg_blend_state _sgp_blend_state(sgp_blend_mode blend_mode) {
sg_blend_state blend;
memset(&blend, 0, sizeof(sg_blend_state));
switch(blend_mode) {
case SGP_BLENDMODE_NONE:
blend.enabled = false;
blend.src_factor_rgb = SG_BLENDFACTOR_ONE;
blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO;
blend.op_rgb = SG_BLENDOP_ADD;
blend.src_factor_alpha = SG_BLENDFACTOR_ONE;
blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO;
blend.op_alpha = SG_BLENDOP_ADD;
break;
case SGP_BLENDMODE_BLEND:
blend.enabled = true;
blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
blend.op_rgb = SG_BLENDOP_ADD;
blend.src_factor_alpha = SG_BLENDFACTOR_ONE;
blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
blend.op_alpha = SG_BLENDOP_ADD;
break;
case SGP_BLENDMODE_ADD:
blend.enabled = true;
blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA;
blend.dst_factor_rgb = SG_BLENDFACTOR_ONE;
blend.op_rgb = SG_BLENDOP_ADD;
blend.src_factor_alpha = SG_BLENDFACTOR_ZERO;
blend.dst_factor_alpha = SG_BLENDFACTOR_ONE;
blend.op_alpha = SG_BLENDOP_ADD;