#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