Implement blender scene export script, add support for asset based level geom instancing
This commit is contained in:
parent
5f4fa12040
commit
a81e81c52c
1
.gitignore
vendored
1
.gitignore
vendored
@ -19,3 +19,4 @@ game_web/
|
|||||||
.venv
|
.venv
|
||||||
build/
|
build/
|
||||||
bin/
|
bin/
|
||||||
|
.direnv/
|
||||||
|
1
.tool-versions
Normal file
1
.tool-versions
Normal file
@ -0,0 +1 @@
|
|||||||
|
python 3.11.13
|
BIN
assets/blender/ice_cream_truck_blend/Split.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/ice_cream_truck_blend/Split.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/test_level_blend/NurbsPath.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/test_level_blend/NurbsPath.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/test_level_blend/Plane.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/test_level_blend/Plane.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
50
assets/blender/test_level_blend/Scene.scn
Normal file
50
assets/blender/test_level_blend/Scene.scn
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Bakery.glb"
|
||||||
|
:pos (0.000000 12.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/test_level_blend/Plane.glb"
|
||||||
|
:pos (0.000000 0.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (22.469545 22.469545 22.469545))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Fire_Station.glb"
|
||||||
|
:pos (9.000000 13.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
|
||||||
|
:pos (-8.000000 11.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
|
||||||
|
:pos (-16.000000 11.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Gas_Station_Shop.glb"
|
||||||
|
:pos (-15.559284 0.259853 1.609015)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Green_House.glb"
|
||||||
|
:pos (14.000000 -7.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Hotel.glb"
|
||||||
|
:pos (8.000000 -18.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/test_level_blend/NurbsPath.glb"
|
||||||
|
:pos (0.000000 0.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
||||||
|
(inst
|
||||||
|
:model "assets/blender/ice_cream_truck_blend/Split.glb"
|
||||||
|
:pos (-1.000000 3.000000 0.000000)
|
||||||
|
:rot (0.000000 0.000000 0.000000 1.000000)
|
||||||
|
:scale (1.000000 1.000000 1.000000))
|
BIN
assets/blender/testblend_blend/Bakery.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/testblend_blend/Bakery.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/testblend_blend/Fire_Station.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/testblend_blend/Fire_Station.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/testblend_blend/Gas_Station_Shop.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/testblend_blend/Gas_Station_Shop.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/testblend_blend/Green_House.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/testblend_blend/Green_House.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/blender/testblend_blend/Hotel.glb
(Stored with Git LFS)
Normal file
BIN
assets/blender/testblend_blend/Hotel.glb
(Stored with Git LFS)
Normal file
Binary file not shown.
87
blender/batch_export.py
Normal file
87
blender/batch_export.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import bpy
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
# Ensure blend file is saved
|
||||||
|
blend_filepath = bpy.data.filepath
|
||||||
|
if not blend_filepath:
|
||||||
|
raise Exception("Blend file is not saved")
|
||||||
|
|
||||||
|
assert bpy.context.scene is not None
|
||||||
|
|
||||||
|
def clean_blend_path(blend_path: str) -> str:
|
||||||
|
return os.path.join(os.path.dirname(blend_path), bpy.path.clean_name(os.path.basename(blend_path)))
|
||||||
|
|
||||||
|
# Directory setup
|
||||||
|
abs_filepath = bpy.path.abspath(blend_filepath)
|
||||||
|
src_assets_path = os.path.dirname(abs_filepath)
|
||||||
|
project_path = os.path.dirname(src_assets_path)
|
||||||
|
assets_path = os.path.join(project_path, "assets")
|
||||||
|
rel_blend_path = os.path.relpath(abs_filepath, src_assets_path)
|
||||||
|
clean_rel_path = clean_blend_path(rel_blend_path)
|
||||||
|
scene_name = bpy.context.scene.name
|
||||||
|
instance_output_path = os.path.join(assets_path, "blender", clean_rel_path, f"{scene_name}.scn")
|
||||||
|
|
||||||
|
# Utility: returns path to store the glb
|
||||||
|
def get_model_export_path(obj: bpy.types.Object) -> str:
|
||||||
|
if obj.instance_type == 'COLLECTION' and obj.instance_collection:
|
||||||
|
lib_path = obj.instance_collection.library.filepath
|
||||||
|
collection_name = bpy.path.clean_name(obj.instance_collection.name)
|
||||||
|
rel_lib_path = os.path.relpath(bpy.path.abspath(lib_path), src_assets_path)
|
||||||
|
rel_lib_path = clean_blend_path(rel_lib_path)
|
||||||
|
return os.path.join("blender", rel_lib_path, f"{collection_name}.glb")
|
||||||
|
else:
|
||||||
|
obj_name = bpy.path.clean_name(obj.name)
|
||||||
|
return os.path.join("blender", clean_rel_path, f"{obj_name}.glb")
|
||||||
|
|
||||||
|
# Utility: writes an object to glb
|
||||||
|
def export_object_as_glb(obj: bpy.types.Object, export_path: str):
|
||||||
|
full_export_path = os.path.join(assets_path, export_path)
|
||||||
|
pathlib.Path(os.path.dirname(full_export_path)).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
obj.select_set(True)
|
||||||
|
|
||||||
|
assert bpy.context.view_layer is not None
|
||||||
|
bpy.context.view_layer.objects.active = obj
|
||||||
|
|
||||||
|
bpy.ops.export_scene.gltf(filepath=full_export_path, use_selection=True, export_apply=True)
|
||||||
|
print(f"Exported {obj.name} -> {export_path}")
|
||||||
|
|
||||||
|
# Collect all visible, non-hidden objects in the scene
|
||||||
|
visible_objects = [
|
||||||
|
obj for obj in bpy.context.scene.objects
|
||||||
|
if obj.visible_get()
|
||||||
|
]
|
||||||
|
|
||||||
|
exported = set()
|
||||||
|
instances = []
|
||||||
|
|
||||||
|
for obj in visible_objects:
|
||||||
|
model_path = get_model_export_path(obj)
|
||||||
|
|
||||||
|
if model_path not in exported:
|
||||||
|
export_object_as_glb(obj, model_path)
|
||||||
|
exported.add(model_path)
|
||||||
|
|
||||||
|
loc = obj.location
|
||||||
|
rot = obj.rotation_quaternion
|
||||||
|
scale = obj.scale
|
||||||
|
instance_sexpr = (
|
||||||
|
'(inst'
|
||||||
|
f'\n\t:model "assets/{model_path}"'
|
||||||
|
f'\n\t:pos ({loc.x:.6f} {loc.y:.6f} {loc.z:.6f}) '
|
||||||
|
f'\n\t:rot ({rot.x:.6f} {rot.y:.6f} {rot.z:.6f} {rot.w:.6f}) '
|
||||||
|
f'\n\t:scale ({scale.x:.6f} {scale.y:.6f} {scale.z:.6f}))'
|
||||||
|
)
|
||||||
|
instances.append(instance_sexpr)
|
||||||
|
|
||||||
|
# Save instances to scene file
|
||||||
|
instance_output_abs = os.path.join(project_path, instance_output_path)
|
||||||
|
pathlib.Path(os.path.dirname(instance_output_abs)).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(instance_output_abs, "w", encoding="utf-8") as f:
|
||||||
|
for line in instances:
|
||||||
|
f.write(line + "\n")
|
||||||
|
|
||||||
|
print(f"Written instances to {instance_output_abs}")
|
@ -15,11 +15,24 @@ import "libs:tracy"
|
|||||||
|
|
||||||
_ :: math
|
_ :: math
|
||||||
|
|
||||||
|
@(private = "file")
|
||||||
|
g_assetman_instance: ^Asset_Manager
|
||||||
|
|
||||||
|
init :: proc(assetman: ^Asset_Manager) {
|
||||||
|
g_assetman_instance = assetman
|
||||||
|
}
|
||||||
|
|
||||||
|
manager :: #force_inline proc() -> ^Asset_Manager {
|
||||||
|
return g_assetman_instance
|
||||||
|
}
|
||||||
|
|
||||||
Loaded_BVH :: struct {
|
Loaded_BVH :: struct {
|
||||||
// AABB of all bvhs
|
// AABB of all bvhs
|
||||||
aabb: bvh.AABB,
|
aabb: bvh.AABB,
|
||||||
// BVH for each mesh in a model
|
// BVH for each mesh in a model
|
||||||
bvhs: []bvh.BVH,
|
bvh: bvh.BVH,
|
||||||
|
vertices: []rl.Vector3,
|
||||||
|
indices: []u16,
|
||||||
modtime: physfs.sint64,
|
modtime: physfs.sint64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,13 +47,12 @@ Loaded_Curve_2D :: struct {
|
|||||||
points: [][2]f32,
|
points: [][2]f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_loaded_bvh :: proc(loaded_bvh: Loaded_BVH) {
|
destroy_loaded_bvh :: proc(loaded_bvh: ^Loaded_BVH) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
for &mesh_bvh in loaded_bvh.bvhs {
|
bvh.destroy_bvh(&loaded_bvh.bvh)
|
||||||
bvh.destroy_bvh(&mesh_bvh)
|
delete(loaded_bvh.vertices)
|
||||||
}
|
delete(loaded_bvh.indices)
|
||||||
delete(loaded_bvh.bvhs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Curve_2D :: [][2]f32
|
Curve_2D :: [][2]f32
|
||||||
@ -361,7 +373,7 @@ get_music :: proc(assetman: ^Asset_Manager, path: cstring) -> rl.Music {
|
|||||||
|
|
||||||
null_bvhs: []bvh.BVH
|
null_bvhs: []bvh.BVH
|
||||||
|
|
||||||
get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> (Loaded_BVH, bool) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
loaded_bvh, ok := assetman.bvhs[path]
|
loaded_bvh, ok := assetman.bvhs[path]
|
||||||
@ -370,22 +382,39 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
|||||||
should_recreate := reloaded || !ok
|
should_recreate := reloaded || !ok
|
||||||
|
|
||||||
if ok && should_recreate {
|
if ok && should_recreate {
|
||||||
destroy_loaded_bvh(loaded_bvh)
|
destroy_loaded_bvh(&loaded_bvh)
|
||||||
delete_key(&assetman.bvhs, path)
|
delete_key(&assetman.bvhs, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_recreate {
|
if should_recreate {
|
||||||
new_bvhs := make([]bvh.BVH, model.meshCount)
|
vert_count := 0
|
||||||
|
indices_count := 0
|
||||||
outer_aabb := bvh.AABB {
|
|
||||||
min = max(f32),
|
|
||||||
max = min(f32),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 0 ..< model.meshCount {
|
for i in 0 ..< model.meshCount {
|
||||||
mesh := model.meshes[i]
|
mesh := model.meshes[i]
|
||||||
vertices := (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount]
|
vert_count += int(mesh.vertexCount)
|
||||||
indices := mesh.indices[:mesh.triangleCount * 3]
|
indices_count += int(mesh.triangleCount * 3)
|
||||||
|
}
|
||||||
|
vertices := make([]bvh.Vec3, vert_count)
|
||||||
|
indices := make([]u16, indices_count)
|
||||||
|
|
||||||
|
vert_count = 0
|
||||||
|
indices_count = 0
|
||||||
|
for i in 0 ..< model.meshCount {
|
||||||
|
mesh := model.meshes[i]
|
||||||
|
mesh_vertices := (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount]
|
||||||
|
mesh_indices := mesh.indices[:mesh.triangleCount * 3]
|
||||||
|
|
||||||
|
copy(vertices[vert_count:], mesh_vertices)
|
||||||
|
|
||||||
|
for j in 0 ..< len(mesh_indices) {
|
||||||
|
indices[indices_count + j] = u16(vert_count) + mesh_indices[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
vert_count += len(mesh_vertices)
|
||||||
|
indices_count += len(mesh_indices)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
mesh_bvh := bvh.build_bvh_from_mesh(
|
mesh_bvh := bvh.build_bvh_from_mesh(
|
||||||
{vertices = vertices, indices = indices},
|
{vertices = vertices, indices = indices},
|
||||||
@ -393,20 +422,17 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> Loaded_BVH {
|
|||||||
)
|
)
|
||||||
|
|
||||||
root_aabb := mesh_bvh.bvh.nodes[0].aabb
|
root_aabb := mesh_bvh.bvh.nodes[0].aabb
|
||||||
outer_aabb.min = lg.min(outer_aabb.min, root_aabb.min)
|
|
||||||
outer_aabb.max = lg.max(outer_aabb.max, root_aabb.max)
|
|
||||||
|
|
||||||
new_bvhs[i] = mesh_bvh.bvh
|
|
||||||
}
|
|
||||||
|
|
||||||
assetman.bvhs[path] = Loaded_BVH {
|
assetman.bvhs[path] = Loaded_BVH {
|
||||||
aabb = outer_aabb,
|
aabb = root_aabb,
|
||||||
bvhs = new_bvhs,
|
bvh = mesh_bvh.bvh,
|
||||||
|
vertices = vertices,
|
||||||
|
indices = indices,
|
||||||
modtime = modtime,
|
modtime = modtime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return assetman.bvhs[path]
|
return assetman.bvhs[path], should_recreate
|
||||||
}
|
}
|
||||||
|
|
||||||
get_curve_1d :: proc(assetman: ^Asset_Manager, path: cstring) -> (curve: []f32) {
|
get_curve_1d :: proc(assetman: ^Asset_Manager, path: cstring) -> (curve: []f32) {
|
||||||
@ -827,8 +853,8 @@ shutdown :: proc(assetman: ^Asset_Manager) {
|
|||||||
assetcache_destroy(&assetman.curves_1d)
|
assetcache_destroy(&assetman.curves_1d)
|
||||||
assetcache_destroy(&assetman.curves_2d)
|
assetcache_destroy(&assetman.curves_2d)
|
||||||
|
|
||||||
for _, loaded_bvh in assetman.bvhs {
|
for _, &loaded_bvh in assetman.bvhs {
|
||||||
destroy_loaded_bvh(loaded_bvh)
|
destroy_loaded_bvh(&loaded_bvh)
|
||||||
}
|
}
|
||||||
delete(assetman.bvhs)
|
delete(assetman.bvhs)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import "core:log"
|
|||||||
import "core:math"
|
import "core:math"
|
||||||
import "core:math/linalg"
|
import "core:math/linalg"
|
||||||
import "game:physics"
|
import "game:physics"
|
||||||
import "game:physics/bvh"
|
|
||||||
import "game:render"
|
import "game:render"
|
||||||
import rl "libs:raylib"
|
import rl "libs:raylib"
|
||||||
import "libs:raylib/rlgl"
|
import "libs:raylib/rlgl"
|
||||||
@ -59,6 +58,9 @@ World :: struct {
|
|||||||
engine_handle: physics.Engine_Handle,
|
engine_handle: physics.Engine_Handle,
|
||||||
debug_state: Debug_Draw_State,
|
debug_state: Debug_Draw_State,
|
||||||
}
|
}
|
||||||
|
world_init :: proc(world: ^World) {
|
||||||
|
physics.scene_init(&world.physics_scene, &g_mem.assetman)
|
||||||
|
}
|
||||||
copy_world :: proc(dst, src: ^World) {
|
copy_world :: proc(dst, src: ^World) {
|
||||||
copy_track(&dst.track, &src.track)
|
copy_track(&dst.track, &src.track)
|
||||||
physics.copy_physics_scene(&dst.physics_scene, &src.physics_scene)
|
physics.copy_physics_scene(&dst.physics_scene, &src.physics_scene)
|
||||||
@ -71,7 +73,7 @@ copy_world :: proc(dst, src: ^World) {
|
|||||||
}
|
}
|
||||||
destroy_world :: proc(world: ^World) {
|
destroy_world :: proc(world: ^World) {
|
||||||
destroy_track(&world.track)
|
destroy_track(&world.track)
|
||||||
physics.destroy_physics_scene(&world.physics_scene)
|
physics.scene_destroy(&world.physics_scene)
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime_World :: struct {
|
Runtime_World :: struct {
|
||||||
@ -91,6 +93,7 @@ Runtime_World :: struct {
|
|||||||
runtime_world_init :: proc(runtime_world: ^Runtime_World, num_snapshots: int = 2) {
|
runtime_world_init :: proc(runtime_world: ^Runtime_World, num_snapshots: int = 2) {
|
||||||
runtime_world.world_snapshots = make([]World, num_snapshots)
|
runtime_world.world_snapshots = make([]World, num_snapshots)
|
||||||
world := runtime_world_current_world(runtime_world)
|
world := runtime_world_current_world(runtime_world)
|
||||||
|
physics.scene_init(&world.physics_scene, &g_mem.assetman)
|
||||||
world.debug_state.show_menu = true
|
world.debug_state.show_menu = true
|
||||||
world.debug_state.draw_physics_scene = true
|
world.debug_state.draw_physics_scene = true
|
||||||
}
|
}
|
||||||
@ -125,7 +128,6 @@ Game_Memory :: struct {
|
|||||||
name_container: name.Container,
|
name_container: name.Container,
|
||||||
assetman: assets.Asset_Manager,
|
assetman: assets.Asset_Manager,
|
||||||
runtime_world: Runtime_World,
|
runtime_world: Runtime_World,
|
||||||
fluid_scene: Fluid_Scene,
|
|
||||||
es: Editor_State,
|
es: Editor_State,
|
||||||
ui_context: ui.Context,
|
ui_context: ui.Context,
|
||||||
default_font: rl.Font,
|
default_font: rl.Font,
|
||||||
@ -169,6 +171,8 @@ world_stack_init :: proc(stack: ^World_Stack, num_snapshots: int, allocator := c
|
|||||||
assert(num_snapshots > 0)
|
assert(num_snapshots > 0)
|
||||||
stack.worlds = make([]World, num_snapshots, allocator)
|
stack.worlds = make([]World, num_snapshots, allocator)
|
||||||
world_stack_push(stack)
|
world_stack_push(stack)
|
||||||
|
|
||||||
|
world_init(world_stack_current(stack))
|
||||||
}
|
}
|
||||||
|
|
||||||
world_stack_destroy :: proc(stack: ^World_Stack, allocator := context.allocator) {
|
world_stack_destroy :: proc(stack: ^World_Stack, allocator := context.allocator) {
|
||||||
@ -695,6 +699,20 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
wheel.turn_angle = TURN_ANGLE * turn_vel_correction * turn_input
|
wheel.turn_angle = TURN_ANGLE * turn_vel_correction * turn_input
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
physics.immediate_level_geom(
|
||||||
|
&world.physics_scene,
|
||||||
|
u32(name.from_string("level_geom_from_asset")),
|
||||||
|
{
|
||||||
|
position = physics.Vec3{5, 0, 0},
|
||||||
|
rotation = linalg.QUATERNIONF32_IDENTITY,
|
||||||
|
source = physics.Level_Geometry_Asset(
|
||||||
|
"assets/blender/test_level_blend/NurbsPath.glb",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb")
|
level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb")
|
||||||
|
|
||||||
@ -712,9 +730,11 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
{
|
{
|
||||||
position = pos,
|
position = pos,
|
||||||
rotation = rotation,
|
rotation = rotation,
|
||||||
|
source = physics.Level_Geometry_Mesh {
|
||||||
vertices = (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount],
|
vertices = (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount],
|
||||||
indices = mesh.indices[:mesh.triangleCount * 3],
|
indices = mesh.indices[:mesh.triangleCount * 3],
|
||||||
},
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -734,9 +754,11 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) {
|
|||||||
#hash("track", "fnv32a"),
|
#hash("track", "fnv32a"),
|
||||||
{
|
{
|
||||||
rotation = linalg.QUATERNIONF32_IDENTITY,
|
rotation = linalg.QUATERNIONF32_IDENTITY,
|
||||||
|
source = physics.Level_Geometry_Mesh {
|
||||||
vertices = track_verts,
|
vertices = track_verts,
|
||||||
indices = track_inds,
|
indices = track_inds,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,33 +995,33 @@ update :: proc() {
|
|||||||
dt := rl.GetFrameTime()
|
dt := rl.GetFrameTime()
|
||||||
|
|
||||||
// Debug BVH traversal
|
// Debug BVH traversal
|
||||||
mesh_bvh := assets.get_bvh(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
|
// mesh_bvh := assets.get_bvh(&g_mem.assetman, "assets/toyota_corolla_ae86_trueno.glb")
|
||||||
|
|
||||||
if rl.IsKeyDown(.LEFT_SHIFT) {
|
// if rl.IsKeyDown(.LEFT_SHIFT) {
|
||||||
if g_mem.preview_bvh >= 0 && g_mem.preview_bvh < len(mesh_bvh.bvhs) {
|
// if g_mem.preview_bvh >= 0 && g_mem.preview_bvh < len(mesh_bvh.bvhs) {
|
||||||
b := mesh_bvh.bvhs[g_mem.preview_bvh]
|
// b := mesh_bvh.bvhs[g_mem.preview_bvh]
|
||||||
node := &b.nodes[g_mem.preview_node]
|
// node := &b.nodes[g_mem.preview_node]
|
||||||
|
|
||||||
if !bvh.is_leaf_node(node^) {
|
// if !bvh.is_leaf_node(node^) {
|
||||||
if rl.IsKeyPressed(.LEFT_BRACKET) {
|
// if rl.IsKeyPressed(.LEFT_BRACKET) {
|
||||||
g_mem.preview_node = int(node.child_or_prim_start)
|
// g_mem.preview_node = int(node.child_or_prim_start)
|
||||||
} else if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
// } else if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
||||||
g_mem.preview_node = int(node.child_or_prim_start + 1)
|
// g_mem.preview_node = int(node.child_or_prim_start + 1)
|
||||||
} else if rl.IsKeyPressed(.P) {
|
// } else if rl.IsKeyPressed(.P) {
|
||||||
g_mem.preview_node = 0
|
// g_mem.preview_node = 0
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if rl.IsKeyPressed(.LEFT_BRACKET) {
|
// if rl.IsKeyPressed(.LEFT_BRACKET) {
|
||||||
g_mem.preview_bvh -= 1
|
// g_mem.preview_bvh -= 1
|
||||||
g_mem.preview_node = 0
|
// g_mem.preview_node = 0
|
||||||
}
|
// }
|
||||||
if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
// if rl.IsKeyPressed(.RIGHT_BRACKET) {
|
||||||
g_mem.preview_bvh += 1
|
// g_mem.preview_bvh += 1
|
||||||
g_mem.preview_node = 0
|
// g_mem.preview_node = 0
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if rl.IsKeyPressed(.SPACE) {
|
if rl.IsKeyPressed(.SPACE) {
|
||||||
g_mem.physics_pause = !g_mem.physics_pause
|
g_mem.physics_pause = !g_mem.physics_pause
|
||||||
@ -1429,9 +1451,9 @@ game_init :: proc() {
|
|||||||
name.init(&g_mem.name_container)
|
name.init(&g_mem.name_container)
|
||||||
name.setup_global_container(&g_mem.name_container)
|
name.setup_global_container(&g_mem.name_container)
|
||||||
init_physifs_raylib_callbacks()
|
init_physifs_raylib_callbacks()
|
||||||
assets.assetman_init(&g_mem.assetman)
|
|
||||||
|
|
||||||
fluid_scene_init(&g_mem.fluid_scene)
|
assets.assetman_init(&g_mem.assetman)
|
||||||
|
assets.init(&g_mem.assetman)
|
||||||
|
|
||||||
editor_state_init(&g_mem.es, 100)
|
editor_state_init(&g_mem.es, 100)
|
||||||
runtime_world_init(&g_mem.runtime_world, DEV_BUILD ? 100 : 2)
|
runtime_world_init(&g_mem.runtime_world, DEV_BUILD ? 100 : 2)
|
||||||
@ -1454,7 +1476,6 @@ game_shutdown :: proc() {
|
|||||||
editor_state_destroy(&g_mem.es)
|
editor_state_destroy(&g_mem.es)
|
||||||
delete(g_mem.es.point_selection)
|
delete(g_mem.es.point_selection)
|
||||||
runtime_world_destroy(&g_mem.runtime_world)
|
runtime_world_destroy(&g_mem.runtime_world)
|
||||||
fluid_scene_destroy(&g_mem.fluid_scene)
|
|
||||||
|
|
||||||
free(g_mem)
|
free(g_mem)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package physics
|
package physics
|
||||||
|
|
||||||
|
import "bvh"
|
||||||
import "collision"
|
import "collision"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
@ -299,13 +300,14 @@ body_get_convex_shapes_world :: proc(
|
|||||||
|
|
||||||
level_geom_get_convex_shape :: proc(
|
level_geom_get_convex_shape :: proc(
|
||||||
sim_state: ^Sim_State,
|
sim_state: ^Sim_State,
|
||||||
level_geom: Level_Geom_Ptr,
|
level_geom_handle: Level_Geom_Handle,
|
||||||
tri_idx: int,
|
tri_idx: int,
|
||||||
allocator := context.temp_allocator,
|
allocator := context.temp_allocator,
|
||||||
) -> (
|
) -> (
|
||||||
mesh: collision.Convex,
|
mesh: collision.Convex,
|
||||||
) {
|
) {
|
||||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
level_geom := get_level_geom(sim_state, level_geom_handle)
|
||||||
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
return collision.double_sided_triangle_to_convex(
|
return collision.double_sided_triangle_to_convex(
|
||||||
get_transformed_triangle(vertices, indices, tri_idx, level_geom.x, level_geom.q),
|
get_transformed_triangle(vertices, indices, tri_idx, level_geom.x, level_geom.q),
|
||||||
allocator,
|
allocator,
|
||||||
@ -396,3 +398,8 @@ rpm_to_angular_velocity :: proc(rpm: f32) -> f32 {
|
|||||||
angular_velocity_to_rpm :: proc(w: f32) -> f32 {
|
angular_velocity_to_rpm :: proc(w: f32) -> f32 {
|
||||||
return (w / (2.0 * math.PI)) * 60.0
|
return (w / (2.0 * math.PI)) * 60.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use one format everywhere...
|
||||||
|
bvh_aabb_to_phys_aabb :: proc(aabb: bvh.AABB) -> AABB {
|
||||||
|
return AABB{center = (aabb.max + aabb.min) * 0.5, extent = (aabb.max - aabb.min) * 0.5}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,8 @@ import "bvh"
|
|||||||
import "collision"
|
import "collision"
|
||||||
import "common:name"
|
import "common:name"
|
||||||
import lg "core:math/linalg"
|
import lg "core:math/linalg"
|
||||||
|
import "core:strings"
|
||||||
|
import "game:assets"
|
||||||
import "game:container/spanpool"
|
import "game:container/spanpool"
|
||||||
import "libs:tracy"
|
import "libs:tracy"
|
||||||
|
|
||||||
@ -78,6 +80,7 @@ contact_container_copy :: proc(dst: ^Contact_Container, src: Contact_Container)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Sim_State :: struct {
|
Sim_State :: struct {
|
||||||
|
scene: ^Scene,
|
||||||
bodies: #soa[dynamic]Body,
|
bodies: #soa[dynamic]Body,
|
||||||
suspension_constraints: #soa[dynamic]Suspension_Constraint,
|
suspension_constraints: #soa[dynamic]Suspension_Constraint,
|
||||||
engines: [dynamic]Engine,
|
engines: [dynamic]Engine,
|
||||||
@ -120,6 +123,7 @@ Sim_State :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Scene :: struct {
|
Scene :: struct {
|
||||||
|
assetman: ^assets.Asset_Manager,
|
||||||
simulation_states: [2]Sim_State,
|
simulation_states: [2]Sim_State,
|
||||||
simulation_state_index: i32,
|
simulation_state_index: i32,
|
||||||
solver_state: Solver_State,
|
solver_state: Solver_State,
|
||||||
@ -130,6 +134,7 @@ copy_sim_state :: proc(dst: ^Sim_State, src: ^Sim_State) {
|
|||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
convex_container_reconcile(&src.convex_container)
|
convex_container_reconcile(&src.convex_container)
|
||||||
|
|
||||||
|
dst.scene = src.scene
|
||||||
dst.num_bodies = src.num_bodies
|
dst.num_bodies = src.num_bodies
|
||||||
dst.first_free_body_plus_one = src.first_free_body_plus_one
|
dst.first_free_body_plus_one = src.first_free_body_plus_one
|
||||||
dst.first_free_suspension_constraint_plus_one = src.first_free_suspension_constraint_plus_one
|
dst.first_free_suspension_constraint_plus_one = src.first_free_suspension_constraint_plus_one
|
||||||
@ -168,12 +173,12 @@ copy_sim_state :: proc(dst: ^Sim_State, src: ^Sim_State) {
|
|||||||
copy_physics_scene :: proc(dst, src: ^Scene) {
|
copy_physics_scene :: proc(dst, src: ^Scene) {
|
||||||
tracy.Zone()
|
tracy.Zone()
|
||||||
|
|
||||||
|
dst.assetman = src.assetman
|
||||||
dst.simulation_state_index = src.simulation_state_index
|
dst.simulation_state_index = src.simulation_state_index
|
||||||
src_sim_state := get_sim_state(src)
|
src_sim_state := get_sim_state(src)
|
||||||
dst_sim_state := get_sim_state(dst)
|
dst_sim_state := get_sim_state(dst)
|
||||||
|
|
||||||
copy_sim_state(dst_sim_state, src_sim_state)
|
copy_sim_state(dst_sim_state, src_sim_state)
|
||||||
|
|
||||||
copy_solver_state(&dst.solver_state, &src.solver_state)
|
copy_solver_state(&dst.solver_state, &src.solver_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,11 +396,24 @@ BLAS_Handle :: struct {
|
|||||||
primitives: spanpool.Handle,
|
primitives: spanpool.Handle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Level_Geom_Source_Local :: struct {
|
||||||
|
geometry: Geometry_Handle,
|
||||||
|
blas: BLAS_Handle,
|
||||||
|
}
|
||||||
|
|
||||||
|
Level_Geom_Source_Asset :: struct {
|
||||||
|
assetpath: name.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
Level_Geom_Source :: union #no_nil {
|
||||||
|
Level_Geom_Source_Local,
|
||||||
|
Level_Geom_Source_Asset,
|
||||||
|
}
|
||||||
|
|
||||||
Level_Geom :: struct {
|
Level_Geom :: struct {
|
||||||
alive: bool,
|
alive: bool,
|
||||||
aabb: AABB,
|
aabb: AABB,
|
||||||
geometry: Geometry_Handle,
|
source: Level_Geom_Source,
|
||||||
blas: BLAS_Handle,
|
|
||||||
x: Vec3,
|
x: Vec3,
|
||||||
q: Quat,
|
q: Quat,
|
||||||
next_plus_one: i32,
|
next_plus_one: i32,
|
||||||
@ -584,11 +602,23 @@ Engine_Config :: struct {
|
|||||||
axle: Drive_Axle_Config,
|
axle: Drive_Axle_Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Level_Geometry_Asset :: distinct string
|
||||||
|
|
||||||
|
Level_Geometry_Mesh :: struct {
|
||||||
|
vertices: []Vec3,
|
||||||
|
indices: []u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either runtime mesh or asset reference which will be fetched from assetmanager
|
||||||
|
Level_Geometry_Source :: union #no_nil {
|
||||||
|
Level_Geometry_Mesh,
|
||||||
|
Level_Geometry_Asset,
|
||||||
|
}
|
||||||
|
|
||||||
Level_Geom_Config :: struct {
|
Level_Geom_Config :: struct {
|
||||||
position: Vec3,
|
position: Vec3,
|
||||||
rotation: Quat,
|
rotation: Quat,
|
||||||
vertices: []Vec3,
|
source: Level_Geometry_Source,
|
||||||
indices: []u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_body_params_from_config :: proc(
|
calculate_body_params_from_config :: proc(
|
||||||
@ -919,20 +949,50 @@ get_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> Leve
|
|||||||
|
|
||||||
get_level_geom_data :: proc(
|
get_level_geom_data :: proc(
|
||||||
sim_state: ^Sim_State,
|
sim_state: ^Sim_State,
|
||||||
handle: Geometry_Handle,
|
handle: Level_Geom_Handle,
|
||||||
) -> (
|
) -> (
|
||||||
vertices: []Vec3,
|
vertices: []Vec3,
|
||||||
indices: []u16,
|
indices: []u16,
|
||||||
) {
|
) {
|
||||||
vertices = spanpool.resolve_slice(&sim_state.geometry_vertices_pool, handle.vertices)
|
level_geom := get_level_geom(sim_state, handle)
|
||||||
indices = spanpool.resolve_slice(&sim_state.geometry_indices_pool, handle.indices)
|
|
||||||
|
switch s in level_geom.source {
|
||||||
|
case Level_Geom_Source_Local:
|
||||||
|
vertices = spanpool.resolve_slice(&sim_state.geometry_vertices_pool, s.geometry.vertices)
|
||||||
|
indices = spanpool.resolve_slice(&sim_state.geometry_indices_pool, s.geometry.indices)
|
||||||
|
case Level_Geom_Source_Asset:
|
||||||
|
loaded_bvh, reloaded := assets.get_bvh(
|
||||||
|
sim_state.scene.assetman,
|
||||||
|
strings.unsafe_string_to_cstring(name.to_string(s.assetpath)),
|
||||||
|
)
|
||||||
|
if reloaded {
|
||||||
|
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb)
|
||||||
|
}
|
||||||
|
vertices = loaded_bvh.vertices
|
||||||
|
indices = loaded_bvh.indices
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
get_level_geom_blas :: proc(sim_state: ^Sim_State, handle: BLAS_Handle) -> (bvh: bvh.BVH) {
|
get_level_geom_blas :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> (bvh: bvh.BVH) {
|
||||||
bvh.nodes = spanpool.resolve_slice(&sim_state.blas_nodes_pool, handle.nodes)
|
level_geom := get_level_geom(sim_state, handle)
|
||||||
bvh.primitives = spanpool.resolve_slice(&sim_state.blas_primitives_pool, handle.primitives)
|
switch s in level_geom.source {
|
||||||
|
case Level_Geom_Source_Local:
|
||||||
|
bvh.nodes = spanpool.resolve_slice(&sim_state.blas_nodes_pool, s.blas.nodes)
|
||||||
|
bvh.primitives = spanpool.resolve_slice(&sim_state.blas_primitives_pool, s.blas.primitives)
|
||||||
bvh.nodes_used = i32(len(bvh.nodes))
|
bvh.nodes_used = i32(len(bvh.nodes))
|
||||||
|
case Level_Geom_Source_Asset:
|
||||||
|
loaded_bvh, reloaded := assets.get_bvh(
|
||||||
|
sim_state.scene.assetman,
|
||||||
|
strings.unsafe_string_to_cstring(name.to_string(s.assetpath)),
|
||||||
|
)
|
||||||
|
if reloaded {
|
||||||
|
level_geom.aabb = bvh_aabb_to_phys_aabb(loaded_bvh.aabb)
|
||||||
|
}
|
||||||
|
|
||||||
|
bvh = loaded_bvh.bvh
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,32 +1005,36 @@ update_level_geom_from_config :: proc(
|
|||||||
level_geom.q = config.rotation
|
level_geom.q = config.rotation
|
||||||
|
|
||||||
// TODO: figure out if asset changed and rebuild only then
|
// TODO: figure out if asset changed and rebuild only then
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Level_Geom_Handle {
|
add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Level_Geom_Handle {
|
||||||
assert(len(config.vertices) > 0)
|
|
||||||
assert(len(config.vertices) <= int(max(u16)))
|
|
||||||
|
|
||||||
sim_state.num_level_geoms += 1
|
sim_state.num_level_geoms += 1
|
||||||
|
|
||||||
level_geom: Level_Geom
|
level_geom: Level_Geom
|
||||||
level_geom.alive = true
|
level_geom.alive = true
|
||||||
update_level_geom_from_config(sim_state, &level_geom, config)
|
update_level_geom_from_config(sim_state, &level_geom, config)
|
||||||
|
|
||||||
|
switch s in config.source {
|
||||||
|
case Level_Geometry_Mesh:
|
||||||
|
assert(len(s.vertices) > 0)
|
||||||
|
assert(len(s.vertices) <= int(max(u16)))
|
||||||
blas :=
|
blas :=
|
||||||
bvh.build_bvh_from_mesh(bvh.Mesh{vertices = config.vertices, indices = config.indices}, context.temp_allocator).bvh
|
bvh.build_bvh_from_mesh(bvh.Mesh{vertices = s.vertices, indices = s.indices}, context.temp_allocator).bvh
|
||||||
|
|
||||||
level_geom.blas.nodes = spanpool.allocate_elems(
|
source: Level_Geom_Source_Local
|
||||||
|
source.blas.nodes = spanpool.allocate_elems(
|
||||||
&sim_state.blas_nodes_pool,
|
&sim_state.blas_nodes_pool,
|
||||||
..blas.nodes[:blas.nodes_used],
|
..blas.nodes[:blas.nodes_used],
|
||||||
)
|
)
|
||||||
level_geom.blas.primitives = spanpool.allocate_elems(
|
source.blas.primitives = spanpool.allocate_elems(
|
||||||
&sim_state.blas_primitives_pool,
|
&sim_state.blas_primitives_pool,
|
||||||
..blas.primitives,
|
..blas.primitives,
|
||||||
)
|
)
|
||||||
|
|
||||||
aabb_min, aabb_max: Vec3 = max(f32), min(f32)
|
aabb_min, aabb_max: Vec3 = max(f32), min(f32)
|
||||||
for v in config.vertices {
|
for v in s.vertices {
|
||||||
aabb_min = lg.min(aabb_min, v)
|
aabb_min = lg.min(aabb_min, v)
|
||||||
aabb_max = lg.max(aabb_max, v)
|
aabb_max = lg.max(aabb_max, v)
|
||||||
}
|
}
|
||||||
@ -978,19 +1042,37 @@ add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Leve
|
|||||||
level_geom.aabb.center = (aabb_max + aabb_min) * 0.5
|
level_geom.aabb.center = (aabb_max + aabb_min) * 0.5
|
||||||
level_geom.aabb.extent = (aabb_max - aabb_min) * 0.5
|
level_geom.aabb.extent = (aabb_max - aabb_min) * 0.5
|
||||||
|
|
||||||
if spanpool.is_handle_valid(&sim_state.geometry_vertices_pool, level_geom.geometry.vertices) {
|
// if spanpool.is_handle_valid(
|
||||||
spanpool.free(&sim_state.geometry_vertices_pool, level_geom.geometry.vertices)
|
// &sim_state.geometry_vertices_pool,
|
||||||
spanpool.free(&sim_state.geometry_indices_pool, level_geom.geometry.indices)
|
// level_geom.geometry.vertices,
|
||||||
|
// ) {
|
||||||
|
// spanpool.free(&sim_state.geometry_vertices_pool, level_geom.geometry.vertices)
|
||||||
|
// spanpool.free(&sim_state.geometry_indices_pool, level_geom.geometry.indices)
|
||||||
|
// }
|
||||||
|
|
||||||
|
source.geometry.vertices = spanpool.allocate_elems(
|
||||||
|
&sim_state.geometry_vertices_pool,
|
||||||
|
..s.vertices,
|
||||||
|
)
|
||||||
|
source.geometry.indices = spanpool.allocate_elems(
|
||||||
|
&sim_state.geometry_indices_pool,
|
||||||
|
..s.indices,
|
||||||
|
)
|
||||||
|
level_geom.source = source
|
||||||
|
case Level_Geometry_Asset:
|
||||||
|
level_geom.source = Level_Geom_Source_Asset {
|
||||||
|
assetpath = name.from_string(string(s)),
|
||||||
}
|
}
|
||||||
|
|
||||||
level_geom.geometry.vertices = spanpool.allocate_elems(
|
bvh, _ := assets.get_bvh(
|
||||||
&sim_state.geometry_vertices_pool,
|
sim_state.scene.assetman,
|
||||||
..config.vertices,
|
strings.unsafe_string_to_cstring(string(s)),
|
||||||
)
|
|
||||||
level_geom.geometry.indices = spanpool.allocate_elems(
|
|
||||||
&sim_state.geometry_indices_pool,
|
|
||||||
..config.indices,
|
|
||||||
)
|
)
|
||||||
|
level_geom.aabb = AABB {
|
||||||
|
center = (bvh.aabb.max + bvh.aabb.min) * 0.5,
|
||||||
|
extent = (bvh.aabb.max - bvh.aabb.min) * 0.5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if sim_state.first_free_level_geom_plus_one > 0 {
|
if sim_state.first_free_level_geom_plus_one > 0 {
|
||||||
index := sim_state.first_free_level_geom_plus_one
|
index := sim_state.first_free_level_geom_plus_one
|
||||||
@ -1009,11 +1091,15 @@ add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Leve
|
|||||||
remove_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) {
|
remove_level_geom :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) {
|
||||||
level_geom := get_level_geom(sim_state, handle)
|
level_geom := get_level_geom(sim_state, handle)
|
||||||
|
|
||||||
spanpool.free(&sim_state.geometry_vertices_pool, level_geom.geometry.vertices)
|
switch s in level_geom.source {
|
||||||
spanpool.free(&sim_state.geometry_indices_pool, level_geom.geometry.indices)
|
case Level_Geom_Source_Local:
|
||||||
|
spanpool.free(&sim_state.geometry_vertices_pool, s.geometry.vertices)
|
||||||
|
spanpool.free(&sim_state.geometry_indices_pool, s.geometry.indices)
|
||||||
|
|
||||||
spanpool.free(&sim_state.blas_nodes_pool, level_geom.blas.nodes)
|
spanpool.free(&sim_state.blas_nodes_pool, s.blas.nodes)
|
||||||
spanpool.free(&sim_state.blas_primitives_pool, level_geom.blas.primitives)
|
spanpool.free(&sim_state.blas_primitives_pool, s.blas.primitives)
|
||||||
|
case Level_Geom_Source_Asset:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_get_first_free_body :: proc(sim_state: ^Sim_State) -> i32 {
|
_get_first_free_body :: proc(sim_state: ^Sim_State) -> i32 {
|
||||||
@ -1039,7 +1125,14 @@ destry_sim_state :: proc(sim_state: ^Sim_State) {
|
|||||||
dynamic_tlas_destroy(&sim_state.dynamic_tlas)
|
dynamic_tlas_destroy(&sim_state.dynamic_tlas)
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy_physics_scene :: proc(scene: ^Scene) {
|
scene_init :: proc(scene: ^Scene, assetman: ^assets.Asset_Manager) {
|
||||||
|
scene.assetman = assetman
|
||||||
|
for &sim_state in scene.simulation_states {
|
||||||
|
sim_state.scene = scene
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_destroy :: proc(scene: ^Scene) {
|
||||||
for &sim_state in scene.simulation_states {
|
for &sim_state in scene.simulation_states {
|
||||||
destry_sim_state(&sim_state)
|
destry_sim_state(&sim_state)
|
||||||
}
|
}
|
||||||
|
@ -200,9 +200,8 @@ raycasts_level :: proc(
|
|||||||
level_geom_handle := index_to_level_geom(
|
level_geom_handle := index_to_level_geom(
|
||||||
int(tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j]),
|
int(tlas.bvh_tree.primitives[leaf_node.child_or_prim_start + j]),
|
||||||
)
|
)
|
||||||
level_geom := get_level_geom(sim_state, level_geom_handle)
|
blas := get_level_geom_blas(sim_state, level_geom_handle)
|
||||||
blas := get_level_geom_blas(sim_state, level_geom.blas)
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
|
||||||
|
|
||||||
// TODO: transform ray into blas space and back
|
// TODO: transform ray into blas space and back
|
||||||
|
|
||||||
@ -388,7 +387,7 @@ remove_invalid_contacts :: proc(
|
|||||||
|
|
||||||
if !should_remove {
|
if !should_remove {
|
||||||
tri_idx := int(contact.local_tri_idx)
|
tri_idx := int(contact.local_tri_idx)
|
||||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
should_remove |= tri_idx * 3 >= len(indices)
|
should_remove |= tri_idx * 3 >= len(indices)
|
||||||
|
|
||||||
if !should_remove {
|
if !should_remove {
|
||||||
@ -547,11 +546,8 @@ find_new_contacts :: proc(
|
|||||||
)
|
)
|
||||||
level_geom := get_level_geom(sim_state, level_geom_handle)
|
level_geom := get_level_geom(sim_state, level_geom_handle)
|
||||||
if level_geom.alive {
|
if level_geom.alive {
|
||||||
blas := get_level_geom_blas(sim_state, level_geom.blas)
|
blas := get_level_geom_blas(sim_state, level_geom_handle)
|
||||||
vertices, indices := get_level_geom_data(
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
sim_state,
|
|
||||||
level_geom.geometry,
|
|
||||||
)
|
|
||||||
|
|
||||||
blas_it := bvh.iterator_intersect_leaf_aabb(&blas, body_aabb)
|
blas_it := bvh.iterator_intersect_leaf_aabb(&blas, body_aabb)
|
||||||
for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
|
for blas_leaf_node in bvh.iterator_intersect_leaf_next(&blas_it) {
|
||||||
@ -808,8 +804,7 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) {
|
|||||||
)
|
)
|
||||||
case .Body_vs_Level:
|
case .Body_vs_Level:
|
||||||
level_geom_handle := Level_Geom_Handle(contact.b)
|
level_geom_handle := Level_Geom_Handle(contact.b)
|
||||||
level_geom := get_level_geom(sim_state, level_geom_handle)
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
|
||||||
tri := get_triangle(vertices, indices, int(contact.local_tri_idx))
|
tri := get_triangle(vertices, indices, int(contact.local_tri_idx))
|
||||||
|
|
||||||
m2 = collision.double_sided_triangle_to_convex(tri, context.temp_allocator)
|
m2 = collision.double_sided_triangle_to_convex(tri, context.temp_allocator)
|
||||||
|
9
src_assets/blender_assets.cats.txt
Normal file
9
src_assets/blender_assets.cats.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# This is an Asset Catalog Definition file for Blender.
|
||||||
|
#
|
||||||
|
# Empty lines and lines starting with `#` will be ignored.
|
||||||
|
# The first non-ignored line should be the version indicator.
|
||||||
|
# Other lines are of the format "UUID:catalog/path/for/assets:simple catalog name"
|
||||||
|
|
||||||
|
VERSION 1
|
||||||
|
|
||||||
|
65988f84-4b5f-463a-bcae-896eba4975c5:Buildings:Buildings
|
9
src_assets/blender_assets.cats.txt~
Normal file
9
src_assets/blender_assets.cats.txt~
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# This is an Asset Catalog Definition file for Blender.
|
||||||
|
#
|
||||||
|
# Empty lines and lines starting with `#` will be ignored.
|
||||||
|
# The first non-ignored line should be the version indicator.
|
||||||
|
# Other lines are of the format "UUID:catalog/path/for/assets:simple catalog name"
|
||||||
|
|
||||||
|
VERSION 1
|
||||||
|
|
||||||
|
65988f84-4b5f-463a-bcae-896eba4975c5:Buildings:Buildings
|
BIN
src_assets/ice_cream_truck.blend
(Stored with Git LFS)
BIN
src_assets/ice_cream_truck.blend
(Stored with Git LFS)
Binary file not shown.
BIN
src_assets/ice_cream_truck.blend1
(Stored with Git LFS)
BIN
src_assets/ice_cream_truck.blend1
(Stored with Git LFS)
Binary file not shown.
BIN
src_assets/test_level.blend
(Stored with Git LFS)
Normal file
BIN
src_assets/test_level.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src_assets/test_level.blend1
(Stored with Git LFS)
Normal file
BIN
src_assets/test_level.blend1
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src_assets/testblend.blend
(Stored with Git LFS)
BIN
src_assets/testblend.blend
(Stored with Git LFS)
Binary file not shown.
BIN
src_assets/testblend.blend1
(Stored with Git LFS)
BIN
src_assets/testblend.blend1
(Stored with Git LFS)
Binary file not shown.
BIN
src_assets/tools.blend
(Stored with Git LFS)
Normal file
BIN
src_assets/tools.blend
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src_assets/tools.blend1
(Stored with Git LFS)
Normal file
BIN
src_assets/tools.blend1
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user