#include "CCreatureAnimation.h" #include "../lib/CLodHandler.h" #include "../lib/VCMI_Lib.h" #include #include "SDL_Extensions.h" /* * CCreatureAnimation.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ CCreatureAnim::EAnimType CCreatureAnimation::getType() const { return type; } void CCreatureAnimation::setType(CCreatureAnim::EAnimType type) { assert(framesInGroup(type) > 0 && "Bad type for void CCreatureAnimation::setType(int type)!"); this->type = type; internalFrame = 0; if(type!=-1) { curFrame = frameGroups[type][0]; } else { if(curFrame>=frames) { curFrame = 0; } } } CCreatureAnimation::CCreatureAnimation(std::string name) : internalFrame(0), once(false) { FDef = spriteh->giveFile(name, FILE_ANIMATION); //load main file //init anim data int i,j, totalInBlock; defName=name; i = 0; DEFType = readNormalNr<4>(i,FDef); i+=4; fullWidth = readNormalNr<4>(i,FDef); i+=4; fullHeight = readNormalNr<4>(i,FDef); i+=4; i=0xc; totalBlocks = readNormalNr<4>(i,FDef); i+=4; i=0x10; for (int it=0;it<256;it++) { palette[it].R = FDef[i++]; palette[it].G = FDef[i++]; palette[it].B = FDef[i++]; palette[it].F = 0; } i=0x310; totalEntries=0; for (int z=0; z frameIDs; int group = readNormalNr<4>(i,FDef); i+=4; //block ID totalInBlock = readNormalNr<4>(i,FDef); i+=4; for (j=SEntries.size(); j(i,FDef); i+=4; //TODO use me int unknown3 = readNormalNr<4>(i,FDef); i+=4; //TODO use me i+=13*totalInBlock; //ommiting names for (j=0; j(i,FDef); i+=4; } //totalEntries+=totalInBlock; for(int hh=0; hh=frames) curFrame = 0; } } int CCreatureAnimation::getFrame() const { return curFrame; } int CCreatureAnimation::getAnimationFrame() const { return internalFrame; } bool CCreatureAnimation::onFirstFrameInGroup() { return internalFrame == 0; } bool CCreatureAnimation::onLastFrameInGroup() { if(internalFrame == frameGroups[type].size() - 1) return true; return false; } void CCreatureAnimation::playOnce( CCreatureAnim::EAnimType type ) { setType(type); once = true; } template int CCreatureAnimation::nextFrameT(SDL_Surface * dest, int x, int y, bool attacker, unsigned char animCount, bool IncrementFrame /*= true*/, bool yellowBorder /*= false*/, bool blueBorder /*= false*/, SDL_Rect * destRect /*= NULL*/) { //increasing frame number int SIndex = curFrame; if (IncrementFrame) incrementFrame(); long BaseOffset, SpriteWidth, SpriteHeight, //sprite format LeftMargin, RightMargin, TopMargin,BottomMargin, i, FullHeight,FullWidth, TotalRowLength; // length of read segment unsigned char SegmentType, SegmentLength; i = BaseOffset = SEntries[SIndex].offset; int prSize = readNormalNr<4>(i, FDef); i += 4; //TODO use me int defType2 = readNormalNr<4>(i, FDef); i += 4; FullWidth = readNormalNr<4>(i, FDef); i += 4; FullHeight = readNormalNr<4>(i, FDef); i += 4; SpriteWidth = readNormalNr<4>(i, FDef); i += 4; SpriteHeight = readNormalNr<4>(i, FDef); i += 4; LeftMargin = readNormalNr<4>(i, FDef); i += 4; TopMargin = readNormalNr<4>(i, FDef); i += 4; RightMargin = FullWidth - SpriteWidth - LeftMargin; BottomMargin = FullHeight - SpriteHeight - TopMargin; int BaseOffsetor = BaseOffset = i; int ftcp = 0; if (defType2 == 1) //as it should be always in creature animations { if (TopMargin > 0) { ftcp += FullWidth * TopMargin; } int *RLEntries = (int*)(FDef + BaseOffset); BaseOffset += sizeof(int) * SpriteHeight; for (int i = 0; i < SpriteHeight; i++) { BaseOffset = BaseOffsetor + RLEntries[i]; if (LeftMargin > 0) { ftcp += LeftMargin; } TotalRowLength = 0; // Note: Bug fixed (Rev 2115): The implementation of omitting lines was false. // We've to calculate several things so not showing/putting pixels should suffice. int yB = ftcp / FullWidth + y; do { SegmentType = FDef[BaseOffset++]; SegmentLength = FDef[BaseOffset++]; int xB = (attacker ? ftcp % FullWidth : FullWidth - ftcp % FullWidth - 1) + x; unsigned char aCountMod = (animCount & 0x20) ? ((animCount & 0x1e) >> 1) << 4 : 0x0f - ((animCount & 0x1e) >> 1) << 4; for (int k = 0; k <= SegmentLength; k++) { if(xB >= 0 && xB < dest->w && yB >= 0 && yB < dest->h) { if(!destRect || (destRect->x <= xB && destRect->x + destRect->w > xB && destRect->y <= yB && destRect->y + destRect->h > yB)) { const ui8 colorNr = SegmentType == 0xff ? FDef[BaseOffset+k] : SegmentType; putPixel(dest, xB, yB, palette[colorNr], colorNr, yellowBorder, blueBorder, aCountMod); } } ftcp++; //increment pos if(attacker) xB++; else xB--; if ( SegmentType == 0xFF && TotalRowLength+k+1 >= SpriteWidth ) break; } if (SegmentType == 0xFF) { BaseOffset += SegmentLength+1; } TotalRowLength+=SegmentLength+1; } while(TotalRowLength < SpriteWidth); if (RightMargin > 0) { ftcp += RightMargin; } } if (BottomMargin > 0) { ftcp += BottomMargin * FullWidth; } } return 0; } int CCreatureAnimation::nextFrame(SDL_Surface *dest, int x, int y, bool attacker, unsigned char animCount, bool IncrementFrame, bool yellowBorder, bool blueBorder, SDL_Rect * destRect) { switch(dest->format->BytesPerPixel) { case 2: return nextFrameT<2>(dest, x, y, attacker, animCount, IncrementFrame, yellowBorder, blueBorder, destRect); case 3: return nextFrameT<3>(dest, x, y, attacker, animCount, IncrementFrame, yellowBorder, blueBorder, destRect); case 4: return nextFrameT<4>(dest, x, y, attacker, animCount, IncrementFrame, yellowBorder, blueBorder, destRect); default: tlog1 << (int)dest->format->BitsPerPixel << " bpp is not supported!!!\n"; return -1; } } int CCreatureAnimation::framesInGroup(CCreatureAnim::EAnimType group) const { if(frameGroups.find(group) == frameGroups.end()) return 0; return frameGroups.find(group)->second.size(); } CCreatureAnimation::~CCreatureAnimation() { delete [] FDef; } template inline void CCreatureAnimation::putPixel( SDL_Surface * dest, const int & ftcpX, const int & ftcpY, const BMPPalette & color, const unsigned char & palc, const bool & yellowBorder, const bool & blueBorder, const unsigned char & animCount ) const { if(palc!=0) { Uint8 * p = (Uint8*)dest->pixels + ftcpX*dest->format->BytesPerPixel + ftcpY*dest->pitch; if(palc > 7) //normal color { ColorPutter::PutColor(p, color.R, color.G, color.B); } else if((yellowBorder || blueBorder) && (palc == 6 || palc == 7)) //selection highlight { if(blueBorder) ColorPutter::PutColor(p, 0, 0x0f + animCount, 0x0f + animCount); else ColorPutter::PutColor(p, 0x0f + animCount, 0x0f + animCount, 0); } else if (palc == 5) //selection highlight or transparent { if(blueBorder) ColorPutter::PutColor(p, color.B, color.G - 0xf0 + animCount, color.R - 0xf0 + animCount); //shouldnt it be reversed? its bgr instead of rgb else if (yellowBorder) ColorPutter::PutColor(p, color.R - 0xf0 + animCount, color.G - 0xf0 + animCount, color.B); } else //shadow { //determining transparency value, 255 or 0 should be already filtered static Uint16 colToAlpha[8] = {255,192,128,128,128,255,128,192}; Uint16 alpha = colToAlpha[palc]; if(bpp != 3 && bpp != 4) { ColorPutter::PutColor(p, 0, 0, 0, alpha); } else { p[0] = (p[0] * alpha)>>8; p[1] = (p[1] * alpha)>>8; p[2] = (p[2] * alpha)>>8; } } } }