Many editor improvements

This commit is contained in:
sergeypdev 2025-01-04 00:06:55 +04:00
parent 686d034b06
commit aa0f945b0c
2 changed files with 152 additions and 20 deletions

View File

@ -15,6 +15,9 @@
package game package game
import "assets" import "assets"
import "core:c"
import "core:fmt"
import "core:log"
import "core:math" import "core:math"
import "core:math/linalg" import "core:math/linalg"
import rl "vendor:raylib" import rl "vendor:raylib"
@ -62,6 +65,7 @@ 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,
total_movement_world: rl.Vector3,
initial_point_pos: rl.Vector3, initial_point_pos: rl.Vector3,
} }
@ -218,17 +222,25 @@ update_editor :: proc() {
if is_point_selected() { if is_point_selected() {
if rl.IsKeyPressed(.X) { if rl.IsKeyPressed(.X) {
if len(es.point_selection) <= 1 {
for i in es.point_selection {
ordered_remove(&get_world().track.points, i)
}
} else {
#reverse for _, i in get_world().track.points { #reverse for _, i in get_world().track.points {
if i in es.point_selection { if i in es.point_selection {
ordered_remove(&get_world().track.points, i) ordered_remove(&get_world().track.points, i)
} }
} }
}
clear(&es.point_selection) clear(&es.point_selection)
} }
if rl.IsKeyPressed(.G) { if rl.IsKeyPressed(.G) {
es.track_edit_state = .Move es.track_edit_state = .Move
es.move_axis = .None es.move_axis = .None
es.total_movement_world = {}
// es.initial_point_pos = g_mem.track.points[es.selected_track_point] // es.initial_point_pos = g_mem.track.points[es.selected_track_point]
} }
} }
@ -297,6 +309,8 @@ update_editor :: proc() {
for k in es.point_selection { for k in es.point_selection {
get_world().track.points[k] += movement_world get_world().track.points[k] += movement_world
} }
es.total_movement_world += movement_world
} }
} }
} }
@ -380,6 +394,12 @@ draw :: proc() {
// road_uvs.allocator = context.temp_allocator // road_uvs.allocator = context.temp_allocator
// road_indices.allocator = context.temp_allocator // road_indices.allocator = context.temp_allocator
interpolated_points := calculate_spline_interpolated_points(
points[:],
context.temp_allocator,
)
{ {
// Debug draw spline road // Debug draw spline road
{ {
@ -388,11 +408,6 @@ draw :: proc() {
rlgl.Color3f(1, 0, 0) rlgl.Color3f(1, 0, 0)
interpolated_points := calculate_spline_interpolated_points(
points[:],
context.temp_allocator,
)
debug_draw_spline(interpolated_points) debug_draw_spline(interpolated_points)
debug_draw_spline_mesh(interpolated_points) debug_draw_spline_mesh(interpolated_points)
} }
@ -432,6 +447,18 @@ draw :: proc() {
if g_mem.editor { if g_mem.editor {
rl.DrawText("Editor", 5, 5, 8, rl.ORANGE) rl.DrawText("Editor", 5, 5, 8, rl.ORANGE)
switch g_mem.es.track_edit_state {
case .Select:
case .Move:
rl.DrawText(
fmt.ctprintf("%v %v", g_mem.es.move_axis, g_mem.es.total_movement_world),
5,
16,
8,
rl.ORANGE,
)
}
} }
} }
@ -441,8 +468,67 @@ draw :: proc() {
points := &get_world().track.points points := &get_world().track.points
points_len := len(points) points_len := len(points)
if points_len > 0 {
// Add point before first
{
tangent: rl.Vector3
if points_len > 1 {
tangent = linalg.normalize0(points[1] - points[0])
} else {
tangent = rl.Vector3{-1, 0, 0}
}
new_point_pos := points[0] - tangent * 4
if (spline_handle(
new_point_pos,
camera,
false,
rl.GuiIconName.ICON_TARGET_POINT,
)) {
inject_at(&get_world().track.points, 0, new_point_pos)
log.debugf("add point before 0")
}
}
// Add point after last
{
tangent: rl.Vector3
if points_len > 1 {
tangent = linalg.normalize0(points[points_len - 1] - points[points_len - 2])
} else {
tangent = rl.Vector3{-1, 0, 0}
}
new_point_pos := points[points_len - 1] + tangent * 4
if (spline_handle(
new_point_pos,
camera,
false,
rl.GuiIconName.ICON_TARGET_POINT,
)) {
inject_at(&get_world().track.points, points_len - 1 + 1, new_point_pos)
log.debugf("add point before 0")
}
}
}
selected_point := false selected_point := false
for i in 0 ..< points_len { for i in 0 ..< points_len {
if i < points_len - 1 {
t := (f32(i) + 0.5) / f32(points_len)
middle_pos := sample_spline(points[:], t)
if (spline_handle(middle_pos, camera, false, rl.GuiIconName.ICON_TARGET_POINT)) {
inject_at(&get_world().track.points, i + 1, middle_pos)
log.debugf("add point after %d", i)
}
}
if spline_handle(get_world().track.points[i], camera, es.point_selection[i]) { if spline_handle(get_world().track.points[i], camera, es.point_selection[i]) {
if !rl.IsKeyDown(.LEFT_CONTROL) { if !rl.IsKeyDown(.LEFT_CONTROL) {
clear(&g_mem.es.point_selection) clear(&g_mem.es.point_selection)
@ -485,6 +571,8 @@ spline_handle :: proc(
world_pos: rl.Vector3, world_pos: rl.Vector3,
camera: rl.Camera, camera: rl.Camera,
selected: bool, selected: bool,
icon := rl.GuiIconName.ICON_NONE,
size := f32(20),
) -> ( ) -> (
clicked: bool, clicked: bool,
) { ) {
@ -492,18 +580,28 @@ spline_handle :: proc(
return return
} }
pos := rl.GetWorldToScreen(world_pos, camera) pos := rl.GetWorldToScreen(world_pos, camera)
size := rl.Vector2{10, 10}
min, max := pos - size, pos + size min, max := pos - size, pos + size
mouse_pos := rl.GetMousePosition() mouse_pos := rl.GetMousePosition()
is_hover := is_hover :=
mouse_pos.x >= min.x && (mouse_pos.x >= min.x &&
mouse_pos.y >= min.y && mouse_pos.y >= min.y &&
mouse_pos.x <= max.x && mouse_pos.x <= max.x &&
mouse_pos.y <= max.y mouse_pos.y <= max.y)
rl.DrawRectangleV(pos, size, selected ? rl.BLUE : (is_hover ? rl.ORANGE : rl.WHITE))
rl.DrawCircleV(pos, size / 2, selected ? rl.BLUE : (is_hover ? rl.ORANGE : rl.WHITE))
if icon != .ICON_NONE {
rl.GuiDrawIcon(
icon,
c.int(pos.x) - 7,
c.int(pos.y) - 7,
1,
selected || is_hover ? rl.WHITE : rl.BLACK,
)
}
// rl.DrawRectangleV(pos, size, selected ? rl.BLUE : (is_hover ? rl.ORANGE : rl.WHITE))
return rl.IsMouseButtonPressed(.LEFT) && is_hover return rl.IsMouseButtonPressed(.LEFT) && is_hover
} }

View File

@ -1,5 +1,7 @@
package game package game
import "base:builtin"
import "core:math"
import lg "core:math/linalg" import lg "core:math/linalg"
import rl "vendor:raylib" import rl "vendor:raylib"
import "vendor:raylib/rlgl" import "vendor:raylib/rlgl"
@ -39,6 +41,39 @@ Interpolated_Point :: struct {
normal: rl.Vector3, normal: rl.Vector3,
} }
sample_spline :: proc(points: []rl.Vector3, t: f32) -> rl.Vector3 {
points_len := len(points)
if points_len >= 2 {
t_mul_len := math.saturate(t) * f32(len(points))
i := int(t_mul_len)
frac_t := t_mul_len - f32(i)
extended_start := points[0] + (points[0] - points[1])
extended_end := points[points_len - 1] + points[points_len - 1] - points[points_len - 2]
extended_end2 := extended_end + points[points_len - 1] - points[points_len - 2]
prev := i > 0 ? points[i - 1] : extended_start
current := points[i]
next := i < points_len - 1 ? points[i + 1] : extended_end
next2 := i < points_len - 2 ? points[i + 2] : extended_end2
a, b, c, d := catmull_rom_coefs(
prev,
current,
next,
next2,
CATMULL_ROM_ALPHA,
CATMULL_ROM_TENSION,
)
return catmull_rom(a, b, c, d, frac_t)
} else if len(points) == 1 {
return points[0]
}
return {}
}
calculate_spline_interpolated_points :: proc( calculate_spline_interpolated_points :: proc(
points: []rl.Vector3, points: []rl.Vector3,
allocator := context.allocator, allocator := context.allocator,
@ -47,7 +82,6 @@ calculate_spline_interpolated_points :: proc(
ctrl_rotations := calculate_spline_ctrl_rotations(points, context.temp_allocator) ctrl_rotations := calculate_spline_ctrl_rotations(points, context.temp_allocator)
if points_len >= 2 { if points_len >= 2 {
interpolated_points := make( interpolated_points := make(
[]Interpolated_Point, []Interpolated_Point,