Compare commits
17 Commits
fd424c94bb
...
master
Author | SHA1 | Date | |
---|---|---|---|
87d5cda2c0 | |||
b15503c079 | |||
2e8381b097 | |||
ff91e41da9 | |||
74567ae98a | |||
cf7151a1ce | |||
bf5ecd0e0d | |||
54db9a7d57 | |||
3fd4e139d9 | |||
01e989adc8 | |||
29130cb367 | |||
5b0878d14d | |||
85dbaa37b9 | |||
0f5f9c18b1 | |||
07cd28226f | |||
0cd2d84c64 | |||
7680290650 |
@ -21,7 +21,6 @@ indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
|
||||
[*.{natvis, natstepfilter}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
34
.gitignore
vendored
34
.gitignore
vendored
@ -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
|
||||
|
56
Readme.md
56
Readme.md
@ -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
|
||||

|
||||

|
||||

|
||||
|
||||
## 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": "\\*/"
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
|
@ -1,4 +1,4 @@
|
||||
VEFontCache Odin
|
||||
VEFontCache Odin
|
||||
Copyright 2024 Edward R. Gonzalez
|
||||
|
||||
This project is based on Vertex Engine GPU Font Cache
|
||||
|
@ -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 )
|
||||
|
||||
|
@ -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 )
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
2
code/grime/hashmap_kt1cx.odin
Normal file
2
code/grime/hashmap_kt1cx.odin
Normal file
@ -0,0 +1,2 @@
|
||||
package grime
|
||||
|
48
code/grime/hashmap_kt1l.odin
Normal file
48
code/grime/hashmap_kt1l.odin
Normal 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),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 )
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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"),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 )
|
||||
|
@ -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
|
||||
|
10002
examples/gencpp_singleheader.hpp
Normal file
10002
examples/gencpp_singleheader.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
26
thirdparty/stb/LICENSE
vendored
Normal 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
8
thirdparty/stb/README.md
vendored
Normal 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
BIN
thirdparty/stb/lib/stb_truetype.a
vendored
Normal file
Binary file not shown.
BIN
thirdparty/stb/lib/stb_truetype.lib
vendored
BIN
thirdparty/stb/lib/stb_truetype.lib
vendored
Binary file not shown.
39
thirdparty/stb/src/Makefile
vendored
39
thirdparty/stb/src/Makefile
vendored
@ -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
|
||||
|
10824
thirdparty/stb/src/gb/gb.h
vendored
10824
thirdparty/stb/src/gb/gb.h
vendored
File diff suppressed because it is too large
Load Diff
2
thirdparty/stb/src/stb_image.c
vendored
2
thirdparty/stb/src/stb_image.c
vendored
@ -1,2 +0,0 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
7897
thirdparty/stb/src/stb_image.h
vendored
7897
thirdparty/stb/src/stb_image.h
vendored
File diff suppressed because it is too large
Load Diff
14
thirdparty/stb/src/stb_truetype.h
vendored
14
thirdparty/stb/src/stb_truetype.h
vendored
@ -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
19055
thirdparty/stb/src/zpl/zpl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10
thirdparty/stb/truetype/stb_truetype.odin
vendored
10
thirdparty/stb/truetype/stb_truetype.odin
vendored
@ -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
Reference in New Issue
Block a user