1 //////////////////////////////////////////////////////////////////////////////////////////
3 // functions for image for a texture
4 // Downloaded from: www.paulsprojects.net
5 // Created: 20th July 2002
7 // Copyright (c) 2006, Paul Baker
8 // Distributed under the New BSD Licence. (See accompanying file License.txt or copy at
9 // http://www.paulsprojects.net/NewBSDLicense.txt)
10 //////////////////////////////////////////////////////////////////////////////////////////
18 //Load - load a texture from a file
19 bool IMAGE::Load(const char * filename
)
21 //Clear the data if already used
30 int filenameLength
=strlen(filename
);
32 if( strncmp((filename
+filenameLength
-3), "BMP", 3)==0 ||
33 strncmp((filename
+filenameLength
-3), "bmp", 3)==0)
34 return LoadBMP(filename
);
36 if( strncmp((filename
+filenameLength
-3), "PCX", 3)==0 ||
37 strncmp((filename
+filenameLength
-3), "pcx", 3)==0)
38 return LoadPCX(filename
);
40 if( strncmp((filename
+filenameLength
-3), "TGA", 3)==0 ||
41 strncmp((filename
+filenameLength
-3), "tga", 3)==0)
42 return LoadTGA(filename
);
44 errorLog
.OutputError("%s does not end in \".tga\", \".bmp\" or \"pcx\"", filename
);
50 bool IMAGE::LoadBMP(const char * filename
)
52 FILE * file
; //the texture file
53 BITMAPFILEHEADER fileHeader
; //bitmap file header
54 BITMAPINFOHEADER infoHeader
; //bitmap info header
56 //open file for reading
57 file
=fopen(filename
, "rb");
60 errorLog
.OutputError("Unable to open %s", filename
);
64 //read the file header
65 fread(&fileHeader
, sizeof(BITMAPFILEHEADER
), 1, file
);
68 if(fileHeader
.bfType
!= BITMAP_ID
)
71 errorLog
.OutputError("%s is not a legal .BMP", filename
);
75 //read in the information header
76 fread(&infoHeader
, sizeof(BITMAPINFOHEADER
), 1, file
);
82 if(infoHeader
.biBitCount
==24)
83 return Load24BitBMP(filename
);
84 if(infoHeader
.biBitCount
==8)
85 return Load8BitBMP(filename
);
87 errorLog
.OutputError("%s has an unknown bpp", filename
);
92 //Load24BitBMP - load a 24 bit bitmap file
93 bool IMAGE::Load24BitBMP(const char * filename
)
95 errorLog
.OutputSuccess("Loading %s in Load24bitBMP()", filename
);
101 FILE * file
; //the texture file
102 BITMAPFILEHEADER fileHeader
; //bitmap file header
103 BITMAPINFOHEADER infoHeader
; //bitmap info header
105 //open file for reading
106 file
=fopen(filename
, "rb");
109 errorLog
.OutputError("Unable to open %s", filename
);
113 //read the file header
114 fread(&fileHeader
, sizeof(BITMAPFILEHEADER
), 1, file
);
116 //check it's a bitmap
117 if(fileHeader
.bfType
!= BITMAP_ID
)
120 errorLog
.OutputError("%s is not a legal .BMP", filename
);
124 //read in the information header
125 fread(&infoHeader
, sizeof(BITMAPINFOHEADER
), 1, file
);
128 width
=infoHeader
.biWidth
;
129 height
=infoHeader
.biHeight
;
131 //calculate the stride in bytes: width*bpp/8 plus padding bytes at the end of each row
132 unsigned int stride
=width
*bpp
/8;
140 //point file to the beginning of the data
141 fseek(file
, fileHeader
.bfOffBits
, SEEK_SET
);
143 //allocate space for the image data
144 data
=new unsigned char[stride
*height
];
148 errorLog
.OutputError("Unable to allocate memory for %s", filename
);
153 fread(data
, 1, stride
*height
, file
);
158 //data is in BGR format
160 for(unsigned int row
=0; row
<height
; row
++)
162 for(unsigned int i
=0; i
<width
*3; i
+=bpp
/8)
164 //repeated XOR to swap bytes 0 and 2
165 data
[(row
*stride
)+i
] ^= data
[(row
*stride
)+i
+2] ^=
166 data
[(row
*stride
)+i
] ^= data
[(row
*stride
)+i
+2];
170 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
174 //Load8BitBMP - load an 8 bit paletted bitmap file
175 bool IMAGE::Load8BitBMP(const char * filename
)
177 errorLog
.OutputSuccess("Loading %s in Load8bitBMP()", filename
);
180 bpp
=24; //after conversion
183 FILE * file
; //the texture file
184 BITMAPFILEHEADER fileHeader
; //bitmap file header
185 BITMAPINFOHEADER infoHeader
; //bitmap info header
187 //open file for reading
188 file
=fopen(filename
, "rb");
191 errorLog
.OutputError("Unable to open %s", filename
);
195 //read the file header
196 fread(&fileHeader
, sizeof(BITMAPFILEHEADER
), 1, file
);
198 //check it's a bitmap
199 if(fileHeader
.bfType
!= BITMAP_ID
)
202 errorLog
.OutputError("%s is not a legal .BMP", filename
);
206 //read in the information header
207 fread(&infoHeader
, sizeof(BITMAPINFOHEADER
), 1, file
);
210 width
=infoHeader
.biWidth
;
211 height
=infoHeader
.biHeight
;
213 //make space for palette
214 unsigned char * palette
=new unsigned char[256*4];
217 errorLog
.OutputError("Unable to alllocate memory for palette");
222 fread(palette
, 256*4, 1, file
);
224 //point file to the beginning of the data
225 fseek(file
, fileHeader
.bfOffBits
, SEEK_SET
);
227 //calculate the stride in bytes between one row and the next
228 unsigned int stride
=width
;
232 //allocate space for color indices
233 unsigned char * indices
=new unsigned char[stride
*height
];
236 errorLog
.OutputError("Unable to allocate memory for indices");
241 fread(indices
, 1, stride
*height
, file
);
246 //allocate space for the image data
247 data
=new unsigned char[stride
*height
*bpp
/8];
251 errorLog
.OutputError("Unable to allocate memory for %s", filename
);
255 //calculate the color values - keeping the padding colors
256 for(unsigned int currentRow
=0; currentRow
<height
; currentRow
++)
258 for(unsigned int i
=0; i
<stride
; i
++)
260 data
[(currentRow
*stride
+i
)*3+0]=palette
[indices
[currentRow
*stride
+i
]*4+2];
261 data
[(currentRow
*stride
+i
)*3+1]=palette
[indices
[currentRow
*stride
+i
]*4+1];
262 data
[(currentRow
*stride
+i
)*3+2]=palette
[indices
[currentRow
*stride
+i
]*4+0];//BGR
266 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
276 //LoadPCX - load a .pcx texture - 256 color, paletted
277 bool IMAGE::LoadPCX(const char * filename
)
279 errorLog
.OutputSuccess("Loading %s in LoadPCX()", filename
);
287 file
=fopen(filename
, "rb");
290 errorLog
.OutputError("Unable to open %s", filename
);
294 //retrieve header, first 4 bytes, first 2 should be 0x0A0C
295 unsigned short header
[2];
296 fread(header
, 4, 1, file
);
298 if(header
[0]!=0x050A)
300 errorLog
.OutputError("%s is not a legal .PCX file", filename
);
305 //retrieve minimum x value
306 int xMin
=fgetc(file
); //loword
307 xMin
|= fgetc(file
) << 8; //hiword
309 //retrieve minimum y value
310 int yMin
=fgetc(file
); //loword
311 yMin
|= fgetc(file
) << 8; //hiword
313 //retrieve maximum x value
314 int xMax
=fgetc(file
); //loword
315 xMax
|= fgetc(file
) << 8; //hiword
317 //retrieve maximum y value
318 int yMax
=fgetc(file
); //loword
319 yMax
|= fgetc(file
) << 8; //hiword
321 //calculate width and height
325 //allocate memory for pixel data (paletted)
326 unsigned char * pixelData
=new unsigned char[width
*height
];
329 errorLog
.OutputError("Unable to allocate %d bytes for the image data of %s",
330 width
*height
, filename
);
335 //set file pointer to beginning of image data
336 fseek(file
, 128, SEEK_SET
);
338 //decode and store the pixel data
339 unsigned int index
=0;
341 while(index
<(width
*height
))
347 int numRepeat
= 0x3F & c
;
350 for(int i
=0; i
<numRepeat
; i
++)
351 pixelData
[index
++] = c
;
354 pixelData
[index
++] = c
;
359 //allocate memory for the image palette
360 unsigned char * paletteData
= new unsigned char[768];
362 //the palette is the last 769 bytes of the file
363 fseek(file
, -769, SEEK_END
);
365 //retrieve first character, should be equal to 12
369 errorLog
.OutputError("%s is not a legal .PCX file - the palette data has an illegal header, %d",
375 //read and store the palette
376 fread(paletteData
, 1, 768, file
);
381 //allocate memory for the "unpaletted" data
382 data
= new unsigned char[width
*height
*3];
385 errorLog
.OutputError("Unable to allocate memory for the expanded data of %s", filename
);
389 //calculate the "unpaletted" data - "flipping" the texture top-bottom
390 for(unsigned int j
=0; j
<height
; j
++)
392 for(unsigned int i
=0; i
<width
; i
++)
394 data
[3*(j
*width
+i
)] = (unsigned char) paletteData
[3*pixelData
[(height
-1-j
)*width
+i
]];
395 data
[3*(j
*width
+i
)+1] = (unsigned char) paletteData
[3*pixelData
[(height
-1-j
)*width
+i
]+1];
396 data
[3*(j
*width
+i
)+2] = (unsigned char) paletteData
[3*pixelData
[(height
-1-j
)*width
+i
]+2];
400 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
409 bool IMAGE::LoadTGA(const char * filename
)
411 unsigned char UncompressedTGAHeader
[12]={0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0};
412 unsigned char CompressedTGAHeader
[12]={0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0};
413 unsigned char Uncompressed8BitTGAHeader
[12]={0, 1, 1, 0, 0, 0, 1, 24, 0, 0, 0, 0};
415 unsigned char TGAcompare
[12]; //Used to compare TGA header
417 FILE * file
= fopen(filename
, "rb"); //Open the TGA file
419 if( file
==NULL
) //Does the file exist?
421 errorLog
.OutputError("%s does not exist", filename
);
426 fread(TGAcompare
, 1, sizeof(TGAcompare
), file
);
429 if(memcmp(UncompressedTGAHeader
, TGAcompare
, sizeof(UncompressedTGAHeader
))==0)
431 return LoadUncompressedTrueColorTGA(filename
);
433 else if(memcmp(CompressedTGAHeader
, TGAcompare
, sizeof(CompressedTGAHeader
))==0)
435 return LoadCompressedTrueColorTGA(filename
);
437 else if(memcmp(Uncompressed8BitTGAHeader
, TGAcompare
, sizeof(Uncompressed8BitTGAHeader
))==0)
439 return LoadUncompressed8BitTGA(filename
);
443 errorLog
.OutputError("%s is not a recognised type of TGA", filename
);
450 //load an 8 bit uncompressed paletted TGA
451 bool IMAGE::LoadUncompressed8BitTGA(const char * filename
)
453 unsigned char TGAHeader
[12]={0, 1, 1, 0, 0, 0, 1, 24, 0, 0, 0, 0};
454 unsigned char TGAcompare
[12]; //Used to compare TGA header
455 unsigned char header
[6]; //First 6 useful bytes of the header
457 errorLog
.OutputSuccess("Loading %s in LoadUncompressed8BitTGA()", filename
);
459 FILE * file
= fopen(filename
, "rb"); //Open the TGA file
461 if(file
== NULL
) //Does the file exist?
463 errorLog
.OutputError("%s does not exist.", filename
);
467 if( fread(TGAcompare
, 1, sizeof(TGAcompare
), file
)!=sizeof(TGAcompare
)|| //Are there 12 bytes to read?
468 memcmp(TGAHeader
, TGAcompare
, sizeof(TGAHeader
))!=0 || //Is the header correct?
469 fread(header
, 1, sizeof(header
), file
)!=sizeof(header
)) //Read next 6 bytes
471 fclose(file
); //If anything else failed, close the file
472 errorLog
.OutputError("Could not load %s correctly, general failure.", filename
);
476 //save data into class member variables
477 width
= header
[1]*256+header
[0]; //determine the image width
478 height
= header
[3]*256+header
[2]; //determine image height
481 if( width
<=0 || //if width <=0
482 height
<=0 || //or height<=0
485 fclose(file
); //close the file
486 errorLog
.OutputError("%s's height or width is less than zero, or the TGA is not 8 bpp.", filename
);
493 //make space for palette
494 unsigned char * palette
=new unsigned char[256*3];
497 errorLog
.OutputError("Unable to allocate memory for palette");
502 fread(palette
, 256*3, 1, file
);
504 //allocate space for color indices
505 unsigned char * indices
=new unsigned char[width
*height
];
508 errorLog
.OutputError("Unable to allocate memory for indices");
513 fread(indices
, 1, width
*height
, file
);
518 //allocate space for the image data
519 data
=new unsigned char[width
*height
*3];
523 errorLog
.OutputError("Unable to allocate memory for %s", filename
);
527 //calculate the color values
528 for(unsigned int currentRow
=0; currentRow
<height
; currentRow
++)
530 for(unsigned int i
=0; i
<width
; i
++)
532 data
[(currentRow
*width
+i
)*3+0]=palette
[indices
[currentRow
*width
+i
]*3+2];
533 data
[(currentRow
*width
+i
)*3+1]=palette
[indices
[currentRow
*width
+i
]*3+1];
534 data
[(currentRow
*width
+i
)*3+2]=palette
[indices
[currentRow
*width
+i
]*3+0];//BGR
538 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
546 //load an uncompressed TGA texture (24 or 32 bpp)
547 bool IMAGE::LoadUncompressedTrueColorTGA(const char * filename
)
549 unsigned char TGAheader
[12]={0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Uncompressed TGA header
550 unsigned char TGAcompare
[12]; //Used to compare TGA header
551 unsigned char header
[6]; //First 6 useful bytes of the header
552 unsigned int bytesPerPixel
; //bytes per pixel
553 unsigned int imageSize
; //Stores Image size when in RAM
555 errorLog
.OutputSuccess("Loading %s in LoadUncompressedTGA()", filename
);
557 FILE * file
= fopen(filename
, "rb"); //Open the TGA file
559 if(file
== NULL
) //Does the file exist?
561 errorLog
.OutputError("%s does not exist.", filename
);
565 if( fread(TGAcompare
, 1, sizeof(TGAcompare
), file
)!=sizeof(TGAcompare
)|| //Are there 12 bytes to read?
566 memcmp(TGAheader
, TGAcompare
, sizeof(TGAheader
))!=0 || //Is the header correct?
567 fread(header
, 1, sizeof(header
), file
)!=sizeof(header
)) //Read next 6 bytes
569 fclose(file
); //If anything else failed, close the file
570 errorLog
.OutputError("Could not load %s correctly, general failure.", filename
);
574 //save data into class member variables
575 width
= header
[1]*256+header
[0]; //determine the image width
576 height
= header
[3]*256+header
[2]; //determine image height
579 if( width
<=0 || //if width <=0
580 height
<=0 || //or height<=0
581 bpp
!=24 && bpp
!=32) //bpp not 24 or 32
583 fclose(file
); //close the file
584 errorLog
.OutputError("%s's height or width is less than zero, or the TGA is not 24 or 32 bpp.", filename
);
594 bytesPerPixel
=bpp
/8; //calc bytes per pixel
595 imageSize
=width
*height
*bytesPerPixel
; //calc memory required
597 data
=new unsigned char[imageSize
]; //reserve the memory for the data
599 if( data
==NULL
) //Does the storage memory exist?
601 errorLog
.OutputError("Unable to allocate memory for %s image", filename
);
606 //read in the image data
607 if(fread(data
, 1, imageSize
, file
)!=imageSize
) //Does the image size match the required?
609 if(data
) //If data loaded
610 delete [] data
; //free memory
611 errorLog
.OutputError("Could not read %s image data", filename
);
612 fclose(file
); //close file
618 //data is in BGR format
620 for(int i
=0; i
<(int)imageSize
; i
+=bytesPerPixel
)
622 //repeated XOR to swap bytes 0 and 2
623 data
[i
] ^= data
[i
+2] ^= data
[i
] ^= data
[i
+2];
626 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
634 //load a compressed TGA texture (24 or 32 bpp)
635 bool IMAGE::LoadCompressedTrueColorTGA(const char * filename
)
637 unsigned char TGAheader
[12]={0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Compressed TGA header
638 unsigned char TGAcompare
[12]; //Used to compare TGA header
639 unsigned char header
[6]; //First 6 useful bytes of the header
640 unsigned int bytesPerPixel
; //bytes per pixel
641 unsigned int imageSize
; //Stores Image size when in RAM
643 errorLog
.OutputSuccess("Loading %s in LoadCompressedTGA()", filename
);
645 FILE * file
= fopen(filename
, "rb"); //Open the TGA file
647 if(file
== NULL
) //Does the file exist?
649 errorLog
.OutputError("%s does not exist.", filename
);
653 if( fread(TGAcompare
, 1, sizeof(TGAcompare
), file
)!=sizeof(TGAcompare
)|| //Are there 12 bytes to read?
654 memcmp(TGAheader
, TGAcompare
, sizeof(TGAheader
))!=0 || //Is the header correct?
655 fread(header
, 1, sizeof(header
), file
)!=sizeof(header
)) //Read next 6 bytes
657 fclose(file
); //If anything else failed, close the file
658 errorLog
.OutputError("Could not load %s correctly, general failure.", filename
);
662 //save data into class member variables
663 width
= header
[1]*256+header
[0]; //determine the image width
664 height
= header
[3]*256+header
[2]; //determine image height
667 if( width
<=0 || //if width <=0
668 height
<=0 || //or height<=0
669 bpp
!=24 && bpp
!=32) //bpp not 24 or 32
671 fclose(file
); //close the file
672 errorLog
.OutputError("%s's height or width is less than zero, or the TGA is not 24 or 32 bpp.", filename
);
682 bytesPerPixel
=bpp
/8; //calc bytes per pixel
683 imageSize
=width
*height
*bytesPerPixel
; //calc memory required
685 data
=new unsigned char[imageSize
]; //reserve the memory for the data
686 if(!data
) //Does the storage memory exist?
688 errorLog
.OutputError("Unable to allocate memory for %s image", filename
);
693 //read in the image data
694 int pixelCount
= height
*width
;
697 unsigned char * colorBuffer
=new unsigned char[bytesPerPixel
];
701 unsigned char chunkHeader
=0;
703 if(fread(&chunkHeader
, sizeof(unsigned char), 1, file
) == 0)
705 errorLog
.OutputError("Could not read RLE chunk header");
713 if(chunkHeader
<128) //Read raw color values
717 for(short counter
=0; counter
<chunkHeader
; counter
++)
719 if(fread(colorBuffer
, 1, bytesPerPixel
, file
) != bytesPerPixel
)
721 errorLog
.OutputError("Unable to read %s image data", filename
);
727 delete [] colorBuffer
;
735 //transfer pixel color to data (swapping r and b values)
736 data
[currentByte
] = colorBuffer
[2];
737 data
[currentByte
+1] = colorBuffer
[1];
738 data
[currentByte
+2] = colorBuffer
[0];
741 data
[currentByte
+3]=colorBuffer
[3];
743 currentByte
+=bytesPerPixel
;
746 if(currentPixel
> pixelCount
)
748 errorLog
.OutputError("Too many pixels read");
752 delete [] colorBuffer
;
759 else //chunkHeader>=128
763 if(fread(colorBuffer
, 1, bytesPerPixel
, file
) != bytesPerPixel
)
765 errorLog
.OutputError("Unable to read %s image data", filename
);
770 delete [] colorBuffer
;
776 for(short counter
=0; counter
<chunkHeader
; counter
++)
778 //transfer pixel color to data (swapping r and b values)
779 data
[currentByte
] = colorBuffer
[2];
780 data
[currentByte
+1] = colorBuffer
[1];
781 data
[currentByte
+2] = colorBuffer
[0];
784 data
[currentByte
+3]=colorBuffer
[3];
786 currentByte
+=bytesPerPixel
;
789 if(currentPixel
> pixelCount
)
791 errorLog
.OutputError("Too many pixels read");
795 delete [] colorBuffer
;
802 }while(currentPixel
<pixelCount
);
806 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
822 //load in an 8 bit greyscale TGA as an alpha channel
823 bool IMAGE::LoadAlphaTGA(const char * filename
)
825 unsigned char TGAHeader
[12]={0, 1, 1, 0, 0, 0, 1, 24, 0, 0, 0, 0};
826 unsigned char TGAcompare
[12]; //Used to compare TGA header
827 unsigned char header
[6]; //First 6 useful bytes of the header
829 errorLog
.OutputSuccess("Loading %s in LoadAlphaTGA()", filename
);
831 if(!(format
==GL_RGB
|| format
==GL_RGBA
))
833 errorLog
.OutputError("Can only load an alpha channel to RGB / RGBA format images. %s caused error", filename
);
837 FILE * file
= fopen(filename
, "rb"); //Open the TGA file
839 if(file
== NULL
) //Does the file exist?
841 errorLog
.OutputError("%s does not exist.", filename
);
845 if( fread(TGAcompare
, 1, sizeof(TGAcompare
), file
)!=sizeof(TGAcompare
)|| //Are there 12 bytes to read?
846 memcmp(TGAHeader
, TGAcompare
, sizeof(TGAHeader
))!=0 || //Is the header correct?
847 fread(header
, 1, sizeof(header
), file
)!=sizeof(header
)) //Read next 6 bytes
849 fclose(file
); //If anything else failed, close the file
850 errorLog
.OutputError("Could not load %s correctly, general failure.", filename
);
854 //save data into class member variables
855 unsigned int alphaWidth
= header
[1]*256+header
[0]; //determine the image width
856 unsigned int alphaHeight
= header
[3]*256+header
[2]; //determine image height
857 int alphaBpp
= header
[4];
859 if( alphaWidth
<=0 || //if width <=0
860 alphaHeight
<=0 || //or height<=0
861 alphaBpp
!=8) //bpp not 8
863 fclose(file
); //close the file
864 errorLog
.OutputError("%s's height or width is less than zero, or the TGA is not 8 bpp.", filename
);
868 //check it is the same size as the image
869 if(alphaWidth
!=width
|| alphaHeight
!=height
)
871 errorLog
.OutputError("%s is not the same size as the color texture", filename
);
875 //make space for palette
876 unsigned char * palette
=new unsigned char[256*3];
879 errorLog
.OutputError("Unable to allocate memory for palette");
884 fread(palette
, 256*3, 1, file
);
886 //we dont use the palette
890 //allocate space for alpha values
891 unsigned char * values
=new unsigned char[width
*height
];
894 errorLog
.OutputError("Unable to allocate memory for alpha values");
899 fread(values
, 1, alphaWidth
*alphaHeight
, file
);
904 //now put in the alpha data
907 for(unsigned int i
=0; i
<width
*height
; i
++)
909 data
[i
*4+3]=values
[i
];
912 else if(format
==GL_RGB
)
914 unsigned char * tempData
=new unsigned char[width
*height
*4];
917 errorLog
.OutputError("Unable to allocate memory for Temporary Data");
921 for(unsigned int i
=0; i
<width
*height
; i
++)
923 tempData
[i
*4+0]=data
[i
*3+0];
924 tempData
[i
*4+1]=data
[i
*3+1];
925 tempData
[i
*4+2]=data
[i
*3+2];
926 tempData
[i
*4+3]=values
[i
];
929 //update member variables
938 errorLog
.OutputSuccess("Loaded %s correctly.", filename
);
943 void IMAGE::FlipVertically()
945 //dont flip zero or 1 height images
946 if(height
==0 || height
==1)
950 //see how many rows to swap
952 rowsToSwap
=(height
-1)/2;
956 //create space for a temporary row
957 GLubyte
* tempRow
=new GLubyte
[width
*bpp
/8];
960 errorLog
.OutputError("Unable to flip image, unable to create space for temporary row");
964 //loop through rows to swap
965 for(int i
=0; i
<rowsToSwap
; ++i
)
967 //copy row i into temp
968 memcpy(tempRow
, &data
[i
*width
*bpp
/8], width
*bpp
/8);
969 //copy row height-i-1 to row i
970 memcpy(&data
[i
*width
*bpp
/8], &data
[(height
-i
-1)*width
*bpp
/8], width
*bpp
/8);
971 //copy temp into row height-i-1
972 memcpy(&data
[(height
-i
-1)*width
*bpp
/8], tempRow
, width
*bpp
/8);