Font drawing is nice now
This commit is contained in:
parent
f36b05e795
commit
5c124521dc
BIN
assets/FiraCode-Regular.ttf
Normal file
BIN
assets/FiraCode-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/Squidgy Slimes.ttf
Normal file
BIN
assets/Squidgy Slimes.ttf
Normal file
Binary file not shown.
@ -46,17 +46,24 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
|
||||
transient_slice := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size )
|
||||
temp_slice := slice_ptr( memory_after( transient_slice), memory_trans_temp_size )
|
||||
|
||||
// We assign the beginning of the block to be the host's persistent memory's arena.
|
||||
// Then we offset past the arena and determine its slice to be the amount left after for the size of host's persistent.
|
||||
persistent = tracked_allocator_init_vmem( persistent_slice, internals_size )
|
||||
transient = tracked_allocator_init_vmem( transient_slice, internals_size )
|
||||
temp = tracked_allocator_init_vmem( temp_slice , internals_size )
|
||||
when Use_TrackingAllocator {
|
||||
// We assign the beginning of the block to be the host's persistent memory's arena.
|
||||
// Then we offset past the arena and determine its slice to be the amount left after for the size of host's persistent.
|
||||
persistent = tracked_allocator_init_vmem( persistent_slice, internals_size )
|
||||
transient = tracked_allocator_init_vmem( transient_slice, internals_size )
|
||||
temp = tracked_allocator_init_vmem( temp_slice , internals_size )
|
||||
}
|
||||
else {
|
||||
persistent = arena_allocator_init_vmem( persistent_slice )
|
||||
transient = arena_allocator_init_vmem( transient_slice )
|
||||
temp = arena_allocator_init_vmem( temp_slice )
|
||||
}
|
||||
|
||||
context.allocator = tracked_allocator( transient )
|
||||
context.temp_allocator = tracked_allocator( temp )
|
||||
context.allocator = transient_allocator()
|
||||
context.temp_allocator = temp_allocator()
|
||||
}
|
||||
|
||||
state := new( State, tracked_allocator( memory.persistent ) )
|
||||
state := new( State, persistent_allocator() )
|
||||
using state
|
||||
|
||||
context.user_ptr = state
|
||||
@ -64,7 +71,7 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
|
||||
input = & input_data[1]
|
||||
input_prev = & input_data[0]
|
||||
|
||||
rl.SetConfigFlags( { rl.ConfigFlag.WINDOW_RESIZABLE, rl.ConfigFlag.WINDOW_TOPMOST } )
|
||||
rl.SetConfigFlags( { rl.ConfigFlag.WINDOW_RESIZABLE /*, rl.ConfigFlag.WINDOW_TOPMOST*/ } )
|
||||
|
||||
// Rough setup of window with rl stuff
|
||||
window_width : i32 = 1000
|
||||
@ -79,7 +86,7 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
|
||||
|
||||
// We do not support non-uniform DPI.
|
||||
window.dpi_scale = rl.GetWindowScaleDPI().x
|
||||
window.dpc = os_default_dpc * window.dpi_scale
|
||||
window.ppcm = os_default_ppcm * window.dpi_scale
|
||||
|
||||
// Determining current monitor and setting the target frametime based on it..
|
||||
monitor_id = rl.GetCurrentMonitor()
|
||||
@ -89,17 +96,25 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
|
||||
|
||||
// Basic Font Setup
|
||||
{
|
||||
font_provider_startup()
|
||||
path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" })
|
||||
cstr := strings.clone_to_cstring( path_rec_mono_semicasual_reg )
|
||||
font_rec_mono_semicasual_reg = font_load( path_rec_mono_semicasual_reg, 24.0, "RecMonoSemiCasual_Regular" )
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_rec_mono_semicasual_reg )
|
||||
verify( ! read_succeded, fmt.tprintf("Failed to read font file for: %v", path_rec_mono_semicasual_reg) )
|
||||
path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } )
|
||||
font_squidgy_slimes = font_load( path_squidgy_slimes, 24.0, "Squidgy_Slime" )
|
||||
|
||||
font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, cast(i32) points_to_pixels(24.0), nil, 0 )
|
||||
delete( cstr)
|
||||
path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" } )
|
||||
font_firacode = font_load( path_firacode, 24.0, "FiraCode" )
|
||||
|
||||
rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything?
|
||||
default_font = font_rec_mono_semicasual_reg
|
||||
// font_data, read_succeded : = os.read_entire_file( path_rec_mono_semicasual_reg )
|
||||
// verify( ! read_succeded, fmt.tprintf("Failed to read font file for: %v", path_rec_mono_semicasual_reg) )
|
||||
|
||||
// cstr := strings.clone_to_cstring( path_rec_mono_semicasual_reg )
|
||||
// font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, cast(i32) points_to_pixels(24.0), nil, 0 )
|
||||
// delete( cstr)
|
||||
|
||||
// rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything?
|
||||
default_font = font_firacode
|
||||
log( "Default font loaded" )
|
||||
}
|
||||
|
||||
@ -112,10 +127,10 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
|
||||
{
|
||||
using project.workspace
|
||||
cam = {
|
||||
target = { 0, 0 },
|
||||
offset = transmute(Vec2) window.extent,
|
||||
target = { 0, 0 },
|
||||
offset = transmute(Vec2) window.extent,
|
||||
rotation = 0,
|
||||
zoom = 1.0,
|
||||
zoom = 1.0,
|
||||
}
|
||||
// cam = {
|
||||
// position = { 0, 0, -100 },
|
||||
@ -150,11 +165,8 @@ sectr_shutdown :: proc()
|
||||
os.close( memory.replay.active_file )
|
||||
}
|
||||
|
||||
// Raylib
|
||||
{
|
||||
rl.UnloadFont ( state.font_rec_mono_semicasual_reg )
|
||||
rl.CloseWindow()
|
||||
}
|
||||
font_provider_shutdown()
|
||||
|
||||
log("Module shutdown complete")
|
||||
}
|
||||
|
||||
@ -171,10 +183,19 @@ reload :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ L
|
||||
transient_slice := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size )
|
||||
temp_slice := slice_ptr( memory_after( transient_slice), memory_trans_temp_size )
|
||||
|
||||
persistent = cast( ^TrackedAllocator ) & persistent_slice[0]
|
||||
transient = cast( ^TrackedAllocator ) & transient_slice[0]
|
||||
temp = cast( ^TrackedAllocator ) & temp_slice[0]
|
||||
when Use_TrackingAllocator {
|
||||
persistent = cast( ^ TrackedAllocator ) & persistent_slice[0]
|
||||
transient = cast( ^ TrackedAllocator ) & transient_slice[0]
|
||||
temp = cast( ^ TrackedAllocator ) & temp_slice[0]
|
||||
}
|
||||
else {
|
||||
persistent = cast( ^ Arena ) & persistent_slice[0]
|
||||
transient = cast( ^ Arena ) & transient_slice[0]
|
||||
temp = cast( ^ Arena ) & temp_slice[0]
|
||||
}
|
||||
|
||||
context.allocator = transient_allocator()
|
||||
context.temp_allocator = temp_allocator()
|
||||
log("Module reloaded")
|
||||
}
|
||||
|
||||
@ -192,7 +213,11 @@ tick :: proc ( delta_time : f64 ) -> b32
|
||||
}
|
||||
|
||||
@export
|
||||
clean_temp :: proc()
|
||||
{
|
||||
mem.tracking_allocator_clear( & memory.temp.tracker )
|
||||
clean_temp :: proc() {
|
||||
when Use_TrackingAllocator {
|
||||
mem.tracking_allocator_clear( & memory.temp.tracker )
|
||||
}
|
||||
else {
|
||||
free_all( temp_allocator() )
|
||||
}
|
||||
}
|
||||
|
@ -11,18 +11,66 @@ import rl "vendor:raylib"
|
||||
memory : Memory
|
||||
|
||||
memory_chunk_size :: 2 * Gigabyte
|
||||
memory_persistent_size :: 128 * Megabyte
|
||||
memory_persistent_size :: 256 * Megabyte
|
||||
memory_trans_temp_size :: (memory_chunk_size - memory_persistent_size ) / 2
|
||||
|
||||
Memory :: struct {
|
||||
live : virtual.Arena,
|
||||
snapshot : []u8,
|
||||
persistent : ^ TrackedAllocator,
|
||||
transient : ^ TrackedAllocator,
|
||||
temp : ^ TrackedAllocator,
|
||||
// TODO(Ed): There is an issue with mutex locks on the tracking allocator..
|
||||
Use_TrackingAllocator :: false
|
||||
|
||||
replay : ReplayState,
|
||||
logger : Logger,
|
||||
when Use_TrackingAllocator
|
||||
{
|
||||
Memory :: struct {
|
||||
live : virtual.Arena,
|
||||
snapshot : []u8,
|
||||
|
||||
persistent : ^ TrackedAllocator,
|
||||
transient : ^ TrackedAllocator,
|
||||
temp : ^ TrackedAllocator,
|
||||
|
||||
replay : ReplayState,
|
||||
logger : Logger,
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Memory :: struct {
|
||||
live : virtual.Arena,
|
||||
snapshot : []u8,
|
||||
|
||||
persistent : ^ Arena,
|
||||
transient : ^ Arena,
|
||||
temp : ^ Arena,
|
||||
|
||||
replay : ReplayState,
|
||||
logger : Logger,
|
||||
}
|
||||
}
|
||||
|
||||
persistent_allocator :: proc () -> Allocator {
|
||||
when Use_TrackingAllocator {
|
||||
return tracked_allocator( memory.persistent )
|
||||
}
|
||||
else {
|
||||
return arena_allocator( memory.persistent )
|
||||
}
|
||||
}
|
||||
|
||||
transient_allocator :: proc () -> Allocator {
|
||||
when Use_TrackingAllocator {
|
||||
return tracked_allocator( memory.transient )
|
||||
}
|
||||
else {
|
||||
return arena_allocator( memory.transient )
|
||||
}
|
||||
}
|
||||
|
||||
temp_allocator :: proc () -> Allocator {
|
||||
when Use_TrackingAllocator {
|
||||
return tracked_allocator( memory.temp )
|
||||
}
|
||||
else {
|
||||
return arena_allocator( memory.temp )
|
||||
}
|
||||
}
|
||||
|
||||
save_snapshot :: proc( snapshot : [^]u8 ) {
|
||||
@ -38,10 +86,14 @@ load_snapshot :: proc( snapshot : [^]u8 ) {
|
||||
AppConfig :: struct {
|
||||
resolution_width : uint,
|
||||
resolution_height : uint,
|
||||
refresh_rate : uint
|
||||
refresh_rate : uint,
|
||||
min_zoom : uint,
|
||||
max_zoom : uint,
|
||||
}
|
||||
|
||||
State :: struct {
|
||||
font_provider_data : FontProviderData,
|
||||
|
||||
input_data : [2] InputState,
|
||||
input_prev : ^ InputState,
|
||||
input : ^ InputState,
|
||||
@ -59,18 +111,25 @@ State :: struct {
|
||||
engine_refresh_hz : i32,
|
||||
engine_refresh_target : i32,
|
||||
|
||||
font_rec_mono_semicasual_reg : Font,
|
||||
default_font : Font,
|
||||
font_firacode : FontID,
|
||||
font_squidgy_slimes : FontID,
|
||||
font_rec_mono_semicasual_reg : FontID,
|
||||
default_font : FontID,
|
||||
}
|
||||
|
||||
get_state :: proc "contextless" () -> ^ State {
|
||||
return cast( ^ State ) raw_data( memory.persistent.backing.data )
|
||||
when Use_TrackingAllocator {
|
||||
return cast( ^ State ) raw_data( memory.persistent.backing.data )
|
||||
}
|
||||
else {
|
||||
return cast( ^ State ) raw_data( memory.persistent. data )
|
||||
}
|
||||
}
|
||||
|
||||
AppWindow :: struct {
|
||||
extent : Extents2, // Window half-size
|
||||
dpi_scale : f32, // Dots per inch scale (provided by raylib via glfw)
|
||||
dpc : f32, // Dots per centimetre
|
||||
ppcm : f32, // Dots per centimetre
|
||||
}
|
||||
|
||||
Project :: struct {
|
||||
|
174
code/font_provider.odin
Normal file
174
code/font_provider.odin
Normal file
@ -0,0 +1,174 @@
|
||||
package sectr
|
||||
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:mem"
|
||||
import "core:path/filepath"
|
||||
import "core:os"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Font_Arena_Size :: 32 * Megabyte
|
||||
Font_Largest_Px_Size :: 96
|
||||
|
||||
Font_Default :: ""
|
||||
Font_Default_Point_Size :: 18.0
|
||||
|
||||
Font_TTF_Default_Chars_Padding :: 4
|
||||
|
||||
Font_Load_Use_Default_Size :: -1
|
||||
Font_Load_Gen_ID :: ""
|
||||
|
||||
Font_Atlas_Packing_Method :: enum u32 {
|
||||
Raylib_Basic = 0, // Basic packing algo
|
||||
Skyeline_Rect = 1, // stb_pack_rect
|
||||
}
|
||||
|
||||
// TODO(Ed) : This isn't good enough for what we need font wise..
|
||||
Font :: rl.Font
|
||||
|
||||
// TODO(Ed) : Use this instead of the raylib font directly
|
||||
FontID :: distinct string
|
||||
FontTag :: struct {
|
||||
key : FontID,
|
||||
point_size : f32
|
||||
}
|
||||
|
||||
FontGlyphsRender :: struct {
|
||||
size : i32,
|
||||
count : i32,
|
||||
padding : i32,
|
||||
texture : rl.Texture2D,
|
||||
recs : [^]rl.Rectangle, // Characters rectangles in texture
|
||||
glyphs : [^]rl.GlyphInfo, // Characters info data
|
||||
}
|
||||
|
||||
FontDef :: struct {
|
||||
path_file : string,
|
||||
data : [] u8,
|
||||
default_size : i32,
|
||||
size_table : [Font_Largest_Px_Size] FontGlyphsRender,
|
||||
}
|
||||
|
||||
FontProviderData :: struct {
|
||||
font_arena : Arena,
|
||||
font_cache : ^ map [FontID] FontDef,
|
||||
}
|
||||
|
||||
font_provider_startup :: proc()
|
||||
{
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
data, alloc_result := alloc_bytes( Font_Arena_Size, allocator = persistent_allocator() )
|
||||
verify( alloc_result != AllocatorError.None, "Failed to allocate memory for font_arena from persistent" )
|
||||
log("font_arena allocated from persistent memory")
|
||||
|
||||
arena_init( & font_arena, data )
|
||||
|
||||
font_cache = new( type_of(font_cache ^), arena_allocator( & font_arena) )
|
||||
log("font_cache created")
|
||||
log("font_provider initialized")
|
||||
}
|
||||
|
||||
font_provider_shutdown :: proc()
|
||||
{
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
for key, & value in font_cache {
|
||||
for & px_render in value.size_table {
|
||||
using px_render
|
||||
rl.UnloadFontData( glyphs, count )
|
||||
rl.UnloadTexture ( texture )
|
||||
rl.MemFree( recs )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font_load :: proc ( path_file : string,
|
||||
default_size : f32 = Font_Load_Use_Default_Size,
|
||||
desired_id : FontID = Font_Load_Gen_ID
|
||||
) -> FontID
|
||||
{
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_file )
|
||||
verify( ! read_succeded, fmt.tprintf("Failed to read font file for: %v", path_file) )
|
||||
font_data_size := cast(i32) len(font_data)
|
||||
|
||||
desired_id := desired_id
|
||||
// Use file name as key
|
||||
if len(desired_id) == 0 {
|
||||
// NOTE(Ed): This should never be used except for laziness so I'll be throwing a warning everytime.
|
||||
log("desired_key not provided, using file name. Give it a proper name!")
|
||||
desired_id = cast(FontID) file_name_from_path(path_file)
|
||||
}
|
||||
|
||||
default_size := default_size
|
||||
if default_size == Font_Load_Use_Default_Size {
|
||||
default_size = Font_Default_Point_Size
|
||||
}
|
||||
|
||||
font_cache[desired_id] = {}
|
||||
def := & font_cache[desired_id];
|
||||
def.path_file = path_file
|
||||
def.data = font_data
|
||||
def.default_size = i32(points_to_pixels(default_size))
|
||||
|
||||
// TODO(Ed): this is extremely slow
|
||||
// Render all sizes at once
|
||||
for id : i32 = 0; id < Font_Largest_Px_Size; id += 1
|
||||
{
|
||||
px_render := & def.size_table[id]
|
||||
using px_render
|
||||
size = id + 1
|
||||
count = 95 // This is the default codepoint count from raylib when loading a font.
|
||||
padding = Font_TTF_Default_Chars_Padding
|
||||
glyphs = rl.LoadFontData( raw_data(font_data), font_data_size,
|
||||
fontSize = size,
|
||||
codepoints = nil,
|
||||
codepointCount = count,
|
||||
type = rl.FontType.DEFAULT )
|
||||
verify( glyphs == nil, fmt.tprintf("Failed to load glyphs for font: %v at desired size: %v", desired_id, size ) )
|
||||
|
||||
atlas := rl.GenImageFontAtlas( glyphs, & recs, count, size, padding, i32(Font_Atlas_Packing_Method.Raylib_Basic) )
|
||||
texture = rl.LoadTextureFromImage( atlas )
|
||||
rl.SetTextureFilter( texture, rl.TextureFilter.POINT )
|
||||
|
||||
// glyphs_slice := slice_ptr( glyphs, count )
|
||||
// for glyph in glyphs_slice {
|
||||
// TODO(Ed) : See if above can properly reference
|
||||
|
||||
// NOTE(raylib): Update glyphs[i].image to use alpha, required to be used on image_draw_text()
|
||||
for glyph_id : i32 = 0; glyph_id < count; glyph_id += 1 {
|
||||
glyph := & glyphs[glyph_id]
|
||||
|
||||
rl.UnloadImage( glyph.image )
|
||||
glyph.image = rl.ImageFromImage( atlas, recs[glyph_id] )
|
||||
}
|
||||
rl.UnloadImage( atlas )
|
||||
}
|
||||
|
||||
return desired_id
|
||||
}
|
||||
|
||||
Font_Use_Default_Size :: f32(0.0)
|
||||
|
||||
to_rl_Font :: proc ( id : FontID, size := Font_Use_Default_Size ) -> rl.Font {
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
size := clamp( i32(math.round(size)), 12, Font_Largest_Px_Size )
|
||||
|
||||
verify( size > Font_Largest_Px_Size, "attempt to get a font larger than the largest loaded pixel size" )
|
||||
def := & font_cache[id]
|
||||
size = size if size != i32(Font_Use_Default_Size) else def.default_size
|
||||
px_render := & def.size_table[ size - 1 ]
|
||||
|
||||
rl_font : rl.Font
|
||||
rl_font.baseSize = px_render.size
|
||||
rl_font.charsCount = px_render.count
|
||||
rl_font.charsPadding = px_render.padding
|
||||
rl_font.glyphs = px_render.glyphs
|
||||
rl_font.recs = px_render.recs
|
||||
rl_font.texture = px_render.texture
|
||||
return rl_font
|
||||
}
|
@ -4,6 +4,7 @@ package sectr
|
||||
|
||||
import "core:mem"
|
||||
import "core:mem/virtual"
|
||||
import "core:path/filepath"
|
||||
|
||||
Byte :: 1
|
||||
Kilobyte :: 1024 * Byte
|
||||
@ -27,7 +28,9 @@ terabyte :: proc ( tb : $ integer_type ) -> integer_type {
|
||||
}
|
||||
|
||||
Allocator :: mem.Allocator
|
||||
AllocatorError :: mem.Allocator_Error
|
||||
alloc :: mem.alloc
|
||||
alloc_bytes :: mem.alloc_bytes
|
||||
Arena :: mem.Arena
|
||||
arena_allocator :: mem.arena_allocator
|
||||
arena_init :: mem.arena_init
|
||||
@ -36,12 +39,9 @@ slice_ptr :: mem.slice_ptr
|
||||
Tracking_Allocator :: mem.Tracking_Allocator
|
||||
tracking_allocator :: mem.tracking_allocator
|
||||
tracking_allocator_init :: mem.tracking_allocator_init
|
||||
file_name_from_path :: filepath.short_stem
|
||||
OS_Type :: type_of(ODIN_OS)
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Font :: rl.Font
|
||||
|
||||
get_bounds :: proc {
|
||||
box_get_bounds,
|
||||
view_get_bounds,
|
||||
|
@ -86,3 +86,16 @@ tracked_allocator_init_vmem :: proc( vmem : [] byte, internals_size : int ) -> ^
|
||||
tracking_allocator_init( & result.tracker, arena_allocator( backing ), arena_allocator( internals ) )
|
||||
return result
|
||||
}
|
||||
|
||||
arena_allocator_init_vmem :: proc ( vmem : [] byte ) -> ^ Arena
|
||||
{
|
||||
arena_size :: size_of( Arena)
|
||||
backing_size := len(vmem)
|
||||
|
||||
result := cast( ^ Arena) & vmem[0]
|
||||
result_slice := slice_ptr( & vmem[0], arena_size )
|
||||
|
||||
backing_slice := slice_ptr( memory_after( result_slice), backing_size )
|
||||
arena_init( result, backing_slice )
|
||||
return result
|
||||
}
|
||||
|
110
code/space.odin
110
code/space.odin
@ -6,13 +6,16 @@ import rl "vendor:raylib"
|
||||
// an object from world space to screen-space.
|
||||
// This prototype engine will have all its spacial unit base for distances in centimetres.
|
||||
|
||||
Inches_To_CM :: cast(f32)2.54
|
||||
Points_Per_CM :: cast(f32)28.3465
|
||||
CM_Per_Point :: cast(f32)1.0 / 28.3465 // Precalculated reciprocal for multiplication
|
||||
DPT_DPC :: cast(f32)72.0 * Inches_To_CM
|
||||
Inches_To_CM :: cast(f32) 2.54
|
||||
Points_Per_CM :: cast(f32) 28.3465
|
||||
CM_Per_Point :: cast(f32) 1.0 / DPT_DPCM
|
||||
CM_Per_Pixel :: cast(f32) 1.0 / DPT_PPCM
|
||||
DPT_DPCM :: cast(f32) 72.0 * Inches_To_CM // 182.88 points/dots per cm
|
||||
DPT_PPCM :: cast(f32) 96.0 * Inches_To_CM // 243.84 pixels per cm
|
||||
|
||||
when ODIN_OS == OS_Type.Windows {
|
||||
os_default_dpc :: 96 * Inches_To_CM
|
||||
op_default_dpcm :: 72.0 * Inches_To_CM
|
||||
os_default_ppcm :: 96.0 * Inches_To_CM
|
||||
// 1 inch = 2.54 cm, 96 inch * 2.54 = 243.84 DPC
|
||||
}
|
||||
|
||||
@ -31,7 +34,6 @@ points_to_pixels :: proc {
|
||||
vec2_points_to_pixels,
|
||||
}
|
||||
|
||||
|
||||
//region Unit Conversion Impl
|
||||
|
||||
// cm_to_points :: proc ( cm : f32 ) -> f32 {
|
||||
@ -46,43 +48,43 @@ points_to_pixels :: proc {
|
||||
// }
|
||||
|
||||
f32_cm_to_pixels :: proc(cm: f32) -> f32 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
return cm * screen_dpc
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
return cm * screen_ppcm
|
||||
}
|
||||
|
||||
f32_pixels_to_cm :: proc(pixels: f32) -> f32 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
cm_per_pixel := 1.0 / screen_dpc
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return pixels * cm_per_pixel
|
||||
}
|
||||
|
||||
f32_points_to_pixels :: proc(points: f32) -> f32 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
cm_per_pixel := 1.0 / screen_dpc
|
||||
return points * DPT_DPC * cm_per_pixel
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return points * DPT_PPCM * cm_per_pixel
|
||||
}
|
||||
|
||||
f32_pixels_to_points :: proc(pixels: f32) -> f32 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
cm_per_pixel := 1.0 / screen_dpc
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return pixels * cm_per_pixel * Points_Per_CM
|
||||
}
|
||||
|
||||
vec2_cm_to_pixels :: proc(v: Vec2) -> Vec2 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
return v * screen_dpc
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
return v * screen_ppcm
|
||||
}
|
||||
|
||||
vec2_pixels_to_cm :: proc(v: Vec2) -> Vec2 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
cm_per_pixel := 1.0 / screen_dpc
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return v * cm_per_pixel
|
||||
}
|
||||
|
||||
vec2_points_to_pixels :: proc(vpoints: Vec2) -> Vec2 {
|
||||
screen_dpc := get_state().app_window.dpc
|
||||
cm_per_pixel := 1.0 / screen_dpc
|
||||
return vpoints * DPT_DPC * cm_per_pixel
|
||||
screen_ppcm := get_state().app_window.ppcm
|
||||
cm_per_pixel := 1.0 / screen_ppcm
|
||||
return vpoints * DPT_PPCM * cm_per_pixel
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +109,7 @@ BoundsCorners2 :: struct {
|
||||
top_left, top_right, bottom_left, bottom_right: Vec2,
|
||||
}
|
||||
|
||||
Extents2 :: distinct Vec2
|
||||
Extents2 :: distinct Vec2
|
||||
Extents2i :: distinct Vec2i
|
||||
|
||||
WS_Pos :: struct {
|
||||
@ -116,72 +118,72 @@ WS_Pos :: struct {
|
||||
}
|
||||
|
||||
bounds2_radius :: proc(bounds: Bounds2) -> f32 {
|
||||
return max(bounds.bottom_right.x, bounds.top_left.y)
|
||||
return max( bounds.bottom_right.x, bounds.top_left.y )
|
||||
}
|
||||
|
||||
extent_from_size :: proc(size: AreaSize) -> Extents2 {
|
||||
return transmute(Extents2)size * 2.0
|
||||
return transmute(Extents2) size * 2.0
|
||||
}
|
||||
|
||||
screen_size :: proc "contextless" () -> AreaSize {
|
||||
extent := get_state().app_window.extent
|
||||
return transmute(AreaSize)(extent * 2.0)
|
||||
return transmute(AreaSize) ( extent * 2.0 )
|
||||
}
|
||||
|
||||
screen_get_corners :: proc() -> BoundsCorners2 {
|
||||
state := get_state();using state
|
||||
state := get_state();using state
|
||||
screen_extent := state.app_window.extent
|
||||
top_left := Vec2{-screen_extent.x, screen_extent.y}
|
||||
top_right := Vec2{screen_extent.x, screen_extent.y}
|
||||
bottom_left := Vec2{-screen_extent.x, -screen_extent.y}
|
||||
bottom_right := Vec2{screen_extent.x, -screen_extent.y}
|
||||
return {top_left, top_right, bottom_left, bottom_right}
|
||||
top_left := Vec2 { -screen_extent.x, screen_extent.y }
|
||||
top_right := Vec2 { screen_extent.x, screen_extent.y }
|
||||
bottom_left := Vec2 { -screen_extent.x, -screen_extent.y }
|
||||
bottom_right := Vec2 { screen_extent.x, -screen_extent.y }
|
||||
return { top_left, top_right, bottom_left, bottom_right }
|
||||
}
|
||||
|
||||
view_get_bounds :: proc() -> Bounds2 {
|
||||
state := get_state();using state
|
||||
cam := &project.workspace.cam
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
screen_extent := state.app_window.extent
|
||||
top_left := cam.target + Vec2{-screen_extent.x, screen_extent.y}
|
||||
bottom_right := cam.target + Vec2{screen_extent.x, -screen_extent.y}
|
||||
return {top_left, bottom_right}
|
||||
top_left := cam.target + Vec2 { -screen_extent.x, screen_extent.y}
|
||||
bottom_right := cam.target + Vec2 { screen_extent.x, -screen_extent.y}
|
||||
return { top_left, bottom_right }
|
||||
}
|
||||
|
||||
view_get_corners :: proc() -> BoundsCorners2 {
|
||||
state := get_state();using state
|
||||
cam := &project.workspace.cam
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
screen_extent := state.app_window.extent * cam_zoom_ratio
|
||||
top_left := cam.target + Vec2{-screen_extent.x, screen_extent.y}
|
||||
top_right := cam.target + Vec2{screen_extent.x, screen_extent.y}
|
||||
bottom_left := cam.target + Vec2{-screen_extent.x, -screen_extent.y}
|
||||
bottom_right := cam.target + Vec2{screen_extent.x, -screen_extent.y}
|
||||
return {top_left, top_right, bottom_left, bottom_right}
|
||||
screen_extent := state.app_window.extent * cam_zoom_ratio
|
||||
top_left := cam.target + Vec2 { -screen_extent.x, screen_extent.y }
|
||||
top_right := cam.target + Vec2 { screen_extent.x, screen_extent.y }
|
||||
bottom_left := cam.target + Vec2 { -screen_extent.x, -screen_extent.y }
|
||||
bottom_right := cam.target + Vec2 { screen_extent.x, -screen_extent.y }
|
||||
return { top_left, top_right, bottom_left, bottom_right }
|
||||
}
|
||||
|
||||
screen_to_world :: proc(pos: Vec2) -> Vec2 {
|
||||
state := get_state();using state
|
||||
cam := &project.workspace.cam
|
||||
return vec2_pixels_to_cm(cam.target + pos * (1 / cam.zoom))
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
return vec2_pixels_to_cm( cam.target + pos * (1 / cam.zoom) )
|
||||
}
|
||||
|
||||
screen_to_render :: proc(pos: Vec2) -> Vec2 {
|
||||
screen_extent := transmute(Vec2)get_state().project.workspace.cam.offset
|
||||
return pos + {screen_extent.x, -screen_extent.y}
|
||||
screen_extent := transmute(Vec2) get_state().project.workspace.cam.offset
|
||||
return pos + { screen_extent.x, -screen_extent.y }
|
||||
}
|
||||
|
||||
world_screen_extent :: proc() -> Extents2 {
|
||||
state := get_state();using state
|
||||
state := get_state(); using state
|
||||
cam_zoom_ratio := 1.0 / project.workspace.cam.zoom
|
||||
return app_window.extent * cam_zoom_ratio
|
||||
}
|
||||
|
||||
world_to_screen_pos :: proc(position: Vec2) -> Vec2 {
|
||||
return {position.x, position.y * -1}
|
||||
return { position.x, position.y * -1 }
|
||||
}
|
||||
|
||||
world_to_screen_no_zoom :: proc(position: Vec2) -> Vec2 {
|
||||
state := get_state();using state
|
||||
state := get_state(); using state
|
||||
cam_zoom_ratio := 1.0 / state.project.workspace.cam.zoom
|
||||
return {position.x, position.y * -1} * cam_zoom_ratio
|
||||
return { position.x, position.y * -1 } * cam_zoom_ratio
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package sectr
|
||||
|
||||
import "core:math"
|
||||
import "core:unicode/utf8"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : rl.Font = {} )
|
||||
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
@ -13,30 +14,63 @@ debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Co
|
||||
runes := utf8.string_to_runes( content, context.temp_allocator )
|
||||
|
||||
font := font
|
||||
if ( font.glyphs == nil ) {
|
||||
if ( len(font) == 0 ) {
|
||||
font = default_font
|
||||
}
|
||||
|
||||
pos := screen_to_render(pos)
|
||||
|
||||
rl.DrawTextCodepoints( font,
|
||||
px_size := size
|
||||
|
||||
rl_font := to_rl_Font(font, px_size )
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = size,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
}
|
||||
|
||||
debug_draw_text_world :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content ) == 0 {
|
||||
return
|
||||
}
|
||||
runes := utf8.string_to_runes( content, context.temp_allocator )
|
||||
|
||||
font := font
|
||||
if ( len(font) == 0 ) {
|
||||
font = default_font
|
||||
}
|
||||
pos := world_to_screen_pos(pos)
|
||||
|
||||
px_size := size
|
||||
zoom_adjust := px_size * project.workspace.cam.zoom
|
||||
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
}
|
||||
|
||||
// Raylib's equivalent doesn't take a length for the string (making it a pain in the ass)
|
||||
// So this is a 1:1 copy except it takes Odin strings
|
||||
measure_text_size :: proc ( text : string, font : Font, font_size, spacing : f32 ) -> AreaSize
|
||||
measure_text_size :: proc ( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> AreaSize
|
||||
{
|
||||
px_size := math.round( points_to_pixels( font_size ) )
|
||||
rl_font := to_rl_Font( font, font_size )
|
||||
|
||||
// This is a static var within raylib. We don't have getter access to it.
|
||||
// Note(Ed) : raylib font size is in pixels so this is also.
|
||||
@static text_line_spacing : f32 = 15
|
||||
|
||||
text_size : AreaSize
|
||||
|
||||
if font.texture.id == 0 || len(text) == 0 {
|
||||
if rl_font.texture.id == 0 || len(text) == 0 {
|
||||
return text_size
|
||||
}
|
||||
|
||||
@ -46,30 +80,31 @@ measure_text_size :: proc ( text : string, font : Font, font_size, spacing : f32
|
||||
text_width : f32 = 0.0
|
||||
temp_text_width : f32 = 0.0 // Used to counter longer text line width
|
||||
|
||||
text_height := cast(f32) font.baseSize
|
||||
scale_factor := font_size / text_height
|
||||
text_height := cast(f32) rl_font.baseSize
|
||||
scale_factor := px_size / text_height
|
||||
|
||||
letter : rune
|
||||
index : i32 = 0
|
||||
|
||||
for id : i32 = 0; id < i32(len(text)); {
|
||||
for id : i32 = 0; id < i32(len(text));
|
||||
{
|
||||
byte_counter += 1
|
||||
|
||||
next : i32 = 0
|
||||
|
||||
ctext := cast(cstring) ( & raw_data( text )[id] )
|
||||
letter = rl.GetCodepointNext( ctext, & next )
|
||||
index = rl.GetGlyphIndex( font, letter )
|
||||
index = rl.GetGlyphIndex( rl_font, letter )
|
||||
|
||||
id += 1
|
||||
|
||||
if letter != rune('\n')
|
||||
{
|
||||
if font.glyphs[index].advanceX != 0 {
|
||||
text_width += f32(font.glyphs[index].advanceX)
|
||||
if rl_font.glyphs[index].advanceX != 0 {
|
||||
text_width += f32(rl_font.glyphs[index].advanceX)
|
||||
}
|
||||
else {
|
||||
text_width += font.recs[index].width + f32(font.glyphs[index].offsetX)
|
||||
text_width += rl_font.recs[index].width + f32(rl_font.glyphs[index].offsetX)
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -87,11 +122,9 @@ measure_text_size :: proc ( text : string, font : Font, font_size, spacing : f32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if temp_text_width < text_width {
|
||||
temp_text_width = text_width
|
||||
}
|
||||
|
||||
text_size.x = temp_text_width * scale_factor + f32(temp_byte_counter - 1) * spacing
|
||||
text_size.y = text_height * scale_factor
|
||||
|
||||
|
@ -22,9 +22,9 @@ render :: proc()
|
||||
// Render Screenspace
|
||||
{
|
||||
fps_msg := fmt.tprint( "FPS:", rl.GetFPS() )
|
||||
fps_msg_width := measure_text_size( fps_msg, default_font, points_to_pixels(24.0), 0.0 ).x
|
||||
fps_msg_width := measure_text_size( fps_msg, default_font, 16.0, 0.0 ).x
|
||||
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 }
|
||||
debug_draw_text( fps_msg, fps_msg_pos, points_to_pixels(24.0), color = rl.GREEN )
|
||||
debug_draw_text( fps_msg, fps_msg_pos, 16.0, color = rl.GREEN )
|
||||
|
||||
debug_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@ -43,7 +43,7 @@ render :: proc()
|
||||
position.y += debug.draw_debug_text_y
|
||||
|
||||
content := fmt.bprintf( draw_text_scratch[:], format, ..args )
|
||||
debug_draw_text( content, position, points_to_pixels(24.0) )
|
||||
debug_draw_text( content, position, 16.0 )
|
||||
|
||||
debug.draw_debug_text_y += 16
|
||||
}
|
||||
@ -100,6 +100,8 @@ render_mode_2d :: proc() {
|
||||
rl.DrawRectangleRec( rect, box.color )
|
||||
}
|
||||
|
||||
debug_draw_text_world( "This is text in world space", { 0, 0 }, 16.0 )
|
||||
|
||||
if debug.mouse_vis {
|
||||
// rl.DrawCircleV( screen_to_world(input.mouse.pos), 10, Color_GreyRed )
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package sectr
|
||||
|
||||
import "base:runtime"
|
||||
import "core:math"
|
||||
import "core:fmt"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
@ -136,11 +137,14 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
// Camera Manual Nav
|
||||
{
|
||||
digital_move_speed : f32 = 200.0
|
||||
zoom_sensitiviity : f32 = 3.5
|
||||
zoom_sensitiviity : f32 = 0.05
|
||||
|
||||
cam := & project.workspace.cam
|
||||
cam.zoom *= 1 + input.mouse.vertical_wheel * zoom_sensitiviity * f32(delta_time)
|
||||
cam.zoom = clamp( cam.zoom, 0.05, 10.0 )
|
||||
cam := & project.workspace.cam
|
||||
zoom_delta := input.mouse.vertical_wheel * zoom_sensitiviity
|
||||
// zoom_delta *= f32(delta_time)
|
||||
cam.zoom *= 1 + zoom_delta
|
||||
cam.zoom = clamp( cam.zoom, 0.5, 10.0 )
|
||||
// cam.zoom = 2.0
|
||||
|
||||
move_velocity : Vec2 = {
|
||||
- cast(f32) i32(debug_actions.cam_move_left) + cast(f32) i32(debug_actions.cam_move_right),
|
||||
|
26
code/ui.odin
26
code/ui.odin
@ -12,6 +12,25 @@ Axis2 :: enum {
|
||||
Count,
|
||||
}
|
||||
|
||||
UI_IconKind :: enum u32 {
|
||||
Null,
|
||||
Arrow_Up,
|
||||
Arrow_Left,
|
||||
Arrow_Right,
|
||||
Arrow_Down,
|
||||
Caret_Up,
|
||||
Caret_Left,
|
||||
Caret_Right,
|
||||
Caret_Down,
|
||||
Check_Hollow,
|
||||
Check_Filled,
|
||||
Count,
|
||||
}
|
||||
|
||||
UI_IconInfo :: struct {
|
||||
placehodler : int
|
||||
}
|
||||
|
||||
UI_SizeKind :: enum u32 {
|
||||
Null,
|
||||
Pixels,
|
||||
@ -19,6 +38,7 @@ UI_SizeKind :: enum u32 {
|
||||
TextContent,
|
||||
PercentOfParent,
|
||||
ChildrenSum,
|
||||
Count,
|
||||
}
|
||||
|
||||
UI_Size :: struct {
|
||||
@ -95,6 +115,8 @@ UI_BoxFlag :: enum u64 {
|
||||
Has_Display_String,
|
||||
Has_Fuzzy_Match_Ranges,
|
||||
Round_Children_By_Parent,
|
||||
|
||||
Count,
|
||||
}
|
||||
UI_BoxFlags :: bit_set[UI_BoxFlag; u64]
|
||||
|
||||
@ -123,7 +145,9 @@ UI_Box :: struct {
|
||||
|
||||
// Note(rjf) : Per-frame info provided by builders
|
||||
flags : UI_BoxFlags,
|
||||
semantic_size : [Axis2.Count]UI_Size,
|
||||
display_str : string,
|
||||
semantic_size : [Axis2.Count]UI_Size,
|
||||
|
||||
|
||||
// Note(rjf) : Computed every frame
|
||||
computed_rel_pos : Vec2,
|
||||
|
Loading…
Reference in New Issue
Block a user