|
diff --git a/main.c b/main.c
|
| ... |
| 43 |
"Uncompressed" // Index 3 |
43 |
"Uncompressed" // Index 3 |
| 44 |
}; |
44 |
}; |
| 45 |
|
45 |
|
|
|
46 |
typedef enum { |
|
|
47 |
PNG, |
|
|
48 |
BMP, |
|
|
49 |
TGA, |
|
|
50 |
JPG, |
|
|
51 |
} image_format; |
|
|
52 |
|
|
|
53 |
image_format get_format_type(const char *format) { |
|
|
54 |
if (strcasecmp(format, "png") == 0) return PNG; |
|
|
55 |
if (strcasecmp(format, "bmp") == 0) return BMP; |
|
|
56 |
if (strcasecmp(format, "tga") == 0) return TGA; |
|
|
57 |
if (strcasecmp(format, "jpg") == 0 || strcasecmp(format, "jpeg") == 0) return JPG; |
|
|
58 |
return PNG; |
|
|
59 |
} |
|
|
60 |
|
|
|
61 |
bool is_valid_format(const char *format) { |
|
|
62 |
const char *valid_formats[] = {"png", "bmp", "tga", "jpg", "jpeg", NULL}; |
|
|
63 |
for (const char **f = valid_formats; *f != NULL; f++) { |
|
|
64 |
if (strcasecmp(format, *f) == 0) { |
|
|
65 |
return true; |
|
|
66 |
} |
|
|
67 |
} |
|
|
68 |
return false; |
|
|
69 |
} |
|
|
70 |
|
| 46 |
path_components extract_path_components(const char *filepath) { |
71 |
path_components extract_path_components(const char *filepath) { |
| 47 |
path_components result; |
72 |
path_components result; |
| 48 |
result.fullname = filepath; |
73 |
result.fullname = filepath; |
| ... |
| 196 |
} |
221 |
} |
| 197 |
} |
222 |
} |
| 198 |
|
223 |
|
| 199 |
void decode_dxt_image(const uint8_t *image_data, uint32_t width, uint32_t height, int dxt_type, path_components *path, bool verbose) { |
224 |
void decode_dxt_image(const uint8_t *image_data, uint32_t width, uint32_t height, int dxt_type, path_components *path, bool verbose, char *format) { |
| 200 |
uint32_t blocks_wide = (width + 3) / 4; |
225 |
uint32_t blocks_wide = (width + 3) / 4; |
| 201 |
uint32_t blocks_high = (height + 3) / 4; |
226 |
uint32_t blocks_high = (height + 3) / 4; |
| 202 |
uint32_t total_pixels = width * height; |
227 |
uint32_t total_pixels = width * height; |
| ... |
| 246 |
} |
271 |
} |
| 247 |
|
272 |
|
| 248 |
if (verbose) { |
273 |
if (verbose) { |
| 249 |
printf("Saving decoded image as PNG...\n"); |
274 |
printf("Saving decoded image...\n"); |
| 250 |
} |
275 |
} |
| 251 |
|
276 |
|
| 252 |
char output_filename[512]; |
277 |
char output_filename[512]; |
| 253 |
snprintf(output_filename, sizeof(output_filename), "%s/%s.png", path->folder, path->filename); |
278 |
snprintf(output_filename, sizeof(output_filename), "%s/%s.%s", path->folder, path->filename, format); |
| 254 |
|
279 |
|
| 255 |
if (stbi_write_png(output_filename, width, height, 4, decoded_image, width * 4) == 0) { |
280 |
image_format fmt = get_format_type(format); |
| 256 |
printf("Failed to write PNG file\n"); |
281 |
switch (fmt) { |
| 257 |
} else { |
282 |
case PNG: |
| 258 |
printf("Successfully saved %s\n", output_filename); |
283 |
if (verbose) printf("Processing as PNG format\n"); |
|
|
284 |
if (stbi_write_png(output_filename, width, height, 4, decoded_image, width * 4) == 0) { |
|
|
285 |
printf("Failed to write %s file\n", output_filename); |
|
|
286 |
} else { |
|
|
287 |
printf("Successfully saved %s\n", output_filename); |
|
|
288 |
} |
|
|
289 |
break; |
|
|
290 |
case BMP: |
|
|
291 |
if (verbose) printf("Processing as BMP format\n"); |
|
|
292 |
if (stbi_write_bmp(output_filename, width, height, 4, decoded_image) == 0) { |
|
|
293 |
printf("Failed to write %s file\n", output_filename); |
|
|
294 |
} else { |
|
|
295 |
printf("Successfully saved %s\n", output_filename); |
|
|
296 |
} |
|
|
297 |
break; |
|
|
298 |
case TGA: |
|
|
299 |
if (verbose) printf("Processing as TGA format\n"); |
|
|
300 |
if (stbi_write_tga(output_filename, width, height, 4, decoded_image) == 0) { |
|
|
301 |
printf("Failed to write %s file\n", output_filename); |
|
|
302 |
} else { |
|
|
303 |
printf("Successfully saved %s\n", output_filename); |
|
|
304 |
} |
|
|
305 |
break; |
|
|
306 |
case JPG: |
|
|
307 |
if (verbose) printf("Processing as JPEG format\n"); |
|
|
308 |
if (stbi_write_jpg(output_filename, width, height, 4, decoded_image, 100) == 0) { |
|
|
309 |
printf("Failed to write %s file\n", output_filename); |
|
|
310 |
} else { |
|
|
311 |
printf("Successfully saved %s\n", output_filename); |
|
|
312 |
} |
|
|
313 |
break; |
| 259 |
} |
314 |
} |
| 260 |
|
315 |
|
| 261 |
// Print first few pixels for verification. |
316 |
// Print first few pixels for verification. |
| ... |
| 277 |
free(decoded_image); |
332 |
free(decoded_image); |
| 278 |
} |
333 |
} |
| 279 |
|
334 |
|
| 280 |
void convert_blp_file(path_components *path, bool verbose) { |
335 |
void convert_blp_file(path_components *path, bool verbose, char *format) { |
| 281 |
FILE *file = fopen(path->fullname, "rb"); |
336 |
FILE *file = fopen(path->fullname, "rb"); |
| 282 |
if (!file) { |
337 |
if (!file) { |
| 283 |
perror("Error opening file"); |
338 |
perror("Error opening file"); |
| ... |
| 346 |
|
401 |
|
| 347 |
switch (header.alpha_type) { |
402 |
switch (header.alpha_type) { |
| 348 |
case 0: // DXT1 |
403 |
case 0: // DXT1 |
| 349 |
decode_dxt_image(image_data, header.width, header.height, 1, path, verbose); |
404 |
decode_dxt_image(image_data, header.width, header.height, 1, path, verbose, format); |
| 350 |
break; |
405 |
break; |
| 351 |
case 1: // DXT3 |
406 |
case 1: // DXT3 |
| 352 |
decode_dxt_image(image_data, header.width, header.height, 3, path, verbose); |
407 |
decode_dxt_image(image_data, header.width, header.height, 3, path, verbose, format); |
| 353 |
break; |
408 |
break; |
| 354 |
case 7: // DXT5 |
409 |
case 7: // DXT5 |
| 355 |
decode_dxt_image(image_data, header.width, header.height, 5, path, verbose); |
410 |
decode_dxt_image(image_data, header.width, header.height, 5, path, verbose, format); |
| 356 |
break; |
411 |
break; |
| 357 |
default: |
412 |
default: |
| 358 |
printf("Unsupported alpha type: %d\n", header.alpha_type); |
413 |
printf("Unsupported alpha type: %d\n", header.alpha_type); |
| ... |
| 367 |
void print_help(const char *program_name) { |
422 |
void print_help(const char *program_name) { |
| 368 |
printf("Usage: %s [OPTIONS] file1 [file2 ...]\n\n", program_name); |
423 |
printf("Usage: %s [OPTIONS] file1 [file2 ...]\n\n", program_name); |
| 369 |
printf("Options:\n"); |
424 |
printf("Options:\n"); |
| 370 |
printf(" -h, --help Display this help message\n"); |
425 |
printf(" -h, --help Display this help message\n"); |
| 371 |
printf(" -v, --verbose Enable verbose output\n"); |
426 |
printf(" -v, --verbose Enable verbose output\n"); |
|
|
427 |
printf(" -f, --format=FORMAT Set output format (default: png)\n"); |
|
|
428 |
printf(" Options: png, bmp, tga, jpg, jpeg\n"); |
| 372 |
} |
429 |
} |
| 373 |
|
|
|
| 374 |
|
430 |
|
| 375 |
int main(int argc, char *argv[]) { |
431 |
int main(int argc, char *argv[]) { |
| 376 |
bool verbose = false; |
432 |
bool verbose = false; |
|
|
433 |
char *format = "png"; |
| 377 |
int c; |
434 |
int c; |
| 378 |
|
435 |
|
| 379 |
static struct option long_options[] = { |
436 |
static struct option long_options[] = { |
|
|
437 |
{"format", required_argument, 0, 'f'}, |
| 380 |
{"help", no_argument, 0, 'h'}, |
438 |
{"help", no_argument, 0, 'h'}, |
| 381 |
{"verbose", no_argument, 0, 'v'}, |
439 |
{"verbose", no_argument, 0, 'v'}, |
| 382 |
{0, 0, 0, 0} |
440 |
{0, 0, 0, 0} |
| ... |
| 385 |
// Parse command line options |
443 |
// Parse command line options |
| 386 |
while (1) { |
444 |
while (1) { |
| 387 |
int option_index = 0; |
445 |
int option_index = 0; |
| 388 |
c = getopt_long(argc, argv, "hv", long_options, &option_index); |
446 |
c = getopt_long(argc, argv, "f:hv", long_options, &option_index); |
| 389 |
if (c == -1) { break; } |
447 |
if (c == -1) { break; } |
| 390 |
|
448 |
|
| 391 |
switch (c) { |
449 |
switch (c) { |
| ... |
| 395 |
case 'v': |
453 |
case 'v': |
| 396 |
verbose = true; |
454 |
verbose = true; |
| 397 |
break; |
455 |
break; |
|
|
456 |
case 'f': |
|
|
457 |
if (!is_valid_format(optarg)) { |
|
|
458 |
fprintf(stderr, "Error: Invalid format '%s'. Valid formats are: png, bmp, tga, jpg, jpeg\n", optarg); |
|
|
459 |
return 1; |
|
|
460 |
} |
|
|
461 |
format = optarg; |
|
|
462 |
break; |
| 398 |
case '?': |
463 |
case '?': |
| 399 |
return 1; |
464 |
return 1; |
| 400 |
default: |
465 |
default: |
| ... |
| 408 |
print_help(argv[0]); |
473 |
print_help(argv[0]); |
| 409 |
return 1; |
474 |
return 1; |
| 410 |
} |
475 |
} |
| 411 |
|
|
|
| 412 |
|
476 |
|
| 413 |
// Loop though all provided files. |
477 |
// Loop though all provided files. |
| 414 |
while (optind < argc) { |
478 |
while (optind < argc) { |
| ... |
| 420 |
printf(" Folder: %s\n", path.folder); |
484 |
printf(" Folder: %s\n", path.folder); |
| 421 |
printf(" Filename: %s\n", path.filename); |
485 |
printf(" Filename: %s\n", path.filename); |
| 422 |
printf(" Extension: %s\n", path.extension); |
486 |
printf(" Extension: %s\n", path.extension); |
|
|
487 |
printf(" Format: %s\n", format); |
| 423 |
} |
488 |
} |
| 424 |
|
489 |
|
| 425 |
convert_blp_file(&path, verbose); |
490 |
convert_blp_file(&path, verbose, format); |
| 426 |
free_path_components(&path); |
491 |
free_path_components(&path); |
| 427 |
} |
492 |
} |
| 428 |
|
493 |
|
| ... |