diff --git a/src/dawntools/texturetool/CMakeLists.txt b/src/dawntools/texturetool/CMakeLists.txt index 4a598fa0..3e6bc6bf 100644 --- a/src/dawntools/texturetool/CMakeLists.txt +++ b/src/dawntools/texturetool/CMakeLists.txt @@ -46,6 +46,10 @@ function(tool_texture target) set(WRAP_X "") set(WRAP_Y "") set(SCALE "") + set(CROP_START_X "") + set(CROP_START_Y "") + set(CROP_END_X "") + set(CROP_END_Y "") # Parse Args foreach(_PAIR IN LISTS ARGN) @@ -75,6 +79,10 @@ function(tool_texture target) --filterMin="${FILTER_MIN}" --filterMag="${FILTER_MIN}" --scale="${SCALE}" + --cropStartX="${CROP_START_X}" + --cropStartY="${CROP_START_Y}" + --cropEndX="${CROP_END_X}" + --cropEndY="${CROP_END_Y}" COMMENT "Generating texture ${target} from ${FILE}" DEPENDS ${DEPS} ) diff --git a/src/dawntools/texturetool/TextureTool.cpp b/src/dawntools/texturetool/TextureTool.cpp index a01da438..4e65db9e 100644 --- a/src/dawntools/texturetool/TextureTool.cpp +++ b/src/dawntools/texturetool/TextureTool.cpp @@ -21,7 +21,11 @@ std::map TextureTool::getOptionalFlags() { { "scaleWrapX", "clamp" }, { "scaleWrapY", "clamp" }, { "scaleFilterX", "nearest" }, - { "scaleFilterY", "nearest" } + { "scaleFilterY", "nearest" }, + { "cropStartX", "" }, + { "cropStartY", "" }, + { "cropEndX", "" }, + { "cropEndY", "" } }; } @@ -36,41 +40,84 @@ int32_t TextureTool::start() { std::cout << "Failed to open input file " << in.filename << std::endl; return 1; } - - int w, h, channels; - auto imageRaw = stbi_load_from_file(in.file, &w, &h, &channels, STBI_rgb_alpha); - if(imageRaw == NULL) { + + 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(); - // Buffer to output - size_t len = STBI_rgb_alpha * w * h; - uint8_t *dataImage = (uint8_t*)malloc(sizeof(uint8_t) * len); + // 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; - float_t scale = 1; - if(!flags["scale"].empty()) { - scale = std::stof(flags["scale"]); + // 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_BOX, STBIR_FILTER_BOX, + STBIR_COLORSPACE_LINEAR, NULL, + s0, t0, s1, t1 + ); + memcpy(bufferCurrent, bufferTemporary, sizeof(uint8_t) * len); + + currentWidth = cropWidth; + currentHeight = cropHeight; } - if(scale != 1) { + // 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( - imageRaw, w, h, 0, - dataImage, w * scale, h * scale, 0, + bufferCurrent, currentWidth, currentHeight, 0, + bufferTemporary, scaleWidth, scaleHeight, 0, STBI_rgb_alpha, -1, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_TRIANGLE, STBIR_COLORSPACE_LINEAR, NULL ); - w = w * scale; - h = h * scale; - printf("Changing size to %ix%i\n", w, h); - } else { - memcpy(dataImage, imageRaw, len); + memcpy(bufferCurrent, bufferTemporary, sizeof(uint8_t) * len); + + currentWidth = scaleWidth; + currentHeight = scaleHeight; } - stbi_image_free(imageRaw); - + // Wrapping Settings std::function wrapFromString = [&](std::string wr) { if(wr == "repeat") return 0; if(wr == "mirror") return 1; @@ -94,8 +141,8 @@ int32_t TextureTool::start() { // Write info char headerBuffer[256]; size_t headerBufferLength = sprintf((char *)headerBuffer, "DT_2.00|%i|%i|%i|%i|%i|%i|%i|", - w, - h, + currentWidth, + currentHeight, 4, // RGBA, wrapX, // WRAPX wrapY, // WRAPY @@ -119,11 +166,12 @@ int32_t TextureTool::start() { } // Write texture - if(!out.writeRaw((char *)dataImage, sizeof(uint8_t) * len)) { + if(!out.writeRaw((char*)bufferCurrent, sizeof(uint8_t) * len)) { std::cout << "Failed to write texture data for " << out.filename << std::endl; return 1; } - free(dataImage); + free(bufferCurrent); + free(bufferTemporary); return 0; } \ No newline at end of file