1// tTexture.h 
2// 
3// A tTexture is a 'hardware-ready' format. tTextures contain functionality for creating mipmap layers in a variety of 
4// block-compressed and uncompressed formats. A tTexture stores each mipmap layer in a tLayer. A tTexture can be 
5// created from either a tPicture or a dds file. The purpose of a dds file is so that content-creators have control 
6// over the authoring of each mipmap level and the exact pixel format used. Basically if you've created a dds file, 
7// you're saying you want the final hardware to use the image data unchanged and as authored -- same mip levels, same 
8// pixel format, same dimensions. For this reason, dds files should not be loaded into tPictures where image 
9// manipulation occurs and possibly lossy block-compressed dds images would be decompressed. A dds file may contain more 
10// than one image if it is a cubemap, but a tTexture only ever represents a single image. The tTexture dds constructor 
11// allows you to decide which one gets loaded. tTextures can save and load to a tChunk-based format, and are therefore 
12// useful at both pipeline and for runtime loading. To save to a tChunk file format a tTexture will call the Save 
13// method of all the tLayers. 
14// 
15// Copyright (c) 2006, 2016, 2017, 2019, 2020 Tristan Grimmer. 
16// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
17// granted, provided that the above copyright notice and this permission notice appear in all copies. 
18// 
19// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
21// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
22// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
23// PERFORMANCE OF THIS SOFTWARE. 
24 
25#pragma once 
26#include <Foundation/tList.h> 
27#include <Foundation/tString.h> 
28#include <System/tChunk.h> 
29#include "Image/tImageDDS.h" 
30#include "Image/tPicture.h" 
31#include "Image/tResample.h" 
32namespace tImage 
33
34 
35 
36class tTexture : public tLink<tTexture
37
38public
39 // Creates an empty and initially invalid tTexture. You must manually call Set or Load. 
40 tTexture() { } 
41 
42 // This constructor is for cases where you just have a list of layers that you want to give the tTexture. After 
43 // construction the layer list will be empty. This is used by the tCubemap class so it can grab all 6 sides of a 
44 // cubemap dds and give them to 6 different tTextures. 
45 tTexture(tList<tLayer>& layers) { Set(layers); } 
46 
47 // Constructs from a dds file or dds object. Since dds files can have up to 6 images in them, these are explicitly 
48 // different constructors than the ones that load other image types. Additionally, the dds constructors don't mess 
49 // with compression or mip layers. What you put in the dds you get. correctRowOrder should normally be left set to 
50 // true unless you are loading a cubemap surface. Essentially dds files are upside down in terms of row order, but 
51 // only the cubemap loader know about it (and they use left handed side ordering). 
52 tTexture 
53
54 const tString& ddsFile, tImageDDS::tSurfIndex surface = tImageDDS::tSurfIndex_Default
55 bool correctRowOrder = true 
56 ) { Load(ddsFile, surface, correctRowOrder); } 
57 
58 // Similar to above but accepts an in-memory object. The ddsObject will be invalid after as the layers are stolen 
59 // from it. If necessary, a constructor can easily be added that does a copy and keeps it valid, but it will be 
60 // less efficient. 
61 tTexture(tImageDDS& ddsObject, tImageDDS::tSurfIndex surface = tImageDDS::tSurfIndex_Default) { Set(ddsObject, surface); } 
62 
63 // The other constructors require you to know a quality setting for resampling (mipmap generation) and compression. 
64 // For simplicity there is only Fast and Production quality settings, and it affects resampling _and_ compression. 
65 enum class tQuality 
66
67 Fast, // Bilinear resample filter. Fast BCn compress mode. 
68 Development, // Bicubic resample filter. High quality BCn compression. 
69 Production // Lanczos sinc-based resample filter. High quality BCn compression. 
70 }; 
71 
72 // This constructor creates a texture from an image file such as a jpg, gif, tga, or bmp. It does this by creating 
73 // a temporary tPicture object. If tPixelFormat is Auto, the constructor automatically chooses the most appropriate 
74 // format for the texture based on the image's properties. DXT1/BC1 is chosen if the image is perfectly opaque, and 
75 // DXT5/BC3 if it has alphas. This constructor forces power-of-2 texture dimensions and will resample to the nearest 
76 // power-of-2 if required. If forceWidth is > 0, the image will be resampled if necessary to have that width. The 
77 // same logic applies to forceHeight. Both forceWidth and forceHeight, if supplied, must be powers of 2. 
78 tTexture 
79
80 const tString& imageFile, bool generateMipMaps, tPixelFormat pixelFormat = tPixelFormat::Auto
81 tQuality quality = tQuality::Production, int forceWidth = 0, int forceHeight = 0 
82 ) { Load(imageFile, generateMipMaps, pixelFormat, quality, forceWidth, forceHeight); } 
83 
84 // Same as above except that an in-memory tPicture is used instead of a filename. The supplied tPicture will be 
85 // invalid after this constructor. This is because resampling may occur on the tPicture. 
86 tTexture 
87
88 tPicture& imageObject, bool generateMipMaps, tPixelFormat pixelFormat = tPixelFormat::Auto
89 tQuality quality = tQuality::Production, int forceWidth = 0, int forceHeight = 0 
90 ) { Set(imageObject, generateMipMaps, pixelFormat, quality, forceWidth, forceHeight); } 
91 
92 virtual ~tTexture() { Clear(); } 
93 
94 // If any constructor fails, you will be left with an invalid object. 
95 bool IsValid() const { return (Layers.GetNumItems() > 0) ? true : false; } 
96 
97 // See the corresponding constructors for a description of the behaviour of these functions. These functions all 
98 // return true on success. On failure, the tTexture is left invalid and in the case of the layer list Set, the list 
99 // is emptied. 
100 bool Set(tList<tLayer>&); 
101 bool Load 
102
103 const tString& ddsFile, tImageDDS::tSurfIndex surface = tImageDDS::tSurfIndex_Default
104 bool correctRowOrder = true 
105 ); 
106 bool Set(tImageDDS& ddsObject, tImageDDS::tSurfIndex = tImageDDS::tSurfIndex_Default); 
107 bool Load 
108
109 const tString& imageFile, bool generateMipMaps, tPixelFormat = tPixelFormat::Auto
110 tQuality = tQuality::Production, int forceWidth = 0, int forceHeight = 0 
111 ); 
112 bool Set 
113
114 tPicture& imageObject, bool generateMipMaps, tPixelFormat = tPixelFormat::Auto
115 tQuality = tQuality::Production, int forceWidth = 0, int forceHeight = 0 
116 ); 
117 
118 void Clear() { Layers.Clear(); Opaque = true; } 
119 
120 int GetWidth() const /* Returns width of the main layer. */ { return IsValid() ? Layers.First()->Width : 0; } 
121 int GetHeight() const /* Returns width of the main layer. */ { return IsValid() ? Layers.First()->Height : 0; } 
122 tPixelFormat GetPixelFormat() const { return IsValid() ? Layers.First()->PixelFormat : tPixelFormat::Invalid; } 
123 bool IsMipmapped() const { return (Layers.GetNumItems() > 1) ? true : false; } 
124 void RemoveMipmaps(); 
125 bool IsOpaque() const { return Opaque; } 
126 int GetNumLayers() const { return Layers.GetNumItems(); } 
127 int GetNumMipmaps() const { return Layers.GetNumItems(); } 
128 tLayer* GetFirstLayer() const { return Layers.First(); } 
129 tLayer* GetMainLayer() const { return Layers.First(); } 
130 void StealLayers(tList<tLayer>&); // Leaves the object invalid. 
131 const tList<tLayer>& GetLayers() { return Layers; } 
132 int GetTotalPixelDataSize() const
133 
134 // Save and Load to tChunk format. 
135 void Save(tChunkWriter&) const
136 void Load(const tChunk&); 
137 
138 // Returns 1 + log2( max(width, height) ). The returned number is how many mipmaps it would take to make the 
139 // smallest a 1x1 square. Some pipelines may care about this and require all of them if mipmapping at all. 
140 int ComputeMaxNumberOfMipmaps() const
141 
142 // Textures are considered equal if the pixel format, opacity, and layers are the same. Invalid textures are always 
143 // considered not equal to other textures, even other invalid textures. 
144 bool operator==(const tTexture&) const
145 bool operator!=(const tTexture& src) const { return !(*this == src); } 
146 
147private
148 tPixelFormat DeterminePixelFormat(const tPicture&); 
149 tResampleFilter DetermineFilter(tQuality); 
150 int DetermineBlockEncodeQualityLevel(tQuality); 
151 
152 void ProcessImageTo_R8G8B8_Or_R8G8B8A8(tPicture&, tPixelFormat, bool generateMipmaps, tQuality); 
153 void ProcessImageTo_G3B5R5G3(tPicture&, bool generateMipmaps, tQuality); 
154 void ProcessImageTo_BCTC(tPicture&, tPixelFormat, bool generateMipmaps, tQuality); 
155 
156 bool Opaque = true; // Only true if the texture is completely opaque. 
157 
158 // The tTexture is only valid if there is at least one layer. The texture is considered to have mipmaps if the 
159 // number of layers is > 1. 
160 tList<tLayer> Layers
161 
162 static bool BC7EncInitialized
163}; 
164 
165 
166// Implementation below this line. 
167 
168 
169inline int tTexture::GetTotalPixelDataSize() const 
170
171 int total = 0
172 for (tLayer* layer = Layers.First(); layer; layer = layer->Next()) 
173 total += layer->GetDataSize(); 
174 
175 return total
176
177 
178 
179inline tPixelFormat tTexture::DeterminePixelFormat(const tPicture& image
180
181 if (Opaque
182 return tPixelFormat::BC1_DXT1
183 else 
184 return tPixelFormat::BC3_DXT5
185
186 
187 
188inline tResampleFilter tTexture::DetermineFilter(tQuality quality
189
190 switch (quality
191
192 case tQuality::Fast: return tResampleFilter::Bilinear
193 case tQuality::Development: return tResampleFilter::Bicubic
194 case tQuality::Production: return tResampleFilter::Lanczos
195
196 return tResampleFilter::Bicubic
197
198 
199 
200inline int tTexture::DetermineBlockEncodeQualityLevel(tQuality quality
201
202 switch (quality
203
204 case tQuality::Fast: return 4
205 case tQuality::Development: return 10
206 case tQuality::Production: return 10
207
208 return 4
209
210 
211 
212inline void tTexture::RemoveMipmaps() 
213
214 if (!IsMipmapped()) 
215 return
216 
217 tLayer* main = Layers.Remove(); 
218 Layers.Empty(); 
219 Layers.Append(main); 
220
221 
222 
223inline void tTexture::StealLayers(tList<tLayer>& layers
224
225 while (!Layers.IsEmpty()) 
226 layers.Append(Layers.Remove()); 
227 
228 Clear(); 
229
230 
231 
232
233