1050 lines
18 KiB
C++
1050 lines
18 KiB
C++
/*=========================================================================
|
|
|
|
DPANM.HPP
|
|
|
|
Author: Gary Liddon @ Fareham
|
|
Created:
|
|
Project:
|
|
Purpose:
|
|
|
|
Copyright (c) 1997 Gary Liddon
|
|
|
|
===========================================================================*/
|
|
|
|
/*----------------------------------------------------------------------
|
|
Includes
|
|
-------- */
|
|
|
|
/* Std Lib
|
|
------- */
|
|
//#include <stdlib.h>
|
|
#include <minmax.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
/* Glib
|
|
---- */
|
|
|
|
/* Local
|
|
----- */
|
|
#include "dpanim.hpp"
|
|
//#include "ilbm.hpp"
|
|
|
|
/* Name space
|
|
---------- */
|
|
using namespace std;
|
|
|
|
/*----------------------------------------------------------------------
|
|
Structure defintions
|
|
-------------------- */
|
|
typedef UWORD LP_TABLE_ELEMENT;
|
|
|
|
#define MAX_NUMBER_CYCLES 16
|
|
|
|
#define BMBODY_RUNSKIPDUMP 1
|
|
#define MAX_COLORS 256
|
|
#define PALETTE_SIZE (MAX_COLORS * sizeof(long))
|
|
#define MAX_RECORDS 0xffffu
|
|
#define MAX_LARGE_PAGE 256
|
|
|
|
#define LARGE_PAGE_SIZE 0x10000L
|
|
|
|
#define LPF_HEADER_HEAD_SIZE_IN_FILE 256
|
|
#define LPF_HEADER_SIZE_IN_FILE ((sizeof(AnimHdr)) + (8 * 16) + (4 * 256) + (sizeof(LpTable[MAX_LARGE_PAGE])))
|
|
#define LP_FILE_OFFSET(nLp) ((nLp) * LARGE_PAGE_SIZE + LPF_HEADER_SIZE_IN_FILE)
|
|
|
|
#define MakeID(d,c,b,a) (((ULONG)(a)<<24l) | ((ULONG)(b)<<16l) | ((ULONG)(c)<<8l) | ((ULONG)(d)))
|
|
|
|
#define LARGE_PAGE_FILE_ID MakeID('L','P','F',' ')
|
|
#define ANIM_CONTENTS_ID MakeID('A','N','I','M')
|
|
|
|
#define FIRST_FRAME_N 1
|
|
#define FIRST_RECORD_N 0 // Records #d from 0.
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Typedefs
|
|
-------- */
|
|
class LpObj;
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Class Defintions
|
|
---------------- */
|
|
|
|
/* Compressed Frame
|
|
---------------- */
|
|
class CompFrame : public GObject
|
|
{
|
|
public:
|
|
CompFrame(void);
|
|
CompFrame(CompFrame const & C);
|
|
|
|
~CompFrame(void);
|
|
|
|
void operator=(CompFrame const &);
|
|
|
|
/* Make Vectorable */
|
|
|
|
bool operator==(CompFrame const &) const;
|
|
bool operator<(CompFrame const &) const;
|
|
|
|
void WriteByte(u8 Byte);
|
|
void WriteWord(u16 Word);
|
|
void WriteData(u8 const * Src,int Amount);
|
|
void Write(ofstream & Out) const;
|
|
|
|
friend ostream & operator<<(ostream & str,CompFrame & Fr);
|
|
|
|
u8 const * SeeData(void) const {return(BinData);}
|
|
int GetSize() const {return(Len);}
|
|
|
|
protected:
|
|
void Dump();
|
|
void Init();
|
|
void Resize(int NewLen);
|
|
void Increase(int NewLen) {Resize(ActualLen+NewLen);}
|
|
|
|
u8 * BinData;
|
|
int Len;
|
|
|
|
int ActualLen;
|
|
|
|
enum
|
|
{
|
|
RESIZE_CHUNKS=1000,
|
|
};
|
|
};
|
|
|
|
|
|
typedef std::vector<CompFrame> CompFrameVec;
|
|
|
|
/* Large Frame Object
|
|
------------------ */
|
|
class LpObj : public GObject
|
|
{
|
|
public:
|
|
LpObj(void);
|
|
|
|
bool AddFrame(CompFrame const & C );
|
|
void SetBaseRecord(int f){BaseRecord=f;}
|
|
int NumOfFrames(void) { return(MyFrames.size());}
|
|
|
|
void Write(std::ofstream & Out) const;
|
|
void WriteHdr(std::ofstream & Out) const;
|
|
|
|
/* Make Vectorable */
|
|
|
|
void operator=(LpObj const &);
|
|
bool operator==(LpObj const &) const;
|
|
bool operator<(LpObj const &) const;
|
|
|
|
|
|
protected:
|
|
int GetSizeInAll(void) const;
|
|
int BaseRecord;
|
|
CompFrameVec MyFrames;
|
|
};
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function Prototypes
|
|
------------------- */
|
|
static void GenerateLpTable(LpObjVec & LpTable,CompFrameVec & CompFrames);
|
|
static int GetMaxRecsPerLp(LpObjVec & LpTable);
|
|
static void WriteWord(std::ofstream & Out,u16 Word);
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Vars
|
|
---- */
|
|
//static FilterDetails MyDetails(DpAnimFilter(),".anm");
|
|
|
|
/*----------------------------------------------------------------------
|
|
Data
|
|
---- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function: Main
|
|
---------------------------------------------------------------------- */
|
|
DpAnimFilter::DpAnimFilter()
|
|
{
|
|
InitVars();
|
|
}
|
|
|
|
DpAnimFilter::DpAnimFilter(char const * FName) : GAnimFilter(FName)
|
|
{
|
|
InitVars();
|
|
|
|
loaded_LP=0xffff;
|
|
}
|
|
|
|
DpAnimFilter::~DpAnimFilter(void)
|
|
{
|
|
DeleteVars();
|
|
}
|
|
|
|
bool DpAnimFilter::Load(GAnim & Anm)
|
|
{
|
|
int Frames;
|
|
Palette MyPal;
|
|
|
|
MakeVars();
|
|
|
|
anm_init2(FileName);
|
|
|
|
GetPal(MyPal);
|
|
|
|
anm_read_first_frame();
|
|
Frames=0;
|
|
|
|
do
|
|
{
|
|
Frame * NewFr;
|
|
|
|
NewFr=&Anm.GetNewFrame();
|
|
|
|
NewFr->SetFrame(dst_buffer,320,200,MyPal);
|
|
|
|
Frames++;
|
|
}
|
|
while(anm_read_next_frame());
|
|
|
|
fclose(inANM);
|
|
|
|
DeleteVars();
|
|
|
|
return(true);
|
|
}
|
|
|
|
void DpAnimFilter::GetPal(Palette & MyPal)
|
|
{
|
|
fseek(inANM,sizeof(AnimHdr)+sizeof(ColCycles[MAX_NUMBER_CYCLES]),SEEK_SET);
|
|
|
|
for (int f=0;f<256;f++)
|
|
{
|
|
MyPal[f].SetB(fgetc(inANM));
|
|
MyPal[f].SetG(fgetc(inANM));
|
|
MyPal[f].SetR(fgetc(inANM));
|
|
fgetc(inANM);
|
|
}
|
|
}
|
|
|
|
void DpAnimFilter::InitVars(void)
|
|
{
|
|
lpfTable=NULL;
|
|
current_LP=NULL;
|
|
dst_buffer=NULL;
|
|
|
|
}
|
|
|
|
void DpAnimFilter::MakeVars(void)
|
|
{
|
|
DeleteVars();
|
|
|
|
if (!(lpfTable = new LpTable[MAX_LARGE_PAGE]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
if (!(current_LP = new LpTableMem))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
if (!(dst_buffer=new u8[128960]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
}
|
|
|
|
void DpAnimFilter::DeleteVars(void)
|
|
{
|
|
if (lpfTable)
|
|
delete[] lpfTable;
|
|
|
|
if (current_LP)
|
|
delete current_LP;
|
|
|
|
if (dst_buffer)
|
|
delete dst_buffer;
|
|
|
|
InitVars();
|
|
}
|
|
|
|
|
|
|
|
bool DpAnimFilter::Save(GAnim & Anm)
|
|
{
|
|
|
|
MakeVars();
|
|
|
|
lpfHdr.InitHdr();
|
|
|
|
ofstream Out;
|
|
|
|
Out.open(FileName,ios::trunc|ios::out|ios::binary);
|
|
|
|
if (!Out)
|
|
Error(ERR_FATAL,"Can't open %s for output",(char const *)FileName);
|
|
else
|
|
{
|
|
int NumOfFrames;
|
|
CompFrameVec CompFrames;
|
|
LpObjVec MyLpTable;
|
|
|
|
NumOfFrames=Anm.NumOfFrames();
|
|
|
|
if (NumOfFrames)
|
|
{
|
|
CompFrames.reserve(NumOfFrames);
|
|
CompFrames.resize(NumOfFrames);
|
|
|
|
for (int f=0;f<NumOfFrames;f++)
|
|
Encode(Anm[f],CompFrames[f]);
|
|
|
|
GenerateLpTable(MyLpTable,CompFrames);
|
|
|
|
AnimHdr MyHdr;
|
|
MyHdr.nLps=MyLpTable.size();
|
|
MyHdr.lRecords=NumOfFrames;
|
|
MyHdr.maxRecsPerLp=GetMaxRecsPerLp(MyLpTable);
|
|
MyHdr.nFrames=NumOfFrames;
|
|
|
|
WriteHdr(Out,MyHdr);
|
|
WriteCycs(Out);
|
|
|
|
WritePal(Out,Anm[0].GetPal());
|
|
|
|
WriteLpTable(Out,MyLpTable);
|
|
WriteLps(Out,MyLpTable);
|
|
DiscardAnim();
|
|
}
|
|
}
|
|
|
|
Out.close();
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
ULONG DpAnimFilter::anm_init2(char const * filename)
|
|
{
|
|
FILE * Fp;
|
|
|
|
if(!(Fp=fopen(filename,"rb")))
|
|
Error(ERR_FATAL,"can't open %s",filename);
|
|
|
|
|
|
return(anm_init(Fp));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Setup buffer for playback and buffer for LP.
|
|
---------------------------------------------------------------------- */
|
|
ULONG DpAnimFilter::anm_init(FILE * filename)
|
|
{
|
|
inANM = filename;
|
|
|
|
fseek(inANM,0,SEEK_SET);
|
|
fread(&lpfHdr,sizeof(AnimHdr),1,inANM);
|
|
|
|
if ((lpfHdr.id != LARGE_PAGE_FILE_ID) || (lpfHdr.contentType != ANIM_CONTENTS_ID))
|
|
Error(ERR_FATAL,"Input file: %s is not an ANM file.",filename);
|
|
|
|
fseek(inANM,lpfHdr.lpfTableOffset,SEEK_SET);
|
|
fread(lpfTable,sizeof(LpTable[MAX_LARGE_PAGE]),1,inANM);
|
|
loaded_LP = 0xffff;
|
|
|
|
return(((lpfHdr.hasLastDelta) && (lpfHdr.lastDeltaValid)) ? (lpfHdr.nFrames - 1) : (lpfHdr.nFrames));
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Read LP off disk into memory for playback.
|
|
---------------------------------------------------------------------- */
|
|
void DpAnimFilter::read_LP(UWORD LP_to_load)
|
|
{
|
|
if (LP_to_load == loaded_LP)
|
|
return;
|
|
|
|
loaded_LP = LP_to_load;
|
|
fseek(inANM,LP_FILE_OFFSET(LP_to_load),0);
|
|
|
|
fread(current_LP,(ULONG) (8l + lpfTable[LP_to_load].nRecords * 2l),1,inANM);
|
|
|
|
fread(lp_buffer,(ULONG) lpfTable[LP_to_load].nBytes,1,inANM);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Read next frame from anm file.
|
|
---------------------------------------------------------------------- */
|
|
int DpAnimFilter::anm_read_next_frame(void)
|
|
{
|
|
int loop;
|
|
UWORD load_lp;
|
|
UWORD base;
|
|
ULONG lRecords;
|
|
|
|
|
|
/* next frame */
|
|
current_Frame++;
|
|
|
|
|
|
lRecords = lpfHdr.lRecords;
|
|
|
|
if (lpfHdr.hasLastDelta && lpfHdr.lastDeltaValid)
|
|
lRecords--;
|
|
|
|
if (current_Frame == lRecords)
|
|
return(0);
|
|
|
|
load_lp = 0;
|
|
|
|
while ((current_Frame >= (lpfTable[load_lp].baseRecord + lpfTable[load_lp].nRecords)) || (current_Frame < lpfTable[load_lp].baseRecord))
|
|
{
|
|
load_lp++;
|
|
}
|
|
|
|
|
|
read_LP(load_lp);
|
|
base = 0; /* Set start to beginning of buffer */
|
|
|
|
/* Find start of Frame by adding number of bytes of previous frames. */
|
|
|
|
for (loop = 0;loop <= (current_Frame - current_LP->baseRecord);loop++)
|
|
base += current_LP->size[loop];
|
|
|
|
|
|
if (lp_buffer[base] != 'B')
|
|
Error(ERR_FATAL,"Corrupt Anim File or Non Bitmapped image. base=%d,lp=%d in %s\n",base,load_lp,GetName());
|
|
|
|
if ((UWORD) lp_buffer[base + 2] != BMBODY_RUNSKIPDUMP)
|
|
Error(ERR_FATAL,"Compression scheme for frames is unkown.");
|
|
|
|
PlayRunSkipDump(&lp_buffer[base+4],dst_buffer);
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Read first frame of anm file.
|
|
---------------------------------------------------------------------- */
|
|
void DpAnimFilter::anm_read_first_frame(void)
|
|
{
|
|
lp_buffer = &dst_buffer[320u * 200u];
|
|
|
|
current_Frame = FIRST_FRAME_N;
|
|
|
|
read_LP(loaded_LP);
|
|
|
|
current_Frame = 0xffff;
|
|
|
|
anm_read_next_frame();
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Encode a frame with the DP anim codec and bung it into
|
|
a comp frame
|
|
---------------------------------------------------------------------- */
|
|
void DpAnimFilter::Encode(Frame const & Fr,CompFrame & Cfr)
|
|
{
|
|
Frame NewFrame;
|
|
u8 const * Src;
|
|
int BytesLeft,Index;
|
|
int const px=320;
|
|
int const py=200;
|
|
int const Size=px*py;
|
|
|
|
NewFrame=Fr;
|
|
NewFrame.Crop(Rect(0,0,px,py));
|
|
|
|
Src=NewFrame.SeeData();
|
|
|
|
BytesLeft=px*py;
|
|
Cfr.WriteByte('B');
|
|
Cfr.WriteByte(0);
|
|
Cfr.WriteWord(BMBODY_RUNSKIPDUMP);
|
|
|
|
while (BytesLeft)
|
|
{
|
|
int Length;
|
|
|
|
Index=(px*py)-BytesLeft;
|
|
|
|
Length=GetRunLength(&Src[Index],BytesLeft);
|
|
|
|
if (Length > 3)
|
|
WriteRun(Src[Index],Length,Cfr);
|
|
else
|
|
{
|
|
Length=GetDataLength(&Src[Index],BytesLeft);
|
|
WriteDataRun(&Src[Index],Length,Cfr);
|
|
}
|
|
|
|
BytesLeft-=Length;
|
|
}
|
|
|
|
WriteEnd(Cfr);
|
|
}
|
|
|
|
int DpAnimFilter::GetRunLength(u8 const * Src,int BytesLeft)
|
|
{
|
|
int Index=0;
|
|
int LastIndex;
|
|
bool Done=false;
|
|
int Previous=Src[0];
|
|
|
|
for (Index=0;Index<BytesLeft && !Done;Index++)
|
|
{
|
|
if (Src[Index] != Previous)
|
|
Done=true;
|
|
else
|
|
LastIndex=Index;
|
|
|
|
Previous=Src[Index];
|
|
}
|
|
|
|
// cout<<"Run of "<<LastIndex+1<<endl;
|
|
|
|
return(LastIndex+1);
|
|
}
|
|
|
|
int DpAnimFilter::GetDataLength(u8 const * Src,int BytesLeft)
|
|
{
|
|
int Index=0;
|
|
int LastIndex=0;
|
|
bool Done=false;
|
|
int Previous=Src[0]+1;
|
|
int RunLen=0;
|
|
|
|
for (Index=0;Index<BytesLeft && !Done;Index++)
|
|
{
|
|
if (Src[Index] == Previous)
|
|
{
|
|
RunLen++;
|
|
}
|
|
else
|
|
{
|
|
LastIndex=Index;
|
|
RunLen=0;
|
|
}
|
|
|
|
if (RunLen >= 2)
|
|
Done=true;
|
|
else
|
|
Previous=Src[Index];
|
|
|
|
}
|
|
|
|
// cout<<"Data Run of "<<LastIndex+1<<endl;
|
|
|
|
return(LastIndex+1);
|
|
}
|
|
|
|
void DpAnimFilter::WriteDataRun(u8 const * Data,int Length,CompFrame &Cfr)
|
|
{
|
|
// cout<<"*** Writing unique of "<<Length<<endl;
|
|
|
|
while (Length)
|
|
{
|
|
int ToWrite;
|
|
|
|
ToWrite=min(MAX_RUN_WRITE,Length);
|
|
|
|
if (ToWrite<128)
|
|
Cfr.WriteByte(ToWrite);
|
|
else
|
|
{
|
|
Cfr.WriteByte(0x80);
|
|
Cfr.WriteWord(0x8000|ToWrite);
|
|
}
|
|
|
|
Cfr.WriteData(Data,ToWrite);
|
|
|
|
Length-=ToWrite;
|
|
}
|
|
|
|
}
|
|
|
|
void DpAnimFilter::WriteRun(u8 Val,int Length,CompFrame &Cfr)
|
|
{
|
|
// cout<<"*** Writing run of "<<Length<<endl;
|
|
|
|
while (Length)
|
|
{
|
|
int ToWrite;
|
|
|
|
ToWrite=min(MAX_RUN_WRITE,Length);
|
|
|
|
if (ToWrite<128)
|
|
{
|
|
Cfr.WriteByte(0);
|
|
Cfr.WriteByte(ToWrite);
|
|
}
|
|
else
|
|
{
|
|
Cfr.WriteByte(0x80);
|
|
Cfr.WriteWord(0xc000|ToWrite);
|
|
}
|
|
|
|
Cfr.WriteByte(Val);
|
|
|
|
Length-=ToWrite;
|
|
}
|
|
}
|
|
|
|
void DpAnimFilter::WriteEnd(CompFrame &Cfr)
|
|
{
|
|
Cfr.WriteByte(0x80);
|
|
Cfr.WriteWord(0);
|
|
}
|
|
|
|
void DpAnimFilter::PlayRunSkipDump(UBYTE const *src, UBYTE *dst)
|
|
{
|
|
BOOL Done;
|
|
UBYTE * odst;
|
|
odst=dst;
|
|
|
|
Done=FALSE;
|
|
|
|
while (!Done)
|
|
{
|
|
u8 count;
|
|
count=*src++;
|
|
|
|
if (count == 0)
|
|
{
|
|
u8 clearlength,pixel;
|
|
clearlength=*src++;
|
|
pixel=*src++;
|
|
memset(dst,pixel,clearlength);
|
|
dst+=clearlength;
|
|
}
|
|
else
|
|
{
|
|
if (!(count&0x80))
|
|
{
|
|
memcpy(dst,src,count);
|
|
dst+=count;
|
|
src+=count;
|
|
}
|
|
else
|
|
{
|
|
count&=~0x80;
|
|
|
|
if (count==0)
|
|
{
|
|
uint wordcount;
|
|
|
|
wordcount=(*src++);
|
|
wordcount|=(*src++)<<8;
|
|
|
|
if (wordcount==0)
|
|
Done=TRUE;
|
|
else
|
|
{
|
|
if (wordcount&0x8000)
|
|
{
|
|
wordcount&=~0x8000;
|
|
|
|
if(wordcount&0x4000)
|
|
{
|
|
u8 pixel;
|
|
wordcount&=~0x4000;
|
|
pixel=*src++;
|
|
memset(dst,pixel,wordcount);
|
|
}
|
|
else
|
|
{
|
|
memcpy(dst,src,wordcount);
|
|
src+=wordcount;
|
|
}
|
|
}
|
|
|
|
dst+=wordcount;
|
|
}
|
|
}
|
|
else
|
|
dst+=count;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
DpAnimFIlter Sub Classes
|
|
---------------------------------------------------------------------- */
|
|
DpAnimFilter::AnimHdr::AnimHdr(void)
|
|
{
|
|
InitHdr();
|
|
|
|
}
|
|
|
|
void DpAnimFilter::AnimHdr::InitHdr(void)
|
|
{
|
|
id=MakeID('L','P','F',' ');
|
|
maxLps=256;
|
|
nLps=0; /* updated later */
|
|
lRecords=0; /* updated later */
|
|
maxRecsPerLp=256; /* updated later */
|
|
lpfTableOffset=1280;
|
|
contentType=MakeID('A','N','I','M');
|
|
width=320;
|
|
height=200;
|
|
variant=0;
|
|
version=0;
|
|
hasLastDelta=0;
|
|
lastDeltaValid=0;
|
|
pixelType=0;
|
|
highestBBComp=1;
|
|
otherRecordsPerFrame=0;
|
|
bitmapRecordsPerFrame=1;
|
|
nFrames=0; /* may be updated later */
|
|
framesPerSecond=10;
|
|
}
|
|
|
|
DpAnimFilter::ColCycles::ColCycles(void)
|
|
{
|
|
rate=0;
|
|
count=0;
|
|
flags=0;
|
|
low=0x10;
|
|
low=0x1f;
|
|
}
|
|
|
|
|
|
int GetMaxRecsPerLp(LpObjVec & LpTable)
|
|
{
|
|
int MaxLps=0;
|
|
int f;
|
|
|
|
|
|
for (f=0;f<LpTable.size();f++)
|
|
{
|
|
if (LpTable[f].NumOfFrames() > MaxLps)
|
|
MaxLps=LpTable[f].NumOfFrames();
|
|
}
|
|
|
|
return(MaxLps);
|
|
}
|
|
|
|
void GenerateLpTable(LpObjVec & LpTable,CompFrameVec & CompFrames)
|
|
{
|
|
LpObj * ThisObj;
|
|
int LpIndex;
|
|
int CompIndex;
|
|
bool Done;
|
|
|
|
ThisObj=NULL;
|
|
LpIndex=0;
|
|
CompIndex=0;
|
|
Done=false;
|
|
|
|
while (!Done)
|
|
{
|
|
if (CompIndex==CompFrames.size())
|
|
Done=TRUE;
|
|
else
|
|
{
|
|
if (!ThisObj)
|
|
{
|
|
LpTable.resize(LpTable.size()+1);
|
|
ThisObj=&LpTable[LpTable.size()-1];
|
|
ThisObj->SetBaseRecord(CompIndex);
|
|
}
|
|
|
|
if (ThisObj->AddFrame(CompFrames[CompIndex]))
|
|
CompIndex++;
|
|
else
|
|
ThisObj=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Anim writing stuff
|
|
---------------------------------------------------------------------- */
|
|
void DpAnimFilter::MakeAnim(void)
|
|
{
|
|
}
|
|
|
|
void DpAnimFilter::WriteHdr(ofstream & Out,AnimHdr & A)
|
|
{
|
|
Out.write((char const *) &A,sizeof(A));
|
|
}
|
|
|
|
void DpAnimFilter::WriteCycs(ofstream & Out)
|
|
{
|
|
ColCycles MyCycles[MAX_NUMBER_CYCLES];
|
|
Out.write((char const *) MyCycles,sizeof(MyCycles));
|
|
}
|
|
|
|
void DpAnimFilter::WritePal(ofstream & Out,Palette const & P)
|
|
{
|
|
for (int f=0;f<256;f++)
|
|
{
|
|
Out.put((u8)P[f].GetB());
|
|
Out.put((u8)P[f].GetG());
|
|
Out.put((u8)P[f].GetR());
|
|
Out.put((u8)0);
|
|
}
|
|
}
|
|
|
|
void DpAnimFilter::WriteLpTable(ofstream & Out,LpObjVec & LpTable)
|
|
{
|
|
int WriteFromTable;
|
|
int WriteDummy;
|
|
|
|
int Val=Out.tellp();
|
|
|
|
WriteFromTable=min(MAX_LARGE_PAGE,LpTable.size());
|
|
|
|
for (int f=0;f<WriteFromTable;f++)
|
|
LpTable[f].WriteHdr(Out);
|
|
|
|
WriteDummy=MAX_LARGE_PAGE-WriteFromTable;
|
|
|
|
if (WriteDummy)
|
|
{
|
|
LpObj Dummy;
|
|
|
|
for (int f=0;f<WriteDummy;f++)
|
|
Dummy.WriteHdr(Out);
|
|
}
|
|
|
|
int NewVal=Out.tellp();
|
|
Val=NewVal-Val;
|
|
}
|
|
|
|
void DpAnimFilter::WriteLps(ofstream & Out,LpObjVec & LpTable)
|
|
{
|
|
for (int f=0;f<LpTable.size();f++)
|
|
{
|
|
int Written=Out.tellp();
|
|
|
|
LpTable[f].Write(Out);
|
|
|
|
int CurrentPos;
|
|
CurrentPos=Out.tellp();
|
|
Written=CurrentPos-Written;
|
|
|
|
int ToWrite=LARGE_PAGE_SIZE-Written;
|
|
|
|
if (ToWrite>0)
|
|
{
|
|
for (int f=0;f<ToWrite;f++)
|
|
Out.put((char)'z');
|
|
}
|
|
}
|
|
}
|
|
|
|
void DpAnimFilter::DiscardAnim(void)
|
|
{
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
A Compressed Frame
|
|
---------------------------------------------------------------------- */
|
|
CompFrame::CompFrame(void)
|
|
{
|
|
Init();
|
|
Resize(RESIZE_CHUNKS);
|
|
}
|
|
|
|
void CompFrame::Resize(int NewLen)
|
|
{
|
|
u8 * NewData;
|
|
|
|
if(!(NewData=new u8[NewLen]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
if (BinData)
|
|
{
|
|
int ToCopy;
|
|
ToCopy=min(Len,NewLen);
|
|
memcpy(NewData,BinData,ToCopy);
|
|
delete BinData;
|
|
}
|
|
|
|
BinData=NewData;
|
|
ActualLen=NewLen;
|
|
|
|
Len=min(Len,ActualLen);
|
|
}
|
|
|
|
void CompFrame::Init(void)
|
|
{
|
|
Len=0;
|
|
ActualLen=0;
|
|
BinData=NULL;
|
|
}
|
|
|
|
void CompFrame::Dump(void)
|
|
{
|
|
if (BinData)
|
|
delete BinData;
|
|
|
|
Init();
|
|
}
|
|
|
|
CompFrame::~CompFrame(void)
|
|
{
|
|
Dump();
|
|
}
|
|
|
|
void CompFrame::WriteByte(u8 Byte)
|
|
{
|
|
if ((Len+1) >= ActualLen)
|
|
Increase(RESIZE_CHUNKS);
|
|
|
|
BinData[Len]=Byte;
|
|
|
|
Len+=1;
|
|
}
|
|
|
|
void CompFrame::WriteWord(u16 Word)
|
|
{
|
|
if ((Len+2) >= ActualLen)
|
|
Increase(RESIZE_CHUNKS);
|
|
|
|
BinData[Len]=Word&0xff;
|
|
BinData[Len+1]=Word>>8;
|
|
|
|
Len+=2;
|
|
}
|
|
|
|
void CompFrame::WriteData(u8 const * Src,int Amount)
|
|
{
|
|
if ((Len+Amount) >= ActualLen)
|
|
Increase(Amount+RESIZE_CHUNKS);
|
|
|
|
memcpy(&BinData[Len],Src,Amount);
|
|
|
|
Len+=Amount;
|
|
|
|
}
|
|
|
|
void CompFrame::Write(ofstream & Out) const
|
|
{
|
|
if (Len)
|
|
{
|
|
char const * Data;
|
|
Data=(char const *)BinData;
|
|
|
|
Out.write(Data,Len);
|
|
}
|
|
}
|
|
|
|
ostream & operator<<(ostream & str,CompFrame & Fr)
|
|
{
|
|
str<<"size: "<<Fr.GetSize();
|
|
return(str);
|
|
}
|
|
|
|
|
|
void CompFrame::operator=(CompFrame const & Fr)
|
|
{
|
|
Dump();
|
|
|
|
Resize(Fr.Len);
|
|
|
|
if (Fr.Len)
|
|
memcpy(BinData,Fr.BinData,Fr.Len);
|
|
|
|
Len=Fr.Len;
|
|
}
|
|
|
|
CompFrame::CompFrame(CompFrame const & C)
|
|
{
|
|
Init();
|
|
|
|
*this=C;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Large Page Shite
|
|
---------------------------------------------------------------------- */
|
|
LpObj::LpObj(void)
|
|
{
|
|
BaseRecord=0;
|
|
}
|
|
|
|
void LpObj::WriteHdr(ofstream & Out) const
|
|
{
|
|
WriteWord(Out,BaseRecord);
|
|
WriteWord(Out,MyFrames.size());
|
|
WriteWord(Out,GetSizeInAll()+1+1+2);
|
|
}
|
|
|
|
void LpObj::Write(ofstream & Out) const
|
|
{
|
|
int f;
|
|
|
|
WriteWord(Out,BaseRecord);
|
|
WriteWord(Out,MyFrames.size());
|
|
WriteWord(Out,GetSizeInAll()+1+1+2);
|
|
WriteWord(Out,0);
|
|
|
|
for (f=0;f<MyFrames.size();f++)
|
|
WriteWord(Out,MyFrames[f].GetSize());
|
|
|
|
|
|
for (f=0;f<MyFrames.size();f++)
|
|
{
|
|
|
|
MyFrames[f].Write(Out);
|
|
}
|
|
}
|
|
|
|
bool LpObj::AddFrame(CompFrame const & C )
|
|
{
|
|
|
|
if (((GetSizeInAll()+C.GetSize()) > 64000) && MyFrames.size())
|
|
return(false);
|
|
else
|
|
{
|
|
MyFrames.push_back(C);
|
|
return(true);
|
|
}
|
|
}
|
|
|
|
void LpObj::operator=(LpObj const & No)
|
|
{
|
|
BaseRecord=No.BaseRecord;
|
|
MyFrames=No.MyFrames;
|
|
}
|
|
|
|
int LpObj::GetSizeInAll(void) const
|
|
{
|
|
int Total=0;
|
|
|
|
for (int f=0;f<MyFrames.size();f++)
|
|
Total+=MyFrames[f].GetSize();
|
|
|
|
return(Total);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Helpy Stuff
|
|
---------------------------------------------------------------------- */
|
|
void WriteWord(ofstream & Out,u16 Word)
|
|
{
|
|
Out.put((u8)(Word&0xff));
|
|
Out.put((u8)(Word>>8));
|
|
}
|
|
|
|
|
|
/*===========================================================================
|
|
end */
|
|
|
|
|
|
|
|
|