Compare commits

...

17 Commits

Author SHA1 Message Date
Ed_
87d5cda2c0 more review 2025-07-04 14:40:25 -04:00
Ed_
b15503c079 fleshing out some of the input binding impl 2025-07-04 14:06:51 -04:00
Ed_
2e8381b097 Beginning to review progress on prototype codebase bootstrapping. 2025-07-04 14:06:28 -04:00
Ed_
ff91e41da9 convert all region/endregion directives to the comment signature used with editor plugins 2025-06-30 09:26:17 -04:00
Ed_
74567ae98a adding some stuff from watl but not ready to use yet 2025-06-28 20:57:05 -04:00
Ed_
cf7151a1ce misc changes
not worth comment ing on...
2025-06-28 20:56:49 -04:00
Ed_
bf5ecd0e0d adjust build script to odin_sectr.exe (renamed when compiler builds) 2025-06-28 20:56:11 -04:00
Ed_
54db9a7d57 misc updates to dependencies
removed freetype, updated vefontcache to latest and sokol + sokol gp
2025-06-26 23:27:05 -04:00
Ed_
3fd4e139d9 gitignore fixes 2025-06-26 22:15:43 -04:00
Ed_
01e989adc8 update gitignore 2025-06-26 21:46:32 -04:00
Ed_
29130cb367 old stuff
Planning to come back to this and eval some state.
Not ready to fully come back still out learning from the past.
2025-06-26 21:44:30 -04:00
Ed_
5b0878d14d update to latest vefontcache 2025-02-13 19:47:19 -05:00
Ed_
85dbaa37b9 updating to latest VEFontCache... tested 10k draw call target (worked) 2025-02-13 19:12:13 -05:00
Ed_
0f5f9c18b1 Update readme, build scripts
Add incremental build check for stb truetype lib
2025-02-01 09:29:31 -05:00
Ed_
07cd28226f update to latest 2025-01-13 20:44:07 -05:00
Ed_
0cd2d84c64 Simplified text rendering code (since its now much of the heavily lifting is all on VEFontCache) 2025-01-13 01:08:02 -05:00
Ed_
7680290650 vefontcache fixes 2025-01-13 00:55:42 -05:00
49 changed files with 29785 additions and 19349 deletions

View File

@ -21,7 +21,6 @@ indent_style = tab
indent_size = 2
charset = utf-8
[*.{natvis, natstepfilter}]
indent_style = tab
indent_size = 4

34
.gitignore vendored
View File

