e6318c00f7242faae6f98df5b38f4733d27803f5
[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 typedef struct mipimg
239 {
240 uint32_t w;
241 uint32_t h;
242 uint32_t src_offset;
243 } mipimg_t;
244
245 int nbvtf_power2( uint32_t x )
246 {
247 return (x != 0) && ((x & (x - 1)) == 0);
248 }
249
250 int nbvtf_power2x( uint32_t y, uint32_t x )
251 {
252 return nbvtf_power2( y ) && nbvtf_power2( x );
253 }
254
255 int nbvtf_lower( int *x, int *y )
256 {
257 if( *x == 1 && *y == 1 )
258 {
259 return 0;
260 }
261
262 *x = nbvtf__max( 1, (*x)/2 );
263 *y = nbvtf__max( 1, (*y)/2 );
264
265 return 1;
266 }
267
268 int nbvtf_lowres_index( int w, int h )
269 {
270 int x, y;
271 int i = 0;
272
273 x = w;
274 y = h;
275
276 while(1)
277 {
278 if( (x <= 16) && ( y <= 16 ) )
279 {
280 return i;
281 }
282
283 i ++;
284
285 nbvtf_lower( &x, &y );
286 }
287 }
288
289 // Simple box filter downscale
290 void nbvtf_downscale( uint8_t *src, int w, int h, int dw, int dh, uint8_t *dest )
291 {
292 int bx = w/dw;
293 int by = h/dh;
294 int div = bx*by;
295
296 for( int y = 0; y < dh; y ++ )
297 for( int x = 0; x < dw; x ++ )
298 {
299 // Average block colours
300 uint32_t tr = 0, tg = 0, tb = 0, ta = 0;
301
302 for( int yy = 0; yy < by; yy ++ )
303 for( int xx = 0; xx < bx; xx ++ )
304 {
305 uint8_t *psrc = &src[ (x*bx+xx + (y*by+yy)*w)*4 ];
306 tr+=psrc[0];
307 tg+=psrc[1];
308 tb+=psrc[2];
309 ta+=psrc[3];
310 }
311
312 uint8_t *pdst = &dest[ (y*dw + x)*4 ];
313 pdst[0] = tr / div;
314 pdst[1] = tg / div;
315 pdst[2] = tb / div;
316 pdst[3] = ta / div;
317 }
318 }
319
320 uint8_t *nbvtf_create_mipmaps( uint8_t *src, int w, int h, mipimg_t *offsets, int *num )
321 {
322 int memory = 0;
323 int x, y, i;
324 uint32_t offset;
325
326 x = w;
327 y = h;
328 while( nbvtf_lower( &x, &y ) )
329 memory += x*y*4;
330
331 uint8_t *mipmem = (uint8_t *)malloc( memory );
332
333 if( mipmem )
334 {
335 x = w;
336 y = h;
337 i = 0;
338 offset = 0;
339
340 uint8_t *dest = mipmem;
341
342 while(1)
343 {
344 if( !nbvtf_lower( &x, &y ) )
345 break;
346
347 nbvtf_downscale( src, w, h, x, y, dest );
348
349 offsets[ i ].src_offset = offset;
350 offsets[ i ].w = x;
351 offsets[ i ].h = y;
352 i ++;
353
354 offset += x*y*4;
355 dest = mipmem + offset;
356 }
357
358 *num = i;
359 return mipmem;
360 }
361 else
362 {
363 NBVTF_ERR( "nbvtf_write:err out of memory allocating mipmap buffer!\n" );
364 return NULL;
365 }
366 }
367
368 void nbvtf_reflectivity( uint8_t *src, int w, int h, float *dest )
369 {
370 uint32_t totals[3] = {0,0,0};
371
372 for( int i = 0; i < w*h; i ++ )
373 {
374 totals[0] += src[i*4+0];
375 totals[1] += src[i*4+1];
376 totals[2] += src[i*4+2];
377 }
378
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;
382 }
383
384 #ifdef NBVTF_ALLOW_EXPORT
385 void nbvtf_debug_view_mips( uint8_t *src, int w, int h )
386 {
387 int x, y, i;
388 char fnbuf[512];
389
390 x = w;
391 y = h;
392 i = 1;
393
394 uint8_t *dest = src;
395
396 while( nbvtf_lower( &x, &y ) )
397 {
398 sprintf( fnbuf, "mip_%d.png", i ++ );
399
400 stbi_write_png( fnbuf, x,y, 4, dest, x*4 );
401 dest += x*y*4;
402 }
403 }
404 #endif
405
406 void nbvtf_dxt_pad( uint8_t *src, int bx, int by, int w, int h, uint8_t *dest )
407 {
408 int px = bx*4;
409 int py = by*4;
410
411 uint32_t *stream = (uint32_t *)src;
412 uint32_t *stream_out = (uint32_t *)dest;
413
414 for( int y = 0; y < 4; y ++ )
415 {
416 for( int x = 0; x < 4; x ++ )
417 {
418 stream_out[ y*4+x ] = stream[ nbvtf__min( py+y, h-1 )*w + nbvtf__min( px+x, w-1 ) ];
419 }
420 }
421 }
422
423 uint32_t nbvtf_dxt_sizeimg( int w, int h, int alpha )
424 {
425 uint32_t blocks_x, blocks_y;
426 int block_size = alpha? 16: 8;
427
428 blocks_x = ((uint32_t)w) >> 2;
429 blocks_y = ((uint32_t)h) >> 2;
430
431 int padx = w % 4 != 0? 1: 0;
432 int pady = h % 4 != 0? 1: 0;
433
434 return (blocks_x+padx)*(blocks_y+pady)*block_size;
435 }
436
437 uint32_t nbvtf_sizeimg( int w, int h, EImageFormat_t format )
438 {
439 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_DXT1 )
440 {
441 return nbvtf_dxt_sizeimg( w, h, format == k_EImageFormat_DXT1? 0: 1 );
442 }
443
444 if( format == k_EImageFormat_BGR888 )
445 return w*h*3;
446
447 if( format == k_EImageFormat_ABGR8888 )
448 return w*h*4;
449
450 return 0;
451 }
452
453 #ifdef NBVTF_AS_SO
454 __attribute__((visibility("default")))
455 #endif
456 void nbvtf_init(void)
457 {
458 #ifdef USE_LIBRGBCX
459 rgbcx__init();
460 #endif
461 }
462
463 void nbvtf_dxt_block( uint8_t *dest, uint8_t *src, int alpha, int qual )
464 {
465 #ifdef USE_LIBRGBCX
466 if( alpha )
467 {
468 rgbcx__encode_bc3( qual, dest, src );
469 }
470 else
471 {
472 rgbcx__encode_bc1( qual, dest, src, 0, 0 );
473 }
474 #else
475 stb_compress_dxt_block( dest, src, alpha, STB_DXT_HIGHQUAL );
476 #endif
477 }
478
479 void nbvtf_compress_dxt( uint8_t *src, int w, int h, int alpha, int qual,
480 uint8_t *dest )
481 {
482 uint32_t blocks_x, blocks_y;
483
484 blocks_x = ((uint32_t)w) >> 2;
485 blocks_y = ((uint32_t)h) >> 2;
486
487 int padx = w % 4 != 0? 1: 0;
488 int pady = h % 4 != 0? 1: 0;
489
490 int block_size = alpha? 16: 8;
491
492 uint8_t *dest_block = dest;
493
494 uint8_t working_block[ 4*4*4 ];
495
496 // Compress rows
497 for( int y = 0; y < blocks_y; y ++ )
498 {
499 for( int x = 0; x < blocks_x; x ++ )
500 {
501 uint8_t *src_begin = src + (y*w*4 + x*4)*4;
502 for( int i = 0; i < 4; i ++ )
503 {
504 memcpy( working_block + i*4*4, src_begin + w*4*i, 4*4 );
505 }
506
507 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
508 dest_block += block_size;
509 }
510
511 if( padx )
512 {
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;
516 }
517 }
518
519 // Compress remainder row
520 if( pady )
521 {
522 for( int x = 0; x < blocks_x; x ++ )
523 {
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;
527 }
528 }
529
530 // Compress last little corner
531 if( padx && pady )
532 {
533 nbvtf_dxt_pad( src, blocks_x, blocks_y, w, h, working_block );
534 nbvtf_dxt_block( dest_block, working_block, alpha, qual );
535 }
536 }
537
538 void nbvtf_swizzle_to( uint8_t *src, int n, int nc, uint8_t *dest )
539 {
540 for( int i = 0; i < n; i ++ )
541 {
542 for( int j = 0; j < nc; j ++ )
543 {
544 dest[ i*nc+nc-j-1 ] = src[ i*4+j ];
545 }
546 }
547 }
548
549 void nbvtf_write_img_data( uint8_t *src, int w, int h,
550 EImageFormat_t format, int qual, uint8_t *wb, FILE *file )
551 {
552 switch( format )
553 {
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 );
557 break;
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 );
561 break;
562 case k_EImageFormat_ABGR8888:
563 nbvtf_swizzle_to( src, w*h, 4, wb );
564 fwrite( wb, w*h*4, 1, file );
565 break;
566 case k_EImageFormat_BGR888:
567 nbvtf_swizzle_to( src, w*h, 3, wb );
568 fwrite( wb, w*h*3, 1, file );
569 break;
570
571 default:
572 break;
573 }
574 }
575
576 #ifdef NBVTF_AS_SO
577 __attribute__((visibility("default")))
578 #endif
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 )
581 {
582 if( !nbvtf_power2x(w,h) )
583 {
584 NBVTF_ERR( "nbvtf_write:err image dimentions were not power of two (%d %d)\n", w, h );
585 return 0;
586 }
587
588 mipimg_t mip_offsets[ 16 ];
589 int num_mips;
590
591 uint8_t *src;
592
593 // Convert to directx normal
594 if( usr_flags & TEXTUREFLAGS_NORMAL )
595 {
596 src = malloc( w*h*4 );
597 for( int i = 0; i < w*h; i ++ )
598 {
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];
603 }
604 }
605 else
606 src = reference;
607
608 uint8_t *mip_data = nbvtf_create_mipmaps( src, w, h, mip_offsets, &num_mips );
609
610 if( !mip_data )
611 {
612 NBVTF_ERR( "nbvtf_write:err mipmap data failed to generate" );
613
614 if( usr_flags & TEXTUREFLAGS_NORMAL )
615 free( src );
616
617 return 0;
618 }
619
620 vtfheader_t header = {0};
621
622 header.usig = 0x00465456;
623 header.headerSize = sizeof( vtfheader_t );
624 header.version[0] = 7;
625 header.version[1] = 2;
626
627 header.width = w;
628 header.height = h;
629 header.flags = usr_flags;
630
631 // Append format flags
632 if( !mipmap )
633 {
634 header.flags |= TEXTUREFLAGS_NOLOD;
635 header.flags |= TEXTUREFLAGS_NOMIP;
636 }
637
638 if( format == k_EImageFormat_DXT5 || format == k_EImageFormat_ABGR8888 )
639 {
640 header.flags |= TEXTUREFLAGS_EIGHTBITALPHA;
641 }
642
643 header.frames = 1;
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;
647
648 header.highResImageFormat = format;
649 header.mipmapCount = mipmap?
650 nbvtf__min(num_mips,NBVTF_MAX_MIPLEVELS)+1: 1;
651
652 header.lowResImageFormat = k_EImageFormat_DXT1;
653
654 header.depth = 1;
655 header.numResources = 0;
656
657 int lr_index = nbvtf_lowres_index( w, h );
658
659 uint8_t *lr_src;
660
661 if( lr_index )
662 {
663 mipimg_t *mip = mip_offsets + (lr_index-1);
664 lr_src = mip_data + mip->src_offset;
665
666 header.lowResImageWidth = mip->w;
667 header.lowResImageHeight = mip->h;
668 }
669 else
670 {
671 lr_src = src;
672
673 header.lowResImageWidth = w;
674 header.lowResImageHeight = h;
675 }
676
677 uint32_t size_highres = nbvtf_sizeimg( w, h, format );
678 uint32_t size_lowres =
679 nbvtf_dxt_sizeimg( header.lowResImageWidth, header.lowResImageHeight, 0 );
680
681 uint8_t *working_buffer =
682 (uint8_t *)malloc( nbvtf__max( size_highres, size_lowres ) );
683
684 if( !working_buffer )
685 {
686 NBVTF_ERR( "nbvtf_write:err out of memory allocating working buffer\n" );
687 free( mip_data );
688
689 if( usr_flags & TEXTUREFLAGS_NORMAL )
690 free( src );
691
692 return 0;
693 }
694
695 FILE *file = fopen( dest, "wb" );
696
697 if( !file )
698 {
699 NBVTF_ERR( "nbvtf_write:err could not open file stream for writing\n" );
700
701 free( working_buffer );
702 free( mip_data );
703
704 if( usr_flags & TEXTUREFLAGS_NORMAL )
705 free( src );
706
707 return 0;
708 }
709
710 // Write header
711 fwrite( &header, sizeof( vtfheader_t ), 1, file );
712
713 // Write low res
714 nbvtf_write_img_data(
715 lr_src, header.lowResImageWidth, header.lowResImageHeight,
716 k_EImageFormat_DXT1, qual, working_buffer, file
717 );
718
719 // Write texture data
720 if( mipmap )
721 {
722 // !! Experimental !!
723 int start = nbvtf__max( 0, num_mips-NBVTF_MAX_MIPLEVELS );
724
725 for( int i = start; i < num_mips; i ++ )
726 {
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 );
730 }
731 }
732
733 // Write high resolution
734 nbvtf_write_img_data( src, w, h, format, qual, working_buffer, file );
735
736 fclose( file );
737
738 free( working_buffer );
739 free( mip_data );
740
741 if( usr_flags & TEXTUREFLAGS_NORMAL )
742 free( src );
743
744 return 1;
745 }
746
747 #ifdef NBVTF_AS_SO
748 __attribute__((visibility("default")))
749 #endif
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 )
752 {
753 if( (w && h) && !nbvtf_power2x(w,h) )
754 {
755 NBVTF_ERR( "nbvtf_convert:err requested dimentions were not power of two (%d %d)\n", w, h );
756 return 0;
757 }
758
759 int x,y,n;
760 uint8_t *data = stbi_load( src, &x, &y, &n, 4 );
761
762 if( data )
763 {
764 if( !nbvtf_power2x(x,y) )
765 {
766 NBVTF_ERR( "nbvtf_convert:err loaded image dimentions were not power two (%d %d)\n", x, y );
767 stbi_image_free( data );
768 return 0;
769 }
770
771 // Image size needs retargeting
772 if( (w && h) && ( x > w || y > h ) )
773 nbvtf_downscale( data, x, y, w, h, data );
774
775 int status = nbvtf_write( data, w, h, mipmap, format, qual,
776 usr_flags, dest );
777
778 stbi_image_free( data );
779
780 return status;
781 }
782 else
783 {
784 return 0;
785 }
786 }
787
788 #ifdef __cplusplus
789 }
790 #endif
791
792 /*
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 ------------------------------------------------------------------------------
813 */