Basic texture support
This commit is contained in:
158
draw/shapes.odin
158
draw/shapes.odin
@@ -68,6 +68,19 @@ emit_rectangle :: proc(x, y, width, height: f32, color: Color, vertices: []Verte
|
||||
vertices[offset + 5] = solid_vertex({x, y + height}, color)
|
||||
}
|
||||
|
||||
@(private = "file")
|
||||
prepare_sdf_primitive_textured :: proc(
|
||||
layer: ^Layer,
|
||||
prim: Primitive,
|
||||
texture_id: Texture_Id,
|
||||
sampler: Sampler_Preset,
|
||||
) {
|
||||
offset := u32(len(GLOB.tmp_primitives))
|
||||
append(&GLOB.tmp_primitives, prim)
|
||||
scissor := &GLOB.scissors[layer.scissor_start + layer.scissor_len - 1]
|
||||
append_or_extend_sub_batch(scissor, layer, .SDF, offset, 1, texture_id, sampler)
|
||||
}
|
||||
|
||||
// ----- Drawing functions ----
|
||||
|
||||
pixel :: proc(layer: ^Layer, pos: [2]f32, color: Color) {
|
||||
@@ -358,17 +371,20 @@ triangle_strip :: proc(
|
||||
|
||||
// ----- SDF drawing functions ----
|
||||
|
||||
// Compute new center position after rotating a center-parametrized shape
|
||||
// around a pivot point. The pivot is at (center + origin) in world space.
|
||||
// Compute the visual center of a center-parametrized shape after applying
|
||||
// Convention B origin semantics: `center` is where the origin-point lands in
|
||||
// world space; the visual center is offset by -origin and then rotated around
|
||||
// the landing point.
|
||||
// visual_center = center + R(θ) · (-origin)
|
||||
// When θ=0: visual_center = center - origin (pure positioning shift).
|
||||
// When origin={0,0}: visual_center = center (no change).
|
||||
@(private = "file")
|
||||
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)
|
||||
cos_angle, sin_angle := math.cos(theta), math.sin(theta)
|
||||
// pivot = center + origin; new_center = pivot + R(θ) * (center - pivot)
|
||||
return(
|
||||
center +
|
||||
origin +
|
||||
{cos_angle * (-origin.x) - sin_angle * (-origin.y), sin_angle * (-origin.x) + cos_angle * (-origin.y)} \
|
||||
)
|
||||
}
|
||||
@@ -384,6 +400,13 @@ rotated_aabb_half_extents :: proc(half_width, half_height, rotation_radians: f32
|
||||
// Draw a filled rectangle via SDF (analytical anti-aliasing at all orientations).
|
||||
// `roundness` is a 0–1 fraction controlling uniform corner rounding — 0 is sharp, 1 is fully rounded.
|
||||
// For per-corner pixel-precise rounding, use `rectangle_corners` instead.
|
||||
//
|
||||
// Origin semantics:
|
||||
// `origin` is a local offset from the rect's top-left corner that selects both the positioning
|
||||
// anchor and the rotation pivot. `rect.x, rect.y` specifies where that anchor point lands in
|
||||
// world space. When `origin = {0, 0}` (default), `rect.x, rect.y` is the top-left corner.
|
||||
// When `origin = center_of_rectangle(rect)`, `rect.x, rect.y` is the visual center.
|
||||
// Rotation always occurs around the anchor point.
|
||||
rectangle :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
@@ -400,6 +423,7 @@ rectangle :: proc(
|
||||
// Draw a stroked rectangle via SDF (analytical anti-aliasing at all orientations).
|
||||
// `roundness` is a 0–1 fraction controlling uniform corner rounding — 0 is sharp, 1 is fully rounded.
|
||||
// For per-corner pixel-precise rounding, use `rectangle_corners_lines` instead.
|
||||
// Origin semantics: see `rectangle`.
|
||||
rectangle_lines :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
@@ -415,6 +439,7 @@ rectangle_lines :: proc(
|
||||
}
|
||||
|
||||
// Draw a rectangle with per-corner rounding radii via SDF.
|
||||
// Origin semantics: see `rectangle`.
|
||||
rectangle_corners :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
@@ -436,12 +461,12 @@ rectangle_corners :: proc(
|
||||
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
|
||||
center_x := rect.x + half_width - origin.x
|
||||
center_y := rect.y + half_height - origin.y
|
||||
|
||||
if needs_transform(origin, rotation) {
|
||||
rotation_radians = math.to_radians(rotation)
|
||||
transform := build_pivot_rotation({rect.x, rect.y}, origin, rotation)
|
||||
transform := build_pivot_rotation({rect.x + origin.x, rect.y + origin.y}, origin, rotation)
|
||||
new_center := apply_transform(transform, {half_width, half_height})
|
||||
center_x = new_center.x
|
||||
center_y = new_center.y
|
||||
@@ -480,6 +505,7 @@ rectangle_corners :: proc(
|
||||
}
|
||||
|
||||
// Draw a stroked rectangle with per-corner rounding radii via SDF.
|
||||
// Origin semantics: see `rectangle`.
|
||||
rectangle_corners_lines :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
@@ -502,12 +528,12 @@ rectangle_corners_lines :: proc(
|
||||
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
|
||||
center_x := rect.x + half_width - origin.x
|
||||
center_y := rect.y + half_height - origin.y
|
||||
|
||||
if needs_transform(origin, rotation) {
|
||||
rotation_radians = math.to_radians(rotation)
|
||||
transform := build_pivot_rotation({rect.x, rect.y}, origin, rotation)
|
||||
transform := build_pivot_rotation({rect.x + origin.x, rect.y + origin.y}, origin, rotation)
|
||||
new_center := apply_transform(transform, {half_width, half_height})
|
||||
center_x = new_center.x
|
||||
center_y = new_center.y
|
||||
@@ -545,7 +571,114 @@ rectangle_corners_lines :: proc(
|
||||
prepare_sdf_primitive(layer, prim)
|
||||
}
|
||||
|
||||
// Draw a rectangle with a texture fill via SDF. Supports rounded corners via `roundness`,
|
||||
// rotation, and analytical anti-aliasing on the shape silhouette.
|
||||
// Origin semantics: see `rectangle`.
|
||||
rectangle_texture :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
id: Texture_Id,
|
||||
tint: Color = WHITE,
|
||||
uv_rect: Rectangle = {0, 0, 1, 1},
|
||||
sampler: Sampler_Preset = .Linear_Clamp,
|
||||
roundness: f32 = 0,
|
||||
origin: [2]f32 = {0, 0},
|
||||
rotation: f32 = 0,
|
||||
soft_px: f32 = 1.0,
|
||||
) {
|
||||
cr := min(rect.width, rect.height) * clamp(roundness, 0, 1) * 0.5
|
||||
rectangle_texture_corners(
|
||||
layer,
|
||||
rect,
|
||||
{cr, cr, cr, cr},
|
||||
id,
|
||||
tint,
|
||||
uv_rect,
|
||||
sampler,
|
||||
origin,
|
||||
rotation,
|
||||
soft_px,
|
||||
)
|
||||
}
|
||||
|
||||
// Draw a rectangle with a texture fill and per-corner rounding radii via SDF.
|
||||
// Origin semantics: see `rectangle`.
|
||||
rectangle_texture_corners :: proc(
|
||||
layer: ^Layer,
|
||||
rect: Rectangle,
|
||||
radii: [4]f32,
|
||||
id: Texture_Id,
|
||||
tint: Color = WHITE,
|
||||
uv_rect: Rectangle = {0, 0, 1, 1},
|
||||
sampler: Sampler_Preset = .Linear_Clamp,
|
||||
origin: [2]f32 = {0, 0},
|
||||
rotation: f32 = 0,
|
||||
soft_px: f32 = 1.0,
|
||||
) {
|
||||
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)
|
||||
|
||||
padding := soft_px / GLOB.dpi_scaling
|
||||
dpi_scale := GLOB.dpi_scaling
|
||||
|
||||
half_width := rect.width * 0.5
|
||||
half_height := rect.height * 0.5
|
||||
rotation_radians: f32 = 0
|
||||
center_x := rect.x + half_width - origin.x
|
||||
center_y := rect.y + half_height - origin.y
|
||||
|
||||
if needs_transform(origin, rotation) {
|
||||
rotation_radians = math.to_radians(rotation)
|
||||
transform := build_pivot_rotation({rect.x + origin.x, rect.y + origin.y}, origin, rotation)
|
||||
new_center := apply_transform(transform, {half_width, half_height})
|
||||
center_x = new_center.x
|
||||
center_y = new_center.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 - bounds_half_width - padding,
|
||||
center_y - bounds_half_height - padding,
|
||||
center_x + bounds_half_width + padding,
|
||||
center_y + bounds_half_height + padding,
|
||||
},
|
||||
color = tint,
|
||||
kind_flags = pack_kind_flags(.RRect, {.Textured}),
|
||||
rotation = rotation_radians,
|
||||
uv_rect = {uv_rect.x, uv_rect.y, uv_rect.width, uv_rect.height},
|
||||
}
|
||||
prim.params.rrect = RRect_Params {
|
||||
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,
|
||||
}
|
||||
prepare_sdf_primitive_textured(layer, prim, id, sampler)
|
||||
}
|
||||
|
||||
// Draw a filled circle via SDF.
|
||||
//
|
||||
// Origin semantics (Convention B):
|
||||
// `origin` is a local offset from the shape's center that selects both the positioning anchor
|
||||
// and the rotation pivot. The `center` parameter specifies where that anchor point lands in
|
||||
// world space. When `origin = {0, 0}` (default), `center` is the visual center.
|
||||
// When `origin = {r, 0}`, the point `r` pixels to the right of the shape center lands at
|
||||
// `center`, shifting the shape left by `r`.
|
||||
circle :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
@@ -582,6 +715,7 @@ circle :: proc(
|
||||
}
|
||||
|
||||
// Draw a stroked circle via SDF.
|
||||
// Origin semantics: see `circle`.
|
||||
circle_lines :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
@@ -619,6 +753,7 @@ circle_lines :: proc(
|
||||
}
|
||||
|
||||
// Draw a filled ellipse via SDF.
|
||||
// Origin semantics: see `circle`.
|
||||
ellipse :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
@@ -665,6 +800,7 @@ ellipse :: proc(
|
||||
}
|
||||
|
||||
// Draw a stroked ellipse via SDF.
|
||||
// Origin semantics: see `circle`.
|
||||
ellipse_lines :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
@@ -715,6 +851,7 @@ ellipse_lines :: proc(
|
||||
}
|
||||
|
||||
// Draw a filled ring arc via SDF.
|
||||
// Origin semantics: see `circle`.
|
||||
ring :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
@@ -757,6 +894,7 @@ ring :: proc(
|
||||
}
|
||||
|
||||
// Draw stroked ring arc outlines via SDF.
|
||||
// Origin semantics: see `circle`.
|
||||
ring_lines :: proc(
|
||||
layer: ^Layer,
|
||||
center: [2]f32,
|
||||
|
||||
Reference in New Issue
Block a user