aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/graphics/tga.cpp
blob: 1bf4383ccfde6aa426dfcce345eccf74b37278e7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/* Based on code from eos https://github.com/DrMcCoy/xoreos/
 * relicensed under GPLv2+ with permission from DrMcCoy and clone2727
 */

#include "common/util.h"
#include "common/stream.h"
#include "common/textconsole.h"
#include "common/error.h"

#include "engines/wintermute/graphics/tga.h"

namespace WinterMute {

TGA::TGA() {

}

TGA::~TGA() {
	destroy();
}

void TGA::destroy() {
	_surface.free();
}

bool TGA::loadStream(Common::SeekableReadStream &tga) {
	byte imageType, pixelDepth;
	bool success;
	success = readHeader(tga, imageType, pixelDepth);
	success = readData(tga, imageType, pixelDepth);

	if (tga.err() || !success) {
		warning("Failed reading TGA-file");
		return false;
	}
	return success;
}

bool TGA::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) {
	if (!tga.seek(0)) {
		warning("Failed reading TGA-file");
		return false;
	}

	// TGAs have an optional "id" string in the header
	uint32 idLength = tga.readByte();

	// Number of colors in the color map / palette
	if (tga.readByte() != 0) {
		warning("Unsupported feature: Color map");
		return false;
	}

	// Image type. 2 == unmapped RGB, 3 == Grayscale
	imageType = tga.readByte();
	if ((imageType != 2) && (imageType != 3)) {
		warning("Unsupported image type: %d", imageType);
		return false;
	}

	// Color map specifications + X + Y
	tga.skip(5 + 2 + 2);

	// Image dimensions
	_surface.w = tga.readUint16LE();
	_surface.h = tga.readUint16LE();

	// Bits per pixel
	pixelDepth = tga.readByte();
	_surface.format.bytesPerPixel = pixelDepth / 8;

	if (imageType == 2) {
		if (pixelDepth == 24) {
			_hasAlpha  = false;
			_format = Graphics::PixelFormat(pixelDepth / 8, 8, 8, 8, 0, 16, 8, 0, 0);
		} else if (pixelDepth == 16 || pixelDepth == 32) {
			_hasAlpha  = true;
			_format = Graphics::PixelFormat(pixelDepth / 8, 8, 8, 8, 8, 24, 16, 8, 0);
		} else {
			warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
			return false;
		}
	} else if (imageType == 3) {
		if (pixelDepth != 8) {
			warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth);
			return false;
		}

		_hasAlpha  = false;
		_format = Graphics::PixelFormat(1, 0, 0, 0, 0, 0, 0, 0, 0);
	}

	// Image descriptor
	tga.skip(1);

	// Skip the id string
	tga.skip(idLength);
	return true;
}

bool TGA::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) {
	if (imageType == 2) {
		_surface.create(_surface.w, _surface.h, _format);

		if (pixelDepth == 16) {
			// Convert from 16bpp to 32bpp
			// 16bpp TGA is ARGB1555
			uint16 count = _surface.w * _surface.h;
			byte *dst = (byte *)_surface.pixels;

			while (count--) {
				uint16 pixel = tga.readUint16LE();

				*dst++ = (pixel & 0x1F) << 3;
				*dst++ = (pixel & 0x3E0) >> 2;
				*dst++ = (pixel & 0x7C00) >> 7;
				*dst++ = (pixel & 0x8000) ? 0xFF : 0x00;
			}

		} else {
			// Read it in raw
			tga.read(_surface.pixels, _surface.pitch * _surface.w);
		}
	} else if (imageType == 3) {
		_surface.create(_surface.w, _surface.h, _surface.format);

		byte *data  = (byte *)_surface.pixels;
		uint32 count = _surface.w * _surface.h;

		while (count-- > 0) {
			byte g = tga.readByte();

			memset(data, g, 3);
			data[3] = 0xFF;

			data += 4;
		}

	}
	return true;
}

} // End of namespace Graphics