Skip to content

Commit

Permalink
Refactor|Materials: Decentralized material preparation
Browse files Browse the repository at this point in the history
Preparing a material variant for render is now done via the prepare()
methods of Material and Material::Variant (or, the Materials::cache()
mechanism). The method to call depends on whether the context variant
specialization is already known and/or whether the automatic variant
selection logic is appropriate (see Material::chooseVariant).
  • Loading branch information
danij-deng committed Jan 18, 2013
1 parent 76fa523 commit e0bdf3b
Show file tree
Hide file tree
Showing 20 changed files with 161 additions and 238 deletions.
92 changes: 47 additions & 45 deletions doomsday/engine/include/resource/material.h
Expand Up @@ -128,10 +128,6 @@ class Material : public de::MapElement
float inter;
};

public:
/// Required snapshot data is missing. @ingroup errors
DENG2_ERROR(MissingSnapshotError);

private:
/**
* @param generalCase Material from which this variant is derived.
Expand Down Expand Up @@ -176,6 +172,21 @@ class Material : public de::MapElement
*/
bool isPaused() const;

/**
* Prepare the context variant for render (if necessary, uploading
* GL textures and updating the state snapshot).
*
* @param forceSnapshotUpdate @c true= Force an update of the state
* snapshot. The snapshot is automatically updated when first
* prepared for a new render frame. Typically the only time force
* is needed is when the material variant has changed since.
*
* @return Snapshot for the chosen and prepared variant of Material.
*
* @see Material::chooseVariant(), Material::prepare()
*/
de::MaterialSnapshot const &prepare(bool forceSnapshotUpdate = false);

/**
* Reset the staged animation point for the material. The animation
* states of all context variants will be rewound to the beginning.
Expand All @@ -195,50 +206,11 @@ class Material : public de::MapElement
DecorationState const &decoration(int decorNum);

/**
* Attach new MaterialSnapshot data to the variant. If an existing
* snapshot is already present it will be replaced. Ownership of
* @a materialSnapshot is given to the variant.
*
* @return Same as @a materialSnapshot for caller convenience.
*
* @see detachSnapshot(), snapshot()
*/
de::MaterialSnapshot &attachSnapshot(de::MaterialSnapshot &snapshot);

/**
* Detach the MaterialSnapshot data from the variant, relinquishing
* ownership to the caller.
*
* @see attachSnapshot(), detachSnapshot()
*/
de::MaterialSnapshot *detachSnapshot();

/**
* Returns the MaterialSnapshot data from the variant; otherwise @c 0.
* Ownership is unaffected.
*
* @see attachSnapshot(), detachSnapshot()
* Returns the MaterialSnapshot data for the variant if present;
* otherwise @c 0.
*/
de::MaterialSnapshot *snapshot() const;

/**
* Returns the frame number when the variant's associated snapshot
* was last prepared/updated.
*
* @see setSnapshotPrepareFrame()
*/
int snapshotPrepareFrame() const;

/**
* Change the frame number when the variant's snapshot was last
* prepared/updated.
*
* @param frameNum Frame number to mark the snapshot with.
*
* @see snapshotPrepareFrame()
*/
void setSnapshotPrepareFrame(int frameNum);

friend class Material;
friend struct Material::Instance;

Expand Down Expand Up @@ -455,11 +427,39 @@ class Material : public de::MapElement
/// Returns @c true if one or more of the material's layers are glowing.
bool hasGlow() const;

/**
* Choose/create a variant of thematerial which fulfills @a spec and then
* immediately prepare it for render (e.g., upload textures if necessary).
*
* @note A convenient shorthand of the call tree:
* <pre>
* chooseVariant( @a spec, @c true )->prepare( @a forceSnapshotUpdate )
* </pre>
*
* @param spec Specification for the derivation of @a material.
* @param forceSnapshotUpdate @c true= Force an update of the variant's state
* snapshot. The snapshot is automatically updated
* when first prepared for a new render frame.
* Typically the only time force is needed is when
* the material variant has changed since.
*
* @return Snapshot for the chosen and prepared variant of Material.
*
* @see chooseVariant(), Variant::prepare()
*/
inline de::MaterialSnapshot const &prepare(de::MaterialVariantSpec const &spec,
bool forceSnapshotUpdate = false)
{
return chooseVariant(spec, true /*can-create*/)->prepare(forceSnapshotUpdate);
}

