/*========================================================================= FILENAME.CPP Author: Gary Liddon @ Created: Project: Purpose: Copyright (c) 1997 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ /* Std Lib ------- */ #include <algorithm> #include "conio.h" /* Glib ---- */ #include "gutils.h" /* Local ----- */ #include "tpage.h" #include "grect.h" /* Graphics -------- */ /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ using namespace std; /*---------------------------------------------------------------------- Structure defintions -------------------- */ struct TPInfo { int XAlign; int TpWidth; int BorderX; int BorderY; }; /* Information about where I can place this frame in the Tpage ----------------------------------------------------------- */ /*---------------------------------------------------------------------- Vars ---- */ // changed by dave to get the pixel border back static TPInfo const InfStruct[TP_NUM_OF_TP_TYPES]= { {1,256,0,0}, // TP_4 {2,512,0,0}, // TP_8 {4,256,0,0}, // TP_16 {0,0,0,0}, // TP_SCREEN {16*4,1024*4,0,0}, // TP_PAL }; /* static TPInfo const InfStruct[TP_NUM_OF_TP_TYPES]= { {1,256,1,1}, // TP_4 {2,512,2,1}, // TP_8 {4,256,4,1}, // TP_16 {0,0,0,0}, // TP_SCREEN {16*4,1024*4,0,0}, // TP_PAL }; */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ int TPRect::W2Alloc=1; int TPRect::H2Alloc=1; /*---------------------------------------------------------------------- Data ---- */ /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ VRAM::VRAM(int nTpWidth,int nTpHeightInPixels) { Big2Little=false; RotateEveryEmpty=false; TpWidth=-1; TpHeightInPixels=-1; Clear(nTpWidth,nTpHeightInPixels); } void VRAM::Clear(int nTpWidth,int nTpHeightInPixels) { if (nTpWidth >= 0 ) TpWidth=nTpWidth; if (nTpHeightInPixels >= 0) TpHeightInPixels=nTpHeightInPixels; InitEmpty(0,0,TpWidth*256,TpHeightInPixels); } /*---------------------------------------------------------------------- Function: void VRAM::InitEmpty(void) Purpose: Initialise the VRAM as empty Params: Returns: ---------------------------------------------------------------------- */ void VRAM::InitEmpty(int vX,int vY,int nW,int nH) { const int Width16=256; const int Height16=256; W=nW; H=nH; X=vX; Y=vY; VRAMWidthPages=W/Width16; VRAMHeightPages=H/Height16; if (!VRAMHeightPages) { VRAMHeightPages = 1; } NumOfTPages=VRAMWidthPages*VRAMHeightPages; VecOfPages.resize(NumOfTPages,TPRectList()); Unused.reserve(4000); Used.reserve(2000); Unused.resize(0); Used.resize(0); for (int f=0;f<NumOfTPages;f++) VecOfPages[f].resize(0); for (int y=0;y<VRAMHeightPages;y++) for (int x=0;x<VRAMWidthPages;x++) AddEmpty((x*Width16)+vX,(y*Height16)+vY,Width16,Height16); } /*---------------------------------------------------------------------- Function: bool TryNFit(TPRectList & TpList) Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool VRAM::TryNFit(TPRectList & TpList,TPRect & ThisRect) { bool Done=false; TPRectList::iterator f; for (f=TpList.begin();f!=TpList.end();f++) { TPRect & BlankRect = *f; if (TryRect(BlankRect,ThisRect)) return(true); else { if (RotateEveryEmpty && CanRotate(ThisRect)) { ThisRect.SetRotate(!ThisRect.GetRotate()); if (TryRect(BlankRect,ThisRect)) return(true); else ThisRect.SetRotate(!ThisRect.GetRotate()); } } } return(false); } void VRAM::PosFromTPrect(TPRect & ThisRect,POS_INFO & Pi) { TPInfo const * Tpi; int WorkingWidth; Tpi=&InfStruct[ThisRect.TypeOfPage]; Pi.XAlign=Tpi->XAlign; WorkingWidth=GU_AlignVal(ThisRect.W,Pi.XAlign); Pi.MinX=Tpi->BorderX; Pi.MinY=Tpi->BorderY; Pi.MaxX=W-Tpi->BorderX-WorkingWidth; Pi.MaxY=H-Tpi->BorderY-ThisRect.H; Pi.TpWidthPix=Tpi->TpWidth; Pi.MinXTp=Tpi->BorderX; Pi.MaxXTp=Tpi->TpWidth-Tpi->BorderX-WorkingWidth; Pi.MinYTp=Tpi->BorderY; Pi.MaxYTp=(256-Tpi->BorderY)-ThisRect.H; } bool VRAM::TryRect(TPRect & BlankRect,TPRect & ThisRect) { POS_INFO Pi; PosFromTPrect(ThisRect,Pi); int MinTpX=Pi.MinXTp+(BlankRect.X/Pi.TpWidthPix)*Pi.TpWidthPix; int MaxTpX=Pi.MaxXTp+(BlankRect.X/Pi.TpWidthPix)*Pi.TpWidthPix; int MinTpY=Pi.MinYTp+(BlankRect.Y/256)*256; int MaxTpY=Pi.MaxYTp+(BlankRect.Y/256)*256; /* Move to avoid edges of the map */ int MinX = MinTpX > Pi.MinX ? MinTpX : Pi.MinX; int MaxX = MaxTpX < Pi.MaxX ? MaxTpX : Pi.MaxX; int MinY = MinTpY > Pi.MinY ? MinTpY : Pi.MinY; int MaxY = MaxTpY < Pi.MaxY ? MaxTpY : Pi.MaxY; int ThisX=GU_AlignVal(BlankRect.X,Pi.XAlign); int ThisY=BlankRect.Y; if (ThisX<MinX) ThisX=MinX; if (ThisX>MaxX) return(false); if (ThisY<MinY) ThisY=MinY; if (ThisY>MaxY) return(false); ThisRect.SetXY(ThisX,ThisY); if (!InColisionWithUsed(ThisRect)) { RemovedFromUnused(ThisRect); AddToUsed(ThisRect); return(true); } return(false); } /*---------------------------------------------------------------------- Function: TPRect VRAM::AllocVRAM(TPageType nType,int nW,int nH,bool Rotated) Purpose: Params: Returns: ---------------------------------------------------------------------- */ class Predicate { public: bool operator()(TPRect const & R1,TPRect const & R2) const { u32 R1Val=(R1.H<<16)|(R1.W); u32 R2Val=(R2.H<<16)|(R2.W); return (R1Val<R2Val); } }; class Predicate2 { public: bool operator()(TPRect const & R1,TPRect const & R2) const { u32 R1Val=(R1.H<<16)|(R1.W); u32 R2Val=(R2.H<<16)|(R2.W); return (R1Val>R2Val); } }; /*---------------------------------------------------------------------- Function: TPRect VRAM::AllocVRAM(TpRectVec & RectVec) Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool VRAM::AllocVRAM(TPRectVec & RectVec,bool nRotateEveryEmpty,bool nBig2Little,bool nWiderThanHigher) { int f; RotateEveryEmpty=nRotateEveryEmpty; Big2Little=nBig2Little; WiderThanHigher=nWiderThanHigher; if (WiderThanHigher) { for (f=0;f<RectVec.size();f++) { if ((RectVec[f].H > RectVec[f].W) && CanRotate(RectVec[f])) RectVec[f].SetRotate(!RectVec[f].GetRotate()); } } if (!Big2Little) std::sort(RectVec.begin(),RectVec.end(),Predicate()); else std::sort(RectVec.begin(),RectVec.end(),Predicate2()); bool AllocedEverything=true; for (f=0;f<RectVec.size();f++) { if (!AllocVRAM(RectVec[f])) { AllocedEverything=false; cout<<"Couldn't alloc "<<RectVec[f].W<<","<<RectVec[f].H<<endl; } } return(AllocedEverything); } /*---------------------------------------------------------------------- Function: void VRAM::AllocVRAM(TPageType nType,int nW,int nH) Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool VRAM::AllocVRAM(TPRect & OriginalRect) { bool Done; TPRect ThisRect; ThisRect=OriginalRect; Done=false; for (int Page=0;Page<NumOfTPages && !Done;Page++) { VecOfPages[Page].sort(); TPRect::SetAllocWH(ThisRect.W,ThisRect.H); if (!TryNFit(VecOfPages[Page],ThisRect)) { if (CanRotate(ThisRect)) { ThisRect.SetRotate(!ThisRect.GetRotate()); VecOfPages[Page].sort(); TPRect::SetAllocWH(ThisRect.W,ThisRect.H); if (!TryNFit(VecOfPages[Page],ThisRect)) ThisRect.SetRotate(!ThisRect.GetRotate()); else Done=true; } } else Done=true; } if (Done) { OriginalRect=ThisRect; OriginalRect.SetAlloced(true); return(true); } else { OriginalRect.SetAlloced(false); return(false); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool VRAM::CanRotate(TPRect & ThisRect) { if (ThisRect.GetDontRotate()) return(false); switch (ThisRect.TypeOfPage) { case TP_PAL: return(false); case TP_4: case TP_8: case TP_16: return(true); case TP_SCREEN: case TP_NUM_OF_TP_TYPES: default: Error(ERR_FATAL,"Not catered for"); return(false); } } /*---------------------------------------------------------------------- Function: void VRAM::AllocVRAM(TPageType nType,int nW,int nH) Purpose: Params: Returns: ---------------------------------------------------------------------- */ void VRAM::RectFromTpRect(Rect & R,TPRect const & ThisRect) { R.W=ThisRect.W; R.H=ThisRect.H; R.X=ThisRect.X; R.Y=ThisRect.Y; } void VRAM::RemovedFromUnused(TPRect const & ThisRect) { RectVec Result; Rect NewRect; int f; RectFromTpRect(NewRect,ThisRect); int ColidedWith=0; for ( f=0;f<Unused.size();f++) { Rect UnusedRect; RectFromTpRect(UnusedRect,Unused[f]); if (UnusedRect.IsColiding(ThisRect) ) { CutRect(UnusedRect,ThisRect,Result); ColidedWith++; } else Result.push_back(UnusedRect); } Unused.resize(0); for (f=0;f<NumOfTPages;f++) VecOfPages[f].resize(0); for (f=0;f<Result.size();f++) AddEmpty(Result[f].X,Result[f].Y,Result[f].W,Result[f].H); } void VRAM::AddEmpty(int x,int y,int w,int h) { Unused.resize(Unused.size()+1); TPRect & ThisRect=(Unused[Unused.size()-1]); ThisRect.TypeOfPage=TP_4; ThisRect.W=w; ThisRect.H=h; ThisRect.X=x; ThisRect.Y=y; int TpNum=(x/256)+((y/256)*VRAMWidthPages); VecOfPages[TpNum].insert(VecOfPages[TpNum].end(),ThisRect); } void VRAM::AddToUsed(TPRect const & ThisRect) { Used.push_back(ThisRect); } bool VRAM::InColisionWithUsed(TPRect const & R) { for (int f=0;f<Used.size();f++) { if (R.IsColiding(Used[f])) return(true); } return(false); } /*---------------------------------------------------------------------- Function: bool VRAM::CheckValidAlloc(TPageType nType,int nW,int nH) Purpose: Params: Returns: ---------------------------------------------------------------------- */ bool VRAM::CheckValidAlloc(TPageType nType,int nW,int nH) { return(true); } /*---------------------------------------------------------------------- Function: int VRAM::GetMaxWidthTp(TPageType nType) Purpose: Params: Returns: ---------------------------------------------------------------------- */ int VRAM::GetMaxWidthTp(TPageType nType) { int RetVal; switch (nType) { case TP_4: RetVal=1; break; case TP_8: RetVal=2; break; case TP_16: RetVal=4; break; case TP_SCREEN: RetVal=256; break; default: RetVal=-1; Error(ERR_FATAL,"Illegal tpage type"); break; } return(RetVal); } /*---------------------------------------------------------------------- Function: int VRAM::GetXAlign(TPageType nType) Purpose: Params: Returns: ---------------------------------------------------------------------- */ int VRAM::GetXAlign(TPageType nType) { int RetVal; switch (nType) { case TP_4: RetVal=1; break; case TP_8: RetVal=2; break; case TP_16: RetVal=4; break; case TP_PAL: RetVal=16*4; break; case TP_SCREEN: RetVal=4; break; default: RetVal=-1; Error(ERR_FATAL,"Illegal tpage type"); break; } return(RetVal); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ TPRect & VRAM::NewItem(TPRectVec & TPRects) { TPRects.resize(TPRects.size()+1); return(TPRects[TPRects.size()-1]); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ TPRect::TPRect(void) { InitRect(); } void TPRect::InitRect(void) { X=0; Y=0; W=0; H=0; TypeOfPage=TP_4; Rotated=false; Alloced=false; DontRotate=false; } TPRect::TPRect(TPageType nType,int nW,int nH) { int WidthMul; InitRect(); WidthMul=GetWidthMul(nType); W=nW*WidthMul; H=nH; TypeOfPage=nType; } int TPRect::GetWidthMul(TPageType nType) { int WidthMul; switch (nType) { case TP_4: WidthMul=1; break; case TP_8: WidthMul=2; break; case TP_16: case TP_SCREEN: case TP_PAL: WidthMul=4; break; case TP_NUM_OF_TP_TYPES: default: Error(ERR_FATAL,"Can't alloc type TP_NUM_OF_TP_TYPES"); break; } return (WidthMul); } void TPRect::Set(TPageType nType,int nX,int nY,int nW,int nH) { TypeOfPage=nType; X=nX; Y=nY; W=nW*GetWidthMul(nType); H=nH; } void TPRect::SetXY(int nX,int nY) { X=nX; Y=nY; } u32 TPRect::GetId(void) const { int Colis=0; int PageNum=(X/256)+((Y/256)*16); if ((X/256) != ((X+W2Alloc-1)/256)) Colis|=1; if ((Y/256) != ((Y+H2Alloc-1)/256)) Colis|=2; return ((Colis<<24)|(PageNum<<16)|((Y&0xff)<<8)|(X&0xff)); } bool TPRect::SetRotate(bool Rot) { bool RetBool=Rotated; if (Rot != RetBool) { W/=GetWidthMul(TypeOfPage); int Temp=W; W=H; H=Temp; W*=GetWidthMul(TypeOfPage); } Rotated=Rot; return(RetBool); } void VRAM::getUnusedSpace(TPRectVec & unusedBoxes) { int vX=X; int vY=Y; const int Width16=256; const int Height16=256; for (int y=0;y<VRAMHeightPages;y++) for (int x=0;x<VRAMWidthPages;x++) { TPRect thisRect; bool foundRect; foundRect=false; for (int f=1;f<255 && !foundRect;f++) { int boxBaseY; int boxHeight; boxBaseY=f; boxHeight=255-f; thisRect.X=(x*Width16)+vX; thisRect.Y=(y*Height16)+vY+boxBaseY; thisRect.W=Width16; thisRect.H=boxHeight; if (!InColisionWithUsed(thisRect)) foundRect=true; } if (foundRect) unusedBoxes.push_back(thisRect); } } int VRAM::GetNumOfUsedPages() { int Used=0; int vX=X; int vY=Y; const int Width16=256; const int Height16=256; for (int y=0;y<VRAMHeightPages;y++) for (int x=0;x<VRAMWidthPages;x++) { TPRect ThisRect; ThisRect.X=(x*Width16)+vX; ThisRect.Y=(y*Height16)+vY; ThisRect.W=Width16; ThisRect.H=Height16; if (InColisionWithUsed(ThisRect)) Used++; } return(Used); } bool TPRect::IsAlloced(void) const { return(Alloced); } void TPRect::SetAlloced(bool nAlloced) { Alloced=nAlloced; } int VRAM::GetNumOfItems() { return(Used.size()); } void TPRect::InitFromFrame(Frame const & Fr) { /* !!!!! Make this support other bit widths */ W=Fr.GetWidth(); H=Fr.GetHeight(); if (Fr.GetNumOfCols() <= 16) TypeOfPage=TP_4; else if (Fr.GetNumOfCols() <= 256) TypeOfPage=TP_8; else Error(ERR_FATAL,"Only 4 & 8 bit supported right now"); W*=GetWidthMul(TypeOfPage); } TPageType TPRect::convertTo16Bit(void) { TPageType oldType; switch (TypeOfPage) { case TP_4: // W=GU_AlignVal(W,4)/4; break; case TP_8: // W=GU_AlignVal(W,2)/2; break; default: Error(ERR_FATAL,"Only 4 & 8 bit supported right now"); break; } oldType=TypeOfPage; TypeOfPage=TP_16; return(oldType); } void TPRect::convertFrom16Bit(TPageType newType) { switch (newType) { case TP_4: // W=W*4; break; case TP_8: // W=W*2; break; default: Error(ERR_FATAL,"Only 4 & 8 bit supported right now"); break; } TypeOfPage=newType; } /*=========================================================================== end */