Refactors, lots and lots of it... plus coodinate space
This commit is contained in:
parent
f76ba4e9ba
commit
6147d4e344
@ -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
51
code/collision.odin
Normal 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
35
code/entity_box2.odin
Normal 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
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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,
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
38
code/serialize_manual_unmarshal.odin
Normal file
38
code/serialize_manual_unmarshal.odin
Normal 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"] ),
|
||||
},
|
||||
}
|
104
code/space.odin
104
code/space.odin
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
4
ols.json
4
ols.json
@ -12,6 +12,10 @@
|
||||
{
|
||||
"name": "code",
|
||||
"path": "C:/projects/SectrPrototype/code"
|
||||
},
|
||||
{
|
||||
"name": "ini",
|
||||
"path": "C:/projects/SectrPrototype/thirdparty/ini"
|
||||
}
|
||||
],
|
||||
"enable_document_symbols": true,
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user