Skip to content

Commit

Permalink
Refactor|Sprite|Resources: Cleaned up Sprite representation somewhat
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Nov 20, 2013
1 parent fd39368 commit 68e133d
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 133 deletions.
4 changes: 4 additions & 0 deletions doomsday/client/include/resource/resourcesystem.h
Expand Up @@ -121,6 +121,10 @@ class ResourceSystem : public de::System

SpriteSet &spriteSet(int spriteId);

#ifdef __CLIENT__
void cacheSpriteSet(int spriteId, de::MaterialVariantSpec const &spec);
#endif

/**
* Provides access to the Textures collection.
*/
Expand Down
57 changes: 35 additions & 22 deletions doomsday/client/include/resource/sprite.h
Expand Up @@ -23,7 +23,7 @@
#ifndef DENG_RESOURCE_SPRITE_H
#define DENG_RESOURCE_SPRITE_H

#include "dd_types.h"
#include <de/Error>
#include <de/String>
#include <QList>

Expand All @@ -46,46 +46,57 @@ class Lumobj;
class Sprite
{
public:
/// Required view angle is missing. @ingroup errors
DENG2_ERROR(MissingViewAngleError);

static int const max_angles = 8;

struct ViewAngle {
Material *material;
bool mirrorX;

ViewAngle() : material(0), mirrorX(false)
{}
};

public:
Sprite();
Sprite(Sprite const &other);

Sprite &operator = (Sprite const &other);

void newViewAngle(Material *material, uint rotation, bool flipped);
void newViewAngle(Material *material, uint rotation, bool mirrorX);

/**
* Select an appropriate material for visualizing the sprite given a mobj's
* angle and relative angle with the viewer (the 'eye').
*
* @param mobjAngle Angle of the mobj in the map coordinate space.
* @param angleToEye Relative angle of the mobj from the view position.
* @param noRotation @c true= Ignore rotations and always use the "front".
* Returns @c true iff a view angle is defined for the specified @a rotation.
*
* Return values:
* @param flipX @c true= chosen material should be flipped on the X axis.
* @param flipY @c true= chosen material should be flipped on the Y axis.
*
* @return The chosen material otherwise @c 0.
* @param rotation Rotation index/identifier to lookup the material for. The
* valid range is [0..max_angles)
*/
Material *material(angle_t mobjAngle, angle_t angleToEye, bool noRotation = false,
bool *flipX = 0, bool *flipY = 0) const;
bool hasViewAngle(int rotation) const;

/**
* Returns the material attributed to the specified rotation.
* Returns the view angle for the specified @a rotation.
*
* @param rotation Rotation index/identifier to lookup the material for. The
* valid range is [0...SPRITEFRAME_MAX_ANGLES)
* valid range is [0..max_angles)
*
* Return values:
* @param flipX @c true= chosen material should be flipped on the X axis.
* @param flipY @c true= chosen material should be flipped on the Y axis.
* @return The viewAngle associated with the specified rotation.
*/
ViewAngle const &viewAngle(int rotation) const;

/**
* Select an appropriate view angle for visualizing the sprite given a mobj's
* angle and relative angle with the viewer (the 'eye').
*
* @return The attributed material otherwise @c 0.
* @param mobjAngle Angle of the mobj in the map coordinate space.
* @param angleToEye Relative angle of the mobj from the view position.
* @param noRotation @c true= Ignore rotations and always use the "front".
*
* @return The viewAngle associated with the chosen rotation.
*/
Material *material(int rotation = 0, bool *flipX = 0, bool *flipY = 0) const;
ViewAngle const &closestViewAngle(angle_t mobjAngle, angle_t angleToEye,
bool noRotation = false) const;

#ifdef __CLIENT__
/**
Expand All @@ -104,4 +115,6 @@ class Sprite
DENG2_PRIVATE(d)
};

typedef Sprite::ViewAngle SpriteViewAngle;

#endif // DENG_RESOURCE_SPRITE_H
5 changes: 2 additions & 3 deletions doomsday/client/src/render/api_render.cpp
Expand Up @@ -55,9 +55,8 @@ DENG_EXTERN_C boolean R_GetSpriteInfo(int spriteId, int frame, spriteinfo_t *inf
}

de::zapPtr(info);
bool flip;
info->material = sprite->material(0, &flip);
info->flip = flip;
info->material = sprite->viewAngle(0).material;
info->flip = sprite->viewAngle(0).mirrorX;

if(novideo)
{
Expand Down
4 changes: 2 additions & 2 deletions doomsday/client/src/render/billboard.cpp
Expand Up @@ -210,8 +210,8 @@ static void setupPSpriteParams(rendpspriteparams_t *params, vispsprite_t *spr)

Sprite const *sprite = &App_ResourceSystem().sprite(spriteIdx, frameIdx);

bool flip;
Material *material = sprite->material(0, &flip);
Material *material = sprite->viewAngle(0).material;
bool flip = sprite->viewAngle(0).mirrorX;

MaterialVariantSpec const &spec =
App_Materials().variantSpec(PSpriteContext, 0, 1, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE,
Expand Down
17 changes: 2 additions & 15 deletions doomsday/client/src/render/r_main.cpp
Expand Up @@ -1553,19 +1553,6 @@ static int findSpriteOwner(thinker_t *th, void *context)
return false; // Continue iteration.
}

static void cacheSpriteSet(int spriteId, MaterialVariantSpec const &spec)
{
ResourceSystem::SpriteSet const &sprites = App_ResourceSystem().spriteSet(spriteId);
foreach(Sprite *sprite, sprites)
for(int i = 0; i < Sprite::max_angles; ++i)
{
if(Material *material = sprite->material(i))
{
App_Materials().cache(*material, spec);
}
}
}

#undef Rend_CacheForMobjType
DENG_EXTERN_C void Rend_CacheForMobjType(int num)
{
Expand All @@ -1586,7 +1573,7 @@ DENG_EXTERN_C void Rend_CacheForMobjType(int num)
state_t *state = toState(i);
DENG2_ASSERT(state != 0);

cacheSpriteSet(state->sprite, spec);
App_ResourceSystem().cacheSpriteSet(state->sprite, spec);
}
/// @todo What about sounds?
}
Expand Down Expand Up @@ -1647,7 +1634,7 @@ void Rend_CacheForMap()
findSpriteOwner, &i))
{
// This sprite is used by some state of at least one mobj.
cacheSpriteSet(i, spec);
App_ResourceSystem().cacheSpriteSet(i, spec);
}
}
}
Expand Down
128 changes: 77 additions & 51 deletions doomsday/client/src/render/r_things.cpp
Expand Up @@ -206,9 +206,25 @@ void R_ProjectSprite(mobj_t *mo)

// Decide which material to use according to the sprite's angle and position
// relative to that of the viewer.
bool matFlipS, matFlipT;
Material *mat = sprite->material(mo->angle, R_ViewPointToAngle(mo->origin),
mf != 0, &matFlipS, &matFlipT);
Material *mat = 0;
bool matFlipS = false;
bool matFlipT = false;

try
{
SpriteViewAngle const &sprViewAngle =
sprite->closestViewAngle(mo->angle, R_ViewPointToAngle(mo->origin), mf != 0);

mat = sprViewAngle.material;
matFlipS = sprViewAngle.mirrorX;
}
catch(Sprite::MissingViewAngleError const &er)
{
// Log but otherwise ignore this error.
LOG_WARNING(er.asText() + ". Projecting sprite '%i' frame '%i', ignoring.")
<< mo->sprite << mo->frame;
}

if(!mat) return;

// A valid sprite texture in the "Sprites" scheme is required.
Expand Down Expand Up @@ -428,68 +444,78 @@ void R_ProjectSprite(mobj_t *mo)
// Do we need to project a flare source too?
if(mo->lumIdx != Lumobj::NoIndex)
{
Material *mat = sprite->material(mo->angle, R_ViewPointToAngle(mo->origin));
if(!mat) return;
try
{
SpriteViewAngle const &sprViewAngle =
sprite->closestViewAngle(mo->angle, R_ViewPointToAngle(mo->origin));

// A valid sprite texture in the "Sprites" scheme is required.
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec(mo->tclass, mo->tmap));
if(!ms.hasTexture(MTU_PRIMARY))
return;
Texture &tex = ms.texture(MTU_PRIMARY).generalCase();
if(tex.manifest().schemeName().compareWithoutCase("Sprites"))
return;
Material *mat = sprViewAngle.material;

pointlight_analysis_t const *pl = (pointlight_analysis_t const *)
ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(Texture::BrightPointAnalysis);
DENG_ASSERT(pl != 0);
// A valid sprite texture in the "Sprites" scheme is required.
MaterialSnapshot const &ms = mat->prepare(Rend_SpriteMaterialSpec(mo->tclass, mo->tmap));
if(!ms.hasTexture(MTU_PRIMARY))
return;
Texture &tex = ms.texture(MTU_PRIMARY).generalCase();
if(tex.manifest().schemeName().compareWithoutCase("Sprites"))
return;;
pointlight_analysis_t const *pl = (pointlight_analysis_t const *)
ms.texture(MTU_PRIMARY).generalCase().analysisDataPointer(Texture::BrightPointAnalysis);
DENG2_ASSERT(pl != 0);

Lumobj const *lum = cluster.sector().map().lumobj(mo->lumIdx);
Lumobj const *lum = cluster.sector().map().lumobj(mo->lumIdx);

vissprite_t *vis = R_NewVisSprite(VSPR_FLARE);
vissprite_t *vis = R_NewVisSprite(VSPR_FLARE);

vis->distance = distFromEye;
vis->distance = distFromEye;

// Determine the exact center of the flare.
vis->origin = moPos + visOff;
vis->origin.z += lum->zOffset();
// Determine the exact center of the flare.
vis->origin = moPos + visOff;
vis->origin.z += lum->zOffset();

float flareSize = pl->brightMul;
// X offset to the flare position.
float xOffset = ms.width() * pl->originX - -tex.origin().x;
float flareSize = pl->brightMul;
// X offset to the flare position.
float xOffset = ms.width() * pl->originX - -tex.origin().x;

// Does the mobj have an active light definition?
ded_light_t const *def = (mo->state? stateLights[mo->state - states] : 0);
if(def)
{
if(def->size)
flareSize = def->size;
if(def->haloRadius)
flareSize = def->haloRadius;
if(def->offset[VX])
xOffset = def->offset[VX];

vis->data.flare.flags = def->flags;
}
// Does the mobj have an active light definition?
ded_light_t const *def = (mo->state? stateLights[mo->state - states] : 0);
if(def)
{
if(def->size)
flareSize = def->size;
if(def->haloRadius)
flareSize = def->haloRadius;
if(def->offset[VX])
xOffset = def->offset[VX];

vis->data.flare.flags = def->flags;
}

vis->data.flare.size = flareSize * 60 * (50 + haloSize) / 100.0f;
if(vis->data.flare.size < 8)
vis->data.flare.size = 8;
vis->data.flare.size = flareSize * 60 * (50 + haloSize) / 100.0f;
if(vis->data.flare.size < 8)
vis->data.flare.size = 8;

// Color is taken from the associated lumobj.
V3f_Set(vis->data.flare.color, lum->color().x, lum->color().y, lum->color().z);
// Color is taken from the associated lumobj.
V3f_Set(vis->data.flare.color, lum->color().x, lum->color().y, lum->color().z);

vis->data.flare.factor = mo->haloFactors[viewPlayer - ddPlayers];
vis->data.flare.xOff = xOffset;
vis->data.flare.mul = 1;
vis->data.flare.tex = 0;
vis->data.flare.factor = mo->haloFactors[viewPlayer - ddPlayers];
vis->data.flare.xOff = xOffset;
vis->data.flare.mul = 1;
vis->data.flare.tex = 0;

if(def && def->flare)
{
de::Uri const &flaremapResourceUri = *reinterpret_cast<de::Uri const *>(def->flare);
if(flaremapResourceUri.path().toStringRef().compareWithoutCase("-"))
if(def && def->flare)
{
vis->data.flare.tex = GL_PrepareFlaremap(flaremapResourceUri);
de::Uri const &flaremapResourceUri = *reinterpret_cast<de::Uri const *>(def->flare);
if(flaremapResourceUri.path().toStringRef().compareWithoutCase("-"))
{
vis->data.flare.tex = GL_PrepareFlaremap(flaremapResourceUri);
}
}
}
catch(Sprite::MissingViewAngleError const &er)
{
// Log but otherwise ignore this error.
LOG_WARNING(er.asText() + ". Projecting flare source for sprite '%i' frame '%i', ignoring.")
<< mo->sprite << mo->frame;
}
}
}
3 changes: 2 additions & 1 deletion doomsday/client/src/render/rend_main.cpp
Expand Up @@ -2670,8 +2670,9 @@ static int projectSpriteWorker(mobj_t &mo, void * /*context*/)
if(cluster.visCeiling().surface().hasSkyMaskedMaterial())
{
Sprite *sprite = App_ResourceSystem().spritePtr(mo.sprite, mo.frame);
if(Material *material = sprite->material())
if(sprite->hasViewAngle(0))
{
Material *material = sprite->viewAngle(0).material;
if(!(mo.dPlayer && (mo.dPlayer->flags & DDPF_CAMERA))
&& mo.origin[VZ] <= cluster.visCeiling().heightSmoothed()
&& mo.origin[VZ] >= cluster.visFloor().heightSmoothed())
Expand Down
3 changes: 2 additions & 1 deletion doomsday/client/src/resource/models.cpp
Expand Up @@ -950,8 +950,9 @@ static void scaleModelToSprite(modeldef_t &mf, int spriteIdx, int frameIdx)
{
Sprite *sprite = App_ResourceSystem().spritePtr(spriteIdx, frameIdx);
if(!sprite) return;
if(!sprite->hasViewAngle(0)) return;

MaterialSnapshot const &ms = sprite->material(0)->prepare(Rend_SpriteMaterialSpec());
MaterialSnapshot const &ms = sprite->viewAngle(0).material->prepare(Rend_SpriteMaterialSpec());
Texture const &tex = ms.texture(MTU_PRIMARY).generalCase();
int off = de::max(0, -tex.origin().y - ms.height());
scaleModel(mf, ms.height(), off);
Expand Down
15 changes: 15 additions & 0 deletions doomsday/client/src/resource/resourcesystem.cpp
Expand Up @@ -1514,6 +1514,21 @@ void ResourceSystem::initSprites()
LOG_INFO(String("Completed in %1 seconds.").arg(begunAt.since(), 0, 'g', 2));
}

#ifdef __CLIENT__
void ResourceSystem::cacheSpriteSet(int spriteId, MaterialVariantSpec const &spec)
{
SpriteSet const &set = spriteSet(spriteId);
foreach(Sprite *sprite, set)
for(int i = 0; i < Sprite::max_angles; ++i)
{
if(sprite->hasViewAngle(i))
{
d->materials.cache(*sprite->viewAngle(0).material, spec);
}
}
}
#endif

void ResourceSystem::clearAllColorPalettes()
{
d->colorPaletteNames.clear();
Expand Down

0 comments on commit 68e133d

Please sign in to comment.