2 Copyright (C) 2015, SiPlus, Chasseur de bots.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "bytestreamutils.h"
28 #include "ifilesystem.h"
32 const int KTX_TYPE_UNSIGNED_BYTE = 0x1401;
33 const int KTX_TYPE_UNSIGNED_SHORT_4_4_4_4 = 0x8033;
34 const int KTX_TYPE_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
35 const int KTX_TYPE_UNSIGNED_SHORT_5_6_5 = 0x8363;
37 const int KTX_FORMAT_ALPHA = 0x1906;
38 const int KTX_FORMAT_RGB = 0x1907;
39 const int KTX_FORMAT_RGBA = 0x1908;
40 const int KTX_FORMAT_LUMINANCE = 0x1909;
41 const int KTX_FORMAT_LUMINANCE_ALPHA = 0x190A;
42 const int KTX_FORMAT_BGR = 0x80E0;
43 const int KTX_FORMAT_BGRA = 0x80E1;
45 const int KTX_FORMAT_ETC1_RGB8 = 0x8D64;
49 virtual ~KTX_Decoder() = default;
51 virtual void Decode(PointerInputStream &istream, byte *out) = 0;
53 virtual unsigned int GetPixelSize() = 0;
56 class KTX_Decoder_A8 : public KTX_Decoder {
58 virtual void Decode(PointerInputStream &istream, byte *out)
60 out[0] = out[1] = out[2] = 0;
61 out[3] = istream_read_byte(istream);
64 virtual unsigned int GetPixelSize()
70 class KTX_Decoder_RGB8 : public KTX_Decoder {
72 virtual void Decode(PointerInputStream &istream, byte *out)
78 virtual unsigned int GetPixelSize()
84 class KTX_Decoder_RGBA8 : public KTX_Decoder {
86 virtual void Decode(PointerInputStream &istream, byte *out)
91 virtual unsigned int GetPixelSize()
97 class KTX_Decoder_L8 : public KTX_Decoder {
99 virtual void Decode(PointerInputStream &istream, byte *out)
101 byte l = istream_read_byte(istream);
102 out[0] = out[1] = out[2] = l;
106 virtual unsigned int GetPixelSize()
112 class KTX_Decoder_LA8 : public KTX_Decoder {
114 virtual void Decode(PointerInputStream &istream, byte *out)
118 out[0] = out[1] = out[2] = la[0];
122 virtual unsigned int GetPixelSize()
128 class KTX_Decoder_BGR8 : public KTX_Decoder {
130 virtual void Decode(PointerInputStream &istream, byte *out)
133 istream.read(bgr, 3);
140 virtual unsigned int GetPixelSize()
146 class KTX_Decoder_BGRA8 : public KTX_Decoder {
148 virtual void Decode(PointerInputStream &istream, byte *out)
151 istream.read(bgra, 4);
158 virtual unsigned int GetPixelSize()
164 class KTX_Decoder_RGBA4 : public KTX_Decoder {
168 KTX_Decoder_RGBA4(bool bigEndian) : m_bigEndian(bigEndian)
171 virtual void Decode(PointerInputStream &istream, byte *out)
175 rgba = istream_read_uint16_be(istream);
177 rgba = istream_read_uint16_le(istream);
179 int r = (rgba >> 12) & 0xf;
180 int g = (rgba >> 8) & 0xf;
181 int b = (rgba >> 4) & 0xf;
183 out[0] = (r << 4) | r;
184 out[1] = (g << 4) | g;
185 out[2] = (b << 4) | b;
186 out[3] = (a << 4) | a;
189 virtual unsigned int GetPixelSize()
195 class KTX_Decoder_RGBA5 : public KTX_Decoder {
199 KTX_Decoder_RGBA5(bool bigEndian) : m_bigEndian(bigEndian)
202 virtual void Decode(PointerInputStream &istream, byte *out)
206 rgba = istream_read_uint16_be(istream);
208 rgba = istream_read_uint16_le(istream);
210 int r = (rgba >> 11) & 0x1f;
211 int g = (rgba >> 6) & 0x1f;
212 int b = (rgba >> 1) & 0x1f;
213 out[0] = (r << 3) | (r >> 2);
214 out[1] = (g << 3) | (g >> 2);
215 out[2] = (b << 3) | (b >> 2);
216 out[3] = (rgba & 1) * 255;
219 virtual unsigned int GetPixelSize()
225 class KTX_Decoder_RGB5 : public KTX_Decoder {
229 KTX_Decoder_RGB5(bool bigEndian) : m_bigEndian(bigEndian)
232 virtual void Decode(PointerInputStream &istream, byte *out)
236 rgb = istream_read_uint16_be(istream);
238 rgb = istream_read_uint16_le(istream);
240 int r = (rgb >> 11) & 0x1f;
241 int g = (rgb >> 5) & 0x3f;
243 out[0] = (r << 3) | (r >> 2);
244 out[1] = (g << 2) | (g >> 4);
245 out[2] = (b << 3) | (b >> 2);
249 virtual unsigned int GetPixelSize()
255 static void KTX_DecodeETC1(PointerInputStream &istream, Image &image)
257 unsigned int width = image.getWidth(), height = image.getHeight();
258 unsigned int stride = width * 4;
259 byte *pixbuf = image.getRGBAPixels();
260 byte etc[8], rgba[64];
262 for (unsigned int y = 0; y < height; y += 4, pixbuf += stride * 4) {
263 unsigned int blockrows = height - y;
269 for (unsigned int x = 0; x < width; x += 4, p += 16) {
270 istream.read(etc, 8);
271 ETC_DecodeETC1Block(etc, rgba, qtrue);
273 unsigned int blockrowsize = width - x;
274 if (blockrowsize > 4) {
278 for (unsigned int blockrow = 0; blockrow < blockrows; blockrow++) {
279 memcpy(p + blockrow * stride, rgba + blockrow * 16, blockrowsize);
285 Image *LoadKTXBuff(PointerInputStream &istream)
288 istream.read(identifier, 12);
289 if (memcmp(identifier, "\xABKTX 11\xBB\r\n\x1A\n", 12)) {
290 globalErrorStream() << "LoadKTX: Image has the wrong identifier\n";
294 bool bigEndian = (istream_read_uint32_le(istream) == 0x01020304);
298 type = istream_read_uint32_be(istream);
300 type = istream_read_uint32_le(istream);
303 // For compressed textures, the format is in glInternalFormat.
304 // For uncompressed textures, it's in glBaseInternalFormat.
305 istream.seek((type ? 3 : 2) * sizeof(uint32_t));
308 format = istream_read_uint32_be(istream);
310 format = istream_read_uint32_le(istream);
313 istream.seek(sizeof(uint32_t));
316 unsigned int width, height;
318 width = istream_read_uint32_be(istream);
319 height = istream_read_uint32_be(istream);
321 width = istream_read_uint32_le(istream);
322 height = istream_read_uint32_le(istream);
325 globalErrorStream() << "LoadKTX: Image has zero width\n";
332 // Skip the key/values and load the first 2D image in the texture.
333 // Since KTXorientation is only a hint and has no effect on the texture data and coordinates, it must be ignored.
334 istream.seek(4 * sizeof(uint32_t));
335 unsigned int bytesOfKeyValueData;
337 bytesOfKeyValueData = istream_read_uint32_be(istream);
339 bytesOfKeyValueData = istream_read_uint32_le(istream);
341 istream.seek(bytesOfKeyValueData + sizeof(uint32_t));
343 RGBAImage *image = new RGBAImage(width, height);
346 KTX_Decoder *decoder = NULL;
348 case KTX_TYPE_UNSIGNED_BYTE:
350 case KTX_FORMAT_ALPHA:
351 decoder = new KTX_Decoder_A8();
354 decoder = new KTX_Decoder_RGB8();
356 case KTX_FORMAT_RGBA:
357 decoder = new KTX_Decoder_RGBA8();
359 case KTX_FORMAT_LUMINANCE:
360 decoder = new KTX_Decoder_L8();
362 case KTX_FORMAT_LUMINANCE_ALPHA:
363 decoder = new KTX_Decoder_LA8();
366 decoder = new KTX_Decoder_BGR8();
368 case KTX_FORMAT_BGRA:
369 decoder = new KTX_Decoder_BGRA8();
373 case KTX_TYPE_UNSIGNED_SHORT_4_4_4_4:
374 if (format == KTX_FORMAT_RGBA) {
375 decoder = new KTX_Decoder_RGBA4(bigEndian);
378 case KTX_TYPE_UNSIGNED_SHORT_5_5_5_1:
379 if (format == KTX_FORMAT_RGBA) {
380 decoder = new KTX_Decoder_RGBA5(bigEndian);
383 case KTX_TYPE_UNSIGNED_SHORT_5_6_5:
384 if (format == KTX_FORMAT_RGB) {
385 decoder = new KTX_Decoder_RGB5(bigEndian);
391 globalErrorStream() << "LoadKTX: Image has an unsupported pixel type " << type << " or format " << format
397 unsigned int inRowLength = width * decoder->GetPixelSize();
398 unsigned int inPadding = ((inRowLength + 3) & ~3) - inRowLength;
399 byte *out = image->getRGBAPixels();
400 for (unsigned int y = 0; y < height; y++) {
401 for (unsigned int x = 0; x < width; x++, out += 4) {
402 decoder->Decode(istream, out);
406 istream.seek(inPadding);
413 case KTX_FORMAT_ETC1_RGB8:
414 KTX_DecodeETC1(istream, *image);
417 globalErrorStream() << "LoadKTX: Image has an unsupported compressed format " << format << "\n";
426 Image *LoadKTX(ArchiveFile &file)
428 ScopedArchiveBuffer buffer(file);
429 PointerInputStream istream(buffer.buffer);
430 return LoadKTXBuff(istream);