mirror of
				https://github.com/nicbarker/clay.git
				synced 2025-11-04 08:36:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			452 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			452 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#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.
 | 
						|
 | 
						|
    --- 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;
 | 
						|
 | 
						|
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);
 | 
						|
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_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);
 | 
						|
}
 | 
						|
 | 
						|
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 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]));
 | 
						|
}
 | 
						|
 | 
						|
/* 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 (uint32_t 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: {
 | 
						|
                //TODO
 | 
						|
                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;
 | 
						|
            }
 | 
						|
            default:
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    sgl_pop_pipeline();
 | 
						|
    sfons_flush(_sclay.fonts);
 | 
						|
}
 | 
						|
#endif /* SOKOL_CLAY_IMPL */
 |