265 lines
6.1 KiB
C
265 lines
6.1 KiB
C
/**
|
|
* 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;
|
|
} |