Skip to content

Commit

Permalink
Material: Observe Texture DimensionsChanged
Browse files Browse the repository at this point in the history
Replaced mechanism for inheriting material world dimensions from a
Texture (which in turn may be taken from Image pixel dimensions).

It is now possible to prepare the relevant texture from any part of
the engine, safe in the knowledge that any interested parties will
be notified once dimension data becomes available.
  • Loading branch information
danij-deng committed Mar 24, 2013
1 parent 8b88c67 commit ccead57
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 49 deletions.
13 changes: 11 additions & 2 deletions doomsday/client/include/resource/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#ifdef __CLIENT__
# include "MaterialContext"
#endif
#include "Texture"
#include "uri.hh"
#include <de/Error>
#include <de/Observers>
Expand All @@ -45,7 +46,6 @@ class MaterialManifest;
class MaterialSnapshot;
struct MaterialVariantSpec;
#endif
class Texture;

}

Expand All @@ -54,7 +54,9 @@ class Texture;
*
* @ingroup resource
*/
class Material : public de::MapElement
class Material : public de::MapElement,
DENG2_OBSERVES(de::Texture, DimensionsChange),
DENG2_OBSERVES(de::Texture, Deletion)
{
/// Internal typedefs for brevity/cleanliness.
typedef de::MaterialManifest Manifest;
Expand Down Expand Up @@ -988,6 +990,13 @@ class Material : public de::MapElement
*/
int setProperty(setargs_t const &args);

protected:
// Observes Texture DimensionsChange.
void textureDimensionsChanged(de::Texture const &texture);

// Observes Texture Deletion.
void textureBeingDeleted(de::Texture const &texture);

private:
DENG2_PRIVATE(d)
};
Expand Down
18 changes: 2 additions & 16 deletions doomsday/client/include/resource/texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,6 @@ class Texture
class Variant
{
public:
/// Logical prepare() result.
enum PrepareResult
{
NotFound, ///< Failed. No suitable variant could be found/prepared.
Found, ///< Success. Reusing a cached resource.
UploadedOriginal, ///< Success. Prepared and cached using an original-game resource.
UploadedExternal ///< Success. Prepared and cached using an external-replacement resource.
};

enum Flag
{
/// Texture contains alpha.
Expand Down Expand Up @@ -159,12 +150,9 @@ class Texture
* GL texture will result in "uninitialized" white texels being used
* instead.
*
* @param result If not @c 0 the logical result of this operation
* is written here.
*
* @return GL-name of the uploaded texture.
*/
uint prepare(PrepareResult *result = 0);
uint prepare();

/**
* Release any uploaded GL-texture and clear the associated GL-name
Expand Down Expand Up @@ -369,14 +357,12 @@ class Texture
* </pre>
*
* @param spec Specification for the derivation of the texture.
* @param returnOutcome If not @c 0 the logical result is written back here.
*
* @return The prepared texture variant if successful; otherwise @c 0.
*
* @see chooseVariant()
*/
Variant *prepareVariant(texturevariantspecification_t const &spec,
Variant::PrepareResult *returnOutcome = 0);
Variant *prepareVariant(texturevariantspecification_t const &spec);

/**
* Provides access to the list of variant instances for efficent traversal.
Expand Down
95 changes: 90 additions & 5 deletions doomsday/client/src/resource/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,47 @@ DENG2_PIMPL(Material)
}

#endif // __CLIENT__

/// Notify interested parties of a change in world dimensions.
void notifyDimensionsChanged()
{
/// @todo Replace with a de::Observers-based mechanism.
R_UpdateMapSurfacesOnMaterialChange(&self);
}

/// Returns @c true iff both world dimension axes are defined.
inline bool haveValidDimensions() const
{
return dimensions.x > 0 && dimensions.y > 0;
}

/**
* Determines which texture we would be interested in obtaining our
* world dimensions from if our own dimensions are undefined.
*/
Texture *inheritDimensionsTexture()
{
// We're interested in the texture bound to the primary layer.
if(!layers.count() || !layers[0]->stageCount()) return 0;
return layers[0]->stages()[0]->texture;
}

/**
* Determines whether the world dimensions are now defined and if so
* cancels further notifications about changes to texture dimensions.
*/
void maybeCancelTextureDimensionsChangeNotification()
{
// Both dimensions must still be undefined.
if(haveValidDimensions()) return;

Texture *inheritanceTexture = inheritDimensionsTexture();
if(!inheritanceTexture) return;

inheritanceTexture->audienceForDimensionsChange -= self;
// Thusly, we are no longer interested in deletion notification either.
inheritanceTexture->audienceForDeletion -= self;
}
};

Material::Material(MaterialManifest &manifest)
Expand All @@ -414,6 +455,8 @@ Material::Material(MaterialManifest &manifest)

Material::~Material()
{
d->maybeCancelTextureDimensionsChangeNotification();

DENG2_FOR_AUDIENCE(Deletion, i) i->materialBeingDeleted(*this);
}

Expand All @@ -433,7 +476,9 @@ void Material::setDimensions(Vector2i const &_newDimensions)
if(d->dimensions != newDimensions)
{
d->dimensions = newDimensions;
R_UpdateMapSurfacesOnMaterialChange(this);
d->maybeCancelTextureDimensionsChangeNotification();

d->notifyDimensionsChanged();
}
}

