/**
* @class Frame
* @brief Contains information about the drawing of an animation frame.
* @note All black (0x000000) pixels are transparent.
* @author Samuel Kaufman
* @date 2002
*/
/*****
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*****/
#include "uop.h"
#include <SDL/SDL.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include <fstream>
#include <string>
#include "uopconfig.h"
#include "animation.h"
#include "sprite.h"
#include "gumps.h"
extern Animations *anims;
extern Gumps *gumps;
extern UOPConfig *config;
extern SDL_Surface *screen;
Frame::Frame()
{
width = height = 0;
centerY = centerX = 0;
}
Frame::~Frame()
{
for (vector<Uint8*>::iterator i = runs.begin(); i != runs.end(); i++)
{
delete [] (*i);
}
}
/**
* @todo Support hues.
*/
void Frame::blit(Sint16 x, Sint16 y, Uint16 *palette)
{
if (width<=0 || height<=0)
return;
//cout << "drawing frame: " << flush;
for (vector<Uint8*>::iterator i = runs.begin(); i != runs.end(); i++)
{
Sint32 header = *((Uint32*)(*i));
Sint16 xOffset = header >> 22;
Sint16 yOffset = (header & 0x003FFFFF) >> 12;
if(yOffset & 0x0200)
yOffset |= 0xFC00;
Uint16 xRun = header & 0x00000FFF;
if(y+yOffset>=480 || x+xOffset>=640){
continue;
}
Uint16 *pixels = (Uint16*)screen->pixels+(screen->pitch>>1)*(y+yOffset)+(x+xOffset);
for (Uint16 pix = 0; pix < xRun; pix++, pixels++)
{
Uint16 victim = palette[*((*i)+4+pix)];
Uint16 red = (victim >> 10)&0x1f;
Uint16 green = (victim >> 5)&0x1f;
Uint16 blue = victim&0x1f;
*pixels = (red << 11) | (green << 6) | blue;
}
}
//cout << endl;
}
Animation::Animation()
{
frames = 0;
}
Animation::~Animation()
{
if (frames)
delete [] frames;
}
void Animation::produce(Uint32 index, Animation &anim) throw (string)
{
Uint32 animfilelookup;
Uint32 size;
Uint32 *lookupTable;
cout << "animation loading:\t" << index << ", " << flush;
anims->animidx.seekg(index*12);
assert(anims->animidx.tellg() == index*12);
anims->animidx.read((char*)&animfilelookup, 4);
anims->animidx.read((char*)&size, 4);
if (animfilelookup == 0xffffffff){
cerr << "Animation not found:" << index << endl;
throw string("Animation not found");
return;
}
anims->animfile.seekg(animfilelookup);
anims->animfile.read((char*)anim.palette, 0x200);
anims->animfile.read((char*)&anim.frameCount, 4);
cout << "frames:\t" << anim.frameCount << "; " << flush;
if (anim.frames)
delete [] anim.frames;
anim.frames = new Frame[anim.frameCount];
lookupTable = new Uint32[anim.frameCount];
anims->animfile.read((char*)lookupTable, anim.frameCount*4);
// Debugging values
// TODO: Make these REAL values from animdata.mul
anim.delay = 0;
anim.interval = 500;
cout << " producing frames: " << flush;
for (Uint32 f = 0; f < anim.frameCount; f++)
{
cout << "#" << f << " " << flush;
anims->animfile.seekg(animfilelookup+0x200+lookupTable[f]);
anims->animfile.read((char*)&anim.frames[f].centerX, 2);
anims->animfile.read((char*)&anim.frames[f].centerY, 2);
anims->animfile.read((char*)&anim.frames[f].width, 2);
anims->animfile.read((char*)&anim.frames[f].height, 2);
while (true)
{
Uint32 *storageBuf;
Uint32 header;
anims->animfile.read((char*)&header, 4);
if ((header >> 16) == 0x00007fff || (header & 0x0000FFFF) == 0x00007fff )
break;
Uint16 xRun = header & 0x00000fff;
storageBuf = (Uint32*)new Uint8[4+xRun];
*storageBuf = header;
anims->animfile.read(((char*)storageBuf)+4, xRun);
anim.frames[f].runs.push_back((Uint8*)storageBuf);
}
}
cout << endl;
delete [] lookupTable;
}
void Animation::recycle(Animation &anim)
{
anim.~Animation();
}
AnimationState::AnimationState()
{
this->animIndex = animIndex;
startedAt = 0;
}
bool AnimationState::hasEnded()
{
Animation &anim = anims->anims[animIndex];
return (SDL_GetTicks() - startedAt > anim.runningTime());
}
void AnimationState::blit(int x, int y)
{
Animation &anim = anims->anims[animIndex];
if (!anim.frames)
return;
if (hasEnded())
{
if (timesLeft)
startedAt = SDL_GetTicks();
else
anim.frames[0].blit(x, y, anim.palette);
}
anim.frames[(SDL_GetTicks()-startedAt-anim.delay)/anim.interval].blit(x, y, anim.palette);
}
void AnimationState::start(unsigned int times)
{
startedAt = SDL_GetTicks();
timesLeft = times-1;
}
Animations::Animations() : anims(*(new Animation()))
{
string file1 = config->encapDatLoc("anim.mul");
animfile.open(file1.c_str(), ios::in|ios::binary);
if (!animfile.is_open())
{
cerr << "Couldn't open " << file1 << endl;
exit(1);
}
string file2 = config->encapDatLoc("anim.idx");
animidx.open(file2.c_str(), ios::in|ios::binary);
if (!animidx.is_open())
{
cerr << "Couldn't open " << file2 << endl;
exit(1);
}
string file3 = config->encapDatLoc("animdata.mul");
adatafile.open(file3.c_str(), ios::in|ios::binary);
if (!adatafile.is_open())
{
cerr << "Couldn't open " << file3 << endl;
exit(1);
}
}
Animations::~Animations()
{
adatafile.close();
animidx.close();
animfile.close();
}