/libs/cocos2d/Support/TGAlib.m
Objective C | 272 lines | 172 code | 52 blank | 48 comment | 44 complexity | 2775f3c681677cfdf2b3d22d26dfeaa5 MD5 | raw file
Possible License(s): Apache-2.0
1// 2// TGA lib for cocos2d-iphone 3// 4// sources from: http://www.lighthouse3d.com/opengl/terrain/index.php3?tgasource 5// 6// TGA RLE compression support by Ernesto Corvi 7 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11 12#import "TGAlib.h" 13 14 15// load the image header fields. We only keep those that matter! 16void tgaLoadHeader(FILE *file, tImageTGA *info) { 17 unsigned char cGarbage; 18 short int iGarbage; 19 20 fread(&cGarbage, sizeof(unsigned char), 1, file); 21 fread(&cGarbage, sizeof(unsigned char), 1, file); 22 23 // type must be 2 or 3 24 fread(&info->type, sizeof(unsigned char), 1, file); 25 26 fread(&iGarbage, sizeof(short int), 1, file); 27 fread(&iGarbage, sizeof(short int), 1, file); 28 fread(&cGarbage, sizeof(unsigned char), 1, file); 29 fread(&iGarbage, sizeof(short int), 1, file); 30 fread(&iGarbage, sizeof(short int), 1, file); 31 32 fread(&info->width, sizeof(short int), 1, file); 33 fread(&info->height, sizeof(short int), 1, file); 34 fread(&info->pixelDepth, sizeof(unsigned char), 1, file); 35 36 fread(&cGarbage, sizeof(unsigned char), 1, file); 37 38 info->flipped = 0; 39 if ( cGarbage & 0x20 ) info->flipped = 1; 40} 41 42// loads the image pixels. You shouldn't call this function directly 43void tgaLoadImageData(FILE *file, tImageTGA *info) { 44 45 int mode,total,i; 46 unsigned char aux; 47 48 // mode equal the number of components for each pixel 49 mode = info->pixelDepth / 8; 50 // total is the number of unsigned chars we'll have to read 51 total = info->height * info->width * mode; 52 53 fread(info->imageData,sizeof(unsigned char),total,file); 54 55 // mode=3 or 4 implies that the image is RGB(A). However TGA 56 // stores it as BGR(A) so we'll have to swap R and B. 57 if (mode >= 3) 58 for (i=0; i < total; i+= mode) { 59 aux = info->imageData[i]; 60 info->imageData[i] = info->imageData[i+2]; 61 info->imageData[i+2] = aux; 62 } 63} 64 65// loads the RLE encoded image pixels. You shouldn't call this function directly 66void tgaLoadRLEImageData(FILE *file, tImageTGA *info) 67{ 68 unsigned int mode,total,i, index = 0; 69 unsigned char aux[4], runlength = 0; 70 unsigned int skip = 0, flag = 0; 71 72 // mode equal the number of components for each pixel 73 mode = info->pixelDepth / 8; 74 // total is the number of unsigned chars we'll have to read 75 total = info->height * info->width; 76 77 for( i = 0; i < total; i++ ) 78 { 79 // if we have a run length pending, run it 80 if ( runlength != 0 ) 81 { 82 // we do, update the run length count 83 runlength--; 84 skip = (flag != 0); 85 } 86 else 87 { 88 // otherwise, read in the run length token 89 if ( fread(&runlength,sizeof(unsigned char),1,file) != 1 ) 90 return; 91 92 // see if it's a RLE encoded sequence 93 flag = runlength & 0x80; 94 if ( flag ) runlength -= 128; 95 skip = 0; 96 } 97 98 // do we need to skip reading this pixel? 99 if ( !skip ) 100 { 101 // no, read in the pixel data 102 if ( fread(aux,sizeof(unsigned char),mode,file) != mode ) 103 return; 104 105 // mode=3 or 4 implies that the image is RGB(A). However TGA 106 // stores it as BGR(A) so we'll have to swap R and B. 107 if ( mode >= 3 ) 108 { 109 unsigned char tmp; 110 111 tmp = aux[0]; 112 aux[0] = aux[2]; 113 aux[2] = tmp; 114 } 115 } 116 117 // add the pixel to our image 118 memcpy(&info->imageData[index], aux, mode); 119 index += mode; 120 } 121} 122 123void tgaFlipImage( tImageTGA *info ) 124{ 125 // mode equal the number of components for each pixel 126 int mode = info->pixelDepth / 8; 127 int rowbytes = info->width*mode; 128 unsigned char *row = (unsigned char *)malloc(rowbytes); 129 int y; 130 131 if (row == NULL) return; 132 133 for( y = 0; y < (info->height/2); y++ ) 134 { 135 memcpy(row, &info->imageData[y*rowbytes],rowbytes); 136 memcpy(&info->imageData[y*rowbytes], &info->imageData[(info->height-(y+1))*rowbytes], rowbytes); 137 memcpy(&info->imageData[(info->height-(y+1))*rowbytes], row, rowbytes); 138 } 139 140 free(row); 141 info->flipped = 0; 142} 143 144// this is the function to call when we want to load an image 145tImageTGA * tgaLoad(const char *filename) { 146 147 FILE *file; 148 tImageTGA *info; 149 int mode,total; 150 151 // allocate memory for the info struct and check! 152 info = (tImageTGA *)malloc(sizeof(tImageTGA)); 153 if (info == NULL) 154 return(NULL); 155 156 157 // open the file for reading (binary mode) 158 file = fopen(filename, "rb"); 159 if (file == NULL) { 160 info->status = TGA_ERROR_FILE_OPEN; 161 return(info); 162 } 163 164 // load the header 165 tgaLoadHeader(file,info); 166 167 // check for errors when loading the header 168 if (ferror(file)) { 169 info->status = TGA_ERROR_READING_FILE; 170 fclose(file); 171 return(info); 172 } 173 174 // check if the image is color indexed 175 if (info->type == 1) { 176 info->status = TGA_ERROR_INDEXED_COLOR; 177 fclose(file); 178 return(info); 179 } 180 // check for other types (compressed images) 181 if ((info->type != 2) && (info->type !=3) && (info->type !=10) ) { 182 info->status = TGA_ERROR_COMPRESSED_FILE; 183 fclose(file); 184 return(info); 185 } 186 187 // mode equals the number of image components 188 mode = info->pixelDepth / 8; 189 // total is the number of unsigned chars to read 190 total = info->height * info->width * mode; 191 // allocate memory for image pixels 192 info->imageData = (unsigned char *)malloc(sizeof(unsigned char) * 193 total); 194 195 // check to make sure we have the memory required 196 if (info->imageData == NULL) { 197 info->status = TGA_ERROR_MEMORY; 198 fclose(file); 199 return(info); 200 } 201 // finally load the image pixels 202 if ( info->type == 10 ) 203 tgaLoadRLEImageData(file, info); 204 else 205 tgaLoadImageData(file,info); 206 207 // check for errors when reading the pixels 208 if (ferror(file)) { 209 info->status = TGA_ERROR_READING_FILE; 210 fclose(file); 211 return(info); 212 } 213 fclose(file); 214 info->status = TGA_OK; 215 216 if ( info->flipped ) 217 { 218 tgaFlipImage( info ); 219 if ( info->flipped ) info->status = TGA_ERROR_MEMORY; 220 } 221 222 return(info); 223} 224 225// converts RGB to greyscale 226void tgaRGBtogreyscale(tImageTGA *info) { 227 228 int mode,i,j; 229 230 unsigned char *newImageData; 231 232 // if the image is already greyscale do nothing 233 if (info->pixelDepth == 8) 234 return; 235 236 // compute the number of actual components 237 mode = info->pixelDepth / 8; 238 239 // allocate an array for the new image data 240 newImageData = (unsigned char *)malloc(sizeof(unsigned char) * 241 info->height * info->width); 242 if (newImageData == NULL) { 243 return; 244 } 245 246 // convert pixels: greyscale = o.30 * R + 0.59 * G + 0.11 * B 247 for (i = 0,j = 0; j < info->width * info->height; i +=mode, j++) 248 newImageData[j] = 249 (unsigned char)(0.30 * info->imageData[i] + 250 0.59 * info->imageData[i+1] + 251 0.11 * info->imageData[i+2]); 252 253 254 //free old image data 255 free(info->imageData); 256 257 // reassign pixelDepth and type according to the new image type 258 info->pixelDepth = 8; 259 info->type = 3; 260 // reassing imageData to the new array. 261 info->imageData = newImageData; 262} 263 264// releases the memory used for the image 265void tgaDestroy(tImageTGA *info) { 266 267 if (info != NULL) { 268 if (info->imageData != NULL) 269 free(info->imageData); 270 free(info); 271 } 272}