1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 // This software contains source code provided by NVIDIA Corporation.
4 // License: http://developer.download.nvidia.com/licenses/general_license.txt
5 
6 // Modified DDS reader class from NVIDIA SDK
7 ///////////////////////////////////////////////////////////////////////////////
8 //
9 // Description:
10 //
11 // Loads DDS images (DXTC1, DXTC3, DXTC5, RGB (888, 888X), and RGBA (8888) are
12 // supported) for use in OpenGL. Image is flipped when its loaded as DX images
13 // are stored with different coordinate system. If file has mipmaps and/or
14 // cubemaps then these are loaded as well. Volume textures can be loaded as
15 // well but they must be uncompressed.
16 //
17 // When multiple textures are loaded (i.e a volume or cubemap texture),
18 // additional faces can be accessed using the array operator.
19 //
20 // The mipmaps for each face are also stored in a list and can be accessed like
21 // so: image.get_mipmap() (which accesses the first mipmap of the first
22 // image). To get the number of mipmaps call the get_num_mipmaps function for
23 // a given texture.
24 //
25 // Call the is_volume() or is_cubemap() function to check that a loaded image
26 // is a volume or cubemap texture respectively. If a volume texture is loaded
27 // then the get_depth() function should return a number greater than 1.
28 // Mipmapped volume textures and DXTC compressed volume textures are supported.
29 //
30 ///////////////////////////////////////////////////////////////////////////////
31 //
32 // Update: 9/15/2003
33 //
34 // Added functions to create new image from a buffer of pixels. Added function
35 // to save current image to disk.
36 //
37 // Update: 6/11/2002
38 //
39 // Added some convenience functions to handle uploading textures to OpenGL. The
40 // following functions have been added:
41 //
42 //     bool upload_texture1D();
43 //     bool upload_texture2D(unsigned int imageIndex = 0, GLenum target = GL_TEXTURE_2D);
44 //     bool upload_textureRectangle();
45 //     bool upload_texture3D();
46 //     bool upload_textureCubemap();
47 //
48 // See function implementation below for instructions/comments on using each
49 // function.
50 //
51 // The open function has also been updated to take an optional second parameter
52 // specifying whether the image should be flipped on load. This defaults to
53 // true.
54 //
55 ///////////////////////////////////////////////////////////////////////////////
56 // Sample usage
57 ///////////////////////////////////////////////////////////////////////////////
58 //
59 // Loading a compressed texture:
60 //
61 // CDDSImage image;
62 // GLuint texobj;
63 //
64 // image.load("compressed.dds");
65 //
66 // glGenTextures(1, &texobj);
67 // glEnable(GL_TEXTURE_2D);
68 // glBindTexture(GL_TEXTURE_2D, texobj);
69 //
70 // glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, image.get_format(),
71 //     image.get_width(), image.get_height(), 0, image.get_size(),
72 //     image);
73 //
74 // for (int i = 0; i < image.get_num_mipmaps(); i++)
75 // {
76 //     CSurface mipmap = image.get_mipmap(i);
77 //
78 //     glCompressedTexImage2DARB(GL_TEXTURE_2D, i+1, image.get_format(),
79 //         mipmap.get_width(), mipmap.get_height(), 0, mipmap.get_size(),
80 //         mipmap);
81 // }
82 ///////////////////////////////////////////////////////////////////////////////
83 //
84 // Loading an uncompressed texture:
85 //
86 // CDDSImage image;
87 // GLuint texobj;
88 //
89 // image.load("uncompressed.dds");
90 //
91 // glGenTextures(1, &texobj);
92 // glEnable(GL_TEXTURE_2D);
93 // glBindTexture(GL_TEXTURE_2D, texobj);
94 //
95 // glTexImage2D(GL_TEXTURE_2D, 0, image.get_components(), image.get_width(),
96 //     image.get_height(), 0, image.get_format(), GL_UNSIGNED_BYTE, image);
97 //
98 // for (int i = 0; i < image.get_num_mipmaps(); i++)
99 // {
100 //     glTexImage2D(GL_TEXTURE_2D, i+1, image.get_components(),
101 //         image.get_mipmap(i).get_width(), image.get_mipmap(i).get_height(),
102 //         0, image.get_format(), GL_UNSIGNED_BYTE, image.get_mipmap(i));
103 // }
104 //
105 ///////////////////////////////////////////////////////////////////////////////
106 //
107 // Loading an uncompressed cubemap texture:
108 //
109 // CDDSImage image;
110 // GLuint texobj;
111 // GLenum target;
112 //
113 // image.load("cubemap.dds");
114 //
115 // glGenTextures(1, &texobj);
116 // glEnable(GL_TEXTURE_CUBE_MAP_ARB);
117 // glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, texobj);
118 //
119 // for (int n = 0; n < 6; n++)
120 // {
121 //     target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB+n;
122 //
123 //     glTexImage2D(target, 0, image.get_components(), image[n].get_width(),
124 //         image[n].get_height(), 0, image.get_format(), GL_UNSIGNED_BYTE,
125 //         image[n]);
126 //
127 //     for (int i = 0; i < image[n].get_num_mipmaps(); i++)
128 //     {
129 //         glTexImage2D(target, i+1, image.get_components(),
130 //             image[n].get_mipmap(i).get_width(),
131 //             image[n].get_mipmap(i).get_height(), 0,
132 //             image.get_format(), GL_UNSIGNED_BYTE, image[n].get_mipmap(i));
133 //     }
134 // }
135 //
136 ///////////////////////////////////////////////////////////////////////////////
137 //
138 // Loading a volume texture:
139 //
140 // CDDSImage image;
141 // GLuint texobj;
142 //
143 // image.load("volume.dds");
144 //
145 // glGenTextures(1, &texobj);
146 // glEnable(GL_TEXTURE_3D);
147 // glBindTexture(GL_TEXTURE_3D, texobj);
148 //
149 // PFNGLTEXIMAGE3DPROC glTexImage3D;
150 // glTexImage3D(GL_TEXTURE_3D, 0, image.get_components(), image.get_width(),
151 //     image.get_height(), image.get_depth(), 0, image.get_format(),
152 //     GL_UNSIGNED_BYTE, image);
153 //
154 // for (int i = 0; i < image.get_num_mipmaps(); i++)
155 // {
156 //     glTexImage3D(GL_TEXTURE_3D, i+1, image.get_components(),
157 //         image[0].get_mipmap(i).get_width(),
158 //         image[0].get_mipmap(i).get_height(),
159 //         image[0].get_mipmap(i).get_depth(), 0, image.get_format(),
160 //         GL_UNSIGNED_BYTE, image[0].get_mipmap(i));
161 // }
162 
163 #include <stdio.h>
164 #include <string.h>
165 #include <assert.h>
166 
167 // spring related
168 #include "Rendering/GL/myGL.h"
169 #include "nv_dds.h"
170 #include "System/FileSystem/FileHandler.h"
171 #include "System/Platform/byteorder.h"
172 #include "System/Log/ILog.h"
173 
174 using namespace std;
175 using namespace nv_dds;
176 
177 ///////////////////////////////////////////////////////////////////////////////
178 // CDDSImage public functions
179 
180 ///////////////////////////////////////////////////////////////////////////////
181 // default constructor
CDDSImage()182 CDDSImage::CDDSImage()
183   : m_format(0),
184     m_components(0),
185     m_type(TextureNone),
186     m_valid(false)
187 {
188 }
189 
~CDDSImage()190 CDDSImage::~CDDSImage()
191 {
192 }
193 
create_textureFlat(unsigned int format,unsigned int components,const CTexture & baseImage)194 void CDDSImage::create_textureFlat(unsigned int format, unsigned int components, const CTexture &baseImage)
195 {
196     assert(format != 0);
197     assert(components != 0);
198     assert(baseImage.get_depth() == 1);
199 
200     // remove any existing images
201     clear();
202 
203     m_format = format;
204     m_components = components;
205     m_type = TextureFlat;
206 
207     m_images.push_back(baseImage);
208 
209     m_valid = true;
210 }
211 
create_texture3D(unsigned int format,unsigned int components,const CTexture & baseImage)212 void CDDSImage::create_texture3D(unsigned int format, unsigned int components, const CTexture &baseImage)
213 {
214     assert(format != 0);
215     assert(components != 0);
216     assert(baseImage.get_depth() > 1);
217 
218     // remove any existing images
219     clear();
220 
221     m_format = format;
222     m_components = components;
223     m_type = Texture3D;
224 
225     m_images.push_back(baseImage);
226 
227     m_valid = true;
228 }
229 
same_size(const CTexture & a,const CTexture & b)230 inline bool same_size(const CTexture &a, const CTexture &b)
231 {
232     if (a.get_width() != b.get_width())
233         return false;
234     if (a.get_height() != b.get_height())
235         return false;
236     if (a.get_depth() != b.get_depth())
237         return false;
238 
239     return true;
240 }
241 
create_textureCubemap(unsigned int format,unsigned int components,const CTexture & positiveX,const CTexture & negativeX,const CTexture & positiveY,const CTexture & negativeY,const CTexture & positiveZ,const CTexture & negativeZ)242 void CDDSImage::create_textureCubemap(unsigned int format, unsigned int components,
243                                       const CTexture &positiveX, const CTexture &negativeX,
244                                       const CTexture &positiveY, const CTexture &negativeY,
245                                       const CTexture &positiveZ, const CTexture &negativeZ)
246 {
247     assert(format != 0);
248     assert(components != 0);
249     assert(positiveX.get_depth() == 1);
250 
251     // verify that all dimensions are the same
252     assert(same_size(positiveX, negativeX));
253     assert(same_size(positiveX, positiveY));
254     assert(same_size(positiveX, negativeY));
255     assert(same_size(positiveX, positiveZ));
256     assert(same_size(positiveX, negativeZ));
257 
258     // remove any existing images
259     clear();
260 
261     m_format = format;
262     m_components = components;
263     m_type = TextureCubemap;
264 
265     m_images.push_back(positiveX);
266     m_images.push_back(negativeX);
267     m_images.push_back(positiveY);
268     m_images.push_back(negativeY);
269     m_images.push_back(positiveZ);
270     m_images.push_back(negativeZ);
271 
272     m_valid = true;
273 }
274 
275 ///////////////////////////////////////////////////////////////////////////////
276 // loads DDS image
277 //
278 // filename - fully qualified name of DDS image
279 // flipImage - specifies whether image is flipped on load, default is true
load(string filename,bool flipImage)280 bool CDDSImage::load(string filename, bool flipImage)
281 {
282     assert(filename.length() != 0);
283 
284     // clear any previously loaded images
285     clear();
286 
287     // open file
288    // FILE *fp = fopen(filename.c_str(), "rb");
289 	CFileHandler file(filename);
290 
291 	if (!file.FileExists())
292         return false;
293 
294     // read in file marker, make sure its a DDS file
295     char filecode[4];
296     //fread(filecode, 1, 4, fp);
297 	file.Read(filecode, 4);
298     if (strncmp(filecode, "DDS ", 4) != 0)
299     {
300         //fclose(fp);
301         return false;
302     }
303 
304     // read in DDS header
305     DDS_HEADER ddsh;
306     //fread(&ddsh, sizeof(DDS_HEADER), 1, fp);
307     int tmp = sizeof(unsigned int);
308     file.Read(&ddsh.dwSize, tmp);
309     file.Read(&ddsh.dwFlags, tmp);
310     file.Read(&ddsh.dwHeight, tmp);
311     file.Read(&ddsh.dwWidth, tmp);
312     file.Read(&ddsh.dwPitchOrLinearSize, tmp);
313     file.Read(&ddsh.dwDepth, tmp);
314     file.Read(&ddsh.dwMipMapCount, tmp);
315     file.Read(&ddsh.dwReserved1, tmp*11);
316     file.Read(&ddsh.ddspf.dwSize, tmp);
317     file.Read(&ddsh.ddspf.dwFlags, tmp);
318     file.Read(&ddsh.ddspf.dwFourCC, tmp);
319     file.Read(&ddsh.ddspf.dwRGBBitCount, tmp);
320     file.Read(&ddsh.ddspf.dwRBitMask, tmp);
321     file.Read(&ddsh.ddspf.dwGBitMask, tmp);
322     file.Read(&ddsh.ddspf.dwBBitMask, tmp);
323     file.Read(&ddsh.ddspf.dwABitMask, tmp);
324     file.Read(&ddsh.dwCaps1, tmp);
325     file.Read(&ddsh.dwCaps2, tmp);
326     file.Read(&ddsh.dwReserved2, tmp*3);
327 
328     ddsh.dwSize = swabdword(ddsh.dwSize);
329     ddsh.dwFlags = swabdword(ddsh.dwFlags);
330     ddsh.dwHeight = swabdword(ddsh.dwHeight);
331     ddsh.dwWidth = swabdword(ddsh.dwWidth);
332     ddsh.dwPitchOrLinearSize = swabdword(ddsh.dwPitchOrLinearSize);
333     ddsh.dwDepth = swabdword(ddsh.dwDepth);
334     ddsh.dwMipMapCount = swabdword(ddsh.dwMipMapCount);
335     ddsh.ddspf.dwSize = swabdword(ddsh.ddspf.dwSize);
336     ddsh.ddspf.dwFlags = swabdword(ddsh.ddspf.dwFlags);
337     ddsh.ddspf.dwFourCC = swabdword(ddsh.ddspf.dwFourCC);
338     ddsh.ddspf.dwRGBBitCount = swabdword(ddsh.ddspf.dwRGBBitCount);
339     ddsh.ddspf.dwRBitMask = swabdword(ddsh.ddspf.dwRBitMask);
340     ddsh.ddspf.dwGBitMask = swabdword(ddsh.ddspf.dwGBitMask);
341     ddsh.ddspf.dwBBitMask = swabdword(ddsh.ddspf.dwBBitMask);
342     ddsh.ddspf.dwABitMask = swabdword(ddsh.ddspf.dwABitMask);
343     ddsh.dwCaps1 = swabdword(ddsh.dwCaps1);
344     ddsh.dwCaps2 = swabdword(ddsh.dwCaps2);
345 
346     // default to flat texture type (1D, 2D, or rectangle)
347     m_type = TextureFlat;
348 
349     // check if image is a cubemap
350     if (ddsh.dwCaps2 & DDSF_CUBEMAP)
351         m_type = TextureCubemap;
352 
353     // check if image is a volume texture
354     if ((ddsh.dwCaps2 & DDSF_VOLUME) && (ddsh.dwDepth > 0))
355         m_type = Texture3D;
356 
357     // figure out what the image format is
358     if (ddsh.ddspf.dwFlags & DDSF_FOURCC)
359     {
360         switch(ddsh.ddspf.dwFourCC)
361         {
362             case FOURCC_DXT1:
363                 m_format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
364                 m_components = 3;
365                 break;
366             case FOURCC_DXT3:
367                 m_format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
368                 m_components = 4;
369                 break;
370             case FOURCC_DXT5:
371                 m_format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
372                 m_components = 4;
373                 break;
374             default:
375                 //fclose(fp);
376                 return false;
377         }
378     }
379     else if (ddsh.ddspf.dwFlags == DDSF_RGBA && ddsh.ddspf.dwRGBBitCount == 32)
380     {
381         m_format = GL_BGRA_EXT;
382         m_components = 4;
383     }
384     else if (ddsh.ddspf.dwFlags == DDSF_RGB  && ddsh.ddspf.dwRGBBitCount == 32)
385     {
386         m_format = GL_BGRA_EXT;
387         m_components = 4;
388     }
389     else if (ddsh.ddspf.dwFlags == DDSF_RGB  && ddsh.ddspf.dwRGBBitCount == 24)
390     {
391         m_format = GL_BGR_EXT;
392         m_components = 3;
393     }
394 	else if (ddsh.ddspf.dwRGBBitCount == 8)
395 	{
396 		m_format = GL_LUMINANCE;
397 		m_components = 1;
398 	}
399     else
400     {
401         //fclose(fp);
402         return false;
403     }
404 
405     // store primary surface width/height/depth
406     unsigned int width, height, depth;
407     width = ddsh.dwWidth;
408     height = ddsh.dwHeight;
409     depth = clamp_size(ddsh.dwDepth);   // set to 1 if 0
410 
411     // use correct size calculation function depending on whether image is
412     // compressed
413     unsigned int (CDDSImage::*sizefunc)(unsigned int, unsigned int);
414     sizefunc = (is_compressed() ? &CDDSImage::size_dxtc : &CDDSImage::size_rgb);
415 
416     // load all surfaces for the image (6 surfaces for cubemaps)
417     for (unsigned int n = 0; n < (unsigned int)(m_type == TextureCubemap ? 6 : 1); n++)
418     {
419         // add empty texture object
420         m_images.push_back(CTexture());
421 
422         // get reference to newly added texture object
423         CTexture &img = m_images[n];
424 
425         // calculate surface size
426         unsigned int size = (this->*sizefunc)(width, height)*depth;
427 
428         // load surface
429         unsigned char *pixels = new unsigned char[size];
430         //fread(pixels, 1, size, fp);
431 		file.Read(pixels, size);
432 
433         img.create(width, height, depth, size, pixels);
434 
435         delete [] pixels;
436 
437         if (flipImage) flip(img);
438 
439         unsigned int w = clamp_size(width >> 1);
440         unsigned int h = clamp_size(height >> 1);
441         unsigned int d = clamp_size(depth >> 1);
442 
443         // store number of mipmaps
444         unsigned int numMipmaps = ddsh.dwMipMapCount;
445 
446         // number of mipmaps in file includes main surface so decrease count
447         // by one
448         if (numMipmaps != 0)
449             numMipmaps--;
450 
451         // load all mipmaps for current surface
452         for (unsigned int i = 0; i < numMipmaps && (w || h); i++)
453         {
454             // add empty surface
455             img.add_mipmap(CSurface());
456 
457             // get reference to newly added mipmap
458             CSurface &mipmap = img.get_mipmap(i);
459 
460             // calculate mipmap size
461             size = (this->*sizefunc)(w, h)*d;
462 
463             unsigned char *pixels = new unsigned char[size];
464             //fread(pixels, 1, size, fp);
465 			file.Read(pixels, size);
466 
467             mipmap.create(w, h, d, size, pixels);
468 
469             delete [] pixels;
470 
471             if (flipImage) flip(mipmap);
472 
473             // shrink to next power of 2
474             w = clamp_size(w >> 1);
475             h = clamp_size(h >> 1);
476             d = clamp_size(d >> 1);
477         }
478     }
479 
480     // swap cubemaps on y axis (since image is flipped in OGL)
481     if (m_type == TextureCubemap && flipImage)
482     {
483         CTexture tmp;
484         tmp = m_images[3];
485         m_images[3] = m_images[2];
486         m_images[2] = tmp;
487     }
488 
489     //fclose(fp);
490 
491     m_valid = true;
492 
493     return true;
494 }
495 
write_texture(const CTexture & texture,FILE * fp)496 bool CDDSImage::write_texture(const CTexture &texture, FILE *fp)
497 {
498     assert(get_num_mipmaps() == texture.get_num_mipmaps());
499 
500     int res = fwrite(texture, 1, texture.get_size(), fp);
501     if (res<0) {
502         return false;
503     }
504     for (unsigned int i = 0; i < texture.get_num_mipmaps(); i++)
505     {
506         const CSurface &mipmap = texture.get_mipmap(i);
507         res = fwrite(mipmap, 1, mipmap.get_size(), fp);
508         if (res<0) {
509             return false;
510         }
511     }
512     return true;
513 }
514 
save(std::string filename,bool flipImage)515 bool CDDSImage::save(std::string filename, bool flipImage)
516 {
517     assert(m_valid);
518     assert(m_type != TextureNone);
519 
520     DDS_HEADER ddsh;
521     unsigned int headerSize = sizeof(DDS_HEADER);
522     memset(&ddsh, 0, headerSize);
523     ddsh.dwSize = headerSize;
524     ddsh.dwFlags = DDSF_CAPS | DDSF_WIDTH | DDSF_HEIGHT | DDSF_PIXELFORMAT;
525     ddsh.dwHeight = get_height();
526     ddsh.dwWidth = get_width();
527 
528     if (is_compressed())
529     {
530         ddsh.dwFlags |= DDSF_LINEARSIZE;
531         ddsh.dwPitchOrLinearSize = get_size();
532     }
533     else
534     {
535         ddsh.dwFlags |= DDSF_PITCH;
536         ddsh.dwPitchOrLinearSize = get_dword_aligned_linesize(get_width(), m_components * 8);
537     }
538 
539     if (m_type == Texture3D)
540     {
541         ddsh.dwFlags |= DDSF_DEPTH;
542         ddsh.dwDepth = get_depth();
543     }
544 
545     if (get_num_mipmaps() > 0)
546     {
547         ddsh.dwFlags |= DDSF_MIPMAPCOUNT;
548         ddsh.dwMipMapCount = get_num_mipmaps() + 1;
549     }
550 
551     ddsh.ddspf.dwSize = sizeof(DDS_PIXELFORMAT);
552 
553     if (is_compressed())
554     {
555         ddsh.ddspf.dwFlags = DDSF_FOURCC;
556 
557         if (m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
558             ddsh.ddspf.dwFourCC = FOURCC_DXT1;
559         if (m_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)
560             ddsh.ddspf.dwFourCC = FOURCC_DXT3;
561         if (m_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
562             ddsh.ddspf.dwFourCC = FOURCC_DXT5;
563     }
564     else
565     {
566         ddsh.ddspf.dwFlags = (m_components == 4) ? DDSF_RGBA : DDSF_RGB;
567         ddsh.ddspf.dwRGBBitCount = m_components * 8;
568         ddsh.ddspf.dwRBitMask = 0x00ff0000;
569         ddsh.ddspf.dwGBitMask = 0x0000ff00;
570         ddsh.ddspf.dwBBitMask = 0x000000ff;
571 
572         if (m_components == 4)
573         {
574             ddsh.ddspf.dwFlags |= DDSF_ALPHAPIXELS;
575             ddsh.ddspf.dwABitMask = 0xff000000;
576         }
577     }
578 
579     ddsh.dwCaps1 = DDSF_TEXTURE;
580 
581     if (m_type == TextureCubemap)
582     {
583         ddsh.dwCaps1 |= DDSF_COMPLEX;
584         ddsh.dwCaps2 = DDSF_CUBEMAP | DDSF_CUBEMAP_ALL_FACES;
585     }
586 
587     if (m_type == Texture3D)
588     {
589         ddsh.dwCaps1 |= DDSF_COMPLEX;
590         ddsh.dwCaps2 = DDSF_VOLUME;
591     }
592 
593     if (get_num_mipmaps() > 0)
594         ddsh.dwCaps1 |= DDSF_COMPLEX | DDSF_MIPMAP;
595 
596     // open file
597     FILE *fp = fopen(filename.c_str(), "wb");
598     if (fp == NULL) {
599         LOG_L(L_ERROR, "couldn't create texture %s", filename.c_str());
600         return false;
601     }
602 
603     // write file header
604     int res = fwrite("DDS ", 1, 4, fp);
605     if (res<0) {
606         fclose(fp);
607         return false;
608     }
609 
610     // write dds header
611     res = fwrite(&ddsh, 1, sizeof(DDS_HEADER), fp);
612     if (res<0) {
613         fclose(fp);
614         return false;
615     }
616 
617     if (m_type != TextureCubemap)
618     {
619         CTexture tex = m_images[0];
620         if (flipImage) flip_texture(tex);
621         if (!write_texture(tex, fp)) {
622             LOG_L(L_ERROR, "couldn't write texture %s: %s",filename.c_str(), strerror(ferror(fp)));
623             fclose(fp);
624             return false;
625 	}
626     }
627     else
628     {
629         assert(m_images.size() == 6);
630 
631         for (unsigned int i = 0; i < m_images.size(); i++)
632         {
633             CTexture cubeFace;
634 
635             if (i == 2)
636                 cubeFace = m_images[3];
637             else if (i == 3)
638                 cubeFace = m_images[2];
639             else
640                 cubeFace = m_images[i];
641 
642             if (flipImage) flip_texture(cubeFace);
643             write_texture(cubeFace, fp);
644         }
645     }
646 
647     fclose(fp);
648     return true;
649 }
650 
651 ///////////////////////////////////////////////////////////////////////////////
652 // free image memory
clear()653 void CDDSImage::clear()
654 {
655     m_components = 0;
656     m_format = 0;
657     m_type = TextureNone;
658     m_valid = false;
659 
660     m_images.clear();
661 }
662 
is_compressed() const663 bool CDDSImage::is_compressed() const
664 {
665 	if ((m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
666 		(m_format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) ||
667 		(m_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT))
668 		return true;
669 	else
670 		return false;
671 }
672 
673 #ifndef BITMAP_NO_OPENGL
674 
675 ///////////////////////////////////////////////////////////////////////////////
676 // uploads a compressed/uncompressed 1D texture
upload_texture1D()677 bool CDDSImage::upload_texture1D()
678 {
679     assert(m_valid);
680     assert(!m_images.empty());
681 
682     const CTexture &baseImage = m_images[0];
683 
684     assert(baseImage.get_height() == 1);
685     assert(baseImage.get_width() > 0);
686 
687     if (is_compressed())
688     {
689         glCompressedTexImage1DARB(GL_TEXTURE_1D, 0, m_format,
690             baseImage.get_width(), 0, baseImage.get_size(), baseImage);
691 
692         // load all mipmaps
693         for (unsigned int i = 0; i < baseImage.get_num_mipmaps(); i++)
694         {
695             const CSurface &mipmap = baseImage.get_mipmap(i);
696             glCompressedTexImage1DARB(GL_TEXTURE_1D, i+1, m_format,
697                 mipmap.get_width(), 0, mipmap.get_size(), mipmap);
698         }
699     }
700     else
701     {
702         GLint alignment = -1;
703         if (!is_dword_aligned())
704         {
705             glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
706             glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
707         }
708 
709         glTexImage1D(GL_TEXTURE_1D, 0, m_components, baseImage.get_width(), 0,
710             m_format, GL_UNSIGNED_BYTE, baseImage);
711 
712         // load all mipmaps
713         for (unsigned int i = 0; i < baseImage.get_num_mipmaps(); i++)
714         {
715             const CSurface &mipmap = baseImage.get_mipmap(i);
716 
717             glTexImage1D(GL_TEXTURE_1D, i+1, m_components,
718                 mipmap.get_width(), 0, m_format, GL_UNSIGNED_BYTE, mipmap);
719         }
720 
721         if (alignment != -1)
722             glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
723     }
724 
725     return true;
726 }
727 
728 ///////////////////////////////////////////////////////////////////////////////
729 // uploads a compressed/uncompressed 2D texture
730 //
731 // imageIndex - allows you to optionally specify other loaded surfaces for 2D
732 //              textures such as a face in a cubemap or a slice in a volume
733 //
734 //              default: 0
735 //
736 // target     - allows you to optionally specify a different texture target for
737 //              the 2D texture such as a specific face of a cubemap
738 //
739 //              default: GL_TEXTURE_2D
upload_texture2D(unsigned int imageIndex,int target)740 bool CDDSImage::upload_texture2D(unsigned int imageIndex, int target)
741 {
742     assert(m_valid);
743     assert(!m_images.empty());
744     assert(imageIndex >= 0);
745     assert(imageIndex < m_images.size());
746     assert(m_images[imageIndex]);
747 
748     const CTexture &image = m_images[imageIndex];
749 
750     assert(image.get_height() > 0);
751     assert(image.get_width() > 0);
752     assert(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_NV ||
753         (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
754          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB));
755 
756     if (is_compressed())
757     {
758         glCompressedTexImage2DARB(target, 0, m_format, image.get_width(),
759             image.get_height(), 0, image.get_size(), image);
760 
761         // load all mipmaps
762         for (unsigned int i = 0; i < image.get_num_mipmaps(); i++)
763         {
764             const CSurface &mipmap = image.get_mipmap(i);
765             glCompressedTexImage2DARB(target, i+1, m_format,
766                 mipmap.get_width(), mipmap.get_height(), 0,
767                 mipmap.get_size(), mipmap);
768         }
769     }
770     else
771     {
772         GLint alignment = -1;
773         if (!is_dword_aligned())
774         {
775             glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
776             glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
777         }
778 
779         glTexImage2D(target, 0, m_components, image.get_width(),
780             image.get_height(), 0, m_format, GL_UNSIGNED_BYTE,
781             image);
782 
783         // load all mipmaps
784         for (unsigned int i = 0; i < image.get_num_mipmaps(); i++)
785         {
786             const CSurface &mipmap = image.get_mipmap(i);
787 
788             glTexImage2D(target, i+1, m_components, mipmap.get_width(),
789                 mipmap.get_height(), 0, m_format, GL_UNSIGNED_BYTE, mipmap);
790         }
791 
792         if (alignment != -1)
793             glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
794     }
795 
796     return true;
797 }
798 
799 ///////////////////////////////////////////////////////////////////////////////
800 // uploads a compressed/uncompressed 3D texture
upload_texture3D()801 bool CDDSImage::upload_texture3D()
802 {
803     assert(m_valid);
804     assert(!m_images.empty());
805     assert(m_type == Texture3D);
806 
807     const CTexture &baseImage = m_images[0];
808 
809     assert(baseImage.get_depth() >= 1);
810 
811     if (is_compressed())
812     {
813         glCompressedTexImage3DARB(GL_TEXTURE_3D, 0, m_format,
814             baseImage.get_width(), baseImage.get_height(), baseImage.get_depth(),
815             0, baseImage.get_size(), baseImage);
816 
817         // load all mipmap volumes
818         for (unsigned int i = 0; i < baseImage.get_num_mipmaps(); i++)
819         {
820             const CSurface &mipmap = baseImage.get_mipmap(i);
821             glCompressedTexImage3DARB(GL_TEXTURE_3D, i+1, m_format,
822                 mipmap.get_width(), mipmap.get_height(), mipmap.get_depth(),
823                 0, mipmap.get_size(), mipmap);
824         }
825     }
826     else
827     {
828         GLint alignment = -1;
829         if (!is_dword_aligned())
830         {
831             glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
832             glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
833         }
834 
835         glTexImage3D(GL_TEXTURE_3D, 0, m_components, baseImage.get_width(),
836             baseImage.get_height(), baseImage.get_depth(), 0, m_format,
837             GL_UNSIGNED_BYTE, baseImage);
838 
839         // load all mipmap volumes
840         for (unsigned int i = 0; i < baseImage.get_num_mipmaps(); i++)
841         {
842             const CSurface &mipmap = baseImage.get_mipmap(i);
843 
844             glTexImage3D(GL_TEXTURE_3D, i+1, m_components,
845                 mipmap.get_width(), mipmap.get_height(), mipmap.get_depth(), 0,
846                 m_format, GL_UNSIGNED_BYTE,  mipmap);
847         }
848 
849         if (alignment != -1)
850             glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
851     }
852 
853     return true;
854 }
855 
upload_textureRectangle()856 bool CDDSImage::upload_textureRectangle()
857 {
858     return upload_texture2D(0, GL_TEXTURE_RECTANGLE_NV);
859 }
860 
861 ///////////////////////////////////////////////////////////////////////////////
862 // uploads a compressed/uncompressed cubemap texture
upload_textureCubemap()863 bool CDDSImage::upload_textureCubemap()
864 {
865     assert(m_valid);
866     assert(!m_images.empty());
867     assert(m_type == TextureCubemap);
868     assert(m_images.size() == 6);
869 
870     GLenum target;
871 
872     // loop through cubemap faces and load them as 2D textures
873     for (unsigned int n = 0; n < 6; n++)
874     {
875         // specify cubemap face
876         target = GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + n;
877         if (!upload_texture2D(n, target))
878             return false;
879     }
880 
881     return true;
882 }
883 
884 #endif // !BITMAP_NO_OPENGL
885 
886 ///////////////////////////////////////////////////////////////////////////////
887 // clamps input size to [1-size]
clamp_size(unsigned int size)888 inline unsigned int CDDSImage::clamp_size(unsigned int size)
889 {
890     if (size <= 0)
891         size = 1;
892 
893     return size;
894 }
895 
896 ///////////////////////////////////////////////////////////////////////////////
897 // CDDSImage private functions
898 ///////////////////////////////////////////////////////////////////////////////
899 
900 ///////////////////////////////////////////////////////////////////////////////
901 // calculates size of DXTC texture in bytes
size_dxtc(unsigned int width,unsigned int height)902 inline unsigned int CDDSImage::size_dxtc(unsigned int width, unsigned int height)
903 {
904     return ((width+3)/4)*((height+3)/4)*
905         (m_format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);
906 }
907 
908 ///////////////////////////////////////////////////////////////////////////////
909 // calculates size of uncompressed RGB texture in bytes
size_rgb(unsigned int width,unsigned int height)910 inline unsigned int CDDSImage::size_rgb(unsigned int width, unsigned int height)
911 {
912     return width*height*m_components;
913 }
914 
915 ///////////////////////////////////////////////////////////////////////////////
916 // flip image around X axis
flip(CSurface & surface)917 void CDDSImage::flip(CSurface &surface)
918 {
919     unsigned int linesize;
920 
921     if (!is_compressed())
922     {
923         assert(surface.get_depth() > 0);
924 
925         unsigned int imagesize = surface.get_size()/surface.get_depth();
926         linesize = imagesize / surface.get_height();
927 
928         for (unsigned int n = 0; n < surface.get_depth(); n++)
929         {
930             unsigned int offset = imagesize*n;
931             unsigned char *top = (unsigned char*)surface + offset;
932             unsigned char *bottom = top + (imagesize-linesize);
933 
934             for (unsigned int i = 0; i < (surface.get_height() >> 1); i++)
935             {
936                 swap(bottom, top, linesize);
937 
938                 top += linesize;
939                 bottom -= linesize;
940             }
941         }
942     }
943     else
944     {
945         void (CDDSImage::*flipblocks)(DXTColBlock*, unsigned int);
946         unsigned int xblocks = surface.get_width() / 4;
947         unsigned int yblocks = surface.get_height() / 4;
948         unsigned int blocksize;
949 
950         switch (m_format)
951         {
952             case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
953                 blocksize = 8;
954                 flipblocks = &CDDSImage::flip_blocks_dxtc1;
955                 break;
956             case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
957                 blocksize = 16;
958                 flipblocks = &CDDSImage::flip_blocks_dxtc3;
959                 break;
960             case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
961                 blocksize = 16;
962                 flipblocks = &CDDSImage::flip_blocks_dxtc5;
963                 break;
964             default:
965                 return;
966         }
967 
968         linesize = xblocks * blocksize;
969 
970         DXTColBlock *top;
971         DXTColBlock *bottom;
972 
973         for (unsigned int j = 0; j < (yblocks >> 1); j++)
974         {
975             top = (DXTColBlock*)((unsigned char*)surface+ j * linesize);
976             bottom = (DXTColBlock*)((unsigned char*)surface + (((yblocks-j)-1) * linesize));
977 
978             (this->*flipblocks)(top, xblocks);
979             (this->*flipblocks)(bottom, xblocks);
980 
981             swap(bottom, top, linesize);
982         }
983     }
984 }
985 
flip_texture(CTexture & texture)986 void CDDSImage::flip_texture(CTexture &texture)
987 {
988     flip(texture);
989 
990     for (unsigned int i = 0; i < texture.get_num_mipmaps(); i++)
991     {
992         flip(texture.get_mipmap(i));
993     }
994 }
995 
996 ///////////////////////////////////////////////////////////////////////////////
997 // swap to sections of memory
swap(void * byte1,void * byte2,unsigned int size)998 void CDDSImage::swap(void *byte1, void *byte2, unsigned int size)
999 {
1000     unsigned char *tmp = new unsigned char[size];
1001 
1002     memcpy(tmp, byte1, size);
1003     memcpy(byte1, byte2, size);
1004     memcpy(byte2, tmp, size);
1005 
1006     delete [] tmp;
1007 }
1008 
1009 ///////////////////////////////////////////////////////////////////////////////
1010 // flip a DXT1 color block
flip_blocks_dxtc1(DXTColBlock * line,unsigned int numBlocks)1011 void CDDSImage::flip_blocks_dxtc1(DXTColBlock *line, unsigned int numBlocks)
1012 {
1013     DXTColBlock *curblock = line;
1014 
1015     for (unsigned int i = 0; i < numBlocks; i++)
1016     {
1017         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
1018         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
1019 
1020         curblock++;
1021     }
1022 }
1023 
1024 ///////////////////////////////////////////////////////////////////////////////
1025 // flip a DXT3 color block
flip_blocks_dxtc3(DXTColBlock * line,unsigned int numBlocks)1026 void CDDSImage::flip_blocks_dxtc3(DXTColBlock *line, unsigned int numBlocks)
1027 {
1028     DXTColBlock *curblock = line;
1029     DXT3AlphaBlock *alphablock;
1030 
1031     for (unsigned int i = 0; i < numBlocks; i++)
1032     {
1033         alphablock = reinterpret_cast<DXT3AlphaBlock*>(curblock);
1034 
1035         swap(&alphablock->row[0], &alphablock->row[3], sizeof(unsigned short));
1036         swap(&alphablock->row[1], &alphablock->row[2], sizeof(unsigned short));
1037 
1038         curblock++;
1039 
1040         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
1041         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
1042 
1043         curblock++;
1044     }
1045 }
1046 
1047 ///////////////////////////////////////////////////////////////////////////////
1048 // flip a DXT5 alpha block
flip_dxt5_alpha(DXT5AlphaBlock * block)1049 void CDDSImage::flip_dxt5_alpha(DXT5AlphaBlock *block)
1050 {
1051     unsigned char gBits[4][4];
1052 
1053     const unsigned int mask = 0x00000007;          // bits = 00 00 01 11
1054     unsigned int bits = 0;
1055     memcpy(&bits, &block->row[0], sizeof(unsigned char) * 3);
1056 
1057     gBits[0][0] = (unsigned char)(bits & mask);
1058     bits >>= 3;
1059     gBits[0][1] = (unsigned char)(bits & mask);
1060     bits >>= 3;
1061     gBits[0][2] = (unsigned char)(bits & mask);
1062     bits >>= 3;
1063     gBits[0][3] = (unsigned char)(bits & mask);
1064     bits >>= 3;
1065     gBits[1][0] = (unsigned char)(bits & mask);
1066     bits >>= 3;
1067     gBits[1][1] = (unsigned char)(bits & mask);
1068     bits >>= 3;
1069     gBits[1][2] = (unsigned char)(bits & mask);
1070     bits >>= 3;
1071     gBits[1][3] = (unsigned char)(bits & mask);
1072 
1073     bits = 0;
1074     memcpy(&bits, &block->row[3], sizeof(unsigned char) * 3);
1075 
1076     gBits[2][0] = (unsigned char)(bits & mask);
1077     bits >>= 3;
1078     gBits[2][1] = (unsigned char)(bits & mask);
1079     bits >>= 3;
1080     gBits[2][2] = (unsigned char)(bits & mask);
1081     bits >>= 3;
1082     gBits[2][3] = (unsigned char)(bits & mask);
1083     bits >>= 3;
1084     gBits[3][0] = (unsigned char)(bits & mask);
1085     bits >>= 3;
1086     gBits[3][1] = (unsigned char)(bits & mask);
1087     bits >>= 3;
1088     gBits[3][2] = (unsigned char)(bits & mask);
1089     bits >>= 3;
1090     gBits[3][3] = (unsigned char)(bits & mask);
1091 
1092     memset(block->row, 0, sizeof(unsigned char) * 6);
1093 
1094     unsigned int *pBits = ((unsigned int*) &(block->row[0]));
1095 
1096     *pBits = *pBits | (gBits[3][0] << 0);
1097     *pBits = *pBits | (gBits[3][1] << 3);
1098     *pBits = *pBits | (gBits[3][2] << 6);
1099     *pBits = *pBits | (gBits[3][3] << 9);
1100 
1101     *pBits = *pBits | (gBits[2][0] << 12);
1102     *pBits = *pBits | (gBits[2][1] << 15);
1103     *pBits = *pBits | (gBits[2][2] << 18);
1104     *pBits = *pBits | (gBits[2][3] << 21);
1105 
1106     pBits = ((unsigned int*) &(block->row[3]));
1107 
1108 #ifdef MACOS
1109     *pBits &= 0x000000ff;
1110 #else
1111     *pBits &= 0xff000000;
1112 #endif
1113 
1114     *pBits = *pBits | (gBits[1][0] << 0);
1115     *pBits = *pBits | (gBits[1][1] << 3);
1116     *pBits = *pBits | (gBits[1][2] << 6);
1117     *pBits = *pBits | (gBits[1][3] << 9);
1118 
1119     *pBits = *pBits | (gBits[0][0] << 12);
1120     *pBits = *pBits | (gBits[0][1] << 15);
1121     *pBits = *pBits | (gBits[0][2] << 18);
1122     *pBits = *pBits | (gBits[0][3] << 21);
1123 }
1124 
1125 ///////////////////////////////////////////////////////////////////////////////
1126 // flip a DXT5 color block
flip_blocks_dxtc5(DXTColBlock * line,unsigned int numBlocks)1127 void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, unsigned int numBlocks)
1128 {
1129     DXTColBlock *curblock = line;
1130     DXT5AlphaBlock *alphablock;
1131 
1132     for (unsigned int i = 0; i < numBlocks; i++)
1133     {
1134         alphablock = reinterpret_cast<DXT5AlphaBlock*>(curblock);
1135 
1136         flip_dxt5_alpha(alphablock);
1137 
1138         curblock++;
1139 
1140         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
1141         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
1142 
1143         curblock++;
1144     }
1145 }
1146 
1147 ///////////////////////////////////////////////////////////////////////////////
1148 // CTexture implementation
1149 ///////////////////////////////////////////////////////////////////////////////
1150 
1151 ///////////////////////////////////////////////////////////////////////////////
1152 // default constructor
CTexture()1153 CTexture::CTexture()
1154   : CSurface()  // initialize base class part
1155 {
1156 }
1157 
1158 ///////////////////////////////////////////////////////////////////////////////
1159 // creates an empty texture
CTexture(unsigned int w,unsigned int h,unsigned int d,unsigned int imgsize,const unsigned char * pixels)1160 CTexture::CTexture(unsigned int w, unsigned int h, unsigned int d, unsigned int imgsize, const unsigned char *pixels)
1161   : CSurface(w, h, d, imgsize, pixels)  // initialize base class part
1162 {
1163 }
1164 
~CTexture()1165 CTexture::~CTexture()
1166 {
1167 }
1168 
1169 ///////////////////////////////////////////////////////////////////////////////
1170 // copy constructor
CTexture(const CTexture & copy)1171 CTexture::CTexture(const CTexture &copy)
1172   : CSurface(copy)
1173 {
1174     for (unsigned int i = 0; i < copy.get_num_mipmaps(); i++)
1175         m_mipmaps.push_back(copy.get_mipmap(i));
1176 }
1177 
1178 ///////////////////////////////////////////////////////////////////////////////
1179 // assignment operator
operator =(const CTexture & rhs)1180 CTexture &CTexture::operator= (const CTexture &rhs)
1181 {
1182     if (this != &rhs)
1183     {
1184         CSurface::operator = (rhs);
1185 
1186         m_mipmaps.clear();
1187         for (unsigned int i = 0; i < rhs.get_num_mipmaps(); i++)
1188             m_mipmaps.push_back(rhs.get_mipmap(i));
1189     }
1190 
1191     return *this;
1192 }
1193 
create(unsigned int w,unsigned int h,unsigned int d,unsigned int imgsize,const unsigned char * pixels)1194 void CTexture::create(unsigned int w, unsigned int h, unsigned int d, unsigned int imgsize, const unsigned char *pixels)
1195 {
1196     CSurface::create(w, h, d, imgsize, pixels);
1197 
1198     m_mipmaps.clear();
1199 }
1200 
clear()1201 void CTexture::clear()
1202 {
1203     CSurface::clear();
1204 
1205     m_mipmaps.clear();
1206 }
1207 
1208 ///////////////////////////////////////////////////////////////////////////////
1209 // CSurface implementation
1210 ///////////////////////////////////////////////////////////////////////////////
1211 
1212 ///////////////////////////////////////////////////////////////////////////////
1213 // default constructor
CSurface()1214 CSurface::CSurface()
1215   : m_width(0),
1216     m_height(0),
1217     m_depth(0),
1218     m_size(0),
1219     m_pixels(NULL)
1220 {
1221 }
1222 
1223 ///////////////////////////////////////////////////////////////////////////////
1224 // creates an empty image
CSurface(unsigned int w,unsigned int h,unsigned int d,unsigned int imgsize,const unsigned char * pixels)1225 CSurface::CSurface(unsigned int w, unsigned int h, unsigned int d, unsigned int imgsize, const unsigned char *pixels)
1226   : m_width(0),
1227     m_height(0),
1228     m_depth(0),
1229     m_size(0),
1230     m_pixels(NULL)
1231 {
1232     create(w, h, d, imgsize, pixels);
1233 }
1234 
1235 ///////////////////////////////////////////////////////////////////////////////
1236 // copy constructor
CSurface(const CSurface & copy)1237 CSurface::CSurface(const CSurface &copy)
1238   : m_width(0),
1239     m_height(0),
1240     m_depth(0),
1241     m_size(0),
1242     m_pixels(NULL)
1243 {
1244     if (copy.get_size() != 0)
1245     {
1246         m_size = copy.get_size();
1247         m_width = copy.get_width();
1248         m_height = copy.get_height();
1249         m_depth = copy.get_depth();
1250 
1251         m_pixels = new unsigned char[m_size];
1252         memcpy(m_pixels, copy, m_size);
1253     }
1254 }
1255 
1256 ///////////////////////////////////////////////////////////////////////////////
1257 // assignment operator
operator =(const CSurface & rhs)1258 CSurface &CSurface::operator= (const CSurface &rhs)
1259 {
1260     if (this != &rhs)
1261     {
1262         clear();
1263 
1264         if (rhs.get_size())
1265         {
1266             m_size = rhs.get_size();
1267             m_width = rhs.get_width();
1268             m_height = rhs.get_height();
1269             m_depth = rhs.get_depth();
1270 
1271             m_pixels = new unsigned char[m_size];
1272             memcpy(m_pixels, rhs, m_size);
1273         }
1274     }
1275 
1276     return *this;
1277 }
1278 
1279 ///////////////////////////////////////////////////////////////////////////////
1280 // clean up image memory
~CSurface()1281 CSurface::~CSurface()
1282 {
1283     clear();
1284 }
1285 
1286 ///////////////////////////////////////////////////////////////////////////////
1287 // returns a pointer to image
operator unsigned char*() const1288 CSurface::operator unsigned char*() const
1289 {
1290     return m_pixels;
1291 }
1292 
1293 ///////////////////////////////////////////////////////////////////////////////
1294 // creates an empty image
create(unsigned int w,unsigned int h,unsigned int d,unsigned int imgsize,const unsigned char * pixels)1295 void CSurface::create(unsigned int w, unsigned int h, unsigned int d, unsigned int imgsize, const unsigned char *pixels)
1296 {
1297     assert(w != 0);
1298     assert(h != 0);
1299     assert(d != 0);
1300     assert(imgsize != 0);
1301     assert(pixels);
1302 
1303     clear();
1304 
1305     m_width = w;
1306     m_height = h;
1307     m_depth = d;
1308     m_size = imgsize;
1309     m_pixels = new unsigned char[imgsize];
1310     memcpy(m_pixels, pixels, imgsize);
1311 }
1312 
1313 ///////////////////////////////////////////////////////////////////////////////
1314 // free surface memory
clear()1315 void CSurface::clear()
1316 {
1317     if (m_pixels != NULL)
1318     {
1319         delete [] m_pixels;
1320         m_pixels = NULL;
1321     }
1322 }
1323