/src/ogre/OgreMain/src/OgreASTCCodec.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | |
29 | | #include "OgreStableHeaders.h" |
30 | | #include "OgreASTCCodec.h" |
31 | | |
32 | | #include <cmath> |
33 | | #include "OgreImage.h" |
34 | | |
35 | | namespace Ogre { |
36 | | |
37 | | const uint32 ASTC_MAGIC = 0x5CA1AB13; |
38 | | |
39 | | typedef struct |
40 | | { |
41 | | uint8 magic[4]; |
42 | | uint8 blockdim_x; |
43 | | uint8 blockdim_y; |
44 | | uint8 blockdim_z; |
45 | | uint8 xsize[3]; // x-size = xsize[0] + xsize[1] + xsize[2] |
46 | | uint8 ysize[3]; // x-size, y-size and z-size are given in texels; |
47 | | uint8 zsize[3]; // block count is inferred |
48 | | } ASTCHeader; |
49 | | |
50 | | float ASTCCodec::getBitrateForPixelFormat(PixelFormat fmt) |
51 | 0 | { |
52 | 0 | switch (fmt) |
53 | 0 | { |
54 | 0 | case PF_ASTC_RGBA_4X4_LDR: |
55 | 0 | return 8.00; |
56 | 0 | case PF_ASTC_RGBA_5X4_LDR: |
57 | 0 | return 6.40; |
58 | 0 | case PF_ASTC_RGBA_5X5_LDR: |
59 | 0 | return 5.12; |
60 | 0 | case PF_ASTC_RGBA_6X5_LDR: |
61 | 0 | return 4.27; |
62 | 0 | case PF_ASTC_RGBA_6X6_LDR: |
63 | 0 | return 3.56; |
64 | 0 | case PF_ASTC_RGBA_8X5_LDR: |
65 | 0 | return 3.20; |
66 | 0 | case PF_ASTC_RGBA_8X6_LDR: |
67 | 0 | return 2.67; |
68 | 0 | case PF_ASTC_RGBA_8X8_LDR: |
69 | 0 | return 2.00; |
70 | 0 | case PF_ASTC_RGBA_10X5_LDR: |
71 | 0 | return 2.56; |
72 | 0 | case PF_ASTC_RGBA_10X6_LDR: |
73 | 0 | return 2.13; |
74 | 0 | case PF_ASTC_RGBA_10X8_LDR: |
75 | 0 | return 1.60; |
76 | 0 | case PF_ASTC_RGBA_10X10_LDR: |
77 | 0 | return 1.28; |
78 | 0 | case PF_ASTC_RGBA_12X10_LDR: |
79 | 0 | return 1.07; |
80 | 0 | case PF_ASTC_RGBA_12X12_LDR: |
81 | 0 | return 0.89; |
82 | | |
83 | 0 | default: |
84 | 0 | return 0; |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | | // Utility function to determine 2D block dimensions from a target bitrate. Used for 3D textures. |
89 | | // Taken from astc_toplevel.cpp in ARM's ASTC Evaluation Codec |
90 | | void ASTCCodec::getClosestBlockDim2d(float targetBitrate, int *x, int *y) const |
91 | 0 | { |
92 | 0 | int blockdims[6] = { 4, 5, 6, 8, 10, 12 }; |
93 | |
|
94 | 0 | float best_error = 1000; |
95 | 0 | float aspect_of_best = 1; |
96 | 0 | int i, j; |
97 | | |
98 | | // Y dimension |
99 | 0 | for (i = 0; i < 6; i++) |
100 | 0 | { |
101 | | // X dimension |
102 | 0 | for (j = i; j < 6; j++) |
103 | 0 | { |
104 | | // NxN MxN 8x5 10x5 10x6 |
105 | 0 | int is_legal = (j==i) || (j==i+1) || (j==3 && i==1) || (j==4 && i==1) || (j==4 && i==2); |
106 | |
|
107 | 0 | if(is_legal) |
108 | 0 | { |
109 | 0 | float bitrate = 128.0f / (blockdims[i] * blockdims[j]); |
110 | 0 | float bitrate_error = std::fabs(bitrate - targetBitrate); |
111 | 0 | float aspect = (float)blockdims[j] / blockdims[i]; |
112 | 0 | if (bitrate_error < best_error || (bitrate_error == best_error && aspect < aspect_of_best)) |
113 | 0 | { |
114 | 0 | *x = blockdims[j]; |
115 | 0 | *y = blockdims[i]; |
116 | 0 | best_error = bitrate_error; |
117 | 0 | aspect_of_best = aspect; |
118 | 0 | } |
119 | 0 | } |
120 | 0 | } |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | // Taken from astc_toplevel.cpp in ARM's ASTC Evaluation Codec |
125 | | void ASTCCodec::getClosestBlockDim3d(float targetBitrate, int *x, int *y, int *z) |
126 | 0 | { |
127 | 0 | int blockdims[4] = { 3, 4, 5, 6 }; |
128 | |
|
129 | 0 | float best_error = 1000; |
130 | 0 | float aspect_of_best = 1; |
131 | 0 | int i, j, k; |
132 | |
|
133 | 0 | for (i = 0; i < 4; i++) // Z |
134 | 0 | { |
135 | 0 | for (j = i; j < 4; j++) // Y |
136 | 0 | { |
137 | 0 | for (k = j; k < 4; k++) // X |
138 | 0 | { |
139 | | // NxNxN MxNxN MxMxN |
140 | 0 | int is_legal = ((k==j)&&(j==i)) || ((k==j+1)&&(j==i)) || ((k==j)&&(j==i+1)); |
141 | |
|
142 | 0 | if(is_legal) |
143 | 0 | { |
144 | 0 | float bitrate = 128.0f / (blockdims[i] * blockdims[j] * blockdims[k]); |
145 | 0 | float bitrate_error = std::fabs(bitrate - targetBitrate); |
146 | 0 | float aspect = (float)blockdims[k] / blockdims[j] + (float)blockdims[j] / blockdims[i] + (float)blockdims[k] / blockdims[i]; |
147 | |
|
148 | 0 | if (bitrate_error < best_error || (bitrate_error == best_error && aspect < aspect_of_best)) |
149 | 0 | { |
150 | 0 | *x = blockdims[k]; |
151 | 0 | *y = blockdims[j]; |
152 | 0 | *z = blockdims[i]; |
153 | 0 | best_error = bitrate_error; |
154 | 0 | aspect_of_best = aspect; |
155 | 0 | } |
156 | 0 | } |
157 | 0 | } |
158 | 0 | } |
159 | 0 | } |
160 | 0 | } |
161 | | //--------------------------------------------------------------------- |
162 | | ASTCCodec* ASTCCodec::msInstance = 0; |
163 | | //--------------------------------------------------------------------- |
164 | | void ASTCCodec::startup(void) |
165 | 1 | { |
166 | 1 | if (!msInstance) |
167 | 1 | { |
168 | 1 | msInstance = OGRE_NEW ASTCCodec(); |
169 | 1 | Codec::registerCodec(msInstance); |
170 | 1 | } |
171 | | |
172 | 1 | LogManager::getSingleton().logMessage(LML_NORMAL, |
173 | 1 | "ASTC codec registering"); |
174 | 1 | } |
175 | | //--------------------------------------------------------------------- |
176 | | void ASTCCodec::shutdown(void) |
177 | 1 | { |
178 | 1 | if(msInstance) |
179 | 1 | { |
180 | 1 | Codec::unregisterCodec(msInstance); |
181 | 1 | OGRE_DELETE msInstance; |
182 | 1 | msInstance = 0; |
183 | 1 | } |
184 | 1 | } |
185 | | //--------------------------------------------------------------------- |
186 | | ASTCCodec::ASTCCodec(): |
187 | 1 | mType("astc") |
188 | 1 | { |
189 | 1 | } |
190 | | //--------------------------------------------------------------------- |
191 | | void ASTCCodec::decode(const DataStreamPtr& stream, const Any& output) const |
192 | 0 | { |
193 | 0 | Image* image = any_cast<Image*>(output); |
194 | 0 | ASTCHeader header; |
195 | | |
196 | | // Read the ASTC header |
197 | 0 | stream->read(&header, sizeof(ASTCHeader)); |
198 | |
|
199 | 0 | if (memcmp(&ASTC_MAGIC, &header.magic, sizeof(uint32)) != 0 ) |
200 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
201 | 0 | "This is not a valid ASTC file!", "ASTCCodec::decode"); |
202 | | |
203 | 0 | int xdim = header.blockdim_x; |
204 | 0 | int ydim = header.blockdim_y; |
205 | 0 | int zdim = header.blockdim_z; |
206 | |
|
207 | 0 | int xsize = header.xsize[0] + 256 * header.xsize[1] + 65536 * header.xsize[2]; |
208 | 0 | int ysize = header.ysize[0] + 256 * header.ysize[1] + 65536 * header.ysize[2]; |
209 | 0 | int zsize = header.zsize[0] + 256 * header.zsize[1] + 65536 * header.zsize[2]; |
210 | |
|
211 | 0 | PixelFormat format = PF_UNKNOWN; |
212 | | |
213 | | // For 3D we calculate the bitrate then find the nearest 2D block size. |
214 | 0 | if(zdim > 1) |
215 | 0 | { |
216 | 0 | float bitrate = 128.0f / (xdim * ydim * zdim); |
217 | 0 | getClosestBlockDim2d(bitrate, &xdim, &ydim); |
218 | 0 | } |
219 | |
|
220 | 0 | if(xdim == 4) |
221 | 0 | { |
222 | 0 | format = PF_ASTC_RGBA_4X4_LDR; |
223 | 0 | } |
224 | 0 | else if(xdim == 5) |
225 | 0 | { |
226 | 0 | if(ydim == 4) |
227 | 0 | format = PF_ASTC_RGBA_5X4_LDR; |
228 | 0 | else if(ydim == 5) |
229 | 0 | format = PF_ASTC_RGBA_5X5_LDR; |
230 | 0 | } |
231 | 0 | else if(xdim == 6) |
232 | 0 | { |
233 | 0 | if(ydim == 5) |
234 | 0 | format = PF_ASTC_RGBA_6X5_LDR; |
235 | 0 | else if(ydim == 6) |
236 | 0 | format = PF_ASTC_RGBA_6X6_LDR; |
237 | 0 | } |
238 | 0 | else if(xdim == 8) |
239 | 0 | { |
240 | 0 | if(ydim == 5) |
241 | 0 | format = PF_ASTC_RGBA_8X5_LDR; |
242 | 0 | else if(ydim == 6) |
243 | 0 | format = PF_ASTC_RGBA_8X6_LDR; |
244 | 0 | else if(ydim == 8) |
245 | 0 | format = PF_ASTC_RGBA_8X8_LDR; |
246 | 0 | } |
247 | 0 | else if(xdim == 10) |
248 | 0 | { |
249 | 0 | if(ydim == 5) |
250 | 0 | format = PF_ASTC_RGBA_10X5_LDR; |
251 | 0 | else if(ydim == 6) |
252 | 0 | format = PF_ASTC_RGBA_10X6_LDR; |
253 | 0 | else if(ydim == 8) |
254 | 0 | format = PF_ASTC_RGBA_10X8_LDR; |
255 | 0 | else if(ydim == 10) |
256 | 0 | format = PF_ASTC_RGBA_10X10_LDR; |
257 | 0 | } |
258 | 0 | else if(xdim == 12) |
259 | 0 | { |
260 | 0 | if(ydim == 10) |
261 | 0 | format = PF_ASTC_RGBA_12X10_LDR; |
262 | 0 | else if(ydim == 12) |
263 | 0 | format = PF_ASTC_RGBA_12X12_LDR; |
264 | 0 | } |
265 | | |
266 | | // Always one face, cubemaps are not currently supported |
267 | | // Always 1 mip level per file |
268 | 0 | image->create(format, xsize, ysize, zsize, 1, 0); |
269 | 0 | stream->read(image->getData(), image->getSize()); |
270 | 0 | } |
271 | | //--------------------------------------------------------------------- |
272 | | String ASTCCodec::getType() const |
273 | 2 | { |
274 | 2 | return mType; |
275 | 2 | } |
276 | | //--------------------------------------------------------------------- |
277 | | String ASTCCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const |
278 | 0 | { |
279 | 0 | if (maxbytes >= sizeof(uint32)) |
280 | 0 | { |
281 | 0 | uint32 fileType; |
282 | 0 | memcpy(&fileType, magicNumberPtr, sizeof(uint32)); |
283 | 0 | flipEndian(&fileType, sizeof(uint32), 1); |
284 | |
|
285 | 0 | if (ASTC_MAGIC == fileType) |
286 | 0 | return String("astc"); |
287 | 0 | } |
288 | | |
289 | 0 | return BLANKSTRING; |
290 | 0 | } |
291 | | } |