/**
* Returns the current prepared state of the material:
* @return @c 0= Not yet prepared.
* @c 1= Prepared from original game textures.
* @c 2= Prepared from custom or replacement textures.
*
* @see prepare()
*/
byte prepared() const;

Expand All @@ -468,6 +468,8 @@ class Material : public de::MapElement
* @param state @c 0= Not yet prepared.
* @c 1= Prepared from original game textures.
* @c 2= Prepared from custom or replacement textures.
*
* @see prepare()
*/
void setPrepared(byte state);

Expand Down
43 changes: 0 additions & 43 deletions doomsday/engine/include/resource/materials.h
Expand Up @@ -314,49 +314,6 @@ class Materials
void cache(Material &material, MaterialVariantSpec const &spec,
bool cacheGroups = true);

/**
* Prepare variant @a material for render (e.g., upload textures if necessary).
*
* @see chooseVariant()
*
* @param material Material variant to be prepared.
* @param forceSnapshotUpdate @c true= Force an update of the variant's state
* snapshot. The snapshot is automatically updated
* when first prepared for a new render frame.
* Typically the only time force is needed is when
* the material variant has changed since.
*
* @return Snapshot for the chosen and prepared variant of Material.
*/
MaterialSnapshot const &prepare(Material::Variant &material,
bool forceSnapshotUpdate = false);

/**
* Choose/create a variant of @a material which fulfills @a spec and then
* immediately prepare it for render (e.g., upload textures if necessary).
*
* @note A convenient shorthand of the call tree:
* <pre>
* prepare( Material_ChooseVariant( @a material, @a spec, @c true ), @a forceSnapshotUpdate )
* </pre>
*
* @param material Base Material from which to derive a variant.
* @param spec Specification for the derivation of @a material.
* @param forceSnapshotUpdate @c true= Force an update of the variant's state
* snapshot. The snapshot is automatically updated
* when first prepared for a new render frame.
* Typically the only time force is needed is when
* the material variant has changed since.
*
* @return Snapshot for the chosen and prepared variant of Material.
*/
inline MaterialSnapshot const &prepare(Material &material,
MaterialVariantSpec const &spec, bool forceSnapshotUpdate = false)
{
return prepare(*material.chooseVariant(spec, true /*can-create*/),
forceSnapshotUpdate);
}

/**
* To be called to reset all animations back to their initial state.
*/
Expand Down
6 changes: 2 additions & 4 deletions doomsday/engine/src/gl/gl_main.cpp
Expand Up @@ -748,8 +748,7 @@ void GL_SetMaterialUI2(Material *mat, int wrapS, int wrapT)
MaterialVariantSpec const &spec =
App_Materials()->variantSpecForContext(MC_UI, 0, 1, 0, 0, wrapS, wrapT,
0, 1, 0, false, false, false, false);
MaterialSnapshot const &ms = App_Materials()->prepare(*mat, spec);
GL_BindTexture(reinterpret_cast<texturevariant_s *>(&ms.texture(MTU_PRIMARY)));
GL_BindTexture(reinterpret_cast<texturevariant_s *>(&mat->prepare(spec).texture(MTU_PRIMARY)));
}

void GL_SetMaterialUI(Material* mat)
Expand All @@ -764,8 +763,7 @@ void GL_SetPSprite(Material *mat, int tClass, int tMap)
MaterialVariantSpec const &spec =
App_Materials()->variantSpecForContext(MC_PSPRITE, 0, 1, tClass, tMap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE,
0, 1, 0, false, true, true, false);
MaterialSnapshot const &ms = App_Materials()->prepare(*mat, spec);
GL_BindTexture(reinterpret_cast<texturevariant_s *>(&ms.texture(MTU_PRIMARY)));
GL_BindTexture(reinterpret_cast<texturevariant_s *>(&mat->prepare(spec).texture(MTU_PRIMARY)));
}

void GL_SetRawImage(lumpnum_t lumpNum, int wrapS, int wrapT)
Expand Down
7 changes: 2 additions & 5 deletions doomsday/engine/src/map/r_world.cpp
Expand Up @@ -340,7 +340,6 @@ void R_UpdateMapSurfacesOnMaterialChange(Material *material)
{
if(!material || !theMap || ddMapSetup) return;

// Light decorations will need a refresh.
R_SurfaceListIterate(GameMap_DecoratedSurfaces(theMap), markSurfaceForDecorationUpdate, material);
}

