mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-03-26 06:58:28 -06:00
Implement SdlAnimSprite
This commit is contained in:
parent
6e65f8273b
commit
5b5917fbab
@ -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
327
game/sdl/sdlanimsprite.cpp
Normal 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
61
game/sdl/sdlanimsprite.h
Normal 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__
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user