diff --git a/src/game/console.c b/src/game/console.c index 726c254..c5a999f 100755 --- a/src/game/console.c +++ b/src/game/console.c @@ -159,9 +159,9 @@ void console_on_log_error(struct Console* console, const char* context, const ch void console_command_entity_save(struct Console* console, const char* command) { - char filename[64]; + char filename[MAX_FILENAME_LEN]; char entity_name[MAX_ENTITY_NAME_LEN]; - memset(filename, '\0', 64); + memset(filename, '\0', MAX_FILENAME_LEN); memset(entity_name, '\0', MAX_ENTITY_NAME_LEN); int params_read = sscanf(command, "%s %s", entity_name, filename); @@ -179,7 +179,9 @@ void console_command_entity_save(struct Console* console, const char* command) return; } - if(!entity_save(entity, filename, DIRT_INSTALL)) + char full_filename[MAX_FILENAME_LEN]; + snprintf(full_filename, MAX_FILENAME_LEN, "entities/%s.symtres", filename); + if(!entity_save(entity, full_filename, DIRT_INSTALL)) log_error("entity_save", "Command failed"); } diff --git a/src/game/entity.c b/src/game/entity.c index 4223241..4937b83 100755 --- a/src/game/entity.c +++ b/src/game/entity.c @@ -52,20 +52,18 @@ void entity_reset(struct Entity * entity, int id) bool entity_write(struct Entity* entity, struct Parser_Object* object) { - //if(!object) - //{ - // log_error("entity:write", "Invalid object"); - // return false; - //} + if(!object) + { + log_error("entity:write", "Invalid object"); + return false; + } - ///* First write all properties common to all entity types */ - //struct Hashmap* entity_data = object->data; + /* First write all properties common to all entity types */ + struct Hashmap* entity_data = object->data; - //hashmap_str_set(entity_data, "name", entity->name); - //hashmap_int_set(entity_data, "type", entity->type); - //hashmap_bool_set(entity_data, "is_listener", entity->is_listener); - //hashmap_bool_set(entity_data, "renderable", entity->renderable); - //hashmap_bool_set(entity_data, "has_collision", entity->has_collision); + hashmap_str_set(entity_data, "name", entity->name); + hashmap_int_set(entity_data, "type", entity->type); + hashmap_bool_set(entity_data, "active", entity->active); //if(entity->has_collision) //{ @@ -125,72 +123,71 @@ bool entity_write(struct Entity* entity, struct Parser_Object* object) //hashmap_vec3_set(entity_data, "position", &entity->transform.position); //hashmap_vec3_set(entity_data, "scale", &entity->transform.scale); //hashmap_quat_set(entity_data, "rotation", &entity->transform.rotation); - //switch(entity->type) - //{ - //case ET_CAMERA: - //{ - // struct Camera* camera = &entity->camera; - // hashmap_bool_set(entity_data, "ortho", camera->ortho); - // hashmap_bool_set(entity_data, "resizeable", camera->resizeable); - // hashmap_float_set(entity_data, "fov", camera->fov); - // hashmap_float_set(entity_data, "zoom", camera->zoom); - // hashmap_float_set(entity_data, "nearz", camera->nearz); - // hashmap_float_set(entity_data, "farz", camera->farz); - // hashmap_vec4_set(entity_data, "clear_color", &camera->clear_color); - // if(entity->camera.fbo != -1) - // { - // hashmap_bool_set(entity_data, "has_fbo", true); - // hashmap_int_set(entity_data, "fbo_height", framebuffer_height_get(camera->fbo)); - // hashmap_int_set(entity_data, "fbo_width", framebuffer_width_get(camera->fbo)); - // hashmap_bool_set(entity_data, "fbo_has_render_tex", camera->render_tex == -1 ? false : true); - // hashmap_bool_set(entity_data, "fbo_has_depth_tex", camera->depth_tex == -1 ? false : true); - // } - // else - // { - // hashmap_bool_set(entity_data, "has_fbo", true); - // } - // break; - //} - //case ET_STATIC_MODEL: - //{ - // /* TODO: Change this after adding proper support for exported models from blender */ - // struct Material* material = material_get(entity->model.material); - // struct Geometry* geom = geom_get(entity->model.geometry_index); - // hashmap_str_set(entity_data, "material", material->name); - // hashmap_str_set(entity_data, "geometry", geom->filename); - // break; - //} - //case ET_LIGHT: - //{ - // struct Light* light = &entity->light; - // hashmap_int_set(entity_data, "light_type", light->type); - // hashmap_float_set(entity_data, "outer_angle", light->outer_angle); - // hashmap_float_set(entity_data, "inner_angle", light->inner_angle); - // hashmap_float_set(entity_data, "falloff", light->falloff); - // hashmap_float_set(entity_data, "radius", light->radius); - // hashmap_float_set(entity_data, "intensity", light->intensity); - // hashmap_float_set(entity_data, "depth_bias", light->depth_bias); - // hashmap_bool_set(entity_data, "valid", light->valid); - // hashmap_bool_set(entity_data, "cast_shadow", light->cast_shadow); - // hashmap_bool_set(entity_data, "pcf_enabled", light->pcf_enabled); - // hashmap_vec3_set(entity_data, "color", &light->color); - // break; - //} - //case ET_SOUND_SOURCE: - //{ - // struct Sound_Source* sound_source = &entity->sound_source; - // hashmap_str_set(entity_data, "source_filename", sound_source->source_filename); - // hashmap_bool_set(entity_data, "playing", sound_source->playing); - // hashmap_int_set(entity_data, "sound_type", sound_source->type); - // hashmap_bool_set(entity_data, "loop", sound_source->loop); - // hashmap_float_set(entity_data, "volume", sound_source->volume); - // hashmap_float_set(entity_data, "sound_min_distance", sound_source->min_distance); - // hashmap_float_set(entity_data, "sound_max_distance", sound_source->max_distance); - // hashmap_float_set(entity_data, "rolloff_factor", sound_source->rolloff_factor); - // hashmap_int_set(entity_data, "sound_attenuation_type", sound_source->attenuation_type); - // break; - //} - //}; + switch(entity->type) + { + case ET_CAMERA: + { + struct Camera* camera = (struct Camera*)entity; + hashmap_bool_set(entity_data, "ortho", camera->ortho); + hashmap_bool_set(entity_data, "resizeable", camera->resizeable); + hashmap_float_set(entity_data, "fov", camera->fov); + hashmap_float_set(entity_data, "zoom", camera->zoom); + hashmap_float_set(entity_data, "nearz", camera->nearz); + hashmap_float_set(entity_data, "farz", camera->farz); + hashmap_vec4_set(entity_data, "clear_color", &camera->clear_color); + if(camera->fbo != -1) + { + hashmap_bool_set(entity_data, "has_fbo", true); + hashmap_int_set(entity_data, "fbo_height", framebuffer_height_get(camera->fbo)); + hashmap_int_set(entity_data, "fbo_width", framebuffer_width_get(camera->fbo)); + hashmap_bool_set(entity_data, "fbo_has_render_tex", camera->render_tex == -1 ? false : true); + hashmap_bool_set(entity_data, "fbo_has_depth_tex", camera->depth_tex == -1 ? false : true); + } + else + { + hashmap_bool_set(entity_data, "has_fbo", true); + } + break; + } + case ET_STATIC_MESH: + { + struct Static_Mesh* mesh = (struct Static_Mesh*)entity; + struct Geometry* geom = geom_get(mesh->model.geometry_index); + hashmap_int_set(entity_data, "material", mesh->model.material->type); + hashmap_str_set(entity_data, "geometry", geom->filename); + break; + } + case ET_LIGHT: + { + struct Light* light = (struct Light*)entity; + hashmap_int_set(entity_data, "light_type", light->type); + hashmap_float_set(entity_data, "outer_angle", light->outer_angle); + hashmap_float_set(entity_data, "inner_angle", light->inner_angle); + hashmap_float_set(entity_data, "falloff", light->falloff); + hashmap_float_set(entity_data, "radius", light->radius); + hashmap_float_set(entity_data, "intensity", light->intensity); + hashmap_float_set(entity_data, "depth_bias", light->depth_bias); + hashmap_bool_set(entity_data, "valid", light->valid); + hashmap_bool_set(entity_data, "cast_shadow", light->cast_shadow); + hashmap_bool_set(entity_data, "pcf_enabled", light->pcf_enabled); + hashmap_vec3_set(entity_data, "color", &light->color); + break; + } + case ET_SOUND_SOURCE: + { + struct Sound_Source* sound_source = (struct Sound_Source*)entity; + hashmap_str_set(entity_data, "source_filename", sound_source->source_buffer->filename); + hashmap_bool_set(entity_data, "playing", sound_source->playing); + hashmap_int_set(entity_data, "sound_type", sound_source->type); + hashmap_bool_set(entity_data, "loop", sound_source->loop); + hashmap_float_set(entity_data, "volume", sound_source->volume); + hashmap_float_set(entity_data, "sound_min_distance", sound_source->min_distance); + hashmap_float_set(entity_data, "sound_max_distance", sound_source->max_distance); + hashmap_float_set(entity_data, "rolloff_factor", sound_source->rolloff_factor); + hashmap_int_set(entity_data, "sound_attenuation_type", sound_source->attenuation_type); + break; + } + }; return true; } @@ -209,6 +206,7 @@ bool entity_save(struct Entity* entity, const char* filename, int directory_type if(!entity_write(entity, object)) { log_error("entity:save", "Failed to save entity : %s to file : %s", entity->name, filename); + parser_free(parser); fclose(entity_file); return false; } @@ -218,7 +216,7 @@ bool entity_save(struct Entity* entity, const char* filename, int directory_type parser_free(parser); fclose(entity_file); - return false; + return true; } struct Entity* entity_read(struct Parser_Object* object) diff --git a/src/game/entity.h b/src/game/entity.h index c1eafbe..f1b8c37 100755 --- a/src/game/entity.h +++ b/src/game/entity.h @@ -8,7 +8,6 @@ #include "material.h" #define MAX_ENTITY_NAME_LEN 128 -#define MAX_SOUND_SOURCE_BUFFERS 5 struct Entity; diff --git a/src/game/game.c b/src/game/game.c index b7c5d18..962abaa 100755 --- a/src/game/game.c +++ b/src/game/game.c @@ -77,6 +77,7 @@ bool game_init(struct Window* window, struct Hashmap* cvars) game_state->editor = calloc(1, sizeof(*game_state->editor)); game_state->gui = calloc(1, sizeof(*game_state->gui)); game_state->event_manager = calloc(1, sizeof(*game_state->event_manager)); + game_state->sound = calloc(1, sizeof(*game_state->sound)); log_message_callback_set(game_on_log_message); log_warning_callback_set(game_on_log_warning); @@ -105,6 +106,7 @@ bool game_init(struct Window* window, struct Hashmap* cvars) physics_gravity_set(0.f, -9.8f, 0.f); physics_body_set_moved_callback(entity_rigidbody_on_move); physics_body_set_collision_callback(entity_rigidbody_on_collision); + sound_init(game_state->sound); scene_init(game_state->scene); editor_init(game_state->editor); @@ -545,7 +547,7 @@ void game_post_update(float dt) { input_post_update(); scene_post_update(game_state->scene); - sound_update_3d(); + sound_update_3d(game_state->sound); } void game_debug_gui(float dt) @@ -1887,6 +1889,7 @@ void game_cleanup(void) framebuffer_cleanup(); texture_cleanup(); shader_cleanup(); + sound_cleanup(game_state->sound); event_manager_cleanup(game_state->event_manager); free(game_state->editor); @@ -1895,6 +1898,7 @@ void game_cleanup(void) free(game_state->renderer); free(game_state->event_manager); free(game_state->gui); + free(game_state->sound); } free(game_state); game_state = NULL; diff --git a/src/game/game.h b/src/game/game.h index f7c6477..47ef0e0 100755 --- a/src/game/game.h +++ b/src/game/game.h @@ -13,6 +13,7 @@ struct Gui; struct Event_Manager; struct Editor; struct Hashmap; +struct Sound; enum Game_Mode { @@ -32,6 +33,7 @@ struct Game_State struct Event_Manager* event_manager; struct Editor* editor; struct Hashmap* cvars; + struct Sound* sound; }; diff --git a/src/game/material.c b/src/game/material.c index 97cda64..1db368a 100755 --- a/src/game/material.c +++ b/src/game/material.c @@ -130,12 +130,14 @@ bool material_register_static_mesh(struct Material* material, struct Static_Mesh variant_assign_int(&mesh->model.material_params[MMP_DIFFUSE_TEX], texture_create_from_file("default.tga", TU_DIFFUSE)); variant_assign_float(&mesh->model.material_params[MMP_SPECULAR], 1.f); variant_assign_float(&mesh->model.material_params[MMP_SPECULAR_STRENGTH], 50.f); + mesh->model.material = material; } break; case MAT_UNSHADED: { variant_assign_vec4f(&mesh->model.material_params[MMP_DIFFUSE_COL], 1.f, 0.f, 1.f, 1.f); variant_assign_int(&mesh->model.material_params[MMP_DIFFUSE_TEX], texture_create_from_file("default.tga", TU_DIFFUSE)); + mesh->model.material = material; } break; default: diff --git a/src/game/model.c b/src/game/model.c index 8db43f1..3b7bce5 100755 --- a/src/game/model.c +++ b/src/game/model.c @@ -18,15 +18,15 @@ void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geome assert(model && material_type > -1 && material_type < MAT_MAX); /* if no name is given for geometry, use default */ - int geo_index = geom_create_from_file(geometry_name ? geometry_name : "default.pamesh"); + int geo_index = geom_create_from_file(geometry_name ? geometry_name : "default.symbres"); if(geo_index == -1) { log_error("model:init", "Failed to load model %s", geometry_name); - geo_index = geom_create_from_file("default.pamesh"); + geo_index = geom_create_from_file("default.symbres"); if(geo_index == -1) { - log_error("model:init", "Could not load default model 'default.pamesh' "); + log_error("model:init", "Could not load default model 'default.symbres' "); return; } } @@ -35,7 +35,7 @@ void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geome struct Material* material = &game_state_get()->renderer->materials[material_type]; if(!material_register_static_mesh(material, mesh)) { - log_error("model:create", "Unable to register model with Unshaded material, component not added"); + log_error("model:create", "Unable to register model with Unshaded material"); model_reset(model, mesh); } } diff --git a/src/game/scene.c b/src/game/scene.c index db590e8..ef69931 100755 --- a/src/game/scene.c +++ b/src/game/scene.c @@ -96,6 +96,7 @@ void scene_update(struct Scene* scene, float 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++) { @@ -144,7 +145,7 @@ void scene_post_update(struct Scene* scene) { vec3 abs_pos = { 0.f, 0.f, 0.f }; transform_get_absolute_position(&sound_source->base, &abs_pos); - sound_source_instance_update_position(sound_source->source_instance, abs_pos.x, abs_pos.y, abs_pos.z); + sound_source_instance_update_position(sound, sound_source->source_instance, abs_pos); sound_source->base.transform.is_modified = false; } } @@ -198,16 +199,7 @@ void scene_post_update(struct Scene* scene) if(scene->player.base.transform.is_modified) { - vec3 abs_pos = { 0.f, 0.f, 0.f }; - vec3 abs_fwd = { 0.f, 0.f, -1.f }; - vec3 abs_up = { 0.f, 1.f, 0.f }; - transform_get_absolute_position(&scene->player, &abs_pos); - transform_get_absolute_forward(&scene->player, &abs_fwd); - transform_get_absolute_up(&scene->player, &abs_up); - - sound_listener_update(abs_pos.x, abs_pos.y, abs_pos.z, - abs_fwd.x, abs_fwd.y, abs_fwd.z, - abs_up.x, abs_up.y, abs_up.z); + sound_listener_update(sound); scene->player.base.transform.is_modified = false; } } @@ -329,6 +321,7 @@ struct Static_Mesh* scene_static_mesh_create(struct Scene* scene, const char* na 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++) { @@ -346,7 +339,7 @@ struct Sound_Source* scene_sound_source_create(struct Scene* scene, const char* new_sound_source->base.type = ET_SOUND_SOURCE; struct Entity* entity = &new_sound_source->base; - new_sound_source->source_buffer = sound_source_create(filename, type); + 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); @@ -354,14 +347,10 @@ struct Sound_Source* scene_sound_source_create(struct Scene* scene, const char* return new_sound_source; } - new_sound_source->source_instance = sound_source_instance_create(new_sound_source->source_buffer, true); + 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 }; - vec3 abs_fwd = { 0.f, 0.f, -1.f }; - vec3 abs_up = { 0.f, 1.f, 0.f }; transform_get_absolute_position(entity, &abs_pos); - transform_get_absolute_forward(entity, &abs_fwd); - transform_get_absolute_up(entity, &abs_up); - sound_source_instance_update_position(new_sound_source->source_instance, abs_pos.x, abs_pos.y, abs_pos.z); + 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; @@ -372,13 +361,13 @@ struct Sound_Source* scene_sound_source_create(struct Scene* scene, const char* new_sound_source->volume = 1.f; new_sound_source->type = type; - sound_source_instance_loop_set(new_sound_source->source_instance, new_sound_source->loop); - sound_source_instance_min_max_distance_set(new_sound_source->source_instance, new_sound_source->min_distance, new_sound_source->max_distance); - sound_source_instance_attenuation_set(new_sound_source->source_instance, new_sound_source->attenuation_type, new_sound_source->rolloff_factor); - sound_source_instance_volume_set(new_sound_source->source_instance, new_sound_source->volume); + 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(); - if(new_sound_source->playing) sound_source_instance_play(new_sound_source->source_instance); + sound_update_3d(sound); + if(new_sound_source->playing) sound_source_instance_play(sound, new_sound_source->source_instance); } else { @@ -429,7 +418,7 @@ void scene_sound_source_remove(struct Scene* scene, struct Sound_Source* source) { assert(scene && source); - sound_source_instance_destroy(source->source_instance); + sound_source_instance_destroy(game_state_get()->sound, source->source_instance); source->source_instance = 0; scene_entity_remove(scene, &source->base); } @@ -456,7 +445,7 @@ struct Light* scene_light_find(struct Scene* scene, const char* name) assert(scene && name); struct Light* light = NULL; - for(int i = 0; i < MAX_ENTITIES; i++) + for(int i = 0; i < MAX_LIGHTS; i++) { if(strncmp(name, scene->lights[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { @@ -473,7 +462,7 @@ struct Camera* scene_camera_find(struct Scene* scene, const char* name) assert(scene && name); struct Camera* camera = NULL; - for(int i = 0; i < MAX_ENTITIES; i++) + for(int i = 0; i < MAX_CAMERAS; i++) { if(strncmp(name, scene->cameras[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { @@ -490,7 +479,7 @@ 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_ENTITIES; i++) + for(int i = 0; i < MAX_STATIC_MESHES; i++) { if(strncmp(name, scene->static_meshes[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { @@ -507,7 +496,7 @@ struct Sound_Source* scene_sound_source_find(struct Scene* scene, const char* na assert(scene && name); struct Sound_Source* sound_source = NULL; - for(int i = 0; i < MAX_ENTITIES; i++) + for(int i = 0; i < MAX_SOUND_SOURCES; i++) { if(strncmp(name, scene->sound_sources[i].base.name, MAX_ENTITY_NAME_LEN) == 0) { diff --git a/src/system/file_io.h b/src/system/file_io.h index 94a7195..9f87ef9 100755 --- a/src/system/file_io.h +++ b/src/system/file_io.h @@ -4,6 +4,8 @@ #include #include +#define MAX_FILENAME_LEN 128 + enum Directory_Type { DIRT_USER, /* User directory or preferences directory */ diff --git a/src/system/main.c b/src/system/main.c index 51e90d6..ceb1269 100755 --- a/src/system/main.c +++ b/src/system/main.c @@ -87,12 +87,6 @@ bool init(void) return false; } - if(!sound_init()) - { - log_error("main:init", "Failed to initialize sound"); - return false; - } - return true; } @@ -101,7 +95,6 @@ void cleanup(void) game_cleanup(); if(window) window_destroy(window); log_reset_all_callbacks(); // Now that the game library has been unloaded, reset all callbacks to stubs so we don't crash on exit - sound_cleanup(); platform_unload_gl(); platform_cleanup(); config_vars_cleanup(cvars); diff --git a/src/system/sound.c b/src/system/sound.c index d2e30da..8e041a6 100755 --- a/src/system/sound.c +++ b/src/system/sound.c @@ -4,125 +4,114 @@ #include "../common/hashmap.h" #include "../common/variant.h" #include "../common/string_utils.h" -#include "file_io.h" + +#include "../game/entity.h" +#include "../game/transform.h" #include #include #include +#include #include -struct Sound_Source_Buffer -{ - int type; - union - { - Wav* wav; - WavStream* wavstream; - }; -}; - -struct Sound_State -{ - Soloud* soloud_context; - float volume; -}; - -static struct Sound_State sound_state = -{ - .soloud_context = NULL, - .volume = 1.f -}; - -static struct Hashmap* sound_sources = NULL; - -bool sound_init(void) +bool sound_init(struct Sound* sound) { - sound_sources = hashmap_new(); + sound->soloud_context = Soloud_create(); - sound_state.soloud_context = Soloud_create(); - - if(!sound_state.soloud_context) + if(!sound->soloud_context) { log_error("sound:init", "Failed to create sound context"); return false; } - Soloud_initEx(sound_state.soloud_context, SOLOUD_CLIP_ROUNDOFF | SOLOUD_ENABLE_VISUALIZATION, SOLOUD_SDL2, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO); - Soloud_setGlobalVolume(sound_state.soloud_context, 4); + Soloud_initEx(sound->soloud_context, SOLOUD_CLIP_ROUNDOFF | SOLOUD_ENABLE_VISUALIZATION, SOLOUD_SDL2, SOLOUD_AUTO, SOLOUD_AUTO, SOLOUD_AUTO); + Soloud_setGlobalVolume(sound->soloud_context, 4); - Soloud_set3dListenerParameters(sound_state.soloud_context, + Soloud_set3dListenerParameters(sound->soloud_context, 0.f, 0.f, 0.f, // Position 0.f, 0.f, -1.f, // At 0.f, 1.f, 0.f); // Up + sound->listener = NULL; + + log_message("Sound initialized with %s", Soloud_getBackendString(sound->soloud_context)); - log_message("Sound initialized with %s", Soloud_getBackendString(sound_state.soloud_context)); + for(int i = 0; i < MAX_SOUND_BUFFERS; i++) + { + sound->sound_buffers[i].type = ST_NONE; + memset(sound->sound_buffers[i].filename, '\0', MAX_FILENAME_LEN); + sound->sound_buffers[i].wav = NULL; + } return true; } -void sound_listener_update(float apos_x, float apos_y, float apos_z, - float afwd_x, float afwd_y, float afwd_z, - float aup_x, float aup_y, float aup_z) +void sound_listener_update(struct Sound* sound) { - Soloud_set3dListenerParameters(sound_state.soloud_context, - apos_x, apos_y, apos_z, // Position - afwd_x, afwd_y, afwd_z, // At - aup_x, aup_y, aup_z); // Up + vec3 position = { 0.f, 0.f, 0.f }; + vec3 at = { 0.f, 0.f, -1.f }; + vec3 up = { 0.f, 1.f, 0.f }; + if(sound->listener) + { + transform_get_absolute_position(sound->listener, &position); + transform_get_absolute_forward(sound->listener, &at); + transform_get_absolute_up(sound->listener, &up); + } + + Soloud_set3dListenerParameters(sound->soloud_context, + position.x, position.y, position.z, // Position + at.x, at.y, at.z, // At + up.x, up.y, up.z); // Up } -void sound_volume_set(float volume) +void sound_master_volume_set(struct Sound* sound, float volume) { if(volume < 0.f) volume = 0.f; - sound_state.volume = volume; - Soloud_setGlobalVolume(sound_state.soloud_context, sound_state.volume); + sound->master_volume = volume; + Soloud_setGlobalVolume(sound->soloud_context, sound->master_volume); } -void sound_update_3d(void) +void sound_update_3d(struct Sound* sound) { - Soloud_update3dAudio(sound_state.soloud_context); + Soloud_update3dAudio(sound->soloud_context); } -void sound_cleanup(void) +void sound_cleanup(struct Sound* sound) { - char* key = NULL; - struct Variant* value = NULL; - HASHMAP_FOREACH(sound_sources, key, value) + for(int i = 0; i < MAX_SOUND_BUFFERS; i++ ) { - struct Sound_Source_Buffer* source = value->val_voidptr; - sound_source_stop_all(source); + struct Sound_Source_Buffer* source = &sound->sound_buffers[i]; + sound_source_stop_all(sound, source); switch(source->type) { case ST_WAV: Wav_destroy(source->wav); break; case ST_WAV_STREAM: WavStream_destroy(source->wavstream); break; } - free(source); } - hashmap_free(sound_sources); - Soloud_deinit(sound_state.soloud_context); - Soloud_destroy(sound_state.soloud_context); + Soloud_deinit(sound->soloud_context); + Soloud_destroy(sound->soloud_context); - sound_state.volume = 0.f; - sound_state.soloud_context = NULL; + sound->master_volume = 0.f; + sound->soloud_context = NULL; } -void sound_source_instance_destroy(uint source_instance) +void sound_source_instance_destroy(struct Sound* sound, uint source_instance) { - Soloud_stop(sound_state.soloud_context, source_instance); + Soloud_stop(sound->soloud_context, source_instance); } -void sound_source_instance_update_position(uint source_instance, float apos_x, float apos_y, float apos_z) +void sound_source_instance_update_position(struct Sound* sound, uint source_instance, vec3 abs_pos) { - Soloud_set3dSourceParameters(sound_state.soloud_context, source_instance, apos_x, apos_y, apos_z); + Soloud_set3dSourceParameters(sound->soloud_context, source_instance, abs_pos.x, abs_pos.y, abs_pos.z); } -uint sound_source_instance_create(struct Sound_Source_Buffer* source, bool is3d) +uint sound_source_instance_create(struct Sound* sound, struct Sound_Source_Buffer* source, bool is3d) { assert(source); uint source_instance = 0; if(is3d) { - source_instance = Soloud_play3dEx(sound_state.soloud_context, + source_instance = Soloud_play3dEx(sound->soloud_context, source->type == ST_WAV ? source->wav : source->wavstream, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, @@ -132,88 +121,104 @@ uint sound_source_instance_create(struct Sound_Source_Buffer* source, bool is3d) } else { - source_instance = Soloud_playEx(sound_state.soloud_context, source->type == ST_WAV ? source->wav : source->wavstream, 1.f, 0.0f, true, 0); + source_instance = Soloud_playEx(sound->soloud_context, source->type == ST_WAV ? source->wav : source->wavstream, 1.f, 0.0f, true, 0); } return source_instance; } -void sound_source_instance_volume_set(uint source_instance, float volume) +void sound_source_instance_volume_set(struct Sound* sound, uint source_instance, float volume) { if(volume < 0.f) volume = 0.f; - Soloud_setVolume(sound_state.soloud_context, source_instance, volume); + Soloud_setVolume(sound->soloud_context, source_instance, volume); } -void sound_source_instance_loop_set(uint source_instance, bool loop) +void sound_source_instance_loop_set(struct Sound* sound, uint source_instance, bool loop) { - Soloud_setLooping(sound_state.soloud_context, source_instance, loop); + Soloud_setLooping(sound->soloud_context, source_instance, loop); } -void sound_source_instance_play(uint source_instance) +void sound_source_instance_play(struct Sound* sound, uint source_instance) { - Soloud_setPause(sound_state.soloud_context, source_instance, false); + Soloud_setPause(sound->soloud_context, source_instance, false); } -void sound_source_instance_pause(uint source_instance) +void sound_source_instance_pause(struct Sound* sound, uint source_instance) { - Soloud_setPause(sound_state.soloud_context, source_instance, true); + Soloud_setPause(sound->soloud_context, source_instance, true); } -void sound_source_instance_rewind(uint source_instance) +void sound_source_instance_rewind(struct Sound* sound, uint source_instance) { - Soloud_seek(sound_state.soloud_context, source_instance, 0.0); + Soloud_seek(sound->soloud_context, source_instance, 0.0); } -void sound_source_instance_stop(uint source_instance) +void sound_source_instance_stop(struct Sound* sound, uint source_instance) { - Soloud_stop(sound_state.soloud_context, source_instance); + Soloud_stop(sound->soloud_context, source_instance); } -void sound_source_instance_min_max_distance_set(uint source_instance, float min_distance, float max_distance) +void sound_source_instance_min_max_distance_set(struct Sound* sound, uint source_instance, float min_distance, float max_distance) { - Soloud_set3dSourceMinMaxDistance(sound_state.soloud_context, source_instance, min_distance, max_distance); + Soloud_set3dSourceMinMaxDistance(sound->soloud_context, source_instance, min_distance, max_distance); } -void sound_source_instance_attenuation_set(uint source_instance, int attenuation_type, float rolloff_factor) +void sound_source_instance_attenuation_set(struct Sound* sound, uint source_instance, int attenuation_type, float rolloff_factor) { - Soloud_set3dSourceAttenuation(sound_state.soloud_context, source_instance, attenuation_type, rolloff_factor); + Soloud_set3dSourceAttenuation(sound->soloud_context, source_instance, attenuation_type, rolloff_factor); } -float sound_source_instance_volume_get(uint source_instance) +float sound_source_instance_volume_get(struct Sound* sound, uint source_instance) { - return Soloud_getVolume(sound_state.soloud_context, source_instance); + return Soloud_getVolume(sound->soloud_context, source_instance); } -bool sound_source_instance_loop_get(uint source_instance) +bool sound_source_instance_loop_get(struct Sound* sound, uint source_instance) { - return Soloud_getLooping(sound_state.soloud_context, source_instance); + return Soloud_getLooping(sound->soloud_context, source_instance); } -bool sound_source_instance_is_paused(uint source_instance) +bool sound_source_instance_is_paused(struct Sound* sound, uint source_instance) { - return Soloud_getPause(sound_state.soloud_context, source_instance); + return Soloud_getPause(sound->soloud_context, source_instance); } -struct Sound_Source_Buffer* sound_source_create(const char* filename, int type) +struct Sound_Source_Buffer* sound_source_create(struct Sound* sound, const char* filename, int type) { - if(!filename) return NULL; + if(!filename) + return NULL; - struct Sound_Source_Buffer* source = NULL; + struct Sound_Source_Buffer* source = sound_source_get(sound, filename); - //See if we've already loaded this file - if(hashmap_value_exists(sound_sources, filename)) + // See if we've already loaded this file otherwise, get the next empty slot. + // If we can't find an empty slot, print error and return NULL + if(source) { - source = (struct Sound_Source_Buffer*)hashmap_ptr_get(sound_sources, filename); return source; } + else + { + for(int i = 0; i < MAX_SOUND_BUFFERS; i++) + { + if(sound->sound_buffers[i].type == ST_NONE) + { + source = &sound->sound_buffers[i]; + break; + } + } + + if(!source) + { + log_error("sound:source_create", "Could not find empty sound source slot for '%s'", filename); + return source; + } + } long size = 0L; unsigned char* memory = io_file_read(DIRT_INSTALL, filename, "rb", &size); - - source = malloc(sizeof(*source)); - if(!source) + if(!memory) { - log_error("sound:source_create", "Out of memory!"); - return NULL; + log_error("sound:source_create", "Failed to read file"); + return source; } switch(type) @@ -224,8 +229,8 @@ struct Sound_Source_Buffer* sound_source_create(const char* filename, int type) int rc = Wav_loadMem(wave, memory, (uint)size); if(rc != 0) { - log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound_state.soloud_context, rc)); - free(source); + log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound->soloud_context, rc)); + free(memory); return 0; } source->type = ST_WAV; @@ -238,8 +243,8 @@ struct Sound_Source_Buffer* sound_source_create(const char* filename, int type) int rc = WavStream_loadMem(wave_stream, memory, (uint)size); if(rc != 0) { - log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound_state.soloud_context, rc)); - free(source); + log_error("sound:source_create", "Failed to load %s, Soloud: %s", filename, Soloud_getErrorString(sound->soloud_context, rc)); + free(memory); return 0; } source->type = ST_WAV_STREAM; @@ -248,38 +253,45 @@ struct Sound_Source_Buffer* sound_source_create(const char* filename, int type) default: log_error("sound:source_create", "Invalid source type %d", type); break; } - hashmap_ptr_set(sound_sources, filename, (void*)source); - if(memory) free(memory); + strncpy(source->filename, filename, MAX_FILENAME_LEN); + free(memory); return source; } -struct Sound_Source_Buffer* sound_source_get(const char* name) +struct Sound_Source_Buffer* sound_source_get(struct Sound* sound, const char* name) { struct Sound_Source_Buffer* source = NULL; - if(hashmap_value_exists(sound_sources, name)) + for(int i = 0; i < MAX_SOUND_BUFFERS; i++) { - source = (struct Sound_Source_Buffer*)hashmap_ptr_get(sound_sources, name); + if(sound->sound_buffers[i].type == ST_NONE) + continue; + + if(strncmp(name, sound->sound_buffers[i].filename, MAX_FILENAME_LEN) == 0) + { + source = &sound->sound_buffers[i]; + break; + } } return source; } -void sound_source_destroy(const char* name) +void sound_source_destroy(struct Sound* sound, const char* name) { - struct Sound_Source_Buffer* source = sound_source_get(name); + struct Sound_Source_Buffer* source = sound_source_get(sound, name); if(source) { - sound_source_stop_all(source); + sound_source_stop_all(sound, source); switch(source->type) { - case ST_WAV: Wav_destroy(source->wav); break; - case ST_WAV_STREAM: WavStream_destroy(source->wavstream); break; + case ST_WAV: Wav_destroy(source->wav); source->wav = NULL; break; + case ST_WAV_STREAM: WavStream_destroy(source->wavstream); source->wavstream = NULL; break; } - free(source); + source->type = ST_NONE; + memset(source->filename, '\0', MAX_FILENAME_LEN); } - hashmap_value_remove(sound_sources, name); } -void sound_source_volume_set(struct Sound_Source_Buffer* source, float volume) +void sound_source_volume_set(struct Sound* sound, struct Sound_Source_Buffer* source, float volume) { assert(source); switch(source->type) @@ -289,7 +301,7 @@ void sound_source_volume_set(struct Sound_Source_Buffer* source, float volume) } } -void sound_source_loop_set(struct Sound_Source_Buffer* source, bool loop) +void sound_source_loop_set(struct Sound* sound, struct Sound_Source_Buffer* source, bool loop) { assert(source); switch(source->type) @@ -299,17 +311,17 @@ void sound_source_loop_set(struct Sound_Source_Buffer* source, bool loop) } } -void sound_source_stop_all(struct Sound_Source_Buffer* source) +void sound_source_stop_all(struct Sound* sound, struct Sound_Source_Buffer* source) { assert(source); switch(source->type) { - case ST_WAV: Soloud_stopAudioSource(sound_state.soloud_context, source->wav); break; - case ST_WAV_STREAM: Soloud_stopAudioSource(sound_state.soloud_context, source->wavstream); break; + case ST_WAV: Soloud_stopAudioSource(sound->soloud_context, source->wav); break; + case ST_WAV_STREAM: Soloud_stopAudioSource(sound->soloud_context, source->wavstream); break; } } -void sound_source_min_max_distance_set(struct Sound_Source_Buffer* source, float min_distance, float max_distance) +void sound_source_min_max_distance_set(struct Sound* sound, struct Sound_Source_Buffer* source, float min_distance, float max_distance) { assert(source); switch(source->type) diff --git a/src/system/sound.h b/src/system/sound.h index 62231ea..4e3336a 100755 --- a/src/system/sound.h +++ b/src/system/sound.h @@ -2,10 +2,19 @@ #define SOUND_H #include "../common/num_types.h" +#include "../common/linmath.h" +#include "file_io.h" + +#define MAX_SOUND_BUFFERS 128 + +typedef void* Wav; +typedef void* WavStream; +typedef void* Soloud; enum Sound_Source_Type { - ST_WAV = 0, + ST_NONE = 0, + ST_WAV, ST_WAV_STREAM }; @@ -17,40 +26,53 @@ enum Sound_Attenuation_Type SA_EXPONENTIAL // Exponential distance attenuation model }; -struct Sound_Source_Buffer; - -bool sound_init(void); -void sound_cleanup(void); -void sound_volume_set(float volume); -void sound_update_3d(void); - -void sound_listener_update(float apos_x, float apos_y, float apos_z, - float afwd_x, float afwd_y, float afwd_z, - float aup_x, float aup_y, float aup_z); - - -void sound_source_instance_update_position(uint source_instance, float apos_x, float apos_y, float apos_z); -uint sound_source_instance_create(struct Sound_Source_Buffer* source, bool is3d); -void sound_source_instance_destroy(uint source_instance); -void sound_source_instance_volume_set(uint source_instance, float volume); -void sound_source_instance_loop_set(uint source_instance, bool loop); -void sound_source_instance_play(uint source_instance); -void sound_source_instance_pause(uint source_instance); -void sound_source_instance_rewind(uint source_instance); -void sound_source_instance_stop(uint source_instance); -void sound_source_instance_min_max_distance_set(uint source_instance, float min_distance, float max_distance); -void sound_source_instance_attenuation_set(uint source_instance, int attenuation_type, float rolloff_factor); - -float sound_source_instance_volume_get(uint source_instance); -bool sound_source_instance_loop_get(uint source_instance); -bool sound_source_instance_is_paused(uint source_instance); - -struct Sound_Source_Buffer* sound_source_create(const char* filename, int type); -struct Sound_Source_Buffer* sound_source_get(const char* name); -void sound_source_destroy(const char* buffer_name); -void sound_source_volume_set(struct Sound_Source_Buffer* source, float volume); -void sound_source_loop_set(struct Sound_Source_Buffer* source, bool loop); -void sound_source_stop_all(struct Sound_Source_Buffer* source); -void sound_source_min_max_distance_set(struct Sound_Source_Buffer* source, float min_distance, float max_distance); +struct Sound_Source_Buffer +{ + int type; + char filename[MAX_FILENAME_LEN]; + union + { + Wav* wav; + WavStream* wavstream; + }; +}; + +struct Sound +{ + Soloud* soloud_context; + struct Entity* listener; + float master_volume; + struct Sound_Source_Buffer sound_buffers[MAX_SOUND_BUFFERS]; +}; + +bool sound_init(struct Sound* sound); +void sound_cleanup(struct Sound* sound); +void sound_master_volume_set(struct Sound* sound, float volume); +void sound_update_3d(struct Sound* sound); +void sound_listener_update(struct Sound* sound); + +void sound_source_instance_update_position(struct Sound* sound, uint source_instance, vec3 abs_pos); +uint sound_source_instance_create(struct Sound* sound, struct Sound_Source_Buffer* source, bool is3d); +void sound_source_instance_destroy(struct Sound* sound, uint source_instance); +void sound_source_instance_volume_set(struct Sound* sound, uint source_instance, float volume); +void sound_source_instance_loop_set(struct Sound* sound, uint source_instance, bool loop); +void sound_source_instance_play(struct Sound* sound, uint source_instance); +void sound_source_instance_pause(struct Sound* sound, uint source_instance); +void sound_source_instance_rewind(struct Sound* sound, uint source_instance); +void sound_source_instance_stop(struct Sound* sound, uint source_instance); +void sound_source_instance_min_max_distance_set(struct Sound* sound, uint source_instance, float min_distance, float max_distance); +void sound_source_instance_attenuation_set(struct Sound* sound, uint source_instance, int attenuation_type, float rolloff_factor); + +float sound_source_instance_volume_get(struct Sound* sound, uint source_instance); +bool sound_source_instance_loop_get(struct Sound* sound, uint source_instance); +bool sound_source_instance_is_paused(struct Sound* sound, uint source_instance); + +struct Sound_Source_Buffer* sound_source_create(struct Sound* sound, const char* filename, int type); +struct Sound_Source_Buffer* sound_source_get(struct Sound* sound, const char* name); +void sound_source_destroy(struct Sound* sound, const char* buffer_name); +void sound_source_volume_set(struct Sound* sound, struct Sound_Source_Buffer* source, float volume); +void sound_source_loop_set(struct Sound* sound, struct Sound_Source_Buffer* source, bool loop); +void sound_source_stop_all(struct Sound* sound, struct Sound_Source_Buffer* source); +void sound_source_min_max_distance_set(struct Sound* sound, struct Sound_Source_Buffer* source, float min_distance, float max_distance); #endif diff --git a/todo.txt b/todo.txt index 90d3d14..85eb0b0 100644 --- a/todo.txt +++ b/todo.txt @@ -50,6 +50,8 @@ Todo: - Move Gui_State and Editor_State into game_state and modify usage as needed - Get editor camera speed and other settings from config file - Recompile Soloud on windows to use static sdl2 backend + - Refactor input sub-system to be the same as other sub-systems embedded + in game state. - Figure out a way to reduce of remove snprintf calls from render code - Re-Implement saving/loading scene to/from files - Implement storing console's scroll location and restore it when console is toggled