small refactors
[vg.git] / src / texsheet.c
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 #define VG_TOOLS
4 #include "vg/vg.h"
5
6 #define STB_IMAGE_IMPLEMENTATION
7 #include "stb/stb_image.h"
8
9 struct image_src
10 {
11 int x,y,ch;
12
13 u8 *data;
14 };
15
16 int image_sort( const void* a, const void* b)
17 {
18 struct image_src *p_a = (struct image_src *)a;
19 struct image_src *p_b = (struct image_src *)b;
20
21 if( p_a->x == p_b->x )
22 return 0;
23 else if ( p_a->x < p_b->x )
24 return 1;
25 else
26 return -1;
27 }
28
29 int main( int argc, const char *argv[] )
30 {
31 struct image_src *source_images = malloc( sizeof( struct image_src ) * argc );
32
33 u32 num_images = 0;
34
35 if( argc < 4 )
36 {
37 vg_error( "Missing output file paths\n" );
38 return 0;
39 }
40
41 // Open header handle
42 // ------------------
43 FILE *fp = fopen( argv[2], "w" );
44 if( !fp )
45 {
46 vg_error( "Could not open file for writing\n" );
47 return 0;
48 }
49
50 fprintf( fp, "enum %s_index\n{\n", argv[3] );
51
52 // Load images
53 // -----------
54 stbi_set_flip_vertically_on_load(1);
55
56 for( int i = 4; i < argc; i ++ )
57 {
58 struct image_src *src = &source_images[ num_images ];
59 src->data = (u8 *)stbi_load( argv[i], &src->x, &src->y, &src->ch, 4 );
60
61 char name[ 256 ];
62 int j = 0; int ext = 0;
63 for( ; j < vg_list_size( name )-1; j ++ )
64 {
65 if( argv[i][j] )
66 {
67 name[j] = argv[i][j];
68
69 if( name[j] == '.' )
70 ext = j;
71
72 if( name[j] == '.' || name[j] == '-' )
73 name[j] = '_';
74 }
75 else
76 break;
77 }
78
79 if( ext )
80 name[ext] = 0x00;
81 else
82 name[j] = 0x00;
83
84 fprintf( fp, "\tk_sprite_%s,\n", name );
85
86 if( src->data )
87 {
88 if( src->x != src->y )
89 {
90 vg_error( "Non-square images are currently not supported ('%s')\n", argv[i] );
91 free( src->data );
92 }
93 else
94 num_images ++;
95 }
96 else
97 vg_error( "Could not decode '%s'\n", argv[i] );
98 }
99
100 fprintf( fp, "};\n\n" );
101
102 // Sort by size
103 // ------------
104 qsort( source_images, num_images, sizeof(struct image_src), image_sort );
105
106 // Process images
107 // --------------
108 fprintf( fp, "static struct vg_sprite %s[] = \n{\n", argv[3] );
109
110 u8 *dest = (u8 *)malloc( 1024*1024*4 );
111
112 for( int i = 0; i < 1024*1024; i ++ )
113 {
114 dest[ i*4 + 0 ] = 0;
115 dest[ i*4 + 1 ] = 0;
116 dest[ i*4 + 2 ] = 0;
117 dest[ i*4 + 3 ] = 0;
118 }
119
120 struct region
121 {
122 v2i p0;
123 v2i p1;
124 }
125 region_stack[ 32 ] =
126 {
127 {
128 .p0 = { 0, 0 },
129 .p1 = { 1024, 1024 }
130 }
131 };
132 int stack_h = 0;
133
134 for( int i = 0; i < num_images; i ++ )
135 {
136 struct image_src *psrc = &source_images[ i ];
137
138 // Region checks
139 while( 1 )
140 {
141 struct region *pregion = &region_stack[ stack_h ];
142
143 if( (pregion->p0[ 0 ] + psrc->x <= pregion->p1[0]) && (pregion->p0[ 1 ] + psrc->y <= pregion->p1[1]) )
144 {
145 // Passed, add image and create subdivisions
146 fprintf( fp, "\t{{ %f, %f, %f, %f }}",
147 (float)pregion->p0[0] / 1024.0f,
148 (float)pregion->p0[1] / 1024.0f,
149 (float)psrc->x / 1024.0f,
150 (float)psrc->y / 1024.0f
151 );
152
153 if( i != num_images-1 )
154 fputs( ",\n", fp );
155 else
156 fputc( '\n', fp );
157
158 // Write image
159 for( int y = 0; y < psrc->y; y ++ )
160 {
161 int px = pregion->p0[0];
162 int py = pregion->p0[1] + y;
163
164 memcpy( &dest[ (py*1024+px) * 4 ], &psrc->data[ y*psrc->x*4 ], psrc->x*4 );
165 }
166
167 // Subdivisions
168 stack_h ++;
169 struct region *new_region = &region_stack[ stack_h ];
170
171 new_region->p0[0] = pregion->p0[0] + psrc->x;
172 new_region->p0[1] = pregion->p0[1];
173 new_region->p1[0] = pregion->p1[0];
174 new_region->p1[1] = pregion->p0[1] + psrc->y;
175
176 pregion->p0[ 1 ] += psrc->y;
177 break;
178 }
179 else
180 {
181 // Failed, loop up to next region if can
182 if( stack_h == 0 )
183 {
184 vg_error( "Could not fit image %d. Pack failed\n", i );
185
186 goto IL_END_ERR;
187 }
188 else
189 stack_h --;
190 }
191 }
192 }
193
194 IL_END_ERR:
195 fprintf( fp, "};" );
196 fclose( fp );
197
198 // Write output
199 // ------------
200 qoi_write( argv[1], dest, &(qoi_desc){
201 .width = 1024,
202 .height = 1024,
203 .channels = 4,
204 .colorspace = QOI_SRGB
205 });
206
207 // Free
208 // ----
209 for( int i = 0; i < num_images; i ++ )
210 free( source_images[ i ].data );
211 free( dest );
212 free( source_images );
213
214 vg_success( "Processed %u images\n", num_images );
215
216 }