Refactors, lots and lots of it... plus coodinate space

This commit is contained in:
Edward R. Gonzalez 2024-02-11 23:00:06 -05:00
parent f76ba4e9ba
commit 6147d4e344
18 changed files with 596 additions and 174 deletions

View File

@ -64,16 +64,22 @@ 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 } )
// Rough setup of window with rl stuff
screen_width = 1920
screen_height = 1080
window_width : i32 = 1000
window_height : i32 = 600
win_title : cstring = "Sectr Prototype"
rl.InitWindow( screen_width, screen_height, win_title )
rl.InitWindow( window_width, window_height, win_title )
log( "Raylib initialized and window opened" )
window := & state.app_window
window.extent.x = f32(window_width) * 0.5
window.extent.y = f32(window_height) * 0.5
// We do not support non-uniform DPI.
screen_dpi_scale = rl.GetWindowScaleDPI().x
screen_dpc = os_default_dpc * screen_dpi_scale
window.dpi_scale = rl.GetWindowScaleDPI().x
window.dpc = os_default_dpc * window.dpi_scale
// Determining current monitor and setting the target frametime based on it..
monitor_id = rl.GetCurrentMonitor()
@ -102,7 +108,7 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
using project.workspace
cam = {
target = { 0, 0 },
offset = { f32(screen_width) / 2, f32(screen_height) / 2 },
offset = transmute(Vec2) window.extent,
rotation = 0,
zoom = 1.0,
}
@ -116,8 +122,8 @@ startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^
frame_1.color = Color_BG_TextBox
// Frame is getting interpreted as points (It doesn't have to be, I'm just doing it...)
frame_1.width = 400
frame_1.height = 250
box_set_size( & frame_1, { 400, 200 } )
// frame_1.position = { 1000, 1000 }
}
}
}

51
code/collision.odin Normal file
View File

@ -0,0 +1,51 @@
package sectr
import "core:math/linalg"
// Not sure if I should in the future not do the radius check,
// As it maybe be better off as a general proc used in an iteration...
box_is_within_view :: proc( box : ^ Box2 ) -> b32
{
state := get_state(); using state
screen_extent := app_window.extent
screen_bounds_radius := max(screen_extent.x, screen_extent.y)
box_bounds_radius := max(box.extent.x, box.extent.y)
cam := project.workspace.cam
cam_box_distance := linalg.distance(cam.target, box.position)
acceptable_distance := box_bounds_radius + screen_bounds_radius
if cam_box_distance > acceptable_distance {
return false
}
screen_bounds := view_get_bounds()
box_bounds := box_get_bounds( box )
within_bounds : b32 = false
when false {
within_x : b32 = box_bounds.top_left.x > screen_bounds.top_left.x
within_x &= box_bounds.top_left.x < screen_bounds.bottom_right.x
within_y : b32 = box_bounds.top_left.y > screen_bounds.top_left.y
state := get_state(); using state
screen_extent := state.app_window.extent
cam := & project.workspace.cam
within_x_bounds : b32 = pos.x >= -screen_extent.x && pos.x <= screen_extent.x
within_y_bounds : b32 = pos.y >= -screen_extent.y && pos.y <= screen_extent.y
}
return within_bounds
}
is_within_screenspace :: proc( pos : Vec2 ) -> b32 {
state := get_state(); using state
screen_extent := state.app_window.extent
cam := & project.workspace.cam
within_x_bounds : b32 = pos.x >= -screen_extent.x && pos.x <= screen_extent.x
within_y_bounds : b32 = pos.y >= -screen_extent.y && pos.y <= screen_extent.y
return within_x_bounds && within_y_bounds
}

35
code/entity_box2.odin Normal file
View File

