Converted tooling to C.
This commit is contained in:
@ -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}
|
||||
)
|
||||
|
@ -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);
|
@ -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;
|
||||
}
|
Reference in New Issue
Block a user