PageRenderTime 88ms CodeModel.GetById 11ms app.highlight 74ms RepoModel.GetById 1ms app.codeStats 0ms

/libs/cocos2d/Support/TGAlib.m

http://github.com/kstenerud/ObjectAL-for-iPhone
Objective C | 272 lines | 172 code | 52 blank | 48 comment | 44 complexity | 2775f3c681677cfdf2b3d22d26dfeaa5 MD5 | raw file
  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}