Cleaned slate.
This commit is contained in:
@ -1,9 +0,0 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
add_subdirectory(display)
|
||||
add_subdirectory(file)
|
||||
add_subdirectory(game)
|
||||
add_subdirectory(vn)
|
@ -1,39 +0,0 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# Texture Build Tool
|
||||
project(texture_generation VERSION 1.0)
|
||||
add_executable(texture_generation)
|
||||
target_sources(texture_generation
|
||||
PRIVATE
|
||||
texture_generation.c
|
||||
../utils/file.c
|
||||
../utils/image.c
|
||||
)
|
||||
target_include_directories(texture_generation
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../
|
||||
)
|
||||
target_link_libraries(texture_generation
|
||||
PUBLIC
|
||||
stb
|
||||
)
|
||||
target_link_libraries(texture_generation
|
||||
PRIVATE
|
||||
${LIBS_PLATFORM}
|
||||
)
|
||||
|
||||
# Function for creating the target
|
||||
function(tool_texture target in out)
|
||||
add_custom_target(${target}
|
||||
COMMAND texture_generation "${in}" "${ASSETS_BUILD_DIR}/${out}"
|
||||
COMMENT "Generating texture ${target} from ${in}"
|
||||
DEPENDS texture_generation ${ARGN}
|
||||
)
|
||||
endfunction()
|
@ -1,127 +0,0 @@
|
||||
/**
|
||||
* 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"
|
||||
|
||||
#define RESIZE_VARIANT_COUNT 5
|
||||
int RESIZE_SCALES[RESIZE_VARIANT_COUNT] = { 1, 2, 3, 4, 10 };
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
FILE *file;
|
||||
char path[FILENAME_MAX + 1];
|
||||
char xml[2048];
|
||||
char *in;
|
||||
char *out;
|
||||
int w, h, channels, rw, rh, i, scale;
|
||||
stbi_uc *dataOriginal;
|
||||
stbi_uc *dataResized;
|
||||
|
||||
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
|
||||
sprintf(path, "%s.xml", out);
|
||||
file = fopen(path, "rb");
|
||||
if(file != NULL) {
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read in original texture
|
||||
file = fopen(in, "rb");
|
||||
if(file == NULL) {
|
||||
printf("Failed to open file!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
dataOriginal = stbi_load_from_file(file, &w, &h, &channels, STBI_rgb_alpha);
|
||||
if(dataOriginal == NULL) {
|
||||
printf("Failed to load input texture!\n");
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
// Begin XML buffering
|
||||
xml[0] = '\0';
|
||||
sprintf(xml,
|
||||
"<texture channels=\"%i\" width=\"%i\" height=\"%i\">",
|
||||
STBI_rgb_alpha, w, h
|
||||
);
|
||||
|
||||
// For each scale.
|
||||
for(i = 0; i < RESIZE_VARIANT_COUNT; i++) {
|
||||
// Resize image
|
||||
scale = RESIZE_SCALES[i];
|
||||
rw = w / scale;
|
||||
rh = h / scale;
|
||||
dataResized = malloc(sizeof(stbi_uc) * rw * rh * STBI_rgb_alpha);
|
||||
stbir_resize_uint8(
|
||||
dataOriginal, w, h, 0,
|
||||
dataResized, rw, rh, 0,
|
||||
STBI_rgb_alpha
|
||||
);
|
||||
|
||||
// Determine output path
|
||||
sprintf(path, "%s_%i.texture", out, scale);
|
||||
|
||||
// Open output file
|
||||
fileMkdirp(path);
|
||||
printf("OPOut %s\n", path);
|
||||
|
||||
file = fopen(path, "wb");
|
||||
if(file == NULL) {
|
||||
printf("Invalid texture file out!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Write texture
|
||||
fwrite(dataResized, sizeof(unsigned char), rw * rh * STBI_rgb_alpha, file);
|
||||
|
||||
// Cleanup
|
||||
fclose(file);
|
||||
free(dataResized);
|
||||
|
||||
// Buffer XML info.
|
||||
sprintf(xml,
|
||||
"%s\n <texture-scale scale=\"%i\" width=\"%i\" height=\"%i\" />",
|
||||
xml, scale, rw, rh
|
||||
);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
stbi_image_free(dataOriginal);
|
||||
|
||||
// Finalize XML
|
||||
sprintf(xml, "%s\n</texture>", xml);
|
||||
|
||||
// Determine XML path
|
||||
sprintf(path, "%s.xml", out);
|
||||
|
||||
// Write XML
|
||||
fileMkdirp(path);
|
||||
file = fopen(path, "w");
|
||||
if(file == NULL) {
|
||||
printf("Invalid XML File Out!\n");
|
||||
return 1;
|
||||
}
|
||||
fwrite(xml, sizeof(char), strlen(xml), file);
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
function(tool_assets args)
|
||||
add_custom_target(assets
|
||||
# COMMAND tar -C ${ASSETS_BUILD_DIR} -czvf assets.tar.gz *
|
||||
COMMAND echo ${ASSETS_BUILD_DIR}
|
||||
DEPENDS ${ARGV}
|
||||
COMMENT "Compressing Assets"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(tool_copy target)
|
||||
math(EXPR CARGSN "${ARGC} - 1")
|
||||
set(LOOP_DEPENDENCIES)
|
||||
|
||||
foreach(index RANGE 1 ${CARGSN} 2)
|
||||
math(EXPR indexnext "${index} + 1")
|
||||
set(LOOP_TARGET "item_${target}_${index}")
|
||||
|
||||
LIST(GET ARGV ${index} from)
|
||||
LIST(GET ARGV ${indexnext} to)
|
||||
LIST(APPEND LOOP_DEPENDENCIES ${LOOP_TARGET})
|
||||
add_custom_command(OUTPUT ${LOOP_TARGET}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${from}" "${ASSETS_BUILD_DIR}/${to}"
|
||||
COMMENT "Copying ${from} => ${to}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${target}
|
||||
DEPENDS ${LOOP_DEPENDENCIES}
|
||||
COMMENT "Creating dependency set ${target}"
|
||||
)
|
||||
endfunction()
|
@ -1,12 +0,0 @@
|
||||
function(tool_game name version)
|
||||
add_compile_definitions(
|
||||
GAME_NAME=${name}
|
||||
GAME_VERSION=${version}
|
||||
)
|
||||
|
||||
file(WRITE ${TEMP_DIR}/dawn/game/game.h
|
||||
"#pragma once\n#include <games/${TARGET_GAME}/game.h>"
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${TEMP_DIR}/dawn)
|
||||
endfunction()
|
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
@ -1,148 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "file.h"
|
||||
|
||||
void fileNormalizeSlashes(char *string) {
|
||||
char c;
|
||||
int i = 0;
|
||||
|
||||
while(c = string[i++]) {
|
||||
if(c != '\\' && c != '/') continue;
|
||||
string[i-1] = FILE_PATH_SEP;
|
||||
}
|
||||
}
|
||||
|
||||
void fileMkdirp(char *path) {
|
||||
char buffer[FILENAME_MAX];
|
||||
char c;
|
||||
int i = 0;
|
||||
bool inFile;
|
||||
bool hasMore;
|
||||
|
||||
inFile = false;
|
||||
hasMore = false;
|
||||
while(c = path[i]) {
|
||||
if((c == '\\' || c == '/') && i > 0) {
|
||||
buffer[i] = '\0';
|
||||
fileMkdir(buffer, 0755);
|
||||
inFile = false;
|
||||
hasMore = false;
|
||||
buffer[i] = FILE_PATH_SEP;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == '.') inFile = true;
|
||||
hasMore = true;
|
||||
buffer[i] = c;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(!inFile && hasMore) {
|
||||
buffer[i] = '\0';
|
||||
fileMkdir(buffer, 0755);
|
||||
}
|
||||
}
|
||||
|
||||
void assetReadString(FILE *file, char *buffer) {
|
||||
size_t length;
|
||||
fseek(file, 0, SEEK_END);// Seek to the end
|
||||
length = ftell(file);// Get our current position (the end)
|
||||
fseek(file, 0, SEEK_SET);// Reset the seek
|
||||
fread(buffer, 1, length, file);// Read all the bytes
|
||||
}
|
||||
|
||||
void fileGetDirectory(char *file, char* buffer) {
|
||||
char *c, *p;
|
||||
int32_t i;
|
||||
p = strrchr(file, FILE_PATH_SEP);
|
||||
c = file;
|
||||
i = 0;
|
||||
do {
|
||||
buffer[i++] = *c;
|
||||
} while(++c < p);
|
||||
buffer[i] = '\0';
|
||||
}
|
||||
|
||||
bool fileListChildren(
|
||||
char *directory,
|
||||
char *buffer,
|
||||
int32_t *count,
|
||||
uint8_t *types,
|
||||
char **children
|
||||
) {
|
||||
#if defined(_MSC_VER)
|
||||
WIN32_FIND_DATA fdFile;
|
||||
HANDLE hFind = NULL;
|
||||
char sPath[2048];
|
||||
int32_t i;
|
||||
|
||||
// Append wildcard
|
||||
sprintf(sPath, "%s\\*.*", directory);
|
||||
|
||||
// Scan first
|
||||
if((hFind = FindFirstFile(sPath, &fdFile)) == INVALID_HANDLE_VALUE) {
|
||||
printf("Path not found: [%s]\n", directory);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate
|
||||
i = 0;
|
||||
do {
|
||||
if(
|
||||
strcmp(fdFile.cFileName, ".") == 0 ||
|
||||
strcmp(fdFile.cFileName, "..") == 0
|
||||
) continue;
|
||||
|
||||
// Get Full path.
|
||||
sprintf(sPath, "%s\\%s", directory, fdFile.cFileName);
|
||||
|
||||
//Is the entity a File or Folder?
|
||||
if(fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
types[i] = FILE_CHILD_TYPE_DIR;
|
||||
} else {
|
||||
types[i] = FILE_CHILD_TYPE_FILE;
|
||||
}
|
||||
|
||||
children[i] = buffer + (i * FILE_CHILD_NAME_MAX);
|
||||
strcpy(children[i], fdFile.cFileName);
|
||||
i++;
|
||||
} while(FindNextFile(hFind, &fdFile));
|
||||
|
||||
*count = i;
|
||||
return true;
|
||||
#else
|
||||
struct dirent *de;
|
||||
DIR *dr;
|
||||
int32_t i;
|
||||
|
||||
// Open Dir
|
||||
dr = opendir(directory);
|
||||
if(dr == NULL) {
|
||||
printf("Could not open directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Iterate
|
||||
i = 0;
|
||||
while ((de = readdir(dr)) != NULL) {
|
||||
// File or folder?
|
||||
if(de->d_type != DT_REG) continue;
|
||||
|
||||
// Copy into child buffer
|
||||
children[i] = buffer + (i * FILE_CHILD_NAME_MAX);
|
||||
strcpy(children[i], de->d_name);
|
||||
i++;
|
||||
}
|
||||
if(closedir(dr)) return false;
|
||||
|
||||
*count = i;
|
||||
return true;
|
||||
#endif
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
|
||||
#define FILE_CHILD_TYPE_DIR 0x00
|
||||
#define FILE_CHILD_TYPE_FILE 0x01
|
||||
#define FILE_CHILD_NAME_MAX 512
|
||||
#define FILE_CHILD_COUNT_MAX 64
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <direct.h>
|
||||
#include <windows.h>
|
||||
#define getcwd _getcwd
|
||||
#define FILE_PATH_SEP '\\'
|
||||
#define fileMkdir(path, perms) _mkdir(path)
|
||||
#elif defined(__GNUC__)
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#define FILE_PATH_SEP '/'
|
||||
#define fileMkdir(path, perms) mkdir(path, perms)
|
||||
#endif
|
||||
|
||||
void fileNormalizeSlashes(char *string);
|
||||
|
||||
void fileMkdirp(char *path);
|
||||
|
||||
void assetReadString(FILE *file, char *buffer);
|
||||
|
||||
void fileGetDirectory(char *file, char* buffer);
|
||||
|
||||
bool fileListChildren(
|
||||
char *directory,
|
||||
char *buffer,
|
||||
int32_t *count,
|
||||
uint8_t *types,
|
||||
char **children
|
||||
);
|
@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
|
||||
#ifndef STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include <stb_image_resize.h>
|
||||
#endif
|
||||
|
||||
#ifndef STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
#endif
|
||||
|
||||
void imageCopy(
|
||||
uint8_t *source, int32_t sourceWidth, int32_t sourceHeight,
|
||||
uint8_t *dest, int32_t destWidth, int32_t destHeight,
|
||||
int32_t cropX, int32_t cropY, int32_t cropWidth, int32_t cropHeight,
|
||||
int32_t pasteX, int32_t pasteY,
|
||||
int32_t channels
|
||||
) {
|
||||
int32_t x, y, c;
|
||||
int32_t absX, absY;
|
||||
int32_t sourceIndex, targetIndex;
|
||||
|
||||
if(cropX == -1) cropX = 0;
|
||||
if(cropY == -1) cropY = 0;
|
||||
if(cropWidth == -1) cropWidth = sourceWidth;
|
||||
if(cropHeight == -1) cropHeight = sourceHeight;
|
||||
if(pasteX == -1) pasteX = 0;
|
||||
if(pasteY == -1) pasteY = 0;
|
||||
|
||||
for(x = cropX; x < cropX + cropWidth; x++) {
|
||||
for(y = cropY; y < cropY + cropHeight; y++) {
|
||||
absX = x - cropX + pasteX;
|
||||
absY = y - cropY + pasteY;
|
||||
if(absX >= destWidth || absY >= destHeight || absX < 0 || absY < 0)continue;
|
||||
targetIndex = absY * destWidth + absX;
|
||||
sourceIndex = y * sourceWidth + x;
|
||||
for(c = 0; c < channels; c++) {
|
||||
dest[(targetIndex*channels) + c] = source[(sourceIndex*channels) + c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "file.h"
|
||||
|
||||
#include <stb_image.h>
|
||||
#include <stb_image_resize.h>
|
||||
#include <stb_image_write.h>
|
||||
|
||||
void imageCopy(
|
||||
uint8_t *source, int32_t sourceWidth, int32_t sourceHeight,
|
||||
uint8_t *dest, int32_t destWidth, int32_t destHeight,
|
||||
int32_t cropX, int32_t cropY, int32_t cropWidth, int32_t cropHeight,
|
||||
int32_t pasteX, int32_t pasteY,
|
||||
int32_t channels
|
||||
);
|
@ -1,210 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "xml.h"
|
||||
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
|
||||
char c;
|
||||
int32_t level = 0;
|
||||
uint8_t doing = XML_DOING_NOTHING;
|
||||
bool insideTag = false;
|
||||
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
int32_t bufferLength = 0;
|
||||
|
||||
xml->value = NULL;
|
||||
xml->attributeCount = 0;
|
||||
|
||||
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
|
||||
xml->childrenCount = 0;
|
||||
|
||||
while(c = data[i++]) {
|
||||
switch(doing) {
|
||||
case XML_DOING_NOTHING:
|
||||
// Look for either an opening tag (<) or a word for a value.
|
||||
if(c == '>') continue;
|
||||
if(c == '<') {
|
||||
if(insideTag) {
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
doing = XML_PARSING_CHILD;
|
||||
} else {
|
||||
doing = XML_PARSING_TAG_NAME;
|
||||
level++;
|
||||
insideTag = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
doing = XML_PARSING_VALUE;
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_TAG_NAME:
|
||||
// Just keep reading until we either hit a space (end of the tag name)
|
||||
// or a closing tag value, either / or >
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->node = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
} else {
|
||||
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE:
|
||||
// Look until we hit either the end of a tag, or the attribute itself
|
||||
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
if(c == '/') {
|
||||
level--;
|
||||
insideTag = false;
|
||||
doing = XML_PARSING_CLOSE;
|
||||
}
|
||||
} else if(c == '=') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
|
||||
} else {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
}
|
||||
|
||||
if(bufferLength > 0) {
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeNames[xml->attributeCount++] = buffer;
|
||||
xml->attributeDatas[xml->attributeCount] = NULL;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
|
||||
// Keep looking until we find a quote mark
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
if(c == '>' || c == '/') {
|
||||
doing = XML_DOING_NOTHING;
|
||||
insideTag = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c != '"') continue;
|
||||
doing = XML_PARSING_ATTRIBUTE_VALUE;
|
||||
break;
|
||||
|
||||
case XML_PARSING_ATTRIBUTE_VALUE:
|
||||
// Parse the attribute value until we find a quote mark.
|
||||
if(c == '"') {
|
||||
doing = XML_LOOKING_FOR_ATTRIBUTE;
|
||||
buffer[bufferLength] = '\0';
|
||||
xml->attributeDatas[xml->attributeCount - 1] = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
bufferLength = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_VALUE:
|
||||
// Keep parsing child until we find a < for an opening/closing tag.
|
||||
if(c == '<') {
|
||||
// In HTML Spec there could be a child here but not in XML spec.
|
||||
doing = XML_PARSING_CLOSE;
|
||||
buffer[bufferLength] = '\0';
|
||||
bufferLength = 0;
|
||||
xml->value = buffer;
|
||||
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferLength++] = c;
|
||||
break;
|
||||
|
||||
case XML_PARSING_CHILD:
|
||||
if(c == '<') {
|
||||
// Read ahead and confirm this is a close or not
|
||||
if(data[i] == '/') {
|
||||
doing = XML_PARSING_CLOSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Likely another child.
|
||||
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
|
||||
}
|
||||
|
||||
if(xmlIsWhitespace(c)) continue;
|
||||
|
||||
// In HTML Spec there's a chance for there to be a value here, but not
|
||||
// in the XML spec.
|
||||
break;
|
||||
|
||||
case XML_PARSING_CLOSE:
|
||||
// Just keep parsing until the tag closer finishes.
|
||||
if(c != '>') continue;
|
||||
doing = XML_DOING_NOTHING;
|
||||
|
||||
//TODO: Return index or something?
|
||||
free(buffer);
|
||||
return i;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return i;
|
||||
}
|
||||
|
||||
void xmlLoad(xml_t *xml, char *data) {
|
||||
xmlLoadChild(xml, data, 0);
|
||||
}
|
||||
|
||||
void xmlDispose(xml_t *xml) {
|
||||
uint8_t i;
|
||||
|
||||
// Dispose children recursively
|
||||
for(i = 0; i < xml->childrenCount; i++) {
|
||||
xmlDispose(xml->children + i);
|
||||
}
|
||||
|
||||
// Free children array.
|
||||
free(xml->children);
|
||||
|
||||
// Dispose attributes
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
free(xml->attributeNames[i]);
|
||||
if((xml->attributeDatas + i) != NULL) {
|
||||
free(xml->attributeDatas[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(xml->node);
|
||||
if(xml-> value != NULL) free(xml->value);
|
||||
}
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
|
||||
int16_t i;
|
||||
for(i = 0; i < xml->attributeCount; i++) {
|
||||
if(strcmp(xml->attributeNames[i], name) == 0) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool xmlIsWhitespace(char c) {
|
||||
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common.h"
|
||||
#include "file.h"
|
||||
|
||||
#define XML_DOING_NOTHING 0x00
|
||||
#define XML_PARSING_TAG_NAME 0x01
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE 0x02
|
||||
#define XML_PARSING_ATTRIBUTE_NAME 0x03
|
||||
#define XML_LOOKING_FOR_ATTRIBUTE_VALUE 0x04
|
||||
#define XML_PARSING_ATTRIBUTE_VALUE 0x05
|
||||
#define XML_PARSING_VALUE 0x06
|
||||
#define XML_PARSING_CHILD 0x07
|
||||
#define XML_PARSING_CLOSE 0x08
|
||||
|
||||
#define XML_TEXT_BUFFER_MAX 256
|
||||
#define XML_CHILD_COUNT_MAX 16
|
||||
#define XML_ATTRIBUTE_MAX 16
|
||||
|
||||
typedef struct _xml_t xml_t;
|
||||
|
||||
typedef struct _xml_t {
|
||||
char *node;
|
||||
char *value;
|
||||
|
||||
char *attributeNames[XML_ATTRIBUTE_MAX];
|
||||
char *attributeDatas[XML_ATTRIBUTE_MAX];
|
||||
uint8_t attributeCount;
|
||||
|
||||
xml_t *children;
|
||||
uint8_t childrenCount;
|
||||
} xml_t;
|
||||
|
||||
/**
|
||||
* Load an XML child from a string buffer.
|
||||
*
|
||||
* @param xml XML to load.
|
||||
* @param data Data to parse
|
||||
* @param i Character index within the data
|
||||
* @return The index in the data string this XML node ends.
|
||||
*/
|
||||
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i);
|
||||
|
||||
/**
|
||||
* Load an XML String into an XML memory.
|
||||
*
|
||||
* @param xml XML to load into.
|
||||
* @param data XML string.
|
||||
*/
|
||||
void xmlLoad(xml_t *xml, char *data);
|
||||
|
||||
/**
|
||||
* Dispose a previously loaded XML.
|
||||
*
|
||||
* @param xml XML to dispose.
|
||||
*/
|
||||
void xmlDispose(xml_t *xml);
|
||||
|
||||
int16_t xmlGetAttributeByName(xml_t *xml, char *name);
|
||||
|
||||
bool xmlIsWhitespace(char c);
|
@ -1,45 +0,0 @@
|
||||
# Copyright (c) 2021 Dominic Msters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# Build Tool
|
||||
project(character_generator VERSION 1.0)
|
||||
add_executable(character_generator)
|
||||
target_sources(character_generator
|
||||
PRIVATE
|
||||
character_generator.c
|
||||
../utils/file.c
|
||||
../utils/xml.c
|
||||
../utils/image.c
|
||||
)
|
||||
target_include_directories(character_generator
|
||||
PUBLIC
|
||||
${CMAKE_CURRENT_LIST_DIR}/../
|
||||
)
|
||||
target_link_libraries(character_generator
|
||||
PUBLIC
|
||||
stb
|
||||
)
|
||||
target_link_libraries(character_generator
|
||||
PRIVATE
|
||||
${LIBS_PLATFORM}
|
||||
)
|
||||
|
||||
# Function Target
|
||||
function(tool_vn_character target in out)
|
||||
add_custom_target(vn_character_${target}
|
||||
COMMAND character_generator "${in}" "${TEMP_DIR}/${out}.png"
|
||||
COMMENT "Generating character ${target} from ${in}"
|
||||
DEPENDS character_generator ${ARGN}
|
||||
)
|
||||
|
||||
tool_texture(${target}
|
||||
${TEMP_DIR}/${out}.png ${out}
|
||||
vn_character_${target}
|
||||
)
|
||||
endfunction()
|
@ -1,265 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
Reference in New Issue
Block a user