250 lines
6.4 KiB
C++
250 lines
6.4 KiB
C++
#include "Sprite.h"
|
|
#include "common.h"
|
|
|
|
|
|
#include "minorGems/math/geometry/Angle3D.h"
|
|
|
|
#include "minorGems/util/log/AppLog.h"
|
|
|
|
|
|
|
|
|
|
Sprite::Sprite( const char *inImageFileName,
|
|
char inTransparentLowerLeftCorner,
|
|
int inNumFrames,
|
|
int inNumPages ) {
|
|
Image *spriteImage = readTGA( inImageFileName );
|
|
|
|
if( spriteImage == NULL ) {
|
|
AppLog::getLog()->logPrintf(
|
|
Log::ERROR_LEVEL,
|
|
"Failed to read image file: %s\n", inImageFileName );
|
|
|
|
// soft fail: default image
|
|
spriteImage = new Image( 16, 16, 3, true );
|
|
}
|
|
|
|
|
|
initTexture( spriteImage, inTransparentLowerLeftCorner, inNumFrames,
|
|
inNumPages );
|
|
|
|
delete spriteImage;
|
|
}
|
|
|
|
|
|
Sprite::Sprite( Image *inImage,
|
|
char inTransparentLowerLeftCorner,
|
|
int inNumFrames,
|
|
int inNumPages ) {
|
|
|
|
initTexture( inImage, inTransparentLowerLeftCorner, inNumFrames,
|
|
inNumPages );
|
|
}
|
|
|
|
|
|
|
|
void Sprite::initTexture( Image *inImage,
|
|
char inTransparentLowerLeftCorner,
|
|
int inNumFrames,
|
|
int inNumPages ) {
|
|
|
|
mNumFrames = inNumFrames;
|
|
mNumPages = inNumPages;
|
|
|
|
Image *spriteImage = inImage;
|
|
|
|
Image *imageToDelete = NULL;
|
|
|
|
if( spriteImage->getNumChannels() == 3 && inTransparentLowerLeftCorner ) {
|
|
// use lower-left corner color as transparent color for alpha
|
|
|
|
Image *fourChannelImage = new Image( spriteImage->getWidth(),
|
|
spriteImage->getHeight(),
|
|
4, false );
|
|
|
|
// copy first three
|
|
for( int c=0; c<3; c++ ) {
|
|
fourChannelImage->pasteChannel( spriteImage->getChannel( c ),
|
|
c );
|
|
}
|
|
|
|
double *r = fourChannelImage->getChannel( 0 );
|
|
double *g = fourChannelImage->getChannel( 1 );
|
|
double *b = fourChannelImage->getChannel( 2 );
|
|
|
|
// index of transparency
|
|
int tI =
|
|
fourChannelImage->getWidth() *
|
|
( fourChannelImage->getHeight() - 1 );
|
|
|
|
// color of transparency
|
|
double tR = r[tI];
|
|
double tG = g[tI];
|
|
double tB = b[tI];
|
|
|
|
double *alpha = fourChannelImage->getChannel( 3 );
|
|
|
|
int numPixels =
|
|
fourChannelImage->getWidth() *
|
|
fourChannelImage->getHeight();
|
|
|
|
for( int i=0; i<numPixels; i++ ) {
|
|
|
|
if( r[i] == tR &&
|
|
g[i] == tG &&
|
|
b[i] == tB ) {
|
|
alpha[i] = 0;
|
|
}
|
|
else {
|
|
alpha[i] = 1;
|
|
}
|
|
}
|
|
|
|
spriteImage = fourChannelImage;
|
|
imageToDelete = fourChannelImage;
|
|
}
|
|
|
|
|
|
|
|
mTexture = new SingleTextureGL( spriteImage,
|
|
// no wrap
|
|
false );
|
|
|
|
mBaseScaleX = spriteImage->getWidth() / mNumPages;
|
|
mBaseScaleY = spriteImage->getHeight() / mNumFrames;
|
|
|
|
if( imageToDelete != NULL ) {
|
|
delete imageToDelete;
|
|
}
|
|
|
|
mFlipHorizontal = false;
|
|
mHorizontalOffset = 0;
|
|
mCurrentPage = 0;
|
|
}
|
|
|
|
|
|
|
|
Sprite::~Sprite() {
|
|
delete mTexture;
|
|
}
|
|
|
|
|
|
|
|
// opt (found with profiler)
|
|
// only construct these once, not every draw call
|
|
Vector3D corners[4];
|
|
|
|
|
|
|
|
void Sprite::draw( int inFrame,
|
|
double inRotation, Vector3D *inPosition,
|
|
double inScale,
|
|
double inFadeFactor,
|
|
Color *inColor ) {
|
|
/*
|
|
printf( "Drawing sprite %d, r%f, (%f,%f), s%f, f%f\n",
|
|
(int)(this), inRotation, inPosition->mX, inPosition->mY, inScale,
|
|
inFadeFactor );
|
|
*/
|
|
|
|
// profiler opt:
|
|
// this is expensive, and the game never needs it
|
|
// (all frame references are specific and never auto-cycling)
|
|
// inFrame = inFrame % mNumFrames;
|
|
|
|
|
|
double xRadius = inScale * mBaseScaleX / 2;
|
|
double yRadius = inScale * mBaseScaleY / 2;
|
|
|
|
double xOffset = mHorizontalOffset * inScale;
|
|
|
|
|
|
if( mFlipHorizontal ) {
|
|
xRadius = -xRadius;
|
|
}
|
|
|
|
|
|
|
|
// first, set up corners relative to 0,0
|
|
// loop is unrolled here, with all offsets added in
|
|
// also, mZ ignored now, since rotation no longer done
|
|
double posX = inPosition->mX + xOffset;
|
|
double posY = inPosition->mY;
|
|
|
|
corners[0].mX = posX - xRadius;
|
|
corners[0].mY = posY - yRadius;
|
|
//corners[0].mZ = 0;
|
|
|
|
corners[1].mX = posX + xRadius;
|
|
corners[1].mY = posY - yRadius;
|
|
//corners[1].mZ = 0;
|
|
|
|
corners[2].mX = posX + xRadius;
|
|
corners[2].mY = posY + yRadius;
|
|
//corners[2].mZ = 0;
|
|
|
|
corners[3].mX = posX - xRadius;
|
|
corners[3].mY = posY + yRadius;
|
|
//corners[3].mZ = 0;
|
|
|
|
// int i;
|
|
|
|
|
|
// now rotate around center
|
|
// then add inPosition so that center is at inPosition
|
|
|
|
// Found with profiler: ignore rotation, since game doesn't use it anyway.
|
|
// Angle3D rot( 0, 0, inRotation );
|
|
|
|
// found with profiler:
|
|
// unroll this loop
|
|
/*
|
|
for( i=0; i<4; i++ ) {
|
|
corners[i].mX += xOffset;
|
|
|
|
// corners[i].rotate( &rot );
|
|
corners[i].add( inPosition );
|
|
}
|
|
*/
|
|
|
|
if( inColor != NULL ) {
|
|
glColor4f( inColor->r, inColor->g, inColor->b, inFadeFactor );
|
|
}
|
|
else {
|
|
glColor4f( 1, 1, 1, inFadeFactor );
|
|
}
|
|
|
|
mTexture->enable();
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
|
|
|
double textXA = (1.0 / mNumPages) * mCurrentPage;
|
|
double textXB = textXA + (1.0 / mNumPages );
|
|
|
|
|
|
double textYB = (1.0 / mNumFrames) * inFrame;
|
|
double textYA = textYB + (1.0 / mNumFrames );
|
|
|
|
|
|
|
|
glBegin( GL_QUADS ); {
|
|
|
|
glTexCoord2f( textXA, textYA );
|
|
glVertex2d( corners[0].mX, corners[0].mY );
|
|
|
|
glTexCoord2f( textXB, textYA );
|
|
glVertex2d( corners[1].mX, corners[1].mY );
|
|
|
|
glTexCoord2f( textXB, textYB );
|
|
glVertex2d( corners[2].mX, corners[2].mY );
|
|
|
|
glTexCoord2f( textXA, textYB );
|
|
glVertex2d( corners[3].mX, corners[3].mY );
|
|
}
|
|
glEnd();
|
|
mTexture->disable();
|
|
}
|
|
|
|
|