A 3D game engine from scratch.
at main 279 lines 10 kB view raw
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net> 2 3#include "../src_external/pstr.h" 4#include "peony_parser_utils.hpp" 5#include "logs.hpp" 6#include "constants.hpp" 7#include "renderer.hpp" 8#include "intrinsics.hpp" 9 10 11char * 12peony_parser_utils::get_string(peony_parser::Prop *prop) 13{ 14 if (!prop) { return nullptr; } 15 return prop->values[0].string_value; 16} 17 18 19bool * 20peony_parser_utils::get_boolean(peony_parser::Prop *prop) 21{ 22 if (!prop) { return nullptr; } 23 return &prop->values[0].boolean_value; 24} 25 26 27f32 * 28peony_parser_utils::get_number(peony_parser::Prop *prop) 29{ 30 if (!prop) { return nullptr; } 31 return &prop->values[0].number_value; 32} 33 34 35v2 * 36peony_parser_utils::get_vec2(peony_parser::Prop *prop) 37{ 38 if (!prop) { return nullptr; } 39 return &prop->values[0].vec2_value; 40} 41 42 43v3 * 44peony_parser_utils::get_vec3(peony_parser::Prop *prop) 45{ 46 if (!prop) { return nullptr; } 47 return &prop->values[0].vec3_value; 48} 49 50 51v4 * 52peony_parser_utils::get_vec4(peony_parser::Prop *prop) 53{ 54 if (!prop) { return nullptr; } 55 return &prop->values[0].vec4_value; 56} 57 58 59peony_parser::Prop * 60peony_parser_utils::find_prop(peony_parser::Entry *entry, char const *name) 61{ 62 range (0, entry->n_props) { 63 if (pstr_eq(name, entry->props[idx].name)) { 64 return &entry->props[idx]; 65 } 66 } 67 logs::warning("Could not find prop %s", name); 68 return nullptr; 69} 70 71 72void 73peony_parser_utils::get_unique_string_values_for_prop_name( 74 peony_parser::PeonyFile *pf, 75 Array<char[MAX_COMMON_NAME_LENGTH]> *unique_values, 76 char const *prop_name 77) { 78 range_named (idx_entry, 0, pf->n_entries) { 79 peony_parser::Entry *entry = &pf->entries[idx_entry]; 80 peony_parser::Prop *prop = find_prop(entry, prop_name); 81 if (!prop) { 82 continue; 83 } 84 range_named (idx_value, 0, prop->n_values) { 85 peony_parser::PropValue *value = &prop->values[idx_value]; 86 bool does_material_already_exist = false; 87 each (unique_value, *unique_values) { 88 if (pstr_eq(value->string_value, *unique_value)) { 89 does_material_already_exist = true; 90 break; 91 } 92 } 93 if (!does_material_already_exist) { 94 pstr_copy(*(unique_values->push()), 95 MAX_COMMON_NAME_LENGTH, value->string_value); 96 } 97 } 98 } 99} 100 101 102void 103peony_parser_utils::create_material_from_peony_file_entry( 104 mats::Material *material, 105 peony_parser::Entry *entry, 106 memory::Pool *memory_pool 107) { 108 mats::init_material(material, entry->name); 109 110 // We're calling `find_prop()` a lot here, which goes through the full 111 // list of props every time, and so this is kind of #slow. Not a huge deal, but 112 // good to keep in mind. 113 peony_parser::Prop *prop; 114 115 if ((prop = find_prop(entry, "albedo_static"))) { 116 material->albedo_static = *get_vec4(prop); 117 } 118 if ((prop = find_prop(entry, "metallic_static"))) { 119 material->metallic_static = *get_number(prop); 120 } 121 if ((prop = find_prop(entry, "roughness_static"))) { 122 material->roughness_static = *get_number(prop); 123 } 124 if ((prop = find_prop(entry, "ao_static"))) { 125 material->ao_static = *get_number(prop); 126 } 127 128 if ((prop = find_prop(entry, "shader_asset.vert_path"))) { 129 if (!pstr_is_empty(get_string(prop))) { 130 shaders::init_shader_asset(&material->shader_asset, 131 memory_pool, 132 entry->name, 133 shaders::Type::standard, 134 get_string(find_prop(entry, "shader_asset.vert_path")), 135 get_string(find_prop(entry, "shader_asset.frag_path")), 136 get_string(find_prop(entry, "shader_asset.geom_path"))); 137 } 138 } 139 140 if ((prop = find_prop(entry, "depth_shader_asset.vert_path"))) { 141 if (!pstr_is_empty(get_string(prop))) { 142 shaders::init_shader_asset(&material->depth_shader_asset, 143 memory_pool, 144 entry->name, 145 shaders::Type::depth, 146 get_string(find_prop(entry, "depth_shader_asset.vert_path")), 147 get_string(find_prop(entry, "depth_shader_asset.frag_path")), 148 get_string(find_prop(entry, "depth_shader_asset.geom_path"))); 149 } 150 } 151 152 auto *builtin_textures = renderer::get_builtin_textures(); 153 154 // Iterate through all props to get textures, since those could have any name 155 range (0, entry->n_props) { 156 prop = &entry->props[idx]; 157 158 if (pstr_starts_with(prop->name, TEXTURE_PREFIX)) { 159 // Handle a texture 160 mats::Texture texture = {}; 161 // The uniform name is the prop name without the prefix 162 // The first value is the type, and the second the path 163 // e.g. textures.foam_texture = [other, water_foam.png] 164 char const *uniform_name = &prop->name[TEXTURE_PREFIX_LENGTH]; 165 mats::init_texture(&texture, 166 mats::texture_type_from_string(prop->values[0].string_value), 167 prop->values[1].string_value); 168 mats::add_texture_to_material(material, texture, uniform_name); 169 } else if (pstr_starts_with(prop->name, BUILTIN_TEXTURE_PREFIX)) { 170 // Handle a builtin texture 171 char const *builtin_uniform_name = &prop->name[BUILTIN_TEXTURE_PREFIX_LENGTH]; 172 if (pstr_eq(builtin_uniform_name, "g_position_texture")) { 173 mats::add_texture_to_material( 174 material, *builtin_textures->g_position_texture, builtin_uniform_name); 175 } else if (pstr_eq(builtin_uniform_name, "g_albedo_texture")) { 176 mats::add_texture_to_material( 177 material, *builtin_textures->g_albedo_texture, builtin_uniform_name); 178 } else if (pstr_eq(builtin_uniform_name, "shadowmaps_3d")) { 179 mats::add_texture_to_material( 180 material, *builtin_textures->shadowmaps_3d_texture, builtin_uniform_name); 181 } else if (pstr_eq(builtin_uniform_name, "shadowmaps_2d")) { 182 mats::add_texture_to_material( 183 material, *builtin_textures->shadowmaps_2d_texture, builtin_uniform_name); 184 } else { 185 logs::fatal("Attempted to use unsupported built-in texture %s", 186 builtin_uniform_name); 187 } 188 } 189 } 190} 191 192 193void 194peony_parser_utils::create_model_loader_from_peony_file_entry( 195 peony_parser::Entry *entry, 196 entities::Handle entity_handle, 197 models::ModelLoader *model_loader 198) { 199 peony_parser::Prop *model_path_prop = find_prop(entry, "model_path"); 200 assert(model_path_prop); 201 char const *model_path = get_string(model_path_prop); 202 203 models::init_model_loader(model_loader, model_path); 204 205 peony_parser::Prop *materials_prop = find_prop(entry, "materials"); 206 model_loader->n_material_names = materials_prop->n_values; 207 range (0, materials_prop->n_values) { 208 pstr_copy(model_loader->material_names[idx], 209 MAX_COMMON_NAME_LENGTH, 210 materials_prop->values[idx].string_value); 211 } 212} 213 214 215void 216peony_parser_utils::create_entity_loader_from_peony_file_entry( 217 peony_parser::Entry *entry, 218 entities::Handle entity_handle, 219 models::EntityLoader *entity_loader 220) { 221 peony_parser::Prop *model_path_prop = find_prop(entry, "model_path"); 222 assert(model_path_prop); 223 char const *model_path = get_string(model_path_prop); 224 225 // Get render pass 226 auto render_pass = drawable::Pass::none; 227 peony_parser::Prop *render_passes_prop = find_prop(entry, "render_passes"); 228 if (render_passes_prop) { 229 range (0, render_passes_prop->n_values) { 230 render_pass = (drawable::Pass)( 231 (u32)render_pass | 232 (u32)drawable::render_pass_from_string( 233 render_passes_prop->values[idx].string_value)); 234 } 235 } else { 236 logs::warning( 237 "Loading EntityLoader with no RenderPasses, you probably don't want this?"); 238 } 239 240 // Initialise everything except the components 241 models::init_entity_loader(entity_loader, entry->name, model_path, 242 render_pass, entity_handle); 243 244 // Build physics::Component, spatial::Component, lights::Component, behavior::Component 245 range (0, entry->n_props) { 246 peony_parser::Prop *prop = &entry->props[idx]; 247 if (pstr_eq(prop->name, "physics_component.obb.center")) { 248 entity_loader->physics_component.obb.center = *get_vec3(prop); 249 } else if (pstr_eq(prop->name, "physics_component.obb.x_axis")) { 250 entity_loader->physics_component.obb.x_axis = *get_vec3(prop); 251 } else if (pstr_eq(prop->name, "physics_component.obb.y_axis")) { 252 entity_loader->physics_component.obb.y_axis = *get_vec3(prop); 253 } else if (pstr_eq(prop->name, "physics_component.obb.extents")) { 254 entity_loader->physics_component.obb.extents = *get_vec3(prop); 255 } else if (pstr_eq(prop->name, "spatial_component.position")) { 256 entity_loader->spatial_component.position = *get_vec3(prop); 257 } else if (pstr_eq(prop->name, "spatial_component.rotation")) { 258 entity_loader->spatial_component.rotation = glm::angleAxis( 259 radians((*get_vec4(prop))[0]), 260 v3((*get_vec4(prop))[1], 261 (*get_vec4(prop))[2], 262 (*get_vec4(prop))[3])); 263 } else if (pstr_eq(prop->name, "spatial_component.scale")) { 264 entity_loader->spatial_component.scale = *get_vec3(prop); 265 } else if (pstr_eq(prop->name, "light_component.type")) { 266 entity_loader->light_component.type = 267 lights::light_type_from_string(get_string(prop)); 268 } else if (pstr_eq(prop->name, "light_component.direction")) { 269 entity_loader->light_component.direction = *get_vec3(prop); 270 } else if (pstr_eq(prop->name, "light_component.color")) { 271 entity_loader->light_component.color = *get_vec4(prop); 272 } else if (pstr_eq(prop->name, "light_component.attenuation")) { 273 entity_loader->light_component.attenuation = *get_vec4(prop); 274 } else if (pstr_eq(prop->name, "behavior_component.behavior")) { 275 entity_loader->behavior_component.behavior = 276 behavior::behavior_from_string(get_string(prop)); 277 } 278 } 279}