/*========================================================================= SPRSET.CPP Author: Gary Liddon @ Fareham Created: Project: TPW Parkgrab Purpose: Object that reads in all the frames for sprites processes them into tpages and spits it all out to disk Copyright (c) 1998 G R Liddon ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ #include <algorithm> #include <conio.h> #include <math.h> /* Glib ---- */ #include <gfname.hpp> #include <dpanim.hpp> #include <misc.hpp> #include <gutils.h> #include <tquant.h> /* Local ----- */ #include "sprset.h" #include "cross.h" /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ using namespace std; /*---------------------------------------------------------------------- Structure defintions -------------------- */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ /*---------------------------------------------------------------------- Data ---- */ static const char BadFileChars[] = { '+', '-', '*', '/', '\\', '#', ',', '.', '(', ')', '!', '"', '�', '$', '%', '^', '&', '=', '#', ':', ';', '<', '>', '?', '@', '{', '}', '[', ']', '�', }; static const int nbBadFileChars = (sizeof(BadFileChars) / sizeof(char)); /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ GString ReplaceBadFileChars(GString s) { GString out; const char *textin = (const char*)s; char *textout = new char[s.Len()+1]; memset(textout, 0, s.Len()+1); int i, p; p=0; for (i=0; i<s.Len(); i++) { char ic; ic=textin[i]; for (int c=0;c<nbBadFileChars;c++) { if (ic == BadFileChars[c]) ic = '_'; } textout[i] = ic; } out = textout; delete textout; return out; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddFiles(FIVec const & FileList) { FIVecConstIt It; for (It=FileList.begin();It !=FileList.end();It++) AddFile(*It); } /*---------------------------------------------------------------------- Function: Purpose: Add and process a file from the file info Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddFile(FileInfo const & ThisInfo) { GFName FileName(ThisInfo.GetActualFileName()); GString Ext(FileName.Ext()); Ext.Upper(); if (ThisInfo.getHasMemFrame()) { // NEW!! Frames from memory :o) Dave AddFrame(ThisInfo.getMemFrame(),ThisInfo); } else { if (Ext == "LBM" || Ext == "BMP") AddLbm(ThisInfo); else if (Ext == "ANM") AddAnm(ThisInfo); else Error(ERR_FATAL,"Don't deal with these sort of files : %s", FileName.FullName()); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddFrame(Frame const & Fr,FileInfo const & ThisInfo) { AllSprFrames.resize(AllSprFrames.size()+1); SprFrame & AddFr=AllSprFrames[AllSprFrames.size()-1]; AddFr.SetFrameAndInfo(Fr,ThisInfo,MaxSize); } /*---------------------------------------------------------------------- Function: Purpose: Add an LBM file process it according to the file info Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddLbm(FileInfo const & ThisInfo) { Frame MyFrame; GString Ext; GFName Fname(ThisInfo.GetActualFileName()); Ext=Fname.Ext(); Ext.Upper(); if (Ext=="LBM") MyFrame.LoadLbm(ThisInfo.GetActualFileName()); else if (Ext =="BMP") MyFrame.LoadBMP(ThisInfo.GetActualFileName()); AddFrame(MyFrame,ThisInfo); } /*---------------------------------------------------------------------- Function: Purpose: Add an ANM file process it according to the file info Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddAnm(FileInfo const & ThisInfo) { DpAnimFilter Filter; GAnim ThisAnim; FileInfo TempFileInfo; TempFileInfo=ThisInfo; ThisAnim.Load(Filter,ThisInfo.GetActualFileName()); GFName ThisName(ThisInfo.GetFileName()); GString MyStr(ThisName.File()); MyStr+="_%04d"; for (int f=0;f<ThisAnim.NumOfFrames();f++) { char NameBuff[200]; sprintf(NameBuff,MyStr,f); TempFileInfo.SetName(NameBuff); AddFrame(ThisAnim[f],TempFileInfo); } if (DebugFlag) cout<<"Added anim file "<<ThisInfo.GetFileName()<<" ("<<ThisAnim.NumOfFrames()<<" frames)"<<endl; } /*---------------------------------------------------------------------- Function: Purpose: Get a list of unique pals from the frames we have Params: Returns: ---------------------------------------------------------------------- */ void SprSet::ProcessPals(void) { SprFrIt it; /* Reduce each frame's palette give each frame a paletteindex Also make each zero entry of the palette black */ for (it=AllSprFrames.begin();it!=AllSprFrames.end();it++) { SprFrame & frm=(*it); frm.ReducePal(); if (frm.GetZeroColZero() || frm.GetPlusColZero()) { frm.GetPal()[0]=Colour(0,0,0); } } /* Create a list of unique palettes from the frames we've got and then give each frame a paletteindex */ for (it=AllSprFrames.begin();it!=AllSprFrames.end();it++) { SprPalVecIt PalIt; int PalIndex; /* Run through the palettes we already have to see if it's already there */ Palette const & ThisPal=(*it).GetPal(); PalIndex=-1; for (PalIt=AllSprPals.begin();PalIt != AllSprPals.end() && PalIndex==-1;PalIt++) { if (ThisPal.IsIntersecting(*PalIt)) { if (ThisPal.GetNumOfCols() > (*PalIt).GetNumOfCols()) (*PalIt)=ThisPal; PalIndex=PalIt-AllSprPals.begin(); } } /* If Palindex == -1 then we couldn't find the palette we wanted so add this one to the pool */ if (PalIndex==-1) { AllSprPals.resize(AllSprPals.size()+1); SprPal & ThisSprPal=AllSprPals[AllSprPals.size()-1]; PalIndex=AllSprPals.size()-1; ThisSprPal=ThisPal; ThisSprPal.SetPlusColZero((*it).GetPlusColZero()); ThisSprPal.SetZeroColZero((*it).GetZeroColZero()); ThisSprPal.SetName((*it).GetName()); } /* Set the sprframe to have the write pal index */ (*it).SetPalIndex(PalIndex); AllSprPals[PalIndex].SetPalIndex(PalIndex); } if (DebugFlag) cout<<"Found "<<AllSprPals.size()<<" unique pal(s)"<<endl; } /*---------------------------------------------------------------------- Function: Purpose: Allocate all processed frames into tpages Params: Returns: ---------------------------------------------------------------------- */ void SprSet::WriteLBM(char const * FileName) { if (Vi) Vi->SaveAs16ColLbm(FileName); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ #include <direct.h> void SprSet::WriteReport(char const * File) { const int DirLen=1024; char Dir[DirLen+1]; GString CurrDir; CurrDir=getcwd(Dir,DirLen); CurrDir.Upper(); CurrDir=CurrDir+"\\"; GString OutFileName(File); OutFileName.Lower(); Gofstream Out; Out.open(OutFileName,ios::out); if (Out) { Out<<"File\tTPage\tClut\tu\tv\tw\th\tRotated"<<endl; for (int f=0;f<AllSprFrames.size();f++) { GString RelName; u16 Clut; u16 Tpage; int Rotated; GString Name; int u,v,w,h; SprFrame & Frm =AllSprFrames[f]; Clut=Frm.GetClut(); Tpage=Frm.GetTpage(); Rotated=Frm.IsRotated()==true ? 1 : 0; Name=Frm.GetFileInfo()->GetActualName(); u=Frm.GetTPRect().X; v=Frm.GetTPRect().Y; w=Frm.GetWidth(); h=Frm.GetHeight(); RelName=GFName::makerelative(CurrDir,Name,Dir); Out<<(char const *)RelName<<"\t$"<<hex<<Tpage<<"\t$"<<Clut<<"\t$"<<u<<"\t$"<<v<<"\t$"<<w<<"\t$"<<h<<" "<<Rotated<<endl; } Out.close(); } else Error(ERR_FATAL,"Couldn't open file %s for output",(char const *)OutFileName); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ #include <direct.h> void SprSet::CreateTexInfo(std::vector<sTexOutInfo> &TexInfo) { int ListSize=AllSprFrames.size(); const int DirLen=1024; char Dir[DirLen+1]; GString CurrDir; CurrDir=getcwd(Dir,DirLen); CurrDir.Upper(); CurrDir=CurrDir+"\\"; TexInfo.resize(ListSize); for (int f=0;f<ListSize;f++) { SprFrame &Frm =AllSprFrames[f]; sTexOutInfo &ThisInfo=TexInfo[f]; GString Name=Frm.GetFileInfo()->GetActualName(); ThisInfo.Name=GFName::makerelative(CurrDir,Name,Dir); ThisInfo.Clut=Frm.GetClut(); ThisInfo.Tpage=Frm.GetTpage(); ThisInfo.Rotated=Frm.IsRotated(); ThisInfo.u=Frm.GetTPRect().X; ThisInfo.v=Frm.GetTPRect().Y; ThisInfo.w=Frm.GetWidth(); ThisInfo.h=Frm.GetHeight(); ThisInfo.XOfs=Frm.GetX(); ThisInfo.YOfs=Frm.GetY(); ThisInfo.OrigW=Frm.GetOrigW(); ThisInfo.OrigH=Frm.GetOrigH(); } } /*---------------------------------------------------------------------- Function: Purpose: Allocate all processed frames into tpages Params: Returns: ---------------------------------------------------------------------- */ void SprSet::Write(char const * File,int TpNumber,int WidthInTpages,int HeightInTpages) { int HeightInPixels; if (m_halfTpage) { HeightInPixels = 128; } else { HeightInPixels = HeightInTpages * 256; } ProcessPals(); VRAM MyVram(WidthInTpages,HeightInPixels); /* Add all the frames to a Tpage object */ AddFramesAndPalsToVRAM(MyVram,TpNumber,WidthInTpages,HeightInPixels); /* Now make the output VRAM image */ int f; Vi=new VRAMImage(WidthInTpages,HeightInPixels); if (!Vi) Error(ERM_OUTOFMEM); for (f=0;f<AllSprFrames.size();f++) Vi->PlotFrame(AllSprFrames[f]); for (f=0;f<AllSprPals.size();f++) Vi->PlotPal(AllSprPals[f]); /* struct SpriteBankHdr { u16 NumOfSprites; u16 NumOfTPages; u16 TpageStart; u16 WidthInTpages; u16 HeightInTpages; u16 NumOfSpareBoxes; }; */ Gofstream Out(Gofstream::LITTLE_ENDIAN); GString OutFileName(File); OutFileName.Lower(); Out.open(OutFileName,ios::out|ios::binary); TPRectVec spareVRAM; MyVram.getUnusedSpace(spareVRAM); if (Out) { int FrameCount=AllSprFrames.size(); if (m_AnimatedHeadersOnly) { FrameCount=0; for (f=0;f<AllSprFrames.size();f++) if (AllSprFrames[f].IsAnimated()) FrameCount++; } Out.Put16(FrameCount); if (m_noWriteTpages) Out.Put16(0); else Out.Put16(WidthInTpages*HeightInTpages); Out.Put16(TpNumber); if (m_noWriteTpages) { Out.Put16(0); Out.Put16(0); } else { Out.Put16(WidthInTpages); Out.Put16(HeightInPixels); } // Dont output spare boxes if (m_DontOutputBoxes) Out.Put16(0); else Out.Put16(spareVRAM.size()); Out.Put16(m_compressTpages ? 1 : 0); Out.Put16(0); Out.Align(sizeof(u32)); int f; int thisPos,size; thisPos=Out.tellp(); if (m_AnimatedHeadersOnly) { // printf("Writing only animated headers (%i).\n",FrameCount); for (f=0;f<AllSprFrames.size();f++) // Write Animated headers only { if (AllSprFrames[f].IsAnimated()) AllSprFrames[f].WriteHeader(Out); } } else { printf("Writing All headers (%i).\n",AllSprFrames.size()); for (f=0;f<AllSprFrames.size();f++) // Write all headers { AllSprFrames[f].WriteHeader(Out); } } size=int(Out.tellp())-thisPos; if (DebugFlag) cout<<"size of headers == "<<size<<endl; Out.Align(sizeof(u32)); if (m_DontOutputBoxes) { // printf("Skipping spare boxes.\n"); } else { for (f=0;f<spareVRAM.size();f++) { Out.Put16(spareVRAM[f].X); Out.Put16(spareVRAM[f].Y); Out.Put16(spareVRAM[f].W); Out.Put16(spareVRAM[f].H); } Out.Align(sizeof(u32)); } if (m_AlignHeaders) { // printf("Aligning headers to 2k chunk.\n"); Out.Align(2048); } if (!m_noWriteTpages) { Vi->setDoCompress(m_compressTpages); Vi->Write(Out); } Out.close(); } else Error(ERR_FATAL,"Error wring file %s",(char const *)OutFileName); WriteHeaderFile(GetHeaderFileName(File)); } GString SprSet::GetHeaderFileName(char const * File) { GString HeaderFileName; if (IncOutFile == "") { GFName HeaderFile(File); HeaderFile.Ext("h"); HeaderFileName=HeaderFile.FullName(); } else HeaderFileName=IncOutFile; HeaderFileName.Lower(); return(HeaderFileName); } void SprSet::WriteHeaderFile(char const * HName) { ofstream HOut; int f; GFName HeaderFile(HName); GString OFileDefine; OFileDefine="__SPR_"; OFileDefine+=HeaderFile.File(); OFileDefine+="_H__"; OFileDefine.Upper(); GString HeaderFileName(HeaderFile.FullName()); HeaderFileName.Lower(); HOut.open(HeaderFileName,ios::out); if (HOut) { HOut<<"#ifndef "<<(char const *)OFileDefine<<endl; HOut<<"#define "<<(char const *)OFileDefine<<endl; HOut<<"/* Palette defines */"<<endl; for (f=0;f<AllSprPals.size();f++) HOut<<"#define PAL_"<<ReplaceBadFileChars(AllSprPals[f].GetName())<<" "<<AllSprPals[f].GetClut()<<endl; HOut<<"/* Frame defines */"<<endl; for (f=0;f<AllSprFrames.size();f++) { HOut<<"#define FRM_"<<ReplaceBadFileChars(AllSprFrames[f].GetName())<<" "<<f<<endl; } HOut<<"#endif "<<endl; HOut.close(); } else Error(ERR_FATAL,"Error writing out file %s",(char const *)HeaderFileName); } /*---------------------------------------------------------------------- Function: Purpose: Allocate all processed frames into tpages Params: Returns: ---------------------------------------------------------------------- */ void SprSet::AddFramesAndPalsToVRAM(VRAM & Vr,int TpNumber,int WidthInTpages,int HeightInPixels) { int f; /* Add Palettes first */ std::vector<SprPal> CopySprPals; /* Make a copy of the palettes */ CopySprPals=AllSprPals; std::sort(CopySprPals.begin(),CopySprPals.end()); /* Sort em according to how many cols */ for (f=0;f<AllSprPals.size();f++) { TPRect MyPalRect; SprPal & OriginalPal=AllSprPals[CopySprPals[f].GetPalIndex()]; MyPalRect.Set(TP_PAL,0,0,OriginalPal.GetNumOfCols(),1); if (Vr.AllocVRAM(MyPalRect)) OriginalPal.SetVRAMPos(MyPalRect); else Error(ERR_FATAL,"Couldn't fit frames palettes into VRAM"); } /* Add Frames */ std::vector<TPRect> AllocRects; AllocRects.resize(AllSprFrames.size()); std::vector<TPageType> oldTypes; oldTypes.resize(AllSprFrames.size()); for (f=0;f<AllSprFrames.size();f++) { AllocRects[f].InitFromFrame(AllSprFrames[f]); AllocRects[f].SetDontRotate(!AllSprFrames[f].GetAllowRotate()); AllocRects[f].SetId(f); if (AllSprFrames[f].GetFileInfo()->getAllocateAs16Bit()) oldTypes[f]=AllocRects[f].convertTo16Bit(); } /* Allocate int VRAM */ if(Vr.AllocVRAM(AllocRects,false,true,true)) { /* Now go back through all the sprite frames and tell them where they are going to sit in VRAM */ for (f=0;f<AllocRects.size();f++) { if (AllSprFrames[AllocRects[f].GetId()].GetFileInfo()->getAllocateAs16Bit()) AllocRects[f].convertFrom16Bit(oldTypes[AllocRects[f].GetId()]); AllSprFrames[AllocRects[f].GetId()].SetVRAMPos(AllocRects[f]); } } else { Error(ERR_FATAL,"Couldn't fit frames into VRAM"); } /* Go through and tell all pals and frames what the base tpage is */ for (f=0;f<AllSprFrames.size();f++) AllSprFrames[f].SetTpBase(TpNumber); for (f=0;f<AllSprPals.size();f++) AllSprPals[f].SetTpBase(TpNumber); /* Now go through all the frames and tell them what Clut values they need */ for (f=0;f<AllSprFrames.size();f++) AllSprFrames[f].SetClut(AllSprPals[AllSprFrames[f].GetPalIndex()].GetClut()); } /*---------------------------------------------------------------------- ---------------------------------------------------------------------- */ void SprSet::writeRawTPage(char const * file) { ofstream out; out.open(file,ios::binary|ios::out|ios::trunc); if (out) { if (Vi) Vi->WriteInTpageChunks(out); } else Error(ERR_FATAL,"Error opening raw file %s",file); } /*---------------------------------------------------------------------- Function: Purpose: Write out sprs and pals to a sprite file (not a VRAM block) Params: Returns: ---------------------------------------------------------------------- */ void SprSet::WriteSprFile(char const * Name) { std::vector<int> SprOffsets; std::vector<int> PalOffsets; ProcessPals(); Gofstream SpriteOut(Gofstream::LITTLE_ENDIAN); GString SpriteOutName(Name); SpriteOutName.Lower(); SpriteOut.open(SpriteOutName,ios::binary|ios::out|ios::trunc); if (SpriteOut) { int NumOfSprs; int NumOfPals; int PalOffsetTable; int SprOffsetTable; /* struct SPR_RAM_HDR { int NumOfPals; int NumOfSprs; int PalOffsets[NumOfPals]; int SprOfffsets[NumOfSprs]; RAM_FRAME_HDR Frames[NumOfSprs]; Pals Pals[NumOfPals]; Data [NumOfSprs] } */ NumOfSprs=AllSprFrames.size(); NumOfPals=AllSprPals.size(); SpriteOut.Put32(NumOfPals); SpriteOut.Put32(NumOfSprs); SprOffsets.resize(NumOfSprs); PalOffsets.resize(NumOfPals); PalOffsetTable=SpriteOut.tellp(); SpriteOut.seekp(sizeof(u32)*NumOfPals,ios::cur); SprOffsetTable=SpriteOut.tellp(); SpriteOut.seekp(sizeof(u32)*NumOfSprs,ios::cur); int f; for (f=0;f<NumOfSprs;f++) AllSprFrames[f].WriteHeaderNotInVram(SpriteOut); for (f=0;f<NumOfPals;f++) { PalOffsets[f]=SpriteOut.tellp(); AllSprPals[f].Write(SpriteOut); } for (f=0;f<NumOfSprs;f++) { SprOffsets[f]=SpriteOut.tellp(); AllSprFrames[f].Write(SpriteOut); } SpriteOut.seekp(PalOffsetTable,ios::beg); for (f=0;f<NumOfPals;f++) SpriteOut.Put32(PalOffsets[f]); SpriteOut.seekp(SprOffsetTable,ios::beg); for (f=0;f<NumOfSprs;f++) SpriteOut.Put32(SprOffsets[f]); SpriteOut.close(); } else Error(ERR_FATAL,"Error opeing sprite file %s",(char const *)SpriteOutName); WriteHeaderFile(GetHeaderFileName(Name)); } /*---------------------------------------------------------------------- Function: Purpose: Add an ANM file process it according to the file info Params: Returns: ---------------------------------------------------------------------- */ void SprFrame::SetFrameAndInfo(Frame const & Fr,FileInfo const & NewMyFileInfo,int MaxSize) { if (this!=&Fr) { Frame::CopyFrame(Fr); } MyFileInfo=NewMyFileInfo; OrigW=Fr.GetWidth(); OrigH=Fr.GetHeight(); GFName MyName(MyFileInfo.GetFileName()); GString TempName=MyName.File(); TempName.Upper(); Name=TempName; /* Now Process the frame as needed */ int XOff; int YOff; XOff=0; YOff=0; if (MyFileInfo.GetCrossHair() && !NewMyFileInfo.getAllocateAs16Bit()) { CROSS_RES CrossRes; if (CrossRes.FindCrossHair(*this,255)) { XOff=-CrossRes.x; YOff=-CrossRes.y; ReplaceColour(255,0); } } /* Crop sprite down to only the pixels we want */ if (MyFileInfo.GetShrinkToFit() && !NewMyFileInfo.getAllocateAs16Bit()) { Rect Bound; Bound=FindBoundingRect(); if (Bound) { } else { Bound.X=0; Bound.Y=0; Bound.W=1; Bound.H=1; } Crop(Bound); XOff+=Bound.X; YOff+=Bound.Y; } if (MyFileInfo.GetForceOffsets() && !NewMyFileInfo.getAllocateAs16Bit()) { XOff=-(MyFileInfo.GetXOff()-XOff); YOff=-(MyFileInfo.GetYOff()-YOff); } if (MaxSize && !NewMyFileInfo.getAllocateAs16Bit()) { int NewWidth; int NewHeight; NewWidth=GetWidth(); NewHeight=GetHeight(); if (NewWidth > MaxSize) NewWidth=MaxSize; if (NewHeight > MaxSize) NewHeight=MaxSize; if (NewWidth != GetWidth() || NewHeight != GetHeight()) { cout<<"Reducing frame "<<GetFileInfo()->GetActualFileName()<<endl; ResizeAndReduce(*this,GetNumOfCols(),float(NewWidth)/float(GetWidth()),float(NewHeight)/float(GetHeight()),MyFileInfo.GetZeroColZero()); #if 0 char Name[1024]; static int Val; sprintf(Name,"c:\\data\\%d.lbm",Val); Val++; SaveLbm(Name); #endif } } if (NewMyFileInfo.getAllocateAs16Bit()) { int NewWidth = GU_AlignVal( GetWidth(), 4); int NewHeight = GU_AlignVal( GetHeight(), 4); if (NewWidth != GetWidth() || NewHeight != GetHeight()) { cout<<"Reducing frame "<<GetFileInfo()->GetActualFileName()<<endl; ResizeAndReduce(*this,GetNumOfCols(),float(NewWidth)/float(GetWidth()),float(NewHeight)/float(GetHeight()),MyFileInfo.GetZeroColZero()); #if 0 char Name[1024]; static int Val; sprintf(Name,"c:\\data\\%d.lbm",Val); Val++; SaveLbm(Name); #endif } } X=XOff; Y=YOff; if (Width > 254 || Height > 254) { Error(ERR_FATAL,"Images only allowed to 254x254, this is %dx%d : %s",Width,Height,MyFileInfo.GetActualFileName()); } } struct fRGBA { void Set(float _R,float _G,float _B,float _A) {R=_R;G=_G;B=_B;A=_A;} float R,G,B,A; }; void SprFrame::ResizeAndReduce(Frame & Frm,int TargCols,float XPerc,float YPerc,bool ZeroSeeThrough) { std::vector<fRGBA> FullColNewScreen; std::vector<u8> DestBytePic; std::vector<u8> Bitmap; u8 Pal[256*3]; u8 * Dest; int f; Bitmap.resize(Frm.GetWidth()*Frm.GetHeight()*4); Frm.MakeRGBA(&Bitmap[0],ZeroSeeThrough); int Width,Height; Width=Frm.GetWidth(); Height=Frm.GetHeight(); int NewWidth=float(Width)*XPerc; int NewHeight=float(Height)*YPerc; if (!(Dest=new u8[NewWidth*NewHeight])) GObject::Error(ERM_OUTOFMEM); FullColNewScreen.resize(NewWidth*NewHeight); DestBytePic.resize(NewWidth*NewHeight*3); /* Now Super Sample it down */ const int Samples=8; int DestW=NewWidth; int DestH=NewHeight; float YMul=float(Height)/DestH; float XMul=float(Width)/DestW; for (int dy=0;dy<DestH;dy++) { float YPos=YMul*float(dy); for (int dx=0;dx<DestW;dx++) { float XPos=XMul*float(dx); float R=0; float G=0; float B=0; float A=0; for (int Ys=0;Ys<Samples;Ys++) for (int Xs=0;Xs<Samples;Xs++) { float xp=floor((XPos)+(Xs*(XMul/Samples))); float yp=floor((YPos)+(Ys*(YMul/Samples))); int Index=(yp*Width+xp); R+=float(Bitmap[Index*4+0])/255.0f; G+=float(Bitmap[Index*4+1])/255.0f; B+=float(Bitmap[Index*4+2])/255.0f; A+=float(Bitmap[Index*4+3])/255.0f; } R/=float(Samples*Samples); G/=float(Samples*Samples); B/=float(Samples*Samples); A/=float(Samples*Samples); if (R>1.0f) R=1.0f; if (G>1.0f) B=1.0f; if (B>1.0f) B=1.0f; int DestIndex=(dy*NewWidth+dx); FullColNewScreen[DestIndex].Set(R,G,B,A); } } /* Convert Back to RGBA into a dest byte picture */ const float Bound=0.5f; for (f=0;f<NewWidth*NewHeight;f++) { float R=FullColNewScreen[f].R; float G=FullColNewScreen[f].G; float B=FullColNewScreen[f].B; if (FullColNewScreen[f].A > Bound) { DestBytePic[f*3+0]=R*255; DestBytePic[f*3+1]=G*255; DestBytePic[f*3+2]=B*255; } else { DestBytePic[f*3+0]=0; DestBytePic[f*3+1]=0; DestBytePic[f*3+2]=0; } } /* Now reduce colours */ Palette NewPal; if (ZeroSeeThrough) { int Cols=TargCols-1; tquant(&DestBytePic[0],Dest,Pal,Cols,NewWidth*NewHeight); for (f=0;f<NewWidth*NewHeight;f++) { if (FullColNewScreen[f].A > Bound) Dest[f]=Dest[f]+1; else Dest[f]=0; } for (f=1;f<Cols+1;f++) NewPal[f].SetRGB(Pal[(f-1)*3+0],Pal[(f-1)*3+1],Pal[(f-1)*3+2]); NewPal[0].SetRGB(255,0,255); } else { int Cols=TargCols; tquant(&DestBytePic[0],Dest,Pal,Cols,NewWidth*NewHeight); for (f=0;f<Cols;f++) NewPal[f].SetRGB(Pal[f*3+0],Pal[f*3+1],Pal[f*3+2]); } Frm.SetFrame(&Dest[0],NewWidth,NewHeight,NewPal); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ SprFrame::SprFrame(void) { } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprFrame::SetVRAMPos(TPRect const & NewRect) { MyRect=NewRect; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprFrame::WriteHeader(Gofstream & Out) { /* struct VRAM_FRAME_HDR { u16 tpage; u16 clut; u8 x,y,w,h; u8 u,v; u8 Rotated; }; */ Out.Align(sizeof(u16)); u16 OutTpage=GetTpage(); u16 OutClut=GetClut(); Out.Put16(GetTpage()); Out.Put16(OutClut); Out.put(s8(X)); Out.put(s8(Y)); if (MyFileInfo.GetMoveUVs() && Width && !MyFileInfo.getAllocateAs16Bit()) Out.put(s8(Width-1)); else Out.put(s8(Width)); if (MyFileInfo.GetMoveUVs() && Height && !MyFileInfo.getAllocateAs16Bit()) Out.put(s8(Height-1)); else Out.put(s8(Height)); BDEPTH RetDepth; RetDepth=GetBitDepth(); Out.put(getU()); Out.put(u8(MyRect.Y)); IsRotated() ? Out.put(u8(1)) : Out.put(u8(0)); MyFileInfo.getAllocateAs16Bit() ? Out.put(u8(1)) : Out.put(u8(0)); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprFrame::WriteHeaderNotInVram(Gofstream & Out) { /* struct RAM_FRAME_HDR { u32 PalNum; u8 x,y,w,h; }; */ Out.Align(sizeof(u32)); Out.Put32(PalIndex); Out.put(s8(X)); Out.put(s8(Y)); if (MyFileInfo.GetMoveUVs() && Width) Out.put(s8(Width-1)); else Out.put(s8(Width)); if (MyFileInfo.GetMoveUVs() && Height) Out.put(s8(Height-1)); else Out.put(s8(Height)); Out.Align(sizeof(u32)); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprFrame::Write(Gofstream & Out) const { /* Note, this is shite, it only works on 16 col images. Doh! Gaz */ const int AlignPixels=4; std::vector<u8> Body; Frame NewFrame; NewFrame=*this; Rect OriginalRect; OriginalRect=NewFrame; OriginalRect.X=0; OriginalRect.Y=0; OriginalRect.W=GU_AlignVal(OriginalRect.W,AlignPixels); NewFrame.Crop(OriginalRect); int nfW,nfH,nfLineWidthBytes,nfAreaBytes; nfW=NewFrame.GetWidth(); nfH=NewFrame.GetHeight(); nfLineWidthBytes=GU_AlignVal(nfW,2)/2; nfAreaBytes=nfLineWidthBytes*nfH; Body.resize(nfAreaBytes); for (int y=0;y<nfH;y++) for (int x=0;x<nfW;x++) { u8 * PixAddr; u8 ScrNib; ScrNib=NewFrame.SeeData()[y*nfW+x]&0xf; PixAddr=&Body[(x/2)+(nfLineWidthBytes*y)]; if ((x&1)) { *PixAddr&=0x0f; *PixAddr|=ScrNib<<4; } else { *PixAddr&=0xf0; *PixAddr|=ScrNib; } } Out.write((char *)(&Body[0]),nfAreaBytes); Out.Align(sizeof(u32)); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprPal::Write(Gofstream & Out) const { std::vector<u16> OutPal; MakePSXPal(OutPal); Out.Put32(OutPal.size()); for (int f=0;f<OutPal.size();f++) Out.Put16(OutPal[f]); Out.Align(sizeof(u32)); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ u16 SprPal::GetPsxCol(Colour const & Col) const { int R,G,B; R=Col.GetR()>>3; G=Col.GetG()>>3; B=Col.GetB()>>3; return((R&0x1f)<<0)|((G&0x1f)<<5)|((B&0x1f)<<10); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SprPal::MakePSXPal(std::vector<u16> & OutWords) const { int NumOfCols; int f; NumOfCols=(*this).GetNumOfCols(); OutWords.resize(NumOfCols); if (GetZeroColZero() || GetPlusColZero()) { OutWords[0]=0; for (f=1;f<NumOfCols;f++) { u16 Col=GetPsxCol((*this)[f]); Col += Col ? 0 : 1; OutWords[f]=Col|0x8000; } } else { for (f=0;f<NumOfCols;f++) { u16 Col=GetPsxCol((*this)[f]); OutWords[f]=Col|0x8000; } } } /*=========================================================================== end */