Expand All @@ -442,7 +487,9 @@ void Material::setWidth(int newWidth)
if(d->dimensions.x != newWidth)
{
d->dimensions.x = newWidth;
R_UpdateMapSurfacesOnMaterialChange(this);
d->maybeCancelTextureDimensionsChangeNotification();

d->notifyDimensionsChanged();
}
}

Expand All @@ -451,7 +498,9 @@ void Material::setHeight(int newHeight)
if(d->dimensions.y != newHeight)
{
d->dimensions.y = newHeight;
R_UpdateMapSurfacesOnMaterialChange(this);
d->maybeCancelTextureDimensionsChangeNotification();

d->notifyDimensionsChanged();
}
}

Expand Down Expand Up @@ -483,12 +532,12 @@ bool Material::isAnimated() const

bool Material::isDetailed() const
{
return !!d->detailLayer;
return d->detailLayer != 0;
}

bool Material::isShiny() const
{
return !!d->shineLayer;
return d->shineLayer != 0;
}

bool Material::hasGlow() const
Expand All @@ -514,6 +563,8 @@ void Material::setAudioEnvironment(AudioEnvironmentClass envClass)

void Material::clearLayers()
{
d->maybeCancelTextureDimensionsChangeNotification();

#ifdef __CLIENT__
d->animationsAreDirty = true;
#endif
Expand All @@ -539,6 +590,18 @@ Material::Layer *Material::newLayer(ded_material_layer_t const *def)

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

// Are we interested in inheriting dimensions from the layer's texture?
if(!d->haveValidDimensions() && d->layers.count() == 1)
{
Texture *inheritanceTexture = d->inheritDimensionsTexture();
if(inheritanceTexture)
{
inheritanceTexture->audienceForDimensionsChange += this;
// Thusly, we are also interested in deletion notification.
inheritanceTexture->audienceForDeletion += this;
}
}
return newLayer;
}

Expand Down Expand Up @@ -593,6 +656,28 @@ Material::ShineLayer const &Material::shineLayer() const
throw UnknownLayerError("Material::shineLayer", "Material has no shine layer");
}

void Material::textureDimensionsChanged(Texture const &texture)
{
DENG2_ASSERT(!d->haveValidDimensions()); // Sanity check.
setDimensions(texture.dimensions());
}

void Material::textureBeingDeleted(de::Texture const &texture)
{
// If here it means the texture we were planning to inherit dimensions
// from is being deleted and therefore we won't be able to.

DENG2_ASSERT(!d->haveValidDimensions()); // Sanity check.
DENG2_ASSERT(d->inheritDimensionsTexture() == &texture); // Sanity check.

// Clear the association so we don't try to cancel notifications later.
d->layers[0]->stages()[0]->texture = 0;

#if !defined(DENG2_DEBUG)
DENG2_UNUSED(texture);
#endif
}

#ifdef __CLIENT__

void Material::addDecoration(Material::Decoration &decor)
Expand Down
15 changes: 1 addition & 14 deletions doomsday/client/src/resource/materialsnapshot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,20 +243,7 @@ void MaterialSnapshot::Instance::takeSnapshot()
if(Texture *tex = lsCur->texture)
{
// Pick the instance matching the specified context.
TextureVariant::PrepareResult result;
prepTextures[i][0] = tex->prepareVariant(*variant->spec().primarySpec, &result);

// Primary texture was (re)prepared?
if(i == 0 && l.stage == 0 &&
(TextureVariant::UploadedOriginal == result ||
TextureVariant::UploadedExternal == result))
{
// Are we inheriting the logical dimensions from the texture?
if(material->width() == 0 && material->height() == 0)
{
material->setDimensions(tex->dimensions());
}
}
prepTextures[i][0] = tex->prepareVariant(*variant->spec().primarySpec);
}

// Smooth Texture Animation?
Expand Down
5 changes: 2 additions & 3 deletions doomsday/client/src/resource/texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,11 @@ Texture::Variant *Texture::chooseVariant(ChooseVariantMethod method,
return d->variants.back();
}

Texture::Variant *Texture::prepareVariant(texturevariantspecification_t const &spec,
Variant::PrepareResult *prepareResult)
Texture::Variant *Texture::prepareVariant(texturevariantspecification_t const &spec)
{
Variant *variant = chooseVariant(MatchSpec, spec, true /*can create*/);
DENG2_ASSERT(variant);
variant->prepare(prepareResult);
variant->prepare();
return variant;
}

Expand Down
10 changes: 1 addition & 9 deletions doomsday/client/src/resource/texturevariant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,25 +312,19 @@ static void performImageAnalyses(image_t const &image,
}
}

uint Texture::Variant::prepare(Variant::PrepareResult *result)
uint Texture::Variant::prepare()
{
LOG_AS("TextureVariant::prepare");

// Have we already prepared this?
if(isPrepared())
{
if(result) *result = Found;
return d->glTexName;
}

// Load the source image data.
image_t image;
TexSource source = GL_LoadSourceImage(image, d->texture, d->spec);
if(source == TEXS_NONE)
{
if(result) *result = NotFound;
return 0;
}

// Do we need to perform any image pixel data analyses?
if(d->spec.type == TST_GENERAL)
Expand Down Expand Up @@ -409,8 +403,6 @@ uint Texture::Variant::prepare(Variant::PrepareResult *result)
// We're done with the image data.
Image_Destroy(&image);

if(result) *result = source == TEXS_ORIGINAL? UploadedOriginal : UploadedExternal;

return d->glTexName;
}

Expand Down

0 comments on commit ccead57

Please sign in to comment.