#include <string.h>
#include <stdio.h>
#include "objgfx30.h"
#include "ogSprite.h"
static bool
fileExists(const char *file)
{
FILE *f = fopen(file, "r");
if (!f)
return false;
fclose(f);
return true;
}
ogSprite::ogSprite(void) {
image = NULL;
pal = NULL;
imageSize = 0;
width = 0;
height = 0;
bitDepth = 0;
RFP = 0;
GFP = 0;
BFP = 0;
AFP = 0;
RShift = 0;
GShift = 0;
BShift = 0;
AShift = 0;
tColour = 0;
return;
} // ogSprite
void
ogSprite::get(ogSurface& SrcObject, int32 x1, int32 y1, int32 x2, int32 y2) {
ogPixelFmt pixfmt;
uInt32 xx,yy,xOfs,yOfs;
uInt32 rx1, ry1, rx2, ry2;
uInt32 xCount, yCount, count;
void *p;
uInt32 bm; // bit multiplier
uInt32 MaxX, MaxY;
if (SrcObject.ogAvail()==false) return;
free(image);
free(pal);
MaxX = SrcObject.ogGetMaxX();
MaxY = SrcObject.ogGetMaxY();
tColour = SrcObject.ogGetTransparentColor();
SrcObject.ogGetPixFmt(pixfmt);
bitDepth = pixfmt.BPP;
RFP = pixfmt.redFieldPosition;
GFP = pixfmt.greenFieldPosition;
BFP = pixfmt.blueFieldPosition;
AFP = pixfmt.alphaFieldPosition;
RShift = 8-pixfmt.redMaskSize;
GShift = 8-pixfmt.greenMaskSize;
BShift = 8-pixfmt.blueMaskSize;
AShift = 8-pixfmt.alphaMaskSize;
if (bitDepth==8) {
if (pal==NULL) pal = new ogRGBA[256];
if (pal==NULL) return;
for (count=0; count<256; count++)
SrcObject.ogUnpackRGB(count,pal[count].red, pal[count].green, pal[count].blue);
// memcpy(pal, SrcObject.pal, sizeof(ogRGBA)*256);
} // if
bm = ((bitDepth+7) >> 3);
if (x1>x2) {
xx = x1;
x1 = x2;
x2 = xx;
} // if
if (y1>y2) {
yy = y1;
y1 = y2;
y2 = yy;
} // if
xCount = abs(x2-x1)+1;
yCount = abs(y2-y1)+1;
width = xCount;
height = yCount;
imageSize = xCount*yCount*bm;
image = malloc(imageSize);
p = image;
if ( ((uInt32)x1>MaxX) || ((uInt32)y1>MaxY) ||
((uInt32)x2>MaxX) || ((uInt32)y2>MaxY) ) {
for (count=0; count<xCount*yCount; count++) {
setPixel(p,tColour);
(uInt8 *)p+=bm;
} // for
p = image; // reset the pointer;
} // if
xOfs = 0;
yOfs = 0;
if (y1<0) {
yCount += y1;
ry1 = 0;
yOfs = xCount*abs(y1);
} else ry1 = y1;
if (x1<0) {
xCount += x1;
rx1 = 0;
xOfs = abs(x1);
} else rx1 = x1;
if (x2>(int32)MaxX) {
xCount -= MaxX-x2+1;
rx2 = MaxX;
} else rx2 = x2;
if (y2>(int32)MaxY) {
yCount -= MaxY-y2+1;
ry2=MaxY;
} else ry2 = y2;
xCount *= bm;
// rx1 *= bm;
for (yy=0; yy<yCount; yy++) {
( (uInt8 *)p ) += xOfs;
SrcObject.ogCopyLineFrom(rx1,ry1+yy,p,xCount);
// memcpy(p,((uInt8 *)SrcObject.Buffer+SrcObject.LineOfs[ry1+yy]+rx1),xCount);
( (uInt8 *)p ) += xCount;
}
return;
} // ogSprite::get
uInt32
ogSprite::getPixel(void * p) {
uInt32 result;
switch (bitDepth) {
case 8:
return *(uInt8 *)p;
break;
case 15:
case 16:
return *(uInt16 *)p;
break;
case 24:
asm(
" xor %%eax, %%eax \n" // xor eax, eax
" mov 2(%%edi),%%al \n" // mov al, [edi+2]
" shl $16, %%eax \n" // shl eax, 16
" mov (%%edi), %%ax \n" // mov ax, [edi]
" mov %%eax, %1 \n" // mov result, eax
:
: "D" (p), "m" (result)
);
return result;
break;
case 32:
return *(uInt32 *)p;
break;
default:
return 0;
break;
} // switch
} // ogSprite::getPixel
void
ogSprite::setPixel(void * p, uInt32 colour) {
switch (bitDepth) {
case 8:
*(uInt8 *)p=(uInt8)colour;
break;
case 15:
case 16:
*(uInt16 *)p=(uInt16)colour;
break;
case 24:
asm(
" mov %%ax, (%%edi) \n" // mov [edi], ax
" shr $16, %%eax \n" // shr eax, 16
" mov %%al, 2(%%edi)\n" // mov [edi+2],al
:
: "D" (p), "a" (colour)
);
break;
case 32:
*(uInt32 *)p=colour;
break;
} // switch
return;
} // ogSprite::setPixel
uInt32
ogSprite::getSize(void) {
/*
* getSize
*
* returns the size of the image as it would take on disk. This includes
* all header related information (width/height, bitdepth, pixel format,
* etc) along with an extra sizeof(uInt32)
* for storing the complete size. This allows easy indexing of images,
* since you can figure out exactly how much the image will take up on
* disk. This function computes the size in the exact order it is on disk.
* If the image is 8bpp, then there is a 768 byte palette stored after the
* image data along with an extra sizeof(uInt32) for the palette size in
* bytes. Currently we store the entire palette, but later I expect we
* will add the ability to optimize the palette so only used entries are
* stored.
*
* If you were to store a single bitmap in a file, getSize would equal the
* filesize.
*/
uInt32 tmpsize;
char header_ident[4];
tmpsize = sizeof(header_ident)+
sizeof(uInt32)+ // total size
sizeof(width)+sizeof(height)+ // width/height
sizeof(bitDepth)+ // bitDepth
sizeof(RFP)+sizeof(GFP)+sizeof(BFP)+sizeof(AFP)+ // field positions
sizeof(RShift)+sizeof(GShift)+sizeof(BShift)+sizeof(AShift)+ // shifters
sizeof(tColour)+ // tColour
sizeof(imageSize)+ // image size in bytes
imageSize; // actual image area in bytes
if (bitDepth==8) tmpsize += sizeof(uInt32)+sizeof(ogRGBA)*256;
return tmpsize;
} // ogSprite::getSize
bool
ogSprite::load(const char * filename) {
return loadFrom(filename,0);
} // ogSprite::load
bool
ogSprite::loadFrom(const char * filename, uInt32 offset) {
FILE * infile;
uInt32 lresult, tresult, totSize;
uInt32 tmpSize;
char header_ident[4];
if (fileExists(filename)==false) return false;
if ((infile = fopen(filename,"rb"))==NULL) return false;
fseek(infile, offset, SEEK_SET);
// for now just free up the previous image. This will be changed
// later so it doesn't affect the current image (if any) if there
// is a failure loading
free(image);
free(pal);
image = NULL;
imageSize = 0;
pal = NULL;
tresult = 0; // total bytes we've read in so far
lresult = fread(&header_ident, sizeof(header_ident), 1, infile);
tresult += lresult*sizeof(header_ident);
if ((header_ident[0]!='S') ||
(header_ident[1]!='P') ||
(header_ident[2]!='R') ||
(header_ident[3]!=(char)0x1A)) {
fclose(infile);
return false;
}
lresult = fread(&totSize, sizeof(totSize), 1, infile);
tresult += lresult*sizeof(totSize);
lresult = fread(&width, sizeof(width), 1, infile);
tresult += lresult*sizeof(width);
lresult = fread(&height, sizeof(height), 1, infile);
tresult += lresult*sizeof(height);
lresult = fread(&bitDepth, sizeof(bitDepth), 1, infile);
tresult += lresult*sizeof(bitDepth);
lresult = fread(&RFP, sizeof(RFP), 1, infile);
tresult += lresult*sizeof(RFP);
lresult = fread(&GFP, sizeof(GFP), 1, infile);
tresult += lresult*sizeof(GFP);
lresult = fread(&BFP, sizeof(BFP), 1, infile);
tresult += lresult*sizeof(BFP);
lresult = fread(&AFP, sizeof(AFP), 1, infile);
tresult += lresult*sizeof(AFP);
lresult = fread(&RShift, sizeof(RShift), 1, infile);
tresult += lresult*sizeof(RShift);
lresult = fread(&GShift, sizeof(GShift), 1, infile);
tresult += lresult*sizeof(GShift);
lresult = fread(&BShift, sizeof(BShift), 1, infile);
tresult += lresult*sizeof(BShift);
lresult = fread(&AShift, sizeof(AShift), 1, infile);
tresult += lresult*sizeof(AShift);
lresult = fread(&imageSize, sizeof(imageSize), 1, infile);
tresult += lresult*sizeof(imageSize);
image = malloc(imageSize);
if (image== NULL) {
fclose(infile);
return false;
}
// I suppose we could interchange the imageSize and record count to produce
// the number of bytes we read it... we'll try it this way for now.
lresult = fread(image, imageSize, 1, infile);
tresult += lresult*imageSize;
if (bitDepth==8) {
// 8bpp sprites have palettes
if (pal==NULL) pal = new ogRGBA[256];
if (pal==NULL) {
fclose(infile);
return false;
} // if pal==NULL
lresult = fread(&tmpSize, sizeof(tmpSize), 1, infile);
tresult += lresult*sizeof(tmpSize);
if (tmpSize>sizeof(ogRGBA)*256) {
fclose(infile);
return false;
}
lresult = fread(pal, tmpSize, 1, infile);
tresult += lresult*tmpSize;
} // if bitDepth == 8
fclose(infile);
return (tresult == totSize);
} // ogSprite::loadFrom;
void
ogSprite::put(ogSurface& DestObject, int32 x, int32 y) {
uInt32 xx, yy, bm;
int32 xCount, yCount;
uInt32 yOfs;
uInt32 xLeft, xRight;
int32 MaxX, MaxY;
void * p;
uInt8 r,g,b;
ogPixelFmt pixfmt;
if (image==NULL) return;
if (DestObject.ogAvail()==false) return;
MaxX = DestObject.ogGetMaxX();
MaxY = DestObject.ogGetMaxY();
xCount = width;
yCount = height;
bm = (bitDepth+7) >> 3;
// check to see if the image is totally off the screen
if ((x+xCount<0) || (y+yCount<0) || (x>(int32)MaxX) || (y>(int32)MaxY)) return;
p = image;
if (y<0) {
yOfs = abs(y)*xCount*bm;
yCount+=y;
y=0;
} else yOfs=0;
if (x<0) {
xLeft = abs(x)*bm;
xCount += x;
x = 0;
} else xLeft = 0;
if (x+xCount > MaxX) {
xRight = (xCount - (MaxX-x+1))*bm;
xCount = (MaxX-x)+1;
} else xRight = 0;
if ((y+yCount)>MaxY) yCount = (MaxY-y)+1;
DestObject.ogGetPixFmt(pixfmt);
(uInt8 *)p += yOfs;
if ((pixfmt.BPP!=bitDepth) ||
(pixfmt.redFieldPosition!=RFP) ||
(pixfmt.greenFieldPosition!=GFP) ||
(pixfmt.blueFieldPosition!=BFP)) {
for (yy=0; yy<(uInt32)yCount; yy++) {
(uInt8 *)p += xLeft;
for (xx=0; xx<(uInt32)xCount; xx++) {
unpackRGB(getPixel(p),r,g,b);
(uInt8 *)p += bm;
DestObject.ogSetPixel(x+xx,y+yy,DestObject.ogRGB(r,g,b));
} // for
(uInt8 *)p += xRight;
} // for
} // if
else { // pixel formats match
xCount *= bm;
// x *= (pixfmt.BPP+7) >> 3;
for (yy=0; yy<(uInt32)yCount; yy++) {
(uInt8 *)p += xLeft;
DestObject.ogCopyLineTo(x,y+yy,p,xCount);
// memcpy((uInt8 *)DestObject.Buffer+DestObject.LineOfs[y+yy]+x,p,xCount);
(uInt8 *)p += xCount;
(uInt8 *)p += xRight;
} // for
} // else
return;
} // ogSurface::put
bool
ogSprite::save(const char * filename) {
return saveTo(filename,0);
} // ogSprite::save
bool
ogSprite::saveTo(const char * filename, int32 offset) {
/*
* saveTo
*
* saves a bitmap to disk. If the file doesn't exit then we will create
* a new one (doing this will ignore any specified offset). If the file
* exists, we will seek to the specified offset and place the bitmap there.
* If offset is -1, then we seek to the end of the file.
*
* This function will fail on files larger than 2GB.
*
*/
FILE * outfile = NULL;
char header_ident[4];
uInt32 tmpSize;
if (image==NULL) return false;
if ((bitDepth==8) && (pal==NULL)) return false;
if (fileExists(filename)==false) { // file doesn't exist
if ((outfile = fopen(filename,"wb")) == NULL) return false;
} else {
// file exists. Now we check to see where we put it
if (offset==-1) {
if ((outfile = fopen(filename, "ab")) == NULL) return false;
} else {
// we have an existing file and an offset to place the data
if ((outfile = fopen(filename, "wb")) == NULL) return false;
if (offset!=0) fseek(outfile, offset, SEEK_SET);
} // else
} // else
header_ident[0] = 'S';
header_ident[1] = 'P';
header_ident[2] = 'R';
header_ident[3] = (char)0x1A; // EOF marker
// we store exactly how bit this sucker is inside the header. This includes
// the header information before it, and the size itself
tmpSize = getSize();
fwrite(header_ident, sizeof(header_ident), 1, outfile);
fwrite(&tmpSize, sizeof(tmpSize), 1, outfile);
fwrite(&width, sizeof(width), 1, outfile);
fwrite(&height, sizeof(height), 1, outfile);
fwrite(&bitDepth, sizeof(bitDepth), 1, outfile);
fwrite(&RFP, sizeof(RFP), 1, outfile);
fwrite(&GFP, sizeof(GFP), 1, outfile);
fwrite(&BFP, sizeof(BFP), 1, outfile);
fwrite(&AFP, sizeof(AFP), 1, outfile);
fwrite(&RShift, sizeof(RShift), 1, outfile);
fwrite(&GShift, sizeof(GShift), 1, outfile);
fwrite(&BShift, sizeof(BShift), 1, outfile);
fwrite(&AShift, sizeof(AShift), 1, outfile);
fwrite(&imageSize, sizeof(imageSize), 1, outfile);
fwrite(image, imageSize, 1, outfile);
if (bitDepth == 8) {
tmpSize = sizeof(ogRGBA)*256;
fwrite(&tmpSize, sizeof(tmpSize), 1, outfile);
fwrite(pal, sizeof(ogRGBA), 256, outfile);
} // if bitDepth == 8
fclose(outfile);
return true;
} // ogSprite::saveTo
void
ogSprite::unpackRGB(uInt32 colour, uInt8& red, uInt8& green, uInt8& blue) {
switch (bitDepth) {
case 8:
if (colour>255) colour&=255;
if (pal==NULL) return;
red=pal[colour].red;
green=pal[colour].green;
blue=pal[colour].blue;
break;
case 15:
case 16:
red = (uInt8)(colour >> RFP) << RShift;
green = (uInt8)(colour >> GFP) << GShift;
blue = (uInt8)(colour >> BFP) << BShift;
if ((red!=0) && (RShift!=0)) red+=(1 << RShift)-1;
if ((green!=0) && (GShift!=0)) green+=(1 << GShift)-1;
if ((blue!=0) && (BShift!=0)) blue+=(1 << BShift)-1;
break;
case 24:
case 32:
red = (uInt8)(colour >> RFP);
green = (uInt8)(colour >> GFP);
blue = (uInt8)(colour >> BFP);
break;
default:
red = 0;
green = 0;
blue = 0;
break;
} // switch
return;
} // ogSprite::unpackRGB
ogSprite::~ogSprite(void) {
free(image);
delete [] pal;
image = NULL;
pal = NULL;
imageSize = 0;
width = 0;
height = 0;
bitDepth = 0;
RFP = 0;
GFP = 0;
BFP = 0;
AFP = 0;
RShift = 0;
GShift = 0;
BShift = 0;
AShift = 0;
tColour = 0;
return;
} // ogSprite::~ogSprite