Implement SdlAnimSprite

This commit is contained in:
Nathan Fulton 2016-08-31 08:59:47 -04:00
parent 6e65f8273b
commit 5b5917fbab
4 changed files with 399 additions and 3 deletions

View File

@ -346,6 +346,8 @@
D813C0A01D6E3CDF007132EE /* NavBackSmall.png in Resources */ = {isa = PBXBuildFile; fileRef = D813C0591D6E3B2F007132EE /* NavBackSmall.png */; };
D813C0A11D6E3CDF007132EE /* NavForwardSmall.png in Resources */ = {isa = PBXBuildFile; fileRef = D813C05A1D6E3B2F007132EE /* NavForwardSmall.png */; };
D813C0A21D6E3CDF007132EE /* webview.mm in Sources */ = {isa = PBXBuildFile; fileRef = D813C05C1D6E3B2F007132EE /* webview.mm */; };
D8408C041D770C0900304E05 /* sdlanimsprite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8408C021D770C0900304E05 /* sdlanimsprite.cpp */; };
D8408C051D770C2D00304E05 /* sdlanimsprite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D8408C021D770C0900304E05 /* sdlanimsprite.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -685,6 +687,8 @@
D813C08A1D6E3C30007132EE /* CoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudio.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/CoreAudio.framework; sourceTree = DEVELOPER_DIR; };
D813C08C1D6E3C46007132EE /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/AVFoundation.framework; sourceTree = DEVELOPER_DIR; };
D813C08E1D6E3C4E007132EE /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/AudioToolbox.framework; sourceTree = DEVELOPER_DIR; };
D8408C021D770C0900304E05 /* sdlanimsprite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sdlanimsprite.cpp; sourceTree = "<group>"; };
D8408C031D770C0900304E05 /* sdlanimsprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sdlanimsprite.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -1105,6 +1109,8 @@
55C5AC511390627C003B15C5 /* htplatform.h */,
55C5AC651390627C003B15C5 /* main.cpp */,
55C5AC791390627C003B15C5 /* savegame.cpp */,
D8408C021D770C0900304E05 /* sdlanimsprite.cpp */,
D8408C031D770C0900304E05 /* sdlanimsprite.h */,
C169F5B013A43CD800B4491D /* sdleventserver.h */,
55C5AC7E1390627C003B15C5 /* sdlpackfile.cpp */,
55C5AC7F1390627C003B15C5 /* sdlpackfile.h */,
@ -1374,6 +1380,7 @@
5501E616139076E20048AAFE /* main.cpp in Sources */,
551C91601390A40F0018ECBA /* yajl.c in Sources */,
551C91611390A40F0018ECBA /* yajl_buf.c in Sources */,
D8408C041D770C0900304E05 /* sdlanimsprite.cpp in Sources */,
551C91621390A40F0018ECBA /* yajl_encode.c in Sources */,
551C91641390A40F0018ECBA /* yajl_lex.c in Sources */,
551C91651390A40F0018ECBA /* yajl_parser.c in Sources */,
@ -1552,6 +1559,7 @@
D813C01C1D6E3A5E007132EE /* selectserver.cpp in Sources */,
D813C01D1D6E3A5E007132EE /* socket.cpp in Sources */,
D813C01E1D6E3A5E007132EE /* socketaddress.cpp in Sources */,
D8408C051D770C2D00304E05 /* sdlanimsprite.cpp in Sources */,
D813C01F1D6E3A5E007132EE /* socketserver.cpp in Sources */,
D813C0201D6E3A5E007132EE /* thread.cpp in Sources */,
D813C0211D6E3A5E007132EE /* tick.cpp in Sources */,

327
game/sdl/sdlanimsprite.cpp Normal file
View File

