made get_normalized_position_scale (got rid of get_snapped_position), more docs

This commit is contained in:
2025-01-10 17:45:15 -05:00
parent 52584f888c
commit 4afa50f1df
2 changed files with 214 additions and 80 deletions

View File

@@ -156,16 +156,28 @@ draw_text_string_pos_norm :: proc( content : string, font : Font_ID, size : f32,
def := demo_ctx.font_ids[ font.label ]
size := size > 2.0 ? size : f32(def.default_size)
norm_pos, norm_scale := ve.get_normalized_position_scale( pos, scale, demo_ctx.screen_size )
ve.draw_text_normalized_space( & demo_ctx.ve_ctx,
def.ve_id,
size,
color_norm,
demo_ctx.screen_size,
pos,
scale,
norm_pos,
norm_scale,
1.0,
content
)
// ve.draw_text_view_space( & demo_ctx.ve_ctx,
// def.ve_id,
// size,
// color_norm,
// demo_ctx.screen_size,
// pos,
// scale,
// 1.0,
// content
// )
return
}
@@ -193,7 +205,6 @@ draw_text_zoomed_norm :: proc(content : string, font : Font_ID, size : f32, pos
def.ve_id,
resolved_size,
color_norm,
screen_size,
pos,
text_scale,
1.0,

View File

@@ -39,19 +39,19 @@ Entry_Default :: Entry {
// Ease of use encapsulation of common fields for a canvas space
VPZ_Transform :: struct {
view : Vec2,
position : Vec2,
zoom : f32,
view : Vec2,
position : Vec2,
zoom : f32,
}
Scope_Stack :: struct {
font : [dynamic]Font_ID,
font_size : [dynamic]f32,
colour : [dynamic]RGBAN,
view : [dynamic]Vec2,
position : [dynamic]Vec2,
scale : [dynamic]Vec2,
zoom : [dynamic]f32,
font : [dynamic]Font_ID,
font_size : [dynamic]f32,
colour : [dynamic]RGBAN,
view : [dynamic]Vec2,
position : [dynamic]Vec2,
scale : [dynamic]Vec2,
zoom : [dynamic]f32,
}
Context :: struct {
@@ -104,8 +104,6 @@ Context :: struct {
px_scalar : f32, // Improves hinting, positioning, etc. Can make zoomed out text too jagged.
default_curve_quality : i32,
}
Init_Atlas_Params :: struct {
@@ -644,21 +642,29 @@ auto_pop_vpz :: #force_inline proc( ctx : ^Context, camera : VPZ_Transform ) {
get_cursor_pos :: #force_inline proc "contextless" ( ctx : Context ) -> Vec2 { return ctx.cursor_pos }
// Does nothing when view is 1 or 0.
get_snapped_position :: #force_inline proc "contextless" ( position : Vec2, view : Vec2 ) -> (snapped_position : Vec2) {
// Will normalize the value of the position and scale based on the provided view.
// Position will also be snapped to the nearest pixel via ceil.
// (Does nothing if view is 1 or 0)
get_normalized_position_scale :: #force_inline proc "contextless" ( position, scale, view : Vec2 ) -> (position_norm, scale_norm : Vec2)
{
snap_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) }
should_snap := view * snap_quotient
snapped_position = position
snapped_position := position
snapped_position.x = ceil(position.x * view.x) * snap_quotient.x
snapped_position.y = ceil(position.y * view.y) * snap_quotient.y
snapped_position *= should_snap
snapped_position.x = max(snapped_position.x, position.x)
snapped_position.y = max(snapped_position.y, position.y)
return snapped_position
position_norm = snapped_position
scale_norm = scale * snap_quotient
return
}
resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, default_size, interval, min, max : f32 ) -> (resolved_size : f32)
{
// Used to constrain the px_size used in draw calls.
resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, default_size, interval, min, max : f32 ) -> (resolved_size : f32) {
interval_quotient := 1.0 / f32(interval)
size := px_size == 0.0 ? default_size : px_size
even_size := round(size * interval_quotient) * interval
@@ -666,27 +672,49 @@ resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, default_size
return
}
set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar }
set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar }
set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar }
set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar }
// During a shaping pass on text, will snap each glyph's position via ceil.
set_snap_glyph_shape_position :: #force_inline proc( ctx : ^Context, should_snap : b32 ) {
assert(ctx != nil)
ctx.shaper_ctx.snap_glyph_position = should_snap
}
// During to_cache pass within batch_generate_glyphs_draw_list, will snap the quad's size using ceil.
set_snap_glyph_render_height :: #force_inline proc( ctx : ^Context, should_snap : b32 ) {
assert(ctx != nil)
ctx.glyph_buffer.snap_glyph_height = cast(f32) i32(should_snap)
}
// Non-scoping context. The most fundamental interface-level draw shape procedure.
// (everything else is quality of life warppers)
/* The most fundamental interface-level draw shape procedure.
Context's stack is not used. Only modifications for alpha sharpen and px_scalar are applied.
view, position, and scale are expected to be in unsigned normalized space:
| +----------------------------------+ (1.0, 1.0)
| | |
| | |
| | Glyph Quad |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +--------+--------+.... |
| | position ^ ^ scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +----------------------------------+
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size.
*/
@(optimization_mode="favor_size")
draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
font : Font_ID,
px_size : f32,
colour : RGBAN,
view : Vec2, // Screen
position : Vec2,
scale : Vec2,
zoom : f32, // TODO(Ed): Implement zoom support
@@ -697,18 +725,13 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )
adjusted_position := get_snapped_position( position, view )
entry := ctx.entries[ font ]
adjusted_colour := colour
adjusted_colour.a += ctx.alpha_sharpen
view_norm := 1 / view
scale_norm := scale * view_norm
target_px_size := px_size * ctx.px_scalar
target_scale := scale_norm * (1 / ctx.px_scalar)
target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
@@ -722,14 +745,35 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
)
}
// Non-scoping context. The most fundamental interface-level draw text procedure.
// (everything else is quality of life warppers)
/* Non-scoping context. The most fundamental interface-level draw shape procedure (everything else is quality of life warppers).
Context's stack is not used. Only modifications for alpha sharpen and px_scalar are applied.
view, position, and scale are expected to be in unsigned normalized space:
| +----------------------------------+ (1.0, 1.0)
| | |
| | |
| | Glyph Quad |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +--------+--------+.... |
| | position ^ ^ scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +----------------------------------+
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size.
*/
@(optimization_mode = "favor_size")
draw_text_normalized_space :: proc( ctx : ^Context,
font : Font_ID,
px_size : f32,
colour : RGBAN,
view : Vec2,
position : Vec2,
scale : Vec2,
zoom : f32, // TODO(Ed): Implement Zoom support
@@ -744,17 +788,12 @@ draw_text_normalized_space :: proc( ctx : ^Context,
ctx.cursor_pos = {}
entry := ctx.entries[ font ]
adjusted_position := get_snapped_position( position, view )
adjusted_colour := colour
adjusted_colour.a += ctx.alpha_sharpen
view_norm := 1 / view
scale_norm := scale * view_norm
// Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar
target_scale := scale_norm * (1 / ctx.px_scalar)
target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
@@ -770,12 +809,33 @@ draw_text_normalized_space :: proc( ctx : ^Context,
entry,
target_px_size,
target_font_scale,
adjusted_position,
position,
target_scale,
)
}
// Equivalent to draw_text_shape_normalized_space, however position's unit convention is expected to be relative to the view
/* Equivalent to draw_text_shape_normalized_space, however the coordinate space is expected to be relative to the view.
view, position, and scale are expected to be in unsigned view space:
| +----------------------------------+ (view.x, view.y)
| | |
| | |
| | Glyph Quad |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +--------+--------+.... |
| | position ^ ^ scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +----------------------------------+
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size.
*/
// @(optimization_mode="favor_size")
draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
font : Font_ID,
@@ -791,19 +851,18 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
profile(#procedure)
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )
norm_position := position * (1 / view)
view := view; view.x = max(view.x, 1); view.y = max(view.y, 1)
adjusted_position := get_snapped_position( norm_position, view )
assert( ctx.px_scalar > 0.0 )
entry := ctx.entries[ font ]
adjusted_colour := colour
adjusted_colour.a = 1.0 + ctx.alpha_sharpen
target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar)
norm_position, norm_scale := get_normalized_position_scale( position, scale, view )
// Does nothing if px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
@@ -812,12 +871,33 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
entry,
target_px_size,
target_font_scale,
position,
norm_position,
target_scale,
)
}
// Equivalent to draw_text_shape_normalized_space, however position's unit convention is expected to be relative to the view
/* Equivalent to draw_text_shape_normalized_space, however the coordinate space is expected to be relative to the view.
view, position, and scale are expected to be in unsigned view space:
| +----------------------------------+ (view.x, view.y)
| | |
| | |
| | Glyph Quad |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +--------+--------+.... |
| | position ^ ^ scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +----------------------------------+
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size.
*/
// @(optimization_mode = "favor_size")
draw_text_view_space :: proc(ctx : ^Context,
font : Font_ID,
@@ -834,20 +914,19 @@ draw_text_view_space :: proc(ctx : ^Context,
assert( ctx != nil )
assert( font >= 0 && int(font) < len(ctx.entries) )
assert( len(text_utf8) > 0 )
assert( ctx.px_scalar > 0.0 )
ctx.cursor_pos = {}
entry := ctx.entries[ font ]
norm_position := position * (1 / view)
adjusted_colour := colour
adjusted_colour.a += ctx.alpha_sharpen
adjusted_position := get_snapped_position( norm_position, view )
norm_position, norm_scale := get_normalized_position_scale( position, scale, view )
adjusted_colour := colour
adjusted_colour.a = 1.0 + ctx.alpha_sharpen
// Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar)
// Does nothing if px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
@@ -863,26 +942,48 @@ draw_text_view_space :: proc(ctx : ^Context,
entry,
target_px_size,
target_font_scale,
adjusted_position,
norm_position,
target_scale,
)
}
// Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
/* Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
absolute_position := peek(stack.position) + position
absolute_scale := peek(stack.scale ) * scale
| +-----------------------------------+ (view.x, view.y)
| | |
| | |
| | Glyph Quad absolute |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +---------+--------+.... |
| | absolute ^ ^ absolute |
| | position scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +-----------------------------------+
*/
// @(optimization_mode = "favor_size")
draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text )
{
profile(#procedure)
assert( ctx != nil )
assert( ctx.px_scalar > 0.0 )
stack := & ctx.stack
assert(len(stack.font) > 0)
assert(len(stack.view) > 0)
assert(len(stack.colour) > 0)
assert(len(stack.position) > 0)
assert(len(stack.scale) > 0)
assert(len(stack.font) > 0)
assert(len(stack.view) > 0)
assert(len(stack.colour) > 0)
assert(len(stack.position) > 0)
assert(len(stack.scale) > 0)
assert(len(stack.font_size) > 0)
assert(len(stack.zoom) > 0)
assert(len(stack.zoom) > 0)
// TODO(Ed): This should be taken from the shape instead (you cannot use a different font with a shape)
font := peek(stack.font)
@@ -893,8 +994,8 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
ctx.cursor_pos = {}
entry := ctx.entries[ font ]
adjusted_colour := peek(stack.colour)
adjusted_colour.a = 1.0 + ctx.alpha_sharpen
adjusted_colour := peek(stack.colour)
adjusted_colour.a += ctx.alpha_sharpen
// TODO(Ed): Implement zoom for draw_text
zoom := peek(stack.zoom)
@@ -922,22 +1023,44 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
)
}
// Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
/* Uses the ctx.stack, position and scale are relative to the position and scale on the stack.
absolute_position := peek(stack.position) + position
absolute_scale := peek(stack.scale ) * scale
| +-----------------------------------+ (view.x, view.y)
| | |
| | |
| | Glyph Quad absolute |
| | +---------+ < scale.y |
| | | ** | * | |
| | | * * | **** | |
| | | **** | * * | |
| | | * * | **** | |
| | +---------+--------+.... |
| | absolute ^ ^ absolute |
| | position scale.x |
| | |
| | |
| | |
| (0.0, 0.0) +-----------------------------------+
*/
// @(optimization_mode = "favor_size")
draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
{
profile(#procedure)
assert( ctx != nil )
assert( len(text_utf8) > 0 )
assert( ctx.px_scalar > 0.0 )
stack := & ctx.stack
assert(len(stack.font) > 0)
assert(len(stack.font) > 0)
assert(len(stack.font_size) > 0)
assert(len(stack.colour) > 0)
assert(len(stack.view) > 0)
assert(len(stack.position) > 0)
assert(len(stack.scale) > 0)
assert(len(stack.zoom) > 0)
assert(len(stack.colour) > 0)
assert(len(stack.view) > 0)
assert(len(stack.position) > 0)
assert(len(stack.scale) > 0)
assert(len(stack.zoom) > 0)
font := peek(stack.font)
assert( font >= 0 &&int(font) < len(ctx.entries) )
@@ -947,8 +1070,8 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
ctx.cursor_pos = {}
entry := ctx.entries[ font ]
adjusted_colour := peek(stack.colour)
adjusted_colour.a = 1.0 + ctx.alpha_sharpen
adjusted_colour := peek(stack.colour)
adjusted_colour.a += ctx.alpha_sharpen
// TODO(Ed): Implement zoom for draw_text
zoom := peek(stack.zoom)