Compare commits
2 Commits
5f4fa12040
...
7da986970e
Author | SHA1 | Date | |
---|---|---|---|
7da986970e | |||
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.
45
assets/blender/test_level_blend/Scene.scn
Normal file
45
assets/blender/test_level_blend/Scene.scn
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
(inst
|
||||||
|
:model "assets/blender/testblend_blend/Bakery.glb"
|
||||||
|
:pos (0.000000 0.000000 12.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 -1.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 0.000000 13.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 0.000000 11.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 0.000000 11.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 1.609015 0.259853)
|
||||||
|
: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 0.000000 -7.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 0.000000 -18.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))
|
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.z:.6f} {loc.y:.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}")
|
@ -4,6 +4,7 @@ import "common:name"
|
|||||||
import "core:container/intrusive/list"
|
import "core:container/intrusive/list"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:io"
|
import "core:io"
|
||||||
|
import "core:strconv"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:testing"
|
import "core:testing"
|
||||||
import "core:unicode"
|
import "core:unicode"
|
||||||
@ -151,7 +152,13 @@ parse_atom :: proc(ctx: ^SEXP_Parser) -> (atom: Atom, error: Error) {
|
|||||||
result := ctx.data[start:ctx.pos]
|
result := ctx.data[start:ctx.pos]
|
||||||
ctx.pos = next
|
ctx.pos = next
|
||||||
return result, nil
|
return result, nil
|
||||||
|
case '0' ..= '9', '-', '+':
|
||||||
|
value, n, ok := strconv.parse_f64_prefix(ctx.data[ctx.pos:])
|
||||||
|
if !ok {
|
||||||
|
return nil, make_error(ctx, "failed to parse number")
|
||||||
|
}
|
||||||
|
ctx.pos += n
|
||||||
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, make_error(ctx, fmt.tprintf("unknown atom {}", c))
|
return nil, make_error(ctx, fmt.tprintf("unknown atom {}", c))
|
||||||
@ -233,6 +240,43 @@ iterator_next_checked :: proc(it: ^List_Iterator) -> Sexp {
|
|||||||
return node.expr
|
return node.expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator_has_more :: proc(it: List_Iterator) -> bool {
|
||||||
|
return it.curr != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_expect_list :: proc(it: ^List_Iterator) -> (Sexp_List, bool) {
|
||||||
|
next, ok := iterator_next(it)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
list_expr: Sexp_List
|
||||||
|
list_expr, ok = next.expr.(Sexp_List)
|
||||||
|
|
||||||
|
return list_expr, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator_expect_atom :: proc(it: ^List_Iterator, $T: typeid) -> (T, bool) {
|
||||||
|
next, ok := iterator_next(it)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
atom_expr: Atom
|
||||||
|
atom_expr, ok = next.expr.(Atom)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
result: T
|
||||||
|
result, ok = atom_expr.(T)
|
||||||
|
|
||||||
|
return result, ok
|
||||||
|
}
|
||||||
|
|
||||||
print_list :: proc(it: List_Iterator, w: io.Writer) -> io.Error {
|
print_list :: proc(it: List_Iterator, w: io.Writer) -> io.Error {
|
||||||
it := it
|
it := it
|
||||||
io.write_byte(w, '(') or_return
|
io.write_byte(w, '(') or_return
|
||||||
@ -402,6 +446,16 @@ print_pretty_error :: proc(w: io.Writer, data: string, error: Error) -> io.Error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prints pretty error to temp string
|
||||||
|
temp_pretty_error :: proc(data: string, error: Error) -> string {
|
||||||
|
builder: strings.Builder
|
||||||
|
strings.builder_init(&builder, context.temp_allocator)
|
||||||
|
|
||||||
|
writer := strings.to_writer(&builder)
|
||||||
|
print_pretty_error(writer, data, error)
|
||||||
|
return strings.to_string(builder)
|
||||||
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
test_parse :: proc(t: ^testing.T) {
|
test_parse :: proc(t: ^testing.T) {
|
||||||
ctx: SEXP_Parser
|
ctx: SEXP_Parser
|
||||||
|
@ -81,3 +81,7 @@ to_string :: proc(name: Name) -> string {
|
|||||||
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
|
sync.atomic_rw_mutex_shared_guard(&global_container.lock)
|
||||||
return global_container.names_array[name]
|
return global_container.names_array[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to_cstring :: proc(name: Name) -> cstring {
|
||||||
|
return strings.unsafe_string_to_cstring(to_string(name))
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
|
import "common:encoding/sexp"
|
||||||
|
import "common:name"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:math"
|
import "core:math"
|
||||||
import lg "core:math/linalg"
|
import lg "core:math/linalg"
|
||||||
@ -15,11 +17,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,17 +49,28 @@ 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
|
||||||
|
|
||||||
|
Scene_Instance :: struct {
|
||||||
|
model: name.Name,
|
||||||
|
// TODO: common format definitions
|
||||||
|
pos: rl.Vector3,
|
||||||
|
rot: rl.Quaternion,
|
||||||
|
scale: rl.Vector3,
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene_Desc :: struct {
|
||||||
|
instances: []Scene_Instance,
|
||||||
|
}
|
||||||
|
|
||||||
Asset_Manager :: struct {
|
Asset_Manager :: struct {
|
||||||
textures: Asset_Cache(rl.Texture2D),
|
textures: Asset_Cache(rl.Texture2D),
|
||||||
models: Asset_Cache(rl.Model),
|
models: Asset_Cache(rl.Model),
|
||||||
@ -53,6 +79,7 @@ Asset_Manager :: struct {
|
|||||||
music: Asset_Cache(rl.Music),
|
music: Asset_Cache(rl.Music),
|
||||||
curves_1d: Asset_Cache([]f32),
|
curves_1d: Asset_Cache([]f32),
|
||||||
curves_2d: Asset_Cache(Curve_2D),
|
curves_2d: Asset_Cache(Curve_2D),
|
||||||
|
scenes: Asset_Cache(Scene_Desc),
|
||||||
bvhs: map[cstring]Loaded_BVH,
|
bvhs: map[cstring]Loaded_BVH,
|
||||||
curves: map[cstring]Loaded_Curve_2D,
|
curves: map[cstring]Loaded_Curve_2D,
|
||||||
}
|
}
|
||||||
@ -191,6 +218,104 @@ CURVE_2D_CSV_LOADER :: Asset_Cache_Loader(Curve_2D) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENE_DESC_LOADER :: Asset_Cache_Loader(Scene_Desc) {
|
||||||
|
load = proc(path: cstring, payload: Asset_Cache_Loader_Payload) -> (Scene_Desc, bool) {
|
||||||
|
data, err := physfs.read_entire_file(string(path), context.temp_allocator)
|
||||||
|
if err != nil {
|
||||||
|
log.errorf("Failed to read curve: %s, %v", path, err)
|
||||||
|
return {}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
parser: sexp.SEXP_Parser
|
||||||
|
parser.data = string(data)
|
||||||
|
parsed, err2 := sexp.parse(&parser, context.temp_allocator)
|
||||||
|
|
||||||
|
if err2 != nil {
|
||||||
|
log.errorf(
|
||||||
|
"Failed to parse curve: %s\n%s",
|
||||||
|
path,
|
||||||
|
sexp.temp_pretty_error(parser.data, err2),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inst_identifier := sexp.Ident(name.from_string("inst"))
|
||||||
|
|
||||||
|
num_instances: int
|
||||||
|
|
||||||
|
top_it := sexp.iterator_list(parsed)
|
||||||
|
for top_level_expr in sexp.iterator_next(&top_it) {
|
||||||
|
list_expr := top_level_expr.expr.(sexp.Sexp_List) or_continue
|
||||||
|
|
||||||
|
it := sexp.iterator_list(list_expr)
|
||||||
|
ident := sexp.iterator_expect_atom(&it, sexp.Ident) or_continue
|
||||||
|
|
||||||
|
if ident != inst_identifier {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
num_instances += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
instances := make([]Scene_Instance, num_instances)
|
||||||
|
num_instances = 0
|
||||||
|
|
||||||
|
top_it = sexp.iterator_list(parsed)
|
||||||
|
for top_level_expr in sexp.iterator_next(&top_it) {
|
||||||
|
list_expr := top_level_expr.expr.(sexp.Sexp_List) or_continue
|
||||||
|
|
||||||
|
it := sexp.iterator_list(list_expr)
|
||||||
|
ident := sexp.iterator_expect_atom(&it, sexp.Ident) or_continue
|
||||||
|
|
||||||
|
if ident != inst_identifier {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
inst: Scene_Instance
|
||||||
|
|
||||||
|
for sexp.iterator_has_more(it) {
|
||||||
|
key := sexp.iterator_expect_atom(&it, sexp.Tag) or_continue
|
||||||
|
|
||||||
|
switch name.Name(key) {
|
||||||
|
case name.from_string("model"):
|
||||||
|
model_path := sexp.iterator_expect_atom(&it, string) or_continue
|
||||||
|
inst.model = name.from_string(model_path)
|
||||||
|
case name.from_string("pos"):
|
||||||
|
pos_list := sexp.iterator_expect_list(&it) or_continue
|
||||||
|
pos_it := sexp.iterator_list(pos_list)
|
||||||
|
x := sexp.iterator_expect_atom(&pos_it, f64) or_continue
|
||||||
|
y := sexp.iterator_expect_atom(&pos_it, f64) or_continue
|
||||||
|
z := sexp.iterator_expect_atom(&pos_it, f64) or_continue
|
||||||
|
|
||||||
|
inst.pos = {f32(x), f32(y), f32(z)}
|
||||||
|
case name.from_string("rot"):
|
||||||
|
rot_list := sexp.iterator_expect_list(&it) or_continue
|
||||||
|
rot_it := sexp.iterator_list(rot_list)
|
||||||
|
inst.rot.x = f32(sexp.iterator_expect_atom(&rot_it, f64) or_continue)
|
||||||
|
inst.rot.y = f32(sexp.iterator_expect_atom(&rot_it, f64) or_continue)
|
||||||
|
inst.rot.z = f32(sexp.iterator_expect_atom(&rot_it, f64) or_continue)
|
||||||
|
inst.rot.w = f32(sexp.iterator_expect_atom(&rot_it, f64) or_continue)
|
||||||
|
case name.from_string("scale"):
|
||||||
|
scale_list := sexp.iterator_expect_list(&it) or_continue
|
||||||
|
scale_it := sexp.iterator_list(scale_list)
|
||||||
|
x := sexp.iterator_expect_atom(&scale_it, f64) or_continue
|
||||||
|
y := sexp.iterator_expect_atom(&scale_it, f64) or_continue
|
||||||
|
z := sexp.iterator_expect_atom(&scale_it, f64) or_continue
|
||||||
|
|
||||||
|
inst.scale = {f32(x), f32(y), f32(z)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instances[num_instances] = inst
|
||||||
|
num_instances += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scene_Desc{instances = instances[:num_instances]}, true
|
||||||
|
},
|
||||||
|
unload = proc(scene_desc: Scene_Desc) {
|
||||||
|
delete(scene_desc.instances)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
assetman_init :: proc(assetman: ^Asset_Manager) {
|
assetman_init :: proc(assetman: ^Asset_Manager) {
|
||||||
assetman.models = {
|
assetman.models = {
|
||||||
loader = MODEL_LOADER,
|
loader = MODEL_LOADER,
|
||||||
@ -213,6 +338,9 @@ assetman_init :: proc(assetman: ^Asset_Manager) {
|
|||||||
assetman.curves_2d = {
|
assetman.curves_2d = {
|
||||||
loader = CURVE_2D_CSV_LOADER,
|
loader = CURVE_2D_CSV_LOADER,
|
||||||
}
|
}
|
||||||
|
assetman.scenes = {
|
||||||
|
loader = SCENE_DESC_LOADER,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Asset_Cache_Result :: enum {
|
Asset_Cache_Result :: enum {
|
||||||
@ -226,6 +354,7 @@ assetcache_fetch_or_load :: proc(
|
|||||||
ac: ^$T/Asset_Cache($E),
|
ac: ^$T/Asset_Cache($E),
|
||||||
path: cstring,
|
path: cstring,
|
||||||
payload: Asset_Cache_Loader_Payload = nil,
|
payload: Asset_Cache_Loader_Payload = nil,
|
||||||
|
force_no_reload := false,
|
||||||
) -> (
|
) -> (
|
||||||
value: E,
|
value: E,
|
||||||
modtime: physfs.sint64,
|
modtime: physfs.sint64,
|
||||||
@ -238,7 +367,7 @@ assetcache_fetch_or_load :: proc(
|
|||||||
if has_existing {
|
if has_existing {
|
||||||
new_modtime := physfs.getLastModTime(path)
|
new_modtime := physfs.getLastModTime(path)
|
||||||
|
|
||||||
if existing.modtime == new_modtime {
|
if force_no_reload || existing.modtime == new_modtime {
|
||||||
result = .Cached
|
result = .Cached
|
||||||
return existing.value, new_modtime, result
|
return existing.value, new_modtime, result
|
||||||
} else {
|
} else {
|
||||||
@ -361,7 +490,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 +499,41 @@ 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) {
|
||||||
|
index := vert_count + int(mesh_indices[j])
|
||||||
|
assert(index <= int(max(u16)))
|
||||||
|
indices[indices_count + j] = u16(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +541,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) {
|
||||||
@ -420,6 +565,20 @@ get_curve_2d :: proc(assetman: ^Asset_Manager, path: cstring) -> (curve: Curve_2
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reads a two column comma separated csv file as a curve
|
||||||
|
get_scene_desc :: proc(
|
||||||
|
assetman: ^Asset_Manager,
|
||||||
|
path: name.Name,
|
||||||
|
force_no_reload := false,
|
||||||
|
) -> (
|
||||||
|
scene: Scene_Desc,
|
||||||
|
reloaded: bool,
|
||||||
|
) {
|
||||||
|
res: Asset_Cache_Result
|
||||||
|
scene, _, res = assetcache_fetch_or_load(&assetman.scenes, name.to_cstring(path))
|
||||||
|
return scene, (res == .Loaded || res == .Reloaded)
|
||||||
|
}
|
||||||
|
|
||||||
get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_Convex) {
|
get_convex :: proc(assetman: ^Asset_Manager, path: cstring) -> (result: Loaded_Convex) {
|
||||||
bytes, err := physfs.read_entire_file(string(path), context.temp_allocator)
|
bytes, err := physfs.read_entire_file(string(path), context.temp_allocator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -826,9 +985,10 @@ shutdown :: proc(assetman: ^Asset_Manager) {
|
|||||||
assetcache_destroy(&assetman.music)
|
assetcache_destroy(&assetman.music)
|
||||||
assetcache_destroy(&assetman.curves_1d)
|
assetcache_destroy(&assetman.curves_1d)
|
||||||
assetcache_destroy(&assetman.curves_2d)
|
assetcache_destroy(&assetman.curves_2d)
|
||||||
|
assetcache_destroy(&assetman.scenes)
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
158
game/game.odin
158
game/game.odin
@ -17,12 +17,10 @@ package game
|
|||||||
import "assets"
|
import "assets"
|
||||||
import "common:name"
|
import "common:name"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:hash"
|
|
||||||
import "core:log"
|
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"
|
||||||
@ -49,6 +47,65 @@ Debug_Draw_State :: struct {
|
|||||||
draw_physics_scene: bool,
|
draw_physics_scene: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scene :: struct {
|
||||||
|
scene_desc_path: name.Name,
|
||||||
|
level_geoms: []physics.Level_Geom_Handle,
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_destroy :: proc(world: ^World, scene: ^Scene) {
|
||||||
|
scene.scene_desc_path = name.NONE
|
||||||
|
sim_state := physics.get_sim_state(&world.physics_scene)
|
||||||
|
for handle in scene.level_geoms {
|
||||||
|
physics.remove_level_geom(sim_state, handle)
|
||||||
|
}
|
||||||
|
delete(scene.level_geoms)
|
||||||
|
scene.level_geoms = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
immediate_scene :: proc(world: ^World, scene: ^Scene, path: cstring) {
|
||||||
|
path_name := name.from_string(string(path))
|
||||||
|
|
||||||
|
desc, reloaded := assets.get_scene_desc(&g_mem.assetman, path_name)
|
||||||
|
|
||||||
|
if reloaded || scene.scene_desc_path != path_name {
|
||||||
|
scene_destroy(world, scene)
|
||||||
|
|
||||||
|
scene.scene_desc_path = path_name
|
||||||
|
|
||||||
|
sim_state := physics.get_sim_state(&world.physics_scene)
|
||||||
|
for inst in desc.instances {
|
||||||
|
physics.add_level_geom(
|
||||||
|
sim_state,
|
||||||
|
physics.Level_Geom_Config {
|
||||||
|
position = inst.pos,
|
||||||
|
rotation = inst.rot,
|
||||||
|
source = physics.Level_Geometry_Asset(name.to_string(inst.model)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_copy :: proc(dst, src: ^Scene) {
|
||||||
|
dst.scene_desc_path = src.scene_desc_path
|
||||||
|
if len(dst.level_geoms) != len(src.level_geoms) {
|
||||||
|
delete(dst.level_geoms)
|
||||||
|
dst.level_geoms = make([]physics.Level_Geom_Handle, len(src.level_geoms))
|
||||||
|
}
|
||||||
|
copy(dst.level_geoms, src.level_geoms)
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_draw :: proc(scene: ^Scene) {
|
||||||
|
desc, _ := assets.get_scene_desc(&g_mem.assetman, scene.scene_desc_path, true)
|
||||||
|
for geo in desc.instances {
|
||||||
|
render.draw_model(
|
||||||
|
assets.get_model(&g_mem.assetman, name.to_cstring(geo.model)),
|
||||||
|
{},
|
||||||
|
auto_cast linalg.matrix4_from_trs(geo.pos, geo.rot, geo.scale),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
World :: struct {
|
World :: struct {
|
||||||
player_pos: rl.Vector3,
|
player_pos: rl.Vector3,
|
||||||
track: Track,
|
track: Track,
|
||||||
@ -58,10 +115,15 @@ World :: struct {
|
|||||||
car_handle: physics.Body_Handle,
|
car_handle: physics.Body_Handle,
|
||||||
engine_handle: physics.Engine_Handle,
|
engine_handle: physics.Engine_Handle,
|
||||||
debug_state: Debug_Draw_State,
|
debug_state: Debug_Draw_State,
|
||||||
|
main_scene: Scene,
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
scene_copy(&dst.main_scene, &src.main_scene)
|
||||||
dst.player_pos = src.player_pos
|
dst.player_pos = src.player_pos
|
||||||
dst.pause = src.pause
|
dst.pause = src.pause
|
||||||
dst.car_com = src.car_com
|
dst.car_com = src.car_com
|
||||||
@ -71,7 +133,8 @@ 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)
|
scene_destroy(world, &world.main_scene)
|
||||||
|
physics.scene_destroy(&world.physics_scene)
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime_World :: struct {
|
Runtime_World :: struct {
|
||||||
@ -91,6 +154,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 +189,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 +232,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,30 +760,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
immediate_scene(world, &world.main_scene, "assets/blender/test_level_blend/Scene.scn")
|
||||||
level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb")
|
|
||||||
|
|
||||||
for i in 0 ..< level_model.meshCount {
|
|
||||||
mesh := &level_model.meshes[i]
|
|
||||||
|
|
||||||
if mesh.triangleCount > 0 {
|
|
||||||
assert(mesh.vertexCount <= i32(max(u16)))
|
|
||||||
m := level_model.transform
|
|
||||||
pos := physics.Vec3{m[3][0], m[3][1], m[3][2]}
|
|
||||||
rotation := linalg.quaternion_from_matrix4_f32(auto_cast level_model.transform)
|
|
||||||
physics.immediate_level_geom(
|
|
||||||
&world.physics_scene,
|
|
||||||
hash.fnv32a(transmute([]byte)(fmt.tprintf("level mesh {}", i))),
|
|
||||||
{
|
|
||||||
position = pos,
|
|
||||||
rotation = rotation,
|
|
||||||
vertices = (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount],
|
|
||||||
indices = mesh.indices[:mesh.triangleCount * 3],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(world.track.points) > 1 {
|
if len(world.track.points) > 1 {
|
||||||
interpolated_points := calculate_spline_interpolated_points(
|
interpolated_points := calculate_spline_interpolated_points(
|
||||||
@ -734,9 +776,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 +1017,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
|
||||||
@ -1072,7 +1116,6 @@ draw_world :: proc(world: ^World) {
|
|||||||
|
|
||||||
sim_state := physics.get_sim_state(&world.physics_scene)
|
sim_state := physics.get_sim_state(&world.physics_scene)
|
||||||
|
|
||||||
level_model := assets.get_model(&g_mem.assetman, "assets/testblend.glb")
|
|
||||||
car_model := assets.get_model(&g_mem.assetman, "assets/ice_cream_truck.glb")
|
car_model := assets.get_model(&g_mem.assetman, "assets/ice_cream_truck.glb")
|
||||||
|
|
||||||
phys_debug_state: physics.Debug_State
|
phys_debug_state: physics.Debug_State
|
||||||
@ -1161,7 +1204,7 @@ draw_world :: proc(world: ^World) {
|
|||||||
// .VEC3,
|
// .VEC3,
|
||||||
// )
|
// )
|
||||||
|
|
||||||
render.draw_model(level_model, {}, 1)
|
scene_draw(&world.main_scene)
|
||||||
|
|
||||||
render.draw_model(car_model, {}, car_matrix)
|
render.draw_model(car_model, {}, car_matrix)
|
||||||
|
|
||||||
@ -1429,9 +1472,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 +1497,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,52 @@ 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)
|
||||||
|
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
|
||||||
|
}
|
||||||
|
|
||||||
|
bvh = loaded_bvh.bvh
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,32 +1007,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 +1044,39 @@ 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q)
|
||||||
|
|
||||||
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 +1095,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 +1129,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)
|
||||||
}
|
}
|
||||||
|
@ -201,8 +201,8 @@ raycasts_level :: proc(
|
|||||||
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)
|
level_geom := get_level_geom(sim_state, level_geom_handle)
|
||||||
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(sim_state, level_geom.geometry)
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
|
|
||||||
// TODO: transform ray into blas space and back
|
// TODO: transform ray into blas space and back
|
||||||
|
|
||||||
@ -211,7 +211,13 @@ raycasts_level :: proc(
|
|||||||
for k in 0 ..< blas_leaf_node.prim_len {
|
for k in 0 ..< blas_leaf_node.prim_len {
|
||||||
tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k])
|
tri_idx := int(blas.primitives[blas_leaf_node.child_or_prim_start + k])
|
||||||
|
|
||||||
tri := get_triangle(vertices, indices, tri_idx)
|
tri := get_transformed_triangle(
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
tri_idx,
|
||||||
|
level_geom.x,
|
||||||
|
level_geom.q,
|
||||||
|
)
|
||||||
|
|
||||||
hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle(
|
hit_t, tmp_normal, _, ok := collision.intersect_ray_triangle(
|
||||||
{origin, origin + dir},
|
{origin, origin + dir},
|
||||||
@ -388,12 +394,18 @@ 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 {
|
||||||
aabb_a := dyn_tlas.body_aabbs[body_handle_to_index(contact.a)]
|
aabb_a := dyn_tlas.body_aabbs[body_handle_to_index(contact.a)]
|
||||||
tri := get_triangle(vertices, indices, tri_idx)
|
tri := get_transformed_triangle(
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
tri_idx,
|
||||||
|
level_geom.x,
|
||||||
|
level_geom.q,
|
||||||
|
)
|
||||||
aabb_b := get_triangle_aabb(tri)
|
aabb_b := get_triangle_aabb(tri)
|
||||||
|
|
||||||
should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b)
|
should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b)
|
||||||
@ -547,11 +559,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) {
|
||||||
@ -559,7 +568,13 @@ find_new_contacts :: proc(
|
|||||||
tri_idx := int(
|
tri_idx := int(
|
||||||
blas.primitives[blas_leaf_node.child_or_prim_start + k],
|
blas.primitives[blas_leaf_node.child_or_prim_start + k],
|
||||||
)
|
)
|
||||||
tri := get_triangle(vertices, indices, tri_idx)
|
tri := get_transformed_triangle(
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
tri_idx,
|
||||||
|
level_geom.x,
|
||||||
|
level_geom.q,
|
||||||
|
)
|
||||||
prim_aabb := get_triangle_aabb(tri)
|
prim_aabb := get_triangle_aabb(tri)
|
||||||
|
|
||||||
if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) {
|
if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) {
|
||||||
@ -809,8 +824,14 @@ 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)
|
level_geom := get_level_geom(sim_state, level_geom_handle)
|
||||||
vertices, indices := get_level_geom_data(sim_state, level_geom.geometry)
|
vertices, indices := get_level_geom_data(sim_state, level_geom_handle)
|
||||||
tri := get_triangle(vertices, indices, int(contact.local_tri_idx))
|
tri := get_transformed_triangle(
|
||||||
|
vertices,
|
||||||
|
indices,
|
||||||
|
int(contact.local_tri_idx),
|
||||||
|
level_geom.x,
|
||||||
|
level_geom.q,
|
||||||
|
)
|
||||||
|
|
||||||
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