@ -0,0 +1,327 @@
#include "base/tick.h"
#include "base/thread.h"
#include "game/sdl/sdlanimsprite.h"
#include "game/sdl/sysmessages.h"
namespace wi {
SdlAnimSprite::SdlAnimSprite(SpriteManager *psprm) {
hash_ = 0;
cx_ = 0;
cy_ = 0;
xOrigin_ = 0;
yOrigin_ = 0;
texture_ = NULL;
surface_ = NULL;
nScale_ = 1.0f;
x_ = 0;
y_ = 0;
fVisible_ = true;
psprm_ = psprm;
}
SdlAnimSprite::~SdlAnimSprite() {
psprm_->Remove(this);
crit_.Enter();
SDL_DestroyTexture(texture_);
texture_ = NULL;
SDL_FreeSurface(surface_);
surface_ = NULL;
crit_.Leave();
}
void SdlAnimSprite::CaptureFrame(UnitGob *pgob) {
// Surface already created?
dword hash = pgob->GetAnimationHash();
if (hash == hash_) {
return;
}
// Enter critical section since drawing occurs on the main thread
crit_.Enter();
hash_ = hash;
// Remember UIBounds
UnitConsts *puntc = GetUnitConsts(pgob->GetType());
rcUI_.FromWorldRect(&puntc->wrcUIBounds);
// Create surface
bool fSuccess = CreateSurface(pgob);
crit_.Leave();
if (!fSuccess) {
return;
}
// Add this sprite
psprm_->Add(this);
}
bool SdlAnimSprite::CreateSurface(UnitGob *pgob) {
// Get height/width
Rect rcAni;
pgob->GetAnimationBounds(&rcAni, false);
cx_ = (rcAni.Width() + 1) & ~1;
cy_ = rcAni.Height();
// Remember the bounds of the base. This'll be used later for y
// positioning.
pgob->GetAnimationBounds(&rcBase_, true);
// rcAni has negative left and top. This identifies the origin.
xOrigin_ = rcAni.left;
yOrigin_ = rcAni.top;
// Alloc the 8bpp buffer.
int cp = cx_ * cy_;
byte *pb8 = new byte[cp];
if (pb8 == NULL) {
return false;
}
// Draw the animation into an 8 bit DibBitmap
// The 8->32 conversion palette has been tweaked so that 255
// will map to RGBA transparent on output.
DibBitmap bm;
bm.Init(pb8, cx_, cy_);
memset(pb8, 255, cp);
// Subvert the TBitmap shdowing to our purpose.
// The background is 255. Force TBitmap shadowing to turn this into 254.
// 254 has been to RGBA color with appropriate alpha, when the 8->32bpp
// conversion occurs.
byte bSav = gmpiclriclrShadow[255];
gmpiclriclrShadow[255] = 254;
pgob->DrawAnimation(&bm, -xOrigin_, -yOrigin_);
gmpiclriclrShadow[255] = bSav;
// Alloc the 32bpp buffer.
dword *pdw32 = new dword[cp];
if (pdw32 == NULL) {
delete[] pb8;
return false;
}
// Convert to 32bpp. Sdl will rotate at draw time.
byte *pbT = pb8;
dword *pdwT = pdw32;
int cpT = cp;
while (cpT-- != 0) {
*pdwT++ = mp8bpp32bpp_[*pbT++];
}
delete[] pb8;
// Create the appropriate masks
dword rmask = 0xff000000;
dword gmask = 0x00ff0000;
dword bmask = 0x0000ff00;
dword amask = 0x000000ff;
surface_ = SDL_CreateRGBSurfaceFrom(pdw32, cx_, cy_, 32, (cx_ * sizeof(dword)), bmask, gmask, rmask, amask);
if (surface_ == NULL) {
delete[] pdw32;
return false;
}
return true;
}
void SdlAnimSprite::Draw(void *pv, Size *psiz) {
if (!fVisible_) {
return;
}
// This gets called on the drawing thread.
// The coordinate space pre-rotated to be the game coordinate space but at
// sector 0 (0, 0 is at bottom left). As always, xOrigin_ and yOrigin_
// are negative.
crit_.Enter();
Rect rcBounds;
GetBounds(&rcBounds);
SDL_Rect rc = {
x_ + rcBounds.left,
y_ + rcBounds.top,
rcBounds.Width() ,
rcBounds.Height()
};
if (surface_ != NULL) {
// Create a texture from the surface
texture_ = SDL_CreateTextureFromSurface((SDL_Renderer *)pv, surface_);
// Render the texture
SDL_RenderCopy((SDL_Renderer *)pv, texture_, NULL, &rc);
}
crit_.Leave();
}
void SdlAnimSprite::GetBounds(Rect *prc) {
base::CritScope cs(&crit_);
// Scale the UI rect, centered on the non-scaled UI rect
Rect rcUIScaled = rcUI_;
rcUIScaled.Inflate(rcUI_.Width() * (nScale_ - 1.0f) / 2,
rcUI_.Height() * (nScale_ - 1.0f) / 2);
// Center the height within the scaled UI rect, so it is centered under
// the finger. Use the base height, since that doesn't change as other
// parts animate. Offset by the base origin so the base stays in one
// place (even if the height changes). Finally, use the same percentage
// offset from the UI rect to position correctly.
int xNew = rcUIScaled.left + (xOrigin_ - rcUI_.left) * nScale_;
int yNew = (rcUIScaled.top + rcUIScaled.bottom -
rcBase_.Height() * nScale_) / 2 - rcBase_.top * nScale_ +
yOrigin_ * nScale_;
int cxNew = (float)cx_ * nScale_;
int cyNew = (float)cy_ * nScale_;
prc->left = xNew;
prc->top = yNew;
prc->right = xNew + cxNew;
prc->bottom = yNew + cyNew;
}
void SdlAnimSprite::SetPalette(Palette *ppal) {
// Set the palette mapping table
// Note the AMXs use the first 131 colors of the palette.
for (int n = 0; n < BigWord(ppal->cEntries); n++) {
byte *pb = (byte *)&mp8bpp32bpp_[n];
*pb++ = 255;
*pb++ = ppal->argb[n][0];
*pb++ = ppal->argb[n][1];
*pb++ = ppal->argb[n][2];
}
// Make the last color of the palete RGBA for transparent.
// We'll fill the 8bpp image with this, so that at 8->32 conversion,
// we get transparency.
mp8bpp32bpp_[255] = 0;
// Make the second to last 40% black. AMX transparent will map to this
// with clever remapping. 40% is equivalent to tbitmap shadowmap.
byte *pb = (byte *)&mp8bpp32bpp_[254];
*pb++ = 102;
*pb++ = 0;
*pb++ = 0;
*pb++ = 0;
}
void SdlAnimSprite::SetScale(float nScale) {
if (nScale_ == nScale) {
return;
}
nScale_ = nScale;
psprm_->Update(this);
}
void SdlAnimSprite::SetPosition(int x, int y) {
if (x_ == x && y_ == y) {
return;
}
x_ = x;
y_ = y;
psprm_->Update(this);
}
void SdlAnimSprite::Show(bool fShow) {
if (fVisible_ == fShow) {
return;
}
fVisible_ = fShow;
psprm_->Update(this);
}
void SdlAnimSprite::SetScaleAnimation(float nScaleStart, float nScaleEnd,
dword cms, dword cmsRate, bool fAutoDestroy) {
#if 1
SetScale(nScaleEnd);
return;
#endif
// If the current scale is inside the requested range, advance the
// animation timing to that point. For example if while it is scaling
// up there is a request to scale it down, this keeps the animation
// stepping constant.
if (nScale_ >= nScaleStart && nScale_ <= nScaleEnd) {
float nPercent = (float)(nScaleEnd - nScale_) /
(float)(nScaleEnd - nScaleStart);
cms *= nPercent;
nScaleStart = nScale_;
}
nScaleStart_ = nScaleStart;
nScaleEnd_ = nScaleEnd;
msAnimateStart_ = base::GetMillisecondCount();
cmsAnimate_ = cms;
cmsAnimationRate_ = cmsRate;
fAutoDestroy_ = fAutoDestroy;
thread_.Clear(this, kidmAnimationTimer);
base::Message msg;
msg.handler = this;
msg.id = kidmAnimationTimer;
thread_.PostDelayed(&msg, cmsAnimationRate_ / 10);
SetScale(nScaleStart_);
psprm_->Update(this);
}
void SdlAnimSprite::OnMessage(base::Message *pmsg) {
if (pmsg->id == kidmAnimationTimer) {
long msCurrent = base::GetMillisecondCount();
float nPercent = (float)(msCurrent - msAnimateStart_) /
(float)cmsAnimate_;
bool fFinished = false;
if (nPercent >= 1.0f) {
nPercent = 1.0f;
fFinished = true;
}
SetScale(nScaleStart_ + (nScaleEnd_ - nScaleStart_) * nPercent);
psprm_->Update(this);
if (fFinished) {
if (fAutoDestroy_) {
// Delete after the next timer, so the current frame shows
base::Message msg;
msg.handler = this;
msg.id = kidmDestroyAfterAnimation;
thread_.PostDelayed(&msg, cmsAnimationRate_ / 10);
}
return;
}
// Schedule the next timer
base::Message msg;
msg.handler = this;
msg.id = kidmAnimationTimer;
thread_.PostDelayed(&msg, cmsAnimationRate_ / 10);
}
if (pmsg->id == kidmDestroyAfterAnimation) {
// This deletes asynchronously - very convenient
thread_.Dispose(this);
}
}
} // namespace wi

