added linear, circular, angular gradient texture creation helpers

This commit is contained in:
Turánszki János
2023-07-15 11:32:09 +02:00
parent 9b1a46ee85
commit 6a1cb4a31f
4 changed files with 144 additions and 5 deletions
+12
View File
@@ -115,6 +115,18 @@ namespace wi::math
{
return (pos - value1) / (value2 - value1);
}
constexpr XMFLOAT2 InverseLerp(const XMFLOAT2& value1, const XMFLOAT2& value2, const XMFLOAT2& pos)
{
return XMFLOAT2(InverseLerp(value1.x, value2.x, pos.x), InverseLerp(value1.y, value2.y, pos.y));
}
constexpr XMFLOAT3 InverseLerp(const XMFLOAT3& value1, const XMFLOAT3& value2, const XMFLOAT3& pos)
{
return XMFLOAT3(InverseLerp(value1.x, value2.x, pos.x), InverseLerp(value1.y, value2.y, pos.y), InverseLerp(value1.z, value2.z, pos.z));
}
constexpr XMFLOAT4 InverseLerp(const XMFLOAT4& value1, const XMFLOAT4& value2, const XMFLOAT4& pos)
{
return XMFLOAT4(InverseLerp(value1.x, value2.x, pos.x), InverseLerp(value1.y, value2.y, pos.y), InverseLerp(value1.z, value2.z, pos.z), InverseLerp(value1.w, value2.w, pos.w));
}
constexpr float Lerp(float value1, float value2, float amount)
{
return value1 + (value2 - value1) * amount;
+104 -4
View File
@@ -244,12 +244,12 @@ namespace wi::texturehelper
bool CreateTexture(
wi::graphics::Texture& texture,
Texture& texture,
const uint8_t* data,
uint32_t width,
uint32_t height,
Format format,
wi::graphics::Swizzle swizzle
Swizzle swizzle
)
{
if (data == nullptr)
@@ -275,12 +275,112 @@ namespace wi::texturehelper
return device->CreateTexture(&desc, &InitData, &texture);
}
wi::graphics::Texture CreateCircularProgressGradientTexture(
Texture CreateGradientTexture(
GradientType type,
uint32_t width,
uint32_t height,
const XMFLOAT2& uv_start,
const XMFLOAT2& uv_end,
GradientFlags flags,
Swizzle swizzle
)
{
wi::vector<uint8_t> data(width * height);
switch (type)
{
default:
case GradientType::Linear:
{
const XMVECTOR a = XMLoadFloat2(&uv_start);
const XMVECTOR b = XMLoadFloat2(&uv_end);
const float distance = XMVectorGetX(XMVector3Length(b - a));
for (uint32_t y = 0; y < height; ++y)
{
for (uint32_t x = 0; x < width; ++x)
{
const XMFLOAT2 uv = XMFLOAT2(float(x) / float(width - 1), float(y) / float(height - 1));
const XMVECTOR point_on_line = wi::math::ClosestPointOnLineSegment(a, b, XMLoadFloat2(&uv));
const float uv_distance = XMVectorGetX(XMVector3Length(point_on_line - a));
float gradient = wi::math::saturate(wi::math::InverseLerp(0, distance, uv_distance));
if (has_flag(flags, GradientFlags::Inverse))
{
gradient = 1 - gradient;
}
if (has_flag(flags, GradientFlags::Smoothstep))
{
gradient = wi::math::SmoothStep(0, 1, gradient);
}
data[x + y * width] = uint8_t(gradient * 255);
}
}
}
break;
case GradientType::Circular:
{
const XMVECTOR a = XMLoadFloat2(&uv_start);
const XMVECTOR b = XMLoadFloat2(&uv_end);
const float distance = XMVectorGetX(XMVector3Length(b - a));
for (uint32_t y = 0; y < height; ++y)
{
for (uint32_t x = 0; x < width; ++x)
{
const XMFLOAT2 uv = XMFLOAT2(float(x) / float(width - 1), float(y) / float(height - 1));
const float uv_distance = wi::math::Clamp(XMVectorGetX(XMVector3Length(XMLoadFloat2(&uv) - a)), 0, distance);
float gradient = wi::math::saturate(wi::math::InverseLerp(0, distance, uv_distance));
if (has_flag(flags, GradientFlags::Inverse))
{
gradient = 1 - gradient;
}
if (has_flag(flags, GradientFlags::Smoothstep))
{
gradient = wi::math::SmoothStep(0, 1, gradient);
}
data[x + y * width] = uint8_t(gradient * 255);
}
}
}
break;
case GradientType::Angular:
{
XMFLOAT2 direction;
XMStoreFloat2(&direction, XMVector2Normalize(XMLoadFloat2(&uv_end) - XMLoadFloat2(&uv_start)));
for (uint32_t y = 0; y < height; ++y)
{
for (uint32_t x = 0; x < width; ++x)
{
const XMFLOAT2 uv = XMFLOAT2(float(x) / float(width - 1), float(y) / float(height - 1));
const XMFLOAT2 coord = XMFLOAT2(uv.x - uv_start.x, uv.y - uv_start.y);
float gradient = wi::math::GetAngle(direction, coord) / XM_2PI;
if (has_flag(flags, GradientFlags::Inverse))
{
gradient = 1 - gradient;
}
if (has_flag(flags, GradientFlags::Smoothstep))
{
gradient = wi::math::SmoothStep(0, 1, gradient);
}
data[x + y * width] = uint8_t(gradient * 255);
}
}
}
break;
}
Texture texture;
CreateTexture(texture, data.data(), width, height, Format::R8_UNORM, swizzle);
return texture;
}
Texture CreateCircularProgressGradientTexture(
uint32_t width,
uint32_t height,
const XMFLOAT2& direction,
bool counter_clockwise,
wi::graphics::Swizzle swizzle
Swizzle swizzle
)
{
wi::vector<uint8_t> data(width * height);
+27
View File
@@ -29,6 +29,29 @@ namespace wi::texturehelper
wi::graphics::Swizzle swizzle = {}
);
enum class GradientType
{
Linear,
Circular,
Angular,
};
enum class GradientFlags
{
None = 0,
Inverse = 1 << 0, // inverts resulting gradient
Smoothstep = 1 << 1 // applies smoothstep function to resulting gradient
};
wi::graphics::Texture CreateGradientTexture(
GradientType type,
uint32_t width,
uint32_t height,
const XMFLOAT2& uv_start = XMFLOAT2(0, 0),
const XMFLOAT2& uv_end = XMFLOAT2(1, 0),
GradientFlags gradient_flags = GradientFlags::None,
wi::graphics::Swizzle swizzle = { wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R }
);
// Similar to CreateGradientTexture() with GradientType::Angular type but different parameters
wi::graphics::Texture CreateCircularProgressGradientTexture(
uint32_t width,
uint32_t height,
@@ -38,3 +61,7 @@ namespace wi::texturehelper
);
};
template<>
struct enable_bitmask_operators<wi::texturehelper::GradientFlags> {
static const bool enable = true;
};
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 243;
const int revision = 244;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);