177 lines
5.1 KiB
C++
177 lines
5.1 KiB
C++
// Copyright (c) 2023 Dominic Masters
|
|
//
|
|
// This software is released under the MIT License.
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
#include "TextureTool.hpp"
|
|
|
|
using namespace Dawn;
|
|
|
|
std::vector<std::string> TextureTool::getRequiredFlags() {
|
|
return std::vector<std::string>{ "input", "output" };
|
|
}
|
|
|
|
std::map<std::string, std::string> TextureTool::getOptionalFlags() {
|
|
return {
|
|
{ "wrapX", "clamp" },
|
|
{ "wrapY", "clamp" },
|
|
{ "filterMin", "linear" },
|
|
{ "filterMax", "linear" },
|
|
{ "scale", "" },
|
|
{ "scaleWrapX", "clamp" },
|
|
{ "scaleWrapY", "clamp" },
|
|
{ "scaleFilterX", "nearest" },
|
|
{ "scaleFilterY", "nearest" },
|
|
{ "cropStartX", "" },
|
|
{ "cropStartY", "" },
|
|
{ "cropEndX", "" },
|
|
{ "cropEndY", "" }
|
|
};
|
|
}
|
|
|
|
int32_t TextureTool::start() {
|
|
// Finished with XML data, now we can write data out.
|
|
File fileOut(flags["output"] + ".texture");
|
|
if(fileOut.exists()) return 0;
|
|
|
|
// Load input file
|
|
File in(flags["input"]);
|
|
if(!in.open(FILE_MODE_READ)) {
|
|
std::cout << "Failed to open input file " << in.filename << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
int32_t originalWidth, originalHeight, channels;
|
|
auto bufferCurrent = stbi_load_from_file(
|
|
in.file,
|
|
&originalWidth,
|
|
&originalHeight,
|
|
&channels,
|
|
STBI_rgb_alpha
|
|
);
|
|
if(bufferCurrent == NULL) {
|
|
std::cout << "Failed to load input texture!" << std::endl;
|
|
return 1;
|
|
}
|
|
in.close();
|
|
|
|
// Create a temporary buffer to hold pixels.
|
|
size_t len = STBI_rgb_alpha * originalWidth * originalHeight;
|
|
uint8_t *bufferTemporary = (uint8_t*)malloc(sizeof(uint8_t) * len);
|
|
int32_t currentWidth = originalWidth;
|
|
int32_t currentHeight = originalHeight;
|
|
|
|
// Crop
|
|
int32_t cropStartX = 0;
|
|
int32_t cropStartY = 0;
|
|
int32_t cropEndX = 0;
|
|
int32_t cropEndY = 0;
|
|
|
|
if(!flags["cropStartX"].empty()) cropStartX = std::stoi(flags["cropStartX"]);
|
|
if(!flags["cropStartY"].empty()) cropStartY = std::stoi(flags["cropStartY"]);
|
|
if(!flags["cropEndX"].empty()) cropEndX = std::stoi(flags["cropEndX"]);
|
|
if(!flags["cropEndY"].empty()) cropEndY = std::stoi(flags["cropEndY"]);
|
|
|
|
if(cropStartX > 0 || cropStartY > 0 || cropEndX > 0 || cropEndY > 0) {
|
|
int32_t cropWidth = originalWidth - cropStartX - cropEndX;
|
|
int32_t cropHeight = originalHeight - cropStartY - cropEndY;
|
|
|
|
float_t s0, t0, s1, t1;
|
|
s0 = (float_t)cropStartX / (float_t)originalWidth;
|
|
t0 = (float_t)cropStartY / (float_t)originalHeight;
|
|
s1 = 1.0f - ((float_t)cropEndX / (float_t)originalWidth);
|
|
t1 = 1.0f - ((float_t)cropEndY / (float_t)originalHeight);
|
|
|
|
stbir_resize_region(
|
|
bufferCurrent, currentWidth, currentHeight, 0,
|
|
bufferTemporary, cropWidth, cropHeight, 0,
|
|
STBIR_TYPE_UINT8,
|
|
STBI_rgb_alpha, -1, 0,
|
|
STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP,
|
|
STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
|
|
STBIR_COLORSPACE_LINEAR, NULL,
|
|
s0, t0, s1, t1
|
|
);
|
|
memcpy(bufferCurrent, bufferTemporary, sizeof(uint8_t) * len);
|
|
|
|
currentWidth = cropWidth;
|
|
currentHeight = cropHeight;
|
|
}
|
|
|
|
// Scale
|
|
if(!flags["scale"].empty()) {
|
|
float_t scale = std::stof(flags["scale"]);
|
|
int32_t scaleWidth = currentWidth * scale;
|
|
int32_t scaleHeight = currentHeight * scale;
|
|
|
|
stbir_resize_uint8_generic(
|
|
bufferCurrent, currentWidth, currentHeight, 0,
|
|
bufferTemporary, scaleWidth, scaleHeight, 0,
|
|
STBI_rgb_alpha, -1, 0,
|
|
STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT, STBIR_COLORSPACE_LINEAR,
|
|
NULL
|
|
);
|
|
memcpy(bufferCurrent, bufferTemporary, sizeof(uint8_t) * len);
|
|
|
|
currentWidth = scaleWidth;
|
|
currentHeight = scaleHeight;
|
|
}
|
|
|
|
// Wrapping Settings
|
|
std::function<int32_t(std::string)> wrapFromString = [&](std::string wr) {
|
|
if(wr == "repeat") return 0;
|
|
if(wr == "mirror") return 1;
|
|
if(wr == "clamp") return 2;
|
|
if(wr == "border") return 3;
|
|
return -1;
|
|
};
|
|
|
|
int32_t wrapX = wrapFromString(flags["wrapX"]);
|
|
if(wrapX == -1) {
|
|
std::cout << "Invalid wrapX value " << flags["wrapX"] << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
int32_t wrapY = wrapFromString(flags["wrapY"]);
|
|
if(wrapY == -1) {
|
|
std::cout << "Invalid wrapY value " << flags["wrapY"] << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
// Write info
|
|
char headerBuffer[256];
|
|
size_t headerBufferLength = sprintf((char *)headerBuffer, "DT_2.00|%i|%i|%i|%i|%i|%i|%i|",
|
|
currentWidth,
|
|
currentHeight,
|
|
4, // RGBA,
|
|
wrapX, // WRAPX
|
|
wrapY, // WRAPY
|
|
flags["filterMin"] == "nearest" ? 0 : 1,
|
|
flags["filterMag"] == "nearest" ? 0 : 1
|
|
);
|
|
|
|
// Open and create output
|
|
File out(flags["output"] + ".texture");
|
|
if(!out.mkdirp()) {
|
|
std::cout << "Failed to make output dir " << out.filename << std::endl;
|
|
return 1;
|
|
}
|
|
if(!out.open(FILE_MODE_WRITE)) {
|
|
std::cout << "Failed to open texture file for writing " << out.filename << std::endl;
|
|
return 1;
|
|
}
|
|
if(!out.writeRaw(headerBuffer, headerBufferLength)) {
|
|
std::cout << "Failed to write texture header for " << out.filename << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
// Write texture
|
|
if(!out.writeRaw((char*)bufferCurrent, sizeof(uint8_t) * len)) {
|
|
std::cout << "Failed to write texture data for " << out.filename << std::endl;
|
|
return 1;
|
|
}
|
|
free(bufferCurrent);
|
|
free(bufferTemporary);
|
|
|
|
return 0;
|
|
} |