/** * Copyright (c) 2021 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "../utils/common.h" #include "../utils/file.h" #include "../utils/image.h" #include "../utils/xml.h" int main(int argc, char *argv[]) { FILE *file; char *in, *out; char bufferA[FILE_CHILD_NAME_MAX * FILE_CHILD_COUNT_MAX]; char bufferB[FILENAME_MAX]; char directory[FILENAME_MAX]; uint8_t i, *pixels, *data; int32_t fullWidth, fullHeight, size; int32_t j, baseWidth, baseHeight, childrenCount, l, x, y, w, h, px, py, iw, ih; xml_t node, *base, *child; uint8_t childrenTypes[FILE_CHILD_COUNT_MAX]; char *children[FILE_CHILD_COUNT_MAX]; if(argc != 3) { printf("Invalid number of arguments\n"); return 1; } // Set up strings in = argv[1]; out = argv[2]; // Normalize slashes fileNormalizeSlashes(in); fileNormalizeSlashes(out); // Check the output doesn't already exist file = fopen(out, "rb"); if(file != NULL) { fclose(file); return 0; } // Open XML file file = fopen(in, "rb"); if(file == NULL) { printf("Failed to open file!\n"); return 1; } // Bufer XML data assetReadString(file, bufferA); fclose(file); xmlLoad(&node, bufferA); // Begin parsing if(strcmp(node.node, "vncharacter") != 0) { printf("Invalid character XML!\n"); xmlDispose(&node); return 1; } // Find base base = NULL; for(i = 0; i < node.childrenCount; i++) { if(strcmp(node.children[i].node, "base") != 0) continue; base = node.children + i; break; } if(base == NULL) { printf("XML is missing base layer!\n"); xmlDispose(&node); return 1; } // Prepare to load base info fileGetDirectory(in, bufferA); sprintf(directory, "%s%c%s", bufferA, FILE_PATH_SEP, node.attributeDatas[xmlGetAttributeByName(&node, "context")] ); sprintf(bufferA, "%s%c%s", directory, FILE_PATH_SEP, base->attributeDatas[xmlGetAttributeByName(base, "file")] ); printf("Reading texture info for %s\n", bufferA); file = fopen(bufferA, "rb"); if(file == NULL) { printf("Failed to load base texture file %s!\n", bufferA); xmlDispose(&node); return 1; } // Read base info. if(!stbi_info_from_file(file, &baseWidth, &baseHeight, NULL)) { printf("Failed to read base texture %s!\n", bufferA); xmlDispose(&node); fclose(file); return 1; } // Read in the information for each layer. fullWidth = 0; fullHeight = 0; for(i = 0; i < node.childrenCount; i++) { child = node.children + i; if(strcmp(child->node, "layer") != 0) continue; // Get the full path of the directory where the layers' images reside sprintf(bufferB, "%s%c%s", directory, FILE_PATH_SEP, child->attributeDatas[xmlGetAttributeByName(child, "directory")] ); // Scan the directory. if(!fileListChildren( bufferB, bufferA, &childrenCount, childrenTypes, children )) { printf("Failed to scandir!\n"); xmlDispose(&node); fclose(file); return 1; } if(childrenCount == 0) continue; // Update sizes size = childrenCount * atoi( child->attributeDatas[xmlGetAttributeByName(child, "width")] ); if(size > fullWidth) fullWidth = size; fullHeight += atoi( child->attributeDatas[xmlGetAttributeByName(child, "height")] ); } // Update final full sizes fullWidth += baseWidth; fullHeight = fullHeight > baseHeight ? fullHeight : baseHeight; l = STBI_rgb_alpha; // Create output data pixels = calloc(fullWidth * fullHeight * l, sizeof(uint8_t)); if(pixels == NULL) { xmlDispose(&node); fclose(file); printf("Failed to create memory for pixels!\n"); return 1; } // Read in base data data = stbi_load_from_file(file, &baseWidth, &baseHeight, NULL, l); imageCopy( data, baseWidth, baseHeight, pixels, fullWidth, fullHeight, -1, -1, -1, -1, -1, -1, l ); stbi_image_free(data); fclose(file); // Now read in each layer x = 0; y = 0; py = 0; for(i = 0; i < node.childrenCount; i++) { child = node.children + i; if(strcmp(child->node, "layer") != 0) continue; // Get the full path of the directory where the layers' images reside sprintf(bufferB, "%s%c%s", directory, FILE_PATH_SEP, child->attributeDatas[xmlGetAttributeByName(child, "directory")] ); // Scan the directory. if(!fileListChildren( bufferB, bufferA, &childrenCount, childrenTypes, children )) { printf("Failed to scandir!\n"); xmlDispose(&node); free(pixels); return 1; } if(childrenCount == 0) continue; // Read in layer info x = atoi(child->attributeDatas[xmlGetAttributeByName(child, "x")]); y = atoi(child->attributeDatas[xmlGetAttributeByName(child, "y")]); w = atoi(child->attributeDatas[xmlGetAttributeByName(child, "width")]); h = atoi(child->attributeDatas[xmlGetAttributeByName(child, "height")]); // Reset for the iteration. px = baseWidth; ih = 0; // For each image in the layer... for(j = 0; j < childrenCount; j++) { // Find the path sprintf(bufferB, "%s%c%s%c%s", directory, FILE_PATH_SEP, child->attributeDatas[xmlGetAttributeByName(child, "directory")], FILE_PATH_SEP, children[j] ); // Open image file file = fopen(bufferB, "rb"); if(file == NULL) { printf("Failed to open %s for reading!\n", bufferB); xmlDispose(&node); free(pixels); } // Copy the cropped area data = stbi_load_from_file(file, &iw, &ih, NULL, l); imageCopy( data, iw, ih, pixels, fullWidth, fullHeight, x, y, w, h, px, py, l ); // Cleanup stbi_image_free(data); fclose(file); // Prep for next image px += w; } // Prepare for next row. py += h; } // Done with the XML! xmlDispose(&node); // Now write the data! fileMkdirp(out); stbi_write_png(out, fullWidth, fullHeight, l, pixels, fullWidth * l ); // Cleanup free(pixels); return 0; }