#include <string.h>
#include <stdio.h>
#include <iostream>
#include "objgfx30.h"
#include "ogBlit.h"
using namespace std;
static bool
fileExists(const char *file)
{
FILE *f = fopen(file, "r");
if (!f)
return false;
fclose(f);
return true;
}
ogBlit::ogBlit(void) {
blitMask = NULL;
blitMaskSize = 0;
totalPixCount = 0;
startX = 0;
startY = 0;
endX = 0;
endY = 0;
return;
} // ogBlit::ogBlit
void
ogBlit::blitSize(ogSurface& SrcObject, int32 x1, int32 y1, int32 x2, int32 y2) {
int32 x,y;
uInt8 zerocount;
uInt8 pixcount;
uInt32 bm;
bool inZeros;
bool found;
// first free the image data or the blitMask data if we already have some
free(image);
delete [] blitMask;
image = NULL;
blitMask = NULL;
imageSize = 0;
blitMaskSize = 0;
bm = (bitDepth+7) >> 3;
tColour = SrcObject.ogGetTransparentColor();
startX = x1;
startY = y1;
endX = x2;
endY = y2;
// start by locating the left-most non-transparent pixel in the region defined
// by (x1,y1) to (x2,y2)
found = false;
while ((!found) && (startX<=x2)) {
for (y=y1; y<=y2; y++)
found |= (SrcObject.ogGetPixel(startX,y)!=tColour);
if (!found) startX++;
} // while
// now we look for the top-most non-transparent pixel in the regsion defined by
// (StartX,y1) to (x2,y2)
found = false;
while ((!found) && (startY<=y2)) {
for (x=startX; x<=x2; x++)
found |= (SrcObject.ogGetPixel(x,startY)!=tColour);
if (!found) startY++;
} // while
found = false;
while ((!found) && (endX>=startX)) {
for (y=startY; y<=y2; y++)
found |= (SrcObject.ogGetPixel(endX,y)!=tColour);
if (!found) endX--;
} // while
found = false;
while ((!found) && (endY>=startY)) {
for (x=startX; x<=endX; x++)
found |= (SrcObject.ogGetPixel(x,endY)!=tColour);
if (!found) endY--;
} // while
for (y = startY; y <= endY; y++) {
zerocount = 0;
blitMaskSize++; // save room for xlcount
x = startX;
inZeros = (SrcObject.ogGetPixel(x,y)==tColour);
while (x<=endX) {
switch (inZeros) {
case true:
zerocount = 0; // How many zeros?
while ((x<=endX) && (SrcObject.ogGetPixel(x,y)==tColour)) {
x++;
if (zerocount == 255) {
zerocount = 0;
blitMaskSize += 2;
} else zerocount++;
} // while
inZeros = false;
break; // case true
case false:
pixcount = 0;
blitMaskSize += 2;
do {
x++;
if (pixcount == 255) {
blitMaskSize += 2;
pixcount = 0;
} else pixcount++;
totalPixCount++;
imageSize += bm;
} while ((x<=endX) && (SrcObject.ogGetPixel(x,y)!=tColour));
inZeros = true;
break; // case false
} // switch
} // while
} // for
startX -= x1;
startY -= y1;
endX -= x1;
endY -= y1;
blitMask = new uInt8[blitMaskSize]; //(uInt8 *)malloc(blitMaskSize);
// memset(blitMask,0,blitMaskSize);
return;
} // ogBlit::blitSize
void
ogBlit::getBlitMask(ogSurface& SrcObject, int32 x1, int32 y1) {
uInt8 * blitMaskPtr;
uInt8 * lineCountPtr;
uInt32 bm;
int32 x,y;
bool inZeros;
uInt8 pixCount, zeroCount;
if (blitMask==NULL) return;
blitMaskPtr = blitMask;
bm = (bitDepth+7) >> 3;
// This is done elsewhere tColour = SrcObject.ogGetTransparentColor();
for (y = y1+startY; y <= y1+endY; y++) {
zeroCount = 0;
lineCountPtr = blitMaskPtr;
*lineCountPtr = 0;
blitMaskPtr++;
x = x1+startX;
inZeros = (SrcObject.ogGetPixel(x,y)==tColour);
while (x<=x1+endX) {
switch (inZeros) {
case true:
zeroCount = 0;
while ((x<=x1+endX) && (SrcObject.ogGetPixel(x,y)==tColour)) {
x++;
if (zeroCount == 255) {
(*lineCountPtr)++;
*blitMaskPtr = 255; // offset
blitMaskPtr++; // increment to next byte
*blitMaskPtr = 0; // runcount
blitMaskPtr++; // increment to next byte
*blitMaskPtr = 0; // offset
zeroCount = 0;
} else zeroCount++;
} // while
inZeros = false; // we are no longer in zeros}
break; // case true
case false:
(*lineCountPtr)++;
*blitMaskPtr = zeroCount;
blitMaskPtr++;
*blitMaskPtr = 0;
pixCount = 0;
do {
x++;
if (pixCount == 255) {
(*lineCountPtr)++;
*blitMaskPtr = 255; // runcount
blitMaskPtr++; // advance pointer
*blitMaskPtr = 0; // offset to next run
blitMaskPtr++; // advance pointer
*blitMaskPtr = 0; // next run count (incremented below)
pixCount = 0;
} else pixCount++;
(*blitMaskPtr)++;
} while ((x<=(x1+endX)) &&
(SrcObject.ogGetPixel(x,y)!=tColour));
blitMaskPtr++;
inZeros = true; // set inZeros to true to toggle
break; // case false
} // switch
} // while
} // for
return;
} // ogBlit::getBlitMask
void
ogBlit::get(ogSurface& SrcObject, int32 x1, int32 y1, int32 x2, int32 y2) {
int32 tmp;
ogPixelFmt pixfmt;
if (x1 > x2) {
tmp = x1;
x1 = x2;
x2 = tmp;
} // if
if (y1 > y2) {
tmp = y1;
y1 = y2;
y2 = tmp;
} // if
width = (x2-x1)+1;
height = (y2-y1)+1;
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];
for (tmp=0; tmp<256; tmp++)
SrcObject.ogUnpackRGB(tmp,pal[tmp].red, pal[tmp].green, pal[tmp].blue);
// memcpy(pal, SrcObject.pal, sizeof(ogRGBA)*256);
} // if
blitSize(SrcObject, x1, y1, x2, y2);
getBlitMask(SrcObject, x1, y1);
getBlitWithMask(SrcObject, x1, y1);
return;
} // ogBlit::get()
void
ogBlit::getBlitWithMask(ogSurface& SrcObject, int32 x, int32 y) {
/*
* getBlitWithMask
*
* Retrieves the data portion of a blit using a predefined mask and
* stores the data in the Image pointer. If the source buffer is
* a different pixel format, we will adjust the image pointer
* to accommodate the new data and update the pixel format. The put()
* function will adjust the pixels to the dest buffer as needed.
* Before calling this routine, you must call getBlitMask.
*/
int32 sx, sy;
uInt8 lineCount, offset, pixCount;
uInt32 nsy, ney; // new start y, new end y
uInt8 * blitMaskPtr;
void * imagePtr;
uInt32 distToEdge, bm, xRight, count;
ogPixelFmt pixfmt;
// can we draw anything?
if (blitMask==NULL) return;
// see if the blit is outside the buffer
if ( (x+startX > (int32)SrcObject.ogGetMaxX()) || (x+endX<0) ||
(y+startY > (int32)SrcObject.ogGetMaxY()) || (y+endY<0)) return;
blitMaskPtr = blitMask;
// first check to see if the pixel format we get the blitmask from is
// different than what we're dealing with now.
SrcObject.ogGetPixFmt(pixfmt);
if ( (bitDepth!=pixfmt.BPP) ||
(RFP!=pixfmt.redFieldPosition) ||
(GFP!=pixfmt.greenFieldPosition) ||
(BFP!=pixfmt.blueFieldPosition) ) {
if (image!=NULL) free(image);
image = NULL;
imageSize = 0;
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
bm = (bitDepth+7) >> 3; // bit multiplier
if (image==NULL) {
imageSize = totalPixCount*bm;
image = malloc(imageSize);
} // if
imagePtr = image;
// If any part of the blit data is out of bounds, we need to fill it with the
// transparent colour
if ((x+startX<0) || (x+endX>(int32)SrcObject.ogGetMaxX()) ||
(y+startY<0) || (y+endY>(int32)SrcObject.ogGetMaxY())) {
for (count=0; count<totalPixCount; count++) {
setPixel(imagePtr,tColour);
(uInt8 *)imagePtr+=bm;
} // for
imagePtr = image; // reset the image ptr
} // if
// first do clipping on the top edge
nsy = startY;
if (y+startY<0) {
/*
* If we're here then part of the blit is above the top edge of the
* buffer. The distance to the top of the buffer is abs(y+startY).
* So, we need to loop through the blit geometry and advance the
* relative pointers (BlitMaskPtr and ImagePtr)
*/
for (sy = (y+startY); sy<0; sy++) {
nsy++;
lineCount = *blitMaskPtr;
blitMaskPtr++;
while (lineCount>0) {
blitMaskPtr++;
pixCount = *blitMaskPtr;
blitMaskPtr++;
if (pixCount>0) (uInt8 *)imagePtr+=pixCount*bm;
lineCount--;
} // while
} // for sy
} // if
// Now do clipping on the bottom edge. This is easy.
if (y+endY>(int32)SrcObject.ogGetMaxY())
ney = (SrcObject.ogGetMaxY()-y);
else
ney = endY;
for (sy = nsy; (uInt32)sy <= ney; sy++) {
sx = x+startX;
lineCount = *blitMaskPtr;
blitMaskPtr++;
while (lineCount>0) {
offset = *blitMaskPtr;
blitMaskPtr++;
sx += offset;
pixCount = *blitMaskPtr;
blitMaskPtr++;
if (pixCount>0) {
if (sx<=(int32)SrcObject.ogGetMaxX()) {
if ((sx<0) && (sx+pixCount>0)) {
pixCount += sx; // remember, sx is negative
(uInt8*)imagePtr -= sx*bm; // remember, sx is negative
sx=0;
} // if sx<0 && sx+pixcount>0
if (sx+pixCount>(int32)SrcObject.ogGetMaxX()+1) {
distToEdge = (SrcObject.ogGetMaxX()-sx)+1;
xRight = (pixCount - distToEdge)*bm;
pixCount = distToEdge;
} else xRight = 0; // if sx+pixCount>MaxX
if (sx>=0)
SrcObject.ogCopyLineFrom(sx,y+sy,imagePtr,pixCount*bm);
// memcpy(imagePtr, // dest
// ((uInt8*)SrcObject.Buffer+SrcObject.LineOfs[y+sy]+sx*bm),
// pixCount*bm);
(uInt8*)imagePtr += xRight;
} // if sx <= MaxX
sx += pixCount;
(uInt8*)imagePtr += pixCount*bm;
} // if pixCount>0
lineCount--;
} // while
} // for
return;
} // ogBlit::getBlitWithMask
uInt32
ogBlit::getSize(void) {
return ogSprite::getSize() +
sizeof(totalPixCount) +
sizeof(blitMaskSize) +
blitMaskSize +
sizeof(startX) +
sizeof(startY) +
sizeof(endX) +
sizeof(endY);
} // ogBlit::getSize
bool
ogBlit::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);
delete [] pal;
delete [] blitMask;
imageSize = 0;
blitMaskSize = 0;
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]!='B') ||
(header_ident[1]!='L') ||
(header_ident[2]!='T') ||
(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(&tColour, sizeof(tColour), 1, infile);
tresult += lresult*sizeof(tColour);
lresult = fread(&totalPixCount, sizeof(totalPixCount), 1, infile);
tresult += lresult*sizeof(totalPixCount);
lresult = fread(&startX, sizeof(startX), 1, infile);
tresult += lresult*sizeof(startX);
lresult = fread(&startY, sizeof(startY), 1, infile);
tresult += lresult*sizeof(startY);
lresult = fread(&endX, sizeof(endX), 1, infile);
tresult += lresult*sizeof(endX);
lresult = fread(&endY, sizeof(endY), 1, infile);
tresult += lresult*sizeof(endY);
lresult = fread(&blitMaskSize, sizeof(blitMaskSize), 1, infile);
tresult += lresult*sizeof(blitMaskSize);
lresult = fread(&imageSize, sizeof(imageSize), 1, infile);
tresult += lresult*sizeof(imageSize);
blitMask = new uInt8[blitMaskSize];
if (blitMask == NULL) {
fclose(infile);
return false;
}
image = malloc(imageSize);
if (image == NULL) {
fclose(infile);
return false;
}
// read in the blit mask
lresult = fread(blitMask, blitMaskSize, 1, infile);
tresult += lresult*blitMaskSize;
// read in the image data
// it's possible that if we start saving only blit masks this section will be
// blank
lresult = fread(image, 1, imageSize, infile);
tresult += lresult;
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);
} // ogBlit::loadFrom
void
ogBlit::put(ogSurface& DestObject, int32 x, int32 y) {
int32 sx, sy;
uInt32 nsy, ney;
uInt8 lineCount, offset, pixCount;
uInt8* blitMaskPtr;
void * imagePtr;
uInt32 distToEdge, bm, xRight, xx;
uInt8 r, g, b;
ogPixelFmt pixfmt;
// can we draw anything?
if ((blitMask==NULL) || (image==NULL)) return;
if (DestObject.ogAvail()==false) return;
// see if the blit is oustide the buffer
if ( ((x+startX)>(int32)DestObject.ogGetMaxX()) ||
((y+startY)>(int32)DestObject.ogGetMaxY()) ||
((x+endX)<0) || ((y+endY)<0) ) return;
blitMaskPtr = blitMask;
imagePtr = image;
bm = (bitDepth+7) >> 3;
// first do clipping on the top edge
nsy = startY;
if (y+startY<0) {
/*
* If we're here then part of the blit is above the top edge of the
* buffer. The distance to the top of the buffer is abs(y+startY).
* So, we need to loop through the blit geometry and advance the
* relative pointers (BlitMaskPtr and ImagePtr)
*/
for (sy = (y+startY); sy<0; sy++) {
nsy++;
lineCount = *blitMaskPtr;
blitMaskPtr++;
while (lineCount>0) {
blitMaskPtr++;
pixCount = *blitMaskPtr;
blitMaskPtr++;
if (pixCount>0) (uInt8 *)imagePtr+=pixCount*bm;
lineCount--;
} // while
} // for sy
} // if
// Now do clipping on the bottom edge. This is easy
// y is guaranteed to be >=0
if (y+endY>(int32)DestObject.ogGetMaxY())
ney = (DestObject.ogGetMaxY()-y);
else
ney = endY;
DestObject.ogGetPixFmt(pixfmt);
if ( (pixfmt.BPP != bitDepth) ||
(pixfmt.redFieldPosition != RFP) ||
(pixfmt.greenFieldPosition != GFP) ||
(pixfmt.blueFieldPosition != BFP)) {
for (sy = nsy; (uInt32)sy <= ney; sy++) {
sx = x+startX;
lineCount = *blitMaskPtr;
blitMaskPtr++;
while (lineCount>0) {
offset = *blitMaskPtr;
blitMaskPtr++;
sx += offset;
pixCount = *blitMaskPtr;
blitMaskPtr++;
if (pixCount>0) {
if (sx<=(int32)DestObject.ogGetMaxX()) {
if ((sx<0) && (sx+(int32)pixCount>0)) {
pixCount += sx; // remember, sx is negative
(uInt8*)imagePtr -= sx*bm; // remember, sx is negative
sx = 0;
} // if sx<0 && sx+pixCount>0
if (sx+pixCount>(int32)DestObject.ogGetMaxX()) {
distToEdge = (DestObject.ogGetMaxX()-sx)+1;
xRight = (pixCount-distToEdge)*bm;
pixCount = distToEdge;
} else xRight = 0; // if sx+pixCount>MaxX
if (sx>=0)
for (xx=0; xx<pixCount; xx++) {
unpackRGB(getPixel((uInt8*)imagePtr+(xx*bm)),r,g,b);
DestObject.ogSetPixel(sx+xx,sy+y,DestObject.ogRGB(r,g,b));
} // for
(uInt8*)imagePtr+=xRight;
} // if sx <= MaxX
sx += pixCount;
(uInt8*)imagePtr += pixCount*bm;
} // if pixCount != 0
lineCount--;
} // while
} // for
} else {
for (sy = nsy; (uInt32)sy <= ney; sy++) {
sx = x+startX;
lineCount = *blitMaskPtr;
blitMaskPtr++;
while (lineCount>0) {
offset = *blitMaskPtr;
blitMaskPtr++;
sx += offset;
pixCount = *blitMaskPtr;
blitMaskPtr++;
if (pixCount>0) {
if (sx<=(int32)DestObject.ogGetMaxX()) {
if ((sx<0) && (sx+pixCount>0)) {
pixCount += sx; // remember, sx is negative
(uInt8*)imagePtr -= sx*bm; // remember, sx is negative
sx = 0;
} // if sx<0 && sx+pixCount>0
if (sx+pixCount>(int32)DestObject.ogGetMaxX()+1) {
distToEdge = (DestObject.ogGetMaxX()-sx)+1;
xRight = (pixCount - distToEdge)*bm;
pixCount = distToEdge;
} else xRight = 0; // if sx+pixCount>MaxX
if (sx>=0)
DestObject.ogCopyLineTo(sx,y+sy,imagePtr,pixCount*bm);
// memcpy( ((uInt8*)DestObject.Buffer+DestObject.LineOfs[y+sy]+sx*bm),
// imagePtr,
// pixCount*bm);
(uInt8*)imagePtr += xRight;
} // if sx <= MaxX
sx += pixCount;
(uInt8*)imagePtr += pixCount*bm;
} // if pixCount>0
lineCount--;
} // while
} // for
} // else
return;
} // ogBlit::put
bool
ogBlit::saveTo(const char * filename, int32 offset) {
/*
* saveTo
*
* saves a blit 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
tmpSize = getSize();
header_ident[0] = 'B';
header_ident[1] = 'L';
header_ident[2] = 'T';
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
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(&tColour, sizeof(tColour), 1, outfile);
fwrite(&totalPixCount, sizeof(totalPixCount), 1, outfile);
fwrite(&startX, sizeof(startX), 1, outfile);
fwrite(&startY, sizeof(startY), 1, outfile);
fwrite(&endX, sizeof(endX), 1, outfile);
fwrite(&endY, sizeof(endY), 1, outfile);
fwrite(&blitMaskSize, sizeof(blitMaskSize), 1, outfile);
fwrite(&imageSize, sizeof(imageSize), 1, outfile);
fwrite(blitMask, blitMaskSize, 1, outfile);
fwrite(image, 1, imageSize, 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;
} // ogBlit::saveTo
ogBlit::~ogBlit(void) {
delete [] blitMask;
blitMask = NULL;
blitMaskSize = 0;
return;
} // ogBlit::~ogBlit