extern "C" { #include <string.h> #include <stdio.h> #include <stdlib.h> } #include <objgfx40/objgfx40.h> #include <objgfx40/ogSprite.h> static bool fileExists(const char *file) { FILE *f = fopen(file, "rb"); if (!f) return false; fclose(f); return true; } ogSprite::ogSprite(const ogSprite& srcSprite) { 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; pixelFmtID = 0; bytesPerPixel = 0; dAlpha = 0; if ((srcSprite.image == NULL) || (srcSprite.imageSize == 0)) return; // allocate space for the sprite image = malloc(srcSprite.imageSize); if (image == NULL) return; // copy the image size imageSize = srcSprite.imageSize; if (srcSprite.pal != NULL) { pal = new ogRGBA8[256]; if (pal != NULL) memcpy(srcSprite.pal, pal, sizeof(ogRGBA8) * 256); } // if width = srcSprite.width; height = srcSprite.height; bitDepth = srcSprite.bitDepth; RFP = srcSprite.RFP; GFP = srcSprite.GFP; BFP = srcSprite.BFP; AFP = srcSprite.AFP; rShift = srcSprite.rShift; gShift = srcSprite.gShift; bShift = srcSprite.bShift; aShift = srcSprite.aShift; tColour = srcSprite.tColour; pixelFmtID = srcSprite.bytesPerPixel; dAlpha = srcSprite.dAlpha; return; } // ogSprite::ogSprite 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; pixelFmtID = 0; bytesPerPixel = 0; dAlpha = 0; return; } // ogSprite::ogSprite ogSprite & ogSprite::operator=(ogSprite const & srcSprite) { if ((srcSprite.image == NULL) || (srcSprite.imageSize == NULL)) return *this; free(image); delete [] pal; // allocate space for the sprite image = malloc(srcSprite.imageSize); // this is such a bad case it should probably throw an exception if (image == NULL) return *this; // copy the image size imageSize = srcSprite.imageSize; if (srcSprite.pal != NULL) { pal = new ogRGBA8[256]; if (pal != NULL) memcpy(srcSprite.pal, pal, sizeof(ogRGBA8) * 256); } // if width = srcSprite.width; height = srcSprite.height; bitDepth = srcSprite.bitDepth; RFP = srcSprite.RFP; GFP = srcSprite.GFP; BFP = srcSprite.BFP; AFP = srcSprite.AFP; rShift = srcSprite.rShift; gShift = srcSprite.gShift; bShift = srcSprite.bShift; aShift = srcSprite.aShift; tColour = srcSprite.tColour; pixelFmtID = srcSprite.bytesPerPixel; dAlpha = srcSprite.dAlpha; return *this; } 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 maxX, maxY; if (!srcObject.ogAvail()) return; free(image); free(pal); maxX = srcObject.ogGetMaxX(); maxY = srcObject.ogGetMaxY(); 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; pixelFmtID = srcObject.ogGetPixFmtID(); dAlpha = srcObject.ogGetAlpha(); tColour = srcObject.ogGetTransparentColor(); bytesPerPixel = srcObject.ogGetBytesPerPix(); if (bytesPerPixel == 1) { if (pal == NULL) pal = new ogRGBA8[256]; if (pal == NULL) return; srcObject.ogGetPalette(pal); /* for (count = 0; count < 256; count++) srcObject.Unpack(count, pal[count].red, pal[count].green, pal[count].blue, pal[count].alpha); */ // memcpy(pal, srcObject.pal, sizeof(ogRGBA8)*256); } // if 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*bytesPerPixel; 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 += bytesPerPixel; } // 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 *= bytesPerPixel; for (yy = 0; yy < yCount; yy++) { ( (uInt8 *)p ) += xOfs; srcObject.ogCopyLineFrom(rx1, ry1+yy, p, xCount); ( (uInt8 *)p ) += xCount; } return; } // ogSprite::Get uInt32 ogSprite::GetPixel(void * p) { uInt32 result; switch (bytesPerPixel) { case 4: return *(uInt32 *)p; break; case 3: 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 2: return *(uInt16 *)p; break; case 1: return *(uInt8 *)p; break; default: return 0; break; } // switch } // ogSprite::GetPixel void ogSprite::SetPixel(void * p, uInt32 colour) { switch (bytesPerPixel) { case 4: *(uInt32 *)p = colour; break; case 3: 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 2: *(uInt16 *)p = (uInt16)colour; break; case 1: *(uInt8 *)p = (uInt8)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 1024 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 sprite in a file, getSize would equal the * filesize. */ uInt32 tmpsize; char headerIdent[4]; tmpsize = sizeof(headerIdent)+ 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(bytesPerPixel)+ // bytes per pixel sizeof(pixelFmtID)+ // pixel format ID sizeof(dAlpha)+ // default alpha sizeof(imageSize)+ // image size in bytes imageSize; // actual image area in bytes if (bytesPerPixel == 1) tmpsize += sizeof(uInt32)+sizeof(ogRGBA8)*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 headerIdent[4]; if (!fileExists(filename)) 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(&headerIdent, sizeof(headerIdent), 1, infile); tresult += lresult*sizeof(headerIdent); if ((headerIdent[0] != 'S') || (headerIdent[1] != 'P') || (headerIdent[2] != 'R') || (headerIdent[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(&pixelFmtID, sizeof(pixelFmtID), 1, infile); tresult += lresult*sizeof(pixelFmtID); lresult = fread(&bytesPerPixel, sizeof(bytesPerPixel), 1, infile); tresult += lresult*sizeof(bytesPerPixel); lresult = fread(&dAlpha, sizeof(dAlpha), 1, infile); tresult += lresult*sizeof(dAlpha); 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 (bytesPerPixel == 1) { // 8bpp sprites have palettes if (pal == NULL) pal = new ogRGBA8[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(ogRGBA8)*256) { fclose(infile); return false; } // if lresult = fread(pal, tmpSize, 1, infile); tresult += lresult*tmpSize; } // if bytesPerPixel == 1 fclose(infile); return (tresult == totSize); } // ogSprite::LoadFrom; void ogSprite::Put(ogSurface& destObject, int32 x, int32 y) { uInt32 xx, yy; int32 xCount, yCount; uInt32 yOfs; uInt32 xLeft, xRight; int32 maxX, maxY; void * p; uInt8 r, g, b, a; ogPixelFmt pixfmt; if (image == NULL) return; if (!destObject.ogAvail()) return; maxX = destObject.ogGetMaxX(); maxY = destObject.ogGetMaxY(); xCount = width; yCount = height; // 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*bytesPerPixel; yCount += y; y = 0; } else yOfs = 0; if (x < 0) { xLeft = abs(x)*bytesPerPixel; xCount += x; x = 0; } else xLeft = 0; if (x+xCount > maxX) { xRight = (xCount - (maxX-x+1))*bytesPerPixel; xCount = (maxX-x)+1; } else xRight = 0; if ((y+yCount) > maxY) yCount = (maxY-y)+1; destObject.ogGetPixFmt(pixfmt); (uInt8 *)p += yOfs; if ((destObject.ogGetPixFmtID() != pixelFmtID) || (destObject.ogIsBlending())) { for (yy = 0; yy < (uInt32)yCount; yy++) { (uInt8 *)p += xLeft; for (xx = 0; xx < (uInt32)xCount; xx++) { Unpack(GetPixel(p), r, g, b, a); (uInt8 *)p += bytesPerPixel; // this could probably be rawSetPixelRGBA instead destObject.ogSetPixel(x+xx, y+yy, r, g, b, a); } // for (uInt8 *)p += xRight; } // for yy } else { // pixel formats match xCount *= bytesPerPixel; for (yy = 0; yy < (uInt32)yCount; yy++) { (uInt8 *)p += xLeft; destObject.ogCopyLineTo(x, y+yy, 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 headerIdent[4]; uInt32 tmpSize; if (image == NULL) return false; if ((bytesPerPixel == 1) && (pal == NULL)) return false; if (!fileExists(filename)) { // 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 headerIdent[0] = 'S'; headerIdent[1] = 'P'; headerIdent[2] = 'R'; headerIdent[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(headerIdent, sizeof(headerIdent), 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(&pixelFmtID, sizeof(pixelFmtID), 1, outfile); fwrite(&bytesPerPixel, sizeof(bytesPerPixel), 1, outfile); fwrite(&dAlpha, sizeof(dAlpha), 1, outfile); fwrite(&imageSize, sizeof(imageSize), 1, outfile); fwrite(image, imageSize, 1, outfile); if (bytesPerPixel == 1) { tmpSize = sizeof(ogRGBA8)*256; fwrite(&tmpSize, sizeof(tmpSize), 1, outfile); fwrite(pal, sizeof(ogRGBA8), 256, outfile); } // if bytesPerPixel == 1 fclose(outfile); return true; } // ogSprite::SaveTo void ogSprite::Unpack(uInt32 colour, uInt8& red, uInt8& green, uInt8& blue, uInt8& alpha) { switch (bytesPerPixel) { case 4: red = (uInt8)(colour >> RFP); green = (uInt8)(colour >> GFP); blue = (uInt8)(colour >> BFP); alpha = (uInt8)(colour >> AFP); break; case 3: red = (uInt8)(colour >> RFP); green = (uInt8)(colour >> GFP); blue = (uInt8)(colour >> BFP); alpha = dAlpha; break; case 2: red = (uInt8)(colour >> RFP) << rShift; green = (uInt8)(colour >> GFP) << gShift; blue = (uInt8)(colour >> BFP) << bShift; if (red != 0) red += OG_MASKS[rShift]; if (green != 0) green += OG_MASKS[gShift]; if (blue != 0) blue += OG_MASKS[bShift]; if (aShift != 8) { alpha = (uInt8)(colour >> AFP) << aShift; if (alpha != 0) alpha += OG_MASKS[aShift]; } else alpha = dAlpha; break; case 1: if (pal == NULL) { red = green = blue = alpha = 0; return; } // if if (colour > 255) colour &= 255; red = pal[colour].red; green = pal[colour].green; blue = pal[colour].blue; alpha = pal[colour].alpha; break; default: red = green = blue = alpha = 0; break; } // switch return; } // ogSprite::Unpack 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; pixelFmtID= 0; bytesPerPixel = 0; dAlpha = 0; return; } // ogSprite::~ogSprite