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