SBSPSS/Utils/Libs/TexGrab/sprset.cpp
2001-04-01 20:22:49 +00:00

1367 lines
28 KiB
C++

/*=========================================================================
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 */