From 986db49947fe67f9ef5a847ef93c01c5eb7436ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Tue, 24 Oct 2023 08:59:52 +0200 Subject: [PATCH] gradient texture helper improvements, lua bindings --- .../ScriptingAPI-Documentation.md | 45 +++++++ Tests/test_script.lua | 14 +++ WickedEngine/wiGraphics.h | 39 ++++++ WickedEngine/wiMath.h | 2 +- WickedEngine/wiTextureHelper.cpp | 76 +++++++++++- WickedEngine/wiTextureHelper.h | 10 +- WickedEngine/wiTexture_BindLua.cpp | 115 +++++++++++++++++- WickedEngine/wiTexture_BindLua.h | 4 + 8 files changed, 295 insertions(+), 10 deletions(-) diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index cc41a821d..7d7fb9db3 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -385,6 +385,51 @@ Gives you the ability to render text with a custom font. ### Texture Just holds texture information in VRAM. - [constructor]Texture(opt string filename) -- creates a texture from file +- [outer]texturehelper -- a global helper texture creation utility +- GetLogo() : Texture -- returns the Wicked Engine logo texture +- CreateGradientTexture( + GradientType type = GradientType.Linear, + int width = 256, + int height = 256, + Vector uv_start = Vector(0,0), + Vector uv_end = Vector(0,0), + GradientFlags flags = GradientFlags.None, + string swizzle = "rgba", + float perlin_scale = 1, + int perlin_seed = 1234, + int perlin_octaves = 8, + float perlin_persistence = 0.5) -- creates a gradient texture from parameters + +```lua +GradientType = { + Linear = 0, + Circular = 1, + Angular = 2, +} + +GradientFlags = { + None = 0, + Inverse = 1 << 0, + Smoothstep = 1 << 1, + PerlinNoise = 1 << 2, + R16Unorm = 1 << 3, +} +``` + +Example gradient texture creation: +```lua +texture = texturehelper.CreateGradientTexture( + GradientType.Circular, -- gradient type + 256, 256, -- resolution of the texture + Vector(0.5, 0.5), Vector(0.5, 0), -- start and end uv coordinates will specify the gradient direction and extents + GradientFlags.Inverse | GradientFlags.Smoothstep | GradientFlags.PerlinNoise, -- modifier flags bitwise combination + "rrr1", -- for each channel ,you can specify one of the following characters: 0, 1, r, g, b, a + 2, -- perlin noise scale + 123, -- perlin noise seed + 6, -- perlin noise octaves + 0.8 -- perlin noise persistence +) +``` ### Audio Loads and plays an audio files. diff --git a/Tests/test_script.lua b/Tests/test_script.lua index 38859927d..b53fa37fc 100644 --- a/Tests/test_script.lua +++ b/Tests/test_script.lua @@ -13,6 +13,20 @@ ToggleCameraAnimation(); -- Load an image: local sprite = Sprite("../Content/logo_small.png"); +--sprite.SetTexture( +-- texturehelper.CreateGradientTexture( +-- GradientType.Circular, -- gradient type +-- 256, 256, -- resolution of the texture +-- Vector(0.5, 0.5), Vector(0.5, 0), -- start and end uv coordinates will specify the gradient direction and extents +-- GradientFlags.Inverse | GradientFlags.Smoothstep | GradientFlags.PerlinNoise, -- modifier flags bitwise combination +-- "111R", -- for each channel ,you can specify one of the following characters: 0, 1, r, g, b, a +-- 2, -- perlin noise scale +-- 123, -- perlin noise seed +-- 6, -- perlin noise octaves +-- 0.8 -- perlin noise persistence +-- ) +--) +--sprite.SetTexture(texturehelper.GetLogo()) sprite.SetParams(ImageParams(100,100,128,128)); -- Set this image as renderable to the active component: local component = main.GetActivePath(); diff --git a/WickedEngine/wiGraphics.h b/WickedEngine/wiGraphics.h index b46c53d8a..a7ed4a496 100644 --- a/WickedEngine/wiGraphics.h +++ b/WickedEngine/wiGraphics.h @@ -1728,6 +1728,45 @@ namespace wi::graphics ret.chars[4] = 0; return ret; } + constexpr Swizzle SwizzleFromString(const char* str) + { + Swizzle swizzle; + if (str == nullptr) + return swizzle; + ComponentSwizzle* comp = (ComponentSwizzle*)&swizzle; + for (int i = 0; i < 4; ++i) + { + switch (str[i]) + { + case 'r': + case 'R': + *comp = ComponentSwizzle::R; + break; + case 'g': + case 'G': + *comp = ComponentSwizzle::G; + break; + case 'b': + case 'B': + *comp = ComponentSwizzle::B; + break; + case 'a': + case 'A': + *comp = ComponentSwizzle::A; + break; + case '0': + *comp = ComponentSwizzle::ZERO; + break; + case '1': + *comp = ComponentSwizzle::ONE; + break; + case 0: + return swizzle; + } + comp++; + } + return swizzle; + } template constexpr T AlignTo(T value, T alignment) diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index 5d19da123..006f7b506 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -113,7 +113,7 @@ namespace wi::math } constexpr float InverseLerp(float value1, float value2, float pos) { - return (pos - value1) / (value2 - value1); + return value2 == value1 ? 0 : ((pos - value1) / (value2 - value1)); } constexpr XMFLOAT2 InverseLerp(const XMFLOAT2& value1, const XMFLOAT2& value2, const XMFLOAT2& pos) { diff --git a/WickedEngine/wiTextureHelper.cpp b/WickedEngine/wiTextureHelper.cpp index 51a2eeac3..9832c9197 100644 --- a/WickedEngine/wiTextureHelper.cpp +++ b/WickedEngine/wiTextureHelper.cpp @@ -6,6 +6,7 @@ #include "wiTimer.h" #include "wiUnorderedMap.h" #include "logo.h" +#include "wiNoise.h" using namespace wi::graphics; @@ -279,10 +280,30 @@ namespace wi::texturehelper const XMFLOAT2& uv_start, const XMFLOAT2& uv_end, GradientFlags flags, - Swizzle swizzle + Swizzle swizzle, + float perlin_scale, + uint32_t perlin_seed, + int perlin_octaves, + float perlin_persistence ) { - wi::vector data(width * height); + wi::vector data; + wi::vector data16; + if (has_flag(flags, GradientFlags::R16Unorm)) + { + data16.resize(width * height); + } + else + { + data.resize(width * height); + } + wi::noise::Perlin perlin; + if (has_flag(flags, GradientFlags::PerlinNoise)) + { + perlin.init(perlin_seed); + } + float aspect = float(height) / float(width); + XMFLOAT2 perlin_scale2 = XMFLOAT2(perlin_scale, perlin_scale * aspect); switch (type) { @@ -308,7 +329,19 @@ namespace wi::texturehelper { gradient = wi::math::SmoothStep(0, 1, gradient); } - data[x + y * width] = uint8_t(gradient * 255); + if (has_flag(flags, GradientFlags::PerlinNoise)) + { + gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; + } + gradient = wi::math::saturate(gradient); + if (has_flag(flags, GradientFlags::R16Unorm)) + { + data16[x + y * width] = uint16_t(gradient * 65535); + } + else + { + data[x + y * width] = uint8_t(gradient * 255); + } } } } @@ -334,7 +367,19 @@ namespace wi::texturehelper { gradient = wi::math::SmoothStep(0, 1, gradient); } - data[x + y * width] = uint8_t(gradient * 255); + if (has_flag(flags, GradientFlags::PerlinNoise)) + { + gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; + } + gradient = wi::math::saturate(gradient); + if (has_flag(flags, GradientFlags::R16Unorm)) + { + data16[x + y * width] = uint16_t(gradient * 65535); + } + else + { + data[x + y * width] = uint8_t(gradient * 255); + } } } } @@ -359,7 +404,19 @@ namespace wi::texturehelper { gradient = wi::math::SmoothStep(0, 1, gradient); } - data[x + y * width] = uint8_t(gradient * 255); + if (has_flag(flags, GradientFlags::PerlinNoise)) + { + gradient *= perlin.compute(uv.x * perlin_scale2.x, uv.y * perlin_scale2.y, 0, perlin_octaves, perlin_persistence) * 0.5f + 0.5f; + } + gradient = wi::math::saturate(gradient); + if (has_flag(flags, GradientFlags::R16Unorm)) + { + data16[x + y * width] = uint16_t(gradient * 65535); + } + else + { + data[x + y * width] = uint8_t(gradient * 255); + } } } } @@ -368,7 +425,14 @@ namespace wi::texturehelper } Texture texture; - CreateTexture(texture, data.data(), width, height, Format::R8_UNORM, swizzle); + if (has_flag(flags, GradientFlags::R16Unorm)) + { + CreateTexture(texture, (const uint8_t*)data16.data(), width, height, Format::R16_UNORM, swizzle); + } + else + { + CreateTexture(texture, data.data(), width, height, Format::R8_UNORM, swizzle); + } return texture; } diff --git a/WickedEngine/wiTextureHelper.h b/WickedEngine/wiTextureHelper.h index 9d56192aa..5e9b52064 100644 --- a/WickedEngine/wiTextureHelper.h +++ b/WickedEngine/wiTextureHelper.h @@ -39,7 +39,9 @@ namespace wi::texturehelper { None = 0, Inverse = 1 << 0, // inverts resulting gradient - Smoothstep = 1 << 1 // applies smoothstep function to resulting gradient + Smoothstep = 1 << 1, // applies smoothstep function to resulting gradient + PerlinNoise = 1 << 2, // applies perlin noise to gradient + R16Unorm = 1 << 3, // the texture will be created in R16_UNORM format instead of R8_UNORM }; wi::graphics::Texture CreateGradientTexture( GradientType type, @@ -48,7 +50,11 @@ namespace wi::texturehelper 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 } + wi::graphics::Swizzle swizzle = { wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R, wi::graphics::ComponentSwizzle::R }, + float perlin_scale = 1, + uint32_t perlin_seed = 1234u, + int perlin_octaves = 8, + float perlin_persistence = 0.5f ); // Similar to CreateGradientTexture() with GradientType::Angular type but different parameters diff --git a/WickedEngine/wiTexture_BindLua.cpp b/WickedEngine/wiTexture_BindLua.cpp index fb8bca384..d90be6fb2 100644 --- a/WickedEngine/wiTexture_BindLua.cpp +++ b/WickedEngine/wiTexture_BindLua.cpp @@ -1,4 +1,6 @@ #include "wiTexture_BindLua.h" +#include "wiTextureHelper.h" +#include "wiMath_BindLua.h" using namespace wi::graphics; @@ -6,6 +8,8 @@ namespace wi::lua { Luna::FunctionType Texture_BindLua::methods[] = { + lunamethod(Texture_BindLua, GetLogo), + lunamethod(Texture_BindLua, CreateGradientTexture), { NULL, NULL } }; Luna::PropertyType Texture_BindLua::properties[] = { @@ -22,13 +26,122 @@ namespace wi::lua } } + int Texture_BindLua::GetLogo(lua_State* L) + { + Luna::push(L, *wi::texturehelper::getLogo()); + return 1; + } + int Texture_BindLua::CreateGradientTexture(lua_State* L) + { + wi::texturehelper::GradientType gradient_type = wi::texturehelper::GradientType::Linear; + uint32_t width = 256; + uint32_t height = 256; + XMFLOAT2 uv_start = XMFLOAT2(0, 0); + XMFLOAT2 uv_end = XMFLOAT2(0, 0); + wi::texturehelper::GradientFlags gradient_flags = wi::texturehelper::GradientFlags::None; + std::string swizzle_string; + float perlin_scale = 1; + uint32_t perlin_seed = 1234u; + int perlin_octaves = 8; + float perlin_persistence = 0.5f; + int argc = wi::lua::SGetArgCount(L); + if (argc > 0) + { + gradient_type = (wi::texturehelper::GradientType)wi::lua::SGetInt(L, 1); + if (argc > 1) + { + width = (uint32_t)wi::lua::SGetInt(L, 2); + if (argc > 2) + { + height = (uint32_t)wi::lua::SGetInt(L, 3); + if (argc > 3) + { + Vector_BindLua* v1 = Luna::lightcheck(L, 4); + if (v1) + { + uv_start = v1->GetFloat2(); + } + else + { + wi::lua::SError(L, "CreateGradientTexture() uv_start argument is not a vector!"); + } + if (argc > 4) + { + Vector_BindLua* v2 = Luna::lightcheck(L, 5); + if (v2) + { + uv_end = v2->GetFloat2(); + } + else + { + wi::lua::SError(L, "CreateGradientTexture() uv_end argument is not a vector!"); + } + if (argc > 5) + { + gradient_flags = (wi::texturehelper::GradientFlags)wi::lua::SGetInt(L, 6); + if (argc > 6) + { + swizzle_string = wi::lua::SGetString(L, 7); + if (argc > 7) + { + perlin_scale = wi::lua::SGetFloat(L, 8); + if (argc > 8) + { + perlin_seed = (uint32_t)wi::lua::SGetInt(L, 9); + if (argc > 9) + { + perlin_octaves = wi::lua::SGetInt(L, 10); + if (argc > 10) + { + perlin_persistence = wi::lua::SGetFloat(L, 11); + } + } + } + } + } + } + } + } + } + } + } + wi::graphics::Texture texture = wi::texturehelper::CreateGradientTexture( + gradient_type, + width, height, + uv_start, uv_end, + gradient_flags, + wi::graphics::SwizzleFromString(swizzle_string.c_str()), + perlin_scale, + perlin_seed, + perlin_octaves, + perlin_persistence + ); + Luna::push(L, texture); + return 1; + } + void Texture_BindLua::Bind() { static bool initialized = false; if (!initialized) { - Luna::Register(wi::lua::GetLuaState()); initialized = true; + Luna::Register(wi::lua::GetLuaState()); + Luna::push_global(wi::lua::GetLuaState(), "texturehelper"); + wi::lua::RunText(R"( +GradientType = { + Linear = 0, + Circular = 1, + Angular = 2, +} +GradientFlags = { + None = 0, + Inverse = 1 << 0, + Smoothstep = 1 << 1, + PerlinNoise = 1 << 2, + R16Unorm = 1 << 3, +} +)"); } } diff --git a/WickedEngine/wiTexture_BindLua.h b/WickedEngine/wiTexture_BindLua.h index 5d99c4477..e5f90b282 100644 --- a/WickedEngine/wiTexture_BindLua.h +++ b/WickedEngine/wiTexture_BindLua.h @@ -16,10 +16,14 @@ namespace wi::lua static Luna::FunctionType methods[]; static Luna::PropertyType properties[]; + Texture_BindLua() = default; Texture_BindLua(wi::Resource resource) :resource(resource) {} Texture_BindLua(wi::graphics::Texture texture) { resource.SetTexture(texture); } Texture_BindLua(lua_State* L); + int GetLogo(lua_State* L); + int CreateGradientTexture(lua_State* L); + static void Bind(); };