Clean up SDL code and fix sloppy mistakes

This commit is contained in:
Rats 2025-10-21 18:41:25 -05:00
parent eb8368216a
commit 6824a942a7
4 changed files with 268 additions and 416 deletions

View file

@ -100,7 +100,7 @@ video_demo_layout :: proc(data: ^Video_Demo_Data) -> clay.ClayArray(clay.RenderC
// Child elements go inside braces // Child elements go inside braces
if clay.UI(clay.ID("HeaderBar"))( if clay.UI(clay.ID("HeaderBar"))(
{ {
layout = {sizing = {height = clay.SizingFixed(60), width = clay.SizingFixed(0)}, padding = {16, 16, 0, 0}, childGap = 16, childAlignment = {y = .Center}}, layout = {sizing = {height = clay.SizingFixed(60), width = clay.SizingGrow()}, padding = {16, 16, 0, 0}, childGap = 16, childAlignment = {y = .Center}},
backgroundColor = contentBackgroundColor, backgroundColor = contentBackgroundColor,
cornerRadius = clay.CornerRadiusAll(8), cornerRadius = clay.CornerRadiusAll(8),
}, },
@ -154,7 +154,7 @@ video_demo_layout :: proc(data: ^Video_Demo_Data) -> clay.ClayArray(clay.RenderC
clay.TextDynamic(document.title, clay.TextConfig({fontId = VIDEO_DEMO_FONT_ID_BODY, fontSize = 20, textColor = {255, 255, 255, 255}})) clay.TextDynamic(document.title, clay.TextConfig({fontId = VIDEO_DEMO_FONT_ID_BODY, fontSize = 20, textColor = {255, 255, 255, 255}}))
} }
} else { } else {
clickData := new_clone((Sidebar_Click_Data) { clickData := new_clone(Sidebar_Click_Data {
requestedDocumentIndex = i, requestedDocumentIndex = i,
selectedDocumentIndex = &data.selectedDocumentIndex, selectedDocumentIndex = &data.selectedDocumentIndex,
}, context.temp_allocator) }, context.temp_allocator)

View file

@ -1,4 +1,4 @@
Odin doesn't directly package SDL, so on Windows, you'll want to copy `SDL3.dll` and `SDL3_ttf.dll` into this directory. On Linux and Mac, you should install SDL3 via your package manager Odin doesn't directly package SDL, so on Windows, you'll want to copy `SDL3.dll` and `SDL3_ttf.dll` into this directory from odin's `vendor/sdl3` directory located next to the compiler. You can use `odin root` to figure out where your compiler is installed. On Linux and Mac, you should install SDL3 via your package manager
## Running on Windows ## Running on Windows
In an embdedded termninal, missing dependencies will fail silently on Windows, so if you have any unexplainable crashes, make sure the DLLs are in your current working directory (the path you run the command from). It's easiest to just copy them next to this file, and run from here as well. In an embdedded termninal, missing dependencies will fail silently on Windows, so if you have any unexplainable crashes, make sure the DLLs are in your current working directory (the path you run the command from). It's easiest to just copy them next to this file, and run from here as well.

View file

@ -10,7 +10,7 @@ import "vendor:sdl3/ttf"
App_State :: struct { App_State :: struct {
window: ^sdl.Window, window: ^sdl.Window,
rendererData: Clay_SDL3RendererData, rendererData: Clay_SDL_Render_Data,
} }
state: App_State state: App_State
@ -22,7 +22,7 @@ errorHandler :: proc "c" (errorData: clay.ErrorData) {
} }
load_font :: proc(data: []byte, size: f32, id: u16, fonts: ^[dynamic]^ttf.Font) { load_font :: proc(data: []byte, size: f32, id: u16, fonts: ^[dynamic]^ttf.Font) {
font_stream := sdl.IOFromConstMem(raw_data(ROBOTO), uint(len(ROBOTO))) font_stream := sdl.IOFromConstMem(raw_data(data), uint(len(data)))
font := ttf.OpenFontIO(font_stream, true, size * 2) font := ttf.OpenFontIO(font_stream, true, size * 2)
assign_at(fonts, int(id), font) assign_at(fonts, int(id), font)
} }
@ -38,7 +38,7 @@ measure_text :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfi
sdl.LogError(i32(sdl.LogCategory.ERROR), "Failed to measure text: %s", sdl.GetError()) sdl.LogError(i32(sdl.LogCategory.ERROR), "Failed to measure text: %s", sdl.GetError())
} }
return clay.Dimensions{f32(width), f32(height)} return {f32(width), f32(height)}
} }
// Load at compile time, directly into the binary // Load at compile time, directly into the binary
ROBOTO := #load("./Roboto-Regular.ttf") ROBOTO := #load("./Roboto-Regular.ttf")
@ -58,9 +58,9 @@ main :: proc() {
state.window = window state.window = window
state.rendererData.renderer = renderer state.rendererData.renderer = renderer
state.rendererData.textEngine = ttf.CreateRendererTextEngine(renderer) state.rendererData.text_engine = ttf.CreateRendererTextEngine(renderer)
minMemorySize := (uint)(clay.MinMemorySize()) minMemorySize := uint(clay.MinMemorySize())
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, make([^]u8, minMemorySize)) arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, make([^]u8, minMemorySize))
clay.Initialize(arena, {1280, 720}, {handler = errorHandler}) clay.Initialize(arena, {1280, 720}, {handler = errorHandler})
clay.SetMeasureTextFunction(measure_text, &state.rendererData.fonts) clay.SetMeasureTextFunction(measure_text, &state.rendererData.fonts)
@ -78,12 +78,10 @@ main :: proc() {
window_width, window_height: i32 window_width, window_height: i32
for !done { for !done {
defer free_all(context.temp_allocator)
scrollDelta: clay.Vector2 scrollDelta: clay.Vector2
for (sdl.PollEvent(&event)) { for sdl.PollEvent(&event) {
if (event.type == .QUIT) { if event.type == .QUIT {
done = true done = true
} else if event.type == .MOUSE_WHEEL { } else if event.type == .MOUSE_WHEEL {
scrollDelta.x = event.wheel.x scrollDelta.x = event.wheel.x
@ -99,10 +97,8 @@ main :: proc() {
clay.SetLayoutDimensions({width = f32(window_width), height = f32(window_height)}) clay.SetLayoutDimensions({width = f32(window_width), height = f32(window_height)})
mouseX: f32 = 0 mousePosition : clay.Vector2
mouseY: f32 = 0 mouseState := sdl.GetMouseState(&mousePosition.x, &mousePosition.y)
mouseState := sdl.GetMouseState(&mouseX, &mouseY)
mousePosition := (clay.Vector2){mouseX, mouseY}
clay.SetPointerState(mousePosition, .LEFT in mouseState) clay.SetPointerState(mousePosition, .LEFT in mouseState)
clay.UpdateScrollContainers(false, scrollDelta, f32(deltaTime)) clay.UpdateScrollContainers(false, scrollDelta, f32(deltaTime))
@ -112,7 +108,7 @@ main :: proc() {
sdl.SetRenderDrawColor(renderer, 0, 0, 0, 255) sdl.SetRenderDrawColor(renderer, 0, 0, 0, 255)
sdl.RenderClear(renderer) sdl.RenderClear(renderer)
sdl_Clay_RenderClayCommands(&state.rendererData, &commands) sdl_render_clay_commands(&state.rendererData, &commands)
sdl.RenderPresent(renderer) sdl.RenderPresent(renderer)
} }

View file

@ -3,16 +3,17 @@ package video_demo_sdl
import clay "../../clay-odin" import clay "../../clay-odin"
import "core:math" import "core:math"
import "core:math/linalg"
import sdl "vendor:sdl3" import sdl "vendor:sdl3"
import "vendor:sdl3/ttf" import "vendor:sdl3/ttf"
Clay_SDL3RendererData :: struct { Clay_SDL_Render_Data :: struct {
renderer: ^sdl.Renderer, renderer: ^sdl.Renderer,
textEngine: ^ttf.TextEngine, text_engine: ^ttf.TextEngine,
fonts: [dynamic]^ttf.Font, fonts: [dynamic]^ttf.Font,
} }
// SDL_ttf works in pts, but clay expects pixels. // SDL_ttf works in pts, but clay expects pixels.
// 0.85 looks correct from what I've seen, but this calculation is probably incorrect. // 0.85 looks correct from what I've seen, but this calculation is probably incorrect.
px_to_pt :: proc "contextless" (pixels: f32) -> f32 { px_to_pt :: proc "contextless" (pixels: f32) -> f32 {
return pixels * 0.85 return pixels * 0.85
@ -24,432 +25,287 @@ px_to_pt :: proc "contextless" (pixels: f32) -> f32 {
NUM_CIRCLE_SEGMENTS :: 16 NUM_CIRCLE_SEGMENTS :: 16
//all rendering is performed by a single SDL call, avoiding multiple RenderRect + plumbing choice for circles. //all rendering is performed by a single SDL call, avoiding multiple RenderRect + plumbing choice for circles.
sdl_Clay_RenderFillRoundedRect :: proc( @(private = "file")
rendererData: ^Clay_SDL3RendererData, fill_rounded_rect :: proc(rendererData: ^Clay_SDL_Render_Data, rect: sdl.FRect, cornerRadius: f32, _color: clay.Color) {
rect: sdl.FRect, color := sdl.FColor(_color / 255)
cornerRadius: f32,
_color: clay.Color,
) {
color := sdl.FColor(_color / 255)
indexCount: i32 = 0 indexCount: i32 = 0
vertexCount: i32 = 0 vertexCount: i32 = 0
minRadius := sdl.min(rect.w, rect.h) / 2 minRadius := min(rect.w, rect.h) / 2
clampedRadius := sdl.min(cornerRadius, minRadius) clampedRadius := min(cornerRadius, minRadius)
numCircleSegments := sdl.max(NUM_CIRCLE_SEGMENTS, i32(clampedRadius * 0.5)) numCircleSegments := max(NUM_CIRCLE_SEGMENTS, i32(clampedRadius * 0.5))
totalVertices := 4 + (4 * (numCircleSegments * 2)) + 2 * 4 totalVertices := 4 + (4 * (numCircleSegments * 2)) + 2 * 4
totalIndices := 6 + (4 * (numCircleSegments * 3)) + 6 * 4 totalIndices := 6 + (4 * (numCircleSegments * 3)) + 6 * 4
// Maybe instrinsics.alloca these? // Maybe instrinsics.alloca these?
vertices := make([]sdl.Vertex, totalVertices, allocator = context.temp_allocator) vertices := make([]sdl.Vertex, totalVertices, allocator = context.temp_allocator)
indices := make([]i32, totalIndices, allocator = context.temp_allocator) indices := make([]i32, totalIndices, allocator = context.temp_allocator)
//define center rectangle //define center rectangle
vertices[vertexCount + 0] = (sdl.Vertex) { vertices[vertexCount + 0] = {{rect.x + clampedRadius, rect.y + clampedRadius}, color, {0, 0}} //0 center TL
{rect.x + clampedRadius, rect.y + clampedRadius}, vertices[vertexCount + 1] = {{rect.x + rect.w - clampedRadius, rect.y + clampedRadius}, color, {1, 0}} //1 center TR
color, vertices[vertexCount + 2] = {{rect.x + rect.w - clampedRadius, rect.y + rect.h - clampedRadius}, color, {1, 1}} //2 center BR
{0, 0}, vertices[vertexCount + 3] = {{rect.x + clampedRadius, rect.y + rect.h - clampedRadius}, color, {0, 1}} //3 center BL
} //0 center TL
vertices[vertexCount + 1] = (sdl.Vertex) {
{rect.x + rect.w - clampedRadius, rect.y + clampedRadius},
color,
{1, 0},
} //1 center TR
vertices[vertexCount + 2] = (sdl.Vertex) {
{rect.x + rect.w - clampedRadius, rect.y + rect.h - clampedRadius},
color,
{1, 1},
} //2 center BR
vertices[vertexCount + 3] = (sdl.Vertex) {
{rect.x + clampedRadius, rect.y + rect.h - clampedRadius},
color,
{0, 1},
} //3 center BL
vertexCount += 4 vertexCount += 4
indices[indexCount + 0] = 0 indices[indexCount + 0] = 0
indices[indexCount + 1] = 1 indices[indexCount + 1] = 1
indices[indexCount + 2] = 3 indices[indexCount + 2] = 3
indices[indexCount + 3] = 1 indices[indexCount + 3] = 1
indices[indexCount + 4] = 2 indices[indexCount + 4] = 2
indices[indexCount + 5] = 3 indices[indexCount + 5] = 3
indexCount += 6 indexCount += 6
//define rounded corners as triangle fans //define rounded corners as triangle fans
step := (f32(math.PI) / 2) / f32(numCircleSegments) step := (f32(math.PI) / 2) / f32(numCircleSegments)
for i in 0 ..< numCircleSegments { for i in 0 ..< numCircleSegments {
angle1 := f32(i) * step angle1 := f32(i) * step
angle2 := (f32(i) + 1) * step angle2 := (f32(i) + 1) * step
for j in i32(0) ..< 4 { // Iterate over four corners for j in i32(0) ..< 4 { // Iterate over four corners
cx, cy, signX, signY: f32 cx, cy, signX, signY: f32
switch (j) { switch j {
case 0: case 0:
cx = rect.x + clampedRadius cx = rect.x + clampedRadius
cy = rect.y + clampedRadius cy = rect.y + clampedRadius
signX = -1 signX = -1
signY = -1 signY = -1
// Top-left // Top-left
case 1: case 1:
cx = rect.x + rect.w - clampedRadius cx = rect.x + rect.w - clampedRadius
cy = rect.y + clampedRadius cy = rect.y + clampedRadius
signX = 1 signX = 1
signY = -1 // Top-right signY = -1 // Top-right
case 2: case 2:
cx = rect.x + rect.w - clampedRadius cx = rect.x + rect.w - clampedRadius
cy = rect.y + rect.h - clampedRadius cy = rect.y + rect.h - clampedRadius
signX = 1 signX = 1
signY = 1 // Bottom-right signY = 1 // Bottom-right
case 3: case 3:
cx = rect.x + clampedRadius cx = rect.x + clampedRadius
cy = rect.y + rect.h - clampedRadius cy = rect.y + rect.h - clampedRadius
signX = -1 signX = -1
signY = 1 // Bottom-left signY = 1 // Bottom-left
case: case:
return return
} }
vertices[vertexCount + 0] = (sdl.Vertex) { vertices[vertexCount + 0] = {{cx + math.cos(angle1) * clampedRadius * signX, cy + math.sin(angle1) * clampedRadius * signY}, color, {0, 0}}
{ vertices[vertexCount + 1] = {{cx + math.cos(angle2) * clampedRadius * signX, cy + math.sin(angle2) * clampedRadius * signY}, color, {0, 0}}
cx + sdl.cosf(angle1) * clampedRadius * signX,
cy + sdl.sinf(angle1) * clampedRadius * signY,
},
color,
{0, 0},
}
vertices[vertexCount + 1] = (sdl.Vertex) {
{
cx + sdl.cosf(angle2) * clampedRadius * signX,
cy + sdl.sinf(angle2) * clampedRadius * signY,
},
color,
{0, 0},
}
vertexCount += 2 vertexCount += 2
indices[indexCount + 0] = j // Connect to corresponding central rectangle vertex indices[indexCount + 0] = j // Connect to corresponding central rectangle vertex
indices[indexCount + 1] = vertexCount - 2 indices[indexCount + 1] = vertexCount - 2
indices[indexCount + 2] = vertexCount - 1 indices[indexCount + 2] = vertexCount - 1
indexCount += 3 indexCount += 3
} }
} }
//Define edge rectangles //Define edge rectangles
// Top edge // Top edge
vertices[vertexCount + 0] = (sdl.Vertex){{rect.x + clampedRadius, rect.y}, color, {0, 0}} //TL vertices[vertexCount + 0] = {{rect.x + clampedRadius, rect.y}, color, {0, 0}} //TL
vertices[vertexCount + 1] = (sdl.Vertex) { vertices[vertexCount + 1] = {{rect.x + rect.w - clampedRadius, rect.y}, color, {1, 0}} //TR
{rect.x + rect.w - clampedRadius, rect.y},
color,
{1, 0},
} //TR
vertexCount += 2 vertexCount += 2
indices[indexCount + 0] = 0 indices[indexCount + 0] = 0
indices[indexCount + 1] = vertexCount - 2 //TL indices[indexCount + 1] = vertexCount - 2 //TL
indices[indexCount + 2] = vertexCount - 1 //TR indices[indexCount + 2] = vertexCount - 1 //TR
indices[indexCount + 3] = 1 indices[indexCount + 3] = 1
indices[indexCount + 4] = 0 indices[indexCount + 4] = 0
indices[indexCount + 5] = vertexCount - 1 //TR indices[indexCount + 5] = vertexCount - 1 //TR
indexCount += 6 indexCount += 6
// Right edge // Right edge
vertices[vertexCount + 0] = (sdl.Vertex) { vertices[vertexCount + 0] = {{rect.x + rect.w, rect.y + clampedRadius}, color, {1, 0}} //RT
{rect.x + rect.w, rect.y + clampedRadius}, vertices[vertexCount + 1] = {{rect.x + rect.w, rect.y + rect.h - clampedRadius}, color, {1, 1}} //RB
color, vertexCount += 2
{1, 0},
} //RT
vertices[vertexCount + 1] = (sdl.Vertex) {
{rect.x + rect.w, rect.y + rect.h - clampedRadius},
color,
{1, 1},
} //RB
vertexCount += 2
indices[indexCount + 0] = 1 indices[indexCount + 0] = 1
indices[indexCount + 1] = vertexCount - 2 //RT indices[indexCount + 1] = vertexCount - 2 //RT
indices[indexCount + 2] = vertexCount - 1 //RB indices[indexCount + 2] = vertexCount - 1 //RB
indices[indexCount + 3] = 2 indices[indexCount + 3] = 2
indices[indexCount + 4] = 1 indices[indexCount + 4] = 1
indices[indexCount + 5] = vertexCount - 1 //RB indices[indexCount + 5] = vertexCount - 1 //RB
indexCount += 6 indexCount += 6
// Bottom edge // Bottom edge
vertices[vertexCount + 0] = (sdl.Vertex) { vertices[vertexCount + 0] = {{rect.x + rect.w - clampedRadius, rect.y + rect.h}, color, {1, 1}} //BR
{rect.x + rect.w - clampedRadius, rect.y + rect.h}, vertices[vertexCount + 1] = {{rect.x + clampedRadius, rect.y + rect.h}, color, {0, 1}} //BL
color, vertexCount += 2
{1, 1},
} //BR
vertices[vertexCount + 1] = (sdl.Vertex) {
{rect.x + clampedRadius, rect.y + rect.h},
color,
{0, 1},
} //BL
vertexCount += 2
indices[indexCount + 0] = 2 indices[indexCount + 0] = 2
indices[indexCount + 1] = vertexCount - 2 //BR indices[indexCount + 1] = vertexCount - 2 //BR
indices[indexCount + 2] = vertexCount - 1 //BL indices[indexCount + 2] = vertexCount - 1 //BL
indices[indexCount + 3] = 3 indices[indexCount + 3] = 3
indices[indexCount + 4] = 2 indices[indexCount + 4] = 2
indices[indexCount + 5] = vertexCount - 1 //BL indices[indexCount + 5] = vertexCount - 1 //BL
indexCount += 6 indexCount += 6
// Left edge // Left edge
vertices[vertexCount + 0] = (sdl.Vertex) { vertices[vertexCount + 0] = {{rect.x, rect.y + rect.h - clampedRadius}, color, {0, 1}} //LB
{rect.x, rect.y + rect.h - clampedRadius}, vertices[vertexCount + 1] = {{rect.x, rect.y + clampedRadius}, color, {0, 0}} //LT
color, vertexCount += 2
{0, 1},
} //LB
vertices[vertexCount + 1] = (sdl.Vertex){{rect.x, rect.y + clampedRadius}, color, {0, 0}} //LT
vertexCount += 2
indices[indexCount + 0] = 3 indices[indexCount + 0] = 3
indices[indexCount + 1] = vertexCount - 2 //LB indices[indexCount + 1] = vertexCount - 2 //LB
indices[indexCount + 2] = vertexCount - 1 //LT indices[indexCount + 2] = vertexCount - 1 //LT
indices[indexCount + 3] = 0 indices[indexCount + 3] = 0
indices[indexCount + 4] = 3 indices[indexCount + 4] = 3
indices[indexCount + 5] = vertexCount - 1 //LT indices[indexCount + 5] = vertexCount - 1 //LT
indexCount += 6 indexCount += 6
// Render everything // Render everything
sdl.RenderGeometry( sdl.RenderGeometry(rendererData.renderer, nil, raw_data(vertices), vertexCount, raw_data(indices), indexCount)
rendererData.renderer,
nil,
raw_data(vertices),
vertexCount,
raw_data(indices),
indexCount,
)
} }
sdl_Clay_RenderArc :: proc( @(private = "file")
rendererData: ^Clay_SDL3RendererData, render_arc :: proc(rendererData: ^Clay_SDL_Render_Data, center: sdl.FPoint, radius: f32, startAngle: f32, endAngle: f32, thickness: f32, color: clay.Color) {
center: sdl.FPoint, sdl.SetRenderDrawColor(rendererData.renderer, clay_to_sdl_color(color))
radius: f32,
startAngle: f32,
endAngle: f32,
thickness: f32,
color: clay.Color,
) {
sdl.SetRenderDrawColor(
rendererData.renderer,
u8(color.r),
u8(color.g),
u8(color.b),
u8(color.a),
)
radStart := startAngle * (math.PI / 180.0) radStart := math.to_radians(startAngle)
radEnd := endAngle * (math.PI / 180.0) radEnd := math.to_radians(endAngle)
numCircleSegments := sdl.max(NUM_CIRCLE_SEGMENTS, i32(radius * 1.5)) //increase circle segments for larger circles, 1.5 is arbitrary. numCircleSegments := max(NUM_CIRCLE_SEGMENTS, i32(radius * 1.5)) //increase circle segments for larger circles, 1.5 is arbitrary.
angleStep := (radEnd - radStart) / f32(numCircleSegments) angleStep := (radEnd - radStart) / f32(numCircleSegments)
thicknessStep: f32 = 0.4 //arbitrary value to avoid overlapping lines. Changing THICKNESS_STEP or numCircleSegments might cause artifacts. thicknessStep: f32 = 0.4 //arbitrary value to avoid overlapping lines. Changing THICKNESS_STEP or numCircleSegments might cause artifacts.
for t := thicknessStep; t < thickness - thicknessStep; t += thicknessStep { for t := thicknessStep; t < thickness - thicknessStep; t += thicknessStep {
points := make([]sdl.FPoint, numCircleSegments + 1, allocator = context.temp_allocator) points := make([]sdl.FPoint, numCircleSegments + 1, allocator = context.temp_allocator)
clampedRadius := sdl.max(radius - t, 1) clampedRadius := max(radius - t, 1)
for i in 0 ..= numCircleSegments { for i in 0 ..= numCircleSegments {
angle := radStart + f32(i) * angleStep angle := radStart + f32(i) * angleStep
points[i] = (sdl.FPoint) { points[i] = sdl.FPoint{math.round(center.x + math.cos(angle) * clampedRadius), math.round(center.y + math.sin(angle) * clampedRadius)}
sdl.roundf(center.x + sdl.cosf(angle) * clampedRadius), }
sdl.roundf(center.y + sdl.sinf(angle) * clampedRadius), sdl.RenderLines(rendererData.renderer, raw_data(points), numCircleSegments + 1)
} }
}
sdl.RenderLines(rendererData.renderer, raw_data(points), numCircleSegments + 1)
}
} }
currentClippingRectangle: sdl.Rect @(private = "file")
current_clipping_rect: sdl.Rect
sdl_Clay_RenderClayCommands :: proc( clay_to_sdl_color :: proc(color: clay.Color) -> (r, g, b, a: u8) {
rendererData: ^Clay_SDL3RendererData, return expand_values(linalg.array_cast(color, u8))
rcommands: ^clay.ClayArray(clay.RenderCommand), }
) {
for i in 0 ..< rcommands.length { sdl_render_clay_commands :: proc(renderer_data: ^Clay_SDL_Render_Data, commands: ^clay.ClayArray(clay.RenderCommand)) {
rcmd := clay.RenderCommandArray_Get(rcommands, i) for i in 0 ..< commands.length {
bounding_box := rcmd.boundingBox cmd := clay.RenderCommandArray_Get(commands, i)
rect := sdl.FRect{bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height} bounding_box := cmd.boundingBox
rect := sdl.FRect{bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height}
#partial switch (rcmd.commandType) {
case .Rectangle: #partial switch cmd.commandType {
config := &rcmd.renderData.rectangle case .Rectangle:
sdl.SetRenderDrawBlendMode(rendererData.renderer, sdl.BLENDMODE_BLEND) config := &cmd.renderData.rectangle
sdl.SetRenderDrawColor( sdl.SetRenderDrawBlendMode(renderer_data.renderer, sdl.BLENDMODE_BLEND)
rendererData.renderer, sdl.SetRenderDrawColor(renderer_data.renderer, clay_to_sdl_color(config.backgroundColor))
u8(config.backgroundColor.r), if config.cornerRadius.topLeft > 0 {
u8(config.backgroundColor.g), fill_rounded_rect(renderer_data, rect, config.cornerRadius.topLeft, config.backgroundColor)
u8(config.backgroundColor.b), } else {
u8(config.backgroundColor.a), sdl.RenderFillRect(renderer_data.renderer, &rect)
) }
if (config.cornerRadius.topLeft > 0) {
sdl_Clay_RenderFillRoundedRect( case .Text:
rendererData, config := &cmd.renderData.text
rect, font := renderer_data.fonts[config.fontId]
config.cornerRadius.topLeft, ttf.SetFontSize(font, px_to_pt(f32(config.fontSize)))
config.backgroundColor, text := ttf.CreateText(renderer_data.text_engine, font, cstring(config.stringContents.chars), uint(config.stringContents.length))
) ttf.SetTextColor(text, clay_to_sdl_color(config.textColor))
} else { ttf.DrawRendererText(text, rect.x, rect.y)
sdl.RenderFillRect(rendererData.renderer, &rect) ttf.DestroyText(text)
}
case .Border:
case .Text: config := &cmd.renderData.border
config := &rcmd.renderData.text
font := rendererData.fonts[config.fontId] minRadius := min(rect.w, rect.h) / 2
ttf.SetFontSize(font, px_to_pt(f32(config.fontSize))) clampedRadii := clay.CornerRadius {
text := ttf.CreateText( topLeft = min(config.cornerRadius.topLeft, minRadius),
rendererData.textEngine, topRight = min(config.cornerRadius.topRight, minRadius),
font, bottomLeft = min(config.cornerRadius.bottomLeft, minRadius),
cstring(config.stringContents.chars), bottomRight = min(config.cornerRadius.bottomRight, minRadius),
uint(config.stringContents.length), }
) //edges
ttf.SetTextColor( sdl.SetRenderDrawColor(renderer_data.renderer, clay_to_sdl_color(config.color))
text, if config.width.left > 0 {
u8(config.textColor.r), starting_y := rect.y + clampedRadii.topLeft
u8(config.textColor.g), length := rect.h - clampedRadii.topLeft - clampedRadii.bottomLeft
u8(config.textColor.b), line := sdl.FRect{rect.x - 1, starting_y, f32(config.width.left), length}
u8(config.textColor.a), sdl.RenderFillRect(renderer_data.renderer, &line)
) }
ttf.DrawRendererText(text, rect.x, rect.y) if config.width.right > 0 {
ttf.DestroyText(text) starting_x := rect.x + rect.w - f32(config.width.right) + 1
starting_y := rect.y + clampedRadii.topRight
case .Border: length := rect.h - clampedRadii.topRight - clampedRadii.bottomRight
config := &rcmd.renderData.border line := sdl.FRect{starting_x, starting_y, f32(config.width.right), length}
sdl.RenderFillRect(renderer_data.renderer, &line)
minRadius := sdl.min(rect.w, rect.h) / 2 }
clampedRadii := clay.CornerRadius { if config.width.top > 0 {
topLeft = sdl.min(config.cornerRadius.topLeft, minRadius), starting_x := rect.x + clampedRadii.topLeft
topRight = sdl.min(config.cornerRadius.topRight, minRadius), length := rect.w - clampedRadii.topLeft - clampedRadii.topRight
bottomLeft = sdl.min(config.cornerRadius.bottomLeft, minRadius), line := sdl.FRect{starting_x, rect.y - 1, length, f32(config.width.top)}
bottomRight = sdl.min(config.cornerRadius.bottomRight, minRadius), sdl.RenderFillRect(renderer_data.renderer, &line)
} }
//edges if config.width.bottom > 0 {
sdl.SetRenderDrawColor( starting_x := rect.x + clampedRadii.bottomLeft
rendererData.renderer, starting_y := rect.y + rect.h - f32(config.width.bottom) + 1
u8(config.color.r), length := rect.w - clampedRadii.bottomLeft - clampedRadii.bottomRight
u8(config.color.g), line := sdl.FRect{starting_x, starting_y, length, f32(config.width.bottom)}
u8(config.color.b), sdl.SetRenderDrawColor(renderer_data.renderer, clay_to_sdl_color(config.color))
u8(config.color.a), sdl.RenderFillRect(renderer_data.renderer, &line)
) }
if (config.width.left > 0) { //corners
starting_y := rect.y + clampedRadii.topLeft if config.cornerRadius.topLeft > 0 {
length := rect.h - clampedRadii.topLeft - clampedRadii.bottomLeft centerX := rect.x + clampedRadii.topLeft - 1
line := sdl.FRect{rect.x - 1, starting_y, f32(config.width.left), length} centerY := rect.y + clampedRadii.topLeft - 1
sdl.RenderFillRect(rendererData.renderer, &line) render_arc(renderer_data, {centerX, centerY}, clampedRadii.topLeft, 180, 270, f32(config.width.top), config.color)
} }
if (config.width.right > 0) { if config.cornerRadius.topRight > 0 {
starting_x := rect.x + rect.w - f32(config.width.right) + 1 centerX := rect.x + rect.w - clampedRadii.topRight
starting_y := rect.y + clampedRadii.topRight centerY := rect.y + clampedRadii.topRight - 1
length := rect.h - clampedRadii.topRight - clampedRadii.bottomRight render_arc(renderer_data, {centerX, centerY}, clampedRadii.topRight, 270, 360, f32(config.width.top), config.color)
line := sdl.FRect{starting_x, starting_y, f32(config.width.right), length} }
sdl.RenderFillRect(rendererData.renderer, &line) if config.cornerRadius.bottomLeft > 0 {
} centerX := rect.x + clampedRadii.bottomLeft - 1
if (config.width.top > 0) { centerY := rect.y + rect.h - clampedRadii.bottomLeft
starting_x := rect.x + clampedRadii.topLeft render_arc(renderer_data, {centerX, centerY}, clampedRadii.bottomLeft, 90, 180, f32(config.width.bottom), config.color)
length := rect.w - clampedRadii.topLeft - clampedRadii.topRight }
line := sdl.FRect{starting_x, rect.y - 1, length, f32(config.width.top)} if config.cornerRadius.bottomRight > 0 {
sdl.RenderFillRect(rendererData.renderer, &line) centerX := rect.x + rect.w - clampedRadii.bottomRight
} centerY := rect.y + rect.h - clampedRadii.bottomRight
if (config.width.bottom > 0) { render_arc(renderer_data, {centerX, centerY}, clampedRadii.bottomRight, 0, 90, f32(config.width.bottom), config.color)
starting_x := rect.x + clampedRadii.bottomLeft }
starting_y := rect.y + rect.h - f32(config.width.bottom) + 1
length := rect.w - clampedRadii.bottomLeft - clampedRadii.bottomRight
line := sdl.FRect{starting_x, starting_y, length, f32(config.width.bottom)} case .ScissorStart:
sdl.SetRenderDrawColor( boundingBox := cmd.boundingBox
rendererData.renderer, current_clipping_rect = sdl.Rect {
u8(config.color.r), x = i32(boundingBox.x),
u8(config.color.g), y = i32(boundingBox.y),
u8(config.color.b), w = i32(boundingBox.width),
u8(config.color.a), h = i32(boundingBox.height),
) }
sdl.RenderFillRect(rendererData.renderer, &line) sdl.SetRenderClipRect(renderer_data.renderer, &current_clipping_rect)
}
//corners case .ScissorEnd:
if (config.cornerRadius.topLeft > 0) { sdl.SetRenderClipRect(renderer_data.renderer, nil)
centerX := rect.x + clampedRadii.topLeft - 1
centerY := rect.y + clampedRadii.topLeft - 1
sdl_Clay_RenderArc( case .Image:
rendererData, texture := (^sdl.Texture)(cmd.renderData.image.imageData)
(sdl.FPoint){centerX, centerY}, dest := sdl.FRect{rect.x, rect.y, rect.w, rect.h}
clampedRadii.topLeft, sdl.RenderTexture(renderer_data.renderer, texture, nil, &dest)
180.0,
270.0,
f32(config.width.top), case:
config.color, sdl.Log("Unknown render command type: %d", cmd.commandType)
) }
} }
if (config.cornerRadius.topRight > 0) {
centerX := rect.x + rect.w - clampedRadii.topRight
centerY := rect.y + clampedRadii.topRight - 1
sdl_Clay_RenderArc(
rendererData,
(sdl.FPoint){centerX, centerY},
clampedRadii.topRight,
270.0,
360.0,
f32(config.width.top),
config.color,
)
}
if (config.cornerRadius.bottomLeft > 0) {
centerX := rect.x + clampedRadii.bottomLeft - 1
centerY := rect.y + rect.h - clampedRadii.bottomLeft
sdl_Clay_RenderArc(
rendererData,
(sdl.FPoint){centerX, centerY},
clampedRadii.bottomLeft,
90.0,
180.0,
f32(config.width.bottom),
config.color,
)
}
if (config.cornerRadius.bottomRight > 0) {
centerX := rect.x + rect.w - clampedRadii.bottomRight
centerY := rect.y + rect.h - clampedRadii.bottomRight
sdl_Clay_RenderArc(
rendererData,
(sdl.FPoint){centerX, centerY},
clampedRadii.bottomRight,
0.0,
90.0,
f32(config.width.bottom),
config.color,
)
}
case .ScissorStart:
boundingBox := rcmd.boundingBox
currentClippingRectangle = (sdl.Rect) {
x = i32(boundingBox.x),
y = i32(boundingBox.y),
w = i32(boundingBox.width),
h = i32(boundingBox.height),
}
sdl.SetRenderClipRect(rendererData.renderer, &currentClippingRectangle)
case .ScissorEnd:
sdl.SetRenderClipRect(rendererData.renderer, nil)
case .Image:
texture := (^sdl.Texture)(rcmd.renderData.image.imageData)
dest := sdl.FRect{rect.x, rect.y, rect.w, rect.h}
sdl.RenderTexture(rendererData.renderer, texture, nil, &dest)
case:
sdl.Log("Unknown render command type: %d", rcmd.commandType)
}
}
} }