mirror of
https://github.com/nicbarker/clay.git
synced 2025-09-18 04:26:18 +00:00

The text bounding box width was incorrect because the measurement function was using logical pixels while the rendering function was using physical pixels (scaled by DPI). This caused a mismatch where: - sclay_measure_text() set font size and letter spacing without DPI scaling - sclay_render() applied DPI scaling to both font size and letter spacing - fontstash's fonsTextBounds() returned physical pixel measurements even when given logical pixel sizes, leading to incorrect width calculations The fix ensures consistent DPI scaling by: 1. Scaling font size and letter spacing by dpi_scale during measurement 2. Dividing the returned bounds by dpi_scale to convert back to logical pixels 3. This ensures Clay receives measurements in logical pixels that match what will actually be rendered This was particularly noticeable with long continuous text where the discrepancy accumulated across many characters. The issue was font-size dependent because different font sizes have different rounding behaviors in the underlying font rendering system. Also adds text alignment support to properly measure and render centered/right-aligned text.
477 lines
20 KiB
C
477 lines
20 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);
|
|
switch (config->textAlignment) {
|
|
case CLAY_TEXT_ALIGN_LEFT:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_LEFT | FONS_ALIGN_TOP);
|
|
break;
|
|
case CLAY_TEXT_ALIGN_CENTER:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_CENTER | FONS_ALIGN_TOP);
|
|
break;
|
|
case CLAY_TEXT_ALIGN_RIGHT:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_RIGHT | FONS_ALIGN_TOP);
|
|
break;
|
|
default:
|
|
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);
|
|
switch (config->textAlignment) {
|
|
case CLAY_TEXT_ALIGN_LEFT:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_LEFT | FONS_ALIGN_TOP);
|
|
break;
|
|
case CLAY_TEXT_ALIGN_CENTER:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_CENTER | FONS_ALIGN_TOP);
|
|
break;
|
|
case CLAY_TEXT_ALIGN_RIGHT:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_RIGHT | FONS_ALIGN_TOP);
|
|
break;
|
|
default:
|
|
fonsSetAlign(_sclay.fonts, FONS_ALIGN_LEFT | FONS_ALIGN_TOP);
|
|
}
|
|
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 */
|