1 // nbvtf.h - v1.03 - Writer for Valve Texture Format - public domain
2 // Written by Harry 'hgn' Godden
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)
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.
13 // Since this project uses stb_image, use '#define STB_IMAGE_IMPLEMENTATION' before including
14 // Additionally, to use high quality DXT, '#define USE_LIBRGBCX'
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 );
22 // src - RGBA byte data 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)
32 // src - file path of source image to convert
33 // w, h - MAXIMUM image dimentions of final product. Set as 0 to be automatic
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
42 // See end of file for license information.
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))
58 #define NBVTF_SHOW_STDERR
59 #define STB_IMAGE_IMPLEMENTATION
60 #define STB_IMAGE_WRITE_IMPLEMENTATION
63 #define STBI_NO_THREAD_LOCALS
64 #include "stb/stb_image.h"
65 #include "stb/stb_image_write.h"
68 // #define RGBCX_NO_ALGORITHM
70 #define HAS_DXT_COMPRESSOR
74 #define STB_DXT_IMPLEMENTATION
75 #include "stb/stb_dxt.h"
76 #define HAS_DXT_COMPRESSOR
79 #ifndef HAS_DXT_COMPRESSOR
80 #warning No DXT compressor specified! S3 Output will be invalid.
83 #ifdef NBVTF_SHOW_STDERR
84 #define NBVTF_ERR(...)
86 #define NBVTF_ERR(...) fprintf( stderr, __VA_ARGS__ )
91 typedef enum EImageFormat
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
// - -
124 const char *vtf_format_strings
[] =
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,
179 // These are automatically generated by vtex from the texture data.
180 TEXTUREFLAGS_ONEBITALPHA
= 0x00001000,
181 TEXTUREFLAGS_EIGHTBITALPHA
= 0x00002000,
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,
191 TEXTUREFLAGS_UNUSED_00100000
= 0x00100000,
192 TEXTUREFLAGS_UNUSED_00200000
= 0x00200000,
193 TEXTUREFLAGS_UNUSED_00400000
= 0x00400000,
195 TEXTUREFLAGS_NODEPTHBUFFER
= 0x00800000,
197 TEXTUREFLAGS_UNUSED_01000000
= 0x01000000,
199 TEXTUREFLAGS_CLAMPU
= 0x02000000,
200 TEXTUREFLAGS_VERTEXTEXTURE
= 0x04000000,
201 TEXTUREFLAGS_SSBUMP
= 0x08000000,
203 TEXTUREFLAGS_UNUSED_10000000
= 0x10000000,
205 TEXTUREFLAGS_BORDER
= 0x20000000,
207 TEXTUREFLAGS_UNUSED_40000000
= 0x40000000,
208 TEXTUREFLAGS_UNUSED_80000000
= 0x80000000,
211 typedef struct vtfheader
215 char signature
[4]; // File signature ("VTF\0"). (or as little-endian integer, 0x00465456)
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.
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).
241 unsigned char padding2
[3]; // depth padding (4 byte alignment).
242 unsigned int numResources
; // Number of resources this vtf has
244 unsigned char padding3
[8]; // Necessary on certain compilers
249 #pragma pack(push, 1)
250 struct DDS_PIXELFORMAT
255 uint32_t dwRGBBitCount
;
267 uint32_t dwPitchOrLinearSize
;
269 uint32_t dwMipMapCount
;
270 uint32_t dwReserved1
[11];
271 struct DDS_PIXELFORMAT ddspf
;
276 uint32_t dwReserved2
;
281 uint32_t swap_endian(uint32_t val
)
283 return (val
<< 24) | ((val
<< 8) & 0x00ff0000) |
284 ((val
>> 8) & 0x0000ff00) | (val
>> 24);
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
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
303 #define DDSCAPS_COMPLEX 0x8
304 #define DDSCAPS_MIPMAP 0x400000
305 #define DDSCAPS_TEXTURE 0x1000
307 #define BLOCK_SIZE_DXT1 8
308 #define BLOCK_SIZE_DXT5 16
310 #define BBP_RGB888 24
311 #define BBP_RGBA8888 32
313 #define DDS_HEADER_SIZE 124
314 #define DDS_HEADER_PFSIZE 32
315 #define DDS_MAGICNUM 0x20534444;
317 #define DDS_FLIP_VERTICALLY_ON_WRITE
319 typedef struct mipimg
326 int nbvtf_power2( uint32_t x
)
328 return (x
!= 0) && ((x
& (x
- 1)) == 0);
331 int nbvtf_power2x( uint32_t y
, uint32_t x
)
333 return nbvtf_power2( y
) && nbvtf_power2( x
);
336 int nbvtf_lower( int *x
, int *y
)
338 if( *x
== 1 && *y
== 1 )
343 *x
= nbvtf__max( 1, (*x
)/2 );
344 *y
= nbvtf__max( 1, (*y
)/2 );
349 int nbvtf_lowres_index( int w
, int h
)
359 if( (x
<= 16) && ( y
<= 16 ) )
366 nbvtf_lower( &x
, &y
);
370 // Simple box filter downscale
371 void nbvtf_downscale( uint8_t *src
, int w
, int h
, int dw
, int dh
, uint8_t *dest
)
377 for( int y
= 0; y
< dh
; y
++ )
378 for( int x
= 0; x
< dw
; x
++ )
380 // Average block colours
381 uint32_t tr
= 0, tg
= 0, tb
= 0, ta
= 0;
383 for( int yy
= 0; yy
< by
; yy
++ )
384 for( int xx
= 0; xx
< bx
; xx
++ )
386 uint8_t *psrc
= &src
[ (x
*bx
+xx
+ (y
*by
+yy
)*w
)*4 ];
393 uint8_t *pdst
= &dest
[ (y
*dw
+ x
)*4 ];
401 uint8_t *nbvtf_create_mipmaps( uint8_t *src
, int w
, int h
, mipimg_t
*offsets
, int *num
)
409 while( nbvtf_lower( &x
, &y
) )
412 uint8_t *mipmem
= (uint8_t *)malloc( memory
);
421 uint8_t *dest
= mipmem
;
425 if( !nbvtf_lower( &x
, &y
) )
428 nbvtf_downscale( src
, w
, h
, x
, y
, dest
);
430 offsets
[ i
].src_offset
= offset
;
436 dest
= mipmem
+ offset
;
444 NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
449 void nbvtf_reflectivity( uint8_t *src
, int w
, int h
, float *dest
)
451 uint32_t totals
[3] = {0,0,0};
453 for( int i
= 0; i
< w
*h
; i
++ )
455 totals
[0] += src
[i
*4+0];
456 totals
[1] += src
[i
*4+1];
457 totals
[2] += src
[i
*4+2];
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
;
465 #ifdef NBVTF_ALLOW_EXPORT
466 void nbvtf_debug_view_mips( uint8_t *src
, int w
, int h
)
477 while( nbvtf_lower( &x
, &y
) )
479 sprintf( fnbuf
, "mip_%d.png", i
++ );
481 stbi_write_png( fnbuf
, x
,y
, 4, dest
, x
*4 );
487 void nbvtf_dxt_pad( uint8_t *src
, int bx
, int by
, int w
, int h
, uint8_t *dest
)
492 uint32_t *stream
= (uint32_t *)src
;
493 uint32_t *stream_out
= (uint32_t *)dest
;
495 for( int y
= 0; y
< 4; y
++ )
497 for( int x
= 0; x
< 4; x
++ )
499 stream_out
[ y
*4+x
] = stream
[ nbvtf__min( py
+y
, h
-1 )*w
+ nbvtf__min( px
+x
, w
-1 ) ];
504 uint32_t nbvtf_dxt_sizeimg( int w
, int h
, int alpha
)
506 uint32_t blocks_x
, blocks_y
;
507 int block_size
= alpha
? 16: 8;
509 blocks_x
= ((uint32_t)w
) >> 2;
510 blocks_y
= ((uint32_t)h
) >> 2;
512 int padx
= w
% 4 != 0? 1: 0;
513 int pady
= h
% 4 != 0? 1: 0;
515 return (blocks_x
+padx
)*(blocks_y
+pady
)*block_size
;
518 uint32_t nbvtf_sizeimg( int w
, int h
, EImageFormat_t format
)
520 if( format
== k_EImageFormat_DXT5
|| format
== k_EImageFormat_DXT1
)
522 return nbvtf_dxt_sizeimg( w
, h
, format
== k_EImageFormat_DXT1
? 0: 1 );
525 if( format
== k_EImageFormat_BGR888
)
528 if( format
== k_EImageFormat_ABGR8888
)
535 __attribute__((visibility("default")))
537 void nbvtf_init(void)
544 void nbvtf_dxt_block( uint8_t *dest
, uint8_t *src
, int alpha
, int qual
)
549 rgbcx__encode_bc3( qual
, dest
, src
);
553 rgbcx__encode_bc1( qual
, dest
, src
, 0, 0 );
558 stb_compress_dxt_block( dest
, src
, alpha
, STB_DXT_HIGHQUAL
);
561 #ifndef HAS_DXT_COMPRESSOR
563 for( int i
=0; i
<alpha
? 16: 8; i
++ )
564 dest
[i
] = i
%1? 0xff: 0x00;
568 void nbvtf_dxt_block_unpack( uint8_t *src
, uint8_t *dest
, int alpha
)
573 rgbcx__unpack_bc3( src
, dest
);
577 rgbcx__unpack_bc1( src
, dest
);
582 stb_decompress_dxt_block( src
, dest
, alpha
);
585 #ifndef HAS_DXT_COMPRESSOR
586 for( int i
=0; i
<alpha
? 128: 64; i
++ )
587 dest
[i
] = i
%1? 0xff: 0x00;
591 void nbvtf_compress_dxt( uint8_t *src
, int w
, int h
, int alpha
, int qual
,
594 uint32_t blocks_x
, blocks_y
;
596 blocks_x
= ((uint32_t)w
) >> 2;
597 blocks_y
= ((uint32_t)h
) >> 2;
599 int padx
= w
% 4 != 0? 1: 0;
600 int pady
= h
% 4 != 0? 1: 0;
602 int block_size
= alpha
? 16: 8;
604 uint8_t *dest_block
= dest
;
606 uint8_t working_block
[ 4*4*4 ];
609 for( int y
= 0; y
< blocks_y
; y
++ )
611 for( int x
= 0; x
< blocks_x
; x
++ )
613 uint8_t *src_begin
= src
+ (y
*w
*4 + x
*4)*4;
614 for( int i
= 0; i
< 4; i
++ )
616 memcpy( working_block
+ i
*4*4, src_begin
+ w
*4*i
, 4*4 );
619 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
620 dest_block
+= block_size
;
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
;
631 // Compress remainder row
634 for( int x
= 0; x
< blocks_x
; x
++ )
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
;
642 // Compress last little corner
645 nbvtf_dxt_pad( src
, blocks_x
, blocks_y
, w
, h
, working_block
);
646 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
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
)
653 uint32_t blocks_x
, blocks_y
;
655 blocks_x
= ((uint32_t)w
) >> 2;
656 blocks_y
= ((uint32_t)h
) >> 2;
658 int padx
= w
% 4 != 0? 1: 0;
659 int pady
= h
% 4 != 0? 1: 0;
661 int block_size
= alpha
? 16: 8;
663 uint8_t *dxt_block
= src
;
664 uint8_t working_block
[ 4*4*4 ];
667 for( int y
= 0; y
< blocks_y
; y
++ )
669 for( int x
= 0; x
< blocks_x
; x
++ )
671 nbvtf_dxt_block_unpack( dxt_block
, working_block
, alpha
);
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 );
677 dxt_block
+= block_size
;
681 dxt_block
+= block_size
;
685 for( int x
= 0; x
< blocks_x
; x
++ )
686 dxt_block
+= block_size
;
692 static void nbvtf_swizzle_to( uint8_t *src
, int n
, int nc
, uint8_t *dest
)
694 for( int i
= 0; i
< n
; i
++ )
696 for( int j
= 0; j
< nc
; j
++ )
698 dest
[ i
*nc
+nc
-j
-1 ] = src
[ i
*4+j
];
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
)
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
);
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
);
716 case k_EImageFormat_ABGR8888
:
717 nbvtf_swizzle_to( src
, w
*h
, 4, wb
);
718 fwrite( wb
, w
*h
*4, 1, file
);
720 case k_EImageFormat_BGR888
:
721 nbvtf_swizzle_to( src
, w
*h
, 3, wb
);
722 fwrite( wb
, w
*h
*3, 1, file
);
730 static size_t nbvtf_img_size( int w
, int h
, EImageFormat_t format
)
732 int block_count
= nbvtf__max(1, ((w
+ 3) / 4)) *
733 nbvtf__max(1, ((h
+ 3) / 4));
737 case k_EImageFormat_RGBA8888
:
738 case k_EImageFormat_ABGR8888
:
739 case k_EImageFormat_ARGB8888
:
740 case k_EImageFormat_BGRA8888
:
743 case k_EImageFormat_RGB888
:
744 case k_EImageFormat_BGR888
:
747 case k_EImageFormat_RGB565
:
748 case k_EImageFormat_IA88
:
751 case k_EImageFormat_I8
:
754 case k_EImageFormat_DXT1
:
755 return block_count
* BLOCK_SIZE_DXT1
;
757 case k_EImageFormat_DXT5
:
758 return block_count
* BLOCK_SIZE_DXT5
;
765 static void nbvtf_read_img_data( uint8_t *src
, int w
, int h
,
766 EImageFormat_t format
, uint8_t *dst
)
770 case k_EImageFormat_RGBA8888
:
771 for( int i
=0; i
<w
*h
*4; i
++ )
775 case k_EImageFormat_ABGR8888
:
776 for( int i
=0; i
<w
*h
; i
++ )
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];
785 case k_EImageFormat_RGB888
:
786 for( int i
=0; i
<w
*h
; i
++ )
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];
795 case k_EImageFormat_BGR888
:
796 for( int i
=0; i
<w
*h
; i
++ )
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];
805 case k_EImageFormat_RGB565
:
806 case k_EImageFormat_I8
:
807 case k_EImageFormat_IA88
:
811 case k_EImageFormat_ARGB8888
:
812 for( int i
=0; i
<w
*h
; i
++ )
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];
821 case k_EImageFormat_BGRA8888
:
822 for( int i
=0; i
<w
*h
; i
++ )
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];
831 case k_EImageFormat_DXT1
:
832 nbvtf_decompress_dxt( src
, w
, h
, 0, dst
);
835 case k_EImageFormat_DXT5
:
836 nbvtf_decompress_dxt( src
, w
, h
, 1, dst
);
845 __attribute__((visibility("default")))
847 int nbvtf_write_dds_dxt1( uint8_t *reference
, int w
, int h
, int qual
, const char *dest
)
849 if( !nbvtf_power2x(w
,h
) )
851 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w
, h
);
855 struct DDS_HEADER header
= {0};
856 header
.dwSize
= DDS_HEADER_SIZE
;
857 header
.dwFlags
= DDSD_CAPS
| DDSD_HEIGHT
| DDSD_WIDTH
| DDSD_PIXELFORMAT
;
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) |
865 ((uint32_t)'T'<<16) |
868 header
.dwFlags
|= DDSD_LINEARSIZE
;
869 header
.dwMipMapCount
= 0;
870 header
.dwCaps
= DDSCAPS_TEXTURE
;
873 uint32_t magic
= DDS_MAGICNUM
;
875 FILE *file
= fopen( dest
, "wb" );
876 fwrite( &magic
, sizeof(uint32_t), 1, file
);
877 fwrite( &header
, DDS_HEADER_SIZE
, 1, file
);
879 uint32_t size_highres
= nbvtf_sizeimg( w
, h
, k_EImageFormat_DXT1
);
880 uint8_t *working_buffer
= malloc( size_highres
);
882 nbvtf_compress_dxt( reference
, w
, h
, 0, qual
, working_buffer
);
883 fwrite( working_buffer
, size_highres
, 1, file
);
885 free( working_buffer
);
890 static void nbvtf_correct_normal( uint8_t *src
, uint8_t *dst
, int w
, int h
)
892 for( int i
=0; i
< w
*h
; i
++ )
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];
902 __attribute__((visibility("default")))
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
)
907 if( !nbvtf_power2x(w
,h
) )
909 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w
, h
);
913 mipimg_t mip_offsets
[ 16 ];
918 // Convert to directx normal
919 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
921 src
= malloc( w
*h
*4 );
922 nbvtf_correct_normal( reference
, src
, w
, h
);
927 uint8_t *mip_data
= nbvtf_create_mipmaps( src
, w
, h
, mip_offsets
, &num_mips
);
931 NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
933 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
939 vtfheader_t header
= {0};
941 header
.usig
= 0x00465456;
942 header
.headerSize
= sizeof( vtfheader_t
);
943 header
.version
[0] = 7;
944 header
.version
[1] = 2;
948 header
.flags
= usr_flags
;
950 // Append format flags
953 header
.flags
|= TEXTUREFLAGS_NOLOD
;
954 header
.flags
|= TEXTUREFLAGS_NOMIP
;
957 if( format
== k_EImageFormat_DXT5
|| format
== k_EImageFormat_ABGR8888
)
959 header
.flags
|= TEXTUREFLAGS_EIGHTBITALPHA
;
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
;
967 header
.highResImageFormat
= format
;
968 header
.mipmapCount
= mipmap
?
969 nbvtf__min(num_mips
,NBVTF_MAX_MIPLEVELS
)+1: 1;
971 header
.lowResImageFormat
= k_EImageFormat_DXT1
;
974 header
.numResources
= 0;
976 int lr_index
= nbvtf_lowres_index( w
, h
);
982 mipimg_t
*mip
= mip_offsets
+ (lr_index
-1);
983 lr_src
= mip_data
+ mip
->src_offset
;
985 header
.lowResImageWidth
= mip
->w
;
986 header
.lowResImageHeight
= mip
->h
;
992 header
.lowResImageWidth
= w
;
993 header
.lowResImageHeight
= h
;
996 uint32_t size_highres
= nbvtf_sizeimg( w
, h
, format
);
997 uint32_t size_lowres
=
998 nbvtf_dxt_sizeimg( header
.lowResImageWidth
, header
.lowResImageHeight
, 0 );
1000 uint8_t *working_buffer
=
1001 (uint8_t *)malloc( nbvtf__max( size_highres
, size_lowres
) );
1003 if( !working_buffer
)
1005 NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
1008 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
1014 FILE *file
= fopen( dest
, "wb" );
1018 NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
1020 free( working_buffer
);
1023 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
1030 fwrite( &header
, sizeof( vtfheader_t
), 1, file
);
1033 nbvtf_write_img_data(
1034 lr_src
, header
.lowResImageWidth
, header
.lowResImageHeight
,
1035 k_EImageFormat_DXT1
, qual
, working_buffer
, file
1038 // Write texture data
1041 // !! Experimental !!
1042 int start
= nbvtf__max( 0, num_mips
-NBVTF_MAX_MIPLEVELS
);
1044 for( int i
= start
; i
< num_mips
; i
++ )
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
);
1052 // Write high resolution
1053 nbvtf_write_img_data( src
, w
, h
, format
, qual
, working_buffer
, file
);
1057 free( working_buffer
);
1060 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
1067 __attribute__((visibility("default")))
1069 uint8_t *nbvtf_read( vtfheader_t
*header
, int32_t *w
, int32_t *h
, int normal
)
1072 *h
= header
->height
;
1074 uint8_t *rgba
= malloc( header
->width
* header
->height
* 4 );
1080 int x
= header
->width
,
1085 while( nbvtf_lower( &x
, &y
) )
1087 if( mip_iter
== header
->mipmapCount
)
1091 memory
+= nbvtf_img_size( x
, y
, header
->highResImageFormat
);
1094 if( header
->lowResImageWidth
== 0 || header
->lowResImageHeight
== 0 ||
1095 header
->lowResImageFormat
== 0xffffffff )
1100 memory
+= nbvtf_img_size( header
->lowResImageWidth
,
1101 header
->lowResImageHeight
,
1102 header
->lowResImageFormat
);
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
,
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 );
1117 stbi_write_png( "/tmp/cxr_hello.png", header
->width
, header
->height
,
1118 4, rgba
, header
->width
*4 );
1125 __attribute__((visibility("default")))
1127 uint8_t *nbvtf_raw_data( vtfheader_t
*header
, int32_t *w
, int32_t *h
, int32_t *format
)
1130 *h
= header
->height
;
1131 *format
= header
->highResImageFormat
;
1133 return ((uint8_t *)header
) + header
->headerSize
;
1137 __attribute__((visibility("default")))
1139 void nbvtf_free( uint8_t *data
)
1145 __attribute__((visibility("default")))
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
)
1150 if( (w
&& h
) && !nbvtf_power2x(w
,h
) )
1152 NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w
, h
);
1157 uint8_t *data
= stbi_load( src
, &x
, &y
, &n
, 4 );
1161 if( !nbvtf_power2x(x
,y
) )
1163 NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x
, y
);
1164 stbi_image_free( data
);
1168 // Image size needs to be made smaller
1169 if( (w
&& h
) && ( x
> w
|| y
> h
) )
1171 nbvtf_downscale( data
, x
, y
, w
, h
, data
);
1176 int status
= nbvtf_write( data
, x
,y
, mipmap
, format
, qual
, usr_flags
, dest
);
1178 stbi_image_free( data
);
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 ------------------------------------------------------------------------------