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
62 #include "stb/stb_image.h"
67 #define STB_DXT_IMPLEMENTATION
68 #include "stb/stb_dxt.h"
71 #ifdef NBVTF_SHOW_STDERR
72 #define NBVTF_ERR(...)
74 #define NBVTF_ERR(...) fprintf( stderr, __VA_ARGS__ )
79 typedef enum EImageFormat
82 k_EImageFormat_NONE
= -1,
83 k_EImageFormat_RGBA8888
= 0, // YES
84 k_EImageFormat_ABGR8888
,
85 k_EImageFormat_RGB888
, // YES
86 k_EImageFormat_BGR888
,
87 k_EImageFormat_RGB565
,
92 k_EImageFormat_RGB888_BLUESCREEN
,
93 k_EImageFormat_BGR888_BLUESCREEN
,
94 k_EImageFormat_ARGB8888
,
95 k_EImageFormat_BGRA8888
,
96 k_EImageFormat_DXT1
, // YES
98 k_EImageFormat_DXT5
, // YES
99 k_EImageFormat_BGRX8888
,
100 k_EImageFormat_BGR565
,
101 k_EImageFormat_BGRX5551
,
102 k_EImageFormat_BGRA4444
,
103 k_EImageFormat_DXT1_ONEBITALPHA
,
104 k_EImageFormat_BGRA5551
,
106 k_EImageFormat_UVWQ8888
,
107 k_EImageFormat_RGBA16161616F
,
108 k_EImageFormat_RGBA16161616
,
109 k_EImageFormat_UVLX8888
112 const char *vtf_format_strings
[] =
114 // Name // Supported?
154 // Flags from the *.txt config file
155 TEXTUREFLAGS_POINTSAMPLE
= 0x00000001,
156 TEXTUREFLAGS_TRILINEAR
= 0x00000002,
157 TEXTUREFLAGS_CLAMPS
= 0x00000004,
158 TEXTUREFLAGS_CLAMPT
= 0x00000008,
159 TEXTUREFLAGS_ANISOTROPIC
= 0x00000010,
160 TEXTUREFLAGS_HINT_DXT5
= 0x00000020,
161 TEXTUREFLAGS_PWL_CORRECTED
= 0x00000040,
162 TEXTUREFLAGS_NORMAL
= 0x00000080,
163 TEXTUREFLAGS_NOMIP
= 0x00000100,
164 TEXTUREFLAGS_NOLOD
= 0x00000200,
165 TEXTUREFLAGS_ALL_MIPS
= 0x00000400,
166 TEXTUREFLAGS_PROCEDURAL
= 0x00000800,
168 // These are automatically generated by vtex from the texture data.
169 TEXTUREFLAGS_ONEBITALPHA
= 0x00001000,
170 TEXTUREFLAGS_EIGHTBITALPHA
= 0x00002000,
172 // Newer flags from the *.txt config file
173 TEXTUREFLAGS_ENVMAP
= 0x00004000,
174 TEXTUREFLAGS_RENDERTARGET
= 0x00008000,
175 TEXTUREFLAGS_DEPTHRENDERTARGET
= 0x00010000,
176 TEXTUREFLAGS_NODEBUGOVERRIDE
= 0x00020000,
177 TEXTUREFLAGS_SINGLECOPY
= 0x00040000,
178 TEXTUREFLAGS_PRE_SRGB
= 0x00080000,
180 TEXTUREFLAGS_UNUSED_00100000
= 0x00100000,
181 TEXTUREFLAGS_UNUSED_00200000
= 0x00200000,
182 TEXTUREFLAGS_UNUSED_00400000
= 0x00400000,
184 TEXTUREFLAGS_NODEPTHBUFFER
= 0x00800000,
186 TEXTUREFLAGS_UNUSED_01000000
= 0x01000000,
188 TEXTUREFLAGS_CLAMPU
= 0x02000000,
189 TEXTUREFLAGS_VERTEXTEXTURE
= 0x04000000,
190 TEXTUREFLAGS_SSBUMP
= 0x08000000,
192 TEXTUREFLAGS_UNUSED_10000000
= 0x10000000,
194 TEXTUREFLAGS_BORDER
= 0x20000000,
196 TEXTUREFLAGS_UNUSED_40000000
= 0x40000000,
197 TEXTUREFLAGS_UNUSED_80000000
= 0x80000000,
200 typedef struct vtfheader
204 char signature
[4]; // File signature ("VTF\0"). (or as little-endian integer, 0x00465456)
208 unsigned int version
[2]; // version[0].version[1] (currently 7.2).
209 unsigned int headerSize
; // Size of the header struct (16 byte aligned; currently 80 bytes) + size of the resources dictionary (7.3+).
210 unsigned short width
; // Width of the largest mipmap in pixels. Must be a power of 2.
211 unsigned short height
; // Height of the largest mipmap in pixels. Must be a power of 2.
212 unsigned int flags
; // VTF flags.
213 unsigned short frames
; // Number of frames, if animated (1 for no animation).
214 unsigned short firstFrame
; // First frame in animation (0 based).
215 unsigned char padding0
[4]; // reflectivity padding (16 byte alignment).
216 float reflectivity
[3]; // reflectivity vector.
217 unsigned char padding1
[4]; // reflectivity padding (8 byte packing).
218 float bumpmapScale
; // Bumpmap scale.
219 unsigned int highResImageFormat
; // High resolution image format.
220 unsigned char mipmapCount
; // Number of mipmaps.
221 unsigned int lowResImageFormat
; // Low resolution image format (always DXT1).
222 unsigned char lowResImageWidth
; // Low resolution image width.
223 unsigned char lowResImageHeight
; // Low resolution image height.
226 unsigned short depth
; // Depth of the largest mipmap in pixels.
227 // Must be a power of 2. Can be 0 or 1 for a 2D texture (v7.2 only).
230 unsigned char padding2
[3]; // depth padding (4 byte alignment).
231 unsigned int numResources
; // Number of resources this vtf has
233 unsigned char padding3
[8]; // Necessary on certain compilers
238 typedef struct mipimg
245 int nbvtf_power2( uint32_t x
)
247 return (x
!= 0) && ((x
& (x
- 1)) == 0);
250 int nbvtf_power2x( uint32_t y
, uint32_t x
)
252 return nbvtf_power2( y
) && nbvtf_power2( x
);
255 int nbvtf_lower( int *x
, int *y
)
257 if( *x
== 1 && *y
== 1 )
262 *x
= nbvtf__max( 1, (*x
)/2 );
263 *y
= nbvtf__max( 1, (*y
)/2 );
268 int nbvtf_lowres_index( int w
, int h
)
278 if( (x
<= 16) && ( y
<= 16 ) )
285 nbvtf_lower( &x
, &y
);
289 // Simple box filter downscale
290 void nbvtf_downscale( uint8_t *src
, int w
, int h
, int dw
, int dh
, uint8_t *dest
)
296 for( int y
= 0; y
< dh
; y
++ )
297 for( int x
= 0; x
< dw
; x
++ )
299 // Average block colours
300 uint32_t tr
= 0, tg
= 0, tb
= 0, ta
= 0;
302 for( int yy
= 0; yy
< by
; yy
++ )
303 for( int xx
= 0; xx
< bx
; xx
++ )
305 uint8_t *psrc
= &src
[ (x
*bx
+xx
+ (y
*by
+yy
)*w
)*4 ];
312 uint8_t *pdst
= &dest
[ (y
*dw
+ x
)*4 ];
320 uint8_t *nbvtf_create_mipmaps( uint8_t *src
, int w
, int h
, mipimg_t
*offsets
, int *num
)
328 while( nbvtf_lower( &x
, &y
) )
331 uint8_t *mipmem
= (uint8_t *)malloc( memory
);
340 uint8_t *dest
= mipmem
;
344 if( !nbvtf_lower( &x
, &y
) )
347 nbvtf_downscale( src
, w
, h
, x
, y
, dest
);
349 offsets
[ i
].src_offset
= offset
;
355 dest
= mipmem
+ offset
;
363 NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
368 void nbvtf_reflectivity( uint8_t *src
, int w
, int h
, float *dest
)
370 uint32_t totals
[3] = {0,0,0};
372 for( int i
= 0; i
< w
*h
; i
++ )
374 totals
[0] += src
[i
*4+0];
375 totals
[1] += src
[i
*4+1];
376 totals
[2] += src
[i
*4+2];
379 dest
[0] = (float)( totals
[0] / (w
*h
) ) / 255.0f
;
380 dest
[1] = (float)( totals
[1] / (w
*h
) ) / 255.0f
;
381 dest
[2] = (float)( totals
[2] / (w
*h
) ) / 255.0f
;
384 #ifdef NBVTF_ALLOW_EXPORT
385 void nbvtf_debug_view_mips( uint8_t *src
, int w
, int h
)
396 while( nbvtf_lower( &x
, &y
) )
398 sprintf( fnbuf
, "mip_%d.png", i
++ );
400 stbi_write_png( fnbuf
, x
,y
, 4, dest
, x
*4 );
406 void nbvtf_dxt_pad( uint8_t *src
, int bx
, int by
, int w
, int h
, uint8_t *dest
)
411 uint32_t *stream
= (uint32_t *)src
;
412 uint32_t *stream_out
= (uint32_t *)dest
;
414 for( int y
= 0; y
< 4; y
++ )
416 for( int x
= 0; x
< 4; x
++ )
418 stream_out
[ y
*4+x
] = stream
[ nbvtf__min( py
+y
, h
-1 )*w
+ nbvtf__min( px
+x
, w
-1 ) ];
423 uint32_t nbvtf_dxt_sizeimg( int w
, int h
, int alpha
)
425 uint32_t blocks_x
, blocks_y
;
426 int block_size
= alpha
? 16: 8;
428 blocks_x
= ((uint32_t)w
) >> 2;
429 blocks_y
= ((uint32_t)h
) >> 2;
431 int padx
= w
% 4 != 0? 1: 0;
432 int pady
= h
% 4 != 0? 1: 0;
434 return (blocks_x
+padx
)*(blocks_y
+pady
)*block_size
;
437 uint32_t nbvtf_sizeimg( int w
, int h
, EImageFormat_t format
)
439 if( format
== k_EImageFormat_DXT5
|| format
== k_EImageFormat_DXT1
)
441 return nbvtf_dxt_sizeimg( w
, h
, format
== k_EImageFormat_DXT1
? 0: 1 );
444 if( format
== k_EImageFormat_BGR888
)
447 if( format
== k_EImageFormat_ABGR8888
)
454 __attribute__((visibility("default")))
456 void nbvtf_init(void)
463 void nbvtf_dxt_block( uint8_t *dest
, uint8_t *src
, int alpha
, int qual
)
468 rgbcx__encode_bc3( qual
, dest
, src
);
472 rgbcx__encode_bc1( qual
, dest
, src
, 0, 0 );
475 stb_compress_dxt_block( dest
, src
, alpha
, STB_DXT_HIGHQUAL
);
479 void nbvtf_compress_dxt( uint8_t *src
, int w
, int h
, int alpha
, int qual
,
482 uint32_t blocks_x
, blocks_y
;
484 blocks_x
= ((uint32_t)w
) >> 2;
485 blocks_y
= ((uint32_t)h
) >> 2;
487 int padx
= w
% 4 != 0? 1: 0;
488 int pady
= h
% 4 != 0? 1: 0;
490 int block_size
= alpha
? 16: 8;
492 uint8_t *dest_block
= dest
;
494 uint8_t working_block
[ 4*4*4 ];
497 for( int y
= 0; y
< blocks_y
; y
++ )
499 for( int x
= 0; x
< blocks_x
; x
++ )
501 uint8_t *src_begin
= src
+ (y
*w
*4 + x
*4)*4;
502 for( int i
= 0; i
< 4; i
++ )
504 memcpy( working_block
+ i
*4*4, src_begin
+ w
*4*i
, 4*4 );
507 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
508 dest_block
+= block_size
;
513 nbvtf_dxt_pad( src
, blocks_x
, y
, w
, h
, working_block
);
514 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
515 dest_block
+= block_size
;
519 // Compress remainder row
522 for( int x
= 0; x
< blocks_x
; x
++ )
524 nbvtf_dxt_pad( src
, x
, blocks_y
, w
, h
, working_block
);
525 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
526 dest_block
+= block_size
;
530 // Compress last little corner
533 nbvtf_dxt_pad( src
, blocks_x
, blocks_y
, w
, h
, working_block
);
534 nbvtf_dxt_block( dest_block
, working_block
, alpha
, qual
);
538 void nbvtf_swizzle_to( uint8_t *src
, int n
, int nc
, uint8_t *dest
)
540 for( int i
= 0; i
< n
; i
++ )
542 for( int j
= 0; j
< nc
; j
++ )
544 dest
[ i
*nc
+nc
-j
-1 ] = src
[ i
*4+j
];
549 void nbvtf_write_img_data( uint8_t *src
, int w
, int h
,
550 EImageFormat_t format
, int qual
, uint8_t *wb
, FILE *file
)
554 case k_EImageFormat_DXT1
:
555 nbvtf_compress_dxt( src
, w
, h
, 0, qual
, wb
);
556 fwrite( wb
, nbvtf_dxt_sizeimg( w
, h
, 0 ), 1, file
);
558 case k_EImageFormat_DXT5
:
559 nbvtf_compress_dxt( src
, w
, h
, 1, qual
, wb
);
560 fwrite( wb
, nbvtf_dxt_sizeimg( w
, h
, 1 ), 1, file
);
562 case k_EImageFormat_ABGR8888
:
563 nbvtf_swizzle_to( src
, w
*h
, 4, wb
);
564 fwrite( wb
, w
*h
*4, 1, file
);
566 case k_EImageFormat_BGR888
:
567 nbvtf_swizzle_to( src
, w
*h
, 3, wb
);
568 fwrite( wb
, w
*h
*3, 1, file
);
577 __attribute__((visibility("default")))
579 int nbvtf_write( uint8_t *reference
, int w
, int h
, int mipmap
,
580 EImageFormat_t format
, int qual
, uint32_t usr_flags
, const char *dest
)
582 if( !nbvtf_power2x(w
,h
) )
584 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w
, h
);
588 mipimg_t mip_offsets
[ 16 ];
593 // Convert to directx normal
594 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
596 src
= malloc( w
*h
*4 );
597 for( int i
= 0; i
< w
*h
; i
++ )
599 src
[i
*4+0] = reference
[i
*4+0];
600 src
[i
*4+1] = 0xFF-reference
[i
*4+1];
601 src
[i
*4+2] = reference
[i
*4+2];
602 src
[i
*4+3] = reference
[i
*4+3];
608 uint8_t *mip_data
= nbvtf_create_mipmaps( src
, w
, h
, mip_offsets
, &num_mips
);
612 NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
614 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
620 vtfheader_t header
= {0};
622 header
.usig
= 0x00465456;
623 header
.headerSize
= sizeof( vtfheader_t
);
624 header
.version
[0] = 7;
625 header
.version
[1] = 2;
629 header
.flags
= usr_flags
;
631 // Append format flags
634 header
.flags
|= TEXTUREFLAGS_NOLOD
;
635 header
.flags
|= TEXTUREFLAGS_NOMIP
;
638 if( format
== k_EImageFormat_DXT5
|| format
== k_EImageFormat_ABGR8888
)
640 header
.flags
|= TEXTUREFLAGS_EIGHTBITALPHA
;
644 header
.firstFrame
= 0;
645 nbvtf_reflectivity( mip_data
+ mip_offsets
[ num_mips
-1 ].src_offset
, 1,1, header
.reflectivity
);
646 header
.bumpmapScale
= 1.0f
;
648 header
.highResImageFormat
= format
;
649 header
.mipmapCount
= mipmap
?
650 nbvtf__min(num_mips
,NBVTF_MAX_MIPLEVELS
)+1: 1;
652 header
.lowResImageFormat
= k_EImageFormat_DXT1
;
655 header
.numResources
= 0;
657 int lr_index
= nbvtf_lowres_index( w
, h
);
663 mipimg_t
*mip
= mip_offsets
+ (lr_index
-1);
664 lr_src
= mip_data
+ mip
->src_offset
;
666 header
.lowResImageWidth
= mip
->w
;
667 header
.lowResImageHeight
= mip
->h
;
673 header
.lowResImageWidth
= w
;
674 header
.lowResImageHeight
= h
;
677 uint32_t size_highres
= nbvtf_sizeimg( w
, h
, format
);
678 uint32_t size_lowres
=
679 nbvtf_dxt_sizeimg( header
.lowResImageWidth
, header
.lowResImageHeight
, 0 );
681 uint8_t *working_buffer
=
682 (uint8_t *)malloc( nbvtf__max( size_highres
, size_lowres
) );
684 if( !working_buffer
)
686 NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
689 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
695 FILE *file
= fopen( dest
, "wb" );
699 NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
701 free( working_buffer
);
704 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
711 fwrite( &header
, sizeof( vtfheader_t
), 1, file
);
714 nbvtf_write_img_data(
715 lr_src
, header
.lowResImageWidth
, header
.lowResImageHeight
,
716 k_EImageFormat_DXT1
, qual
, working_buffer
, file
719 // Write texture data
722 // !! Experimental !!
723 int start
= nbvtf__max( 0, num_mips
-NBVTF_MAX_MIPLEVELS
);
725 for( int i
= start
; i
< num_mips
; i
++ )
727 mipimg_t
*mip
= mip_offsets
+ (num_mips
- i
-1);
728 nbvtf_write_img_data( mip_data
+ mip
->src_offset
, mip
->w
, mip
->h
,
729 format
, qual
, working_buffer
, file
);
733 // Write high resolution
734 nbvtf_write_img_data( src
, w
, h
, format
, qual
, working_buffer
, file
);
738 free( working_buffer
);
741 if( usr_flags
& TEXTUREFLAGS_NORMAL
)
748 __attribute__((visibility("default")))
750 int nbvtf_convert( const char *src
, int w
, int h
, int mipmap
,
751 EImageFormat_t format
, int qual
, uint32_t usr_flags
, const char *dest
)
753 if( (w
&& h
) && !nbvtf_power2x(w
,h
) )
755 NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w
, h
);
760 uint8_t *data
= stbi_load( src
, &x
, &y
, &n
, 4 );
764 if( !nbvtf_power2x(x
,y
) )
766 NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x
, y
);
767 stbi_image_free( data
);
771 // Image size needs retargeting
772 if( (w
&& h
) && ( x
> w
|| y
> h
) )
773 nbvtf_downscale( data
, x
, y
, w
, h
, data
);
775 int status
= nbvtf_write( data
, w
, h
, mipmap
, format
, qual
,
778 stbi_image_free( data
);
793 LICENSE - Applies to nbvtf.h, pynbvtf.py, librgbcx.cc, librgbcx.h, vtf_cmd.c
794 ------------------------------------------------------------------------------
795 Public Domain (www.unlicense.org)
796 This is free and unencumbered software released into the public domain.
797 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
798 software, either in source code form or as a compiled binary, for any purpose,
799 commercial or non-commercial, and by any means.
800 In jurisdictions that recognize copyright laws, the author or authors of this
801 software dedicate any and all copyright interest in the software to the public
802 domain. We make this dedication for the benefit of the public at large and to
803 the detriment of our heirs and successors. We intend this dedication to be an
804 overt act of relinquishment in perpetuity of all present and future rights to
805 this software under copyright law.
806 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
807 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
808 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
809 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
810 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
811 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
812 ------------------------------------------------------------------------------