xoreos  0.0.5
txb.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include "src/common/scopedptr.h"
26 #include "src/common/util.h"
27 #include "src/common/error.h"
29 
32 
33 static const byte kEncodingBGRA = 0x04;
34 static const byte kEncodingGray = 0x09;
35 static const byte kEncodingDXT1 = 0x0A;
36 static const byte kEncodingDXT5 = 0x0C;
37 
38 namespace Graphics {
39 
41  load(txb);
42 }
43 
45 }
46 
48  try {
49 
50  uint32 dataSize;
51  byte encoding;
52 
53  readHeader(txb, encoding, dataSize);
54  readData (txb, encoding);
55 
56  txb.seek(dataSize + 128);
57 
58  readTXI(txb);
59 
60  } catch (Common::Exception &e) {
61  e.add("Failed reading TXB file");
62  throw;
63  }
64 }
65 
66 static uint32 getTXBDataSize(byte encoding, PixelFormatRaw format, int32 width, int32 height) {
67  switch (encoding) {
68  case kEncodingBGRA:
69  case kEncodingDXT1:
70  case kEncodingDXT5:
71  return getDataSize(format, width, height);
72 
73  case kEncodingGray:
74  return width * height;
75  }
76 
77  return 0;
78 }
79 
80 void TXB::readHeader(Common::SeekableReadStream &txb, byte &encoding, uint32 &dataSize) {
81  // Number of bytes for the pixel data in one full image
82  dataSize = txb.readUint32LE();
83 
84  txb.skip(4); // Some float
85 
86  // Image dimensions
87  uint32 width = txb.readUint16LE();
88  uint32 height = txb.readUint16LE();
89 
90  if ((width >= 0x8000) || (height >= 0x8000))
91  throw Common::Exception("Unsupported image dimensions (%ux%u)", width, height);
92 
93  // How's the pixel data encoded?
94  encoding = txb.readByte();
95 
96  // Number of mip maps in the image
97  byte mipMapCount = txb.readByte();
98 
99  txb.skip(2); // Unknown (Always 0x0101 on 0x0A and 0x0C types, 0x0100 on 0x09?)
100  txb.skip(4); // Some float
101  txb.skip(108); // Reserved
102 
103  if (encoding == kEncodingBGRA) {
104  // Raw BGRA, swizzled
105 
106  _compressed = false;
107  _hasAlpha = true;
111 
112  } else if (encoding == kEncodingGray) {
113  // Raw Grayscale, swizzled. We map it to BGR
114 
115  _compressed = false;
116  _hasAlpha = false;
120 
121  } else if (encoding == kEncodingDXT1) {
122  // S3TC DXT1
123 
124  _compressed = true;
125  _hasAlpha = false;
129 
130  } else if (encoding == kEncodingDXT5) {
131  // S3TC DXT5
132 
133  _compressed = true;
134  _hasAlpha = true;
138 
139  } else
140  throw Common::Exception("Unknown TXB encoding 0x%02X (%dx%d, %d, %d)",
141  encoding, width, height, mipMapCount, dataSize);
142 
143  if (!hasValidDimensions(_formatRaw, width, height))
144  throw Common::Exception("Invalid dimensions (%dx%d) for format %d", width, height, _formatRaw);
145 
146  const size_t fullImageDataSize = getTXBDataSize(encoding, _formatRaw, width, height);
147  if (dataSize < fullImageDataSize)
148  throw Common::Exception("Image wouldn't fit into data");
149 
150  _mipMaps.reserve(mipMapCount);
151  for (uint32 i = 0; i < mipMapCount; i++) {
152  Common::ScopedPtr<MipMap> mipMap(new MipMap(this));
153 
154  mipMap->width = width;
155  mipMap->height = height;
156  mipMap->size = getTXBDataSize(encoding, _formatRaw, width, height);
157 
158  _mipMaps.push_back(mipMap.release());
159 
160  if (width > 1) width >>= 1;
161  if (height > 1) height >>= 1;
162  }
163 
164 }
165 
166 void TXB::deSwizzle(byte *dst, const byte *src, uint32 width, uint32 height, uint8 bpp) {
167  for (uint32 y = 0; y < height; y++) {
168  for (uint32 x = 0; x < width; x++) {
169  const uint32 offset = deSwizzleOffset(x, y, width, height) * bpp;
170 
171  for (uint8 p = 0; p < bpp; p++)
172  *dst++ = src[offset + p];
173  }
174  }
175 }
176 
178  for (MipMaps::iterator mipMap = _mipMaps.begin(); mipMap != _mipMaps.end(); ++mipMap) {
179  const bool needDeSwizzle = (encoding == kEncodingBGRA) || (encoding == kEncodingGray);
180 
181  // If the texture width is a power of two, the texture memory layout is "swizzled"
182  const bool widthPOT = ((*mipMap)->width & ((*mipMap)->width - 1)) == 0;
183  const bool swizzled = needDeSwizzle && widthPOT;
184 
185  (*mipMap)->data.reset(new byte[(*mipMap)->size]);
186  if (txb.read((*mipMap)->data.get(), (*mipMap)->size) != (*mipMap)->size)
188 
189  if (encoding == kEncodingGray) {
190  // Convert grayscale into BGR
191 
192  const uint32 oldSize = (*mipMap)->size;
193  const uint32 newSize = (*mipMap)->size * 3;
194 
195  Common::ScopedArray<byte> tmp1(new byte[newSize]);
196  for (uint32 i = 0; i < oldSize; i++)
197  tmp1[i * 3 + 0] = tmp1[i * 3 + 1] = tmp1[i * 3 + 2] = (*mipMap)->data[i];
198 
199  if (swizzled) {
200  Common::ScopedArray<byte> tmp2(new byte[newSize]);
201  deSwizzle(tmp2.get(), tmp1.get(), (*mipMap)->width, (*mipMap)->height, 3);
202 
203  tmp1.swap(tmp2);
204  }
205 
206  (*mipMap)->data.swap(tmp1);
207  (*mipMap)->size = newSize;
208 
209  } else if (swizzled) {
210  Common::ScopedArray<byte> tmp(new byte[(*mipMap)->size]);
211 
212  deSwizzle(tmp.get(), (*mipMap)->data.get(), (*mipMap)->width, (*mipMap)->height, 4);
213 
214  (*mipMap)->data.swap(tmp);
215  }
216 
217  }
218 }
219 
221  const size_t txiDataSize = txb.size() - txb.pos();
222  if (txiDataSize == 0)
223  return;
224 
226 
227  try {
228  _txi.load(*txiData);
229  } catch (...) {
230  }
231 }
232 
233 } // End of namespace Graphics
uint16 readUint16LE()
Read an unsigned 16-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:122
static const byte kEncodingGray
Definition: txb.cpp:34
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
uint32 readUint32LE()
Read an unsigned 32-bit word stored in little endian (LSB first) order from the stream and return it...
Definition: readstream.h:133
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
PointerType release()
Returns the plain pointer value and releases ScopedPtr.
Definition: scopedptr.h:103
MemoryReadStream * readStream(size_t dataSize)
Read the specified amount of data into a new[]&#39;ed buffer which then is wrapped into a MemoryReadStrea...
Definition: readstream.cpp:67
uint8_t uint8
Definition: types.h:200
static bool hasValidDimensions(PixelFormatRaw format, int32 width, int32 height)
Are these image dimensions valid for this format?
Definition: util.h:73
TXB(Common::SeekableReadStream &txb)
Definition: txb.cpp:40
Implementing the reading stream interfaces for plain memory blocks.
void load(Common::SeekableReadStream &txb)
Definition: txb.cpp:47
void swap(ScopedPtrBase< T, Deallocator > &right)
Swap the managed pointers of two ScopedPtrs of the same type.
Definition: scopedptr.h:110
PixelFormatRaw
Definition: types.h:55
void load(Common::SeekableReadStream &stream)
Definition: txi.cpp:112
PixelDataType _dataType
Definition: decoder.h:124
Exception that provides a stack of explanations.
Definition: error.h:36
A simple scoped smart pointer template.
Basic exceptions to throw.
static uint32 deSwizzleOffset(uint32 x, uint32 y, uint32 width, uint32 height)
De-"swizzle" a texture pixel offset.
Definition: util.h:179
void readTXI(Common::SeekableReadStream &txb)
Definition: txb.cpp:220
PixelFormat _format
Definition: decoder.h:122
Utility templates and functions.
TXB (another one of BioWare&#39;s own texture formats) loading.
static uint32 getTXBDataSize(byte encoding, PixelFormatRaw format, int32 width, int32 height)
Definition: txb.cpp:66
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Definition: readstream.h:317
PixelFormatRaw _formatRaw
Definition: decoder.h:123
virtual size_t read(void *dataPtr, size_t dataSize)=0
Read data from the stream.
static const byte kEncodingDXT5
Definition: txb.cpp:36
static void deSwizzle(byte *dst, const byte *src, uint32 width, uint32 height, uint8 bpp)
Definition: txb.cpp:166
Image related utility functions.
StackException Exception
Definition: error.h:59
const Exception kReadError("Read error")
Exception when reading from a stream failed.
Definition: error.h:62
A scoped plain pointer, allowing pointer-y access and normal deletion.
Definition: scopedptr.h:120
void readData(Common::SeekableReadStream &txb, byte encoding)
Definition: txb.cpp:177
virtual size_t size() const =0
Obtains the total size of the stream, measured in bytes.
static uint32 getDataSize(PixelFormatRaw format, int32 width, int32 height)
Return the number of bytes necessary to hold an image of these dimensions and in this format...
Definition: util.h:43
virtual size_t pos() const =0
Obtains the current value of the stream position indicator of the stream.
static const byte kEncodingBGRA
Definition: txb.cpp:33
PointerType get() const
Returns the plain pointer value.
Definition: scopedptr.h:96
uint32_t uint32
Definition: types.h:204
static const byte kEncodingDXT1
Definition: txb.cpp:35
Interface for a seekable & readable data stream.
Definition: readstream.h:265
byte readByte()
Read an unsigned byte from the stream and return it.
Definition: readstream.h:92
uint8 byte
Definition: types.h:209
int32_t int32
Definition: types.h:203
void readHeader(Common::SeekableReadStream &txb, byte &encoding, uint32 &dataSize)
Definition: txb.cpp:80