/*========================================================================= DPANM.HPP Author: Gary Liddon @ Fareham Created: Project: Purpose: Copyright (c) 1997 Gary Liddon ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ //#include #include #include #include /* 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 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= (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= 2) Done=true; else Previous=Src[Index]; } // cout<<"Data Run of "< 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;f0) { for (int f=0;f= 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: "< 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>8)); } /*=========================================================================== end */