/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include "gpu/gpu_material.h" #include "gpu/gpu_renderer.h" #include "core/material_to_shader_tree.h" #include "core/shader_tree_convert_static_texture_block_to_dynamic.h" #include "core/shader_tree_to_shader.h" #include "core/shader_tree.h" #include "log/log.h" using namespace GS; using namespace GPU; //------------------------------------------------------------------------------ bool Material::ShouldReloadOnDependencyChange(const char *n) const { return (name == n) || (shader->GetName() == n); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool Material::LoadTextureTable(Render::ResourceFactory &rf, const Core::Material &m) { bool r = true; for (uint n = 0; n < Core::Material::max_texture_stage; ++n) { texture_table[n] = rf.LoadTexture(m.texstage[n].t); if (texture_table[n].IsNull()) r = false; } return r; } static bool LoadCoreShader(Render::ResourceFactory &rf, const Core::Material &m, Core::Shader &core_shader, const char *name) { using namespace Core; if (name == NULL) { // TODO convert material to shader directly (avoid creating an AST). ShaderTree shader_tree; if (!MaterialToShaderTree::Convert(m, shader_tree) || !ConvertShaderTreeToShader(shader_tree, core_shader)) return false; } else { using namespace NML; // Load shader/shader tree. File file; if (!Parser::Load(name, file)) return false; if (Tag *tag = file.GetTag("Shader")) { if (!core_shader.FromMetaTag(*tag)) return false; core_shader.name = m.shader; } else if (Tag *tag = file.GetTag("ShaderMap")) { ShaderTree shader_tree; if (!shader_tree.FromMetaTag(*tag)) return false; ConvertStaticToDynamicTextureBlocks(shader_tree, m); if (!ConvertShaderTreeToShader(shader_tree, core_shader)) return false; } else __ERR__(__LOG_E__ << "No shader or shader tree definition found in '" << m.shader << "'.\n", false) } return true; } bool Material::Create(Render::ResourceFactory &rf, const Core::Material &m) { __LOG_H__ << "Load render material '" << m.name << "'.\n"; name = m.name; using namespace Core; // Transfer basic material informations to the render data. *((BasicMaterial *)this) = ((BasicMaterial &)m); // Load texture table. LoadTextureTable(rf, m); // Load core shader. MaterialShaderStaticParm parm; parm.no_lighting = asbool(m.renderword & Core::Material::Render_Unlit); parm.use_skinning = asbool(m.renderword & Core::Material::Render_Skinned); parm.use_alpha_test = asbool(m.renderword & Core::Material::Render_AlphaTest); parm.use_depth_bias = asbool(m.depth_bias); Core::Shader core_shader; bool load_core_shader = LoadCoreShader(rf, m, core_shader, m.shader); // Drop current material shader. shader = NULL; // Look for a compatible material shader in cache. if (load_core_shader) ListForeachPtr(MaterialShader *, s, renderer.material_shaders) if ((s->GetName() == core_shader.name) && (s->GetStaticParm() == parm)) { __LOG_V__ << "Reusing cached material shader for material '" << m.name << "'.\n"; shader = s; return true; } // Build a new one otherwise. shader = new MaterialShader(renderer); if (shader.IsNull()) return false; if (!load_core_shader || !shader->Create(rf, core_shader, parm)) { if (!LoadCoreShader(rf, m, core_shader, "@core/builtin/shader/shader_error.nsa")) return false; if (!shader->Create(rf, core_shader, parm)) return false; } return true; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ Render::Material *Material::Clone() const { Material *cloned = new Material(renderer); // __LOG_W__ << "[MaterialClone] Step 1c: 'new' returned successfully!\n"; if (!cloned) { __LOG_E__ << "[MaterialClone] ERROR: Failed to allocate memory for cloned material!\n"; return NULL; } // __LOG_W__ << "[MaterialClone] Step 1: Material instance created at " << (void*)cloned << "\n"; // Copy name (with "_clone" suffix to distinguish it) // __LOG_W__ << "[MaterialClone] Step 2: Copying name...\n"; cloned->name = name + "_clone"; // __LOG_W__ << "[MaterialClone] Step 2: Name copied: '" << cloned->name << "'\n"; // Copy basic material properties (diffuse, specular, self, ambient, glossiness, etc.) // __LOG_W__ << "[MaterialClone] Step 3: Copying BasicMaterial properties...\n"; *((Core::BasicMaterial *)cloned) = *((Core::BasicMaterial *)this); // __LOG_W__ << "[MaterialClone] Step 3: BasicMaterial properties copied.\n"; // Copy shader reference // __LOG_W__ << "[MaterialClone] Step 4: Copying shader reference...\n"; cloned->shader = shader; // __LOG_W__ << "[MaterialClone] Step 4: Shader reference copied.\n"; // Copy texture table (smart pointers, so textures are shared, not duplicated) // __LOG_W__ << "[MaterialClone] Step 5: Copying texture table...\n"; for (uint n = 0; n < Core::Material::max_texture_stage; ++n) { cloned->texture_table[n] = texture_table[n]; } // __LOG_W__ << "[MaterialClone] Step 5: Texture table copied.\n"; // __LOG_W__ << "[MaterialClone] SUCCESS: Material cloned successfully as '" << cloned->name << "'.\n"; return cloned; } //------------------------------------------------------------------------------