@ -0,0 +1,35 @@
package sectr
import "core:encoding/json"
import rl "vendor:raylib"
Box2 :: struct {
position : Vec2,
extent : Extents2,
color : Color
}
box_size :: proc( box : ^ Box2 ) -> AreaSize {
return transmute(AreaSize) box.extent * 2.0
}
box_get_bounds :: proc( box : ^ Box2 ) -> Bounds2 {
top_left := box.position + Vec2 { -box.extent.x, box.extent.y }
bottom_right := box.position + Vec2 { box.extent.x, -box.extent.y }
return { top_left, bottom_right }
}
box_set_size :: proc( box : ^ Box2, size : AreaSize ) {
box.extent = transmute(Extents2) size * 0.5
}
get_rl_rect :: proc ( box : ^ Box2 ) -> rl.Rectangle {
rect : rl.Rectangle = {
x = box.position.x - box.extent.x,
y = box.position.y - box.extent.y,
width = box.extent.x * 2.0,
height = box.extent.y * 2.0,
}
return rect
}

View File

@ -26,11 +26,6 @@ Memory :: struct {
}
save_snapshot :: proc( snapshot : [^]u8 ) {
state := get_state()
// state.font_rec_mono_semicasual_reg
// state.default_font
live_ptr := cast( ^ rawptr ) memory.live.curr_block.base
mem.copy_non_overlapping( & snapshot[0], live_ptr, memory_chunk_size )
}
@ -40,6 +35,12 @@ load_snapshot :: proc( snapshot : [^]u8 ) {
mem.copy_non_overlapping( live_ptr, snapshot, memory_chunk_size )
}
AppConfig :: struct {
resolution_width : uint,
resolution_height : uint,
refresh_rate : uint
}
State :: struct {
input_data : [2] InputState,
input_prev : ^ InputState,
@ -49,10 +50,8 @@ State :: struct {
project : Project,
screen_width : i32,
screen_height : i32,
screen_dpi_scale : f32,
screen_dpc : f32, // Pixels per cm
config : AppConfig,
app_window : AppWindow,
monitor_id : i32,
monitor_refresh_hz : i32,
@ -64,10 +63,16 @@ State :: struct {
default_font : Font,
}
get_state :: proc() -> (^ State) {
get_state :: proc "contextless" () -> ^ State {
return cast( ^ State ) raw_data( memory.persistent.backing.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
}
Project :: struct {
path : string,
name : string,
@ -80,7 +85,7 @@ Workspace :: struct {
name : string,
cam : Camera,
frame_1 : Frame
frame_1 : Box2
}
DebugData :: struct {
@ -89,6 +94,8 @@ DebugData :: struct {
draw_debug_text_y : f32,
mouse_vis : b32,
mouse_pos : Vec2,
cursor_locked : b32,
cursor_unlock_pos : Vec2, // Raylib changes the mose position on lock, we want restore the position the user would be in on screen
mouse_vis : b32,
last_mouse_pos : Vec2,
}

View File

@ -1,27 +0,0 @@
package sectr
Frame :: struct {
position : Vec2,
width, height : f32,
color : Color
}
get_bounds :: proc( frame : ^ Frame ) -> Bounds2 {
half_width := frame.width / 2
half_height := frame.height / 2
bottom_left := Vec2 { -half_width, -half_height }
top_right := Vec2 { half_width, half_height }
return { bottom_left, top_right }
}
get_rect :: proc ( frame : ^ Frame ) -> Rectangle {
half_width := frame.width / 2
half_height := frame.height / 2
rect : Rectangle = {
x = frame.position.x - half_width,
y = frame.position.y - half_height,
width = frame.width,
height = frame.height,
}
return rect
}

View File

@ -40,5 +40,9 @@ OS_Type :: type_of(ODIN_OS)
import rl "vendor:raylib"
Font :: rl.Font
Rectangle :: rl.Rectangle
Font :: rl.Font
get_bounds :: proc {
box_get_bounds,
view_get_bounds,
}

View File

@ -1,6 +1,8 @@
// TODO(Ed) : This if its gets larget can be moved to its own package
package sectr
import "base:runtime"
AnalogAxis :: f32
AnalogStick :: struct {
X, Y : f32
@ -267,9 +269,8 @@ MouseState :: struct {
side, forward, back, extra : DigitalBtn
}
},
X, Y,
vertical_wheel,
horizontal_wheel : AnalogAxis
pos, delta : Vec2,
vertical_wheel, horizontal_wheel : AnalogAxis
}
InputState :: struct {
@ -308,10 +309,6 @@ poll_input :: proc( old, new : ^ InputState )
key_id := cast(KeyboardKey) id
is_down := cast(b32) rl.IsKeyDown( to_raylib_key(id) )
if is_down {
nothing := true
nothing = false
}
input_process_digital_btn( entry_old, entry_new, is_down )
}
}
@ -337,14 +334,12 @@ poll_input :: proc( old, new : ^ InputState )
mouse_id := cast(MouseBtn) id
is_down := cast(b32) rl.IsMouseButtonPressed( to_raylib_mouse_btn(id) )
input_process_digital_btn( & old.mouse.left, & new.mouse.left, is_down )
is_down := cast(b32) rl.IsMouseButtonDown( to_raylib_mouse_btn(id) )
input_process_digital_btn( old_btn, new_btn, is_down )
}
mouse_pos := rl.GetMousePosition()
new.mouse.X = mouse_pos.x
new.mouse.Y = mouse_pos.y
new.mouse.pos = rl.GetMousePosition() - transmute(Vec2) get_state().app_window.extent
new.mouse.delta = rl.GetMouseDelta()
new.mouse.vertical_wheel = rl.GetMouseWheelMove()
}
}

View File

@ -5,9 +5,8 @@ import "core:math/linalg"
Vec2 :: linalg.Vector2f32
Vec3 :: linalg.Vector3f32
Vec2i :: [2]i32
Vec3i :: [3]i32
when false {
// TODO(Ed) : Evaluate if this is needed

View File

@ -3,8 +3,76 @@ package sectr
import "core:encoding/json"
import "core:fmt"
import "core:os"
import "core:reflect"
import "core:runtime"
import "core:strings"
@(private="file")
assign_int :: proc(val: any, i: $T) -> bool {
v := reflect.any_core(val)
switch &dst in v {
case i8: dst = i8 (i)
case i16: dst = i16 (i)
case i16le: dst = i16le (i)
case i16be: dst = i16be (i)
case i32: dst = i32 (i)
case i32le: dst = i32le (i)
case i32be: dst = i32be (i)
case i64: dst = i64 (i)
case i64le: dst = i64le (i)
case i64be: dst = i64be (i)
case i128: dst = i128 (i)
case i128le: dst = i128le (i)
case i128be: dst = i128be (i)
case u8: dst = u8 (i)
case u16: dst = u16 (i)
case u16le: dst = u16le (i)
case u16be: dst = u16be (i)
case u32: dst = u32 (i)
case u32le: dst = u32le (i)
case u32be: dst = u32be (i)
case u64: dst = u64 (i)
case u64le: dst = u64le (i)
case u64be: dst = u64be (i)
case u128: dst = u128 (i)
case u128le: dst = u128le (i)
case u128be: dst = u128be (i)
case int: dst = int (i)
case uint: dst = uint (i)
case uintptr: dst = uintptr(i)
case: return false
}
return true
}
when false {
unmarshal_from_object :: proc( $Type: typeid, object : json.Object ) -> Type
{
result : Type
type_info := type_info_of(Type)
#partial switch type in type_info.variant {
case runtime.Type_Info_Union:
ensure( true, "This proc doesn't support raw unions" )
}
base_ptr := uintptr( & result )
field_infos := reflect.struct_fields_zipped(Type)
for field_info in field_infos
{
field_type := field_info.type.id
field_ptr := cast(field_type) rawptr( base_ptr + field_info.offset )
#partial switch type in field_info.type.variant {
case runtime.Type_Info_Integer:
field_ptr = object[filed_info.name].(json.Integer)
}
}
return result
}
}
Serializer_Version :: 1
Serializer_Loading :: false
@ -31,12 +99,14 @@ project_serialize :: proc ( project : ^ Project, archive : ^ ArchiveData, is_wri
options.pretty = true
options.use_spaces = false
if is_writting
{
marshal_archive : struct {
MarshalArchive :: struct {
version : i32,
project : Project
}
}
if is_writting
{
marshal_archive : MarshalArchive
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
@ -55,12 +125,30 @@ project_serialize :: proc ( project : ^ Project, archive : ^ ArchiveData, is_wri
archive_version : i32 = cast(i32) archive_json["version"].(json.Float)
verify( Serializer_Version != archive_version, "Version mismatch on archive!" )
project_json := archive_json["project"].(json.Object)
project.name = project_json["name"].(json.String)
// 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
json.unmarshal( archive.data, & marshal_archive, spec = json.Specification.MJSON, allocator = context.temp_allocator )
if marshal_archive.version == Serializer_Version {
project^ = marshal_archive.project
}
// TODO(Ed) : Make this a separate proc
workspace_json := project_json["workspace"].(json.Object)
project.workspace.name = workspace_json["name"].(json.String)
// Manual unmarshal
when false
{
project_json := archive_json["project"].(json.Object)
project.name = project_json["name"].(json.String)
// TODO(Ed) : Make this a separate proc
workspace_json := project_json["workspace"].(json.Object)
{
using project.workspace
name = workspace_json["name"].(json.String)
// cam = unmarshal_from_object(Camera, workspace_json["camera"].(json.Object) )
frame_1 = frame_json_unmarshal( & workspace_json["frame_1"] )
}
}
// DEBUG DUD
options.use_spaces = false

View File

@ -0,0 +1,38 @@
package sectr
import "core:encoding/json"
import "core:reflect"
// TODO(Ed) : Generic Unmarshling of json objects (There should be a way I believe todo this generically but the reflect library is not well documented)
vec2_json_unmarshal :: proc ( value : ^ json.Value ) -> Vec2 {
json_v := value.(json.Array)
return {
f32(json_v[0].(json.Float)),
f32(json_v[1].(json.Float)),
}
}
color_json_unmarshal :: proc ( value : ^ json.Value ) -> Color {
json_color := value.(json.Array)
r := u8(json_color[0].(json.Float))
g := u8(json_color[1].(json.Float))
b := u8(json_color[2].(json.Float))
a := u8(json_color[3].(json.Float))
return { r, g, b, a }
}
box_json_unmarshal :: proc ( value : ^ json.Value ) -> Box2 {
object := value.(json.Object)
json_pos := object["position"].(json.Array)
position := Vec2 { f32(json_pos[0].(json.Float)), f32(json_pos[1].(json.Float)) }
width := f32( object["width"] .(json.Float))
height := f32( object["height"].(json.Float))
return {
position = position,
extent = { width, height },
color = color_json_unmarshal( & object["color"] ),
},
}

View File

@ -16,42 +16,110 @@ when ODIN_OS == OS_Type.Windows {
// 1 inch = 2.54 cm, 96 inch * 2.54 = 243.84 DPC
}
f32_cm_to_pixels :: proc ( cm : f32 ) -> f32 {
state := get_state(); using state
cm_to_pixels :: proc( cm : f32 ) -> f32 {
screen_dpc := get_state().app_window.dpc
return cm * screen_dpc
}
vec2_cm_to_pixels :: proc ( v : Vec2 ) -> Vec2 {
state := get_state(); using state
vec2_cm_to_pixels :: proc( v : Vec2 ) -> Vec2 {
screen_dpc := get_state().app_window.dpc
return v * screen_dpc
}
points_to_pixels :: proc ( points : f32 ) -> f32 {
state := get_state(); using state
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
}
pixels_to_points :: proc ( pixels : f32 ) -> f32 {
state := get_state(); using state
pixels_to_points :: proc( pixels : f32 ) -> f32 {
screen_dpc := get_state().app_window.dpc
cm_per_pixel := 1.0 / screen_dpc
return pixels * cm_per_pixel * Points_Per_Centimetre
}
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
}
Camera :: rl.Camera2D
get_half_screen :: proc() -> AreaSize {
state := get_state(); using state
return {
f32(screen_width) / 2,
f32(screen_height) / 2,
}
}
AreaSize :: distinct Vec2
Bounds2 :: struct {
bottom_left, top_right : Vec2
top_left, bottom_right : Vec2
}
AreaSize :: struct {
width, height : f32
BoundsCorners2 :: struct {
top_left, top_right, bottom_left, bottom_right : Vec2
}
Extents2 :: distinct Vec2
Extents2i :: distinct Vec2i
bounds2_radius :: proc( bounds : Bounds2 ) -> f32 {
return max( bounds.bottom_right.x, bounds.top_left.y )
}
extent_from_size :: proc ( size : AreaSize ) -> Extents2 {
return transmute(Extents2) size * 2.0
}
screen_size :: proc "contextless" () -> AreaSize {
extent := get_state().app_window.extent
return transmute(AreaSize) (extent * 2.0)
}
screen_get_corners :: proc() -> BoundsCorners2 {
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 }
}
view_get_bounds :: proc() -> Bounds2 {
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 }
}
view_get_corners :: proc() -> BoundsCorners2 {
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_to_render :: proc( pos : Vec2 ) -> Vec2 {
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
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 }
}
world_to_screen_no_zoom :: proc( position : Vec2 ) -> Vec2 {
state := get_state(); using state
cam_zoom_ratio := 1.0 / state.project.workspace.cam.zoom
return { position.x, position.y * -1 } * cam_zoom_ratio
}

View File

@ -3,18 +3,22 @@ package sectr
import "core:unicode/utf8"
import rl "vendor:raylib"
debug_text :: proc( content : string, pos : Vec2, size : f32 = 16.0, color : rl.Color = rl.WHITE, font : rl.Font = {} )
debug_draw_text :: proc( content : string, pos : Vec2, size : f32 = 16.0, color : rl.Color = rl.WHITE, font : rl.Font = {} )
{
state := get_state(); using state
if len( content ) == 0 {
return
}
runes := utf8.string_to_runes( content, context.temp_allocator )
font := font
if ( font.chars == nil ) {
font = get_state().default_font
if ( font.glyphs == nil ) {
font = default_font
}
pos := screen_to_render(pos)
rl.DrawTextCodepoints( font,
raw_data(runes), cast(i32) len(runes),
position = transmute(rl.Vector2) pos,
@ -22,3 +26,74 @@ debug_text :: proc( content : string, pos : Vec2, size : f32 = 16.0, color : rl.
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
{
// This is a static var within raylib. We don't have getter access to it.
@static text_line_spacing : f32 = 15
text_size : AreaSize
if font.texture.id == 0 || len(text) == 0 {
return text_size
}
temp_byte_counter : i32 = 0 // Used to count longer text line num chars
byte_counter : i32 = 0
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
letter : rune
index : i32 = 0
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 )
id += 1
if letter != rune('\n')
{
if font.glyphs[index].advanceX != 0 {
text_width += f32(font.glyphs[index].advanceX)
}
else {
text_width += font.recs[index].width + f32(font.glyphs[index].offsetX)
}
}
else
{
if temp_text_width < text_width {
temp_text_width = text_width
}
byte_counter = 0
text_width = 0
text_height += text_line_spacing
if temp_byte_counter < byte_counter {
temp_byte_counter = byte_counter
}
}
}
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
return text_size
}

View File

@ -8,78 +8,114 @@ render :: proc()
{
state := get_state(); using state
replay := & memory.replay
cam := & project.workspace.cam
win_extent := state.app_window.extent
half_screen_width := f32(screen_width) / 2
half_screen_height := f32(screen_height) / 2
screen_top_left : Vec2 = {
-win_extent.x + cam.target.x,
-win_extent.y + cam.target.y,
}
rl.BeginDrawing()
rl.ClearBackground( Color_BG )
rl.BeginMode2D( project.workspace.cam )
// rl.BeginMode3D( project.workspace.cam )
defer {
fps_msg := fmt.tprint( "FPS:", rl.GetFPS() )
debug_text( fps_msg, { -half_screen_width, -half_screen_height }, color = rl.GREEN )
render_mode_2d()
{
fps_msg := fmt.tprint( "FPS:", rl.GetFPS() )
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, color = rl.GREEN )
rl.EndMode2D()
// rl.EndMode3D()
rl.EndDrawing()
// Note(Ed) : Polls input as well.
debug_text :: proc( format : string, args : ..any )
{
@static draw_text_scratch : [Kilobyte * 64]u8
state := get_state(); using state
if debug.draw_debug_text_y > 800 {
debug.draw_debug_text_y = 50
}
cam := & project.workspace.cam
screen_corners := screen_get_corners()
position := screen_corners.top_right
position.x -= 300
position.y += debug.draw_debug_text_y
content := fmt.bprintf( draw_text_scratch[:], format, ..args )
debug_draw_text( content, position )
debug.draw_debug_text_y += 16
}
// Debug Text
{
debug_text( "Screen Width : %v", rl.GetScreenWidth () )
debug_text( "Screen Height: %v", rl.GetScreenHeight() )
if replay.mode == ReplayMode.Record {
debug_text( "Recording Input")
}
if replay.mode == ReplayMode.Playback {
debug_text( "Replaying Input")
}
}
if debug.mouse_vis {
debug_text( "Position: %v", input.mouse.pos )
rect_pos := transmute(Vec2) state.app_window.extent + input.mouse.pos
width : f32 = 32
mouse_rect : rl.Rectangle
mouse_rect.x = rect_pos.x - width * 0.5
mouse_rect.y = rect_pos.y - width * 0.5
mouse_rect.width = width
mouse_rect.height = width
rl.DrawRectangleRec( mouse_rect, Color_White )
}
debug.draw_debug_text_y = 50
}
rl.EndDrawing()
}
render_mode_2d :: proc() {
state := get_state(); using state
cam := & project.workspace.cam
win_extent := state.app_window.extent
rl.BeginMode2D( project.workspace.cam )
// Frame 1
{
frame_1 := & project.workspace.frame_1
rect := get_rect( frame_1 )
rect := get_rl_rect( frame_1 )
screen_pos := world_to_screen_pos(frame_1.position)
rect.width = points_to_pixels( rect.width )
rect.height = points_to_pixels( rect.height )
rect.x = points_to_pixels( rect.x )
rect.y = points_to_pixels( rect.y )
rect.x = points_to_pixels( screen_pos.x )
rect.y = points_to_pixels( screen_pos.y )
rl.DrawRectangleRec( rect, frame_1.color )
// rl.DrawRectangleV( frame_1.position, { frame_1.width, frame_1.height }, frame_1.color )
// rl.DrawRectanglePro( rect, frame_1.position, 0, frame_1.color )
}
debug_draw_text :: proc( format : string, args : ..any )
{
@static draw_text_scratch : [Kilobyte * 64]u8
// Frame 2
when false
{
frame_1 := & project.workspace.frame_1
rect := get_rl_rect( frame_1 )
screen_pos := world_to_screen_pos(frame_1.position)
state := get_state(); using state
if debug.draw_debug_text_y > 800 {
debug.draw_debug_text_y = 50
rect.width = points_to_pixels( rect.width )
rect.height = points_to_pixels( rect.height )
rect.x = points_to_pixels( screen_pos.x )
rect.y = points_to_pixels( screen_pos.y )
rl.DrawRectangleRec( rect, frame_1.color )
// rl.DrawRectangleV( frame_1.position, { frame_1.width, frame_1.height }, frame_1.color )
// rl.DrawRectanglePro( rect, frame_1.position, 0, frame_1.color )
}
content := fmt.bprintf( draw_text_scratch[:], format, ..args )
debug_text( content, { 25, debug.draw_debug_text_y } )
debug.draw_debug_text_y += 16
}
// Debug Text
{
debug_draw_text( "Screen Width : %v", rl.GetScreenWidth () )
debug_draw_text( "Screen Height: %v", rl.GetScreenHeight() )
if replay.mode == ReplayMode.Record {
debug_draw_text( "Recording Input")
}
if replay.mode == ReplayMode.Playback {
debug_draw_text( "Replaying Input")
}
}
if debug.mouse_vis {
width : f32 = 32
pos := debug.mouse_pos
debug_draw_text( "Position: %v", rl.GetMousePosition() )
mouse_rect : rl.Rectangle
mouse_rect.x = pos.x - width/2
mouse_rect.y = pos.y - width/2
mouse_rect.width = width
mouse_rect.height = width
// rl.DrawRectangleRec( mouse_rect, Color_White )
}
debug.draw_debug_text_y = 50
}
rl.EndMode2D()
}

View File

@ -1,5 +1,6 @@
package sectr
import "base:runtime"
import "core:fmt"
import rl "vendor:raylib"
@ -19,6 +20,7 @@ DebugActions :: struct {
cam_move_left : b32,
cam_move_down : b32,
cam_move_right : b32,
cam_mouse_pan : b32,
}
poll_debug_actions :: proc( actions : ^ DebugActions, input : ^ InputState )
@ -26,6 +28,13 @@ poll_debug_actions :: proc( actions : ^ DebugActions, input : ^ InputState )
using actions
using input
modifier_active := keyboard.right_alt.ended_down ||
keyboard.right_control.ended_down ||
keyboard.right_shift.ended_down ||
keyboard.left_alt.ended_down ||
keyboard.left_control.ended_down ||
keyboard.left_shift.ended_down
load_project = keyboard.left_control.ended_down && pressed( keyboard.O )
save_project = keyboard.left_control.ended_down && pressed( keyboard.S )
@ -35,10 +44,12 @@ poll_debug_actions :: proc( actions : ^ DebugActions, input : ^ InputState )
show_mouse_pos = keyboard.right_alt.ended_down && pressed(keyboard.M)
cam_move_up = keyboard.W.ended_down
cam_move_left = keyboard.A.ended_down
cam_move_down = keyboard.S.ended_down
cam_move_right = keyboard.D.ended_down
cam_move_up = keyboard.W.ended_down && ( ! modifier_active || keyboard.left_shift.ended_down )
cam_move_left = keyboard.A.ended_down && ( ! modifier_active || keyboard.left_shift.ended_down )
cam_move_down = keyboard.S.ended_down && ( ! modifier_active || keyboard.left_shift.ended_down )
cam_move_right = keyboard.D.ended_down && ( ! modifier_active || keyboard.left_shift.ended_down )
cam_mouse_pan = mouse.right.ended_down && ! pressed(mouse.right)
}
update :: proc( delta_time : f64 ) -> b32
@ -46,6 +57,14 @@ update :: proc( delta_time : f64 ) -> b32
state := get_state(); using state
replay := & memory.replay
if rl.IsWindowResized() {
window := & state.app_window
window.extent.x = f32(rl.GetScreenWidth()) * 0.5
window.extent.y = f32(rl.GetScreenHeight()) * 0.5
project.workspace.cam.offset = transmute(Vec2) window.extent
}
state.input, state.input_prev = swap( state.input, state.input_prev )
poll_input( state.input_prev, state.input )
@ -110,14 +129,12 @@ update :: proc( delta_time : f64 ) -> b32
debug.mouse_vis = !debug.mouse_vis
}
debug.mouse_pos = { input.mouse.X, input.mouse.Y }
// Camera Manual Nav
{
move_speed : f32 = 200.0
zoom_sensitiviity : f32 = 3.5
digital_move_speed : f32 = 200.0
zoom_sensitiviity : f32 = 3.5
cam := & project.workspace.cam
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 )
@ -125,10 +142,20 @@ update :: proc( delta_time : f64 ) -> b32
- cast(f32) i32(debug_actions.cam_move_left) + cast(f32) i32(debug_actions.cam_move_right),
- cast(f32) i32(debug_actions.cam_move_up) + cast(f32) i32(debug_actions.cam_move_down),
}
move_velocity *= move_speed * f32(delta_time)
move_velocity *= digital_move_speed * f32(delta_time)
cam.target += move_velocity
if debug_actions.cam_mouse_pan
{
if is_within_screenspace(input.mouse.pos) {
pan_velocity := input.mouse.delta * (1/cam.zoom)
cam.target -= pan_velocity
}
}
}
debug.last_mouse_pos = input.mouse.pos
should_shutdown : b32 = ! cast(b32) rl.WindowShouldClose()
return should_shutdown
}

View File

@ -12,6 +12,10 @@
{
"name": "code",
"path": "C:/projects/SectrPrototype/code"
},
{
"name": "ini",
"path": "C:/projects/SectrPrototype/thirdparty/ini"
}
],
"enable_document_symbols": true,

View File

@ -5,8 +5,10 @@ $path_code = join-path $path_root 'code'
$path_build = join-path $path_root 'build'
$path_thirdparty = join-path $path_root 'thirdparty'
$url_odin_repo = 'https://github.com/Ed94/Odin.git'
$path_odin = join-path $path_thirdparty 'Odin'
$url_odin_repo = 'https://github.com/Ed94/Odin.git'
$url_ini_parser = 'https://github.com/laytan/odin-ini-parser.git'
$path_odin = join-path $path_thirdparty 'Odin'
$path_ini_parser = join-path $path_thirdparty 'ini'
$incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1'
. $incremental_checks
@ -25,21 +27,18 @@ if (Test-Path -Path $path_odin)
# Get the latest local and remote commit hashes for the current branch
$localCommit = git -C $path_odin rev-parse HEAD
$remoteCommit = git -C $path_odin rev-parse '@{u}'
# Compare local and remote commits
if ($localCommit -ne $remoteCommit)
if ($localCommit -ne $remoteCommit)
{
Write-Host "Odin repository is out-of-date. Pulling changes and rebuilding..."
git -C $path_odin pull
push-location $path_odin
& .\build.bat
pop-location
Write-Host "Odin repository is out-of-date. Pulling changes and rebuilding..."
git -C $path_odin pull
push-location $path_odin
& .\build.bat
pop-location
$binaries_dirty = $true
$binaries_dirty = $true
}
else
{
Write-Host "Odin repository is up-to-date. No need to rebuild."
else {
Write-Host "Odin repository is up-to-date. No need to rebuild."
}
}
else
@ -54,6 +53,23 @@ else
$binaries_dirty = $true
}
if (Test-Path -Path $path_ini_parser)
{
Write-Host "Checking for updates on the ini-parser"
$localCommit = git -C $path_ini_parser rev-parse HEAD
$remoteCommit = git -C $path_ini_parser rev-parse '@{u}'
if ($localCommit -ne $remoteCommit)
{
Write-Host "ini-parser repository is out-of-date. Pulling changes and rebuilding..."
git -C $path_ini_parser pull
}
}
else
{
Write-Host "Cloning Odin repository..."
git clone $url_ini_parser $path_ini_parser
}
$path_vendor = join-path $path_odin 'vendor'
$path_vendor_raylib = join-path $path_vendor 'raylib'
$path_raylib_dlls = join-path $path_vendor_raylib 'windows'