#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