Editor improvements and some refactoring
This commit is contained in:
parent
f8b73786aa
commit
890ac2494a
@ -1,6 +1,9 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
import lg "core:math/linalg"
|
import lg "core:math/linalg"
|
||||||
|
import "game:physics/collision"
|
||||||
|
import "game:ui"
|
||||||
import rl "libs:raylib"
|
import rl "libs:raylib"
|
||||||
|
|
||||||
update_editor :: proc(es: ^Editor_State, dt: f32) {
|
update_editor :: proc(es: ^Editor_State, dt: f32) {
|
||||||
@ -40,11 +43,21 @@ update_editor :: proc(es: ^Editor_State, dt: f32) {
|
|||||||
clear(&es.point_selection)
|
clear(&es.point_selection)
|
||||||
}
|
}
|
||||||
if rl.IsKeyPressed(.G) {
|
if rl.IsKeyPressed(.G) {
|
||||||
|
track := &world_stack_current(&es.world_stack).track
|
||||||
|
selected_count := 0
|
||||||
|
es.move_initial_pos = 0
|
||||||
|
for k in es.point_selection {
|
||||||
|
es.move_initial_pos += track.points[k]
|
||||||
|
selected_count += 1
|
||||||
|
}
|
||||||
|
if selected_count > 0 {
|
||||||
|
es.move_initial_pos /= f32(selected_count)
|
||||||
es.track_edit_state = .Move
|
es.track_edit_state = .Move
|
||||||
es.move_axis = .None
|
es.move_axis = .None
|
||||||
es.total_movement_world = {}
|
es.total_movement_world = {}
|
||||||
|
|
||||||
world_stack_push(&es.world_stack)
|
world_stack_push(&es.world_stack)
|
||||||
// es.initial_point_pos = g_mem.track.points[es.selected_track_point]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,24 +102,53 @@ update_editor :: proc(es: ^Editor_State, dt: f32) {
|
|||||||
|
|
||||||
camera := game_camera_3d()
|
camera := game_camera_3d()
|
||||||
|
|
||||||
mouse_delta := rl.GetMouseDelta() * 0.05
|
mouse_pos := rl.GetMousePosition()
|
||||||
|
prev_mouse_pos := es.prev_mouse_pos
|
||||||
view_rotation := lg.transpose(rl.GetCameraMatrix(camera))
|
prev_ray := rl.GetScreenToWorldRay(prev_mouse_pos, camera)
|
||||||
view_rotation[3].xyz = 0
|
ray := rl.GetScreenToWorldRay(mouse_pos, camera)
|
||||||
view_proj := view_rotation * rl.MatrixOrtho(-1, 1, 1, -1, -1, 1)
|
|
||||||
|
|
||||||
axes_buf: [2]rl.Vector3
|
axes_buf: [2]rl.Vector3
|
||||||
colors_buf: [2]rl.Color
|
colors_buf: [2]rl.Color
|
||||||
axes, _ := get_movement_axes(es.move_axis, &axes_buf, &colors_buf)
|
axes, _ := get_movement_axes(es.move_axis, &axes_buf, &colors_buf)
|
||||||
|
|
||||||
movement_world: rl.Vector3
|
movement_world: rl.Vector3
|
||||||
for axis in axes {
|
if len(axes) == 2 {
|
||||||
axis_screen := (rl.Vector4{axis.x, axis.y, axis.z, 1} * view_proj).xy
|
normal := lg.normalize0(lg.cross(axes[0], axes[1]))
|
||||||
axis_screen = lg.normalize0(axis_screen)
|
plane := collision.plane_from_point_normal(es.move_initial_pos, normal)
|
||||||
|
|
||||||
movement_screen := lg.dot(axis_screen, mouse_delta) * axis_screen
|
_, pos1 := collision.intersect_ray_plane(
|
||||||
movement_world +=
|
prev_ray.position,
|
||||||
(rl.Vector4{movement_screen.x, movement_screen.y, 0, 1} * rl.MatrixInvert(view_proj)).xyz
|
prev_ray.direction,
|
||||||
|
plane,
|
||||||
|
)
|
||||||
|
_, pos2 := collision.intersect_ray_plane(
|
||||||
|
ray.position,
|
||||||
|
ray.direction,
|
||||||
|
plane,
|
||||||
|
)
|
||||||
|
world_delta := pos2 - pos1
|
||||||
|
world_delta -= lg.dot(world_delta, plane.normal) * plane.normal
|
||||||
|
movement_world += world_delta
|
||||||
|
} else if len(axes) == 1 {
|
||||||
|
for axis in axes {
|
||||||
|
tangent := lg.cross(es.move_initial_pos - camera.position, axis)
|
||||||
|
normal := lg.normalize0(lg.cross(axis, tangent))
|
||||||
|
|
||||||
|
plane := collision.plane_from_point_normal(es.move_initial_pos, normal)
|
||||||
|
_, pos1 := collision.intersect_ray_plane(
|
||||||
|
prev_ray.position,
|
||||||
|
prev_ray.direction,
|
||||||
|
plane,
|
||||||
|
)
|
||||||
|
_, pos2 := collision.intersect_ray_plane(
|
||||||
|
ray.position,
|
||||||
|
ray.direction,
|
||||||
|
plane,
|
||||||
|
)
|
||||||
|
|
||||||
|
world_delta := pos2 - pos1
|
||||||
|
movement_world += lg.dot(axis, world_delta) * axis
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k in es.point_selection {
|
for k in es.point_selection {
|
||||||
@ -117,8 +159,26 @@ update_editor :: proc(es: ^Editor_State, dt: f32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// world := world_stack_current(&es.world_stack)
|
|
||||||
// update_world(world, dt, false)
|
es.prev_mouse_pos = rl.GetMousePosition()
|
||||||
|
|
||||||
|
ui_ctx := &g_mem.ui_context
|
||||||
|
if ui.window(ui_ctx, "Editor", ui.Rect{x = 500, y = 0, w = 500, h = 600}) {
|
||||||
|
cnt := ui.get_current_container(ui_ctx)
|
||||||
|
cnt.rect.w = max(cnt.rect.w, 500)
|
||||||
|
cnt.rect.h = max(cnt.rect.h, 600)
|
||||||
|
|
||||||
|
if .ACTIVE in ui.header(ui_ctx, "Details", {.EXPANDED}) {
|
||||||
|
ui.layout_row(ui_ctx, {100, -1})
|
||||||
|
|
||||||
|
ui.label(ui_ctx, "mov")
|
||||||
|
ui.label(ui_ctx, fmt.tprintf("%v", es.move_initial_pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world := world_stack_current(&es.world_stack)
|
||||||
|
config := World_Update_Config {
|
||||||
|
commit_physics = false,
|
||||||
|
}
|
||||||
|
update_world(world, dt, config)
|
||||||
}
|
}
|
||||||
|
@ -222,13 +222,18 @@ Editor_State :: struct {
|
|||||||
point_selection: map[int]bool,
|
point_selection: map[int]bool,
|
||||||
track_edit_state: Track_Edit_State,
|
track_edit_state: Track_Edit_State,
|
||||||
move_axis: Move_Axis,
|
move_axis: Move_Axis,
|
||||||
|
prev_mouse_pos: rl.Vector2,
|
||||||
|
move_initial_pos: rl.Vector3,
|
||||||
total_movement_world: rl.Vector3,
|
total_movement_world: rl.Vector3,
|
||||||
initial_point_pos: rl.Vector3,
|
|
||||||
camera: Free_Camera,
|
camera: Free_Camera,
|
||||||
}
|
}
|
||||||
|
|
||||||
editor_state_init :: proc(es: ^Editor_State, num_snapshots: int) {
|
editor_state_init :: proc(es: ^Editor_State, num_snapshots: int) {
|
||||||
world_stack_init(&es.world_stack, num_snapshots)
|
world_stack_init(&es.world_stack, num_snapshots)
|
||||||
|
world_stack_current(&es.world_stack).debug_state = {
|
||||||
|
show_menu = true,
|
||||||
|
draw_physics_scene = true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editor_state_destroy :: proc(es: ^Editor_State) {
|
editor_state_destroy :: proc(es: ^Editor_State) {
|
||||||
@ -348,7 +353,12 @@ get_movement_axes :: proc(
|
|||||||
return out_axes[0:0], out_colors[0:0]
|
return out_axes[0:0], out_colors[0:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
update_world :: proc(world: ^World, dt: f32, single_step_physics: bool) {
|
World_Update_Config :: struct {
|
||||||
|
single_step_physics: bool,
|
||||||
|
commit_physics: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
||||||
if !world.pause {
|
if !world.pause {
|
||||||
car_model := assets.get_model(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
|
car_model := assets.get_model(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
|
||||||
car_bounds := rl.GetModelBoundingBox(car_model)
|
car_bounds := rl.GetModelBoundingBox(car_model)
|
||||||
@ -608,8 +618,8 @@ update_world :: proc(world: ^World, dt: f32, single_step_physics: bool) {
|
|||||||
&world.physics_scene,
|
&world.physics_scene,
|
||||||
SOLVER_CONFIG,
|
SOLVER_CONFIG,
|
||||||
dt,
|
dt,
|
||||||
commit = true,
|
commit = config.commit_physics,
|
||||||
step_mode = single_step_physics ? physics.Step_Mode.Single : physics.Step_Mode.Accumulated_Time,
|
step_mode = config.single_step_physics ? physics.Step_Mode.Single : physics.Step_Mode.Accumulated_Time,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,7 +636,11 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
if !runtime_world.rewind_simulation {
|
if !runtime_world.rewind_simulation {
|
||||||
next_world := runtime_world_next_world(runtime_world)
|
next_world := runtime_world_next_world(runtime_world)
|
||||||
copy_world(next_world, cur_world)
|
copy_world(next_world, cur_world)
|
||||||
update_world(next_world, dt, should_single_step)
|
config := World_Update_Config {
|
||||||
|
commit_physics = true,
|
||||||
|
single_step_physics = should_single_step,
|
||||||
|
}
|
||||||
|
update_world(next_world, dt, config)
|
||||||
|
|
||||||
if runtime_world.commit_simulation {
|
if runtime_world.commit_simulation {
|
||||||
runtime_world.current_world_index =
|
runtime_world.current_world_index =
|
||||||
@ -676,7 +690,7 @@ collect_camera_input :: proc() -> (delta: rl.Vector2, sense: f32) {
|
|||||||
|
|
||||||
mouse_delta := g_mem.mouse_captured ? rl.GetMouseDelta() : 0
|
mouse_delta := g_mem.mouse_captured ? rl.GetMouseDelta() : 0
|
||||||
|
|
||||||
MOUSE_SENSE :: 0.01
|
MOUSE_SENSE :: 0.005
|
||||||
GAMEPAD_SENSE :: 1
|
GAMEPAD_SENSE :: 1
|
||||||
|
|
||||||
if linalg.length2(mouse_delta) > linalg.length2(gamepad_delta) {
|
if linalg.length2(mouse_delta) > linalg.length2(gamepad_delta) {
|
||||||
@ -786,6 +800,14 @@ update :: proc() {
|
|||||||
|
|
||||||
if rl.IsKeyPressed(.TAB) {
|
if rl.IsKeyPressed(.TAB) {
|
||||||
g_mem.editor = !g_mem.editor
|
g_mem.editor = !g_mem.editor
|
||||||
|
|
||||||
|
// When switching from editor to game, copy editor world into game world
|
||||||
|
if !g_mem.editor {
|
||||||
|
es := &g_mem.es
|
||||||
|
|
||||||
|
editor_world := world_stack_current(&es.world_stack)
|
||||||
|
copy_world(runtime_world_current_world(&g_mem.runtime_world), editor_world)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(.F1) {
|
if rl.IsKeyPressed(.F1) {
|
||||||
@ -921,8 +943,8 @@ draw_world :: proc(world: ^World) {
|
|||||||
if world.debug_state.show_menu {
|
if world.debug_state.show_menu {
|
||||||
ui_ctx := &g_mem.ui_context
|
ui_ctx := &g_mem.ui_context
|
||||||
|
|
||||||
ui.push_font_size_style(ui_ctx, 20)
|
//ui.push_font_size_style(ui_ctx, 20)
|
||||||
defer ui.pop_style(ui_ctx)
|
// defer ui.pop_style(ui_ctx)
|
||||||
|
|
||||||
if ui.window(ui_ctx, "Debug Menu", {x = 0, y = 0, w = 200, h = 300}) {
|
if ui.window(ui_ctx, "Debug Menu", {x = 0, y = 0, w = 200, h = 300}) {
|
||||||
cnt := ui.get_current_container(ui_ctx)
|
cnt := ui.get_current_container(ui_ctx)
|
||||||
@ -961,7 +983,6 @@ draw_world :: proc(world: ^World) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
car_matrix := rl.QuaternionToMatrix(car_body.q)
|
car_matrix := rl.QuaternionToMatrix(car_body.q)
|
||||||
@ -1050,9 +1071,9 @@ draw :: proc() {
|
|||||||
for v in soa_zip(axis = axes, color = colors) {
|
for v in soa_zip(axis = axes, color = colors) {
|
||||||
rlgl.Color4ub(v.color.r, v.color.g, v.color.b, v.color.a)
|
rlgl.Color4ub(v.color.r, v.color.g, v.color.b, v.color.a)
|
||||||
start, end :=
|
start, end :=
|
||||||
es.initial_point_pos -
|
es.move_initial_pos -
|
||||||
v.axis * 100000,
|
v.axis * 100000,
|
||||||
es.initial_point_pos +
|
es.move_initial_pos +
|
||||||
v.axis * 100000
|
v.axis * 100000
|
||||||
|
|
||||||
rlgl.Vertex3f(start.x, start.y, start.z)
|
rlgl.Vertex3f(start.x, start.y, start.z)
|
||||||
@ -1251,9 +1272,8 @@ game_init :: proc() {
|
|||||||
ui.init(&g_mem.ui_context)
|
ui.init(&g_mem.ui_context)
|
||||||
|
|
||||||
g_mem.ui_context.default_style.font = ui.Font(&g_mem.default_font)
|
g_mem.ui_context.default_style.font = ui.Font(&g_mem.default_font)
|
||||||
g_mem.ui_context.default_style.font_size = 32
|
g_mem.ui_context.default_style.font_size = 20
|
||||||
g_mem.ui_context.text_width = ui.rl_measure_text_width
|
g_mem.ui_context.text_size = ui.rl_measure_text_2d
|
||||||
g_mem.ui_context.text_height = ui.rl_measure_text_height
|
|
||||||
|
|
||||||
game_hot_reloaded(g_mem)
|
game_hot_reloaded(g_mem)
|
||||||
}
|
}
|
||||||
|
@ -620,6 +620,13 @@ intersect_ray_triangle :: proc(
|
|||||||
return t, normal, barycentric, true
|
return t, normal, barycentric, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intersect_ray_plane :: proc(origin, dir: Vec3, plane: Plane) -> (t: f32, pos: Vec3) {
|
||||||
|
t = (dot(plane.normal, (plane.normal * plane.dist - origin))) / dot(plane.normal, dir)
|
||||||
|
pos = origin + dir * t
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
intersect_segment_plane :: proc(
|
intersect_segment_plane :: proc(
|
||||||
segment: [2]Vec3,
|
segment: [2]Vec3,
|
||||||
plane: Plane,
|
plane: Plane,
|
||||||
|
@ -10,26 +10,115 @@ Body_Config_Inertia_Mode :: enum {
|
|||||||
Explicit,
|
Explicit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Immedate_State :: struct($T: typeid) {
|
||||||
|
handle: T,
|
||||||
|
// When was this referenced last time (frame number)
|
||||||
|
last_ref: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
Immediate_Container :: struct($T: typeid) {
|
||||||
|
items: map[u32]Immedate_State(T),
|
||||||
|
num_items: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// When ok = true, it means we found an existing item
|
||||||
|
immediate_container_find_or_add :: proc(
|
||||||
|
c: $T/^Immediate_Container($E),
|
||||||
|
simulation_frame: u32,
|
||||||
|
id: u32,
|
||||||
|
) -> (
|
||||||
|
handle: ^E,
|
||||||
|
ok: bool,
|
||||||
|
) {
|
||||||
|
if id in c.items {
|
||||||
|
item := &c.items[id]
|
||||||
|
if item.last_ref != simulation_frame {
|
||||||
|
item.last_ref = simulation_frame
|
||||||
|
c.num_items += 1
|
||||||
|
}
|
||||||
|
handle = &item.handle
|
||||||
|
ok = true
|
||||||
|
} else {
|
||||||
|
c.num_items += 1
|
||||||
|
c.items[id] = {
|
||||||
|
handle = {},
|
||||||
|
last_ref = simulation_frame,
|
||||||
|
}
|
||||||
|
item := &c.items[id]
|
||||||
|
handle = &item.handle
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns removed handles, allocated using allocator
|
||||||
|
immediate_container_prune :: proc(
|
||||||
|
c: $T/^Immediate_Container($E),
|
||||||
|
simulation_frame: u32,
|
||||||
|
allocator := context.temp_allocator,
|
||||||
|
) -> (
|
||||||
|
removed_handles: []E,
|
||||||
|
) {
|
||||||
|
if int(c.num_items) == len(c.items) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
num_unreferenced := len(c.items) - int(c.num_items)
|
||||||
|
assert(num_unreferenced >= 0)
|
||||||
|
|
||||||
|
removed_handles = make([]E, num_unreferenced, allocator)
|
||||||
|
items_to_remove := make([]u32, num_unreferenced, context.temp_allocator)
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for k, &v in c.items {
|
||||||
|
if v.last_ref != simulation_frame {
|
||||||
|
items_to_remove[i] = k
|
||||||
|
removed_handles[i] = v.handle
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i == len(items_to_remove))
|
||||||
|
|
||||||
|
for k in items_to_remove {
|
||||||
|
delete_key(&c.items, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_map :: proc(dst, src: $T/^map[$K]$V) {
|
||||||
|
clear(dst)
|
||||||
|
reserve_map(dst, len(src))
|
||||||
|
|
||||||
|
for k, v in src {
|
||||||
|
dst[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
immediate_container_copy :: proc(dst, src: $T/^Immediate_Container($E)) {
|
||||||
|
copy_map(&dst.items, &src.items)
|
||||||
|
dst.num_items = src.num_items
|
||||||
|
}
|
||||||
|
|
||||||
|
immediate_container_destroy :: proc(c: $T/^Immediate_Container($E)) {
|
||||||
|
delete_map(c.items)
|
||||||
|
}
|
||||||
|
|
||||||
immediate_body :: proc(scene: ^Scene, id: u32, config: Body_Config) -> (handle: Body_Handle) {
|
immediate_body :: proc(scene: ^Scene, id: u32, config: Body_Config) -> (handle: Body_Handle) {
|
||||||
state := &scene.solver_state
|
state := &scene.solver_state
|
||||||
sim_state := get_sim_state(scene)
|
sim_state := get_sim_state(scene)
|
||||||
if id in state.immedate_bodies {
|
h, ok := immediate_container_find_or_add(&state.immediate_bodies, state.simulation_frame, id)
|
||||||
body := &state.immedate_bodies[id]
|
|
||||||
if body.last_ref != state.simulation_frame {
|
if ok {
|
||||||
body.last_ref = state.simulation_frame
|
update_body_from_config(sim_state, get_body(sim_state, h^), config)
|
||||||
state.num_referenced_bodies += 1
|
|
||||||
}
|
|
||||||
handle = body.handle
|
|
||||||
update_body_from_config(sim_state, get_body(sim_state, handle), config)
|
|
||||||
} else {
|
} else {
|
||||||
state.num_referenced_bodies += 1
|
h^ = add_body(sim_state, config)
|
||||||
handle = add_body(sim_state, config)
|
|
||||||
state.immedate_bodies[id] = {
|
|
||||||
handle = handle,
|
|
||||||
last_ref = state.simulation_frame,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle = h^
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,22 +130,17 @@ immediate_suspension_constraint :: proc(
|
|||||||
handle: Suspension_Constraint_Handle,
|
handle: Suspension_Constraint_Handle,
|
||||||
) {
|
) {
|
||||||
state := &scene.solver_state
|
state := &scene.solver_state
|
||||||
if id in state.immediate_suspension_constraints {
|
h, ok := immediate_container_find_or_add(
|
||||||
constraint := &state.immediate_suspension_constraints[id]
|
&state.immediate_suspension_constraints,
|
||||||
if constraint.last_ref != state.simulation_frame {
|
state.simulation_frame,
|
||||||
constraint.last_ref = state.simulation_frame
|
id,
|
||||||
state.num_referenced_suspension_constraints += 1
|
)
|
||||||
}
|
|
||||||
handle = constraint.handle
|
if !ok {
|
||||||
} else {
|
h^ = add_suspension_constraint(get_sim_state(scene), {})
|
||||||
state.num_referenced_suspension_constraints += 1
|
|
||||||
handle = add_suspension_constraint(get_sim_state(scene), {})
|
|
||||||
state.immediate_suspension_constraints[id] = {
|
|
||||||
handle = handle,
|
|
||||||
last_ref = state.simulation_frame,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle = h^
|
||||||
update_suspension_constraint_from_config(
|
update_suspension_constraint_from_config(
|
||||||
get_suspension_constraint(get_sim_state(scene), handle),
|
get_suspension_constraint(get_sim_state(scene), handle),
|
||||||
config,
|
config,
|
||||||
@ -74,117 +158,36 @@ immediate_engine :: proc(
|
|||||||
) {
|
) {
|
||||||
state := &scene.solver_state
|
state := &scene.solver_state
|
||||||
sim_state := get_sim_state(scene)
|
sim_state := get_sim_state(scene)
|
||||||
if id in state.immediate_engines {
|
h, ok := immediate_container_find_or_add(&state.immediate_engines, state.simulation_frame, id)
|
||||||
engine := &state.immediate_engines[id]
|
|
||||||
if engine.last_ref != state.simulation_frame {
|
if ok {
|
||||||
engine.last_ref = state.simulation_frame
|
update_engine_from_config(sim_state, get_engine(sim_state, h^), config)
|
||||||
state.num_referenced_engines += 1
|
|
||||||
}
|
|
||||||
handle = engine.handle
|
|
||||||
update_engine_from_config(sim_state, get_engine(sim_state, handle), config)
|
|
||||||
} else {
|
} else {
|
||||||
state.num_referenced_engines += 1
|
h^ = add_engine(sim_state, config)
|
||||||
handle = add_engine(sim_state, config)
|
|
||||||
state.immediate_engines[id] = {
|
|
||||||
handle = handle,
|
|
||||||
last_ref = state.simulation_frame,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
handle = h^
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prune_immediate :: proc(scene: ^Scene) {
|
prune_immediate :: proc(scene: ^Scene) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
prune_immediate_bodies(scene)
|
|
||||||
prune_immediate_suspension_constraints(scene)
|
|
||||||
prune_immediate_engines(scene)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Generic version
|
sim_state := get_sim_state(scene)
|
||||||
prune_immediate_bodies :: proc(scene: ^Scene) {
|
|
||||||
state := &scene.solver_state
|
state := &scene.solver_state
|
||||||
if int(state.num_referenced_bodies) == len(state.immedate_bodies) {
|
removed_bodies := immediate_container_prune(&state.immediate_bodies, state.simulation_frame)
|
||||||
return
|
removed_wheels := immediate_container_prune(
|
||||||
|
&state.immediate_suspension_constraints,
|
||||||
|
state.simulation_frame,
|
||||||
|
)
|
||||||
|
removed_engines := immediate_container_prune(&state.immediate_engines, state.simulation_frame)
|
||||||
|
for handle in removed_bodies {
|
||||||
|
remove_body(sim_state, handle)
|
||||||
}
|
}
|
||||||
|
for handle in removed_wheels {
|
||||||
num_unreferenced_bodies := len(state.immedate_bodies) - int(state.num_referenced_bodies)
|
remove_suspension_constraint(sim_state, handle)
|
||||||
assert(num_unreferenced_bodies >= 0)
|
|
||||||
|
|
||||||
bodies_to_remove := make([]u32, num_unreferenced_bodies, context.temp_allocator)
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
for k, &v in state.immedate_bodies {
|
|
||||||
if v.last_ref != state.simulation_frame {
|
|
||||||
bodies_to_remove[i] = k
|
|
||||||
i += 1
|
|
||||||
}
|
}
|
||||||
}
|
for handle in removed_engines {
|
||||||
|
remove_engine(sim_state, handle)
|
||||||
assert(i == len(bodies_to_remove))
|
|
||||||
|
|
||||||
for k in bodies_to_remove {
|
|
||||||
handle := state.immedate_bodies[k].handle
|
|
||||||
delete_key(&state.immedate_bodies, k)
|
|
||||||
remove_body(get_sim_state(scene), handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prune_immediate_suspension_constraints :: proc(scene: ^Scene) {
|
|
||||||
state := &scene.solver_state
|
|
||||||
if int(state.num_referenced_suspension_constraints) ==
|
|
||||||
len(state.immediate_suspension_constraints) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
num_unreferenced_constraints :=
|
|
||||||
len(state.immediate_suspension_constraints) -
|
|
||||||
int(state.num_referenced_suspension_constraints)
|
|
||||||
assert(num_unreferenced_constraints >= 0)
|
|
||||||
|
|
||||||
constraints_to_remove := make([]u32, num_unreferenced_constraints, context.temp_allocator)
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
for k, &v in state.immediate_suspension_constraints {
|
|
||||||
if v.last_ref != state.simulation_frame {
|
|
||||||
constraints_to_remove[i] = k
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(i == len(constraints_to_remove))
|
|
||||||
|
|
||||||
for k in constraints_to_remove {
|
|
||||||
handle := state.immediate_suspension_constraints[k].handle
|
|
||||||
delete_key(&state.immediate_suspension_constraints, k)
|
|
||||||
remove_suspension_constraint(get_sim_state(scene), handle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prune_immediate_engines :: proc(scene: ^Scene) {
|
|
||||||
state := &scene.solver_state
|
|
||||||
if int(state.num_referenced_engines) == len(state.immediate_engines) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
num_unreferenced_engines := len(state.immediate_engines) - int(state.num_referenced_engines)
|
|
||||||
assert(num_unreferenced_engines >= 0)
|
|
||||||
|
|
||||||
engines_to_remove := make([]u32, num_unreferenced_engines, context.temp_allocator)
|
|
||||||
|
|
||||||
i := 0
|
|
||||||
for k, &v in state.immediate_engines {
|
|
||||||
if v.last_ref != state.simulation_frame {
|
|
||||||
engines_to_remove[i] = k
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(i == len(engines_to_remove))
|
|
||||||
|
|
||||||
for k in engines_to_remove {
|
|
||||||
handle := state.immediate_engines[k].handle
|
|
||||||
delete_key(&state.immediate_engines, k)
|
|
||||||
remove_engine(get_sim_state(scene), handle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,46 +35,27 @@ Solver_State :: struct {
|
|||||||
simulation_frame: u32,
|
simulation_frame: u32,
|
||||||
|
|
||||||
// Number of immediate bodies referenced this frame
|
// Number of immediate bodies referenced this frame
|
||||||
num_referenced_bodies: i32,
|
immediate_bodies: Immediate_Container(Body_Handle),
|
||||||
num_referenced_suspension_constraints: i32,
|
immediate_suspension_constraints: Immediate_Container(Suspension_Constraint_Handle),
|
||||||
num_referenced_engines: i32,
|
immediate_engines: Immediate_Container(Engine_Handle),
|
||||||
immedate_bodies: map[u32]Immedate_State(Body_Handle),
|
|
||||||
immediate_suspension_constraints: map[u32]Immedate_State(Suspension_Constraint_Handle),
|
|
||||||
immediate_engines: map[u32]Immedate_State(Engine_Handle),
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_map :: proc(dst, src: $T/^map[$K]$V) {
|
|
||||||
clear(dst)
|
|
||||||
reserve_map(dst, len(src))
|
|
||||||
|
|
||||||
for k, v in src {
|
|
||||||
dst[k] = v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_solver_state :: proc(dst, src: ^Solver_State) {
|
copy_solver_state :: proc(dst, src: ^Solver_State) {
|
||||||
dst.accumulated_time = src.accumulated_time
|
dst.accumulated_time = src.accumulated_time
|
||||||
dst.simulation_frame = src.simulation_frame
|
dst.simulation_frame = src.simulation_frame
|
||||||
|
|
||||||
dst.num_referenced_bodies = src.num_referenced_bodies
|
immediate_container_copy(&dst.immediate_bodies, &src.immediate_bodies)
|
||||||
dst.num_referenced_suspension_constraints = src.num_referenced_suspension_constraints
|
immediate_container_copy(
|
||||||
dst.num_referenced_engines = src.num_referenced_engines
|
&dst.immediate_suspension_constraints,
|
||||||
|
&src.immediate_suspension_constraints,
|
||||||
copy_map(&dst.immedate_bodies, &src.immedate_bodies)
|
)
|
||||||
copy_map(&dst.immediate_suspension_constraints, &src.immediate_suspension_constraints)
|
immediate_container_copy(&dst.immediate_engines, &src.immediate_engines)
|
||||||
copy_map(&dst.immediate_engines, &src.immediate_engines)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_solver_state :: proc(state: ^Solver_State) {
|
destroy_solver_state :: proc(state: ^Solver_State) {
|
||||||
delete(state.immedate_bodies)
|
immediate_container_destroy(&state.immediate_bodies)
|
||||||
delete(state.immediate_suspension_constraints)
|
immediate_container_destroy(&state.immediate_suspension_constraints)
|
||||||
delete(state.immediate_engines)
|
immediate_container_destroy(&state.immediate_engines)
|
||||||
}
|
|
||||||
|
|
||||||
Immedate_State :: struct($T: typeid) {
|
|
||||||
handle: T,
|
|
||||||
// When was this referenced last time (frame number)
|
|
||||||
last_ref: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MAX_STEPS :: 10
|
MAX_STEPS :: 10
|
||||||
@ -253,9 +234,9 @@ simulate :: proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.simulation_frame += 1
|
state.simulation_frame += 1
|
||||||
state.num_referenced_bodies = 0
|
state.immediate_bodies.num_items = 0
|
||||||
state.num_referenced_suspension_constraints = 0
|
state.immediate_suspension_constraints.num_items = 0
|
||||||
state.num_referenced_engines = 0
|
state.immediate_engines.num_items = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBAL_PLANE :: collision.Plane {
|
GLOBAL_PLANE :: collision.Plane {
|
||||||
|
@ -241,8 +241,7 @@ Style :: struct {
|
|||||||
|
|
||||||
Context :: struct {
|
Context :: struct {
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
text_width: proc(font: Font, font_size: i32, str: string) -> i32,
|
text_size: proc(font: Font, font_size: i32, str: string) -> [2]i32,
|
||||||
text_height: proc(font: Font, font_size: i32) -> i32,
|
|
||||||
draw_frame: proc(ctx: ^Context, rect: Rect, colorid: Color_Type),
|
draw_frame: proc(ctx: ^Context, rect: Rect, colorid: Color_Type),
|
||||||
/* core state */
|
/* core state */
|
||||||
default_style: Style,
|
default_style: Style,
|
||||||
@ -304,6 +303,7 @@ unclipped_rect := Rect{0, 0, 0x1000000, 0x1000000}
|
|||||||
default_style := Style {
|
default_style := Style {
|
||||||
font = nil,
|
font = nil,
|
||||||
size = {68, 10},
|
size = {68, 10},
|
||||||
|
font_size = 16,
|
||||||
padding = 5,
|
padding = 5,
|
||||||
spacing = 4,
|
spacing = 4,
|
||||||
indent = 24,
|
indent = 24,
|
||||||
@ -402,8 +402,7 @@ init :: proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
begin :: proc(ctx: ^Context) {
|
begin :: proc(ctx: ^Context) {
|
||||||
assert(ctx.text_width != nil, "ctx.text_width is not set")
|
assert(ctx.text_size != nil, "ctx.text_size is not set")
|
||||||
assert(ctx.text_height != nil, "ctx.text_height is not set")
|
|
||||||
ctx.command_list.idx = 0
|
ctx.command_list.idx = 0
|
||||||
ctx.root_list.idx = 0
|
ctx.root_list.idx = 0
|
||||||
ctx.line_segments_num = 0
|
ctx.line_segments_num = 0
|
||||||
@ -792,12 +791,8 @@ draw_text :: proc(
|
|||||||
pos: Vec2,
|
pos: Vec2,
|
||||||
color: Color,
|
color: Color,
|
||||||
) {
|
) {
|
||||||
rect := Rect {
|
text_size := ctx.text_size(font, font_size, str)
|
||||||
pos.x,
|
rect := Rect{pos.x, pos.y, text_size.x, text_size.y}
|
||||||
pos.y,
|
|
||||||
ctx.text_width(font, font_size, str),
|
|
||||||
ctx.text_height(font, font_size),
|
|
||||||
}
|
|
||||||
clipped := check_clip(ctx, rect)
|
clipped := check_clip(ctx, rect)
|
||||||
switch clipped {
|
switch clipped {
|
||||||
case .NONE: // okay
|
case .NONE: // okay
|
||||||
@ -1049,13 +1044,13 @@ draw_control_text :: proc(
|
|||||||
pos: Vec2
|
pos: Vec2
|
||||||
font := get_style(ctx).font
|
font := get_style(ctx).font
|
||||||
font_size := get_style(ctx).font_size
|
font_size := get_style(ctx).font_size
|
||||||
tw := ctx.text_width(font, font_size, str)
|
ts := ctx.text_size(font, font_size, str)
|
||||||
push_clip_rect(ctx, rect)
|
push_clip_rect(ctx, rect)
|
||||||
pos.y = rect.y + (rect.h - ctx.text_height(font, font_size)) / 2
|
pos.y = rect.y + (rect.h - ts.y) / 2
|
||||||
if .ALIGN_CENTER in opt {
|
if .ALIGN_CENTER in opt {
|
||||||
pos.x = rect.x + (rect.w - tw) / 2
|
pos.x = rect.x + (rect.w - ts.x) / 2
|
||||||
} else if .ALIGN_RIGHT in opt {
|
} else if .ALIGN_RIGHT in opt {
|
||||||
pos.x = rect.x + rect.w - tw - get_style(ctx).padding
|
pos.x = rect.x + rect.w - ts.x - get_style(ctx).padding
|
||||||
} else {
|
} else {
|
||||||
pos.x = rect.x + get_style(ctx).padding
|
pos.x = rect.x + get_style(ctx).padding
|
||||||
}
|
}
|
||||||
@ -1109,7 +1104,7 @@ text :: proc(ctx: ^Context, text: string) {
|
|||||||
font_size := style.font_size
|
font_size := style.font_size
|
||||||
color := style.colors[.TEXT]
|
color := style.colors[.TEXT]
|
||||||
layout_begin_column(ctx)
|
layout_begin_column(ctx)
|
||||||
layout_row(ctx, {-1}, ctx.text_height(font, font_size))
|
layout_row(ctx, {-1}, ctx.text_size(font, font_size, text).y)
|
||||||
for len(text) > 0 {
|
for len(text) > 0 {
|
||||||
w: i32
|
w: i32
|
||||||
start: int
|
start: int
|
||||||
@ -1118,12 +1113,12 @@ text :: proc(ctx: ^Context, text: string) {
|
|||||||
for ch, i in text {
|
for ch, i in text {
|
||||||
if ch == ' ' || ch == '\n' {
|
if ch == ' ' || ch == '\n' {
|
||||||
word := text[start:i]
|
word := text[start:i]
|
||||||
w += ctx.text_width(font, font_size, word)
|
w += ctx.text_size(font, font_size, word).x
|
||||||
if w > r.w && start != 0 {
|
if w > r.w && start != 0 {
|
||||||
end = start
|
end = start
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
w += ctx.text_width(font, font_size, text[i:i + 1])
|
w += ctx.text_size(font, font_size, text[i:i + 1]).x
|
||||||
if ch == '\n' {
|
if ch == '\n' {
|
||||||
end = i + 1
|
end = i + 1
|
||||||
break
|
break
|
||||||
@ -1317,7 +1312,7 @@ textbox_raw :: proc(
|
|||||||
if ctx.mouse_pos.x <
|
if ctx.mouse_pos.x <
|
||||||
r.x +
|
r.x +
|
||||||
ctx.textbox_offset +
|
ctx.textbox_offset +
|
||||||
ctx.text_width(font, font_size, string(textbuf[:i])) {
|
ctx.text_size(font, font_size, string(textbuf[:i])).x {
|
||||||
idx = i
|
idx = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1336,10 +1331,11 @@ textbox_raw :: proc(
|
|||||||
if ctx.focus_id == id {
|
if ctx.focus_id == id {
|
||||||
text_color := style.colors[.TEXT]
|
text_color := style.colors[.TEXT]
|
||||||
sel_color := style.colors[.SELECTION_BG]
|
sel_color := style.colors[.SELECTION_BG]
|
||||||
textw := ctx.text_width(font, font_size, textstr)
|
text_size := ctx.text_size(font, font_size, textstr)
|
||||||
texth := ctx.text_height(font, font_size)
|
textw := text_size.x
|
||||||
headx := ctx.text_width(font, font_size, textstr[:ctx.textbox_state.selection[0]])
|
texth := text_size.y
|
||||||
tailx := ctx.text_width(font, font_size, textstr[:ctx.textbox_state.selection[1]])
|
headx := ctx.text_size(font, font_size, textstr[:ctx.textbox_state.selection[0]]).x
|
||||||
|
tailx := ctx.text_size(font, font_size, textstr[:ctx.textbox_state.selection[1]]).x
|
||||||
ofmin := max(get_style(ctx).padding - headx, r.w - textw - get_style(ctx).padding)
|
ofmin := max(get_style(ctx).padding - headx, r.w - textw - get_style(ctx).padding)
|
||||||
ofmax := min(r.w - headx - get_style(ctx).padding, get_style(ctx).padding)
|
ofmax := min(r.w - headx - get_style(ctx).padding, get_style(ctx).padding)
|
||||||
ctx.textbox_offset = clamp(ctx.textbox_offset, ofmin, ofmax)
|
ctx.textbox_offset = clamp(ctx.textbox_offset, ofmin, ofmax)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
import "core:math"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import rl "libs:raylib"
|
import rl "libs:raylib"
|
||||||
import "libs:raylib/rlgl"
|
import "libs:raylib/rlgl"
|
||||||
@ -16,7 +17,7 @@ rl_init :: proc() {
|
|||||||
rl.UnloadTexture(default_atlas_texture)
|
rl.UnloadTexture(default_atlas_texture)
|
||||||
default_atlas_texture = {}
|
default_atlas_texture = {}
|
||||||
|
|
||||||
image := rl.Image{
|
image := rl.Image {
|
||||||
data = &default_atlas_alpha,
|
data = &default_atlas_alpha,
|
||||||
width = DEFAULT_ATLAS_WIDTH,
|
width = DEFAULT_ATLAS_WIDTH,
|
||||||
height = DEFAULT_ATLAS_HEIGHT,
|
height = DEFAULT_ATLAS_HEIGHT,
|
||||||
@ -40,7 +41,7 @@ to_rl_rect :: proc(r: Rect) -> rl.Rectangle {
|
|||||||
return rl.Rectangle{x = f32(r.x), y = f32(r.y), width = f32(r.w), height = f32(r.h)}
|
return rl.Rectangle{x = f32(r.x), y = f32(r.y), width = f32(r.w), height = f32(r.h)}
|
||||||
}
|
}
|
||||||
|
|
||||||
rl_measure_text_2d :: #force_inline proc(font: Font, font_size: i32, text: string) -> rl.Vector2 {
|
rl_measure_text_2d :: #force_inline proc(font: Font, font_size: i32, text: string) -> [2]i32 {
|
||||||
font := (cast(^rl.Font)font)
|
font := (cast(^rl.Font)font)
|
||||||
size := rl.MeasureTextEx(
|
size := rl.MeasureTextEx(
|
||||||
font^ if font != nil else rl.GetFontDefault(),
|
font^ if font != nil else rl.GetFontDefault(),
|
||||||
@ -49,15 +50,7 @@ rl_measure_text_2d :: #force_inline proc(font: Font, font_size: i32, text: strin
|
|||||||
f32(font_size / (font.baseSize if font != nil else 10)),
|
f32(font_size / (font.baseSize if font != nil else 10)),
|
||||||
)
|
)
|
||||||
|
|
||||||
return size
|
return {i32(math.ceil(size.x)), i32(math.ceil(size.y))}
|
||||||
}
|
|
||||||
|
|
||||||
rl_measure_text_width :: proc(font: Font, font_size: i32, text: string) -> i32 {
|
|
||||||
return i32(rl_measure_text_2d(font, font_size, text).x)
|
|
||||||
}
|
|
||||||
|
|
||||||
rl_measure_text_height :: proc(font: Font, font_size: i32) -> i32 {
|
|
||||||
return i32(rl_measure_text_2d(font, font_size, "A").y)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rl_draw :: proc(ctx: ^Context) {
|
rl_draw :: proc(ctx: ^Context) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user