Font drawing is nice now

This commit is contained in:
Edward R. Gonzalez 2024-02-13 17:16:39 -05:00
parent f36b05e795
commit 5c124521dc
13 changed files with 465 additions and 128 deletions

BIN
assets/FiraCode-Regular.ttf Normal file

Binary file not shown.

BIN
assets/Squidgy Slimes.ttf Normal file

Binary file not shown.

View File

@ -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() )
}
}

View File

@ -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
View 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
}

View File

@ -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,

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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 )
}

View File

@ -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),

View File

@ -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,

View File

@ -21,5 +21,6 @@
"enable_document_symbols": true,
"enable_semantic_tokens": false,
"enable_hover": true,
"enable_snippets": true
"enable_snippets": true,
"enable_format": false
}