Converted tooling to C.

This commit is contained in:
2021-11-07 23:34:05 -08:00
parent a2a839cbac
commit a6bae07e38
18 changed files with 637 additions and 394 deletions

View File

@ -15,6 +15,7 @@ target_sources(character_generator
character_generator.c
../utils/file.c
../utils/xml.c
../utils/image.c
)
target_include_directories(character_generator
PUBLIC
@ -28,7 +29,7 @@ target_link_libraries(character_generator
# Function Target
function(tool_vn_character target in out)
add_custom_target(vn_character_${target}
COMMAND character_generator "${in}" "${TEMP_DIR}/${out}"
COMMAND character_generator "${in}" "${TEMP_DIR}/${out}.png"
COMMENT "Generating character ${target} from ${in}"
DEPENDS character_generator ${ARGN}
)

View File

@ -1,139 +0,0 @@
const path = require('path');
const { imageCreate, imageWrite, imageLoad, imageCopy } = require('./../utils/image');
const fs = require('fs');
const xml = require('xml-js');
const { args } = require('./../utils/args');
const { mkdirp } = require('../utils/file');
// Parse Args
// if(!args.temp) throw new Error(`Missing temp argument`);
if(!args.in) throw new Error(`Missing in argument`);
if(!args.out) throw new Error(`Missing out argument`);
if(!args.dep) throw new Error(`Missing dep argument`);
if(!args.in.endsWith('xml')) throw new Error(`Invalid in XML`);
if(!args.out.endsWith('png')) throw new Error(`Invalid out PNG`);
// Determine in and out.
const file = path.resolve(args.in);
const outFile = path.resolve(args.out);
console.log(outFile);
// const cOut = path.resolve(args.temp, 'vn', `${args.dep}.c`);
// const hOut = path.resolve(args.temp, 'vn', `${args.dep}.h`);
if(!fs.existsSync(file)) throw new Error(`Could not find ${file}`);
// if(fs.existsSync(outFile) && fs.existsSync(cOut) && fs.existsSync(hOut)) return;
if(fs.existsSync(outFile)) return;
// Load XML
const data = xml.xml2js(fs.readFileSync(file, 'utf-8'));
const [ character ] = data.elements;
// Validate file.
if(!character.attributes.context) throw new Error(`Missing context`)
const dir = path.resolve(path.dirname(file), character.attributes.context);
// Parse base and layers
const base = character.elements.find(e => e.name == 'base').attributes;
if(!base) throw new Error(`Failed to find base`);
const layers = character.elements
.filter(e => e.name == 'layer')
.map(e => e.attributes)
.map(e => ({
...e,
x: parseInt(e.x),
y: parseInt(e.y),
width: parseInt(e.width),
height: parseInt(e.height)
}))
;
(async () => {
// Load the base
const baseImage = await imageLoad(path.join(dir, base.file));
let columnsMax = 0;
let widthMax = 0;
let strLayers = ``;
layers.forEach((layer,row) => {
if(!layer.width || !layer.height || !layer.x || !layer.y) {
throw new Error(`Missing layer info`);
}
const layerDir = path.join(dir, layer.directory);
const scan = fs.readdirSync(layerDir);
columnsMax = Math.max(scan.length, columnsMax);
widthMax = Math.max(widthMax, layer.width);
});
// Create the output buffer
const out = imageCreate(
baseImage.width + (columnsMax * widthMax),
baseImage.height
);
// Copy the base
imageCopy(out, baseImage, 0, 0);
// Now begin copying the children, row is defined by the directory
let y = 0;
for(let row = 0; row < layers.length; row++) {
const layer = layers[row];
const layerDir = path.join(dir, layer.directory);
const scan = fs.readdirSync(layerDir);
// Column defined by the file index
for(let col = 0; col < scan.length; col++) {
const img = await imageLoad(path.join(layerDir, scan[col]));
console.log('Copying', scan[col]);
imageCopy(out, img,
baseImage.width+(col*layer.width), y,
layer
);
}
strLayers += `
vnCharacterLayerAdd(vnc, ${scan.length},
${baseImage.width}, ${y},
${layer.x}, ${layer.y},
${layer.width}, ${layer.height}
);
`;
y += layer.height;
}
mkdirp(outFile);
await imageWrite(out, outFile);
let name = character.attributes.name || args.name || args.dep;
// mkdirp(cOut);
// fs.writeFileSync(cOut, `
// #include "${args.dep}.h"
// void vnCharacter${name}Init(vncharacter_t *vnc, texture_t *texture) {
// assetTextureLoad(texture, VN_CHARACTER_${name.toUpperCase()}_TEXTURE);
// vnCharacterInit(vnc, texture);
// // Base Layer
// vnCharacterLayerAdd(vnc, 1, 0, 0, 0, 0, ${baseImage.width}, ${baseImage.height});
// // Layers
// ${strLayers}
// }
// `);
// fs.writeFileSync(hOut, `
// #pragma once
// #include <libs.h>
// #include <vn/vncharacter.h>
// #include <display/texture.h>
// #include <file/asset.h>
// #define VN_CHARACTER_${name.toUpperCase()}_TEXTURE "${args.out}"
// void vnCharacter${name}Init(vncharacter_t *vnc, texture_t *texture);
// `);
})().catch(console.error);

View File

@ -12,9 +12,16 @@
int main(int argc, char *argv[]) {
FILE *file;
char *in;
char *out;
char xmlBuffer[2048];
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");
@ -29,18 +36,230 @@ int main(int argc, char *argv[]) {
fileNormalizeSlashes(in);
fileNormalizeSlashes(out);
// Check the output doesn't already exist
file = fopen(out, "rb");
if(file != NULL) {
fclose(file);
return 0;
}
// Read in XML file
// Open XML file
file = fopen(in, "rb");
if(file == NULL) {
printf("Failed to open file!\n");
return 1;
}
assetReadString(file, xmlBuffer);
// Bufer XML data
assetReadString(file, bufferA);
fclose(file);
xmlLoad(&node, bufferA);
xmlnode_t node;
xmlParseElement(&node, xmlBuffer);
// 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;
}