WoW Model Viewer
Your premiere tool for viewing, equipping and animating World of Warcraft models.
Loading...
Searching...
No Matches
Texture.cpp
Go to the documentation of this file.
1#include "Texture.h"
2#include "GameFile.h"
3#include "video.h"
4#include "SoftwareImage.h"
5#include <glad/gl.h>
6#include "ddslib.h"
7
8using uint = unsigned int;
9
10Texture::Texture(GameFile* f) : ManagedItem(f->fullname()), w(0), h(0), id(0), compressed(false), file(f)
11{
12}
13
14void Texture::getPixels(unsigned char* buf, unsigned int format)
15{
16 glBindTexture(GL_TEXTURE_2D, id);
17 glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, buf);
18}
19
21{
22 // Vars
23 int offsets[16], sizes[16], type = 0;
24 uint width = 0, height = 0;
25 char attr[4];
26
27 // bind the texture
28 glBindTexture(GL_TEXTURE_2D, id);
29
30 if (!file || !file->open() || file->isEof())
31 {
32 id = 0;
33 return;
34 }
35 else
36 {
37 //tex->id = id; // I don't see the id being set anywhere, should I set it now?
38 }
39
40 file->seek(4);
41 file->read(&type, 4);
42 file->read(attr, 4);
43 file->read(&width, 4);
44 file->read(&height, 4);
45 file->read(offsets, 4 * 16);
46 file->read(sizes, 4 * 16);
47
48 const bool hasmipmaps = (attr[3] > 0);
49 const size_t mipmax = hasmipmaps ? 16 : 1;
50
51 w = width;
52 h = height;
53
54 LOG_INFO << "Loading texture" << itemName() << "type" << type << "attrs"
55 << static_cast<uint>(attr[0]) << static_cast<uint>(attr[1]) << static_cast<uint>(attr[2])
56 << static_cast<uint>(attr[3]) << "width" << width << "height" << height;
57
58 /*
59 reference: http://en.wikipedia.org/wiki/.BLP
60 */
61 if (type == 0) // JPEG compression
62 {
63 /*
64 * DWORD JpegHeaderSize;
65 * BYTE[JpegHeaderSize] JpegHeader;
66 * struct MipMap[16]
67 * {
68 * BYTE[???] JpegData;
69 * }
70 */
71 LOG_ERROR << __FILE__ << __FUNCTION__ << __LINE__ << "type=" << type;
72
73 unsigned char* buf = new unsigned char[sizes[0]];
74
75 file->seek(offsets[0]);
76 file->read(buf, sizes[0]);
77
78 SoftwareImage image = SoftwareImage::loadFromMemory(buf, sizes[0]);
79
80 if (image.empty())
81 {
82 LOG_ERROR << __FUNCTION__ << __LINE__ << "Failed to load texture";
83 }
84 else
85 {
86 // BLP JPEG textures need to be vertically flipped
87 SoftwareImage flipped = image.mirrored();
88
89 // Upload as BGRA (our internal SoftwareImage format)
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, flipped.width(), flipped.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, flipped.data());
91 }
92
93 delete [] buf;
94 buf = nullptr;
95 }
96 else if (type == 1)
97 {
98 if (attr[0] == 2)
99 {
100 /*
101 Type 1 Encoding 2 AlphaDepth 0 (DXT1 no alpha)
102 The image data is formatted using DXT1 compression with no alpha channel.
103
104 Type 1 Encoding 2 AlphaDepth 1 (DXT1 one bit alpha)
105 The image data is formatted using DXT1 compression with a one-bit alpha channel.
106
107 Type 1 Encoding 2 AlphaDepth 8 (DXT3)
108 The image data is formatted using DXT3 compression.
109
110 Type 1 Encoding 2 AlphaDepth 8 AlphaEncoding 7 (DXT5)
111 The image data are formatted using DXT5 compression.
112 */
113 // encoding 2, directx compressed
114 unsigned char* ucbuf = nullptr;
116 ucbuf = new unsigned char[width * height * 4];
117
118 GLint format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
119 int blocksize = 8;
120
121 // guesswork here :(
122 // new alpha bit depth == 4 for DXT3, alfred 2008/10/11
123 if (attr[1] == 8 || attr[1] == 4)
124 {
125 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
126 blocksize = 16;
127 }
128
129 if (attr[1] == 0 && attr[2] == 0)
130 {
131 format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
132 }
133
134
135 // Fix to the BLP2 format required in WoW 2.0 thanks to Linghuye (creator of MyWarCraftStudio)
136 if (attr[1] == 8 && attr[2] == 7)
137 {
138 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
139 blocksize = 16;
140 }
141
142 compressed = true;
143
144 unsigned char* buf = new unsigned char[sizes[0]];
145
146 // do every mipmap level
147 for (size_t i = 0; i < mipmax; i++)
148 {
149 if (width == 0) width = 1;
150 if (height == 0) height = 1;
151 if (offsets[i] && sizes[i])
152 {
153 file->seek(offsets[i]);
154 file->read(buf, sizes[i]);
155
156 const int size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
157
159 {
160 glCompressedTexImage2DARB(GL_TEXTURE_2D, static_cast<GLint>(i), format, width, height, 0, size, buf);
161 }
162 else
163 {
164 decompressDXTC(format, width, height, size, buf, ucbuf);
165 glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(i), GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
166 ucbuf);
167 }
168 }
169 else
170 {
171 break;
172 }
173 width >>= 1;
174 height >>= 1;
175 }
176
177 delete [] buf;
178 buf = nullptr;
180 {
181 delete ucbuf;
182 ucbuf = nullptr;
183 }
184 }
185 else if (attr[0] == 1)
186 {
187 /*
188 Type 1 Encoding 0 AlphaDepth 0 (uncompressed paletted image with no alpha)
189 Each by of the image data is an index into Palette which contains the actual RGB value for the pixel. Although the palette entries are 32-bits, the alpha value of each Palette entry may contain garbage and should be discarded.
190
191 Type 1 Encoding 1 AlphaDepth 1 (uncompressed paletted image with 1-bit alpha)
192 This is the same as Type 1 Encoding 1 AlphaDepth 0 except that immediately following the index array is a second image array containing 1-bit alpha values for each pixel. The first byte of the array is for pixels 0 through 7, the second byte for pixels 8 through 15 and so on. Bit 0 of each byte corresponds to the first pixel (leftmost) in the group, bit 7 to the rightmost. A set bit indicates the pixel is opaque while a zero bit indicates a transparent pixel.
193
194 Type 1 Encoding 1 AlphaDepth 8(uncompressed paletted image with 8-bit alpha)
195 This is the same as Type 1 Encoding 1 AlphaDepth 0 except that immediately following the index array is a second image array containing the actual 8-bit alpha values for each pixel. This second array starts at BLP2Header.Offset[0] + BLP2Header.Width * BLP2Header.Height.
196 */
197
198 // encoding 1, uncompressed
199 unsigned int pal[256];
200 file->read(pal, 1024);
201
202 unsigned char* buf = new unsigned char[sizes[0]];
203 unsigned int* buf2 = new unsigned int[width * height];
204
205 const int alphabits = attr[1];
206 const bool hasalpha = (alphabits != 0);
207
208 compressed = false;
209
210 for (size_t i = 0; i < mipmax; i++)
211 {
212 if (width == 0) width = 1;
213 if (height == 0) height = 1;
214 if (offsets[i] && sizes[i])
215 {
216 file->seek(offsets[i]);
217 file->read(buf, sizes[i]);
218
219 int cnt = 0;
220 int alpha = 0;
221
222 unsigned int* p = buf2;
223 const unsigned char* c = buf;
224 const unsigned char* a = buf + width * height;
225 for (uint y = 0; y < height; y++)
226 {
227 for (uint x = 0; x < width; x++)
228 {
229 uint k = pal[*c++];
230
231 k = ((k & 0x00FF0000) >> 16) | ((k & 0x0000FF00)) | ((k & 0x000000FF) << 16);
232
233 if (hasalpha)
234 {
235 if (alphabits == 8)
236 {
237 alpha = (*a++);
238 }
239 else if (alphabits == 4)
240 {
241 alpha = (*a & (0xf << cnt++)) * 0x11;
242 if (cnt == 2)
243 {
244 cnt = 0;
245 a++;
246 }
247 }
248 else if (alphabits == 1)
249 {
250 //alpha = (*a & (128 >> cnt++)) ? 0xff : 0;
251 alpha = (*a & (1 << cnt++)) ? 0xff : 0;
252 if (cnt == 8)
253 {
254 cnt = 0;
255 a++;
256 }
257 }
258 }
259 else alpha = 0xff;
260
261 k |= alpha << 24;
262 *p++ = k;
263 }
264 }
265
266 glTexImage2D(GL_TEXTURE_2D, static_cast<GLint>(i), GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf2);
267 }
268 else break;
269
270 width >>= 1;
271 height >>= 1;
272 }
273
274 delete [] buf2;
275 buf2 = nullptr;
276 delete [] buf;
277 buf = nullptr;
278 }
279 else
280 {
281 LOG_ERROR << __FILE__ << __FUNCTION__ << __LINE__ << "type=" << type << "attr[0]=" << attr[0];
282 }
283 }
284
285 file->close();
286 /*
287 // TODO: Add proper support for mipmaps
288 if (hasmipmaps) {
289 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
290 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
291 } else {
292 */
293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
295 //}
296}
297
298/*
299struct Color {
300unsigned char r, g, b;
301};
302*/
303
304void Texture::decompressDXTC(GLint format, int W, int H, size_t size, unsigned char* src, unsigned char* dest)
305{
306 // DXT1 Textures, currently being handles by our routine below
307 if (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
308 {
309 DDSDecompressDXT1(src, W, H, dest);
310 return;
311 }
312
313 // DXT3 Textures
314 if (format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT)
315 {
316 DDSDecompressDXT3(src, W, H, dest);
317 return;
318 }
319
320 // DXT5 Textures
321 if (format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
322 {
323 //DXT5UnpackAlphaValues(src, w, h, dest);
324 DDSDecompressDXT5(src, W, H, dest);
325 return;
326 }
327
328 /*
329 // sort of copied from linghuye
330 int bsx = (w<4) ? w : 4;
331 int bsy = (h<4) ? h : 4;
332
333 for(int y=0; y<h; y += bsy) {
334 for(int x=0; x<w; x += bsx) {
335 //unsigned long alpha = 0;
336 //unsigned int a0 = 0, a1 = 0;
337
338 unsigned int c0 = *(unsigned short*)(src + 0);
339 unsigned int c1 = *(unsigned short*)(src + 2);
340 src += 4;
341
342 Color color[4];
343 color[0].b = (unsigned char) ((c0 >> 11) & 0x1f) << 3;
344 color[0].g = (unsigned char) ((c0 >> 5) & 0x3f) << 2;
345 color[0].r = (unsigned char) ((c0 ) & 0x1f) << 3;
346 color[1].b = (unsigned char) ((c1 >> 11) & 0x1f) << 3;
347 color[1].g = (unsigned char) ((c1 >> 5) & 0x3f) << 2;
348 color[1].r = (unsigned char) ((c1 ) & 0x1f) << 3;
349
350 if(c0 > c1 || format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) {
351 color[2].r = (color[0].r * 2 + color[1].r) / 3;
352 color[2].g = (color[0].g * 2 + color[1].g) / 3;
353 color[2].b = (color[0].b * 2 + color[1].b) / 3;
354 color[3].r = (color[0].r + color[1].r * 2) / 3;
355 color[3].g = (color[0].g + color[1].g * 2) / 3;
356 color[3].b = (color[0].b + color[1].b * 2) / 3;
357 } else {
358 color[2].r = (color[0].r + color[1].r) / 2;
359 color[2].g = (color[0].g + color[1].g) / 2;
360 color[2].b = (color[0].b + color[1].b) / 2;
361 color[3].r = 0;
362 color[3].g = 0;
363 color[3].b = 0;
364 }
365
366 for (ssize_t j=0; j<bsy; j++) {
367 unsigned int index = *src++;
368 unsigned char* dd = dest + (w*(y+j)+x)*4;
369 for (size_t i=0; i<bsx; i++) {
370 *dd++ = color[index & 0x03].b;
371 *dd++ = color[index & 0x03].g;
372 *dd++ = color[index & 0x03].r;
373 //if (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) {
374 *dd++ = ((index & 0x03) == 3 && c0 <= c1) ? 0 : 255;
375 //}
376 index >>= 2;
377 }
378 }
379 }
380 }
381 */
382}
#define LOG_ERROR
Definition Logger.h:11
#define LOG_INFO
Definition Logger.h:10
Abstract base class representing a file within the game data archive.
Definition GameFile.h:12
bool open(bool useMemoryBuffer=true)
Open the file, optionally loading into a memory buffer.
Definition GameFile.cpp:41
virtual void seek(size_t offset)
Seek to an absolute byte offset.
Definition GameFile.cpp:29
bool close()
Close the file and release the internal buffer.
Definition GameFile.cpp:74
virtual size_t read(void *dest, size_t bytes)
Read bytes from the file into dest.
Definition GameFile.cpp:5
bool isEof()
True if the read pointer has reached the end of the file.
Definition GameFile.cpp:24
Reference-counted item stored in a Manager.
Definition manager.h:15
const std::string & itemName() const
Definition manager.h:39
CPU-side image buffer storing BGRA pixel data.
SoftwareImage mirrored() const
Return a vertically mirrored copy.
bool empty() const
True if the image has zero dimensions.
static SoftwareImage loadFromMemory(const uint8_t *data, int size)
Load a JPEG image from a memory buffer.
int height() const
Image height in pixels.
uint8_t * data()
Mutable pointer to the raw BGRA pixel buffer.
int width() const
Image width in pixels.
GameFile * file
Definition Texture.h:14
Texture(GameFile *)
Definition Texture.cpp:10
int h
Definition Texture.h:11
bool compressed
Definition Texture.h:13
void decompressDXTC(GLint format, int w, int h, size_t size, unsigned char *src, unsigned char *dest)
Definition Texture.cpp:304
void getPixels(unsigned char *buff, unsigned int format=GL_RGBA)
Definition Texture.cpp:14
int w
Definition Texture.h:11
void load()
Definition Texture.cpp:20
bool supportCompression
Definition video.h:93
int DDSDecompressDXT1(unsigned char *src, int width, int height, unsigned char *dest)
Decompress a DXT1 (BC1) compressed texture into raw RGBA pixels.
Definition ddslib.cpp:479
int DDSDecompressDXT3(unsigned char *src, int width, int height, unsigned char *dest)
Decompress a DXT3 (BC2) compressed texture into raw RGBA pixels.
Definition ddslib.cpp:519
int DDSDecompressDXT5(unsigned char *src, int width, int height, unsigned char *dest)
Decompress a DXT5 (BC3) compressed texture into raw RGBA pixels.
Definition ddslib.cpp:566
unsigned int uint
Definition types.h:36
VideoSettings video
Definition video.cpp:38