Initial revision
[0ad:0ad.git] / terrain / bak / 0 / Bitmap.cpp
1 //***********************************************************
2 //
3 // Name:                Bitmap.Cpp
4 // Author:              Poya Manouchehri
5 //
6 // Description: CBitmap operates on a bitmap. Currently it
7 //                              can load BMPs and TGAs. All bitmaps (even 8-bit
8 //                              ones) are converted into full RGBAs.
9 //
10 //***********************************************************
11
12 #include "Bitmap.H"
13 #include "RenderPrims.H"
14
15 CBitmap::CBitmap ()
16 {
17         //everthing is 0
18         m_pBits = NULL;
19         m_Height = m_Width = 0;
20 }
21
22 CBitmap::~CBitmap ()
23 {
24         //destroy the data
25         DestroyData ();
26 }
27
28 //Load the image from a file
29 FRESULT CBitmap::LoadBitmap (char *path, RESOURCETYPE type)
30 {
31         FILE *ImageFile = NULL;
32         int ImageType;
33         FRESULT Result;
34
35         CFileResource::SetupParams (path, type);
36
37         //clean up
38         DestroyData ();
39
40         ImageFile = fopen (path, "rb");
41
42         if (!ImageFile)
43         {
44                 return R_FILE_NOOPEN;
45         }
46
47         ImageType = GetImageType (ImageFile);
48
49         switch (ImageType)
50         {
51                 case FILE_TYPE_BMP:
52                         //try to load as a BMP
53                         Result = LoadBMP (ImageFile);
54                         break;
55
56                 case FILE_TYPE_TGA:
57                         //try to load as a TGA
58                         Result = LoadTGA (ImageFile);
59                         break;
60
61                 default:
62                         return R_BADPARAMS;
63                         break;
64         }
65
66         if (Result != R_OK)
67                 return R_FAIL;
68
69
70         return R_OK;
71 }
72
73 FRESULT CBitmap::CreateBitmap (RESOURCETYPE type, char *name, int width, int height)
74 {
75         //clean any old data
76         DestroyData ();
77
78         strcpy (m_Name, name);
79         m_Type = type;
80
81         m_Width = width;
82         m_Height = height;
83
84         m_pBits = new unsigned char [m_Width*m_Height*4];
85
86         if (!m_pBits)
87                 return R_NOMEMORY;
88
89         return R_OK;
90 }
91
92 //Get the file format
93 int CBitmap::GetImageType (FILE *file)
94 {
95         short int type;
96
97         //is the file valid ?
98         if (!file)
99         {
100                 fclose(file);
101                 return FILE_TYPE_NOSUPPORT;
102         }
103
104         // Read the first 2 bytes of the file
105         if (fread (&type, 2, 1, file) != 1)
106         {
107                 fclose(file);
108                 return FILE_TYPE_NOSUPPORT;
109         }
110         
111         rewind(file);
112
113         // Is it a bitmap ?
114         if (type == 0x4d42)
115         {
116                 rewind (file);
117                 return FILE_TYPE_BMP;
118         }
119
120         // TGA's don't have a header ID, so just take a guess
121         rewind(file);
122         return FILE_TYPE_TGA;
123 }
124
125 //Load a bmp file
126 FRESULT CBitmap::LoadBMP (FILE *file)
127 {
128         BITMAPFILEHEADER bmfileh;
129         BITMAPINFOHEADER bminfoh;
130         RGBQUAD bmColors[256];
131
132         //Note: the file format of a BMP file is:
133
134         //              BITMAPFILEHEADER
135         //              BITMAPINFOHEADER
136         //              RGBQUAD[2^bitcount]
137         //              the actual bits (indices in case of an 8 bit bitmap)
138
139         fread (&bmfileh, sizeof (BITMAPFILEHEADER), 1, file);
140         //read the file header
141         fread (&bminfoh, sizeof (BITMAPINFOHEADER), 1, file);
142         //read the bitmap header
143
144         m_Width = bminfoh.biWidth;
145         m_Height = abs(bminfoh.biHeight);
146
147         //read the color table if indexed
148         if (bminfoh.biBitCount < 24)
149                 fread (&bmColors, sizeof (RGBQUAD), 256, file);
150
151         //move to the point where the actual bit data start
152         fseek (file, bmfileh.bfOffBits, SEEK_SET);
153
154         //load the data
155         return LoadData (file, bminfoh.biBitCount, bmColors);
156 }
157
158 //Load a TGA file
159 FRESULT CBitmap::LoadTGA (FILE *file)
160 {
161         TGAHeader tgaHeader;
162
163         int loadedOK = 1;
164         int i, temp;
165
166         // We have to load the header explicitly, due to some time
167         // weird memory aligning thing that goes on at compile
168         loadedOK &= fread(&tgaHeader.IDLength, 1, 1, file);
169         loadedOK &= fread(&tgaHeader.MapType, 1, 1, file);
170         loadedOK &= fread(&tgaHeader.ImageType, 1, 1, file);
171         loadedOK &= fread(&tgaHeader.MapOrigin, 2, 1, file);
172         loadedOK &= fread(&tgaHeader.MapLength, 2, 1, file);
173         loadedOK &= fread(&tgaHeader.MapEntrySize, 1, 1, file);
174         loadedOK &= fread(&tgaHeader.XOrigin, 2, 1, file);
175         loadedOK &= fread(&tgaHeader.YOrigin, 2, 1, file);
176         loadedOK &= fread(&tgaHeader.Width, 2, 1, file);
177         loadedOK &= fread(&tgaHeader.Height, 2, 1, file);
178         loadedOK &= fread(&tgaHeader.BPP, 1, 1, file);
179         loadedOK &= fread(&tgaHeader.Descriptor, 1, 1, file);
180
181         // Ensure all elements of the file header were loaded
182         if (!loadedOK) 
183         {
184                 fclose(file);
185                 return R_FAIL;
186         }
187
188         // Check the image type
189         if (tgaHeader.ImageType != 1 && tgaHeader.ImageType != 2 && tgaHeader.ImageType != 3)
190         {
191                 fclose(file);
192                 return R_FAIL;
193         }
194         
195         if (tgaHeader.BPP != 24 && tgaHeader.BPP != 32)
196         {
197                 fclose(file);
198                 return R_FAIL;
199         }
200
201         // Skip any identification data in the header (we're not interested in that)
202         for (i=0; i<tgaHeader.IDLength; i++)
203                 fread(&temp, sizeof(unsigned char), 1, file);
204
205         // Skip the colour look up tables
206         for (i=0; i<tgaHeader.MapLength*(tgaHeader.MapEntrySize>>3); i++)
207                 fread(&temp, sizeof(unsigned char), 1, file);
208
209         m_Width = tgaHeader.Width;
210         m_Height = tgaHeader.Height;
211
212         return LoadData (file, tgaHeader.BPP, NULL);
213 }
214
215 //Load the actual bits from a file. the table is NULL
216 //unless the image is 8-bit
217 FRESULT CBitmap::LoadData (FILE *file, int bpp, RGBQUAD *table)
218 {
219         unsigned char *TempBits = NULL;
220         //temporary bits which are read straight from the file
221
222         m_pBits = new unsigned char[m_Width*m_Height*4];
223         //allocate memory for the bits
224         
225         //this is rather bad: no memory
226         if (!m_pBits)
227         {
228                 fclose (file);
229                 return R_NOMEMORY;
230         }
231         
232         //read the bits
233         switch (bpp)
234         {
235                 case 8:
236                 {
237                         TempBits = new unsigned char[m_Width*m_Height];
238                         //allocate some memory for temporary bits
239                         break;
240                 }
241
242                 case 24:
243                 {
244                         TempBits = new unsigned char[m_Width*m_Height*3];
245                         //allocate some memory for temporary bits
246                         break;
247                 }
248
249                 case 32:
250                 {
251                         TempBits = new unsigned char[m_Width*m_Height*4];
252                         //allocate some memory for temporary bits
253                         break;
254                 }
255                 
256                 default:
257                 {
258                         fclose (file);
259                         return R_FILE_INVALID;
260                         break;
261                 }
262         }
263
264         //no memory
265         if (!TempBits)
266         {
267                 fclose (file);
268                 return R_NOMEMORY;
269         }               
270
271         //now lets actually read the bits from the file and copy them into
272         //Bits in the proper fashion
273         switch (bpp)
274         {
275                 case 8:
276                 {
277                         //only one channel (8-bit) so there are Width*Height values to read
278                         if (fread (TempBits, sizeof (unsigned char), m_Width*m_Height, file) != (unsigned int)(m_Width*m_Height))
279                         {
280                                 fclose (file);
281                                 return R_FILE_NOREAD;
282                         }
283
284                         //the following loop converts the index data of TempBits,
285                         //into actual color data (read from the color table) and
286                         //stores it to Bits
287                         int i;
288
289                         for (int index=0;index<m_Width*m_Height;index++)
290                         {
291                                 i = TempBits[index];
292                                 m_pBits[index*4    ] = table[i].rgbRed;
293                                 m_pBits[index*4 + 1] = table[i].rgbGreen;
294                                 m_pBits[index*4 + 2] = table[i].rgbBlue;
295                                 m_pBits[index*4 + 3] = 255;
296                         }
297
298                         break;
299                 }
300
301                 case 24:
302                 {
303                         //3 channels (24-bit) so there are Width*Height*3 values to read
304                         if (fread (TempBits, sizeof (unsigned char), m_Width*m_Height*3, file) != (unsigned int)(m_Width*m_Height*3))
305                         {
306                                 fclose (file);
307                                 return R_FILE_NOREAD;
308                         }
309
310                         //we have no palette so just read all the color values
311                         for (int index=0;index<m_Width*m_Height;index++)
312                         {
313                                 //since data is stored in BGR we convert it to RGB
314                                 m_pBits[index*4    ] = TempBits[index*3  ];
315                                 m_pBits[index*4 + 1] = TempBits[index*3+1];
316                                 m_pBits[index*4 + 2] = TempBits[index*3+2];
317                                 m_pBits[index*4 + 3] = 255;
318                         }
319
320                         break;
321                 }
322
323                 case 32:
324                 {
325                         //4 channels (32-bit) so there are Width*Height*4 values to read
326                         if (fread (TempBits, sizeof (unsigned char), m_Width*m_Height*4, file) != (unsigned int)(m_Width*m_Height*4))
327                         {
328                                 fclose (file);
329                                 return R_FILE_NOREAD;
330                         }
331
332                         //load a 32 bit image. The 4th channel is the alpha data
333                         //again we convert from BGRA to RGBA
334                         for (int index=0;index<m_Width*m_Height;index++)
335                         {
336                                 m_pBits[index*4    ] = TempBits[index*4  ];
337                                 m_pBits[index*4 + 1] = TempBits[index*4+1];
338                                 m_pBits[index*4 + 2] = TempBits[index*4+2];
339                                 m_pBits[index*4 + 3] = TempBits[index*4+3];
340                         }
341
342                         break;
343                 }
344         }
345
346         //delete all the unwanted:
347         delete [] TempBits;
348
349         return R_OK;
350 }
351
352 void CBitmap::DestroyData ()
353 {
354         if (m_pBits)
355         {
356                 delete [] m_pBits;
357                 m_pBits = NULL;
358         }
359
360         m_Width = m_Height = 0;
361 }