]> git.lizzy.rs Git - irrlicht.git/blob - include/IImage.h
Fix COSOperator::getSystemMemory
[irrlicht.git] / include / IImage.h
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #ifndef __I_IMAGE_H_INCLUDED__\r
6 #define __I_IMAGE_H_INCLUDED__\r
7 \r
8 #include "IReferenceCounted.h"\r
9 #include "position2d.h"\r
10 #include "rect.h"\r
11 #include "SColor.h"\r
12 #include "irrAllocator.h"\r
13 #include <string.h>\r
14 \r
15 namespace irr\r
16 {\r
17 namespace video\r
18 {\r
19 \r
20 //! Interface for software image data.\r
21 /** Image loaders create these images from files. IVideoDrivers convert\r
22 these images into their (hardware) textures.\r
23 NOTE: Floating point formats are not well supported yet. Basically only getData() works for them.\r
24 */\r
25 class IImage : public virtual IReferenceCounted\r
26 {\r
27 public:\r
28 \r
29         //! constructor\r
30         IImage(ECOLOR_FORMAT format, const core::dimension2d<u32>& size, bool deleteMemory) :\r
31                 Format(format), Size(size), Data(0), MipMapsData(0), BytesPerPixel(0), Pitch(0), DeleteMemory(deleteMemory), DeleteMipMapsMemory(false)\r
32 #if defined(IRRLICHT_sRGB)\r
33                 ,Format_sRGB(1)\r
34 #endif\r
35         {\r
36                 BytesPerPixel = getBitsPerPixelFromFormat(Format) / 8;\r
37                 Pitch = BytesPerPixel * Size.Width;\r
38         }\r
39 \r
40         //! destructor\r
41         virtual ~IImage()\r
42         {\r
43                 if (DeleteMemory)\r
44                         delete[] Data;\r
45 \r
46                 if (DeleteMipMapsMemory)\r
47                         Allocator.deallocate(MipMapsData);\r
48         }\r
49 \r
50         //! Returns the color format\r
51         ECOLOR_FORMAT getColorFormat() const\r
52         {\r
53                 return Format;\r
54         }\r
55 \r
56 #if defined(IRRLICHT_sRGB)\r
57         //! Texture is linear/sRGB (should be part of ColorFormat: default yes)\r
58         int get_sRGB() const\r
59         {\r
60                 return Format_sRGB;\r
61         }\r
62         void set_sRGB(int val)\r
63         {\r
64                 Format_sRGB = val;\r
65         }\r
66 #endif\r
67 \r
68         //! Returns width and height of image data.\r
69         const core::dimension2d<u32>& getDimension() const\r
70         {\r
71                 return Size;\r
72         }\r
73 \r
74         //! Returns bits per pixel.\r
75         u32 getBitsPerPixel() const\r
76         {\r
77 \r
78                 return getBitsPerPixelFromFormat(Format);\r
79         }\r
80 \r
81         //! Returns bytes per pixel\r
82         u32 getBytesPerPixel() const\r
83         {\r
84                 return BytesPerPixel;\r
85         }\r
86 \r
87         //! Returns image data size in bytes\r
88         u32 getImageDataSizeInBytes() const\r
89         {\r
90                 return getDataSizeFromFormat(Format, Size.Width, Size.Height);\r
91         }\r
92 \r
93         //! Returns image data size in pixels\r
94         u32 getImageDataSizeInPixels() const\r
95         {\r
96                 return Size.Width * Size.Height;\r
97         }\r
98 \r
99         //! Returns pitch of image\r
100         u32 getPitch() const\r
101         {\r
102                 return Pitch;\r
103         }\r
104 \r
105         //! Returns mask for red value of a pixel\r
106         u32 getRedMask() const\r
107         {\r
108                 switch (Format)\r
109                 {\r
110                 case ECF_A1R5G5B5:\r
111                         return 0x1F << 10;\r
112                 case ECF_R5G6B5:\r
113                         return 0x1F << 11;\r
114                 case ECF_R8G8B8:\r
115                         return 0x00FF0000;\r
116                 case ECF_A8R8G8B8:\r
117                         return 0x00FF0000;\r
118                 default:\r
119                         return 0x0;\r
120                 }\r
121         }\r
122 \r
123         //! Returns mask for green value of a pixel\r
124         u32 getGreenMask() const\r
125         {\r
126                 switch (Format)\r
127                 {\r
128                 case ECF_A1R5G5B5:\r
129                         return 0x1F << 5;\r
130                 case ECF_R5G6B5:\r
131                         return 0x3F << 5;\r
132                 case ECF_R8G8B8:\r
133                         return 0x0000FF00;\r
134                 case ECF_A8R8G8B8:\r
135                         return 0x0000FF00;\r
136                 default:\r
137                         return 0x0;\r
138                 }\r
139         }\r
140 \r
141         //! Returns mask for blue value of a pixel\r
142         u32 getBlueMask() const\r
143         {\r
144                 switch (Format)\r
145                 {\r
146                 case ECF_A1R5G5B5:\r
147                         return 0x1F;\r
148                 case ECF_R5G6B5:\r
149                         return 0x1F;\r
150                 case ECF_R8G8B8:\r
151                         return 0x000000FF;\r
152                 case ECF_A8R8G8B8:\r
153                         return 0x000000FF;\r
154                 default:\r
155                         return 0x0;\r
156                 }\r
157         }\r
158 \r
159         //! Returns mask for alpha value of a pixel\r
160         u32 getAlphaMask() const\r
161         {\r
162                 switch (Format)\r
163                 {\r
164                 case ECF_A1R5G5B5:\r
165                         return 0x1 << 15;\r
166                 case ECF_R5G6B5:\r
167                         return 0x0;\r
168                 case ECF_R8G8B8:\r
169                         return 0x0;\r
170                 case ECF_A8R8G8B8:\r
171                         return 0xFF000000;\r
172                 default:\r
173                         return 0x0;\r
174                 }\r
175         }\r
176 \r
177         //! Use this to get a pointer to the image data.\r
178         /**\r
179         \return Pointer to the image data. What type of data is pointed to\r
180         depends on the color format of the image. For example if the color\r
181         format is ECF_A8R8G8B8, it is of u32. */\r
182         void* getData() const\r
183         {\r
184                 return Data;\r
185         }\r
186 \r
187         //! Lock function. Use this to get a pointer to the image data.\r
188         /** Use getData instead.\r
189         \return Pointer to the image data. What type of data is pointed to\r
190         depends on the color format of the image. For example if the color\r
191         format is ECF_A8R8G8B8, it is of u32. Be sure to call unlock() after\r
192         you don't need the pointer any more. */\r
193         _IRR_DEPRECATED_ void* lock()\r
194         {\r
195                 return getData();\r
196         }\r
197 \r
198         //! Unlock function.\r
199         /** Should be called after the pointer received by lock() is not\r
200         needed anymore. */\r
201         _IRR_DEPRECATED_ void unlock()\r
202         {\r
203         }\r
204 \r
205         //! Get the mipmap size for this image for a certain mipmap level\r
206         /** level 0 will be full image size. Every further level is half the size.\r
207                 Doesn't care if the image actually has mipmaps, just which size would be needed. */\r
208         core::dimension2du getMipMapsSize(u32 mipmapLevel) const\r
209         {\r
210                 return getMipMapsSize(Size, mipmapLevel);\r
211         }\r
212 \r
213 \r
214         //! Calculate mipmap size for a certain level\r
215         /** level 0 will be full image size. Every further level is half the size.      */\r
216         static core::dimension2du getMipMapsSize(const core::dimension2du& sizeLevel0, u32 mipmapLevel)\r
217         {\r
218                 core::dimension2du result(sizeLevel0);\r
219                 u32 i=0;\r
220                 while (i != mipmapLevel)\r
221                 {\r
222                         if (result.Width>1)\r
223                                 result.Width >>= 1;\r
224                         if (result.Height>1)\r
225                                 result.Height>>=1;\r
226                         ++i;\r
227 \r
228                         if ( result.Width == 1 && result.Height == 1 && i < mipmapLevel )\r
229                                 return core::dimension2du(0,0);\r
230                 }\r
231                 return result;\r
232         }\r
233 \r
234 \r
235         //! Get mipmaps data.\r
236         /** Note that different mip levels are just behind each other in memory block.\r
237                 So if you just get level 1 you also have the data for all other levels.\r
238                 There is no level 0 - use getData to get the original image data.\r
239         */\r
240         void* getMipMapsData(irr::u32 mipLevel=1) const\r
241         {\r
242                 if ( MipMapsData && mipLevel > 0)\r
243                 {\r
244                         size_t dataSize = 0;\r
245                         core::dimension2du mipSize(Size);\r
246                         u32 i = 1;      // We want the start of data for this level, not end.\r
247 \r
248                         while (i != mipLevel)\r
249                         {\r
250                                 if (mipSize.Width > 1)\r
251                                         mipSize.Width >>= 1;\r
252 \r
253                                 if (mipSize.Height > 1)\r
254                                         mipSize.Height >>= 1;\r
255 \r
256                                 dataSize += getDataSizeFromFormat(Format, mipSize.Width, mipSize.Height);\r
257 \r
258                                 ++i;\r
259                                 if ( mipSize.Width == 1 && mipSize.Height == 1 && i < mipLevel)\r
260                                         return 0;\r
261                         }\r
262 \r
263                         return MipMapsData + dataSize;\r
264                 }\r
265 \r
266                 return 0;\r
267         }\r
268 \r
269         //! Set mipmaps data.\r
270         /** This method allows you to put custom mipmaps data for\r
271         image.\r
272         \param data A byte array with pixel color information\r
273         \param ownForeignMemory If true, the image will use the data\r
274         pointer directly and own it afterward. If false, the memory\r
275         will by copied internally.\r
276         \param deleteMemory Whether the memory is deallocated upon\r
277         destruction. */\r
278         void setMipMapsData(void* data, bool ownForeignMemory, bool deleteMemory)\r
279         {\r
280                 if (data != MipMapsData)\r
281                 {\r
282                         if (DeleteMipMapsMemory)\r
283                         {\r
284                                 Allocator.deallocate(MipMapsData);\r
285 \r
286                                 DeleteMipMapsMemory = false;\r
287                         }\r
288 \r
289                         if (data)\r
290                         {\r
291                                 if (ownForeignMemory)\r
292                                 {\r
293                                         MipMapsData = static_cast<u8*>(data);\r
294 \r
295                                         DeleteMipMapsMemory = deleteMemory;\r
296                                 }\r
297                                 else\r
298                                 {\r
299                                         u32 dataSize = 0;\r
300                                         u32 width = Size.Width;\r
301                                         u32 height = Size.Height;\r
302 \r
303                                         do\r
304                                         {\r
305                                                 if (width > 1)\r
306                                                         width >>= 1;\r
307 \r
308                                                 if (height > 1)\r
309                                                         height >>= 1;\r
310 \r
311                                                 dataSize += getDataSizeFromFormat(Format, width, height);\r
312                                         } while (width != 1 || height != 1);\r
313 \r
314                                         MipMapsData = Allocator.allocate(dataSize);\r
315                                         memcpy(MipMapsData, data, dataSize);\r
316 \r
317                                         DeleteMipMapsMemory = true;\r
318                                 }\r
319                         }\r
320                         else\r
321                         {\r
322                                 MipMapsData = 0;\r
323                         }\r
324                 }\r
325         }\r
326 \r
327         //! Returns a pixel\r
328         virtual SColor getPixel(u32 x, u32 y) const = 0;\r
329 \r
330         //! Sets a pixel\r
331         virtual void setPixel(u32 x, u32 y, const SColor &color, bool blend = false ) = 0;\r
332 \r
333         //! Copies the image into the target, scaling the image to fit\r
334         /**     NOTE: mipmaps are ignored */\r
335         virtual void copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format=ECF_A8R8G8B8, u32 pitch=0) =0;\r
336 \r
337         //! Copies the image into the target, scaling the image to fit\r
338         /**     NOTE: mipmaps are ignored */\r
339         virtual void copyToScaling(IImage* target) =0;\r
340 \r
341         //! copies this surface into another\r
342         /**     NOTE: mipmaps are ignored */\r
343         virtual void copyTo(IImage* target, const core::position2d<s32>& pos=core::position2d<s32>(0,0)) =0;\r
344 \r
345         //! copies this surface into another\r
346         /**     NOTE: mipmaps are ignored */\r
347         virtual void copyTo(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect=0) =0;\r
348 \r
349         //! copies this surface into another, using the alpha mask and cliprect and a color to add with\r
350         /**     NOTE: mipmaps are ignored\r
351         \param combineAlpha - When true then combine alpha channels. When false replace target image alpha with source image alpha.\r
352         */\r
353         virtual void copyToWithAlpha(IImage* target, const core::position2d<s32>& pos,\r
354                         const core::rect<s32>& sourceRect, const SColor &color,\r
355                         const core::rect<s32>* clipRect = 0,\r
356                         bool combineAlpha=false) =0;\r
357 \r
358         //! copies this surface into another, scaling it to fit, applying a box filter\r
359         /**     NOTE: mipmaps are ignored */\r
360         virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) = 0;\r
361 \r
362         //! fills the surface with given color\r
363         virtual void fill(const SColor &color) =0;\r
364 \r
365         //! Inform whether the image is compressed\r
366         _IRR_DEPRECATED_ bool isCompressed() const\r
367         {\r
368                 return IImage::isCompressedFormat(Format);\r
369         }\r
370 \r
371         //! Check whether the image has MipMaps\r
372         /** \return True if image has MipMaps, else false. */\r
373         _IRR_DEPRECATED_ bool hasMipMaps() const\r
374         {\r
375                 return (getMipMapsData() != 0);\r
376         }\r
377 \r
378         //! get the amount of Bits per Pixel of the given color format\r
379         static u32 getBitsPerPixelFromFormat(const ECOLOR_FORMAT format)\r
380         {\r
381                 switch(format)\r
382                 {\r
383                 case ECF_A1R5G5B5:\r
384                         return 16;\r
385                 case ECF_R5G6B5:\r
386                         return 16;\r
387                 case ECF_R8G8B8:\r
388                         return 24;\r
389                 case ECF_A8R8G8B8:\r
390                         return 32;\r
391                 case ECF_DXT1:\r
392                         return 16;\r
393                 case ECF_DXT2:\r
394                 case ECF_DXT3:\r
395                 case ECF_DXT4:\r
396                 case ECF_DXT5:\r
397                         return 32;\r
398                 case ECF_PVRTC_RGB2:\r
399                         return 12;\r
400                 case ECF_PVRTC_ARGB2:\r
401                 case ECF_PVRTC2_ARGB2:\r
402                         return 16;\r
403                 case ECF_PVRTC_RGB4:\r
404                         return 24;\r
405                 case ECF_PVRTC_ARGB4:\r
406                 case ECF_PVRTC2_ARGB4:\r
407                         return 32;\r
408                 case ECF_ETC1:\r
409                 case ECF_ETC2_RGB:\r
410                         return 24;\r
411                 case ECF_ETC2_ARGB:\r
412                         return 32;\r
413                 case ECF_D16:\r
414                         return 16;\r
415                 case ECF_D32:\r
416                         return 32;\r
417                 case ECF_D24S8:\r
418                         return 32;\r
419                 case ECF_R8:\r
420                         return 8;\r
421                 case ECF_R8G8:\r
422                         return 16;\r
423                 case ECF_R16:\r
424                         return 16;\r
425                 case ECF_R16G16:\r
426                         return 32;\r
427                 case ECF_R16F:\r
428                         return 16;\r
429                 case ECF_G16R16F:\r
430                         return 32;\r
431                 case ECF_A16B16G16R16F:\r
432                         return 64;\r
433                 case ECF_R32F:\r
434                         return 32;\r
435                 case ECF_G32R32F:\r
436                         return 64;\r
437                 case ECF_A32B32G32R32F:\r
438                         return 128;\r
439                 default:\r
440                         return 0;\r
441                 }\r
442         }\r
443 \r
444         //! calculate image data size in bytes for selected format, width and height.\r
445         static u32 getDataSizeFromFormat(ECOLOR_FORMAT format, u32 width, u32 height)\r
446         {\r
447                 u32 imageSize = 0;\r
448 \r
449                 switch (format)\r
450                 {\r
451                 case ECF_DXT1:\r
452                         imageSize = ((width + 3) / 4) * ((height + 3) / 4) * 8;\r
453                         break;\r
454                 case ECF_DXT2:\r
455                 case ECF_DXT3:\r
456                 case ECF_DXT4:\r
457                 case ECF_DXT5:\r
458                         imageSize = ((width + 3) / 4) * ((height + 3) / 4) * 16;\r
459                         break;\r
460                 case ECF_PVRTC_RGB2:\r
461                 case ECF_PVRTC_ARGB2:\r
462                         imageSize = (core::max_<u32>(width, 16) * core::max_<u32>(height, 8) * 2 + 7) / 8;\r
463                         break;\r
464                 case ECF_PVRTC_RGB4:\r
465                 case ECF_PVRTC_ARGB4:\r
466                         imageSize = (core::max_<u32>(width, 8) * core::max_<u32>(height, 8) * 4 + 7) / 8;\r
467                         break;\r
468                 case ECF_PVRTC2_ARGB2:\r
469                         imageSize = core::ceil32(width / 8.0f) * core::ceil32(height / 4.0f) * 8;\r
470                         break;\r
471                 case ECF_PVRTC2_ARGB4:\r
472                 case ECF_ETC1:\r
473                 case ECF_ETC2_RGB:\r
474                         imageSize = core::ceil32(width / 4.0f) * core::ceil32(height / 4.0f) * 8;\r
475                         break;\r
476                 case ECF_ETC2_ARGB:\r
477                         imageSize = core::ceil32(width / 4.0f) * core::ceil32(height / 4.0f) * 16;\r
478                         break;\r
479                 default: // uncompressed formats\r
480                         imageSize = getBitsPerPixelFromFormat(format) / 8 * width;\r
481                         imageSize *= height;\r
482                         break;\r
483                 }\r
484 \r
485                 return imageSize;\r
486         }\r
487 \r
488 // Define to check for all compressed image formats cases in a switch\r
489 #define IRR_CASE_IIMAGE_COMPRESSED_FORMAT\\r
490         case ECF_DXT1:\\r
491         case ECF_DXT2:\\r
492         case ECF_DXT3:\\r
493         case ECF_DXT4:\\r
494         case ECF_DXT5:\\r
495         case ECF_PVRTC_RGB2:\\r
496         case ECF_PVRTC_ARGB2:\\r
497         case ECF_PVRTC2_ARGB2:\\r
498         case ECF_PVRTC_RGB4:\\r
499         case ECF_PVRTC_ARGB4:\\r
500         case ECF_PVRTC2_ARGB4:\\r
501         case ECF_ETC1:\\r
502         case ECF_ETC2_RGB:\\r
503         case ECF_ETC2_ARGB:\r
504 \r
505         //! check if this is compressed color format\r
506         static bool isCompressedFormat(const ECOLOR_FORMAT format)\r
507         {\r
508                 switch(format)\r
509                 {\r
510                         IRR_CASE_IIMAGE_COMPRESSED_FORMAT\r
511                                 return true;\r
512                         default:\r
513                                 return false;\r
514                 }\r
515         }\r
516 \r
517         //! check if the color format is only viable for depth/stencil textures\r
518         static bool isDepthFormat(const ECOLOR_FORMAT format)\r
519         {\r
520                 switch(format)\r
521                 {\r
522                         case ECF_D16:\r
523                         case ECF_D32:\r
524                         case ECF_D24S8:\r
525                                 return true;\r
526                         default:\r
527                                 return false;\r
528                 }\r
529         }\r
530 \r
531         //! Check if the color format uses floating point values for pixels\r
532         static bool isFloatingPointFormat(const ECOLOR_FORMAT format)\r
533         {\r
534                 if (isCompressedFormat(format))\r
535                         return false;\r
536 \r
537                 switch(format)\r
538                 {\r
539                 case ECF_R16F:\r
540                 case ECF_G16R16F:\r
541                 case ECF_A16B16G16R16F:\r
542                 case ECF_R32F:\r
543                 case ECF_G32R32F:\r
544                 case ECF_A32B32G32R32F:\r
545                         return true;\r
546                 default:\r
547                         break;\r
548                 }\r
549                 return false;\r
550         }\r
551 \r
552 #if defined(PATCH_SUPERTUX_8_0_1_with_1_9_0)\r
553         static bool isRenderTargetOnlyFormat(const ECOLOR_FORMAT format)\r
554         {\r
555                 switch (format)\r
556                 {\r
557                 case ECF_A1R5G5B5:\r
558                 case ECF_R5G6B5:\r
559                 case ECF_R8G8B8:\r
560                 case ECF_A8R8G8B8:\r
561                         return false;\r
562                 default:\r
563                         return true;\r
564                 }\r
565         }\r
566 #endif\r
567 \r
568 protected:\r
569         ECOLOR_FORMAT Format;\r
570         core::dimension2d<u32> Size;\r
571 \r
572         u8* Data;\r
573         u8* MipMapsData;\r
574 \r
575         u32 BytesPerPixel;\r
576         u32 Pitch;\r
577 \r
578         bool DeleteMemory;\r
579         bool DeleteMipMapsMemory;\r
580 \r
581         core::irrAllocator<u8> Allocator;\r
582 #if defined(IRRLICHT_sRGB)\r
583         int Format_sRGB;\r
584 #endif\r
585 };\r
586 \r
587 \r
588 } // end namespace video\r
589 } // end namespace irr\r
590 \r
591 #endif\r
592 \r