// // TGA lib for cocos2d-iphone // // sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource // // TGA RLE compression support by Ernesto Corvi #include #include #include #import "TGAlib.h" void tgaLoadRLEImageData(FILE *file, tImageTGA *info); void tgaFlipImage( tImageTGA *info ); // load the image header fields. We only keep those that matter! void tgaLoadHeader(FILE *file, tImageTGA *info) { unsigned char cGarbage; short int iGarbage; fread(&cGarbage, sizeof(unsigned char), 1, file); fread(&cGarbage, sizeof(unsigned char), 1, file); // type must be 2 or 3 fread(&info->type, sizeof(unsigned char), 1, file); fread(&iGarbage, sizeof(short int), 1, file); fread(&iGarbage, sizeof(short int), 1, file); fread(&cGarbage, sizeof(unsigned char), 1, file); fread(&iGarbage, sizeof(short int), 1, file); fread(&iGarbage, sizeof(short int), 1, file); fread(&info->width, sizeof(short int), 1, file); fread(&info->height, sizeof(short int), 1, file); fread(&info->pixelDepth, sizeof(unsigned char), 1, file); fread(&cGarbage, sizeof(unsigned char), 1, file); info->flipped = 0; if ( cGarbage & 0x20 ) info->flipped = 1; } // loads the image pixels. You shouldn't call this function directly void tgaLoadImageData(FILE *file, tImageTGA *info) { int mode,total,i; unsigned char aux; // mode equal the number of components for each pixel mode = info->pixelDepth / 8; // total is the number of unsigned chars we'll have to read total = info->height * info->width * mode; fread(info->imageData,sizeof(unsigned char),total,file); // mode=3 or 4 implies that the image is RGB(A). However TGA // stores it as BGR(A) so we'll have to swap R and B. if (mode >= 3) for (i=0; i < total; i+= mode) { aux = info->imageData[i]; info->imageData[i] = info->imageData[i+2]; info->imageData[i+2] = aux; } } // loads the RLE encoded image pixels. You shouldn't call this function directly void tgaLoadRLEImageData(FILE *file, tImageTGA *info) { unsigned int mode,total,i, index = 0; unsigned char aux[4], runlength = 0; unsigned int skip = 0, flag = 0; // mode equal the number of components for each pixel mode = info->pixelDepth / 8; // total is the number of unsigned chars we'll have to read total = info->height * info->width; for( i = 0; i < total; i++ ) { // if we have a run length pending, run it if ( runlength != 0 ) { // we do, update the run length count runlength--; skip = (flag != 0); } else { // otherwise, read in the run length token if ( fread(&runlength,sizeof(unsigned char),1,file) != 1 ) return; // see if it's a RLE encoded sequence flag = runlength & 0x80; if ( flag ) runlength -= 128; skip = 0; } // do we need to skip reading this pixel? if ( !skip ) { // no, read in the pixel data if ( fread(aux,sizeof(unsigned char),mode,file) != mode ) return; // mode=3 or 4 implies that the image is RGB(A). However TGA // stores it as BGR(A) so we'll have to swap R and B. if ( mode >= 3 ) { unsigned char tmp; tmp = aux[0]; aux[0] = aux[2]; aux[2] = tmp; } } // add the pixel to our image memcpy(&info->imageData[index], aux, mode); index += mode; } } void tgaFlipImage( tImageTGA *info ) { // mode equal the number of components for each pixel int mode = info->pixelDepth / 8; int rowbytes = info->width*mode; unsigned char *row = (unsigned char *)malloc(rowbytes); int y; if (row == NULL) return; for( y = 0; y < (info->height/2); y++ ) { memcpy(row, &info->imageData[y*rowbytes],rowbytes); memcpy(&info->imageData[y*rowbytes], &info->imageData[(info->height-(y+1))*rowbytes], rowbytes); memcpy(&info->imageData[(info->height-(y+1))*rowbytes], row, rowbytes); } free(row); info->flipped = 0; } // this is the function to call when we want to load an image tImageTGA * tgaLoad(const char *filename) { FILE *file; tImageTGA *info; int mode,total; // allocate memory for the info struct and check! info = (tImageTGA *)malloc(sizeof(tImageTGA)); if (info == NULL) return(NULL); // open the file for reading (binary mode) file = fopen(filename, "rb"); if (file == NULL) { info->status = TGA_ERROR_FILE_OPEN; return(info); } // load the header tgaLoadHeader(file,info); // check for errors when loading the header if (ferror(file)) { info->status = TGA_ERROR_READING_FILE; fclose(file); return(info); } // check if the image is color indexed if (info->type == 1) { info->status = TGA_ERROR_INDEXED_COLOR; fclose(file); return(info); } // check for other types (compressed images) if ((info->type != 2) && (info->type !=3) && (info->type !=10) ) { info->status = TGA_ERROR_COMPRESSED_FILE; fclose(file); return(info); } // mode equals the number of image components mode = info->pixelDepth / 8; // total is the number of unsigned chars to read total = info->height * info->width * mode; // allocate memory for image pixels info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * total); // check to make sure we have the memory required if (info->imageData == NULL) { info->status = TGA_ERROR_MEMORY; fclose(file); return(info); } // finally load the image pixels if ( info->type == 10 ) tgaLoadRLEImageData(file, info); else tgaLoadImageData(file,info); // check for errors when reading the pixels if (ferror(file)) { info->status = TGA_ERROR_READING_FILE; fclose(file); return(info); } fclose(file); info->status = TGA_OK; if ( info->flipped ) { tgaFlipImage( info ); if ( info->flipped ) info->status = TGA_ERROR_MEMORY; } return(info); } // converts RGB to greyscale void tgaRGBtogreyscale(tImageTGA *info) { int mode,i,j; unsigned char *newImageData; // if the image is already greyscale do nothing if (info->pixelDepth == 8) return; // compute the number of actual components mode = info->pixelDepth / 8; // allocate an array for the new image data newImageData = (unsigned char *)malloc(sizeof(unsigned char) * info->height * info->width); if (newImageData == NULL) { return; } // convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++) newImageData[j] = (unsigned char)(0.30 * info->imageData[i] + 0.59 * info->imageData[i+1] + 0.11 * info->imageData[i+2]); //free old image data free(info->imageData); // reassign pixelDepth and type according to the new image type info->pixelDepth = 8; info->type = 3; // reassing imageData to the new array. info->imageData = newImageData; } // releases the memory used for the image void tgaDestroy(tImageTGA *info) { if (info != NULL) { if (info->imageData != NULL) free(info->imageData); free(info); } }