the asumptions were of course, incorrect
[convexer.git] / nbvtf / nbvtf.h
1 // nbvtf.h - v1.03 - Writer for Valve Texture Format - public domain
2 // Written by Harry 'hgn' Godden
3 //
4 // Credits:
5 // Rich Geldreich - bc7enc (BC1/BC3 High Quality texture compression)
6 // Fabian "ryg" Giesen, stb - stb_dxt (BC1/BC3 realtime compressors)
7 // Sean Barrett - stb_image.h, stb_image_write.h (Image I/O)
8 //
9 // Note:
10 // This library assumes normal maps are input in OpenGL(correct) format, and will be converted into DirectX(incorrect) at
11 // compile time automatically. Do not submit DirectX normals into this software.
12 //
13 // Since this project uses stb_image, use '#define STB_IMAGE_IMPLEMENTATION' before including
14 // Additionally, to use high quality DXT, '#define USE_LIBRGBCX'
15 //
16 // USAGE:
17 // Call these functions:
18 // int nbvtf_convert( const char *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest );
19 // int nbvtf_write( uint8_t *src, int w, int h, int mipmap, EImageFormat_t format, uint32_t usr_flags, const char *dest );
20 //
21 // Param definitions:
22 // src - RGBA byte data of image
23 // w - width of image
24 // h - height of image
25 // mipmap - enable mipmap generation (box filter), 1/0
26 // format - Choose from: k_EImageFormat_DXT1, compressedk_EImageFormat_DXT5, k_EImageFormat_BGR888, k_EImageFormat_ABGR8888
27 // usr_flags - You can append any flags but only really need TEXTUREFLAGS_NORMAL if texture is normal map
28 // dest - file path to write vtf to
29 // qual - Image quality 0-18 (rgbcx, stb always highqual)
30 //
31 // Convert specific:
32 // src - file path of source image to convert
33 // w, h - MAXIMUM image dimentions of final product. Set as 0 to be automatic
34 //
35 // version history:
36 // v1.03 - Added quality switch, moved init (major api revision)
37 // v1.02 - Improved box filtering, small bug fixes
38 // v1.01 - switch to OpenGL normal format for input
39 // v1.00 - (hgn) first release
40 //
41 // LICENSE
42 // See end of file for license information.
43
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47
48 #define NBVTF_MAX_MIPLEVELS 9
49 #define nbvtf__min(a,b) (((a)<(b))?(a):(b))
50 #define nbvtf__max(a,b) (((a)>(b))?(a):(b))
51
52 #ifdef NBVTF_AS_SO
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdint.h>
56 #include <math.h>
57
58 #define NBVTF_SHOW_STDERR
59 #define STB_IMAGE_IMPLEMENTATION
60 #define STB_IMAGE_WRITE_IMPLEMENTATION
61 #endif
62
63 #define STBI_NO_THREAD_LOCALS
64 #include "stb/stb_image.h"
65 #include "stb/stb_image_write.h"
66
67 #ifdef USE_LIBRGBCX
68 // #define RGBCX_NO_ALGORITHM
69 #include "librgbcx.h"
70 #define HAS_DXT_COMPRESSOR
71 #endif
72
73 #if USE_STB_DXT
74 #define STB_DXT_IMPLEMENTATION
75 #include "stb/stb_dxt.h"
76 #define HAS_DXT_COMPRESSOR
77 #endif
78
79 #ifndef HAS_DXT_COMPRESSOR
80 #warning No DXT compressor specified! S3 Output will be invalid.
81 #endif
82
83 #ifdef NBVTF_SHOW_STDERR
84 #define NBVTF_ERR(...)
85 #else
86 #define NBVTF_ERR(...) fprintf( stderr, __VA_ARGS__ )
87 #endif
88
89 #pragma pack(push, 1)
90
91 typedef enum EImageFormat
92 {
93 /* Format Export Import */
94 k_EImageFormat_NONE = -1,
95 k_EImageFormat_RGBA8888 = 0, // - yes
96 k_EImageFormat_ABGR8888, // yes yes
97 k_EImageFormat_RGB888, // - yes
98 k_EImageFormat_BGR888, // yes yes
99 k_EImageFormat_RGB565, // - planned
100 k_EImageFormat_I8, // - planned
101 k_EImageFormat_IA88, // - planned
102 k_EImageFormat_P8, // - -
103 k_EImageFormat_A8, // - -
104 k_EImageFormat_RGB888_BLUESCREEN,// - -
105 k_EImageFormat_BGR888_BLUESCREEN,// - -
106 k_EImageFormat_ARGB8888, // - yes
107 k_EImageFormat_BGRA8888, // - yes
108 k_EImageFormat_DXT1, // yes yes
109 k_EImageFormat_DXT3, // - -
110 k_EImageFormat_DXT5, // yes yes
111 k_EImageFormat_BGRX8888, // - -
112 k_EImageFormat_BGR565, // - planned
113 k_EImageFormat_BGRX5551, // - -
114 k_EImageFormat_BGRA4444, // - -
115 k_EImageFormat_DXT1_ONEBITALPHA, // - planned
116 k_EImageFormat_BGRA5551, // - -
117 k_EImageFormat_UV88, // - -
118 k_EImageFormat_UVWQ8888, // - -
119 k_EImageFormat_RGBA16161616F, // - -
120 k_EImageFormat_RGBA16161616, // - -
121 k_EImageFormat_UVLX8888 // - -
122 } EImageFormat_t;
123
124 const char *vtf_format_strings[] =
125 {
126 "RGBA8888",
127 "ABGR8888",
128 "RGB888",
129 "BGR888",
130 "RGB565",
131 "I8",
132 "IA88",
133 "P8",
134 "A8",
135 "RGB888_BLUESCREEN",
136 "BGR888_BLUESCREEN",
137 "ARGB8888",
138 "BGRA8888",
139 #ifdef USE_LIBRGBCX
140 "DXT1 (rgbcx.h)",
141 #else
142 "DXT1 (stb_dxt.h)",
143 #endif
144 "DXT3",
145 #ifdef USE_LIBRGBCX
146 "DXT5 (rgbcx.h)",
147 #else
148 "DXT5 (stb_dxt.h)",
149 #endif
150 "BGRX8888",
151 "BGR565",
152 "BGRX5551",
153 "BGRA4444",
154 "DXT1_ONEBITALPHA",
155 "BGRA5551",
156 "UV88",
157 "UVWQ8888",
158 "RGBA16161616F",
159 "RGBA16161616",
160 "UVLX8888"
161 };
162
163 enum flag
164 {
165 // Flags from the *.txt config file
166 TEXTUREFLAGS_POINTSAMPLE = 0x00000001,
167 TEXTUREFLAGS_TRILINEAR = 0x00000002,
168 TEXTUREFLAGS_CLAMPS = 0x00000004,
169 TEXTUREFLAGS_CLAMPT = 0x00000008,
170 TEXTUREFLAGS_ANISOTROPIC = 0x00000010,
171 TEXTUREFLAGS_HINT_DXT5 = 0x00000020,
172 TEXTUREFLAGS_PWL_CORRECTED = 0x00000040,
173 TEXTUREFLAGS_NORMAL = 0x00000080,
174 TEXTUREFLAGS_NOMIP = 0x00000100,
175 TEXTUREFLAGS_NOLOD = 0x00000200,
176 TEXTUREFLAGS_ALL_MIPS = 0x00000400,
177 TEXTUREFLAGS_PROCEDURAL = 0x00000800,
178
179 // These are automatically generated by vtex from the texture data.
180 TEXTUREFLAGS_ONEBITALPHA = 0x00001000,
181 TEXTUREFLAGS_EIGHTBITALPHA = 0x00002000,
182
183 // Newer flags from the *.txt config file
184 TEXTUREFLAGS_ENVMAP = 0x00004000,
185 TEXTUREFLAGS_RENDERTARGET = 0x00008000,
186 TEXTUREFLAGS_DEPTHRENDERTARGET = 0x00010000,
187 TEXTUREFLAGS_NODEBUGOVERRIDE = 0x00020000,
188 TEXTUREFLAGS_SINGLECOPY = 0x00040000,
189 TEXTUREFLAGS_PRE_SRGB = 0x00080000,
190
191 TEXTUREFLAGS_UNUSED_00100000 = 0x00100000,
192 TEXTUREFLAGS_UNUSED_00200000 = 0x00200000,
193 TEXTUREFLAGS_UNUSED_00400000 = 0x00400000,
194
195 TEXTUREFLAGS_NODEPTHBUFFER = 0x00800000,
196
197 TEXTUREFLAGS_UNUSED_01000000 = 0x01000000,
198
199 TEXTUREFLAGS_CLAMPU = 0x02000000,
200 TEXTUREFLAGS_VERTEXTEXTURE = 0x04000000,
201 TEXTUREFLAGS_SSBUMP = 0x08000000,
202
203 TEXTUREFLAGS_UNUSED_10000000 = 0x10000000,
204
205 TEXTUREFLAGS_BORDER = 0x20000000,
206
207 TEXTUREFLAGS_UNUSED_40000000 = 0x40000000,
208 TEXTUREFLAGS_UNUSED_80000000 = 0x80000000,
209 };
210
211 typedef struct vtfheader
212 {
213 union
214 {
215 char signature[4]; // File signature ("VTF\0"). (or as little-endian integer, 0x00465456)
216 uint32_t usig;
217 };
218
219 unsigned int version[2]; // version[0].version[1] (currently 7.2).
220 unsigned int headerSize; // Size of the header struct (16 byte aligned; currently 80 bytes) + size of the resources dictionary (7.3+).
221 unsigned short width; // Width of the largest mipmap in pixels. Must be a power of 2.
222 unsigned short height; // Height of the largest mipmap in pixels. Must be a power of 2.
223 unsigned int flags; // VTF flags.
224 unsigned short frames; // Number of frames, if animated (1 for no animation).
225 unsigned short firstFrame; // First frame in animation (0 based).
226 unsigned char padding0[4]; // reflectivity padding (16 byte alignment).
227 float reflectivity[3]; // reflectivity vector.
228 unsigned char padding1[4]; // reflectivity padding (8 byte packing).
229 float bumpmapScale; // Bumpmap scale.
230 unsigned int highResImageFormat; // High resolution image format.
231 unsigned char mipmapCount; // Number of mipmaps.
232 unsigned int lowResImageFormat; // Low resolution image format (always DXT1).
233 unsigned char lowResImageWidth; // Low resolution image width.
234 unsigned char lowResImageHeight; // Low resolution image height.
235
236 // 7.2+
237 unsigned short depth; // Depth of the largest mipmap in pixels.
238 // Must be a power of 2. Can be 0 or 1 for a 2D texture (v7.2 only).
239
240 // 7.3+
241 unsigned char padding2[3]; // depth padding (4 byte alignment).
242 unsigned int numResources; // Number of resources this vtf has
243
244 unsigned char padding3[8]; // Necessary on certain compilers
245 } vtfheader_t;
246
247 #pragma pack(pop)
248
249 #pragma pack(push, 1)
250 struct DDS_PIXELFORMAT
251 {
252 uint32_t dwSize;
253 uint32_t dwFlags;
254 uint32_t dwFourCC;
255 uint32_t dwRGBBitCount;
256 uint32_t dwRBitMask;
257 uint32_t dwGBitMask;
258 uint32_t dwBBitMask;
259 uint32_t dwABitMask;
260 };
261
262 struct DDS_HEADER {
263 uint32_t dwSize;
264 uint32_t dwFlags;
265 uint32_t dwHeight;
266 uint32_t dwWidth;
267 uint32_t dwPitchOrLinearSize;
268 uint32_t dwDepth;
269 uint32_t dwMipMapCount;
270 uint32_t dwReserved1[11];
271 struct DDS_PIXELFORMAT ddspf;
272 uint32_t dwCaps;
273 uint32_t dwCaps2;
274 uint32_t dwCaps3;
275 uint32_t dwCaps4;
276 uint32_t dwReserved2;
277 };
278
279 #pragma pack(pop)
280
281 uint32_t swap_endian(uint32_t val)
282 {
283 return (val << 24) | ((val << 8) & 0x00ff0000) |
284 ((val >> 8) & 0x0000ff00) | (val >> 24);
285 }
286
287 #define DDSD_CAPS 0x1
288 #define DDSD_HEIGHT 0x2
289 #define DDSD_WIDTH 0x4
290 #define DDSD_PITCH 0x8
291 #define DDSD_PIXELFORMAT 0x1000
292 #define DDSD_MIPMAPCOUNT 0x20000
293 #define DDSD_LINEARSIZE 0x80000
294 #define DDSD_DEPTH 0x800000
295
296 #define DDPF_ALPHAPIXELS 0x1
297 #define DDPF_ALPHA 0x2
298 #define DDPF_FOURCC 0x4
299 #define DDPF_RGB 0x40
300 #define DDPF_YUV 0x200
301 #define DDPF_LUMINANCE 0x20000
302
303 #define DDSCAPS_COMPLEX 0x8
304 #define DDSCAPS_MIPMAP 0x400000
305 #define DDSCAPS_TEXTURE 0x1000
306
307 #define BLOCK_SIZE_DXT1 8
308 #define BLOCK_SIZE_DXT5 16
309
310 #define BBP_RGB888 24
311 #define BBP_RGBA8888 32
312
313 #define DDS_HEADER_SIZE 124
314 #define DDS_HEADER_PFSIZE 32
315 #define DDS_MAGICNUM 0x20534444;
316
317 #define DDS_FLIP_VERTICALLY_ON_WRITE
318
319 typedef struct mipimg
320 {
321 uint32_t w;
322 uint32_t h;
323 uint32_t src_offset;
324 } mipimg_t;
325
326 int nbvtf_power2( uint32_t x )
327 {
328 return (x != 0) && ((x & (x - 1)) == 0);
329 }
330
331 int nbvtf_power2x( uint32_t y, uint32_t x )
332 {
333 return nbvtf_power2( y ) && nbvtf_power2( x );
334 }
335
336 int nbvtf_lower( int *x, int *y )
337 {
338 if( *x == 1 && *y == 1 )
339 {
340 return 0;
341 }
342
343 *x = nbvtf__max( 1, (*x)/2 );
344 *y = nbvtf__max( 1, (*y)/2 );
345
346 return 1;
347 }
348
349 int nbvtf_lowres_index( int w, int h )
350 {
351 int x, y;
352 int i = 0;
353
354 x = w;
355 y = h;
356
357 while(1)
358 {
359 if( (x <= 16) && ( y <= 16 ) )
360 {
361 return i;
362 }
363
364 i ++;
365
366 nbvtf_lower( &x, &y );
367 }
368 }
369
370 // Simple box filter downscale
371 void nbvtf_downscale( uint8_t *src, int w, int h, int dw, int dh, uint8_t *dest )
372 {
373 int bx = w/dw;
374 int by = h/dh;
375 int div = bx*by;
376
377 for( int y = 0; y < dh; y ++ )
378 for( int x = 0; x < dw; x ++ )
379 {
380 // Average block colours
381 uint32_t tr = 0, tg = 0, tb = 0, ta = 0;
382
383 for( int yy = 0; yy < by; yy ++ )
384 for( int xx = 0; xx < bx; xx ++ )
385 {
386 uint8_t *psrc = &src[ (x*bx+xx + (y*by+yy)*w)*4 ];
387 tr+=psrc[0];
388 tg+=psrc[1];
389 tb+=psrc[2];
390 ta+=psrc[3];
391 }
392
393 uint8_t *pdst = &dest[ (y*dw + x)*4 ];
394 pdst[0] = tr / div;
395 pdst[1] = tg / div;
396 pdst[2] = tb / div;
397 pdst[3] = ta / div;
398 }
399 }
400
401 uint8_t *nbvtf_create_mipmaps( uint8_t *src, int w, int h, mipimg_t *offsets, int *num )
402 {
403 int memory = 0;
404 int x, y, i;
405 uint32_t offset;
406
407 x = w;
408 y = h;
409 while( nbvtf_lower( &x, &y ) )
410 memory += x*y*4;
411
412 uint8_t *mipmem = (uint8_t *)malloc( memory );
413
414 if( mipmem )
415 {
416 x = w;
417 y = h;
418 i = 0;
419 offset = 0;
420
421 uint8_t *dest = mipmem;
422
423 while(1)
424 {
425 if( !nbvtf_lower( &x, &y ) )
426 break;
427
428 nbvtf_downscale( src, w, h, x, y, dest );
429
430 offsets[ i ].src_offset = offset;
431 offsets[ i ].w = x;
432 offsets[ i ].h = y;
433 i ++;
434
435 offset += x*y*4;
436 dest = mipmem + offset;
437 }
438
439 *num = i;
440 return mipmem;
441 }
442 else
443 {
444 NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
445 return NULL;
446 }
447 }
448
449 void nbvtf_reflectivity( uint8_t *src, int w, int h, float *dest )
450 {
451 uint32_t totals[3] = {0,0,0};
452
453 for( int i = 0; i < w*h; i ++ )
454 {
455 totals[0] += src[i*4+0];
456 totals[1] += src[i*4+1];
457 totals[2] += src[i*4+2];
458 }
459
460 dest[0] = (float)( totals[0] / (w*h) ) / 255.0f;
461 dest[1] = (float)( totals[1] / (w*h) ) / 255.0f;
462 dest[2] = (float)( totals[2] / (w*h) ) / 255.0f;
463 }
464
465 #ifdef NBVTF_ALLOW_EXPORT
466 void nbvtf_debug_view_mips( uint8_t *src, int w, int h )
467 {
468 int x, y, i;
469 char fnbuf[512];
470
471 x = w;
472 y = h;
473 i = 1;
474
475 uint8_t *dest = src;
476
477 while( nbvtf_lower( &x, &y ) )
478 {
479 sprintf( fnbuf, "mip_%d.png", i ++ );
480
481 stbi_write_png( fnbuf, x,y, 4, dest, x*4 );
482 dest += x*y*4;
483 }
484 }
485 #endif
486
487 void nbvtf_dxt_pad( uint8_t *src, int bx, int by, int w, int h, uint8_t *dest )
488 {
489 int px = bx*4;
490 int py = by*4;
491
492 uint32_t *stream = (uint32_t *)src;
493 uint32_t *stream_out = (uint32_t *)dest;
494
495 for( int y = 0; y < 4; y ++ )
496 {
497 for( int x = 0; x < 4; x ++ )
498 {
499 stream_out[ y*4+x ] = stream[ nbvtf__min( py+y, h-1 )*w + nbvtf__min( px+x, w-1 ) ];
500 }
501 }
502 }
503
504 uint32_t nbvtf_dxt_sizeimg( int w, int h, int alpha )
505 {
506 uint32_t blocks_x, blocks_y;
507 int block_size = alpha? 16: 8;
508
509 blocks_x = ((uint32_t)w) >> 2;
510 blocks_y = ((uint32_t)h) >> 2;
511
512 int padx = w % 4 != 0? 1: 0;
513 int pady = h % 4 != 0? 1: 0;
514
515 return (blocks_x+padx)*(blocks_y+pady)*block_size;
516 }
517
518 uint32_t nbvtf_sizeimg( int w, int h, EImageFormat_t format )
519 {
520 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_DXT1 )
521 {
522 return nbvtf_dxt_sizeimg( w, h, format == k_EImageFormat_DXT1? 0: 1 );
523 }
524
525 if( format == k_EImageFormat_BGR888 )
526 return w*h*3;
527
528 if( format == k_EImageFormat_ABGR8888 )
529 return w*h*4;
530
531 return 0;
532 }
533
534 #ifdef NBVTF_AS_SO
535 __attribute__((visibility("default")))
536 #endif
537 void nbvtf_init(void)
538 {
539 #ifdef USE_LIBRGBCX
540 rgbcx__init();
541 #endif
542 }
543
544 void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha, int qual )
545 {
546 #ifdef USE_LIBRGBCX
547 if( alpha )
548 {
549 rgbcx__encode_bc3( qual, dest, src );
550 }
551 else
552 {
553 rgbcx__encode_bc1( qual, dest, src, 0, 0 );
554 }
555 #endif
556
557 #if USE_STB_DXT
558 stb_compress_dxt_block( dest, src, alpha, STB_DXT_HIGHQUAL );
559 #endif
560
561 #ifndef HAS_DXT_COMPRESSOR
562
563 for( int i=0; i<alpha? 16: 8; i++ )
564 dest[i] = i%1? 0xff: 0x00;
565 #endif
566 }
567
568 void nbvtf_dxt_block_unpack( uint8_t *src, uint8_t *dest, int alpha )
569 {
570 #ifdef USE_LIBRGBCX
571 if( alpha )
572 {
573 rgbcx__unpack_bc3( src, dest );
574 }
575 else
576 {
577 rgbcx__unpack_bc1( src, dest );
578 }
579 #endif
580
581 #if USE_STB_DXT
582 stb_decompress_dxt_block( src, dest, alpha );
583 #endif
584
585 #ifndef HAS_DXT_COMPRESSOR
586 for( int i=0; i<alpha? 128: 64; i++ )
587 dest[i] = i%1? 0xff: 0x00;
588 #endif
589 }
590
591 void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual,
592 uint8_t *dest )
593 {
594 uint32_t blocks_x, blocks_y;
595
596 blocks_x = ((uint32_t)w) >> 2;
597 blocks_y = ((uint32_t)h) >> 2;
598
599 int padx = w % 4 != 0? 1: 0;
600 int pady = h % 4 != 0? 1: 0;
601
602 int block_size = alpha? 16: 8;
603
604 uint8_t *dest_block = dest;
605
606 uint8_t working_block[ 4*4*4 ];
607
608 // Compress rows
609 for( int y = 0; y < blocks_y; y ++ )
610 {
611 for( int x = 0; x < blocks_x; x ++ )
612 {
613 uint8_t *src_begin = src + (y*w*4 + x*4)*4;
614 for( int i = 0; i < 4; i ++ )
615 {
616 memcpy( working_block + i*4*4, src_begin + w*4*i, 4*4 );
617 }
618
619 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
620 dest_block += block_size;
621 }
622
623 if( padx )
624 {
625 nbvtf_dxt_pad( src, blocks_x, y, w, h, working_block );
626 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
627 dest_block += block_size;
628 }
629 }
630
631 // Compress remainder row
632 if( pady )
633 {
634 for( int x = 0; x < blocks_x; x ++ )
635 {
636 nbvtf_dxt_pad( src, x, blocks_y, w, h, working_block );
637 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
638 dest_block += block_size;
639 }
640 }
641
642 // Compress last little corner
643 if( padx && pady )
644 {
645 nbvtf_dxt_pad( src, blocks_x, blocks_y, w, h, working_block );
646 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
647 }
648 }
649
650 /* Decompress block to rgba, padding currently doesn't get read */
651 void nbvtf_decompress_dxt(uint8_t *src, int w, int h, int alpha, uint8_t *dest )
652 {
653 uint32_t blocks_x, blocks_y;
654
655 blocks_x = ((uint32_t)w) >> 2;
656 blocks_y = ((uint32_t)h) >> 2;
657
658 int padx = w % 4 != 0? 1: 0;
659 int pady = h % 4 != 0? 1: 0;
660
661 int block_size = alpha? 16: 8;
662
663 uint8_t *dxt_block = src;
664 uint8_t working_block[ 4*4*4 ];
665
666 // Compress rows
667 for( int y = 0; y < blocks_y; y ++ )
668 {
669 for( int x = 0; x < blocks_x; x ++ )
670 {
671 nbvtf_dxt_block_unpack( dxt_block, working_block, alpha );
672
673 uint8_t *dest_begin = dest + (y*w*4 + x*4)*4;
674 for( int i = 0; i < 4; i ++ )
675 memcpy( dest_begin + w*4*i, working_block + i*4*4, 4*4 );
676
677 dxt_block += block_size;
678 }
679
680 if( padx )
681 dxt_block += block_size;
682 }
683
684 if( pady )
685 for( int x = 0; x < blocks_x; x ++ )
686 dxt_block += block_size;
687
688 if( padx && pady )
689 {
690 }
691 }
692 static void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
693 {
694 for( int i = 0; i < n; i ++ )
695 {
696 for( int j = 0; j < nc; j ++ )
697 {
698 dest[ i*nc+nc-j-1 ] = src[ i*4+j ];
699 }
700 }
701 }
702
703 static void nbvtf_write_img_data( uint8_t *src, int w, int h,
704 EImageFormat_t format, int qual, uint8_t *wb, FILE *file )
705 {
706 switch( format )
707 {
708 case k_EImageFormat_DXT1:
709 nbvtf_compress_dxt( src, w, h, 0, qual, wb );
710 fwrite( wb, nbvtf_dxt_sizeimg( w, h, 0 ), 1, file );
711 break;
712 case k_EImageFormat_DXT5:
713 nbvtf_compress_dxt( src, w, h, 1, qual, wb );
714 fwrite( wb, nbvtf_dxt_sizeimg( w, h, 1 ), 1, file );
715 break;
716 case k_EImageFormat_ABGR8888:
717 nbvtf_swizzle_to( src, w*h, 4, wb );
718 fwrite( wb, w*h*4, 1, file );
719 break;
720 case k_EImageFormat_BGR888:
721 nbvtf_swizzle_to( src, w*h, 3, wb );
722 fwrite( wb, w*h*3, 1, file );
723 break;
724
725 default:
726 break;
727 }
728 }
729
730 static size_t nbvtf_img_size( int w, int h, EImageFormat_t format )
731 {
732 int block_count = nbvtf__max(1, ((w + 3) / 4)) *
733 nbvtf__max(1, ((h + 3) / 4));
734
735 switch( format )
736 {
737 case k_EImageFormat_RGBA8888:
738 case k_EImageFormat_ABGR8888:
739 case k_EImageFormat_ARGB8888:
740 case k_EImageFormat_BGRA8888:
741 return 4*w*h;
742
743 case k_EImageFormat_RGB888:
744 case k_EImageFormat_BGR888:
745 return 3*w*h;
746
747 case k_EImageFormat_RGB565:
748 case k_EImageFormat_IA88:
749 return 2*w*h;
750
751 case k_EImageFormat_I8:
752 return w*h;
753
754 case k_EImageFormat_DXT1:
755 return block_count * BLOCK_SIZE_DXT1;
756
757 case k_EImageFormat_DXT5:
758 return block_count * BLOCK_SIZE_DXT5;
759
760 default:
761 break;
762 }
763 }
764
765 static void nbvtf_read_img_data( uint8_t *src, int w, int h,
766 EImageFormat_t format, uint8_t *dst )
767 {
768 switch( format )
769 {
770 case k_EImageFormat_RGBA8888:
771 for( int i=0; i<w*h*4; i++ )
772 dst[i] = src[i];
773 break;
774
775 case k_EImageFormat_ABGR8888:
776 for( int i=0; i<w*h; i++ )
777 {
778 dst[i*4+0] = src[i*4+3];
779 dst[i*4+1] = src[i*4+2];
780 dst[i*4+2] = src[i*4+1];
781 dst[i*4+3] = src[i*4+0];
782 }
783 break;
784
785 case k_EImageFormat_RGB888:
786 for( int i=0; i<w*h; i++ )
787 {
788 dst[i*4+0] = src[i*3+0];
789 dst[i*4+1] = src[i*3+1];
790 dst[i*4+2] = src[i*3+2];
791 dst[i*4+3] = 0xFF;
792 }
793 break;
794
795 case k_EImageFormat_BGR888:
796 for( int i=0; i<w*h; i++ )
797 {
798 dst[i*4+0] = src[i*3+2];
799 dst[i*4+1] = src[i*3+1];
800 dst[i*4+2] = src[i*3+0];
801 dst[i*4+3] = 0xFF;
802 }
803 break;
804
805 case k_EImageFormat_RGB565:
806 case k_EImageFormat_I8:
807 case k_EImageFormat_IA88:
808 /* Planned */
809 break;
810
811 case k_EImageFormat_ARGB8888:
812 for( int i=0; i<w*h; i++ )
813 {
814 dst[i*4+0] = src[i*4+1];
815 dst[i*4+1] = src[i*4+2];
816 dst[i*4+2] = src[i*4+3];
817 dst[i*4+3] = src[i*4+0];
818 }
819 break;
820
821 case k_EImageFormat_BGRA8888:
822 for( int i=0; i<w*h; i++ )
823 {
824 dst[i*4+0] = src[i*4+2];
825 dst[i*4+1] = src[i*4+1];
826 dst[i*4+2] = src[i*4+0];
827 dst[i*4+3] = src[i*4+3];
828 }
829 break;
830
831 case k_EImageFormat_DXT1:
832 nbvtf_decompress_dxt( src, w, h, 0, dst );
833 break;
834
835 case k_EImageFormat_DXT5:
836 nbvtf_decompress_dxt( src, w, h, 1, dst );
837 break;
838
839 default:
840 break;
841 }
842 }
843
844 #ifdef NBVTF_AS_SO
845 __attribute__((visibility("default")))
846 #endif
847 int nbvtf_write_dds_dxt1( uint8_t *reference, int w, int h, int qual, const char *dest )
848 {
849 if( !nbvtf_power2x(w,h) )
850 {
851 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
852 return 0;
853 }
854
855 struct DDS_HEADER header = {0};
856 header.dwSize = DDS_HEADER_SIZE;
857 header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
858 header.dwHeight = h;
859 header.dwWidth = w;
860 header.dwPitchOrLinearSize = nbvtf__max(1, ((w + 3) / 4)) * BLOCK_SIZE_DXT1;
861 header.ddspf.dwSize = DDS_HEADER_PFSIZE;
862 header.ddspf.dwFlags |= DDPF_FOURCC;
863 header.ddspf.dwFourCC = ((uint32_t)'D'<<0) |
864 ((uint32_t)'X'<<8) |
865 ((uint32_t)'T'<<16) |
866 ((uint32_t)'1'<<24);
867
868 header.dwFlags |= DDSD_LINEARSIZE;
869 header.dwMipMapCount = 0;
870 header.dwCaps = DDSCAPS_TEXTURE;
871
872 // Magic number
873 uint32_t magic = DDS_MAGICNUM;
874
875 FILE *file = fopen( dest, "wb" );
876 fwrite( &magic, sizeof(uint32_t), 1, file );
877 fwrite( &header, DDS_HEADER_SIZE, 1, file );
878
879 uint32_t size_highres = nbvtf_sizeimg( w, h, k_EImageFormat_DXT1 );
880 uint8_t *working_buffer = malloc( size_highres );
881
882 nbvtf_compress_dxt( reference, w, h, 0, qual, working_buffer );
883 fwrite( working_buffer, size_highres, 1, file );
884
885 free( working_buffer );
886 fclose( file );
887 return 1;
888 }
889
890 static void nbvtf_correct_normal( uint8_t *src, uint8_t *dst, int w, int h )
891 {
892 for( int i=0; i < w*h; i++ )
893 {
894 dst[i*4+0] = src[i*4+0];
895 dst[i*4+1] = 0xFF-src[i*4+1];
896 dst[i*4+2] = src[i*4+2];
897 dst[i*4+3] = src[i*4+3];
898 }
899 }
900
901 #ifdef NBVTF_AS_SO
902 __attribute__((visibility("default")))
903 #endif
904 int nbvtf_write( uint8_t *reference, int w, int h, int mipmap,
905 EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest )
906 {
907 if( !nbvtf_power2x(w,h) )
908 {
909 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
910 return 0;
911 }
912
913 mipimg_t mip_offsets[ 16 ];
914 int num_mips;
915
916 uint8_t *src;
917
918 // Convert to directx normal
919 if( usr_flags & TEXTUREFLAGS_NORMAL )
920 {
921 src = malloc( w*h*4 );
922 nbvtf_correct_normal( reference, src, w, h );
923 }
924 else
925 src = reference;
926
927 uint8_t *mip_data = nbvtf_create_mipmaps( src, w, h, mip_offsets, &num_mips );
928
929 if( !mip_data )
930 {
931 NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
932
933 if( usr_flags & TEXTUREFLAGS_NORMAL )
934 free( src );
935
936 return 0;
937 }
938
939 vtfheader_t header = {0};
940
941 header.usig = 0x00465456;
942 header.headerSize = sizeof( vtfheader_t );
943 header.version[0] = 7;
944 header.version[1] = 2;
945
946 header.width = w;
947 header.height = h;
948 header.flags = usr_flags;
949
950 // Append format flags
951 if( !mipmap )
952 {
953 header.flags |= TEXTUREFLAGS_NOLOD;
954 header.flags |= TEXTUREFLAGS_NOMIP;
955 }
956
957 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_ABGR8888 )
958 {
959 header.flags |= TEXTUREFLAGS_EIGHTBITALPHA;
960 }
961
962 header.frames = 1;
963 header.firstFrame = 0;
964 nbvtf_reflectivity( mip_data + mip_offsets[ num_mips-1 ].src_offset, 1,1, header.reflectivity );
965 header.bumpmapScale = 1.0f;
966
967 header.highResImageFormat = format;
968 header.mipmapCount = mipmap?
969 nbvtf__min(num_mips,NBVTF_MAX_MIPLEVELS)+1: 1;
970
971 header.lowResImageFormat = k_EImageFormat_DXT1;
972
973 header.depth = 1;
974 header.numResources = 0;
975
976 int lr_index = nbvtf_lowres_index( w, h );
977
978 uint8_t *lr_src;
979
980 if( lr_index )
981 {
982 mipimg_t *mip = mip_offsets + (lr_index-1);
983 lr_src = mip_data + mip->src_offset;
984
985 header.lowResImageWidth = mip->w;
986 header.lowResImageHeight = mip->h;
987 }
988 else
989 {
990 lr_src = src;
991
992 header.lowResImageWidth = w;
993 header.lowResImageHeight = h;
994 }
995
996 uint32_t size_highres = nbvtf_sizeimg( w, h, format );
997 uint32_t size_lowres =
998 nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 );
999
1000 uint8_t *working_buffer =
1001 (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) );
1002
1003 if( !working_buffer )
1004 {
1005 NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
1006 free( mip_data );
1007
1008 if( usr_flags & TEXTUREFLAGS_NORMAL )
1009 free( src );
1010
1011 return 0;
1012 }
1013
1014 FILE *file = fopen( dest, "wb" );
1015
1016 if( !file )
1017 {
1018 NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
1019
1020 free( working_buffer );
1021 free( mip_data );
1022
1023 if( usr_flags & TEXTUREFLAGS_NORMAL )
1024 free( src );
1025
1026 return 0;
1027 }
1028
1029 // Write header
1030 fwrite( &header, sizeof( vtfheader_t ), 1, file );
1031
1032 // Write low res
1033 nbvtf_write_img_data(
1034 lr_src, header.lowResImageWidth, header.lowResImageHeight,
1035 k_EImageFormat_DXT1, qual, working_buffer, file
1036 );
1037
1038 // Write texture data
1039 if( mipmap )
1040 {
1041 // !! Experimental !!
1042 int start = nbvtf__max( 0, num_mips-NBVTF_MAX_MIPLEVELS );
1043
1044 for( int i = start; i < num_mips; i ++ )
1045 {
1046 mipimg_t *mip = mip_offsets + (num_mips - i -1);
1047 nbvtf_write_img_data( mip_data + mip->src_offset, mip->w, mip->h,
1048 format, qual, working_buffer, file );
1049 }
1050 }
1051
1052 // Write high resolution
1053 nbvtf_write_img_data( src, w, h, format, qual, working_buffer, file );
1054
1055 fclose( file );
1056
1057 free( working_buffer );
1058 free( mip_data );
1059
1060 if( usr_flags & TEXTUREFLAGS_NORMAL )
1061 free( src );
1062
1063 return 1;
1064 }
1065
1066 #ifdef NBVTF_AS_SO
1067 __attribute__((visibility("default")))
1068 #endif
1069 uint8_t *nbvtf_read( vtfheader_t *header, int32_t *w, int32_t *h, int normal )
1070 {
1071 *w = header->width;
1072 *h = header->height;
1073
1074 uint8_t *rgba = malloc( header->width * header->height * 4 );
1075
1076 if( !rgba )
1077 return NULL;
1078
1079 size_t memory = 0;
1080 int x = header->width,
1081 y = header->height;
1082
1083 int mip_iter = 0;
1084
1085 while( nbvtf_lower( &x, &y ) )
1086 {
1087 if( mip_iter == header->mipmapCount )
1088 break;
1089
1090 mip_iter ++;
1091 memory += nbvtf_img_size( x, y, header->highResImageFormat );
1092 }
1093
1094 if( header->lowResImageWidth == 0 || header->lowResImageHeight == 0 ||
1095 header->lowResImageFormat == 0xffffffff )
1096 {
1097 /* no thumbnail? */
1098 }
1099 else
1100 memory += nbvtf_img_size( header->lowResImageWidth,
1101 header->lowResImageHeight,
1102 header->lowResImageFormat );
1103
1104 /* Decode high res image into rgba */
1105 nbvtf_read_img_data( ((uint8_t *)header) + header->headerSize + memory,
1106 header->width, header->height,
1107 header->highResImageFormat,
1108 rgba );
1109
1110 if( normal )
1111 {
1112 nbvtf_correct_normal( rgba, rgba, header->width, header->height );
1113 stbi_write_png( "/tmp/cxr_hello_n.png", header->width, header->height,
1114 4, rgba, header->width*4 );
1115 }
1116 else
1117 stbi_write_png( "/tmp/cxr_hello.png", header->width, header->height,
1118 4, rgba, header->width*4 );
1119
1120
1121 return rgba;
1122 }
1123
1124 #ifdef NBVTF_AS_SO
1125 __attribute__((visibility("default")))
1126 #endif
1127 uint8_t *nbvtf_raw_data( vtfheader_t *header, int32_t *w, int32_t *h, int32_t *format )
1128 {
1129 *w = header->width;
1130 *h = header->height;
1131 *format = header->highResImageFormat;
1132
1133 return ((uint8_t *)header) + header->headerSize;
1134 }
1135
1136 #ifdef NBVTF_AS_SO
1137 __attribute__((visibility("default")))
1138 #endif
1139 void nbvtf_free( uint8_t *data )
1140 {
1141 free(data);
1142 }
1143
1144 #ifdef NBVTF_AS_SO
1145 __attribute__((visibility("default")))
1146 #endif
1147 int nbvtf_convert( const char *src, int w, int h, int mipmap,
1148 EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest )
1149 {
1150 if( (w && h) && !nbvtf_power2x(w,h) )
1151 {
1152 NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w, h );
1153 return 0;
1154 }
1155
1156 int x,y,n;
1157 uint8_t *data = stbi_load( src, &x, &y, &n, 4 );
1158
1159 if( data )
1160 {
1161 if( !nbvtf_power2x(x,y) )
1162 {
1163 NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x, y );
1164 stbi_image_free( data );
1165 return 0;
1166 }
1167
1168 // Image size needs to be made smaller
1169 if( (w && h) && ( x > w || y > h ) )
1170 {
1171 nbvtf_downscale( data, x, y, w, h, data );
1172 x = w;
1173 y = h;
1174 }
1175
1176 int status = nbvtf_write( data, x,y, mipmap, format, qual, usr_flags, dest );
1177
1178 stbi_image_free( data );
1179
1180 return status;
1181 }
1182 else
1183 {
1184 return 0;
1185 }
1186 }
1187
1188 #ifdef __cplusplus
1189 }
1190 #endif
1191
1192 /*
1193 LICENSE - Applies to nbvtf.h, pynbvtf.py, librgbcx.cc, librgbcx.h, vtf_cmd.c
1194 ------------------------------------------------------------------------------
1195 Public Domain (www.unlicense.org)
1196 This is free and unencumbered software released into the public domain.
1197 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
1198 software, either in source code form or as a compiled binary, for any purpose,
1199 commercial or non-commercial, and by any means.
1200 In jurisdictions that recognize copyright laws, the author or authors of this
1201 software dedicate any and all copyright interest in the software to the public
1202 domain. We make this dedication for the benefit of the public at large and to
1203 the detriment of our heirs and successors. We intend this dedication to be an
1204 overt act of relinquishment in perpetuity of all present and future rights to
1205 this software under copyright law.
1206 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1207 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1208 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1209 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1210 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1211 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1212 ------------------------------------------------------------------------------
1213 */