Got "Line LODs" working for the whitespace AST test, first step toward hboxes

Yet another issue with memory persists (seems to be related to slab free)
This commit is contained in:
2024-03-15 00:02:28 -04:00
parent ee8b68ac3e
commit 49a4e117a2
16 changed files with 463 additions and 146 deletions

View File

@ -91,8 +91,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 256 * Kilobyte, alignment })
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 512 * Kilobyte, alignment })
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 1 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment })
// push( policy_ptr, SlabSizeClass { 8 * Megabyte, 8 * Megabyte, alignment })
// push( policy_ptr, SlabSizeClass { 16 * Megabyte, 16 * Megabyte, alignment })
// push( policy_ptr, SlabSizeClass { 32 * Megabyte, 32 * Megabyte, alignment })
@ -135,6 +135,8 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
engine_refresh_hz = 30
timing_fps_moving_avg_alpha = 0.9
ui_resize_border_width = 5
}
@ -359,6 +361,10 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
}
}
config.timing_fps_moving_avg_alpha = 0.99
frametime_avg_ms = mov_avg_exp( f64(config.timing_fps_moving_avg_alpha), frametime_elapsed_ms, frametime_avg_ms )
fps_avg = 1 / (frametime_avg_ms * MS_To_S)
if frametime_elapsed_ms > 60.0 {
log( str_fmt_tmp("Big tick! %v ms", frametime_elapsed_ms), LogLevel.Warning )
}

View File

