diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llimage | |
parent | README.txt (diff) | |
download | meta-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')
-rw-r--r-- | linden/indra/llimage/files.lst | 6 | ||||
-rw-r--r-- | linden/indra/llimage/llimage.cpp | 1791 | ||||
-rw-r--r-- | linden/indra/llimage/llimage.h | 317 | ||||
-rw-r--r-- | linden/indra/llimage/llimage.vcproj | 209 | ||||
-rw-r--r-- | linden/indra/llimage/llimagebmp.cpp | 643 | ||||
-rw-r--r-- | linden/indra/llimage/llimagebmp.h | 64 | ||||
-rw-r--r-- | linden/indra/llimage/llimagedxt.cpp | 494 | ||||
-rw-r--r-- | linden/indra/llimage/llimagedxt.h | 139 | ||||
-rw-r--r-- | linden/indra/llimage/llimagej2c.cpp | 402 | ||||
-rw-r--r-- | linden/indra/llimage/llimagej2c.h | 99 | ||||
-rw-r--r-- | linden/indra/llimage/llimagejpeg.cpp | 621 | ||||
-rw-r--r-- | linden/indra/llimage/llimagejpeg.h | 82 | ||||
-rw-r--r-- | linden/indra/llimage/llimagetga.cpp | 1109 | ||||
-rw-r--r-- | linden/indra/llimage/llimagetga.h | 108 | ||||
-rw-r--r-- | linden/indra/llimage/llmapimagetype.h | 41 |
15 files changed, 6125 insertions, 0 deletions
diff --git a/linden/indra/llimage/files.lst b/linden/indra/llimage/files.lst new file mode 100644 index 0000000..83f53bc --- /dev/null +++ b/linden/indra/llimage/files.lst | |||
@@ -0,0 +1,6 @@ | |||
1 | llimage/llimagebmp.cpp | ||
2 | llimage/llimage.cpp | ||
3 | llimage/llimagedxt.cpp | ||
4 | llimage/llimagej2c.cpp | ||
5 | llimage/llimagejpeg.cpp | ||
6 | llimage/llimagetga.cpp \ No newline at end of file | ||
diff --git a/linden/indra/llimage/llimage.cpp b/linden/indra/llimage/llimage.cpp new file mode 100644 index 0000000..acd6aef --- /dev/null +++ b/linden/indra/llimage/llimage.cpp | |||
@@ -0,0 +1,1791 @@ | |||
1 | /** | ||
2 | * @file llimage.cpp | ||
3 | * @brief Base class for images. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <stdio.h> | ||
33 | #include <algorithm> | ||
34 | #include <iostream> | ||
35 | |||
36 | #include "llmath.h" | ||
37 | #include "stdtypes.h" | ||
38 | #include "v4coloru.h" | ||
39 | #include "llmemory.h" | ||
40 | |||
41 | #include "llimage.h" | ||
42 | #include "llimagebmp.h" | ||
43 | #include "llimagetga.h" | ||
44 | #include "llimagej2c.h" | ||
45 | #if JPEG_SUPPORT | ||
46 | #include "llimagejpeg.h" | ||
47 | #endif | ||
48 | #include "llimagedxt.h" | ||
49 | |||
50 | //--------------------------------------------------------------------------- | ||
51 | // LLImageBase | ||
52 | //--------------------------------------------------------------------------- | ||
53 | |||
54 | LLImageBase::LLImageBase() | ||
55 | : mData(NULL), | ||
56 | mDataSize(0), | ||
57 | mWidth(0), | ||
58 | mHeight(0), | ||
59 | mComponents(0), | ||
60 | mMemType(LLMemType::MTYPE_IMAGEBASE) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | // virtual | ||
65 | LLImageBase::~LLImageBase() | ||
66 | { | ||
67 | deleteData(); // virtual | ||
68 | } | ||
69 | |||
70 | // virtual | ||
71 | void LLImageBase::dump() | ||
72 | { | ||
73 | llinfos << "LLImageBase mComponents " << mComponents | ||
74 | << " mData " << mData | ||
75 | << " mDataSize " << mDataSize | ||
76 | << " mWidth " << mWidth | ||
77 | << " mHeight " << mHeight | ||
78 | << llendl; | ||
79 | } | ||
80 | |||
81 | // virtual | ||
82 | void LLImageBase::sanityCheck() | ||
83 | { | ||
84 | if (mWidth > MAX_IMAGE_SIZE | ||
85 | || mHeight > MAX_IMAGE_SIZE | ||
86 | || mDataSize > (S32)MAX_IMAGE_DATA_SIZE | ||
87 | || mComponents > (S8)MAX_IMAGE_COMPONENTS | ||
88 | ) | ||
89 | { | ||
90 | llerrs << "Failed LLImageBase::sanityCheck " | ||
91 | << "width " << mWidth | ||
92 | << "height " << mHeight | ||
93 | << "datasize " << mDataSize | ||
94 | << "components " << mComponents | ||
95 | << "data " << mData | ||
96 | << llendl; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | LLString LLImageBase::sLastErrorMessage; | ||
101 | BOOL LLImageBase::sSizeOverride = FALSE; | ||
102 | |||
103 | BOOL LLImageBase::setLastError(const LLString& message, const LLString& filename) | ||
104 | { | ||
105 | sLastErrorMessage = message; | ||
106 | if (filename != "") | ||
107 | { | ||
108 | sLastErrorMessage += LLString(" FILE:"); | ||
109 | sLastErrorMessage += filename; | ||
110 | } | ||
111 | llwarns << sLastErrorMessage << llendl; | ||
112 | return FALSE; | ||
113 | } | ||
114 | |||
115 | // virtual | ||
116 | void LLImageBase::deleteData() | ||
117 | { | ||
118 | delete[] mData; | ||
119 | mData = NULL; | ||
120 | mDataSize = 0; | ||
121 | } | ||
122 | |||
123 | // virtual | ||
124 | U8* LLImageBase::allocateData(S32 size) | ||
125 | { | ||
126 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
127 | |||
128 | if (size < 0) | ||
129 | { | ||
130 | size = mWidth * mHeight * mComponents; | ||
131 | if (size <= 0) | ||
132 | { | ||
133 | llerrs << llformat("LLImageBase::allocateData called with bad dimentions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl; | ||
134 | } | ||
135 | } | ||
136 | else if ((size <= 0 || size > 4096*4096*16) && sSizeOverride == FALSE) | ||
137 | { | ||
138 | llerrs << "LLImageBase::allocateData: bad size: " << size << llendl; | ||
139 | } | ||
140 | |||
141 | resetLastError(); | ||
142 | |||
143 | if (!mData || size != mDataSize) | ||
144 | { | ||
145 | deleteData(); // virtual | ||
146 | mData = new U8[size]; | ||
147 | if (!mData) | ||
148 | { | ||
149 | llerrs << "allocate image data: " << size << llendl; | ||
150 | } | ||
151 | mDataSize = size; | ||
152 | } | ||
153 | |||
154 | return mData; | ||
155 | } | ||
156 | |||
157 | // virtual | ||
158 | U8* LLImageBase::reallocateData(S32 size) | ||
159 | { | ||
160 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
161 | U8 *new_datap = new U8[size]; | ||
162 | if (!new_datap) | ||
163 | { | ||
164 | llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; | ||
165 | return 0; | ||
166 | } | ||
167 | if (mData) | ||
168 | { | ||
169 | S32 bytes = llmin(mDataSize, size); | ||
170 | memcpy(new_datap, mData, bytes); | ||
171 | delete[] mData; | ||
172 | } | ||
173 | mData = new_datap; | ||
174 | mDataSize = size; | ||
175 | return mData; | ||
176 | } | ||
177 | |||
178 | |||
179 | void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents) | ||
180 | { | ||
181 | mWidth = width; | ||
182 | mHeight = height; | ||
183 | mComponents = ncomponents; | ||
184 | } | ||
185 | |||
186 | U8* LLImageBase::allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size) | ||
187 | { | ||
188 | setSize(width, height, ncomponents); | ||
189 | return allocateData(size); // virtual | ||
190 | } | ||
191 | |||
192 | //--------------------------------------------------------------------------- | ||
193 | // LLImageRaw | ||
194 | //--------------------------------------------------------------------------- | ||
195 | |||
196 | S32 LLImageRaw::sGlobalRawMemory = 0; | ||
197 | S32 LLImageRaw::sRawImageCount = 0; | ||
198 | |||
199 | LLImageRaw::LLImageRaw() | ||
200 | : LLImageBase() | ||
201 | { | ||
202 | mMemType = LLMemType::MTYPE_IMAGERAW; | ||
203 | ++sRawImageCount; | ||
204 | } | ||
205 | |||
206 | LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) | ||
207 | : LLImageBase() | ||
208 | { | ||
209 | mMemType = LLMemType::MTYPE_IMAGERAW; | ||
210 | llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE ); | ||
211 | allocateDataSize(width, height, components); | ||
212 | ++sRawImageCount; | ||
213 | } | ||
214 | |||
215 | LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) | ||
216 | : LLImageBase() | ||
217 | { | ||
218 | mMemType = LLMemType::MTYPE_IMAGERAW; | ||
219 | copyData(data, width, height, components); | ||
220 | ++sRawImageCount; | ||
221 | } | ||
222 | |||
223 | LLImageRaw::LLImageRaw(const LLString &filename, bool j2c_lowest_mip_only) | ||
224 | : LLImageBase() | ||
225 | { | ||
226 | createFromFile(filename, j2c_lowest_mip_only); | ||
227 | } | ||
228 | |||
229 | LLImageRaw::~LLImageRaw() | ||
230 | { | ||
231 | // NOTE: ~LLimageBase() call to deleteData() calls LLImageBase::deleteData() | ||
232 | // NOT LLImageRaw::deleteData() | ||
233 | deleteData(); | ||
234 | --sRawImageCount; | ||
235 | } | ||
236 | |||
237 | // virtual | ||
238 | U8* LLImageRaw::allocateData(S32 size) | ||
239 | { | ||
240 | U8* res = LLImageBase::allocateData(size); | ||
241 | sGlobalRawMemory += getDataSize(); | ||
242 | return res; | ||
243 | } | ||
244 | |||
245 | // virtual | ||
246 | U8* LLImageRaw::reallocateData(S32 size) | ||
247 | { | ||
248 | sGlobalRawMemory -= getDataSize(); | ||
249 | U8* res = LLImageBase::reallocateData(size); | ||
250 | sGlobalRawMemory += getDataSize(); | ||
251 | return res; | ||
252 | } | ||
253 | |||
254 | // virtual | ||
255 | void LLImageRaw::deleteData() | ||
256 | { | ||
257 | sGlobalRawMemory -= getDataSize(); | ||
258 | LLImageBase::deleteData(); | ||
259 | } | ||
260 | |||
261 | BOOL LLImageRaw::copyData(U8 *data, U16 width, U16 height, S8 components) | ||
262 | { | ||
263 | if (!resize(width, height, components)) | ||
264 | { | ||
265 | return FALSE; | ||
266 | } | ||
267 | memcpy(getData(), data, width*height*components); | ||
268 | return TRUE; | ||
269 | } | ||
270 | |||
271 | BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) | ||
272 | { | ||
273 | if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components)) | ||
274 | { | ||
275 | return TRUE; | ||
276 | } | ||
277 | // Reallocate the data buffer. | ||
278 | deleteData(); | ||
279 | |||
280 | allocateDataSize(width,height,components); | ||
281 | |||
282 | return TRUE; | ||
283 | } | ||
284 | |||
285 | U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const | ||
286 | { | ||
287 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
288 | U8 *data = new U8[width*height*getComponents()]; | ||
289 | |||
290 | // Should do some simple bounds checking | ||
291 | |||
292 | U32 i; | ||
293 | for (i = y_pos; i < y_pos+height; i++) | ||
294 | { | ||
295 | memcpy(data + i*width*getComponents(), | ||
296 | getData() + ((y_pos + i)*getWidth() + x_pos)*getComponents(), getComponents()*width); | ||
297 | } | ||
298 | return data; | ||
299 | } | ||
300 | |||
301 | BOOL LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, | ||
302 | const U8 *data, U32 stride, BOOL reverse_y) | ||
303 | { | ||
304 | if (!getData()) | ||
305 | { | ||
306 | return FALSE; | ||
307 | } | ||
308 | if (!data) | ||
309 | { | ||
310 | return FALSE; | ||
311 | } | ||
312 | |||
313 | // Should do some simple bounds checking | ||
314 | |||
315 | U32 i; | ||
316 | U32 to_offset; | ||
317 | U32 from_offset; | ||
318 | if (!reverse_y) | ||
319 | { | ||
320 | for (i = 0; i < height; i++) | ||
321 | { | ||
322 | to_offset = (y_pos + i)*getWidth() + x_pos; | ||
323 | if (stride != 0) | ||
324 | { | ||
325 | from_offset = i*stride; | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | from_offset = i*width*getComponents(); | ||
330 | } | ||
331 | memcpy(getData() + to_offset*getComponents(), | ||
332 | data + from_offset, getComponents()*width); | ||
333 | } | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | for (i = 0; i < height; i++) | ||
338 | { | ||
339 | to_offset = (y_pos + i)*getWidth() + x_pos; | ||
340 | if (stride != 0) | ||
341 | { | ||
342 | from_offset = (height - 1 - i)*stride; | ||
343 | } | ||
344 | else | ||
345 | { | ||
346 | from_offset = (height - 1 - i)*width*getComponents(); | ||
347 | } | ||
348 | memcpy(getData() + to_offset*getComponents(), | ||
349 | data + from_offset, getComponents()*width); | ||
350 | } | ||
351 | } | ||
352 | return TRUE; | ||
353 | } | ||
354 | |||
355 | void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) | ||
356 | { | ||
357 | llassert( getComponents() <= 4 ); | ||
358 | // This is fairly bogus, but it'll do for now. | ||
359 | U8 *pos = getData(); | ||
360 | U32 x, y; | ||
361 | for (x = 0; x < getWidth(); x++) | ||
362 | { | ||
363 | for (y = 0; y < getHeight(); y++) | ||
364 | { | ||
365 | *pos = r; | ||
366 | pos++; | ||
367 | if (getComponents() == 1) | ||
368 | { | ||
369 | continue; | ||
370 | } | ||
371 | *pos = g; | ||
372 | pos++; | ||
373 | if (getComponents() == 2) | ||
374 | { | ||
375 | continue; | ||
376 | } | ||
377 | *pos = b; | ||
378 | pos++; | ||
379 | if (getComponents() == 3) | ||
380 | { | ||
381 | continue; | ||
382 | } | ||
383 | *pos = a; | ||
384 | pos++; | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | |||
389 | // Reverses the order of the rows in the image | ||
390 | void LLImageRaw::verticalFlip() | ||
391 | { | ||
392 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
393 | S32 row_bytes = getWidth() * getComponents(); | ||
394 | U8* line_buffer = new U8[row_bytes]; | ||
395 | S32 mid_row = getHeight() / 2; | ||
396 | for( S32 row = 0; row < mid_row; row++ ) | ||
397 | { | ||
398 | U8* row_a_data = getData() + row * row_bytes; | ||
399 | U8* row_b_data = getData() + (getHeight() - 1 - row) * row_bytes; | ||
400 | memcpy( line_buffer, row_a_data, row_bytes ); | ||
401 | memcpy( row_a_data, row_b_data, row_bytes ); | ||
402 | memcpy( row_b_data, line_buffer, row_bytes ); | ||
403 | } | ||
404 | delete[] line_buffer; | ||
405 | } | ||
406 | |||
407 | |||
408 | void LLImageRaw::expandToPowerOfTwo(S32 max_dim, BOOL scale_image) | ||
409 | { | ||
410 | // Find new sizes | ||
411 | S32 new_width = MIN_IMAGE_SIZE; | ||
412 | S32 new_height = MIN_IMAGE_SIZE; | ||
413 | |||
414 | while( (new_width < getWidth()) && (new_width < max_dim) ) | ||
415 | { | ||
416 | new_width <<= 1; | ||
417 | } | ||
418 | |||
419 | while( (new_height < getHeight()) && (new_height < max_dim) ) | ||
420 | { | ||
421 | new_height <<= 1; | ||
422 | } | ||
423 | |||
424 | scale( new_width, new_height, scale_image ); | ||
425 | } | ||
426 | |||
427 | void LLImageRaw::contractToPowerOfTwo(S32 max_dim, BOOL scale_image) | ||
428 | { | ||
429 | // Find new sizes | ||
430 | S32 new_width = max_dim; | ||
431 | S32 new_height = max_dim; | ||
432 | |||
433 | while( (new_width > getWidth()) && (new_width > MIN_IMAGE_SIZE) ) | ||
434 | { | ||
435 | new_width >>= 1; | ||
436 | } | ||
437 | |||
438 | while( (new_height > getHeight()) && (new_height > MIN_IMAGE_SIZE) ) | ||
439 | { | ||
440 | new_height >>= 1; | ||
441 | } | ||
442 | |||
443 | scale( new_width, new_height, scale_image ); | ||
444 | } | ||
445 | |||
446 | void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) | ||
447 | { | ||
448 | // Strong bias towards rounding down (to save bandwidth) | ||
449 | // No bias would mean THRESHOLD == 1.5f; | ||
450 | const F32 THRESHOLD = 1.75f; | ||
451 | |||
452 | // Find new sizes | ||
453 | S32 larger_w = max_dim; // 2^n >= mWidth | ||
454 | S32 smaller_w = max_dim; // 2^(n-1) <= mWidth | ||
455 | while( (smaller_w > getWidth()) && (smaller_w > MIN_IMAGE_SIZE) ) | ||
456 | { | ||
457 | larger_w = smaller_w; | ||
458 | smaller_w >>= 1; | ||
459 | } | ||
460 | S32 new_width = ( (F32)getWidth() / smaller_w > THRESHOLD ) ? larger_w : smaller_w; | ||
461 | |||
462 | |||
463 | S32 larger_h = max_dim; // 2^m >= mHeight | ||
464 | S32 smaller_h = max_dim; // 2^(m-1) <= mHeight | ||
465 | while( (smaller_h > getHeight()) && (smaller_h > MIN_IMAGE_SIZE) ) | ||
466 | { | ||
467 | larger_h = smaller_h; | ||
468 | smaller_h >>= 1; | ||
469 | } | ||
470 | S32 new_height = ( (F32)getHeight() / smaller_h > THRESHOLD ) ? larger_h : smaller_h; | ||
471 | |||
472 | |||
473 | scale( new_width, new_height ); | ||
474 | } | ||
475 | |||
476 | |||
477 | |||
478 | |||
479 | // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f). Thanks, Jim Blinn! | ||
480 | inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) | ||
481 | { | ||
482 | U32 i = a * b + 128; | ||
483 | return U8((i + (i>>8)) >> 8); | ||
484 | } | ||
485 | |||
486 | |||
487 | void LLImageRaw::composite( LLImageRaw* src ) | ||
488 | { | ||
489 | LLImageRaw* dst = this; // Just for clarity. | ||
490 | |||
491 | llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); | ||
492 | llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) ); | ||
493 | |||
494 | if( 3 == dst->getComponents() ) | ||
495 | { | ||
496 | if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) | ||
497 | { | ||
498 | // No scaling needed | ||
499 | if( 3 == src->getComponents() ) | ||
500 | { | ||
501 | copyUnscaled( src ); // alpha is one so just copy the data. | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | compositeUnscaled4onto3( src ); | ||
506 | } | ||
507 | } | ||
508 | else | ||
509 | { | ||
510 | if( 3 == src->getComponents() ) | ||
511 | { | ||
512 | copyScaled( src ); // alpha is one so just copy the data. | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | compositeScaled4onto3( src ); | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | else | ||
521 | { | ||
522 | // 4 == dst->mComponents | ||
523 | llassert(0); // not implemented yet. | ||
524 | } | ||
525 | } | ||
526 | |||
527 | // Src and dst can be any size. Src has 4 components. Dst has 3 components. | ||
528 | void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) | ||
529 | { | ||
530 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
531 | llinfos << "compositeScaled4onto3" << llendl; | ||
532 | |||
533 | LLImageRaw* dst = this; // Just for clarity. | ||
534 | |||
535 | llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); | ||
536 | |||
537 | // Vertical: scale but no composite | ||
538 | S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents(); | ||
539 | U8* temp_buffer = new U8[ temp_data_size ]; | ||
540 | for( S32 col = 0; col < src->getWidth(); col++ ) | ||
541 | { | ||
542 | copyLineScaled( src->getData() + (src->getComponents() * col), temp_buffer + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); | ||
543 | } | ||
544 | |||
545 | // Horizontal: scale and composite | ||
546 | for( S32 row = 0; row < dst->getHeight(); row++ ) | ||
547 | { | ||
548 | compositeRowScaled4onto3( temp_buffer + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() ); | ||
549 | } | ||
550 | |||
551 | // Clean up | ||
552 | delete[] temp_buffer; | ||
553 | } | ||
554 | |||
555 | |||
556 | // Src and dst are same size. Src has 4 components. Dst has 3 components. | ||
557 | void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src ) | ||
558 | { | ||
559 | /* | ||
560 | //test fastFractionalMult() | ||
561 | { | ||
562 | U8 i = 255; | ||
563 | U8 j = 255; | ||
564 | do | ||
565 | { | ||
566 | do | ||
567 | { | ||
568 | llassert( fastFractionalMult(i, j) == (U8)(255*(i/255.f)*(j/255.f) + 0.5f) ); | ||
569 | } while( j-- ); | ||
570 | } while( i-- ); | ||
571 | } | ||
572 | */ | ||
573 | |||
574 | LLImageRaw* dst = this; // Just for clarity. | ||
575 | |||
576 | llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); | ||
577 | llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); | ||
578 | |||
579 | |||
580 | U8* src_data = src->getData(); | ||
581 | U8* dst_data = dst->getData(); | ||
582 | S32 pixels = getWidth() * getHeight(); | ||
583 | while( pixels-- ) | ||
584 | { | ||
585 | U8 alpha = src_data[3]; | ||
586 | if( alpha ) | ||
587 | { | ||
588 | if( 255 == alpha ) | ||
589 | { | ||
590 | dst_data[0] = src_data[0]; | ||
591 | dst_data[1] = src_data[1]; | ||
592 | dst_data[2] = src_data[2]; | ||
593 | } | ||
594 | else | ||
595 | { | ||
596 | |||
597 | U8 transparency = 255 - alpha; | ||
598 | dst_data[0] = fastFractionalMult( dst_data[0], transparency ) + fastFractionalMult( src_data[0], alpha ); | ||
599 | dst_data[1] = fastFractionalMult( dst_data[1], transparency ) + fastFractionalMult( src_data[1], alpha ); | ||
600 | dst_data[2] = fastFractionalMult( dst_data[2], transparency ) + fastFractionalMult( src_data[2], alpha ); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | src_data += 4; | ||
605 | dst_data += 3; | ||
606 | } | ||
607 | } | ||
608 | |||
609 | // Fill the buffer with a constant color | ||
610 | void LLImageRaw::fill( const LLColor4U& color ) | ||
611 | { | ||
612 | S32 pixels = getWidth() * getHeight(); | ||
613 | if( 4 == getComponents() ) | ||
614 | { | ||
615 | U32* data = (U32*) getData(); | ||
616 | for( S32 i = 0; i < pixels; i++ ) | ||
617 | { | ||
618 | data[i] = color.mAll; | ||
619 | } | ||
620 | } | ||
621 | else | ||
622 | if( 3 == getComponents() ) | ||
623 | { | ||
624 | U8* data = getData(); | ||
625 | for( S32 i = 0; i < pixels; i++ ) | ||
626 | { | ||
627 | data[0] = color.mV[0]; | ||
628 | data[1] = color.mV[1]; | ||
629 | data[2] = color.mV[2]; | ||
630 | data += 3; | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | |||
635 | |||
636 | |||
637 | |||
638 | // Src and dst can be any size. Src and dst can each have 3 or 4 components. | ||
639 | void LLImageRaw::copy(LLImageRaw* src) | ||
640 | { | ||
641 | LLImageRaw* dst = this; // Just for clarity. | ||
642 | |||
643 | llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); | ||
644 | llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) ); | ||
645 | |||
646 | if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) | ||
647 | { | ||
648 | // No scaling needed | ||
649 | if( src->getComponents() == dst->getComponents() ) | ||
650 | { | ||
651 | copyUnscaled( src ); | ||
652 | } | ||
653 | else | ||
654 | if( 3 == src->getComponents() ) | ||
655 | { | ||
656 | copyUnscaled3onto4( src ); | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | // 4 == src->getComponents() | ||
661 | copyUnscaled4onto3( src ); | ||
662 | } | ||
663 | } | ||
664 | else | ||
665 | { | ||
666 | // Scaling needed | ||
667 | // No scaling needed | ||
668 | if( src->getComponents() == dst->getComponents() ) | ||
669 | { | ||
670 | copyScaled( src ); | ||
671 | } | ||
672 | else | ||
673 | if( 3 == src->getComponents() ) | ||
674 | { | ||
675 | copyScaled3onto4( src ); | ||
676 | } | ||
677 | else | ||
678 | { | ||
679 | // 4 == src->getComponents() | ||
680 | copyScaled4onto3( src ); | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | |||
685 | // Src and dst are same size. Src and dst have same number of components. | ||
686 | void LLImageRaw::copyUnscaled(LLImageRaw* src) | ||
687 | { | ||
688 | LLImageRaw* dst = this; // Just for clarity. | ||
689 | |||
690 | llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); | ||
691 | llassert( src->getComponents() == dst->getComponents() ); | ||
692 | llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); | ||
693 | |||
694 | memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() ); | ||
695 | } | ||
696 | |||
697 | |||
698 | // Src and dst can be any size. Src has 3 components. Dst has 4 components. | ||
699 | void LLImageRaw::copyScaled3onto4(LLImageRaw* src) | ||
700 | { | ||
701 | llassert( (3 == src->getComponents()) && (4 == getComponents()) ); | ||
702 | |||
703 | // Slow, but simple. Optimize later if needed. | ||
704 | LLImageRaw temp( src->getWidth(), src->getHeight(), 4); | ||
705 | temp.copyUnscaled3onto4( src ); | ||
706 | copyScaled( &temp ); | ||
707 | } | ||
708 | |||
709 | |||
710 | // Src and dst can be any size. Src has 4 components. Dst has 3 components. | ||
711 | void LLImageRaw::copyScaled4onto3(LLImageRaw* src) | ||
712 | { | ||
713 | llassert( (4 == src->getComponents()) && (3 == getComponents()) ); | ||
714 | |||
715 | // Slow, but simple. Optimize later if needed. | ||
716 | LLImageRaw temp( src->getWidth(), src->getHeight(), 3); | ||
717 | temp.copyUnscaled4onto3( src ); | ||
718 | copyScaled( &temp ); | ||
719 | } | ||
720 | |||
721 | |||
722 | // Src and dst are same size. Src has 4 components. Dst has 3 components. | ||
723 | void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src ) | ||
724 | { | ||
725 | LLImageRaw* dst = this; // Just for clarity. | ||
726 | |||
727 | llassert( (3 == dst->getComponents()) && (4 == src->getComponents()) ); | ||
728 | llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); | ||
729 | |||
730 | S32 pixels = getWidth() * getHeight(); | ||
731 | U8* src_data = src->getData(); | ||
732 | U8* dst_data = dst->getData(); | ||
733 | for( S32 i=0; i<pixels; i++ ) | ||
734 | { | ||
735 | dst_data[0] = src_data[0]; | ||
736 | dst_data[1] = src_data[1]; | ||
737 | dst_data[2] = src_data[2]; | ||
738 | src_data += 4; | ||
739 | dst_data += 3; | ||
740 | } | ||
741 | } | ||
742 | |||
743 | |||
744 | // Src and dst are same size. Src has 3 components. Dst has 4 components. | ||
745 | void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src ) | ||
746 | { | ||
747 | LLImageRaw* dst = this; // Just for clarity. | ||
748 | llassert( 3 == src->getComponents() ); | ||
749 | llassert( 4 == dst->getComponents() ); | ||
750 | llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); | ||
751 | |||
752 | S32 pixels = getWidth() * getHeight(); | ||
753 | U8* src_data = src->getData(); | ||
754 | U8* dst_data = dst->getData(); | ||
755 | for( S32 i=0; i<pixels; i++ ) | ||
756 | { | ||
757 | dst_data[0] = src_data[0]; | ||
758 | dst_data[1] = src_data[1]; | ||
759 | dst_data[2] = src_data[2]; | ||
760 | dst_data[3] = 255; | ||
761 | src_data += 3; | ||
762 | dst_data += 4; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | |||
767 | // Src and dst can be any size. Src and dst have same number of components. | ||
768 | void LLImageRaw::copyScaled( LLImageRaw* src ) | ||
769 | { | ||
770 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
771 | LLImageRaw* dst = this; // Just for clarity. | ||
772 | |||
773 | llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); | ||
774 | llassert( src->getComponents() == dst->getComponents() ); | ||
775 | |||
776 | if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) | ||
777 | { | ||
778 | memcpy( dst->getData(), src->getData(), getWidth() * getHeight() * getComponents() ); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | // Vertical | ||
783 | S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents(); | ||
784 | U8* temp_buffer = new U8[ temp_data_size ]; | ||
785 | for( S32 col = 0; col < src->getWidth(); col++ ) | ||
786 | { | ||
787 | copyLineScaled( src->getData() + (getComponents() * col), temp_buffer + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); | ||
788 | } | ||
789 | |||
790 | // Horizontal | ||
791 | for( S32 row = 0; row < dst->getHeight(); row++ ) | ||
792 | { | ||
793 | copyLineScaled( temp_buffer + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 ); | ||
794 | } | ||
795 | |||
796 | // Clean up | ||
797 | delete[] temp_buffer; | ||
798 | } | ||
799 | |||
800 | |||
801 | void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) | ||
802 | { | ||
803 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
804 | llassert( (3 == getComponents()) || (4 == getComponents()) ); | ||
805 | |||
806 | S32 old_width = getWidth(); | ||
807 | S32 old_height = getHeight(); | ||
808 | |||
809 | if( (old_width == new_width) && (old_height == new_height) ) | ||
810 | { | ||
811 | return; // Nothing to do. | ||
812 | } | ||
813 | |||
814 | // Reallocate the data buffer. | ||
815 | |||
816 | if (scale_image_data) | ||
817 | { | ||
818 | // Vertical | ||
819 | S32 temp_data_size = old_width * new_height * getComponents(); | ||
820 | U8* temp_buffer = new U8[ temp_data_size ]; | ||
821 | for( S32 col = 0; col < old_width; col++ ) | ||
822 | { | ||
823 | copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width ); | ||
824 | } | ||
825 | |||
826 | deleteData(); | ||
827 | |||
828 | U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); | ||
829 | |||
830 | // Horizontal | ||
831 | for( S32 row = 0; row < new_height; row++ ) | ||
832 | { | ||
833 | copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 ); | ||
834 | } | ||
835 | |||
836 | // Clean up | ||
837 | delete[] temp_buffer; | ||
838 | } | ||
839 | else | ||
840 | { | ||
841 | // copy out existing image data | ||
842 | S32 temp_data_size = old_width * old_height * getComponents(); | ||
843 | U8* temp_buffer = new U8[ temp_data_size ]; | ||
844 | memcpy(temp_buffer, getData(), temp_data_size); | ||
845 | |||
846 | // allocate new image data, will delete old data | ||
847 | U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); | ||
848 | |||
849 | for( S32 row = 0; row < new_height; row++ ) | ||
850 | { | ||
851 | if (row < old_height) | ||
852 | { | ||
853 | memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); | ||
854 | if (old_width < new_width) | ||
855 | { | ||
856 | // pad out rest of row with black | ||
857 | memset(new_buffer + (getComponents() * ((new_width * row) + old_width)), 0, getComponents() * (new_width - old_width)); | ||
858 | } | ||
859 | } | ||
860 | else | ||
861 | { | ||
862 | // pad remaining rows with black | ||
863 | memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents()); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | // Clean up | ||
868 | delete[] temp_buffer; | ||
869 | } | ||
870 | } | ||
871 | |||
872 | void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) | ||
873 | { | ||
874 | const S32 components = getComponents(); | ||
875 | llassert( components >= 1 && components <= 4 ); | ||
876 | |||
877 | const F32 ratio = F32(in_pixel_len) / out_pixel_len; // ratio of old to new | ||
878 | const F32 norm_factor = 1.f / ratio; | ||
879 | |||
880 | S32 goff = components >= 2 ? 1 : 0; | ||
881 | S32 boff = components >= 3 ? 2 : 0; | ||
882 | for( S32 x = 0; x < out_pixel_len; x++ ) | ||
883 | { | ||
884 | // Sample input pixels in range from sample0 to sample1. | ||
885 | // Avoid floating point accumulation error... don't just add ratio each time. JC | ||
886 | const F32 sample0 = x * ratio; | ||
887 | const F32 sample1 = (x+1) * ratio; | ||
888 | const S32 index0 = llfloor(sample0); // left integer (floor) | ||
889 | const S32 index1 = llfloor(sample1); // right integer (floor) | ||
890 | const F32 fract0 = 1.f - (sample0 - F32(index0)); // spill over on left | ||
891 | const F32 fract1 = sample1 - F32(index1); // spill-over on right | ||
892 | |||
893 | if( index0 == index1 ) | ||
894 | { | ||
895 | // Interval is embedded in one input pixel | ||
896 | S32 t0 = x * out_pixel_step * components; | ||
897 | S32 t1 = index0 * in_pixel_step * components; | ||
898 | U8* outp = out + t0; | ||
899 | U8* inp = in + t1; | ||
900 | for (S32 i = 0; i < components; ++i) | ||
901 | { | ||
902 | *outp = *inp; | ||
903 | ++outp; | ||
904 | ++inp; | ||
905 | } | ||
906 | } | ||
907 | else | ||
908 | { | ||
909 | // Left straddle | ||
910 | S32 t1 = index0 * in_pixel_step * components; | ||
911 | F32 r = in[t1 + 0] * fract0; | ||
912 | F32 g = in[t1 + goff] * fract0; | ||
913 | F32 b = in[t1 + boff] * fract0; | ||
914 | F32 a = 0; | ||
915 | if( components == 4) | ||
916 | { | ||
917 | a = in[t1 + 3] * fract0; | ||
918 | } | ||
919 | |||
920 | // Central interval | ||
921 | if (components < 4) | ||
922 | { | ||
923 | for( S32 u = index0 + 1; u < index1; u++ ) | ||
924 | { | ||
925 | S32 t2 = u * in_pixel_step * components; | ||
926 | r += in[t2 + 0]; | ||
927 | g += in[t2 + goff]; | ||
928 | b += in[t2 + boff]; | ||
929 | } | ||
930 | } | ||
931 | else | ||
932 | { | ||
933 | for( S32 u = index0 + 1; u < index1; u++ ) | ||
934 | { | ||
935 | S32 t2 = u * in_pixel_step * components; | ||
936 | r += in[t2 + 0]; | ||
937 | g += in[t2 + 1]; | ||
938 | b += in[t2 + 2]; | ||
939 | a += in[t2 + 3]; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | // right straddle | ||
944 | // Watch out for reading off of end of input array. | ||
945 | if( fract1 && index1 < in_pixel_len ) | ||
946 | { | ||
947 | S32 t3 = index1 * in_pixel_step * components; | ||
948 | if (components < 4) | ||
949 | { | ||
950 | U8 in0 = in[t3 + 0]; | ||
951 | U8 in1 = in[t3 + goff]; | ||
952 | U8 in2 = in[t3 + boff]; | ||
953 | r += in0 * fract1; | ||
954 | g += in1 * fract1; | ||
955 | b += in2 * fract1; | ||
956 | } | ||
957 | else | ||
958 | { | ||
959 | U8 in0 = in[t3 + 0]; | ||
960 | U8 in1 = in[t3 + 1]; | ||
961 | U8 in2 = in[t3 + 2]; | ||
962 | U8 in3 = in[t3 + 3]; | ||
963 | r += in0 * fract1; | ||
964 | g += in1 * fract1; | ||
965 | b += in2 * fract1; | ||
966 | a += in3 * fract1; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | r *= norm_factor; | ||
971 | g *= norm_factor; | ||
972 | b *= norm_factor; | ||
973 | a *= norm_factor; // skip conditional | ||
974 | |||
975 | S32 t4 = x * out_pixel_step * components; | ||
976 | out[t4 + 0] = U8(llround(r)); | ||
977 | if (components >= 2) | ||
978 | out[t4 + 1] = U8(llround(g)); | ||
979 | if (components >= 3) | ||
980 | out[t4 + 2] = U8(llround(b)); | ||
981 | if( components == 4) | ||
982 | out[t4 + 3] = U8(llround(a)); | ||
983 | } | ||
984 | } | ||
985 | } | ||
986 | |||
987 | void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ) | ||
988 | { | ||
989 | llassert( getComponents() == 3 ); | ||
990 | |||
991 | const S32 IN_COMPONENTS = 4; | ||
992 | const S32 OUT_COMPONENTS = 3; | ||
993 | |||
994 | const F32 ratio = F32(in_pixel_len) / out_pixel_len; // ratio of old to new | ||
995 | const F32 norm_factor = 1.f / ratio; | ||
996 | |||
997 | for( S32 x = 0; x < out_pixel_len; x++ ) | ||
998 | { | ||
999 | // Sample input pixels in range from sample0 to sample1. | ||
1000 | // Avoid floating point accumulation error... don't just add ratio each time. JC | ||
1001 | const F32 sample0 = x * ratio; | ||
1002 | const F32 sample1 = (x+1) * ratio; | ||
1003 | const S32 index0 = S32(sample0); // left integer (floor) | ||
1004 | const S32 index1 = S32(sample1); // right integer (floor) | ||
1005 | const F32 fract0 = 1.f - (sample0 - F32(index0)); // spill over on left | ||
1006 | const F32 fract1 = sample1 - F32(index1); // spill-over on right | ||
1007 | |||
1008 | U8 in_scaled_r; | ||
1009 | U8 in_scaled_g; | ||
1010 | U8 in_scaled_b; | ||
1011 | U8 in_scaled_a; | ||
1012 | |||
1013 | if( index0 == index1 ) | ||
1014 | { | ||
1015 | // Interval is embedded in one input pixel | ||
1016 | S32 t1 = index0 * IN_COMPONENTS; | ||
1017 | in_scaled_r = in[t1 + 0]; | ||
1018 | in_scaled_g = in[t1 + 0]; | ||
1019 | in_scaled_b = in[t1 + 0]; | ||
1020 | in_scaled_a = in[t1 + 0]; | ||
1021 | } | ||
1022 | else | ||
1023 | { | ||
1024 | // Left straddle | ||
1025 | S32 t1 = index0 * IN_COMPONENTS; | ||
1026 | F32 r = in[t1 + 0] * fract0; | ||
1027 | F32 g = in[t1 + 1] * fract0; | ||
1028 | F32 b = in[t1 + 2] * fract0; | ||
1029 | F32 a = in[t1 + 3] * fract0; | ||
1030 | |||
1031 | // Central interval | ||
1032 | for( S32 u = index0 + 1; u < index1; u++ ) | ||
1033 | { | ||
1034 | S32 t2 = u * IN_COMPONENTS; | ||
1035 | r += in[t2 + 0]; | ||
1036 | g += in[t2 + 1]; | ||
1037 | b += in[t2 + 2]; | ||
1038 | a += in[t2 + 3]; | ||
1039 | } | ||
1040 | |||
1041 | // right straddle | ||
1042 | // Watch out for reading off of end of input array. | ||
1043 | if( fract1 && index1 < in_pixel_len ) | ||
1044 | { | ||
1045 | S32 t3 = index1 * IN_COMPONENTS; | ||
1046 | r += in[t3 + 0] * fract1; | ||
1047 | g += in[t3 + 1] * fract1; | ||
1048 | b += in[t3 + 2] * fract1; | ||
1049 | a += in[t3 + 3] * fract1; | ||
1050 | } | ||
1051 | |||
1052 | r *= norm_factor; | ||
1053 | g *= norm_factor; | ||
1054 | b *= norm_factor; | ||
1055 | a *= norm_factor; | ||
1056 | |||
1057 | in_scaled_r = U8(llround(r)); | ||
1058 | in_scaled_g = U8(llround(g)); | ||
1059 | in_scaled_b = U8(llround(b)); | ||
1060 | in_scaled_a = U8(llround(a)); | ||
1061 | } | ||
1062 | |||
1063 | if( in_scaled_a ) | ||
1064 | { | ||
1065 | if( 255 == in_scaled_a ) | ||
1066 | { | ||
1067 | out[0] = in_scaled_r; | ||
1068 | out[1] = in_scaled_g; | ||
1069 | out[2] = in_scaled_b; | ||
1070 | } | ||
1071 | else | ||
1072 | { | ||
1073 | U8 transparency = 255 - in_scaled_a; | ||
1074 | out[0] = fastFractionalMult( out[0], transparency ) + fastFractionalMult( in_scaled_r, in_scaled_a ); | ||
1075 | out[1] = fastFractionalMult( out[1], transparency ) + fastFractionalMult( in_scaled_g, in_scaled_a ); | ||
1076 | out[2] = fastFractionalMult( out[2], transparency ) + fastFractionalMult( in_scaled_b, in_scaled_a ); | ||
1077 | } | ||
1078 | } | ||
1079 | out += OUT_COMPONENTS; | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | |||
1084 | //---------------------------------------------------------------------------- | ||
1085 | |||
1086 | static struct | ||
1087 | { | ||
1088 | const char* exten; | ||
1089 | S8 codec; | ||
1090 | } | ||
1091 | file_extensions[] = | ||
1092 | { | ||
1093 | { "bmp", IMG_CODEC_BMP }, | ||
1094 | { "tga", IMG_CODEC_TGA }, | ||
1095 | { "j2c", IMG_CODEC_J2C }, | ||
1096 | { "jp2", IMG_CODEC_J2C }, | ||
1097 | { "texture", IMG_CODEC_J2C }, | ||
1098 | { "jpg", IMG_CODEC_JPEG }, | ||
1099 | { "jpeg", IMG_CODEC_JPEG }, | ||
1100 | { "mip", IMG_CODEC_DXT }, | ||
1101 | { "dxt", IMG_CODEC_DXT } | ||
1102 | }; | ||
1103 | #define NUM_FILE_EXTENSIONS sizeof(file_extensions)/sizeof(file_extensions[0]) | ||
1104 | |||
1105 | static LLString find_file(LLString &name, S8 *codec) | ||
1106 | { | ||
1107 | LLString tname; | ||
1108 | for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) | ||
1109 | { | ||
1110 | tname = name + "." + LLString(file_extensions[i].exten); | ||
1111 | llifstream ifs(tname.c_str(), llifstream::binary); | ||
1112 | if (ifs.is_open()) | ||
1113 | { | ||
1114 | ifs.close(); | ||
1115 | if (codec) | ||
1116 | *codec = file_extensions[i].codec; | ||
1117 | return LLString(file_extensions[i].exten); | ||
1118 | } | ||
1119 | } | ||
1120 | return LLString(""); | ||
1121 | } | ||
1122 | |||
1123 | static S8 get_codec(const LLString& exten) | ||
1124 | { | ||
1125 | for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) | ||
1126 | { | ||
1127 | if (exten == file_extensions[i].exten) | ||
1128 | return file_extensions[i].codec; | ||
1129 | } | ||
1130 | return IMG_CODEC_INVALID; | ||
1131 | } | ||
1132 | |||
1133 | bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_only) | ||
1134 | { | ||
1135 | LLString name = filename; | ||
1136 | size_t dotidx = name.rfind('.'); | ||
1137 | S8 codec = IMG_CODEC_INVALID; | ||
1138 | LLString exten; | ||
1139 | |||
1140 | deleteData(); // delete any existing data | ||
1141 | |||
1142 | if (dotidx != LLString::npos) | ||
1143 | { | ||
1144 | exten = name.substr(dotidx+1); | ||
1145 | LLString::toLower(exten); | ||
1146 | codec = get_codec(exten); | ||
1147 | } | ||
1148 | else | ||
1149 | { | ||
1150 | exten = find_file(name, &codec); | ||
1151 | name = name + "." + exten; | ||
1152 | } | ||
1153 | if (codec == IMG_CODEC_INVALID) | ||
1154 | { | ||
1155 | return false; // format not recognized | ||
1156 | } | ||
1157 | |||
1158 | llifstream ifs(name.c_str(), llifstream::binary); | ||
1159 | if (!ifs.is_open()) | ||
1160 | { | ||
1161 | // SJB: changed from llinfos to lldebugs to reduce spam | ||
1162 | lldebugs << "Unable to open image file: " << name << llendl; | ||
1163 | return false; | ||
1164 | } | ||
1165 | |||
1166 | ifs.seekg (0, std::ios::end); | ||
1167 | int length = ifs.tellg(); | ||
1168 | if (j2c_lowest_mip_only && length > 2048) | ||
1169 | { | ||
1170 | length = 2048; | ||
1171 | } | ||
1172 | ifs.seekg (0, std::ios::beg); | ||
1173 | |||
1174 | if (!length) | ||
1175 | { | ||
1176 | llinfos << "Zero length file file: " << name << llendl; | ||
1177 | return false; | ||
1178 | } | ||
1179 | |||
1180 | LLPointer<LLImageFormatted> image; | ||
1181 | switch(codec) | ||
1182 | { | ||
1183 | //case IMG_CODEC_RGB: | ||
1184 | case IMG_CODEC_BMP: | ||
1185 | image = new LLImageBMP(); | ||
1186 | break; | ||
1187 | case IMG_CODEC_TGA: | ||
1188 | image = new LLImageTGA(); | ||
1189 | break; | ||
1190 | #if JPEG_SUPPORT | ||
1191 | case IMG_CODEC_JPEG: | ||
1192 | image = new LLImageJPEG(); | ||
1193 | break; | ||
1194 | #endif | ||
1195 | case IMG_CODEC_J2C: | ||
1196 | image = new LLImageJ2C(); | ||
1197 | break; | ||
1198 | case IMG_CODEC_DXT: | ||
1199 | image = new LLImageDXT(); | ||
1200 | break; | ||
1201 | default: | ||
1202 | return false; | ||
1203 | } | ||
1204 | llassert(image.notNull()); | ||
1205 | |||
1206 | U8 *buffer = image->allocateData(length); | ||
1207 | ifs.read ((char*)buffer, length); | ||
1208 | ifs.close(); | ||
1209 | |||
1210 | image->updateData(); | ||
1211 | |||
1212 | if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) | ||
1213 | { | ||
1214 | S32 width = image->getWidth(); | ||
1215 | S32 height = image->getHeight(); | ||
1216 | S32 discard_level = 0; | ||
1217 | while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL) | ||
1218 | { | ||
1219 | width >>= 1; | ||
1220 | height >>= 1; | ||
1221 | discard_level++; | ||
1222 | } | ||
1223 | ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); | ||
1224 | } | ||
1225 | |||
1226 | BOOL success = image->decode(this, 100000.0f); | ||
1227 | image = NULL; // deletes image | ||
1228 | |||
1229 | if (!success) | ||
1230 | { | ||
1231 | deleteData(); | ||
1232 | llwarns << "Unable to decode image" << name << llendl; | ||
1233 | return false; | ||
1234 | } | ||
1235 | |||
1236 | return true; | ||
1237 | } | ||
1238 | |||
1239 | //--------------------------------------------------------------------------- | ||
1240 | // LLImageFormatted | ||
1241 | //--------------------------------------------------------------------------- | ||
1242 | |||
1243 | //static | ||
1244 | S32 LLImageFormatted::sGlobalFormattedMemory = 0; | ||
1245 | |||
1246 | //static | ||
1247 | LLWorkerThread* LLImageFormatted::sWorkerThread = NULL; | ||
1248 | |||
1249 | //static | ||
1250 | void LLImageFormatted::initClass(bool threaded, bool run_always) | ||
1251 | { | ||
1252 | sWorkerThread = new LLWorkerThread(threaded, run_always); | ||
1253 | } | ||
1254 | |||
1255 | //static | ||
1256 | void LLImageFormatted::cleanupClass() | ||
1257 | { | ||
1258 | delete sWorkerThread; | ||
1259 | sWorkerThread = NULL; | ||
1260 | } | ||
1261 | |||
1262 | |||
1263 | LLImageFormatted::LLImageFormatted(S8 codec) | ||
1264 | : LLImageBase(), LLWorkerClass(sWorkerThread, "ImageFormatted"), | ||
1265 | mCodec(codec), | ||
1266 | mDecoding(0), | ||
1267 | mDecoded(0), | ||
1268 | mDiscardLevel(0) | ||
1269 | { | ||
1270 | mMemType = LLMemType::MTYPE_IMAGEFORMATTED; | ||
1271 | } | ||
1272 | |||
1273 | // virtual | ||
1274 | LLImageFormatted::~LLImageFormatted() | ||
1275 | { | ||
1276 | // NOTE: ~LLimageBase() call to deleteData() calls LLImageBase::deleteData() | ||
1277 | // NOT LLImageFormatted::deleteData() | ||
1278 | deleteData(); | ||
1279 | releaseDecodedData(); | ||
1280 | } | ||
1281 | |||
1282 | //---------------------------------------------------------------------------- | ||
1283 | |||
1284 | //virtual | ||
1285 | void LLImageFormatted::startWork(S32 param) | ||
1286 | { | ||
1287 | if (mDecoding) llerrs << "WTF?" << llendl; | ||
1288 | } | ||
1289 | |||
1290 | bool LLImageFormatted::doWork(S32 param) | ||
1291 | { | ||
1292 | if (!(isWorking())) llerrs << "WTF?" << llendl; | ||
1293 | llassert(mDecodedImage.notNull()); | ||
1294 | if (param == 0) | ||
1295 | { | ||
1296 | // Decode primary channels | ||
1297 | mDecoded = decode(mDecodedImage, .001f); // 1ms | ||
1298 | } | ||
1299 | else | ||
1300 | { | ||
1301 | // Decode aux channel | ||
1302 | mDecoded = decode(mDecodedImage, .001f, param, param); // 1ms | ||
1303 | } | ||
1304 | if (mDecoded) | ||
1305 | { | ||
1306 | return true; | ||
1307 | } | ||
1308 | else | ||
1309 | { | ||
1310 | return false; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | void LLImageFormatted::endWork(S32 param, bool aborted) | ||
1315 | { | ||
1316 | if (mDecoding) llerrs << "WTF?" << llendl; | ||
1317 | if (!mDecoded) llerrs << "WTF?" << llendl; | ||
1318 | } | ||
1319 | |||
1320 | //---------------------------------------------------------------------------- | ||
1321 | |||
1322 | // static | ||
1323 | LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring) | ||
1324 | { | ||
1325 | LLString exten; | ||
1326 | size_t dotidx = instring.rfind('.'); | ||
1327 | if (dotidx != LLString::npos) | ||
1328 | { | ||
1329 | exten = instring.substr(dotidx+1); | ||
1330 | } | ||
1331 | else | ||
1332 | { | ||
1333 | exten = instring; | ||
1334 | } | ||
1335 | S8 codec = get_codec(exten); | ||
1336 | LLPointer<LLImageFormatted> image; | ||
1337 | switch(codec) | ||
1338 | { | ||
1339 | case IMG_CODEC_BMP: | ||
1340 | image = new LLImageBMP(); | ||
1341 | break; | ||
1342 | case IMG_CODEC_TGA: | ||
1343 | image = new LLImageTGA(); | ||
1344 | break; | ||
1345 | #if JPEG_SUPPORT | ||
1346 | case IMG_CODEC_JPEG: | ||
1347 | image = new LLImageJPEG(); | ||
1348 | break; | ||
1349 | #endif | ||
1350 | case IMG_CODEC_J2C: | ||
1351 | image = new LLImageJ2C(); | ||
1352 | break; | ||
1353 | case IMG_CODEC_DXT: | ||
1354 | image = new LLImageDXT(); | ||
1355 | break; | ||
1356 | default: | ||
1357 | break; | ||
1358 | } | ||
1359 | return image; | ||
1360 | } | ||
1361 | //---------------------------------------------------------------------------- | ||
1362 | |||
1363 | // virtual | ||
1364 | void LLImageFormatted::dump() | ||
1365 | { | ||
1366 | LLImageBase::dump(); | ||
1367 | |||
1368 | llinfos << "LLImageFormatted" | ||
1369 | << " mDecoding " << mDecoding | ||
1370 | << " mCodec " << S32(mCodec) | ||
1371 | << " mDecoded " << mDecoded | ||
1372 | << llendl; | ||
1373 | } | ||
1374 | |||
1375 | //---------------------------------------------------------------------------- | ||
1376 | |||
1377 | void LLImageFormatted::readHeader(U8* data, S32 size) | ||
1378 | { | ||
1379 | if (size <= 0) | ||
1380 | { | ||
1381 | size = calcHeaderSize(); | ||
1382 | } | ||
1383 | copyData(data, size); // calls updateData() | ||
1384 | } | ||
1385 | |||
1386 | S32 LLImageFormatted::calcDataSize(S32 discard_level) | ||
1387 | { | ||
1388 | if (discard_level < 0) | ||
1389 | { | ||
1390 | discard_level = mDiscardLevel; | ||
1391 | } | ||
1392 | S32 w = getWidth() >> discard_level; | ||
1393 | S32 h = getHeight() >> discard_level; | ||
1394 | w = llmax(w, 1); | ||
1395 | h = llmax(h, 1); | ||
1396 | return w * h * getComponents(); | ||
1397 | } | ||
1398 | |||
1399 | S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes) | ||
1400 | { | ||
1401 | llassert(bytes >= 0); | ||
1402 | S32 discard_level = 0; | ||
1403 | while (1) | ||
1404 | { | ||
1405 | S32 bytes_needed = calcDataSize(discard_level); // virtual | ||
1406 | if (bytes_needed <= bytes) | ||
1407 | { | ||
1408 | break; | ||
1409 | } | ||
1410 | discard_level++; | ||
1411 | if (discard_level > MAX_IMAGE_MIP) | ||
1412 | { | ||
1413 | return -1; | ||
1414 | } | ||
1415 | } | ||
1416 | return discard_level; | ||
1417 | } | ||
1418 | |||
1419 | |||
1420 | //---------------------------------------------------------------------------- | ||
1421 | |||
1422 | // Subclasses that can handle more than 4 channels should override this function. | ||
1423 | BOOL LLImageFormatted::decode(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel) | ||
1424 | { | ||
1425 | llassert( (first_channel == 0) && (max_channel == 4) ); | ||
1426 | return decode( raw_image, decode_time ); // Loads first 4 channels by default. | ||
1427 | } | ||
1428 | |||
1429 | // virtual | ||
1430 | BOOL LLImageFormatted::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard, F32 decode_time) | ||
1431 | { | ||
1432 | llassert(getData() && getDataSize()); | ||
1433 | // For most codecs, only mDiscardLevel data is available. (see LLImageDXT for exception) | ||
1434 | if (discard >= 0 && discard != mDiscardLevel) | ||
1435 | { | ||
1436 | llerrs << "Request for invalid discard level" << llendl; | ||
1437 | } | ||
1438 | if (haveWork()) | ||
1439 | { | ||
1440 | checkWork(); | ||
1441 | } | ||
1442 | if (!mDecoded) | ||
1443 | { | ||
1444 | if (!haveWork()) | ||
1445 | { | ||
1446 | llassert(!mDecoding); | ||
1447 | mDecodedImage = new LLImageRaw(getWidth(), getHeight(), getComponents()); | ||
1448 | addWork(0); | ||
1449 | } | ||
1450 | return FALSE; | ||
1451 | } | ||
1452 | else | ||
1453 | { | ||
1454 | llassert(mDecodedImage.notNull()); | ||
1455 | llassert(!mDecoding); | ||
1456 | raw = mDecodedImage; | ||
1457 | return TRUE; | ||
1458 | } | ||
1459 | } | ||
1460 | |||
1461 | BOOL LLImageFormatted::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, | ||
1462 | S32 discard, F32 decode_time) | ||
1463 | { | ||
1464 | llassert(getData() && getDataSize()); | ||
1465 | // For most codecs, only mDiscardLevel data is available. (see LLImageDXT for exception) | ||
1466 | if (discard >= 0 && discard != mDiscardLevel) | ||
1467 | { | ||
1468 | llerrs << "Request for invalid discard level" << llendl; | ||
1469 | } | ||
1470 | if (haveWork()) | ||
1471 | { | ||
1472 | checkWork(); | ||
1473 | } | ||
1474 | if (!mDecoded) | ||
1475 | { | ||
1476 | if (!haveWork()) | ||
1477 | { | ||
1478 | llassert(!mDecoding); | ||
1479 | mDecodedImage = new LLImageRaw(getWidth(), getHeight(), 1); | ||
1480 | addWork(channel); | ||
1481 | } | ||
1482 | return FALSE; | ||
1483 | } | ||
1484 | else | ||
1485 | { | ||
1486 | llassert(mDecodedImage.notNull()); | ||
1487 | llassert(!mDecoding); | ||
1488 | raw = mDecodedImage; | ||
1489 | return TRUE; | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | |||
1494 | // virtual | ||
1495 | void LLImageFormatted::releaseDecodedData() | ||
1496 | { | ||
1497 | if (mDecoded || mDecoding) | ||
1498 | { | ||
1499 | mDecodedImage = NULL; // deletes image | ||
1500 | mDecoded = FALSE; | ||
1501 | mDecoding = FALSE; | ||
1502 | } | ||
1503 | } | ||
1504 | |||
1505 | //---------------------------------------------------------------------------- | ||
1506 | |||
1507 | // virtual | ||
1508 | U8* LLImageFormatted::allocateData(S32 size) | ||
1509 | { | ||
1510 | U8* res = LLImageBase::allocateData(size); // calls deleteData() | ||
1511 | sGlobalFormattedMemory += getDataSize(); | ||
1512 | return res; | ||
1513 | } | ||
1514 | |||
1515 | // virtual | ||
1516 | U8* LLImageFormatted::reallocateData(S32 size) | ||
1517 | { | ||
1518 | sGlobalFormattedMemory -= getDataSize(); | ||
1519 | U8* res = LLImageBase::reallocateData(size); | ||
1520 | sGlobalFormattedMemory += getDataSize(); | ||
1521 | return res; | ||
1522 | } | ||
1523 | |||
1524 | // virtual | ||
1525 | void LLImageFormatted::deleteData() | ||
1526 | { | ||
1527 | sGlobalFormattedMemory -= getDataSize(); | ||
1528 | LLImageBase::deleteData(); | ||
1529 | } | ||
1530 | |||
1531 | //---------------------------------------------------------------------------- | ||
1532 | |||
1533 | // virtual | ||
1534 | void LLImageFormatted::sanityCheck() | ||
1535 | { | ||
1536 | LLImageBase::sanityCheck(); | ||
1537 | |||
1538 | if (mCodec >= IMG_CODEC_EOF) | ||
1539 | { | ||
1540 | llerrs << "Failed LLImageFormatted::sanityCheck " | ||
1541 | << "decoding " << S32(mDecoding) | ||
1542 | << "decoded " << S32(mDecoded) | ||
1543 | << "codec " << S32(mCodec) | ||
1544 | << llendl; | ||
1545 | } | ||
1546 | } | ||
1547 | |||
1548 | //---------------------------------------------------------------------------- | ||
1549 | |||
1550 | BOOL LLImageFormatted::copyData(U8 *data, S32 size) | ||
1551 | { | ||
1552 | if (data && data != getData()) | ||
1553 | { | ||
1554 | deleteData(); | ||
1555 | allocateData(size); | ||
1556 | memcpy(getData(), data, size); | ||
1557 | } | ||
1558 | updateData(); // virtual | ||
1559 | |||
1560 | return TRUE; | ||
1561 | } | ||
1562 | |||
1563 | BOOL LLImageFormatted::appendData(U8 *data, S32 size) | ||
1564 | { | ||
1565 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
1566 | S32 old_size = getDataSize(); | ||
1567 | U8* old_data = getData(); | ||
1568 | S32 new_size = old_size + size; | ||
1569 | U8* new_data = new U8[new_size]; | ||
1570 | // resize the image | ||
1571 | setDataAndSize(new_data, new_size); | ||
1572 | // copy the old data and delete it | ||
1573 | memcpy(new_data, old_data, old_size); | ||
1574 | delete old_data; | ||
1575 | // if we have new data, copy it and call updateData() | ||
1576 | if (data) | ||
1577 | { | ||
1578 | memcpy(new_data + old_size, data, size); | ||
1579 | updateData(); // virtual | ||
1580 | } | ||
1581 | return TRUE; | ||
1582 | } | ||
1583 | |||
1584 | BOOL LLImageFormatted::setData(U8 *data, S32 size) | ||
1585 | { | ||
1586 | if (data && data != getData()) | ||
1587 | { | ||
1588 | deleteData(); | ||
1589 | setDataAndSize(data, size); // Access private LLImageBase members | ||
1590 | sGlobalFormattedMemory += getDataSize(); | ||
1591 | } | ||
1592 | return updateData(); // virtual | ||
1593 | } | ||
1594 | |||
1595 | //---------------------------------------------------------------------------- | ||
1596 | |||
1597 | BOOL LLImageFormatted::load(const LLString &filename) | ||
1598 | { | ||
1599 | resetLastError(); | ||
1600 | |||
1601 | S32 file_size = 0; | ||
1602 | apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size); | ||
1603 | if (!apr_file) | ||
1604 | { | ||
1605 | setLastError("Unable to open file for reading", filename); | ||
1606 | return FALSE; | ||
1607 | } | ||
1608 | if (file_size == 0) | ||
1609 | { | ||
1610 | setLastError("File is empty",filename); | ||
1611 | apr_file_close(apr_file); | ||
1612 | return FALSE; | ||
1613 | } | ||
1614 | |||
1615 | BOOL res; | ||
1616 | U8 *data = allocateData(file_size); | ||
1617 | apr_size_t bytes_read = file_size; | ||
1618 | apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read | ||
1619 | if (s != APR_SUCCESS || (S32) bytes_read != file_size) | ||
1620 | { | ||
1621 | deleteData(); | ||
1622 | setLastError("Unable to read entire file",filename); | ||
1623 | res = FALSE; | ||
1624 | } | ||
1625 | else | ||
1626 | { | ||
1627 | res = updateData(); | ||
1628 | } | ||
1629 | apr_file_close(apr_file); | ||
1630 | |||
1631 | return res; | ||
1632 | } | ||
1633 | |||
1634 | BOOL LLImageFormatted::save(const LLString &filename) | ||
1635 | { | ||
1636 | resetLastError(); | ||
1637 | |||
1638 | apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_WB); | ||
1639 | if (!apr_file) | ||
1640 | { | ||
1641 | setLastError("Unable to open file for reading", filename); | ||
1642 | return FALSE; | ||
1643 | } | ||
1644 | |||
1645 | ll_apr_file_write(apr_file, getData(), getDataSize()); | ||
1646 | apr_file_close(apr_file); | ||
1647 | |||
1648 | return TRUE; | ||
1649 | } | ||
1650 | |||
1651 | // BOOL LLImageFormatted::save(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type) | ||
1652 | // Depricated to remove VFS dependency. | ||
1653 | // Use: | ||
1654 | // LLVFile::writeFile(image->getData(), image->getDataSize(), vfs, uuid, type); | ||
1655 | |||
1656 | //---------------------------------------------------------------------------- | ||
1657 | |||
1658 | S8 LLImageFormatted::getCodec() const | ||
1659 | { | ||
1660 | return mCodec; | ||
1661 | } | ||
1662 | |||
1663 | //============================================================================ | ||
1664 | |||
1665 | //---------------------------------------------------------------------------- | ||
1666 | |||
1667 | static void avg4_colors4(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst) | ||
1668 | { | ||
1669 | dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2); | ||
1670 | dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2); | ||
1671 | dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2); | ||
1672 | dst[3] = (U8)(((U32)(a[3]) + b[3] + c[3] + d[3])>>2); | ||
1673 | } | ||
1674 | |||
1675 | static void avg4_colors3(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst) | ||
1676 | { | ||
1677 | dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2); | ||
1678 | dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2); | ||
1679 | dst[2] = (U8)(((U32)(a[2]) + b[2] + c[2] + d[2])>>2); | ||
1680 | } | ||
1681 | |||
1682 | static void avg4_colors2(const U8* a, const U8* b, const U8* c, const U8* d, U8* dst) | ||
1683 | { | ||
1684 | dst[0] = (U8)(((U32)(a[0]) + b[0] + c[0] + d[0])>>2); | ||
1685 | dst[1] = (U8)(((U32)(a[1]) + b[1] + c[1] + d[1])>>2); | ||
1686 | } | ||
1687 | |||
1688 | //static | ||
1689 | void LLImageBase::generateMip(const U8* indata, U8* mipdata, S32 width, S32 height, S32 nchannels) | ||
1690 | { | ||
1691 | llassert(width > 0 && height > 0); | ||
1692 | U8* data = mipdata; | ||
1693 | S32 in_width = width*2; | ||
1694 | for (S32 h=0; h<height; h++) | ||
1695 | { | ||
1696 | for (S32 w=0; w<width; w++) | ||
1697 | { | ||
1698 | switch(nchannels) | ||
1699 | { | ||
1700 | case 4: | ||
1701 | avg4_colors4(indata, indata+4, indata+4*in_width, indata+4*in_width+4, data); | ||
1702 | break; | ||
1703 | case 3: | ||
1704 | avg4_colors3(indata, indata+3, indata+3*in_width, indata+3*in_width+3, data); | ||
1705 | break; | ||
1706 | case 2: | ||
1707 | avg4_colors2(indata, indata+2, indata+2*in_width, indata+2*in_width+2, data); | ||
1708 | break; | ||
1709 | case 1: | ||
1710 | *(U8*)data = (U8)(((U32)(indata[0]) + indata[1] + indata[in_width] + indata[in_width+1])>>2); | ||
1711 | break; | ||
1712 | default: | ||
1713 | llerrs << "generateMmip called with bad num channels" << llendl; | ||
1714 | } | ||
1715 | indata += nchannels*2; | ||
1716 | data += nchannels; | ||
1717 | } | ||
1718 | indata += nchannels*in_width; // skip odd lines | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | |||
1723 | //============================================================================ | ||
1724 | |||
1725 | //static | ||
1726 | F32 LLImageBase::calc_download_priority(F32 virtual_size, F32 visible_pixels, S32 bytes_sent) | ||
1727 | { | ||
1728 | F32 w_priority; | ||
1729 | |||
1730 | F32 bytes_weight = 1.f; | ||
1731 | if (!bytes_sent) | ||
1732 | { | ||
1733 | bytes_weight = 20.f; | ||
1734 | } | ||
1735 | else if (bytes_sent < 1000) | ||
1736 | { | ||
1737 | bytes_weight = 1.f; | ||
1738 | } | ||
1739 | else if (bytes_sent < 2000) | ||
1740 | { | ||
1741 | bytes_weight = 1.f/1.5f; | ||
1742 | } | ||
1743 | else if (bytes_sent < 4000) | ||
1744 | { | ||
1745 | bytes_weight = 1.f/3.f; | ||
1746 | } | ||
1747 | else if (bytes_sent < 8000) | ||
1748 | { | ||
1749 | bytes_weight = 1.f/6.f; | ||
1750 | } | ||
1751 | else if (bytes_sent < 16000) | ||
1752 | { | ||
1753 | bytes_weight = 1.f/12.f; | ||
1754 | } | ||
1755 | else if (bytes_sent < 32000) | ||
1756 | { | ||
1757 | bytes_weight = 1.f/20.f; | ||
1758 | } | ||
1759 | else if (bytes_sent < 64000) | ||
1760 | { | ||
1761 | bytes_weight = 1.f/32.f; | ||
1762 | } | ||
1763 | else | ||
1764 | { | ||
1765 | bytes_weight = 1.f/64.f; | ||
1766 | } | ||
1767 | bytes_weight *= bytes_weight; | ||
1768 | |||
1769 | |||
1770 | //llinfos << "VS: " << virtual_size << llendl; | ||
1771 | F32 virtual_size_factor = virtual_size / (10.f*10.f); | ||
1772 | |||
1773 | // The goal is for weighted priority to be <= 0 when we've reached a point where | ||
1774 | // we've sent enough data. | ||
1775 | //llinfos << "BytesSent: " << bytes_sent << llendl; | ||
1776 | //llinfos << "BytesWeight: " << bytes_weight << llendl; | ||
1777 | //llinfos << "PreLog: " << bytes_weight * virtual_size_factor << llendl; | ||
1778 | w_priority = (F32)log10(bytes_weight * virtual_size_factor); | ||
1779 | |||
1780 | //llinfos << "PreScale: " << w_priority << llendl; | ||
1781 | |||
1782 | // We don't want to affect how MANY bytes we send based on the visible pixels, but the order | ||
1783 | // in which they're sent. We post-multiply so we don't change the zero point. | ||
1784 | if (w_priority > 0.f) | ||
1785 | { | ||
1786 | F32 pixel_weight = (F32)log10(visible_pixels + 1)*3.0f; | ||
1787 | w_priority *= pixel_weight; | ||
1788 | } | ||
1789 | |||
1790 | return w_priority; | ||
1791 | } | ||
diff --git a/linden/indra/llimage/llimage.h b/linden/indra/llimage/llimage.h new file mode 100644 index 0000000..eb1805a --- /dev/null +++ b/linden/indra/llimage/llimage.h | |||
@@ -0,0 +1,317 @@ | |||
1 | /** | ||
2 | * @file llimage.h | ||
3 | * @brief Object for managing images and their textures. | ||
4 | * | ||
5 | * Copyright (c) 2000-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLIMAGE_H | ||
29 | #define LL_LLIMAGE_H | ||
30 | |||
31 | #include "stdtypes.h" | ||
32 | #include "lluuid.h" | ||
33 | #include "llstring.h" | ||
34 | #include "llmemory.h" | ||
35 | #include "llworkerthread.h" | ||
36 | |||
37 | const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 | ||
38 | const S32 MAX_IMAGE_MIP = 11; // 2048x2048 | ||
39 | const S32 MAX_DISCARD_LEVEL = 5; | ||
40 | |||
41 | const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2 | ||
42 | const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048 | ||
43 | const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE; | ||
44 | const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE; | ||
45 | const S32 MAX_IMAGE_COMPONENTS = 8; | ||
46 | const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; | ||
47 | |||
48 | // Note! These CANNOT be changed without invalidating the viewer VFS files, I think? | ||
49 | const S32 FIRST_PACKET_SIZE = 600; | ||
50 | const S32 MAX_IMG_PACKET_SIZE = 1000; | ||
51 | |||
52 | // Base classes for images. | ||
53 | // There are two major parts for the image: | ||
54 | // The compressed representation, and the decompressed representation. | ||
55 | |||
56 | class LLImageFormatted; | ||
57 | class LLImageRaw; | ||
58 | class LLColor4U; | ||
59 | |||
60 | enum | ||
61 | { | ||
62 | IMG_CODEC_INVALID = 0, | ||
63 | IMG_CODEC_RGB = 1, | ||
64 | IMG_CODEC_J2C = 2, | ||
65 | IMG_CODEC_BMP = 3, | ||
66 | IMG_CODEC_TGA = 4, | ||
67 | IMG_CODEC_JPEG = 5, | ||
68 | IMG_CODEC_DXT = 6, | ||
69 | IMG_CODEC_EOF = 7 | ||
70 | }; | ||
71 | |||
72 | //============================================================================ | ||
73 | |||
74 | class LLImageBase : public LLThreadSafeRefCount | ||
75 | { | ||
76 | protected: | ||
77 | virtual ~LLImageBase(); | ||
78 | |||
79 | public: | ||
80 | LLImageBase(); | ||
81 | |||
82 | enum | ||
83 | { | ||
84 | TYPE_NORMAL = 0, | ||
85 | TYPE_AVATAR_BAKE = 1, | ||
86 | }; | ||
87 | |||
88 | virtual void deleteData(); | ||
89 | virtual U8* allocateData(S32 size = -1); | ||
90 | virtual U8* reallocateData(S32 size = -1); | ||
91 | |||
92 | virtual void dump(); | ||
93 | virtual void sanityCheck(); | ||
94 | |||
95 | U16 getWidth() const { return mWidth; } | ||
96 | U16 getHeight() const { return mHeight; } | ||
97 | S8 getComponents() const { return mComponents; } | ||
98 | S32 getDataSize() const { return mDataSize; } | ||
99 | |||
100 | const U8 *getData() const { return mData; } // read only | ||
101 | U8 *getData() { return mData; } | ||
102 | |||
103 | void setSize(S32 width, S32 height, S32 ncomponents); | ||
104 | U8* allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size = -1); // setSize() + allocateData() | ||
105 | |||
106 | protected: | ||
107 | // special accessor to allow direct setting of mData and mDataSize by LLImageFormatted | ||
108 | void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }; | ||
109 | |||
110 | public: | ||
111 | static const LLString& getLastError() {return sLastErrorMessage;}; | ||
112 | static void resetLastError() {sLastErrorMessage = LLString("No Error"); }; | ||
113 | static BOOL setLastError(const LLString& message, const LLString& filename = ""); // returns FALSE | ||
114 | |||
115 | static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); | ||
116 | |||
117 | // Function for calculating the download priority for textes | ||
118 | // <= 0 priority means that there's no need for more data. | ||
119 | static F32 calc_download_priority(F32 virtual_size, F32 visible_area, S32 bytes_sent); | ||
120 | |||
121 | static void setSizeOverride(BOOL enabled) { sSizeOverride = enabled; } | ||
122 | |||
123 | private: | ||
124 | U8 *mData; | ||
125 | S32 mDataSize; | ||
126 | |||
127 | U16 mWidth; | ||
128 | U16 mHeight; | ||
129 | |||
130 | S8 mComponents; | ||
131 | |||
132 | public: | ||
133 | S16 mMemType; // debug | ||
134 | |||
135 | static LLString sLastErrorMessage; | ||
136 | |||
137 | static BOOL sSizeOverride; | ||
138 | }; | ||
139 | |||
140 | // Raw representation of an image (used for textures, and other uncompressed formats | ||
141 | class LLImageRaw : public LLImageBase | ||
142 | { | ||
143 | protected: | ||
144 | /*virtual*/ ~LLImageRaw(); | ||
145 | |||
146 | public: | ||
147 | LLImageRaw(); | ||
148 | LLImageRaw(U16 width, U16 height, S8 components); | ||
149 | LLImageRaw(U8 *data, U16 width, U16 height, S8 components); | ||
150 | // Construct using createFromFile (used by tools) | ||
151 | LLImageRaw(const LLString& filename, bool j2c_lowest_mip_only = false); | ||
152 | |||
153 | /*virtual*/ void deleteData(); | ||
154 | /*virtual*/ U8* allocateData(S32 size = -1); | ||
155 | /*virtual*/ U8* reallocateData(S32 size); | ||
156 | |||
157 | BOOL copyData(U8 *data, U16 width, U16 height, S8 components); | ||
158 | |||
159 | BOOL resize(U16 width, U16 height, S8 components); | ||
160 | |||
161 | U8 * getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const; | ||
162 | BOOL setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, | ||
163 | const U8 *data, U32 stride = 0, BOOL reverse_y = FALSE); | ||
164 | |||
165 | void clear(U8 r=0, U8 g=0, U8 b=0, U8 a=255); | ||
166 | |||
167 | void verticalFlip(); | ||
168 | |||
169 | void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); | ||
170 | void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); | ||
171 | void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); | ||
172 | void scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); | ||
173 | |||
174 | // Fill the buffer with a constant color | ||
175 | void fill( const LLColor4U& color ); | ||
176 | |||
177 | // Copy operations | ||
178 | |||
179 | // Src and dst can be any size. Src and dst can each have 3 or 4 components. | ||
180 | void copy( LLImageRaw* src ); | ||
181 | |||
182 | // Src and dst are same size. Src and dst have same number of components. | ||
183 | void copyUnscaled( LLImageRaw* src ); | ||
184 | |||
185 | // Src and dst are same size. Src has 4 components. Dst has 3 components. | ||
186 | void copyUnscaled4onto3( LLImageRaw* src ); | ||
187 | |||
188 | // Src and dst are same size. Src has 3 components. Dst has 4 components. | ||
189 | void copyUnscaled3onto4( LLImageRaw* src ); | ||
190 | |||
191 | // Src and dst can be any size. Src and dst have same number of components. | ||
192 | void copyScaled( LLImageRaw* src ); | ||
193 | |||
194 | // Src and dst can be any size. Src has 3 components. Dst has 4 components. | ||
195 | void copyScaled3onto4( LLImageRaw* src ); | ||
196 | |||
197 | // Src and dst can be any size. Src has 4 components. Dst has 3 components. | ||
198 | void copyScaled4onto3( LLImageRaw* src ); | ||
199 | |||
200 | |||
201 | // Composite operations | ||
202 | |||
203 | // Src and dst can be any size. Src and dst can each have 3 or 4 components. | ||
204 | void composite( LLImageRaw* src ); | ||
205 | |||
206 | // Src and dst can be any size. Src has 4 components. Dst has 3 components. | ||
207 | void compositeScaled4onto3( LLImageRaw* src ); | ||
208 | |||
209 | // Src and dst are same size. Src has 4 components. Dst has 3 components. | ||
210 | void compositeUnscaled4onto3( LLImageRaw* src ); | ||
211 | |||
212 | protected: | ||
213 | // Create an image from a local file (generally used in tools) | ||
214 | bool createFromFile(const LLString& filename, bool j2c_lowest_mip_only = false); | ||
215 | |||
216 | void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); | ||
217 | void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); | ||
218 | |||
219 | U8 fastFractionalMult(U8 a,U8 b); | ||
220 | |||
221 | public: | ||
222 | static S32 sGlobalRawMemory; | ||
223 | static S32 sRawImageCount; | ||
224 | }; | ||
225 | |||
226 | // Compressed representation of image. | ||
227 | // Subclass from this class for the different representations (J2C, bmp) | ||
228 | class LLImageFormatted : public LLImageBase, public LLWorkerClass | ||
229 | { | ||
230 | public: | ||
231 | static void initClass(bool threaded = true, bool run_always = true); | ||
232 | static void cleanupClass(); | ||
233 | static LLImageFormatted* createFromExtension(const LLString& instring); | ||
234 | |||
235 | protected: | ||
236 | /*virtual*/ ~LLImageFormatted(); | ||
237 | |||
238 | public: | ||
239 | LLImageFormatted(S8 codec); | ||
240 | |||
241 | // LLImageBase | ||
242 | public: | ||
243 | /*virtual*/ void deleteData(); | ||
244 | /*virtual*/ U8* allocateData(S32 size = -1); | ||
245 | /*virtual*/ U8* reallocateData(S32 size); | ||
246 | |||
247 | /*virtual*/ void dump(); | ||
248 | /*virtual*/ void sanityCheck(); | ||
249 | |||
250 | // LLWorkerThread | ||
251 | public: | ||
252 | // called from WORKER THREAD, returns TRUE if done | ||
253 | /*virtual*/ bool doWork(S32 param); | ||
254 | private: | ||
255 | // called from MAIN THREAD | ||
256 | /*virtual*/ void startWork(S32 param); // called from addWork() | ||
257 | /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() | ||
258 | |||
259 | // New methods | ||
260 | public: | ||
261 | // calcHeaderSize() returns the maximum size of header; | ||
262 | // 0 indicates we don't know have a header and have to lead the entire file | ||
263 | virtual S32 calcHeaderSize() { return 0; }; | ||
264 | // readHeader() reads size bytes into mData, and sets width/height/ncomponents | ||
265 | virtual void readHeader(U8* data, S32 size); | ||
266 | // calcDataSize() returns how many bytes to read to load discard_level (including header) | ||
267 | virtual S32 calcDataSize(S32 discard_level); | ||
268 | // calcDiscardLevelBytes() returns the smallest valid discard level based on the number of input bytes | ||
269 | virtual S32 calcDiscardLevelBytes(S32 bytes); | ||
270 | // getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C) | ||
271 | virtual S8 getRawDiscardLevel() { return mDiscardLevel; } | ||
272 | |||
273 | BOOL load(const LLString& filename); | ||
274 | BOOL save(const LLString& filename); | ||
275 | // BOOL save(LLVFS *vfs, const LLUUID &uuid, const LLAssetType::EType type); | ||
276 | // Depricated to remove VFS dependency (see .cpp for replacement): | ||
277 | |||
278 | virtual BOOL updateData() = 0; // pure virtual | ||
279 | BOOL copyData(U8 *data, S32 size); // calls updateData() | ||
280 | BOOL setData(U8 *data, S32 size); // calls updateData() | ||
281 | BOOL appendData(U8 *data, S32 size); // use if some data (e.g header) is already loaded, calls updateData() | ||
282 | |||
283 | // Loads first 4 channels. | ||
284 | virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0) = 0; | ||
285 | // Subclasses that can handle more than 4 channels should override this function. | ||
286 | virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel); | ||
287 | |||
288 | // Decode methods to return a pointer to raw data for purposes of passing to | ||
289 | // opengl or such. This class tracks the decoded data and keeps it alive until | ||
290 | // destroyed or releaseDecodedData() is called. | ||
291 | virtual BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1, F32 decode_time=0.0); | ||
292 | virtual BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, | ||
293 | S32 discard = -1, F32 decode_time=0.0); | ||
294 | virtual void releaseDecodedData(); | ||
295 | |||
296 | virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0) = 0; | ||
297 | |||
298 | S8 getCodec() const; | ||
299 | BOOL isDecoding() const { return mDecoding ? TRUE : FALSE; } | ||
300 | BOOL isDecoded() const { return mDecoded ? TRUE : FALSE; } | ||
301 | void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; } | ||
302 | S8 getDiscardLevel() const { return mDiscardLevel; } | ||
303 | |||
304 | protected: | ||
305 | S8 mCodec; | ||
306 | S8 mDecoding; | ||
307 | S8 mDecoded; | ||
308 | S8 mDiscardLevel; | ||
309 | |||
310 | LLPointer<LLImageRaw> mDecodedImage; | ||
311 | |||
312 | public: | ||
313 | static S32 sGlobalFormattedMemory; | ||
314 | static LLWorkerThread* sWorkerThread; | ||
315 | }; | ||
316 | |||
317 | #endif | ||
diff --git a/linden/indra/llimage/llimage.vcproj b/linden/indra/llimage/llimage.vcproj new file mode 100644 index 0000000..cd4c735 --- /dev/null +++ b/linden/indra/llimage/llimage.vcproj | |||
@@ -0,0 +1,209 @@ | |||
1 | <?xml version="1.0" encoding="Windows-1252"?> | ||
2 | <VisualStudioProject | ||
3 | ProjectType="Visual C++" | ||
4 | Version="7.10" | ||
5 | Name="llimage" | ||
6 | ProjectGUID="{681FDD6C-2FAE-4CB9-AF6D-B952F2B151C5}" | ||
7 | Keyword="Win32Proj"> | ||
8 | <Platforms> | ||
9 | <Platform | ||
10 | Name="Win32"/> | ||
11 | </Platforms> | ||
12 | <Configurations> | ||
13 | <Configuration | ||
14 | Name="Debug|Win32" | ||
15 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
16 | IntermediateDirectory="$(ConfigurationName)" | ||
17 | ConfigurationType="4" | ||
18 | CharacterSet="1"> | ||
19 | <Tool | ||
20 | Name="VCCLCompilerTool" | ||
21 | Optimization="0" | ||
22 | AdditionalIncludeDirectories="..\llcommon;..\llmath; ..\llvfs; ..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
23 | PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG" | ||
24 | MinimalRebuild="TRUE" | ||
25 | BasicRuntimeChecks="3" | ||
26 | RuntimeLibrary="1" | ||
27 | StructMemberAlignment="4" | ||
28 | ForceConformanceInForLoopScope="TRUE" | ||
29 | UsePrecompiledHeader="0" | ||
30 | WarningLevel="3" | ||
31 | WarnAsError="TRUE" | ||
32 | Detect64BitPortabilityProblems="FALSE" | ||
33 | DebugInformationFormat="4"/> | ||
34 | <Tool | ||
35 | Name="VCCustomBuildTool"/> | ||
36 | <Tool | ||
37 | Name="VCLibrarianTool" | ||
38 | OutputFile="$(OutDir)/llimage.lib"/> | ||
39 | <Tool | ||
40 | Name="VCMIDLTool"/> | ||
41 | <Tool | ||
42 | Name="VCPostBuildEventTool"/> | ||
43 | <Tool | ||
44 | Name="VCPreBuildEventTool"/> | ||
45 | <Tool | ||
46 | Name="VCPreLinkEventTool"/> | ||
47 | <Tool | ||
48 | Name="VCResourceCompilerTool"/> | ||
49 | <Tool | ||
50 | Name="VCWebServiceProxyGeneratorTool"/> | ||
51 | <Tool | ||
52 | Name="VCXMLDataGeneratorTool"/> | ||
53 | <Tool | ||
54 | Name="VCManagedWrapperGeneratorTool"/> | ||
55 | <Tool | ||
56 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
57 | </Configuration> | ||
58 | <Configuration | ||
59 | Name="Release|Win32" | ||
60 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
61 | IntermediateDirectory="$(ConfigurationName)" | ||
62 | ConfigurationType="4" | ||
63 | CharacterSet="1"> | ||
64 | <Tool | ||
65 | Name="VCCLCompilerTool" | ||
66 | GlobalOptimizations="TRUE" | ||
67 | InlineFunctionExpansion="2" | ||
68 | EnableIntrinsicFunctions="TRUE" | ||
69 | OptimizeForProcessor="3" | ||
70 | OptimizeForWindowsApplication="TRUE" | ||
71 | AdditionalIncludeDirectories="..\llcommon;..\llmath; ..\llvfs; ..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
72 | PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE" | ||
73 | RuntimeLibrary="0" | ||
74 | StructMemberAlignment="0" | ||
75 | ForceConformanceInForLoopScope="TRUE" | ||
76 | UsePrecompiledHeader="0" | ||
77 | WarningLevel="3" | ||
78 | WarnAsError="FALSE" | ||
79 | Detect64BitPortabilityProblems="FALSE" | ||
80 | DebugInformationFormat="3"/> | ||
81 | <Tool | ||
82 | Name="VCCustomBuildTool"/> | ||
83 | <Tool | ||
84 | Name="VCLibrarianTool" | ||
85 | OutputFile="$(OutDir)/llimage.lib"/> | ||
86 | <Tool | ||
87 | Name="VCMIDLTool"/> | ||
88 | <Tool | ||
89 | Name="VCPostBuildEventTool"/> | ||
90 | <Tool | ||
91 | Name="VCPreBuildEventTool"/> | ||
92 | <Tool | ||
93 | Name="VCPreLinkEventTool"/> | ||
94 | <Tool | ||
95 | Name="VCResourceCompilerTool"/> | ||
96 | <Tool | ||
97 | Name="VCWebServiceProxyGeneratorTool"/> | ||
98 | <Tool | ||
99 | Name="VCXMLDataGeneratorTool"/> | ||
100 | <Tool | ||
101 | Name="VCManagedWrapperGeneratorTool"/> | ||
102 | <Tool | ||
103 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
104 | </Configuration> | ||
105 | <Configuration | ||
106 | Name="ReleaseNoOpt|Win32" | ||
107 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
108 | IntermediateDirectory="$(ConfigurationName)" | ||
109 | ConfigurationType="4" | ||
110 | CharacterSet="1"> | ||
111 | <Tool | ||
112 | Name="VCCLCompilerTool" | ||
113 | Optimization="0" | ||
114 | AdditionalIncludeDirectories="..\llcommon;..\llmath; ..\llvfs; ..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
115 | PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE" | ||
116 | RuntimeLibrary="0" | ||
117 | StructMemberAlignment="0" | ||
118 | ForceConformanceInForLoopScope="TRUE" | ||
119 | UsePrecompiledHeader="0" | ||
120 | WarningLevel="3" | ||
121 | WarnAsError="TRUE" | ||
122 | Detect64BitPortabilityProblems="FALSE" | ||
123 | DebugInformationFormat="3"/> | ||
124 | <Tool | ||
125 | Name="VCCustomBuildTool"/> | ||
126 | <Tool | ||
127 | Name="VCLibrarianTool" | ||
128 | OutputFile="$(OutDir)/llimage.lib"/> | ||
129 | <Tool | ||
130 | Name="VCMIDLTool"/> | ||
131 | <Tool | ||
132 | Name="VCPostBuildEventTool"/> | ||
133 | <Tool | ||
134 | Name="VCPreBuildEventTool"/> | ||
135 | <Tool | ||
136 | Name="VCPreLinkEventTool"/> | ||
137 | <Tool | ||
138 | Name="VCResourceCompilerTool"/> | ||
139 | <Tool | ||
140 | Name="VCWebServiceProxyGeneratorTool"/> | ||
141 | <Tool | ||
142 | Name="VCXMLDataGeneratorTool"/> | ||
143 | <Tool | ||
144 | Name="VCManagedWrapperGeneratorTool"/> | ||
145 | <Tool | ||
146 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
147 | </Configuration> | ||
148 | </Configurations> | ||
149 | <References> | ||
150 | </References> | ||
151 | <Files> | ||
152 | <Filter | ||
153 | Name="Source Files" | ||
154 | Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||
155 | UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> | ||
156 | <File | ||
157 | RelativePath=".\llimage.cpp"> | ||
158 | </File> | ||
159 | <File | ||
160 | RelativePath=".\llimagebmp.cpp"> | ||
161 | </File> | ||
162 | <File | ||
163 | RelativePath=".\llimagedxt.cpp"> | ||
164 | </File> | ||
165 | <File | ||
166 | RelativePath=".\llimagej2c.cpp"> | ||
167 | </File> | ||
168 | <File | ||
169 | RelativePath=".\llimagejpeg.cpp"> | ||
170 | </File> | ||
171 | <File | ||
172 | RelativePath=".\llimagetga.cpp"> | ||
173 | </File> | ||
174 | </Filter> | ||
175 | <Filter | ||
176 | Name="Header Files" | ||
177 | Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||
178 | UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> | ||
179 | <File | ||
180 | RelativePath=".\llimage.h"> | ||
181 | </File> | ||
182 | <File | ||
183 | RelativePath=".\llimagebmp.h"> | ||
184 | </File> | ||
185 | <File | ||
186 | RelativePath=".\llimageconstants.h"> | ||
187 | </File> | ||
188 | <File | ||
189 | RelativePath=".\llimagedxt.h"> | ||
190 | </File> | ||
191 | <File | ||
192 | RelativePath=".\llimagej2c.h"> | ||
193 | </File> | ||
194 | <File | ||
195 | RelativePath=".\llimagejpeg.h"> | ||
196 | </File> | ||
197 | <File | ||
198 | RelativePath=".\llimagetga.h"> | ||
199 | </File> | ||
200 | </Filter> | ||
201 | <Filter | ||
202 | Name="Resource Files" | ||
203 | Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" | ||
204 | UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> | ||
205 | </Filter> | ||
206 | </Files> | ||
207 | <Globals> | ||
208 | </Globals> | ||
209 | </VisualStudioProject> | ||
diff --git a/linden/indra/llimage/llimagebmp.cpp b/linden/indra/llimage/llimagebmp.cpp new file mode 100644 index 0000000..fc9532e --- /dev/null +++ b/linden/indra/llimage/llimagebmp.cpp | |||
@@ -0,0 +1,643 @@ | |||
1 | /** | ||
2 | * @file llimagebmp.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 "llimagebmp.h" | ||
30 | #include "llerror.h" | ||
31 | |||
32 | #include "llendianswizzle.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * @struct LLBMPHeader | ||
37 | * | ||
38 | * This struct helps deal with bmp files. | ||
39 | */ | ||
40 | struct LLBMPHeader | ||
41 | { | ||
42 | S32 mSize; | ||
43 | S32 mWidth; | ||
44 | S32 mHeight; | ||
45 | S16 mPlanes; | ||
46 | S16 mBitsPerPixel; | ||
47 | S16 mCompression; | ||
48 | S16 mAlignmentPadding; // pads out to next word boundary | ||
49 | S32 mImageSize; | ||
50 | S32 mHorzPelsPerMeter; | ||
51 | S32 mVertPelsPerMeter; | ||
52 | S32 mNumColors; | ||
53 | S32 mNumColorsImportant; | ||
54 | }; | ||
55 | |||
56 | /** | ||
57 | * @struct Win95BmpHeaderExtension | ||
58 | */ | ||
59 | struct Win95BmpHeaderExtension | ||
60 | { | ||
61 | U32 mReadMask; | ||
62 | U32 mGreenMask; | ||
63 | U32 mBlueMask; | ||
64 | U32 mAlphaMask; | ||
65 | U32 mColorSpaceType; | ||
66 | U16 mRed[3]; // Red CIE endpoint | ||
67 | U16 mGreen[3]; // Green CIE endpoint | ||
68 | U16 mBlue[3]; // Blue CIE endpoint | ||
69 | U32 mGamma[3]; // Gamma scale for r g and b | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * LLImageBMP | ||
74 | */ | ||
75 | LLImageBMP::LLImageBMP() | ||
76 | : | ||
77 | LLImageFormatted(IMG_CODEC_BMP), | ||
78 | mColorPaletteColors( 0 ), | ||
79 | mColorPalette( NULL ), | ||
80 | mBitmapOffset( 0 ), | ||
81 | mBitsPerPixel( 0 ), | ||
82 | mOriginAtTop( FALSE ) | ||
83 | { | ||
84 | mBitfieldMask[0] = 0; | ||
85 | mBitfieldMask[1] = 0; | ||
86 | mBitfieldMask[2] = 0; | ||
87 | mBitfieldMask[3] = 0; | ||
88 | } | ||
89 | |||
90 | LLImageBMP::~LLImageBMP() | ||
91 | { | ||
92 | delete[] mColorPalette; | ||
93 | } | ||
94 | |||
95 | |||
96 | BOOL LLImageBMP::updateData() | ||
97 | { | ||
98 | resetLastError(); | ||
99 | |||
100 | // Check to make sure that this instance has been initialized with data | ||
101 | U8* mdata = getData(); | ||
102 | if (!mdata || (0 == getDataSize())) | ||
103 | { | ||
104 | setLastError("Uninitialized instance of LLImageBMP"); | ||
105 | return FALSE; | ||
106 | } | ||
107 | |||
108 | // Read the bitmap headers in order to get all the useful info | ||
109 | // about this image | ||
110 | |||
111 | //////////////////////////////////////////////////////////////////// | ||
112 | // Part 1: "File Header" | ||
113 | // 14 bytes consisting of | ||
114 | // 2 bytes: either BM or BA | ||
115 | // 4 bytes: file size in bytes | ||
116 | // 4 bytes: reserved (always 0) | ||
117 | // 4 bytes: bitmap offset (starting position of image data in bytes) | ||
118 | const S32 FILE_HEADER_SIZE = 14; | ||
119 | if ((mdata[0] != 'B') || (mdata[1] != 'M')) | ||
120 | { | ||
121 | if ((mdata[0] != 'B') || (mdata[1] != 'A')) | ||
122 | { | ||
123 | setLastError("OS/2 bitmap array BMP files are not supported"); | ||
124 | return FALSE; | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | setLastError("Does not appear to be a bitmap file"); | ||
129 | return FALSE; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | mBitmapOffset = mdata[13]; | ||
134 | mBitmapOffset <<= 8; mBitmapOffset += mdata[12]; | ||
135 | mBitmapOffset <<= 8; mBitmapOffset += mdata[11]; | ||
136 | mBitmapOffset <<= 8; mBitmapOffset += mdata[10]; | ||
137 | |||
138 | |||
139 | //////////////////////////////////////////////////////////////////// | ||
140 | // Part 2: "Bitmap Header" | ||
141 | const S32 BITMAP_HEADER_SIZE = 40; | ||
142 | LLBMPHeader header; | ||
143 | llassert( sizeof( header ) == BITMAP_HEADER_SIZE ); | ||
144 | |||
145 | memcpy((void *)&header, mdata + FILE_HEADER_SIZE, BITMAP_HEADER_SIZE); | ||
146 | |||
147 | // convert BMP header from little endian (no-op on little endian builds) | ||
148 | llendianswizzleone(header.mSize); | ||
149 | llendianswizzleone(header.mWidth); | ||
150 | llendianswizzleone(header.mHeight); | ||
151 | llendianswizzleone(header.mPlanes); | ||
152 | llendianswizzleone(header.mBitsPerPixel); | ||
153 | llendianswizzleone(header.mCompression); | ||
154 | llendianswizzleone(header.mAlignmentPadding); | ||
155 | llendianswizzleone(header.mImageSize); | ||
156 | llendianswizzleone(header.mHorzPelsPerMeter); | ||
157 | llendianswizzleone(header.mVertPelsPerMeter); | ||
158 | llendianswizzleone(header.mNumColors); | ||
159 | llendianswizzleone(header.mNumColorsImportant); | ||
160 | |||
161 | BOOL windows_nt_version = FALSE; | ||
162 | BOOL windows_95_version = FALSE; | ||
163 | if( 12 == header.mSize ) | ||
164 | { | ||
165 | setLastError("Windows 2.x and OS/2 1.x BMP files are not supported"); | ||
166 | return FALSE; | ||
167 | } | ||
168 | else | ||
169 | if( 40 == header.mSize ) | ||
170 | { | ||
171 | if( 3 == header.mCompression ) | ||
172 | { | ||
173 | // Windows NT | ||
174 | windows_nt_version = TRUE; | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | // Windows 3.x | ||
179 | } | ||
180 | } | ||
181 | else | ||
182 | if( 12 <= header.mSize && 64 <= header.mSize ) | ||
183 | { | ||
184 | setLastError("OS/2 2.x BMP files are not supported"); | ||
185 | return FALSE; | ||
186 | } | ||
187 | else | ||
188 | if( 108 == header.mSize ) | ||
189 | { | ||
190 | // BITMAPV4HEADER | ||
191 | windows_95_version = TRUE; | ||
192 | } | ||
193 | else | ||
194 | if( 108 < header.mSize ) | ||
195 | { | ||
196 | // BITMAPV5HEADER or greater | ||
197 | // Should work as long at Microsoft maintained backwards compatibility (which they did in V4 and V5) | ||
198 | windows_95_version = TRUE; | ||
199 | } | ||
200 | |||
201 | S32 width = header.mWidth; | ||
202 | S32 height = header.mHeight; | ||
203 | if (height < 0) | ||
204 | { | ||
205 | mOriginAtTop = TRUE; | ||
206 | height = -height; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | mOriginAtTop = FALSE; | ||
211 | } | ||
212 | |||
213 | mBitsPerPixel = header.mBitsPerPixel; | ||
214 | S32 components; | ||
215 | switch( mBitsPerPixel ) | ||
216 | { | ||
217 | case 8: | ||
218 | components = 1; | ||
219 | break; | ||
220 | case 24: | ||
221 | case 32: | ||
222 | components = 3; | ||
223 | break; | ||
224 | case 1: | ||
225 | case 4: | ||
226 | case 16: // Started work on 16, but doesn't work yet | ||
227 | // These are legal, but we don't support them yet. | ||
228 | setLastError("Unsupported bit depth"); | ||
229 | return FALSE; | ||
230 | default: | ||
231 | setLastError("Unrecognized bit depth"); | ||
232 | return FALSE; | ||
233 | } | ||
234 | |||
235 | setSize(width, height, components); | ||
236 | |||
237 | switch( header.mCompression ) | ||
238 | { | ||
239 | case 0: | ||
240 | // Uncompressed | ||
241 | break; | ||
242 | |||
243 | case 1: | ||
244 | setLastError("8 bit RLE compression not supported."); | ||
245 | return FALSE; | ||
246 | |||
247 | case 2: | ||
248 | setLastError("4 bit RLE compression not supported."); | ||
249 | return FALSE; | ||
250 | |||
251 | case 3: | ||
252 | // Windows NT or Windows 95 | ||
253 | break; | ||
254 | |||
255 | default: | ||
256 | setLastError("Unsupported compression format."); | ||
257 | return FALSE; | ||
258 | } | ||
259 | |||
260 | //////////////////////////////////////////////////////////////////// | ||
261 | // Part 3: Bitfield Masks and other color data | ||
262 | S32 extension_size = 0; | ||
263 | if( windows_nt_version ) | ||
264 | { | ||
265 | if( (16 != header.mBitsPerPixel) && (32 != header.mBitsPerPixel) ) | ||
266 | { | ||
267 | setLastError("Bitfield encoding requires 16 or 32 bits per pixel."); | ||
268 | return FALSE; | ||
269 | } | ||
270 | |||
271 | if( 0 != header.mNumColors ) | ||
272 | { | ||
273 | setLastError("Bitfield encoding is not compatible with a color table."); | ||
274 | return FALSE; | ||
275 | } | ||
276 | |||
277 | |||
278 | extension_size = 4 * 3; | ||
279 | memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, extension_size); | ||
280 | } | ||
281 | else | ||
282 | if( windows_95_version ) | ||
283 | { | ||
284 | Win95BmpHeaderExtension win_95_extension; | ||
285 | extension_size = sizeof( win_95_extension ); | ||
286 | |||
287 | llassert( sizeof( win_95_extension ) + BITMAP_HEADER_SIZE == 108 ); | ||
288 | memcpy( &win_95_extension, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, sizeof( win_95_extension ) ); | ||
289 | |||
290 | if( 3 == header.mCompression ) | ||
291 | { | ||
292 | memcpy( mBitfieldMask, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE, 4 * 4); | ||
293 | } | ||
294 | |||
295 | // Color correction ignored for now | ||
296 | } | ||
297 | |||
298 | |||
299 | //////////////////////////////////////////////////////////////////// | ||
300 | // Part 4: Color Palette (optional) | ||
301 | // Note: There's no color palette if there are 16 or more bits per pixel | ||
302 | S32 color_palette_size = 0; | ||
303 | mColorPaletteColors = 0; | ||
304 | if( header.mBitsPerPixel < 16 ) | ||
305 | { | ||
306 | if( 0 == header.mNumColors ) | ||
307 | { | ||
308 | mColorPaletteColors = (1 << header.mBitsPerPixel); | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | mColorPaletteColors = header.mNumColors; | ||
313 | } | ||
314 | } | ||
315 | color_palette_size = mColorPaletteColors * 4; | ||
316 | |||
317 | if( 0 != mColorPaletteColors ) | ||
318 | { | ||
319 | mColorPalette = new U8[color_palette_size]; | ||
320 | memcpy( mColorPalette, mdata + FILE_HEADER_SIZE + BITMAP_HEADER_SIZE + extension_size, color_palette_size ); | ||
321 | } | ||
322 | |||
323 | return TRUE; | ||
324 | } | ||
325 | |||
326 | BOOL LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) | ||
327 | { | ||
328 | llassert_always(raw_image); | ||
329 | |||
330 | resetLastError(); | ||
331 | |||
332 | // Check to make sure that this instance has been initialized with data | ||
333 | U8* mdata = getData(); | ||
334 | if (!mdata || (0 == getDataSize())) | ||
335 | { | ||
336 | setLastError("llimagebmp trying to decode an image with no data!"); | ||
337 | return FALSE; | ||
338 | } | ||
339 | |||
340 | raw_image->resize(getWidth(), getHeight(), 3); | ||
341 | |||
342 | U8* src = mdata + mBitmapOffset; | ||
343 | U8* dst = raw_image->getData(); | ||
344 | |||
345 | BOOL success = FALSE; | ||
346 | |||
347 | switch( mBitsPerPixel ) | ||
348 | { | ||
349 | case 8: | ||
350 | if( mColorPaletteColors >= 256 ) | ||
351 | { | ||
352 | success = decodeColorTable8( dst, src ); | ||
353 | } | ||
354 | break; | ||
355 | |||
356 | case 16: | ||
357 | success = decodeColorMask16( dst, src ); | ||
358 | break; | ||
359 | |||
360 | case 24: | ||
361 | success = decodeTruecolor24( dst, src ); | ||
362 | break; | ||
363 | |||
364 | case 32: | ||
365 | success = decodeColorMask32( dst, src ); | ||
366 | break; | ||
367 | } | ||
368 | |||
369 | if( success && mOriginAtTop ) | ||
370 | { | ||
371 | raw_image->verticalFlip(); | ||
372 | } | ||
373 | |||
374 | return success; | ||
375 | } | ||
376 | |||
377 | U32 LLImageBMP::countTrailingZeros( U32 m ) | ||
378 | { | ||
379 | U32 shift_count = 0; | ||
380 | while( !(m & 1) ) | ||
381 | { | ||
382 | shift_count++; | ||
383 | m >>= 1; | ||
384 | } | ||
385 | return shift_count; | ||
386 | } | ||
387 | |||
388 | |||
389 | BOOL LLImageBMP::decodeColorMask16( U8* dst, U8* src ) | ||
390 | { | ||
391 | llassert( 16 == mBitsPerPixel ); | ||
392 | |||
393 | if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) | ||
394 | { | ||
395 | // Use default values | ||
396 | mBitfieldMask[0] = 0x00007C00; | ||
397 | mBitfieldMask[1] = 0x000003E0; | ||
398 | mBitfieldMask[2] = 0x0000001F; | ||
399 | } | ||
400 | |||
401 | S32 src_row_span = getWidth() * 2; | ||
402 | S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 | ||
403 | |||
404 | U32 r_shift = countTrailingZeros( mBitfieldMask[2] ); | ||
405 | U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); | ||
406 | U32 b_shift = countTrailingZeros( mBitfieldMask[0] ); | ||
407 | |||
408 | for( S32 row = 0; row < getHeight(); row++ ) | ||
409 | { | ||
410 | for( S32 col = 0; col < getWidth(); col++ ) | ||
411 | { | ||
412 | U32 value = *((U16*)src); | ||
413 | dst[0] = U8((value & mBitfieldMask[2]) >> r_shift); // Red | ||
414 | dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green | ||
415 | dst[2] = U8((value & mBitfieldMask[0]) >> b_shift); // Blue | ||
416 | src += 2; | ||
417 | dst += 3; | ||
418 | } | ||
419 | src += alignment_bytes; | ||
420 | } | ||
421 | |||
422 | return TRUE; | ||
423 | } | ||
424 | |||
425 | BOOL LLImageBMP::decodeColorMask32( U8* dst, U8* src ) | ||
426 | { | ||
427 | // Note: alpha is not supported | ||
428 | |||
429 | llassert( 32 == mBitsPerPixel ); | ||
430 | |||
431 | if( !mBitfieldMask[0] && !mBitfieldMask[1] && !mBitfieldMask[2] ) | ||
432 | { | ||
433 | // Use default values | ||
434 | mBitfieldMask[0] = 0x00FF0000; | ||
435 | mBitfieldMask[1] = 0x0000FF00; | ||
436 | mBitfieldMask[2] = 0x000000FF; | ||
437 | } | ||
438 | |||
439 | |||
440 | S32 src_row_span = getWidth() * 4; | ||
441 | S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 | ||
442 | |||
443 | U32 r_shift = countTrailingZeros( mBitfieldMask[0] ); | ||
444 | U32 g_shift = countTrailingZeros( mBitfieldMask[1] ); | ||
445 | U32 b_shift = countTrailingZeros( mBitfieldMask[2] ); | ||
446 | |||
447 | for( S32 row = 0; row < getHeight(); row++ ) | ||
448 | { | ||
449 | for( S32 col = 0; col < getWidth(); col++ ) | ||
450 | { | ||
451 | U32 value = *((U32*)src); | ||
452 | dst[0] = U8((value & mBitfieldMask[0]) >> r_shift); // Red | ||
453 | dst[1] = U8((value & mBitfieldMask[1]) >> g_shift); // Green | ||
454 | dst[2] = U8((value & mBitfieldMask[2]) >> b_shift); // Blue | ||
455 | src += 4; | ||
456 | dst += 3; | ||
457 | } | ||
458 | src += alignment_bytes; | ||
459 | } | ||
460 | |||
461 | return TRUE; | ||
462 | } | ||
463 | |||
464 | |||
465 | BOOL LLImageBMP::decodeColorTable8( U8* dst, U8* src ) | ||
466 | { | ||
467 | llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) ); | ||
468 | |||
469 | S32 src_row_span = getWidth() * 1; | ||
470 | S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 | ||
471 | |||
472 | for( S32 row = 0; row < getHeight(); row++ ) | ||
473 | { | ||
474 | for( S32 col = 0; col < getWidth(); col++ ) | ||
475 | { | ||
476 | S32 index = 4 * src[0]; | ||
477 | dst[0] = mColorPalette[index + 2]; // Red | ||
478 | dst[1] = mColorPalette[index + 1]; // Green | ||
479 | dst[2] = mColorPalette[index + 0]; // Blue | ||
480 | src++; | ||
481 | dst += 3; | ||
482 | } | ||
483 | src += alignment_bytes; | ||
484 | } | ||
485 | |||
486 | return TRUE; | ||
487 | } | ||
488 | |||
489 | |||
490 | BOOL LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) | ||
491 | { | ||
492 | llassert( 24 == mBitsPerPixel ); | ||
493 | llassert( 3 == getComponents() ); | ||
494 | S32 src_row_span = getWidth() * 3; | ||
495 | S32 alignment_bytes = (3 * src_row_span) % 4; // round up to nearest multiple of 4 | ||
496 | |||
497 | for( S32 row = 0; row < getHeight(); row++ ) | ||
498 | { | ||
499 | for( S32 col = 0; col < getWidth(); col++ ) | ||
500 | { | ||
501 | dst[0] = src[2]; // Red | ||
502 | dst[1] = src[1]; // Green | ||
503 | dst[2] = src[0]; // Blue | ||
504 | src += 3; | ||
505 | dst += 3; | ||
506 | } | ||
507 | src += alignment_bytes; | ||
508 | } | ||
509 | |||
510 | return TRUE; | ||
511 | } | ||
512 | |||
513 | BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) | ||
514 | { | ||
515 | llassert_always(raw_image); | ||
516 | |||
517 | resetLastError(); | ||
518 | |||
519 | S32 src_components = raw_image->getComponents(); | ||
520 | S32 dst_components = ( src_components < 3 ) ? 1 : 3; | ||
521 | |||
522 | if( (2 == src_components) || (4 == src_components) ) | ||
523 | { | ||
524 | llinfos << "Dropping alpha information during BMP encoding" << llendl; | ||
525 | } | ||
526 | |||
527 | setSize(raw_image->getWidth(), raw_image->getHeight(), dst_components); | ||
528 | |||
529 | U8 magic[14]; | ||
530 | LLBMPHeader header; | ||
531 | int header_bytes = 14+sizeof(header); | ||
532 | llassert(header_bytes == 54); | ||
533 | if (getComponents() == 1) | ||
534 | { | ||
535 | header_bytes += 1024; // Need colour LUT. | ||
536 | } | ||
537 | int line_bytes = getComponents() * getWidth(); | ||
538 | int alignment_bytes = (3 * line_bytes) % 4; | ||
539 | line_bytes += alignment_bytes; | ||
540 | int file_bytes = line_bytes*getHeight() + header_bytes; | ||
541 | |||
542 | // Allocate the new buffer for the data. | ||
543 | allocateData(file_bytes); | ||
544 | |||
545 | magic[0] = 'B'; magic[1] = 'M'; | ||
546 | magic[2] = (U8) file_bytes; | ||
547 | magic[3] = (U8)(file_bytes>>8); | ||
548 | magic[4] = (U8)(file_bytes>>16); | ||
549 | magic[5] = (U8)(file_bytes>>24); | ||
550 | magic[6] = magic[7] = magic[8] = magic[9] = 0; | ||
551 | magic[10] = (U8) header_bytes; | ||
552 | magic[11] = (U8)(header_bytes>>8); | ||
553 | magic[12] = (U8)(header_bytes>>16); | ||
554 | magic[13] = (U8)(header_bytes>>24); | ||
555 | header.mSize = 40; | ||
556 | header.mWidth = getWidth(); | ||
557 | header.mHeight = getHeight(); | ||
558 | header.mPlanes = 1; | ||
559 | header.mBitsPerPixel = (getComponents()==1)?8:24; | ||
560 | header.mCompression = 0; | ||
561 | header.mAlignmentPadding = 0; | ||
562 | header.mImageSize = 0; | ||
563 | #if LL_DARWIN | ||
564 | header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 2834; // 72dpi | ||
565 | #else | ||
566 | header.mHorzPelsPerMeter = header.mVertPelsPerMeter = 0; | ||
567 | #endif | ||
568 | header.mNumColors = header.mNumColorsImportant = 0; | ||
569 | |||
570 | // convert BMP header to little endian (no-op on little endian builds) | ||
571 | llendianswizzleone(header.mSize); | ||
572 | llendianswizzleone(header.mWidth); | ||
573 | llendianswizzleone(header.mHeight); | ||
574 | llendianswizzleone(header.mPlanes); | ||
575 | llendianswizzleone(header.mBitsPerPixel); | ||
576 | llendianswizzleone(header.mCompression); | ||
577 | llendianswizzleone(header.mAlignmentPadding); | ||
578 | llendianswizzleone(header.mImageSize); | ||
579 | llendianswizzleone(header.mHorzPelsPerMeter); | ||
580 | llendianswizzleone(header.mVertPelsPerMeter); | ||
581 | llendianswizzleone(header.mNumColors); | ||
582 | llendianswizzleone(header.mNumColorsImportant); | ||
583 | |||
584 | U8* mdata = getData(); | ||
585 | |||
586 | // Output magic, then header, then the palette table, then the data. | ||
587 | U32 cur_pos = 0; | ||
588 | memcpy(mdata, magic, 14); | ||
589 | cur_pos += 14; | ||
590 | memcpy(mdata+cur_pos, &header, 40); | ||
591 | cur_pos += 40; | ||
592 | if (getComponents() == 1) | ||
593 | { | ||
594 | S32 n; | ||
595 | for (n=0; n < 256; n++) | ||
596 | { | ||
597 | mdata[cur_pos++] = (U8)n; | ||
598 | mdata[cur_pos++] = (U8)n; | ||
599 | mdata[cur_pos++] = (U8)n; | ||
600 | mdata[cur_pos++] = 0; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | // Need to iterate through, because we need to flip the RGB. | ||
605 | const U8* src = raw_image->getData(); | ||
606 | U8* dst = mdata + cur_pos; | ||
607 | |||
608 | for( S32 row = 0; row < getHeight(); row++ ) | ||
609 | { | ||
610 | for( S32 col = 0; col < getWidth(); col++ ) | ||
611 | { | ||
612 | switch( src_components ) | ||
613 | { | ||
614 | case 1: | ||
615 | *dst++ = *src++; | ||
616 | break; | ||
617 | case 2: | ||
618 | { | ||
619 | U32 lum = src[0]; | ||
620 | U32 alpha = src[1]; | ||
621 | *dst++ = (U8)(lum * alpha / 255); | ||
622 | src += 2; | ||
623 | break; | ||
624 | } | ||
625 | case 3: | ||
626 | case 4: | ||
627 | dst[0] = src[2]; | ||
628 | dst[1] = src[1]; | ||
629 | dst[2] = src[0]; | ||
630 | src += src_components; | ||
631 | dst += 3; | ||
632 | break; | ||
633 | } | ||
634 | |||
635 | for( S32 i = 0; i < alignment_bytes; i++ ) | ||
636 | { | ||
637 | *dst++ = 0; | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | return TRUE; | ||
643 | } | ||
diff --git a/linden/indra/llimage/llimagebmp.h b/linden/indra/llimage/llimagebmp.h new file mode 100644 index 0000000..43724f2 --- /dev/null +++ b/linden/indra/llimage/llimagebmp.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /** | ||
2 | * @file llimagebmp.h | ||
3 | * @brief Image implementation for BMP. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLIMAGEBMP_H | ||
29 | #define LL_LLIMAGEBMP_H | ||
30 | |||
31 | #include "llimage.h" | ||
32 | |||
33 | // This class compresses and decompressed BMP files | ||
34 | |||
35 | class LLImageBMP : public LLImageFormatted | ||
36 | { | ||
37 | protected: | ||
38 | virtual ~LLImageBMP(); | ||
39 | |||
40 | public: | ||
41 | LLImageBMP(); | ||
42 | |||
43 | /*virtual*/ BOOL updateData(); | ||
44 | /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); | ||
45 | /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); | ||
46 | |||
47 | protected: | ||
48 | BOOL decodeColorTable8( U8* dst, U8* src ); | ||
49 | BOOL decodeColorMask16( U8* dst, U8* src ); | ||
50 | BOOL decodeTruecolor24( U8* dst, U8* src ); | ||
51 | BOOL decodeColorMask32( U8* dst, U8* src ); | ||
52 | |||
53 | U32 countTrailingZeros( U32 m ); | ||
54 | |||
55 | protected: | ||
56 | S32 mColorPaletteColors; | ||
57 | U8* mColorPalette; | ||
58 | S32 mBitmapOffset; | ||
59 | S32 mBitsPerPixel; | ||
60 | U32 mBitfieldMask[4]; // rgba | ||
61 | BOOL mOriginAtTop; | ||
62 | }; | ||
63 | |||
64 | #endif | ||
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 | ||
32 | void 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 | ||
40 | S32 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 | ||
61 | S32 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 | ||
70 | S32 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 | ||
91 | LLImageDXT::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 | ||
114 | S32 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 | ||
137 | void 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 | ||
149 | S32 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 | |||
163 | LLImageDXT::LLImageDXT() | ||
164 | : LLImageFormatted(IMG_CODEC_DXT), | ||
165 | mFileFormat(FORMAT_UNKNOWN), | ||
166 | mHeaderSize(0) | ||
167 | { | ||
168 | } | ||
169 | |||
170 | LLImageDXT::~LLImageDXT() | ||
171 | { | ||
172 | } | ||
173 | |||
174 | // virtual | ||
175 | BOOL 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 | ||
223 | S32 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 | |||
247 | void 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 | ||
260 | BOOL 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 | ||
288 | BOOL 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 | |||
305 | void LLImageDXT::releaseDecodedData() | ||
306 | { | ||
307 | // nothing to do | ||
308 | } | ||
309 | |||
310 | BOOL 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 | ||
396 | BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time) | ||
397 | { | ||
398 | return encode(raw_image, time, false); | ||
399 | } | ||
400 | |||
401 | // virtual | ||
402 | bool 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 | ||
447 | S32 LLImageDXT::calcHeaderSize() | ||
448 | { | ||
449 | return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t)); | ||
450 | } | ||
451 | |||
452 | // virtual | ||
453 | S32 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 | ||
474 | void 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 | //============================================================================ | ||
diff --git a/linden/indra/llimage/llimagedxt.h b/linden/indra/llimage/llimagedxt.h new file mode 100644 index 0000000..c3c01c1 --- /dev/null +++ b/linden/indra/llimage/llimagedxt.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /** | ||
2 | * @file llimagedxt.h | ||
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 | #ifndef LL_LLIMAGEDXT_H | ||
28 | #define LL_LLIMAGEDXT_H | ||
29 | |||
30 | #include "llimage.h" | ||
31 | |||
32 | // This class decodes and encodes LL DXT files (which may unclude uncompressed RGB or RGBA mipped data) | ||
33 | |||
34 | class LLImageDXT : public LLImageFormatted | ||
35 | { | ||
36 | public: | ||
37 | enum EFileFormat | ||
38 | { | ||
39 | FORMAT_UNKNOWN = 0, | ||
40 | FORMAT_I8 = 1, | ||
41 | FORMAT_A8, | ||
42 | FORMAT_RGB8, | ||
43 | FORMAT_RGBA8, | ||
44 | FORMAT_DXT1, | ||
45 | FORMAT_DXT2, | ||
46 | FORMAT_DXT3, | ||
47 | FORMAT_DXT4, | ||
48 | FORMAT_DXT5, | ||
49 | FORMAT_DXR1, | ||
50 | FORMAT_DXR2, | ||
51 | FORMAT_DXR3, | ||
52 | FORMAT_DXR4, | ||
53 | FORMAT_DXR5, | ||
54 | FORMAT_NOFILE = 0xff, | ||
55 | }; | ||
56 | |||
57 | struct dxtfile_header_old_t | ||
58 | { | ||
59 | S32 format; | ||
60 | S32 maxlevel; | ||
61 | S32 maxwidth; | ||
62 | S32 maxheight; | ||
63 | }; | ||
64 | |||
65 | struct dxtfile_header_t | ||
66 | { | ||
67 | S32 fourcc; | ||
68 | // begin DDSURFACEDESC2 struct | ||
69 | S32 header_size; // size of the header | ||
70 | S32 flags; // flags - unused | ||
71 | S32 maxheight; | ||
72 | S32 maxwidth; | ||
73 | S32 image_size; // size of the compressed image | ||
74 | S32 depth; | ||
75 | S32 num_mips; | ||
76 | S32 reserved[11]; | ||
77 | struct pixel_format | ||
78 | { | ||
79 | S32 struct_size; // size of this structure | ||
80 | S32 flags; | ||
81 | S32 fourcc; | ||
82 | S32 bit_count; | ||
83 | S32 r_mask; | ||
84 | S32 g_mask; | ||
85 | S32 b_mask; | ||
86 | S32 a_mask; | ||
87 | } pixel_fmt; | ||
88 | S32 caps[4]; | ||
89 | S32 reserved2; | ||
90 | }; | ||
91 | |||
92 | protected: | ||
93 | /*virtual*/ ~LLImageDXT(); | ||
94 | |||
95 | public: | ||
96 | LLImageDXT(); | ||
97 | |||
98 | /*virtual*/ BOOL updateData(); | ||
99 | |||
100 | /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); | ||
101 | BOOL encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips); | ||
102 | /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); | ||
103 | |||
104 | /*virtual*/ BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard=-1, F32 decode_time=0.0); | ||
105 | /*virtual*/ void releaseDecodedData(); | ||
106 | |||
107 | /*virtual*/ S32 calcHeaderSize(); | ||
108 | /*virtual*/ S32 calcDataSize(S32 discard_level = 0); | ||
109 | |||
110 | void setFormat(); | ||
111 | S32 getMipOffset(S32 discard); | ||
112 | |||
113 | EFileFormat getFileFormat() { return mFileFormat; } | ||
114 | bool isCompressed() { return (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5); } | ||
115 | |||
116 | bool convertToDXR(); // convert from DXT to DXR | ||
117 | |||
118 | static void checkMinWidthHeight(EFileFormat format, S32& width, S32& height); | ||
119 | static S32 formatBits(EFileFormat format); | ||
120 | static S32 formatBytes(EFileFormat format, S32 width, S32 height); | ||
121 | static S32 formatOffset(EFileFormat format, S32 width, S32 height, S32 max_width, S32 max_height); | ||
122 | static S32 formatComponents(EFileFormat format); | ||
123 | |||
124 | static EFileFormat getFormat(S32 fourcc); | ||
125 | static S32 getFourCC(EFileFormat format); | ||
126 | |||
127 | static void calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height); | ||
128 | static S32 calcNumMips(S32 width, S32 height); | ||
129 | |||
130 | private: | ||
131 | static void extractMip(const U8 *indata, U8* mipdata, int width, int height, | ||
132 | int mip_width, int mip_height, EFileFormat format); | ||
133 | |||
134 | private: | ||
135 | EFileFormat mFileFormat; | ||
136 | S32 mHeaderSize; | ||
137 | }; | ||
138 | |||
139 | #endif | ||
diff --git a/linden/indra/llimage/llimagej2c.cpp b/linden/indra/llimage/llimagej2c.cpp new file mode 100644 index 0000000..87852e7 --- /dev/null +++ b/linden/indra/llimage/llimagej2c.cpp | |||
@@ -0,0 +1,402 @@ | |||
1 | /** | ||
2 | * @file llimagej2c.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 | #include "linden_common.h" | ||
27 | |||
28 | #include <apr-1/apr_pools.h> | ||
29 | #include <apr-1/apr_dso.h> | ||
30 | |||
31 | #include "lldir.h" | ||
32 | #include "llimagej2c.h" | ||
33 | #include "llmemory.h" | ||
34 | |||
35 | typedef LLImageJ2CImpl* (*CreateLLImageJ2CFunction)(); | ||
36 | typedef void (*DestroyLLImageJ2CFunction)(LLImageJ2CImpl*); | ||
37 | |||
38 | //some "private static" variables so we only attempt to load | ||
39 | //dynamic libaries once | ||
40 | CreateLLImageJ2CFunction j2cimpl_create_func; | ||
41 | DestroyLLImageJ2CFunction j2cimpl_destroy_func; | ||
42 | apr_pool_t *j2cimpl_dso_memory_pool; | ||
43 | apr_dso_handle_t *j2cimpl_dso_handle; | ||
44 | |||
45 | //Declare the prototype for theses functions here, their functionality | ||
46 | //will be implemented in other files which define a derived LLImageJ2CImpl | ||
47 | //but only ONE static library which has the implementation for this | ||
48 | //function should ever be included | ||
49 | LLImageJ2CImpl* fallbackCreateLLImageJ2CImpl(); | ||
50 | void fallbackDestroyLLImageJ2CImpl(LLImageJ2CImpl* impl); | ||
51 | |||
52 | //static | ||
53 | //Loads the required "create" and "destroy" functions needed | ||
54 | void LLImageJ2C::openDSO() | ||
55 | { | ||
56 | //attempt to load a DSO and get some functions from it | ||
57 | std::string dso_name; | ||
58 | std::string dso_path; | ||
59 | |||
60 | bool all_functions_loaded = false; | ||
61 | apr_status_t rv; | ||
62 | |||
63 | #if LL_WINDOWS | ||
64 | dso_name = "llkdu.dll"; | ||
65 | #elif LL_DARWIN | ||
66 | dso_name = "libllkdu.dylib"; | ||
67 | #else | ||
68 | dso_name = "libllkdu.so"; | ||
69 | #endif | ||
70 | |||
71 | dso_path = gDirUtilp->findFile(dso_name, | ||
72 | gDirUtilp->getAppRODataDir(), | ||
73 | gDirUtilp->getExecutableDir()); | ||
74 | |||
75 | j2cimpl_dso_handle = NULL; | ||
76 | j2cimpl_dso_memory_pool = NULL; | ||
77 | |||
78 | //attempt to load the shared library | ||
79 | apr_pool_create(&j2cimpl_dso_memory_pool, NULL); | ||
80 | rv = apr_dso_load(&j2cimpl_dso_handle, | ||
81 | dso_path.c_str(), | ||
82 | j2cimpl_dso_memory_pool); | ||
83 | |||
84 | //now, check for success | ||
85 | if ( rv == APR_SUCCESS ) | ||
86 | { | ||
87 | //found the dynamic library | ||
88 | //now we want to load the functions we're interested in | ||
89 | CreateLLImageJ2CFunction create_func = NULL; | ||
90 | DestroyLLImageJ2CFunction dest_func = NULL; | ||
91 | |||
92 | rv = apr_dso_sym((apr_dso_handle_sym_t*)&create_func, | ||
93 | j2cimpl_dso_handle, | ||
94 | "createLLImageJ2CKDU"); | ||
95 | if ( rv == APR_SUCCESS ) | ||
96 | { | ||
97 | //we've loaded the create function ok | ||
98 | //we need to delete via the DSO too | ||
99 | //so lets check for a destruction function | ||
100 | rv = apr_dso_sym((apr_dso_handle_sym_t*)&dest_func, | ||
101 | j2cimpl_dso_handle, | ||
102 | "destroyLLImageJ2CKDU"); | ||
103 | if ( rv == APR_SUCCESS ) | ||
104 | { | ||
105 | //k, everything is loaded alright | ||
106 | j2cimpl_create_func = create_func; | ||
107 | j2cimpl_destroy_func = dest_func; | ||
108 | all_functions_loaded = true; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if ( !all_functions_loaded ) | ||
114 | { | ||
115 | //something went wrong with the DSO or function loading.. | ||
116 | //fall back onto our satefy impl creation function | ||
117 | |||
118 | #if 0 | ||
119 | // precious verbose debugging, sadly we can't use our | ||
120 | // 'llinfos' stream etc. this early in the initialisation seq. | ||
121 | char errbuf[256]; | ||
122 | fprintf(stderr, "failed to load syms from DSO %s (%s)\n", | ||
123 | dso_name.c_str(), dso_path.c_str()); | ||
124 | apr_strerror(rv, errbuf, sizeof(errbuf)); | ||
125 | fprintf(stderr, "error: %d, %s\n", rv, errbuf); | ||
126 | apr_dso_error(j2cimpl_dso_handle, errbuf, sizeof(errbuf)); | ||
127 | fprintf(stderr, "dso-error: %d, %s\n", rv, errbuf); | ||
128 | #endif | ||
129 | |||
130 | if ( j2cimpl_dso_handle ) | ||
131 | { | ||
132 | apr_dso_unload(j2cimpl_dso_handle); | ||
133 | j2cimpl_dso_handle = NULL; | ||
134 | } | ||
135 | |||
136 | if ( j2cimpl_dso_memory_pool ) | ||
137 | { | ||
138 | apr_pool_destroy(j2cimpl_dso_memory_pool); | ||
139 | j2cimpl_dso_memory_pool = NULL; | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | //static | ||
145 | void LLImageJ2C::closeDSO() | ||
146 | { | ||
147 | if ( j2cimpl_dso_handle ) apr_dso_unload(j2cimpl_dso_handle); | ||
148 | if (j2cimpl_dso_memory_pool) apr_pool_destroy(j2cimpl_dso_memory_pool); | ||
149 | } | ||
150 | |||
151 | LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), | ||
152 | mMaxBytes(0), | ||
153 | mRawDiscardLevel(-1), | ||
154 | mRate(0.0f) | ||
155 | { | ||
156 | //We assume here that if we wanted to destory via | ||
157 | //a dynamic library that the approriate open calls were made | ||
158 | //before any calls to this constructor. | ||
159 | |||
160 | //Therefore, a NULL creation function pointer here means | ||
161 | //we either did not want to create using functions from the dynamic | ||
162 | //library or there were issues loading it, either way | ||
163 | //use our fall back | ||
164 | if ( !j2cimpl_create_func ) | ||
165 | { | ||
166 | j2cimpl_create_func = fallbackCreateLLImageJ2CImpl; | ||
167 | } | ||
168 | |||
169 | mImpl = j2cimpl_create_func(); | ||
170 | } | ||
171 | |||
172 | // virtual | ||
173 | LLImageJ2C::~LLImageJ2C() | ||
174 | { | ||
175 | //We assume here that if we wanted to destory via | ||
176 | //a dynamic library that the approriate open calls were made | ||
177 | //before any calls to this destructor. | ||
178 | |||
179 | //Therefore, a NULL creation function pointer here means | ||
180 | //we either did not want to destroy using functions from the dynamic | ||
181 | //library or there were issues loading it, either way | ||
182 | //use our fall back | ||
183 | if ( !j2cimpl_destroy_func ) | ||
184 | { | ||
185 | j2cimpl_destroy_func = fallbackDestroyLLImageJ2CImpl; | ||
186 | } | ||
187 | |||
188 | if ( mImpl ) | ||
189 | { | ||
190 | j2cimpl_destroy_func(mImpl); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | // virtual | ||
195 | S8 LLImageJ2C::getRawDiscardLevel() | ||
196 | { | ||
197 | return mRawDiscardLevel; | ||
198 | } | ||
199 | |||
200 | BOOL LLImageJ2C::updateData() | ||
201 | { | ||
202 | resetLastError(); | ||
203 | |||
204 | // Check to make sure that this instance has been initialized with data | ||
205 | if (!getData() || (getDataSize() < 16)) | ||
206 | { | ||
207 | setLastError("LLImageJ2C uninitialized"); | ||
208 | return FALSE; | ||
209 | } | ||
210 | |||
211 | if (!mImpl->getMetadata(*this)) | ||
212 | { | ||
213 | return FALSE; | ||
214 | } | ||
215 | // SJB: override discard based on mMaxBytes elsewhere | ||
216 | S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize(); | ||
217 | S32 discard = calcDiscardLevelBytes(max_bytes); | ||
218 | setDiscardLevel(discard); | ||
219 | |||
220 | return TRUE; | ||
221 | } | ||
222 | |||
223 | |||
224 | BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) | ||
225 | { | ||
226 | return decode(raw_imagep, decode_time, 0, 4); | ||
227 | } | ||
228 | |||
229 | |||
230 | BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) | ||
231 | { | ||
232 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
233 | |||
234 | resetLastError(); | ||
235 | |||
236 | // Check to make sure that this instance has been initialized with data | ||
237 | if (!getData() || (getDataSize() < 16)) | ||
238 | { | ||
239 | setLastError("LLImageJ2C uninitialized"); | ||
240 | return FALSE; | ||
241 | } | ||
242 | |||
243 | // Update the raw discard level | ||
244 | updateRawDiscardLevel(); | ||
245 | |||
246 | return mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); | ||
247 | } | ||
248 | |||
249 | |||
250 | BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time) | ||
251 | { | ||
252 | return encode(raw_imagep, NULL, encode_time); | ||
253 | } | ||
254 | |||
255 | |||
256 | BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time) | ||
257 | { | ||
258 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
259 | return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time); | ||
260 | } | ||
261 | |||
262 | //static | ||
263 | S32 LLImageJ2C::calcHeaderSizeJ2C() | ||
264 | { | ||
265 | return 600; //2048; // ??? hack... just needs to be >= actual header size... | ||
266 | } | ||
267 | |||
268 | //static | ||
269 | S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) | ||
270 | { | ||
271 | if (rate <= 0.f) rate = .125f; | ||
272 | while (discard_level > 0) | ||
273 | { | ||
274 | if (w < 1 || h < 1) | ||
275 | break; | ||
276 | w >>= 1; | ||
277 | h >>= 1; | ||
278 | discard_level--; | ||
279 | } | ||
280 | S32 bytes = (S32)((F32)(w*h*comp)*rate); | ||
281 | bytes = llmax(bytes, calcHeaderSizeJ2C()); | ||
282 | return bytes; | ||
283 | } | ||
284 | |||
285 | S32 LLImageJ2C::calcHeaderSize() | ||
286 | { | ||
287 | return calcHeaderSizeJ2C(); | ||
288 | } | ||
289 | |||
290 | S32 LLImageJ2C::calcDataSize(S32 discard_level) | ||
291 | { | ||
292 | return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); | ||
293 | } | ||
294 | |||
295 | S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) | ||
296 | { | ||
297 | llassert(bytes >= 0); | ||
298 | S32 discard_level = 0; | ||
299 | if (bytes == 0) | ||
300 | { | ||
301 | return MAX_DISCARD_LEVEL; | ||
302 | } | ||
303 | while (1) | ||
304 | { | ||
305 | S32 bytes_needed = calcDataSize(discard_level); // virtual | ||
306 | if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes | ||
307 | { | ||
308 | break; | ||
309 | } | ||
310 | discard_level++; | ||
311 | if (discard_level >= MAX_DISCARD_LEVEL) | ||
312 | { | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | return discard_level; | ||
317 | } | ||
318 | |||
319 | void LLImageJ2C::setRate(F32 rate) | ||
320 | { | ||
321 | mRate = rate; | ||
322 | } | ||
323 | |||
324 | void LLImageJ2C::setMaxBytes(S32 max_bytes) | ||
325 | { | ||
326 | mMaxBytes = max_bytes; | ||
327 | } | ||
328 | // NOT USED | ||
329 | // void LLImageJ2C::setReversible(const BOOL reversible) | ||
330 | // { | ||
331 | // mReversible = reversible; | ||
332 | // } | ||
333 | |||
334 | |||
335 | BOOL LLImageJ2C::loadAndValidate(const LLString &filename) | ||
336 | { | ||
337 | resetLastError(); | ||
338 | |||
339 | S32 file_size = 0; | ||
340 | apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size); | ||
341 | if (!apr_file) | ||
342 | { | ||
343 | setLastError("Unable to open file for reading", filename); | ||
344 | return FALSE; | ||
345 | } | ||
346 | if (file_size == 0) | ||
347 | { | ||
348 | setLastError("File is empty",filename); | ||
349 | apr_file_close(apr_file); | ||
350 | return FALSE; | ||
351 | } | ||
352 | |||
353 | U8 *data = new U8[file_size]; | ||
354 | apr_size_t bytes_read = file_size; | ||
355 | apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read | ||
356 | if (s != APR_SUCCESS || bytes_read != file_size) | ||
357 | { | ||
358 | delete[] data; | ||
359 | setLastError("Unable to read entire file"); | ||
360 | return FALSE; | ||
361 | } | ||
362 | apr_file_close(apr_file); | ||
363 | |||
364 | return validate(data, file_size); | ||
365 | } | ||
366 | |||
367 | |||
368 | BOOL LLImageJ2C::validate(U8 *data, U32 file_size) | ||
369 | { | ||
370 | LLMemType mt1((LLMemType::EMemType)mMemType); | ||
371 | // Taken from setData() | ||
372 | |||
373 | BOOL res = LLImageFormatted::setData(data, file_size); | ||
374 | if ( !res ) | ||
375 | { | ||
376 | return FALSE; | ||
377 | } | ||
378 | |||
379 | // Check to make sure that this instance has been initialized with data | ||
380 | if (!getData() || (0 == getDataSize())) | ||
381 | { | ||
382 | setLastError("LLImageJ2C uninitialized"); | ||
383 | return FALSE; | ||
384 | } | ||
385 | |||
386 | return mImpl->getMetadata(*this); | ||
387 | } | ||
388 | |||
389 | void LLImageJ2C::setDecodingDone(BOOL complete) | ||
390 | { | ||
391 | mDecoding = FALSE; | ||
392 | mDecoded = complete; | ||
393 | } | ||
394 | |||
395 | void LLImageJ2C::updateRawDiscardLevel() | ||
396 | { | ||
397 | mRawDiscardLevel = mMaxBytes ? calcDiscardLevelBytes(mMaxBytes) : mDiscardLevel; | ||
398 | } | ||
399 | |||
400 | LLImageJ2CImpl::~LLImageJ2CImpl() | ||
401 | { | ||
402 | } | ||
diff --git a/linden/indra/llimage/llimagej2c.h b/linden/indra/llimage/llimagej2c.h new file mode 100644 index 0000000..a6894ab --- /dev/null +++ b/linden/indra/llimage/llimagej2c.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /** | ||
2 | * @file llimagej2c.h | ||
3 | * @brief Image implmenation for jpeg2000. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLIMAGEJ2C_H | ||
29 | #define LL_LLIMAGEJ2C_H | ||
30 | |||
31 | #include "llimage.h" | ||
32 | #include "llassettype.h" | ||
33 | |||
34 | class LLImageJ2CImpl; | ||
35 | class LLImageJ2C : public LLImageFormatted | ||
36 | { | ||
37 | protected: | ||
38 | virtual ~LLImageJ2C(); | ||
39 | |||
40 | public: | ||
41 | LLImageJ2C(); | ||
42 | |||
43 | // Base class overrides | ||
44 | /*virtual*/ BOOL updateData(); | ||
45 | /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time=0.0); | ||
46 | /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count); | ||
47 | /*virtual*/ BOOL encode(const LLImageRaw *raw_imagep, F32 encode_time=0.0); | ||
48 | /*virtual*/ S32 calcHeaderSize(); | ||
49 | /*virtual*/ S32 calcDataSize(S32 discard_level = 0); | ||
50 | /*virtual*/ S32 calcDiscardLevelBytes(S32 bytes); | ||
51 | /*virtual*/ S8 getRawDiscardLevel(); | ||
52 | |||
53 | // Encode with comment text | ||
54 | BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0); | ||
55 | |||
56 | BOOL validate(U8 *data, U32 file_size); | ||
57 | BOOL loadAndValidate(const LLString &filename); | ||
58 | |||
59 | // Encode accessors | ||
60 | void setReversible(const BOOL reversible); // Use non-lossy? | ||
61 | void setRate(F32 rate); | ||
62 | void setMaxBytes(S32 max_bytes); | ||
63 | S32 getMaxBytes() const { return mMaxBytes; } | ||
64 | |||
65 | static S32 calcHeaderSizeJ2C(); | ||
66 | static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = 0.f); | ||
67 | |||
68 | static void openDSO(); | ||
69 | static void closeDSO(); | ||
70 | |||
71 | protected: | ||
72 | friend class LLImageJ2CImpl; | ||
73 | friend class LLImageJ2COJ; | ||
74 | friend class LLImageJ2CKDU; | ||
75 | void setDecodingDone(BOOL complete = TRUE); | ||
76 | void updateRawDiscardLevel(); | ||
77 | |||
78 | S32 mMaxBytes; // Maximum number of bytes of data to use... | ||
79 | S8 mRawDiscardLevel; | ||
80 | F32 mRate; | ||
81 | LLImageJ2CImpl *mImpl; | ||
82 | }; | ||
83 | |||
84 | // Derive from this class to implement JPEG2000 decoding | ||
85 | class LLImageJ2CImpl | ||
86 | { | ||
87 | public: | ||
88 | virtual ~LLImageJ2CImpl(); | ||
89 | protected: | ||
90 | virtual BOOL getMetadata(LLImageJ2C &base) = 0; | ||
91 | virtual BOOL decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) = 0; | ||
92 | virtual BOOL encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0) = 0; | ||
93 | |||
94 | friend class LLImageJ2C; | ||
95 | }; | ||
96 | |||
97 | #define LINDEN_J2C_COMMENT_PREFIX "LL_" | ||
98 | |||
99 | #endif | ||
diff --git a/linden/indra/llimage/llimagejpeg.cpp b/linden/indra/llimage/llimagejpeg.cpp new file mode 100644 index 0000000..5c83f20 --- /dev/null +++ b/linden/indra/llimage/llimagejpeg.cpp | |||
@@ -0,0 +1,621 @@ | |||
1 | /** | ||
2 | * @file llimagejpeg.cpp | ||
3 | * | ||
4 | * Copyright (c) 2002-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 | #include "stdtypes.h" | ||
29 | |||
30 | #include "llimagejpeg.h" | ||
31 | |||
32 | #include "llerror.h" | ||
33 | |||
34 | LLImageJPEG::LLImageJPEG() | ||
35 | : | ||
36 | LLImageFormatted(IMG_CODEC_JPEG), | ||
37 | mOutputBuffer( NULL ), | ||
38 | mOutputBufferSize( 0 ), | ||
39 | mEncodeQuality( 75 ) // on a scale from 1 to 100 | ||
40 | { | ||
41 | } | ||
42 | |||
43 | LLImageJPEG::~LLImageJPEG() | ||
44 | { | ||
45 | llassert( !mOutputBuffer ); // Should already be deleted at end of encode. | ||
46 | delete[] mOutputBuffer; | ||
47 | } | ||
48 | |||
49 | BOOL LLImageJPEG::updateData() | ||
50 | { | ||
51 | resetLastError(); | ||
52 | |||
53 | // Check to make sure that this instance has been initialized with data | ||
54 | if (!getData() || (0 == getDataSize())) | ||
55 | { | ||
56 | setLastError("Uninitialized instance of LLImageJPEG"); | ||
57 | return FALSE; | ||
58 | } | ||
59 | |||
60 | //////////////////////////////////////// | ||
61 | // Step 1: allocate and initialize JPEG decompression object | ||
62 | |||
63 | // This struct contains the JPEG decompression parameters and pointers to | ||
64 | // working space (which is allocated as needed by the JPEG library). | ||
65 | struct jpeg_decompress_struct cinfo; | ||
66 | cinfo.client_data = this; | ||
67 | |||
68 | struct jpeg_error_mgr jerr; | ||
69 | cinfo.err = jpeg_std_error(&jerr); | ||
70 | |||
71 | // Customize with our own callbacks | ||
72 | jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller | ||
73 | jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message | ||
74 | jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message | ||
75 | |||
76 | try | ||
77 | { | ||
78 | // Now we can initialize the JPEG decompression object. | ||
79 | jpeg_create_decompress(&cinfo); | ||
80 | |||
81 | //////////////////////////////////////// | ||
82 | // Step 2: specify data source | ||
83 | // (Code is modified version of jpeg_stdio_src(); | ||
84 | if (cinfo.src == NULL) | ||
85 | { | ||
86 | cinfo.src = (struct jpeg_source_mgr *) | ||
87 | (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, | ||
88 | sizeof(struct jpeg_source_mgr)); | ||
89 | } | ||
90 | cinfo.src->init_source = &LLImageJPEG::decodeInitSource; | ||
91 | cinfo.src->fill_input_buffer = &LLImageJPEG::decodeFillInputBuffer; | ||
92 | cinfo.src->skip_input_data = &LLImageJPEG::decodeSkipInputData; | ||
93 | cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better. | ||
94 | cinfo.src->term_source = &LLImageJPEG::decodeTermSource; | ||
95 | |||
96 | cinfo.src->bytes_in_buffer = getDataSize(); | ||
97 | cinfo.src->next_input_byte = getData(); | ||
98 | |||
99 | //////////////////////////////////////// | ||
100 | // Step 3: read file parameters with jpeg_read_header() | ||
101 | jpeg_read_header( &cinfo, TRUE ); | ||
102 | |||
103 | // Data set by jpeg_read_header | ||
104 | setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB) | ||
105 | |||
106 | /* | ||
107 | // More data set by jpeg_read_header | ||
108 | cinfo.num_components; | ||
109 | cinfo.jpeg_color_space; // Colorspace of image | ||
110 | cinfo.saw_JFIF_marker; // TRUE if a JFIF APP0 marker was seen | ||
111 | cinfo.JFIF_major_version; // Version information from JFIF marker | ||
112 | cinfo.JFIF_minor_version; // | ||
113 | cinfo.density_unit; // Resolution data from JFIF marker | ||
114 | cinfo.X_density; | ||
115 | cinfo.Y_density; | ||
116 | cinfo.saw_Adobe_marker; // TRUE if an Adobe APP14 marker was seen | ||
117 | cinfo.Adobe_transform; // Color transform code from Adobe marker | ||
118 | */ | ||
119 | } | ||
120 | catch (int) | ||
121 | { | ||
122 | jpeg_destroy_decompress(&cinfo); | ||
123 | |||
124 | return FALSE; | ||
125 | } | ||
126 | //////////////////////////////////////// | ||
127 | // Step 4: Release JPEG decompression object | ||
128 | jpeg_destroy_decompress(&cinfo); | ||
129 | |||
130 | return TRUE; | ||
131 | } | ||
132 | |||
133 | // Initialize source --- called by jpeg_read_header | ||
134 | // before any data is actually read. | ||
135 | void LLImageJPEG::decodeInitSource( j_decompress_ptr cinfo ) | ||
136 | { | ||
137 | // no work necessary here | ||
138 | } | ||
139 | |||
140 | // Fill the input buffer --- called whenever buffer is emptied. | ||
141 | boolean LLImageJPEG::decodeFillInputBuffer( j_decompress_ptr cinfo ) | ||
142 | { | ||
143 | // jpeg_source_mgr* src = cinfo->src; | ||
144 | // LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
145 | |||
146 | // Should never get here, since we provide the entire buffer up front. | ||
147 | ERREXIT(cinfo, JERR_INPUT_EMPTY); | ||
148 | |||
149 | return TRUE; | ||
150 | } | ||
151 | |||
152 | // Skip data --- used to skip over a potentially large amount of | ||
153 | // uninteresting data (such as an APPn marker). | ||
154 | // | ||
155 | // Writers of suspendable-input applications must note that skip_input_data | ||
156 | // is not granted the right to give a suspension return. If the skip extends | ||
157 | // beyond the data currently in the buffer, the buffer can be marked empty so | ||
158 | // that the next read will cause a fill_input_buffer call that can suspend. | ||
159 | // Arranging for additional bytes to be discarded before reloading the input | ||
160 | // buffer is the application writer's problem. | ||
161 | void LLImageJPEG::decodeSkipInputData (j_decompress_ptr cinfo, long num_bytes) | ||
162 | { | ||
163 | jpeg_source_mgr* src = cinfo->src; | ||
164 | // LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
165 | |||
166 | src->next_input_byte += (size_t) num_bytes; | ||
167 | src->bytes_in_buffer -= (size_t) num_bytes; | ||
168 | } | ||
169 | |||
170 | void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo) | ||
171 | { | ||
172 | // no work necessary here | ||
173 | } | ||
174 | |||
175 | |||
176 | BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) | ||
177 | { | ||
178 | llassert_always(raw_image); | ||
179 | |||
180 | resetLastError(); | ||
181 | |||
182 | // Check to make sure that this instance has been initialized with data | ||
183 | if (!getData() || (0 == getDataSize())) | ||
184 | { | ||
185 | setLastError("LLImageJPEG trying to decode an image with no data!"); | ||
186 | return FALSE; | ||
187 | } | ||
188 | |||
189 | S32 row_stride = 0; | ||
190 | U8* raw_image_data = NULL; | ||
191 | |||
192 | //////////////////////////////////////// | ||
193 | // Step 1: allocate and initialize JPEG decompression object | ||
194 | |||
195 | // This struct contains the JPEG decompression parameters and pointers to | ||
196 | // working space (which is allocated as needed by the JPEG library). | ||
197 | struct jpeg_decompress_struct cinfo; | ||
198 | |||
199 | struct jpeg_error_mgr jerr; | ||
200 | cinfo.err = jpeg_std_error(&jerr); | ||
201 | |||
202 | // Customize with our own callbacks | ||
203 | jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller | ||
204 | jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message | ||
205 | jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message | ||
206 | |||
207 | |||
208 | try | ||
209 | { | ||
210 | // Now we can initialize the JPEG decompression object. | ||
211 | jpeg_create_decompress(&cinfo); | ||
212 | |||
213 | //////////////////////////////////////// | ||
214 | // Step 2: specify data source | ||
215 | // (Code is modified version of jpeg_stdio_src(); | ||
216 | if (cinfo.src == NULL) | ||
217 | { | ||
218 | cinfo.src = (struct jpeg_source_mgr *) | ||
219 | (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, | ||
220 | sizeof(struct jpeg_source_mgr)); | ||
221 | } | ||
222 | cinfo.src->init_source = &LLImageJPEG::decodeInitSource; | ||
223 | cinfo.src->fill_input_buffer = &LLImageJPEG::decodeFillInputBuffer; | ||
224 | cinfo.src->skip_input_data = &LLImageJPEG::decodeSkipInputData; | ||
225 | cinfo.src->resync_to_restart = jpeg_resync_to_restart; // For now, use default method, but we should be able to do better. | ||
226 | cinfo.src->term_source = &LLImageJPEG::decodeTermSource; | ||
227 | cinfo.src->bytes_in_buffer = getDataSize(); | ||
228 | cinfo.src->next_input_byte = getData(); | ||
229 | |||
230 | //////////////////////////////////////// | ||
231 | // Step 3: read file parameters with jpeg_read_header() | ||
232 | |||
233 | jpeg_read_header(&cinfo, TRUE); | ||
234 | |||
235 | // We can ignore the return value from jpeg_read_header since | ||
236 | // (a) suspension is not possible with our data source, and | ||
237 | // (b) we passed TRUE to reject a tables-only JPEG file as an error. | ||
238 | // See libjpeg.doc for more info. | ||
239 | |||
240 | setSize(cinfo.image_width, cinfo.image_height, 3); // Force to 3 components (RGB) | ||
241 | |||
242 | raw_image->resize(getWidth(), getHeight(), getComponents()); | ||
243 | raw_image_data = raw_image->getData(); | ||
244 | |||
245 | |||
246 | //////////////////////////////////////// | ||
247 | // Step 4: set parameters for decompression | ||
248 | cinfo.out_color_components = 3; | ||
249 | cinfo.out_color_space = JCS_RGB; | ||
250 | |||
251 | |||
252 | //////////////////////////////////////// | ||
253 | // Step 5: Start decompressor | ||
254 | |||
255 | jpeg_start_decompress(&cinfo); | ||
256 | // We can ignore the return value since suspension is not possible | ||
257 | // with our data source. | ||
258 | |||
259 | // We may need to do some setup of our own at this point before reading | ||
260 | // the data. After jpeg_start_decompress() we have the correct scaled | ||
261 | // output image dimensions available, as well as the output colormap | ||
262 | // if we asked for color quantization. | ||
263 | // In this example, we need to make an output work buffer of the right size. | ||
264 | |||
265 | // JSAMPLEs per row in output buffer | ||
266 | row_stride = cinfo.output_width * cinfo.output_components; | ||
267 | |||
268 | //////////////////////////////////////// | ||
269 | // Step 6: while (scan lines remain to be read) | ||
270 | // jpeg_read_scanlines(...); | ||
271 | |||
272 | // Here we use the library's state variable cinfo.output_scanline as the | ||
273 | // loop counter, so that we don't have to keep track ourselves. | ||
274 | |||
275 | // Move pointer to last line | ||
276 | raw_image_data += row_stride * (cinfo.output_height - 1); | ||
277 | |||
278 | while (cinfo.output_scanline < cinfo.output_height) | ||
279 | { | ||
280 | // jpeg_read_scanlines expects an array of pointers to scanlines. | ||
281 | // Here the array is only one element long, but you could ask for | ||
282 | // more than one scanline at a time if that's more convenient. | ||
283 | |||
284 | jpeg_read_scanlines(&cinfo, &raw_image_data, 1); | ||
285 | raw_image_data -= row_stride; // move pointer up a line | ||
286 | } | ||
287 | |||
288 | //////////////////////////////////////// | ||
289 | // Step 7: Finish decompression | ||
290 | jpeg_finish_decompress(&cinfo); | ||
291 | |||
292 | //////////////////////////////////////// | ||
293 | // Step 8: Release JPEG decompression object | ||
294 | jpeg_destroy_decompress(&cinfo); | ||
295 | } | ||
296 | |||
297 | catch (int) | ||
298 | { | ||
299 | jpeg_destroy_decompress(&cinfo); | ||
300 | return FALSE; | ||
301 | } | ||
302 | |||
303 | // Check to see whether any corrupt-data warnings occurred | ||
304 | if( jerr.num_warnings != 0 ) | ||
305 | { | ||
306 | // TODO: extract the warning to find out what went wrong. | ||
307 | setLastError( "Unable to decode JPEG image."); | ||
308 | return FALSE; | ||
309 | } | ||
310 | |||
311 | return TRUE; | ||
312 | } | ||
313 | |||
314 | |||
315 | // Initialize destination --- called by jpeg_start_compress before any data is actually written. | ||
316 | // static | ||
317 | void LLImageJPEG::encodeInitDestination ( j_compress_ptr cinfo ) | ||
318 | { | ||
319 | LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
320 | |||
321 | cinfo->dest->next_output_byte = self->mOutputBuffer; | ||
322 | cinfo->dest->free_in_buffer = self->mOutputBufferSize; | ||
323 | } | ||
324 | |||
325 | |||
326 | // Empty the output buffer --- called whenever buffer fills up. | ||
327 | // | ||
328 | // In typical applications, this should write the entire output buffer | ||
329 | // (ignoring the current state of next_output_byte & free_in_buffer), | ||
330 | // reset the pointer & count to the start of the buffer, and return TRUE | ||
331 | // indicating that the buffer has been dumped. | ||
332 | // | ||
333 | // In applications that need to be able to suspend compression due to output | ||
334 | // overrun, a FALSE return indicates that the buffer cannot be emptied now. | ||
335 | // In this situation, the compressor will return to its caller (possibly with | ||
336 | // an indication that it has not accepted all the supplied scanlines). The | ||
337 | // application should resume compression after it has made more room in the | ||
338 | // output buffer. Note that there are substantial restrictions on the use of | ||
339 | // suspension --- see the documentation. | ||
340 | // | ||
341 | // When suspending, the compressor will back up to a convenient restart point | ||
342 | // (typically the start of the current MCU). next_output_byte & free_in_buffer | ||
343 | // indicate where the restart point will be if the current call returns FALSE. | ||
344 | // Data beyond this point will be regenerated after resumption, so do not | ||
345 | // write it out when emptying the buffer externally. | ||
346 | |||
347 | boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) | ||
348 | { | ||
349 | LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
350 | |||
351 | // Should very rarely happen, since our output buffer is | ||
352 | // as large as the input to start out with. | ||
353 | |||
354 | // Double the buffer size; | ||
355 | S32 new_buffer_size = self->mOutputBufferSize * 2; | ||
356 | U8* new_buffer = new U8[ new_buffer_size ]; | ||
357 | memcpy( new_buffer, self->mOutputBuffer, self->mOutputBufferSize ); | ||
358 | delete[] self->mOutputBuffer; | ||
359 | self->mOutputBuffer = new_buffer; | ||
360 | |||
361 | cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize; | ||
362 | cinfo->dest->free_in_buffer = self->mOutputBufferSize; | ||
363 | self->mOutputBufferSize = new_buffer_size; | ||
364 | |||
365 | return TRUE; | ||
366 | } | ||
367 | |||
368 | // Terminate destination --- called by jpeg_finish_compress | ||
369 | // after all data has been written. Usually needs to flush buffer. | ||
370 | // | ||
371 | // NB: *not* called by jpeg_abort or jpeg_destroy; surrounding | ||
372 | // application must deal with any cleanup that should happen even | ||
373 | // for error exit. | ||
374 | void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo ) | ||
375 | { | ||
376 | LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
377 | |||
378 | S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer); | ||
379 | self->allocateData(file_bytes); | ||
380 | |||
381 | memcpy( self->getData(), self->mOutputBuffer, file_bytes ); | ||
382 | } | ||
383 | |||
384 | // static | ||
385 | void LLImageJPEG::errorExit( j_common_ptr cinfo ) | ||
386 | { | ||
387 | //LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; | ||
388 | |||
389 | // Always display the message | ||
390 | (*cinfo->err->output_message)(cinfo); | ||
391 | |||
392 | // Let the memory manager delete any temp files | ||
393 | jpeg_destroy(cinfo); | ||
394 | |||
395 | // Return control to the setjmp point | ||
396 | throw 1; | ||
397 | } | ||
398 | |||
399 | // Decide whether to emit a trace or warning message. | ||
400 | // msg_level is one of: | ||
401 | // -1: recoverable corrupt-data warning, may want to abort. | ||
402 | // 0: important advisory messages (always display to user). | ||
403 | // 1: first level of tracing detail. | ||
404 | // 2,3,...: successively more detailed tracing messages. | ||
405 | // An application might override this method if it wanted to abort on warnings | ||
406 | // or change the policy about which messages to display. | ||
407 | // static | ||
408 | void LLImageJPEG::errorEmitMessage( j_common_ptr cinfo, int msg_level ) | ||
409 | { | ||
410 | struct jpeg_error_mgr * err = cinfo->err; | ||
411 | |||
412 | if (msg_level < 0) | ||
413 | { | ||
414 | // It's a warning message. Since corrupt files may generate many warnings, | ||
415 | // the policy implemented here is to show only the first warning, | ||
416 | // unless trace_level >= 3. | ||
417 | if (err->num_warnings == 0 || err->trace_level >= 3) | ||
418 | { | ||
419 | (*err->output_message) (cinfo); | ||
420 | } | ||
421 | // Always count warnings in num_warnings. | ||
422 | err->num_warnings++; | ||
423 | } | ||
424 | else | ||
425 | { | ||
426 | // It's a trace message. Show it if trace_level >= msg_level. | ||
427 | if (err->trace_level >= msg_level) | ||
428 | { | ||
429 | (*err->output_message) (cinfo); | ||
430 | } | ||
431 | } | ||
432 | } | ||
433 | |||
434 | // static | ||
435 | void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo ) | ||
436 | { | ||
437 | // Create the message | ||
438 | char buffer[JMSG_LENGTH_MAX]; | ||
439 | (*cinfo->err->format_message) (cinfo, buffer); | ||
440 | |||
441 | ((LLImageJPEG*) cinfo->client_data)->setLastError( buffer ); | ||
442 | |||
443 | BOOL is_decode = (cinfo->is_decompressor != 0); | ||
444 | llwarns << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << llendl; | ||
445 | } | ||
446 | |||
447 | BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) | ||
448 | { | ||
449 | llassert_always(raw_image); | ||
450 | |||
451 | resetLastError(); | ||
452 | |||
453 | switch( raw_image->getComponents() ) | ||
454 | { | ||
455 | case 1: | ||
456 | case 3: | ||
457 | break; | ||
458 | default: | ||
459 | setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components."); | ||
460 | return FALSE; | ||
461 | } | ||
462 | |||
463 | setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); | ||
464 | |||
465 | // Allocate a temporary buffer big enough to hold the entire compressed image (and then some) | ||
466 | // (Note: we make it bigger in emptyOutputBuffer() if we need to) | ||
467 | delete[] mOutputBuffer; | ||
468 | mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024; | ||
469 | mOutputBuffer = new U8[ mOutputBufferSize ]; | ||
470 | |||
471 | const U8* raw_image_data = NULL; | ||
472 | S32 row_stride = 0; | ||
473 | |||
474 | //////////////////////////////////////// | ||
475 | // Step 1: allocate and initialize JPEG compression object | ||
476 | |||
477 | // This struct contains the JPEG compression parameters and pointers to | ||
478 | // working space (which is allocated as needed by the JPEG library). | ||
479 | struct jpeg_compress_struct cinfo; | ||
480 | cinfo.client_data = this; | ||
481 | |||
482 | // We have to set up the error handler first, in case the initialization | ||
483 | // step fails. (Unlikely, but it could happen if you are out of memory.) | ||
484 | // This routine fills in the contents of struct jerr, and returns jerr's | ||
485 | // address which we place into the link field in cinfo. | ||
486 | struct jpeg_error_mgr jerr; | ||
487 | cinfo.err = jpeg_std_error(&jerr); | ||
488 | |||
489 | // Customize with our own callbacks | ||
490 | jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller | ||
491 | jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message | ||
492 | jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message | ||
493 | |||
494 | // Establish the setjmp return context mSetjmpBuffer. Used by library to abort. | ||
495 | if( setjmp(mSetjmpBuffer) ) | ||
496 | { | ||
497 | // If we get here, the JPEG code has signaled an error. | ||
498 | // We need to clean up the JPEG object, close the input file, and return. | ||
499 | jpeg_destroy_compress(&cinfo); | ||
500 | delete[] mOutputBuffer; | ||
501 | mOutputBuffer = NULL; | ||
502 | mOutputBufferSize = 0; | ||
503 | return FALSE; | ||
504 | } | ||
505 | |||
506 | try | ||
507 | { | ||
508 | |||
509 | // Now we can initialize the JPEG compression object. | ||
510 | jpeg_create_compress(&cinfo); | ||
511 | |||
512 | //////////////////////////////////////// | ||
513 | // Step 2: specify data destination | ||
514 | // (code is a modified form of jpeg_stdio_dest() ) | ||
515 | if( cinfo.dest == NULL) | ||
516 | { | ||
517 | cinfo.dest = (struct jpeg_destination_mgr *) | ||
518 | (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, | ||
519 | sizeof(struct jpeg_destination_mgr)); | ||
520 | } | ||
521 | cinfo.dest->next_output_byte = mOutputBuffer; // => next byte to write in buffer | ||
522 | cinfo.dest->free_in_buffer = mOutputBufferSize; // # of byte spaces remaining in buffer | ||
523 | cinfo.dest->init_destination = &LLImageJPEG::encodeInitDestination; | ||
524 | cinfo.dest->empty_output_buffer = &LLImageJPEG::encodeEmptyOutputBuffer; | ||
525 | cinfo.dest->term_destination = &LLImageJPEG::encodeTermDestination; | ||
526 | |||
527 | //////////////////////////////////////// | ||
528 | // Step 3: set parameters for compression | ||
529 | // | ||
530 | // First we supply a description of the input image. | ||
531 | // Four fields of the cinfo struct must be filled in: | ||
532 | |||
533 | cinfo.image_width = getWidth(); // image width and height, in pixels | ||
534 | cinfo.image_height = getHeight(); | ||
535 | |||
536 | switch( getComponents() ) | ||
537 | { | ||
538 | case 1: | ||
539 | cinfo.input_components = 1; // # of color components per pixel | ||
540 | cinfo.in_color_space = JCS_GRAYSCALE; // colorspace of input image | ||
541 | break; | ||
542 | case 3: | ||
543 | cinfo.input_components = 3; // # of color components per pixel | ||
544 | cinfo.in_color_space = JCS_RGB; // colorspace of input image | ||
545 | break; | ||
546 | default: | ||
547 | setLastError("Unable to encode a JPEG image that doesn't have 1 or 3 components."); | ||
548 | return FALSE; | ||
549 | } | ||
550 | |||
551 | // Now use the library's routine to set default compression parameters. | ||
552 | // (You must set at least cinfo.in_color_space before calling this, | ||
553 | // since the defaults depend on the source color space.) | ||
554 | jpeg_set_defaults(&cinfo); | ||
555 | |||
556 | // Now you can set any non-default parameters you wish to. | ||
557 | jpeg_set_quality(&cinfo, mEncodeQuality, TRUE ); // limit to baseline-JPEG values | ||
558 | |||
559 | //////////////////////////////////////// | ||
560 | // Step 4: Start compressor | ||
561 | // | ||
562 | // TRUE ensures that we will write a complete interchange-JPEG file. | ||
563 | // Pass TRUE unless you are very sure of what you're doing. | ||
564 | |||
565 | jpeg_start_compress(&cinfo, TRUE); | ||
566 | |||
567 | //////////////////////////////////////// | ||
568 | // Step 5: while (scan lines remain to be written) | ||
569 | // jpeg_write_scanlines(...); | ||
570 | |||
571 | // Here we use the library's state variable cinfo.next_scanline as the | ||
572 | // loop counter, so that we don't have to keep track ourselves. | ||
573 | // To keep things simple, we pass one scanline per call; you can pass | ||
574 | // more if you wish, though. | ||
575 | |||
576 | row_stride = getWidth() * getComponents(); // JSAMPLEs per row in image_buffer | ||
577 | |||
578 | // NOTE: For compatibility with LLImage, we need to invert the rows. | ||
579 | raw_image_data = raw_image->getData(); | ||
580 | |||
581 | const U8* last_row_data = raw_image_data + (getHeight()-1) * row_stride; | ||
582 | |||
583 | JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] | ||
584 | while (cinfo.next_scanline < cinfo.image_height) | ||
585 | { | ||
586 | // jpeg_write_scanlines expects an array of pointers to scanlines. | ||
587 | // Here the array is only one element long, but you could pass | ||
588 | // more than one scanline at a time if that's more convenient. | ||
589 | |||
590 | //Ugly const uncast here (jpeg_write_scanlines should take a const* but doesn't) | ||
591 | //row_pointer[0] = (JSAMPROW)(raw_image_data + (cinfo.next_scanline * row_stride)); | ||
592 | row_pointer[0] = (JSAMPROW)(last_row_data - (cinfo.next_scanline * row_stride)); | ||
593 | |||
594 | jpeg_write_scanlines(&cinfo, row_pointer, 1); | ||
595 | } | ||
596 | |||
597 | //////////////////////////////////////// | ||
598 | // Step 6: Finish compression | ||
599 | jpeg_finish_compress(&cinfo); | ||
600 | |||
601 | // After finish_compress, we can release the temp output buffer. | ||
602 | delete[] mOutputBuffer; | ||
603 | mOutputBuffer = NULL; | ||
604 | mOutputBufferSize = 0; | ||
605 | |||
606 | //////////////////////////////////////// | ||
607 | // Step 7: release JPEG compression object | ||
608 | jpeg_destroy_compress(&cinfo); | ||
609 | } | ||
610 | |||
611 | catch(int) | ||
612 | { | ||
613 | jpeg_destroy_compress(&cinfo); | ||
614 | delete[] mOutputBuffer; | ||
615 | mOutputBuffer = NULL; | ||
616 | mOutputBufferSize = 0; | ||
617 | return FALSE; | ||
618 | } | ||
619 | |||
620 | return TRUE; | ||
621 | } | ||
diff --git a/linden/indra/llimage/llimagejpeg.h b/linden/indra/llimage/llimagejpeg.h new file mode 100644 index 0000000..8f8e7bb --- /dev/null +++ b/linden/indra/llimage/llimagejpeg.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /** | ||
2 | * @file llimagejpeg.h | ||
3 | * @brief This class compresses and decompresses JPEG files | ||
4 | * | ||
5 | * Copyright (c) 2002-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLIMAGEJPEG_H | ||
29 | #define LL_LLIMAGEJPEG_H | ||
30 | |||
31 | #include <setjmp.h> | ||
32 | |||
33 | #include "llimage.h" | ||
34 | |||
35 | extern "C" { | ||
36 | #include "jpeglib/jinclude.h" | ||
37 | #include "jpeglib/jpeglib.h" | ||
38 | #include "jpeglib/jerror.h" | ||
39 | } | ||
40 | |||
41 | class LLImageJPEG : public LLImageFormatted | ||
42 | { | ||
43 | protected: | ||
44 | virtual ~LLImageJPEG(); | ||
45 | |||
46 | public: | ||
47 | LLImageJPEG(); | ||
48 | |||
49 | /*virtual*/ BOOL updateData(); | ||
50 | /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); | ||
51 | /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); | ||
52 | |||
53 | void setEncodeQuality( S32 q ) { mEncodeQuality = q; } // on a scale from 1 to 100 | ||
54 | S32 getEncodeQuality() { return mEncodeQuality; } | ||
55 | |||
56 | // Callbacks registered with jpeglib | ||
57 | static void encodeInitDestination ( j_compress_ptr cinfo ); | ||
58 | static boolean encodeEmptyOutputBuffer(j_compress_ptr cinfo); | ||
59 | static void encodeTermDestination(j_compress_ptr cinfo); | ||
60 | |||
61 | static void decodeInitSource(j_decompress_ptr cinfo); | ||
62 | static boolean decodeFillInputBuffer(j_decompress_ptr cinfo); | ||
63 | static void decodeSkipInputData(j_decompress_ptr cinfo, long num_bytes); | ||
64 | static void decodeTermSource(j_decompress_ptr cinfo); | ||
65 | |||
66 | |||
67 | static void errorExit(j_common_ptr cinfo); | ||
68 | static void errorEmitMessage(j_common_ptr cinfo, int msg_level); | ||
69 | static void errorOutputMessage(j_common_ptr cinfo); | ||
70 | |||
71 | static BOOL decompress(LLImageJPEG* imagep); | ||
72 | |||
73 | protected: | ||
74 | U8* mOutputBuffer; // temp buffer used during encoding | ||
75 | S32 mOutputBufferSize; // bytes in mOuputBuffer | ||
76 | |||
77 | S32 mEncodeQuality; // on a scale from 1 to 100 | ||
78 | |||
79 | jmp_buf mSetjmpBuffer; // To allow the library to abort. | ||
80 | }; | ||
81 | |||
82 | #endif // LL_LLIMAGEJPEG_H | ||
diff --git a/linden/indra/llimage/llimagetga.cpp b/linden/indra/llimage/llimagetga.cpp new file mode 100644 index 0000000..722bd1e --- /dev/null +++ b/linden/indra/llimage/llimagetga.cpp | |||
@@ -0,0 +1,1109 @@ | |||
1 | /** | ||
2 | * @file llimagetga.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 "llimagetga.h" | ||
30 | #include "llerror.h" | ||
31 | #include "llmath.h" | ||
32 | |||
33 | // For expanding 5-bit pixel values to 8-bit with best rounding | ||
34 | // static | ||
35 | const U8 LLImageTGA::s5to8bits[32] = | ||
36 | { | ||
37 | 0, 8, 16, 25, 33, 41, 49, 58, | ||
38 | 66, 74, 82, 90, 99, 107, 115, 123, | ||
39 | 132, 140, 148, 156, 165, 173, 181, 189, | ||
40 | 197, 206, 214, 222, 230, 239, 247, 255 | ||
41 | }; | ||
42 | |||
43 | inline void LLImageTGA::decodeTruecolorPixel15( U8* dst, const U8* src ) | ||
44 | { | ||
45 | // We expand 5 bit data to 8 bit sample width. | ||
46 | // The format of the 16-bit (LSB first) input word is | ||
47 | // xRRRRRGGGGGBBBBB | ||
48 | U32 t = U32(src[0]) + (U32(src[1]) << 8); | ||
49 | dst[2] = s5to8bits[t & 0x1F]; // blue | ||
50 | t >>= 5; | ||
51 | dst[1] = s5to8bits[t & 0x1F]; // green | ||
52 | t >>= 5; | ||
53 | dst[0] = s5to8bits[t & 0x1F]; // red | ||
54 | } | ||
55 | |||
56 | LLImageTGA::LLImageTGA() | ||
57 | : LLImageFormatted(IMG_CODEC_TGA), | ||
58 | mColorMap( NULL ), | ||
59 | mColorMapStart( 0 ), | ||
60 | mColorMapLength( 0 ), | ||
61 | mColorMapBytesPerEntry( 0 ), | ||
62 | mIs15Bit( FALSE ) | ||
63 | { | ||
64 | } | ||
65 | |||
66 | LLImageTGA::LLImageTGA(const LLString& file_name) | ||
67 | : LLImageFormatted(IMG_CODEC_TGA), | ||
68 | mColorMap( NULL ), | ||
69 | mColorMapStart( 0 ), | ||
70 | mColorMapLength( 0 ), | ||
71 | mColorMapBytesPerEntry( 0 ), | ||
72 | mIs15Bit( FALSE ) | ||
73 | { | ||
74 | loadFile(file_name); | ||
75 | } | ||
76 | |||
77 | LLImageTGA::~LLImageTGA() | ||
78 | { | ||
79 | delete mColorMap; | ||
80 | } | ||
81 | |||
82 | BOOL LLImageTGA::updateData() | ||
83 | { | ||
84 | resetLastError(); | ||
85 | |||
86 | // Check to make sure that this instance has been initialized with data | ||
87 | if (!getData() || (0 == getDataSize())) | ||
88 | { | ||
89 | setLastError("LLImageTGA uninitialized"); | ||
90 | return FALSE; | ||
91 | } | ||
92 | |||
93 | // Pull image information from the header... | ||
94 | U8 flags; | ||
95 | U8 junk[256]; | ||
96 | |||
97 | /**************************************************************************** | ||
98 | ** | ||
99 | ** For more information about the original Truevision TGA(tm) file format, | ||
100 | ** or for additional information about the new extensions to the | ||
101 | ** Truevision TGA file, refer to the "Truevision TGA File Format | ||
102 | ** Specification Version 2.0" available from Truevision or your | ||
103 | ** Truevision dealer. | ||
104 | ** | ||
105 | ** FILE STRUCTURE FOR THE ORIGINAL TRUEVISION TGA FILE | ||
106 | ** FIELD 1 : NUMBER OF CHARACTERS IN ID FIELD (1 BYTES) | ||
107 | ** FIELD 2 : COLOR MAP TYPE (1 BYTES) | ||
108 | ** FIELD 3 : IMAGE TYPE CODE (1 BYTES) | ||
109 | ** = 0 NO IMAGE DATA INCLUDED | ||
110 | ** = 1 UNCOMPRESSED, COLOR-MAPPED IMAGE | ||
111 | ** = 2 UNCOMPRESSED, TRUE-COLOR IMAGE | ||
112 | ** = 3 UNCOMPRESSED, BLACK AND WHITE IMAGE | ||
113 | ** = 9 RUN-LENGTH ENCODED COLOR-MAPPED IMAGE | ||
114 | ** = 10 RUN-LENGTH ENCODED TRUE-COLOR IMAGE | ||
115 | ** = 11 RUN-LENGTH ENCODED BLACK AND WHITE IMAGE | ||
116 | ** FIELD 4 : COLOR MAP SPECIFICATION (5 BYTES) | ||
117 | ** 4.1 : COLOR MAP ORIGIN (2 BYTES) | ||
118 | ** 4.2 : COLOR MAP LENGTH (2 BYTES) | ||
119 | ** 4.3 : COLOR MAP ENTRY SIZE (2 BYTES) | ||
120 | ** FIELD 5 : IMAGE SPECIFICATION (10 BYTES) | ||
121 | ** 5.1 : X-ORIGIN OF IMAGE (2 BYTES) | ||
122 | ** 5.2 : Y-ORIGIN OF IMAGE (2 BYTES) | ||
123 | ** 5.3 : WIDTH OF IMAGE (2 BYTES) | ||
124 | ** 5.4 : HEIGHT OF IMAGE (2 BYTES) | ||
125 | ** 5.5 : IMAGE PIXEL SIZE (1 BYTE) | ||
126 | ** 5.6 : IMAGE DESCRIPTOR BYTE (1 BYTE) | ||
127 | ** FIELD 6 : IMAGE ID FIELD (LENGTH SPECIFIED BY FIELD 1) | ||
128 | ** FIELD 7 : COLOR MAP DATA (BIT WIDTH SPECIFIED BY FIELD 4.3 AND | ||
129 | ** NUMBER OF COLOR MAP ENTRIES SPECIFIED IN FIELD 4.2) | ||
130 | ** FIELD 8 : IMAGE DATA FIELD (WIDTH AND HEIGHT SPECIFIED IN | ||
131 | ** FIELD 5.3 AND 5.4) | ||
132 | ****************************************************************************/ | ||
133 | |||
134 | mDataOffset = 0; | ||
135 | mIDLength = *(getData()+mDataOffset++); | ||
136 | mColorMapType = *(getData()+mDataOffset++); | ||
137 | mImageType = *(getData()+mDataOffset++); | ||
138 | mColorMapIndexLo = *(getData()+mDataOffset++); | ||
139 | mColorMapIndexHi = *(getData()+mDataOffset++); | ||
140 | mColorMapLengthLo = *(getData()+mDataOffset++); | ||
141 | mColorMapLengthHi = *(getData()+mDataOffset++); | ||
142 | mColorMapDepth = *(getData()+mDataOffset++); | ||
143 | mXOffsetLo = *(getData()+mDataOffset++); | ||
144 | mXOffsetHi = *(getData()+mDataOffset++); | ||
145 | mYOffsetLo = *(getData()+mDataOffset++); | ||
146 | mYOffsetHi = *(getData()+mDataOffset++); | ||
147 | mWidthLo = *(getData()+mDataOffset++); | ||
148 | mWidthHi = *(getData()+mDataOffset++); | ||
149 | mHeightLo = *(getData()+mDataOffset++); | ||
150 | mHeightHi = *(getData()+mDataOffset++); | ||
151 | mPixelSize = *(getData()+mDataOffset++); | ||
152 | flags = *(getData()+mDataOffset++); | ||
153 | mAttributeBits = flags & 0xf; | ||
154 | mOriginRightBit = (flags & 0x10) >> 4; | ||
155 | mOriginTopBit = (flags & 0x20) >> 5; | ||
156 | mInterleave = (flags & 0xc0) >> 6; | ||
157 | |||
158 | switch( mImageType ) | ||
159 | { | ||
160 | case 0: | ||
161 | // No image data included in file | ||
162 | setLastError("Unable to load file. TGA file contains no image data."); | ||
163 | return FALSE; | ||
164 | case 1: | ||
165 | // Colormapped uncompressed | ||
166 | if( 8 != mPixelSize ) | ||
167 | { | ||
168 | setLastError("Unable to load file. Colormapped images must have 8 bits per pixel."); | ||
169 | return FALSE; | ||
170 | } | ||
171 | break; | ||
172 | case 2: | ||
173 | // Truecolor uncompressed | ||
174 | break; | ||
175 | case 3: | ||
176 | // Monochrome uncompressed | ||
177 | if( 8 != mPixelSize ) | ||
178 | { | ||
179 | setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); | ||
180 | return FALSE; | ||
181 | } | ||
182 | break; | ||
183 | case 9: | ||
184 | // Colormapped, RLE | ||
185 | break; | ||
186 | case 10: | ||
187 | // Truecolor, RLE | ||
188 | break; | ||
189 | case 11: | ||
190 | // Monochrome, RLE | ||
191 | if( 8 != mPixelSize ) | ||
192 | { | ||
193 | setLastError("Unable to load file. Monochrome images must have 8 bits per pixel."); | ||
194 | return FALSE; | ||
195 | } | ||
196 | break; | ||
197 | default: | ||
198 | setLastError("Unable to load file. Unrecoginzed TGA image type."); | ||
199 | return FALSE; | ||
200 | } | ||
201 | |||
202 | // discard the ID field, if any | ||
203 | if (mIDLength) | ||
204 | { | ||
205 | memcpy(junk, getData()+mDataOffset, mIDLength); | ||
206 | mDataOffset += mIDLength; | ||
207 | } | ||
208 | |||
209 | // check to see if there's a colormap since even rgb files can have them | ||
210 | S32 color_map_bytes = 0; | ||
211 | if( (1 == mColorMapType) && (mColorMapDepth > 0) ) | ||
212 | { | ||
213 | mColorMapStart = (S32(mColorMapIndexHi) << 8) + mColorMapIndexLo; | ||
214 | mColorMapLength = (S32(mColorMapLengthHi) << 8) + mColorMapLengthLo; | ||
215 | |||
216 | if( mColorMapDepth > 24 ) | ||
217 | { | ||
218 | mColorMapBytesPerEntry = 4; | ||
219 | } | ||
220 | else | ||
221 | if( mColorMapDepth > 16 ) | ||
222 | { | ||
223 | mColorMapBytesPerEntry = 3; | ||
224 | } | ||
225 | else | ||
226 | if( mColorMapDepth > 8 ) | ||
227 | { | ||
228 | mColorMapBytesPerEntry = 2; | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | mColorMapBytesPerEntry = 1; | ||
233 | } | ||
234 | color_map_bytes = mColorMapLength * mColorMapBytesPerEntry; | ||
235 | |||
236 | // Note: although it's legal for TGA files to have color maps and not use them | ||
237 | // (some programs actually do this and use the color map for other ends), we'll | ||
238 | // only allocate memory for one if _we_ intend to use it. | ||
239 | if ( (1 == mImageType) || (9 == mImageType) ) | ||
240 | { | ||
241 | mColorMap = new U8[ color_map_bytes ]; | ||
242 | memcpy( mColorMap, getData() + mDataOffset, color_map_bytes ); | ||
243 | } | ||
244 | |||
245 | mDataOffset += color_map_bytes; | ||
246 | } | ||
247 | |||
248 | // heights are read as bytes to prevent endian problems | ||
249 | S32 height = (S32(mHeightHi) << 8) + mHeightLo; | ||
250 | S32 width = (S32(mWidthHi) << 8) + mWidthLo; | ||
251 | |||
252 | // make sure that it's a pixel format that we understand | ||
253 | S32 bits_per_pixel; | ||
254 | if( mColorMap ) | ||
255 | { | ||
256 | bits_per_pixel = mColorMapDepth; | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | bits_per_pixel = mPixelSize; | ||
261 | } | ||
262 | |||
263 | S32 components; | ||
264 | switch(bits_per_pixel) | ||
265 | { | ||
266 | case 24: | ||
267 | components = 3; | ||
268 | break; | ||
269 | case 32: | ||
270 | components = 4; | ||
271 | // Don't enforce this. ACDSee doesn't bother to set the attributes bits correctly. Arrgh! | ||
272 | // if( mAttributeBits != 8 ) | ||
273 | // { | ||
274 | // setLastError("Unable to load file. 32 bit TGA image does not have 8 bits of alpha."); | ||
275 | // return FALSE; | ||
276 | // } | ||
277 | mAttributeBits = 8; | ||
278 | break; | ||
279 | case 15: | ||
280 | case 16: | ||
281 | components = 3; | ||
282 | mIs15Bit = TRUE; // 16th bit is used for Targa hardware interupts and is ignored. | ||
283 | break; | ||
284 | case 8: | ||
285 | components = 1; | ||
286 | break; | ||
287 | default: | ||
288 | setLastError("Unable to load file. Unknown pixel size."); | ||
289 | return FALSE; | ||
290 | } | ||
291 | setSize(width, height, components); | ||
292 | |||
293 | return TRUE; | ||
294 | } | ||
295 | |||
296 | BOOL LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time) | ||
297 | { | ||
298 | llassert_always(raw_image); | ||
299 | |||
300 | // Check to make sure that this instance has been initialized with data | ||
301 | if (!getData() || (0 == getDataSize())) | ||
302 | { | ||
303 | setLastError("LLImageTGA trying to decode an image with no data!"); | ||
304 | return FALSE; | ||
305 | } | ||
306 | |||
307 | // Copy everything after the header. | ||
308 | |||
309 | raw_image->resize(getWidth(), getHeight(), getComponents()); | ||
310 | |||
311 | if( (getComponents() != 1) && | ||
312 | (getComponents() != 3) && | ||
313 | (getComponents() != 4) ) | ||
314 | { | ||
315 | setLastError("TGA images with a number of components other than 1, 3, and 4 are not supported."); | ||
316 | return FALSE; | ||
317 | } | ||
318 | |||
319 | |||
320 | if( mOriginRightBit ) | ||
321 | { | ||
322 | setLastError("TGA images with origin on right side are not supported."); | ||
323 | return FALSE; | ||
324 | } | ||
325 | |||
326 | BOOL flipped = (mOriginTopBit != 0); | ||
327 | BOOL rle_compressed = ((mImageType & 0x08) != 0); | ||
328 | |||
329 | if( mColorMap ) | ||
330 | { | ||
331 | return decodeColorMap( raw_image, rle_compressed, flipped ); | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | return decodeTruecolor( raw_image, rle_compressed, flipped ); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | BOOL LLImageTGA::decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped ) | ||
340 | { | ||
341 | BOOL success = FALSE; | ||
342 | BOOL alpha_opaque = FALSE; | ||
343 | if( rle ) | ||
344 | { | ||
345 | |||
346 | switch( getComponents() ) | ||
347 | { | ||
348 | case 1: | ||
349 | success = decodeTruecolorRle8( raw_image ); | ||
350 | break; | ||
351 | case 3: | ||
352 | if( mIs15Bit ) | ||
353 | { | ||
354 | success = decodeTruecolorRle15( raw_image ); | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | success = decodeTruecolorRle24( raw_image ); | ||
359 | } | ||
360 | break; | ||
361 | case 4: | ||
362 | success = decodeTruecolorRle32( raw_image, alpha_opaque ); | ||
363 | if (alpha_opaque) | ||
364 | { | ||
365 | // alpha was entirely opaque | ||
366 | // convert to 24 bit image | ||
367 | LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); | ||
368 | compacted_image->copy(raw_image); | ||
369 | raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); | ||
370 | raw_image->copy(compacted_image); | ||
371 | } | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | BOOL alpha_opaque; | ||
378 | success = decodeTruecolorNonRle( raw_image, alpha_opaque ); | ||
379 | if (alpha_opaque && raw_image->getComponents() == 4) | ||
380 | { | ||
381 | // alpha was entirely opaque | ||
382 | // convert to 24 bit image | ||
383 | LLPointer<LLImageRaw> compacted_image = new LLImageRaw(raw_image->getWidth(), raw_image->getHeight(), 3); | ||
384 | compacted_image->copy(raw_image); | ||
385 | raw_image->resize(raw_image->getWidth(), raw_image->getHeight(), 3); | ||
386 | raw_image->copy(compacted_image); | ||
387 | } | ||
388 | } | ||
389 | |||
390 | if( success && flipped ) | ||
391 | { | ||
392 | // This works because the Targa definition requires that RLE blocks never | ||
393 | // encode pixels from more than one scanline. | ||
394 | // (On the other hand, it's not as fast as writing separate flipped versions as | ||
395 | // we did with TruecolorNonRle.) | ||
396 | raw_image->verticalFlip(); | ||
397 | } | ||
398 | |||
399 | return success; | ||
400 | } | ||
401 | |||
402 | |||
403 | BOOL LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaque ) | ||
404 | { | ||
405 | alpha_opaque = TRUE; | ||
406 | |||
407 | // Origin is the bottom left | ||
408 | U8* dst = raw_image->getData(); | ||
409 | U8* src = getData() + mDataOffset; | ||
410 | S32 pixels = getWidth() * getHeight(); | ||
411 | |||
412 | if (getComponents() == 4) | ||
413 | { | ||
414 | while( pixels-- ) | ||
415 | { | ||
416 | // Our data is stored in RGBA. TGA stores them as BGRA (little-endian ARGB) | ||
417 | dst[0] = src[2]; // Red | ||
418 | dst[1] = src[1]; // Green | ||
419 | dst[2] = src[0]; // Blue | ||
420 | dst[3] = src[3]; // Alpha | ||
421 | if (dst[3] != 255) | ||
422 | { | ||
423 | alpha_opaque = FALSE; | ||
424 | } | ||
425 | dst += 4; | ||
426 | src += 4; | ||
427 | } | ||
428 | } | ||
429 | else if (getComponents() == 3) | ||
430 | { | ||
431 | if( mIs15Bit ) | ||
432 | { | ||
433 | while( pixels-- ) | ||
434 | { | ||
435 | decodeTruecolorPixel15( dst, src ); | ||
436 | dst += 3; | ||
437 | src += 2; | ||
438 | } | ||
439 | } | ||
440 | else | ||
441 | { | ||
442 | while( pixels-- ) | ||
443 | { | ||
444 | dst[0] = src[2]; // Red | ||
445 | dst[1] = src[1]; // Green | ||
446 | dst[2] = src[0]; // Blue | ||
447 | dst += 3; | ||
448 | src += 3; | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | else if (getComponents() == 1) | ||
453 | { | ||
454 | memcpy(dst, src, pixels); | ||
455 | } | ||
456 | |||
457 | return TRUE; | ||
458 | } | ||
459 | |||
460 | void LLImageTGA::decodeColorMapPixel8( U8* dst, const U8* src ) | ||
461 | { | ||
462 | S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); | ||
463 | dst[0] = mColorMap[ index ]; | ||
464 | } | ||
465 | |||
466 | void LLImageTGA::decodeColorMapPixel15( U8* dst, const U8* src ) | ||
467 | { | ||
468 | S32 index = llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); | ||
469 | decodeTruecolorPixel15( dst, mColorMap + 2 * index ); | ||
470 | } | ||
471 | |||
472 | void LLImageTGA::decodeColorMapPixel24( U8* dst, const U8* src ) | ||
473 | { | ||
474 | S32 index = 3 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); | ||
475 | dst[0] = mColorMap[ index + 2 ]; // Red | ||
476 | dst[1] = mColorMap[ index + 1 ]; // Green | ||
477 | dst[2] = mColorMap[ index + 0 ]; // Blue | ||
478 | } | ||
479 | |||
480 | void LLImageTGA::decodeColorMapPixel32( U8* dst, const U8* src ) | ||
481 | { | ||
482 | S32 index = 4 * llclamp( *src - mColorMapStart, 0, mColorMapLength - 1 ); | ||
483 | dst[0] = mColorMap[ index + 2 ]; // Red | ||
484 | dst[1] = mColorMap[ index + 1 ]; // Green | ||
485 | dst[2] = mColorMap[ index + 0 ]; // Blue | ||
486 | dst[3] = mColorMap[ index + 3 ]; // Alpha | ||
487 | } | ||
488 | |||
489 | |||
490 | BOOL LLImageTGA::decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped ) | ||
491 | { | ||
492 | // If flipped, origin is the top left. Need to reverse the order of the rows. | ||
493 | // Otherwise the origin is the bottom left. | ||
494 | |||
495 | if( 8 != mPixelSize ) | ||
496 | { | ||
497 | return FALSE; | ||
498 | } | ||
499 | |||
500 | U8* src = getData() + mDataOffset; | ||
501 | U8* dst = raw_image->getData(); // start from the top | ||
502 | |||
503 | void (LLImageTGA::*pixel_decoder)( U8*, const U8* ); | ||
504 | |||
505 | switch( mColorMapBytesPerEntry ) | ||
506 | { | ||
507 | case 1: pixel_decoder = &LLImageTGA::decodeColorMapPixel8; break; | ||
508 | case 2: pixel_decoder = &LLImageTGA::decodeColorMapPixel15; break; | ||
509 | case 3: pixel_decoder = &LLImageTGA::decodeColorMapPixel24; break; | ||
510 | case 4: pixel_decoder = &LLImageTGA::decodeColorMapPixel32; break; | ||
511 | default: llassert(0); return FALSE; | ||
512 | } | ||
513 | |||
514 | if( rle ) | ||
515 | { | ||
516 | U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); | ||
517 | while( dst <= last_dst ) | ||
518 | { | ||
519 | // Read RLE block header | ||
520 | U8 block_header_byte = *src; | ||
521 | src++; | ||
522 | |||
523 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
524 | if( block_header_byte & 0x80 ) | ||
525 | { | ||
526 | // Encoded (duplicate-pixel) block | ||
527 | do | ||
528 | { | ||
529 | (this->*pixel_decoder)( dst, src ); | ||
530 | dst += getComponents(); | ||
531 | block_pixel_count--; | ||
532 | } | ||
533 | while( block_pixel_count > 0 ); | ||
534 | src++; | ||
535 | } | ||
536 | else | ||
537 | { | ||
538 | // Unencoded block | ||
539 | do | ||
540 | { | ||
541 | (this->*pixel_decoder)( dst, src ); | ||
542 | dst += getComponents(); | ||
543 | src++; | ||
544 | block_pixel_count--; | ||
545 | } | ||
546 | while( block_pixel_count > 0 ); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | raw_image->verticalFlip(); | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | S32 src_row_bytes = getWidth(); | ||
555 | S32 dst_row_bytes = getWidth() * getComponents(); | ||
556 | |||
557 | if( flipped ) | ||
558 | { | ||
559 | U8* src_last_row_start = src + (getHeight() - 1) * src_row_bytes; | ||
560 | src = src_last_row_start; // start from the bottom | ||
561 | src_row_bytes *= -1; | ||
562 | } | ||
563 | |||
564 | |||
565 | S32 i; | ||
566 | S32 j; | ||
567 | |||
568 | for( S32 row = 0; row < getHeight(); row++ ) | ||
569 | { | ||
570 | for( i = 0, j = 0; j < getWidth(); i += getComponents(), j++ ) | ||
571 | { | ||
572 | (this->*pixel_decoder)( dst + i, src + j ); | ||
573 | } | ||
574 | |||
575 | dst += dst_row_bytes; | ||
576 | src += src_row_bytes; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | return TRUE; | ||
581 | } | ||
582 | |||
583 | |||
584 | |||
585 | BOOL LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time) | ||
586 | { | ||
587 | llassert_always(raw_image); | ||
588 | |||
589 | deleteData(); | ||
590 | |||
591 | setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); | ||
592 | |||
593 | // Data from header | ||
594 | mIDLength = 0; // Length of identifier string | ||
595 | mColorMapType = 0; // 0 = No Map | ||
596 | |||
597 | // Supported: 2 = Uncompressed true color, 3 = uncompressed monochrome without colormap | ||
598 | switch( getComponents() ) | ||
599 | { | ||
600 | case 1: | ||
601 | mImageType = 3; | ||
602 | break; | ||
603 | case 2: // Interpret as intensity plus alpha | ||
604 | case 3: | ||
605 | case 4: | ||
606 | mImageType = 2; | ||
607 | break; | ||
608 | default: | ||
609 | return FALSE; | ||
610 | } | ||
611 | |||
612 | // Color map stuff (unsupported) | ||
613 | mColorMapIndexLo = 0; // First color map entry (low order byte) | ||
614 | mColorMapIndexHi = 0; // First color map entry (high order byte) | ||
615 | mColorMapLengthLo = 0; // Color map length (low order byte) | ||
616 | mColorMapLengthHi = 0; // Color map length (high order byte) | ||
617 | mColorMapDepth = 0; // Size of color map entry (15, 16, 24, or 32 bits) | ||
618 | |||
619 | // Image offset relative to origin. | ||
620 | mXOffsetLo = 0; // X offset from origin (low order byte) | ||
621 | mXOffsetHi = 0; // X offset from origin (hi order byte) | ||
622 | mYOffsetLo = 0; // Y offset from origin (low order byte) | ||
623 | mYOffsetHi = 0; // Y offset from origin (hi order byte) | ||
624 | |||
625 | // Height and width | ||
626 | mWidthLo = U8(getWidth() & 0xFF); // Width (low order byte) | ||
627 | mWidthHi = U8((getWidth() >> 8) & 0xFF); // Width (hi order byte) | ||
628 | mHeightLo = U8(getHeight() & 0xFF); // Height (low order byte) | ||
629 | mHeightHi = U8((getHeight() >> 8) & 0xFF); // Height (hi order byte) | ||
630 | |||
631 | S32 bytes_per_pixel; | ||
632 | switch( getComponents() ) | ||
633 | { | ||
634 | case 1: | ||
635 | bytes_per_pixel = 1; | ||
636 | break; | ||
637 | case 3: | ||
638 | bytes_per_pixel = 3; | ||
639 | break; | ||
640 | case 2: // Interpret as intensity plus alpha. Store as RGBA. | ||
641 | case 4: | ||
642 | bytes_per_pixel = 4; | ||
643 | break; | ||
644 | default: | ||
645 | return FALSE; | ||
646 | } | ||
647 | mPixelSize = U8(bytes_per_pixel * 8); // 8, 16, 24, 32 bits per pixel | ||
648 | |||
649 | mAttributeBits = (4 == bytes_per_pixel) ? 8 : 0; // 4 bits: number of attribute bits (alpha) per pixel | ||
650 | mOriginRightBit = 0; // 1 bit: origin, 0 = left, 1 = right | ||
651 | mOriginTopBit = 0; // 1 bit: origin, 0 = bottom, 1 = top | ||
652 | mInterleave = 0; // 2 bits: interleaved flag, 0 = none, 1 = interleaved 2, 2 = interleaved 4 | ||
653 | |||
654 | |||
655 | const S32 TGA_HEADER_SIZE = 18; | ||
656 | const S32 COLOR_MAP_SIZE = 0; | ||
657 | mDataOffset = TGA_HEADER_SIZE + mIDLength + COLOR_MAP_SIZE; // Offset from start of data to the actual header. | ||
658 | |||
659 | S32 pixels = getWidth() * getHeight(); | ||
660 | S32 datasize = mDataOffset + bytes_per_pixel * pixels; | ||
661 | U8* dst = allocateData(datasize); | ||
662 | |||
663 | // Write header | ||
664 | *(dst++) = mIDLength; | ||
665 | *(dst++) = mColorMapType; | ||
666 | *(dst++) = mImageType; | ||
667 | *(dst++) = mColorMapIndexLo; | ||
668 | *(dst++) = mColorMapIndexHi; | ||
669 | *(dst++) = mColorMapLengthLo; | ||
670 | *(dst++) = mColorMapLengthHi; | ||
671 | *(dst++) = mColorMapDepth; | ||
672 | *(dst++) = mXOffsetLo; | ||
673 | *(dst++) = mXOffsetHi; | ||
674 | *(dst++) = mYOffsetLo; | ||
675 | *(dst++) = mYOffsetHi; | ||
676 | *(dst++) = mWidthLo; | ||
677 | *(dst++) = mWidthHi; | ||
678 | *(dst++) = mHeightLo; | ||
679 | *(dst++) = mHeightHi; | ||
680 | *(dst++) = mPixelSize; | ||
681 | *(dst++) = | ||
682 | ((mInterleave & 3) << 5) | | ||
683 | ((mOriginTopBit & 1) << 4) | | ||
684 | ((mOriginRightBit & 1) << 3) | | ||
685 | ((mAttributeBits & 0xF) << 0); | ||
686 | |||
687 | // Write pixels | ||
688 | const U8* src = raw_image->getData(); | ||
689 | llassert( dst == getData() + mDataOffset ); | ||
690 | S32 i = 0; | ||
691 | S32 j = 0; | ||
692 | switch( getComponents() ) | ||
693 | { | ||
694 | case 1: | ||
695 | memcpy( dst, src, bytes_per_pixel * pixels ); | ||
696 | break; | ||
697 | |||
698 | case 2: | ||
699 | while( pixels-- ) | ||
700 | { | ||
701 | dst[i + 0] = src[j + 0]; // intensity | ||
702 | dst[i + 1] = src[j + 0]; // intensity | ||
703 | dst[i + 2] = src[j + 0]; // intensity | ||
704 | dst[i + 3] = src[j + 1]; // alpha | ||
705 | i += 4; | ||
706 | j += 2; | ||
707 | } | ||
708 | break; | ||
709 | |||
710 | case 3: | ||
711 | while( pixels-- ) | ||
712 | { | ||
713 | dst[i + 0] = src[i + 2]; // blue | ||
714 | dst[i + 1] = src[i + 1]; // green | ||
715 | dst[i + 2] = src[i + 0]; // red | ||
716 | i += 3; | ||
717 | } | ||
718 | break; | ||
719 | |||
720 | case 4: | ||
721 | while( pixels-- ) | ||
722 | { | ||
723 | dst[i + 0] = src[i + 2]; // blue | ||
724 | dst[i + 1] = src[i + 1]; // green | ||
725 | dst[i + 2] = src[i + 0]; // red | ||
726 | dst[i + 3] = src[i + 3]; // alpha | ||
727 | i += 4; | ||
728 | } | ||
729 | break; | ||
730 | } | ||
731 | |||
732 | return TRUE; | ||
733 | } | ||
734 | |||
735 | BOOL LLImageTGA::decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque ) | ||
736 | { | ||
737 | llassert( getComponents() == 4 ); | ||
738 | alpha_opaque = TRUE; | ||
739 | |||
740 | U8* dst = raw_image->getData(); | ||
741 | U32* dst_pixels = (U32*) dst; | ||
742 | |||
743 | U8* src = getData() + mDataOffset; | ||
744 | |||
745 | U32 rgba; | ||
746 | U8* rgba_byte_p = (U8*) &rgba; | ||
747 | |||
748 | U32* last_dst_pixel = dst_pixels + getHeight() * getWidth() - 1; | ||
749 | while( dst_pixels <= last_dst_pixel ) | ||
750 | { | ||
751 | // Read RLE block header | ||
752 | U8 block_header_byte = *src; | ||
753 | src++; | ||
754 | |||
755 | U32 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
756 | if( block_header_byte & 0x80 ) | ||
757 | { | ||
758 | // Encoded (duplicate-pixel) block | ||
759 | rgba_byte_p[0] = src[2]; | ||
760 | rgba_byte_p[1] = src[1]; | ||
761 | rgba_byte_p[2] = src[0]; | ||
762 | rgba_byte_p[3] = src[3]; | ||
763 | if (rgba_byte_p[3] != 255) | ||
764 | { | ||
765 | alpha_opaque = FALSE; | ||
766 | } | ||
767 | |||
768 | src += 4; | ||
769 | register U32 value = rgba; | ||
770 | do | ||
771 | { | ||
772 | *dst_pixels = value; | ||
773 | dst_pixels++; | ||
774 | block_pixel_count--; | ||
775 | } | ||
776 | while( block_pixel_count > 0 ); | ||
777 | } | ||
778 | else | ||
779 | { | ||
780 | // Unencoded block | ||
781 | do | ||
782 | { | ||
783 | ((U8*)dst_pixels)[0] = src[2]; | ||
784 | ((U8*)dst_pixels)[1] = src[1]; | ||
785 | ((U8*)dst_pixels)[2] = src[0]; | ||
786 | ((U8*)dst_pixels)[3] = src[3]; | ||
787 | if (src[3] != 255) | ||
788 | { | ||
789 | alpha_opaque = FALSE; | ||
790 | } | ||
791 | src += 4; | ||
792 | dst_pixels++; | ||
793 | block_pixel_count--; | ||
794 | } | ||
795 | while( block_pixel_count > 0 ); | ||
796 | } | ||
797 | } | ||
798 | |||
799 | return TRUE; | ||
800 | } | ||
801 | |||
802 | BOOL LLImageTGA::decodeTruecolorRle15( LLImageRaw* raw_image ) | ||
803 | { | ||
804 | llassert( getComponents() == 3 ); | ||
805 | llassert( mIs15Bit ); | ||
806 | |||
807 | U8* dst = raw_image->getData(); | ||
808 | U8* src = getData() + mDataOffset; | ||
809 | |||
810 | U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); | ||
811 | while( dst <= last_dst ) | ||
812 | { | ||
813 | // Read RLE block header | ||
814 | U8 block_header_byte = *src; | ||
815 | src++; | ||
816 | |||
817 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
818 | if( block_header_byte & 0x80 ) | ||
819 | { | ||
820 | // Encoded (duplicate-pixel) block | ||
821 | do | ||
822 | { | ||
823 | decodeTruecolorPixel15( dst, src ); // slow | ||
824 | dst += 3; | ||
825 | block_pixel_count--; | ||
826 | } | ||
827 | while( block_pixel_count > 0 ); | ||
828 | src += 2; | ||
829 | } | ||
830 | else | ||
831 | { | ||
832 | // Unencoded block | ||
833 | do | ||
834 | { | ||
835 | decodeTruecolorPixel15( dst, src ); | ||
836 | dst += 3; | ||
837 | src += 2; | ||
838 | block_pixel_count--; | ||
839 | } | ||
840 | while( block_pixel_count > 0 ); | ||
841 | } | ||
842 | } | ||
843 | |||
844 | return TRUE; | ||
845 | } | ||
846 | |||
847 | |||
848 | |||
849 | BOOL LLImageTGA::decodeTruecolorRle24( LLImageRaw* raw_image ) | ||
850 | { | ||
851 | llassert( getComponents() == 3 ); | ||
852 | |||
853 | U8* dst = raw_image->getData(); | ||
854 | U8* src = getData() + mDataOffset; | ||
855 | |||
856 | U8* last_dst = dst + getComponents() * (getHeight() * getWidth() - 1); | ||
857 | while( dst <= last_dst ) | ||
858 | { | ||
859 | // Read RLE block header | ||
860 | U8 block_header_byte = *src; | ||
861 | src++; | ||
862 | |||
863 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
864 | if( block_header_byte & 0x80 ) | ||
865 | { | ||
866 | // Encoded (duplicate-pixel) block | ||
867 | do | ||
868 | { | ||
869 | dst[0] = src[2]; | ||
870 | dst[1] = src[1]; | ||
871 | dst[2] = src[0]; | ||
872 | dst += 3; | ||
873 | block_pixel_count--; | ||
874 | } | ||
875 | while( block_pixel_count > 0 ); | ||
876 | src += 3; | ||
877 | } | ||
878 | else | ||
879 | { | ||
880 | // Unencoded block | ||
881 | do | ||
882 | { | ||
883 | dst[0] = src[2]; | ||
884 | dst[1] = src[1]; | ||
885 | dst[2] = src[0]; | ||
886 | dst += 3; | ||
887 | src += 3; | ||
888 | block_pixel_count--; | ||
889 | } | ||
890 | while( block_pixel_count > 0 ); | ||
891 | } | ||
892 | } | ||
893 | |||
894 | return TRUE; | ||
895 | } | ||
896 | |||
897 | |||
898 | BOOL LLImageTGA::decodeTruecolorRle8( LLImageRaw* raw_image ) | ||
899 | { | ||
900 | llassert( getComponents() == 1 ); | ||
901 | |||
902 | U8* dst = raw_image->getData(); | ||
903 | U8* src = getData() + mDataOffset; | ||
904 | |||
905 | U8* last_dst = dst + getHeight() * getWidth() - 1; | ||
906 | while( dst <= last_dst ) | ||
907 | { | ||
908 | // Read RLE block header | ||
909 | U8 block_header_byte = *src; | ||
910 | src++; | ||
911 | |||
912 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
913 | if( block_header_byte & 0x80 ) | ||
914 | { | ||
915 | // Encoded (duplicate-pixel) block | ||
916 | memset( dst, *src, block_pixel_count ); | ||
917 | dst += block_pixel_count; | ||
918 | src++; | ||
919 | } | ||
920 | else | ||
921 | { | ||
922 | // Unencoded block | ||
923 | do | ||
924 | { | ||
925 | *dst = *src; | ||
926 | dst++; | ||
927 | src++; | ||
928 | block_pixel_count--; | ||
929 | } | ||
930 | while( block_pixel_count > 0 ); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | return TRUE; | ||
935 | } | ||
936 | |||
937 | |||
938 | // Decoded and process the image for use in avatar gradient masks. | ||
939 | // Processing happens during the decode for speed. | ||
940 | BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight ) | ||
941 | { | ||
942 | llassert_always(raw_image); | ||
943 | |||
944 | // "Domain" isn't really the right word. It refers to the width of the | ||
945 | // ramp portion of the function that relates input and output pixel values. | ||
946 | // A domain of 0 gives a step function. | ||
947 | // | ||
948 | // | /---------------- | ||
949 | // O| / | | ||
950 | // u| / | | ||
951 | // t| / | | ||
952 | // p|------------------/ | | ||
953 | // u| | | | ||
954 | // t|<---------------->|<-->| | ||
955 | // | "offset" "domain" | ||
956 | // | | ||
957 | // --+---Input-------------------------------- | ||
958 | // | | ||
959 | |||
960 | if (!getData() || (0 == getDataSize())) | ||
961 | { | ||
962 | setLastError("LLImageTGA trying to decode an image with no data!"); | ||
963 | return FALSE; | ||
964 | } | ||
965 | |||
966 | // Only works for unflipped monochrome RLE images | ||
967 | if( (getComponents() != 1) || (mImageType != 11) || mOriginTopBit || mOriginRightBit ) | ||
968 | { | ||
969 | llerrs << "LLImageTGA trying to alpha-gradient process an image that's not a standard RLE, one component image" << llendl; | ||
970 | return FALSE; | ||
971 | } | ||
972 | |||
973 | raw_image->resize(getWidth(), getHeight(), getComponents()); | ||
974 | |||
975 | U8* dst = raw_image->getData(); | ||
976 | U8* src = getData() + mDataOffset; | ||
977 | U8* last_dst = dst + getHeight() * getWidth() - 1; | ||
978 | |||
979 | if( domain > 0 ) | ||
980 | { | ||
981 | // Process using a look-up table (lut) | ||
982 | const S32 LUT_LEN = 256; | ||
983 | U8 lut[LUT_LEN]; | ||
984 | S32 i; | ||
985 | |||
986 | F32 scale = 1.f / domain; | ||
987 | F32 offset = (1.f - domain) * llclampf( 1.f - weight ); | ||
988 | F32 bias = -(scale * offset); | ||
989 | |||
990 | for( i = 0; i < LUT_LEN; i++ ) | ||
991 | { | ||
992 | lut[i] = (U8)llclampb( 255.f * ( i/255.f * scale + bias ) ); | ||
993 | } | ||
994 | |||
995 | while( dst <= last_dst ) | ||
996 | { | ||
997 | // Read RLE block header | ||
998 | U8 block_header_byte = *src; | ||
999 | src++; | ||
1000 | |||
1001 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
1002 | if( block_header_byte & 0x80 ) | ||
1003 | { | ||
1004 | // Encoded (duplicate-pixel) block | ||
1005 | memset( dst, lut[ *src ], block_pixel_count ); | ||
1006 | dst += block_pixel_count; | ||
1007 | src++; | ||
1008 | } | ||
1009 | else | ||
1010 | { | ||
1011 | // Unencoded block | ||
1012 | do | ||
1013 | { | ||
1014 | *dst = lut[ *src ]; | ||
1015 | dst++; | ||
1016 | src++; | ||
1017 | block_pixel_count--; | ||
1018 | } | ||
1019 | while( block_pixel_count > 0 ); | ||
1020 | } | ||
1021 | } | ||
1022 | } | ||
1023 | else | ||
1024 | { | ||
1025 | // Process using a simple comparison agains a threshold | ||
1026 | const U8 threshold = (U8)(0xFF * llclampf( 1.f - weight )); | ||
1027 | |||
1028 | while( dst <= last_dst ) | ||
1029 | { | ||
1030 | // Read RLE block header | ||
1031 | U8 block_header_byte = *src; | ||
1032 | src++; | ||
1033 | |||
1034 | U8 block_pixel_count = (block_header_byte & 0x7F) + 1; | ||
1035 | if( block_header_byte & 0x80 ) | ||
1036 | { | ||
1037 | // Encoded (duplicate-pixel) block | ||
1038 | memset( dst, ((*src >= threshold) ? 0xFF : 0), block_pixel_count ); | ||
1039 | dst += block_pixel_count; | ||
1040 | src++; | ||
1041 | } | ||
1042 | else | ||
1043 | { | ||
1044 | // Unencoded block | ||
1045 | do | ||
1046 | { | ||
1047 | *dst = (*src >= threshold) ? 0xFF : 0; | ||
1048 | dst++; | ||
1049 | src++; | ||
1050 | block_pixel_count--; | ||
1051 | } | ||
1052 | while( block_pixel_count > 0 ); | ||
1053 | } | ||
1054 | } | ||
1055 | } | ||
1056 | return TRUE; | ||
1057 | } | ||
1058 | |||
1059 | // Reads a .tga file and creates an LLImageTGA with its data. | ||
1060 | bool LLImageTGA::loadFile( const LLString& path ) | ||
1061 | { | ||
1062 | S32 len = path.size(); | ||
1063 | if( len < 5 ) | ||
1064 | { | ||
1065 | return false; | ||
1066 | } | ||
1067 | |||
1068 | LLString extension = path.substr( len - 4, 4 ); | ||
1069 | LLString::toLower(extension); | ||
1070 | if( ".tga" != extension ) | ||
1071 | { | ||
1072 | return false; | ||
1073 | } | ||
1074 | |||
1075 | FILE *file = LLFile::fopen(path.c_str(), "rb"); | ||
1076 | if( !file ) | ||
1077 | { | ||
1078 | llwarns << "Couldn't open file " << path << llendl; | ||
1079 | return false; | ||
1080 | } | ||
1081 | |||
1082 | S32 file_size = 0; | ||
1083 | if (!fseek(file, 0, SEEK_END)) | ||
1084 | { | ||
1085 | file_size = ftell(file); | ||
1086 | fseek(file, 0, SEEK_SET); | ||
1087 | } | ||
1088 | |||
1089 | U8* buffer = allocateData(file_size); | ||
1090 | S32 bytes_read = fread(buffer, 1, file_size, file); | ||
1091 | if( bytes_read != file_size ) | ||
1092 | { | ||
1093 | deleteData(); | ||
1094 | llwarns << "Couldn't read file " << path << llendl; | ||
1095 | return false; | ||
1096 | } | ||
1097 | |||
1098 | fclose( file ); | ||
1099 | |||
1100 | if( !updateData() ) | ||
1101 | { | ||
1102 | llwarns << "Couldn't decode file " << path << llendl; | ||
1103 | deleteData(); | ||
1104 | return false; | ||
1105 | } | ||
1106 | return true; | ||
1107 | } | ||
1108 | |||
1109 | |||
diff --git a/linden/indra/llimage/llimagetga.h b/linden/indra/llimage/llimagetga.h new file mode 100644 index 0000000..9575b4d --- /dev/null +++ b/linden/indra/llimage/llimagetga.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /** | ||
2 | * @file llimagetga.h | ||
3 | * @brief Image implementation to compresses and decompressed TGA files. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLIMAGETGA_H | ||
29 | #define LL_LLIMAGETGA_H | ||
30 | |||
31 | #include "llimage.h" | ||
32 | |||
33 | // This class compresses and decompressed TGA (targa) files | ||
34 | |||
35 | class LLImageTGA : public LLImageFormatted | ||
36 | { | ||
37 | protected: | ||
38 | virtual ~LLImageTGA(); | ||
39 | |||
40 | public: | ||
41 | LLImageTGA(); | ||
42 | LLImageTGA(const LLString& file_name); | ||
43 | |||
44 | /*virtual*/ BOOL updateData(); | ||
45 | /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0); | ||
46 | /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0); | ||
47 | |||
48 | BOOL decodeAndProcess(LLImageRaw* raw_image, F32 domain, F32 weight); | ||
49 | |||
50 | private: | ||
51 | BOOL decodeTruecolor( LLImageRaw* raw_image, BOOL rle, BOOL flipped ); | ||
52 | |||
53 | BOOL decodeTruecolorRle8( LLImageRaw* raw_image ); | ||
54 | BOOL decodeTruecolorRle15( LLImageRaw* raw_image ); | ||
55 | BOOL decodeTruecolorRle24( LLImageRaw* raw_image ); | ||
56 | BOOL decodeTruecolorRle32( LLImageRaw* raw_image, BOOL &alpha_opaque ); | ||
57 | |||
58 | void decodeTruecolorPixel15( U8* dst, const U8* src ); | ||
59 | |||
60 | BOOL decodeTruecolorNonRle( LLImageRaw* raw_image, BOOL &alpha_opaque ); | ||
61 | |||
62 | BOOL decodeColorMap( LLImageRaw* raw_image, BOOL rle, BOOL flipped ); | ||
63 | |||
64 | void decodeColorMapPixel8(U8* dst, const U8* src); | ||
65 | void decodeColorMapPixel15(U8* dst, const U8* src); | ||
66 | void decodeColorMapPixel24(U8* dst, const U8* src); | ||
67 | void decodeColorMapPixel32(U8* dst, const U8* src); | ||
68 | |||
69 | bool loadFile(const LLString& file_name); | ||
70 | |||
71 | private: | ||
72 | // Class specific data | ||
73 | U32 mDataOffset; // Offset from start of data to the actual header. | ||
74 | |||
75 | // Data from header | ||
76 | U8 mIDLength; // Length of identifier string | ||
77 | U8 mColorMapType; // 0 = No Map | ||
78 | U8 mImageType; // Supported: 2 = Uncompressed true color, 3 = uncompressed monochrome without colormap | ||
79 | U8 mColorMapIndexLo; // First color map entry (low order byte) | ||
80 | U8 mColorMapIndexHi; // First color map entry (high order byte) | ||
81 | U8 mColorMapLengthLo; // Color map length (low order byte) | ||
82 | U8 mColorMapLengthHi; // Color map length (high order byte) | ||
83 | U8 mColorMapDepth; // Size of color map entry (15, 16, 24, or 32 bits) | ||
84 | U8 mXOffsetLo; // X offset of image (low order byte) | ||
85 | U8 mXOffsetHi; // X offset of image (hi order byte) | ||
86 | U8 mYOffsetLo; // Y offset of image (low order byte) | ||
87 | U8 mYOffsetHi; // Y offset of image (hi order byte) | ||
88 | U8 mWidthLo; // Width (low order byte) | ||
89 | U8 mWidthHi; // Width (hi order byte) | ||
90 | U8 mHeightLo; // Height (low order byte) | ||
91 | U8 mHeightHi; // Height (hi order byte) | ||
92 | U8 mPixelSize; // 8, 16, 24, 32 bits per pixel | ||
93 | U8 mAttributeBits; // 4 bits: number of attributes per pixel | ||
94 | U8 mOriginRightBit; // 1 bit: origin, 0 = left, 1 = right | ||
95 | U8 mOriginTopBit; // 1 bit: origin, 0 = bottom, 1 = top | ||
96 | U8 mInterleave; // 2 bits: interleaved flag, 0 = none, 1 = interleaved 2, 2 = interleaved 4 | ||
97 | |||
98 | U8* mColorMap; | ||
99 | S32 mColorMapStart; | ||
100 | S32 mColorMapLength; | ||
101 | S32 mColorMapBytesPerEntry; | ||
102 | |||
103 | BOOL mIs15Bit; | ||
104 | |||
105 | static const U8 s5to8bits[32]; | ||
106 | }; | ||
107 | |||
108 | #endif | ||
diff --git a/linden/indra/llimage/llmapimagetype.h b/linden/indra/llimage/llmapimagetype.h new file mode 100644 index 0000000..1f83b71 --- /dev/null +++ b/linden/indra/llimage/llmapimagetype.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /** | ||
2 | * @file llmapimagetype.h | ||
3 | * | ||
4 | * Copyright (c) 2003-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 | #ifndef LL_LLMAPIMAGETYPE_H | ||
28 | #define LL_LLMAPIMAGETYPE_H | ||
29 | |||
30 | typedef enum e_map_image_type | ||
31 | { | ||
32 | MIT_TERRAIN = 0, | ||
33 | MIT_POPULAR = 1, | ||
34 | MIT_OBJECTS = 2, | ||
35 | MIT_OBJECTS_FOR_SALE = 3, | ||
36 | MIT_LAND_TO_BUY = 4, | ||
37 | MIT_OBJECT_NEW = 5, | ||
38 | MIT_EOF = 6 | ||
39 | } EMapImageType; | ||
40 | |||
41 | #endif | ||