Skip to content

Commit

Permalink
Refactor: Automatically rebuild Material layers on engine reset
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Feb 24, 2013
1 parent 4778694 commit 9513ba9
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 76 deletions.
57 changes: 52 additions & 5 deletions doomsday/client/include/resource/material.h
Expand Up @@ -553,12 +553,9 @@ class Material : public de::MapElement

public:
/**
* Construct a new material.
*
* @param manifest Manifest derived to yield the material.
* @param def Definition for the material.
*/
Material(Manifest &manifest, ded_material_t const *def);
Material(Manifest &manifest);
~Material();

/**
Expand Down Expand Up @@ -721,11 +718,61 @@ class Material : public de::MapElement
*/
void setAudioEnvironment(audioenvironmentclass_e newEnvironment);

/**
* Add a new layer to the end of the material's layer stack. Ownership of the
* layer is @em not transferred to the caller.
*
* @note As this invalidates the existing logical state, any previously derived
* context variants are cleared in the process (they will be automatically
* rebuilt later if/when needed).
*
* @param def Definition for the new layer. Can be @c NULL in which case a
* default-initialized layer will be constructed.
*/
Layer *newLayer(ded_material_layer_t const *def);

/**
* Add a new detail layer to the material. Note that only one detail layer is
* supported (any existing layer will be replaced). Ownership of the layer is
* @em not transferred to the caller.
*
* @note As this invalidates the existing logical state, any previously derived
* context variants are cleared in the process (they will be automatically
* rebuilt later if/when needed).
*
* @param def Definition for the new layer. Can be @c NULL in which case a
* default-initialized layer will be constructed.
*/
DetailLayer *newDetailLayer(ded_detailtexture_t const *def);

/**
* Add a new shine layer to the material. Note that only one shine layer is
* supported (any existing layer will be replaced). Ownership of the layer is
* @em not transferred to the caller.
*
* @note As this invalidates the existing logical state, any previously derived
* context variants are cleared in the process (they will be automatically
* rebuilt later if/when needed).
*
* @param def Definition for the new layer. Can be @c NULL in which case a
* default-initialized layer will be constructed.
*/
ShineLayer *newShineLayer(ded_reflection_t const *def);

/**
* Returns the number of material layers.
*/
inline int layerCount() const { return layers().count(); }

/**
* Destroys all the material's layers.
*
* @note As this invalidates the existing logical state, any previously derived
* context variants are cleared in the process (they will be automatically
* rebuilt later if/when needed).
*/
void clearLayers();

/**
* Provides access to the list of layers for efficient traversal.
*/
Expand Down Expand Up @@ -753,7 +800,7 @@ class Material : public de::MapElement
int decorationCount() const { return decorations().count(); }

/**
* Destroys all derived context variants for the material.
* Destroys all the material's decorations.
*/
void clearDecorations();

Expand Down
69 changes: 49 additions & 20 deletions doomsday/client/src/def_main.cpp
Expand Up @@ -1042,6 +1042,36 @@ static void generateMaterialDefs()
textures.iterateDeclared("Sprites", generateMaterialDefForTextureWorker);
}

static void rebuildMaterialLayers(Material &material, ded_material_t const &def)
{
material.clearLayers();

for(int i = 0; i < DED_MAX_MATERIAL_LAYERS; ++i)
{
Material::Layer *layer = material.newLayer(&def.layers[i]);

foreach(Material::Layer::Stage *stageDef, layer->stages())
{
if(!stageDef->texture) continue;

de::Uri textureUri(stageDef->texture->manifest().composeUri());
ded_detailtexture_t *detailDef = Def_GetDetailTex(reinterpret_cast<uri_s *>(&textureUri)/*, UNKNOWN VALUE, manifest.isCustom()*/);
if(detailDef)
{
material.newDetailLayer(detailDef);
// Add stages.
}

ded_reflection_t *shineDef = Def_GetReflection(reinterpret_cast<uri_s *>(&textureUri)/*, UNKNOWN VALUE, manifest.isCustom()*/);
if(shineDef)
{
material.newShineLayer(shineDef);
// Add stages.
}
}
}
}

#ifdef __CLIENT__
static void rebuildMaterialDecorations(Material &material, ded_material_t const &def)
{
Expand Down Expand Up @@ -1153,42 +1183,41 @@ static void interpretMaterialDef(ded_material_t &def)
// An entirely new material?
if(!manifest->hasMaterial())
{
{
Material *material = new Material(*manifest, &def);
// Associate the new material with the manifest.
manifest->setMaterial(material);
// Include the material in the scheme-agnostic list of instances.
App_Materials().addMaterial(*material);
}
Material &material = manifest->material();
Material &material = *(new Material(*manifest));

material.setAudioEnvironment(S_AudioEnvironmentForMaterial(reinterpret_cast<struct uri_s const *>(&uri)));
// Associate the new material with the manifest.
manifest->setMaterial(&material);

// Include the material in the scheme-agnostic list of instances.
App_Materials().addMaterial(material);
}
else
{
// Update the existing material.
// Updating the existing material.
#ifdef __CLIENT__
Material &material = manifest->material();

#ifdef __CLIENT__
/// @todo We should be able to rebuild the variants.
material.clearVariants();
#endif
}

Material::Flags newFlags;
if(def.flags & MATF_NO_DRAW) newFlags |= Material::NoDraw;
if(def.flags & MATF_SKYMASK) newFlags |= Material::SkyMask;
material.setFlags(newFlags);
Material &material = manifest->material();

material.setDimensions(QSize(MAX_OF(0, def.width), MAX_OF(0, def.height)));
material.setAudioEnvironment(S_AudioEnvironmentForMaterial(def.uri));
Material::Flags newFlags;
if(def.flags & MATF_NO_DRAW) newFlags |= Material::NoDraw;
if(def.flags & MATF_SKYMASK) newFlags |= Material::SkyMask;
material.setFlags(newFlags);

/// @todo $revise-texture-animation Rebuild layers.
}
material.setDimensions(QSize(de::max(0, def.width), de::max(0, def.height)));

