diff --git a/assets/blender/test_level_blend/Plane.glb b/assets/blender/test_level_blend/Plane.glb index a9d5130..b8903ae 100644 --- a/assets/blender/test_level_blend/Plane.glb +++ b/assets/blender/test_level_blend/Plane.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:631a1098a36d2ca2e4f859ecf329df96c8c5990ab8c7a0860ffbe2b00f814711 -size 1088 +oid sha256:c8c21befe6000244cb579414a283dd1985ede41529de5136810bcb971ed484bb +size 1112 diff --git a/assets/blender/test_level_blend/Scene.scn b/assets/blender/test_level_blend/Scene.scn index fda5fe8..a11f3cb 100644 --- a/assets/blender/test_level_blend/Scene.scn +++ b/assets/blender/test_level_blend/Scene.scn @@ -1,50 +1,45 @@ (inst :model "assets/blender/testblend_blend/Bakery.glb" - :pos (0.000000 12.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 0.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 13.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 11.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 11.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 0.259853 1.609015) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 -7.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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 -18.000000 0.000000) - :rot (0.000000 0.000000 0.000000 1.000000) + :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)) -(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) + :pos (0.000000 0.000000 0.000000) + :rot (0.000000 0.000000 0.000000 1.000000) :scale (1.000000 1.000000 1.000000)) diff --git a/blender/batch_export.py b/blender/batch_export.py index d5686af..bd47d3d 100644 --- a/blender/batch_export.py +++ b/blender/batch_export.py @@ -70,8 +70,8 @@ for obj in visible_objects: 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: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) diff --git a/common/encoding/sexp/sexp.odin b/common/encoding/sexp/sexp.odin index 12e9c1e..f45153b 100644 --- a/common/encoding/sexp/sexp.odin +++ b/common/encoding/sexp/sexp.odin @@ -4,6 +4,7 @@ import "common:name" import "core:container/intrusive/list" import "core:fmt" import "core:io" +import "core:strconv" import "core:strings" import "core:testing" import "core:unicode" @@ -151,7 +152,13 @@ parse_atom :: proc(ctx: ^SEXP_Parser) -> (atom: Atom, error: Error) { result := ctx.data[start:ctx.pos] ctx.pos = next 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)) @@ -233,6 +240,43 @@ iterator_next_checked :: proc(it: ^List_Iterator) -> Sexp { 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 { it := it 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 } +// 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_parse :: proc(t: ^testing.T) { ctx: SEXP_Parser diff --git a/common/name/name.odin b/common/name/name.odin index eb4be4e..cc60140 100644 --- a/common/name/name.odin +++ b/common/name/name.odin @@ -81,3 +81,7 @@ to_string :: proc(name: Name) -> string { sync.atomic_rw_mutex_shared_guard(&global_container.lock) return global_container.names_array[name] } + +to_cstring :: proc(name: Name) -> cstring { + return strings.unsafe_string_to_cstring(to_string(name)) +} diff --git a/game/assets/assets.odin b/game/assets/assets.odin index a579261..4736afc 100644 --- a/game/assets/assets.odin +++ b/game/assets/assets.odin @@ -1,5 +1,7 @@ package assets +import "common:encoding/sexp" +import "common:name" import "core:log" import "core:math" import lg "core:math/linalg" @@ -57,6 +59,18 @@ destroy_loaded_bvh :: proc(loaded_bvh: ^Loaded_BVH) { 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 { textures: Asset_Cache(rl.Texture2D), models: Asset_Cache(rl.Model), @@ -65,6 +79,7 @@ Asset_Manager :: struct { music: Asset_Cache(rl.Music), curves_1d: Asset_Cache([]f32), curves_2d: Asset_Cache(Curve_2D), + scenes: Asset_Cache(Scene_Desc), bvhs: map[cstring]Loaded_BVH, curves: map[cstring]Loaded_Curve_2D, } @@ -203,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.models = { loader = MODEL_LOADER, @@ -225,6 +338,9 @@ assetman_init :: proc(assetman: ^Asset_Manager) { assetman.curves_2d = { loader = CURVE_2D_CSV_LOADER, } + assetman.scenes = { + loader = SCENE_DESC_LOADER, + } } Asset_Cache_Result :: enum { @@ -238,6 +354,7 @@ assetcache_fetch_or_load :: proc( ac: ^$T/Asset_Cache($E), path: cstring, payload: Asset_Cache_Loader_Payload = nil, + force_no_reload := false, ) -> ( value: E, modtime: physfs.sint64, @@ -250,7 +367,7 @@ assetcache_fetch_or_load :: proc( if has_existing { new_modtime := physfs.getLastModTime(path) - if existing.modtime == new_modtime { + if force_no_reload || existing.modtime == new_modtime { result = .Cached return existing.value, new_modtime, result } else { @@ -408,7 +525,9 @@ get_bvh :: proc(assetman: ^Asset_Manager, path: cstring) -> (Loaded_BVH, bool) { copy(vertices[vert_count:], mesh_vertices) for j in 0 ..< len(mesh_indices) { - indices[indices_count + j] = u16(vert_count) + mesh_indices[j] + index := vert_count + int(mesh_indices[j]) + assert(index <= int(max(u16))) + indices[indices_count + j] = u16(index) } vert_count += len(mesh_vertices) @@ -446,6 +565,20 @@ get_curve_2d :: proc(assetman: ^Asset_Manager, path: cstring) -> (curve: Curve_2 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) { bytes, err := physfs.read_entire_file(string(path), context.temp_allocator) if err != nil { @@ -852,6 +985,7 @@ shutdown :: proc(assetman: ^Asset_Manager) { assetcache_destroy(&assetman.music) assetcache_destroy(&assetman.curves_1d) assetcache_destroy(&assetman.curves_2d) + assetcache_destroy(&assetman.scenes) for _, &loaded_bvh in assetman.bvhs { destroy_loaded_bvh(&loaded_bvh) diff --git a/game/game.odin b/game/game.odin index bf0d083..4989782 100644 --- a/game/game.odin +++ b/game/game.odin @@ -17,7 +17,6 @@ package game import "assets" import "common:name" import "core:fmt" -import "core:hash" import "core:log" import "core:math" import "core:math/linalg" @@ -48,6 +47,65 @@ Debug_Draw_State :: struct { 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 { player_pos: rl.Vector3, track: Track, @@ -57,6 +115,7 @@ World :: struct { car_handle: physics.Body_Handle, engine_handle: physics.Engine_Handle, debug_state: Debug_Draw_State, + main_scene: Scene, } world_init :: proc(world: ^World) { physics.scene_init(&world.physics_scene, &g_mem.assetman) @@ -64,6 +123,7 @@ world_init :: proc(world: ^World) { copy_world :: proc(dst, src: ^World) { copy_track(&dst.track, &src.track) 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.pause = src.pause dst.car_com = src.car_com @@ -73,6 +133,7 @@ copy_world :: proc(dst, src: ^World) { } destroy_world :: proc(world: ^World) { destroy_track(&world.track) + scene_destroy(world, &world.main_scene) physics.scene_destroy(&world.physics_scene) } @@ -699,46 +760,7 @@ update_world :: proc(world: ^World, dt: f32, config: World_Update_Config) { 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") - - 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, - source = physics.Level_Geometry_Mesh { - vertices = (cast([^]rl.Vector3)mesh.vertices)[:mesh.vertexCount], - indices = mesh.indices[:mesh.triangleCount * 3], - }, - }, - ) - } - } - } + immediate_scene(world, &world.main_scene, "assets/blender/test_level_blend/Scene.scn") if len(world.track.points) > 1 { interpolated_points := calculate_spline_interpolated_points( @@ -1094,7 +1116,6 @@ draw_world :: proc(world: ^World) { 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") phys_debug_state: physics.Debug_State @@ -1183,7 +1204,7 @@ draw_world :: proc(world: ^World) { // .VEC3, // ) - render.draw_model(level_model, {}, 1) + scene_draw(&world.main_scene) render.draw_model(car_model, {}, car_matrix) diff --git a/game/physics/scene.odin b/game/physics/scene.odin index 0c11c86..624b942 100644 --- a/game/physics/scene.odin +++ b/game/physics/scene.odin @@ -967,6 +967,7 @@ get_level_geom_data :: proc( ) 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 @@ -989,6 +990,7 @@ get_level_geom_blas :: proc(sim_state: ^Sim_State, handle: Level_Geom_Handle) -> ) 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 @@ -1074,6 +1076,8 @@ add_level_geom :: proc(sim_state: ^Sim_State, config: Level_Geom_Config) -> Leve } } + level_geom.aabb = aabb_transform(level_geom.aabb, level_geom.x, level_geom.q) + if sim_state.first_free_level_geom_plus_one > 0 { index := sim_state.first_free_level_geom_plus_one new_level_geom := get_level_geom(sim_state, Level_Geom_Handle(index)) diff --git a/game/physics/simulation.odin b/game/physics/simulation.odin index 8ddd80a..cd8e03a 100644 --- a/game/physics/simulation.odin +++ b/game/physics/simulation.odin @@ -200,6 +200,7 @@ raycasts_level :: proc( level_geom_handle := index_to_level_geom( 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) vertices, indices := get_level_geom_data(sim_state, level_geom_handle) @@ -210,7 +211,13 @@ raycasts_level :: proc( for k in 0 ..< blas_leaf_node.prim_len { 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( {origin, origin + dir}, @@ -392,7 +399,13 @@ remove_invalid_contacts :: proc( if !should_remove { 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) should_remove |= !bvh.test_aabb_vs_aabb(aabb_a, aabb_b) @@ -555,7 +568,13 @@ find_new_contacts :: proc( 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, + ) prim_aabb := get_triangle_aabb(tri) if bvh.test_aabb_vs_aabb(body_aabb, prim_aabb) { @@ -804,8 +823,15 @@ update_contacts :: proc(sim_state: ^Sim_State, static_tlas: ^Static_TLAS) { ) case .Body_vs_Level: 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) - 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) } diff --git a/src_assets/test_level.blend b/src_assets/test_level.blend index 113339b..1babbcd 100644 --- a/src_assets/test_level.blend +++ b/src_assets/test_level.blend @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e441b8e05842e881ba06f6836ca439780d05f3241c9667472191ceed984826a8 -size 514980 +oid sha256:533225496bc26bb37bc4a1d760b34beb5868bee3835923c2ab78e1f2de05672c +size 511650 diff --git a/src_assets/test_level.blend1 b/src_assets/test_level.blend1 index 9de9cab..13ae2ee 100644 --- a/src_assets/test_level.blend1 +++ b/src_assets/test_level.blend1 @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9646c9e2d88c2e1cbe6127969f661abbcb1840cc626b8b5f6eb5a57151366182 -size 514980 +oid sha256:7e8e7a7dbb89d5013fdde3302bccced191e784b7a09d86495317deeaca189121 +size 511650