@ -2,14 +2,23 @@ package sectr
import "core:math/linalg"
pos_within_range2 :: proc( pos : Vec2, range : Range2 ) -> b32 {
within_x := pos.x > range.min.x && pos.x < range.max.x
within_y := pos.y > range.min.y && pos.y < range.max.y
return b32(within_x && within_y)
// AABB: Separating Axis Theorem
intersects_range2 :: #force_inline proc "contextless" ( a, b: Range2 ) -> bool
{
// Check if there's no overlap on the x-axis
if a.max.x < b.min.x || b.max.x < a.min.x {
return false; // No overlap on x-axis means no intersection
}
// Check if there's no overlap on the y-axis
if a.max.y < b.min.y || b.max.y < a.min.y {
return false; // No overlap on y-axis means no intersection
}
// If neither of the above conditions are true, there's at least a partial overlap
return true;
}
// TODO(Ed): Do we need this? Also does it even work (looks unfinished)?
is_within_screenspace :: proc( pos : Vec2 ) -> b32 {
is_within_screenspace :: #force_inline proc "contextless" ( pos : Vec2 ) -> b32 {
state := get_state(); using state
screen_extent := state.app_window.extent
cam := & project.workspace.cam
@ -18,13 +27,14 @@ is_within_screenspace :: proc( pos : Vec2 ) -> b32 {
return within_x_bounds && within_y_bounds
}
within_range2 :: #force_inline proc ( a, b : Range2 ) -> bool {
a_half_size := size_range2( a ) * 0.5
b_half_size := size_range2( b ) * 0.5
a_center := a.p0 + { a_half_size.x, -a_half_size.y }
b_center := b.p0 + { b_half_size.x, -b_half_size.y }
within_x := abs(a_center.x - b_center.x) <= (a_half_size.x + b_half_size.y)
within_y := abs(a_center.y - b_center.y) <= (a_half_size.y + b_half_size.y)
within_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> bool {
within_x := b.min.x >= a.min.x && b.max.x <= a.max.x
within_y := b.min.y >= a.min.y && b.max.y <= a.max.y
return within_x && within_y
}
pos_within_range2 :: #force_inline proc "contextless" ( pos : Vec2, range : Range2 ) -> b32 {
within_x := pos.x > range.min.x && pos.x < range.max.x
within_y := pos.y > range.min.y && pos.y < range.max.y
return b32(within_x && within_y)
}

View File

@ -137,6 +137,8 @@ AppConfig :: struct {
engine_refresh_hz : uint,
timing_fps_moving_avg_alpha : f32,
ui_resize_border_width : f32,
}
@ -169,12 +171,13 @@ State :: struct {
sleep_is_granular : b32,
frametime_delta_seconds : f64,
frametime_delta_ms : f64,
frametime_delta_ns : Duration,
frametime_target_ms : f64,
frametime_elapsed_ms : f64,
frametime_delta_seconds : f64,
frametime_delta_ms : f64,
frametime_delta_ns : Duration,
frametime_target_ms : f64,
frametime_elapsed_ms : f64,
frametime_avg_ms : f64,
fps_avg : f64,
font_firacode : FontID,
font_squidgy_slimes : FontID,

View File

@ -104,6 +104,11 @@ draw_text :: proc {
draw_text_string_cached,
}
mov_avg_exp :: proc {
mov_avg_exp_f32,
mov_avg_exp_f64,
}
get_bounds :: proc {
view_get_bounds,
}

View File

@ -82,7 +82,7 @@ zpl_hmap_destroy :: proc( using self : ^ HMapZPL( $ Type ) ) {
}
}
zpl_hmap_get :: proc( using self : ^ HMapZPL( $ Type ), key : u64 ) -> ^ Type
zpl_hmap_get :: proc ( using self : ^ HMapZPL( $ Type ), key : u64 ) -> ^ Type
{
// profile(#procedure)
id := zpl_hmap_find( self, key ).entry_index

View File

@ -7,11 +7,23 @@ Axis2 :: enum i32 {
Count,
}
is_power_of_two_u32 :: proc( value : u32 ) -> b32
is_power_of_two_u32 :: #force_inline proc "contextless" ( value : u32 ) -> b32
{
return value != 0 && ( value & ( value - 1 )) == 0
}
mov_avg_exp_f32 := #force_inline proc "contextless" ( alpha, delta_interval, last_value : f32 ) -> f32
{
result := (delta_interval * alpha) + (delta_interval * (1.0 - alpha))
return result
}
mov_avg_exp_f64 := #force_inline proc "contextless" ( alpha, delta_interval, last_value : f64 ) -> f64
{
result := (delta_interval * alpha) + (delta_interval * (1.0 - alpha))
return result
}
import "core:math/linalg"
Vec2 :: linalg.Vector2f32

17
code/render.odin Normal file
View File

@ -0,0 +1,17 @@
package sectr
import rl "vendor:raylib"
range2_to_rl_rect :: #force_inline proc "contextless"( range : Range2 ) -> rl.Rectangle
{
rect := rl.Rectangle {
range.min.x,
range.max.y,
abs(range.max.x - range.min.x),
abs(range.max.y - range.min.y),
}
return rect
}

View File

@ -32,53 +32,53 @@ when ODIN_OS == OS_Type.Windows {
// return points *
// }
f32_cm_to_pixels :: proc(cm: f32) -> f32 {
f32_cm_to_pixels :: #force_inline proc "contextless"(cm: f32) -> f32 {
screen_ppcm := get_state().app_window.ppcm
return cm * screen_ppcm
}
f32_pixels_to_cm :: proc(pixels: f32) -> f32 {
f32_pixels_to_cm :: #force_inline proc "contextless"(pixels: f32) -> f32 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
return pixels * cm_per_pixel
}
f32_points_to_pixels :: proc(points: f32) -> f32 {
f32_points_to_pixels :: #force_inline proc "contextless"(points: f32) -> f32 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
return points * DPT_PPCM * cm_per_pixel
}
f32_pixels_to_points :: proc(pixels: f32) -> f32 {
f32_pixels_to_points :: #force_inline proc "contextless"(pixels: f32) -> f32 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
return pixels * cm_per_pixel * Points_Per_CM
}
vec2_cm_to_pixels :: proc(v: Vec2) -> Vec2 {
vec2_cm_to_pixels :: #force_inline proc "contextless"(v: Vec2) -> Vec2 {
screen_ppcm := get_state().app_window.ppcm
return v * screen_ppcm
}
vec2_pixels_to_cm :: proc(v: Vec2) -> Vec2 {
vec2_pixels_to_cm :: #force_inline proc "contextless"(v: Vec2) -> Vec2 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
return v * cm_per_pixel
}
vec2_points_to_pixels :: proc(vpoints: Vec2) -> Vec2 {
vec2_points_to_pixels :: #force_inline proc "contextless"(vpoints: Vec2) -> Vec2 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
return vpoints * DPT_PPCM * cm_per_pixel
}
range2_cm_to_pixels :: proc( range : Range2 ) -> Range2 {
range2_cm_to_pixels :: #force_inline proc "contextless"( range : Range2 ) -> Range2 {
screen_ppcm := get_state().app_window.ppcm
result := Range2 { pts = { range.min * screen_ppcm, range.max * screen_ppcm }}
return result
}
range2_pixels_to_cm :: proc( range : Range2 ) -> Range2 {
range2_pixels_to_cm :: #force_inline proc "contextless"( range : Range2 ) -> Range2 {
screen_ppcm := get_state().app_window.ppcm
cm_per_pixel := 1.0 / screen_ppcm
result := Range2 { pts = { range.min * cm_per_pixel, range.max * cm_per_pixel }}
@ -132,7 +132,7 @@ screen_size :: proc "contextless" () -> AreaSize {
return transmute(AreaSize) ( extent * 2.0 )
}
screen_get_corners :: proc() -> BoundsCorners2 {
screen_get_corners :: #force_inline proc "contextless"() -> BoundsCorners2 {
state := get_state(); using state
screen_extent := state.app_window.extent
top_left := Vec2 { -screen_extent.x, screen_extent.y }
@ -142,16 +142,17 @@ screen_get_corners :: proc() -> BoundsCorners2 {
return { top_left, top_right, bottom_left, bottom_right }
}
view_get_bounds :: proc() -> Range2 {
state := get_state(); using state
cam := & project.workspace.cam
screen_extent := state.app_window.extent
top_left := Vec2 { cam.target.x, -cam.target.y } + Vec2 { -screen_extent.x, screen_extent.y} * (1/cam.zoom)
bottom_right := Vec2 { cam.target.x, -cam.target.y } + Vec2 { screen_extent.x, -screen_extent.y} * (1/cam.zoom)
return range2(top_left, bottom_right)
view_get_bounds :: #force_inline proc "contextless"() -> Range2 {
state := get_state(); using state
cam := & project.workspace.cam
screen_extent := state.app_window.extent
cam_zoom_ratio := 1.0 / cam.zoom
bottom_left := Vec2 { cam.target.x, -cam.target.y } + Vec2 { -screen_extent.x, -screen_extent.y} * cam_zoom_ratio
top_right := Vec2 { cam.target.x, -cam.target.y } + Vec2 { screen_extent.x, screen_extent.y} * cam_zoom_ratio
return range2( bottom_left, top_right )
}
view_get_corners :: proc() -> BoundsCorners2 {
view_get_corners :: #force_inline proc "contextless"() -> BoundsCorners2 {
state := get_state(); using state
cam := & project.workspace.cam
cam_zoom_ratio := 1.0 / cam.zoom
@ -170,22 +171,22 @@ screen_to_world :: #force_inline proc "contextless" (pos: Vec2) -> Vec2 {
return result
}
screen_to_render :: proc(pos: Vec2) -> Vec2 {
screen_to_render :: #force_inline proc "contextless"(pos: Vec2) -> Vec2 {
screen_extent := transmute(Vec2) get_state().project.workspace.cam.offset
return pos + { screen_extent.x, -screen_extent.y }
}
world_screen_extent :: proc() -> Extents2 {
world_screen_extent :: #force_inline proc "contextless"() -> Extents2 {
state := get_state(); using state
cam_zoom_ratio := 1.0 / project.workspace.cam.zoom
return app_window.extent * cam_zoom_ratio
}
world_to_screen_pos :: proc(position: Vec2) -> Vec2 {
world_to_screen_pos :: #force_inline proc "contextless"(position: Vec2) -> Vec2 {
return { position.x, position.y * -1 }
}
world_to_screen_no_zoom :: proc(position: Vec2) -> Vec2 {
world_to_screen_no_zoom :: #force_inline proc "contextless"(position: Vec2) -> Vec2 {
state := get_state(); using state
cam_zoom_ratio := 1.0 / state.project.workspace.cam.zoom
return { position.x, position.y * -1 } * cam_zoom_ratio

View File

@ -4,6 +4,7 @@ import "core:fmt"
import rl "vendor:raylib"
//@(optimization_mode="speed")
render :: proc()
{
profile(#procedure)
@ -23,7 +24,7 @@ render :: proc()
//region Render Screenspace
{
profile("Render Screenspace")
fps_msg := str_fmt_tmp( "FPS: %f", 1 / (frametime_elapsed_ms * MS_To_S) )
fps_msg := str_fmt_tmp( "FPS: %f", fps_avg)
fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 }
debug_draw_text( fps_msg, fps_msg_pos, 16.0, color = rl.GREEN )
@ -77,21 +78,21 @@ render :: proc()
ui := project.workspace.ui
debug_text("Box Count: %v", ui.built_box_count )
// debug_text("Box Count: %v", ui.built_box_count )
hot_box := ui_box_from_key( ui.curr_cache, ui.hot )
active_box := ui_box_from_key( ui.curr_cache, ui.active )
if hot_box != nil {
debug_text("Hot Box : %v", hot_box.label.str )
debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
// debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
}
if active_box != nil{
debug_text("Active Box: %v", active_box.label.str )
// debug_text("Active Box: %v", active_box.label.str )
}
// debug_text("Active Resizing: %v", ui.active_start_signal.resizing)
view := view_get_bounds()
debug_text("View Bounds (World): %v", view.pts )
// debug_text("View Bounds (World): %v", view.pts )
debug.draw_debug_text_y = 50
}
@ -122,9 +123,9 @@ render_mode_2d :: proc()
}}
view_rect := rl.Rectangle {
render_view.min.x,
render_view.min.y,
render_view.max.x - render_view.min.x,
render_view.max.y - render_view.min.y,
render_view.max.y,
abs(render_view.max.x - render_view.min.x),
abs(render_view.max.y - render_view.min.y),
}
rl.DrawRectangleRounded( view_rect, 0.3, 9, { 255, 0, 0, 20 } )
}
@ -141,7 +142,7 @@ render_mode_2d :: proc()
current := root.first
for ; current != nil; current = ui_box_tranverse_next( current )
{
profile("Box")
// profile("Box")
parent := current.parent
style := current.style
@ -149,18 +150,25 @@ render_mode_2d :: proc()
computed_size := computed.bounds.p1 - computed.bounds.p0
if ! within_range2( view_bounds, computed.bounds ) {
if ! intersects_range2( view_bounds, computed.bounds ) {
continue
}
// TODO(Ed) : Render Borders
// profile_begin("Calculating Raylib rectangles")
render_anchors := range2(
world_to_screen_pos(computed.anchors.min),
world_to_screen_pos(computed.anchors.max),
)
render_margins := range2(
world_to_screen_pos(computed.margins.min),
world_to_screen_pos(computed.margins.max),
)
render_bounds := range2(
world_to_screen_pos(computed.bounds.min),
world_to_screen_pos(computed.bounds.max),
)
render_padding := range2(
world_to_screen_pos(computed.padding.min),
world_to_screen_pos(computed.padding.max),
@ -170,24 +178,11 @@ render_mode_2d :: proc()
world_to_screen_pos(computed.content.max),
)
rect_bounds := rl.Rectangle {
render_bounds.min.x,
render_bounds.max.y,
abs(render_bounds.max.x - render_bounds.min.x),
abs(render_bounds.max.y - render_bounds.min.y),
}
rect_padding := rl.Rectangle {
render_padding.min.x,
render_padding.max.y,
abs(render_padding.max.x - render_padding.min.x),
abs(render_padding.max.y - render_padding.min.y),
}
rect_content := rl.Rectangle {
render_content.min.x,
render_content.max.y,
abs(render_content.max.x - render_content.min.x),
abs(render_content.max.y - render_content.min.y),
}
rect_anchors := range2_to_rl_rect( render_anchors )
rect_margins := range2_to_rl_rect( render_margins )
rect_bounds := range2_to_rl_rect( render_bounds )
rect_padding := range2_to_rl_rect( render_padding )
rect_content := range2_to_rl_rect( render_content )
// profile_end()
draw_rectangle :: #force_inline proc "contextless" ( rect : rl.Rectangle, style : UI_Style ) {

View File

@ -4,6 +4,7 @@ import "base:runtime"
import "core:math"
import "core:math/linalg"
import "core:os"
import str "core:strings"
import rl "vendor:raylib"
@ -63,6 +64,7 @@ frametime_delta32 :: #force_inline proc "contextless" () -> f32 {
return cast(f32) get_state().frametime_delta_seconds
}
//@(optimization_mode="speed")
update :: proc( delta_time : f64 ) -> b32
{
profile(#procedure)
@ -205,7 +207,7 @@ update :: proc( delta_time : f64 ) -> b32
}
default_layout := UI_Layout {
anchor = {},
alignment = { 0.0, 0.0 },
alignment = { 0., 0.0 },
text_alignment = { 0.0, 0.0 },
// corner_radii = { 0.2, 0.2, 0.2, 0.2 },
pos = { 0, 0 },
@ -240,7 +242,7 @@ update :: proc( delta_time : f64 ) -> b32
// test_text_box()
// test_parenting()
if true
if false
{
// frame := ui_widget( "Frame", {} )
// ui_parent(frame)
@ -292,11 +294,11 @@ update :: proc( delta_time : f64 ) -> b32
}
child_layout := default_layout
child_layout.size = range2({ 75, 75 }, { 0, 0 })
child_layout.alignment = { 0.5, 0.0 }
child_layout.size = range2({ 0, 0 }, { 0, 0 })
child_layout.alignment = { 0.5, 0.5 }
child_layout.margins = { 20, 20, 20, 20 }
child_layout.padding = {}
child_layout.anchor = range2({ 0.0, 0.0 }, { 0.0, 1.0 })
child_layout.anchor = range2({ 0.0, 0.0 }, { 0.0, 0.0 })
child_layout.pos = { 0, 0 }
child_theme := frame_style_default
@ -310,16 +312,19 @@ update :: proc( delta_time : f64 ) -> b32
}
// Whitespace AST test
if false
if true
{
profile("Whitespace AST test")
text_style := frame_style_default
text_style.flags = {
.Size_To_Text,
.Origin_At_Anchor_Center,
.Fixed_Position_X, .Fixed_Position_Y,
// .Fixed_Width, .Fixed_Height,
}
text_style.text_alignment = { 0.0, 0.5 }
text_style.alignment = { 0.0, 1.0 }
text_style.size.min = { 1600, 30 }
text_theme := UI_StyleTheme { styles = {
text_style,
@ -332,7 +337,7 @@ update :: proc( delta_time : f64 ) -> b32
text_theme.hot.bg_color = Color_Frame_Hover
text_theme.active.bg_color = Color_Frame_Select
layout_text := default_layout
layout_text := text_style.layout
ui_style_theme( text_theme )
@ -347,65 +352,114 @@ update :: proc( delta_time : f64 ) -> b32
// index := 0
widgets : Array(UI_Widget)
widgets, alloc_error = array_init( UI_Widget, frame_slab_allocator() )
widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), Kilobyte * 4 )
widgets_ptr := & widgets
label_id := 0
line_id := 0
for line in array_to_slice_num( debug.lorem_parse.lines )
{
profile("WS AST Line")
head := line.first
for ; head != nil;
{
ui_style_theme_set_layout( layout_text )
widget : UI_Widget
// We're assumping PWS_Token for now...
// Eventually I'm going to flatten this, its not worth doing it the way I am...
#partial switch head.type
{
case .Visible:
label := str_intern( str_fmt_alloc( "%v %v", head.content.str, label_id ))
widget = ui_text( label.str, head.content )
label_id += 1
layout_text.pos.x += size_range2( widget.computed.bounds ).x
case .Spaces:
label := str_intern( str_fmt_alloc( "%v %v", "space", label_id ))
widget = ui_space( label.str )
label_id += 1
for idx in 1 ..< len( head.content.runes )
{
// TODO(Ed): VIRTUAL WHITESPACE
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
}
layout_text.pos.x += size_range2( widget.computed.bounds ).x
case .Tabs:
label := str_intern( str_fmt_alloc( "%v %v", "tab", label_id ))
widget = ui_tab( label.str )
label_id += 1
for idx in 1 ..< len( head.content.runes )
{
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
}
layout_text.pos.x += size_range2( widget.computed.bounds ).x
}
array_append( widgets_ptr, widget )
head = head.next
if line_id == 0 {
line_id += 1
continue
}
layout_text.pos.x = default_layout.pos.x
layout_text.pos.y -= 30
ui_style_theme_set_layout( layout_text )
line_hbox := ui_widget(str_fmt_alloc( "line %v", line_id ), {})
if line_hbox.key == ui.hot
{
line_hbox.text = StringCached {}
ui_parent(line_hbox)
chunk_layout := layout_text
chunk_layout.alignment = { 0.0, 1.0 }
chunk_layout.anchor = range2({ 0.0, 0 }, { 0.0, 0 })
chunk_layout.pos = {}
chunk_style := text_style
chunk_style.flags = { .Fixed_Position_X, .Size_To_Text }
chunk_style.layout = chunk_layout
chunk_theme := UI_StyleTheme { styles = {
chunk_style,
chunk_style,
chunk_style,
chunk_style,
}}
ui_style_theme( chunk_theme )
head := line.first
for ; head != nil;
{
ui_style_theme_set_layout( chunk_layout )
widget : UI_Widget
#partial switch head.type
{
case .Visible:
label := str_intern( str_fmt_alloc( "%v %v", head.content.str, label_id ))
widget = ui_text( label.str, head.content )
label_id += 1
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
case .Spaces:
label := str_intern( str_fmt_alloc( "%v %v", "space", label_id ))
widget = ui_text_spaces( label.str )
label_id += 1
for idx in 1 ..< len( head.content.runes )
{
// TODO(Ed): VIRTUAL WHITESPACE
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
}
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
case .Tabs:
label := str_intern( str_fmt_alloc( "%v %v", "tab", label_id ))
widget = ui_text_tabs( label.str )
label_id += 1
for idx in 1 ..< len( head.content.runes )
{
// widget.style.layout.size.x += range2_size( widget.computed.bounds )
}
chunk_layout.pos.x += size_range2( widget.computed.bounds ).x
}
array_append( widgets_ptr, widget )
head = head.next
}
line_hbox.style.size.min.x = chunk_layout.pos.x
}
else
{
builder_backing : [16 * Kilobyte] byte
builder := str.builder_from_bytes( builder_backing[:] )
line_hbox.style.flags |= { .Size_To_Text }
head := line.first.next
for ; head != nil;
{
str.write_string( & builder, head.content.str )
head = head.next
}
line_hbox.text = str_intern( to_string( builder ) )
}
array_append( widgets_ptr, line_hbox )
layout_text.pos.x = text_style.layout.pos.x
layout_text.pos.y += size_range2(line_hbox.computed.bounds).y
line_id += 1
}
label_id += 1
label_id += 1 // Dummy action
}
}
//endregion Imgui Tick

View File

@ -183,6 +183,10 @@ UI_StyleFlag :: enum u32 {
Fixed_Width,
Fixed_Height,
// Sets the (0, 0) position of the child box to the parents anchor's center (post-margins bounds)
// By Default, the origin is at the top left of the anchor's bounds
Origin_At_Anchor_Center,
// Will size the box to its text. (Padding & Margins will thicken )
Size_To_Text,
Text_Wrap,
@ -340,7 +344,7 @@ ui_reload :: proc( ui : ^ UI_State, cache_allocator : Allocator )
ui_shutdown :: proc() {
}
ui_box_equal :: proc( a, b : ^ UI_Box ) -> b32 {
ui_box_equal :: #force_inline proc "contextless" ( a, b : ^ UI_Box ) -> b32 {
BoxSize :: size_of(UI_Box)
result : b32 = true
@ -349,10 +353,11 @@ ui_box_equal :: proc( a, b : ^ UI_Box ) -> b32 {
return result
}
ui_box_from_key :: proc( cache : ^HMapZPL(UI_Box), key : UI_Key ) -> (^UI_Box) {
ui_box_from_key :: #force_inline proc ( cache : ^HMapZPL(UI_Box), key : UI_Key ) -> (^UI_Box) {
return zpl_hmap_get( cache, cast(u64) key )
}
//@(optimization_mode="speed")
ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
{
// profile(#procedure)
@ -407,8 +412,10 @@ ui_box_make :: proc( flags : UI_BoxFlags, label : string ) -> (^ UI_Box)
ui_box_tranverse_next :: proc "contextless" ( box : ^ UI_Box ) -> (^ UI_Box)
{
// Check to make sure parent is present on the screen, if its not don't bother.
// If current has children, do them first
if box.first != nil {
if intersects_range2( view_get_bounds(), box.computed.bounds) && box.first != nil
{
return box.first
}
@ -479,7 +486,8 @@ ui_graph_build :: proc( ui : ^ UI_State ) {
ui_graph_build_begin( ui )
}
ui_key_from_string :: proc( value : string ) -> UI_Key
//@(optimization_mode="speed")
ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_Key
{
// profile(#procedure)
USE_RAD_DEBUGGERS_METHOD :: true

View File

@ -3,6 +3,8 @@ package sectr
import "core:math"
import "core:math/linalg"
// Note(Ed): This is naturally pretty expensive
//@(optimization_mode="speed")
ui_compute_layout :: proc()
{
profile(#procedure)
@ -21,7 +23,7 @@ ui_compute_layout :: proc()
current := root.first
for ; current != nil;
{
profile("Layout Box")
// profile("Layout Box")
style := current.style
// These are used to choose via multiplication weather to apply
@ -118,15 +120,18 @@ ui_compute_layout :: proc()
// 5. Determine relative position
// TODO(Ed): Let the user determine the coordinate space origin?
// rel_pos := margined_bounds_origin + alignment_offset + layout.pos
rel_pos := margined_bounds_origin + layout.pos
origin_center := margined_bounds_origin
origin_top_left := Vec2 { margined_bounds.min.x, margined_bounds.max.y }
origin := .Origin_At_Anchor_Center in style.flags ? origin_center : origin_top_left
rel_pos := origin + layout.pos
if .Fixed_Position_X in style.flags {
rel_pos.x = parent_center.x + layout.pos.x
rel_pos.x = origin.x + layout.pos.x
}
if .Fixed_Position_Y in style.flags {
rel_pos.y = parent_center.y + layout.pos.y
rel_pos.y = origin.y + layout.pos.y
}
vec2_one := Vec2 { 1, 1 }

View File

@ -1,5 +1,6 @@
package sectr
//@(optimization_mode="speed")
ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
{
// profile(#procedure)
@ -182,7 +183,6 @@ ui_signal_from_box :: proc ( box : ^ UI_Box ) -> UI_Signal
if ! was_active {
box.prev_style = box.style
box.style_delta = 0
log( str_fmt_tmp("NEW ACTIVE: %v", box.label.str))
}
box.style = stack_peek( & ui.theme_stack ).active
}

View File

@ -5,6 +5,7 @@ UI_Widget :: struct {
using signal : UI_Signal,
}
//@(optimization_mode="speed")
ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
{
// profile(#procedure)
@ -14,6 +15,7 @@ ui_widget :: proc( label : string, flags : UI_BoxFlags ) -> (widget : UI_Widget)
return
}
//@(optimization_mode="speed")
ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widget)
{
// profile(#procedure)
@ -24,6 +26,7 @@ ui_button :: proc( label : string, flags : UI_BoxFlags = {} ) -> (btn : UI_Widge
return
}
//@(optimization_mode="speed")
ui_text :: proc( label : string, content : StringCached, flags : UI_BoxFlags = {} ) -> UI_Widget
{
// profile(#procedure)
@ -36,7 +39,8 @@ ui_text :: proc( label : string, content : StringCached, flags : UI_BoxFlags = {
return { box, signal }
}
ui_space :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
//@(optimization_mode="speed")
ui_text_spaces :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
{
// profile(#procedure)
state := get_state(); using state
@ -51,7 +55,8 @@ ui_space :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
return { box, signal }
}
ui_tab :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
//@(optimization_mode="speed")
ui_text_tabs :: proc( label : string, flags : UI_BoxFlags = {} ) -> UI_Widget
{
// profile(#procedure)
state := get_state(); using state