Files
Webcam/include/engine/gpu/gpu_material.cpp

173 lines
5.5 KiB
C++

/* -----------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------------