round rect and rounded filled rect
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled

This commit is contained in:
2025-04-24 14:04:27 -05:00
parent daef2fd2f2
commit de63e0e52d
3 changed files with 130 additions and 7 deletions

View File

@@ -31,7 +31,7 @@ render.initialize = function(config)
prosperon.window = prosperon.engine_start({width:500,height:500})
console.log(prosperon.window)
context = prosperon.window.make_renderer("metal")
context = prosperon.window.make_renderer()
}
// img here is the engine surface
@@ -55,6 +55,7 @@ render.image = function(image, rect)
rect.width ??= image.texture.width
rect.height ??= image.texture.height
var T =
context.texture(image.texture, rect);
}
@@ -90,6 +91,131 @@ render.circle = function(pos, radius, color = Color.white)
}
}
/*------------------------------------------------------------*
* Rounded-rect outline any stroke width ≥ 1 *
*------------------------------------------------------------*/
render.round_rect = function(rect, radius, line_width = 1,
color = Color.white)
{
if (line_width <= 0) return
radius = Math.min(radius, rect.width >> 1, rect.height >> 1)
if (radius <= 0) { render.rectangle(rect, color); return }
const x0 = rect.x,
y0 = rect.y,
x1 = rect.x + rect.width - 1, // inclusive
y1 = rect.y + rect.height - 1
/* fast-path: stroke swallows the whole thing → just fill */
if ((line_width << 1) >= rect.width ||
(line_width << 1) >= rect.height) {
render.fill_round_rect(rect, radius, color)
return
}
const cx_l = x0 + radius, cx_r = x1 - radius
const cy_t = y0 + radius, cy_b = y1 - radius
const r_out = radius
const r_in = Math.max(radius - line_width, 0)
context.draw_color(color)
/* straight bands ---------------------------------------------------------*/
context.rects([
{ x:x0 + radius, y:y0, width:rect.width - (radius << 1),
height:line_width }, // top
{ x:x0 + radius, y:y1 - line_width + 1,
width:rect.width - (radius << 1), height:line_width }, // bottom
{ x:x0, y:y0 + radius, width:line_width,
height:rect.height - (radius << 1) }, // left
{ x:x1 - line_width + 1, y:y0 + radius, width:line_width,
height:rect.height - (radius << 1) } // right
])
/* corner arcs ------------------------------------------------------------*/
const strips = [] // batch for speed
for (let dy = 0; dy < radius; ++dy) {
const dy_sq = dy * dy
const dx_out = Math.floor(Math.sqrt(r_out * r_out - dy_sq))
const dx_in = (r_in && dy < r_in)
? Math.floor(Math.sqrt(r_in * r_in - dy_sq))
: -1 // no inner rim
const w = dx_out - dx_in // strip width
if (w <= 0) continue
/* top */
strips.push(
{ x:cx_l - dx_out, y:cy_t - dy, width:w, height:1 }, // NW
{ x:cx_r + dx_in + 1, y:cy_t - dy, width:w, height:1 } // NE
)
/* bottom */
strips.push(
{ x:cx_l - dx_out, y:cy_b + dy, width:w, height:1 }, // SW
{ x:cx_r + dx_in + 1, y:cy_b + dy, width:w, height:1 } // SE
)
}
context.rects(strips)
}
/*------------------------------------------------------------*
* Filled rounded-rect *
*------------------------------------------------------------*/
render.fill_round_rect = function(rect, radius,
color = Color.white)
{
radius = Math.min(radius, rect.width >> 1, rect.height >> 1)
if (radius <= 0) { context.draw_color(color); context.rects([rect]); return }
const x0 = rect.x,
y0 = rect.y,
x1 = rect.x + rect.width - 1,
y1 = rect.y + rect.height - 1
context.draw_color(color)
/* main rectangle column (everything between the caps) ----*/
context.rects([
{ x:x0 + radius, y:y0, width:rect.width - (radius << 1),
height:rect.height }
])
/* side columns (left & right) -----------------------------*/
context.rects([
{ x:x0, y:y0 + radius, width:radius,
height:rect.height - (radius << 1) },
{ x:x1 - radius + 1, y:y0 + radius, width:radius,
height:rect.height - (radius << 1) }
])
/* corner caps --------------------------------------------*/
const cx_l = x0 + radius, cx_r = x1 - radius
const cy_t = y0 + radius, cy_b = y1 - radius
const caps = []
for (let dy = 0; dy < radius; ++dy) {
const dx = Math.floor(Math.sqrt(radius * radius - dy * dy))
const w = (dx << 1) + 1
/* top */
caps.push(
{ x:cx_l - dx, y:cy_t - dy, width:w, height:1 },
{ x:cx_r - dx, y:cy_t - dy, width:w, height:1 }
)
/* bottom */
caps.push(
{ x:cx_l - dx, y:cy_b + dy, width:w, height:1 },
{ x:cx_r - dx, y:cy_b + dy, width:w, height:1 }
)
}
context.rects(caps)
}
render.ellipse = function(pos, radiuses, color = Color.white)
{
var rx = radiuses[0], ry = radiuses[1]

View File

@@ -2566,14 +2566,9 @@ static const JSCFunctionListEntry js_camera_funcs[] = {
JSC_SCALL(SDL_Window_make_renderer,
SDL_Window *win = js2SDL_Window(js,self);
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0);
SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, win);
SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, str);
renderer_ctx *ctx = malloc(sizeof(*ctx));
ctx->sdl = SDL_CreateRendererWithProperties(props);
ctx->sdl = SDL_CreateRenderer(win, NULL);
ctx->cam = (shader_globals){0};
SDL_DestroyProperties(props);
if (!ctx->sdl) {
free(ctx);
return JS_ThrowReferenceError(js, "Error creating renderer: %s",SDL_GetError());

View File

@@ -44,6 +44,8 @@ function loop()
render.circle([200,200],40)
render.ellipse([300,300],[20,40])
render.rectangle({x:150,y:150,width:50,height:50})
render.round_rect({x:100, y:60, width:200, height:60}, 20, 2)
render.fill_round_rect({x:350, y:60, width:200, height:120}, 10)
//render.image("button_grey", [100,100])
// draw.rectangle({x:50,y:-50,width:50,height:50})
render.present()