#load "../renderer/directional_light.jai"; #load "particles.jai"; #placeholder Entity_Storage; #placeholder serialize_entity; #placeholder deserialize_entity; MAX_CACHED_PILES :: 8; last_unnamed_scene_id := 0; Scene :: struct { name: string; entities : [..] *Entity; particle_systems : Bucket_Array(Particle_System, 64); by_type : Entity_Storage; pool : Flat_Pool; allocator : Allocator; camera : Camera; directional_light : Directional_Light; } Entity_File_Info :: struct { id: s64; full_path: string; } visitor :: (info : *File_Visit_Info, files: *[..] Entity_File_Info) { if info.is_directory return; path, basename, ext := path_decomp (info.full_name); // Entity text files if ext == "ent" && basename != "cam" { file_info : Entity_File_Info; file_info.id = cast(s32)string_to_int(basename); file_info.full_path = copy_temporary_string(info.full_name); array_add(files, file_info); } } load_scene :: (path: string) -> *Scene { split_path := split(path, "/"); name := split_path[split_path.count-1]; scene := create_scene(name, 1024); files : [..] Entity_File_Info; files.allocator = temp; visit_files(path, true, *files, visitor); for file: files { deserialize_entity(scene, file.full_path); } return scene; } save_scene :: (scene: *Scene, path: string) { builder : String_Builder; builder.allocator = temp; full_path := tprint("%/%", path, scene.name); make_directory_if_it_does_not_exist(full_path); for scene.entities { if it.flags & .DONT_SAVE continue; serialize_entity(it, full_path); } // Save camera //print_to_builder(*builder, "Camera: % % % % %\n", scene.camera.position.x, scene.camera.position.y, scene.camera.position.z, scene.camera.rotation.yaw, scene.camera.rotation.pitch); //write_entire_file(path, builder_to_string(*builder)); } unload_scene :: (scene: *Scene) { for e: scene.entities { destroy_entity(e, false); } fini(*scene.pool); free(scene); } create_scene :: (name: string = "", max_entities: s64 = 256) -> *Scene { scene := New(Scene); new_name := name; // If no name was specified, we're going to pick an unused "unnamed_scene"-variant if new_name.count == 0 { while true { defer last_unnamed_scene_id += 1; temp_name := tprint("unnamed_scene_%", last_unnamed_scene_id); if !file_exists(tprint("../assets/scenes/%", temp_name)) { new_name = temp_name; break; } } } scene.name = copy_string(new_name); // Setup allocator scene.pool = .{}; scene.allocator.data = *scene.pool; scene.allocator.proc = flat_pool_allocator_proc; // Assign allocator to everything that needs allocations scene.entities.allocator = scene.allocator; scene.particle_systems.allocator = scene.allocator; array_reserve(*scene.entities, max_entities); scene.directional_light.color_and_intensity = .{1,1,1,1}; scene.directional_light.direction = to_v4(normalize(Vector3.{0.2, -0.7, 0.4})); dir_light_data : Directional_Light_Buffer_Data; dir_light_data.color_and_intensity = scene.directional_light.color_and_intensity; dir_light_data.direction = scene.directional_light.direction; upload_data_to_buffer(engine.renderer, engine.directional_light_buffer, *dir_light_data, size_of(Directional_Light_Buffer_Data)); return scene; } register_entity :: (scene: *Scene, entity: *Entity) { entity.scene = scene; entity.id = next_entity_id; array_add(*scene.entities, entity); next_entity_id += 1; #if NETWORKING { if net_data.net_mode == { case .LISTEN_SERVER; #through; case .DEDICATED_SERVER; { //net_spawn_entity(entity); } } } } unregister_entity :: (scene: *Scene, entity: *Entity) { array_unordered_remove_by_value(*scene.entities, entity); } update_animators :: (dt: float) { for e: engine.current_scene.entities { if e.flags & .ANIMATED { update_animator(e, *e.animator, dt); } } } update_transforms :: () { for e: engine.current_scene.entities { if e.parent == null { update_entity_transform(e, Matrix4_Identity); } } } update_entity_node :: (e: *Entity, model_node: Node, index: s64, parent_matrix: Matrix4) { n := *e.renderable.nodes[index]; update_matrix(*n.transform); n.transform.world_matrix = parent_matrix * n.transform.model_matrix; for children_index: 0..model_node.children.count-1 { index := model_node.children[children_index]-1; mn := e.renderable.model.nodes[index]; update_entity_node(e, mn, xx index, n.transform.world_matrix); } } update_entity_transform :: (e: *Entity, parent_matrix: Matrix4 = Matrix4_Identity) { if e.transform.dirty { update_matrix(*e.transform); e.transform.dirty = false; } e.transform.world_matrix = parent_matrix * e.transform.model_matrix; for model_node, i: e.renderable.model.nodes { if model_node.parent == 0 { update_entity_node(e, model_node, i, e.transform.world_matrix); } } for i: 0..e.num_children-1 { child := e.children[i]; matrix := e.transform.world_matrix; if child.attach_node_index != -1 { matrix = e.renderable.nodes[child.attach_node_index].transform.world_matrix; } update_entity_transform(child, matrix); } } #scope_file next_entity_id: Entity_Id;