aa82cbf6a302823416a011f99a956e89e0f43383
[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 #endif
61
62 #define STBI_NO_THREAD_LOCALS
63 #include "stb/stb_image.h"
64
65 #ifdef USE_LIBRGBCX
66 // #define RGBCX_NO_ALGORITHM
67 #include "librgbcx.h"
68 #define HAS_DXT_COMPRESSOR
69 #endif
70
71 #if USE_STB_DXT
72 #define STB_DXT_IMPLEMENTATION
73 #include "stb/stb_dxt.h"
74 #define HAS_DXT_COMPRESSOR
75 #endif
76
77 #ifndef HAS_DXT_COMPRESSOR
78 #warning No DXT compressor specified! S3 Output will be invalid.
79 #endif
80
81 #ifdef NBVTF_SHOW_STDERR
82 #define NBVTF_ERR(...)
83 #else
84 #define NBVTF_ERR(...) fprintf( stderr, __VA_ARGS__ )
85 #endif
86
87 #pragma pack(push, 1)
88
89 typedef enum EImageFormat
90 {
91 // Name // Supported?
92 k_EImageFormat_NONE = -1,
93 k_EImageFormat_RGBA8888 = 0, // YES
94 k_EImageFormat_ABGR8888,
95 k_EImageFormat_RGB888, // YES
96 k_EImageFormat_BGR888,
97 k_EImageFormat_RGB565,
98 k_EImageFormat_I8,
99 k_EImageFormat_IA88,
100 k_EImageFormat_P8,
101 k_EImageFormat_A8,
102 k_EImageFormat_RGB888_BLUESCREEN,
103 k_EImageFormat_BGR888_BLUESCREEN,
104 k_EImageFormat_ARGB8888,
105 k_EImageFormat_BGRA8888,
106 k_EImageFormat_DXT1, // YES
107 k_EImageFormat_DXT3,
108 k_EImageFormat_DXT5, // YES
109 k_EImageFormat_BGRX8888,
110 k_EImageFormat_BGR565,
111 k_EImageFormat_BGRX5551,
112 k_EImageFormat_BGRA4444,
113 k_EImageFormat_DXT1_ONEBITALPHA,
114 k_EImageFormat_BGRA5551,
115 k_EImageFormat_UV88,
116 k_EImageFormat_UVWQ8888,
117 k_EImageFormat_RGBA16161616F,
118 k_EImageFormat_RGBA16161616,
119 k_EImageFormat_UVLX8888
120 } EImageFormat_t;
121
122 const char *vtf_format_strings[] =
123 {
124 // Name // Supported?
125 "RGBA8888",
126 "ABGR8888",
127 "RGB888",
128 "BGR888",
129 "RGB565",
130 "I8",
131 "IA88",
132 "P8",
133 "A8",
134 "RGB888_BLUESCREEN",
135 "BGR888_BLUESCREEN",
136 "ARGB8888",
137 "BGRA8888",
138 #ifdef USE_LIBRGBCX
139 "DXT1 (rgbcx.h)",
140 #else
141 "DXT1 (stb_dxt.h)",
142 #endif
143 "DXT3",
144 #ifdef USE_LIBRGBCX
145 "DXT5 (rgbcx.h)",
146 #else
147 "DXT5 (stb_dxt.h)",
148 #endif
149 "BGRX8888",
150 "BGR565",
151 "BGRX5551",
152 "BGRA4444",
153 "DXT1_ONEBITALPHA",
154 "BGRA5551",
155 "UV88",
156 "UVWQ8888",
157 "RGBA16161616F",
158 "RGBA16161616",
159 "UVLX8888"
160 };
161
162 enum flag
163 {
164 // Flags from the *.txt config file
165 TEXTUREFLAGS_POINTSAMPLE = 0x00000001,
166 TEXTUREFLAGS_TRILINEAR = 0x00000002,
167 TEXTUREFLAGS_CLAMPS = 0x00000004,
168 TEXTUREFLAGS_CLAMPT = 0x00000008,
169 TEXTUREFLAGS_ANISOTROPIC = 0x00000010,
170 TEXTUREFLAGS_HINT_DXT5 = 0x00000020,
171 TEXTUREFLAGS_PWL_CORRECTED = 0x00000040,
172 TEXTUREFLAGS_NORMAL = 0x00000080,
173 TEXTUREFLAGS_NOMIP = 0x00000100,
174 TEXTUREFLAGS_NOLOD = 0x00000200,
175 TEXTUREFLAGS_ALL_MIPS = 0x00000400,
176 TEXTUREFLAGS_PROCEDURAL = 0x00000800,
177
178 // These are automatically generated by vtex from the texture data.
179 TEXTUREFLAGS_ONEBITALPHA = 0x00001000,
180 TEXTUREFLAGS_EIGHTBITALPHA = 0x00002000,
181
182 // Newer flags from the *.txt config file
183 TEXTUREFLAGS_ENVMAP = 0x00004000,
184 TEXTUREFLAGS_RENDERTARGET = 0x00008000,
185 TEXTUREFLAGS_DEPTHRENDERTARGET = 0x00010000,
186 TEXTUREFLAGS_NODEBUGOVERRIDE = 0x00020000,
187 TEXTUREFLAGS_SINGLECOPY = 0x00040000,
188 TEXTUREFLAGS_PRE_SRGB = 0x00080000,
189
190 TEXTUREFLAGS_UNUSED_00100000 = 0x00100000,
191 TEXTUREFLAGS_UNUSED_00200000 = 0x00200000,
192 TEXTUREFLAGS_UNUSED_00400000 = 0x00400000,
193
194 TEXTUREFLAGS_NODEPTHBUFFER = 0x00800000,
195
196 TEXTUREFLAGS_UNUSED_01000000 = 0x01000000,
197
198 TEXTUREFLAGS_CLAMPU = 0x02000000,
199 TEXTUREFLAGS_VERTEXTEXTURE = 0x04000000,
200 TEXTUREFLAGS_SSBUMP = 0x08000000,
201
202 TEXTUREFLAGS_UNUSED_10000000 = 0x10000000,
203
204 TEXTUREFLAGS_BORDER = 0x20000000,
205
206 TEXTUREFLAGS_UNUSED_40000000 = 0x40000000,
207 TEXTUREFLAGS_UNUSED_80000000 = 0x80000000,
208 };
209
210 typedef struct vtfheader
211 {
212 union
213 {
214 char signature[4]; // File signature ("VTF\0"). (or as little-endian integer, 0x00465456)
215 uint32_t usig;
216 };
217
218 unsigned int version[2]; // version[0].version[1] (currently 7.2).
219 unsigned int headerSize; // Size of the header struct (16 byte aligned; currently 80 bytes) + size of the resources dictionary (7.3+).
220 unsigned short width; // Width of the largest mipmap in pixels. Must be a power of 2.
221 unsigned short height; // Height of the largest mipmap in pixels. Must be a power of 2.
222 unsigned int flags; // VTF flags.
223 unsigned short frames; // Number of frames, if animated (1 for no animation).
224 unsigned short firstFrame; // First frame in animation (0 based).
225 unsigned char padding0[4]; // reflectivity padding (16 byte alignment).
226 float reflectivity[3]; // reflectivity vector.
227 unsigned char padding1[4]; // reflectivity padding (8 byte packing).
228 float bumpmapScale; // Bumpmap scale.
229 unsigned int highResImageFormat; // High resolution image format.
230 unsigned char mipmapCount; // Number of mipmaps.
231 unsigned int lowResImageFormat; // Low resolution image format (always DXT1).
232 unsigned char lowResImageWidth; // Low resolution image width.
233 unsigned char lowResImageHeight; // Low resolution image height.
234
235 // 7.2+
236 unsigned short depth; // Depth of the largest mipmap in pixels.
237 // Must be a power of 2. Can be 0 or 1 for a 2D texture (v7.2 only).
238
239 // 7.3+
240 unsigned char padding2[3]; // depth padding (4 byte alignment).
241 unsigned int numResources; // Number of resources this vtf has
242
243 unsigned char padding3[8]; // Necessary on certain compilers
244 } vtfheader_t;
245
246 #pragma pack(pop)
247
248 #pragma pack(push, 1)
249 struct DDS_PIXELFORMAT
250 {
251 uint32_t dwSize;
252 uint32_t dwFlags;
253 uint32_t dwFourCC;
254 uint32_t dwRGBBitCount;
255 uint32_t dwRBitMask;
256 uint32_t dwGBitMask;
257 uint32_t dwBBitMask;
258 uint32_t dwABitMask;
259 };
260
261 struct DDS_HEADER {
262 uint32_t dwSize;
263 uint32_t dwFlags;
264 uint32_t dwHeight;
265 uint32_t dwWidth;
266 uint32_t dwPitchOrLinearSize;
267 uint32_t dwDepth;
268 uint32_t dwMipMapCount;
269 uint32_t dwReserved1[11];
270 struct DDS_PIXELFORMAT ddspf;
271 uint32_t dwCaps;
272 uint32_t dwCaps2;
273 uint32_t dwCaps3;
274 uint32_t dwCaps4;
275 uint32_t dwReserved2;
276 };
277
278 #pragma pack(pop)
279
280 uint32_t swap_endian(uint32_t val)
281 {
282 return (val << 24) | ((val << 8) & 0x00ff0000) |
283 ((val >> 8) & 0x0000ff00) | (val >> 24);
284 }
285
286 #define DDSD_CAPS 0x1
287 #define DDSD_HEIGHT 0x2
288 #define DDSD_WIDTH 0x4
289 #define DDSD_PITCH 0x8
290 #define DDSD_PIXELFORMAT 0x1000
291 #define DDSD_MIPMAPCOUNT 0x20000
292 #define DDSD_LINEARSIZE 0x80000
293 #define DDSD_DEPTH 0x800000
294
295 #define DDPF_ALPHAPIXELS 0x1
296 #define DDPF_ALPHA 0x2
297 #define DDPF_FOURCC 0x4
298 #define DDPF_RGB 0x40
299 #define DDPF_YUV 0x200
300 #define DDPF_LUMINANCE 0x20000
301
302 #define DDSCAPS_COMPLEX 0x8
303 #define DDSCAPS_MIPMAP 0x400000
304 #define DDSCAPS_TEXTURE 0x1000
305
306 #define BLOCK_SIZE_DXT1 8
307 #define BLOCK_SIZE_DXT5 16
308
309 #define BBP_RGB888 24
310 #define BBP_RGBA8888 32
311
312 #define DDS_HEADER_SIZE 124
313 #define DDS_HEADER_PFSIZE 32
314 #define DDS_MAGICNUM 0x20534444;
315
316 #define DDS_FLIP_VERTICALLY_ON_WRITE
317
318 typedef struct mipimg
319 {
320 uint32_t w;
321 uint32_t h;
322 uint32_t src_offset;
323 } mipimg_t;
324
325 int nbvtf_power2( uint32_t x )
326 {
327 return (x != 0) && ((x & (x - 1)) == 0);
328 }
329
330 int nbvtf_power2x( uint32_t y, uint32_t x )
331 {
332 return nbvtf_power2( y ) && nbvtf_power2( x );
333 }
334
335 int nbvtf_lower( int *x, int *y )
336 {
337 if( *x == 1 && *y == 1 )
338 {
339 return 0;
340 }
341
342 *x = nbvtf__max( 1, (*x)/2 );
343 *y = nbvtf__max( 1, (*y)/2 );
344
345 return 1;
346 }
347
348 int nbvtf_lowres_index( int w, int h )
349 {
350 int x, y;
351 int i = 0;
352
353 x = w;
354 y = h;
355
356 while(1)
357 {
358 if( (x <= 16) && ( y <= 16 ) )
359 {
360 return i;
361 }
362
363 i ++;
364
365 nbvtf_lower( &x, &y );
366 }
367 }
368
369 // Simple box filter downscale
370 void nbvtf_downscale( uint8_t *src, int w, int h, int dw, int dh, uint8_t *dest )
371 {
372 int bx = w/dw;
373 int by = h/dh;
374 int div = bx*by;
375
376 for( int y = 0; y < dh; y ++ )
377 for( int x = 0; x < dw; x ++ )
378 {
379 // Average block colours
380 uint32_t tr = 0, tg = 0, tb = 0, ta = 0;
381
382 for( int yy = 0; yy < by; yy ++ )
383 for( int xx = 0; xx < bx; xx ++ )
384 {
385 uint8_t *psrc = &src[ (x*bx+xx + (y*by+yy)*w)*4 ];
386 tr+=psrc[0];
387 tg+=psrc[1];
388 tb+=psrc[2];
389 ta+=psrc[3];
390 }
391
392 uint8_t *pdst = &dest[ (y*dw + x)*4 ];
393 pdst[0] = tr / div;
394 pdst[1] = tg / div;
395 pdst[2] = tb / div;
396 pdst[3] = ta / div;
397 }
398 }
399
400 uint8_t *nbvtf_create_mipmaps( uint8_t *src, int w, int h, mipimg_t *offsets, int *num )
401 {
402 int memory = 0;
403 int x, y, i;
404 uint32_t offset;
405
406 x = w;
407 y = h;
408 while( nbvtf_lower( &x, &y ) )
409 memory += x*y*4;
410
411 uint8_t *mipmem = (uint8_t *)malloc( memory );
412
413 if( mipmem )
414 {
415 x = w;
416 y = h;
417 i = 0;
418 offset = 0;
419
420 uint8_t *dest = mipmem;
421
422 while(1)
423 {
424 if( !nbvtf_lower( &x, &y ) )
425 break;
426
427 nbvtf_downscale( src, w, h, x, y, dest );
428
429 offsets[ i ].src_offset = offset;
430 offsets[ i ].w = x;
431 offsets[ i ].h = y;
432 i ++;
433
434 offset += x*y*4;
435 dest = mipmem + offset;
436 }
437
438 *num = i;
439 return mipmem;
440 }
441 else
442 {
443 NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
444 return NULL;
445 }
446 }
447
448 void nbvtf_reflectivity( uint8_t *src, int w, int h, float *dest )
449 {
450 uint32_t totals[3] = {0,0,0};
451
452 for( int i = 0; i < w*h; i ++ )
453 {
454 totals[0] += src[i*4+0];
455 totals[1] += src[i*4+1];
456 totals[2] += src[i*4+2];
457 }
458
459 dest[0] = (float)( totals[0] / (w*h) ) / 255.0f;
460 dest[1] = (float)( totals[1] / (w*h) ) / 255.0f;
461 dest[2] = (float)( totals[2] / (w*h) ) / 255.0f;
462 }
463
464 #ifdef NBVTF_ALLOW_EXPORT
465 void nbvtf_debug_view_mips( uint8_t *src, int w, int h )
466 {
467 int x, y, i;
468 char fnbuf[512];
469
470 x = w;
471 y = h;
472 i = 1;
473
474 uint8_t *dest = src;
475
476 while( nbvtf_lower( &x, &y ) )
477 {
478 sprintf( fnbuf, "mip_%d.png", i ++ );
479
480 stbi_write_png( fnbuf, x,y, 4, dest, x*4 );
481 dest += x*y*4;
482 }
483 }
484 #endif
485
486 void nbvtf_dxt_pad( uint8_t *src, int bx, int by, int w, int h, uint8_t *dest )
487 {
488 int px = bx*4;
489 int py = by*4;
490
491 uint32_t *stream = (uint32_t *)src;
492 uint32_t *stream_out = (uint32_t *)dest;
493
494 for( int y = 0; y < 4; y ++ )
495 {
496 for( int x = 0; x < 4; x ++ )
497 {
498 stream_out[ y*4+x ] = stream[ nbvtf__min( py+y, h-1 )*w + nbvtf__min( px+x, w-1 ) ];
499 }
500 }
501 }
502
503 uint32_t nbvtf_dxt_sizeimg( int w, int h, int alpha )
504 {
505 uint32_t blocks_x, blocks_y;
506 int block_size = alpha? 16: 8;
507
508 blocks_x = ((uint32_t)w) >> 2;
509 blocks_y = ((uint32_t)h) >> 2;
510
511 int padx = w % 4 != 0? 1: 0;
512 int pady = h % 4 != 0? 1: 0;
513
514 return (blocks_x+padx)*(blocks_y+pady)*block_size;
515 }
516
517 uint32_t nbvtf_sizeimg( int w, int h, EImageFormat_t format )
518 {
519 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_DXT1 )
520 {
521 return nbvtf_dxt_sizeimg( w, h, format == k_EImageFormat_DXT1? 0: 1 );
522 }
523
524 if( format == k_EImageFormat_BGR888 )
525 return w*h*3;
526
527 if( format == k_EImageFormat_ABGR8888 )
528 return w*h*4;
529
530 return 0;
531 }
532
533 #ifdef NBVTF_AS_SO
534 __attribute__((visibility("default")))
535 #endif
536 void nbvtf_init(void)
537 {
538 #ifdef USE_LIBRGBCX
539 rgbcx__init();
540 #endif
541 }
542
543 void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha, int qual )
544 {
545 #ifdef USE_LIBRGBCX
546 if( alpha )
547 {
548 rgbcx__encode_bc3( qual, dest, src );
549 }
550 else
551 {
552 rgbcx__encode_bc1( qual, dest, src, 0, 0 );
553 }
554 #endif
555
556 #if USE_STB_DXT
557 stb_compress_dxt_block( dest, src, alpha, STB_DXT_HIGHQUAL );
558 #endif
559
560 #ifndef HAS_DXT_COMPRESSOR
561
562 for( int i=0; i<alpha? 16: 8; i++ )
563 dest[i] = i%1? 0xff: 0x00;
564 #endif
565 }
566
567 void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual,
568 uint8_t *dest )
569 {
570 uint32_t blocks_x, blocks_y;
571
572 blocks_x = ((uint32_t)w) >> 2;
573 blocks_y = ((uint32_t)h) >> 2;
574
575 int padx = w % 4 != 0? 1: 0;
576 int pady = h % 4 != 0? 1: 0;
577
578 int block_size = alpha? 16: 8;
579
580 uint8_t *dest_block = dest;
581
582 uint8_t working_block[ 4*4*4 ];
583
584 // Compress rows
585 for( int y = 0; y < blocks_y; y ++ )
586 {
587 for( int x = 0; x < blocks_x; x ++ )
588 {
589 uint8_t *src_begin = src + (y*w*4 + x*4)*4;
590 for( int i = 0; i < 4; i ++ )
591 {
592 memcpy( working_block + i*4*4, src_begin + w*4*i, 4*4 );
593 }
594
595 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
596 dest_block += block_size;
597 }
598
599 if( padx )
600 {
601 nbvtf_dxt_pad( src, blocks_x, y, w, h, working_block );
602 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
603 dest_block += block_size;
604 }
605 }
606
607 // Compress remainder row
608 if( pady )
609 {
610 for( int x = 0; x < blocks_x; x ++ )
611 {
612 nbvtf_dxt_pad( src, x, blocks_y, w, h, working_block );
613 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
614 dest_block += block_size;
615 }
616 }
617
618 // Compress last little corner
619 if( padx && pady )
620 {
621 nbvtf_dxt_pad( src, blocks_x, blocks_y, w, h, working_block );
622 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
623 }
624 }
625
626 void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
627 {
628 for( int i = 0; i < n; i ++ )
629 {
630 for( int j = 0; j < nc; j ++ )
631 {
632 dest[ i*nc+nc-j-1 ] = src[ i*4+j ];
633 }
634 }
635 }
636
637 void nbvtf_write_img_data( uint8_t *src, int w, int h,
638 EImageFormat_t format, int qual, uint8_t *wb, FILE *file )
639 {
640 switch( format )
641 {
642 case k_EImageFormat_DXT1:
643 nbvtf_compress_dxt( src, w, h, 0, qual, wb );
644 fwrite( wb, nbvtf_dxt_sizeimg( w, h, 0 ), 1, file );
645 break;
646 case k_EImageFormat_DXT5:
647 nbvtf_compress_dxt( src, w, h, 1, qual, wb );
648 fwrite( wb, nbvtf_dxt_sizeimg( w, h, 1 ), 1, file );
649 break;
650 case k_EImageFormat_ABGR8888:
651 nbvtf_swizzle_to( src, w*h, 4, wb );
652 fwrite( wb, w*h*4, 1, file );
653 break;
654 case k_EImageFormat_BGR888:
655 nbvtf_swizzle_to( src, w*h, 3, wb );
656 fwrite( wb, w*h*3, 1, file );
657 break;
658
659 default:
660 break;
661 }
662 }
663
664
665
666 #ifdef NBVTF_AS_SO
667 __attribute__((visibility("default")))
668 #endif
669 int nbvtf_write_dds_dxt1( uint8_t *reference, int w, int h, int qual, const char *dest )
670 {
671 if( !nbvtf_power2x(w,h) )
672 {
673 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
674 return 0;
675 }
676
677 struct DDS_HEADER header = {0};
678 header.dwSize = DDS_HEADER_SIZE;
679 header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
680 header.dwHeight = h;
681 header.dwWidth = w;
682 header.dwPitchOrLinearSize = nbvtf__max(1, ((w + 3) / 4)) * BLOCK_SIZE_DXT1;
683 header.ddspf.dwSize = DDS_HEADER_PFSIZE;
684 header.ddspf.dwFlags |= DDPF_FOURCC;
685 header.ddspf.dwFourCC = ((uint32_t)'D'<<0) |
686 ((uint32_t)'X'<<8) |
687 ((uint32_t)'T'<<16) |
688 ((uint32_t)'1'<<24);
689
690 header.dwFlags |= DDSD_LINEARSIZE;
691 header.dwMipMapCount = 0;
692 header.dwCaps = DDSCAPS_TEXTURE;
693
694 // Magic number
695 uint32_t magic = DDS_MAGICNUM;
696
697 FILE *file = fopen( dest, "wb" );
698 fwrite( &magic, sizeof(uint32_t), 1, file );
699 fwrite( &header, DDS_HEADER_SIZE, 1, file );
700
701 uint32_t size_highres = nbvtf_sizeimg( w, h, k_EImageFormat_DXT1 );
702 uint8_t *working_buffer = malloc( size_highres );
703
704 nbvtf_compress_dxt( reference, w, h, 0, qual, working_buffer );
705 fwrite( working_buffer, size_highres, 1, file );
706
707 free( working_buffer );
708 fclose( file );
709 return 1;
710 }
711
712 #ifdef NBVTF_AS_SO
713 __attribute__((visibility("default")))
714 #endif
715 int nbvtf_write( uint8_t *reference, int w, int h, int mipmap,
716 EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest )
717 {
718 if( !nbvtf_power2x(w,h) )
719 {
720 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
721 return 0;
722 }
723
724 mipimg_t mip_offsets[ 16 ];
725 int num_mips;
726
727 uint8_t *src;
728
729 // Convert to directx normal
730 if( usr_flags & TEXTUREFLAGS_NORMAL )
731 {
732 src = malloc( w*h*4 );
733 for( int i = 0; i < w*h; i ++ )
734 {
735 src[i*4+0] = reference[i*4+0];
736 src[i*4+1] = 0xFF-reference[i*4+1];
737 src[i*4+2] = reference[i*4+2];
738 src[i*4+3] = reference[i*4+3];
739 }
740 }
741 else
742 src = reference;
743
744 uint8_t *mip_data = nbvtf_create_mipmaps( src, w, h, mip_offsets, &num_mips );
745
746 if( !mip_data )
747 {
748 NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
749
750 if( usr_flags & TEXTUREFLAGS_NORMAL )
751 free( src );
752
753 return 0;
754 }
755
756 vtfheader_t header = {0};
757
758 header.usig = 0x00465456;
759 header.headerSize = sizeof( vtfheader_t );
760 header.version[0] = 7;
761 header.version[1] = 2;
762
763 header.width = w;
764 header.height = h;
765 header.flags = usr_flags;
766
767 // Append format flags
768 if( !mipmap )
769 {
770 header.flags |= TEXTUREFLAGS_NOLOD;
771 header.flags |= TEXTUREFLAGS_NOMIP;
772 }
773
774 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_ABGR8888 )
775 {
776 header.flags |= TEXTUREFLAGS_EIGHTBITALPHA;
777 }
778
779 header.frames = 1;
780 header.firstFrame = 0;
781 nbvtf_reflectivity( mip_data + mip_offsets[ num_mips-1 ].src_offset, 1,1, header.reflectivity );
782 header.bumpmapScale = 1.0f;
783
784 header.highResImageFormat = format;
785 header.mipmapCount = mipmap?
786 nbvtf__min(num_mips,NBVTF_MAX_MIPLEVELS)+1: 1;
787
788 header.lowResImageFormat = k_EImageFormat_DXT1;
789
790 header.depth = 1;
791 header.numResources = 0;
792
793 int lr_index = nbvtf_lowres_index( w, h );
794
795 uint8_t *lr_src;
796
797 if( lr_index )
798 {
799 mipimg_t *mip = mip_offsets + (lr_index-1);
800 lr_src = mip_data + mip->src_offset;
801
802 header.lowResImageWidth = mip->w;
803 header.lowResImageHeight = mip->h;
804 }
805 else
806 {
807 lr_src = src;
808
809 header.lowResImageWidth = w;
810 header.lowResImageHeight = h;
811 }
812
813 uint32_t size_highres = nbvtf_sizeimg( w, h, format );
814 uint32_t size_lowres =
815 nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 );
816
817 uint8_t *working_buffer =
818 (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) );
819
820 if( !working_buffer )
821 {
822 NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
823 free( mip_data );
824
825 if( usr_flags & TEXTUREFLAGS_NORMAL )
826 free( src );
827
828 return 0;
829 }
830
831 FILE *file = fopen( dest, "wb" );
832
833 if( !file )
834 {
835 NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
836
837 free( working_buffer );
838 free( mip_data );
839
840 if( usr_flags & TEXTUREFLAGS_NORMAL )
841 free( src );
842
843 return 0;
844 }
845
846 // Write header
847 fwrite( &header, sizeof( vtfheader_t ), 1, file );
848
849 // Write low res
850 nbvtf_write_img_data(
851 lr_src, header.lowResImageWidth, header.lowResImageHeight,
852 k_EImageFormat_DXT1, qual, working_buffer, file
853 );
854
855 // Write texture data
856 if( mipmap )
857 {
858 // !! Experimental !!
859 int start = nbvtf__max( 0, num_mips-NBVTF_MAX_MIPLEVELS );
860
861 for( int i = start; i < num_mips; i ++ )
862 {
863 mipimg_t *mip = mip_offsets + (num_mips - i -1);
864 nbvtf_write_img_data( mip_data + mip->src_offset, mip->w, mip->h,
865 format, qual, working_buffer, file );
866 }
867 }
868
869 // Write high resolution
870 nbvtf_write_img_data( src, w, h, format, qual, working_buffer, file );
871
872 fclose( file );
873
874 free( working_buffer );
875 free( mip_data );
876
877 if( usr_flags & TEXTUREFLAGS_NORMAL )
878 free( src );
879
880 return 1;
881 }
882
883 #ifdef NBVTF_AS_SO
884 __attribute__((visibility("default")))
885 #endif
886 int nbvtf_convert( const char *src, int w, int h, int mipmap,
887 EImageFormat_t format, int qual, uint32_t usr_flags, const char *dest )
888 {
889 if( (w && h) && !nbvtf_power2x(w,h) )
890 {
891 NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w, h );
892 return 0;
893 }
894
895 int x,y,n;
896 uint8_t *data = stbi_load( src, &x, &y, &n, 4 );
897
898 if( data )
899 {
900 if( !nbvtf_power2x(x,y) )
901 {
902 NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x, y );
903 stbi_image_free( data );
904 return 0;
905 }
906
907 // Image size needs to be made smaller
908 if( (w && h) && ( x > w || y > h ) )
909 {
910 nbvtf_downscale( data, x, y, w, h, data );
911 x = w;
912 y = h;
913 }
914
915 int status = nbvtf_write( data, x,y, mipmap, format, qual, usr_flags, dest );
916
917 stbi_image_free( data );
918
919 return status;
920 }
921 else
922 {
923 return 0;
924 }
925 }
926
927 #ifdef __cplusplus
928 }
929 #endif
930
931 /*
932 LICENSE - Applies to nbvtf.h, pynbvtf.py, librgbcx.cc, librgbcx.h, vtf_cmd.c
933 ------------------------------------------------------------------------------
934 Public Domain (www.unlicense.org)
935 This is free and unencumbered software released into the public domain.
936 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
937 software, either in source code form or as a compiled binary, for any purpose,
938 commercial or non-commercial, and by any means.
939 In jurisdictions that recognize copyright laws, the author or authors of this
940 software dedicate any and all copyright interest in the software to the public
941 domain. We make this dedication for the benefit of the public at large and to
942 the detriment of our heirs and successors. We intend this dedication to be an
943 overt act of relinquishment in perpetuity of all present and future rights to
944 this software under copyright law.
945 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
946 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
947 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
948 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
949 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
950 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
951 ------------------------------------------------------------------------------
952 */