319 lines
8.1 KiB
Plaintext
319 lines
8.1 KiB
Plaintext
#load "../renderer/directional_light.jai";
|
|
#load "../renderer/point_light.jai";
|
|
#load "particles.jai";
|
|
|
|
MAX_CACHED_PILES :: 8;
|
|
last_unnamed_scene_id := 0;
|
|
|
|
Scene :: struct {
|
|
name: string;
|
|
|
|
entities : [..] *Entity;
|
|
|
|
particle_systems : Bucket_Array(Particle_System, 128);
|
|
|
|
by_type : Entity_Storage;
|
|
|
|
pool : Flat_Pool;
|
|
allocator : Allocator;
|
|
|
|
camera : Camera;
|
|
directional_light : Directional_Light;
|
|
|
|
mode: Engine_Mode;
|
|
|
|
physx_scene: *PhysX.PxScene;
|
|
|
|
using custom_fields: _Custom_Scene_Fields;
|
|
}
|
|
|
|
Entity_File_Info :: struct {
|
|
id: Entity_Id;
|
|
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(Entity_Id)string_to_int(basename);
|
|
file_info.full_path = copy_temporary_string(info.full_name);
|
|
array_add(files, file_info);
|
|
}
|
|
}
|
|
|
|
load_scene :: (name: string, make_current: bool = true) -> *Scene {
|
|
scene := create_scene(name, 1024);
|
|
|
|
if make_current {
|
|
engine.current_scene = scene;
|
|
}
|
|
|
|
scene.mode = engine.mode;
|
|
|
|
if engine.procs.on_pre_scene_loaded != null {
|
|
engine.procs.on_pre_scene_loaded(scene, engine.mode);
|
|
}
|
|
|
|
path := tprint("../assets/scenes/%", name);
|
|
|
|
files : [..] Entity_File_Info;
|
|
files.allocator = temp;
|
|
visit_files(path, true, *files, visitor);
|
|
|
|
highest : Entity_Id = 0;
|
|
for file: files {
|
|
deserialize_entity(scene, file.id, file.full_path);
|
|
if file.id > highest {
|
|
highest = file.id;
|
|
}
|
|
}
|
|
|
|
next_entity_id = cast(Entity_Id)(highest + 1);
|
|
|
|
update_transforms(scene);
|
|
calculate_aabbs(scene);
|
|
make_sure_nothing_collides(scene);
|
|
|
|
if engine.procs.on_scene_loaded != null {
|
|
engine.procs.on_scene_loaded(scene, engine.mode);
|
|
}
|
|
|
|
if engine.mode == .EDITING {
|
|
save_last_opened_scene_file(name);
|
|
}
|
|
|
|
return scene;
|
|
}
|
|
|
|
get_last_opened_scene_file :: () -> string {
|
|
if file_exists("../.config") {
|
|
return read_entire_file("../.config");
|
|
}
|
|
|
|
return .{};
|
|
}
|
|
|
|
save_last_opened_scene_file :: (name: string) {
|
|
write_entire_file("../.config", name);
|
|
}
|
|
|
|
save_scene :: (scene: *Scene) {
|
|
path := "../assets/scenes/";
|
|
save_scene(scene, path);
|
|
}
|
|
|
|
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;
|
|
if it.flags & .DELETED continue;
|
|
|
|
serialize_entity(it, full_path);
|
|
}
|
|
|
|
for scene.entities {
|
|
if it.flags & .DELETED {
|
|
delete_entity(it);
|
|
remove it;
|
|
}
|
|
}
|
|
|
|
// 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) {
|
|
if engine.procs.on_pre_scene_unloaded != null {
|
|
engine.procs.on_pre_scene_unloaded(scene);
|
|
}
|
|
|
|
for e: scene.entities {
|
|
destroy_entity(e);
|
|
}
|
|
|
|
PhysX.PxScene_release(scene.physx_scene);
|
|
|
|
free(scene.name);
|
|
fini(*scene.pool);
|
|
free(scene);
|
|
}
|
|
|
|
switch_to_scene :: (scene_name: string) {
|
|
prev := engine.current_scene;
|
|
new_scene := load_scene(scene_name);
|
|
unload_scene(prev);
|
|
}
|
|
|
|
reload_scene :: (scene: *Scene) {
|
|
name := copy_temporary_string(scene.name);
|
|
unload_scene(engine.current_scene);
|
|
load_scene(name);
|
|
}
|
|
|
|
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);
|
|
scene.mode = engine.mode;
|
|
|
|
// Setup allocator
|
|
scene.pool = .{};
|
|
scene.allocator.data = *scene.pool;
|
|
scene.allocator.proc = flat_pool_allocator_proc;
|
|
|
|
init_scene(scene);
|
|
|
|
// 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.physx_scene = create_physx_scene();
|
|
|
|
scene.directional_light.color_and_intensity = .{1,1,1,2};
|
|
scene.directional_light.direction = to_v4(normalize(Vector3.{0.4, -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, id: Entity_Id = -1) {
|
|
entity.scene = scene;
|
|
if id != -1 {
|
|
entity.id = id;
|
|
} else {
|
|
entity.id = next_entity_id;
|
|
next_entity_id += 1;
|
|
}
|
|
|
|
array_add(*scene.entities, entity);
|
|
|
|
#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) {
|
|
if engine.current_scene == null return;
|
|
|
|
for e: engine.current_scene.entities {
|
|
if e.flags & .ANIMATED {
|
|
update_animator(e, *e.animator, dt);
|
|
}
|
|
}
|
|
}
|
|
|
|
update_transforms :: (scene: *Scene) {
|
|
if scene == null return;
|
|
|
|
for e: 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;
|
|
|
|
model := get_model_by_handle(e.renderable.model);
|
|
|
|
for children_index: 0..model_node.children.count-1 {
|
|
index := model_node.children[children_index]-1;
|
|
mn := 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;
|
|
}
|
|
|
|
if length(e.rendering_offset) > 0.0 {
|
|
offset := create_identity_transform();
|
|
set_position(*offset, e.rendering_offset);
|
|
e.transform.world_matrix = parent_matrix * e.transform.model_matrix * offset.model_matrix;
|
|
} else {
|
|
e.transform.world_matrix = parent_matrix * e.transform.model_matrix;
|
|
}
|
|
|
|
if e.flags & .RENDERABLE {
|
|
if e.renderable.model != 0 {
|
|
model := get_model_by_handle(e.renderable.model);
|
|
for model_node, i: 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);
|
|
}
|
|
}
|
|
|
|
get_entity_by_id :: (scene: *Scene, id: s64) -> *Entity {
|
|
for scene.entities {
|
|
if it.id == id return it;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
#scope_file
|
|
next_entity_id: Entity_Id;
|