Load convex from obj
This commit is contained in:
parent
196bafb401
commit
8cefc48049
@ -35,7 +35,7 @@ esac
|
|||||||
|
|
||||||
# Build the game.
|
# Build the game.
|
||||||
echo "Building game$DLL_EXT"
|
echo "Building game$DLL_EXT"
|
||||||
odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug -o:speed
|
odin build game -extra-linker-flags:"$EXTRA_LINKER_FLAGS" -define:RAYLIB_SHARED=true -define:TRACY_ENABLE=true -collection:libs=./libs -collection:common=./common -collection:game=./game -build-mode:dll -out:game_tmp$DLL_EXT -strict-style -vet -debug
|
||||||
|
|
||||||
# Need to use a temp file on Linux because it first writes an empty `game.so`, which the game will load before it is actually fully written.
|
# Need to use a temp file on Linux because it first writes an empty `game.so`, which the game will load before it is actually fully written.
|
||||||
mv game_tmp$DLL_EXT game$DLL_EXT
|
mv game_tmp$DLL_EXT game$DLL_EXT
|
||||||
|
@ -4,7 +4,11 @@ import "core:c"
|
|||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
import lg "core:math/linalg"
|
import lg "core:math/linalg"
|
||||||
|
import "core:os/os2"
|
||||||
|
import "core:strconv"
|
||||||
|
import "game:halfedge"
|
||||||
import "game:physics/bvh"
|
import "game:physics/bvh"
|
||||||
|
import "game:physics/collision"
|
||||||
import "libs:tracy"
|
import "libs:tracy"
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
@ -26,6 +30,10 @@ Loaded_BVH :: struct {
|
|||||||
modtime: c.long,
|
modtime: c.long,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loaded_Convex :: struct {
|
||||||
|
mesh: collision.Convex,
|
||||||
|
}
|
||||||
|
|
||||||
destroy_loaded_bvh :: proc(loaded_bvh: Loaded_BVH) {
|
destroy_loaded_bvh :: proc(loaded_bvh: Loaded_BVH) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
@ -163,6 +171,186 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
|||||||
return assetman.bvhs[path]
|
return assetman.bvhs[path]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_Convex) {
|
||||||
|
bytes, err := os2.read_entire_file(string(path), context.temp_allocator)
|
||||||
|
if err != nil {
|
||||||
|
log.errorf("error reading file %v %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Parse_Ctx :: struct {
|
||||||
|
bytes: []byte,
|
||||||
|
it: int,
|
||||||
|
line: int,
|
||||||
|
}
|
||||||
|
|
||||||
|
advance :: proc(ctx: ^Parse_Ctx, by: int = 1) -> bool {
|
||||||
|
ctx.it = min(ctx.it + by, len(ctx.bytes) + 1)
|
||||||
|
return ctx.it < len(ctx.bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
is_whitespace :: proc(b: byte) -> bool {
|
||||||
|
return b == ' ' || b == '\t' || b == '\r' || b == '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_line :: proc(ctx: ^Parse_Ctx) {
|
||||||
|
for ctx.it < len(ctx.bytes) && ctx.bytes[ctx.it] != '\n' {
|
||||||
|
advance(ctx) or_break
|
||||||
|
}
|
||||||
|
advance(ctx)
|
||||||
|
ctx.line += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_whitespase :: proc(ctx: ^Parse_Ctx) {
|
||||||
|
switch ctx.bytes[ctx.it] {
|
||||||
|
case ' ', '\t', '\r', '\n':
|
||||||
|
if ctx.bytes[ctx.it] == '\n' {
|
||||||
|
ctx.line += 1
|
||||||
|
}
|
||||||
|
advance(ctx) or_break
|
||||||
|
case '#':
|
||||||
|
skip_line(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge :: [2]u16
|
||||||
|
edges_map := make_map(map[Edge]halfedge.Edge_Index, context.temp_allocator)
|
||||||
|
|
||||||
|
edges := make_dynamic_array([dynamic]halfedge.Half_Edge, context.temp_allocator)
|
||||||
|
vertices := make_dynamic_array([dynamic]halfedge.Vertex, context.temp_allocator)
|
||||||
|
faces := make_dynamic_array([dynamic]halfedge.Face, context.temp_allocator)
|
||||||
|
center: rl.Vector3
|
||||||
|
|
||||||
|
// Parse obj file directly into halfedge data structure
|
||||||
|
{
|
||||||
|
ctx := Parse_Ctx {
|
||||||
|
bytes = bytes,
|
||||||
|
line = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
for ctx.it < len(ctx.bytes) {
|
||||||
|
skip_whitespase(&ctx)
|
||||||
|
switch ctx.bytes[ctx.it] {
|
||||||
|
case 'v':
|
||||||
|
// vertex
|
||||||
|
advance(&ctx) or_break
|
||||||
|
|
||||||
|
vertex: rl.Vector3
|
||||||
|
|
||||||
|
coord_idx := 0
|
||||||
|
for ctx.bytes[ctx.it] != '\n' {
|
||||||
|
skip_whitespase(&ctx)
|
||||||
|
s := string(ctx.bytes[ctx.it:])
|
||||||
|
coord_val, nr, ok := strconv.parse_f32_prefix(s)
|
||||||
|
if !ok {
|
||||||
|
log.errorf("failed to parse float at line %d", ctx.line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
advance(&ctx, nr) or_break
|
||||||
|
|
||||||
|
vertex[coord_idx] = coord_val
|
||||||
|
coord_idx += 1
|
||||||
|
}
|
||||||
|
append(&vertices, halfedge.Vertex{pos = vertex, edge = -1})
|
||||||
|
center += vertex
|
||||||
|
|
||||||
|
advance(&ctx)
|
||||||
|
ctx.line += 1
|
||||||
|
case 'f':
|
||||||
|
advance(&ctx) or_break
|
||||||
|
|
||||||
|
MAX_FACE_VERTS :: 10
|
||||||
|
|
||||||
|
indices_buf: [MAX_FACE_VERTS]u16
|
||||||
|
index_count := 0
|
||||||
|
|
||||||
|
for ctx.bytes[ctx.it] != '\n' {
|
||||||
|
skip_whitespase(&ctx)
|
||||||
|
index_f, nr, ok := strconv.parse_f32_prefix(string(ctx.bytes[ctx.it:]))
|
||||||
|
if !ok {
|
||||||
|
log.errorf("failed to parse index at line %d", ctx.line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
advance(&ctx, nr) or_break
|
||||||
|
index := u16(index_f) - 1
|
||||||
|
indices_buf[index_count] = u16(index)
|
||||||
|
index_count += 1
|
||||||
|
}
|
||||||
|
advance(&ctx)
|
||||||
|
ctx.line += 1
|
||||||
|
|
||||||
|
assert(index_count >= 3)
|
||||||
|
indices := indices_buf[:index_count]
|
||||||
|
|
||||||
|
append(&faces, halfedge.Face{})
|
||||||
|
face_idx := len(faces) - 1
|
||||||
|
face := &faces[face_idx]
|
||||||
|
|
||||||
|
first_edge_idx := len(edges)
|
||||||
|
|
||||||
|
face.edge = halfedge.Edge_Index(first_edge_idx)
|
||||||
|
|
||||||
|
plane: collision.Plane
|
||||||
|
{
|
||||||
|
i1, i2, i3 := indices[0], indices[1], indices[2]
|
||||||
|
v1, v2, v3 := vertices[i1].pos, vertices[i2].pos, vertices[i3].pos
|
||||||
|
|
||||||
|
collision.plane_from_point_normal(
|
||||||
|
v1,
|
||||||
|
lg.normalize0(lg.cross(v2 - v1, v3 - v1)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
face.normal = plane.normal
|
||||||
|
|
||||||
|
for index in indices[3:] {
|
||||||
|
assert(
|
||||||
|
abs(collision.signed_distance_plane(vertices[index].pos, plane)) < 0.00001,
|
||||||
|
"mesh has non planar faces",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0 ..< len(indices) {
|
||||||
|
edge_idx := halfedge.Edge_Index(first_edge_idx + i)
|
||||||
|
prev_edge_relative := i == 0 ? len(indices) - 1 : i - 1
|
||||||
|
next_edge_relative := (i + 1) % len(indices)
|
||||||
|
i1, i2 := indices[i], indices[next_edge_relative]
|
||||||
|
v1 := &vertices[i1]
|
||||||
|
|
||||||
|
if v1.edge == -1 {
|
||||||
|
v1.edge = edge_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
edge := halfedge.Half_Edge {
|
||||||
|
origin = halfedge.Vertex_Index(i1),
|
||||||
|
face = halfedge.Face_Index(face_idx),
|
||||||
|
twin = -1,
|
||||||
|
next = halfedge.Edge_Index(first_edge_idx + next_edge_relative),
|
||||||
|
prev = halfedge.Edge_Index(first_edge_idx + prev_edge_relative),
|
||||||
|
}
|
||||||
|
|
||||||
|
stable_index := [2]u16{min(i1, i2), max(i1, i2)}
|
||||||
|
if stable_index in edges_map {
|
||||||
|
edge.twin = edges_map[stable_index]
|
||||||
|
twin_edge := &edges[edge.twin]
|
||||||
|
assert(twin_edge.twin == -1, "edge has more than two faces attached")
|
||||||
|
twin_edge.twin = edge_idx
|
||||||
|
} else {
|
||||||
|
edges_map[stable_index] = edge_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
append(&edges, edge)
|
||||||
|
}
|
||||||
|
case:
|
||||||
|
skip_line(&ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
center /= f32(len(vertices))
|
||||||
|
|
||||||
|
return {mesh = {vertices = vertices[:], edges = edges[:], faces = faces[:], center = center}}
|
||||||
|
}
|
||||||
|
|
||||||
shutdown :: proc(assetman: ^Asset_Manager) {
|
shutdown :: proc(assetman: ^Asset_Manager) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
physics.Body_Config {
|
physics.Body_Config {
|
||||||
initial_pos = {0, -0.5, 0},
|
initial_pos = {0, -0.5, 0},
|
||||||
initial_rot = linalg.QUATERNIONF32_IDENTITY,
|
initial_rot = linalg.QUATERNIONF32_IDENTITY,
|
||||||
shape = physics.Shape_Box{size = {100, 1, 100}},
|
shape = physics.Shape_Box{size = {1000, 1, 1000}},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if true {
|
if false {
|
||||||
|
|
||||||
for x in -3 ..< 3 {
|
for x in -3 ..< 3 {
|
||||||
for y in -3 ..< 3 {
|
for y in -3 ..< 3 {
|
||||||
@ -370,7 +370,7 @@ update_runtime_world :: proc(runtime_world: ^Runtime_World, dt: f32) {
|
|||||||
drive_wheels := []physics.Suspension_Constraint_Handle{wheel_rl, wheel_rr}
|
drive_wheels := []physics.Suspension_Constraint_Handle{wheel_rl, wheel_rr}
|
||||||
turn_wheels := []physics.Suspension_Constraint_Handle{wheel_fl, wheel_fr}
|
turn_wheels := []physics.Suspension_Constraint_Handle{wheel_fl, wheel_fr}
|
||||||
|
|
||||||
DRIVE_IMPULSE :: 5
|
DRIVE_IMPULSE :: 10
|
||||||
BRAKE_IMPULSE :: 20
|
BRAKE_IMPULSE :: 20
|
||||||
TURN_ANGLE :: -f32(30) * math.RAD_PER_DEG
|
TURN_ANGLE :: -f32(30) * math.RAD_PER_DEG
|
||||||
|
|
||||||
@ -552,6 +552,10 @@ draw :: proc() {
|
|||||||
rad = 0.5,
|
rad = 0.5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
car_convex := assets.get_convex(&g_mem.assetman, "assets/car_convex.obj")
|
||||||
|
|
||||||
|
halfedge.debug_draw_mesh_wires(car_convex.mesh, rl.RED)
|
||||||
|
|
||||||
box1_convex := collision.box_to_convex(box1, context.temp_allocator)
|
box1_convex := collision.box_to_convex(box1, context.temp_allocator)
|
||||||
box2_convex := collision.box_to_convex(box2, context.temp_allocator)
|
box2_convex := collision.box_to_convex(box2, context.temp_allocator)
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
)
|
)
|
||||||
contact_pair.lambda_tangent[point_idx] = lambda_tangent
|
contact_pair.lambda_tangent[point_idx] = lambda_tangent
|
||||||
|
|
||||||
STATIC_FRICTION :: 0.5
|
STATIC_FRICTION :: 0.3
|
||||||
if ok_tangent &&
|
if ok_tangent &&
|
||||||
lambda_tangent < lambda_norm * STATIC_FRICTION {
|
lambda_tangent < lambda_norm * STATIC_FRICTION {
|
||||||
apply_correction(body, corr1_tangent, p1)
|
apply_correction(body, corr1_tangent, p1)
|
||||||
@ -302,7 +302,7 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
v_normal := lg.dot(manifold.normal, v) * manifold.normal
|
v_normal := lg.dot(manifold.normal, v) * manifold.normal
|
||||||
v_tangent := v - v_normal
|
v_tangent := v - v_normal
|
||||||
|
|
||||||
DYNAMIC_FRICTION :: 0.4
|
DYNAMIC_FRICTION :: 0.1
|
||||||
v_tangent_len := lg.length(v_tangent)
|
v_tangent_len := lg.length(v_tangent)
|
||||||
if v_tangent_len > 0 {
|
if v_tangent_len > 0 {
|
||||||
delta_v :=
|
delta_v :=
|
||||||
@ -312,9 +312,11 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
v_tangent_len,
|
v_tangent_len,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
delta_v_norm := lg.normalize0(delta_v)
|
||||||
|
|
||||||
w1, w2 :=
|
w1, w2 :=
|
||||||
get_body_inverse_mass(body1, manifold.normal, p1),
|
get_body_inverse_mass(body1, delta_v_norm, p1),
|
||||||
get_body_inverse_mass(body2, manifold.normal, p2)
|
get_body_inverse_mass(body2, delta_v_norm, p2)
|
||||||
|
|
||||||
w := w1 + w2
|
w := w1 + w2
|
||||||
if w != 0 {
|
if w != 0 {
|
||||||
@ -323,8 +325,8 @@ simulate_step :: proc(scene: ^Scene, config: Solver_Config) {
|
|||||||
body1.v += p * body1.inv_mass
|
body1.v += p * body1.inv_mass
|
||||||
body2.v -= p * body2.inv_mass
|
body2.v -= p * body2.inv_mass
|
||||||
|
|
||||||
body1.w += multiply_inv_mass(body1, lg.cross(r1, p))
|
body1.w += multiply_inv_intertia(body1, lg.cross(r1, p))
|
||||||
body2.w -= multiply_inv_mass(body2, lg.cross(r2, p))
|
body2.w -= multiply_inv_intertia(body2, lg.cross(r2, p))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -523,7 +525,7 @@ apply_constraint_correction_unilateral :: proc(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
multiply_inv_mass :: proc(body: Body_Ptr, vec: rl.Vector3) -> (result: rl.Vector3) {
|
multiply_inv_intertia :: proc(body: Body_Ptr, vec: rl.Vector3) -> (result: rl.Vector3) {
|
||||||
q := body.q
|
q := body.q
|
||||||
inv_q := lg.quaternion_normalize0(lg.quaternion_inverse(q))
|
inv_q := lg.quaternion_normalize0(lg.quaternion_inverse(q))
|
||||||
|
|
||||||
|
BIN
src_assets/car_convex.blend
Normal file
BIN
src_assets/car_convex.blend
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user