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