Material &material = manifest->material();
material.setAudioEnvironment(S_AudioEnvironmentForMaterial(def.uri));

rebuildMaterialLayers(material, def);
#ifdef __CLIENT__
rebuildMaterialDecorations(material, def);
#endif

material.markValid(true);
}

Expand Down
113 changes: 62 additions & 51 deletions doomsday/client/src/resource/material.cpp
Expand Up @@ -334,61 +334,13 @@ DENG2_PIMPL(Material)
self.clearVariants();
self.clearDecorations();
#endif
clearLayers();
}

void clearLayers()
{
qDeleteAll(layers);
layers.clear();

if(detailLayer) delete detailLayer;
if(shineLayer) delete shineLayer;
self.clearLayers();
}
};

Material::Material(MaterialManifest &_manifest, ded_material_t const *def)
Material::Material(MaterialManifest &_manifest)
: de::MapElement(DMU_MATERIAL), d(new Instance(this, _manifest))
{
DENG_ASSERT(def);
if(def->flags & MATF_NO_DRAW) d->flags |= NoDraw;
if(def->flags & MATF_SKYMASK) d->flags |= SkyMask;
d->dimensions = QSize(de::max(0, def->width), de::max(0, def->height));

for(int i = 0; i < DED_MAX_MATERIAL_LAYERS; ++i)
{
Layer *layer = Layer::fromDef(def->layers[i]);
d->layers.push_back(layer);

foreach(Layer::Stage *stageDef, layer->stages())
{
if(!stageDef->texture) continue;

de::Uri textureUri(stageDef->texture->manifest().composeUri());
ded_detailtexture_t *detailDef = Def_GetDetailTex(reinterpret_cast<uri_s *>(&textureUri)/*, UNKNOWN VALUE, manifest.isCustom()*/);
if(detailDef)
{
// Time to allocate the detail layer?
if(!d->detailLayer)
{
d->detailLayer = DetailLayer::fromDef(*detailDef);
}
// Add stages.
}

ded_reflection_t *reflectionDef = Def_GetReflection(reinterpret_cast<uri_s *>(&textureUri)/*, UNKNOWN VALUE, manifest.isCustom()*/);
if(reflectionDef)
{
// Time to allocate the shine layer?
if(!d->shineLayer)
{
d->shineLayer = ShineLayer::fromDef(*reflectionDef);
}
// Add stages.
}
}
}
}
{}

Material::~Material()
{
Expand Down Expand Up @@ -501,6 +453,64 @@ void Material::setAudioEnvironment(AudioEnvironmentClass envClass)
d->envClass = envClass;
}

void Material::clearLayers()
{
#ifdef __CLIENT__
// Context variants will be invalid after this, so clear them.
clearVariants();
#endif

qDeleteAll(d->layers);
d->layers.clear();

if(d->detailLayer)
{
delete d->detailLayer; d->detailLayer = 0;
}
if(d->shineLayer)
{
delete d->shineLayer; d->shineLayer = 0;
}
}

Material::Layer *Material::newLayer(ded_material_layer_t const *def)
{
#ifdef __CLIENT__
// Context variants will be invalid after this, so clear them.
clearVariants();
#endif

Layer *newLayer = def? Layer::fromDef(*def) : new Layer();
d->layers.push_back(newLayer);
return newLayer;
}

Material::DetailLayer *Material::newDetailLayer(ded_detailtexture_t const *def)
{
#ifdef __CLIENT__
// Context variants will be invalid after this, so clear them.
clearVariants();
#endif

DetailLayer *newLayer = def? DetailLayer::fromDef(*def) : new DetailLayer();
if(d->detailLayer) delete d->detailLayer;
d->detailLayer = newLayer;
return newLayer;
}

Material::ShineLayer *Material::newShineLayer(ded_reflection_t const *def)
{
#ifdef __CLIENT__
// Context variants will be invalid after this, so clear them.
clearVariants();
#endif

ShineLayer *newLayer = def? ShineLayer::fromDef(*def) : new ShineLayer();
if(d->shineLayer) delete d->shineLayer;
d->shineLayer = newLayer;
return newLayer;
}

Material::Layers const &Material::layers() const
{
return d->layers;
Expand Down Expand Up @@ -532,6 +542,7 @@ Material::ShineLayer const &Material::shineLayer() const

void Material::addDecoration(Material::Decoration &decor)
{
if(d->decorations.contains(&decor)) return;
d->decorations.push_back(&decor);
}

Expand Down

0 comments on commit 9513ba9

Please sign in to comment.