From 0953462b3b137b3be60ed6ac3447085773093ecd Mon Sep 17 00:00:00 2001 From: Zachary Levy Date: Sun, 19 Apr 2026 19:37:27 -0700 Subject: [PATCH] Massive renaming --- draw/draw.odin | 175 +++++----- draw/examples/hellope.odin | 16 +- draw/pipeline_2d_base.odin | 136 ++++---- draw/shapes.odin | 668 +++++++++++++++++++------------------ draw/text.odin | 68 ++-- 5 files changed, 551 insertions(+), 512 deletions(-) diff --git a/draw/draw.odin b/draw/draw.odin index 4f9f95c..5247692 100644 --- a/draw/draw.odin +++ b/draw/draw.odin @@ -36,14 +36,14 @@ BLUE :: Color{0, 0, 255, 255} BLANK :: Color{0, 0, 0, 0} // Convert clay.Color ([4]c.float in 0–255 range) to Color. -color_from_clay :: proc(cc: clay.Color) -> Color { - return Color{u8(cc[0]), u8(cc[1]), u8(cc[2]), u8(cc[3])} +color_from_clay :: proc(clay_color: clay.Color) -> Color { + return Color{u8(clay_color[0]), u8(clay_color[1]), u8(clay_color[2]), u8(clay_color[3])} } // Convert Color to [4]f32 in 0.0–1.0 range. Useful for SDL interop (e.g. clear color). -color_to_f32 :: proc(c: Color) -> [4]f32 { +color_to_f32 :: proc(color: Color) -> [4]f32 { INV :: 1.0 / 255.0 - return {f32(c[0]) * INV, f32(c[1]) * INV, f32(c[2]) * INV, f32(c[3]) * INV} + return {f32(color[0]) * INV, f32(color[1]) * INV, f32(color[2]) * INV, f32(color[3]) * INV} } // --------------------------------------------------------------------------------------------------------------------- @@ -51,10 +51,10 @@ color_to_f32 :: proc(c: Color) -> [4]f32 { // --------------------------------------------------------------------------------------------------------------------- Rectangle :: struct { - x: f32, - y: f32, - w: f32, - h: f32, + x: f32, + y: f32, + width: f32, + height: f32, } Sub_Batch_Kind :: enum u8 { @@ -102,7 +102,7 @@ Global :: struct { tmp_primitives: [dynamic]Primitive, tmp_sub_batches: [dynamic]Sub_Batch, tmp_uncached_text: [dynamic]^sdl_ttf.Text, // Uncached TTF_Text objects to destroy after end() - clay_mem: [^]u8, + clay_memory: [^]u8, msaa_texture: ^sdl.GPUTexture, curr_layer_index: uint, max_layers: int, @@ -114,8 +114,8 @@ Global :: struct { max_primitives: int, max_sub_batches: int, dpi_scaling: f32, - msaa_w: u32, - msaa_h: u32, + msaa_width: u32, + msaa_height: u32, sample_count: sdl.GPUSampleCount, clay_z_index: i16, cleared: bool, @@ -174,13 +174,13 @@ init :: proc( tmp_uncached_text = make([dynamic]^sdl_ttf.Text, 0, 16, allocator = allocator), odin_context = odin_context, dpi_scaling = sdl.GetWindowDisplayScale(window), - clay_mem = make([^]u8, min_memory_size, allocator = allocator), + clay_memory = make([^]u8, min_memory_size, allocator = allocator), sample_count = resolved_sample_count, pipeline_2d_base = pipeline, text_cache = text_cache, } log.debug("Window DPI scaling:", GLOB.dpi_scaling) - arena := clay.CreateArenaWithCapacityAndMemory(min_memory_size, GLOB.clay_mem) + arena := clay.CreateArenaWithCapacityAndMemory(min_memory_size, GLOB.clay_memory) window_width, window_height: c.int sdl.GetWindowSize(window, &window_width, &window_height) @@ -219,9 +219,9 @@ destroy :: proc(device: ^sdl.GPUDevice, allocator := context.allocator) { delete(GLOB.tmp_text_batches) delete(GLOB.tmp_primitives) delete(GLOB.tmp_sub_batches) - for t in GLOB.tmp_uncached_text do sdl_ttf.DestroyText(t) + for ttf_text in GLOB.tmp_uncached_text do sdl_ttf.DestroyText(ttf_text) delete(GLOB.tmp_uncached_text) - free(GLOB.clay_mem, allocator) + free(GLOB.clay_memory, allocator) if GLOB.msaa_texture != nil { sdl.ReleaseGPUTexture(device, GLOB.msaa_texture) } @@ -235,7 +235,7 @@ clear_global :: proc() { GLOB.clay_z_index = 0 GLOB.cleared = false // Destroy uncached TTF_Text objects from the previous frame (after end() has submitted draw data) - for t in GLOB.tmp_uncached_text do sdl_ttf.DestroyText(t) + for ttf_text in GLOB.tmp_uncached_text do sdl_ttf.DestroyText(ttf_text) clear(&GLOB.tmp_uncached_text) clear(&GLOB.layers) clear(&GLOB.scissors) @@ -260,12 +260,12 @@ measure_text_clay :: proc "c" ( context = GLOB.odin_context text := string(text.chars[:text.length]) c_text := strings.clone_to_cstring(text, context.temp_allocator) - w, h: c.int - if !sdl_ttf.GetStringSize(get_font(config.fontId, config.fontSize), c_text, 0, &w, &h) { + width, height: c.int + if !sdl_ttf.GetStringSize(get_font(config.fontId, config.fontSize), c_text, 0, &width, &height) { log.panicf("Failed to measure text: %s", sdl.GetError()) } - return clay.Dimensions{width = f32(w) / GLOB.dpi_scaling, height = f32(h) / GLOB.dpi_scaling} + return clay.Dimensions{width = f32(width) / GLOB.dpi_scaling, height = f32(height) / GLOB.dpi_scaling} } // --------------------------------------------------------------------------------------------------------------------- @@ -282,8 +282,8 @@ begin :: proc(bounds: Rectangle) -> ^Layer { bounds = sdl.Rect { x = i32(bounds.x * GLOB.dpi_scaling), y = i32(bounds.y * GLOB.dpi_scaling), - w = i32(bounds.w * GLOB.dpi_scaling), - h = i32(bounds.h * GLOB.dpi_scaling), + w = i32(bounds.width * GLOB.dpi_scaling), + h = i32(bounds.height * GLOB.dpi_scaling), }, } append(&GLOB.scissors, scissor) @@ -313,8 +313,8 @@ new_layer :: proc(prev_layer: ^Layer, bounds: Rectangle) -> ^Layer { bounds = sdl.Rect { x = i32(bounds.x * GLOB.dpi_scaling), y = i32(bounds.y * GLOB.dpi_scaling), - w = i32(bounds.w * GLOB.dpi_scaling), - h = i32(bounds.h * GLOB.dpi_scaling), + w = i32(bounds.width * GLOB.dpi_scaling), + h = i32(bounds.height * GLOB.dpi_scaling), }, } append(&GLOB.scissors, scissor) @@ -344,8 +344,8 @@ prepare_sdf_primitive :: proc(layer: ^Layer, prim: Primitive) { // Submit a text element to the given layer for rendering. // Copies SDL_ttf vertices directly (with baked position) and copies indices for indexed drawing. -prepare_text :: proc(layer: ^Layer, txt: Text) { - data := sdl_ttf.GetGPUTextDrawData(txt.ref) +prepare_text :: proc(layer: ^Layer, text: Text) { + data := sdl_ttf.GetGPUTextDrawData(text.sdl_text) if data == nil { return // nil is normal for empty text } @@ -363,9 +363,9 @@ prepare_text :: proc(layer: ^Layer, txt: Text) { append( &GLOB.tmp_text_verts, Vertex { - position = {pos.x + txt.position[0] * GLOB.dpi_scaling, -pos.y + txt.position[1] * GLOB.dpi_scaling}, + position = {pos.x + text.position[0] * GLOB.dpi_scaling, -pos.y + text.position[1] * GLOB.dpi_scaling}, uv = {uv.x, uv.y}, - color = txt.color, + color = text.color, }, ) } @@ -396,8 +396,8 @@ prepare_text :: proc(layer: ^Layer, txt: Text) { // Used by the high-level `text` proc when rotation or a non-zero origin is specified. // NOTE: xform must be in physical (DPI-scaled) pixel space — the caller pre-scales // pos and origin by GLOB.dpi_scaling before building the transform. -prepare_text_transformed :: proc(layer: ^Layer, txt: Text, xform: Transform_2D) { - data := sdl_ttf.GetGPUTextDrawData(txt.ref) +prepare_text_transformed :: proc(layer: ^Layer, text: Text, transform: Transform_2D) { + data := sdl_ttf.GetGPUTextDrawData(text.sdl_text) if data == nil { return } @@ -416,7 +416,7 @@ prepare_text_transformed :: proc(layer: ^Layer, txt: Text, xform: Transform_2D) // so we apply directly — no per-vertex DPI divide/multiply. append( &GLOB.tmp_text_verts, - Vertex{position = apply_transform(xform, {pos.x, -pos.y}), uv = {uv.x, uv.y}, color = txt.color}, + Vertex{position = apply_transform(transform, {pos.x, -pos.y}), uv = {uv.x, uv.y}, color = text.color}, ) } @@ -501,10 +501,10 @@ prepare_clay_batch :: proc( // Translate bounding box of the primitive by the layer position bounds := Rectangle { - x = render_command.boundingBox.x + layer.bounds.x, - y = render_command.boundingBox.y + layer.bounds.y, - w = render_command.boundingBox.width, - h = render_command.boundingBox.height, + x = render_command.boundingBox.x + layer.bounds.x, + y = render_command.boundingBox.y + layer.bounds.y, + width = render_command.boundingBox.width, + height = render_command.boundingBox.height, } if render_command.zIndex > GLOB.clay_z_index { @@ -532,9 +532,7 @@ prepare_clay_batch :: proc( prepare_text(layer, Text{sdl_text, {bounds.x, bounds.y}, color_from_clay(render_data.textColor)}) case clay.RenderCommandType.Image: case clay.RenderCommandType.ScissorStart: - if bounds.w == 0 || bounds.h == 0 { - continue - } + if bounds.width == 0 || bounds.height == 0 do continue curr_scissor := &GLOB.scissors[layer.scissor_start + layer.scissor_len - 1] @@ -545,8 +543,8 @@ prepare_clay_batch :: proc( bounds = sdl.Rect { c.int(bounds.x * GLOB.dpi_scaling), c.int(bounds.y * GLOB.dpi_scaling), - c.int(bounds.w * GLOB.dpi_scaling), - c.int(bounds.h * GLOB.dpi_scaling), + c.int(bounds.width * GLOB.dpi_scaling), + c.int(bounds.height * GLOB.dpi_scaling), }, } append(&GLOB.scissors, new) @@ -555,8 +553,8 @@ prepare_clay_batch :: proc( curr_scissor.bounds = sdl.Rect { c.int(bounds.x * GLOB.dpi_scaling), c.int(bounds.y * GLOB.dpi_scaling), - c.int(bounds.w * GLOB.dpi_scaling), - c.int(bounds.h * GLOB.dpi_scaling), + c.int(bounds.width * GLOB.dpi_scaling), + c.int(bounds.height * GLOB.dpi_scaling), } } case clay.RenderCommandType.ScissorEnd: @@ -575,13 +573,13 @@ prepare_clay_batch :: proc( render_data := render_command.renderData.border cr := render_data.cornerRadius color := color_from_clay(render_data.color) - thick := f32(render_data.width.top) + thickness := f32(render_data.width.top) radii := [4]f32{cr.topLeft, cr.topRight, cr.bottomRight, cr.bottomLeft} if radii == {0, 0, 0, 0} { - rectangle_lines(layer, bounds, color, thick) + rectangle_lines(layer, bounds, color, thickness) } else { - rectangle_corners_lines(layer, bounds, radii, color, thick) + rectangle_corners_lines(layer, bounds, radii, color, thickness) } case clay.RenderCommandType.Custom: } @@ -601,8 +599,8 @@ end :: proc(device: ^sdl.GPUDevice, window: ^sdl.Window, clear_color: Color = BL sdl.EndGPUCopyPass(copy_pass) swapchain_texture: ^sdl.GPUTexture - w, h: u32 - if !sdl.WaitAndAcquireGPUSwapchainTexture(cmd_buffer, window, &swapchain_texture, &w, &h) { + width, height: u32 + if !sdl.WaitAndAcquireGPUSwapchainTexture(cmd_buffer, window, &swapchain_texture, &width, &height) { log.panicf("Failed to acquire swapchain texture: %s", sdl.GetError()) } @@ -618,16 +616,16 @@ end :: proc(device: ^sdl.GPUDevice, window: ^sdl.Window, clear_color: Color = BL render_texture := swapchain_texture if use_msaa { - ensure_msaa_texture(device, sdl.GetGPUSwapchainTextureFormat(device, window), w, h) + ensure_msaa_texture(device, sdl.GetGPUSwapchainTextureFormat(device, window), width, height) render_texture = GLOB.msaa_texture } - cc := color_to_f32(clear_color) + clear_color_f32 := color_to_f32(clear_color) // Draw layers. One render pass per layer; sub-batches draw in submission order within each scissor. for &layer, index in GLOB.layers { log.debug("Drawing layer", index) - draw_layer(device, window, cmd_buffer, render_texture, w, h, cc, &layer) + draw_layer(device, window, cmd_buffer, render_texture, width, height, clear_color_f32, &layer) } // Resolve MSAA render texture to the swapchain. @@ -659,15 +657,15 @@ end :: proc(device: ^sdl.GPUDevice, window: ^sdl.Window, clear_color: Color = BL max_sample_count :: proc(device: ^sdl.GPUDevice, window: ^sdl.Window) -> sdl.GPUSampleCount { format := sdl.GetGPUSwapchainTextureFormat(device, window) counts := [?]sdl.GPUSampleCount{._8, ._4, ._2} - for sc in counts { - if sdl.GPUTextureSupportsSampleCount(device, format, sc) do return sc + for count in counts { + if sdl.GPUTextureSupportsSampleCount(device, format, count) do return count } return ._1 } @(private = "file") -ensure_msaa_texture :: proc(device: ^sdl.GPUDevice, format: sdl.GPUTextureFormat, w, h: u32) { - if GLOB.msaa_texture != nil && GLOB.msaa_w == w && GLOB.msaa_h == h { +ensure_msaa_texture :: proc(device: ^sdl.GPUDevice, format: sdl.GPUTextureFormat, width, height: u32) { + if GLOB.msaa_texture != nil && GLOB.msaa_width == width && GLOB.msaa_height == height { return } if GLOB.msaa_texture != nil { @@ -679,18 +677,18 @@ ensure_msaa_texture :: proc(device: ^sdl.GPUDevice, format: sdl.GPUTextureFormat type = .D2, format = format, usage = {.COLOR_TARGET}, - width = w, - height = h, + width = width, + height = height, layer_count_or_depth = 1, num_levels = 1, sample_count = GLOB.sample_count, }, ) if GLOB.msaa_texture == nil { - log.panicf("Failed to create MSAA texture (%dx%d): %s", w, h, sdl.GetError()) + log.panicf("Failed to create MSAA texture (%dx%d): %s", width, height, sdl.GetError()) } - GLOB.msaa_w = w - GLOB.msaa_h = h + GLOB.msaa_width = width + GLOB.msaa_height = height } // --------------------------------------------------------------------------------------------------------------------- @@ -718,9 +716,21 @@ Vertex_Uniforms :: struct { } // Push projection, dpi scale, and rendering mode as a single uniform block (slot 0). -push_globals :: proc(cmd_buffer: ^sdl.GPUCommandBuffer, w: f32, h: f32, mode: Draw_Mode = .Tessellated) { +push_globals :: proc( + cmd_buffer: ^sdl.GPUCommandBuffer, + width: f32, + height: f32, + mode: Draw_Mode = .Tessellated, +) { globals := Vertex_Uniforms { - projection = ortho_rh(left = 0.0, top = 0.0, right = f32(w), bottom = f32(h), near = -1.0, far = 1.0), + projection = ortho_rh( + left = 0.0, + top = 0.0, + right = f32(width), + bottom = f32(height), + near = -1.0, + far = 1.0, + ), scale = GLOB.dpi_scaling, mode = mode, } @@ -818,23 +828,26 @@ Transform_2D :: struct { // origin – pivot point in local space (measured from the shape's natural reference point). // rotation_deg – rotation in degrees, counter-clockwise. // -build_pivot_rot :: proc(pos: [2]f32, origin: [2]f32, rotation_deg: f32) -> Transform_2D { - rad := math.to_radians(rotation_deg) - c := math.cos(rad) - s := math.sin(rad) +build_pivot_rotation :: proc(position: [2]f32, origin: [2]f32, rotation_deg: f32) -> Transform_2D { + radians := math.to_radians(rotation_deg) + cos_angle := math.cos(radians) + sin_angle := math.sin(radians) return Transform_2D { - m00 = c, - m01 = -s, - m10 = s, - m11 = c, - tx = pos.x - (c * origin.x - s * origin.y), - ty = pos.y - (s * origin.x + c * origin.y), + m00 = cos_angle, + m01 = -sin_angle, + m10 = sin_angle, + m11 = cos_angle, + tx = position.x - (cos_angle * origin.x - sin_angle * origin.y), + ty = position.y - (sin_angle * origin.x + cos_angle * origin.y), } } // Apply the transform to a local-space point, producing a world-space point. -apply_transform :: #force_inline proc(t: Transform_2D, p: [2]f32) -> [2]f32 { - return {t.m00 * p.x + t.m01 * p.y + t.tx, t.m10 * p.x + t.m11 * p.y + t.ty} +apply_transform :: #force_inline proc(transform: Transform_2D, point: [2]f32) -> [2]f32 { + return { + transform.m00 * point.x + transform.m01 * point.y + transform.tx, + transform.m10 * point.x + transform.m11 * point.y + transform.ty, + } } // Fast-path check callers use BEFORE building a transform. @@ -849,55 +862,55 @@ needs_transform :: #force_inline proc(origin: [2]f32, rotation: f32) -> bool { // --------------------------------------------------------------------------------------------------------------------- center_of :: proc { - center_of_rect, + center_of_rectangle, center_of_triangle, center_of_text, } top_left_of :: proc { - top_left_of_rect, + top_left_of_rectangle, top_left_of_triangle, top_left_of_text, } top_of :: proc { - top_of_rect, + top_of_rectangle, top_of_triangle, top_of_text, } top_right_of :: proc { - top_right_of_rect, + top_right_of_rectangle, top_right_of_triangle, top_right_of_text, } left_of :: proc { - left_of_rect, + left_of_rectangle, left_of_triangle, left_of_text, } right_of :: proc { - right_of_rect, + right_of_rectangle, right_of_triangle, right_of_text, } bottom_left_of :: proc { - bottom_left_of_rect, + bottom_left_of_rectangle, bottom_left_of_triangle, bottom_left_of_text, } bottom_of :: proc { - bottom_of_rect, + bottom_of_rectangle, bottom_of_triangle, bottom_of_text, } bottom_right_of :: proc { - bottom_right_of_rect, + bottom_right_of_rectangle, bottom_right_of_triangle, bottom_right_of_text, } diff --git a/draw/examples/hellope.odin b/draw/examples/hellope.odin index 7cdcba5..3a6082b 100644 --- a/draw/examples/hellope.odin +++ b/draw/examples/hellope.odin @@ -24,14 +24,14 @@ hellope_shapes :: proc() { if ev.type == .QUIT do return } spin_angle += 1 - base_layer := draw.begin({w = 500, h = 500}) + base_layer := draw.begin({width = 500, height = 500}) // Background draw.rectangle(base_layer, {0, 0, 500, 500}, {40, 40, 40, 255}) // ----- Shapes without rotation (existing demo) ----- draw.rectangle(base_layer, {20, 20, 200, 120}, {80, 120, 200, 255}) - draw.rectangle_lines(base_layer, {20, 20, 200, 120}, draw.WHITE, thick = 2) + draw.rectangle_lines(base_layer, {20, 20, 200, 120}, draw.WHITE, thickness = 2) draw.rectangle(base_layer, {240, 20, 240, 120}, {200, 80, 80, 255}, roundness = 0.3) draw.rectangle_gradient( base_layer, @@ -57,7 +57,7 @@ hellope_shapes :: proc() { base_layer, rect, draw.WHITE, - thick = 2, + thickness = 2, origin = draw.center_of(rect), rotation = spin_angle, ) @@ -100,8 +100,8 @@ hellope_shapes :: proc() { ) // Polygon rotating around its center (already had rotation; now with origin for orbit) - draw.poly(base_layer, {460, 450}, 6, 30, {180, 100, 220, 255}, rotation = spin_angle) - draw.poly_lines(base_layer, {460, 450}, 6, 30, draw.WHITE, rotation = spin_angle, thick = 2) + draw.polygon(base_layer, {460, 450}, 6, 30, {180, 100, 220, 255}, rotation = spin_angle) + draw.polygon_lines(base_layer, {460, 450}, 6, 30, draw.WHITE, rotation = spin_angle, thickness = 2) draw.end(gpu, window) } @@ -125,7 +125,7 @@ hellope_text :: proc() { if ev.type == .QUIT do return } spin_angle += 0.5 - base_layer := draw.begin({w = 600, h = 600}) + base_layer := draw.begin({width = 600, height = 600}) // Grey background draw.rectangle(base_layer, {0, 0, 600, 600}, {127, 127, 127, 255}) @@ -217,8 +217,8 @@ hellope_clay :: proc() { for sdl.PollEvent(&ev) { if ev.type == .QUIT do return } - base_layer := draw.begin({w = 500, h = 500}) - clay.SetLayoutDimensions({width = base_layer.bounds.w, height = base_layer.bounds.h}) + base_layer := draw.begin({width = 500, height = 500}) + clay.SetLayoutDimensions({width = base_layer.bounds.width, height = base_layer.bounds.height}) clay.BeginLayout() if clay.UI()( { diff --git a/draw/pipeline_2d_base.odin b/draw/pipeline_2d_base.odin index d17bc56..80b4cd3 100644 --- a/draw/pipeline_2d_base.odin +++ b/draw/pipeline_2d_base.odin @@ -240,31 +240,31 @@ create_pipeline_2d_base :: proc( } // Create vertex buffer - vb_ok: bool - pipeline.vertex_buffer, vb_ok = create_buffer( + vert_buf_ok: bool + pipeline.vertex_buffer, vert_buf_ok = create_buffer( device, size_of(Vertex) * BUFFER_INIT_SIZE, sdl.GPUBufferUsageFlags{.VERTEX}, ) - if !vb_ok do return pipeline, false + if !vert_buf_ok do return pipeline, false // Create index buffer (used by text) - ib_ok: bool - pipeline.index_buffer, ib_ok = create_buffer( + idx_buf_ok: bool + pipeline.index_buffer, idx_buf_ok = create_buffer( device, size_of(c.int) * BUFFER_INIT_SIZE, sdl.GPUBufferUsageFlags{.INDEX}, ) - if !ib_ok do return pipeline, false + if !idx_buf_ok do return pipeline, false // Create primitive storage buffer (used by SDF instanced drawing) - pb_ok: bool - pipeline.primitive_buffer, pb_ok = create_buffer( + prim_buf_ok: bool + pipeline.primitive_buffer, prim_buf_ok = create_buffer( device, size_of(Primitive) * BUFFER_INIT_SIZE, sdl.GPUBufferUsageFlags{.GRAPHICS_STORAGE_READ}, ) - if !pb_ok do return pipeline, false + if !prim_buf_ok do return pipeline, false // Create static 6-vertex unit quad buffer (two triangles, TRIANGLELIST) pipeline.unit_quad_buffer = sdl.CreateGPUBuffer( @@ -297,23 +297,23 @@ create_pipeline_2d_base :: proc( // Upload white pixel and unit quad data in a single command buffer white_pixel := [4]u8{255, 255, 255, 255} - white_transfer := sdl.CreateGPUTransferBuffer( + white_transfer_buf := sdl.CreateGPUTransferBuffer( device, sdl.GPUTransferBufferCreateInfo{usage = .UPLOAD, size = size_of(white_pixel)}, ) - if white_transfer == nil { + if white_transfer_buf == nil { log.errorf("Failed to create white pixel transfer buffer: %s", sdl.GetError()) return pipeline, false } - defer sdl.ReleaseGPUTransferBuffer(device, white_transfer) + defer sdl.ReleaseGPUTransferBuffer(device, white_transfer_buf) - white_ptr := sdl.MapGPUTransferBuffer(device, white_transfer, false) + white_ptr := sdl.MapGPUTransferBuffer(device, white_transfer_buf, false) if white_ptr == nil { log.errorf("Failed to map white pixel transfer buffer: %s", sdl.GetError()) return pipeline, false } mem.copy(white_ptr, &white_pixel, size_of(white_pixel)) - sdl.UnmapGPUTransferBuffer(device, white_transfer) + sdl.UnmapGPUTransferBuffer(device, white_transfer_buf) quad_verts := [6]Vertex { {position = {0, 0}}, @@ -323,47 +323,47 @@ create_pipeline_2d_base :: proc( {position = {1, 0}}, {position = {1, 1}}, } - quad_transfer := sdl.CreateGPUTransferBuffer( + quad_transfer_buf := sdl.CreateGPUTransferBuffer( device, sdl.GPUTransferBufferCreateInfo{usage = .UPLOAD, size = size_of(quad_verts)}, ) - if quad_transfer == nil { + if quad_transfer_buf == nil { log.errorf("Failed to create unit quad transfer buffer: %s", sdl.GetError()) return pipeline, false } - defer sdl.ReleaseGPUTransferBuffer(device, quad_transfer) + defer sdl.ReleaseGPUTransferBuffer(device, quad_transfer_buf) - quad_ptr := sdl.MapGPUTransferBuffer(device, quad_transfer, false) + quad_ptr := sdl.MapGPUTransferBuffer(device, quad_transfer_buf, false) if quad_ptr == nil { log.errorf("Failed to map unit quad transfer buffer: %s", sdl.GetError()) return pipeline, false } mem.copy(quad_ptr, &quad_verts, size_of(quad_verts)) - sdl.UnmapGPUTransferBuffer(device, quad_transfer) + sdl.UnmapGPUTransferBuffer(device, quad_transfer_buf) - upload_cmd := sdl.AcquireGPUCommandBuffer(device) - if upload_cmd == nil { + upload_cmd_buffer := sdl.AcquireGPUCommandBuffer(device) + if upload_cmd_buffer == nil { log.errorf("Failed to acquire command buffer for init upload: %s", sdl.GetError()) return pipeline, false } - upload_pass := sdl.BeginGPUCopyPass(upload_cmd) + upload_pass := sdl.BeginGPUCopyPass(upload_cmd_buffer) sdl.UploadToGPUTexture( upload_pass, - sdl.GPUTextureTransferInfo{transfer_buffer = white_transfer}, + sdl.GPUTextureTransferInfo{transfer_buffer = white_transfer_buf}, sdl.GPUTextureRegion{texture = pipeline.white_texture, w = 1, h = 1, d = 1}, false, ) sdl.UploadToGPUBuffer( upload_pass, - sdl.GPUTransferBufferLocation{transfer_buffer = quad_transfer}, + sdl.GPUTransferBufferLocation{transfer_buffer = quad_transfer_buf}, sdl.GPUBufferRegion{buffer = pipeline.unit_quad_buffer, offset = 0, size = size_of(quad_verts)}, false, ) sdl.EndGPUCopyPass(upload_pass) - if !sdl.SubmitGPUCommandBuffer(upload_cmd) { + if !sdl.SubmitGPUCommandBuffer(upload_cmd_buffer) { log.errorf("Failed to submit init upload command buffer: %s", sdl.GetError()) return pipeline, false } @@ -410,16 +410,16 @@ upload :: proc(device: ^sdl.GPUDevice, pass: ^sdl.GPUCopyPass) { sdl.GPUBufferUsageFlags{.VERTEX}, ) - v_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.vertex_buffer.transfer, false) - if v_array == nil { + vert_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.vertex_buffer.transfer, false) + if vert_array == nil { log.panicf("Failed to map vertex transfer buffer: %s", sdl.GetError()) } if shape_vert_size > 0 { - mem.copy(v_array, raw_data(GLOB.tmp_shape_verts), int(shape_vert_size)) + mem.copy(vert_array, raw_data(GLOB.tmp_shape_verts), int(shape_vert_size)) } if text_vert_size > 0 { mem.copy( - rawptr(uintptr(v_array) + uintptr(shape_vert_size)), + rawptr(uintptr(vert_array) + uintptr(shape_vert_size)), raw_data(GLOB.tmp_text_verts), int(text_vert_size), ) @@ -446,11 +446,11 @@ upload :: proc(device: ^sdl.GPUDevice, pass: ^sdl.GPUCopyPass) { sdl.GPUBufferUsageFlags{.INDEX}, ) - i_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.index_buffer.transfer, false) - if i_array == nil { + idx_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.index_buffer.transfer, false) + if idx_array == nil { log.panicf("Failed to map index transfer buffer: %s", sdl.GetError()) } - mem.copy(i_array, raw_data(GLOB.tmp_text_indices), int(index_size)) + mem.copy(idx_array, raw_data(GLOB.tmp_text_indices), int(index_size)) sdl.UnmapGPUTransferBuffer(device, GLOB.pipeline_2d_base.index_buffer.transfer) sdl.UploadToGPUBuffer( @@ -473,11 +473,11 @@ upload :: proc(device: ^sdl.GPUDevice, pass: ^sdl.GPUCopyPass) { sdl.GPUBufferUsageFlags{.GRAPHICS_STORAGE_READ}, ) - p_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.primitive_buffer.transfer, false) - if p_array == nil { + prim_array := sdl.MapGPUTransferBuffer(device, GLOB.pipeline_2d_base.primitive_buffer.transfer, false) + if prim_array == nil { log.panicf("Failed to map primitive transfer buffer: %s", sdl.GetError()) } - mem.copy(p_array, raw_data(GLOB.tmp_primitives), int(prim_size)) + mem.copy(prim_array, raw_data(GLOB.tmp_primitives), int(prim_size)) sdl.UnmapGPUTransferBuffer(device, GLOB.pipeline_2d_base.primitive_buffer.transfer) sdl.UploadToGPUBuffer( @@ -495,8 +495,8 @@ draw_layer :: proc( window: ^sdl.Window, cmd_buffer: ^sdl.GPUCommandBuffer, render_texture: ^sdl.GPUTexture, - swapchain_w: u32, - swapchain_h: u32, + swapchain_width: u32, + swapchain_height: u32, clear_color: [4]f32, layer: ^Layer, ) { @@ -550,19 +550,19 @@ draw_layer :: proc( ) // Shorthand aliases for frequently-used pipeline resources - main_vbuf := GLOB.pipeline_2d_base.vertex_buffer.gpu + main_vert_buf := GLOB.pipeline_2d_base.vertex_buffer.gpu unit_quad := GLOB.pipeline_2d_base.unit_quad_buffer - white := GLOB.pipeline_2d_base.white_texture + white_texture := GLOB.pipeline_2d_base.white_texture sampler := GLOB.pipeline_2d_base.sampler - w := f32(swapchain_w) - h := f32(swapchain_h) + width := f32(swapchain_width) + height := f32(swapchain_height) // Initial GPU state: tessellated mode, main vertex buffer, no atlas bound yet - push_globals(cmd_buffer, w, h, .Tessellated) - sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vbuf, offset = 0}, 1) + push_globals(cmd_buffer, width, height, .Tessellated) + sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vert_buf, offset = 0}, 1) current_mode: Draw_Mode = .Tessellated - current_vbuf := main_vbuf + current_vert_buf := main_vert_buf current_atlas: ^sdl.GPUTexture // Text vertices live after shape vertices in the GPU vertex buffer @@ -575,69 +575,69 @@ draw_layer :: proc( switch batch.kind { case .Shapes: if current_mode != .Tessellated { - push_globals(cmd_buffer, w, h, .Tessellated) + push_globals(cmd_buffer, width, height, .Tessellated) current_mode = .Tessellated } - if current_vbuf != main_vbuf { - sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vbuf, offset = 0}, 1) - current_vbuf = main_vbuf + if current_vert_buf != main_vert_buf { + sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vert_buf, offset = 0}, 1) + current_vert_buf = main_vert_buf } - if current_atlas != white { + if current_atlas != white_texture { sdl.BindGPUFragmentSamplers( render_pass, 0, - &sdl.GPUTextureSamplerBinding{texture = white, sampler = sampler}, + &sdl.GPUTextureSamplerBinding{texture = white_texture, sampler = sampler}, 1, ) - current_atlas = white + current_atlas = white_texture } sdl.DrawGPUPrimitives(render_pass, batch.count, 1, batch.offset, 0) case .Text: if current_mode != .Tessellated { - push_globals(cmd_buffer, w, h, .Tessellated) + push_globals(cmd_buffer, width, height, .Tessellated) current_mode = .Tessellated } - if current_vbuf != main_vbuf { - sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vbuf, offset = 0}, 1) - current_vbuf = main_vbuf + if current_vert_buf != main_vert_buf { + sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = main_vert_buf, offset = 0}, 1) + current_vert_buf = main_vert_buf } - chunk := &GLOB.tmp_text_batches[batch.offset] - if current_atlas != chunk.atlas_texture { + text_batch := &GLOB.tmp_text_batches[batch.offset] + if current_atlas != text_batch.atlas_texture { sdl.BindGPUFragmentSamplers( render_pass, 0, - &sdl.GPUTextureSamplerBinding{texture = chunk.atlas_texture, sampler = sampler}, + &sdl.GPUTextureSamplerBinding{texture = text_batch.atlas_texture, sampler = sampler}, 1, ) - current_atlas = chunk.atlas_texture + current_atlas = text_batch.atlas_texture } sdl.DrawGPUIndexedPrimitives( render_pass, - chunk.index_count, + text_batch.index_count, 1, - chunk.index_start, - i32(text_vertex_gpu_base + chunk.vertex_start), + text_batch.index_start, + i32(text_vertex_gpu_base + text_batch.vertex_start), 0, ) case .SDF: if current_mode != .SDF { - push_globals(cmd_buffer, w, h, .SDF) + push_globals(cmd_buffer, width, height, .SDF) current_mode = .SDF } - if current_vbuf != unit_quad { + if current_vert_buf != unit_quad { sdl.BindGPUVertexBuffers(render_pass, 0, &sdl.GPUBufferBinding{buffer = unit_quad, offset = 0}, 1) - current_vbuf = unit_quad + current_vert_buf = unit_quad } - if current_atlas != white { + if current_atlas != white_texture { sdl.BindGPUFragmentSamplers( render_pass, 0, - &sdl.GPUTextureSamplerBinding{texture = white, sampler = sampler}, + &sdl.GPUTextureSamplerBinding{texture = white_texture, sampler = sampler}, 1, ) - current_atlas = white + current_atlas = white_texture } sdl.DrawGPUPrimitives(render_pass, 6, batch.count, 0, batch.offset) } diff --git a/draw/shapes.odin b/draw/shapes.odin index ade129a..2b15f25 100644 --- a/draw/shapes.odin +++ b/draw/shapes.odin @@ -10,12 +10,12 @@ auto_segments :: proc(radius: f32, arc_degrees: f32) -> int { if radius <= 0 do return 4 phys_radius := radius * GLOB.dpi_scaling acos_arg := clamp(2 * math.pow(1 - SMOOTH_CIRCLE_ERROR_RATE / phys_radius, 2) - 1, -1, 1) - th := math.acos(acos_arg) - if th <= 0 do return 4 - full_circle_segs := int(math.ceil(2 * math.PI / th)) - segs := int(f32(full_circle_segs) * arc_degrees / 360.0) - min_segs := max(int(math.ceil(f64(arc_degrees / 90.0))), 4) - return max(segs, min_segs) + theta := math.acos(acos_arg) + if theta <= 0 do return 4 + full_circle_segments := int(math.ceil(2 * math.PI / theta)) + segments := int(f32(full_circle_segments) * arc_degrees / 360.0) + min_segments := max(int(math.ceil(f64(arc_degrees / 90.0))), 4) + return max(segments, min_segments) } // ----- Internal helpers ---- @@ -23,56 +23,56 @@ auto_segments :: proc(radius: f32, arc_degrees: f32) -> int { @(private = "file") extrude_line :: proc( start, end_pos: [2]f32, - thick: f32, + thickness: f32, color: Color, vertices: []Vertex, offset: int, ) -> int { direction := end_pos - start - dx := direction[0] - dy := direction[1] - length := math.sqrt(dx * dx + dy * dy) + delta_x := direction[0] + delta_y := direction[1] + length := math.sqrt(delta_x * delta_x + delta_y * delta_y) if length < 0.0001 do return 0 - scale := thick / (2 * length) - perpendicular := [2]f32{-dy * scale, dx * scale} + scale := thickness / (2 * length) + perpendicular := [2]f32{-delta_y * scale, delta_x * scale} p0 := start + perpendicular p1 := start - perpendicular p2 := end_pos - perpendicular p3 := end_pos + perpendicular - vertices[offset + 0] = sv(p0, color) - vertices[offset + 1] = sv(p1, color) - vertices[offset + 2] = sv(p2, color) - vertices[offset + 3] = sv(p0, color) - vertices[offset + 4] = sv(p2, color) - vertices[offset + 5] = sv(p3, color) + vertices[offset + 0] = solid_vertex(p0, color) + vertices[offset + 1] = solid_vertex(p1, color) + vertices[offset + 2] = solid_vertex(p2, color) + vertices[offset + 3] = solid_vertex(p0, color) + vertices[offset + 4] = solid_vertex(p2, color) + vertices[offset + 5] = solid_vertex(p3, color) return 6 } // Create a vertex for solid-color shape drawing (no texture, UV defaults to zero). @(private = "file") -sv :: proc(pos: [2]f32, color: Color) -> Vertex { - return Vertex{position = pos, color = color} +solid_vertex :: proc(position: [2]f32, color: Color) -> Vertex { + return Vertex{position = position, color = color} } @(private = "file") -emit_rect :: proc(x, y, w, h: f32, color: Color, vertices: []Vertex, offset: int) { - vertices[offset + 0] = sv({x, y}, color) - vertices[offset + 1] = sv({x + w, y}, color) - vertices[offset + 2] = sv({x + w, y + h}, color) - vertices[offset + 3] = sv({x, y}, color) - vertices[offset + 4] = sv({x + w, y + h}, color) - vertices[offset + 5] = sv({x, y + h}, color) +emit_rectangle :: proc(x, y, width, height: f32, color: Color, vertices: []Vertex, offset: int) { + vertices[offset + 0] = solid_vertex({x, y}, color) + vertices[offset + 1] = solid_vertex({x + width, y}, color) + vertices[offset + 2] = solid_vertex({x + width, y + height}, color) + vertices[offset + 3] = solid_vertex({x, y}, color) + vertices[offset + 4] = solid_vertex({x + width, y + height}, color) + vertices[offset + 5] = solid_vertex({x, y + height}, color) } // ----- Drawing functions ---- pixel :: proc(layer: ^Layer, pos: [2]f32, color: Color) { vertices: [6]Vertex - emit_rect(pos[0], pos[1], 1, 1, color, vertices[:], 0) + emit_rectangle(pos[0], pos[1], 1, 1, color, vertices[:], 0) prepare_shape(layer, vertices[:]) } @@ -84,17 +84,17 @@ rectangle_gradient :: proc( ) { vertices := make([]Vertex, 6, temp_allocator) - tl := [2]f32{rect.x, rect.y} - tr := [2]f32{rect.x + rect.w, rect.y} - br := [2]f32{rect.x + rect.w, rect.y + rect.h} - bl := [2]f32{rect.x, rect.y + rect.h} + corner_top_left := [2]f32{rect.x, rect.y} + corner_top_right := [2]f32{rect.x + rect.width, rect.y} + corner_bottom_right := [2]f32{rect.x + rect.width, rect.y + rect.height} + corner_bottom_left := [2]f32{rect.x, rect.y + rect.height} - vertices[0] = sv(tl, top_left) - vertices[1] = sv(tr, top_right) - vertices[2] = sv(br, bottom_right) - vertices[3] = sv(tl, top_left) - vertices[4] = sv(br, bottom_right) - vertices[5] = sv(bl, bottom_left) + vertices[0] = solid_vertex(corner_top_left, top_left) + vertices[1] = solid_vertex(corner_top_right, top_right) + vertices[2] = solid_vertex(corner_bottom_right, bottom_right) + vertices[3] = solid_vertex(corner_top_left, top_left) + vertices[4] = solid_vertex(corner_bottom_right, bottom_right) + vertices[5] = solid_vertex(corner_bottom_left, bottom_left) prepare_shape(layer, vertices) } @@ -111,42 +111,42 @@ circle_sector :: proc( temp_allocator := context.temp_allocator, ) { arc_length := abs(end_angle - start_angle) - segs := segments > 0 ? segments : auto_segments(radius, arc_length) + segment_count := segments > 0 ? segments : auto_segments(radius, arc_length) - vertex_count := segs * 3 + vertex_count := segment_count * 3 vertices := make([]Vertex, vertex_count, temp_allocator) - start_rad := math.to_radians(start_angle) - end_rad := math.to_radians(end_angle) - step_angle := (end_rad - start_rad) / f32(segs) + start_radians := math.to_radians(start_angle) + end_radians := math.to_radians(end_angle) + step_angle := (end_radians - start_radians) / f32(segment_count) if !needs_transform(origin, rotation) { - for i in 0 ..< segs { - current_angle := start_rad + step_angle * f32(i) - next_angle := start_rad + step_angle * f32(i + 1) + for i in 0 ..< segment_count { + current_angle := start_radians + step_angle * f32(i) + next_angle := start_radians + step_angle * f32(i + 1) edge_current := center + [2]f32{math.cos(current_angle) * radius, math.sin(current_angle) * radius} edge_next := center + [2]f32{math.cos(next_angle) * radius, math.sin(next_angle) * radius} idx := i * 3 - vertices[idx + 0] = sv(center, color) - vertices[idx + 1] = sv(edge_next, color) - vertices[idx + 2] = sv(edge_current, color) + vertices[idx + 0] = solid_vertex(center, color) + vertices[idx + 1] = solid_vertex(edge_next, color) + vertices[idx + 2] = solid_vertex(edge_current, color) } } else { - xform := build_pivot_rot(center, origin, rotation) + transform := build_pivot_rotation(center, origin, rotation) center_local := [2]f32{0, 0} - for i in 0 ..< segs { - current_angle := start_rad + step_angle * f32(i) - next_angle := start_rad + step_angle * f32(i + 1) + for i in 0 ..< segment_count { + current_angle := start_radians + step_angle * f32(i) + next_angle := start_radians + step_angle * f32(i + 1) edge_current := [2]f32{math.cos(current_angle) * radius, math.sin(current_angle) * radius} edge_next := [2]f32{math.cos(next_angle) * radius, math.sin(next_angle) * radius} idx := i * 3 - vertices[idx + 0] = sv(apply_transform(xform, center_local), color) - vertices[idx + 1] = sv(apply_transform(xform, edge_next), color) - vertices[idx + 2] = sv(apply_transform(xform, edge_current), color) + vertices[idx + 0] = solid_vertex(apply_transform(transform, center_local), color) + vertices[idx + 1] = solid_vertex(apply_transform(transform, edge_next), color) + vertices[idx + 2] = solid_vertex(apply_transform(transform, edge_current), color) } } @@ -163,15 +163,15 @@ circle_gradient :: proc( segments: int = 0, temp_allocator := context.temp_allocator, ) { - segs := segments > 0 ? segments : auto_segments(radius, 360) + segment_count := segments > 0 ? segments : auto_segments(radius, 360) - vertex_count := segs * 3 + vertex_count := segment_count * 3 vertices := make([]Vertex, vertex_count, temp_allocator) - step_angle := math.TAU / f32(segs) + step_angle := math.TAU / f32(segment_count) if !needs_transform(origin, rotation) { - for i in 0 ..< segs { + for i in 0 ..< segment_count { current_angle := step_angle * f32(i) next_angle := step_angle * f32(i + 1) @@ -179,14 +179,14 @@ circle_gradient :: proc( edge_next := center + [2]f32{math.cos(next_angle) * radius, math.sin(next_angle) * radius} idx := i * 3 - vertices[idx + 0] = sv(center, inner) - vertices[idx + 1] = sv(edge_next, outer) - vertices[idx + 2] = sv(edge_current, outer) + vertices[idx + 0] = solid_vertex(center, inner) + vertices[idx + 1] = solid_vertex(edge_next, outer) + vertices[idx + 2] = solid_vertex(edge_current, outer) } } else { - xform := build_pivot_rot(center, origin, rotation) + transform := build_pivot_rotation(center, origin, rotation) center_local := [2]f32{0, 0} - for i in 0 ..< segs { + for i in 0 ..< segment_count { current_angle := step_angle * f32(i) next_angle := step_angle * f32(i + 1) @@ -194,9 +194,9 @@ circle_gradient :: proc( edge_next := [2]f32{math.cos(next_angle) * radius, math.sin(next_angle) * radius} idx := i * 3 - vertices[idx + 0] = sv(apply_transform(xform, center_local), inner) - vertices[idx + 1] = sv(apply_transform(xform, edge_next), outer) - vertices[idx + 2] = sv(apply_transform(xform, edge_current), outer) + vertices[idx + 0] = solid_vertex(apply_transform(transform, center_local), inner) + vertices[idx + 1] = solid_vertex(apply_transform(transform, edge_next), outer) + vertices[idx + 2] = solid_vertex(apply_transform(transform, edge_current), outer) } } @@ -211,19 +211,19 @@ triangle :: proc( rotation: f32 = 0, ) { if !needs_transform(origin, rotation) { - vertices := [3]Vertex{sv(v1, color), sv(v2, color), sv(v3, color)} + vertices := [3]Vertex{solid_vertex(v1, color), solid_vertex(v2, color), solid_vertex(v3, color)} prepare_shape(layer, vertices[:]) return } - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - xform := build_pivot_rot(mn, origin, rotation) - local_v1 := v1 - mn - local_v2 := v2 - mn - local_v3 := v3 - mn + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + transform := build_pivot_rotation(bounds_min, origin, rotation) + local_v1 := v1 - bounds_min + local_v2 := v2 - bounds_min + local_v3 := v3 - bounds_min vertices := [3]Vertex { - sv(apply_transform(xform, local_v1), color), - sv(apply_transform(xform, local_v2), color), - sv(apply_transform(xform, local_v3), color), + solid_vertex(apply_transform(transform, local_v1), color), + solid_vertex(apply_transform(transform, local_v2), color), + solid_vertex(apply_transform(transform, local_v3), color), } prepare_shape(layer, vertices[:]) } @@ -232,7 +232,7 @@ triangle_lines :: proc( layer: ^Layer, v1, v2, v3: [2]f32, color: Color, - thick: f32 = 1, + thickness: f32 = 1, origin: [2]f32 = {0, 0}, rotation: f32 = 0, temp_allocator := context.temp_allocator, @@ -241,18 +241,18 @@ triangle_lines :: proc( write_offset := 0 if !needs_transform(origin, rotation) { - write_offset += extrude_line(v1, v2, thick, color, vertices, write_offset) - write_offset += extrude_line(v2, v3, thick, color, vertices, write_offset) - write_offset += extrude_line(v3, v1, thick, color, vertices, write_offset) + write_offset += extrude_line(v1, v2, thickness, color, vertices, write_offset) + write_offset += extrude_line(v2, v3, thickness, color, vertices, write_offset) + write_offset += extrude_line(v3, v1, thickness, color, vertices, write_offset) } else { - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - xform := build_pivot_rot(mn, origin, rotation) - tv1 := apply_transform(xform, v1 - mn) - tv2 := apply_transform(xform, v2 - mn) - tv3 := apply_transform(xform, v3 - mn) - write_offset += extrude_line(tv1, tv2, thick, color, vertices, write_offset) - write_offset += extrude_line(tv2, tv3, thick, color, vertices, write_offset) - write_offset += extrude_line(tv3, tv1, thick, color, vertices, write_offset) + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + transform := build_pivot_rotation(bounds_min, origin, rotation) + transformed_v1 := apply_transform(transform, v1 - bounds_min) + transformed_v2 := apply_transform(transform, v2 - bounds_min) + transformed_v3 := apply_transform(transform, v3 - bounds_min) + write_offset += extrude_line(transformed_v1, transformed_v2, thickness, color, vertices, write_offset) + write_offset += extrude_line(transformed_v2, transformed_v3, thickness, color, vertices, write_offset) + write_offset += extrude_line(transformed_v3, transformed_v1, thickness, color, vertices, write_offset) } if write_offset > 0 { @@ -277,22 +277,22 @@ triangle_fan :: proc( if !needs_transform(origin, rotation) { for i in 1 ..< len(points) - 1 { idx := (i - 1) * 3 - vertices[idx + 0] = sv(points[0], color) - vertices[idx + 1] = sv(points[i], color) - vertices[idx + 2] = sv(points[i + 1], color) + vertices[idx + 0] = solid_vertex(points[0], color) + vertices[idx + 1] = solid_vertex(points[i], color) + vertices[idx + 2] = solid_vertex(points[i + 1], color) } } else { - mn := [2]f32{max(f32), max(f32)} - for p in points { - mn.x = min(mn.x, p.x) - mn.y = min(mn.y, p.y) + bounds_min := [2]f32{max(f32), max(f32)} + for point in points { + bounds_min.x = min(bounds_min.x, point.x) + bounds_min.y = min(bounds_min.y, point.y) } - xform := build_pivot_rot(mn, origin, rotation) + transform := build_pivot_rotation(bounds_min, origin, rotation) for i in 1 ..< len(points) - 1 { idx := (i - 1) * 3 - vertices[idx + 0] = sv(apply_transform(xform, points[0] - mn), color) - vertices[idx + 1] = sv(apply_transform(xform, points[i] - mn), color) - vertices[idx + 2] = sv(apply_transform(xform, points[i + 1] - mn), color) + vertices[idx + 0] = solid_vertex(apply_transform(transform, points[0] - bounds_min), color) + vertices[idx + 1] = solid_vertex(apply_transform(transform, points[i] - bounds_min), color) + vertices[idx + 2] = solid_vertex(apply_transform(transform, points[i + 1] - bounds_min), color) } } @@ -317,32 +317,32 @@ triangle_strip :: proc( for i in 0 ..< triangle_count { idx := i * 3 if i % 2 == 0 { - vertices[idx + 0] = sv(points[i], color) - vertices[idx + 1] = sv(points[i + 1], color) - vertices[idx + 2] = sv(points[i + 2], color) + vertices[idx + 0] = solid_vertex(points[i], color) + vertices[idx + 1] = solid_vertex(points[i + 1], color) + vertices[idx + 2] = solid_vertex(points[i + 2], color) } else { - vertices[idx + 0] = sv(points[i + 1], color) - vertices[idx + 1] = sv(points[i], color) - vertices[idx + 2] = sv(points[i + 2], color) + vertices[idx + 0] = solid_vertex(points[i + 1], color) + vertices[idx + 1] = solid_vertex(points[i], color) + vertices[idx + 2] = solid_vertex(points[i + 2], color) } } } else { - mn := [2]f32{max(f32), max(f32)} - for p in points { - mn.x = min(mn.x, p.x) - mn.y = min(mn.y, p.y) + bounds_min := [2]f32{max(f32), max(f32)} + for point in points { + bounds_min.x = min(bounds_min.x, point.x) + bounds_min.y = min(bounds_min.y, point.y) } - xform := build_pivot_rot(mn, origin, rotation) + transform := build_pivot_rotation(bounds_min, origin, rotation) for i in 0 ..< triangle_count { idx := i * 3 if i % 2 == 0 { - vertices[idx + 0] = sv(apply_transform(xform, points[i] - mn), color) - vertices[idx + 1] = sv(apply_transform(xform, points[i + 1] - mn), color) - vertices[idx + 2] = sv(apply_transform(xform, points[i + 2] - mn), color) + vertices[idx + 0] = solid_vertex(apply_transform(transform, points[i] - bounds_min), color) + vertices[idx + 1] = solid_vertex(apply_transform(transform, points[i + 1] - bounds_min), color) + vertices[idx + 2] = solid_vertex(apply_transform(transform, points[i + 2] - bounds_min), color) } else { - vertices[idx + 0] = sv(apply_transform(xform, points[i + 1] - mn), color) - vertices[idx + 1] = sv(apply_transform(xform, points[i] - mn), color) - vertices[idx + 2] = sv(apply_transform(xform, points[i + 2] - mn), color) + vertices[idx + 0] = solid_vertex(apply_transform(transform, points[i + 1] - bounds_min), color) + vertices[idx + 1] = solid_vertex(apply_transform(transform, points[i] - bounds_min), color) + vertices[idx + 2] = solid_vertex(apply_transform(transform, points[i + 2] - bounds_min), color) } } } @@ -358,17 +358,21 @@ triangle_strip :: proc( compute_pivot_center :: proc(center: [2]f32, origin: [2]f32, rotation_deg: f32) -> [2]f32 { if origin == {0, 0} do return center theta := math.to_radians(rotation_deg) - c, s := math.cos(theta), math.sin(theta) + cos_angle, sin_angle := math.cos(theta), math.sin(theta) // pivot = center + origin; new_center = pivot + R(θ) * (center - pivot) - return center + origin + {c * (-origin.x) - s * (-origin.y), s * (-origin.x) + c * (-origin.y)} + return( + center + + origin + + {cos_angle * (-origin.x) - sin_angle * (-origin.y), sin_angle * (-origin.x) + cos_angle * (-origin.y)} \ + ) } -// Compute the AABB half-extents of a rectangle with half-size (hx, hy) rotated by rot_rad. +// Compute the AABB half-extents of a rectangle with half-size (half_width, half_height) rotated by rotation_radians. @(private = "file") -rotated_aabb_half :: proc(hx, hy, rot_rad: f32) -> [2]f32 { - c_r := abs(math.cos(rot_rad)) - s_r := abs(math.sin(rot_rad)) - return {hx * c_r + hy * s_r, hx * s_r + hy * c_r} +rotated_aabb_half_extents :: proc(half_width, half_height, rotation_radians: f32) -> [2]f32 { + cos_abs := abs(math.cos(rotation_radians)) + sin_abs := abs(math.sin(rotation_radians)) + return {half_width * cos_abs + half_height * sin_abs, half_width * sin_abs + half_height * cos_abs} } // Draw a filled rectangle via SDF (analytical anti-aliasing at all orientations). @@ -383,7 +387,7 @@ rectangle :: proc( rotation: f32 = 0, soft_px: f32 = 1.0, ) { - cr := min(rect.w, rect.h) * clamp(roundness, 0, 1) * 0.5 + cr := min(rect.width, rect.height) * clamp(roundness, 0, 1) * 0.5 rectangle_corners(layer, rect, {cr, cr, cr, cr}, color, origin, rotation, soft_px) } @@ -394,14 +398,14 @@ rectangle_lines :: proc( layer: ^Layer, rect: Rectangle, color: Color, - thick: f32 = 1, + thickness: f32 = 1, roundness: f32 = 0, origin: [2]f32 = {0, 0}, rotation: f32 = 0, soft_px: f32 = 1.0, ) { - cr := min(rect.w, rect.h) * clamp(roundness, 0, 1) * 0.5 - rectangle_corners_lines(layer, rect, {cr, cr, cr, cr}, color, thick, origin, rotation, soft_px) + cr := min(rect.width, rect.height) * clamp(roundness, 0, 1) * 0.5 + rectangle_corners_lines(layer, rect, {cr, cr, cr, cr}, color, thickness, origin, rotation, soft_px) } // Draw a rectangle with per-corner rounding radii via SDF. @@ -414,45 +418,55 @@ rectangle_corners :: proc( rotation: f32 = 0, soft_px: f32 = 1.0, ) { - max_radius := min(rect.w, rect.h) * 0.5 - tl := clamp(radii[0], 0, max_radius) - tr := clamp(radii[1], 0, max_radius) - br := clamp(radii[2], 0, max_radius) - bl := clamp(radii[3], 0, max_radius) + max_radius := min(rect.width, rect.height) * 0.5 + top_left := clamp(radii[0], 0, max_radius) + top_right := clamp(radii[1], 0, max_radius) + bottom_right := clamp(radii[2], 0, max_radius) + bottom_left := clamp(radii[3], 0, max_radius) - pad := soft_px / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := soft_px / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling - hx := rect.w * 0.5 - hy := rect.h * 0.5 - rot_rad: f32 = 0 - center_x := rect.x + hx - center_y := rect.y + hy + half_width := rect.width * 0.5 + half_height := rect.height * 0.5 + rotation_radians: f32 = 0 + center_x := rect.x + half_width + center_y := rect.y + half_height if needs_transform(origin, rotation) { - rot_rad = math.to_radians(rotation) - xform := build_pivot_rot({rect.x, rect.y}, origin, rotation) - new_center := apply_transform(xform, {hx, hy}) + rotation_radians = math.to_radians(rotation) + transform := build_pivot_rotation({rect.x, rect.y}, origin, rotation) + new_center := apply_transform(transform, {half_width, half_height}) center_x = new_center.x center_y = new_center.y } - bhx, bhy := hx, hy - if rot_rad != 0 { - expanded := rotated_aabb_half(hx, hy, rot_rad) - bhx = expanded.x - bhy = expanded.y + bounds_half_width, bounds_half_height := half_width, half_height + if rotation_radians != 0 { + expanded := rotated_aabb_half_extents(half_width, half_height, rotation_radians) + bounds_half_width = expanded.x + bounds_half_height = expanded.y } prim := Primitive { - bounds = {center_x - bhx - pad, center_y - bhy - pad, center_x + bhx + pad, center_y + bhy + pad}, + bounds = { + center_x - bounds_half_width - padding, + center_y - bounds_half_height - padding, + center_x + bounds_half_width + padding, + center_y + bounds_half_height + padding, + }, color = color, kind_flags = pack_kind_flags(.RRect, {}), - rotation = rot_rad, + rotation = rotation_radians, } prim.params.rrect = RRect_Params { - half_size = {hx * dpi, hy * dpi}, - radii = {tr * dpi, br * dpi, tl * dpi, bl * dpi}, + half_size = {half_width * dpi_scale, half_height * dpi_scale}, + radii = { + top_right * dpi_scale, + bottom_right * dpi_scale, + top_left * dpi_scale, + bottom_left * dpi_scale, + }, soft_px = soft_px, stroke_px = 0, } @@ -465,52 +479,62 @@ rectangle_corners_lines :: proc( rect: Rectangle, radii: [4]f32, color: Color, - thick: f32 = 1, + thickness: f32 = 1, origin: [2]f32 = {0, 0}, rotation: f32 = 0, soft_px: f32 = 1.0, ) { - max_radius := min(rect.w, rect.h) * 0.5 - tl := clamp(radii[0], 0, max_radius) - tr := clamp(radii[1], 0, max_radius) - br := clamp(radii[2], 0, max_radius) - bl := clamp(radii[3], 0, max_radius) + max_radius := min(rect.width, rect.height) * 0.5 + top_left := clamp(radii[0], 0, max_radius) + top_right := clamp(radii[1], 0, max_radius) + bottom_right := clamp(radii[2], 0, max_radius) + bottom_left := clamp(radii[3], 0, max_radius) - pad := (thick * 0.5 + soft_px) / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := (thickness * 0.5 + soft_px) / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling - hx := rect.w * 0.5 - hy := rect.h * 0.5 - rot_rad: f32 = 0 - center_x := rect.x + hx - center_y := rect.y + hy + half_width := rect.width * 0.5 + half_height := rect.height * 0.5 + rotation_radians: f32 = 0 + center_x := rect.x + half_width + center_y := rect.y + half_height if needs_transform(origin, rotation) { - rot_rad = math.to_radians(rotation) - xform := build_pivot_rot({rect.x, rect.y}, origin, rotation) - new_center := apply_transform(xform, {hx, hy}) + rotation_radians = math.to_radians(rotation) + transform := build_pivot_rotation({rect.x, rect.y}, origin, rotation) + new_center := apply_transform(transform, {half_width, half_height}) center_x = new_center.x center_y = new_center.y } - bhx, bhy := hx, hy - if rot_rad != 0 { - expanded := rotated_aabb_half(hx, hy, rot_rad) - bhx = expanded.x - bhy = expanded.y + bounds_half_width, bounds_half_height := half_width, half_height + if rotation_radians != 0 { + expanded := rotated_aabb_half_extents(half_width, half_height, rotation_radians) + bounds_half_width = expanded.x + bounds_half_height = expanded.y } prim := Primitive { - bounds = {center_x - bhx - pad, center_y - bhy - pad, center_x + bhx + pad, center_y + bhy + pad}, + bounds = { + center_x - bounds_half_width - padding, + center_y - bounds_half_height - padding, + center_x + bounds_half_width + padding, + center_y + bounds_half_height + padding, + }, color = color, kind_flags = pack_kind_flags(.RRect, {.Stroke}), - rotation = rot_rad, + rotation = rotation_radians, } prim.params.rrect = RRect_Params { - half_size = {hx * dpi, hy * dpi}, - radii = {tr * dpi, br * dpi, tl * dpi, bl * dpi}, + half_size = {half_width * dpi_scale, half_height * dpi_scale}, + radii = { + top_right * dpi_scale, + bottom_right * dpi_scale, + top_left * dpi_scale, + bottom_left * dpi_scale, + }, soft_px = soft_px, - stroke_px = thick * dpi, + stroke_px = thickness * dpi_scale, } prepare_sdf_primitive(layer, prim) } @@ -525,8 +549,8 @@ circle :: proc( rotation: f32 = 0, soft_px: f32 = 1.0, ) { - pad := soft_px / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := soft_px / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center if origin != {0, 0} { @@ -535,17 +559,17 @@ circle :: proc( prim := Primitive { bounds = { - actual_center.x - radius - pad, - actual_center.y - radius - pad, - actual_center.x + radius + pad, - actual_center.y + radius + pad, + actual_center.x - radius - padding, + actual_center.y - radius - padding, + actual_center.x + radius + padding, + actual_center.y + radius + padding, }, color = color, kind_flags = pack_kind_flags(.Circle, {}), // rotation stays 0 — circle is rotationally symmetric } prim.params.circle = Circle_Params { - radius = radius * dpi, + radius = radius * dpi_scale, soft_px = soft_px, } prepare_sdf_primitive(layer, prim) @@ -557,13 +581,13 @@ circle_lines :: proc( center: [2]f32, radius: f32, color: Color, - thick: f32 = 1, + thickness: f32 = 1, origin: [2]f32 = {0, 0}, rotation: f32 = 0, soft_px: f32 = 1.0, ) { - pad := (thick * 0.5 + soft_px) / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := (thickness * 0.5 + soft_px) / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center if origin != {0, 0} { @@ -572,18 +596,18 @@ circle_lines :: proc( prim := Primitive { bounds = { - actual_center.x - radius - pad, - actual_center.y - radius - pad, - actual_center.x + radius + pad, - actual_center.y + radius + pad, + actual_center.x - radius - padding, + actual_center.y - radius - padding, + actual_center.x + radius + padding, + actual_center.y + radius + padding, }, color = color, kind_flags = pack_kind_flags(.Circle, {.Stroke}), } prim.params.circle = Circle_Params { - radius = radius * dpi, + radius = radius * dpi_scale, soft_px = soft_px, - stroke_px = thick * dpi, + stroke_px = thickness * dpi_scale, } prepare_sdf_primitive(layer, prim) } @@ -598,37 +622,37 @@ ellipse :: proc( rotation: f32 = 0, soft_px: f32 = 1.0, ) { - pad := soft_px / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := soft_px / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center - rot_rad: f32 = 0 + rotation_radians: f32 = 0 if needs_transform(origin, rotation) { actual_center = compute_pivot_center(center, origin, rotation) - rot_rad = math.to_radians(rotation) + rotation_radians = math.to_radians(rotation) } // When rotated, expand the bounds AABB to enclose the rotated ellipse bound_h, bound_v := radius_h, radius_v - if rot_rad != 0 { - expanded := rotated_aabb_half(radius_h, radius_v, rot_rad) + if rotation_radians != 0 { + expanded := rotated_aabb_half_extents(radius_h, radius_v, rotation_radians) bound_h = expanded.x bound_v = expanded.y } prim := Primitive { bounds = { - actual_center.x - bound_h - pad, - actual_center.y - bound_v - pad, - actual_center.x + bound_h + pad, - actual_center.y + bound_v + pad, + actual_center.x - bound_h - padding, + actual_center.y - bound_v - padding, + actual_center.x + bound_h + padding, + actual_center.y + bound_v + padding, }, color = color, kind_flags = pack_kind_flags(.Ellipse, {}), - rotation = rot_rad, + rotation = rotation_radians, } prim.params.ellipse = Ellipse_Params { - radii = {radius_h * dpi, radius_v * dpi}, + radii = {radius_h * dpi_scale, radius_v * dpi_scale}, soft_px = soft_px, } prepare_sdf_primitive(layer, prim) @@ -640,46 +664,46 @@ ellipse_lines :: proc( center: [2]f32, radius_h, radius_v: f32, color: Color, - thick: f32 = 1, + thickness: f32 = 1, origin: [2]f32 = {0, 0}, rotation: f32 = 0, soft_px: f32 = 1.0, ) { // Extra 10% padding: iq's sdEllipse has precision degradation near the tips of highly // eccentric ellipses, so the quad needs additional breathing room beyond the stroke width. - extra := max(radius_h, radius_v) * 0.1 + thick * 0.5 - pad := (extra + soft_px) / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + extra := max(radius_h, radius_v) * 0.1 + thickness * 0.5 + padding := (extra + soft_px) / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center - rot_rad: f32 = 0 + rotation_radians: f32 = 0 if needs_transform(origin, rotation) { actual_center = compute_pivot_center(center, origin, rotation) - rot_rad = math.to_radians(rotation) + rotation_radians = math.to_radians(rotation) } bound_h, bound_v := radius_h, radius_v - if rot_rad != 0 { - expanded := rotated_aabb_half(radius_h, radius_v, rot_rad) + if rotation_radians != 0 { + expanded := rotated_aabb_half_extents(radius_h, radius_v, rotation_radians) bound_h = expanded.x bound_v = expanded.y } prim := Primitive { bounds = { - actual_center.x - bound_h - pad, - actual_center.y - bound_v - pad, - actual_center.x + bound_h + pad, - actual_center.y + bound_v + pad, + actual_center.x - bound_h - padding, + actual_center.y - bound_v - padding, + actual_center.x + bound_h + padding, + actual_center.y + bound_v + padding, }, color = color, kind_flags = pack_kind_flags(.Ellipse, {.Stroke}), - rotation = rot_rad, + rotation = rotation_radians, } prim.params.ellipse = Ellipse_Params { - radii = {radius_h * dpi, radius_v * dpi}, + radii = {radius_h * dpi_scale, radius_v * dpi_scale}, soft_px = soft_px, - stroke_px = thick * dpi, + stroke_px = thickness * dpi_scale, } prepare_sdf_primitive(layer, prim) } @@ -695,8 +719,8 @@ ring :: proc( rotation: f32 = 0, soft_px: f32 = 1.0, ) { - pad := soft_px / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := soft_px / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center rotation_offset: f32 = 0 @@ -707,18 +731,18 @@ ring :: proc( prim := Primitive { bounds = { - actual_center.x - outer_radius - pad, - actual_center.y - outer_radius - pad, - actual_center.x + outer_radius + pad, - actual_center.y + outer_radius + pad, + actual_center.x - outer_radius - padding, + actual_center.y - outer_radius - padding, + actual_center.x + outer_radius + padding, + actual_center.y + outer_radius + padding, }, color = color, kind_flags = pack_kind_flags(.Ring_Arc, {}), // No shader rotation — arc rotation handled by offsetting start/end angles } prim.params.ring_arc = Ring_Arc_Params { - inner_radius = inner_radius * dpi, - outer_radius = outer_radius * dpi, + inner_radius = inner_radius * dpi_scale, + outer_radius = outer_radius * dpi_scale, start_rad = math.to_radians(start_angle) + rotation_offset, end_rad = math.to_radians(end_angle) + rotation_offset, soft_px = soft_px, @@ -733,14 +757,14 @@ ring_lines :: proc( inner_radius, outer_radius: f32, start_angle, end_angle: f32, color: Color, - thick: f32 = 1, + thickness: f32 = 1, origin: [2]f32 = {0, 0}, rotation: f32 = 0, soft_px: f32 = 1.0, ) { // Compute effective angles and pivot-translated center up front - eff_start := start_angle + rotation - eff_end := end_angle + rotation + effective_start_angle := start_angle + rotation + effective_end_angle := end_angle + rotation actual_center := center if needs_transform(origin, rotation) { @@ -751,10 +775,10 @@ ring_lines :: proc( ring( layer, actual_center, - max(0, inner_radius - thick * 0.5), - inner_radius + thick * 0.5, - eff_start, - eff_end, + max(0, inner_radius - thickness * 0.5), + inner_radius + thickness * 0.5, + effective_start_angle, + effective_end_angle, color, soft_px = soft_px, ) @@ -762,37 +786,39 @@ ring_lines :: proc( ring( layer, actual_center, - max(0, outer_radius - thick * 0.5), - outer_radius + thick * 0.5, - eff_start, - eff_end, + max(0, outer_radius - thickness * 0.5), + outer_radius + thickness * 0.5, + effective_start_angle, + effective_end_angle, color, soft_px = soft_px, ) // Start cap - start_rad := math.to_radians(eff_start) - end_rad := math.to_radians(eff_end) - inner_start := actual_center + {math.cos(start_rad) * inner_radius, math.sin(start_rad) * inner_radius} - outer_start := actual_center + {math.cos(start_rad) * outer_radius, math.sin(start_rad) * outer_radius} - line(layer, inner_start, outer_start, color, thick, soft_px) + start_radians := math.to_radians(effective_start_angle) + end_radians := math.to_radians(effective_end_angle) + inner_start := + actual_center + {math.cos(start_radians) * inner_radius, math.sin(start_radians) * inner_radius} + outer_start := + actual_center + {math.cos(start_radians) * outer_radius, math.sin(start_radians) * outer_radius} + line(layer, inner_start, outer_start, color, thickness, soft_px) // End cap - inner_end := actual_center + {math.cos(end_rad) * inner_radius, math.sin(end_rad) * inner_radius} - outer_end := actual_center + {math.cos(end_rad) * outer_radius, math.sin(end_rad) * outer_radius} - line(layer, inner_end, outer_end, color, thick, soft_px) + inner_end := actual_center + {math.cos(end_radians) * inner_radius, math.sin(end_radians) * inner_radius} + outer_end := actual_center + {math.cos(end_radians) * outer_radius, math.sin(end_radians) * outer_radius} + line(layer, inner_end, outer_end, color, thickness, soft_px) } // Draw a line segment via SDF. -line :: proc(layer: ^Layer, start, end_pos: [2]f32, color: Color, thick: f32 = 1, soft_px: f32 = 1.0) { - cap := thick * 0.5 + soft_px / GLOB.dpi_scaling - min_x := min(start.x, end_pos.x) - cap - max_x := max(start.x, end_pos.x) + cap - min_y := min(start.y, end_pos.y) - cap - max_y := max(start.y, end_pos.y) + cap - dpi := GLOB.dpi_scaling +line :: proc(layer: ^Layer, start, end_pos: [2]f32, color: Color, thickness: f32 = 1, soft_px: f32 = 1.0) { + cap_padding := thickness * 0.5 + soft_px / GLOB.dpi_scaling + min_x := min(start.x, end_pos.x) - cap_padding + max_x := max(start.x, end_pos.x) + cap_padding + min_y := min(start.y, end_pos.y) - cap_padding + max_y := max(start.y, end_pos.y) + cap_padding + dpi_scale := GLOB.dpi_scaling center := [2]f32{(min_x + max_x) * 0.5, (min_y + max_y) * 0.5} - local_a := (start - center) * dpi - local_b := (end_pos - center) * dpi + local_start := (start - center) * dpi_scale + local_end := (end_pos - center) * dpi_scale prim := Primitive { bounds = {min_x, min_y, max_x, max_y}, @@ -800,24 +826,24 @@ line :: proc(layer: ^Layer, start, end_pos: [2]f32, color: Color, thick: f32 = 1 kind_flags = pack_kind_flags(.Segment, {}), } prim.params.segment = Segment_Params { - a = local_a, - b = local_b, - width = thick * dpi, + a = local_start, + b = local_end, + width = thickness * dpi_scale, soft_px = soft_px, } prepare_sdf_primitive(layer, prim) } // Draw a line strip via decomposed SDF segments. -line_strip :: proc(layer: ^Layer, points: [][2]f32, color: Color, thick: f32 = 1, soft_px: f32 = 1.0) { +line_strip :: proc(layer: ^Layer, points: [][2]f32, color: Color, thickness: f32 = 1, soft_px: f32 = 1.0) { if len(points) < 2 do return for i in 0 ..< len(points) - 1 { - line(layer, points[i], points[i + 1], color, thick, soft_px) + line(layer, points[i], points[i + 1], color, thickness, soft_px) } } // Draw a filled regular polygon via SDF. -poly :: proc( +polygon :: proc( layer: ^Layer, center: [2]f32, sides: int, @@ -828,8 +854,8 @@ poly :: proc( soft_px: f32 = 1.0, ) { if sides < 3 do return - pad := soft_px / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := soft_px / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center if origin != {0, 0} && rotation != 0 { @@ -838,16 +864,16 @@ poly :: proc( prim := Primitive { bounds = { - actual_center.x - radius - pad, - actual_center.y - radius - pad, - actual_center.x + radius + pad, - actual_center.y + radius + pad, + actual_center.x - radius - padding, + actual_center.y - radius - padding, + actual_center.x + radius + padding, + actual_center.y + radius + padding, }, color = color, kind_flags = pack_kind_flags(.NGon, {}), } prim.params.ngon = NGon_Params { - radius = radius * math.cos(math.PI / f32(sides)) * dpi, + radius = radius * math.cos(math.PI / f32(sides)) * dpi_scale, rotation = math.to_radians(rotation), sides = f32(sides), soft_px = soft_px, @@ -856,7 +882,7 @@ poly :: proc( } // Draw a stroked regular polygon via SDF. -poly_lines :: proc( +polygon_lines :: proc( layer: ^Layer, center: [2]f32, sides: int, @@ -864,12 +890,12 @@ poly_lines :: proc( color: Color, rotation: f32 = 0, origin: [2]f32 = {0, 0}, - thick: f32 = 1, + thickness: f32 = 1, soft_px: f32 = 1.0, ) { if sides < 3 do return - pad := (thick * 0.5 + soft_px) / GLOB.dpi_scaling - dpi := GLOB.dpi_scaling + padding := (thickness * 0.5 + soft_px) / GLOB.dpi_scaling + dpi_scale := GLOB.dpi_scaling actual_center := center if origin != {0, 0} && rotation != 0 { @@ -878,20 +904,20 @@ poly_lines :: proc( prim := Primitive { bounds = { - actual_center.x - radius - pad, - actual_center.y - radius - pad, - actual_center.x + radius + pad, - actual_center.y + radius + pad, + actual_center.x - radius - padding, + actual_center.y - radius - padding, + actual_center.x + radius + padding, + actual_center.y + radius + padding, }, color = color, kind_flags = pack_kind_flags(.NGon, {.Stroke}), } prim.params.ngon = NGon_Params { - radius = radius * math.cos(math.PI / f32(sides)) * dpi, + radius = radius * math.cos(math.PI / f32(sides)) * dpi_scale, rotation = math.to_radians(rotation), sides = f32(sides), soft_px = soft_px, - stroke_px = thick * dpi, + stroke_px = thickness * dpi_scale, } prepare_sdf_primitive(layer, prim) } @@ -905,49 +931,49 @@ poly_lines :: proc( // // Text anchor helpers are in text.odin (they depend on measure_text / SDL_ttf). -// ----- Rectangle anchors (origin measured from rect's top-left) -------------------------------------------------- +// ----- Rectangle anchors (origin measured from rectangle's top-left) --------------------------------------------- -center_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w * 0.5, r.h * 0.5} +center_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width * 0.5, rectangle.height * 0.5} } -top_left_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { +top_left_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { return {0, 0} } -top_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w * 0.5, 0} +top_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width * 0.5, 0} } -top_right_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w, 0} +top_right_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width, 0} } -left_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {0, r.h * 0.5} +left_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {0, rectangle.height * 0.5} } -right_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w, r.h * 0.5} +right_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width, rectangle.height * 0.5} } -bottom_left_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {0, r.h} +bottom_left_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {0, rectangle.height} } -bottom_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w * 0.5, r.h} +bottom_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width * 0.5, rectangle.height} } -bottom_right_of_rect :: #force_inline proc(r: Rectangle) -> [2]f32 { - return {r.w, r.h} +bottom_right_of_rectangle :: #force_inline proc(rectangle: Rectangle) -> [2]f32 { + return {rectangle.width, rectangle.height} } // ----- Triangle anchors (origin measured from AABB top-left) ----------------------------------------------------- center_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - return (v1 + v2 + v3) / 3 - mn + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + return (v1 + v2 + v3) / 3 - bounds_min } top_left_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { @@ -955,43 +981,43 @@ top_left_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { } top_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn_x := min(v1.x, v2.x, v3.x) - mx_x := max(v1.x, v2.x, v3.x) - return {(mx_x - mn_x) * 0.5, 0} + min_x := min(v1.x, v2.x, v3.x) + max_x := max(v1.x, v2.x, v3.x) + return {(max_x - min_x) * 0.5, 0} } top_right_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn_x := min(v1.x, v2.x, v3.x) - mx_x := max(v1.x, v2.x, v3.x) - return {mx_x - mn_x, 0} + min_x := min(v1.x, v2.x, v3.x) + max_x := max(v1.x, v2.x, v3.x) + return {max_x - min_x, 0} } left_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn_y := min(v1.y, v2.y, v3.y) - mx_y := max(v1.y, v2.y, v3.y) - return {0, (mx_y - mn_y) * 0.5} + min_y := min(v1.y, v2.y, v3.y) + max_y := max(v1.y, v2.y, v3.y) + return {0, (max_y - min_y) * 0.5} } right_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - mx := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} - return {mx.x - mn.x, (mx.y - mn.y) * 0.5} + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + bounds_max := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} + return {bounds_max.x - bounds_min.x, (bounds_max.y - bounds_min.y) * 0.5} } bottom_left_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn_y := min(v1.y, v2.y, v3.y) - mx_y := max(v1.y, v2.y, v3.y) - return {0, mx_y - mn_y} + min_y := min(v1.y, v2.y, v3.y) + max_y := max(v1.y, v2.y, v3.y) + return {0, max_y - min_y} } bottom_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - mx := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} - return {(mx.x - mn.x) * 0.5, mx.y - mn.y} + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + bounds_max := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} + return {(bounds_max.x - bounds_min.x) * 0.5, bounds_max.y - bounds_min.y} } bottom_right_of_triangle :: #force_inline proc(v1, v2, v3: [2]f32) -> [2]f32 { - mn := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} - mx := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} - return mx - mn + bounds_min := [2]f32{min(v1.x, v2.x, v3.x), min(v1.y, v2.y, v3.y)} + bounds_max := [2]f32{max(v1.x, v2.x, v3.x), max(v1.y, v2.y, v3.y)} + return bounds_max - bounds_min } diff --git a/draw/text.odin b/draw/text.odin index 742053b..fae7f61 100644 --- a/draw/text.odin +++ b/draw/text.odin @@ -69,7 +69,7 @@ register_font :: proc(bytes: []u8) -> (id: Font_Id, ok: bool) #optional_ok { } Text :: struct { - ref: ^sdl_ttf.Text, + sdl_text: ^sdl_ttf.Text, position: [2]f32, color: Color, } @@ -81,8 +81,8 @@ Text :: struct { // Hash a string to a u32 cache key using the same Jenkins one-at-a-time algorithm as Clay. // This means Clay element IDs and user-chosen string IDs share the same keyspace — same // string produces the same cache key regardless of whether it came from Clay or user code. -text_cache_hash :: #force_inline proc(s: string) -> u32 { - return hash.jenkins(transmute([]u8)s) + 1 // +1 reserves 0 as "no entry" (matches Clay convention) +text_cache_hash :: #force_inline proc(text_string: string) -> u32 { + return hash.jenkins(transmute([]u8)text_string) + 1 // +1 reserves 0 as "no entry" (matches Clay convention) } // Shared cache lookup/create/update logic used by both the `text` proc and the Clay render path. @@ -125,8 +125,8 @@ cache_get_or_update :: proc(cache_id: u32, c_str: cstring, font: ^sdl_ttf.Font) // `rotation` is in degrees, counter-clockwise. text :: proc( layer: ^Layer, - str: string, - pos: [2]f32, + text_string: string, + position: [2]f32, font_id: Font_Id, font_size: u16 = 44, color: Color = BLACK, @@ -135,14 +135,14 @@ text :: proc( id: Maybe(string) = nil, temp_allocator := context.temp_allocator, ) { - c_str := strings.clone_to_cstring(str, temp_allocator) + c_str := strings.clone_to_cstring(text_string, temp_allocator) sdl_text: ^sdl_ttf.Text cached := false - if id_str, ok := id.?; ok { + if id_string, ok := id.?; ok { cached = true - sdl_text = cache_get_or_update(text_cache_hash(id_str), c_str, get_font(font_id, font_size)) + sdl_text = cache_get_or_update(text_cache_hash(id_string), c_str, get_font(font_id, font_size)) } else { sdl_text = sdl_ttf.CreateText(GLOB.text_cache.engine, get_font(font_id, font_size), c_str, 0) if sdl_text == nil { @@ -151,11 +151,11 @@ text :: proc( } if needs_transform(origin, rotation) { - dpi := GLOB.dpi_scaling - xform := build_pivot_rot(pos * dpi, origin * dpi, rotation) - prepare_text_transformed(layer, Text{sdl_text, {0, 0}, color}, xform) + dpi_scale := GLOB.dpi_scaling + transform := build_pivot_rotation(position * dpi_scale, origin * dpi_scale, rotation) + prepare_text_transformed(layer, Text{sdl_text, {0, 0}, color}, transform) } else { - prepare_text(layer, Text{sdl_text, pos, color}) + prepare_text(layer, Text{sdl_text, position, color}) } if !cached { @@ -171,64 +171,64 @@ text :: proc( // Measure a string in logical pixels (pre-DPI-scaling) using the same font backend as the renderer. measure_text :: proc( - str: string, + text_string: string, font_id: Font_Id, font_size: u16 = 44, allocator := context.temp_allocator, ) -> [2]f32 { - c_str := strings.clone_to_cstring(str, allocator) - w, h: c.int - if !sdl_ttf.GetStringSize(get_font(font_id, font_size), c_str, 0, &w, &h) { + c_str := strings.clone_to_cstring(text_string, allocator) + width, height: c.int + if !sdl_ttf.GetStringSize(get_font(font_id, font_size), c_str, 0, &width, &height) { log.panicf("Failed to measure text: %s", sdl.GetError()) } - return {f32(w) / GLOB.dpi_scaling, f32(h) / GLOB.dpi_scaling} + return {f32(width) / GLOB.dpi_scaling, f32(height) / GLOB.dpi_scaling} } // --------------------------------------------------------------------------------------------------------------------- // ----- Text anchor helpers ----------- // --------------------------------------------------------------------------------------------------------------------- -center_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +center_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return size * 0.5 } -top_left_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { +top_left_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { return {0, 0} } -top_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +top_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {size.x * 0.5, 0} } -top_right_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +top_right_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {size.x, 0} } -left_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +left_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {0, size.y * 0.5} } -right_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +right_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {size.x, size.y * 0.5} } -bottom_left_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +bottom_left_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {0, size.y} } -bottom_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +bottom_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return {size.x * 0.5, size.y} } -bottom_right_of_text :: proc(str: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { - size := measure_text(str, font_id, font_size) +bottom_right_of_text :: proc(text_string: string, font_id: Font_Id, font_size: u16 = 44) -> [2]f32 { + size := measure_text(text_string, font_id, font_size) return size }