xoreos  0.0.5
tga.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 /* Based on ScummVM (<http://scummvm.org>) code, which is released
26  * under the terms of version 2 or later of the GNU General Public
27  * License.
28  *
29  * The original copyright note in ScummVM reads as follows:
30  *
31  * ScummVM is the legal property of its developers, whose names
32  * are too numerous to list here. Please refer to the COPYRIGHT
33  * file distributed with this source distribution.
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of the GNU General Public License
37  * as published by the Free Software Foundation; either version 2
38  * of the License, or (at your option) any later version.
39  *
40  * This program is distributed in the hope that it will be useful,
41  * but WITHOUT ANY WARRANTY; without even the implied warranty of
42  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43  * GNU General Public License for more details.
44  *
45  * You should have received a copy of the GNU General Public License
46  * along with this program; if not, write to the Free Software
47  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
48  */
49 
50 #include <cstring>
51 
52 #include "src/common/util.h"
53 #include "src/common/readstream.h"
54 #include "src/common/error.h"
55 
58 
59 namespace Graphics {
60 
61 TGA::TGA(Common::SeekableReadStream &tga, bool cubeMap) {
62  if (cubeMap) {
63  _layerCount = 6;
64  _isCubeMap = true;
65  }
66 
67  _compressed = false;
68 
69  load(tga);
70 }
71 
73 }
74 
76  try {
77 
78  ImageType imageType;
79  byte pixelDepth, imageDesc;
80  readHeader(tga, imageType, pixelDepth, imageDesc);
81  readData (tga, imageType, pixelDepth, imageDesc);
82 
83  } catch (Common::Exception &e) {
84  e.add("Failed reading TGA file");
85  throw;
86  }
87 }
88 
89 void TGA::readHeader(Common::SeekableReadStream &tga, ImageType &imageType, byte &pixelDepth, byte &imageDesc) {
90  tga.seek(0);
91 
92  // TGAs have an optional "id" string in the header
93  uint32 idLength = tga.readByte();
94 
95  // Number of colors in the color map / palette
96  if (tga.readByte() != 0)
97  throw Common::Exception("Unsupported feature: Color map");
98 
99  // Image type. 2 == unmapped RGB, 3 == Grayscale
100  imageType = (ImageType)tga.readByte();
101  if (!isSupportedImageType(imageType))
102  throw Common::Exception("Unsupported image type: %d", imageType);
103 
104  if ((imageType == kImageTypeRLECMap) ||
105  (imageType == kImageTypeRLETrueColor) ||
106  (imageType == kImageTypeRLEBW)) {
107 
108  /* Multi-layer images (e.g. cube maps) are split into multiple images.
109  * RLE compression adds a complexity there, since the split might be
110  * in the middle of a run. We need a file to test this on first.
111  */
112 
113  if (_layerCount > 1)
114  throw Common::Exception("TODO: RLE-compressed multi-layer TGA");
115  }
116 
117  // Color map specifications + X + Y
118  tga.skip(5 + 2 + 2);
119 
120  int32 width = tga.readUint16LE();
121  int32 height = tga.readUint16LE();
122 
123  if ((width >= 0x8000) || (height >= 0x8000))
124  throw Common::Exception("Unsupported image dimensions (%dx%d)", width, height);
125 
126  if ((height % _layerCount) != 0)
127  throw Common::Exception("TGA with %u layers but size of %dx%d", (uint) _layerCount, width, height);
128 
129  height /= _layerCount;
130 
132  for (size_t i = 0; i < _layerCount; i++) {
133  _mipMaps[i] = new MipMap(this);
134 
135  _mipMaps[i]->width = width;
136  _mipMaps[i]->height = height;
137  }
138 
139  // Bits per pixel
140  pixelDepth = tga.readByte();
141 
142  if (imageType == kImageTypeTrueColor || imageType == kImageTypeRLETrueColor) {
143  if (pixelDepth == 24) {
144  _hasAlpha = false;
148  } else if (pixelDepth == 16 || pixelDepth == 32) {
149  _hasAlpha = true;
153  } else if (pixelDepth == 8) {
154  imageType = kImageTypeBW;
155 
156  _hasAlpha = false;
160  } else
161  throw Common::Exception("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
162  } else if (imageType == kImageTypeBW) {
163  if (pixelDepth != 8)
164  throw Common::Exception("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
165 
166  _hasAlpha = false;
170  }
171 
172  // Image descriptor
173  imageDesc = tga.readByte();
174 
175  // Skip the id string
176  tga.skip(idLength);
177 }
178 
179 void TGA::readData(Common::SeekableReadStream &tga, ImageType imageType, byte pixelDepth, byte imageDesc) {
180  for (size_t i = 0; i < _layerCount; i++) {
181  if (imageType == kImageTypeTrueColor || imageType == kImageTypeRLETrueColor) {
182  _mipMaps[i]->size = _mipMaps[i]->width * _mipMaps[i]->height;
183  if (_format == kPixelFormatBGR)
184  _mipMaps[i]->size *= 3;
185  else if (_format == kPixelFormatBGRA)
186  _mipMaps[i]->size *= 4;
187 
188  _mipMaps[i]->data.reset(new byte[_mipMaps[i]->size]);
189 
190  if (imageType == kImageTypeTrueColor) {
191  if (pixelDepth == 16) {
192  // Convert from 16bpp to 32bpp.
193  // 16bpp TGA is usually ARGB1555, but Sonic's are AGBR1555.
194  // Hopefully Sonic is the only game that needs 16bpp TGAs.
195 
196  uint16 count = _mipMaps[i]->width * _mipMaps[i]->height;
197  byte *dst = _mipMaps[i]->data.get();
198 
199  while (count--) {
200  uint16 pixel = tga.readUint16LE();
201 
202  *dst++ = (pixel & 0x7C00) >> 7;
203  *dst++ = (pixel & 0x03E0) >> 2;
204  *dst++ = (pixel & 0x001F) << 3;
205  *dst++ = (pixel & 0x8000) ? 0xFF : 0x00;
206  }
207  } else {
208  // Read it in raw
209  tga.read(_mipMaps[i]->data.get(), _mipMaps[i]->size);
210  }
211  } else {
212  readRLE(tga, pixelDepth, i);
213  }
214  } else if (imageType == kImageTypeBW) {
215  _mipMaps[i]->size = _mipMaps[i]->width * _mipMaps[i]->height * 4;
216  _mipMaps[i]->data.reset(new byte[_mipMaps[i]->size]);
217 
218  byte *data = _mipMaps[i]->data.get();
219  uint32 count = _mipMaps[i]->width * _mipMaps[i]->height;
220 
221  while (count-- > 0) {
222  byte g = tga.readByte();
223 
224  std::memset(data, g, 3);
225  data[3] = 0xFF;
226 
227  data += 4;
228  }
229 
230  }
231 
232  // Bit 5 of imageDesc set means the origin in upper-left corner
233  if (imageDesc & 0x20)
234  flipVertically(_mipMaps[i]->data.get(), _mipMaps[i]->width, _mipMaps[i]->height, pixelDepth / 8);
235  }
236 }
237 
238 void TGA::readRLE(Common::SeekableReadStream &tga, byte pixelDepth, size_t layer) {
239  if (pixelDepth != 24 && pixelDepth != 32)
240  throw Common::Exception("Unhandled RLE depth %d", pixelDepth);
241 
242  byte *data = _mipMaps[layer]->data.get();
243  uint32 count = _mipMaps[layer]->width * _mipMaps[layer]->height;
244 
245  while (count > 0) {
246  byte code = tga.readByte();
247  byte length = MIN<uint32>((code & 0x7F) + 1, count);
248 
249  count -= length;
250 
251  if (code & 0x80) {
252  if (pixelDepth == 32) {
253  uint32 color = tga.readUint32BE();
254 
255  while (length--) {
256  WRITE_BE_UINT32(data, color);
257  data += 4;
258  }
259  } else if (pixelDepth == 24) {
260  byte b = tga.readByte();
261  byte g = tga.readByte();
262  byte r = tga.readByte();
263 
264  while (length--) {
265  *data++ = b;
266  *data++ = g;
267  *data++ = r;
268  }
269  }
270  } else {
271  if (pixelDepth == 32) {
272  while (length--) {
273  WRITE_BE_UINT32(data, tga.readUint32BE());
274  data += 4;
275  }
276  } else if (pixelDepth == 24) {
277  while (length--) {
278  *data++ = tga.readByte();
279  *data++ = tga.readByte();
280  *data++ = tga.readByte();
281  }
282  }
283  }
284  }
285 }
286 
288  // We currently only support a limited number of types
289  switch (type) {
290  case kImageTypeTrueColor:
291  case kImageTypeBW:
293  return true;
294  default:
295  break;
296  }
297 
298  return false;
299 }
300 
301 } // 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
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
void readHeader(Common::SeekableReadStream &tga, ImageType &imageType, byte &pixelDepth, byte &imageDesc)
Definition: tga.cpp:89
virtual size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)=0
Sets the stream position indicator for the stream.
void readData(Common::SeekableReadStream &tga, ImageType imageType, byte pixelDepth, byte imageDesc)
Definition: tga.cpp:179
bool _isCubeMap
Is this image a cube map? A cube map always needs to have 6 layers!
Definition: decoder.h:129
void resize(typename std::vector< T *>::size_type n, typename std::vector< T *>::value_type val=typename std::vector< T *>::value_type())
Definition: ptrvector.h:76
PixelDataType _dataType
Definition: decoder.h:124
Exception that provides a stack of explanations.
Definition: error.h:36
Basic exceptions to throw.
uint16_t uint16
Definition: types.h:202
PixelFormat _format
Definition: decoder.h:122
Utility templates and functions.
size_t _layerCount
Number of layers in this image.
Definition: decoder.h:127
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.
Image related utility functions.
StackException Exception
Definition: error.h:59
Basic reading stream interfaces.
uint32 readUint32BE()
Read an unsigned 32-bit word stored in big endian (MSB first) order from the stream and return it...
Definition: readstream.h:166
Decoding TGA (TarGa) images.
uint32_t uint32
Definition: types.h:204
static void flipVertically(byte *data, int width, int height, int bpp)
Flip an image vertically.
Definition: util.h:122
bool isSupportedImageType(ImageType type) const
Definition: tga.cpp:287
void load(Common::SeekableReadStream &tga)
Definition: tga.cpp:75
Interface for a seekable & readable data stream.
Definition: readstream.h:265
TGA(Common::SeekableReadStream &tga, bool cubeMap=false)
Definition: tga.cpp:61
byte readByte()
Read an unsigned byte from the stream and return it.
Definition: readstream.h:92
uint8 byte
Definition: types.h:209
void readRLE(Common::SeekableReadStream &tga, byte pixelDepth, size_t layer)
Definition: tga.cpp:238
unsigned int uint
Definition: types.h:211
int32_t int32
Definition: types.h:203