Expand Down Expand Up @@ -859,8 +858,7 @@ boolean R_MiddleMaterialCoversOpening(int lineFlags, Sector *frontSec, Sector *b
if(!material) return false;

// Ensure we have up to date info about the material.
MaterialSnapshot const &ms =
App_Materials()->prepare(*material, Rend_MapSurfaceMaterialSpec());
MaterialSnapshot const &ms = material->prepare(Rend_MapSurfaceMaterialSpec());

if(ignoreOpacity || (ms.isOpaque() && !frontDef->SW_middleblendmode && frontDef->SW_middlergba[3] >= 1))
{
Expand Down Expand Up @@ -1279,8 +1277,7 @@ float R_GlowStrength(Plane const *pln)
{
if(material->isDrawable() && !Surface_IsSkyMasked(&pln->surface))
{
MaterialSnapshot const &ms =
App_Materials()->prepare(*material, Rend_MapSurfaceMaterialSpec());
MaterialSnapshot const &ms = material->prepare(Rend_MapSurfaceMaterialSpec());

float glowStrength = ms.glowStrength();
if(glowFactor > .0001f)
Expand Down
8 changes: 3 additions & 5 deletions doomsday/engine/src/render/lumobj.cpp
Expand Up @@ -747,9 +747,8 @@ static void addLuminous(mobj_t *mo)
#endif

// Ensure we have up-to-date information about the material.
MaterialSnapshot const &ms =
App_Materials()->prepare(*mat, Rend_SpriteMaterialSpec());
if(!ms.hasTexture(MTU_PRIMARY)) return; // An invalid sprite texture.
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec());
if(!ms.hasTexture(MTU_PRIMARY)) return; // An invalid sprite texture?

pl = (pointlight_analysis_t const *) ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(TA_SPRITE_AUTOLIGHT);
if(!pl) throw Error("addLuminous", QString("Texture \"%1\" has no TA_SPRITE_AUTOLIGHT analysis").arg(ms.texture(MTU_PRIMARY).generalCase().manifest().composeUri()));
Expand Down Expand Up @@ -962,8 +961,7 @@ static boolean createGlowLightForSurface(Surface *suf, void * /*parameters*/)
return true; // Continue iteration.

// Are we glowing at this moment in time?
MaterialSnapshot const &ms =
App_Materials()->prepare(*suf->material, Rend_MapSurfaceMaterialSpec());
MaterialSnapshot const &ms = suf->material->prepare(Rend_MapSurfaceMaterialSpec());
if(!(ms.glowStrength() > .001f)) return true; // Continue iteration.

averagecolor_analysis_t const *avgColorAmplified = (averagecolor_analysis_t const *) ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(TA_COLOR_AMPLIFIED);
Expand Down
5 changes: 2 additions & 3 deletions doomsday/engine/src/render/r_draw.cpp
Expand Up @@ -215,11 +215,10 @@ void R_DrawViewBorder()
glColor4f(1, 1, 1, 1);

// View background.
Materials &materials = *App_Materials();
Material *mat = materials.find(*reinterpret_cast<de::Uri *>(borderGraphicsNames[BG_BACKGROUND])).material();
Material *mat = App_Materials()->find(*reinterpret_cast<de::Uri *>(borderGraphicsNames[BG_BACKGROUND])).material();
if(mat)
{
MaterialSnapshot const &ms = materials.prepare(*mat, Ui_MaterialSpec());
MaterialSnapshot const &ms = mat->prepare(Ui_MaterialSpec());

GL_BindTexture(reinterpret_cast<texturevariant_s *>(&ms.texture(MTU_PRIMARY)));
GL_DrawCutRectf2Tiled(0, 0, port->geometry.size.width, port->geometry.size.height, ms.dimensions().width(), ms.dimensions().height(), 0, 0,
Expand Down
12 changes: 6 additions & 6 deletions doomsday/engine/src/render/r_main.cpp
Expand Up @@ -1277,8 +1277,6 @@ void R_RenderViewPorts()
R_UseViewPort(NULL);
}

#endif // __CLIENT__

static int findSpriteOwner(thinker_t *th, void *context)
{ mobj_t *mo = (mobj_t *) th;
spritedef_t *sprDef = (spritedef_t *) context;
Expand Down Expand Up @@ -1315,8 +1313,6 @@ static void cacheSpritesForState(int stateIndex, MaterialVariantSpec const &spec
}
}

#ifdef __CLIENT__

#undef Rend_CacheForMobjType
DENG_EXTERN_C void Rend_CacheForMobjType(int num)
{
Expand All @@ -1342,8 +1338,12 @@ DENG_EXTERN_C void Rend_CacheForMobjType(int num)

void Rend_CacheForMap()
{
// Don't precache when playing demo.
if(isDedicated || playback) return;
#ifdef __SERVER__
return;
#endif

// Don't precache when playing a demo (why not? -ds).
if(playback) return;

// Precaching from 100 to 200.
Con_SetProgress(100);
Expand Down
14 changes: 5 additions & 9 deletions doomsday/engine/src/render/r_things.cpp
Expand Up @@ -459,7 +459,7 @@ DENG_EXTERN_C boolean R_GetSpriteInfo(int sprite, int frame, spriteinfo_t *info)
App_Materials()->variantSpecForContext(MC_PSPRITE, 0, 1, 0, 0,
GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, 1, -1,
false, true, true, false);
MaterialSnapshot const &ms = App_Materials()->prepare(*mat, spec);
MaterialSnapshot const &ms = mat->prepare(spec);

Texture &tex = ms.texture(MTU_PRIMARY).generalCase();
variantspecification_t const *texSpec = TS_GENERAL(ms.texture(MTU_PRIMARY).spec());
Expand Down Expand Up @@ -501,8 +501,7 @@ coord_t R_VisualRadius(mobj_t *mo)
// Use the sprite frame's width?
if(Material *material = R_GetMaterialForSprite(mo->sprite, mo->frame))
{
MaterialSnapshot const &ms =
App_Materials()->prepare(*material, Rend_SpriteMaterialSpec());
MaterialSnapshot const &ms = material->prepare(Rend_SpriteMaterialSpec());
return ms.dimensions().width() / 2;
}

Expand Down Expand Up @@ -545,8 +544,7 @@ float R_ShadowStrength(mobj_t *mo)
if(mat)
{
// Ensure we've prepared this.
MaterialSnapshot const &ms =
App_Materials()->prepare(*mat, Rend_SpriteMaterialSpec());
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec());

averagealpha_analysis_t const *aa = (averagealpha_analysis_t const *) ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(TA_ALPHA);
float weightedSpriteAlpha;
Expand Down Expand Up @@ -1047,8 +1045,7 @@ void R_ProjectSprite(mobj_t *mo)
}
matFlipT = false;

MaterialSnapshot const &ms =
App_Materials()->prepare(*mat, Rend_SpriteMaterialSpec(mo->tclass, mo->tmap));
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec(mo->tclass, mo->tmap));

// An invalid sprite texture?
Texture &tex = ms.texture(MTU_PRIMARY).generalCase();
Expand Down Expand Up @@ -1290,8 +1287,7 @@ void R_ProjectSprite(mobj_t *mo)
#endif

// Ensure we have up-to-date information about the material.
MaterialSnapshot const &ms =
App_Materials()->prepare(*mat, Rend_SpriteMaterialSpec());
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec());

pointlight_analysis_t const *pl = (pointlight_analysis_t const *) ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(TA_SPRITE_AUTOLIGHT);
if(!pl)
Expand Down
3 changes: 1 addition & 2 deletions doomsday/engine/src/render/rend_console.cpp
Expand Up @@ -558,8 +558,7 @@ static void drawConsoleBackground(Point2Raw const *origin, Size2Raw const *size,
MaterialVariantSpec const &spec =
App_Materials()->variantSpecForContext(MC_UI, 0, 0, 0, 0, GL_REPEAT, GL_REPEAT,
0, 1, 0, false, false, false, false);
MaterialSnapshot const &ms =
App_Materials()->prepare(*consoleBackgroundMaterial, spec);
MaterialSnapshot const &ms = consoleBackgroundMaterial->prepare(spec);

GL_BindTexture(reinterpret_cast<texturevariant_s *>(&ms.texture(MTU_PRIMARY)));

Expand Down
3 changes: 1 addition & 2 deletions doomsday/engine/src/render/rend_decor.cpp
Expand Up @@ -458,8 +458,7 @@ static void updateSurfaceDecorations2(Surface &suf, float offsetS, float offsetT
if(height < 0) height = -height;

// Generate a number of lights.
MaterialSnapshot const &ms =
App_Materials()->prepare(*suf.material, Rend_MapSurfaceMaterialSpec());
MaterialSnapshot const &ms = suf.material->prepare(Rend_MapSurfaceMaterialSpec());

Material::Decorations const &decorations = suf.material->decorations();
for(int i = 0; i < decorations.count(); ++i)
Expand Down

0 comments on commit e0bdf3b

Please sign in to comment.