#include "scene.h" #include "../common/array.h" #include "entity.h" #include "../common/log.h" #include "transform.h" #include "camera.h" #include "../common/parser.h" #include "model.h" #include "light.h" #include "player.h" #include "game.h" #include "bounding_volumes.h" #include "geometry.h" #include "editor.h" #include "../system/sound.h" #include "../system/physics.h" #include "../system/platform.h" #include #include #include void scene_init(struct Scene* scene) { assert(scene); struct Game_State* game_state = game_state_get(); //Initialize the root entity entity_init(&scene->root_entity, "ROOT_ENTITY", NULL); scene->root_entity.active = true; scene->root_entity.id = 0; scene->root_entity.type = ET_ROOT; for(int i = 0; i < MAX_ENTITIES; i++) entity_reset(&scene->entities[i], i); for(int i = 0; i < MAX_LIGHTS; i++) { entity_reset(&scene->lights[i], i); scene->lights[i].type = ET_LIGHT; } for(int i = 0; i < MAX_STATIC_MESHES; i++) { entity_reset(&scene->static_meshes[i], i); struct Static_Mesh* mesh = &scene->static_meshes[i]; mesh->collision.collision_shape = NULL; mesh->collision.rigidbody = NULL; mesh->collision.on_collision = NULL; mesh->model.geometry_index = -1; mesh->model.material = NULL; } for(int i = 0; i < MAX_SOUND_SOURCES; i++) entity_reset(&scene->sound_sources[i], i); int width = 1280, height = 720; window_get_drawable_size(game_state->window, &width, &height); for(int i = 0; i < MAX_CAMERAS; i++) { entity_init(&scene->cameras[i], NULL, &scene->root_entity); camera_init(&scene->cameras[i], width, height); scene->cameras[i].base.id = i; } player_init(&scene->player, scene); editor_init_camera(game_state->editor, game_state->cvars); scene->active_camera_index = game_state_get()->game_mode == GAME_MODE_GAME ? CAM_GAME : CAM_EDITOR; } bool scene_load(struct Scene* scene, const char* filename, int dir_type) { return false; } bool scene_save(struct Scene* scene, const char* filename, int dir_type) { return false; } void scene_destroy(struct Scene* scene) { assert(scene); for(int i = 0; i < MAX_ENTITIES; i++) scene_entity_base_remove(scene, &scene->entities[i]); for(int i = 0; i < MAX_CAMERAS; i++) scene_camera_remove(scene, &scene->cameras[i]); for(int i = 0; i < MAX_LIGHTS; i++) scene_light_remove(scene, &scene->lights[i]); for(int i = 0; i < MAX_STATIC_MESHES; i++) scene_static_mesh_remove(scene, &scene->static_meshes[i]); for(int i = 0; i < MAX_SOUND_SOURCES; i++) scene_sound_source_remove(scene, &scene->sound_sources[i]); player_destroy(&scene->player); entity_reset(&scene->root_entity, 0); scene->root_entity.active = false; } void scene_update(struct Scene* scene, float dt) { if(game_state_get()->game_mode == GAME_MODE_GAME) player_update(&scene->player, scene, dt); } void scene_post_update(struct Scene* scene) { assert(scene); struct Sound* sound = game_state_get()->sound; for(int i = 0; i < MAX_ENTITIES; i++) { struct Entity* entity = &scene->entities[i]; if(!entity->active) continue; if(entity->marked_for_deletion) { scene_entity_base_remove(scene, entity); continue; } if(entity->transform.is_modified) entity->transform.is_modified = false; } for(int i = 0; i < MAX_CAMERAS; i++) { struct Camera* camera = &scene->cameras[i]; if(!camera->base.active) continue; if(camera->base.marked_for_deletion) { scene_camera_remove(scene, camera); continue; } if(camera->base.transform.is_modified) { camera_update_view(camera); camera->base.transform.is_modified = false; } } for(int i = 0; i < MAX_SOUND_SOURCES; i++) { struct Sound_Source* sound_source = &scene->sound_sources[i]; if(!sound_source->base.active) continue; if(sound_source->base.marked_for_deletion) { scene_sound_source_remove(scene, sound_source); continue; } if(sound_source->base.transform.is_modified) { vec3 abs_pos = { 0.f, 0.f, 0.f }; transform_get_absolute_position(&sound_source->base, &abs_pos); sound_source_instance_update_position(sound, sound_source->source_instance, abs_pos); sound_source->base.transform.is_modified = false; } } for(int i = 0; i < MAX_STATIC_MESHES; i++) { struct Static_Mesh* static_mesh = &scene->static_meshes[i]; if(!static_mesh->base.active) continue; if(static_mesh->base.marked_for_deletion) { scene_static_mesh_remove(scene, static_mesh); continue; } if(static_mesh->base.transform.is_modified) { if(static_mesh->collision.rigidbody && static_mesh->base.transform.sync_physics) { quat abs_rot = { 0.f, 0.f, 0.f, 1.f }; vec3 abs_pos = { 0.f, 0.f, 0.f }; transform_get_absolute_rot(&static_mesh->base, &abs_rot); transform_get_absolute_position(&static_mesh->base, &abs_pos); physics_body_rotation_set(static_mesh->collision.rigidbody, abs_rot.x, abs_rot.y, abs_rot.z, abs_rot.w); physics_body_position_set(static_mesh->collision.rigidbody, abs_pos.x, abs_pos.y, abs_pos.z); } static_mesh->base.transform.sync_physics = false; static_mesh->base.transform.is_modified = false; } } for(int i = 0; i < MAX_LIGHTS; i++) { struct Light* light = &scene->lights[i]; if(!light->base.active) continue; if(light->base.marked_for_deletion) { scene_light_remove(scene, light); continue; } if(light->base.transform.is_modified) light->base.transform.is_modified = false; } for(int i = 0; i < MAX_ENTITIES; i++) { struct Entity* entity = &scene->entities[i]; if(!entity->active) continue; } if(scene->player.base.transform.is_modified) { sound_listener_update(sound); scene->player.base.transform.is_modified = false; } } struct Entity* scene_entity_create(struct Scene* scene, const char* name, struct Entity* parent) { assert(scene); struct Entity* new_entity = NULL; for(int i = 0; i < MAX_ENTITIES; i++) { struct Entity* entity = &scene->entities[i]; if(!entity->active) { new_entity = entity; break; } } if(new_entity) { if(!parent) parent = &scene->root_entity; entity_init(new_entity, name, parent); } else { log_error("scene:entity_create", "Max entity limit reached!"); } return new_entity; } struct Light* scene_light_create(struct Scene* scene, const char* name, struct Entity* parent, int light_type) { assert(scene); struct Light* new_light = NULL; for(int i = 0; i < MAX_LIGHTS; i++) { struct Light* light = &scene->lights[i]; if(!light->base.active) { new_light = light; break; } } if(new_light) { entity_init(&new_light->base, name, parent ? parent : &scene->root_entity); new_light->base.type = ET_LIGHT; light_init(new_light, light_type); } else { log_error("scene:light_create", "Max light limit reached!"); } return new_light; } struct Camera* scene_camera_create(struct Scene* scene, const char* name, struct Entity* parent, int width, int height) { assert(scene); struct Camera* new_camera = NULL; for(int i = 0; i < MAX_CAMERAS; i++) { struct Camera* camera = &scene->cameras[i]; if(!camera->base.active) { new_camera = camera; break; } } if(new_camera) { entity_init(&new_camera->base, name, parent ? parent : &scene->root_entity); new_camera->base.type = ET_CAMERA; camera_init(new_camera, width, height); } else { log_error("scene:camera_create", "Max camera limit reached!"); } return new_camera; } struct Static_Mesh* scene_static_mesh_create(struct Scene* scene, const char* name, struct Entity* parent, const char* geometry_name, int material_type) { assert(scene); struct Static_Mesh* new_static_mesh = NULL; for(int i = 0; i < MAX_STATIC_MESHES; i++) { struct Static_Mesh* static_mesh = &scene->static_meshes[i]; if(!static_mesh->base.active) { new_static_mesh = static_mesh; break; } } if(new_static_mesh) { entity_init(&new_static_mesh->base, name, parent ? parent : &scene->root_entity); new_static_mesh->base.type = ET_STATIC_MESH; model_init(&new_static_mesh->model, new_static_mesh, geometry_name, material_type); // TODO: handle creating collision mesh for the model at creation } else { log_error("scene:model_create", "Max model limit reached!"); } return new_static_mesh; } struct Sound_Source* scene_sound_source_create(struct Scene* scene, const char* name, struct Entity* parent, const char* filename, int type, bool loop, bool play) { assert(scene && filename); struct Sound* sound = game_state_get()->sound; struct Sound_Source* new_sound_source = NULL; for(int i = 0; i < MAX_SOUND_SOURCES; i++) { struct Sound_Source* sound_source = &scene->static_meshes[i]; if(!sound_source->base.active) { new_sound_source = sound_source; break; } } if(new_sound_source) { entity_init(&new_sound_source->base, name, parent ? parent : &scene->root_entity); new_sound_source->base.type = ET_SOUND_SOURCE; struct Entity* entity = &new_sound_source->base; new_sound_source->source_buffer = sound_source_create(sound, filename, type); if(!new_sound_source->source_buffer) { log_error("entity:sync_sound_params", "Failed to load file '%s' to provide sound source for entity %s", filename, entity->name); new_sound_source->source_instance = 0; return new_sound_source; } new_sound_source->source_instance = sound_source_instance_create(sound, new_sound_source->source_buffer, true); vec3 abs_pos = { 0.f, 0.f, 0.f }; transform_get_absolute_position(entity, &abs_pos); sound_source_instance_update_position(sound, new_sound_source->source_instance, abs_pos); new_sound_source->loop = loop; new_sound_source->min_distance = 0.f; new_sound_source->max_distance = 10.f; new_sound_source->playing = play; new_sound_source->attenuation_type = SA_INVERSE; new_sound_source->rolloff_factor = 0.95f; new_sound_source->volume = 1.f; new_sound_source->type = type; sound_source_instance_loop_set(sound, new_sound_source->source_instance, new_sound_source->loop); sound_source_instance_min_max_distance_set(sound, new_sound_source->source_instance, new_sound_source->min_distance, new_sound_source->max_distance); sound_source_instance_attenuation_set(sound, new_sound_source->source_instance, new_sound_source->attenuation_type, new_sound_source->rolloff_factor); sound_source_instance_volume_set(sound, new_sound_source->source_instance, new_sound_source->volume); sound_update_3d(sound); if(new_sound_source->playing) sound_source_instance_play(sound, new_sound_source->source_instance); } else { log_error("scene:sound_source_create", "Max sound source limit reached!"); } return new_sound_source; } void scene_entity_base_remove(struct Scene* scene, struct Entity* entity) { assert(scene && entity && entity->id >= 0); if(!entity->active) return; transform_destroy(entity); entity->active = false; entity->selected_in_editor = false; entity->marked_for_deletion = false; memset(entity->name, '\0', MAX_ENTITY_NAME_LEN); } void scene_light_remove(struct Scene* scene, struct Light* light) { assert(scene && light); scene_entity_base_remove(scene, &light->base); } void scene_camera_remove(struct Scene* scene, struct Camera* camera) { assert(scene && camera); scene_entity_base_remove(scene, &camera->base); } void scene_static_mesh_remove(struct Scene* scene, struct Static_Mesh* mesh) { assert(scene && mesh); mesh->collision.on_collision = NULL; if(mesh->collision.collision_shape) physics_cs_remove(mesh->collision.collision_shape); if(mesh->collision.rigidbody) physics_body_remove(mesh->collision.rigidbody); model_reset(&mesh->model, mesh); scene_entity_base_remove(scene, &mesh->base); } void scene_sound_source_remove(struct Scene* scene, struct Sound_Source* source) { assert(scene && source); sound_source_instance_destroy(game_state_get()->sound, source->source_instance); source->source_instance = 0; scene_entity_base_remove(scene, &source->base); } struct Entity* scene_entity_find(struct Scene* scene, const char* name) { assert(scene && name); struct Entity* entity = NULL; for(int i = 0; i < MAX_ENTITIES; i++) { if(strncmp(name, scene->entities[i].name, MAX_ENTITY_NAME_LEN) == 0) { entity = &scene->entities[i]; break; } } return entity; } struct Light* scene_light_find(struct Scene* scene, const char* name) { assert(scene && name); struct Light* light = NULL; for(int i = 0; i < MAX_LIGHTS; i++) { if(strncmp(name, scene->lights[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { light = &scene->lights[i]; break; } } return light; } struct Camera* scene_camera_find(struct Scene* scene, const char* name) { assert(scene && name); struct Camera* camera = NULL; for(int i = 0; i < MAX_CAMERAS; i++) { if(strncmp(name, scene->cameras[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { camera = &scene->cameras[i]; break; } } return camera; } struct Static_Mesh* scene_static_mesh_find(struct Scene* scene, const char* name) { assert(scene && name); struct Static_Mesh* static_mesh = NULL; for(int i = 0; i < MAX_STATIC_MESHES; i++) { if(strncmp(name, scene->static_meshes[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { static_mesh = &scene->static_meshes[i]; break; } } return static_mesh; } struct Sound_Source* scene_sound_source_find(struct Scene* scene, const char* name) { assert(scene && name); struct Sound_Source* sound_source = NULL; for(int i = 0; i < MAX_SOUND_SOURCES; i++) { if(strncmp(name, scene->sound_sources[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { sound_source = &scene->sound_sources[i]; break; } } return sound_source; } struct Entity* scene_base_entity_get(struct Scene* scene, int id, int type) { assert(scene && id != -1 && type < ET_MAX); struct Entity* entity = NULL; switch(type) { case ET_DEFAULT: entity = &scene->entities[id]; break; case ET_CAMERA: entity = &scene->cameras[id]; break; case ET_LIGHT: entity = &scene->lights[id]; break; case ET_STATIC_MESH: entity = &scene->static_meshes[id]; break; case ET_SOUND_SOURCE: entity = &scene->sound_sources[id]; break; case ET_PLAYER: entity = &scene->player; break; case ET_ROOT: entity = &scene->root_entity; break; } return entity; } void* scene_find(struct Scene* scene, const char* name) { void* entity = NULL; entity = scene_entity_find(scene, name); if(entity) return entity; entity = scene_light_find(scene, name); if(entity) return entity; entity = scene_camera_find(scene, name); if(entity) return entity; entity = scene_static_mesh_find(scene, name); if(entity) return entity; return entity; } void scene_entity_parent_reset(struct Scene* scene, struct Entity* entity) { assert(scene && entity); transform_parent_set(entity, &scene->root_entity, true); } void scene_entity_parent_set(struct Scene* scene, struct Entity* entity, struct Entity* parent) { assert(scene && entity && parent); transform_parent_set(entity, parent, true); } void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Result* out_results) { assert(out_results); memset(&out_results[0], '\0', sizeof(struct Entity*) * MAX_RAYCAST_ENTITIES_INTERSECT); out_results->num_entities_intersected = 0; for(int i = 0; i < MAX_STATIC_MESHES; i++) { struct Static_Mesh* mesh = &scene->static_meshes[i]; if(!mesh->base.active) continue; vec3 abs_pos = { 0.f }; transform_get_absolute_position(mesh, &abs_pos); struct Geometry* geometry = geom_get(mesh->model.geometry_index); if(bv_intersect_sphere_ray(&geometry->bounding_sphere, &abs_pos, ray)) { out_results->entities_intersected[out_results->num_entities_intersected] = &mesh->base; out_results->num_entities_intersected++; } } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool scene_load_(const char* filename, int directory_type) { // FILE* entity_file = platform->file.open(directory_type, filename, "r"); //if(!entity_file) //{ // log_error("scene:load", "Failed to open scenefile %s for reading", filename); // return false; //} //int count = 0; //int eof_char = -1; //while(!feof(entity_file)) //{ // if(eof_char != -1) ungetc(eof_char, entity_file); // struct Entity* new_entity = NULL; // new_entity = entity_read(entity_file); // if(!new_entity) // { // log_error("scene:load", "Error reading entity"); // } // else // { // log_message("Loaded %s", new_entity->name); // count++; // } // eof_char = fgetc(entity_file); // /* To check end of file, we get the next character and before beginning // loop we check if eof occured, feof only returns true if the last read // was an eof. If it wasn't eof then we return the character back to the // stream and carry on. */ //} //log_message("%d entites loaded from %s", count, filename); //fclose(entity_file); return entity_load(filename, directory_type); } bool scene_save_(const char* filename, int directory_type) { bool success = false; /*FILE* scene_file = platform->file.open(directory_type, filename, "w"); if(!scene_file) { log_error("scene:save", "Failed to create scenefile %s for writing", filename); return false; } struct Parser* parser = parser_new(); if(!parser) { log_error("scene:save", "Could not create Parser"); fclose(scene_file); return false; } int* entities_to_write = array_new(int); array_push(entities_to_write, root_node, int); bool done = false; int count = 0; while(!done) { struct Entity* entity = entity_get(entities_to_write[0]); struct Parser_Object* object = parser_object_new(parser, PO_ENTITY); if(!object) { log_error("scene:save", "Failed to create parser object for %s", entity->name); continue; } if(!entity_write(entity, object)) { log_error("scene:save", "Failed to write '%s' into parser object", entity->name); continue; } log_message("Entity '%s' written to file", entity->name); count++; for(int i = 0; i < array_len(entity->transform.children); i++) array_push(entities_to_write, entity->transform.children[i], int); array_remove_at(entities_to_write, 0); if(array_len(entities_to_write) == 0) done = true; } if(parser_write_objects(parser, scene_file, filename)) { log_message("%d entities written to %s", count, filename); } else { log_error("scene:save", "Failed to write scene to %s", filename); success = false; } array_free(entities_to_write); parser_free(parser); fclose(scene_file);*/ return success; }