X-Git-Url: https://harrygodden.com/git/?p=fishladder.git;a=blobdiff_plain;f=texsheet.c;fp=texsheet.c;h=f420866bd1a6dfc5ef6d9f5b033fb7e3f4bf0d97;hp=0000000000000000000000000000000000000000;hb=3cb144985169da3cea1c21a7b0bfba8d43c28fdb;hpb=aa435c13e7184bcd2034b8af1b20db1063baf9ec diff --git a/texsheet.c b/texsheet.c new file mode 100644 index 0000000..f420866 --- /dev/null +++ b/texsheet.c @@ -0,0 +1,214 @@ +// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved + +#define VG_TOOLS +#include "vg/vg.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb/stb_image.h" + +struct image_src +{ + int x,y,ch; + + u8 *data; +}; + +int image_sort( const void* a, const void* b) +{ + struct image_src *p_a = (struct image_src *)a; + struct image_src *p_b = (struct image_src *)b; + + if( p_a->x == p_b->x ) + return 0; + else if ( p_a->x < p_b->x ) + return 1; + else + return -1; +} + +int main( int argc, const char *argv[] ) +{ + struct image_src *source_images = malloc( sizeof( struct image_src ) * argc ); + + u32 num_images = 0; + + if( argc < 4 ) + { + vg_error( "Missing output file paths\n" ); + return 0; + } + + // Open header handle + // ------------------ + FILE *fp = fopen( argv[2], "w" ); + if( !fp ) + { + vg_error( "Could not open file for writing\n" ); + return 0; + } + + fprintf( fp, "static enum %s_index\n{\n", argv[3] ); + + // Load images + // ----------- + stbi_set_flip_vertically_on_load(1); + + for( int i = 4; i < argc; i ++ ) + { + struct image_src *src = &source_images[ num_images ]; + src->data = (u8 *)stbi_load( argv[i], &src->x, &src->y, &src->ch, 4 ); + + char name[ 256 ]; + int j = 0; int ext = 0; + for( ; j < vg_list_size( name )-1; j ++ ) + { + if( argv[i][j] ) + { + name[j] = argv[i][j]; + + if( name[j] == '.' ) + ext = j; + + if( name[j] == '.' || name[j] == '-' ) + name[j] = '_'; + } + else + break; + } + + if( ext ) + name[ext] = 0x00; + else + name[j] = 0x00; + + fprintf( fp, "\tk_sprite_%s,\n", name ); + + if( src->data ) + { + if( src->x != src->y ) + { + vg_error( "Non-square images are currently not supported ('%s')\n", argv[i] ); + free( src->data ); + } + else + num_images ++; + } + else + vg_error( "Could not decode '%s'\n", argv[i] ); + } + + fprintf( fp, "};\n\n" ); + + // Sort by size + // ------------ + qsort( source_images, num_images, sizeof(struct image_src), image_sort ); + + // Process images + // -------------- + fprintf( fp, "static struct vg_sprite %s[] = \n{\n", argv[3] ); + + u8 *dest = (u8 *)malloc( 1024*1024*4 ); + + // Clear (temp) + for( int i = 0; i < 1024*1024; i ++ ) + { + dest[ i*4 + 0 ] = 0; + dest[ i*4 + 1 ] = 0; + dest[ i*4 + 2 ] = 128; + dest[ i*4 + 3 ] = 255; + } + + struct region + { + v2i p0; + v2i p1; + } + region_stack[ 32 ] = + { + { + .p0 = { 0, 0 }, + .p1 = { 1024, 1024 } + } + }; + int stack_h = 0; + + int sf = 64; + + for( int i = 0; i < num_images; i ++ ) + { + struct image_src *psrc = &source_images[ i ]; + + // Region checks + while( 1 ) + { + struct region *pregion = ®ion_stack[ stack_h ]; + + if( (pregion->p0[ 0 ] + psrc->x <= pregion->p1[0]) && (pregion->p0[ 1 ] + psrc->y <= pregion->p1[1]) ) + { + // Passed, add image and create subdivisions + fprintf( fp, "\t{ %hu, %hu, %hu, %hu },\n", + (u16)(sf * pregion->p0[0]), + (u16)(sf * pregion->p0[1]), + (u16)(sf * psrc->x), + (u16)(sf * psrc->y) + ); + + // Write image + for( int y = 0; y < psrc->y; y ++ ) + { + int px = pregion->p0[0]; + int py = pregion->p0[1] + y; + + memcpy( &dest[ (py*1024+px) * 4 ], &psrc->data[ y*psrc->x*4 ], psrc->x*4 ); + } + + // Subdivisions + stack_h ++; + struct region *new_region = ®ion_stack[ stack_h ]; + + new_region->p0[0] = pregion->p0[0] + psrc->x; + new_region->p0[1] = pregion->p0[1]; + new_region->p1[0] = pregion->p1[0]; + new_region->p1[1] = pregion->p0[1] + psrc->y; + + pregion->p0[ 1 ] += psrc->y; + break; + } + else + { + // Failed, loop up to next region if can + if( stack_h == 0 ) + { + vg_error( "Could not fit image %d. Pack failed\n", i ); + + goto IL_END_ERR; + } + else + stack_h --; + } + } + } + +IL_END_ERR: + fprintf( fp, "};" ); + fclose( fp ); + + // Write output + // ------------ + qoi_write( argv[1], dest, &(qoi_desc){ + .width = 1024, + .height = 1024, + .channels = 4, + .colorspace = QOI_SRGB + }); + + // Free + // ---- + for( int i = 0; i < num_images; i ++ ) + free( source_images[ i ].data ); + free( dest ); + free( source_images ); + + vg_success( "Processed %u images\n", num_images ); + +}