diff options
| author | Andre Weissflog <floooh@gmail.com> | 2022-11-16 18:35:00 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-16 18:35:00 +0100 |
| commit | 02f39b3f3fd07cf12403a80e8ef933aa27d08a99 (patch) | |
| tree | 5e7caea0ba46887c9ed5df27a5cd8be3097ad441 | |
| parent | bba1d39476abc719f8737f962d75ba590c37eeb8 (diff) | |
| parent | 18179b2d7d2a034a8962887707c4b1b27dbfd283 (diff) | |
Merge pull request #744 from floooh/sokol-debugtext-layers
Implement layered rendering for sokol_debugtext.h
...also some code cleanup in sokol_gl.h and sokol_spine.h.
| -rw-r--r-- | CHANGELOG.md | 8 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | tests/functional/sokol_debugtext_test.c | 109 | ||||
| -rw-r--r-- | tests/functional/sokol_gl_test.c | 96 | ||||
| -rw-r--r-- | util/sokol_debugtext.h | 324 | ||||
| -rw-r--r-- | util/sokol_gl.h | 146 | ||||
| -rw-r--r-- | util/sokol_spine.h | 88 |
7 files changed, 529 insertions, 244 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6284bebf..c07529aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Updates +- **16-Nov-2022**: Render layer support has been added to sokol_debugtext.h, + same general changes as in sokol_gl.h with two new functions: + sdtx_layer(layer_id) to select the layer to record text into, and + sdtx_draw_layer(layer_id) to draw the recorded text in that layer inside a + sokol-gfx render pass. The new sample [debugtext-layers-sapp](https://floooh.github.io/sokol-html5/debugtext-layers-sapp) demonstrates the feature together with + sokol-gl. + + - **11-Nov-2022**: sokol_gl.h has 2 new public API functions which enable layered rendering: sgl_layer(), sgl_draw_layer() (technically it's three functions: there's also sgl_context_draw_layer(), but that's just a variant of @@ -4,7 +4,7 @@ Simple [STB-style](https://github.com/nothings/stb/blob/master/docs/stb_howto.txt) cross-platform libraries for C and C++, written in C. -[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**11-Nov-2022** sokol_gl.h learned layered rendering) +[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**16-Nov-2022** sokol_debugtext.h learned layered rendering) [](/../../actions/workflows/main.yml) [](/../../actions/workflows/gen_bindings.yml) [](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [](https://github.com/floooh/sokol-odin/actions/workflows/main.yml) diff --git a/tests/functional/sokol_debugtext_test.c b/tests/functional/sokol_debugtext_test.c index ce1bb5e0..d2523502 100644 --- a/tests/functional/sokol_debugtext_test.c +++ b/tests/functional/sokol_debugtext_test.c @@ -57,11 +57,12 @@ UTEST(sokol_debugtext, default_init_shutdown) { T(_sdtx.cur_ctx->desc.color_format == 0); T(_sdtx.cur_ctx->desc.depth_format == 0); T(_sdtx.cur_ctx->desc.sample_count == 0); - T(_sdtx.cur_ctx->cur_vertex_ptr); - T(_sdtx.cur_ctx->max_vertex_ptr); - T(_sdtx.cur_ctx->vertices); - T(_sdtx.cur_ctx->vertices == _sdtx.cur_ctx->cur_vertex_ptr); - T(_sdtx.cur_ctx->max_vertex_ptr == (_sdtx.cur_ctx->vertices + _SDTX_DEFAULT_CHAR_BUF_SIZE * 6)); + T(_sdtx.cur_ctx->vertices.cap == _SDTX_DEFAULT_CHAR_BUF_SIZE * 6); + T(_sdtx.cur_ctx->vertices.next == 0); + T(_sdtx.cur_ctx->vertices.ptr); + T(_sdtx.cur_ctx->commands.cap == _SDTX_DEFAULT_MAX_COMMANDS); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr); T(_sdtx.cur_ctx->vbuf.id != 0); T(_sdtx.cur_ctx->pip.id != 0); TFLT(_sdtx.cur_ctx->canvas_size.x, 640.0f); @@ -112,7 +113,7 @@ UTEST(sokol_debugtext, init_with_params) { T(_sdtx.cur_ctx->desc.color_format == SG_PIXELFORMAT_RGBA8); T(_sdtx.cur_ctx->desc.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL); T(_sdtx.cur_ctx->desc.sample_count == 4); - T(_sdtx.cur_ctx->max_vertex_ptr == (_sdtx.cur_ctx->vertices + 256 * 6)); + T(_sdtx.cur_ctx->vertices.cap == (256 * 6)); TFLT(_sdtx.cur_ctx->canvas_size.x, 320.0f); TFLT(_sdtx.cur_ctx->canvas_size.y, 200.0f); TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 320.0f); @@ -144,9 +145,9 @@ UTEST(sokol_debugtext, make_destroy_context) { T(ctx->desc.color_format == SG_PIXELFORMAT_RGBA32F); T(ctx->desc.depth_format == 0); T(ctx->desc.sample_count == 2); - T(ctx->vertices); - T(ctx->cur_vertex_ptr == ctx->vertices); - T(ctx->max_vertex_ptr == ctx->vertices + 64 * 6); + T(ctx->vertices.ptr); + T(ctx->vertices.next == 0); + T(ctx->vertices.cap == (64 * 6)); TFLT(ctx->canvas_size.x, 1024.0f); TFLT(ctx->canvas_size.y, 768.0f); TFLT(ctx->glyph_size.x, 8.0f / 1024.0f); @@ -155,7 +156,7 @@ UTEST(sokol_debugtext, make_destroy_context) { sdtx_destroy_context(ctx_id); T(0 == _sdtx_lookup_context(ctx_id.id)); T(ctx->desc.char_buf_size == 0); - T(ctx->vertices == 0); + T(ctx->vertices.ptr == 0); shutdown(); } @@ -336,7 +337,7 @@ UTEST(sokol_debugtext, vertex_overflow) { sdtx_puts("1234567890"); sdtx_putr("1234567890", 5); sdtx_printf("Hello World %d!\n", 12); - T(_sdtx.cur_ctx->cur_vertex_ptr == _sdtx.cur_ctx->max_vertex_ptr); + T(_sdtx.cur_ctx->vertices.next == _sdtx.cur_ctx->vertices.cap); shutdown(); } @@ -399,7 +400,7 @@ UTEST(sokol_debugtext, rewind_after_draw) { sdtx_font(3); T(_sdtx.cur_ctx->cur_font == 3); sdtx_printf("Hello World!\n"); - T(_sdtx.cur_ctx->cur_vertex_ptr != _sdtx.cur_ctx->vertices); + T(_sdtx.cur_ctx->vertices.next != 0); sg_begin_default_pass(&(sg_pass_action){ 0 }, 256, 256); sdtx_draw(); sg_end_pass(); @@ -411,21 +412,21 @@ UTEST(sokol_debugtext, rewind_after_draw) { TFLT(_sdtx.cur_ctx->pos.x, 0); TFLT(_sdtx.cur_ctx->pos.x, 0); T(_sdtx.cur_ctx->cur_font == 0); - T(_sdtx.cur_ctx->cur_vertex_ptr == _sdtx.cur_ctx->vertices); + T(_sdtx.cur_ctx->vertices.next == 0); shutdown(); } UTEST(sokol_debugtext, putr) { // test if sdtx_putr() draws the right amount of characters init(); - _sdtx_vertex_t* start_ptr = _sdtx.cur_ctx->cur_vertex_ptr; + int start_index = _sdtx.cur_ctx->vertices.next; sdtx_putr("Hello World!", 5); - T((5 * 6) == (_sdtx.cur_ctx->cur_vertex_ptr - start_ptr)); + T((5 * 6) == (_sdtx.cur_ctx->vertices.next - start_index)); - start_ptr = _sdtx.cur_ctx->cur_vertex_ptr; + start_index = _sdtx.cur_ctx->vertices.next; sdtx_putr("Hello!\n\n\n\n\n\n\n\n\n\n\n", 10); // NOTE: the \n's don't result in rendered vertices - T((6 * 6) == (_sdtx.cur_ctx->cur_vertex_ptr - start_ptr)); + T((6 * 6) == (_sdtx.cur_ctx->vertices.next - start_index)); shutdown(); } @@ -434,3 +435,77 @@ UTEST(sokol_debugtext, default_context) { T(sdtx_default_context().id == SDTX_DEFAULT_CONTEXT.id); shutdown(); } + +// switching layers without any text inbetween should not advance the current draw command +UTEST(sokol_debug_text, empty_layers) { + init(); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); + sdtx_layer(1); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 1); + sdtx_layer(2); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 2); + sdtx_layer(0); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); + shutdown(); +} + +// switching layers with text inbetween should advance the current draw command +UTEST(sokol_debug_text, non_empty_layers) { + init(); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); + T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0); + T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == 0); + sdtx_puts("123"); + T(_sdtx.cur_ctx->commands.next == 1); + T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0); + T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0); + T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == (3 * 6)); + sdtx_layer(1); + sdtx_puts("1234"); + T(_sdtx.cur_ctx->commands.next == 2); + T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1); + T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6)); + T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (4 * 6)); + // switching to same layer should not start a new draw commands + sdtx_layer(1); + sdtx_puts("12345"); + T(_sdtx.cur_ctx->commands.next == 2); + T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1); + T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6)); + T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (9 * 6)); + sdtx_layer(0); + sdtx_puts("123456"); + T(_sdtx.cur_ctx->commands.next == 3); + T(_sdtx.cur_ctx->commands.ptr[2].layer_id == 0); + T(_sdtx.cur_ctx->commands.ptr[2].first_vertex == (12 * 6)); + T(_sdtx.cur_ctx->commands.ptr[2].num_vertices == (6 * 6)); + shutdown(); +} + +UTEST(sokol_debug_text, command_buffer_overflow) { + init_with(&(sdtx_desc_t){ + .context = { + .max_commands = 4 + } + }); + sdtx_puts("0"); + T(_sdtx.cur_ctx->commands.next == 1); + sdtx_layer(1); + sdtx_puts("1"); + T(_sdtx.cur_ctx->commands.next == 2); + sdtx_layer(2); + sdtx_puts("2"); + T(_sdtx.cur_ctx->commands.next == 3); + sdtx_layer(3); + sdtx_puts("3"); + T(_sdtx.cur_ctx->commands.next == 4); + // from here on should fail + sdtx_layer(4); + sdtx_puts("4"); + T(_sdtx.cur_ctx->commands.next == 4); +}
\ No newline at end of file diff --git a/tests/functional/sokol_gl_test.c b/tests/functional/sokol_gl_test.c index 656181ed..1310e440 100644 --- a/tests/functional/sokol_gl_test.c +++ b/tests/functional/sokol_gl_test.c @@ -26,15 +26,15 @@ UTEST(sokol_gl, default_init_shutdown) { T(_sgl.def_ctx_id.id == SGL_DEFAULT_CONTEXT.id); T(_sgl.cur_ctx_id.id == _sgl.def_ctx_id.id); T(_sgl.cur_ctx); - T(_sgl.cur_ctx->num_vertices == 65536); - T(_sgl.cur_ctx->num_commands == 16384); - T(_sgl.cur_ctx->num_uniforms == 16384); - T(_sgl.cur_ctx->cur_vertex == 0); - T(_sgl.cur_ctx->cur_command == 0); - T(_sgl.cur_ctx->cur_uniform == 0); - T(_sgl.cur_ctx->vertices != 0); - T(_sgl.cur_ctx->uniforms != 0); - T(_sgl.cur_ctx->commands != 0); + T(_sgl.cur_ctx->vertices.cap == 65536); + T(_sgl.cur_ctx->commands.cap == 16384); + T(_sgl.cur_ctx->uniforms.cap == 16384); + T(_sgl.cur_ctx->vertices.next == 0); + T(_sgl.cur_ctx->commands.next == 0); + T(_sgl.cur_ctx->uniforms.next == 0); + T(_sgl.cur_ctx->vertices.ptr != 0); + T(_sgl.cur_ctx->uniforms.ptr != 0); + T(_sgl.cur_ctx->commands.ptr != 0); T(_sgl.cur_ctx->error == SGL_NO_ERROR); T(!_sgl.cur_ctx->in_begin); T(_sgl.cur_ctx->def_pip.id != SG_INVALID_ID); @@ -49,42 +49,42 @@ UTEST(sokol_gl, default_init_shutdown) { UTEST(sokol_gl, viewport) { init(); sgl_viewport(1, 2, 3, 4, true); - T(_sgl.cur_ctx->cur_command == 1); - T(_sgl.cur_ctx->commands[0].cmd == SGL_COMMAND_VIEWPORT); - T(_sgl.cur_ctx->commands[0].args.viewport.x == 1); - T(_sgl.cur_ctx->commands[0].args.viewport.y == 2); - T(_sgl.cur_ctx->commands[0].args.viewport.w == 3); - T(_sgl.cur_ctx->commands[0].args.viewport.h == 4); - T(_sgl.cur_ctx->commands[0].args.viewport.origin_top_left); + T(_sgl.cur_ctx->commands.next == 1); + T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_VIEWPORT); + T(_sgl.cur_ctx->commands.ptr[0].args.viewport.x == 1); + T(_sgl.cur_ctx->commands.ptr[0].args.viewport.y == 2); + T(_sgl.cur_ctx->commands.ptr[0].args.viewport.w == 3); + T(_sgl.cur_ctx->commands.ptr[0].args.viewport.h == 4); + T(_sgl.cur_ctx->commands.ptr[0].args.viewport.origin_top_left); sgl_viewport(5, 6, 7, 8, false); - T(_sgl.cur_ctx->cur_command == 2); - T(_sgl.cur_ctx->commands[1].cmd == SGL_COMMAND_VIEWPORT); - T(_sgl.cur_ctx->commands[1].args.viewport.x == 5); - T(_sgl.cur_ctx->commands[1].args.viewport.y == 6); - T(_sgl.cur_ctx->commands[1].args.viewport.w == 7); - T(_sgl.cur_ctx->commands[1].args.viewport.h == 8); - T(!_sgl.cur_ctx->commands[1].args.viewport.origin_top_left); + T(_sgl.cur_ctx->commands.next == 2); + T(_sgl.cur_ctx->commands.ptr[1].cmd == SGL_COMMAND_VIEWPORT); + T(_sgl.cur_ctx->commands.ptr[1].args.viewport.x == 5); + T(_sgl.cur_ctx->commands.ptr[1].args.viewport.y == 6); + T(_sgl.cur_ctx->commands.ptr[1].args.viewport.w == 7); + T(_sgl.cur_ctx->commands.ptr[1].args.viewport.h == 8); + T(!_sgl.cur_ctx->commands.ptr[1].args.viewport.origin_top_left); shutdown(); } UTEST(sokol_gl, scissor_rect) { init(); sgl_scissor_rect(10, 20, 30, 40, true); - T(_sgl.cur_ctx->cur_command == 1); - T(_sgl.cur_ctx->commands[0].cmd == SGL_COMMAND_SCISSOR_RECT); - T(_sgl.cur_ctx->commands[0].args.scissor_rect.x == 10); - T(_sgl.cur_ctx->commands[0].args.scissor_rect.y == 20); - T(_sgl.cur_ctx->commands[0].args.scissor_rect.w == 30); - T(_sgl.cur_ctx->commands[0].args.scissor_rect.h == 40); - T(_sgl.cur_ctx->commands[0].args.scissor_rect.origin_top_left); + T(_sgl.cur_ctx->commands.next == 1); + T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_SCISSOR_RECT); + T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.x == 10); + T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.y == 20); + T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.w == 30); + T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.h == 40); + T(_sgl.cur_ctx->commands.ptr[0].args.scissor_rect.origin_top_left); sgl_scissor_rect(50, 60, 70, 80, false); - T(_sgl.cur_ctx->cur_command == 2); - T(_sgl.cur_ctx->commands[1].cmd == SGL_COMMAND_SCISSOR_RECT); - T(_sgl.cur_ctx->commands[1].args.scissor_rect.x == 50); - T(_sgl.cur_ctx->commands[1].args.scissor_rect.y == 60); - T(_sgl.cur_ctx->commands[1].args.scissor_rect.w == 70); - T(_sgl.cur_ctx->commands[1].args.scissor_rect.h == 80); - T(!_sgl.cur_ctx->commands[1].args.scissor_rect.origin_top_left); + T(_sgl.cur_ctx->commands.next == 2); + T(_sgl.cur_ctx->commands.ptr[1].cmd == SGL_COMMAND_SCISSOR_RECT); + T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.x == 50); + T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.y == 60); + T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.w == 70); + T(_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.h == 80); + T(!_sgl.cur_ctx->commands.ptr[1].args.scissor_rect.origin_top_left); shutdown(); } @@ -111,14 +111,14 @@ UTEST(sokol_gl, begin_end) { sgl_v3f(7.0f, 8.0f, 9.0f); sgl_end(); T(_sgl.cur_ctx->base_vertex == 0); - T(_sgl.cur_ctx->cur_vertex == 3); - T(_sgl.cur_ctx->cur_command == 1); - T(_sgl.cur_ctx->cur_uniform == 1); - T(_sgl.cur_ctx->commands[0].cmd == SGL_COMMAND_DRAW); - T(_sgl.cur_ctx->commands[0].args.draw.pip.id == _sgl_pipeline_at(_sgl.cur_ctx->def_pip.id)->pip[SGL_PRIMITIVETYPE_TRIANGLES].id); - T(_sgl.cur_ctx->commands[0].args.draw.base_vertex == 0); - T(_sgl.cur_ctx->commands[0].args.draw.num_vertices == 3); - T(_sgl.cur_ctx->commands[0].args.draw.uniform_index == 0); + T(_sgl.cur_ctx->vertices.next == 3); + T(_sgl.cur_ctx->commands.next == 1); + T(_sgl.cur_ctx->uniforms.next == 1); + T(_sgl.cur_ctx->commands.ptr[0].cmd == SGL_COMMAND_DRAW); + T(_sgl.cur_ctx->commands.ptr[0].args.draw.pip.id == _sgl_pipeline_at(_sgl.cur_ctx->def_pip.id)->pip[SGL_PRIMITIVETYPE_TRIANGLES].id); + T(_sgl.cur_ctx->commands.ptr[0].args.draw.base_vertex == 0); + T(_sgl.cur_ctx->commands.ptr[0].args.draw.num_vertices == 3); + T(_sgl.cur_ctx->commands.ptr[0].args.draw.uniform_index == 0); shutdown(); } @@ -223,9 +223,9 @@ UTEST(sokol_gl, make_destroy_contexts) { // creating a context should not change the current context T(ctx.id != _sgl.cur_ctx_id.id); sgl_set_context(ctx); - T(_sgl.cur_ctx->num_vertices == 1024); - T(_sgl.cur_ctx->num_commands == 256); - T(_sgl.cur_ctx->num_uniforms == 256); + T(_sgl.cur_ctx->vertices.cap == 1024); + T(_sgl.cur_ctx->commands.cap == 256); + T(_sgl.cur_ctx->uniforms.cap == 256); T(ctx.id == _sgl.cur_ctx_id.id); T(sgl_get_context().id == ctx.id); sgl_set_context(SGL_DEFAULT_CONTEXT); diff --git a/util/sokol_debugtext.h b/util/sokol_debugtext.h index 89f141db..85321f3a 100644 --- a/util/sokol_debugtext.h +++ b/util/sokol_debugtext.h @@ -93,6 +93,11 @@ be active right after sdtx_setup(), or when calling sdtx_set_context(SDTX_DEFAULT_CONTEXT): + .max_commands (default: 4096) + The max number of render commands that can be recorded + into the internal command buffer. This directly translates + to the number of render layer changes in a single frame. + .char_buf_size (default: 4096) The number of characters that can be rendered per frame in this context, defines the size of an internal fixed-size vertex @@ -220,14 +225,36 @@ \n - carriage return + line feed (same as stdx_crlf()) \t - a tab character + --- You can 'record' text into render layers, this allows to mix/interleave + sokol-debugtext rendering with other rendering operations inside + sokol-gfx render passes. To start recording text into a different render + layer, call: + + sdtx_layer(int layer_id) + + ...outside a sokol-gfx render pass. + --- finally, from within a sokol-gfx render pass, call: sdtx_draw() - ...to actually render the text. Calling sdtx_draw() will also rewind - the text context: + ...for non-layered rendering, or to draw a specific layer: + + sdtx_draw_layer(int layer_id) + + NOTE that sdtx_draw() is equivalent to: - - the internal vertex buffer pointer is reset to the beginning + sdtx_draw_layer(0) + + ...so sdtx_draw() will *NOT* render all text layers, instead it will + only render the 'default layer' 0. + + --- at the end of a frame (defined by the call to sg_commit()), sokol-debugtext + will rewind all contexts: + + - the internal vertex index is set to 0 + - the internal command index is set to 0 + - the current layer id is set to 0 - the current font is set to 0 - the cursor position is reset @@ -268,7 +295,8 @@ - the origin position - the current cursor position - the current tab width - - and the current color + - the current color + - and the current layer-id You can get the currently active context with: @@ -291,6 +319,12 @@ If a context is set as active that no longer exists, all sokol-debugtext functions that require an active context will silently fail. + You can directly draw the recorded text in a specific context without + setting the active context: + + sdtx_context_draw(ctx) + sdtx_context_draw_layer(ctx, layer_id) + USING YOUR OWN FONT DATA ======================== @@ -540,6 +574,7 @@ typedef struct sdtx_font_desc_t { of text. */ typedef struct sdtx_context_desc_t { + int max_commands; // max number of draw commands, each layer transition counts as a command, default: 4096 int char_buf_size; // max number of characters rendered in one frame, default: 4096 float canvas_width; // the initial virtual canvas width, default: 640 float canvas_height; // the initial virtual canvas height, default: 400 @@ -618,8 +653,14 @@ SOKOL_DEBUGTEXT_API_DECL void sdtx_set_context(sdtx_context ctx); SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_get_context(void); SOKOL_DEBUGTEXT_API_DECL sdtx_context sdtx_default_context(void); -/* draw and rewind the current context */ +/* drawing functions (call inside sokol-gfx render pass) */ SOKOL_DEBUGTEXT_API_DECL void sdtx_draw(void); +SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw(sdtx_context ctx); +SOKOL_DEBUGTEXT_API_DECL void sdtx_draw_layer(int layer_id); +SOKOL_DEBUGTEXT_API_DECL void sdtx_context_draw_layer(sdtx_context ctx, int layer_id); + +/* switch render layer */ +SOKOL_DEBUGTEXT_API_DECL void sdtx_layer(int layer_id); /* switch to a different font */ SOKOL_DEBUGTEXT_API_DECL void sdtx_font(int font_index); @@ -718,9 +759,10 @@ inline sdtx_context sdtx_make_context(const sdtx_context_desc_t& desc) { return #define _sdtx_def(val, def) (((val) == 0) ? (def) : (val)) #define _SDTX_INIT_COOKIE (0xACBAABCA) +#define _SDTX_DEFAULT_MAX_COMMANDS (4096) #define _SDTX_DEFAULT_CONTEXT_POOL_SIZE (8) -#define _SDTX_DEFAULT_CHAR_BUF_SIZE (1<<12) -#define _SDTX_DEFAULT_PRINTF_BUF_SIZE (1<<12) +#define _SDTX_DEFAULT_CHAR_BUF_SIZE (4096) +#define _SDTX_DEFAULT_PRINTF_BUF_SIZE (4096) #define _SDTX_DEFAULT_CANVAS_WIDTH (640) #define _SDTX_DEFAULT_CANVAS_HEIGHT (480) #define _SDTX_DEFAULT_TAB_WIDTH (4) @@ -3479,14 +3521,30 @@ typedef struct { } _sdtx_vertex_t; typedef struct { + int layer_id; + int first_vertex; + int num_vertices; +} _sdtx_command_t; + +typedef struct { _sdtx_slot_t slot; sdtx_context_desc_t desc; - _sdtx_vertex_t* cur_vertex_ptr; - const _sdtx_vertex_t* max_vertex_ptr; - _sdtx_vertex_t* vertices; + uint32_t frame_id; + uint32_t update_frame_id; + struct { + int cap; + int next; + _sdtx_vertex_t* ptr; + } vertices; + struct { + int cap; + int next; + _sdtx_command_t* ptr; + } commands; sg_buffer vbuf; sg_pipeline pip; int cur_font; + int cur_layer_id; _sdtx_float2_t canvas_size; _sdtx_float2_t glyph_size; _sdtx_float2_t origin; @@ -3704,6 +3762,7 @@ static sdtx_context _sdtx_alloc_context(void) { static sdtx_context_desc_t _sdtx_context_desc_defaults(const sdtx_context_desc_t* desc) { sdtx_context_desc_t res = *desc; + res.max_commands = _sdtx_def(res.max_commands, _SDTX_DEFAULT_MAX_COMMANDS); res.char_buf_size = _sdtx_def(res.char_buf_size, _SDTX_DEFAULT_CHAR_BUF_SIZE); res.canvas_width = _sdtx_def(res.canvas_width, _SDTX_DEFAULT_CANVAS_WIDTH); res.canvas_height = _sdtx_def(res.canvas_height, _SDTX_DEFAULT_CANVAS_HEIGHT); @@ -3715,6 +3774,30 @@ static sdtx_context_desc_t _sdtx_context_desc_defaults(const sdtx_context_desc_t return res; } +static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id); +static void _sdtx_rewind(_sdtx_context_t* ctx) { + SOKOL_ASSERT(ctx); + ctx->frame_id++; + ctx->vertices.next = 0; + ctx->commands.next = 0; + _sdtx_set_layer(ctx, 0); + ctx->cur_font = 0; + ctx->pos.x = 0.0f; + ctx->pos.y = 0.0f; +} + +static void _sdtx_commit_listener(void* userdata) { + _sdtx_context_t* ctx = _sdtx_lookup_context((uint32_t)(uintptr_t)userdata); + if (ctx) { + _sdtx_rewind(ctx); + } +} + +static sg_commit_listener _sdtx_make_commit_listener(_sdtx_context_t* ctx) { + sg_commit_listener listener = { _sdtx_commit_listener, (void*)(uintptr_t)(ctx->slot.id) }; + return listener; +} + static void _sdtx_init_context(sdtx_context ctx_id, const sdtx_context_desc_t* in_desc) { sg_push_debug_group("sokol-debugtext"); @@ -3722,12 +3805,16 @@ static void _sdtx_init_context(sdtx_context ctx_id, const sdtx_context_desc_t* i _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); SOKOL_ASSERT(ctx); ctx->desc = _sdtx_context_desc_defaults(in_desc); + // NOTE: frame_id must be non-zero, so that updates trigger in first frame + ctx->frame_id = 1; + + ctx->vertices.cap = 6 * ctx->desc.char_buf_size; + const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sdtx_vertex_t); + ctx->vertices.ptr = (_sdtx_vertex_t*) _sdtx_malloc(vbuf_size); - const int max_vertices = 6 * ctx->desc.char_buf_size; - const size_t vbuf_size = (size_t)max_vertices * sizeof(_sdtx_vertex_t); - ctx->vertices = (_sdtx_vertex_t*) _sdtx_malloc(vbuf_size); - ctx->cur_vertex_ptr = ctx->vertices; - ctx->max_vertex_ptr = ctx->vertices + max_vertices; + ctx->commands.cap = ctx->desc.max_commands; + ctx->commands.ptr = (_sdtx_command_t*) _sdtx_malloc((size_t)ctx->commands.cap * sizeof(_sdtx_command_t)); + _sdtx_set_layer(ctx, 0); sg_buffer_desc vbuf_desc; _sdtx_clear(&vbuf_desc, sizeof(vbuf_desc)); @@ -3765,21 +3852,33 @@ static void _sdtx_init_context(sdtx_context ctx_id, const sdtx_context_desc_t* i ctx->tab_width = (float) ctx->desc.tab_width; ctx->color = _SDTX_DEFAULT_COLOR; + if (!sg_add_commit_listener(_sdtx_make_commit_listener(ctx))) { + // FIXME: this should actually result in an invalid context, + // fix this when proper error logging/reporting is added + SDTX_LOG("sokol_debugtext.h: failed to add sokol-gfx commit listener"); + } sg_pop_debug_group(); } static void _sdtx_destroy_context(sdtx_context ctx_id) { _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); if (ctx) { - if (ctx->vertices) { - _sdtx_free(ctx->vertices); - ctx->vertices = 0; - ctx->cur_vertex_ptr = 0; - ctx->max_vertex_ptr = 0; + if (ctx->vertices.ptr) { + _sdtx_free(ctx->vertices.ptr); + ctx->vertices.ptr = 0; + ctx->vertices.cap = 0; + ctx->vertices.next = 0; + } + if (ctx->commands.ptr) { + _sdtx_free(ctx->commands.ptr); + ctx->commands.ptr = 0; + ctx->commands.cap = 0; + ctx->commands.next = 0; } sg_push_debug_group("sokol_debugtext"); sg_destroy_buffer(ctx->vbuf); sg_destroy_pipeline(ctx->pip); + sg_remove_commit_listener(_sdtx_make_commit_listener(ctx)); sg_pop_debug_group(); _sdtx_clear(ctx, sizeof(*ctx)); _sdtx_pool_free_index(&_sdtx.context_pool.pool, _sdtx_slot_index(ctx_id.id)); @@ -3869,7 +3968,7 @@ static void _sdtx_setup_common(void) { /* unpack font data */ memset(_sdtx.font_pixels, 0xFF, sizeof(_sdtx.font_pixels)); - const int unpacked_font_size = 256 * 8 * 8; + const int unpacked_font_size = (int) (sizeof(_sdtx.font_pixels) / SDTX_MAX_FONTS); for (int i = 0; i < SDTX_MAX_FONTS; i++) { if (_sdtx.desc.fonts[i].data.ptr) { _sdtx_unpack_font(&_sdtx.desc.fonts[i], &_sdtx.font_pixels[i * unpacked_font_size]); @@ -3887,6 +3986,7 @@ static void _sdtx_setup_common(void) { img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; img_desc.data.subimage[0][0] = SG_RANGE(_sdtx.font_pixels); + img_desc.label = "sdtx-font-texture"; _sdtx.font_img = sg_make_image(&img_desc); SOKOL_ASSERT(SG_INVALID_ID != _sdtx.font_img.id); @@ -3904,17 +4004,17 @@ static void _sdtx_discard_common(void) { sg_pop_debug_group(); } -static inline uint32_t _sdtx_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { +static uint32_t _sdtx_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); } -static inline float _sdtx_clamp(float v, float lo, float hi) { +static float _sdtx_clamp(float v, float lo, float hi) { if (v < lo) return lo; else if (v > hi) return hi; else return v; } -static inline uint32_t _sdtx_pack_rgbaf(float r, float g, float b, float a) { +static uint32_t _sdtx_pack_rgbaf(float r, float g, float b, float a) { uint8_t r_u8 = (uint8_t) (_sdtx_clamp(r, 0.0f, 1.0f) * 255.0f); uint8_t g_u8 = (uint8_t) (_sdtx_clamp(g, 0.0f, 1.0f) * 255.0f); uint8_t b_u8 = (uint8_t) (_sdtx_clamp(b, 0.0f, 1.0f) * 255.0f); @@ -3922,7 +4022,7 @@ static inline uint32_t _sdtx_pack_rgbaf(float r, float g, float b, float a) { return _sdtx_pack_rgbab(r_u8, g_u8, b_u8, a_u8); } -static inline void _sdtx_ctrl_char(_sdtx_context_t* ctx, uint8_t c) { +static void _sdtx_ctrl_char(_sdtx_context_t* ctx, uint8_t c) { switch (c) { case '\r': ctx->pos.x = 0.0f; @@ -3940,31 +4040,88 @@ static inline void _sdtx_ctrl_char(_sdtx_context_t* ctx, uint8_t c) { } } -static inline void _sdtx_draw_char(_sdtx_context_t* ctx, uint8_t c) { - if ((ctx->cur_vertex_ptr + 6) <= ctx->max_vertex_ptr) { +static _sdtx_vertex_t* _sdtx_next_vertex(_sdtx_context_t* ctx) { + if ((ctx->vertices.next + 6) <= ctx->vertices.cap) { + _sdtx_vertex_t* vx = &ctx->vertices.ptr[ctx->vertices.next]; + ctx->vertices.next += 6; + return vx; + } + else { + return 0; + } +} + +static _sdtx_command_t* _sdtx_cur_command(_sdtx_context_t* ctx) { + if (ctx->commands.next > 0) { + return &ctx->commands.ptr[ctx->commands.next - 1]; + } + else { + return 0; + } +} + +static _sdtx_command_t* _sdtx_next_command(_sdtx_context_t* ctx) { + if (ctx->commands.next < ctx->commands.cap) { + return &ctx->commands.ptr[ctx->commands.next++]; + } + else { + SDTX_LOG("sokol_debugtext.h: command buffer full"); + return 0; + } +} + +static void _sdtx_set_layer(_sdtx_context_t* ctx, int layer_id) { + ctx->cur_layer_id = layer_id; + _sdtx_command_t* cur_cmd = _sdtx_cur_command(ctx); + if (cur_cmd) { + if ((cur_cmd->num_vertices == 0) || (cur_cmd->layer_id == layer_id)) { + // no vertices recorded in current draw command, or layer hasn't changed, can just reuse this + cur_cmd->layer_id = layer_id; + } + else { + // layer has changed, need to start a new draw command + _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); + if (next_cmd) { + next_cmd->layer_id = layer_id; + next_cmd->first_vertex = cur_cmd->first_vertex + cur_cmd->num_vertices; + next_cmd->num_vertices = 0; + } + } + } + else { + // first draw command in frame + _sdtx_command_t* next_cmd = _sdtx_next_command(ctx); + if (next_cmd) { + next_cmd->layer_id = layer_id; + next_cmd->first_vertex = 0; + next_cmd->num_vertices = 0; + } + } +} + +static void _sdtx_render_char(_sdtx_context_t* ctx, uint8_t c) { + _sdtx_vertex_t* vx = _sdtx_next_vertex(ctx); + _sdtx_command_t* cmd = _sdtx_cur_command(ctx); + if (vx && cmd) { + // update vertex count in current draw command + cmd->num_vertices += 6; + const float x0 = (ctx->origin.x + ctx->pos.x) * ctx->glyph_size.x; const float y0 = (ctx->origin.y + ctx->pos.y) * ctx->glyph_size.y; const float x1 = x0 + ctx->glyph_size.x; const float y1 = y0 + ctx->glyph_size.y; // glyph width and heigth in font texture space + // NOTE: the '+1' and '-2' fixes texture bleeding into the neighboring font texture cell const uint16_t uvw = 0x10000 / 0x100; const uint16_t uvh = 0x10000 / SDTX_MAX_FONTS; - const uint16_t u0 = ((uint16_t)c) * uvw; - const uint16_t v0 = ((uint16_t)ctx->cur_font) * uvh; - uint16_t u1 = u0 + uvw; - uint16_t v1 = v0 + uvh; - if (u1 == 0x0000) { - u1 = 0xFFFF; - } - if (v1 == 0x0000) { - v1 = 0xFFFF; - } + const uint16_t u0 = (((uint16_t)c) * uvw) + 1; + const uint16_t v0 = (((uint16_t)ctx->cur_font) * uvh) + 1; + uint16_t u1 = (u0 + uvw) - 2; + uint16_t v1 = (v0 + uvh) - 2; const uint32_t color = ctx->color; // write 6 vertices - _sdtx_vertex_t* vx = ctx->cur_vertex_ptr; - vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; vx->x=x1; vx->y=y0; vx->u = u1; vx->v = v0; vx->color = color; vx++; vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; @@ -3972,22 +4129,51 @@ static inline void _sdtx_draw_char(_sdtx_context_t* ctx, uint8_t c) { vx->x=x0; vx->y=y0; vx->u = u0; vx->v = v0; vx->color = color; vx++; vx->x=x1; vx->y=y1; vx->u = u1; vx->v = v1; vx->color = color; vx++; vx->x=x0; vx->y=y1; vx->u = u0; vx->v = v1; vx->color = color; vx++; - - ctx->cur_vertex_ptr = vx; } ctx->pos.x += 1.0f; } -static inline void _sdtx_put_char(_sdtx_context_t* ctx, char c) { +static void _sdtx_put_char(_sdtx_context_t* ctx, char c) { uint8_t c_u8 = (uint8_t)c; if (c_u8 <= 32) { _sdtx_ctrl_char(ctx, c_u8); } else { - _sdtx_draw_char(ctx, c_u8); + _sdtx_render_char(ctx, c_u8); } } +SOKOL_API_IMPL void _sdtx_draw_layer(_sdtx_context_t* ctx, int layer_id) { + SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); + SOKOL_ASSERT(ctx); + if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { + sg_push_debug_group("sokol-debugtext"); + + if (ctx->update_frame_id != ctx->frame_id) { + ctx->update_frame_id = ctx->frame_id; + const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sdtx_vertex_t) }; + sg_update_buffer(ctx->vbuf, &range); + } + + sg_apply_pipeline(ctx->pip); + sg_bindings bindings; + _sdtx_clear(&bindings, sizeof(bindings)); + bindings.vertex_buffers[0] = ctx->vbuf; + bindings.fs_images[0] = _sdtx.font_img; + sg_apply_bindings(&bindings); + for (int cmd_index = 0; cmd_index < ctx->commands.next; cmd_index++) { + const _sdtx_command_t* cmd = &ctx->commands.ptr[cmd_index]; + if (cmd->layer_id != layer_id) { + continue; + } + SOKOL_ASSERT((cmd->num_vertices % 6) == 0); + sg_draw(cmd->first_vertex, cmd->num_vertices, 1); + } + sg_pop_debug_group(); + } +} + + static sdtx_desc_t _sdtx_desc_defaults(const sdtx_desc_t* desc) { SOKOL_ASSERT((desc->allocator.alloc && desc->allocator.free) || (!desc->allocator.alloc && !desc->allocator.free)); sdtx_desc_t res = *desc; @@ -4106,6 +4292,14 @@ SOKOL_API_IMPL sdtx_context sdtx_default_context(void) { return SDTX_DEFAULT_CONTEXT; } +SOKOL_API_IMPL void sdtx_layer(int layer_id) { + SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); + _sdtx_context_t* ctx = _sdtx.cur_ctx; + if (ctx) { + _sdtx_set_layer(ctx, layer_id); + } +} + SOKOL_API_IMPL void sdtx_font(int font_index) { SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); SOKOL_ASSERT((font_index >= 0) && (font_index < SDTX_MAX_FONTS)); @@ -4308,27 +4502,31 @@ SOKOL_API_IMPL void sdtx_draw(void) { SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); _sdtx_context_t* ctx = _sdtx.cur_ctx; if (ctx) { - const int num_verts = (int) (ctx->cur_vertex_ptr - ctx->vertices); - if (num_verts > 0) { - SOKOL_ASSERT((num_verts % 6) == 0); - sg_push_debug_group("sokol-debugtext"); - const sg_range range = { ctx->vertices, (size_t)num_verts * sizeof(_sdtx_vertex_t) }; - int vbuf_offset = sg_append_buffer(ctx->vbuf, &range); - sg_apply_pipeline(ctx->pip); - sg_bindings bindings; - _sdtx_clear(&bindings, sizeof(bindings)); - bindings.vertex_buffers[0] = ctx->vbuf; - bindings.vertex_buffer_offsets[0] = vbuf_offset; - bindings.fs_images[0] = _sdtx.font_img; - sg_apply_bindings(&bindings); - sg_draw(0, num_verts, 1); - sg_pop_debug_group(); - } - ctx->cur_vertex_ptr = ctx->vertices; - ctx->cur_font = 0; - ctx->pos.x = 0.0f; - ctx->pos.y = 0.0f; + _sdtx_draw_layer(ctx, 0); + } +} + +SOKOL_API_IMPL void sdtx_context_draw(sdtx_context ctx_id) { + SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); + _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); + if (ctx) { + _sdtx_draw_layer(ctx, 0); } } +SOKOL_API_IMPL void sdtx_draw_layer(int layer_id) { + SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); + _sdtx_context_t* ctx = _sdtx.cur_ctx; + if (ctx) { + _sdtx_draw_layer(ctx, layer_id); + } +} + +SOKOL_API_IMPL void sdtx_context_draw_layer(sdtx_context ctx_id, int layer_id) { + SOKOL_ASSERT(_SDTX_INIT_COOKIE == _sdtx.init_cookie); + _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id); + if (ctx) { + _sdtx_draw_layer(ctx, layer_id); + } +} #endif /* SOKOL_DEBUGTEXT_IMPL */ diff --git a/util/sokol_gl.h b/util/sokol_gl.h index af2ac3e6..eeb0ad70 100644 --- a/util/sokol_gl.h +++ b/util/sokol_gl.h @@ -2321,16 +2321,21 @@ typedef struct { sgl_context_desc_t desc; uint32_t frame_id; uint32_t update_frame_id; - - int num_vertices; - int num_uniforms; - int num_commands; - int cur_vertex; - int cur_uniform; - int cur_command; - _sgl_vertex_t* vertices; - _sgl_uniform_t* uniforms; - _sgl_command_t* commands; + struct { + int cap; + int next; + _sgl_vertex_t* ptr; + } vertices; + struct { + int cap; + int next; + _sgl_uniform_t* ptr; + } uniforms; + struct { + int cap; + int next; + _sgl_command_t* ptr; + } commands; /* state tracking */ int base_vertex; @@ -2483,9 +2488,9 @@ static void _sgl_pool_free_index(_sgl_pool_t* pool, int slot_index) { static void _sgl_reset_context(_sgl_context_t* ctx) { SOKOL_ASSERT(ctx); - SOKOL_ASSERT(0 == ctx->vertices); - SOKOL_ASSERT(0 == ctx->uniforms); - SOKOL_ASSERT(0 == ctx->commands); + SOKOL_ASSERT(0 == ctx->vertices.ptr); + SOKOL_ASSERT(0 == ctx->uniforms.ptr); + SOKOL_ASSERT(0 == ctx->commands.ptr); _sgl_clear(ctx, sizeof(_sgl_context_t)); } @@ -2763,18 +2768,18 @@ static void _sgl_init_context(sgl_context ctx_id, const sgl_context_desc_t* in_d ctx->cur_img = _sgl.def_img; // allocate buffers and pools - ctx->num_vertices = ctx->desc.max_vertices; - ctx->num_commands = ctx->num_uniforms = ctx->desc.max_commands; - ctx->vertices = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->num_vertices * sizeof(_sgl_vertex_t)); - ctx->uniforms = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->num_uniforms * sizeof(_sgl_uniform_t)); - ctx->commands = (_sgl_command_t*) _sgl_malloc((size_t)ctx->num_commands * sizeof(_sgl_command_t)); + ctx->vertices.cap = ctx->desc.max_vertices; + ctx->commands.cap = ctx->uniforms.cap = ctx->desc.max_commands; + ctx->vertices.ptr = (_sgl_vertex_t*) _sgl_malloc((size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t)); + ctx->uniforms.ptr = (_sgl_uniform_t*) _sgl_malloc((size_t)ctx->uniforms.cap * sizeof(_sgl_uniform_t)); + ctx->commands.ptr = (_sgl_command_t*) _sgl_malloc((size_t)ctx->commands.cap * sizeof(_sgl_command_t)); // create sokol-gfx resource objects sg_push_debug_group("sokol-gl"); sg_buffer_desc vbuf_desc; _sgl_clear(&vbuf_desc, sizeof(vbuf_desc)); - vbuf_desc.size = (size_t)ctx->num_vertices * sizeof(_sgl_vertex_t); + vbuf_desc.size = (size_t)ctx->vertices.cap * sizeof(_sgl_vertex_t); vbuf_desc.type = SG_BUFFERTYPE_VERTEXBUFFER; vbuf_desc.usage = SG_USAGE_STREAM; vbuf_desc.label = "sgl-vertex-buffer"; @@ -2818,17 +2823,16 @@ static sgl_context _sgl_make_context(const sgl_context_desc_t* desc) { static void _sgl_destroy_context(sgl_context ctx_id) { _sgl_context_t* ctx = _sgl_lookup_context(ctx_id.id); if (ctx) { - SOKOL_ASSERT(ctx->vertices); - SOKOL_ASSERT(ctx->uniforms); - SOKOL_ASSERT(ctx->commands); - - _sgl_free(ctx->vertices); - _sgl_free(ctx->uniforms); - _sgl_free(ctx->commands); + SOKOL_ASSERT(ctx->vertices.ptr); + SOKOL_ASSERT(ctx->uniforms.ptr); + SOKOL_ASSERT(ctx->commands.ptr); - ctx->vertices = 0; - ctx->uniforms = 0; - ctx->commands = 0; + _sgl_free(ctx->vertices.ptr); + _sgl_free(ctx->uniforms.ptr); + _sgl_free(ctx->commands.ptr); + ctx->vertices.ptr = 0; + ctx->uniforms.ptr = 0; + ctx->commands.ptr = 0; sg_push_debug_group("sokol-gl"); sg_destroy_buffer(ctx->vbuf); @@ -2841,18 +2845,18 @@ static void _sgl_destroy_context(sgl_context ctx_id) { } } -static inline void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) { +static void _sgl_begin(_sgl_context_t* ctx, _sgl_primitive_type_t mode) { ctx->in_begin = true; - ctx->base_vertex = ctx->cur_vertex; + ctx->base_vertex = ctx->vertices.next; ctx->vtx_count = 0; ctx->cur_prim_type = mode; } static void _sgl_rewind(_sgl_context_t* ctx) { ctx->frame_id++; - ctx->cur_vertex = 0; - ctx->cur_uniform = 0; - ctx->cur_command = 0; + ctx->vertices.next = 0; + ctx->uniforms.next = 0; + ctx->commands.next = 0; ctx->base_vertex = 0; ctx->error = SGL_NO_ERROR; ctx->layer_id = 0; @@ -2872,9 +2876,9 @@ static sg_commit_listener _sgl_make_commit_listener(_sgl_context_t* ctx) { return listener; } -static inline _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { - if (ctx->cur_vertex < ctx->num_vertices) { - return &ctx->vertices[ctx->cur_vertex++]; +static _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { + if (ctx->vertices.next < ctx->vertices.cap) { + return &ctx->vertices.ptr[ctx->vertices.next++]; } else { ctx->error = SGL_ERROR_VERTICES_FULL; @@ -2882,9 +2886,9 @@ static inline _sgl_vertex_t* _sgl_next_vertex(_sgl_context_t* ctx) { } } -static inline _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { - if (ctx->cur_uniform < ctx->num_uniforms) { - return &ctx->uniforms[ctx->cur_uniform++]; +static _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { + if (ctx->uniforms.next < ctx->uniforms.cap) { + return &ctx->uniforms.ptr[ctx->uniforms.next++]; } else { ctx->error = SGL_ERROR_UNIFORMS_FULL; @@ -2892,18 +2896,18 @@ static inline _sgl_uniform_t* _sgl_next_uniform(_sgl_context_t* ctx) { } } -static inline _sgl_command_t* _sgl_prev_command(_sgl_context_t* ctx) { - if (ctx->cur_command > 0) { - return &ctx->commands[ctx->cur_command - 1]; +static _sgl_command_t* _sgl_cur_command(_sgl_context_t* ctx) { + if (ctx->commands.next > 0) { + return &ctx->commands.ptr[ctx->commands.next - 1]; } else { return 0; } } -static inline _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { - if (ctx->cur_command < ctx->num_commands) { - return &ctx->commands[ctx->cur_command++]; +static _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { + if (ctx->commands.next < ctx->commands.cap) { + return &ctx->commands.ptr[ctx->commands.next++]; } else { ctx->error = SGL_ERROR_COMMANDS_FULL; @@ -2911,17 +2915,17 @@ static inline _sgl_command_t* _sgl_next_command(_sgl_context_t* ctx) { } } -static inline uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { +static uint32_t _sgl_pack_rgbab(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (uint32_t)(((uint32_t)a<<24)|((uint32_t)b<<16)|((uint32_t)g<<8)|r); } -static inline float _sgl_clamp(float v, float lo, float hi) { +static float _sgl_clamp(float v, float lo, float hi) { if (v < lo) return lo; else if (v > hi) return hi; else return v; } -static inline uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) { +static uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) { uint8_t r_u8 = (uint8_t) (_sgl_clamp(r, 0.0f, 1.0f) * 255.0f); uint8_t g_u8 = (uint8_t) (_sgl_clamp(g, 0.0f, 1.0f) * 255.0f); uint8_t b_u8 = (uint8_t) (_sgl_clamp(b, 0.0f, 1.0f) * 255.0f); @@ -2929,7 +2933,7 @@ static inline uint32_t _sgl_pack_rgbaf(float r, float g, float b, float a) { return _sgl_pack_rgbab(r_u8, g_u8, b_u8, a_u8); } -static inline void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) { +static void _sgl_vtx(_sgl_context_t* ctx, float x, float y, float z, float u, float v, uint32_t rgba) { SOKOL_ASSERT(ctx->in_begin); _sgl_vertex_t* vtx; /* handle non-native primitive types */ @@ -3143,22 +3147,22 @@ static void _sgl_lookat(_sgl_matrix_t* dst, } /* current top-of-stack projection matrix */ -static inline _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) { +static _sgl_matrix_t* _sgl_matrix_projection(_sgl_context_t* ctx) { return &ctx->matrix_stack[SGL_MATRIXMODE_PROJECTION][ctx->matrix_tos[SGL_MATRIXMODE_PROJECTION]]; } /* get top-of-stack modelview matrix */ -static inline _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) { +static _sgl_matrix_t* _sgl_matrix_modelview(_sgl_context_t* ctx) { return &ctx->matrix_stack[SGL_MATRIXMODE_MODELVIEW][ctx->matrix_tos[SGL_MATRIXMODE_MODELVIEW]]; } /* get top-of-stack texture matrix */ -static inline _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) { +static _sgl_matrix_t* _sgl_matrix_texture(_sgl_context_t* ctx) { return &ctx->matrix_stack[SGL_MATRIXMODE_TEXTURE][ctx->matrix_tos[SGL_MATRIXMODE_TEXTURE]]; } /* get pointer to current top-of-stack of current matrix mode */ -static inline _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) { +static _sgl_matrix_t* _sgl_matrix(_sgl_context_t* ctx) { return &ctx->matrix_stack[ctx->cur_matrix_mode][ctx->matrix_tos[ctx->cur_matrix_mode]]; } @@ -3272,7 +3276,7 @@ static bool _sgl_is_default_context(sgl_context ctx_id) { static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { SOKOL_ASSERT(ctx); - if ((ctx->error == SGL_NO_ERROR) && (ctx->cur_vertex > 0) && (ctx->cur_command > 0)) { + if ((ctx->error == SGL_NO_ERROR) && (ctx->vertices.next > 0) && (ctx->commands.next > 0)) { sg_push_debug_group("sokol-gl"); uint32_t cur_pip_id = SG_INVALID_ID; @@ -3281,12 +3285,12 @@ static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { if (ctx->update_frame_id != ctx->frame_id) { ctx->update_frame_id = ctx->frame_id; - const sg_range range = { ctx->vertices, (size_t)ctx->cur_vertex * sizeof(_sgl_vertex_t) }; + const sg_range range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sgl_vertex_t) }; sg_update_buffer(ctx->vbuf, &range); } - for (int i = 0; i < ctx->cur_command; i++) { - const _sgl_command_t* cmd = &ctx->commands[i]; + for (int i = 0; i < ctx->commands.next; i++) { + const _sgl_command_t* cmd = &ctx->commands.ptr[i]; if (cmd->layer_id != layer_id) { continue; } @@ -3319,7 +3323,7 @@ static void _sgl_draw(_sgl_context_t* ctx, int layer_id) { cur_img_id = args->img.id; } if (cur_uniform_index != args->uniform_index) { - const sg_range ub_range = { &ctx->uniforms[args->uniform_index], sizeof(_sgl_uniform_t) }; + const sg_range ub_range = { &ctx->uniforms.ptr[args->uniform_index], sizeof(_sgl_uniform_t) }; sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, &ub_range); cur_uniform_index = args->uniform_index; } @@ -3698,7 +3702,7 @@ SOKOL_API_IMPL void sgl_end(void) { return; } SOKOL_ASSERT(ctx->in_begin); - SOKOL_ASSERT(ctx->cur_vertex >= ctx->base_vertex); + SOKOL_ASSERT(ctx->vertices.next >= ctx->base_vertex); ctx->in_begin = false; bool matrix_dirty = ctx->matrix_dirty; if (matrix_dirty) { @@ -3709,39 +3713,39 @@ SOKOL_API_IMPL void sgl_end(void) { uni->tm = *_sgl_matrix_texture(ctx); } } - /* check if command can be merged with previous command */ + /* check if command can be merged with current command */ sg_pipeline pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); sg_image img = ctx->texturing_enabled ? ctx->cur_img : _sgl.def_img; - _sgl_command_t* prev_cmd = _sgl_prev_command(ctx); + _sgl_command_t* cur_cmd = _sgl_cur_command(ctx); bool merge_cmd = false; - if (prev_cmd) { - if ((prev_cmd->cmd == SGL_COMMAND_DRAW) && - (prev_cmd->layer_id == ctx->layer_id) && + if (cur_cmd) { + if ((cur_cmd->cmd == SGL_COMMAND_DRAW) && + (cur_cmd->layer_id == ctx->layer_id) && (ctx->cur_prim_type != SGL_PRIMITIVETYPE_LINE_STRIP) && (ctx->cur_prim_type != SGL_PRIMITIVETYPE_TRIANGLE_STRIP) && !matrix_dirty && - (prev_cmd->args.draw.img.id == img.id) && - (prev_cmd->args.draw.pip.id == pip.id)) + (cur_cmd->args.draw.img.id == img.id) && + (cur_cmd->args.draw.pip.id == pip.id)) { merge_cmd = true; } } if (merge_cmd) { /* draw command can be merged with the previous command */ - prev_cmd->args.draw.num_vertices += ctx->cur_vertex - ctx->base_vertex; + cur_cmd->args.draw.num_vertices += ctx->vertices.next - ctx->base_vertex; } else { /* append a new draw command */ _sgl_command_t* cmd = _sgl_next_command(ctx); if (cmd) { - SOKOL_ASSERT(ctx->cur_uniform > 0); + SOKOL_ASSERT(ctx->uniforms.next > 0); cmd->cmd = SGL_COMMAND_DRAW; cmd->layer_id = ctx->layer_id; cmd->args.draw.img = img; cmd->args.draw.pip = _sgl_get_pipeline(ctx->pip_stack[ctx->pip_tos], ctx->cur_prim_type); cmd->args.draw.base_vertex = ctx->base_vertex; - cmd->args.draw.num_vertices = ctx->cur_vertex - ctx->base_vertex; - cmd->args.draw.uniform_index = ctx->cur_uniform - 1; + cmd->args.draw.num_vertices = ctx->vertices.next - ctx->base_vertex; + cmd->args.draw.uniform_index = ctx->uniforms.next - 1; } } } diff --git a/util/sokol_spine.h b/util/sokol_spine.h index 670e5737..157b681a 100644 --- a/util/sokol_spine.h +++ b/util/sokol_spine.h @@ -2619,7 +2619,7 @@ typedef struct { spSkeletonData* sp_skel_data; spAnimationStateData* sp_anim_data; struct { - int num; + int cap; sspine_vec2* ptr; } tform_buf; } _sspine_skeleton_t; @@ -2696,20 +2696,20 @@ typedef struct { _sspine_slot_t slot; float transform[16]; struct { - int num; - int cur; + int cap; + int next; uint32_t rewind_frame_id; _sspine_vertex_t* ptr; } vertices; struct { - int num; - int cur; + int cap; + int next; uint32_t rewind_frame_id; uint32_t* ptr; } indices; struct { - int num; - int cur; + int cap; + int next; uint32_t rewind_frame_id; _sspine_command_t* ptr; } commands; @@ -3114,13 +3114,13 @@ static sspine_resource_state _sspine_init_context(_sspine_context_t* ctx, const SOKOL_ASSERT(desc); // setup vertex, index and command storage - ctx->vertices.num = desc->max_vertices; - ctx->indices.num = ctx->vertices.num * 3; - ctx->commands.num = desc->max_commands; + ctx->vertices.cap = desc->max_vertices; + ctx->indices.cap = ctx->vertices.cap * 3; + ctx->commands.cap = desc->max_commands; - const size_t vbuf_size = (size_t)ctx->vertices.num * sizeof(_sspine_vertex_t); - const size_t ibuf_size = (size_t)ctx->indices.num * sizeof(uint32_t); - const size_t cbuf_size = (size_t)ctx->commands.num * sizeof(_sspine_command_t); + const size_t vbuf_size = (size_t)ctx->vertices.cap * sizeof(_sspine_vertex_t); + const size_t ibuf_size = (size_t)ctx->indices.cap * sizeof(uint32_t); + const size_t cbuf_size = (size_t)ctx->commands.cap * sizeof(_sspine_command_t); ctx->vertices.ptr = (_sspine_vertex_t*) _sspine_malloc(vbuf_size); ctx->indices.ptr = (uint32_t*) _sspine_malloc(ibuf_size); @@ -3483,8 +3483,8 @@ static sspine_resource_state _sspine_init_skeleton(_sspine_skeleton_t* skeleton, } // allocate a shared vertex transform buffer (big enough to hold vertices for biggest mesh attachment) - skeleton->tform_buf.num = max_vertex_count; - skeleton->tform_buf.ptr = (sspine_vec2*) _sspine_malloc((size_t)skeleton->tform_buf.num * sizeof(sspine_vec2)); + skeleton->tform_buf.cap = max_vertex_count; + skeleton->tform_buf.ptr = (sspine_vec2*) _sspine_malloc((size_t)skeleton->tform_buf.cap * sizeof(sspine_vec2)); return SSPINE_RESOURCESTATE_VALID; } @@ -4035,15 +4035,15 @@ static void _sspine_init_image_info(const _sspine_atlas_t* atlas, int index, ssp static void _sspine_check_rewind_commands(_sspine_context_t* ctx) { if (_sspine.frame_id != ctx->commands.rewind_frame_id) { - ctx->commands.cur = 0; + ctx->commands.next = 0; ctx->commands.rewind_frame_id = _sspine.frame_id; } } static _sspine_command_t* _sspine_next_command(_sspine_context_t* ctx) { _sspine_check_rewind_commands(ctx); - if ((ctx->commands.cur + 1) <= ctx->commands.num) { - return &(ctx->commands.ptr[ctx->commands.cur++]); + if (ctx->commands.next < ctx->commands.cap) { + return &(ctx->commands.ptr[ctx->commands.next++]); } else { _SSPINE_ERROR(COMMAND_BUFFER_OVERFLOW); @@ -4051,10 +4051,10 @@ static _sspine_command_t* _sspine_next_command(_sspine_context_t* ctx) { } } -static _sspine_command_t* _sspine_prev_command(_sspine_context_t* ctx) { +static _sspine_command_t* _sspine_cur_command(_sspine_context_t* ctx) { _sspine_check_rewind_commands(ctx); - if ((ctx->commands.cur > 0) && (ctx->commands.cur <= ctx->commands.num)) { - return &ctx->commands.ptr[ctx->commands.cur - 1]; + if (ctx->commands.next > 0) { + return &ctx->commands.ptr[ctx->commands.next - 1]; } else { return 0; @@ -4063,7 +4063,7 @@ static _sspine_command_t* _sspine_prev_command(_sspine_context_t* ctx) { static void _sspine_check_rewind_vertices(_sspine_context_t* ctx) { if (_sspine.frame_id != ctx->vertices.rewind_frame_id) { - ctx->vertices.cur = 0; + ctx->vertices.next = 0; ctx->vertices.rewind_frame_id = _sspine.frame_id; } } @@ -4072,10 +4072,10 @@ static _sspine_alloc_vertices_result_t _sspine_alloc_vertices(_sspine_context_t* _sspine_check_rewind_vertices(ctx); _sspine_alloc_vertices_result_t res; _sspine_clear(&res, sizeof(res)); - if ((ctx->vertices.cur + num) <= ctx->vertices.num) { - res.ptr = &(ctx->vertices.ptr[ctx->vertices.cur]); - res.index = ctx->vertices.cur; - ctx->vertices.cur += num; + if ((ctx->vertices.next + num) <= ctx->vertices.cap) { + res.ptr = &(ctx->vertices.ptr[ctx->vertices.next]); + res.index = ctx->vertices.next; + ctx->vertices.next += num; } else { _SSPINE_ERROR(VERTEX_BUFFER_OVERFLOW); @@ -4085,7 +4085,7 @@ static _sspine_alloc_vertices_result_t _sspine_alloc_vertices(_sspine_context_t* static void _sspine_check_rewind_indices(_sspine_context_t* ctx) { if (_sspine.frame_id != ctx->indices.rewind_frame_id) { - ctx->indices.cur = 0; + ctx->indices.next = 0; ctx->indices.rewind_frame_id = _sspine.frame_id; } } @@ -4094,10 +4094,10 @@ static _sspine_alloc_indices_result_t _sspine_alloc_indices(_sspine_context_t* c _sspine_check_rewind_indices(ctx); _sspine_alloc_indices_result_t res; _sspine_clear(&res, sizeof(res)); - if ((ctx->indices.cur + num) <= ctx->indices.num) { - res.ptr = &(ctx->indices.ptr[ctx->indices.cur]); - res.index = ctx->indices.cur; - ctx->indices.cur += num; + if ((ctx->indices.next + num) <= ctx->indices.cap) { + res.ptr = &(ctx->indices.ptr[ctx->indices.next]); + res.index = ctx->indices.next; + ctx->indices.next += num; } else { _SSPINE_ERROR(INDEX_BUFFER_OVERFLOW); @@ -4114,7 +4114,7 @@ static void _sspine_draw_instance(_sspine_context_t* ctx, _sspine_instance_t* in // see: https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-sdl/src/spine-sdl-c.c const spSkeleton* sp_skel = instance->sp_skel; float* tform_buf = (float*)instance->skel.ptr->tform_buf.ptr; - const int max_tform_buf_verts = instance->skel.ptr->tform_buf.num; + const int max_tform_buf_verts = instance->skel.ptr->tform_buf.cap; SOKOL_UNUSED(max_tform_buf_verts); // only used in asserts const int tform_buf_stride = 2; // each element is 2 floats spSkeletonClipping* sp_clip = instance->sp_clip; @@ -4254,11 +4254,11 @@ static void _sspine_draw_instance(_sspine_context_t* ctx, _sspine_instance_t* in break; } - // write new draw command, or merge with previous draw command - _sspine_command_t* prev_cmd = _sspine_prev_command(ctx); - if (prev_cmd && (prev_cmd->layer == layer) && (prev_cmd->pip.id == pip.id) && (prev_cmd->img.id == img.id) && (prev_cmd->pma == pma)) { - // merge with previous command - prev_cmd->num_elements += num_indices; + // write new draw command, or merge with current draw command + _sspine_command_t* cur_cmd = _sspine_cur_command(ctx); + if (cur_cmd && (cur_cmd->layer == layer) && (cur_cmd->pip.id == pip.id) && (cur_cmd->img.id == img.id) && (cur_cmd->pma == pma)) { + // merge with current command + cur_cmd->num_elements += num_indices; } else { // record a new command @@ -4311,14 +4311,14 @@ static _sspine_vsparams_t _sspine_compute_vsparams(const sspine_layer_transform* } static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_layer_transform* tform) { - if ((ctx->vertices.cur > 0) && (ctx->commands.cur > 0)) { + if ((ctx->vertices.next > 0) && (ctx->commands.next > 0)) { sg_push_debug_group("sokol-spine"); if (ctx->update_frame_id != _sspine.frame_id) { ctx->update_frame_id = _sspine.frame_id; - const sg_range vtx_range = { ctx->vertices.ptr, (size_t)ctx->vertices.cur * sizeof(_sspine_vertex_t) }; + const sg_range vtx_range = { ctx->vertices.ptr, (size_t)ctx->vertices.next * sizeof(_sspine_vertex_t) }; sg_update_buffer(ctx->vbuf, &vtx_range); - const sg_range idx_range = { ctx->indices.ptr, (size_t)ctx->indices.cur * sizeof(uint32_t) }; + const sg_range idx_range = { ctx->indices.ptr, (size_t)ctx->indices.next * sizeof(uint32_t) }; sg_update_buffer(ctx->ibuf, &idx_range); } @@ -4331,7 +4331,7 @@ static void _sspine_draw_layer(_sspine_context_t* ctx, int layer, const sspine_l uint32_t cur_pip_id = SG_INVALID_ID; uint32_t cur_img_id = SG_INVALID_ID; float cur_pma = -1.0f; - for (int i = 0; i < ctx->commands.cur; i++) { + for (int i = 0; i < ctx->commands.next; i++) { const _sspine_command_t* cmd = &ctx->commands.ptr[i]; if ((layer == cmd->layer) && (sg_query_image_state(cmd->img) == SG_RESOURCESTATE_VALID)) { if (cur_pip_id != cmd->pip.id) { @@ -4542,9 +4542,9 @@ SOKOL_API_IMPL sspine_context_info sspine_get_context_info(sspine_context ctx_id _sspine_clear(&res, sizeof(res)); const _sspine_context_t* ctx = _sspine_lookup_context(ctx_id.id); if (ctx) { - res.num_vertices = ctx->vertices.cur; - res.num_indices = ctx->indices.cur; - res.num_commands = ctx->commands.cur; + res.num_vertices = ctx->vertices.next; + res.num_indices = ctx->indices.next; + res.num_commands = ctx->commands.next; } return res; } |