61
game/sdl/sdlanimsprite.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef __SDLANIMSPRITE_H__
#define __SDLANIMSPRITE_H__
#include "base/criticalsection.h"
#include "base/messagehandler.h"
#include "inc/basictypes.h"
#include "game/ht.h"
namespace wi {
class SdlAnimSprite : public AnimSprite, base::MessageHandler {
public:
SdlAnimSprite(SpriteManager *psprm);
~SdlAnimSprite();
// AnimationSprite
virtual void SetPalette(Palette *ppal);
virtual void CaptureFrame(UnitGob *pgob);
virtual void SetScaleAnimation(float nScaleStart, float nScaleEnd,
dword cms, dword cmsRate, bool fAutoDestroy);
// Sprite
virtual SpriteManager *GetManager() { return psprm_; }
virtual void SetScale(float scale);
virtual void SetPosition(int x, int y);
virtual void Show(bool fShow);
virtual bool IsVisible() { return fVisible_; }
virtual void GetBounds(Rect *prc);
// PlatformSprite
virtual void Draw(void *pv, Size *psiz);
private:
bool CreateSurface(UnitGob *pgob);
// MessageHandler
virtual void OnMessage(base::Message *pmsg);
base::CriticalSection crit_;
Rect rcUI_;
int x_, y_;
Rect rcBase_;
float nScale_;
bool fVisible_;
dword hash_;
int cx_, cy_;
int xOrigin_, yOrigin_;
SDL_Texture *texture_;
SDL_Surface *surface_;
SpriteManager *psprm_;
dword mp8bpp32bpp_[256];
float nScaleStart_, nScaleEnd_;
long msAnimateStart_;
dword cmsAnimate_;
dword cmsAnimationRate_;
bool fAutoDestroy_;
};
} // namespace wi
#endif // __SDLANIMSPRITE_H__

View File

@ -3,6 +3,7 @@
#include "game/sprite.h"
#include "game/sdl/sdlselectionsprite.h"
#include "game/sdl/sdlanimsprite.h"
namespace wi {
@ -12,9 +13,8 @@ public:
~SdlSpriteManager();
virtual void SetClipRects(wi::Rect *prc1, wi::Rect *prc2);
virtual wi::AnimSprite *CreateAnimSprite() {
LOG() << "SdlSpriteManager::CreateAnimSprite not implemented yet";
return NULL;
virtual wi::SdlAnimSprite *CreateAnimSprite() {
return new SdlAnimSprite(this);
}
virtual wi::SelectionSprite *CreateSelectionSprite() {
return new SdlSelectionSprite(this);