From 7162c5a14d82c420f1fdc84f551cc4c0db8b9687 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 8 Apr 2024 01:35:53 -0400 Subject: [PATCH] last state of the prototype. * Still has memory issue * Was last using it to learn some PGA from Lengyel's books --- code/api.odin | 13 +- code/grime.odin | 109 +++++++++++++-- code/grime_hashmap_zpl.odin | 2 +- code/grime_pool_allocator.odin | 56 ++++---- code/grime_slab_allocator.odin | 18 +-- code/grime_stack.odin | 5 +- code/grime_string_interning.odin | 3 +- code/host/host.odin | 6 +- code/math.odin | 46 ++++++- code/math_pga.odin | 3 - code/math_pga2.odin | 34 +++++ code/math_pga3.odin | 225 +++++++++++++++++++++++++++++++ code/math_pga3_grime.odin | 24 ++++ code/serialize.odin | 4 +- code/tick_render.odin | 2 +- code/tick_update.odin | 4 +- code/ui.odin | 10 +- toolchain/Odin | 2 +- toolchain/ols | 2 +- 19 files changed, 493 insertions(+), 75 deletions(-) delete mode 100644 code/math_pga.odin create mode 100644 code/math_pga2.odin create mode 100644 code/math_pga3.odin create mode 100644 code/math_pga3_grime.odin diff --git a/code/api.odin b/code/api.odin index 8dc8fd8..2d3c42b 100644 --- a/code/api.odin +++ b/code/api.odin @@ -98,9 +98,9 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment }) push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment }) push( policy_ptr, SlabSizeClass { 8 * Megabyte, 8 * Megabyte, alignment }) - // push( policy_ptr, SlabSizeClass { 16 * Megabyte, 16 * Megabyte, alignment }) - // push( policy_ptr, SlabSizeClass { 32 * Megabyte, 32 * Megabyte, alignment }) - // push( policy_ptr, SlabSizeClass { 64 * Megabyte, 64 * Megabyte, alignment }) + push( policy_ptr, SlabSizeClass { 16 * Megabyte, 16 * Megabyte, alignment }) + push( policy_ptr, SlabSizeClass { 32 * Megabyte, 32 * Megabyte, alignment }) + 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 }) @@ -235,7 +235,6 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem // Make sure to cleanup transient before continuing... // From here on, tarnsinet usage has to be done with care. // For most cases, the frame allocator should be more than enough. - // free_all( transient_allocator() ) } // For some reason odin's symbols conflict with native foreign symbols... @@ -316,7 +315,10 @@ tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32 // Setup Frame Slab { alloc_error : AllocatorError - frame_slab, alloc_error = slab_init( & default_slab_policy, bucket_reserve_num = 0, allocator = frame_allocator(), dbg_name = Frame_Slab_DBG_Name ) + frame_slab, alloc_error = slab_init( & default_slab_policy, bucket_reserve_num = 0, + allocator = frame_allocator(), + dbg_name = Frame_Slab_DBG_Name, + should_zero_buckets = true ) verify( alloc_error == .None, "Failed to allocate frame slab" ) } @@ -389,7 +391,6 @@ clean_frame :: proc() free_all( frame_allocator() ) - transient_clear_elapsed += frametime_delta32() if transient_clear_elapsed >= transient_clear_time && ! transinet_clear_lock { diff --git a/code/grime.odin b/code/grime.odin index 3b2a35b..25f627e 100644 --- a/code/grime.odin +++ b/code/grime.odin @@ -9,14 +9,15 @@ import "base:intrinsics" type_has_field :: intrinsics.type_has_field type_elem_type :: intrinsics.type_elem_type import "base:runtime" - Byte :: runtime.Byte - Kilobyte :: runtime.Kilobyte - Megabyte :: runtime.Megabyte - Gigabyte :: runtime.Gigabyte - Terabyte :: runtime.Terabyte - Petabyte :: runtime.Petabyte - Exabyte :: runtime.Exabyte - resize_non_zeroed :: runtime.non_zero_mem_resize + Byte :: runtime.Byte + Kilobyte :: runtime.Kilobyte + Megabyte :: runtime.Megabyte + Gigabyte :: runtime.Gigabyte + Terabyte :: runtime.Terabyte + Petabyte :: runtime.Petabyte + Exabyte :: runtime.Exabyte + resize_non_zeroed :: runtime.non_zero_mem_resize + SourceCodeLocation :: runtime.Source_Code_Location import c "core:c/libc" import "core:dynlib" import "core:hash" @@ -31,6 +32,7 @@ import fmt_io "core:fmt" str_fmt_buffer :: fmt_io.bprintf str_to_file_ln :: fmt_io.fprintln str_tmp_from_any :: fmt_io.tprint +import "core:math" import "core:mem" align_forward_int :: mem.align_forward_int align_forward_uint :: mem.align_forward_uint @@ -57,8 +59,7 @@ import "core:mem" tracking_allocator_init :: mem.tracking_allocator_init import "core:mem/virtual" VirtualProtectFlags :: virtual.Protect_Flags -import "core:odin" - SourceCodeLocation :: runtime.Source_Code_Location +// import "core:odin" import "core:os" FileFlag_Create :: os.O_CREATE FileFlag_ReadWrite :: os.O_RDWR @@ -107,12 +108,32 @@ add :: proc { add_range2, } +bivec :: proc { + bivec_from_f32s, + vec3_to_bivec, +} + cm_to_pixels :: proc { f32_cm_to_pixels, vec2_cm_to_pixels, range2_cm_to_pixels, } +regress :: proc { + regress_bivec3, +} + +cross :: proc { + cross_vec3, +} + +dot :: proc { + dot_vec2, + dot_vec3, + dot_v3_unitv3, + dot_unitv3_vs, +} + draw_text :: proc { draw_text_string, draw_text_string_cached, @@ -126,6 +147,11 @@ get_bounds :: proc { view_get_bounds, } +inverse_mag :: proc { + inverse_mag_vec3, + inverse_mag_rotor3, +} + is_power_of_two :: proc { is_power_of_two_u32, is_power_of_two_uintptr, @@ -152,6 +178,25 @@ pop :: proc { stack_allocator_pop, } +pow :: proc{ + math.pow_f16, + math.pow_f16le, + math.pow_f16be, + math.pow_f32, + math.pow_f32le, + math.pow_f32be, + math.pow_f64, + math.pow_f64le, + math.pow_f64be, +} + +pow2 :: proc { + math.pow2_f16, + math.pow2_f32, + math.pow2_f64, + pow2_vec3, +} + pressed :: proc { btn_pressed, } @@ -161,12 +206,40 @@ push :: proc { stack_allocator_push, } +rotor3 :: proc { + rotor3_via_comps, + rotor3_via_s_bv, + rotor3_via_from_to, +} + released :: proc { btn_released, } +sqrt :: proc{ + math.sqrt_f16, + math.sqrt_f16le, + math.sqrt_f16be, + math.sqrt_f32, + math.sqrt_f32le, + math.sqrt_f32be, + math.sqrt_f64, + math.sqrt_f64le, + math.sqrt_f64be, +} + +inverse_sqrt :: proc { + inverse_sqrt_f32, +} + sub :: proc { + sub_point3, sub_range2, + sub_bivec3, +} + +to_quat128 :: proc { + rotor3_to_quat128, } to_rl_rect :: proc { @@ -182,6 +255,17 @@ to_string :: proc { str_builder_to_string, } +to_vec3 :: proc { + bivec3_to_vec3, + point3_to_vec3, + pointflat3_to_vec3, + unitvec3_to_vec3, +} + +to_vec4 :: proc { + unitvec4_to_vec4, +} + to_writer :: proc { str_builder_to_writer, } @@ -190,3 +274,8 @@ ui_set_layout :: proc { ui_style_set_layout, ui_style_theme_set_layout, } + +wedge :: proc { + wedge_vec3, + wedge_bivec3, +} diff --git a/code/grime_hashmap_zpl.odin b/code/grime_hashmap_zpl.odin index e963434..5c4f9a2 100644 --- a/code/grime_hashmap_zpl.odin +++ b/code/grime_hashmap_zpl.odin @@ -20,7 +20,7 @@ import "core:slice" HMapZPL_MapProc :: #type proc( $ Type : typeid, key : u64, value : Type ) HMapZPL_MapMutProc :: #type proc( $ Type : typeid, key : u64, value : ^ Type ) -HMapZPL_CritialLoadScale :: 0.50 +HMapZPL_CritialLoadScale :: 0.70 HMapZPL_HashToEntryRatio :: 1.50 HMapZPL_FindResult :: struct { diff --git a/code/grime_pool_allocator.odin b/code/grime_pool_allocator.odin index 29ed2a2..e12cb58 100644 --- a/code/grime_pool_allocator.odin +++ b/code/grime_pool_allocator.odin @@ -25,6 +25,7 @@ Pool :: struct { PoolHeader :: struct { backing : Allocator, + zero_bucket : b32, block_size : uint, bucket_capacity : uint, alignment : uint, @@ -47,11 +48,12 @@ Pool_FreeBlock :: struct { Pool_Check_Release_Object_Validity :: true pool_init :: proc ( - block_size : uint, - bucket_capacity : uint, - bucket_reserve_num : uint = 0, - alignment : uint = mem.DEFAULT_ALIGNMENT, - allocator : Allocator = context.allocator + should_zero_buckets : b32, + block_size : uint, + bucket_capacity : uint, + bucket_reserve_num : uint = 0, + alignment : uint = mem.DEFAULT_ALIGNMENT, + allocator : Allocator = context.allocator ) -> ( pool : Pool, alloc_error : AllocatorError ) { header_size := align_forward_int( size_of(PoolHeader), int(alignment) ) @@ -61,6 +63,7 @@ pool_init :: proc ( if alloc_error != .None do return pool.header = cast( ^PoolHeader) raw_mem + pool.zero_bucket = should_zero_buckets pool.backing = allocator pool.block_size = align_forward_uint(block_size, alignment) pool.bucket_capacity = bucket_capacity @@ -100,13 +103,21 @@ pool_allocate_buckets :: proc( pool : Pool, num_buckets : uint ) -> AllocatorErr bucket_size := header_size + pool.bucket_capacity to_allocate := cast(int) (bucket_size * num_buckets) - log(str_fmt_tmp("Allocating %d bytes for %d buckets with header_size %d bytes & bucket_size %d", to_allocate, num_buckets, header_size, bucket_size )) + // log(str_fmt_tmp("Allocating %d bytes for %d buckets with header_size %d bytes & bucket_size %d", to_allocate, num_buckets, header_size, bucket_size )) + + bucket_memory : []byte + alloc_error : AllocatorError pool_validate( pool ) - bucket_memory, alloc_error := alloc_bytes_non_zeroed( to_allocate, int(pool.alignment), pool.backing ) + if pool.zero_bucket { + bucket_memory, alloc_error = alloc_bytes( to_allocate, int(pool.alignment), pool.backing ) + } + else { + bucket_memory, alloc_error = alloc_bytes_non_zeroed( to_allocate, int(pool.alignment), pool.backing ) + } pool_validate( pool ) - log(str_fmt_tmp("Bucket memory size: %d bytes, without header: %d", len(bucket_memory), len(bucket_memory) - int(header_size))) + // log(str_fmt_tmp("Bucket memory size: %d bytes, without header: %d", len(bucket_memory), len(bucket_memory) - int(header_size))) if alloc_error != .None { return alloc_error @@ -119,13 +130,12 @@ pool_allocate_buckets :: proc( pool : Pool, num_buckets : uint ) -> AllocatorErr bucket := cast( ^PoolBucket) next_bucket_ptr bucket.blocks = memory_after_header(bucket) bucket.next_block = 0 - log( str_fmt_tmp("\tPool (%d) allocated bucket: %p start %p capacity: %d (raw: %d)", - pool.block_size, - raw_data(bucket_memory), - bucket.blocks, - pool.bucket_capacity / pool.block_size, - pool.bucket_capacity - )) + // log( str_fmt_tmp("\tPool (%d) allocated bucket: %p start %p capacity: %d (raw: %d)", + // pool.block_size, + // raw_data(bucket_memory), + // bucket.blocks, + // pool.bucket_capacity / pool.block_size, + // pool.bucket_capacity )) if pool.bucket_list.first == nil { pool.bucket_list.first = bucket @@ -147,13 +157,11 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo if pool.current_bucket != nil { verify( pool.current_bucket.blocks != nil, str_fmt_tmp("(corruption) current_bucket was wiped %p", pool.current_bucket) ) } - // profile(#procedure) alloc_error = .None // Check the free-list first for a block - // if pool.free_list_head != nil - if false + if pool.free_list_head != nil { head := & pool.free_list_head @@ -163,11 +171,10 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo pool.free_list_head = pool.free_list_head.next block = byte_slice( cast([^]byte) last_free, int(pool.block_size) ) - log( str_fmt_tmp("\tReturning free block: %p %d", raw_data(block), pool.block_size)) + // log( str_fmt_tmp("\tReturning free block: %p %d", raw_data(block), pool.block_size)) if zero_memory { slice.zero(block) } - verify(false, "WE SHOULD NEVER BE HERE") return } @@ -192,13 +199,13 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo // if current_bucket.next != nil { if pool.current_bucket.next != nil { // current_bucket = current_bucket.next - log( str_fmt_tmp("\tBucket %p exhausted using %p", pool.current_bucket, pool.current_bucket.next)) + // log( str_fmt_tmp("\tBucket %p exhausted using %p", pool.current_bucket, pool.current_bucket.next)) pool.current_bucket = pool.current_bucket.next verify( pool.current_bucket.blocks != nil, "New current_bucket's blocks are null (new current_bucket is corrupted)" ) } else { - log( "\tAll previous buckets exhausted, allocating new bucket") + // log( "\tAll previous buckets exhausted, allocating new bucket") alloc_error := pool_allocate_buckets( pool, 1 ) if alloc_error != .None { ensure(false, "Failed to allocate bucket") @@ -221,11 +228,11 @@ pool_grab :: proc( pool : Pool, zero_memory := false ) -> ( block : []byte, allo pool.current_bucket.next_block += pool.block_size next = uintptr(pool.current_bucket.blocks) + uintptr(pool.current_bucket.next_block) - log( str_fmt_tmp("\tgrabbing block: %p from %p blocks left: %d", raw_data(block), pool.current_bucket.blocks, (end - next) / uintptr(pool.block_size) )) + // log( str_fmt_tmp("\tgrabbing block: %p from %p blocks left: %d", raw_data(block), pool.current_bucket.blocks, (end - next) / uintptr(pool.block_size) )) if zero_memory { slice.zero(block) - log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", block_ptr, cast(rawptr) (uintptr(block_ptr) + uintptr(pool.block_size)))) + // log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", block_ptr, cast(rawptr) (uintptr(block_ptr) + uintptr(pool.block_size)))) } return } @@ -246,6 +253,7 @@ pool_release :: proc( self : Pool, block : []byte, loc := #caller_location ) // ll_push: new_free_block := cast(^Pool_FreeBlock) raw_data(block) + (new_free_block ^) = {} new_free_block.next = self.free_list_head self.free_list_head = new_free_block diff --git a/code/grime_slab_allocator.odin b/code/grime_slab_allocator.odin index 5cb0641..7a29ca2 100644 --- a/code/grime_slab_allocator.odin +++ b/code/grime_slab_allocator.odin @@ -58,7 +58,7 @@ slab_allocator :: proc( slab : Slab ) -> ( allocator : Allocator ) { return } -slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocator : Allocator, dbg_name : string = "" ) -> ( slab : Slab, alloc_error : AllocatorError ) +slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocator : Allocator, dbg_name : string = "", should_zero_buckets : b32 = false ) -> ( slab : Slab, alloc_error : AllocatorError ) { header_size :: size_of( SlabHeader ) @@ -69,17 +69,17 @@ slab_init :: proc( policy : ^SlabPolicy, bucket_reserve_num : uint = 0, allocato slab.header = cast( ^SlabHeader) raw_mem slab.backing = allocator slab.dbg_name = dbg_name - alloc_error = slab_init_pools( slab, policy, bucket_reserve_num ) + alloc_error = slab_init_pools( slab, policy, bucket_reserve_num, should_zero_buckets ) return } -slab_init_pools :: proc ( using self : Slab, policy : ^SlabPolicy, bucket_reserve_num : uint = 0 ) -> AllocatorError +slab_init_pools :: proc ( using self : Slab, policy : ^SlabPolicy, bucket_reserve_num : uint = 0, should_zero_buckets : b32 ) -> AllocatorError { profile(#procedure) for id in 0 ..< policy.idx { using size_class := policy.items[id] - pool, alloc_error := pool_init( block_size, bucket_capacity, bucket_reserve_num, block_alignment, backing ) + pool, alloc_error := pool_init( should_zero_buckets, block_size, bucket_capacity, bucket_reserve_num, block_alignment, backing ) if alloc_error != .None do return alloc_error push( & self.pools, pool ) @@ -136,7 +136,7 @@ slab_alloc :: proc( self : Slab, ensure(false, "Bad block from pool") return nil, alloc_error } - log( str_fmt_tmp("%v: Retrieved block: %p %d", self.dbg_name, raw_data(block), len(block) )) + // log( str_fmt_tmp("%v: Retrieved block: %p %d", self.dbg_name, raw_data(block), len(block) )) data = byte_slice(raw_data(block), size) if zero_memory { @@ -195,7 +195,7 @@ slab_resize :: proc( using self : Slab, new_data_ptr := memory_after(data) new_data = byte_slice( raw_data(data), new_size ) // log( dump_stacktrace() ) - log( str_fmt_tmp("%v: Resize via expanding block space allocation %p %d", dbg_name, new_data_ptr, int(new_size - old_size))) + // log( str_fmt_tmp("%v: Resize via expanding block space allocation %p %d", dbg_name, new_data_ptr, int(new_size - old_size))) if zero_memory && new_size > old_size { to_zero := byte_slice( new_data_ptr, int(new_size - old_size) ) @@ -204,7 +204,7 @@ slab_resize :: proc( using self : Slab, slice.zero( to_zero ) slab_validate_pools( self ) - log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", new_data_ptr, cast(rawptr) (uintptr(new_data_ptr) + uintptr(new_size - old_size)))) + // log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", new_data_ptr, cast(rawptr) (uintptr(new_data_ptr) + uintptr(new_size - old_size)))) } return } @@ -226,13 +226,13 @@ slab_resize :: proc( using self : Slab, // TODO(Ed): Reapply this when safe. if zero_memory { slice.zero( new_block ) - log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", raw_data(new_block), cast(rawptr) (uintptr(raw_data(new_block)) + uintptr(new_size)))) + // log( str_fmt_tmp("Zeroed memory - Range(%p to %p)", raw_data(new_block), cast(rawptr) (uintptr(raw_data(new_block)) + uintptr(new_size)))) } // log( str_fmt_tmp("Resize via new block: %p %d (old : %p $d )", raw_data(new_block), len(new_block), raw_data(data), old_size )) if raw_data(data) != raw_data(new_block) { - log( str_fmt_tmp("%v: Resize via new block, copying from old data block to new block: (%p %d), (%p %d)", dbg_name, raw_data(data), len(data), raw_data(new_block), len(new_block))) + // log( str_fmt_tmp("%v: Resize via new block, copying from old data block to new block: (%p %d), (%p %d)", dbg_name, raw_data(data), len(data), raw_data(new_block), len(new_block))) copy_non_overlapping( raw_data(new_block), raw_data(data), int(old_size) ) pool_release( pool_old, data ) } diff --git a/code/grime_stack.odin b/code/grime_stack.odin index ce14e2f..f6ea08f 100644 --- a/code/grime_stack.odin +++ b/code/grime_stack.odin @@ -27,8 +27,9 @@ stack_pop :: proc( using stack : ^StackFixed( $ Type, $ Size ) ) { } stack_peek_ref :: proc( using stack : ^StackFixed( $ Type, $ Size ) ) -> ( ^Type) { - last := max( 0, idx - 1 ) if idx > 0 else 0 - return & items[last] + last_idx := max( 0, idx - 1 ) if idx > 0 else 0 + last := & items[last_idx] + return last } stack_peek :: proc ( using stack : ^StackFixed( $ Type, $ Size ) ) -> Type { diff --git a/code/grime_string_interning.odin b/code/grime_string_interning.odin index e967d0e..69848a0 100644 --- a/code/grime_string_interning.odin +++ b/code/grime_string_interning.odin @@ -61,7 +61,8 @@ str_cache_init :: proc( /*allocator : Allocator*/ ) -> ( cache : StringCache ) { cache.slab, alloc_error = slab_init( & policy, allocator = persistent_allocator(), dbg_name = dbg_name ) verify(alloc_error == .None, "Failed to initialize the string cache" ) - cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, persistent_slab_allocator(), 8 ) + cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, persistent_slab_allocator(), 4 * Kilobyte ) + // cache.table, alloc_error = zpl_hmap_init_reserve( StringCached, persistent_slab_allocator(), 8 ) return } diff --git a/code/host/host.odin b/code/host/host.odin index 840f50a..3ab03fd 100644 --- a/code/host/host.odin +++ b/code/host/host.odin @@ -325,6 +325,9 @@ main :: proc() { spall.SCOPED_EVENT( & profiler.ctx, & profiler.buffer, "Host Tick" ) + // Hot-Reload + sync_sectr_api( & sectr_api, & memory, & logger, & profiler ) + running = sectr_api.tick( duration_seconds( delta_ns ), delta_ns ) sectr_api.clean_frame() @@ -332,9 +335,6 @@ main :: proc() host_tick = time.tick_now() free_all( arena_allocator( & state.transient)) - - // Hot-Reload - sync_sectr_api( & sectr_api, & memory, & logger, & profiler ) } // Determine how the run_cyle completed, if it failed due to an error, diff --git a/code/math.odin b/code/math.odin index 4d09566..6d50006 100644 --- a/code/math.odin +++ b/code/math.odin @@ -2,6 +2,8 @@ package sectr +import "core:math" + Axis2 :: enum i32 { Invalid = -1, X = 0, @@ -9,6 +11,32 @@ Axis2 :: enum i32 { Count, } +f32_Infinity :: 0x7F800000 +f32_Min :: 0x00800000 + +// Note(Ed) : I don't see an intrinsict available anywhere for this. So I'll be using the Terathon non-sse impl +// Inverse Square Root +// C++ Source https://github.com/EricLengyel/Terathon-Math-Library/blob/main/TSMath.cpp#L191 +inverse_sqrt_f32 :: proc "contextless" ( value : f32 ) -> f32 +{ + if ( value < f32_Min) { + return f32_Infinity + } + + value_u32 := transmute(u32) value + + initial_approx := 0x5F375A86 - (value_u32 >> 1) + refined_approx := transmute(f32) initial_approx + + // Newton–Raphson method for getting better approximations of square roots + // Done twice for greater accuracy. + refined_approx = refined_approx * (1.5 - value * 0.5 * refined_approx * refined_approx ) + refined_approx = refined_approx * (1.5 - value * 0.5 * refined_approx * refined_approx ) + // refined_approx = (0.5 * refined_approx) * (3.0 - value * refined_approx * refined_approx) + // refined_approx = (0.5 * refined_approx) * (3.0 - value * refined_approx * refined_approx) + return refined_approx +} + is_power_of_two_u32 :: #force_inline proc "contextless" ( value : u32 ) -> b32 { return value != 0 && ( value & ( value - 1 )) == 0 @@ -28,13 +56,17 @@ mov_avg_exp_f64 := #force_inline proc "contextless" ( alpha, delta_interval, las import "core:math/linalg" -Vec2 :: linalg.Vector2f32 -Vec3 :: linalg.Vector3f32 +Quat128 :: quaternion128 +Matrix2 :: matrix [2, 2] f32 +Vec2i :: [2]i32 +Vec3i :: [3]i32 -Vec2i :: [2]i32 -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} -Range2 :: struct #raw_union{ +//region Range2 + +Range2 :: struct #raw_union { using min_max : struct { min, max : Vec2 }, @@ -51,6 +83,8 @@ Range2 :: struct #raw_union{ mat : matrix[2, 2] f32, } +UnitRange2 :: distinct Range2 + range2 :: #force_inline proc "contextless" ( a, b : Vec2 ) -> Range2 { result := Range2 { pts = { a, b } } return result @@ -78,3 +112,5 @@ equal_range2 :: #force_inline proc "contextless" ( a, b : Range2 ) -> b32 { size_range2 :: #force_inline proc "contextless" ( value : Range2 ) -> Vec2 { return { value.p1.x - value.p0.x, value.p0.y - value.p1.y } } + +//endregion Range2 diff --git a/code/math_pga.odin b/code/math_pga.odin deleted file mode 100644 index 7ba6dc6..0000000 --- a/code/math_pga.odin +++ /dev/null @@ -1,3 +0,0 @@ -package sectr - - diff --git a/code/math_pga2.odin b/code/math_pga2.odin new file mode 100644 index 0000000..9dc707e --- /dev/null +++ b/code/math_pga2.odin @@ -0,0 +1,34 @@ +package sectr + +/* +Vec2 : 2D Vector 4D Extension (x, y, z : 0, w : 0) +Bivec2 : 2D Bivector +Transform2 : 3x3 Matrix where 3rd row is always (0, 0, 1) +*/ +Vec2 :: [2]f32 +Bivec2 :: distinct f32 +Tansform2 :: matrix [3, 3] f32 +UnitVec2 :: distinct Vec2 + +Rotor2 :: struct { + bv : Bivec2, + s : f32, // Scalar +} + +rotor2_to_complex64 :: #force_inline proc( rotor : Rotor2 ) -> complex64 { return transmute(complex64) rotor; } + +dot_vec2 :: proc "contextless" ( a, b : Vec2 ) -> (s : f32) { + x := a.x * b.x + y := a.y + b.y + s = x + y + return +} + +/* +PointFlat2 : CGA: 2D flat point (x, y, z) +Line : PGA: 2D line (x, y, z) +*/ + +Point2 :: distinct Vec2 +PointFlat2 :: distinct Vec3 +Line2 :: distinct Vec3 diff --git a/code/math_pga3.odin b/code/math_pga3.odin new file mode 100644 index 0000000..03f9608 --- /dev/null +++ b/code/math_pga3.odin @@ -0,0 +1,225 @@ +package sectr + +/* +Vec3 : 3D Vector (x, y, z) (3x1) 4D Expression : (x, y, z, 0) +Bivec3 : 3D Bivector (yz, zx, xy) (3x1) +Trivec3 : 3D Trivector (xyz) (1x1) +Rotor3 : 3D Rotation Versor-Transform (4x1) +Motor3 : 3D Rotation & Translation Transform (4x2) +*/ + +Vec3 :: [3]f32 +Vec4 :: [4]f32 + +Bivec3 :: struct #raw_union { + using _ : struct { yz, zx, xy : f32 }, + using xyz : Vec3, +} + +Trivec3 :: distinct f32 + +Rotor3 :: struct { + using bv : Bivec3, + s : f32, // Scalar +} + +Shifter3 :: struct { + using bv : Bivec3, + s : f32, // Scalar +} + +Motor3 :: struct { + rotor : Rotor3, + md : Shifter3, +} + +UnitVec3 :: distinct Vec3 +UnitVec4 :: distinct Vec4 +UnitBivec3 :: distinct Bivec3 + +//region Vec3 + +complement_vec3 :: #force_inline proc "contextless" ( v : Vec3 ) -> Bivec3 {return transmute(Bivec3) v} + +cross_vec3 :: proc "contextless" (a, b : Vec3) -> (v : Vec3) { + v = vec3( wedge(a, b)) + return +} + +dot_vec3 :: proc "contextless" ( a, b : Vec3 ) -> (s : f32) { + mult := a * b // array multiply + s = mult.x + mult.y + mult.z + return +} + +inverse_mag_vec3 :: proc "contextless" (v : Vec3) -> (result : f32) { + square := pow2(v) + result = inverse_sqrt( square ) + return +} + +magnitude_vec3 :: proc "contextless" (v : Vec3) -> (mag : f32) { + square := pow2(v) + mag = sqrt(square) + return +} + +normalize_vec3 :: proc "contextless" (v : Vec3) -> (unit_v : UnitVec3) { + unit_v = transmute(UnitVec3) (v * inverse_mag(v)) + return +} + +pow2_vec3 :: #force_inline proc "contextless" ( v : Vec3 ) -> (s : f32) { return dot(v, v) } + +project_vec3 :: proc "contextless" ( a, b : Vec3 ) -> ( a_to_b : Vec3 ) { + return +} + +reject_vec3 :: proc "contextless" ( a, b : Vec3 ) -> ( a_from_b : Vec3 ) { + return +} + +project_v3_unitv3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> (v_to_u : Vec3) { + inner := dot(v, u) + v_to_u = (transmute(Vec3) u) * inner + return +} +project_unitv3_v3 :: #force_inline proc "contextless" (u : UnitVec3, v : Vec3) -> (u_to_v : Vec3) { + inner := dot(u, v) + u_to_v = v * inner + return +} + +regress_vec3 :: proc "contextless" ( a, b : Vec3 ) -> f32 { + return a.x * b.y - a.y * +} + +reject_v3_unitv3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> ( v_from_u : Vec3) { + inner := dot(v, u) + v_from_u = (v - (transmute(Vec3) u)) * inner + return +} +reject_unitv3_v3 :: proc "contextless" ( v : Vec3, u : UnitVec3 ) -> ( u_from_v : Vec3) { + inner := dot(u, v) + u_from_v = ((transmute(Vec3) u) - v) * inner + return +} + +// Combines the deimensions that are present in a & b +wedge_vec3 :: proc "contextless" (a, b : Vec3) -> (bv : Bivec3) { + yzx_zxy := a.yzx * b.zxy + zxy_yzx := a.zxy * b.yzx + bv = transmute(Bivec3) (yzx_zxy - zxy_yzx) + return +} + +//endregion Vec3 + +//region Bivec3 +bivec_from_f32s :: #force_inline proc "contextless" (yz, zx, xy : f32) -> Bivec3 {return { xyz = {yz, zx, xy} }} + +complement_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> Bivec3 {return b.xyz} + +//region Operations isomoprhic to vectors +negate_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> Bivec3 {return transmute(Bivec3) -b.xyz} +add_bivec3 :: #force_inline proc "contextless" (a, b : Bivec3) -> Bivec3 {return transmute(Bivec3) (a.xyz + b.xyz)} +sub_bivec3 :: #force_inline proc "contextless" (a, b : Bivec3) -> Bivec3 {return transmute(Bivec3) (a.xyz - b.xyz)} +mul_bivec3 :: #force_inline proc "contextless" (a, b : Bivec3) -> Bivec3 {return transmute(Bivec3) (a.xyz * b.xyz)} +mul_bivec3_f32 :: #force_inline proc "contextless" (b : Bivec3, s : f32) -> Bivec3 {return transmute(Bivec3) (b.xyz * s)} +mul_f32_bivec3 :: #force_inline proc "contextless" (s : f32, b : Bivec3) -> Bivec3 {return transmute(Bivec3) (s * b.xyz)} +div_bivec3_f32 :: #force_inline proc "contextless" (b : Bivec3, s : f32) -> Bivec3 {return transmute(Bivec3) (b.xyz / s)} +inverse_mag_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> f32 {return transmute(Bivec3) inverse_mag_vec3(b.xyz)} +magnitude_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> f32 {return transmute(Bivec3) magnitude_vec3 (b.xyz)} +normalize_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> UnitBivec3 {return transmute(Bivec3) normalize_vec3 (b.xyz)} +squared_mag_bivec3 :: #force_inline proc "contextless" (b : Bivec3) -> f32 {return transmute(Bivec3) pow_2_vec3 (b.xyz)} +//endregion Operations isomoprhic to vectors + +// anti-wedge (Combines dimensions that are absent from a & b) +regress_bivec3 :: #force_inline proc "contextless" ( a, b : Bivec3 ) -> Vec3 {return wedge(vec3(a), vec3(b))} +// regress_bivec3_v :: #force_inline proc "contextless" (b : Bivec3, v : Vec3) -> f32 {return regress(b.xyz, v)} +// regress_v3_bivec3 :: #force_inline proc "contextless" (v : Vec3, b : Bivec3) -> f32 {return regress(b.xyz, v)} + +//endregion Bivec3 + +//region Rotor3 + +rotor3_via_comps :: proc "contextless" (yz, zx, xy, scalar : f32) -> (rotor : Rotor3) { + rotor = Rotor3 {bivec(yz, zx, xy), scalar} + return +} + +rotor3_via_bv_s :: proc "contextless" (bv : Bivec3, scalar : f32) -> (rotor : Rotor3) { + rotor = Rotor3 {bv, scalar} + return +} + +rotor3_via_from_to :: proc "contextless" ( from, to : Vec3 ) -> (rotor : Rotor3) { + scalar := 1 + dot( from, to ) + return +} + +inverse_mag_rotor3 :: proc "contextless" (rotor : Rotor3) -> (s : f32) { + return +} + +magnitude_rotor3 :: proc "contextless" (rotor : Rotor3) -> (s : f32) { + return +} + +squared_mag :: proc "contextless" (rotor : Rotor3) -> (s : f32) { + return +} + +reverse_rotor3 :: proc "contextless" (rotor : Rotor3) -> (reversed : Rotor3) { + reversed = { negate(rotor.bv), rotor.s } + return +} + +//endregion Rotor3 + +//region Flat Projective Geometry + +Point3 :: distinct Vec3 +PointFlat3 :: distinct Vec4 +Line3 :: struct { + weight : Vec3, + bulk : Bivec3, +} +Plane3 :: distinct Vec4 // 4D Anti-vector + +// aka: wedge operation for points +join_point3 :: proc "contextless" (p, q : Point3) -> (l : Line3) { + weight := sub(q, p) + bulk := wedge(to_vec3(p), to_vec3(q)) + l = {weight, bulk} + return +} + +join_pointflat3 :: proc "contextless" (p, q : PointFlat3) -> (l : Line3) { + weight := p.w * q - p * q.w + bulk := wedge(vec3(p), vec3(q)) + l = {weight, bulk} + return +} + +sub_point3 :: proc "contextless" (a, b : Point3) -> (v : Vec3) { + v = to_vec3(a) - to_vec3(b) + return +} + +//endregion Flat Projective Geometry + +//region Rational Trig + +quadrance :: proc "contextless" (a, b : Point3) -> (q : f32) { + q = pow2( sub(a, b)) + return +} + +// Assumes the weight component is normalized. +spread :: proc "contextless" (l, m : Line3) -> (s : f32) { + s = dot(l.weight, m.weight) + return +} + +//endregion Rational Trig diff --git a/code/math_pga3_grime.odin b/code/math_pga3_grime.odin new file mode 100644 index 0000000..a3bfae8 --- /dev/null +++ b/code/math_pga3_grime.odin @@ -0,0 +1,24 @@ +package sectr + +// A dump of equivalent symbol generatioon (because the toolchain can't do it) +// Symbol alias tables are in grim.odin + +vec3_to_bivec :: #force_inline proc "contextless" (v : Vec3) -> Bivec3 {return transmute(Bivec3) v } +bivec3_to_vec3 :: #force_inline proc "contextless" (bv : Bivec3) -> Vec3 {return transmute(Vec3) bv } +rotor3_to_quat128 :: #force_inline proc "contextless" (rotor : Rotor3) -> Quat128 {return transmute(Quat128) rotor} +unitvec3_to_vec3 :: #force_inline proc "contextless" (v : UnitVec3) -> Vec3 {return transmute(Vec3) v } +unitvec4_to_vec4 :: #force_inline proc "contextless" (v : UnitVec4) -> Vec4 {return transmute(Vec4) v } + +plane_to_vec4 :: #force_inline proc "contextless" (p : Plane3) -> Vec4 {return transmute(Vec4) p} +point3_to_vec3 :: #force_inline proc "contextless" (p : Point3) -> Vec3 {return transmute(Vec3) p} +pointflat3_to_vec3 :: #force_inline proc "contextless" (p : PointFlat3) -> Vec3 {return { p.x, p.y, p.z }} +vec3_to_point3 :: #force_inline proc "contextless" (v : Vec3) -> Point3 {return transmute(Point3) v} + +cross_v3_unitv3 :: #force_inline proc "contextless" (v : Vec3, u : UnitVec3) -> Vec3 {return cross_vec3(v, transmute(Vec3) u)} +cross_unitv3_vs :: #force_inline proc "contextless" (u : UnitVec3, v : Vec3) -> Vec3 {return cross_vec3(transmute(Vec3) u, v)} + +dot_v3_unitv3 :: #force_inline proc "contextless" (v : Vec3, unit_v : UnitVec3) -> f32 {return dot_vec3(v, transmute(Vec3) unit_v)} +dot_unitv3_vs :: #force_inline proc "contextless" (unit_v : UnitVec3, v : Vec3) -> f32 {return dot_vec3(v, transmute(Vec3) unit_v)} + +wedge_v3_unitv3 :: #force_inline proc "contextless" (v : Vec3, unit_v : UnitVec3) -> Bivec3 {return wedge_vec3(v, transmute(Vec3) unit_v)} +wedge_unitv3_vs :: #force_inline proc "contextless" (unit_v : UnitVec3, v : Vec3) -> Bivec3 {return wedge_vec3(transmute(Vec3) unit_v, v)} diff --git a/code/serialize.odin b/code/serialize.odin index 0473dad..303f688 100644 --- a/code/serialize.odin +++ b/code/serialize.odin @@ -106,7 +106,7 @@ project_serialize :: proc( project : ^ Project, archive : ^ ArchiveData, is_writ if is_writting { - marshal_archive : MarshalArchive + marshal_archive := new(MarshalArchive, frame_slab_allocator()) marshal_archive.version = archive.version marshal_archive.project = project^ // TODO(Ed): In the future this will be more complicated, as serialization of workspaces and the code database won't be trivial @@ -127,7 +127,7 @@ project_serialize :: proc( project : ^ Project, archive : ^ ArchiveData, is_writ // Note(Ed) : This works fine for now, but eventually it will most likely break with pointers... // We'll most likely set things up so that all refs in the project & workspace are handles. - marshal_archive : MarshalArchive + marshal_archive := new(MarshalArchive, frame_slab_allocator()) json.unmarshal( archive.data, & marshal_archive, spec = json.Specification.MJSON, allocator = context.temp_allocator ) if marshal_archive.version == Serializer_Version { project^ = marshal_archive.project diff --git a/code/tick_render.odin b/code/tick_render.odin index f585747..e09bca3 100644 --- a/code/tick_render.odin +++ b/code/tick_render.odin @@ -86,7 +86,7 @@ render_mode_screenspace :: proc () rl.DrawCircleV( cursor_pos, 10, Color_White_A125 ) } - ui := project.workspace.ui + ui := & project.workspace.ui // debug_text("Box Count: %v", ui.built_box_count ) diff --git a/code/tick_update.odin b/code/tick_update.odin index 127b918..2b7292e 100644 --- a/code/tick_update.odin +++ b/code/tick_update.odin @@ -350,8 +350,8 @@ update :: proc( delta_time : f64 ) -> b32 // index := 0 widgets : Array(UI_Widget) - widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), Kilobyte * 64 ) - // widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), Kilobyte * 8 ) + widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), 8 ) + // widgets, alloc_error = array_init_reserve( UI_Widget, frame_slab_allocator(), 4 * Kilobyte ) widgets_ptr := & widgets label_id := 0 diff --git a/code/ui.odin b/code/ui.odin index 0d65d90..b264530 100644 --- a/code/ui.odin +++ b/code/ui.odin @@ -274,7 +274,8 @@ UI_Box :: struct { UI_Layout_Stack_Size :: 512 UI_Style_Stack_Size :: 512 UI_Parent_Stack_Size :: 512 -UI_Built_Boxes_Array_Size :: 8 +// UI_Built_Boxes_Array_Size :: 8 +UI_Built_Boxes_Array_Size :: 4 * Kilobyte UI_State :: struct { // TODO(Ed) : Use these @@ -320,14 +321,15 @@ ui_startup :: proc( ui : ^ UI_State, cache_allocator : Allocator ) ui := ui ui^ = {} - for cache in (& ui.caches) { + // cache.ref in ui.caches.ref + for & cache in (& ui.caches) { box_cache, allocation_error := zpl_hmap_init_reserve( UI_Box, cache_allocator, UI_Built_Boxes_Array_Size ) verify( allocation_error == AllocatorError.None, "Failed to allocate box cache" ) cache = box_cache } - ui.curr_cache = & ui.caches[1] - ui.prev_cache = & ui.caches[0] + ui.curr_cache = (& ui.caches[1]) + ui.prev_cache = (& ui.caches[0]) log("ui_startup completed") } diff --git a/toolchain/Odin b/toolchain/Odin index e03fa88..a1f241e 160000 --- a/toolchain/Odin +++ b/toolchain/Odin @@ -1 +1 @@ -Subproject commit e03fa88e4c70f8078a1516d36d9203b729569954 +Subproject commit a1f241e925283d8870cb1ec3d6c32d26119047b4 diff --git a/toolchain/ols b/toolchain/ols index c2097b9..7449c96 160000 --- a/toolchain/ols +++ b/toolchain/ols @@ -1 +1 @@ -Subproject commit c2097b9dd936c796805dd54e655253d6b7523265 +Subproject commit 7449c96e6c20d693a7ada04df743cbb6d468ade5