-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathcolorconversion.cpp
More file actions
2495 lines (2227 loc) · 71 KB
/
colorconversion.cpp
File metadata and controls
2495 lines (2227 loc) · 71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//======= Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//=============================================================================//
#ifdef IS_WINDOWS_PC
#include <windows.h>
#endif
#include "bitmap/imageformat.h"
#include "basetypes.h"
#include "tier0/dbg.h"
#ifndef _PS3
#include <malloc.h>
#include <memory.h>
#endif
#include "mathlib/mathlib.h"
#include "mathlib/vector.h"
#include "tier1/utlmemory.h"
#include "tier1/strtools.h"
#include "mathlib/compressed_vector.h"
#include "nvtc.h"
#if defined( POSIX ) && !defined( _PS3 )
typedef int32 *DWORD_PTR;
#endif
#include "bitmap/floatbitmap.h"
#define STB_DXT_IMPLEMENTATION
#include "bitmap/stb_dxt.h"
// Should be last include
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Various important function types for each color format
//-----------------------------------------------------------------------------
typedef void (*UserFormatToRGBA8888Func_t )( const uint8 *src, uint8 *dst, int numPixels );
typedef void (*RGBA8888ToUserFormatFunc_t )( const uint8 *src, uint8 *dst, int numPixels );
namespace ImageLoader
{
// Color Conversion functions
static void RGBA8888ToRGBA32323232F( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGB323232F( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRG3232F( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToR32F( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToABGR8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGB888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGR888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGB565( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToI8( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToIA88( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToP8( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToA8( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGB888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGR888_BLUESCREEN( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToARGB8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGRA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGRX8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGR565( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGRX5551( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGRA5551( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToBGRA4444( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToUV88( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToUVWQ8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToUVLX8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA8888ToRGBA16161616F( const uint8 *src, uint8 *dst, int numPixels );
static void ABGR8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGB888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGR888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGB565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void I8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void IA88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void P8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void A8ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGB888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGR888_BLUESCREENToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void ARGB8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGRA8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGRX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGR565ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGRX5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGRA5551ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void BGRA4444ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void UV88ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void UVWQ8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void UVLX8888ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static void RGBA16161616ToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
//static void RGBA16161616FToRGBA8888( const uint8 *src, uint8 *dst, int numPixels );
static UserFormatToRGBA8888Func_t GetUserFormatToRGBA8888Func_t( ImageFormat srcImageFormat )
{
switch( srcImageFormat )
{
case IMAGE_FORMAT_RGBA8888:
return RGBA8888ToRGBA8888;
case IMAGE_FORMAT_ABGR8888:
return ABGR8888ToRGBA8888;
case IMAGE_FORMAT_RGB888:
return RGB888ToRGBA8888;
case IMAGE_FORMAT_BGR888:
return BGR888ToRGBA8888;
case IMAGE_FORMAT_RGB565:
return NULL;
case IMAGE_FORMAT_I8:
return I8ToRGBA8888;
case IMAGE_FORMAT_IA88:
return IA88ToRGBA8888;
case IMAGE_FORMAT_A8:
return A8ToRGBA8888;
case IMAGE_FORMAT_RGB888_BLUESCREEN:
return RGB888_BLUESCREENToRGBA8888;
case IMAGE_FORMAT_BGR888_BLUESCREEN:
return BGR888_BLUESCREENToRGBA8888;
case IMAGE_FORMAT_ARGB8888:
return ARGB8888ToRGBA8888;
case IMAGE_FORMAT_BGRA8888:
return BGRA8888ToRGBA8888;
case IMAGE_FORMAT_BGRX8888:
return BGRX8888ToRGBA8888;
case IMAGE_FORMAT_BGR565:
return BGR565ToRGBA8888;
case IMAGE_FORMAT_BGRX5551:
return BGRX5551ToRGBA8888;
case IMAGE_FORMAT_BGRA5551:
return BGRA5551ToRGBA8888;
case IMAGE_FORMAT_BGRA4444:
return BGRA4444ToRGBA8888;
case IMAGE_FORMAT_UV88:
return UV88ToRGBA8888;
case IMAGE_FORMAT_UVWQ8888:
return UVWQ8888ToRGBA8888;
case IMAGE_FORMAT_UVLX8888:
return UVLX8888ToRGBA8888;
case IMAGE_FORMAT_RGBA16161616:
return RGBA16161616ToRGBA8888;
case IMAGE_FORMAT_RGBA16161616F:
return NULL;
case IMAGE_FORMAT_RGBA1010102:
return NULL;
case IMAGE_FORMAT_BGRA1010102:
return NULL;
case IMAGE_FORMAT_R16F:
return NULL;
#if defined( _X360 )
case IMAGE_FORMAT_LINEAR_RGBA8888:
return RGBA8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_ABGR8888:
return ABGR8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_RGB888:
return RGB888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_BGR888:
return BGR888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_I8:
return I8ToRGBA8888;
case IMAGE_FORMAT_LINEAR_ARGB8888:
return ARGB8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_BGRA8888:
return BGRA8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_BGRX8888:
return BGRX8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_BGRX5551:
return BGRX5551ToRGBA8888;
case IMAGE_FORMAT_LINEAR_RGBA16161616:
return RGBA16161616ToRGBA8888;
case IMAGE_FORMAT_LINEAR_A8:
return A8ToRGBA8888;
#endif
default:
return NULL;
}
}
static RGBA8888ToUserFormatFunc_t GetRGBA8888ToUserFormatFunc_t( ImageFormat dstImageFormat )
{
switch( dstImageFormat )
{
case IMAGE_FORMAT_RGBA32323232F:
return RGBA8888ToRGBA32323232F;
case IMAGE_FORMAT_RGB323232F:
return RGBA8888ToRGB323232F;
case IMAGE_FORMAT_RG3232F:
return RGBA8888ToRG3232F;
case IMAGE_FORMAT_R32F:
return RGBA8888ToR32F;
case IMAGE_FORMAT_RGBA8888:
return RGBA8888ToRGBA8888;
case IMAGE_FORMAT_ABGR8888:
return RGBA8888ToABGR8888;
case IMAGE_FORMAT_RGB888:
return RGBA8888ToRGB888;
case IMAGE_FORMAT_BGR888:
return RGBA8888ToBGR888;
case IMAGE_FORMAT_RGB565:
return NULL;
case IMAGE_FORMAT_I8:
return RGBA8888ToI8;
case IMAGE_FORMAT_IA88:
return RGBA8888ToIA88;
case IMAGE_FORMAT_A8:
return RGBA8888ToA8;
case IMAGE_FORMAT_RGB888_BLUESCREEN:
return RGBA8888ToRGB888_BLUESCREEN;
case IMAGE_FORMAT_BGR888_BLUESCREEN:
return RGBA8888ToBGR888_BLUESCREEN;
case IMAGE_FORMAT_ARGB8888:
return RGBA8888ToARGB8888;
case IMAGE_FORMAT_BGRA8888:
return RGBA8888ToBGRA8888;
case IMAGE_FORMAT_BGRX8888:
return RGBA8888ToBGRX8888;
case IMAGE_FORMAT_BGR565:
return RGBA8888ToBGR565;
case IMAGE_FORMAT_BGRX5551:
return RGBA8888ToBGRX5551;
case IMAGE_FORMAT_BGRA5551:
return RGBA8888ToBGRA5551;
case IMAGE_FORMAT_BGRA4444:
return RGBA8888ToBGRA4444;
case IMAGE_FORMAT_UV88:
return RGBA8888ToUV88;
case IMAGE_FORMAT_UVWQ8888:
return RGBA8888ToUVWQ8888;
case IMAGE_FORMAT_UVLX8888:
return RGBA8888ToUVLX8888;
case IMAGE_FORMAT_RGBA16161616F:
return RGBA8888ToRGBA16161616F;
#if defined( _X360 )
case IMAGE_FORMAT_LINEAR_RGBA8888:
return RGBA8888ToRGBA8888;
case IMAGE_FORMAT_LINEAR_ABGR8888:
return RGBA8888ToABGR8888;
case IMAGE_FORMAT_LINEAR_RGB888:
return RGBA8888ToRGB888;
case IMAGE_FORMAT_LINEAR_BGR888:
return RGBA8888ToBGR888;
case IMAGE_FORMAT_LINEAR_I8:
return RGBA8888ToI8;
case IMAGE_FORMAT_LINEAR_ARGB8888:
return RGBA8888ToARGB8888;
case IMAGE_FORMAT_LINEAR_BGRA8888:
return RGBA8888ToBGRA8888;
case IMAGE_FORMAT_LINEAR_BGRX8888:
return RGBA8888ToBGRX8888;
case IMAGE_FORMAT_LINEAR_BGRX5551:
return RGBA8888ToBGRX5551;
case IMAGE_FORMAT_LINEAR_A8:
return RGBA8888ToA8;
#endif
default:
return NULL;
}
}
#pragma pack(1)
struct DXTColBlock
{
uint16 col0;
uint16 col1;
// no bit fields - use bytes
uint8 row[4];
};
struct DXTAlphaBlock3BitLinear
{
uint8 alpha0;
uint8 alpha1;
uint8 stuff[6];
};
#pragma pack()
/*
static unsigned int RescaleBitNumber( unsigned int nSrcValue, unsigned int nSrcBits, unsigned int nScaleToBits )
{
unsigned int nMaxSrc = ( 1 << nSrcBits ) - 1;
float flValue = float( nSrcValue & nMaxSrc ) / float( nMaxSrc );
unsigned int nMaxDest = ( 1 << nScaleToBits ) - 1;
return ( unsigned int ) ( flValue * nMaxDest );
}
-- produces same results as bit-propagation below
*/
static unsigned int RescaleBitNumber( unsigned int nSrcValue, unsigned int nSrcBits, unsigned int nScaleToBits )
{
unsigned int nMaxSrc = ( 1 << nSrcBits ) - 1;
if ( nScaleToBits > nSrcBits )
{
return
( nSrcValue & nMaxSrc ) << ( nScaleToBits - nSrcBits ) |
( nSrcValue & nMaxSrc ) >> ( nSrcBits - ( nScaleToBits - nSrcBits ) );
}
else
{
return ( nSrcValue & nMaxSrc ) >> ( nSrcBits - nScaleToBits );
}
}
static inline void GetColorBlockColorsBGRA8888( DXTColBlock *pBlock, BGRA8888_t *col_0,
BGRA8888_t *col_1, BGRA8888_t *col_2,
BGRA8888_t *col_3, uint16 & wrd )
{
// input data is assumed to be x86 order
// swap to target platform for proper dxt decoding
uint16 color0 = LittleShort( pBlock->col0 );
uint16 color1 = LittleShort( pBlock->col1 );
// shift to full precision
col_0->a = 0xff;
col_0->r = RescaleBitNumber( ((BGR565_t*)&color0)->r, 5, 8 );
col_0->g = RescaleBitNumber( ((BGR565_t*)&color0)->g, 6, 8 );
col_0->b = RescaleBitNumber( ((BGR565_t*)&color0)->b, 5, 8 );
col_1->a = 0xff;
col_1->r = RescaleBitNumber( ((BGR565_t*)&color1)->r, 5, 8 );
col_1->g = RescaleBitNumber( ((BGR565_t*)&color1)->g, 6, 8 );
col_1->b = RescaleBitNumber( ((BGR565_t*)&color1)->b, 5, 8 );
if ( color0 > color1 )
{
// Four-color block: derive the other two colors.
// 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
wrd = ((uint16)col_0->r * 2 + (uint16)col_1->r )/3;
// no +1 for rounding
// as bits have been shifted to 888
col_2->r = (BYTE)wrd;
wrd = ((uint16)col_0->g * 2 + (uint16)col_1->g )/3;
col_2->g = (BYTE)wrd;
wrd = ((uint16)col_0->b * 2 + (uint16)col_1->b )/3;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
wrd = ((uint16)col_0->r + (uint16)col_1->r *2 )/3;
col_3->r = (BYTE)wrd;
wrd = ((uint16)col_0->g + (uint16)col_1->g *2 )/3;
col_3->g = (BYTE)wrd;
wrd = ((uint16)col_0->b + (uint16)col_1->b *2 )/3;
col_3->b = (BYTE)wrd;
col_3->a = 0xff;
}
else
{
// Three-color block: derive the other color.
// 00 = color_0, 01 = color_1, 10 = color_2,
// 11 = transparent.
// These two bit codes correspond to the 2-bit fields
// stored in the 64-bit block.
// explicit for each component, unlike some refrasts...????
wrd = ((uint16)col_0->r + (uint16)col_1->r )/2;
col_2->r = (BYTE)wrd;
wrd = ((uint16)col_0->g + (uint16)col_1->g )/2;
col_2->g = (BYTE)wrd;
wrd = ((uint16)col_0->b + (uint16)col_1->b )/2;
col_2->b = (BYTE)wrd;
col_2->a = 0xff;
col_3->r = 0x00; // random color to indicate alpha
col_3->g = 0xff;
col_3->b = 0xff;
col_3->a = 0x00;
}
}
template <class CDestPixel>
static inline void DecodeColorBlock( CDestPixel *pOutputImage, DXTColBlock *pColorBlock, int width,
BGRA8888_t *col_0, BGRA8888_t *col_1,
BGRA8888_t *col_2, BGRA8888_t *col_3 )
{
// width is width of image in pixels
uint32 bits;
int r,n;
// bit masks = 00000011, 00001100, 00110000, 11000000
const uint32 masks[] = { 3 << 0, 3 << 2, 3 << 4, 3 << 6 };
const int shift[] = { 0, 2, 4, 6 };
// r steps through lines in y
for ( r=0; r < 4; r++, pOutputImage += width-4 ) // no width*4 as uint32 ptr inc will *4
{
// width * 4 bytes per pixel per line
// each j dxtc row is 4 lines of pixels
// n steps through pixels
for ( n=0; n < 4; n++ )
{
bits = pColorBlock->row[r] & masks[n];
bits >>= shift[n];
switch( bits )
{
case 0:
*pOutputImage = *col_0;
pOutputImage++; // increment to next output pixel
break;
case 1:
*pOutputImage = *col_1;
pOutputImage++;
break;
case 2:
*pOutputImage = *col_2;
pOutputImage++;
break;
case 3:
*pOutputImage = *col_3;
pOutputImage++;
break;
default:
Assert( 0 );
pOutputImage++;
break;
}
}
}
}
template <class CDestPixel>
static inline void DecodeAlpha3BitLinear( CDestPixel *pImPos, DXTAlphaBlock3BitLinear *pAlphaBlock, int width, int nChannelSelect = 3 )
{
static BYTE gBits[4][4];
static uint16 gAlphas[8];
static BGRA8888_t gACol[4][4];
gAlphas[0] = pAlphaBlock->alpha0;
gAlphas[1] = pAlphaBlock->alpha1;
// 8-alpha or 6-alpha block?
if( gAlphas[0] > gAlphas[1] )
{
// 8-alpha block: derive the other 6 alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = ( 6 * gAlphas[0] + gAlphas[1]) / 7; // bit code 010
gAlphas[3] = ( 5 * gAlphas[0] + 2 * gAlphas[1]) / 7; // Bit code 011
gAlphas[4] = ( 4 * gAlphas[0] + 3 * gAlphas[1]) / 7; // Bit code 100
gAlphas[5] = ( 3 * gAlphas[0] + 4 * gAlphas[1]) / 7; // Bit code 101
gAlphas[6] = ( 2 * gAlphas[0] + 5 * gAlphas[1]) / 7; // Bit code 110
gAlphas[7] = ( gAlphas[0] + 6 * gAlphas[1]) / 7; // Bit code 111
}
else
{
// 6-alpha block: derive the other alphas.
// 000 = alpha_0, 001 = alpha_1, others are interpolated
gAlphas[2] = (4 * gAlphas[0] + gAlphas[1]) / 5; // Bit code 010
gAlphas[3] = (3 * gAlphas[0] + 2 * gAlphas[1]) / 5; // Bit code 011
gAlphas[4] = (2 * gAlphas[0] + 3 * gAlphas[1]) / 5; // Bit code 100
gAlphas[5] = ( gAlphas[0] + 4 * gAlphas[1]) / 5; // Bit code 101
gAlphas[6] = 0; // Bit code 110
gAlphas[7] = 255; // Bit code 111
}
// Decode 3-bit fields into array of 16 BYTES with same value
// first two rows of 4 pixels each:
// pRows = (Alpha3BitRows*) & ( pAlphaBlock->stuff[0] );
const uint32 mask = 0x00000007; // bits = 00 00 01 11
uint32 bits = *( (uint32*) & ( pAlphaBlock->stuff[0] ));
gBits[0][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[0][3] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[1][3] = (BYTE)( bits & mask );
// now for last two rows:
bits = *( (uint32*) & ( pAlphaBlock->stuff[3] )); // last 3 bytes
gBits[2][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[2][3] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][0] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][1] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][2] = (BYTE)( bits & mask );
bits >>= 3;
gBits[3][3] = (BYTE)( bits & mask );
// decode the codes into alpha values
int row, pix;
for ( row = 0; row < 4; row++ )
{
for ( pix=0; pix < 4; pix++ )
{
gACol[row][pix].a = (BYTE) gAlphas[ gBits[row][pix] ];
Assert( gACol[row][pix].r == 0 );
Assert( gACol[row][pix].g == 0 );
Assert( gACol[row][pix].b == 0 );
}
}
// Write out alpha values to the image bits
for ( row=0; row < 4; row++, pImPos += width-4 )
{
for ( pix = 0; pix < 4; pix++ )
{
// zero the alpha bits of image pixel
switch ( nChannelSelect )
{
case 0:
pImPos->r = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a;
pImPos->g = 0; // Danger...stepping on the other color channels
pImPos->b = 0;
pImPos->a = 0;
break;
case 1:
pImPos->g = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a;
break;
case 2:
pImPos->b = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a;
break;
default:
case 3:
pImPos->a = ( *(( BGRA8888_t *) &(gACol[row][pix])) ).a;
break;
}
pImPos++;
}
}
}
template <class CDestPixel>
static void ConvertFromDXT1( const uint8 *src, CDestPixel *dst, int width, int height )
{
Assert( sizeof( BGRA8888_t ) == 4 );
Assert( sizeof( RGBA8888_t ) == 4 );
Assert( sizeof( RGB888_t ) == 3 );
Assert( sizeof( BGR888_t ) == 3 );
Assert( sizeof( BGR565_t ) == 2 );
Assert( sizeof( BGRA5551_t ) == 2 );
Assert( sizeof( BGRA4444_t ) == 2 );
int realWidth = 0;
int realHeight = 0;
CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 )
{
realWidth = width;
realHeight = height;
// round up to the nearest four
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
realDst = dst;
dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) );
Assert( dst );
}
Assert( !( width % 4 ) );
Assert( !( height % 4 ) );
int xblocks, yblocks;
xblocks = width >> 2;
yblocks = height >> 2;
CDestPixel *pDstScan = dst;
uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock;
BGRA8888_t col_0, col_1, col_2, col_3;
uint16 wrdDummy;
int i, j;
for ( j = 0; j < yblocks; j++ )
{
// 8 bytes per block
pBlock = ( DXTColBlock * )( ( uint8 * )pSrcScan + j * xblocks * 8 );
for ( i=0; i < xblocks; i++, pBlock++ )
{
GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrdDummy );
// now decode the color block into the bitmap bits
// inline func:
pDstScan = dst + i*4 + j*4*width;
DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 );
}
}
// Deal with the case where we have a dimension smaller than 4.
if ( realDst )
{
int x, y;
for ( y = 0; y < realHeight; y++ )
{
for ( x = 0; x < realWidth; x++ )
{
realDst[x+(y*realWidth)] = dst[x+(y*width)];
}
}
}
}
template <class CDestPixel>
static void ConvertFromDXT5( const uint8 *src, CDestPixel *dst, int width, int height )
{
int realWidth = 0;
int realHeight = 0;
CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 )
{
realWidth = width;
realHeight = height;
// round up to the nearest four
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
realDst = dst;
dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) );
Assert( dst );
}
Assert( !( width % 4 ) );
Assert( !( height % 4 ) );
int xblocks, yblocks;
xblocks = width >> 2;
yblocks = height >> 2;
CDestPixel *pDstScan = dst;
uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock;
DXTAlphaBlock3BitLinear *pAlphaBlock;
BGRA8888_t col_0, col_1, col_2, col_3;
uint16 wrd;
int i,j;
for ( j=0; j < yblocks; j++ )
{
// 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (uint8 *)pSrcScan + j * xblocks * 16 );
for ( i=0; i < xblocks; i++, pBlock ++ )
{
// inline
// Get alpha block
pAlphaBlock = (DXTAlphaBlock3BitLinear*) pBlock;
// inline func:
// Get color block & colors
pBlock++;
GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
pDstScan = dst + i*4 + j*4*width;
// Decode the color block into the bitmap bits
// inline func:
DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 );
// Overwrite the previous alpha bits with the alpha block
// info
DecodeAlpha3BitLinear( pDstScan, pAlphaBlock, width );
}
}
// Deal with the case where we have a dimension smaller than 4.
if ( realDst )
{
int x, y;
for( y = 0; y < realHeight; y++ )
{
for( x = 0; x < realWidth; x++ )
{
realDst[x+(y*realWidth)] = dst[x+(y*width)];
}
}
}
}
template <class CDestPixel>
static void ConvertFromDXT5IgnoreAlpha( const uint8 *src, CDestPixel *dst, int width, int height )
{
int realWidth = 0;
int realHeight = 0;
CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 )
{
realWidth = width;
realHeight = height;
// round up to the nearest four
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
realDst = dst;
dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) );
Assert( dst );
}
Assert( !( width % 4 ) );
Assert( !( height % 4 ) );
int xblocks, yblocks;
xblocks = width >> 2;
yblocks = height >> 2;
CDestPixel *pDstScan = dst;
uint32 *pSrcScan = ( uint32 * )src;
DXTColBlock *pBlock;
BGRA8888_t col_0, col_1, col_2, col_3;
uint16 wrd;
int i,j;
for ( j=0; j < yblocks; j++ )
{
// 8 bytes per block
// 1 block for alpha, 1 block for color
pBlock = (DXTColBlock*) ( (uint8 *)pSrcScan + j * xblocks * 16 );
for( i=0; i < xblocks; i++, pBlock ++ )
{
// inline func:
// Get color block & colors
pBlock++;
GetColorBlockColorsBGRA8888( pBlock, &col_0, &col_1, &col_2, &col_3, wrd );
pDstScan = dst + i*4 + j*4*width;
// Decode the color block into the bitmap bits
// inline func:
DecodeColorBlock<CDestPixel>( pDstScan, pBlock, width, &col_0, &col_1, &col_2, &col_3 );
}
}
// Deal with the case where we have a dimension smaller than 4.
if( realDst )
{
int x, y;
for( y = 0; y < realHeight; y++ )
{
for( x = 0; x < realWidth; x++ )
{
realDst[x+(y*realWidth)] = dst[x+(y*width)];
}
}
}
}
template <class CDestPixel>
static void ConvertFromATIxN( const uint8 *src, CDestPixel *dst, int width, int height, bool bATI2N )
{
int realWidth = 0;
int realHeight = 0;
CDestPixel *realDst = NULL;
// Deal with the case where we have a dimension smaller than 4.
if ( width < 4 || height < 4 )
{
realWidth = width;
realHeight = height;
// round up to the nearest four
width = ( width + 3 ) & ~3;
height = ( height + 3 ) & ~3;
realDst = dst;
dst = ( CDestPixel * )stackalloc( width * height * sizeof( CDestPixel ) );
Assert( dst );
}
Assert( !( width % 4 ) );
Assert( !( height % 4 ) );
int xblocks, yblocks;
xblocks = width >> 2;
yblocks = height >> 2;
CDestPixel *pDstScan = dst;
uint32 *pSrcScan = ( uint32 * )src;
DXTAlphaBlock3BitLinear *pBlock;
int nBytesPerBlock = bATI2N ? 16 : 8;
int i,j;
for ( j=0; j < yblocks; j++ )
{
// 8 bytes per block
// 1 block for x, 1 block for y
pBlock = (DXTAlphaBlock3BitLinear*) ( (uint8 *)pSrcScan + j * xblocks * nBytesPerBlock );
for ( i=0; i < xblocks; i++, pBlock++ )
{
pDstScan = dst + i*4 + j*4*width;
DecodeAlpha3BitLinear( pDstScan, pBlock, width, 0 );
if ( bATI2N )
{
pBlock++;
DecodeAlpha3BitLinear( pDstScan, pBlock, width, 1 );
}
}
}
// Deal with the case where we have a dimension smaller than 4.
if ( realDst )
{
int x, y;
for( y = 0; y < realHeight; y++ )
{
for( x = 0; x < realWidth; x++ )
{
realDst[x+(y*realWidth)] = dst[x+(y*width)];
}
}
}
}
static uint32 GetDXTCEncodeType( ImageFormat imageFormat )
{
switch ( imageFormat )
{
case IMAGE_FORMAT_DXT1:
return S3TC_ENCODE_RGB_FULL;
case IMAGE_FORMAT_DXT1_ONEBITALPHA:
return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_RGB_ALPHA_COMPARE;
case IMAGE_FORMAT_DXT3:
return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_ALPHA_EXPLICIT;
case IMAGE_FORMAT_DXT5:
return S3TC_ENCODE_RGB_FULL | S3TC_ENCODE_ALPHA_INTERPOLATED;
default:
return 0;
}
}
// Use AMD compressor to convert RGBA input to ATI1N, ATI2N or DXT5_GA format
bool ConvertToATIxN( const uint8 *src, ImageFormat srcImageFormat,
uint8 *dst, ImageFormat dstImageFormat,
int width, int height, int srcStride, int dstStride, bool bDXT5GA = false )
{
Assert( !"ATIxN is no longer supported." );
return false;
}
bool ConvertToDXT( const uint8 *src, ImageFormat srcImageFormat,
uint8 *dst, ImageFormat dstImageFormat,
int width, int height, int srcStride, int dstStride )
{
#if !defined( _X360 ) && !defined( POSIX )
// from rgb(a) to dxtN
if( srcStride != 0 || dstStride != 0 )
return false;
DDSURFACEDESC descIn;
DDSURFACEDESC descOut;
memset( &descIn, 0, sizeof(descIn) );
memset( &descOut, 0, sizeof(descOut) );
float weight[3] = {0.3086f, 0.6094f, 0.0820f};
uint32 dwEncodeType = GetDXTCEncodeType( dstImageFormat );
// Setup descIn
descIn.dwSize = sizeof(descIn);
descIn.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE |
/*DDSD_PITCH | */ DDSD_PIXELFORMAT;
descIn.dwWidth = width;
descIn.dwHeight = height;
descIn.lPitch = width * ImageLoader::SizeInBytes( srcImageFormat );
descIn.lpSurface = ( LPVOID *) src;
descIn.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
switch ( srcImageFormat )
{
case IMAGE_FORMAT_RGBA8888:
descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
descIn.ddpfPixelFormat.dwRGBBitCount = 32;
descIn.ddpfPixelFormat.dwRBitMask = 0x0000ff;
descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
descIn.ddpfPixelFormat.dwBBitMask = 0xff0000;
// must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
break;
case IMAGE_FORMAT_BGRA8888:
descIn.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
descIn.ddpfPixelFormat.dwRGBBitCount = 32;
descIn.ddpfPixelFormat.dwRBitMask = 0xFF0000;
descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
descIn.ddpfPixelFormat.dwBBitMask = 0x0000FF;
// must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
break;
case IMAGE_FORMAT_BGRX8888:
descIn.ddpfPixelFormat.dwFlags = DDPF_RGB;
descIn.ddpfPixelFormat.dwRGBBitCount = 32;
descIn.ddpfPixelFormat.dwRBitMask = 0xFF0000;
descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
descIn.ddpfPixelFormat.dwBBitMask = 0x0000FF;
// must set this anyway or S3TC will lock up!!!
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
break;
case IMAGE_FORMAT_RGB888:
descIn.ddpfPixelFormat.dwFlags = DDPF_RGB;
descIn.ddpfPixelFormat.dwRGBBitCount = 24;
descIn.ddpfPixelFormat.dwRBitMask = 0x0000ff;
descIn.ddpfPixelFormat.dwGBitMask = 0x00ff00;
descIn.ddpfPixelFormat.dwBBitMask = 0xff0000;
descIn.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
break;
default:
return false;
}
// Setup descOut
descOut.dwSize = sizeof( descOut );
// Encode the texture
S3TCencode( &descIn, NULL, &descOut, dst, dwEncodeType, weight );
return true;
#else
Assert( 0 );
return false;
#endif
}
bool ConvertToDXTRuntime( const uint8 *src, ImageFormat srcImageFormat,
uint8 *dst, ImageFormat dstImageFormat,
int width, int height )
{
// from rgba to dxtN using stb_dxt.h (source format must always be RGBA8888, dest format must be DXT1_RUNTIME or DXT5_RUNTIME
Assert( ( srcImageFormat == IMAGE_FORMAT_RGBA8888 || srcImageFormat == IMAGE_FORMAT_BGRA8888 ) && ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME || dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME ) );
const uint64 *sourcePixels = reinterpret_cast<const uint64 *>(src);
uint32 *dest32 = reinterpret_cast<uint32 *>(dst);
int width64 = width >> 1;
if ( srcImageFormat == IMAGE_FORMAT_BGRA8888 )
{
for ( int y = 0; y < height; y += 4 )
{
if ( width == 1 )
{
uint32 pixelBlock[16];
const uint32 *sourcePixels32 = reinterpret_cast<const uint32 *>(src);
pixelBlock[0] = sourcePixels32[0];
for ( int i = 1; i < 16; i++ )
{
pixelBlock[i] = 0;
}
// compress the pixelBlock into dest32
stb_compress_dxt_block( reinterpret_cast<uint8 *>(dest32), reinterpret_cast<uint8 *>(pixelBlock), (dstImageFormat == IMAGE_FORMAT_DXT5_RUNTIME) ? 1 : 0, STB_DXT_NORMAL );
dest32 += ( dstImageFormat == IMAGE_FORMAT_DXT1_RUNTIME ) ? 2 : 4;
}
else if ( width == 2 )
{
// copy a 4x4 block of pixels from the source image into 'pixelBlock'
uint64 pixelBlock[8];