From fc326115fa154bc19f3f10d7c2c4e57710ef1e0d Mon Sep 17 00:00:00 2001 From: spl3g Date: Sun, 9 Nov 2025 20:43:50 +0300 Subject: Move to sokol (broke the wave screen) --- third-party/sokol/sokol_clay.h | 611 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 611 insertions(+) create mode 100644 third-party/sokol/sokol_clay.h (limited to 'third-party/sokol/sokol_clay.h') diff --git a/third-party/sokol/sokol_clay.h b/third-party/sokol/sokol_clay.h new file mode 100644 index 0000000..58f04ac --- /dev/null +++ b/third-party/sokol/sokol_clay.h @@ -0,0 +1,611 @@ +#ifndef SOKOL_CLAY_INCLUDED +#define SOKOL_CLAY_INCLUDED (1) +/* + sokol_clay.h -- drop-in Clay renderer for sokol_gfx.h + + Do this: + #define SOKOL_CLAY_IMPL + + before you include this file in *one* C file to create the + implementation. + + Optionally provide the following configuration define both before including the + the declaration and implementation: + + SOKOL_CLAY_NO_SOKOL_APP - don't depend on sokol_app.h (see below for details) + + Include the following headers before sokol_clay.h (both before including + the declaration and implementation): + + sokol_gl.h + sokol_fontstash.h + sokol_app.h (except SOKOL_CLAY_NO_SOKOL_APP) + clay.h + + FEATURE OVERVIEW: + ================= + sokol_clay.h implements the rendering and event-handling code for Clay + (https://github.com/nicbarker/clay) on top of sokol_gl.h and (optionally) + sokol_app.h. + + Since sokol_fontstash.h already depends on sokol_gl.h, the rendering is + implemented using sokol_gl calls. (TODO: make fontstash optional?) + + The sokol_app.h dependency is optional and used for input event handling. + If you only use sokol_gfx.h but not sokol_app.h in your application, + define SOKOL_CLAY_NO_SOKOL_APP before including the implementation + of sokol_clay.h, this will remove any dependency to sokol_app.h, but + you must call sclay_set_layout_dimensions and handle input yourself. + + sokol_clay.h is not thread-safe, all calls must be made from the + same thread where sokol_gfx.h is running. + + HOWTO: + ====== + + --- To initialize sokol-clay, call sclay_setup(). This can be done + before or after Clay_Initialize. + + --- Create an array of sclay_font_t and fill it by calling one of: + + sclay_font_t sclay_add_font(const char *filename); + sclay_font_t sclay_add_font_mem(unsigned char *data, int dataLen); + + The fontId value in Clay corresponds to indices in this array. After calling + Clay_Initialize but before calling any layout code, do this: + + Clay_SetMeasureTextFunction(sclay_measure_text, &fonts); + + where `fonts` is the abovementioned array. + + --- At the start of a frame, call sclay_new_frame() if you're using sokol_app.h. + If you're not using sokol_app.h, call: + + void sclay_set_layout_dimensions(Clay_Dimensions size, float dpi_scale); + + at the start of the frame (or just when the window is resized.) + + Either way, do some layout, then at the end of the frame call sclay_render: + + sg_begin_pass(...) + // other rendering... + sclay_render(renderCommands, &fonts); + // other rendering... + sgl_draw(); + sg_end_pass(); + sg_commit(); + + One caveat: sclay_render assumes the default gl view matrix, and handles scaling + automatically. If you've adjusted the view matrix, remember to first call: + + sgl_matrix_mode_modelview(); + sgl_load_identity(); + + before calling sclay_render. + + --- if you're using sokol_app.h, from inside the sokol_app.h event callback, + call: + + void sclay_handle_event(const sapp_event* ev); + + Unfortunately Clay does not currently provide feedback on whether a mouse + click was handled or not. + + --- if you want to use images with clay, you should pass a pointer to a + sclay_image to the CLAY macro, like this: + CLAY({ + ... + .image = { .imageData = &(sclay_image){ .view = view, .sampler = 0 } }, + }) + Using 0 as a sampler uses the sokol default sampler with linear interpolation. + The image should be created using sg_make_image from sokol_gfx. + + --- finally, on application shutdown, call + + sclay_shutdown() + */ +#if !defined(SOKOL_CLAY_NO_SOKOL_APP) && !defined(SOKOL_APP_INCLUDED) +#error "Please include sokol_app.h before sokol_clay.h (or define SOKOL_CLAY_NO_SOKOL_APP)" +#endif + +typedef int sclay_font_t; + +typedef struct sclay_image { + sg_view view; + sg_sampler sampler; + struct { + float u0, v0, u1, v1; + } uv; +} sclay_image; + +typedef void (*sclay_custom_element_cb_t)(Clay_BoundingBox bbox, Clay_CustomRenderData *config); + +void sclay_setup(); +void sclay_shutdown(); + +sclay_font_t sclay_add_font(const char *filename); +sclay_font_t sclay_add_font_mem(unsigned char *data, int dataLen); +void sclay_set_custom_element_cb(sclay_custom_element_cb_t); +Clay_Dimensions sclay_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData); + +#ifndef SOKOL_CLAY_NO_SOKOL_APP +void sclay_new_frame(); +void sclay_handle_event(const sapp_event *ev); +#endif /* SOKOL_CLAY_NO_SOKOL_APP */ + +/* Use this if you don't call sclay_new_frame. `size` is the "virtual" size which + * your layout is relative to (ie. the actual framebuffer size divided by dpi_scale.) + * Set dpi_scale to 1 if you're not using high-dpi support. */ +void sclay_set_layout_dimensions(Clay_Dimensions size, float dpi_scale); + +void sclay_render(Clay_RenderCommandArray renderCommands, sclay_font_t *fonts); + +#endif /* SOKOL_CLAY_INCLUDED */ + +#ifdef SOKOL_CLAY_IMPL +#define SOKOL_CLAY_IMPL_INCLUDED (1) +#ifndef SOKOL_GL_INCLUDED +#error "Please include sokol_gl.h before sokol_clay.h" +#endif +#ifndef SOKOL_FONTSTASH_INCLUDED +#error "Please include sokol_fontstash.h before sokol_clay.h" +#endif +#ifndef CLAY_HEADER +#error "Please include clay.h before sokol_clay.h" +#endif + +typedef struct { + sgl_pipeline pip; +#ifndef SOKOL_CLAY_NO_SOKOL_APP + Clay_Vector2 mouse_pos, scroll; + bool mouse_down; +#endif + Clay_Dimensions size; + float dpi_scale; + FONScontext *fonts; + sclay_custom_element_cb_t custom_element_cb; +} _sclay_state_t; +static _sclay_state_t _sclay; + +void sclay_setup() { + _sclay.pip = sgl_make_pipeline(&(sg_pipeline_desc){ + .colors[0] = { + .blend = { + .enabled = true, + .src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, + .dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + }, + } + }); +#ifndef SOKOL_CLAY_NO_SOKOL_APP + _sclay.mouse_pos = (Clay_Vector2){0, 0}; + _sclay.scroll = (Clay_Vector2){0, 0}; + _sclay.mouse_down = false; +#endif + _sclay.size = (Clay_Dimensions){1, 1}; + _sclay.dpi_scale = 1; + _sclay.fonts = sfons_create(&(sfons_desc_t){ 0 }); + //TODO clay error handler? +} + +void sclay_shutdown() { + sgl_destroy_pipeline(_sclay.pip); + sfons_destroy(_sclay.fonts); +} + +#ifndef SOKOL_CLAY_NO_SOKOL_APP +void sclay_handle_event(const sapp_event* ev) { + switch(ev->type){ + case SAPP_EVENTTYPE_MOUSE_MOVE: + _sclay.mouse_pos.x = ev->mouse_x / _sclay.dpi_scale; + _sclay.mouse_pos.y = ev->mouse_y / _sclay.dpi_scale; + break; + case SAPP_EVENTTYPE_MOUSE_DOWN: + _sclay.mouse_down = true; + break; + case SAPP_EVENTTYPE_MOUSE_UP: + _sclay.mouse_down = false; + break; + case SAPP_EVENTTYPE_MOUSE_SCROLL: + _sclay.scroll.x += ev->scroll_x; + _sclay.scroll.y += ev->scroll_y; + break; + default: break; + } +} + +void sclay_new_frame() { + sclay_set_layout_dimensions((Clay_Dimensions){ (float)sapp_width(), (float)sapp_height() }, + sapp_dpi_scale()); + Clay_SetPointerState(_sclay.mouse_pos, _sclay.mouse_down); + Clay_UpdateScrollContainers(true, _sclay.scroll, sapp_frame_duration()); + _sclay.scroll = (Clay_Vector2){0, 0}; +} +#endif /* SOKOL_CLAY_NO_SOKOL_APP */ + +void sclay_set_layout_dimensions(Clay_Dimensions size, float dpi_scale) { + size.width /= dpi_scale; + size.height /= dpi_scale; + _sclay.size = size; + if(_sclay.dpi_scale != dpi_scale){ + _sclay.dpi_scale = dpi_scale; + Clay_ResetMeasureTextCache(); + } + Clay_SetLayoutDimensions(size); +} + +sclay_font_t sclay_add_font(const char *filename) { + //TODO log something if we get FONS_INVALID + return fonsAddFont(_sclay.fonts, "", filename); +} + +sclay_font_t sclay_add_font_mem(unsigned char *data, int dataLen) { + //TODO log something if we get FONS_INVALID + return fonsAddFontMem(_sclay.fonts, "", data, dataLen, false); +} + +void sclay_set_custom_element_cb(sclay_custom_element_cb_t func) { + _sclay.custom_element_cb = func; +} + +Clay_Dimensions sclay_measure_text(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) { + sclay_font_t *fonts = (sclay_font_t *)userData; + if(!fonts) return (Clay_Dimensions){ 0 }; + fonsSetFont(_sclay.fonts, fonts[config->fontId]); + fonsSetSize(_sclay.fonts, config->fontSize * _sclay.dpi_scale); + fonsSetSpacing(_sclay.fonts, config->letterSpacing * _sclay.dpi_scale); + fonsSetAlign(_sclay.fonts, FONS_ALIGN_LEFT | FONS_ALIGN_TOP); + float ascent, descent, lineh; + fonsVertMetrics(_sclay.fonts, &ascent, &descent, &lineh); + return (Clay_Dimensions) { + .width = fonsTextBounds(_sclay.fonts, 0, 0, text.chars, text.chars + text.length, NULL) / _sclay.dpi_scale, + .height = (ascent - descent) / _sclay.dpi_scale + }; +} + +static void _draw_rect(float x, float y, float w, float h){ + sgl_v2f(x, y); + sgl_v2f(x, y); + sgl_v2f(x+w, y); + sgl_v2f(x, y+h); + sgl_v2f(x+w, y+h); + sgl_v2f(x+w, y+h); +} + +static void _draw_rect_textured(float x, float y, float w, float h, float u0, float v0, float u1, float v1){ + sgl_v2f_t2f(x, y, u0, v0); + sgl_v2f_t2f(x, y, u0, v0); + sgl_v2f_t2f(x+w, y, u1, v0); + sgl_v2f_t2f(x, y+h, u0, v1); + sgl_v2f_t2f(x+w, y+h, u1, v1); + sgl_v2f_t2f(x+w, y+h, u1, v1); +} + +static float _SIN[16] = { + 0.000000f, 0.104528f, 0.207912f, 0.309017f, + 0.406737f, 0.500000f, 0.587785f, 0.669131f, + 0.743145f, 0.809017f, 0.866025f, 0.913545f, + 0.951057f, 0.978148f, 0.994522f, 1.000000f, +}; + +/* rx,ry = radius */ +static void _draw_corner(float x, float y, float rx, float ry){ + x -= rx; + y -= ry; + sgl_v2f(x, y); + for(int i = 0; i < 16; ++i){ + sgl_v2f(x, y); + sgl_v2f(x+(rx*_SIN[15-i]), y+(ry*_SIN[i])); + } + sgl_v2f(x+(rx*_SIN[0]), y+(ry*_SIN[15])); +} + +static void _draw_corner_textured(float x, float y, float rx, float ry, float bx, float by, float bw, float bh, float u0, float v0, float u1, float v1) { + x -= rx; + y -= ry; +#define MAP_U(x) (u0+(((x)-bx)/bw)*(u1-u0)) +#define MAP_V(y) (v0+(((y)-by)/bh)*(v1-v0)) + sgl_v2f_t2f(x, y, MAP_U(x), MAP_V(y)); + for(int i = 0; i < 16; ++i){ + sgl_v2f_t2f(x, y, MAP_U(x), MAP_V(y)); + float px = x+(rx*_SIN[15-i]); + float py = y+(ry*_SIN[i]); + sgl_v2f_t2f(px, py, MAP_U(px), MAP_V(py)); + } + sgl_v2f_t2f(x+(rx*_SIN[0]), y+(ry*_SIN[15]), MAP_U(x+(rx*_SIN[0])), MAP_V(y+(ry*_SIN[15]))); +#undef MAP_U +#undef MAP_V +} + +/* rx,ry = radius ix,iy = inner radius */ +static void _draw_corner_border(float x, float y, float rx, float ry, float ix, float iy){ + x -= rx; + y -= ry; + sgl_v2f(x+(ix*_SIN[15]), y+(iy*_SIN[0])); + for(int i = 0; i < 16; ++i){ + sgl_v2f(x+(ix*_SIN[15-i]), y+(iy*_SIN[i])); + sgl_v2f(x+(rx*_SIN[15-i]), y+(ry*_SIN[i])); + } + sgl_v2f(x+(rx*_SIN[0]), y+(ry*_SIN[15])); +} + +void sclay_render(Clay_RenderCommandArray renderCommands, sclay_font_t *fonts) { + sgl_matrix_mode_modelview(); + sgl_translate(-1.0f, 1.0f, 0.0f); + sgl_scale(2.0f/_sclay.size.width, -2.0f/_sclay.size.height, 1.0f); + sgl_disable_texture(); + sgl_push_pipeline(); + sgl_load_pipeline(_sclay.pip); + for (int i = 0; i < renderCommands.length; i++) { + Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, i); + Clay_BoundingBox bbox = renderCommand->boundingBox; + switch (renderCommand->commandType) { + case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: { + Clay_RectangleRenderData *config = &renderCommand->renderData.rectangle; + sgl_c4f(config->backgroundColor.r / 255.0f, + config->backgroundColor.g / 255.0f, + config->backgroundColor.b / 255.0f, + config->backgroundColor.a / 255.0f); + Clay_CornerRadius r = config->cornerRadius; + sgl_begin_triangle_strip(); + if(r.topLeft > 0 || r.topRight > 0){ + _draw_corner(bbox.x, bbox.y, -r.topLeft, -r.topLeft); + _draw_corner(bbox.x+bbox.width, bbox.y, r.topRight, -r.topRight); + _draw_rect(bbox.x+r.topLeft, bbox.y, + bbox.width-r.topLeft-r.topRight, CLAY__MAX(r.topLeft, r.topRight)); + } + if(r.bottomLeft > 0 || r.bottomRight > 0){ + _draw_corner(bbox.x, bbox.y+bbox.height, -r.bottomLeft, r.bottomLeft); + _draw_corner(bbox.x+bbox.width, bbox.y+bbox.height, r.bottomRight, r.bottomRight); + _draw_rect(bbox.x+r.bottomLeft, + bbox.y+bbox.height-CLAY__MAX(r.bottomLeft, r.bottomRight), + bbox.width-r.bottomLeft-r.bottomRight, CLAY__MAX(r.bottomLeft, r.bottomRight)); + } + if(r.topLeft < r.bottomLeft){ + if(r.topLeft < r.topRight){ + _draw_rect(bbox.x, bbox.y+r.topLeft, r.topLeft, bbox.height-r.topLeft-r.bottomLeft); + _draw_rect(bbox.x+r.topLeft, bbox.y+r.topRight, + r.bottomLeft-r.topLeft, bbox.height-r.topRight-r.bottomLeft); + } else { + _draw_rect(bbox.x, bbox.y+r.topLeft, r.bottomLeft, bbox.height-r.topLeft-r.bottomLeft); + } + } else { + if(r.bottomLeft < r.bottomRight){ + _draw_rect(bbox.x, bbox.y+r.topLeft, r.bottomLeft, bbox.height-r.topLeft-r.bottomLeft); + _draw_rect(bbox.x+r.bottomLeft, bbox.y+r.topLeft, + r.topLeft-r.bottomLeft, bbox.height-r.topLeft-r.bottomRight); + } else { + _draw_rect(bbox.x, bbox.y+r.topLeft, r.topLeft, bbox.height-r.topLeft-r.bottomLeft); + } + } + if(r.topRight < r.bottomRight){ + if(r.topRight < r.topLeft){ + _draw_rect(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topLeft, + r.bottomRight-r.topRight, bbox.height-r.topLeft-r.bottomRight); + _draw_rect(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight, bbox.height-r.topRight-r.bottomRight); + } else { + _draw_rect(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topRight, + r.bottomRight, bbox.height-r.topRight-r.bottomRight); + } + } else { + if(r.bottomRight < r.bottomLeft){ + _draw_rect(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight-r.bottomRight, bbox.height-r.topRight-r.bottomLeft); + _draw_rect(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topRight, + r.bottomRight, bbox.height-r.topRight-r.bottomRight); + } else { + _draw_rect(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight, bbox.height-r.topRight-r.bottomRight); + } + } + _draw_rect(bbox.x+CLAY__MAX(r.topLeft, r.bottomLeft), + bbox.y+CLAY__MAX(r.topLeft, r.topRight), + bbox.width-CLAY__MAX(r.topLeft, r.bottomLeft)-CLAY__MAX(r.topRight, r.bottomRight), + bbox.height-CLAY__MAX(r.topLeft, r.topRight)-CLAY__MAX(r.bottomLeft, r.bottomRight)); + sgl_end(); + break; + } + case CLAY_RENDER_COMMAND_TYPE_TEXT: { + if(!fonts) break; + Clay_TextRenderData *config = &renderCommand->renderData.text; + Clay_StringSlice text = config->stringContents; + fonsSetFont(_sclay.fonts, fonts[config->fontId]); + uint32_t color = sfons_rgba( + config->textColor.r, + config->textColor.g, + config->textColor.b, + config->textColor.a); + fonsSetColor(_sclay.fonts, color); + fonsSetSpacing(_sclay.fonts, config->letterSpacing * _sclay.dpi_scale); + fonsSetAlign(_sclay.fonts, FONS_ALIGN_LEFT | FONS_ALIGN_TOP); + fonsSetSize(_sclay.fonts, config->fontSize * _sclay.dpi_scale); + sgl_matrix_mode_modelview(); + sgl_push_matrix(); + sgl_scale(1.0f/_sclay.dpi_scale, 1.0f/_sclay.dpi_scale, 1.0f); + fonsDrawText(_sclay.fonts, bbox.x*_sclay.dpi_scale, bbox.y*_sclay.dpi_scale, + text.chars, text.chars + text.length); + sgl_pop_matrix(); + break; + } + case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: { + sgl_scissor_rectf(bbox.x*_sclay.dpi_scale, bbox.y*_sclay.dpi_scale, + bbox.width*_sclay.dpi_scale, bbox.height*_sclay.dpi_scale, + true); + break; + } + case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: { + sgl_scissor_rectf(0, 0, + _sclay.size.width*_sclay.dpi_scale, _sclay.size.height*_sclay.dpi_scale, + true); + break; + } + case CLAY_RENDER_COMMAND_TYPE_IMAGE: { + Clay_ImageRenderData *config = &renderCommand->renderData.image; + sclay_image* img = (sclay_image*)config->imageData; + // by default, u1 and v1 are 1. if we pass 0. + // note, we are modifying a copy ! + float u0 = img->uv.u0; + float v0 = img->uv.v0; + float u1 = img->uv.u1; + float v1 = img->uv.v1; + if (u1 == 0.f) { + u1 = 1.f; + } + if (v1 == 0.f) { + v1 = 1.f; + } + + int untinted = config->backgroundColor.r == 0 && config->backgroundColor.g == 0 && config->backgroundColor.b == 0 && config->backgroundColor.a == 0; + float cr = untinted ? 1.f : (config->backgroundColor.r / 255.0f); + float gr = untinted ? 1.f : (config->backgroundColor.g / 255.0f); + float br = untinted ? 1.f : (config->backgroundColor.b / 255.0f); + float ar = untinted ? 1.f : (config->backgroundColor.a / 255.0f); + + sgl_c4f(cr, gr, br, ar); + + Clay_CornerRadius r = config->cornerRadius; + + sgl_enable_texture(); + sgl_texture(img->view, img->sampler); + + sgl_begin_triangle_strip(); + if(r.topLeft > 0 || r.topRight > 0){ + _draw_corner_textured(bbox.x, bbox.y, -r.topLeft, -r.topLeft, bbox.x, bbox.y, bbox.width, bbox.height, u0, v0, u1, v1); + _draw_corner_textured(bbox.x+bbox.width, bbox.y, r.topRight, -r.topRight, bbox.x, bbox.y, bbox.width, bbox.height, u0, v0, u1, v1); + _draw_rect_textured(bbox.x+r.topLeft, bbox.y, + bbox.width-r.topLeft-r.topRight, CLAY__MAX(r.topLeft, r.topRight), + u0 + (r.topLeft/bbox.width)*(u1-u0), v0, u1 - (r.topRight/bbox.width)*(u1-u0), v0 + (CLAY__MAX(r.topLeft, r.topRight)/bbox.height)*(v1-v0)); + } + if(r.bottomLeft > 0 || r.bottomRight > 0){ + _draw_corner_textured(bbox.x, bbox.y+bbox.height, -r.bottomLeft, r.bottomLeft, bbox.x, bbox.y, bbox.width, bbox.height, u0, v0, u1, v1); + _draw_corner_textured(bbox.x+bbox.width, bbox.y+bbox.height, r.bottomRight, r.bottomRight, bbox.x, bbox.y, bbox.width, bbox.height, u0, v0, u1, v1); + _draw_rect_textured(bbox.x+r.bottomLeft, + bbox.y+bbox.height-CLAY__MAX(r.bottomLeft, r.bottomRight), + bbox.width-r.bottomLeft-r.bottomRight, CLAY__MAX(r.bottomLeft, r.bottomRight), + u0 + (r.bottomLeft/bbox.width)*(u1-u0), v1 - (CLAY__MAX(r.bottomLeft, r.bottomRight)/bbox.height)*(v1-v0), u1 - (r.bottomRight/bbox.width)*(u1-u0), v1); + } + if(r.topLeft < r.bottomLeft){ + if(r.topLeft < r.topRight){ + _draw_rect_textured(bbox.x, bbox.y+r.topLeft, r.topLeft, bbox.height-r.topLeft-r.bottomLeft, + u0, v0 + (r.topLeft/bbox.height)*(v1-v0), u0 + (r.topLeft/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + _draw_rect_textured(bbox.x+r.topLeft, bbox.y+r.topRight, + r.bottomLeft-r.topLeft, bbox.height-r.topRight-r.bottomLeft, + u0 + (r.topLeft/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u0 + (r.topLeft/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + } else { + _draw_rect_textured(bbox.x, bbox.y+r.topLeft, r.bottomLeft, bbox.height-r.topLeft-r.bottomLeft, + u0, v0 + (r.topLeft/bbox.height)*(v1-v0), u0 + (r.bottomLeft/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + } + } else { + if(r.bottomLeft < r.bottomRight){ + _draw_rect_textured(bbox.x, bbox.y+r.topLeft, r.bottomLeft, bbox.height-r.topLeft-r.bottomLeft, + u0, v0 + (r.topLeft/bbox.height)*(v1-v0), u0 + (r.bottomLeft/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + _draw_rect_textured(bbox.x+r.bottomLeft, bbox.y+r.topLeft, + r.topLeft-r.bottomLeft, bbox.height-r.topLeft-r.bottomRight, + u0 + (r.bottomLeft/bbox.width)*(u1-u0), v0 + (r.topLeft/bbox.height)*(v1-v0), u0 + (r.topLeft/bbox.width)*(u1-u0), v1 - (r.bottomRight/bbox.height)*(v1-v0)); + } else { + _draw_rect_textured(bbox.x, bbox.y+r.topLeft, r.topLeft, bbox.height-r.topLeft-r.bottomLeft, + u0, v0 + (r.topLeft/bbox.height)*(v1-v0), u0 + (r.topLeft/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + } + } + if(r.topRight < r.bottomRight){ + if(r.topRight < r.topLeft){ + _draw_rect_textured(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topLeft, + r.bottomRight-r.topRight, bbox.height-r.topLeft-r.bottomRight, + u1 - (r.bottomRight/bbox.width)*(u1-u0), v0 + (r.topLeft/bbox.height)*(v1-v0), u1 - (r.topRight/bbox.width)*(u1-u0), v1 - (r.bottomRight/bbox.height)*(v1-v0)); + _draw_rect_textured(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight, bbox.height-r.topRight-r.bottomRight, + u1 - (r.topRight/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u1, v1 - (r.bottomRight/bbox.height)*(v1-v0)); + } else { + _draw_rect_textured(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topRight, + r.bottomRight, bbox.height-r.topRight-r.bottomRight, + u1 - (r.bottomRight/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u1, v1 - (r.bottomRight/bbox.height)*(v1-v0)); + } + } else { + if(r.bottomRight < r.bottomLeft){ + _draw_rect_textured(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight-r.bottomRight, bbox.height-r.topRight-r.bottomLeft, + u1 - (r.topRight/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u1 - (r.bottomRight/bbox.width)*(u1-u0), v1 - (r.bottomLeft/bbox.height)*(v1-v0)); + _draw_rect_textured(bbox.x+bbox.width-r.bottomRight, bbox.y+r.topRight, + r.bottomRight, bbox.height-r.topRight-r.bottomRight, + u1 - (r.bottomRight/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u1, v1 - (r.bottomRight/bbox.height)*(v1-v0)); + } else { + _draw_rect_textured(bbox.x+bbox.width-r.topRight, bbox.y+r.topRight, + r.topRight, bbox.height-r.topRight-r.bottomRight, + u1 - (r.topRight/bbox.width)*(u1-u0), v0 + (r.topRight/bbox.height)*(v1-v0), u1, v1 - (r.bottomRight/bbox.height)*(v1-v0)); + } + } + _draw_rect_textured(bbox.x+CLAY__MAX(r.topLeft, r.bottomLeft), + bbox.y+CLAY__MAX(r.topLeft, r.topRight), + bbox.width-CLAY__MAX(r.topLeft, r.bottomLeft)-CLAY__MAX(r.topRight, r.bottomRight), + bbox.height-CLAY__MAX(r.topLeft, r.topRight)-CLAY__MAX(r.bottomLeft, r.bottomRight), + u0+CLAY__MAX(r.topLeft,r.bottomLeft)/bbox.width*(u1-u0), v0+CLAY__MAX(r.topLeft,r.topRight)/bbox.height*(v1-v0), + u1-CLAY__MAX(r.topRight,r.bottomRight)/bbox.width*(u1-u0), v1-CLAY__MAX(r.bottomLeft,r.bottomRight)/bbox.height*(v1-v0)); + sgl_end(); + sgl_disable_texture(); + break; + } + case CLAY_RENDER_COMMAND_TYPE_BORDER: { + Clay_BorderRenderData *config = &renderCommand->renderData.border; + sgl_c4f(config->color.r / 255.0f, + config->color.g / 255.0f, + config->color.b / 255.0f, + config->color.a / 255.0f); + Clay_BorderWidth w = config->width; + Clay_CornerRadius r = config->cornerRadius; + sgl_begin_triangle_strip(); + if(w.left > 0){ + _draw_rect(bbox.x, bbox.y + r.topLeft, + w.left, bbox.height - r.topLeft - r.bottomLeft); + } + if(w.right > 0){ + _draw_rect(bbox.x + bbox.width - w.right, bbox.y + r.topRight, + w.right, bbox.height - r.topRight - r.bottomRight); + } + if(w.top > 0){ + _draw_rect(bbox.x + r.topLeft, bbox.y, + bbox.width - r.topLeft - r.topRight, w.top); + } + if(w.bottom > 0){ + _draw_rect(bbox.x + r.bottomLeft, bbox.y + bbox.height - w.bottom, + bbox.width - r.bottomLeft - r.bottomRight, w.bottom); + } + if(r.topLeft > 0 && (w.top > 0 || w.left > 0)){ + _draw_corner_border(bbox.x, bbox.y, + -r.topLeft, -r.topLeft, + -r.topLeft+w.left, -r.topLeft+w.top); + } + if(r.topRight > 0 && (w.top > 0 || w.right > 0)){ + _draw_corner_border(bbox.x+bbox.width, bbox.y, + r.topRight, -r.topRight, + r.topRight-w.right, -r.topRight+w.top); + } + if(r.bottomLeft > 0 && (w.bottom > 0 || w.left > 0)){ + _draw_corner_border(bbox.x, bbox.y+bbox.height, + -r.bottomLeft, r.bottomLeft, + -r.bottomLeft+w.left, r.bottomLeft-w.bottom); + } + if(r.bottomRight > 0 && (w.bottom > 0 || w.right > 0)){ + _draw_corner_border(bbox.x+bbox.width, bbox.y+bbox.height, + r.bottomRight, r.bottomRight, + r.bottomRight-w.right, r.bottomRight-w.bottom); + } + sgl_end(); + break; + } + case CLAY_RENDER_COMMAND_TYPE_CUSTOM: { + if (_sclay.custom_element_cb == NULL) { + break; + } + Clay_CustomRenderData *config = &renderCommand->renderData.custom; + _sclay.custom_element_cb(bbox, config); + break; + } + default: + break; + } + } + sgl_pop_pipeline(); + sfons_flush(_sclay.fonts); +} +#endif /* SOKOL_CLAY_IMPL */ -- cgit v1.2.3