diff --git a/doomsday/client/include/resource/sprite.h b/doomsday/client/include/resource/sprite.h index cfd2e933ca..24c989b4ec 100644 --- a/doomsday/client/include/resource/sprite.h +++ b/doomsday/client/include/resource/sprite.h @@ -48,13 +48,13 @@ class Sprite public: static int const max_angles = 8; -public: - byte _rotate; ///< 0= no rotations, 1= only front, 2= more... - Material *_mats[8]; ///< Material to use for view angles 0-7 - byte _flip[8]; ///< Flip (1 = flip) to use for view angles 0-7 - public: Sprite(); + Sprite(Sprite const &other); + + Sprite &operator = (Sprite const &other); + + void newViewAngle(Material *material, uint rotation, bool flipped); /** * Select an appropriate material for visualizing the sprite given a mobj's @@ -99,6 +99,9 @@ class Sprite */ Lumobj *generateLumobj() const; #endif + +private: + DENG2_PRIVATE(d) }; #endif // DENG_RESOURCE_SPRITE_H diff --git a/doomsday/client/src/render/api_render.cpp b/doomsday/client/src/render/api_render.cpp index c5a2ed3c29..aa15cd9f24 100644 --- a/doomsday/client/src/render/api_render.cpp +++ b/doomsday/client/src/render/api_render.cpp @@ -55,7 +55,9 @@ DENG_EXTERN_C boolean R_GetSpriteInfo(int spriteId, int frame, spriteinfo_t *inf } de::zapPtr(info); - info->flip = sprite->_flip[0]; + bool flip; + info->material = sprite->material(0, &flip); + info->flip = flip; if(novideo) { @@ -63,8 +65,6 @@ DENG_EXTERN_C boolean R_GetSpriteInfo(int spriteId, int frame, spriteinfo_t *inf return true; } - info->material = sprite->_mats[0]; - #ifdef __CLIENT__ /// @todo fixme: We should not be using the PSprite spec here. -ds de::MaterialVariantSpec const &spec = diff --git a/doomsday/client/src/render/billboard.cpp b/doomsday/client/src/render/billboard.cpp index 663067e7f4..b5c80cab30 100644 --- a/doomsday/client/src/render/billboard.cpp +++ b/doomsday/client/src/render/billboard.cpp @@ -210,12 +210,13 @@ static void setupPSpriteParams(rendpspriteparams_t *params, vispsprite_t *spr) Sprite const *sprite = &App_ResourceSystem().sprite(spriteIdx, frameIdx); - boolean flip = sprite->_flip[0]; + bool flip; + Material *material = sprite->material(0, &flip); MaterialVariantSpec const &spec = App_Materials().variantSpec(PSpriteContext, 0, 1, 0, 0, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, 0, -2, 0, false, true, true, false); - MaterialSnapshot const &ms = sprite->_mats[0]->prepare(spec); + MaterialSnapshot const &ms = material->prepare(spec); Texture const &tex = ms.texture(MTU_PRIMARY).generalCase(); variantspecification_t const &texSpec = TS_GENERAL(ms.texture(MTU_PRIMARY).spec()); @@ -233,7 +234,7 @@ static void setupPSpriteParams(rendpspriteparams_t *params, vispsprite_t *spr) params->texFlip[0] = flip; params->texFlip[1] = false; - params->mat = sprite->_mats[0]; + params->mat = material; params->ambientColor[CA] = spr->data.sprite.alpha; if(spr->data.sprite.isFullBright) diff --git a/doomsday/client/src/render/r_main.cpp b/doomsday/client/src/render/r_main.cpp index 211deb209f..0b8a4106a9 100644 --- a/doomsday/client/src/render/r_main.cpp +++ b/doomsday/client/src/render/r_main.cpp @@ -1553,16 +1553,16 @@ static int findSpriteOwner(thinker_t *th, void *context) return false; // Continue iteration. } -static void cacheSpritesForState(int stateIdx, MaterialVariantSpec const &spec) +static void cacheSpriteSet(int spriteId, MaterialVariantSpec const &spec) { - state_t *state = toState(stateIdx); - DENG2_ASSERT(state != 0); - - ResourceSystem::SpriteSet const &sprites = App_ResourceSystem().spriteSet(state->sprite); + ResourceSystem::SpriteSet const &sprites = App_ResourceSystem().spriteSet(spriteId); foreach(Sprite *sprite, sprites) for(int i = 0; i < Sprite::max_angles; ++i) { - App_Materials().cache(*sprite->_mats[i], spec); + if(Material *material = sprite->material(i)) + { + App_Materials().cache(*material, spec); + } } } @@ -1583,7 +1583,10 @@ DENG_EXTERN_C void Rend_CacheForMobjType(int num) if(precacheSprites) { - cacheSpritesForState(i, spec); + state_t *state = toState(i); + DENG2_ASSERT(state != 0); + + cacheSpriteSet(state->sprite, spec); } /// @todo What about sounds? } @@ -1644,14 +1647,7 @@ void Rend_CacheForMap() findSpriteOwner, &i)) { // This sprite is used by some state of at least one mobj. - - // Precache all angles for all frames. - ResourceSystem::SpriteSet const &sprites = App_ResourceSystem().spriteSet(i); - foreach(Sprite *sprite, sprites) - for(int k = 0; k < Sprite::max_angles; ++k) - { - App_Materials().cache(*sprite->_mats[k], spec); - } + cacheSpriteSet(i, spec); } } } diff --git a/doomsday/client/src/resource/models.cpp b/doomsday/client/src/resource/models.cpp index 23076e3abd..4a664f2ab1 100644 --- a/doomsday/client/src/resource/models.cpp +++ b/doomsday/client/src/resource/models.cpp @@ -951,7 +951,7 @@ static void scaleModelToSprite(modeldef_t &mf, int spriteIdx, int frameIdx) Sprite *sprite = App_ResourceSystem().spritePtr(spriteIdx, frameIdx); if(!sprite) return; - MaterialSnapshot const &ms = sprite->_mats[0]->prepare(Rend_SpriteMaterialSpec()); + MaterialSnapshot const &ms = sprite->material(0)->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); diff --git a/doomsday/client/src/resource/resourcesystem.cpp b/doomsday/client/src/resource/resourcesystem.cpp index 3968aced1c..61dff6c7f3 100644 --- a/doomsday/client/src/resource/resourcesystem.cpp +++ b/doomsday/client/src/resource/resourcesystem.cpp @@ -1423,36 +1423,6 @@ static SpriteDefs generateSpriteDefs() return spriteDefs; } -static void setupSpriteViewAngle(Sprite *sprTemp, int *maxFrame, - Material *mat, uint frame, uint rotation, bool flipped) -{ - if(frame >= 30) return; - if(rotation > 8) return; - - if((signed) frame > *maxFrame) - { - *maxFrame = frame; - } - - if(rotation == 0) - { - // This frame should be used for all rotations. - sprTemp[frame]._rotate = false; - for(int r = 0; r < 8; ++r) - { - sprTemp[frame]._mats[r] = mat; - sprTemp[frame]._flip[r] = byte( flipped ); - } - return; - } - - rotation--; // Make 0 based. - - sprTemp[frame]._rotate = true; - sprTemp[frame]._mats[rotation] = mat; - sprTemp[frame]._flip[rotation] = byte( flipped ); -} - void ResourceSystem::initSprites() { Time begunAt; @@ -1470,7 +1440,6 @@ void ResourceSystem::initSprites() //groups.reserve(spriteNameCount); // Build the final sprites. - Sprite sprTemp[128]; int customIdx = 0; foreach(SpriteDef const &def, defs) { @@ -1481,25 +1450,38 @@ void ResourceSystem::initSprites() DENG2_ASSERT(!d->spriteGroups.contains(spriteId)); // sanity check. Instance::SpriteGroup &group = d->spriteGroups.insert(spriteId, Instance::SpriteGroup()).value(); - std::memset(sprTemp, -1, sizeof(sprTemp)); + //std::memset(sprTemp, -1, sizeof(sprTemp)); + Sprite sprTemp[128]; int maxSprite = -1; foreach(SpriteFrameDef const &frameDef, def.frames) { - setupSpriteViewAngle(sprTemp, &maxSprite, frameDef.mat, - frameDef.frame[0] - 1, frameDef.rotation[0], - false); + int frame = frameDef.frame[0] - 1; + if(frame < 30) + { + sprTemp[frame].newViewAngle(frameDef.mat, frameDef.rotation[0], false); + if(frame > maxSprite) + { + maxSprite = frame; + } + } if(frameDef.frame[1]) { - setupSpriteViewAngle(sprTemp, &maxSprite, frameDef.mat, - frameDef.frame[1] - 1, frameDef.rotation[1], - true); + frame = frameDef.frame[1] - 1; + if(frame < 30) + { + sprTemp[frame].newViewAngle(frameDef.mat, frameDef.rotation[1], true); + if(frame > maxSprite) + { + maxSprite = frame; + } + } } } ++maxSprite; - for(int k = 0; k < maxSprite; ++k) + /*for(int k = 0; k < maxSprite; ++k) { if(int(sprTemp[k]._rotate) == -1) // Ahem! { @@ -1520,19 +1502,11 @@ void ResourceSystem::initSprites() } } } - } + }*/ for(int k = 0; k < maxSprite; ++k) { - Sprite const &tmpSprite = sprTemp[k]; - - Sprite *sprite = new Sprite; - - sprite->_rotate = tmpSprite._rotate; - std::memcpy(sprite->_mats, tmpSprite._mats, sizeof(sprite->_mats)); - std::memcpy(sprite->_flip, tmpSprite._flip, sizeof(sprite->_flip)); - - group.sprites.append(sprite); + group.sprites.append(new Sprite(sprTemp[k])); } } } diff --git a/doomsday/client/src/resource/sprite.cpp b/doomsday/client/src/resource/sprite.cpp index e55fc7f304..ed4c370725 100644 --- a/doomsday/client/src/resource/sprite.cpp +++ b/doomsday/client/src/resource/sprite.cpp @@ -34,11 +34,60 @@ using namespace de; -Sprite::Sprite() - : _rotate(0) +DENG2_PIMPL_NOREF(Sprite) { - zap(_mats); - zap(_flip); + byte rotate; ///< 0= no rotations, 1= only front, 2= more... + Material *mats[8]; ///< Material to use for view angles 0-7 + byte flip[8]; ///< Flip (1 = flip) to use for view angles 0-7 + + Instance() + : rotate(0) + { + zap(mats); + zap(flip); + } + + Instance(Instance const &other) + : rotate(other.rotate) + { + std::memcpy(mats, other.mats, sizeof(mats)); + std::memcpy(flip, other.flip, sizeof(flip)); + } +}; + +Sprite::Sprite() : d(new Instance) +{} + +Sprite::Sprite(Sprite const &other) : d(new Instance(*other.d)) +{} + +Sprite &Sprite::operator = (Sprite const &other) +{ + d.reset(new Instance(*other.d)); + return *this; +} + +void Sprite::newViewAngle(Material *material, uint rotation, bool flipped) +{ + if(rotation > 8) return; + + if(rotation == 0) + { + // This frame should be used for all rotations. + d->rotate = false; + for(int r = 0; r < 8; ++r) + { + d->mats[r] = material; + d->flip[r] = byte( flipped ); + } + return; + } + + rotation--; // Make 0 based. + + d->rotate = true; + d->mats[rotation] = material; + d->flip[rotation] = byte( flipped ); } Material *Sprite::material(int rotation, bool *flipX, bool *flipY) const @@ -51,9 +100,9 @@ Material *Sprite::material(int rotation, bool *flipX, bool *flipY) const return 0; } - if(flipX) *flipX = CPP_BOOL(_flip[rotation]); + if(flipX) *flipX = CPP_BOOL(d->flip[rotation]); - return _mats[rotation]; + return d->mats[rotation]; } Material *Sprite::material(angle_t mobjAngle, angle_t angleToEye, @@ -61,7 +110,7 @@ Material *Sprite::material(angle_t mobjAngle, angle_t angleToEye, { int rotation = 0; // Use single rotation for all viewing angles (default). - if(!noRotation && _rotate) + if(!noRotation && d->rotate) { // Rotation is determined by the relative angle to the viewer. rotation = (angleToEye - mobjAngle + (unsigned) (ANG45 / 2) * 9) >> 29;