1681 lines
32 KiB
C++
1681 lines
32 KiB
C++
/*=========================================================================
|
|
|
|
FRAME.CPP
|
|
|
|
Author: Gary Liddon @ Fareham
|
|
Created:
|
|
Project:
|
|
Purpose:
|
|
|
|
Copyright (c) 1997 G R Liddon
|
|
|
|
===========================================================================*/
|
|
|
|
/*----------------------------------------------------------------------
|
|
Includes
|
|
-------- */
|
|
|
|
/* Std Lib
|
|
------- */
|
|
#include <conio.h>
|
|
#include <math.h>
|
|
|
|
/* STL
|
|
--- */
|
|
//#include <alogrithm>
|
|
#include <ALGORITHM>
|
|
|
|
|
|
/* Glib
|
|
---- */
|
|
|
|
/* Local
|
|
----- */
|
|
#include "frame.hpp"
|
|
#include "ilbm.hpp"
|
|
#include "gutils.h"
|
|
#include "misc.hpp"
|
|
|
|
using namespace std;
|
|
|
|
static void load_bmp(Frame & frm,char const *filename);
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function: Frame::Frame(void)
|
|
---------------------------------------------------------------------- */
|
|
Frame::Frame(void)
|
|
{
|
|
InitFrame();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function: Copy Constructor
|
|
---------------------------------------------------------------------- */
|
|
Frame::Frame(Frame const & Fr)
|
|
{
|
|
InitFrame();
|
|
CopyFrame(Fr);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function: Destructor
|
|
---------------------------------------------------------------------- */
|
|
Frame::~Frame(void)
|
|
{
|
|
if (Buffa)
|
|
delete Buffa;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function: Init the Frame
|
|
---------------------------------------------------------------------- */
|
|
void Frame::InitFrame(void)
|
|
{
|
|
Buffa=NULL;
|
|
X=0;
|
|
Y=0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::CopyFrame(Frame const & Fr)
|
|
{
|
|
DumpStuff();
|
|
|
|
Width=Fr.Width;
|
|
Height=Fr.Height;
|
|
|
|
if (Fr.Buffa)
|
|
{
|
|
if (!(Buffa=new u8[Width*Height]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memcpy(Buffa,Fr.Buffa,Width*Height);
|
|
}
|
|
else
|
|
Buffa=NULL;
|
|
|
|
Name=Fr.Name;
|
|
|
|
MyPal=Fr.MyPal;
|
|
|
|
X=Fr.X;
|
|
Y=Fr.Y;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::DumpStuff(void)
|
|
{
|
|
if (Buffa)
|
|
delete Buffa;
|
|
Width=0;
|
|
Height=0;
|
|
X=0;
|
|
Y=0;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
bool Frame::IsBlank(u8 BlankVal)
|
|
{
|
|
if (Buffa)
|
|
{
|
|
for (int f=0;f<Width*Height;f++)
|
|
{
|
|
if (Buffa[f] != BlankVal)
|
|
return(false);
|
|
}
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
bool Frame::Grab(Frame const & Fr,Rect const & RetRect)
|
|
{
|
|
Rect GrabRect(RetRect);
|
|
Rect FromRect=Fr;
|
|
|
|
FromRect.X=0;
|
|
FromRect.Y=0;
|
|
FromRect.ClipRect(GrabRect);
|
|
|
|
if (GrabRect)
|
|
{
|
|
InitFrame();
|
|
u8 const * GrAddr=&Fr.Buffa[GrabRect.Y*Fr.Width+GrabRect.X];
|
|
|
|
if (Buffa=new u8[GrabRect.W*GrabRect.H])
|
|
{
|
|
Width=GrabRect.W;
|
|
Height=GrabRect.H;
|
|
MyPal=Fr.MyPal;
|
|
|
|
for (int y=0;y<Height;y++)
|
|
memcpy(&Buffa[y*Width],&GrAddr[y*Fr.Width],Width);
|
|
}
|
|
else
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
return(true);
|
|
}
|
|
|
|
return(false);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
bool Frame::DrawBox(Rect const & RetRect,u8 Col)
|
|
{
|
|
Rect GrabRect(RetRect);
|
|
Rect FromRect=*this;
|
|
|
|
FromRect.X=0;
|
|
FromRect.Y=0;
|
|
FromRect.ClipRect(GrabRect);
|
|
|
|
if (GrabRect)
|
|
{
|
|
u8 * GrAddr=&Buffa[GrabRect.Y*Width+GrabRect.X];
|
|
|
|
for (int y=0;y<Height;y++)
|
|
memset(&GrAddr[y*Width],Col,Width);
|
|
|
|
return(true);
|
|
}
|
|
|
|
return(false);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::SetFrame(u8 const * nBuffa,int W,int H,Palette const & NewPal)
|
|
{
|
|
DumpStuff();
|
|
|
|
Width=W;
|
|
Height=H;
|
|
|
|
MyPal=NewPal;
|
|
|
|
if (!(Buffa=new u8[Width*Height]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memcpy(Buffa,nBuffa,Width*Height);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::ReduceSinglePixels(int Threshold)
|
|
{
|
|
UINT cury,curx,col,lastcol,nextcol;
|
|
UINT r,g,b,lastr,lastg,lastb,nextr,nextg,nextb,dist1,dist2;
|
|
UCHAR * p;
|
|
|
|
UINT RDLBM256_sy=Height;
|
|
UINT RDLBM256_sx=Width;
|
|
u8 * inbuf=Buffa;
|
|
|
|
for(cury=0;cury<RDLBM256_sy;cury++)
|
|
{
|
|
p = inbuf+(cury*RDLBM256_sx);
|
|
for(curx=0;curx<RDLBM256_sx;curx++)
|
|
{
|
|
col = *p;
|
|
nextcol = *(p+1);
|
|
|
|
if(curx && curx!=RDLBM256_sx-1 && col && col != lastcol && col != nextcol)
|
|
{
|
|
Colour * C;
|
|
Colour * LC;
|
|
Colour * NC;
|
|
|
|
C=&MyPal[col];
|
|
LC=&MyPal[lastcol];
|
|
NC=&MyPal[nextcol];
|
|
|
|
r = C->GetR();
|
|
g = C->GetG();;
|
|
b = C->GetB();;
|
|
|
|
lastr = LC->GetR();
|
|
lastg = LC->GetG();
|
|
lastb = LC->GetB();
|
|
|
|
nextr = NC->GetR();
|
|
nextg = NC->GetG();
|
|
nextb = NC->GetB();
|
|
|
|
dist1 = ((lastr-r)*(lastr-r)) + ((lastg-g)*(lastg-g)) + ((lastb-b)*(lastb-b));
|
|
dist2 = ((nextr-r)*(nextr-r)) + ((nextg-g)*(nextg-g)) + ((nextb-b)*(nextb-b));
|
|
|
|
if(dist1 < dist2)
|
|
{
|
|
if(dist1 <= Threshold)
|
|
{
|
|
*p = lastcol;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(dist2 <= Threshold)
|
|
*p = nextcol;
|
|
}
|
|
}
|
|
lastcol = *p++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::ReduceSize(void)
|
|
{
|
|
Rect MRect=FindBoundingRect();
|
|
Crop(MRect);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Crop(Rect const & NewRect)
|
|
{
|
|
if (Buffa && NewRect)
|
|
{
|
|
Rect CopyRect;
|
|
CopyRect=*this;
|
|
CopyRect.X=0;
|
|
CopyRect.Y=0;
|
|
|
|
Rect MyRect=NewRect;
|
|
|
|
CopyRect.ClipRect(MyRect);
|
|
CopyRect=MyRect;
|
|
|
|
if (CopyRect)
|
|
{
|
|
u8 * DestBuffa;
|
|
|
|
if (!(DestBuffa=new u8[NewRect.Area()]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memset(DestBuffa,0,NewRect.Area());
|
|
|
|
u8 * Src=&Buffa[CopyRect.X+CopyRect.Y*Width];
|
|
u8 * Dst=DestBuffa;
|
|
|
|
for (int yy=0;yy<CopyRect.H;yy++)
|
|
{
|
|
memcpy(Dst,Src,CopyRect.W);
|
|
Src+=Width;
|
|
Dst+=NewRect.W;
|
|
}
|
|
|
|
delete Buffa;
|
|
Buffa=DestBuffa;
|
|
|
|
Width=NewRect.W;
|
|
Height=NewRect.H;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose: Resize this image to another size (uses point sampling)
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Resize(int NewWidth,int NewHeight)
|
|
{
|
|
if (NewHeight != Height || NewWidth != Width)
|
|
{
|
|
vector<u8> NewPic;
|
|
|
|
NewPic.resize(NewWidth*NewHeight);
|
|
|
|
for (int y=0;y<NewHeight;y++)
|
|
for (int x=0;x<NewWidth;x++)
|
|
{
|
|
float XFrac=float(x)/float(NewWidth);
|
|
float YFrac=float(y)/float(NewHeight);
|
|
int FromX=float(Width)*XFrac;
|
|
int FromY=float(Height)*YFrac;
|
|
NewPic[y*NewWidth+x]=Buffa[FromY*Width+FromX];
|
|
}
|
|
|
|
DumpStuff();
|
|
|
|
Width=NewWidth;
|
|
Height=NewHeight;
|
|
|
|
if(!(Buffa=new u8[Width*Height]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memcpy(Buffa,&NewPic[0],Width*Height);
|
|
}
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
Rect Frame::FindBoundingRect(void)
|
|
{
|
|
Rect RetRect;
|
|
u8 * Bmap;
|
|
|
|
Bmap=Buffa;
|
|
|
|
if (Bmap)
|
|
{
|
|
int Bottom;
|
|
int x,y;
|
|
|
|
Bottom=-1;
|
|
|
|
for (y=Height-1;y>=0 && Bottom==-1;y--)
|
|
{
|
|
for (x=0;x<Width && Bottom==-1;x++)
|
|
if (Bmap[y*Width+x])
|
|
Bottom=y;
|
|
}
|
|
|
|
if (Bottom != -1)
|
|
{
|
|
int Top=-1;
|
|
for (y=0;y<=Bottom && Top==-1;y++)
|
|
{
|
|
for (x=0;x<Width && Top==-1;x++)
|
|
if (Bmap[y*Width+x])
|
|
Top=y;
|
|
}
|
|
|
|
if (Top != -1)
|
|
{
|
|
int Left=-1;
|
|
|
|
for (x=0;x<Width && Left==-1;x++)
|
|
{
|
|
for (y=Top;y<=Bottom && Left==-1;y++)
|
|
if (Bmap[y*Width+x])
|
|
Left=x;
|
|
}
|
|
|
|
if (Left!=-1)
|
|
{
|
|
int Right=-1;
|
|
|
|
for (x=Width-1;x>=Left && Right==-1;x--)
|
|
{
|
|
for (y=Top;y<=Bottom && Right==-1;y++)
|
|
if (Bmap[y*Width+x])
|
|
Right=x;
|
|
}
|
|
|
|
if (Right !=-1)
|
|
{
|
|
RetRect.X=Left;
|
|
RetRect.Y=Top;
|
|
RetRect.W=Right-Left+1;
|
|
RetRect.H=Bottom-Top+1;
|
|
}
|
|
else
|
|
Error(ERR_FATAL,"Strange frame");
|
|
}
|
|
else
|
|
Error(ERR_FATAL,"Strange frame");
|
|
}
|
|
else
|
|
Error(ERR_FATAL,"Strange frame");
|
|
}
|
|
}
|
|
|
|
return(RetRect);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::SaveLbm(char const * Lbm)
|
|
{
|
|
u8 * Pal;
|
|
|
|
Pal=MyPal.MakeDpPal();
|
|
nilbm::SavePbm((char *)Lbm,Pal,Buffa,Width,Height);
|
|
delete Pal;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::LoadLbm(char const * Lbm)
|
|
{
|
|
nilbm MyLbm(Lbm);
|
|
|
|
if (!MyLbm.error())
|
|
{
|
|
if (Buffa)
|
|
delete Buffa;
|
|
|
|
u8 const * CMap;
|
|
|
|
Buffa=MyLbm.TakeBmap();
|
|
CMap=MyLbm.SeeCmap();
|
|
|
|
Width=MyLbm.GetWidth();
|
|
Height=MyLbm.GetHeight();
|
|
|
|
int NumOfCols=1<<MyLbm.GetPlanes();
|
|
|
|
for (int f=0;f<NumOfCols;f++)
|
|
{
|
|
MyPal[f].SetR(CMap[f*3+0]);
|
|
MyPal[f].SetG(CMap[f*3+1]);
|
|
MyPal[f].SetB(CMap[f*3+2]);
|
|
}
|
|
}
|
|
else
|
|
Error(ERR_FATAL,"Can't load lbm %s",Lbm);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose: Load a paletted BMP file
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void Frame::LoadBMP(char const * FileName)
|
|
{
|
|
load_bmp(*this,FileName);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
int Frame::GetNumOfCols(void) const
|
|
{
|
|
int Ret;
|
|
|
|
Ret=0;
|
|
|
|
if (Buffa)
|
|
{
|
|
for (int f=0;f<Width*Height;f++)
|
|
{
|
|
if (Buffa[f] > Ret)
|
|
Ret=Buffa[f];
|
|
}
|
|
}
|
|
|
|
return(Ret+1);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::FlipX(void)
|
|
{
|
|
if (Buffa && Width && Height)
|
|
{
|
|
vector<u8> Buffa2;
|
|
|
|
Buffa2.resize(Width*Height);
|
|
|
|
for (int y=0;y<Height;y++)
|
|
{
|
|
for (int x=0;x<Width;x++)
|
|
Buffa2[((Width-1)-x)+y*Width]=Buffa[x+y*Width];
|
|
}
|
|
memcpy(Buffa,&Buffa2[0],Width*Height);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::FlipY(void)
|
|
{
|
|
if (Buffa && Width && Height)
|
|
{
|
|
vector<u8> Buffa2;
|
|
|
|
Buffa2.resize(Width*Height);
|
|
|
|
for (int y=0;y<Height;y++)
|
|
memcpy(&Buffa2[((Height-1)-y)*Width],&Buffa[y*Width],Width);
|
|
|
|
memcpy(Buffa,&Buffa2[0],Width*Height);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Remap(Palette const & P)
|
|
{
|
|
if (Buffa)
|
|
{
|
|
int * RemapBuffer;
|
|
|
|
RemapBuffer=P.MakeRemapTable(MyPal);
|
|
|
|
for (int f=0;f<Width*Height;f++)
|
|
Buffa[f]=RemapBuffer[Buffa[f]];
|
|
|
|
MyPal=P;
|
|
delete RemapBuffer;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::MakeRGBA(u8 * Dest,bool ZeroIsTrans)
|
|
{
|
|
if (Buffa)
|
|
{
|
|
int Area;
|
|
Area=Width*Height;
|
|
|
|
for (int f=0;f<Area;f++)
|
|
{
|
|
Dest[f*4+0]=MyPal[Buffa[f]].GetR();
|
|
Dest[f*4+1]=MyPal[Buffa[f]].GetG();
|
|
Dest[f*4+2]=MyPal[Buffa[f]].GetB();
|
|
|
|
if (ZeroIsTrans)
|
|
Dest[f*4+3]=Buffa[f] ? 255 : 0;
|
|
else
|
|
Dest[f*4+3]=255;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::MakeRGB(u8 * Dest)
|
|
{
|
|
if (Buffa)
|
|
{
|
|
int Area;
|
|
Area=Width*Height;
|
|
|
|
for (int f=0;f<Area;f++)
|
|
{
|
|
Dest[f*3+0]=MyPal[Buffa[f]].GetR();
|
|
Dest[f*3+1]=MyPal[Buffa[f]].GetG();
|
|
Dest[f*3+2]=MyPal[Buffa[f]].GetB();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Plot(Frame & Dest,int X,int Y)
|
|
{
|
|
if (Buffa && Dest.Buffa)
|
|
{
|
|
Rect DestRect=Dest;
|
|
Rect NewR(X,Y,Width,Height);
|
|
|
|
DestRect.X=0;
|
|
DestRect.Y=0;
|
|
|
|
DestRect.ClipRect(NewR);
|
|
|
|
if (NewR)
|
|
{
|
|
int NumOfCols=MyPal.GetNumOfCols();
|
|
int * RemapBuffer;
|
|
|
|
int XIndent=NewR.X-X;
|
|
int YIndent=NewR.Y-Y;
|
|
|
|
u8 * PicSrc=&Buffa[XIndent+YIndent*Width];
|
|
|
|
RemapBuffer=Dest.MyPal.MakeRemapTable(MyPal);
|
|
|
|
for (int yy=NewR.Y;yy<NewR.Y+NewR.H;yy++)
|
|
{
|
|
for (int xx=0;xx<NewR.W;xx++)
|
|
Dest.Buffa[yy*Dest.Width+NewR.X+xx]=RemapBuffer[PicSrc[(yy-NewR.Y)*Width+xx]];
|
|
}
|
|
|
|
delete RemapBuffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::PlotBox(Rect const & R,int Col)
|
|
{
|
|
Rect NewR(0,0,Width,Height);
|
|
Rect DRect;
|
|
|
|
DRect=R;
|
|
NewR.ClipRect(DRect);
|
|
|
|
if (DRect && Buffa)
|
|
{
|
|
for (int yy=DRect.Y;yy<DRect.Y+DRect.H;yy++)
|
|
memset(&Buffa[yy*Width+DRect.X],Col,DRect.W);
|
|
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::PlotTrans(Frame & Dest,int X,int Y,int TrCol)
|
|
{
|
|
if (Buffa && Dest.Buffa)
|
|
{
|
|
Rect DestRect=Dest;
|
|
Rect NewR(X,Y,Width,Height);
|
|
|
|
DestRect.X=0;
|
|
DestRect.Y=0;
|
|
|
|
DestRect.ClipRect(NewR);
|
|
|
|
if (NewR)
|
|
{
|
|
int NumOfCols=MyPal.GetNumOfCols();
|
|
int * RemapBuffer;
|
|
|
|
int XIndent=NewR.X-X;
|
|
int YIndent=NewR.Y-Y;
|
|
|
|
u8 * PicSrc=&Buffa[XIndent+YIndent*Width];
|
|
|
|
RemapBuffer=Dest.MyPal.MakeRemapTable(MyPal);
|
|
|
|
for (int yy=NewR.Y;yy<NewR.Y+NewR.H;yy++)
|
|
{
|
|
for (int xx=0;xx<NewR.W;xx++)
|
|
{
|
|
if (PicSrc[(yy-NewR.Y)*Width+xx] != TrCol)
|
|
Dest.Buffa[yy*Dest.Width+NewR.X+xx]=RemapBuffer[PicSrc[(yy-NewR.Y)*Width+xx]];
|
|
}
|
|
}
|
|
|
|
delete RemapBuffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Frame::ReplaceColour(int ColNum,int RepNum)
|
|
{
|
|
if (Buffa && Width && Height)
|
|
{
|
|
if ((ColNum<MyPal.GetNumOfCols()) && (RepNum<MyPal.GetNumOfCols()))
|
|
{
|
|
for (int f=0;f<Width*Height;f++)
|
|
{
|
|
if (Buffa[f]==ColNum)
|
|
Buffa[f]=RepNum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::ReducePal(void)
|
|
{
|
|
if (Buffa && Width && Height)
|
|
MyPal.SetPalSize(GetNumOfCols());
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Clear(int Col)
|
|
{
|
|
if (Buffa && Width && Height)
|
|
memset(Buffa,Col,Width*Height);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
struct ColPair
|
|
{
|
|
Colour C;
|
|
int Uses;
|
|
|
|
bool operator==(ColPair const &Col) const
|
|
{return(Uses==Col.Uses);}
|
|
|
|
bool operator<(ColPair const &Col) const
|
|
{return(Uses<Col.Uses);}
|
|
};
|
|
|
|
class PredicateColPair
|
|
{
|
|
public:
|
|
bool operator()(ColPair const & R1,ColPair const & R2) const
|
|
{
|
|
return (R2.Uses<R1.Uses);
|
|
}
|
|
};
|
|
|
|
void Frame::ReduceColours(int TargColours)
|
|
{
|
|
if (Buffa && TargColours <=255)
|
|
{
|
|
Palette NewPal;
|
|
|
|
for (int f=0;f<TargColours;f++)
|
|
NewPal[f].SetRGB(0xff,0,0xff);
|
|
|
|
vector<ColPair> Colours;
|
|
Colours.resize(256);
|
|
|
|
for (f=0;f<256;f++)
|
|
Colours[f].Uses=0;
|
|
|
|
for (f=0;f<Width*Height;f++)
|
|
{
|
|
if (Buffa[f])
|
|
{
|
|
Colours[Buffa[f]].C=MyPal[Buffa[f]];
|
|
Colours[Buffa[f]].Uses++;
|
|
}
|
|
}
|
|
|
|
sort(Colours.begin(),Colours.end());
|
|
|
|
for (f=63;f>0;f--)
|
|
{
|
|
int ColIndex=255-63+f;
|
|
|
|
if (Colours[ColIndex].Uses)
|
|
NewPal[f]=Colours[ColIndex].C;
|
|
}
|
|
Remap(NewPal);
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::AddPixelSurround(int Col)
|
|
{
|
|
if (Buffa && Col < MyPal.GetNumOfCols())
|
|
{
|
|
Frame NewFrame;
|
|
|
|
NewFrame=*this;
|
|
NewFrame.Width+=2;
|
|
NewFrame.Height+=2;
|
|
|
|
NewFrame.DumpStuff();
|
|
|
|
if(!(NewFrame.Buffa=new u8[NewFrame.Width*NewFrame.Height]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memset(NewFrame.Buffa,0,NewFrame.Width*NewFrame.Height);
|
|
|
|
PlotTrans(NewFrame,0,0);
|
|
PlotTrans(NewFrame,0,1);
|
|
PlotTrans(NewFrame,0,2);
|
|
PlotTrans(NewFrame,1,0);
|
|
PlotTrans(NewFrame,1,2);
|
|
PlotTrans(NewFrame,2,0);
|
|
PlotTrans(NewFrame,2,1);
|
|
PlotTrans(NewFrame,2,2);
|
|
|
|
for (int f=0;f<NewFrame.Width*NewFrame.Height;f++)
|
|
{
|
|
if (NewFrame.Buffa[f])
|
|
NewFrame.Buffa[f]=Col;
|
|
}
|
|
|
|
PlotTrans(NewFrame,1,1);
|
|
*this=NewFrame;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Frame::Expand(int BorderWidth,bool DupeEdges)
|
|
{
|
|
Frame NewFrame;
|
|
NewFrame=*this;
|
|
NewFrame.Width+=BorderWidth*2;
|
|
NewFrame.Height+=BorderWidth*2;
|
|
|
|
if(!(NewFrame.Buffa=new u8[NewFrame.Width*NewFrame.Height]))
|
|
Error(ERM_OUTOFMEM);
|
|
|
|
memset(NewFrame.Buffa,0,NewFrame.Width*NewFrame.Height);
|
|
|
|
if (DupeEdges)
|
|
{
|
|
for (int f=0;f<BorderWidth*2+1;f++)
|
|
Plot(NewFrame,f,BorderWidth);
|
|
|
|
for (f=0;f<BorderWidth*2+1;f++)
|
|
Plot(NewFrame,BorderWidth,f);
|
|
}
|
|
|
|
Plot(NewFrame,BorderWidth,BorderWidth);
|
|
|
|
*this=NewFrame;
|
|
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
Rect::Rect(void)
|
|
{
|
|
|
|
X=0;
|
|
Y=0;
|
|
W=0;
|
|
H=0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
ostream & operator<<(ostream & str,Rect const & Fr)
|
|
{
|
|
str<<"X,Y = ("<<Fr.X<<","<<Fr.Y<<") WH=("<<Fr.W<<","<<Fr.H<<")";
|
|
return(str);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void Rect::ClipRect(Rect & RectToClip) const
|
|
{
|
|
if (IsColiding(RectToClip))
|
|
{
|
|
if (RectToClip.X < X)
|
|
{
|
|
RectToClip.W-=X-RectToClip.X;
|
|
RectToClip.X=X;
|
|
}
|
|
|
|
if (RectToClip.Y < Y)
|
|
{
|
|
RectToClip.H-=Y-RectToClip.Y;
|
|
RectToClip.Y=Y;
|
|
}
|
|
|
|
if ((RectToClip.X+RectToClip.W) > (X+W))
|
|
RectToClip.W-=(RectToClip.X+RectToClip.W)-(X+W);
|
|
|
|
if ((RectToClip.Y+RectToClip.H) > (Y+H))
|
|
RectToClip.H-=(RectToClip.Y+RectToClip.H)-(Y+H);
|
|
}
|
|
else
|
|
{
|
|
RectToClip.W=0;
|
|
RectToClip.H=0;
|
|
RectToClip.X=0;
|
|
RectToClip.Y=0;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
bool Rect::IsColiding(Rect const & NewRect) const
|
|
{
|
|
if ((NewRect.X+NewRect.W) <= X)
|
|
return(false);
|
|
|
|
if ((X+W) <= NewRect.X)
|
|
return(false);
|
|
|
|
if ((NewRect.Y+NewRect.H) <= Y)
|
|
return(false);
|
|
|
|
if ((Y+H) <= NewRect.Y)
|
|
return(false);
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
struct RGB
|
|
{
|
|
u8 r,g,b;
|
|
};
|
|
|
|
class BITMAP
|
|
{
|
|
public:
|
|
BITMAP(void)
|
|
{
|
|
m_width=0;
|
|
m_height=0;
|
|
}
|
|
|
|
void setSize(int width,int height)
|
|
{
|
|
bitMap.resize(width*height);
|
|
|
|
m_width=width;
|
|
m_height=height;
|
|
}
|
|
|
|
void clear(void)
|
|
{
|
|
if (m_width && m_height)
|
|
memset(&bitMap[0],0,m_width*m_height);
|
|
}
|
|
|
|
void line(unsigned int y,unsigned int x,u8 pix)
|
|
{
|
|
if (x >= m_width || y >= m_height)
|
|
GObject::Error(ERR_FATAL,"out of bounds");
|
|
else
|
|
bitMap[y*m_width+x]=pix;
|
|
}
|
|
|
|
u8 const * getBitMap(void) const
|
|
{return(&bitMap[0]);}
|
|
|
|
protected:
|
|
int m_width;
|
|
int m_height;
|
|
vector<u8> bitMap;
|
|
};
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
|
|
#define BI_RGB 0
|
|
#define BI_RLE8 1
|
|
#define BI_RLE4 2
|
|
#define BI_BITFIELDS 3
|
|
|
|
#define OS2INFOHEADERSIZE 12
|
|
#define WININFOHEADERSIZE 40
|
|
|
|
|
|
typedef struct BITMAPFILEHEADER
|
|
{
|
|
unsigned long bfType;
|
|
unsigned long bfSize;
|
|
unsigned short bfReserved1;
|
|
unsigned short bfReserved2;
|
|
unsigned long bfOffBits;
|
|
} BITMAPFILEHEADER;
|
|
|
|
|
|
/* Used for both OS/2 and Windows BMP.
|
|
* Contains only the parameters needed to load the image
|
|
*/
|
|
typedef struct BITMAPINFOHEADER
|
|
{
|
|
unsigned long biWidth;
|
|
unsigned long biHeight;
|
|
unsigned short biBitCount;
|
|
unsigned long biCompression;
|
|
} BITMAPINFOHEADER;
|
|
|
|
|
|
typedef struct WINBMPINFOHEADER /* size: 40 */
|
|
{
|
|
unsigned long biWidth;
|
|
unsigned long biHeight;
|
|
unsigned short biPlanes;
|
|
unsigned short biBitCount;
|
|
unsigned long biCompression;
|
|
unsigned long biSizeImage;
|
|
unsigned long biXPelsPerMeter;
|
|
unsigned long biYPelsPerMeter;
|
|
unsigned long biClrUsed;
|
|
unsigned long biClrImportant;
|
|
} WINBMPINFOHEADER;
|
|
|
|
|
|
typedef struct OS2BMPINFOHEADER /* size: 12 */
|
|
{
|
|
unsigned short biWidth;
|
|
unsigned short biHeight;
|
|
unsigned short biPlanes;
|
|
unsigned short biBitCount;
|
|
} OS2BMPINFOHEADER;
|
|
|
|
|
|
|
|
/* read_bmfileheader:
|
|
* Reads a BMP file header and check that it has the BMP magic number.
|
|
*/
|
|
static int read_bmfileheader(Gifstream & f, BITMAPFILEHEADER *fileheader)
|
|
{
|
|
fileheader->bfType = f.Get16();
|
|
fileheader->bfSize= f.Get32();
|
|
fileheader->bfReserved1= f.Get16();
|
|
fileheader->bfReserved2= f.Get16();
|
|
fileheader->bfOffBits= f.Get32();
|
|
|
|
if (fileheader->bfType != 19778)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* read_win_bminfoheader:
|
|
* Reads information from a BMP file header.
|
|
*/
|
|
static int read_win_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader)
|
|
{
|
|
WINBMPINFOHEADER win_infoheader;
|
|
|
|
win_infoheader.biWidth = f.Get32();
|
|
win_infoheader.biHeight = f.Get32();
|
|
win_infoheader.biPlanes = f.Get16();
|
|
win_infoheader.biBitCount = f.Get16();
|
|
win_infoheader.biCompression = f.Get32();
|
|
win_infoheader.biSizeImage = f.Get32();
|
|
win_infoheader.biXPelsPerMeter = f.Get32();
|
|
win_infoheader.biYPelsPerMeter = f.Get32();
|
|
win_infoheader.biClrUsed = f.Get32();
|
|
win_infoheader.biClrImportant = f.Get32();
|
|
|
|
infoheader->biWidth = win_infoheader.biWidth;
|
|
infoheader->biHeight = win_infoheader.biHeight;
|
|
infoheader->biBitCount = win_infoheader.biBitCount;
|
|
infoheader->biCompression = win_infoheader.biCompression;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* read_os2_bminfoheader:
|
|
* Reads information from an OS/2 format BMP file header.
|
|
*/
|
|
static int read_os2_bminfoheader(Gifstream & f, BITMAPINFOHEADER *infoheader)
|
|
{
|
|
OS2BMPINFOHEADER os2_infoheader;
|
|
|
|
os2_infoheader.biWidth = f.Get16();
|
|
os2_infoheader.biHeight = f.Get32();
|
|
os2_infoheader.biPlanes = f.Get32();
|
|
os2_infoheader.biBitCount = f.Get32();
|
|
|
|
infoheader->biWidth = os2_infoheader.biWidth;
|
|
infoheader->biHeight = os2_infoheader.biHeight;
|
|
infoheader->biBitCount = os2_infoheader.biBitCount;
|
|
infoheader->biCompression = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* read_bmicolors:
|
|
* Loads the color pallete for 1,4,8 bit formats.
|
|
*/
|
|
static void read_bmicolors(int ncols, RGB *pal, Gifstream & f,int win_flag)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<ncols; i++)
|
|
{
|
|
pal[i].b = f.get();
|
|
pal[i].g = f.get();
|
|
pal[i].r = f.get();
|
|
|
|
if (win_flag)
|
|
f.get();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* read_1bit_line:
|
|
* Support function for reading the 1 bit bitmap file format.
|
|
*/
|
|
static void read_1bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
|
|
{
|
|
unsigned char b[32];
|
|
unsigned long n;
|
|
|
|
int i, j, k;
|
|
int pix;
|
|
|
|
for (i=0; i<length; i++)
|
|
{
|
|
j = i % 32;
|
|
if (j == 0)
|
|
{
|
|
n = f.Get32();
|
|
|
|
for (k=0; k<32; k++)
|
|
{
|
|
b[31-k] = n & 1;
|
|
n = n >> 1;
|
|
}
|
|
}
|
|
|
|
pix = b[j];
|
|
bmp->line(line,i,pix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* read_4bit_line:
|
|
* Support function for reading the 4 bit bitmap file format.
|
|
*/
|
|
static void read_4bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
|
|
{
|
|
unsigned char b[8];
|
|
unsigned long n;
|
|
int i, j, k;
|
|
int temp;
|
|
int pix;
|
|
|
|
for (i=0; i<length; i++)
|
|
{
|
|
j = i % 8;
|
|
if (j == 0)
|
|
{
|
|
n = f.Get32();
|
|
|
|
for (k=0; k<4; k++)
|
|
{
|
|
temp = n & 255;
|
|
b[k*2+1] = temp & 15;
|
|
temp = temp >> 4;
|
|
b[k*2] = temp & 15;
|
|
n = n >> 8;
|
|
}
|
|
}
|
|
|
|
pix = b[j];
|
|
bmp->line(line,i,pix);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* read_8bit_line:
|
|
* Support function for reading the 8 bit bitmap file format.
|
|
*/
|
|
static void read_8bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
|
|
{
|
|
unsigned char b[4];
|
|
unsigned long n;
|
|
int i, j, k;
|
|
int pix;
|
|
|
|
for (i=0; i<length; i++)
|
|
{
|
|
j = i % 4;
|
|
if (j == 0)
|
|
{
|
|
n = f.Get32();
|
|
for (k=0; k<4; k++)
|
|
{
|
|
b[k] = n & 255;
|
|
n = n >> 8;
|
|
}
|
|
}
|
|
pix = b[j];
|
|
bmp->line(line,i,pix);
|
|
}
|
|
}
|
|
|
|
|
|
/* read_24bit_line:
|
|
* Support function for reading the 24 bit bitmap file format, doing
|
|
* our best to convert it down to a 256 color pallete.
|
|
*/
|
|
static void read_24bit_line(int length, Gifstream & f, BITMAP *bmp, int line)
|
|
{
|
|
#if 0
|
|
int i, nbytes;
|
|
RGB c;
|
|
|
|
nbytes=0;
|
|
|
|
for (i=0; i<length; i++) {
|
|
c.b = f.get();
|
|
c.g = f.get();
|
|
c.r = f.get();
|
|
bmp->line[line][i*3+_rgb_r_shift_24/8] = c.r;
|
|
bmp->line[line][i*3+_rgb_g_shift_24/8] = c.g;
|
|
bmp->line[line][i*3+_rgb_b_shift_24/8] = c.b;
|
|
nbytes += 3;
|
|
}
|
|
|
|
nbytes = nbytes % 4;
|
|
if (nbytes != 0)
|
|
for (i=nbytes; i<4; i++)
|
|
f.get();;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/* read_image:
|
|
* For reading the noncompressed BMP image format.
|
|
*/
|
|
static void read_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
|
|
{
|
|
int i, line;
|
|
|
|
for (i=0; i<(int)infoheader->biHeight; i++) {
|
|
line = i;
|
|
|
|
switch (infoheader->biBitCount) {
|
|
|
|
case 1:
|
|
read_1bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
|
|
break;
|
|
|
|
case 4:
|
|
read_4bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
|
|
break;
|
|
|
|
case 8:
|
|
read_8bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
|
|
break;
|
|
|
|
case 24:
|
|
read_24bit_line(infoheader->biWidth, f, bmp, infoheader->biHeight-i-1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* read_RLE8_compressed_image:
|
|
* For reading the 8 bit RLE compressed BMP image format.
|
|
*/
|
|
static void read_RLE8_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
|
|
{
|
|
unsigned char count, val, val0;
|
|
int j, pos, line;
|
|
int eolflag, eopicflag;
|
|
|
|
eopicflag = 0;
|
|
line = infoheader->biHeight - 1;
|
|
|
|
while (eopicflag == 0) {
|
|
pos = 0; /* x position in bitmap */
|
|
eolflag = 0; /* end of line flag */
|
|
|
|
while ((eolflag == 0) && (eopicflag == 0)) {
|
|
count = f.get();
|
|
val = f.get();
|
|
|
|
if (count > 0) { /* repeat pixel count times */
|
|
for (j=0;j<count;j++) {
|
|
bmp->line(line,pos,val);
|
|
pos++;
|
|
}
|
|
}
|
|
else {
|
|
switch (val) {
|
|
|
|
case 0: /* end of line flag */
|
|
eolflag=1;
|
|
break;
|
|
|
|
case 1: /* end of picture flag */
|
|
eopicflag=1;
|
|
break;
|
|
|
|
case 2: /* displace picture */
|
|
count = f.get();
|
|
val = f.get();
|
|
pos += count;
|
|
line -= val;
|
|
break;
|
|
|
|
default: /* read in absolute mode */
|
|
for (j=0; j<val; j++) {
|
|
val0 = f.get();
|
|
bmp->line(line,pos,val0);
|
|
pos++;
|
|
}
|
|
|
|
if (j%2 == 1)
|
|
val0 = f.get(); /* align on word boundary */
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (pos > (int)infoheader->biWidth)
|
|
eolflag=1;
|
|
}
|
|
|
|
line--;
|
|
if (line < 0)
|
|
eopicflag = 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* read_RLE4_compressed_image:
|
|
* For reading the 4 bit RLE compressed BMP image format.
|
|
*/
|
|
static void read_RLE4_compressed_image(Gifstream & f, BITMAP *bmp, BITMAPINFOHEADER *infoheader)
|
|
{
|
|
unsigned char b[8];
|
|
unsigned char count;
|
|
unsigned short val0, val;
|
|
int j, k, pos, line;
|
|
int eolflag, eopicflag;
|
|
|
|
eopicflag = 0; /* end of picture flag */
|
|
line = infoheader->biHeight - 1;
|
|
|
|
while (eopicflag == 0) {
|
|
pos = 0;
|
|
eolflag = 0; /* end of line flag */
|
|
|
|
while ((eolflag == 0) && (eopicflag == 0)) {
|
|
count = f.get();
|
|
val = f.get();
|
|
|
|
if (count > 0) { /* repeat pixels count times */
|
|
b[1] = val & 15;
|
|
b[0] = (val >> 4) & 15;
|
|
for (j=0; j<count; j++) {
|
|
bmp->line(line,pos,b[j%2]);
|
|
pos++;
|
|
}
|
|
}
|
|
else {
|
|
switch (val) {
|
|
|
|
case 0: /* end of line */
|
|
eolflag=1;
|
|
break;
|
|
|
|
case 1: /* end of picture */
|
|
eopicflag=1;
|
|
break;
|
|
|
|
case 2: /* displace image */
|
|
count = f.get();
|
|
val = f.get();
|
|
pos += count;
|
|
line -= val;
|
|
break;
|
|
|
|
default: /* read in absolute mode */
|
|
for (j=0; j<val; j++) {
|
|
if ((j%4) == 0) {
|
|
val0 = f.Get16();
|
|
for (k=0; k<2; k++) {
|
|
b[2*k+1] = val0 & 15;
|
|
val0 = val0 >> 4;
|
|
b[2*k] = val0 & 15;
|
|
val0 = val0 >> 4;
|
|
}
|
|
}
|
|
bmp->line(line,pos,b[j%4]);
|
|
pos++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pos > (int)infoheader->biWidth)
|
|
eolflag=1;
|
|
}
|
|
|
|
line--;
|
|
if (line < 0)
|
|
eopicflag = 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* load_bmp:
|
|
* Loads a Windows BMP file, returning a bitmap structure and storing
|
|
* the pallete data in the specified pallete (this should be an array of
|
|
* at least 256 RGB structures).
|
|
*
|
|
* Thanks to Seymour Shlien for contributing this function.
|
|
*/
|
|
|
|
static void load_bmp(Frame & frm,char const *filename)
|
|
{
|
|
BITMAPFILEHEADER fileheader;
|
|
BITMAPINFOHEADER infoheader;
|
|
|
|
RGB pal[256];
|
|
BITMAP bmp;
|
|
|
|
Gifstream f(Gifstream::LITTLE_ENDIAN);
|
|
|
|
int ncol;
|
|
unsigned long biSize;
|
|
|
|
f.open(filename,ios::in|ios::binary);
|
|
|
|
if (!f)
|
|
GObject::Error(ERR_FATAL,"couldn't open file %s",filename);
|
|
|
|
if (read_bmfileheader(f, &fileheader) != 0)
|
|
{
|
|
GObject::Error(ERR_FATAL,"error reading bmp hdr for %s",filename);
|
|
}
|
|
|
|
biSize = f.Get32();
|
|
|
|
if (biSize == WININFOHEADERSIZE)
|
|
{
|
|
if (read_win_bminfoheader(f, &infoheader) != 0)
|
|
GObject::Error(ERR_FATAL,"error reading windows bmp info hdr for %s",filename);
|
|
|
|
/* compute number of colors recorded */
|
|
ncol = (fileheader.bfOffBits - 54) / 4;
|
|
read_bmicolors(ncol, pal, f, 1);
|
|
}
|
|
else if (biSize == OS2INFOHEADERSIZE)
|
|
{
|
|
if (read_os2_bminfoheader(f, &infoheader) != 0)
|
|
GObject::Error(ERR_FATAL,"error reading os2 bmp info hdr for %s",filename);
|
|
|
|
/* compute number of colors recorded */
|
|
ncol = (fileheader.bfOffBits - 26) / 3;
|
|
read_bmicolors(ncol, pal, f, 0);
|
|
}
|
|
else
|
|
{
|
|
GObject::Error(ERR_FATAL,"error finding correct hdr for bmp %s",filename);
|
|
}
|
|
|
|
if (infoheader.biBitCount != 4 && infoheader.biBitCount != 8)
|
|
GObject::Error(ERR_FATAL,"only handles 4 && 8 bit bmps not %d : %s",infoheader.biBitCount,filename);
|
|
|
|
|
|
bmp.setSize(infoheader.biWidth, infoheader.biHeight);
|
|
|
|
bmp.clear();
|
|
|
|
switch (infoheader.biCompression)
|
|
{
|
|
|
|
case BI_RGB:
|
|
read_image(f, &bmp, &infoheader);
|
|
break;
|
|
|
|
case BI_RLE8:
|
|
read_RLE8_compressed_image(f, &bmp, &infoheader);
|
|
break;
|
|
|
|
case BI_RLE4:
|
|
read_RLE4_compressed_image(f, &bmp, &infoheader);
|
|
break;
|
|
|
|
default:
|
|
GObject::Error(ERR_FATAL,"unknown compression foramt for %s",filename);
|
|
break;
|
|
}
|
|
|
|
f.close();
|
|
|
|
|
|
{
|
|
Palette palObj;
|
|
|
|
|
|
|
|
for (int f=0;f<ncol;f++)
|
|
{
|
|
Colour & col = palObj[f];
|
|
col.SetRGB(pal[f].r,pal[f].g,pal[f].b);
|
|
}
|
|
|
|
frm.SetFrame(bmp.getBitMap(),infoheader.biWidth,infoheader.biHeight,palObj);
|
|
}
|
|
|
|
}
|
|
|
|
/*===========================================================================
|
|
end */
|
|
|
|
|