Implemented reading/writing static meshes & their material properties to file. Implemented viewing/editing static mesh properties in editor

dev
Shariq Shah 6 years ago
parent 78992826d6
commit 7413dec494
  1. 5
      src/common/hashmap.c
  2. 85
      src/game/editor.c
  3. 46
      src/game/entity.c
  4. 2
      src/game/game.c
  5. 29
      src/game/model.c
  6. 3
      src/game/model.h
  7. 6
      src/game/texture.c
  8. 1
      src/game/texture.h
  9. 5
      todo.txt

@ -101,7 +101,10 @@ struct Variant* hashmap_value_get(const struct Hashmap* hashmap, const char* key
int compare_len = key_len < HASH_MAX_KEY_LEN ? key_len : HASH_MAX_KEY_LEN; int compare_len = key_len < HASH_MAX_KEY_LEN ? key_len : HASH_MAX_KEY_LEN;
for(int i = 0; i < array_len(hashmap->buckets[index]); i++) for(int i = 0; i < array_len(hashmap->buckets[index]); i++)
{ {
if(strncmp(key, hashmap->buckets[index][i].key, compare_len) == 0) // Check for the length of the key to avoid partial matches. We might be looking for
// "Diffuse" and we'll get matched to "Diffuse_Color" if we're relying on the length
// of "Diffuse" only
if(strnlen(hashmap->buckets[index][i].key, HASH_MAX_KEY_LEN) == compare_len && strncmp(key, hashmap->buckets[index][i].key, compare_len) == 0)
{ {
value = &hashmap->buckets[index][i].value; value = &hashmap->buckets[index][i].value;
break; break;

@ -1783,16 +1783,16 @@ void editor_window_property_inspector(struct nk_context* context, struct Editor*
sound_source_instance_volume_set(sound, sound_source->source_instance, volume); sound_source_instance_volume_set(sound, sound_source->source_instance, volume);
nk_layout_row_dynamic(context, 30, 2); nk_layout_row_dynamic(context, 30, 2);
static char filename_buffer[MAX_FILENAME_LEN]; static char sound_source_filename_buffer[MAX_FILENAME_LEN];
strncpy(filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN); strncpy(sound_source_filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN);
nk_label(context, "File", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE); nk_label(context, "File", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER; int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
int edit_state = nk_edit_string_zero_terminated(context, edit_flags, filename_buffer, MAX_FILENAME_LEN, NULL); int edit_state = nk_edit_string_zero_terminated(context, edit_flags, sound_source_filename_buffer, MAX_FILENAME_LEN, NULL);
if(edit_state & NK_EDIT_COMMITED) if(edit_state & NK_EDIT_COMMITED)
{ {
if(strncmp(filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN) != 0) if(strncmp(sound_source_filename_buffer, sound_source->source_buffer->filename, MAX_FILENAME_LEN) != 0)
{ {
struct Sound_Source_Buffer* new_source_buffer = sound_source_create(sound, filename_buffer, ST_WAV_STREAM); struct Sound_Source_Buffer* new_source_buffer = sound_source_create(sound, sound_source_filename_buffer, ST_WAV_STREAM);
if(new_source_buffer) if(new_source_buffer)
{ {
sound_source_stop_all(sound, sound_source->source_buffer); sound_source_stop_all(sound, sound_source->source_buffer);
@ -1810,6 +1810,79 @@ void editor_window_property_inspector(struct nk_context* context, struct Editor*
} }
} }
/* Static Mesh */
if(entity->type == ET_STATIC_MESH)
{
struct Static_Mesh* mesh = (struct Static_Mesh*)entity;
if(nk_tree_push(context, NK_TREE_TAB, "Static Mesh", NK_MAXIMIZED))
{
nk_layout_row_dynamic(context, 30, 2);
nk_label(context, "Geometry", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
static char geometry_filename_buffer[MAX_FILENAME_LEN];
int edit_flags = NK_EDIT_GOTO_END_ON_ACTIVATE | NK_EDIT_FIELD | NK_EDIT_SIG_ENTER;
struct Geometry* geometry = geom_get(mesh->model.geometry_index);
strncpy(geometry_filename_buffer, geometry->filename, MAX_FILENAME_LEN);
int geometry_buffer_edit_state = nk_edit_string_zero_terminated(context, edit_flags, geometry_filename_buffer, MAX_FILENAME_LEN, NULL);
if(geometry_buffer_edit_state & NK_EDIT_COMMITED)
{
if(strncmp(geometry->filename, geometry_filename_buffer, MAX_FILENAME_LEN) != 0)
{
model_geometry_set(&mesh->model, &geometry_filename_buffer);
}
}
nk_layout_row_dynamic(context, row_height, 2);
nk_label(context, "Material", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
static const char* material_types[] = { "Blinn", "Unshaded" };
int selected_material = nk_combo(context, material_types, 2, mesh->model.material->type, row_height, nk_vec2(180, 180));
if(selected_material != mesh->model.material->type)
{
material_unregister_static_mesh(mesh->model.material, mesh);
struct Material* new_material = &game_state_get()->renderer->materials[selected_material];
if(!material_register_static_mesh(new_material, mesh))
{
log_error("editor:update", "Failed to register mesh with material");
}
}
nk_layout_row_dynamic(context, row_height, 2);
nk_label(context, "Diffuse Color", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
editor_widget_color_combov4(context, &mesh->model.material_params[MMP_DIFFUSE_COL].val_vec4, 200, 300);
nk_layout_row_dynamic(context, row_height, 1);
mesh->model.material_params[MMP_DIFFUSE].val_float = nk_propertyf(context, "Diffuse", 0.f, mesh->model.material_params[MMP_DIFFUSE].val_float, 10.f, 0.5f, 0.1f);
nk_layout_row_dynamic(context, 30, 2);
nk_label(context, "Diffuse Texture", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
static char diffuse_tex_filename_buffer[MAX_FILENAME_LEN];
const char* texture_name = texture_get_name(mesh->model.material_params[MMP_DIFFUSE_TEX].val_int);
strncpy(diffuse_tex_filename_buffer, texture_name, MAX_FILENAME_LEN);
int diffuse_texture_buffer_edit_state = nk_edit_string_zero_terminated(context, edit_flags, diffuse_tex_filename_buffer, MAX_FILENAME_LEN, NULL);
if(diffuse_texture_buffer_edit_state & NK_EDIT_COMMITED)
{
if(strncmp(texture_name, diffuse_tex_filename_buffer, MAX_FILENAME_LEN) != 0)
{
int new_diffuse_texture = texture_create_from_file(&diffuse_tex_filename_buffer, TU_DIFFUSE);
if(new_diffuse_texture != -1)
{
mesh->model.material_params[MMP_DIFFUSE_TEX].val_int = new_diffuse_texture;
}
}
}
if(mesh->model.material->type == MAT_BLINN)
{
nk_layout_row_dynamic(context, row_height, 1);
mesh->model.material_params[MMP_SPECULAR].val_float = nk_propertyf(context, "Specular", 0.f, mesh->model.material_params[MMP_SPECULAR].val_float, 10.f, 0.5f, 0.1f);
nk_layout_row_dynamic(context, row_height, 1);
mesh->model.material_params[MMP_SPECULAR_STRENGTH].val_float = nk_propertyf(context, "Specular Strength", 0.f, mesh->model.material_params[MMP_SPECULAR_STRENGTH].val_float, 100.f, 0.5f, 0.1f);
}
nk_tree_pop(context);
}
}
} }
else else
{ {
@ -1835,13 +1908,13 @@ void editor_window_renderer_settings(struct nk_context* context, struct Editor*
struct Render_Settings* render_settings = &game_state->renderer->settings; struct Render_Settings* render_settings = &game_state->renderer->settings;
if(nk_tree_push(context, NK_TREE_TAB, "Debug", NK_MAXIMIZED)) if(nk_tree_push(context, NK_TREE_TAB, "Debug", NK_MAXIMIZED))
{ {
static const char* draw_modes[] = { "Triangles", "Lines", "Points" };
nk_layout_row_dynamic(context, row_height, 2); nk_layout_row_dynamic(context, row_height, 2);
nk_label(context, "Debug Draw", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE); nk_label(context, "Debug Draw", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
render_settings->debug_draw_enabled = nk_check_label(context, "", render_settings->debug_draw_enabled); render_settings->debug_draw_enabled = nk_check_label(context, "", render_settings->debug_draw_enabled);
nk_layout_row_dynamic(context, row_height, 2); nk_layout_row_dynamic(context, row_height, 2);
nk_label(context, "Debug Draw Mode", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE); nk_label(context, "Debug Draw Mode", NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_MIDDLE);
static const char* draw_modes[] = { "Triangles", "Lines", "Points" };
render_settings->debug_draw_mode = nk_combo(context, draw_modes, 3, render_settings->debug_draw_mode, 20, nk_vec2(180, 100)); render_settings->debug_draw_mode = nk_combo(context, draw_modes, 3, render_settings->debug_draw_mode, 20, nk_vec2(180, 100));
nk_layout_row_dynamic(context, row_height, 2); nk_layout_row_dynamic(context, row_height, 2);

@ -17,6 +17,7 @@
#include "../system/physics.h" #include "../system/physics.h"
#include "scene.h" #include "scene.h"
#include "game.h" #include "game.h"
#include "texture.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -160,6 +161,24 @@ bool entity_write(struct Entity* entity, struct Parser_Object* object, bool writ
struct Static_Mesh* mesh = (struct Static_Mesh*)entity; struct Static_Mesh* mesh = (struct Static_Mesh*)entity;
struct Geometry* geom = geom_get(mesh->model.geometry_index); struct Geometry* geom = geom_get(mesh->model.geometry_index);
hashmap_int_set(entity_data, "material", mesh->model.material->type); hashmap_int_set(entity_data, "material", mesh->model.material->type);
//Set material model params for this particular mesh
struct Model* model = &mesh->model;
switch(model->material->type)
{
case MAT_BLINN:
hashmap_vec4_set(entity_data, "diffuse_color", &model->material_params[MMP_DIFFUSE_COL].val_vec4);
hashmap_str_set(entity_data, "diffuse_texture", texture_get_name(model->material_params[MMP_DIFFUSE_TEX].val_int));
hashmap_float_set(entity_data, "diffuse", model->material_params[MMP_DIFFUSE].val_float);
hashmap_float_set(entity_data, "specular", model->material_params[MMP_SPECULAR].val_float);
hashmap_float_set(entity_data, "specular_strength", model->material_params[MMP_SPECULAR_STRENGTH].val_float);
break;
case MAT_UNSHADED:
hashmap_vec3_set(entity_data, "diffuse_color", &mesh->model.material_params[MMP_DIFFUSE_COL].val_vec3);
hashmap_int_set(entity_data, "diffuse_texture", mesh->model.material_params[MMP_DIFFUSE_TEX].val_int);
break;
};
hashmap_str_set(entity_data, "geometry", geom->filename); hashmap_str_set(entity_data, "geometry", geom->filename);
break; break;
} }
@ -389,9 +408,34 @@ struct Entity* entity_read(struct Parser_Object* object, struct Entity* parent_e
const char* geometry_name = NULL; const char* geometry_name = NULL;
int material_type = MAT_UNSHADED; int material_type = MAT_UNSHADED;
if(hashmap_value_exists(object->data, "geometry")) geometry_name = hashmap_str_get(object->data, "geometry"); if(hashmap_value_exists(object->data, "geometry")) geometry_name = hashmap_str_get(object->data, "geometry");
if(hashmap_value_exists(object->data, "material_type")) material_type = hashmap_int_get(object->data, "material_type"); if(hashmap_value_exists(object->data, "material")) material_type = hashmap_int_get(object->data, "material");
struct Static_Mesh* mesh = scene_static_mesh_create(scene, name, parent_entity, geometry_name, material_type); struct Static_Mesh* mesh = scene_static_mesh_create(scene, name, parent_entity, geometry_name, material_type);
new_entity = &mesh->base; new_entity = &mesh->base;
//Set material model params for this particular mesh
struct Model* model = &mesh->model;
switch(model->material->type)
{
case MAT_BLINN:
if(hashmap_value_exists(object->data, "diffuse_color")) model->material_params[MMP_DIFFUSE_COL].val_vec4 = hashmap_vec4_get(object->data, "diffuse_color");
if(hashmap_value_exists(object->data, "diffuse_texture"))
{
const char* texture_name = hashmap_str_get(object->data, "diffuse_texture");
model->material_params[MMP_DIFFUSE_TEX].val_int = texture_create_from_file(texture_name, TU_DIFFUSE);
}
if(hashmap_value_exists(object->data, "diffuse")) model->material_params[MMP_DIFFUSE].val_float = hashmap_float_get(object->data, "diffuse");
if(hashmap_value_exists(object->data, "specular")) model->material_params[MMP_SPECULAR].val_float = hashmap_float_get(object->data, "specular");
if(hashmap_value_exists(object->data, "specular_strength")) model->material_params[MMP_SPECULAR_STRENGTH].val_float = hashmap_float_get(object->data, "specular_strength");
break;
case MAT_UNSHADED:
if(hashmap_value_exists(object->data, "diffuse_color")) model->material_params[MMP_DIFFUSE_COL].val_vec4 = hashmap_vec4_get(object->data, "diffuse_color");
if(hashmap_value_exists(object->data, "diffuse_texture"))
{
const char* texture_name = hashmap_str_get(object->data, "diffuse_texture");
model->material_params[MMP_DIFFUSE_TEX].val_int = texture_create_from_file(texture_name, TU_DIFFUSE);
}
break;
};
} }
break; break;
case ET_ROOT: case ET_ROOT:

@ -328,7 +328,7 @@ void game_scene_setup(void)
suzanne->model.material_params[MMP_DIFFUSE].val_float = 0.5f; suzanne->model.material_params[MMP_DIFFUSE].val_float = 0.5f;
suzanne->model.material_params[MMP_SPECULAR].val_float = 1.f; suzanne->model.material_params[MMP_SPECULAR].val_float = 1.f;
suzanne->model.material_params[MMP_SPECULAR_STRENGTH].val_float = 1.f; suzanne->model.material_params[MMP_SPECULAR_STRENGTH].val_float = 1.f;
vec3_fill(&suzanne->model.material_params[MMP_DIFFUSE_COL].val_vec3, 1.f, 0.f, 1.f); vec4_fill(&suzanne->model.material_params[MMP_DIFFUSE_COL].val_vec4, 1.f, 0.f, 1.f, 1.f);
suz_pos.x = 0.f; suz_pos.x = 0.f;
suz_pos.y = 5.f; suz_pos.y = 5.f;
suz_pos.z = 5.f; suz_pos.z = 5.f;

@ -20,18 +20,9 @@ void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geome
/* if no name is given for geometry, use default */ /* if no name is given for geometry, use default */
int geo_index = geom_create_from_file(geometry_name ? geometry_name : "default.symbres"); int geo_index = geom_create_from_file(geometry_name ? geometry_name : "default.symbres");
if(geo_index == -1) if(!model_geometry_set(model, geometry_name))
{
log_error("model:init", "Failed to load model %s", geometry_name);
geo_index = geom_create_from_file("default.symbres");
if(geo_index == -1)
{
log_error("model:init", "Could not load default model 'default.symbres' ");
return; return;
}
}
model->geometry_index = geo_index;
struct Material* material = &game_state_get()->renderer->materials[material_type]; struct Material* material = &game_state_get()->renderer->materials[material_type];
if(!material_register_static_mesh(material, mesh)) if(!material_register_static_mesh(material, mesh))
{ {
@ -40,6 +31,24 @@ void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geome
} }
} }
bool model_geometry_set(struct Model* model, const char* geometry_name)
{
/* if no name is given for geometry, use default */
int geo_index = geom_create_from_file(geometry_name ? geometry_name : "default.symbres");
if(geo_index == -1)
{
log_error("model:geometry_set", "Failed to load model %s", geometry_name);
geo_index = geom_create_from_file("default.symbres");
if(geo_index == -1)
{
log_error("model:geometry_set", "Could not load default model 'default.symbres' ");
return false;
}
}
model->geometry_index = geo_index;
return true;
}
void model_reset(struct Model* model, struct Static_Mesh* mesh) void model_reset(struct Model* model, struct Static_Mesh* mesh)
{ {
assert(model); assert(model);

@ -1,10 +1,13 @@
#ifndef MODEL_H #ifndef MODEL_H
#define MODEL_H #define MODEL_H
#include <stdbool.h>
struct Model; struct Model;
struct Static_Mesh; struct Static_Mesh;
void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geometry_name, int material_type); void model_init(struct Model* model, struct Static_Mesh* mesh, const char* geometry_name, int material_type);
bool model_geometry_set(struct Model* model, const char* geometry_name);
void model_reset(struct Model* model, struct Static_Mesh* mesh); void model_reset(struct Model* model, struct Static_Mesh* mesh);
#endif #endif

@ -441,3 +441,9 @@ void texture_resize(int index, int width, int height, const void* data)
if(curr_texture != 0) if(curr_texture != 0)
glBindTexture(GL_TEXTURE_2D, curr_texture); glBindTexture(GL_TEXTURE_2D, curr_texture);
} }
const char* texture_get_name(int index)
{
assert(index > -1 && index < array_len(texture_list));
return texture_list[index].name;
}

@ -31,5 +31,6 @@ int texture_create(const char* name,
int type, int type,
const void* data); const void* data);
void texture_resize(int index, int width, int height, const void* data); void texture_resize(int index, int width, int height, const void* data);
const char* texture_get_name(int index);
#endif #endif

@ -1,5 +1,4 @@
Todo: Todo:
- Finish mesh and material properties serialization to and from file
- Scene read/write to file with scene file only containing names of - Scene read/write to file with scene file only containing names of
entity archetypes entity archetypes
- Console command to read/write scene to/from file - Console command to read/write scene to/from file
@ -98,6 +97,7 @@ Todo:
- Profit! - Profit!
Improvements: Improvements:
- Make selected mesh wireframe alpha in editor configurable
- Better naming semantics for example, init/deinit for initialization and cleanup and create/destroy when memory is allocated or deallocated - Better naming semantics for example, init/deinit for initialization and cleanup and create/destroy when memory is allocated or deallocated
- Categorized entity list in editor for example different subtree for lights and static meshes - Categorized entity list in editor for example different subtree for lights and static meshes
- Depth testing for editor grid - Depth testing for editor grid
@ -320,3 +320,6 @@ Done:
* Fixed all sound related bugs and completede sound to/from file * Fixed all sound related bugs and completede sound to/from file
* Implemented saving/loading entity children when reading/writing entity to file * Implemented saving/loading entity children when reading/writing entity to file
* Editor functionality to add entity from specific file to scene * Editor functionality to add entity from specific file to scene
* Finished mesh and material properties serialization to and from file
* Fixed issue of partial matches returning incorrect hashmap values
* Implemented Static Mesh property viewing/editing in editor

Loading…
Cancel
Save