1 | // tLayer.h  |
2 | //  |
3 | // A tLayer is a data container for texture pixel data. It is used only by the tTexture class to store image data. It  |
4 | // contains data that may be in a variety of hardware-ready formats, like dxt5. It is primarily used to store the  |
5 | // multiple mipmap layers of a texture. Main members are width, height, pixel format, and a function to compute data  |
6 | // size based on those three variables. It knows how to save and load itself in tChunk format.  |
7 | //  |
8 | // tLayers may have any width and height in [1, MaxLayerDimension]. If the pixel format is block-based (4x4 pixels)  |
9 | // the tLayer still allows smaller than 4 width and height. However, a whole block is still needed so the number of  |
10 | // bytes will be the block size for the particular BC format. For example, a 1x1 BC1 format layer still needs 8 bytes.  |
11 | // A 5x5 BC format layer would need 4 blocks (same as an 8x8). The tLayer does not place further constraints on width  |
12 | // and height. A higher level system, for example, may want to ensure power-of-two sizes, or multiple of 4, but that  |
13 | // shouldn't and doesn't happen here.  |
14 | //  |
15 | // Copyright (c) 2006, 2017 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 <System/tChunk.h>  |
28 | #include <Image/tPixelFormat.h>  |
29 | namespace tImage  |
30 | {  |
31 |   |
32 |   |
33 | class tLayer : public tLink<tLayer>  |
34 | {  |
35 | public:  |
36 | tLayer() : PixelFormat(tPixelFormat::Invalid), Width(0), Height(0), Data(nullptr), OwnsData(true) { }  |
37 |   |
38 | // Constructs the layer from the chunk. Normally it copies the layer data from the chunk. However, if ownData is  |
39 | // false no mem-copy is performed and the layer just points into the chunk data. In this case it is vital that the  |
40 | // chunk object exists for the entire lifespan of the layer.  |
41 | tLayer(const tChunk& chunk, bool ownsData = true) : PixelFormat(tPixelFormat::Invalid), Width(0), Height(0), Data(nullptr), OwnsData(ownsData) { Load(chunk, ownsData); }  |
42 |   |
43 | // Constructs a layer having the supplied width, height, and number of bytes. If steal memory is true, the data  |
44 | // array is passed off to this class and it will manage the array deleting it when necessary. If steal is false,  |
45 | // the data gets mem-copied into this object.  |
46 | tLayer(tPixelFormat, int width, int height, uint8* data, bool steal = false);  |
47 |   |
48 | tLayer(const tLayer&);  |
49 | virtual ~tLayer() { Clear(); }  |
50 |   |
51 | bool IsValid() const { return Data ? true : false; }  |
52 |   |
53 | // Returns the size of the data in bytes. For BC formats the data size will be a multiple of the block size. For  |
54 | // example, a 1x1 BC1 format layer still needs 8 bytes. A 5x5 BC1 format layer would need a whole 4 blocks (same as  |
55 | // an 8x8) and would yield 32 bytes.  |
56 | int GetDataSize() const;  |
57 |   |
58 | void Save(tChunkWriter&) const;  |
59 |   |
60 | // Loads the layer from a chunk. Any previous layer data gets destroyed. The bool ownData works the same as with  |
61 | // the constructor.  |
62 | void Load(const tChunk&, bool ownData);  |
63 |   |
64 | // Frees internal layer data and makes the layer invalid.  |
65 | void Clear() { PixelFormat = tPixelFormat::Invalid; Width = Height = 0; if (OwnsData) delete[] Data; Data = nullptr; OwnsData = true; }  |
66 |   |
67 | // This just checks the pixel format to see if it supports alpha. It does NOT check the data.  |
68 | bool IsOpaqueFormat() const;  |
69 |   |
70 | // An invalid layer is never considered equal to another layer even if the other layer is also invalid. Whether the  |
71 | // layer owns the data is considered irrelevant for equivalency purposes.  |
72 | bool operator==(const tLayer&) const;  |
73 | bool operator!=(const tLayer& src) const { return !(*this == src); }  |
74 |   |
75 | tPixelFormat PixelFormat;  |
76 | int Width, Height;  |
77 | uint8* Data;  |
78 | bool OwnsData;  |
79 |   |
80 | // Most hardware can handle up to a 4096 x 4096 texture.  |
81 | const static int MaxLayerDimension = 4096;  |
82 | const static int MinLayerDimension = 1;  |
83 | };  |
84 |   |
85 |   |
86 | // Implementation below this line.  |
87 |   |
88 |   |
89 | inline tLayer::tLayer(tPixelFormat format, int width, int height, uint8* data, bool steal) :  |
90 | PixelFormat(format),  |
91 | Width(width),  |
92 | Height(height),  |
93 | Data(nullptr),  |
94 | OwnsData(true)  |
95 | {  |
96 | if (!width || !height || !data)  |
97 | return;  |
98 |   |
99 | if (steal)  |
100 | {  |
101 | Data = data;  |
102 | }  |
103 | else  |
104 | {  |
105 | int dataSize = GetDataSize();  |
106 | Data = new uint8[dataSize];  |
107 | tStd::tMemcpy(Data, data, dataSize);  |
108 | }  |
109 | }  |
110 |   |
111 |   |
112 | inline tLayer::tLayer(const tLayer& src) :  |
113 | PixelFormat(src.PixelFormat),  |
114 | Width(src.Width),  |
115 | Height(src.Height),  |
116 | OwnsData(src.OwnsData)  |
117 | {  |
118 | if (OwnsData)  |
119 | {  |
120 | int dataSize = src.GetDataSize();  |
121 | Data = new uint8[dataSize];  |
122 | tStd::tMemcpy(Data, src.Data, dataSize);  |
123 | }  |
124 | else  |
125 | {  |
126 | Data = src.Data;  |
127 | }  |
128 | }  |
129 |   |
130 |   |
131 | inline int tLayer::GetDataSize() const  |
132 | {  |
133 | if (!Width || !Height || (PixelFormat == tPixelFormat::Invalid))  |
134 | return 0;  |
135 |   |
136 | int numBytes = 0;  |
137 | if (tIsBlockFormat(PixelFormat))  |
138 | {  |
139 | int widthNumBlocks = (Width + ((Width%4) ? 4-(Width%4) : 0)) >> 2;  |
140 | int heightNumBlocks = (Height + ((Height%4) ? 4-(Height%4) : 0)) >> 2;  |
141 | int numBlocks = widthNumBlocks * heightNumBlocks;  |
142 | numBytes = numBlocks * tGetBytesPer4x4PixelBlock(PixelFormat);  |
143 | }  |
144 | else  |
145 | {  |
146 | numBytes = Width * Height * (tGetBitsPerPixel(PixelFormat) >> 3);  |
147 | }  |
148 |   |
149 | return numBytes;  |
150 | }  |
151 |   |
152 |   |
153 | }  |
154 | |