@ -1,13 +1,29 @@
build/**
*.exe
# thirdparty/**
logs
.ark
logs*.zip
code_flattened
Sectr.sublime-project
Sectr.sublime-workspace
# binaries
build/**
*.exe
# folders
assets/TX-02-1WN9N6Q8
thirdparty/backtrace
thirdparty/harfbuzz
thirdparty/ini
thirdparty/sokol
thirdparty/sokol-tools
toolchain/**
# logs
logs
logs*.zip
# toolchain
.ark
ols.json
.vscode/settings.json
# thirdparty
# toolchain
*.spall
sectr.user
sectr.proj

View File

@ -16,22 +16,24 @@ https://github.com/user-attachments/assets/0a895478-4a04-4ac6-a0ac-5355ff87ef4e
The dependencies are:
* Odin Compiler (Slightly custom [fork](https://github.com/Ed94/Odin))
* Added #region, #endregion directives support for editors
* I added support for 'monlithic packages' or 'uniform-across-subdirectories packages'. It allows me to organize the main package with sub-directories.
* Added the ability to debug using statements on structs (fields get dumped to the stack as ptr refs)
* Remove implicit assignments for container allocators in the Base and Core packages
* I did not enjoy bug hunting a memory corruption because I mistakenly didn't properly initialize a core container with their designated initiatizer: new, make, or init.
* See fork Readme for which procedures were changed..
* Odin repo's base, core, and vendor(raylib) libaries
* An ini parser
* Odin repo's base, core, and some of vendor
* [VEFontCache-Odin](https://github.com/Ed94/VEFontCache-Odin): Text rendering & shaping library created for this prototype
* [stb_truetype-odin](https://github.com/Ed94/stb_truetype-odin): Variant of the stb/truetype package in odin's vendor collection made for VEFontCache-Odin
* [harfbuzz-odin](https://github.com/Ed94/harfbuzz-odin): Custom repo with tailor made bindings for VEFontCache-Odin
* [sokol-odin (Sectr Fork)](https://github.com/Ed94/sokol-odin)
* [sokol-tools](https://github.com/floooh/sokol-tools)
* Powershell (if you want to use my build scripts)
* backtrace (not used yet)
* freetype (not used yet)
* harfbuzz
* sokol
* sokol-tools
* Powershell (if you want to use my build scripts)
* Eventually some config parser (maybe I'll use metadesk, or [ini](https://github.com/laytan/odin-ini-parser))
The project is so far in a "codebase boostrapping" phase. Most the work being done right now is setting up high performance linear zoom rendering for text and UI.
Text has recently hit sufficient peformance targets, and now inital UX has become the focus.
The project's is organized into 2 runtime modules sectr_host & sectr.
The host module loads the main module & its memory. Hot-reloading it's dll when it detects a change.
@ -43,7 +45,6 @@ Codebase organization:
* Has the following definitions: startup, shutdown, reload, tick, clean_frame (which host hooks up to when managing the client dll)
* Will handle async ops.
* Font Provider: Manages fonts.
* Bulk of visualization must be able to render text effectively
* Bulk of implementation maintained as a separate library: [VEFontCache-Odin](https://github.com/Ed94/VEFontCache-Odin)
* Grime: Name speaks for itself, stuff not directly related to the target features to iterate upon for the prototype.
* Defining dependency aliases or procedure overload tables, rolling own allocator, data structures, etc.
@ -76,3 +77,42 @@ They'll be elaborated in their own documentation
![img](docs/assets/sectr_host_2024-05-11_22-34-15.png)
![img](docs/assets/sectr_host_2024-05-15_03-32-36.png)
![img](docs/assets/Code_2024-05-21_23-15-16.gif)
## Notes
Due to bug with custom ols click file in root of sectr to get full symbol reflection setup on the monolithic package.
For support for regions - grab a region extension and use the following regex:
VS-Code Explicit Folding:
```json
"explicitFolding.rules": {
"odin": [
{
"beginRegex": "region\\b",
"endRegex": "endregion\\b"
},
{
"beginRegex": "{",
"endRegex": "}"
},
{
"beginRegex": "\\[",
"endRegex": "\\]"
},
{
"beginRegex": "\\(",
"endRegex": "\\)"
},
{
"beginRegex": "\"",
"endRegex": "\""
},
{
"beginRegex": "/\\*",
"endRegex": "\\*/"
}
]
},
```

View File

@ -1,4 +1,4 @@
VEFontCache Odin
VEFontCache Odin
Copyright 2024 Edward R. Gonzalez
This project is based on Vertex Engine GPU Font Cache

View File

@ -84,6 +84,7 @@ Glyph_Draw_Buffer :: struct{
size : Vec2i,
draw_padding : f32,
snap_glyph_height : f32,
snap_glyph_width : f32,
allocated_x : i32, // Space used (horizontally) within the glyph buffer
clear_draw_list : Draw_List,
@ -463,7 +464,7 @@ generate_shape_draw_list :: proc( draw_list : ^Draw_List, shape : Shaped_Text,
* Oversized will have a draw call setup to blit directly from the glyph buffer to the target.
* to_cache will blit the glyphs rendered from the buffer to the atlas.
*/
@(optimization_mode = "favor_size")
@(optimization_mode="favor_size")
batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
shape : Shaped_Text,
glyph_pack : ^#soa[dynamic]Glyph_Pack_Entry,
@ -640,7 +641,7 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
}
profile_end()
@(optimization_mode = "favor_size")
@(optimization_mode="favor_size")
generate_blit_from_atlas_draw_list :: #force_inline proc (draw_list : ^Draw_List, glyph_pack : #soa[]Glyph_Pack_Entry, sub_pack : []i32, colour : RGBAN )
{
profile(#procedure)
@ -703,13 +704,13 @@ batch_generate_glyphs_draw_list :: proc ( draw_list : ^Draw_List,
dst_glyph_pos := glyph.region_pos
dst_glyph_size := bounds_size_scaled + atlas.glyph_padding
dst_glyph_size.x = ceil(dst_glyph_size.x)
dst_glyph_size.x = max(dst_glyph_size.x, ceil(dst_glyph_size.x) * glyph_buffer.snap_glyph_width) // Note(Ed): Can (in specific cases, rare.) improve hinting
dst_glyph_size.y = max(dst_glyph_size.y, ceil(dst_glyph_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting
to_glyph_buffer_space( & dst_glyph_pos, & dst_glyph_size, atlas_size )
src_position := Vec2 { glyph.buffer_x, 0 }
src_size := (bounds_size_scaled + atlas.glyph_padding) * glyph_buffer.over_sample
src_size.x = ceil(src_size.x)
src_size.x = max(src_size.x, ceil(src_size.x) * glyph_buffer.snap_glyph_width) // Note(Ed): Can (in specific cases, rare.) improve hinting
src_size.y = max(src_size.y, ceil(src_size.y) * glyph_buffer.snap_glyph_height) // Note(Ed): Seems to improve hinting
to_target_space( & src_position, & src_size, glyph_buffer_size )

View File

@ -10,9 +10,9 @@ Freetype isn't really supported and its not a high priority.
~~That interface is not exposed from this parser but could be added to parser_init.~~
STB_Truetype:
* Has macros for its allocation unfortuantely.
TODO(Ed): Just keep a local version of stb_truetype and modify it to support a sokol/odin compatible allocator.
Already wanted to do so anyway to evaluate the shape generation implementation.
* Added ability to set the stb_truetype allocator for STBTT_MALLOC and STBTT_FREE.
* Changed procedure signatures to pass the font_info struct by immutable ptr (#by_ptr)
when the C equivalent has their parameter as `const*`.
*/
import "core:c"
@ -27,10 +27,8 @@ Parser_Kind :: enum u32 {
Parser_Font_Info :: struct {
label : string,
kind : Parser_Kind,
using _ : struct #raw_union {
stbtt_info : stbtt.fontinfo,
// freetype_info : freetype.Face
},
stbtt_info : stbtt.fontinfo,
// freetype_info : freetype.Face
data : []byte,
}
@ -61,7 +59,7 @@ Parser_Context :: struct {
parser_stbtt_allocator_proc :: proc(
allocator_data : rawptr,
type : stbtt.gbAllocationType,
type : stbtt.zpl_allocator_type,
size : c.ssize_t,
alignment : c.ssize_t,
old_memory : rawptr,
@ -86,13 +84,13 @@ parser_init :: proc( ctx : ^Parser_Context, kind : Parser_Kind, allocator := con
ctx.kind = kind
ctx.lib_backing = allocator
stbtt_allocator := stbtt.gbAllocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
stbtt.SetAllocator( stbtt_allocator )
}
parser_reload :: proc( ctx : ^Parser_Context, allocator := context.allocator) {
ctx.lib_backing = allocator
stbtt_allocator := stbtt.gbAllocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
stbtt_allocator := stbtt.zpl_allocator { parser_stbtt_allocator_proc, & ctx.lib_backing }
stbtt.SetAllocator( stbtt_allocator )
}

View File

@ -24,6 +24,9 @@ Entry :: struct {
used : b32,
curve_quality : f32,
// TODO(Ed): Move over settings related to (snapping) hinting, oversample, px_scalar, etc;
// to here as there is no need to restrict the user to have one option for all fonts.
ascent : f32,
descent : f32,
line_gap : f32,
@ -81,9 +84,6 @@ Context :: struct {
// debug_print : b32,
// debug_print_verbose : b32,
// Will enforce even px_size when drawing.
even_size_only : f32,
// Whether or not to snap positioning to the pixel of the view
// Helps with hinting
snap_to_view_extent : b32,
@ -116,7 +116,10 @@ Init_Atlas_Params_Default :: Init_Atlas_Params {
}
Init_Glyph_Draw_Params :: struct {
// During the draw list generation stage when blitting to atlas, the quad wil be ceil()'d to the closest pixel.
// During the draw list generation stage when blitting to atlas, the quad's width will be ceil()'d to the closest pixel.
// Generally its not recommend todo this and is disabled on most renderers, but on rare occasion some fonts benefit from this.
snap_glyph_width : b32,
// During the draw list generation stage when blitting to atlas, the quad's height be ceil()'d to the closest pixel.
snap_glyph_height : b32,
// Intended to be x16 (4x4) super-sampling from the glyph buffer to the atlas.
// Oversized glyphs don't use this and instead do 2x or 1x depending on how massive they are.
@ -131,12 +134,13 @@ Init_Glyph_Draw_Params :: struct {
}
Init_Glyph_Draw_Params_Default :: Init_Glyph_Draw_Params {
snap_glyph_height = true,
over_sample = 4,
draw_padding = Init_Atlas_Params_Default.glyph_padding,
shape_gen_scratch_reserve = 512,
buffer_glyph_limit = 16,
batch_glyph_limit = 256,
snap_glyph_width = false,
snap_glyph_height = true,
over_sample = 4,
draw_padding = Init_Atlas_Params_Default.glyph_padding,
shape_gen_scratch_reserve = 512,
buffer_glyph_limit = 16,
batch_glyph_limit = 256,
}
Init_Shaper_Params :: struct {
@ -176,8 +180,8 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
glyph_draw_params := Init_Glyph_Draw_Params_Default,
shape_cache_params := Init_Shape_Cache_Params_Default,
shaper_params := Init_Shaper_Params_Default,
alpha_sharpen : f32 = 0.35,
px_scalar : f32 = 1.6,
alpha_sharpen : f32 = 0.1,
px_scalar : f32 = 1.4,
zoom_px_interval : i32 = 2,
// Curve quality to use for a font when unspecified,
@ -271,24 +275,24 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
for idx : u32 = 0; idx < shape_cache_params.capacity; idx += 1
{
stroage_entry := & shape_cache.storage[idx]
storage_entry := & shape_cache.storage[idx]
stroage_entry.glyph, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve )
storage_entry.glyph, error = make( [dynamic]Glyph, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate glyphs array for shape cache storage" )
stroage_entry.position, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve )
storage_entry.position, error = make( [dynamic]Vec2, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate positions array for shape cache storage" )
stroage_entry.visible, error = make( [dynamic]i32, len = 0, cap = shape_cache_params.reserve )
storage_entry.visible, error = make( [dynamic]i32, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate visible array for shape cache storage" )
stroage_entry.atlas_lru_code, error = make( [dynamic]Atlas_Key, len = 0, cap = shape_cache_params.reserve )
storage_entry.atlas_lru_code, error = make( [dynamic]Atlas_Key, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate atlas_lru_code array for shape cache storage" )
stroage_entry.region_kind, error = make( [dynamic]Atlas_Region_Kind, len = 0, cap = shape_cache_params.reserve )
storage_entry.region_kind, error = make( [dynamic]Atlas_Region_Kind, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate region_kind array for shape cache storage" )
stroage_entry.bounds, error = make( [dynamic]Range2, len = 0, cap = shape_cache_params.reserve )
storage_entry.bounds, error = make( [dynamic]Range2, len = 0, cap = shape_cache_params.reserve )
assert( error == .None, "VEFontCache.init : Failed to allocate bounds array for shape cache storage" )
}
}
@ -296,6 +300,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
Glyph_Buffer_Setup:
{
glyph_buffer := & ctx.glyph_buffer
glyph_buffer.snap_glyph_width = cast(f32) i32(glyph_draw_params.snap_glyph_width)
glyph_buffer.snap_glyph_height = cast(f32) i32(glyph_draw_params.snap_glyph_height)
glyph_buffer.over_sample = { f32(glyph_draw_params.over_sample), f32(glyph_draw_params.over_sample) }
glyph_buffer.size.x = atlas.region_d.slot_size.x * i32(glyph_buffer.over_sample.x) * i32(glyph_draw_params.buffer_glyph_limit)
@ -415,7 +420,7 @@ hot_reload :: proc( ctx : ^Context, allocator : Allocator )
lru_reload( & shape_cache.state, allocator )
for idx : i32 = 0; idx < i32(len(shape_cache.storage)); idx += 1 {
storage_entry := & shape_cache.storage[idx]
reload_array( & storage_entry.glyph, allocator)
reload_array( & storage_entry.glyph, allocator)
reload_array( & storage_entry.position, allocator)
reload_array( & storage_entry.visible, allocator)
reload_array( & storage_entry.atlas_lru_code, allocator)
@ -604,11 +609,11 @@ clear_shape_cache :: proc (ctx : ^Context)
{
lru_clear(& ctx.shape_cache.state)
for idx : i32 = 0; idx < cast(i32) cap(ctx.shape_cache.storage); idx += 1 {
stroage_entry := & ctx.shape_cache.storage[idx]
stroage_entry.end_cursor_pos = {}
stroage_entry.size = {}
clear(& stroage_entry.glyph)
clear(& stroage_entry.position)
storage_entry := & ctx.shape_cache.storage[idx]
storage_entry.end_cursor_pos = {}
storage_entry.size = {}
clear(& storage_entry.glyph)
clear(& storage_entry.position)
}
ctx.shape_cache.next_cache_id = 0
}
@ -752,7 +757,7 @@ draw_shape_normalized_space :: #force_inline proc( ctx : ^Context,
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")
@(optimization_mode="favor_size")
draw_text_normalized_space :: proc( ctx : ^Context,
font : Font_ID,
px_size : f32,
@ -823,7 +828,7 @@ draw_text_normalized_space :: proc( ctx : ^Context,
zoom : Will affect the scale similar to how the zoom on a canvas would behave.
*/
// @(optimization_mode="favor_size")
draw_shape_view_space :: #force_inline proc( ctx : ^Context,
draw_shape_view_space :: proc( ctx : ^Context,
colour : RGBAN,
view : Vec2,
position : Vec2,
@ -849,10 +854,9 @@ draw_shape_view_space :: #force_inline proc( ctx : ^Context,
resolved_size, zoom_scale := resolve_zoom_size_scale( zoom, px_size, scale, ctx.zoom_px_interval, 2, 999.0, view )
target_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view )
// Does nothing if px_scalar is 1.0
target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * px_scalar_quotient
target_font_scale := parser_scale( entry.parser_info, target_px_size )
target_px_size,
target_font_scale,
target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale)
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar,
@ -918,10 +922,9 @@ draw_text_view_space :: proc(ctx : ^Context,
resolved_size, zoom_scale := resolve_zoom_size_scale( zoom, px_size, scale, ctx.zoom_px_interval, 2, 999.0, view )
target_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view )
// Does nothing if px_scalar is 1.0
target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
target_px_size,
target_font_scale,
target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale)
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font,
@ -1002,11 +1005,9 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
absolute_scale := peek(stack.scale) * zoom_scale
target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view )
// Does nothing when px_scalar is 1.0
target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * px_scalar_quotient
target_font_scale := parser_scale( entry.parser_info, target_px_size )
target_px_size,
target_font_scale,
target_scale := resolve_px_scalar_size(entry.parser_info,resolved_size, ctx.px_scalar, norm_scale)
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar,
@ -1082,11 +1083,9 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string,
absolute_scale := peek(stack.scale) * scale
target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view )
// Does nothing when px_scalar is 1.0
target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size )
target_px_size,
target_font_scale,
target_scale := resolve_px_scalar_size(entry.parser_info, resolved_size, ctx.px_scalar, norm_scale)
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font,
@ -1150,7 +1149,8 @@ measure_shape_size :: #force_inline proc( ctx : Context, shape : Shaped_Text ) -
}
// Don't use this if you already have the shape instead use measure_shape_size
measure_text_size :: #force_inline proc( ctx : ^Context, font : Font_ID, px_size : f32, text_utf8 : string,
@(optimization_mode="favor_size")
measure_text_size :: proc( ctx : ^Context, font : Font_ID, px_size : f32, text_utf8 : string,
shaper_proc : $Shaper_Shape_Text_Uncached_Proc = shaper_shape_harfbuzz
) -> (measured : Vec2)
{
@ -1196,6 +1196,10 @@ get_font_vertical_metrics :: #force_inline proc ( ctx : Context, font : Font_ID,
//#region("miscellaneous")
get_font_entry :: #force_inline proc "contextless" ( ctx : ^Context, font : Font_ID ) -> Entry {
return ctx.entries[font]
}
get_cursor_pos :: #force_inline proc "contextless" ( ctx : Context ) -> Vec2 { return ctx.cursor_pos }
// Will normalize the value of the position and scale based on the provided view.
@ -1203,19 +1207,14 @@ get_cursor_pos :: #force_inline proc "contextless" ( ctx : Context ) -> Vec2 { r
// (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
should_snap := cast(f32) i32(view.x > 0 && view.y > 0)
view_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) }
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
position_snapped := ceil(position) * view_quotient * should_snap
position_norm = position * view_quotient
snapped_position *= should_snap
snapped_position.x = max(snapped_position.x, position.x)
snapped_position.y = max(snapped_position.y, position.y)
position_norm = snapped_position
scale_norm = scale * snap_quotient
position_norm = max(position_snapped, position_norm)
scale_norm = scale * view_quotient
return
}
@ -1242,6 +1241,28 @@ resolve_zoom_size_scale :: #force_inline proc "contextless" (
return
}
// Get the target pixel, font_scale, and scale for the given font pixel size, and scalar multiple to apply. (Normalized space with norm_scale)
// To derived norm_scale use: get_normalized_position_scale or just do (scale * (1 / view))
resolve_px_scalar_size :: #force_inline proc "contextless" ( parser_info : Parser_Font_Info, px_size, px_scalar : f32, norm_scale : Vec2
) -> (target_px_size, target_font_scale : f32, target_scale : Vec2 )
{
// Does nothing when px_scalar is 1.0
target_px_size = px_size * px_scalar
target_scale = norm_scale * (1 / px_scalar)
target_font_scale = parser_scale( parser_info, target_px_size )
return
}
snap_normalized_position_to_view :: #force_inline proc "contextless" ( position, view : Vec2 ) -> (position_snapped : Vec2)
{
should_snap := cast(f32) i32(view.x > 0 && view.y > 0)
view_quotient := 1 / Vec2 { max(view.x, 1), max(view.y, 1) }
position_snapped = ceil(position * view) * view_quotient * should_snap
position_snapped = max(position, position_snapped)
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_zoom_px_interval :: #force_inline proc( ctx : ^Context, interval : i32 ) { assert(ctx != nil); ctx.zoom_px_interval = f32(interval) }
@ -1258,7 +1279,7 @@ set_snap_glyph_render_height :: #force_inline proc( ctx : ^Context, should_snap
ctx.glyph_buffer.snap_glyph_height = cast(f32) i32(should_snap)
}
//#endregion("misc")
//#endregion("miscellaneous")
//#region("scope stack")

View File

@ -37,8 +37,8 @@ array_underlying_slice :: proc(slice: []($ Type)) -> Array(Type)
return array
}
array_to_slice :: #force_inline proc( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(num)) }
array_to_slice_capacity :: #force_inline proc( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(capacity)) }
array_to_slice :: #force_inline proc "contextless" ( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(num)) }
array_to_slice_capacity :: #force_inline proc "contextless" ( using self : Array($ Type) ) -> []Type { return slice_ptr( data, int(capacity)) }
array_grow_formula :: proc( value : u64 ) -> u64 {
result := (2 * value) + 8

View File

@ -107,7 +107,7 @@ hmap_chained_clear :: proc( using self : HMapChained($Type))
continue
}
for probe_slot := slot.next; probe_slot != nil; probe_slot = probe_slot.next {
slot.occupied = false
probe_slot.occupied = false
}
slot.occupied = false
}

View File

@ -0,0 +1,2 @@
package grime

View File

@ -0,0 +1,48 @@
package grime
when (false) {
KT1L_Slot :: struct($Type: typeid) {
key: u64,
value: Type,
}
KT1L_Meta :: struct {
slot_size: uintptr,
kt_value_offset: uintptr,
type_width: uintptr,
type_name: string,
}
kt1l_populate_slice_a2_Slice_Byte :: proc(kt: ^[]byte, backing: Allocator = context.allocator, values: []byte, num_values: int, m: KT1L_Meta) {
assert(kt != nil)
if num_values == 0 { return }
table_size_bytes := num_values * int(m.slot_size)
err : AllocatorError
kt^, err = alloc_bytes(table_size_bytes, allocator = backing)
slice_assert(kt ^)
kt_raw : Raw_Slice = transmute(Raw_Slice) kt^
for cursor in 0 ..< cast(uintptr) num_values {
slot_offset := cursor * m.slot_size
slot_cursor := uintptr(kt_raw.data) + slot_offset
slot_key := cast(^u64) slot_cursor
slot_value := transmute([]byte) Raw_Slice { cast([^]byte) (slot_cursor + m.kt_value_offset), int(m.type_width)}
a2_offset := cursor * m.type_width * 2
a2_cursor := uintptr(& values[a2_offset])
a2_key := (transmute(^[]byte) a2_cursor) ^
a2_value := transmute([]byte) Raw_Slice { rawptr(a2_cursor + m.type_width), int(m.type_width) }
copy(slot_value, a2_value)
slot_key^ = 0; hash64_djb8(slot_key, a2_key)
}
kt_raw.len = num_values
}
kt1l_populate_slice_a2 :: proc($Type: typeid, kt: ^[]KT1L_Slot(Type), backing: AllocatorInfo, values: [][2]Type) {
assert(kt != nil)
values_bytes := transmute([]byte) Raw_Slice{data = raw_data(values), len = len(values) * size_of([2]Type)}
kt1l_populate_slice_a2_Slice_Byte(transmute(^[]byte) kt, backing, values_bytes, len(values), {
slot_size = size_of(KT1L_Slot(Type)),
kt_value_offset = offset_of(KT1L_Slot(Type), KT1L_Slot(Type).value),
type_width = size_of(Type),
type_name = #type_string(Type),
})
}
}

View File

@ -5,20 +5,20 @@ An intersive singly & double linked list implementation
*/
package grime
LL_Node :: struct ( $ Type : typeid ) {
next : ^Type,
SLL_Node :: struct ($Type: typeid) {
next: ^Type,
}
// ll_push :: proc( list_ptr : ^(^ ($ Type)), node : ^Type ) {
ll_push :: #force_inline proc "contextless" ( list_ptr : ^(^ ($ Type)), node : ^Type ) {
list : ^Type = (list_ptr^)
node.next = list
(list_ptr^) = node
sll_push :: #force_inline proc "contextless" ( list_ptr : ^(^ ($ Type)), node : ^Type, node_next: ^(^Type) ) {
list: = (list_ptr ^)
(node_next ^) = list
(list_ptr ^) = node
}
ll_pop :: #force_inline proc "contextless" ( list_ptr : ^(^ ($ Type)) ) -> ( node : ^Type ) {
list : ^Type = (list_ptr^)
(list_ptr^) = list.next
sll_pop :: #force_inline proc "contextless" ( list_ptr: ^(^ ($ Type)), list_next: ^(^Type) ) -> ( node : ^Type ) {
list : ^Type = (list_ptr ^)
(list_ptr ^) = (list_next ^)
return list
}
@ -43,27 +43,17 @@ DLL_NodeFull :: struct ( $ Type : typeid ) {
first, last : ^Type,
prev, next : ^Type,
}
// I have specific members commented out here as the RAD Debugger currently doesn't support transparently exposing using members of a struct (yet).
DLL_NodePN :: struct ( $ Type : typeid ) {
// using _ : struct {
prev, next : ^Type,
// },
// using _ : struct {
// left, right : ^Type,
// },
prev, next : ^Type,
}
DLL_NodeFL :: struct ( $ Type : typeid ) {
// using _ : struct {
first, last : ^Type,
// },
// TODO(Ed): Review this
// using _ : struct {
// bottom, top: ^Type,
// },
first, last : ^Type,
}
DLL_NodeBT :: struct ($Type: typeid) {
bottom, top: ^Type,
}
DLL_NodeLR :: struct ($Type: typeid) {
left, right: ^Type,
}
type_is_node :: #force_inline proc "contextless" ( $ Type : typeid ) -> bool

View File

@ -21,6 +21,7 @@ import "base:runtime"
Exabyte :: runtime.Exabyte
resize_non_zeroed :: runtime.non_zero_mem_resize
SourceCodeLocation :: runtime.Source_Code_Location
Raw_Slice :: runtime.Raw_Slice
//#endregion("base")

View File

@ -353,7 +353,7 @@ pool_validate_ownership :: proc( using self : Pool, block : [] byte ) -> b32
{
misalignment := (block_address - start) % uintptr(block_size)
if misalignment != 0 {
// TODO(Ed): We cannot use thsi to validate that the data is within the pool bucket as we can provide the user different alignments
// TODO(Ed): We cannot use this to validate that the data is within the pool bucket as we can provide the user different alignments
// ensure(false, "pool_validate_ownership: This data is within this pool's buckets, however its not aligned to the start of a block")
// log(str_fmt("Block address: %p Misalignment: %p closest: %p",
// transmute(rawptr)block_address,

View File

@ -64,7 +64,7 @@ str_cache_init :: proc( table_allocator, slabs_allocator : Allocator ) -> (cache
@static dbg_name := "StringCache slab"
// TODO(Ed): Is this nessary (essentially is there a perf impact of using vs not using, which is better because thats all that matters)
// TODO(Ed): Is this necessary (essentially is there a perf impact of using vs not using, which is better because thats all that matters)
// Interning should only be handled on a growing arena anyway so it doesn't really need this.
alloc_error : AllocatorError
cache.slab, alloc_error = slab_init( & policy, allocator = slabs_allocator, dbg_name = dbg_name )

View File

@ -3,9 +3,16 @@
package grime
str_fmt_kt1l :: proc() {
// str_format :: proc ( format : string, tokens : ..args ) {
}
// }
str_tfmt_backed :: proc() {
}
str_tfmt_tmp :: proc() {
}

View File

@ -1,10 +1,11 @@
/*
Odin's virtual arena allocator doesn't do what I ideally want for allocation resizing.
(It was also a nice exercise along with making the other allocators)
~~Odin's virtual arena allocator doesn't do what I ideally want for allocation resizing.~~
It was also a nice exercise along with making the other allocators)
So this is a virtual memory backed arena allocator designed
to take advantage of one large contigous reserve of memory.
With the expectation that resizes with its interface will only occur using the last allocated block.
Note(Ed): Odin's mem allocator now has that feature
All virtual address space memory for this application is managed by a virtual arena.
No other part of the program will directly touch the vitual memory interface direclty other than it.

View File

@ -44,14 +44,14 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
setup_container:
{
using container
if ! is_maximized
if ! is_maximized
{
layout.flags = {
// .Size_To_Content,
.Fixed_Width, .Fixed_Height,
.Fixed_Width, .Fixed_Height,
// .Min_Size_To_Content_Y,
.Fixed_Position_X, .Fixed_Position_Y,
.Origin_At_Anchor_Center
.Fixed_Position_X, .Fixed_Position_Y,
.Origin_At_Anchor_Center
}
layout.pos = pos
layout.size = range2( size, {})
@ -61,17 +61,17 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
layout.flags = {.Origin_At_Anchor_Center }
layout.pos = {}
}
dragged := ui_resizable_handles( & container, & pos, & size)
should_raise |= dragged
// TODO(Ed): This demonstrated a minimum viable-size window to content, however we still need to support a scroll box and switch this window to that.
old_vbox := ui_box_from_key(get_ui_context_mut().prev_cache, ui_key_from_string("Settings Menu: VBox"))
if old_vbox != nil
{
vbox_children_bounds := ui_compute_children_overall_bounds(old_vbox)
joined_size := size_range2( vbox_children_bounds )
if ! dragged
if ! dragged
{
// TODO(Ed): Figure out what this value is
extra_padding :: 3
@ -93,7 +93,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
ui_parent(vbox)
Frame_Bar:
{
{
scope(theme_window_bar)
frame_bar := ui_hbox(.Left_To_Right, "Settings Menu: Frame Bar", { .Mouse_Clickable })
{
@ -624,7 +624,7 @@ ui_settings_menu_builder :: proc( captures : rawptr = nil ) -> ( should_raise :
append( & input_str, to_runes(str_fmt("%v", config.text_size_canvas_scalar)))
}
}
Text_Alpha_Sharpen:
{
ui_settings_entry_inputbox( & text_alpha_sharpen, false, "settings_menu.text_alpha_sharpen", str_intern("Text: Alpha Sharpen"),

View File

@ -8,7 +8,7 @@ import "core:os"
Str_App_State := "App State"
#region("Memory")
//region Memory
Memory_App : Memory
@ -63,11 +63,16 @@ frame_allocator :: proc() -> Allocator {
return result
}
// TODO(Ed): Rethink usage of transient arena
// We can have it so that all usage of transients are chained 64 mb arenas. The users can clear the scratch and make a free-list on the parent varena.
// Anything over 64 mb or the chaining threshold should really have dedicated memory.
transient_allocator :: proc() -> Allocator {
result := varena_allocator( Memory_App.transient )
return result
}
// TODO(Ed): This needs to be reviewed as we technically can keep the whole file in buffer,
// but are we better off with a storage virtual mapping on-demand requested from the host by the client?
files_buffer_allocator :: proc() -> Allocator {
result := varena_allocator( Memory_App.files_buffer )
return result
@ -84,6 +89,9 @@ frame_slab_allocator :: proc() -> Allocator {
return result
}
// TODO(Ed): Rethink usage of transient arena, slab may still be useful but we need to think of the heursitic when this will be actively used
// String generation should use a chained arena, they should never exceed 64 mb or the max threshold (correct?)
// Dynamic arrays that last for a while maybe but are temp for complex workloads? Dynamic hashtables using arrays/arenas?
transient_slab_allocator :: proc() -> Allocator {
result := slab_allocator( get_state().transient_slab )
return result
@ -133,9 +141,9 @@ MemoryConfig :: struct {
commit_initial_filebuffer : uint,
}
#endregion("Memory")
//endregion Memory
#region("State")
//region State
// ALl nobs available for this application
AppConfig :: struct {
@ -216,9 +224,10 @@ State :: struct {
input_data : [2]InputState,
input_prev : ^InputState,
input : ^InputState,
input : ^InputState, // TODO(Ed): Rename to indicate its the device's signal state for the frame?
input_events : InputEvents,
input_events: InputEvents,
input_binds_stack: Array(InputContext),
// Note(Ed): Do not modify directly, use its interface in app/event.odin
staged_input_events : Array(InputEvent),
@ -292,4 +301,7 @@ get_screen_extent :: #force_inline proc "contextless" () -> Extents2 { retu
get_ui_context_mut :: #force_inline proc "contextless" () -> ^UI_State { return get_state().ui_context }
set_ui_context :: #force_inline proc "contextless" ( ui : ^UI_State ) { get_state().ui_context = ui }
#endregion("State")
get_input_binds :: #force_inline proc "contextless" () -> InputContext { return array_back(get_state().input_binds_stack) }
get_input_binds_stack :: #force_inline proc "contextless" () -> []InputContext { return array_to_slice(get_state().input_binds_stack) }
//endregion State

View File

@ -90,6 +90,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
push( policy_ptr, SlabSizeClass { 64 * Megabyte, 64 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 128 * Megabyte, 128 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 256 * Megabyte, 256 * Megabyte, alignment })
push( policy_ptr, SlabSizeClass { 512 * Megabyte, 512 * Megabyte, alignment })
// Anything above 128 meg needs to have its own setup looked into.
alloc_error : AllocatorError
@ -355,19 +356,21 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
// }
// Setup workspace UI state
ui_startup( & workspace.ui, cache_table_size = 8 * Kilo, cache_allocator = persistent_slab_allocator() )
ui_startup( & workspace.ui, cache_table_size = 64 * Kilo, cache_allocator = persistent_slab_allocator() )
}
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (197).txt", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum (1022).txt", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/ve_fontcache.h", allocator = persistent_slab_allocator())
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gp.h", allocator = persistent_slab_allocator())
// debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/sokol_gl.h", allocator = persistent_slab_allocator())
debug.path_lorem = str_fmt("C:\\projects\\SectrPrototype\\examples\\gencpp_singleheader.hpp", allocator = persistent_slab_allocator())
alloc_error : AllocatorError; success : bool
debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() )
debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_allocator() )
assert(success)
debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, persistent_slab_allocator() )
debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, persistent_allocator() )
verify( alloc_error == .None, "Faield to parse due to allocation failure" )
// Render texture test
@ -533,7 +536,7 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
debug.draw_ui_box_bounds_points = false
debug.draw_ui_padding_bounds = false
debug.draw_ui_content_bounds = false
debug.draw_ui_content_bounds = true
// config.engine_refresh_hz = 165

View File

@ -6,7 +6,7 @@ import str "core:strings"
import sokol_app "thirdparty:sokol/app"
#region("Sokol App")
//region Sokol App
sokol_app_init_callback :: proc "c" () {
context = get_state().sokol_context
@ -230,9 +230,9 @@ sokol_app_event_callback :: proc "c" (sokol_event : ^sokol_app.Event)
}
}
#endregion("Sokol App")
//endregion Sokol App
#region("Sokol GFX")
//region Sokol GFX
sokol_gfx_alloc :: proc "c" ( size : uint, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
@ -277,4 +277,4 @@ sokol_gfx_log_callback :: proc "c" (
log_fmt( "%-80s %s::%v", cloned_msg, cloned_tag, line_nr, level = odin_level )
}
#endregion("Sokol GFX")
//endregion Sokol GFX

View File

@ -58,10 +58,6 @@ render_mode_2d_workspace :: proc( screen_extent : Vec2, cam : Camera, input : In
font_provider_set_px_scalar( app_config().text_size_canvas_scalar )
// TODO(Ed): Eventually will be the viewport extents
// ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) )
// ve.configure_snap( ve_ctx, 0, 0 )
Render_Debug:
{
profile("render_reference_dots (workspace)")
@ -125,7 +121,6 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
screen_ratio := screen_size.x * ( 1.0 / screen_size.y )
font_provider_set_px_scalar( app_config().text_size_screen_scalar )
// ve.configure_snap( ve_ctx, u32(screen_size.x), u32(screen_size.y) )
render_screen_ui( screen_extent, screen_ui, ve_ctx, ve_render )
@ -161,8 +156,8 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
font := font
if font.key == Font_Default.key do font = default_font
shape := shape_text_cached( content, font, size, 1.0 )
draw_text_shape_pos_extent( shape, font, size, pos, color )
shape := shape_text_cached( content, font, size )
ve.draw_shape_view_space(& get_state().font_provider_ctx.ve_ctx, normalize_rgba8(color), get_screen_extent() * 2, screen_to_render_pos(pos), 1.0, 1.0, shape)
}
debug_text :: proc( format : string, args : ..any )
@ -177,8 +172,8 @@ render_mode_screenspace :: proc( screen_extent : Extents2, screen_ui : ^UI_State
position.y -= debug.draw_debug_text_y
content := str_fmt( format, ..args )
text_size := measure_text_size( content, default_font, 16.0, 0.0 )
debug_draw_text( content, position, 16.0 )
text_size := measure_text_size( content, default_font, 12.0, 0.0 )
debug_draw_text( content, position, 12.0 )
debug.draw_debug_text_y += text_size.y
}
@ -281,7 +276,6 @@ render_screen_ui :: proc( screen_extent : Extents2, ui : ^UI_State, ve_ctx : ^ve
render_list_box := array_to_slice( ui.render_list_box )
render_list_text := array_to_slice( ui.render_list_text )
render_ui_via_box_list( render_list_box, render_list_text, screen_extent, ve_ctx, ve_render )
// render_ui_via_box_list( render_list, screen_extent, ve_ctx, ve_render )
}
when UI_Render_Method == .Depth_First
{
@ -415,8 +409,7 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_
cam != nil ? cam.position.y : 0,
}
screen_size := screen_extent * 2
screen_size_norm := (1.0 / screen_size)
screen_size := screen_extent * 2
layer_left : b32 = true
for layer_left
@ -461,6 +454,13 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_
shape_enqueued = true
}
if debug.draw_ui_content_bounds
{
render_set_color(RGBA8_Debug_UI_Content_Bounds)
draw_rect_border(entry.bounds, 1.0)
shape_enqueued = true
}
box_id += 1
}
@ -484,12 +484,16 @@ render_ui_via_box_list :: proc( box_list : []UI_RenderBoxInfo, text_list : []UI_
if len(entry.text) == 0 do continue
text_enqueued = true
ve_id := font_provider_font_def(entry.font)
color := normalize_rgba8(entry.color)
if cam != nil {
draw_text_string_pos_extent_zoomed( entry.text, font, entry.font_size, entry.position, cam_offset, screen_size, screen_size_norm, cam.zoom, entry.color )
// draw_text_shape_pos_extent_zoomed( entry.shape, font, entry.font_size, entry.position, cam_offset, screen_size, screen_size_norm, cam.zoom, entry.color )
canvas_position := ws_view_to_render_pos(entry.position)
ve.draw_text_view_space(ve_ctx, ve_id, entry.font_size, color, screen_size, canvas_position, 1.0, cam.zoom, entry.text )
}
else {
draw_text_string_pos_extent( entry.text, font, entry.font_size, entry.position, entry.color )
screen_position := screen_to_render_pos(entry.position)
ve.draw_text_view_space(ve_ctx, ve_id, entry.font_size, color, screen_size, screen_position, 1.0, 1.0, entry.text)
}
}
@ -673,7 +677,20 @@ render_text_layer :: proc( screen_extent : Vec2, ve_ctx : ^ve.Context, render :
}
}
#region("Helpers")
//region Helpers
draw_shape :: proc(color : RGBAN, screen_size, position, scale : Vec2, zoom : f32, shape : ShapedText)
{
ve_ctx := & get_state().font_provider_ctx.ve_ctx
ve.draw_shape_view_space(ve_ctx, color, screen_size, position, scale, zoom, shape )
}
draw_text :: proc(font : FontID, px_size : f32, color : RGBAN, screen_size, position, scale : Vec2, zoom : f32, text : string)
{
ve_ctx := & get_state().font_provider_ctx.ve_ctx
ve_id := font_provider_font_def(font)
ve.draw_text_view_space(ve_ctx, ve_id, px_size, color, screen_size, position, scale, zoom, text )
}
draw_filled_circle :: proc(x, y, radius: f32, edges: int)
{
@ -850,147 +867,6 @@ draw_rect_rounded_border :: proc(rect: Range2, radii: [4]f32, border_width: f32,
draw_corner_border(rect.max.x - bottom_right, rect.max.y - bottom_right, bottom_right, max(bottom_right - border_width, 0), 0, segments)
}
// Draw text using a string and normalized render coordinates
draw_text_string_pos_norm :: #force_inline proc( text : string, id : FontID, font_size : f32, pos : Vec2, color := Color_White, scale : f32 = 1.0 )
{
screen_extent := get_state().app_window.extent // TODO(Ed): Pass this in instead..
screen_size := screen_extent * 2
target_size := font_size
ve_id, resolved_size := font_provider_resolve_draw_id( id, target_size )
color_norm := normalize_rgba8(color)
screen_size_norm := 1 / screen_size
draw_scale := screen_size_norm * scale
ve_ctx := & get_state().font_provider_ctx.ve_ctx
ve.draw_text_normalized_space(ve_ctx,
ve_id,
f32(resolved_size),
color_norm,
pos,
draw_scale,
text
)
return
}
// Draw text using a string and normalized render coordinates
draw_text_shape_pos_norm :: #force_inline proc( shape : ShapedText, id : FontID, font_size : f32, pos : Vec2, color := Color_White, scale : f32 = 1.0 )
{
ve_id, resolved_size := font_provider_resolve_draw_id( id, font_size )
color_norm := normalize_rgba8(color)
screen_size_norm := 1 / get_screen_extent() * 0.5
ve.draw_shape_normalized_space( & get_state().font_provider_ctx.ve_ctx,
color_norm,
pos,
screen_size_norm * scale,
shape
)
return
}
// Draw text using a string and extent-based screen coordinates
draw_text_shape_pos_extent :: #force_inline proc( shape : ShapedText, id : FontID, font_size : f32, pos : Vec2, color := Color_White )
{
profile(#procedure)
state := get_state(); using state
screen_size := app_window.extent * 2
render_pos := screen_to_render_pos(pos)
normalized_pos := render_pos * (1.0 / screen_size)
draw_text_shape_pos_norm( shape, id, font_size, normalized_pos, color )
}
// Draw text using a string and extent-based screen coordinates
draw_text_string_pos_extent :: #force_inline proc( text : string, id : FontID, font_size : f32, pos : Vec2, color := Color_White )
{
profile(#procedure)
screen_extent := get_state().app_window.extent // TODO(Ed): Pass this in instead..
screen_size := screen_extent * 2
render_pos := screen_to_render_pos(pos)
normalized_pos := render_pos * (1.0 / screen_size)
draw_text_string_pos_norm( text, id, font_size, normalized_pos, color )
}
draw_text_shape_pos_extent_zoomed :: #force_inline proc( shape : ShapedText, id : FontID, size : f32, pos, cam_offset, screen_size, screen_size_norm : Vec2, zoom : f32, color := Color_White )
{
profile(#procedure)
state := get_state(); using state // TODO(Ed): Remove usage of direct access to entire mutable state.
zoom_adjust_size := size * zoom
// Over-sample font-size for any render under a camera
over_sample : f32 = f32(app_config().text_size_canvas_scalar)
// zoom_adjust_size *= over_sample
pos_offset := (pos + cam_offset)
render_pos := ws_view_to_render_pos(pos)
normalized_pos := render_pos * screen_size_norm
ve_id, resolved_size := font_provider_resolve_draw_id( id, zoom_adjust_size )
f32_resolved_size := f32(resolved_size)
text_scale : Vec2 = screen_size_norm
// if config.cam_zoom_mode == .Smooth
{
diff_scalar := 1 + (zoom_adjust_size - f32_resolved_size) / f32_resolved_size
text_scale = diff_scalar * screen_size_norm
text_scale.x = clamp( text_scale.x, 0, screen_size.x )
text_scale.y = clamp( text_scale.y, 0, screen_size.y )
}
// Down-sample back
// text_scale /= over_sample
color_norm := normalize_rgba8(color)
// ve.set_px_scalar( & get_state().font_provider_ctx.ve_ctx, config.font_size_canvas_scalar )
ve.draw_shape_normalized_space( & font_provider_ctx.ve_ctx,
color_norm,
normalized_pos,
text_scale,
shape
)
}
draw_text_string_pos_extent_zoomed :: #force_inline proc( text : string, id : FontID, size : f32, pos, cam_offset, screen_size, screen_size_norm : Vec2, zoom : f32, color := Color_White )
{
profile(#procedure)
// state := get_state(); using state // TODO(Ed): Remove usage of direct access to entire mutable state.
config := app_config()
zoom_adjust_size := size * zoom
pos_offset := (pos + cam_offset)
render_pos := ws_view_to_render_pos(pos)
normalized_pos := render_pos * screen_size_norm
ve_id, resolved_size := font_provider_resolve_draw_id( id, zoom_adjust_size )
f32_resolved_size := f32(resolved_size)
text_scale : Vec2 = screen_size_norm
// if config.cam_zoom_mode == .Smooth
{
diff_scalar := 1 + (zoom_adjust_size - f32_resolved_size) / f32_resolved_size
text_scale = diff_scalar * screen_size_norm
text_scale.x = clamp( text_scale.x, 0, screen_size.x )
text_scale.y = clamp( text_scale.y, 0, screen_size.y )
}
color_norm := normalize_rgba8(color)
ve.draw_text_normalized_space( & get_state().font_provider_ctx.ve_ctx,
ve_id,
f32(resolved_size),
color_norm,
normalized_pos,
text_scale,
text
)
}
// TODO(Ed): Eventually the workspace will need a viewport for drawing text
render_flush_gp :: #force_inline proc()
@ -1021,4 +897,4 @@ render_set_view_space :: #force_inline proc( extent : Extents2 )
gp.project( -extent.x, extent.x, extent.y, -extent.y )
}
#endregion("Helpers")
//endregion Helper

View File

@ -137,18 +137,10 @@ font_provider_set_snap_glyph_render_height :: #force_inline proc( should_snap :
Font_Use_Default_Size :: f32(0.0)
font_provider_resolve_draw_id :: #force_inline proc( id : FontID, size := Font_Use_Default_Size ) -> (ve_id :ve.Font_ID, resolved_size : i32)
{
provider_data := get_state().font_provider_ctx; using provider_data
def := hmap_chained_get( font_cache, id.key )
size := size == 0.0 ? f32(def.default_size) : size
even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval)
resolved_size = clamp( i32( even_size), 2, Font_Largest_Px_Size )
id := (resolved_size / Font_Size_Interval) + (resolved_size % Font_Size_Interval)
ve_id = def.ve_id
return
font_provider_font_def :: #force_inline proc( font : FontID) -> ve.Font_ID {
provider := & get_state().font_provider_ctx;
def := hmap_chained_get( provider.font_cache, font.key )
return def.ve_id
}
measure_text_shape :: #force_inline proc( shape : ShapedText ) -> Vec2
@ -159,28 +151,28 @@ measure_text_shape :: #force_inline proc( shape : ShapedText ) -> Vec2
measure_text_size :: #force_inline proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
{
ve_id, size := font_provider_resolve_draw_id( font, font_size )
measured := ve.measure_text_size( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(size), text )
ve_id := font_provider_font_def(font)
measured := ve.measure_text_size( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(font_size), text )
return measured
}
get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Font_Use_Default_Size ) -> ( ascent, descent, line_gap : f32 )
{
ve_id, size := font_provider_resolve_draw_id( font, font_size )
ve_id := font_provider_font_def(font)
ascent, descent, line_gap = ve.get_font_vertical_metrics( get_state().font_provider_ctx.ve_ctx, ve_id, font_size )
return
}
shape_text_cached_latin :: #force_inline proc( text : string, font : FontID, font_size := Font_Use_Default_Size, scalar : f32 ) -> ShapedText
shape_text_cached_latin :: #force_inline proc( text : string, font : FontID, font_size := Font_Use_Default_Size ) -> ShapedText
{
ve_id, size := font_provider_resolve_draw_id( font, font_size * scalar )
shape := ve.shape_text( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(size), text, ve.shaper_shape_text_latin )
ve_id := font_provider_font_def(font)
shape := ve.shape_text( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(font_size), text, ve.shaper_shape_text_latin )
return shape
}
shape_text_cached :: #force_inline proc( text : string, font : FontID, font_size := Font_Use_Default_Size, scalar : f32 ) -> ShapedText
shape_text_cached :: #force_inline proc( text : string, font : FontID, font_size := Font_Use_Default_Size ) -> ShapedText
{
ve_id, size := font_provider_resolve_draw_id( font, font_size * scalar )
shape := ve.shape_text( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(size), text )
ve_id := font_provider_font_def(font)
shape := ve.shape_text( & get_state().font_provider_ctx.ve_ctx, ve_id, f32(font_size), text )
return shape
}

View File

@ -42,11 +42,10 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
BlendState :: sokol_gfx.Blend_State
BorderColor :: sokol_gfx.Border_Color
BufferDesciption :: sokol_gfx.Buffer_Desc
BufferUsage :: sokol_gfx.Usage
BufferType :: sokol_gfx.Buffer_Type
ColorTargetState :: sokol_gfx.Color_Target_State
Filter :: sokol_gfx.Filter
ImageDesc :: sokol_gfx.Image_Desc
ImageUsage :: sokol_gfx.Image_Usage
PassAction :: sokol_gfx.Pass_Action
Range :: sokol_gfx.Range
ResourceState :: sokol_gfx.Resource_State
@ -67,16 +66,14 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
screen_shader = sokol_gfx.make_shader(ve_draw_text_shader_desc(backend) )
draw_list_vbuf = sokol_gfx.make_buffer( BufferDesciption {
size = size_of([4]f32) * 2 * Mega,
usage = BufferUsage.STREAM,
type = BufferType.VERTEXBUFFER,
size = size_of([4]f32) * 4 * Mega,
usage = {vertex_buffer = true, stream_update = true},
})
verify( sokol_gfx.query_buffer_state( draw_list_vbuf) < ResourceState.FAILED, "Failed to make draw_list_vbuf" )
draw_list_ibuf = sokol_gfx.make_buffer( BufferDesciption {
size = size_of(u32) * 3 * Mega,
usage = BufferUsage.STREAM,
type = BufferType.INDEXBUFFER,
size = size_of(u32) * 6 * Mega,
usage = {index_buffer = true, stream_update = true},
})
verify( sokol_gfx.query_buffer_state( draw_list_ibuf) < ResourceState.FAILED, "Failed to make draw_list_iubuf" )
@ -141,12 +138,11 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
{
glyph_rt_color = sokol_gfx.make_image( ImageDesc {
type = ._2D,
render_target = true,
usage = ImageUsage { render_attachment = true, immutable = true },
width = i32(ve_ctx.glyph_buffer.size.x),
height = i32(ve_ctx.glyph_buffer.size.y),
num_slices = 1,
num_mipmaps = 1,
usage = .IMMUTABLE,
pixel_format = .R8,
sample_count = 1,
// TODO(Ed): Setup labels for debug tracing/logging
@ -156,12 +152,11 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
glyph_rt_depth = sokol_gfx.make_image( ImageDesc {
type = ._2D,
render_target = true,
usage = ImageUsage { render_attachment = true, immutable = true },
width = i32(ve_ctx.glyph_buffer.size.x),
height = i32(ve_ctx.glyph_buffer.size.y),
num_slices = 1,
num_mipmaps = 1,
usage = .IMMUTABLE,
pixel_format = .DEPTH,
sample_count = 1,
})
@ -278,12 +273,11 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
{
atlas_rt_color = sokol_gfx.make_image( ImageDesc {
type = ._2D,
render_target = true,
usage = { render_attachment = true, immutable = true },
width = i32(ve_ctx.atlas.size.x),
height = i32(ve_ctx.atlas.size.y),
num_slices = 1,
num_mipmaps = 1,
usage = .IMMUTABLE,
pixel_format = .R8,
sample_count = 1,
// TODO(Ed): Setup labels for debug tracing/logging
@ -293,12 +287,11 @@ font_provider_setup_sokol_gfx_objects :: proc( ctx : ^VE_RenderData, ve_ctx : ve
atlas_rt_depth = sokol_gfx.make_image( ImageDesc {
type = ._2D,
render_target = true,
usage = { render_attachment = true, immutable = true },
width = i32(ve_ctx.atlas.size.x),
height = i32(ve_ctx.atlas.size.y),
num_slices = 1,
num_mipmaps = 1,
usage = .IMMUTABLE,
pixel_format = .DEPTH,
sample_count = 1,
})

View File

@ -1,7 +1,7 @@
package sectr
#region("base")
//region base
import "base:builtin"
copy :: builtin.copy
@ -25,9 +25,9 @@ import "base:runtime"
SourceCodeLocation :: runtime.Source_Code_Location
debug_trap :: runtime.debug_trap
#endregion("base")
//endregion base
#region("core")
//region core
import c "core:c/libc"
@ -124,6 +124,8 @@ import "core:os"
import "core:path/filepath"
file_name_from_path :: filepath.short_stem
import "core:slice"
import "core:strconv"
parse_f32 :: strconv.parse_f32
parse_u64 :: strconv.parse_u64
@ -153,14 +155,14 @@ import "core:unicode/utf8"
runes_to_string :: utf8.runes_to_string
// string_to_runes :: utf8.string_to_runes
#endregion("core")
//endregion core
import "thirdparty:backtrace"
StackTraceData :: backtrace.Trace_Const
stacktrace :: backtrace.trace
stacktrace_lines :: backtrace.lines
#region("codebase")
//region codebase
import "codebase:grime"
// asserts
@ -194,6 +196,7 @@ import "codebase:grime"
array_append_value :: grime.array_append_value
array_append_array :: grime.array_append_array
array_append_at :: grime.array_append_at
array_back :: grime.array_back
array_clear :: grime.array_clear
array_free :: grime.array_free
array_grow_formula :: grime.array_grow_formula
@ -264,10 +267,10 @@ import "codebase:grime"
djb8_hash :: grime.djb8_hash
// linked lists
LL_Node :: grime.LL_Node
SLL_Node :: grime.SLL_Node
ll_push :: grime.ll_push
ll_pop :: grime.ll_pop
sll_push :: grime.sll_push
sll_pop :: grime.sll_pop
DLL_Node :: grime.DLL_Node
DLL_NodeFull :: grime.DLL_NodeFull
@ -345,9 +348,9 @@ import "codebase:grime"
varena_allocator :: grime.varena_allocator
#endregion("codebase")
//endregion codebase
#region("Procedure overload mappings")
//region Procedure overload mappings
// This has to be done on a per-module basis.
@ -366,6 +369,10 @@ append_at :: proc {
grime.array_append_at_slice,
}
back :: proc {
grime.array_back,
}
bivec3 :: proc {
bivec3_via_f32s,
vec3_to_bivec3,
@ -426,7 +433,7 @@ floor :: proc {
math.floor_f64le,
math.floor_f64be,
linalg.floor
linalg.floor,
}
from_bytes :: proc {
@ -717,4 +724,8 @@ wedge :: proc {
wedge_bivec3,
}
#endregion("Proc overload mappings")
zero :: proc {
slice.zero,
}
//endregion Proc overload mappings

View File

@ -1,12 +1,90 @@
package sectr
InputBindSig :: distinct u128
InputBindCallback :: #type proc(user_ptr : rawptr)
InputBind :: struct
{
user_ptr : rawptr,
callback : InputBindCallback,
InputBind :: struct {
keys: [4]KeyCode,
mouse_btns: [4]MouseBtn,
scroll: [2]AnalogAxis,
modifiers: ModifierCodeFlags,
label: string,
}
InputBindStatus :: struct {
detected: b32,
consumed: b32,
frame_id: u64,
}
InputActionProc :: #type proc(user_ptr: rawptr)
InputAction :: struct {
id: int,
user_ptr: rawptr,
cb: InputActionProc,
always: b32,
}
InputContext :: struct {
binds: []InputBind,
status: []InputBindStatus,
onpush_action: []InputAction,
onpop_action: []InputAction,
signature: []InputBindSig,
}
inputbind_signature :: proc(binding: InputBind) -> InputBindSig {
// TODO(Ed): Figure out best hasher for this...
return cast(InputBindSig) 0
}
// Note(Ed): Bindings should be remade for a context when a user modifies any in configuration.
inputcontext_init :: proc(ctx: ^InputContext, binds: []InputBind, onpush: []InputAction = {}, onpop: []InputAction = {}) {
ctx.binds = binds
ctx.onpush_action = onpush
ctx.onpop_action = onpop
for bind, id in ctx.binds {
ctx.signature[id] = inputbind_signature(bind)
}
}
inputcontext_make :: #force_inline proc(binds: []InputBind, onpush: []InputAction = {}, onpop: []InputAction = {}) -> InputContext {
ctx: InputContext; inputcontext_init(& ctx, binds, onpush, onpop); return ctx
}
// Should be called by the user explicitly during frame cleanup.
inputcontext_clear_status :: proc(ctx: ^InputContext) {
zero(ctx.status)
}
inputbinding_status :: #force_inline proc(id: int) -> InputBindStatus {
return get_input_binds().status[id]
}
inputcontext_inherit :: proc(dst: ^InputContext, src: ^InputContext) {
for dst_id, dst_sig in dst.signature
{
for src_id, src_sig in src.signature
{
if dst_sig != src_sig {
continue
}
dst.status[dst_id] = src.status[src_id]
}
}
}
inputcontext_push :: proc(ctx: ^InputContext, dont_inherit_status: b32 = false) {
// push context stack
// clear binding status for context
// optionally inherit status
// detect status
// Dispatch push actions meeting conditions
}
inputcontext_pop :: proc(ctx: ^InputContext, dont_inherit_status: b32 = false) {
// Dispatch pop actions meeting conditions
// parent inherit consumed statuses
// pop context stack
}

View File

@ -73,7 +73,7 @@ Vec3i :: [3]i32
vec2i_to_vec2 :: #force_inline proc "contextless" (v : Vec2i) -> Vec2 {return transmute(Vec2) v}
vec3i_to_vec3 :: #force_inline proc "contextless" (v : Vec3i) -> Vec3 {return transmute(Vec3) v}
#region("Range2")
//region Range2
// TODO(Ed): I rather keep the different usages as different types, then type coerece their procedure mappings
// to support the base p0, p1 range
@ -148,4 +148,4 @@ size_range2 :: #force_inline proc "contextless" ( value : Range2 ) -> Vec2 {
return { abs( value.p1.x - value.p0.x ), abs( value.p0.y - value.p1.y ) }
}
#endregion("Range2")
//endregion Range2

View File

@ -10,7 +10,11 @@ out vec2 uv;
void main()
{
uv = vec2( v_texture.x, 1 - v_texture.y );
#if SOKOL_GLSL
uv = vec2( v_texture.x, v_texture.y );
#else
uv = vec2( v_texture.x, 1.0 - v_texture.y );
#endif
gl_Position = vec4( v_position * 2.0f - 1.0f, 0.0f, 1.0f );
}
@end

View File

@ -48,6 +48,7 @@ UI_InteractState :: struct {
disabled_time : f32,
}
// TODO(Ed): Make the key 128-bit?
UI_Key :: distinct u64
UI_Scalar :: f32
@ -119,7 +120,8 @@ UI_BoxCache_TableSize :: 32 * Kilobyte
// TODO(Ed): Rename to UI_Context
UI_State :: struct {
// TODO(Ed) : Use these?
// TODO(Ed) : Use these? Right now the way our hashtable does things is it implicitly uses a pool allocator.
// We could instead use an arena (CR) allocator, if it chains it won't matter because the boxes are only accessed purely as a DAG.
// build_arenas : [2]Arena,
// build_arena : ^ Arena,
@ -140,11 +142,13 @@ UI_State :: struct {
// render_list : Array(UI_RenderBoxInfo),
render_list_box : Array(UI_RenderBoxInfo),
render_list_text : Array(UI_RenderTextInfo),
// TODO(Ed): We can have multiple list sets, one towards working-set, and the one enqueued for rendering (a buffered list matching the framebuffer)
// We can back these by arenas? Do we want them persistently on the slab?
null_box : ^UI_Box, // This was used with the Linked list interface...
root : ^UI_Box,
// TODO(Ed) : Look into using a build arena like Ryan does for these possibly (and thus have a linked-list stack)
// TODO(Ed) : Look into using a build arena like Ryan does for these possibly (and thus have a linked-list stack) (Chained Arenas)
layout_combo_stack : StackFixed( UI_LayoutCombo, UI_Style_Stack_Size ),
style_combo_stack : StackFixed( UI_StyleCombo, UI_Style_Stack_Size ),
parent_stack : StackFixed( ^UI_Box, UI_Parent_Stack_Size ),
@ -168,7 +172,7 @@ UI_State :: struct {
last_invalid_input_time : Time,
}
#region("Lifetime")
//region Lifetime
ui_startup :: proc( ui : ^ UI_State, spacial_indexing_method : UI_SpacialIndexingMethod = .QuadTree, cache_allocator : Allocator, cache_table_size : uint )
{
@ -287,7 +291,7 @@ ui_graph_build_end :: proc( ui : ^UI_State )
{
if len(current.text) > 0 {
profile("text shape")
current.computed.text_shape = shape_text_cached( current.text, current.style.font, current.layout.font_size, 1.0 )
current.computed.text_shape = shape_text_cached( current.text, current.style.font, current.layout.font_size )
}
ui_box_compute_layout( current )
}
@ -362,9 +366,9 @@ ui_render_entry_tranverse :: proc( entry : ^UI_RenderEntry ) -> ^UI_RenderEntry
@(deferred_in = ui_graph_build_end)
ui_graph_build :: #force_inline proc( ui : ^ UI_State ) { ui_graph_build_begin( ui ) }
#endregion("Lifetime")
//endregion Lifetime
#region("Caching")
//region Caching
// Mainly referenced from RAD Debugger
// TODO(Ed): Need to setup the proper hashing convention for strings the other reference imguis use.
@ -399,7 +403,7 @@ ui_key_from_string :: #force_inline proc "contextless" ( value : string ) -> UI_
return key
}
#endregion("Caching")
//endregion Caching
ui_cursor_pos :: #force_inline proc "contextless" () -> Vec2 {
using state := get_state()

View File

@ -1,5 +1,163 @@
package sectr
ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_LayoutDirection_X, width_ref : ^f32 = nil )
{
container_width : f32
if width_ref != nil {
container_width = width_ref ^
}
else {
container_width = container.computed.content.max.x - container.computed.content.min.x
}
container_height := container.computed.content.max.y - container.computed.content.min.y
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
size_req_children : f32 = 0
for child := container.first; child != nil; child = child.next
{
using child.layout
scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags)
if .Scale_Width_By_Height_Ratio in flags
{
size_req_children += size.min.x * container_height
continue
}
if .Fixed_Width in flags
{
size_req_children += size.min.x
continue
}
size_req_children += size.min.x
total_stretch_ratio += anchor.ratio.x
}
avail_flex_space := container_width - size_req_children
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_height : f32 ) -> (space_allocated : f32)
{
using child.layout
if .Scale_Width_By_Height_Ratio in flags {
size.min.y = container_height
space_allocated = size.min.x * container_height
}
else if ! (.Fixed_Width in flags) {
potential_size := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space
space_allocated = max(potential_size, size.min.x)
size.min.x = space_allocated
}
else {
space_allocated = size.min.x
}
space_allocated -= margins.left - margins.right
size.min.x -= margins.left - margins.right
flags |= {.Fixed_Width}
return
}
space_used : f32 = 0.0
switch direction{
case .Left_To_Right:
for child := container.first; child != nil; child = child.next {
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({0, anchor.bottom}, {0, anchor.top})
alignment = {0, alignment.y}
pos.x = space_used
space_used += child_width + child.layout.margins.left + child.layout.margins.right
}
case .Right_To_Left:
for child := container.first; child != nil; child = child.next {
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({1, anchor.bottom}, {0, anchor.top})
alignment = {1, alignment.y}
pos.x = space_used
space_used -= child_width + child.layout.margins.left + child.layout.margins.right
}
}
}
ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_LayoutDirection_Y, height_ref : ^f32 = nil )
{
container_height : f32
if height_ref != nil {
container_height = height_ref ^
}
else {
container_height = container.computed.content.max.y - container.computed.content.min.y
}
container_width := container.computed.content.max.x - container.computed.content.min.x
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
size_req_children : f32 = 0
for child := container.first; child != nil; child = child.next
{
using child.layout
scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags)
if scaled_height_by_width {
size_req_children += size.min.y * container_width
continue
}
if .Fixed_Height in flags
{
size_req_children += size.min.y
continue
}
size_req_children += size.min.y
total_stretch_ratio += anchor.ratio.y
}
avail_flex_space := container_height - size_req_children
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32)
{
using child.layout
if .Scale_Height_By_Width_Ratio in flags {
size.min.x = container_width
space_allocated = size.min.y * container_width
}
if ! (.Fixed_Height in flags) {
potential_size := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space)
space_allocated = max(potential_size, size.min.y)
size.min.y = space_allocated
}
else {
space_allocated = size.min.y
}
space_allocated -= margins.top - margins.bottom
size.min.y -= margins.top - margins.bottom
flags |= {.Fixed_Height}
return
}
space_used : f32 = 0
switch direction
{
case .Top_To_Bottom:
for child := container.first; child != nil; child = child.next {
using child.layout
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({anchor.left, 1}, {anchor.right, 0})
alignment = {alignment.x, 1}
pos.y = space_used
space_used -= child_height - child.layout.margins.top - child.layout.margins.bottom
}
case .Bottom_To_Top:
for child := container.first; child != nil; child = child.next {
using child.layout
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({anchor.left,0}, {anchor.right, 0})
alignment = {alignment.x, 0}
pos.y = space_used
space_used += child_height - child.layout.margins.top - child.layout.margins.bottom
}
}
}
ui_box_compute_layout :: proc( box : ^UI_Box,
dont_mark_fresh : b32 = false,
ancestors_layout_required : b32 = false,

View File

@ -1,168 +1,8 @@
package sectr
import "base:runtime"
import lalg "core:math/linalg"
/*
Widget Layout Ops
TODO(Ed): Review this file, these are can now be done with ui_box_compute_layout
For complex layout operations that are not supported by the core's auto-layout system.
*/
ui_layout_children_horizontally :: proc( container : ^UI_Box, direction : UI_LayoutDirection_X, width_ref : ^f32 = nil )
{
container_width : f32
if width_ref != nil {
container_width = width_ref ^
}
else {
container_width = container.computed.content.max.x - container.computed.content.min.x
}
container_height := container.computed.content.max.y - container.computed.content.min.y
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
size_req_children : f32 = 0
for child := container.first; child != nil; child = child.next
{
using child.layout
scaled_width_by_height : b32 = b32(.Scale_Width_By_Height_Ratio in flags)
if .Scale_Width_By_Height_Ratio in flags
{
size_req_children += size.min.x * container_height
continue
}
if .Fixed_Width in flags
{
size_req_children += size.min.x
continue
}
size_req_children += size.min.x
total_stretch_ratio += anchor.ratio.x
}
avail_flex_space := container_width - size_req_children
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_height : f32 ) -> (space_allocated : f32)
{
using child.layout
if .Scale_Width_By_Height_Ratio in flags {
size.min.y = container_height
space_allocated = size.min.x * container_height
}
else if ! (.Fixed_Width in flags) {
potential_size := anchor.ratio.x * (1 / total_stretch_ratio) * avail_flex_space
space_allocated = lalg.max(potential_size, size.min.x)
size.min.x = space_allocated
}
else {
space_allocated = size.min.x
}
space_allocated -= margins.left - margins.right
size.min.x -= margins.left - margins.right
flags |= {.Fixed_Width}
return
}
space_used : f32 = 0.0
switch direction{
case .Left_To_Right:
for child := container.first; child != nil; child = child.next {
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({0, anchor.bottom}, {0, anchor.top})
alignment = {0, alignment.y}
pos.x = space_used
space_used += child_width + child.layout.margins.left + child.layout.margins.right
}
case .Right_To_Left:
for child := container.first; child != nil; child = child.next {
using child.layout
child_width := allocate_space(child, total_stretch_ratio, avail_flex_space, container_height)
anchor = range2({1, anchor.bottom}, {0, anchor.top})
alignment = {1, alignment.y}
pos.x = space_used
space_used -= child_width + child.layout.margins.left + child.layout.margins.right
}
}
}
ui_layout_children_vertically :: proc( container : ^UI_Box, direction : UI_LayoutDirection_Y, height_ref : ^f32 = nil )
{
container_height : f32
if height_ref != nil {
container_height = height_ref ^
}
else {
container_height = container.computed.content.max.y - container.computed.content.min.y
}
container_width := container.computed.content.max.x - container.computed.content.min.x
// do layout calculations for the children
total_stretch_ratio : f32 = 0.0
size_req_children : f32 = 0
for child := container.first; child != nil; child = child.next
{
using child.layout
scaled_height_by_width : b32 = b32(.Scale_Height_By_Width_Ratio in flags)
if scaled_height_by_width {
size_req_children += size.min.y * container_width
continue
}
if .Fixed_Height in flags
{
size_req_children += size.min.y
continue
}
size_req_children += size.min.y
total_stretch_ratio += anchor.ratio.y
}
avail_flex_space := container_height - size_req_children
allocate_space :: proc( child : ^UI_Box, total_stretch_ratio, avail_flex_space, container_width : f32 ) -> (space_allocated : f32)
{
using child.layout
if .Scale_Height_By_Width_Ratio in flags {
size.min.x = container_width
space_allocated = size.min.y * container_width
}
if ! (.Fixed_Height in flags) {
potential_size := (anchor.ratio.y * (1 / total_stretch_ratio) * avail_flex_space)
space_allocated = lalg.max(potential_size, size.min.y)
size.min.y = space_allocated
}
else {
space_allocated = size.min.y
}
space_allocated -= margins.top - margins.bottom
size.min.y -= margins.top - margins.bottom
flags |= {.Fixed_Height}
return
}
space_used : f32 = 0
switch direction
{
case .Top_To_Bottom:
for child := container.first; child != nil; child = child.next {
using child.layout
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({anchor.left, 1}, {anchor.right, 0})
alignment = {alignment.x, 1}
pos.y = space_used
space_used -= child_height - child.layout.margins.top - child.layout.margins.bottom
}
case .Bottom_To_Top:
for child := container.first; child != nil; child = child.next {
using child.layout
child_height := allocate_space(child, total_stretch_ratio, avail_flex_space, container_width)
anchor = range2({anchor.left,0}, {anchor.right, 0})
alignment = {alignment.x, 0}
pos.y = space_used
space_used += child_height - child.layout.margins.top - child.layout.margins.bottom
}
}
}

View File

@ -190,13 +190,13 @@ test_whitespace_ast :: proc( default_layout : ^UI_Layout, frame_style_default :
// index := 0
widgets : Array(UI_Widget)
// widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), 8 )
widgets, alloc_error = make( Array(UI_Widget), 8 * Kilobyte )
widgets, alloc_error = make( Array(UI_Widget), 64 * Kilobyte )
widgets_ptr := & widgets
label_id := 0
builder : StringBuilder
str.builder_init_len_cap( & builder, len = 0, cap = 16 * Kilobyte )
str.builder_init_len_cap( & builder, len = 0, cap = 64 * Kilobyte )
line_id := 0
for line in array_to_slice( debug.lorem_parse.lines )

View File

@ -3,9 +3,6 @@ package sectr
import "base:runtime"
import lalg "core:math/linalg"
// Problably cursed way to setup a 'scope' for a widget
// ui_build :: #force_inline proc( captures : $Type, $maker : #type proc(captures : Type) -> $ReturnType ) -> ReturnType { return maker(captures) }
UI_Widget :: struct {
using box : ^UI_Box,
using signal : UI_Signal,
@ -26,7 +23,8 @@ ui_button :: #force_inline proc( label : string, flags : UI_BoxFlags = {} ) -> (
return
}
#region("Drop Down")
//region Drop Down
UI_DropDown :: struct {
btn : UI_Widget,
title : UI_Widget,
@ -109,9 +107,10 @@ ui_drop_down_end_auto :: proc( drop_down : ^UI_DropDown) {
ui_vbox_end(drop_down.vbox, compute_layout = false)
ui_parent_pop()
}
#endregion("Drop Down")
#region("Horizontal Box")
//endregion Drop Down
//region Horizontal Box
/*
Horizontal Boxes automatically manage a collection of widgets and
attempt to slot them adjacent to each other along the x-axis.
@ -169,9 +168,10 @@ ui_hbox_end_auto :: #force_inline proc( direction : UI_LayoutDirection_X, label
ui_hbox_end(hbox, width_ref)
ui_parent_pop()
}
#endregion("Horizontal Box")
//endregion Horizontal Box
//region Resizable
#region("Resizable")
// Parameterized widget def for ui_resizable_handles
UI_Resizable :: struct {
using widget : UI_Widget,
@ -500,8 +500,10 @@ ui_resizable_handles :: #force_no_inline proc( parent : ^UI_Widget, pos : ^Vec2,
// if drag_signal && compute_layout do ui_box_compute_layout(parent)
return
}
#endregion("Resizable")
//endregion Resizable
//region Text
ui_spacer :: proc( label : string ) -> (widget : UI_Widget) {
widget.box = ui_box_make( {.Mouse_Clickable}, label )
widget.signal = ui_signal_from_box( widget.box )
@ -522,7 +524,6 @@ ui_scroll_box :: proc( label : string, flags : UI_BoxFlags ) -> (scroll_box : UI
return
}
#region("Text")
ui_text :: #force_inline proc( label : string, content : StrCached, flags : UI_BoxFlags = {} ) -> UI_Widget
{
profile(#procedure)
@ -569,9 +570,10 @@ ui_text_wrap_panel :: proc( parent : ^UI_Widget )
{
fatal("NOT IMPLEMENTED")
}
#endregion("Text")
//endregion Text
//region Text Input
#region("Text Input")
UI_TextInput_Policy :: struct {
disallow_decimal : b32,
disallow_leading_zeros : b32,
@ -744,9 +746,9 @@ ui_text_input_box :: proc( text_input_box : ^UI_TextInputBox, label : string,
}
}
}
#endregion("Text Input")
//endregion Text Input
#region("Vertical Box")
//region Vertical Box
/*
Vertical Boxes automatically manage a collection of widgets and
attempt to slot them adjacent to each other along the y-axis.
@ -803,4 +805,4 @@ ui_vbox :: #force_inline proc( direction : UI_LayoutDirection_Y, label : string,
ui_parent_push(vbox.widget)
return
}
#endregion("Vertical Box")
//endregion Vertical Box

File diff suppressed because it is too large Load Diff

View File

@ -118,7 +118,7 @@ $msvc_link_default_base_address = 0x180000000
push-location $path_root
$update_deps = join-path $path_scripts 'update_deps.ps1'
$odin_compiler = join-path $path_odin 'odin.exe'
$odin_compiler = join-path $path_odin 'odin_sectr.exe'
function Invoke-WithColorCodedOutput { param( [scriptblock] $command )
& $command 2>&1 | ForEach-Object {
@ -141,22 +141,25 @@ push-location $path_root
$path_font = join-path $path_code 'font'
$module_scripts = $PSScriptRoot
$package_grime = join-path $path_code 'grime'
$package_VEFontCache = join-path $path_font 'VEFontCache'
$module_host = join-path $path_code 'host'
$module_sectr = join-path $path_code 'sectr'
$module_scripts = $PSScriptRoot
$package_grime = join-path $path_code 'grime'
$package_VEFontCache = join-path $path_font 'VEFontCache'
$package_stb_truetype = join-path $path_thirdparty 'stb'
$module_host = join-path $path_code 'host'
$module_sectr = join-path $path_code 'sectr'
if ($force){
mark-ModuleDirty $module_scripts
mark-ModuleDirty $package_VEFontCache
mark-ModuleDirty $package_stb_truetype
mark-ModuleDirty $package_grime
mark-ModuleDirty $module_sectr
mark-ModuleDirty $module_host
}
$module_scripts_dirty = check-ModuleForChanges $module_scripts
$pkg_VEFontCache_dirty = check-ModuleForChanges $package_VEFontCache
$pkg_grime_dirty = check-ModuleForChanges $package_grime
$module_scripts_dirty = check-ModuleForChanges $module_scripts
$pkg_VEFontCache_dirty = check-ModuleForChanges $package_VEFontCache
$pkg_stb_truetype_dirty = check-ModuleForChanges $package_stb_truetype
$pkg_grime_dirty = check-ModuleForChanges $package_grime
$pkg_collection_codebase = 'codebase=' + $path_code
$pkg_collection_thirdparty = 'thirdparty=' + $path_thirdparty
@ -174,7 +177,7 @@ push-location $path_root
function build-sectr
{
$should_build = (check-ModuleForChanges $module_sectr) -or $pkg_grime_dirty -or $pkg_VEFontCache_dirty -or $module_scripts_dirty
$should_build = (check-ModuleForChanges $module_sectr) -or $pkg_grime_dirty -or $pkg_VEFontCache_dirty -or $pkg_stb_truetype_dirty -or $module_scripts_dirty
if ( -not( $should_build)) {
write-host 'Skipping sectr build, module up to date'
return $module_unchanged
@ -197,7 +200,7 @@ push-location $path_root
$build_args = @()
$build_args += $command_build
$build_args += './sectr'
$build_args += 'sectr'
$build_args += $flag_build_mode_dll
$build_args += $flag_output_path + $module_dll
$build_args += ($flag_collection + $pkg_collection_codebase)
@ -205,8 +208,8 @@ push-location $path_root
# $build_args += $flag_micro_architecture_native
$build_args += $flag_use_separate_modules
$build_args += $flag_thread_count + $CoreCount_Physical
$build_args += $flag_optimize_none
# $build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_none
$build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_speed
# $build_args += $falg_optimize_aggressive
$build_args += $flag_debug
@ -286,8 +289,8 @@ push-location $path_root
# $build_args += $flag_micro_architecture_native
$build_args += $flag_use_separate_modules
$build_args += $flag_thread_count + $CoreCount_Physical
$build_args += $flag_optimize_none
# $build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_none
$build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_speed
# $build_args += $falg_optimize_aggressive
$build_args += $flag_debug

View File

@ -32,6 +32,7 @@ $flag_format_odin = '--format=sokol_odin'
$flag_module = '--module'
push-location $path_shaders
write-host 'Compiling shaders'
& $sokol_shdc --input $shadersrc_ve_blit_atlas --output $shaderout_ve_blit_atlas --slang 'hlsl4' $flag_format_odin $flag_module='vefc_blit_atlas'
& $sokol_shdc --input $shadersrc_ve_render_glyph --output $shaderout_ve_render_glyph --slang 'hlsl4' $flag_format_odin $flag_module='vefc_render_glyph'
& $sokol_shdc --input $shadersrc_ve_draw_text --output $shaderout_ve_draw_text --slang 'hlsl4' $flag_format_odin $flag_module='vefc_draw_text'

View File

@ -7,7 +7,6 @@ $path_thirdparty = join-path $path_root 'thirdparty'
$path_toolchain = join-path $path_root 'toolchain'
$url_backtrace_repo = 'https://github.com/Ed94/back.git'
$url_freetype = 'https://github.com/Ed94/odin-freetype.git'
$url_harfbuzz = 'https://github.com/Ed94/harfbuzz-odin.git'
$url_ini_parser = 'https://github.com/laytan/odin-ini-parser.git'
$url_odin_repo = 'https://github.com/Ed94/Odin.git'
@ -15,7 +14,6 @@ $url_sokol = 'https://github.com/Ed94/sokol-odin.git'
$url_sokol_tools = 'https://github.com/floooh/sokol-tools-bin.git'
$path_backtrace = join-path $path_thirdparty 'backtrace'
$path_freetype = join-path $path_thirdparty 'freetype'
$path_harfbuzz = join-path $path_thirdparty 'harfbuzz'
$path_ini_parser = join-path $path_thirdparty 'ini'
$path_odin = join-path $path_toolchain 'Odin'
@ -35,7 +33,6 @@ $result = verify-path $path_toolchain
$binaries_dirty = $false
clone-gitrepo $path_backtrace $url_backtrace_repo
clone-gitrepo $path_freetype $url_freetype
clone-gitrepo $path_ini_parser $url_ini_parser
clone-gitrepo $path_ini_parser $url_ini_parser
clone-gitrepo $path_sokol_tools $url_sokol_tools
@ -46,7 +43,6 @@ Update-GitRepo -path $path_harfbuzz -url $url_harfbuzz -build_command '.\script
$path_vendor = join-path $path_odin 'vendor'
$path_vendor_raylib = join-path $path_vendor 'raylib'
$path_freetype_dlls = join-path $path_freetype 'binaries/release'
$path_harfbuzz_dlls = join-path $path_harfbuzz 'lib/win64'
$path_raylib_dlls = join-path $path_vendor_raylib 'windows'
$path_sokol_dlls = join-path $path_thirdparty 'sokol'
@ -77,8 +73,13 @@ $path_devshell = join-path $path_helpers 'devshell.ps1'
$path_stb = join-path $path_thirdparty 'stb'
$path_stb_src = join-path $path_stb 'src'
push-location $path_stb_src
$pkg_stb_truetype_dirty = check-ModuleForChanges $path_stb
& '.\build.bat'
if ( $pkg_stb_truetype_dirty)
{
push-location $path_stb_src
pop-location
& '.\build.bat'
pop-location
}

26
thirdparty/stb/LICENSE vendored Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2016-2024 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

8
thirdparty/stb/README.md vendored Normal file
View File

@ -0,0 +1,8 @@
# stb_truetype-odin
A modification of the stb_truetype vendor library.
Adds support for:
* Allocator assignement via gb/zpl allocators (essentially equivalent to odin's allocator procedure/data struct)
* Pass #by_ptr on font_info's when they are expected to be immutable (library has the proc signature as `const font_info*`)

BIN
thirdparty/stb/lib/stb_truetype.a vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -6,55 +6,22 @@ else
all: unix
endif
$(info Current OS is: $(OS))
wasm:
mkdir -p ../lib
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image.c -o ../lib/stb_image_wasm.o -DSTBI_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_write.c -o ../lib/stb_image_write_wasm.o -DSTBI_WRITE_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_image_resize.c -o ../lib/stb_image_resize_wasm.o
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_truetype.c -o ../lib/stb_truetype_wasm.o
# $(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_vorbis.c -o ../lib/stb_vorbis_wasm.o -DSTB_VORBIS_NO_STDIO
$(CC) -c -Os --target=wasm32 --sysroot=$(shell odin root)/vendor/libc stb_rect_pack.c -o ../lib/stb_rect_pack_wasm.o
$(CC) -c -Os --target=wasm32 stb_sprintf.c -o ../lib/stb_sprintf_wasm.o
unix:
mkdir -p ../lib
$(CC) -c -O2 -Os -fPIC stb_image.c stb_image_write.c stb_image_resize.c stb_truetype.c stb_rect_pack.c stb_vorbis.c stb_sprintf.c
$(AR) rcs ../lib/stb_image.a stb_image.o
$(AR) rcs ../lib/stb_image_write.a stb_image_write.o
$(AR) rcs ../lib/stb_image_resize.a stb_image_resize.o
$(CC) -c -O2 -Os -fPIC stb_truetype.c
$(AR) rcs ../lib/stb_truetype.a stb_truetype.o
$(AR) rcs ../lib/stb_rect_pack.a stb_rect_pack.o
$(AR) rcs ../lib/stb_vorbis.a stb_vorbis.o
$(AR) rcs ../lib/stb_sprintf.a stb_sprintf.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image.so -o ../lib/stb_image.so stb_image.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_write.so -o ../lib/stb_image_write.so stb_image_write.o
#$(CC) -fPIC -shared -Wl,-soname=stb_image_resize.so -o ../lib/stb_image_resize.so stb_image_resize.o
#$(CC) -fPIC -shared -Wl,-soname=stb_truetype.so -o ../lib/stb_truetype.so stb_image_truetype.o
#$(CC) -fPIC -shared -Wl,-soname=stb_rect_pack.so -o ../lib/stb_rect_pack.so stb_rect_packl.o
#$(CC) -fPIC -shared -Wl,-soname=stb_vorbis.so -o ../lib/stb_vorbis.so stb_vorbisl.o
rm *.o
darwin:
mkdir -p ../lib
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image.c -o stb_image-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image.c -o stb_image-arm64.o -mmacosx-version-min=10.12
lipo -create stb_image-x86_64.o stb_image-arm64.o -output ../lib/darwin/stb_image.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_write.c -o stb_image_write-arm64.o -mmacosx-version-min=10.12
lipo -create stb_image_write-x86_64.o stb_image_write-arm64.o -output ../lib/darwin/stb_image_write.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_image_resize.c -o stb_image_resize-arm64.o -mmacosx-version-min=10.12
lipo -create stb_image_resize-x86_64.o stb_image_resize-arm64.o -output ../lib/darwin/stb_image_resize.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_truetype.c -o stb_truetype-arm64.o -mmacosx-version-min=10.12
lipo -create stb_truetype-x86_64.o stb_truetype-arm64.o -output ../lib/darwin/stb_truetype.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_rect_pack.c -o stb_rect_pack-arm64.o -mmacosx-version-min=10.12
lipo -create stb_rect_pack-x86_64.o stb_rect_pack-arm64.o -output ../lib/darwin/stb_rect_pack.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_vorbis.c -o stb_vorbis-arm64.o -mmacosx-version-min=10.12
lipo -create stb_vorbis-x86_64.o stb_vorbis-arm64.o -output ../lib/darwin/stb_vorbis.a
$(CC) -arch x86_64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-x86_64.o -mmacosx-version-min=10.12
$(CC) -arch arm64 -c -O2 -Os -fPIC stb_sprintf.c -o stb_sprintf-arm64.o -mmacosx-version-min=10.12
lipo -create stb_sprintf-x86_64.o stb_sprintf-arm64.o -output ../lib/darwin/stb_sprintf.a
rm *.o

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff

View File

@ -415,9 +415,9 @@ int main(int arg, char **argv)
#pragma region ODIN: CUSTOM ALLOCATOR
#ifdef STB_TRUETYPE_IMPLEMENTATION
#define GB_IMPLEMENTATION
#define ZPL_IMPLEMENTATION
#endif
#include "gb/gb.h"
#include "zpl/zpl.h"
#ifdef STBTT_STATIC
#define STBTT_DEF static
@ -429,21 +429,21 @@ int main(int arg, char **argv)
extern "C" {
#endif
STBTT_DEF void stbtt_SetAllocator( gbAllocator allocator );
STBTT_DEF void stbtt_SetAllocator( zpl_allocator allocator );
#ifdef __cplusplus
}
#endif
#ifndef STBTT_malloc
#define STBTT_malloc(x,u) ((void)(u), gb_alloc(stbtt__allocator, x))
#define STBTT_free(x,u) ((void)(u), gb_free(stbtt__allocator, x))
#define STBTT_malloc(x,u) ((void)(u), zpl_alloc(stbtt__allocator, x))
#define STBTT_free(x,u) ((void)(u), zpl_free(stbtt__allocator, x))
#endif
#ifdef STB_TRUETYPE_IMPLEMENTATION
gb_global gbAllocator stbtt__allocator = { gb_heap_allocator_proc, NULL };
zpl_global zpl_allocator stbtt__allocator = { zpl_heap_allocator_proc, NULL };
STBTT_DEF void stbtt_SetAllocator( gbAllocator allocator ) {
STBTT_DEF void stbtt_SetAllocator( zpl_allocator allocator ) {
stbtt__allocator = allocator;
}
#endif

19055
thirdparty/stb/src/zpl/zpl.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -40,27 +40,27 @@ when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
// CUSTOM: ODIN COMPATIBLE ALLOCATOR
//-----------------------------------------------------------------------------
gbAllocationType :: enum(i32) {
zpl_allocator_type :: enum(i32) {
Alloc,
Free,
FreeAll,
Resize,
}
gbAllocatorProc :: #type proc(allocator_data: rawptr, type: gbAllocationType,
zpl_allocator_proc :: #type proc(allocator_data: rawptr, type: zpl_allocator_type,
size: c.ssize_t, alignment: c.ssize_t,
old_memory: rawptr, old_size: c.ssize_t,
flags : c.ulonglong
) -> rawptr
gbAllocator :: struct {
procedure: gbAllocatorProc,
zpl_allocator :: struct {
procedure: zpl_allocator_proc,
data: rawptr,
}
@(default_calling_convention="c", link_prefix="stbtt_")
foreign stbtt {
SetAllocator :: proc(allocator : gbAllocator) ---
SetAllocator :: proc(allocator : zpl_allocator) ---
}
//-----------------------------------------------------------------------------

Submodule toolchain/Odin deleted from 3b7833ba65