aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llimage/llimagedxt.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llimage/llimagedxt.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llimage/llimagedxt.cpp')
-rw-r--r--linden/indra/llimage/llimagedxt.cpp494
1 files changed, 494 insertions, 0 deletions
diff --git a/linden/indra/llimage/llimagedxt.cpp b/linden/indra/llimage/llimagedxt.cpp
new file mode 100644
index 0000000..8b16f97
--- /dev/null
+++ b/linden/indra/llimage/llimagedxt.cpp
@@ -0,0 +1,494 @@
1/**
2 * @file llimagedxt.cpp
3 *
4 * Copyright (c) 2001-2007, Linden Research, Inc.
5 *
6 * The source code in this file ("Source Code") is provided by Linden Lab
7 * to you under the terms of the GNU General Public License, version 2.0
8 * ("GPL"), unless you have obtained a separate licensing agreement
9 * ("Other License"), formally executed by you and Linden Lab. Terms of
10 * the GPL can be found in doc/GPL-license.txt in this distribution, or
11 * online at http://secondlife.com/developers/opensource/gplv2
12 *
13 * There are special exceptions to the terms and conditions of the GPL as
14 * it is applied to this Source Code. View the full text of the exception
15 * in the file doc/FLOSS-exception.txt in this software distribution, or
16 * online at http://secondlife.com/developers/opensource/flossexception
17 *
18 * By copying, modifying or distributing this software, you acknowledge
19 * that you have read and understood your obligations described above,
20 * and agree to abide by those obligations.
21 *
22 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
23 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
24 * COMPLETENESS OR PERFORMANCE.
25 */
26
27#include "linden_common.h"
28
29#include "llimagedxt.h"
30
31//static
32void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height)
33{
34 S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1;
35 width = llmax(width, mindim);
36 height = llmax(height, mindim);
37}
38
39//static
40S32 LLImageDXT::formatBits(EFileFormat format)
41{
42 switch (format)
43 {
44 case FORMAT_DXT1: return 4;
45 case FORMAT_DXR1: return 4;
46 case FORMAT_I8: return 8;
47 case FORMAT_A8: return 8;
48 case FORMAT_DXT3: return 8;
49 case FORMAT_DXR3: return 8;
50 case FORMAT_DXR5: return 8;
51 case FORMAT_DXT5: return 8;
52 case FORMAT_RGB8: return 24;
53 case FORMAT_RGBA8: return 32;
54 default:
55 llerrs << "LLImageDXT::Unknown format: " << format << llendl;
56 return 0;
57 }
58};
59
60//static
61S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height)
62{
63 checkMinWidthHeight(format, width, height);
64 S32 bytes = ((width*height*formatBits(format)+7)>>3);
65 S32 aligned = (bytes+3)&~3;
66 return aligned;
67}
68
69//static
70S32 LLImageDXT::formatComponents(EFileFormat format)
71{
72 switch (format)
73 {
74 case FORMAT_DXT1: return 3;
75 case FORMAT_DXR1: return 3;
76 case FORMAT_I8: return 1;
77 case FORMAT_A8: return 1;
78 case FORMAT_DXT3: return 4;
79 case FORMAT_DXR3: return 4;
80 case FORMAT_DXT5: return 4;
81 case FORMAT_DXR5: return 4;
82 case FORMAT_RGB8: return 3;
83 case FORMAT_RGBA8: return 4;
84 default:
85 llerrs << "LLImageDXT::Unknown format: " << format << llendl;
86 return 0;
87 }
88};
89
90// static
91LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc)
92{
93 switch(fourcc)
94 {
95 case 0x20203849: return FORMAT_I8;
96 case 0x20203841: return FORMAT_A8;
97 case 0x20424752: return FORMAT_RGB8;
98 case 0x41424752: return FORMAT_RGBA8;
99 case 0x31525844: return FORMAT_DXR1;
100 case 0x32525844: return FORMAT_DXR2;
101 case 0x33525844: return FORMAT_DXR3;
102 case 0x34525844: return FORMAT_DXR4;
103 case 0x35525844: return FORMAT_DXR5;
104 case 0x31545844: return FORMAT_DXT1;
105 case 0x32545844: return FORMAT_DXT2;
106 case 0x33545844: return FORMAT_DXT3;
107 case 0x34545844: return FORMAT_DXT4;
108 case 0x35545844: return FORMAT_DXT5;
109 default: return FORMAT_UNKNOWN;
110 }
111}
112
113//static
114S32 LLImageDXT::getFourCC(EFileFormat format)
115{
116 switch(format)
117 {
118 case FORMAT_I8: return 0x20203849;
119 case FORMAT_A8: return 0x20203841;
120 case FORMAT_RGB8: return 0x20424752;
121 case FORMAT_RGBA8: return 0x41424752;
122 case FORMAT_DXR1: return 0x31525844;
123 case FORMAT_DXR2: return 0x32525844;
124 case FORMAT_DXR3: return 0x33525844;
125 case FORMAT_DXR4: return 0x34525844;
126 case FORMAT_DXR5: return 0x35525844;
127 case FORMAT_DXT1: return 0x31545844;
128 case FORMAT_DXT2: return 0x32545844;
129 case FORMAT_DXT3: return 0x33545844;
130 case FORMAT_DXT4: return 0x34545844;
131 case FORMAT_DXT5: return 0x35545844;
132 default: return 0x00000000;
133 }
134}
135
136//static
137void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height)
138{
139 while (discard_level > 0 && width > 1 && height > 1)
140 {
141 discard_level--;
142 width >>= 1;
143 height >>= 1;
144 }
145 checkMinWidthHeight(format, width, height);
146}
147
148//static
149S32 LLImageDXT::calcNumMips(S32 width, S32 height)
150{
151 S32 nmips = 0;
152 while (width > 0 && height > 0)
153 {
154 width >>= 1;
155 height >>= 1;
156 nmips++;
157 }
158 return nmips;
159}
160
161//============================================================================
162
163LLImageDXT::LLImageDXT()
164 : LLImageFormatted(IMG_CODEC_DXT),
165 mFileFormat(FORMAT_UNKNOWN),
166 mHeaderSize(0)
167{
168}
169
170LLImageDXT::~LLImageDXT()
171{
172}
173
174// virtual
175BOOL LLImageDXT::updateData()
176{
177 resetLastError();
178
179 U8* data = getData();
180 S32 data_size = getDataSize();
181
182 if (!data || !data_size)
183 {
184 setLastError("LLImageDXT uninitialized");
185 return FALSE;
186 }
187
188 S32 width, height, miplevelmax;
189 dxtfile_header_t* header = (dxtfile_header_t*)data;
190 if (header->fourcc != 0x20534444)
191 {
192 dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header;
193 mHeaderSize = sizeof(dxtfile_header_old_t);
194 mFileFormat = EFileFormat(oldheader->format);
195 miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP);
196 width = oldheader->maxwidth;
197 height = oldheader->maxheight;
198 }
199 else
200 {
201 mHeaderSize = sizeof(dxtfile_header_t);
202 mFileFormat = getFormat(header->pixel_fmt.fourcc);
203 miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP);
204 width = header->maxwidth;
205 height = header->maxheight;
206 }
207
208 if (data_size < mHeaderSize)
209 {
210 llerrs << "LLImageDXT: not enough data" << llendl;
211 }
212 S32 ncomponents = formatComponents(mFileFormat);
213 setSize(width, height, ncomponents);
214
215 S32 discard = calcDiscardLevelBytes(data_size);
216 discard = llmin(discard, miplevelmax);
217 setDiscardLevel(discard);
218
219 return TRUE;
220}
221
222// discard: 0 = largest (last) mip
223S32 LLImageDXT::getMipOffset(S32 discard)
224{
225 if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5)
226 {
227 llerrs << "getMipOffset called with old (unsupported) format" << llendl;
228 }
229 S32 width = getWidth(), height = getHeight();
230 S32 num_mips = calcNumMips(width, height);
231 discard = llclamp(discard, 0, num_mips-1);
232 S32 last_mip = num_mips-1-discard;
233 llassert(mHeaderSize > 0);
234 S32 offset = mHeaderSize;
235 for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--)
236 {
237 if (mipidx < last_mip)
238 {
239 offset += formatBytes(mFileFormat, width, height);
240 }
241 width >>= 1;
242 height >>= 1;
243 }
244 return offset;
245}
246
247void LLImageDXT::setFormat()
248{
249 S32 ncomponents = getComponents();
250 switch (ncomponents)
251 {
252 case 3: mFileFormat = FORMAT_DXR1; break;
253 case 4: mFileFormat = FORMAT_DXR3; break;
254 default: llerrs << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << llendl;
255 }
256 mHeaderSize = calcHeaderSize();
257}
258
259// virtual
260BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
261{
262 llassert_always(raw_image);
263
264 if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
265 {
266 llwarns << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << llendl;
267 return FALSE;
268 }
269
270 S32 width = getWidth(), height = getHeight();
271 S32 ncomponents = getComponents();
272 S32 image_size = formatBytes(mFileFormat, width, height);
273 U8* data = getData() + getMipOffset(0);
274
275 if ((!getData()) || (data + image_size > getData() + getDataSize()))
276 {
277 setLastError("LLImageDXT trying to decode an image with not enough data!");
278 return FALSE;
279 }
280
281 raw_image->resize(width, height, ncomponents);
282 memcpy(raw_image->getData(), data, image_size);
283
284 return TRUE;
285}
286
287// virtual
288BOOL LLImageDXT::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard, F32 decode_time)
289{
290 if (discard < 0)
291 {
292 discard = mDiscardLevel;
293 }
294 else if (discard < mDiscardLevel)
295 {
296 llerrs << "Request for invalid discard level" << llendl;
297 }
298 U8* data = getData() + getMipOffset(discard);
299 S32 width, height;
300 calcDiscardWidthHeight(discard, mFileFormat, width, height);
301 raw = new LLImageRaw(data, width, height, getComponents());
302 return TRUE;
303}
304
305void LLImageDXT::releaseDecodedData()
306{
307 // nothing to do
308}
309
310BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
311{
312 llassert_always(raw_image);
313
314 S32 ncomponents = raw_image->getComponents();
315 EFileFormat format;
316 switch (ncomponents)
317 {
318 case 1:
319 format = FORMAT_A8;
320 break;
321 case 3:
322 format = FORMAT_RGB8;
323 break;
324 case 4:
325 format = FORMAT_RGBA8;
326 break;
327 default:
328 llerrs << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << llendl;
329 return 0;
330 }
331
332 S32 width = raw_image->getWidth();
333 S32 height = raw_image->getHeight();
334
335 if (explicit_mips)
336 {
337 height = (height/3)*2;
338 }
339
340 setSize(width, height, ncomponents);
341 mHeaderSize = sizeof(dxtfile_header_t);
342 mFileFormat = format;
343
344 S32 nmips = calcNumMips(width, height);
345 S32 w = width;
346 S32 h = height;
347
348 S32 totbytes = mHeaderSize;
349 for (S32 mip=0; mip<nmips; mip++)
350 {
351 totbytes += formatBytes(format,w,h);
352 w >>= 1;
353 h >>= 1;
354 }
355
356 allocateData(totbytes);
357
358 U8* data = getData();
359 dxtfile_header_t* header = (dxtfile_header_t*)data;
360 llassert(mHeaderSize > 0);
361 memset(header, 0, mHeaderSize);
362 header->fourcc = 0x20534444;
363 header->pixel_fmt.fourcc = getFourCC(format);
364 header->num_mips = nmips;
365 header->maxwidth = width;
366 header->maxheight = height;
367
368 U8* prev_mipdata = 0;
369 w = width, h = height;
370 for (S32 mip=0; mip<nmips; mip++)
371 {
372 U8* mipdata = data + getMipOffset(mip);
373 S32 bytes = formatBytes(format, w, h);
374 if (mip==0)
375 {
376 memcpy(mipdata, raw_image->getData(), bytes);
377 }
378 else if (explicit_mips)
379 {
380 extractMip(raw_image->getData(), mipdata, width, height, w, h, format);
381 }
382 else
383 {
384 generateMip(prev_mipdata, mipdata, w, h, ncomponents);
385 }
386 w >>= 1;
387 h >>= 1;
388 checkMinWidthHeight(format, w, h);
389 prev_mipdata = mipdata;
390 }
391
392 return TRUE;
393}
394
395// virtual
396BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
397{
398 return encode(raw_image, time, false);
399}
400
401// virtual
402bool LLImageDXT::convertToDXR()
403{
404 EFileFormat newformat = FORMAT_UNKNOWN;
405 switch (mFileFormat)
406 {
407 case FORMAT_DXR1:
408 case FORMAT_DXR2:
409 case FORMAT_DXR3:
410 case FORMAT_DXR4:
411 case FORMAT_DXR5:
412 return false; // nothing to do
413 case FORMAT_DXT1: newformat = FORMAT_DXR1; break;
414 case FORMAT_DXT2: newformat = FORMAT_DXR2; break;
415 case FORMAT_DXT3: newformat = FORMAT_DXR3; break;
416 case FORMAT_DXT4: newformat = FORMAT_DXR4; break;
417 case FORMAT_DXT5: newformat = FORMAT_DXR5; break;
418 default:
419 llwarns << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << llendl;
420 return false;
421 }
422 mFileFormat = newformat;
423 S32 width = getWidth(), height = getHeight();
424 S32 nmips = calcNumMips(width,height);
425 S32 total_bytes = getDataSize();
426 U8* olddata = getData();
427 U8* newdata = new U8[total_bytes];
428 llassert(total_bytes > 0);
429 memset(newdata, 0, total_bytes);
430 memcpy(newdata, olddata, mHeaderSize);
431 for (S32 mip=0; mip<nmips; mip++)
432 {
433 S32 bytes = formatBytes(mFileFormat, width, height);
434 S32 newoffset = getMipOffset(mip);
435 S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes);
436 memcpy(newdata + newoffset, olddata + oldoffset, bytes);
437 width >>= 1;
438 height >>= 1;
439 }
440 dxtfile_header_t* header = (dxtfile_header_t*)newdata;
441 header->pixel_fmt.fourcc = getFourCC(newformat);
442 setData(newdata, total_bytes);
443 return true;
444}
445
446// virtual
447S32 LLImageDXT::calcHeaderSize()
448{
449 return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t));
450}
451
452// virtual
453S32 LLImageDXT::calcDataSize(S32 discard_level)
454{
455 if (mFileFormat == FORMAT_UNKNOWN)
456 {
457 llerrs << "calcDataSize called with unloaded LLImageDXT" << llendl;
458 return 0;
459 }
460 if (discard_level < 0)
461 {
462 discard_level = mDiscardLevel;
463 }
464 S32 bytes = getMipOffset(discard_level); // size of header + previous mips
465 S32 w = getWidth() >> discard_level;
466 S32 h = getHeight() >> discard_level;
467 bytes += formatBytes(mFileFormat,w,h);
468 return bytes;
469}
470
471//============================================================================
472
473//static
474void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height,
475 int mip_width, int mip_height, EFileFormat format)
476{
477 int initial_offset = formatBytes(format, width, height);
478 int line_width = formatBytes(format, width, 1);
479 int mip_line_width = formatBytes(format, mip_width, 1);
480 int line_offset = 0;
481
482 for (int ww=width>>1; ww>mip_width; ww>>=1)
483 {
484 line_offset += formatBytes(format, ww, 1);
485 }
486
487 for (int h=0;h<mip_height;++h)
488 {
489 int start_offset = initial_offset + line_width * h + line_offset;
490 memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width);
491 }
492}
493
494//============================================================================