1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #pragma once
24 
25 #include "../Container/ArrayPtr.h"
26 #include "../Resource/Resource.h"
27 
28 struct SDL_Surface;
29 
30 namespace Urho3D
31 {
32 
33 static const int COLOR_LUT_SIZE = 16;
34 
35 /// Supported compressed image formats.
36 enum CompressedFormat
37 {
38     CF_NONE = 0,
39     CF_RGBA,
40     CF_DXT1,
41     CF_DXT3,
42     CF_DXT5,
43     CF_ETC1,
44     CF_PVRTC_RGB_2BPP,
45     CF_PVRTC_RGBA_2BPP,
46     CF_PVRTC_RGB_4BPP,
47     CF_PVRTC_RGBA_4BPP,
48 };
49 
50 /// Compressed image mip level.
51 struct CompressedLevel
52 {
53     /// Construct empty.
CompressedLevelCompressedLevel54     CompressedLevel() :
55         data_(0),
56         format_(CF_NONE),
57         width_(0),
58         height_(0),
59         depth_(0),
60         blockSize_(0),
61         dataSize_(0),
62         rowSize_(0),
63         rows_(0)
64     {
65     }
66 
67     /// Decompress to RGBA. The destination buffer required is width * height * 4 bytes. Return true if successful.
68     bool Decompress(unsigned char* dest);
69 
70     /// Compressed image data.
71     unsigned char* data_;
72     /// Compression format.
73     CompressedFormat format_;
74     /// Width.
75     int width_;
76     /// Height.
77     int height_;
78     /// Depth.
79     int depth_;
80     /// Block size in bytes.
81     unsigned blockSize_;
82     /// Total data size in bytes.
83     unsigned dataSize_;
84     /// Row size in bytes.
85     unsigned rowSize_;
86     /// Number of rows.
87     unsigned rows_;
88 };
89 
90 /// %Image resource.
91 class URHO3D_API Image : public Resource
92 {
93     URHO3D_OBJECT(Image, Resource);
94 
95 public:
96     /// Construct empty.
97     Image(Context* context);
98     /// Destruct.
99     virtual ~Image();
100     /// Register object factory.
101     static void RegisterObject(Context* context);
102 
103     /// Load resource from stream. May be called from a worker thread. Return true if successful.
104     virtual bool BeginLoad(Deserializer& source);
105     /// Save the image to a stream. Regardless of original format, the image is saved as png. Compressed image data is not supported. Return true if successful.
106     virtual bool Save(Serializer& dest) const;
107     /// Save the image to a file. Format of the image is determined by file extension. JPG is saved with maximum quality.
108     virtual bool SaveFile(const String& fileName) const;
109 
110     /// Set 2D size and number of color components. Old image data will be destroyed and new data is undefined. Return true if successful.
111     bool SetSize(int width, int height, unsigned components);
112     /// Set 3D size and number of color components. Old image data will be destroyed and new data is undefined. Return true if successful.
113     bool SetSize(int width, int height, int depth, unsigned components);
114     /// Set new image data.
115     void SetData(const unsigned char* pixelData);
116     /// Set a 2D pixel.
117     void SetPixel(int x, int y, const Color& color);
118     /// Set a 3D pixel.
119     void SetPixel(int x, int y, int z, const Color& color);
120     /// Set a 2D pixel with an integer color. R component is in the 8 lowest bits.
121     void SetPixelInt(int x, int y, unsigned uintColor);
122     /// Set a 3D pixel with an integer color. R component is in the 8 lowest bits.
123     void SetPixelInt(int x, int y, int z, unsigned uintColor);
124     /// Load as color LUT. Return true if successful.
125     bool LoadColorLUT(Deserializer& source);
126     /// Flip image horizontally. Return true if successful.
127     bool FlipHorizontal();
128     /// Flip image vertically. Return true if successful.
129     bool FlipVertical();
130     /// Resize image by bilinear resampling. Return true if successful.
131     bool Resize(int width, int height);
132     /// Clear the image with a color.
133     void Clear(const Color& color);
134     /// Clear the image with an integer color. R component is in the 8 lowest bits.
135     void ClearInt(unsigned uintColor);
136     /// Save in BMP format. Return true if successful.
137     bool SaveBMP(const String& fileName) const;
138     /// Save in PNG format. Return true if successful.
139     bool SavePNG(const String& fileName) const;
140     /// Save in TGA format. Return true if successful.
141     bool SaveTGA(const String& fileName) const;
142     /// Save in JPG format with specified quality. Return true if successful.
143     bool SaveJPG(const String& fileName, int quality) const;
144     /// Save in DDS format. Only uncompressed RGBA images are supported. Return true if successful.
145     bool SaveDDS(const String& fileName) const;
146     /// Save in WebP format with minimum (fastest) or specified compression. Return true if successful. Fails always if WebP support is not compiled in.
147     bool SaveWEBP(const String& fileName, float compression = 0.0f) const;
148     /// Whether this texture is detected as a cubemap, only relevant for DDS.
IsCubemap()149     bool IsCubemap() const { return cubemap_; }
150     /// Whether this texture has been detected as a volume, only relevant for DDS.
IsArray()151     bool IsArray() const { return array_; }
152     /// Whether this texture is in sRGB, only relevant for DDS.
IsSRGB()153     bool IsSRGB() const { return sRGB_; }
154 
155     /// Return a 2D pixel color.
156     Color GetPixel(int x, int y) const;
157     /// Return a 3D pixel color.
158     Color GetPixel(int x, int y, int z) const;
159     /// Return a 2D pixel integer color. R component is in the 8 lowest bits.
160     unsigned GetPixelInt(int x, int y) const;
161     /// Return a 3D pixel integer color. R component is in the 8 lowest bits.
162     unsigned GetPixelInt(int x, int y, int z) const;
163     /// Return a bilinearly sampled 2D pixel color. X and Y have the range 0-1.
164     Color GetPixelBilinear(float x, float y) const;
165     /// Return a trilinearly sampled 3D pixel color. X, Y and Z have the range 0-1.
166     Color GetPixelTrilinear(float x, float y, float z) const;
167 
168     /// Return width.
GetWidth()169     int GetWidth() const { return width_; }
170 
171     /// Return height.
GetHeight()172     int GetHeight() const { return height_; }
173 
174     /// Return depth.
GetDepth()175     int GetDepth() const { return depth_; }
176 
177     /// Return number of color components.
GetComponents()178     unsigned GetComponents() const { return components_; }
179 
180     /// Return pixel data.
GetData()181     unsigned char* GetData() const { return data_; }
182 
183     /// Return whether is compressed.
IsCompressed()184     bool IsCompressed() const { return compressedFormat_ != CF_NONE; }
185 
186     /// Return compressed format.
GetCompressedFormat()187     CompressedFormat GetCompressedFormat() const { return compressedFormat_; }
188 
189     /// Return number of compressed mip levels. Returns 0 if the image is has not been loaded from a source file containing multiple mip levels.
GetNumCompressedLevels()190     unsigned GetNumCompressedLevels() const { return numCompressedLevels_; }
191 
192     /// Return next mip level by bilinear filtering. Note that if the image is already 1x1x1, will keep returning an image of that size.
193     SharedPtr<Image> GetNextLevel() const;
194     /// Return the next sibling image of an array or cubemap.
GetNextSibling()195     SharedPtr<Image> GetNextSibling() const { return nextSibling_;  }
196     /// Return image converted to 4-component (RGBA) to circumvent modern rendering API's not supporting e.g. the luminance-alpha format.
197     SharedPtr<Image> ConvertToRGBA() const;
198     /// Return a compressed mip level.
199     CompressedLevel GetCompressedLevel(unsigned index) const;
200     /// Return subimage from the image by the defined rect or null if failed. 3D images are not supported. You must free the subimage yourself.
201     Image* GetSubimage(const IntRect& rect) const;
202     /// Return an SDL surface from the image, or null if failed. Only RGB images are supported. Specify rect to only return partial image. You must free the surface yourself.
203     SDL_Surface* GetSDLSurface(const IntRect& rect = IntRect::ZERO) const;
204     /// Precalculate the mip levels. Used by asynchronous texture loading.
205     void PrecalculateLevels();
206     /// Clean up the mip levels.
207     void CleanupLevels();
208     /// Get all stored mip levels starting from this.
209     void GetLevels(PODVector<Image*>& levels);
210     /// Get all stored mip levels starting from this.
211     void GetLevels(PODVector<const Image*>& levels) const;
212 
213 private:
214     /// Decode an image using stb_image.
215     static unsigned char* GetImageData(Deserializer& source, int& width, int& height, unsigned& components);
216     /// Free an image file's pixel data.
217     static void FreeImageData(unsigned char* pixelData);
218 
219     /// Width.
220     int width_;
221     /// Height.
222     int height_;
223     /// Depth.
224     int depth_;
225     /// Number of color components.
226     unsigned components_;
227     /// Number of compressed mip levels.
228     unsigned numCompressedLevels_;
229     /// Cubemap status if DDS.
230     bool cubemap_;
231     /// Texture array status if DDS.
232     bool array_;
233     /// Data is sRGB.
234     bool sRGB_;
235     /// Compressed format.
236     CompressedFormat compressedFormat_;
237     /// Pixel data.
238     SharedArrayPtr<unsigned char> data_;
239     /// Precalculated mip level image.
240     SharedPtr<Image> nextLevel_;
241     /// Next texture array or cube map image.
242     SharedPtr<Image> nextSibling_;
243 };
244 
245 }
246