Skip to content

Commit

Permalink
Refactor|Material: Manage material layers with similar mechanism to d…
Browse files Browse the repository at this point in the history
…ecorations
  • Loading branch information
danij-deng committed Jan 16, 2013
1 parent 66cd263 commit 1556bfa
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 76 deletions.
75 changes: 70 additions & 5 deletions doomsday/engine/include/resource/material.h
Expand Up @@ -72,6 +72,58 @@ class Material
/// A list of variant instances.
typedef QList<MaterialVariant *> Variants;

/**
* Layer.
*/
class Layer
{
public:
/// A list of stages.
typedef QList<ded_material_layer_stage_t *> Stages;

public:
/**
* Construct a new default layer.
*/
Layer() {}

/**
* Construct a new layer from the specified definition.
*/
static Layer *fromDef(ded_material_layer_t &def)
{
Layer *layer = new Layer();
for(int i = 0; i < def.stageCount.num; ++i)
{
layer->stages_.push_back(&def.stages[i]);
}
return layer;
}

/**
* Returns the total number of animation stages for the layer.
*/
int stageCount() const
{
return stages_.count();
}

/**
* Provides access to the animation stages for efficient traversal.
*/
Stages const &stages() const
{
return stages_;
}

private:
/// Animation stages.
Stages stages_;
};

/// A list of layers.
typedef QList<Material::Layer *> Layers;

