move image scaling functions to their own unit, as -O2

This commit is contained in:
Kae 2024-12-28 13:07:51 +11:00
parent 9da08e898d
commit 6b49f382e3
5 changed files with 113 additions and 102 deletions

View File

@ -41,6 +41,7 @@ SET (star_core_HEADERS
StarIdMap.hpp StarIdMap.hpp
StarImage.hpp StarImage.hpp
StarImageProcessing.hpp StarImageProcessing.hpp
StarImageScaling.hpp
StarInputEvent.hpp StarInputEvent.hpp
StarInterpolation.hpp StarInterpolation.hpp
StarRefPtr.hpp StarRefPtr.hpp
@ -152,6 +153,7 @@ SET (star_core_SOURCES
StarIODevice.cpp StarIODevice.cpp
StarImage.cpp StarImage.cpp
StarImageProcessing.cpp StarImageProcessing.cpp
StarImageScaling.cpp
StarInputEvent.cpp StarInputEvent.cpp
StarJson.cpp StarJson.cpp
StarJsonBuilder.cpp StarJsonBuilder.cpp
@ -229,6 +231,10 @@ IF(STAR_PRECOMPILED_HEADERS)
TARGET_PRECOMPILE_HEADERS (star_core PUBLIC StarPch.hpp) TARGET_PRECOMPILE_HEADERS (star_core PUBLIC StarPch.hpp)
ENDIF() ENDIF()
IF(STAR_COMPILER STREQUAL "gnu")
SET_SOURCE_FILES_PROPERTIES(StarImageScaling.cpp PROPERTIES COMPILE_FLAGS "-O2")
ENDIF()
IF(STAR_USE_JEMALLOC AND JEMALLOC_IS_PREFIXED) IF(STAR_USE_JEMALLOC AND JEMALLOC_IS_PREFIXED)
SET_SOURCE_FILES_PROPERTIES(StarMemory.cpp PROPERTIES SET_SOURCE_FILES_PROPERTIES(StarMemory.cpp PROPERTIES
COMPILE_DEFINITIONS STAR_JEMALLOC_IS_PREFIXED COMPILE_DEFINITIONS STAR_JEMALLOC_IS_PREFIXED

View File

@ -1,4 +1,5 @@
#include "StarImageProcessing.hpp" #include "StarImageProcessing.hpp"
#include "StarImageScaling.hpp"
#include "StarMatrix3.hpp" #include "StarMatrix3.hpp"
#include "StarInterpolation.hpp" #include "StarInterpolation.hpp"
#include "StarLexicalCast.hpp" #include "StarLexicalCast.hpp"
@ -10,104 +11,6 @@
namespace Star { namespace Star {
Image scaleNearest(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x)
destImage.set({x, y}, srcImage.clamp(Vec2I::round(vdiv(Vec2F(x, y), scale))));
}
return destImage;
}
#pragma GCC push_options
#pragma GCC optimize("-fno-unsafe-math-optimizations", "-ffloat-store")
Image scaleBilinear(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
auto lerpVec = [](float const& offset, Vec4F f0, Vec4F f1) {
return f0 * (1 - offset) + f1 * (offset);
};
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x) {
auto pos = vdiv(Vec2F(x, y), scale);
auto ipart = Vec2I::floor(pos);
auto fpart = pos - Vec2F(ipart);
auto result = lerpVec(fpart[1], lerpVec(fpart[0], Vec4F(srcImage.clamp(ipart[0], ipart[1])), Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1]))), lerpVec(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 1)), Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 1))));
destImage.set({x, y}, Vec4B(result));
}
}
return destImage;
}
Image scaleBicubic(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x) {
auto pos = vdiv(Vec2F(x, y), scale);
auto ipart = Vec2I::floor(pos);
auto fpart = pos - Vec2F(ipart);
Vec4F a = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1])));
Vec4F b = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 1)));
Vec4F c = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 2)));
Vec4F d = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 3)));
auto result = cubic4(fpart[1], a, b, c, d);
destImage.set({x, y}, Vec4B(
clamp(result[0], 0.0f, 255.0f),
clamp(result[1], 0.0f, 255.0f),
clamp(result[2], 0.0f, 255.0f),
clamp(result[3], 0.0f, 255.0f)
));
}
}
return destImage;
}
#pragma GCC pop_options
StringList colorDirectivesFromConfig(JsonArray const& directives) { StringList colorDirectivesFromConfig(JsonArray const& directives) {
List<String> result; List<String> result;

View File

@ -10,10 +10,6 @@ STAR_CLASS(Image);
STAR_EXCEPTION(ImageOperationException, StarException); STAR_EXCEPTION(ImageOperationException, StarException);
Image scaleNearest(Image const& srcImage, Vec2F const& scale);
Image scaleBilinear(Image const& srcImage, Vec2F const& scale);
Image scaleBicubic(Image const& srcImage, Vec2F const& scale);
StringList colorDirectivesFromConfig(JsonArray const& directives); StringList colorDirectivesFromConfig(JsonArray const& directives);
String paletteSwapDirectivesFromConfig(Json const& swaps); String paletteSwapDirectivesFromConfig(Json const& swaps);

View File

@ -0,0 +1,98 @@
#include "StarImage.hpp"
#include "StarImageScaling.hpp"
#include "StarInterpolation.hpp"
namespace Star {
Image scaleNearest(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x)
destImage.set({x, y}, srcImage.clamp(Vec2I::round(vdiv(Vec2F(x, y), scale))));
}
return destImage;
}
Image scaleBilinear(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x) {
auto pos = vdiv(Vec2F(x, y), scale);
auto ipart = Vec2I::floor(pos);
auto fpart = pos - Vec2F(ipart);
auto result = lerp(fpart[1], lerp(fpart[0], Vec4F(srcImage.clamp(ipart[0], ipart[1])), Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1]))), lerp(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 1)), Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 1))));
destImage.set({x, y}, Vec4B(result));
}
}
return destImage;
}
Image scaleBicubic(Image const& srcImage, Vec2F const& scale) {
Vec2U srcSize = srcImage.size();
Vec2U destSize = Vec2U::round(vmult(Vec2F(srcSize), scale));
destSize[0] = max(destSize[0], 1u);
destSize[1] = max(destSize[1], 1u);
Image destImage(destSize, srcImage.pixelFormat());
for (unsigned y = 0; y < destSize[1]; ++y) {
for (unsigned x = 0; x < destSize[0]; ++x) {
auto pos = vdiv(Vec2F(x, y), scale);
auto ipart = Vec2I::floor(pos);
auto fpart = pos - Vec2F(ipart);
Vec4F a = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1])),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1])));
Vec4F b = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 1)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 1)));
Vec4F c = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 2)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 2)));
Vec4F d = cubic4(fpart[0],
Vec4F(srcImage.clamp(ipart[0], ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 1, ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 2, ipart[1] + 3)),
Vec4F(srcImage.clamp(ipart[0] + 3, ipart[1] + 3)));
auto result = cubic4(fpart[1], a, b, c, d);
destImage.set({x, y}, Vec4B(
clamp(result[0], 0.0f, 255.0f),
clamp(result[1], 0.0f, 255.0f),
clamp(result[2], 0.0f, 255.0f),
clamp(result[3], 0.0f, 255.0f)
));
}
}
return destImage;
}
}

View File

@ -0,0 +1,8 @@
namespace Star {
STAR_CLASS(Image);
Image scaleNearest(Image const& srcImage, Vec2F const& scale);
Image scaleBilinear(Image const& srcImage, Vec2F const& scale);
Image scaleBicubic(Image const& srcImage, Vec2F const& scale);
}