/**
* (Light) decoration.
*/
Expand Down Expand Up @@ -187,15 +239,26 @@ material_t *Material_New(short flags, ded_material_t *def, Size2Raw *dimensions,

void Material_Delete(material_t *mat);

/**
* Returns the number of material variants.
*/
int Material_VariantCount(material_t const *mat);

/**
* Returns the number of material layers.
*/
int Material_LayerCount(material_t const *mat);

/**
* Returns the number of material (light) decorations.
*/
int Material_DecorationCount(material_t const *mat);

/**
* Process a system tick event.
*/
void Material_Ticker(material_t *mat, timespan_t time);

int Material_VariantCount(material_t const *mat);

/**
* Destroys all derived MaterialVariants linked with this Material.
*/
Expand Down Expand Up @@ -264,9 +327,6 @@ boolean Material_HasDecorations(material_t const *mat);
/// Returns @c true if one or more of the material's layers are glowing.
boolean Material_HasGlow(material_t const *mat);

/// @return Number of layers.
int Material_LayerCount(material_t const *mat);

/// @return Prepared state of this material.
byte Material_Prepared(material_t const *mat);

Expand Down Expand Up @@ -394,6 +454,11 @@ int Material_SetProperty(material_t *material, setargs_t const *args);

de::MaterialManifest &Material_Manifest(material_t const *material);

/**
* Provides access to the list of layers for efficient traversal.
*/
de::Material::Layers const &Material_Layers(material_t const *mat);

/**
* Add a new (light) decoration to the material.
*
Expand Down
69 changes: 46 additions & 23 deletions doomsday/engine/src/resource/material.cpp
Expand Up @@ -32,6 +32,8 @@

#include "resource/material.h"

using namespace de;

struct material_s
{
/// DMU object header.
Expand All @@ -41,7 +43,7 @@ struct material_s
ded_material_t *def;

/// Set of use-case/context variant instances.
de::Material::Variants variants;
Material::Variants variants;

/// Environmental sound class.
material_env_class_t envClass;
Expand All @@ -56,38 +58,48 @@ struct material_s
short flags;

/// Detail texture layer & properties.
de::Texture *detailTex;
Texture *detailTex;
float detailScale;
float detailStrength;

/// Shiny texture layer & properties.
de::Texture *shinyTex;
Texture *shinyTex;
blendmode_t shinyBlendmode;
float shinyMinColor[3];
float shinyStrength;
de::Texture *shinyMaskTex;
Texture *shinyMaskTex;

/// Layers.
Material::Layers layers;

/// Decorations (will be projected into the map relative to a surface).
de::Material::Decorations decorations;
Material::Decorations decorations;

/// Current prepared state.
byte prepared;

material_s(short _flags, ded_material_t *_def,
material_s(short _flags, ded_material_t &_def,
Size2Raw &_dimensions, material_env_class_t _envClass)
: def(_def), envClass(_envClass), manifestId(0),
: def(&_def), envClass(_envClass), manifestId(0),
dimensions(Size2_NewFromRaw(&_dimensions)), flags(_flags),
detailTex(0), detailScale(0), detailStrength(0),
shinyTex(0), shinyBlendmode(BM_ADD), shinyStrength(0), shinyMaskTex(0),
prepared(0)
{
header.type = DMU_MATERIAL;
std::memset(shinyMinColor, 0, sizeof(shinyMinColor));

for(int i = 0; i < DED_MAX_MATERIAL_LAYERS; ++i)
{
Material::Layer *layer = Material::Layer::fromDef(_def.layers[i]);
layers.push_back(layer);
}
}

~material_s()
{
clearDecorations();
clearLayers();
clearVariants();
Size2_Delete(dimensions);
}
Expand All @@ -101,6 +113,14 @@ struct material_s
prepared = 0;
}

void clearLayers()
{
while(!layers.isEmpty())
{
delete layers.takeFirst();
}
}

void clearDecorations()
{
while(!decorations.isEmpty())
Expand All @@ -110,12 +130,11 @@ struct material_s
}
};

using namespace de;

material_t *Material_New(short flags, ded_material_t *def,
Size2Raw *dimensions, material_env_class_t envClass)
{
return new material_s(flags, def, *dimensions, envClass);
DENG_ASSERT(def && dimensions);
return new material_s(flags, *def, *dimensions, envClass);
}

void Material_Delete(material_t *mat)
Expand Down Expand Up @@ -179,11 +198,11 @@ void Material_SetDefinition(material_t *mat, struct ded_material_s *def)
/// @todo This should take into account the whole definition, not just whether
/// the primary layer's first texture is custom or not.
manifest.setCustom(false);
if(def->layers[0].stageCount.num > 0 && def->layers[0].stages[0].texture)
if(mat->layers[0]->stageCount() > 0 && mat->layers[0]->stages()[0]->texture)
{
try
{
de::Uri *texUri = reinterpret_cast<de::Uri *>(def->layers[0].stages[0].texture);
de::Uri *texUri = reinterpret_cast<de::Uri *>(mat->layers[0]->stages()[0]->texture);
if(Texture *tex = App_Textures()->find(*texUri).texture())
{
manifest.setCustom(tex->flags().testFlag(Texture::Custom));
Expand Down Expand Up @@ -259,11 +278,9 @@ boolean Material_IsAnimated(material_t const *mat)
// Materials cease animation once they are no longer valid.
if(!Material_IsValid(mat)) return false;

int const layerCount = Material_LayerCount(mat);
for(int i = 0; i < layerCount; ++i)
DENG2_FOR_EACH_CONST(Material::Layers, i, mat->layers)
{
ded_material_layer_t const &layer = mat->def->layers[i];
if(layer.stageCount.num > 1) return true;
if((*i)->stageCount() > 1) return true;
}
return false; // Not at all.
}
Expand All @@ -285,13 +302,12 @@ boolean Material_HasGlow(material_t const *mat)
DENG_ASSERT(mat);
if(mat->def)
{
int const layerCount = Material_LayerCount(mat);
for(int i = 0; i < layerCount; ++i)
DENG2_FOR_EACH_CONST(Material::Layers, i, mat->layers)
{
ded_material_layer_t const &layer = mat->def->layers[i];
for(int k = 0; k < layer.stageCount.num; ++k)
Material::Layer::Stages const &stages = (*i)->stages();
DENG2_FOR_EACH_CONST(Material::Layer::Stages, k, stages)
{
ded_material_layer_stage_t const &stage = layer.stages[k];
ded_material_layer_stage_t const &stage = **k;
if(stage.glowStrength > .0001f) return true;
}
}
Expand All @@ -302,8 +318,7 @@ boolean Material_HasGlow(material_t const *mat)
int Material_LayerCount(material_t const *mat)
{
DENG2_ASSERT(mat);
DENG2_UNUSED(mat);
return 1;
return mat->layers.count();
}

byte Material_Prepared(material_t const *mat)
Expand Down Expand Up @@ -449,6 +464,12 @@ void Material_SetShinyMaskTexture(material_t *mat, struct texture_s *tex)
mat->shinyMaskTex = reinterpret_cast<de::Texture *>(tex);
}

Material::Layers const &Material_Layers(material_t const *mat)
{
DENG_ASSERT(mat);
return mat->layers;
}

void Material_AddDecoration(material_t *mat, de::Material::Decoration &decor)
{
DENG_ASSERT(mat);
Expand All @@ -457,11 +478,13 @@ void Material_AddDecoration(material_t *mat, de::Material::Decoration &decor)

Material::Decorations const &Material_Decorations(material_t const *mat)
{
DENG_ASSERT(mat);
return mat->decorations;
}

Material::Variants const &Material_Variants(material_t const *mat)
{
DENG_ASSERT(mat);
return mat->variants;
}

Expand Down
17 changes: 9 additions & 8 deletions doomsday/engine/src/resource/materials.cpp
Expand Up @@ -740,7 +740,7 @@ void Materials::resetAllMaterialAnimations()

static void printVariantInfo(MaterialVariant &variant, int variantIdx)
{
Con_Printf("Variant #%i: Spec:%p\n", variantIdx, (void *) &variant.spec());
Con_Printf("Variant #%i: Spec:%p\n", variantIdx, de::dintptr(&variant.spec()));

// Print layer state info:
int const layerCount = Material_LayerCount(&variant.generalCase());
Expand Down Expand Up @@ -790,17 +790,18 @@ static void printMaterialInfo(material_t &mat)
Material_IsSkyMasked(&mat) ? "yes" : "no");

// Print full layer config:
int const layerCount = Material_LayerCount(&mat);
for(int idx = 0; idx < layerCount; ++idx)
Material::Layers const &layers = Material_Layers(&mat);
for(int i = 0; i < layers.count(); ++i)
{
ded_material_layer_t const *lDef = &def->layers[idx];
Material::Layer const *lDef = layers[i];
int const stageCount = lDef->stageCount();

Con_Printf("Layer #%i (%i %s):\n", idx, lDef->stageCount.num,
lDef->stageCount.num == 1? "Stage" : "Stages");
Con_Printf("Layer #%i (%i %s):\n",
i, stageCount, stageCount == 1? "Stage" : "Stages");

for(int k = 0; k < lDef->stageCount.num; ++k)
for(int k = 0; k < stageCount; ++k)
{
ded_material_layer_stage_t const *sDef = &lDef->stages[k];
ded_material_layer_stage_t const *sDef = lDef->stages()[k];
QByteArray path = !sDef->texture? QString("(prev)").toUtf8()
: reinterpret_cast<Uri *>(sDef->texture)->asText().toUtf8();

Expand Down
12 changes: 5 additions & 7 deletions doomsday/engine/src/resource/materialsnapshot.cpp
Expand Up @@ -260,7 +260,7 @@ void MaterialSnapshot::Instance::takeSnapshot()
#define LERP(start, end, pos) (end * pos + start * (1 - pos))

material_t *mat = &material->generalCase();
ded_material_t const *def = Material_Definition(mat);
Material::Layers const &layers = Material_Layers(mat);
MaterialVariantSpec const &spec = material->spec();

TextureVariant *prepTextures[NUM_MATERIAL_TEXTURE_UNITS];
Expand All @@ -276,12 +276,10 @@ void MaterialSnapshot::Instance::takeSnapshot()
* If skymasked, we only need to update the primary tex unit (due to it
* being visible when skymask debug drawing is enabled).
*/

int const layerCount = Material_LayerCount(mat);
for(int i = 0; i < layerCount; ++i)
for(int i = 0; i < layers.count(); ++i)
{
MaterialVariant::LayerState const &l = material->layer(i);
ded_material_layer_stage_t const *lsDef = &def->layers[i].stages[l.stage];
ded_material_layer_stage_t const *lsDef = layers[i]->stages()[l.stage];

Texture *tex = findTextureForLayerStage(*lsDef);
if(!tex) continue;
Expand Down Expand Up @@ -351,8 +349,8 @@ void MaterialSnapshot::Instance::takeSnapshot()
if(stored.dimensions.isEmpty()) return;

MaterialVariant::LayerState const &l = material->layer(0);
ded_material_layer_stage_t const *lsCur = &def->layers[0].stages[l.stage];
ded_material_layer_stage_t const *lsNext = &def->layers[0].stages[(l.stage + 1) % def->layers[0].stageCount.num];
ded_material_layer_stage_t const *lsCur = layers[0]->stages()[l.stage];
ded_material_layer_stage_t const *lsNext = layers[0]->stages()[(l.stage + 1) % layers[0]->stageCount()];

// Glow strength is presently taken from layer #0.
if(l.inter == 0)
Expand Down

0 comments on commit 1556bfa

Please sign in to comment.