diff --git a/src/game/Global.h b/src/game/Global.h index 4ab39db..77df6c3 100644 --- a/src/game/Global.h +++ b/src/game/Global.h @@ -6,6 +6,63 @@ struct Vec2 { float x = 0.0f; float y = 0.0f; + + Vec2& operator+=(const Vec2& rhs) + { + x += rhs.x; + y += rhs.y; + return *this; + } + + friend Vec2 operator+(Vec2 lhs, const Vec2& rhs) + { + lhs += rhs; + return lhs; + } + + Vec2& operator-=(const Vec2& rhs) + { + x -= rhs.x; + y -= rhs.y; + return *this; + } + + friend Vec2 operator-(Vec2 lhs, const Vec2& rhs) + { + lhs -= rhs; + return lhs; + } + + Vec2& operator*=(const float rhs) + { + x *= rhs; + y *= rhs; + return *this; + } + + friend Vec2 operator*(Vec2 lhs, const float rhs) + { + lhs *= rhs; + return lhs; + } + + Vec2& operator/=(const float rhs) + { + x /= rhs; + y /= rhs; + return *this; + } + + friend Vec2 operator/(Vec2 lhs, const float rhs) + { + lhs /= rhs; + return lhs; + } + + float Magnitude() + { + return bx::sqrt(x * x + y * y); + } }; struct Vec3 diff --git a/src/game/Level.cpp b/src/game/Level.cpp index 812f1b5..ce6307d 100644 --- a/src/game/Level.cpp +++ b/src/game/Level.cpp @@ -3,7 +3,6 @@ #include "Instance.h" #include "Level.h" #include "Log.h" -#include "Mesh.h" #include "Puzzle.h" #include "SDL3/SDL_mouse.h" #include "bgfx/bgfx.h" @@ -19,8 +18,8 @@ namespace Game { if (ModelHandle == UINT16_MAX || MaterialHandle == UINT16_MAX) return; if (!Visible) return; + auto& rendering = GameRendering::Get(); - // Log("%u", ModelHandle); Transform.UpdateMatrix(); bgfx::setTransform(Transform.M.M); @@ -33,6 +32,7 @@ namespace Game float TimeValues[4]{0.0f}; TimeValues[0] = GetInstance().Time.Now; bgfx::setTexture(0, currentMaterial.Textures[0].SamplerHandle, currentMaterial.Textures[0].Handle); + bgfx::setTexture(1, rendering.DitherTextures.Sampler, rendering.DitherTextures.FinalTex); bgfx::setUniform(currentMaterial.Uniforms[Material::UTime], TimeValues); bgfx::setUniform(currentMaterial.Uniforms[Material::UDotColor], TestColor); diff --git a/src/game/compiled-shaders/dx11/frag.bin b/src/game/compiled-shaders/dx11/frag.bin index 1adb86e..d99be2b 100644 --- a/src/game/compiled-shaders/dx11/frag.bin +++ b/src/game/compiled-shaders/dx11/frag.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bfee536f305a5e9e421e1f5f0092f16cb978d0505fef2786c16e1be526447ab8 -size 12186 +oid sha256:a4f534be349af03c65d024db1a126f6ed229686718f3d409d72d08163b524906 +size 2064 diff --git a/src/game/compiled-shaders/glsl/frag.bin b/src/game/compiled-shaders/glsl/frag.bin index fc0480a..5056f82 100644 --- a/src/game/compiled-shaders/glsl/frag.bin +++ b/src/game/compiled-shaders/glsl/frag.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4c36fc403bd50335ff4d16ca017b39c6a9dd9d6868e2783731d0f644ad5731a -size 13148 +oid sha256:8687ed860438b2035627f5a18dcc3909be909dfaf61d86e60a8bfbf374edc409 +size 12332 diff --git a/src/game/compiled-shaders/spirv/frag.bin b/src/game/compiled-shaders/spirv/frag.bin index 25aa920..6aafbc2 100644 --- a/src/game/compiled-shaders/spirv/frag.bin +++ b/src/game/compiled-shaders/spirv/frag.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c40269d77665cece7e2c2bc760692c9bc19574d1ef6082fcf30f2af1564ce74 -size 7474 +oid sha256:a11349b7c86ccafb8a6c809dd9b447dbb867e5e345b5e4c1ff4a28985857c830 +size 2860 diff --git a/src/game/rendering/Rendering.cpp b/src/game/rendering/Rendering.cpp index e1f9be2..2af06e6 100644 --- a/src/game/rendering/Rendering.cpp +++ b/src/game/rendering/Rendering.cpp @@ -9,7 +9,9 @@ #include "backends/imgui_impl_sdl3.h" #include "bgfx/defines.h" #include "bx/bx.h" +#include "bx/constants.h" #include "bx/filepath.h" +#include "bx/math.h" #include "bx/timer.h" #include #include @@ -191,6 +193,109 @@ namespace Game return handle; } + void DitherGen(DitherData& data) + { + constexpr int32_t MaxRecursion = 1; + data.Points[0] = {0.0f, 0.0f}; + data.Points[1] = {0.5f, 0.5f}; + data.Points[2] = {0.5f, 0.0f}; + data.Points[3] = {0.0f, 0.5f}; + data.PointCount = 4; + + for (int32_t recursionLevel = 0; recursionLevel < MaxRecursion; ++recursionLevel) + { + int32_t startCount = data.PointCount; + float offset = bx::pow(0.5f, recursionLevel + 1); + for (int32_t i = 0; i < 4; ++i) + { + for (int32_t j = 0; j < startCount; ++j) + { + data.Points[data.PointCount] = data.Points[j] + data.Points[i] * offset; + data.PointCount++; + } + } + } + + uint64_t dotsPerSide = bx::round(bx::pow(2, MaxRecursion)); + data.DitherTexDepth = dotsPerSide * dotsPerSide; + data.DitherTexWH = 16 * dotsPerSide; + uint64_t texPixelCount = data.DitherTexWH * data.DitherTexWH * data.DitherTexDepth; + + if (BX_COUNTOF(DitherData::DitherTex) < texPixelCount) + { + Log("Too many pixels: %llu", texPixelCount); + return; + } + + float invRes = 1.0f / data.DitherTexWH; + for (int32_t z = 0; z < data.DitherTexDepth; ++z) + { + int32_t dotCount = z + 1; + float dotArea = 0.5f / dotCount; + float dotRadius = bx::sqrt(dotArea / bx::kPi); + + int zOffset = z * data.DitherTexWH * data.DitherTexWH; + for (int32_t y = 0; y < data.DitherTexWH; ++y) + { + int32_t yOffset = y * data.DitherTexWH; + for (int32_t x = 0; x < data.DitherTexWH; ++x) + { + Vec2 point{(x + 0.5f) * invRes, (y + 0.5f) * invRes}; + float dist = bx::kFloatInfinity; + for (int32_t i = 0; i < dotCount; ++i) + { + Vec2 vec = point - data.Points[i]; + Vec2 wrappedVec{bx::mod(vec.x + 0.5f, 1.0f) - 0.5f, bx::mod(vec.y + 0.5f, 1.0f) - 0.5f}; + float curDist = wrappedVec.Magnitude(); + dist = bx::min(dist, curDist); + } + + dist = dist / (dotRadius * 2.4f); + float val = bx::clamp(1.0f - dist, 0.0f, 1.0f); + data.DitherTex[x + yOffset + zOffset] = Vec4{val, val, val, 1.0f}; + // data.DitherTex[x + yOffset + zOffset] = Vec4{1.0, 0.0f, 0.0f, 1.0f}; + int32_t bucket = bx::clamp(uint32_t(val * DitherData::BrightnessBucketCount), + 0, + DitherData::BrightnessBucketCount - 1); + } + } + } + + // TODO: brightness ramp + + if (isValid(data.PreviewTex)) + { + bgfx::destroy(data.PreviewTex); + data.PreviewTex = BGFX_INVALID_HANDLE; + } + if (isValid(data.FinalTex)) + { + bgfx::destroy(data.FinalTex); + data.FinalTex = BGFX_INVALID_HANDLE; + } + const bgfx::Memory* memPreview = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4)); + const bgfx::Memory* memFinal = bgfx::makeRef(data.DitherTex, texPixelCount * sizeof(Vec4)); + data.PreviewTex = bgfx::createTexture2D(data.DitherTexWH, + data.DitherTexWH * data.DitherTexDepth, + false, + false, + bgfx::TextureFormat::RGBA32F, + 0, + memPreview); + data.FinalTex = bgfx::createTexture3D(data.DitherTexWH, + data.DitherTexWH, + data.DitherTexDepth, + false, + bgfx::TextureFormat::RGBA32F, + 0, + memFinal); + + if (!isValid(data.Sampler)) + { + data.Sampler = bgfx::createUniform("s_ditherSampler", bgfx::UniformType::Sampler); + } + } + GameRendering* Instance = nullptr; } // namespace @@ -269,6 +374,11 @@ namespace Game { ImGui::LoadIniSettingsFromMemory(inst.ImguiIni, inst.ImguiIniSize); } + else + { + ImGui::LoadIniSettingsFromDisk("imgui.ini"); + } + DitherGen(DitherTextures); } void GameRendering::Update() @@ -308,10 +418,12 @@ namespace Game if (isValid(newProgram)) { Materials[0].Shader = newProgram; + LastShaderLoadTime = GetInstance().Time.Now; } else { Log("Failed to load shader!"); + LastShaderLoadTime = -1.0f; } } } @@ -325,16 +437,48 @@ namespace Game { if (ImGui::Begin("Rendering")) { + if (LastShaderLoadTime >= 0.0f) + { + ImGui::TextColored({0.2f, 0.9f, 0.2f, 1.0f}, + "Shader loaded %.0f seconds ago", + GetInstance().Time.Now - LastShaderLoadTime); + } + else + { + ImGui::TextColored({0.9f, 0.2f, 0.2f, 1.0f}, "Shader load Failiure!"); + } if (ImGui::Button("Reload Meshes")) { LoadModels(Models, ModelCount); } + ImGui::SameLine(); if (ImGui::Button("Reload Level")) { auto& lvl = GetInstance().GameLevel; lvl = {}; lvl.Setup(shared.Game); } + if (ImGui::Button("Dithergen")) + { + DitherGen(DitherTextures); + } + ImGui::Text( + "%ux%ux%u", DitherTextures.DitherTexWH, DitherTextures.DitherTexWH, DitherTextures.DitherTexDepth); + if (!isValid(DitherTextures.PreviewTex)) + { + ImGui::Text("Invalid Texture"); + } + else + { + ImGui::Image(DitherTextures.PreviewTex.idx, + {(float)DitherTextures.DitherTexWH, + (float)DitherTextures.DitherTexWH * DitherTextures.DitherTexDepth}); + } + ImGui::Text("Brightness Buckets (TODO)"); + for (int32_t i = 0; i < DitherTextures.BrightnessBucketCount; ++i) + { + ImGui::Text("%u", DitherTextures.BrightnessBuckets[i]); + } } ImGui::End(); } @@ -366,6 +510,7 @@ namespace Game void GameRendering::Shutdown() { Log("--- RENDERING_SHUTDOWN ---"); + ImGui::SaveIniSettingsToDisk("imgui.ini"); const char* iniData = ImGui::SaveIniSettingsToMemory(reinterpret_cast(&GetInstance().ImguiIniSize)); assert(GetInstance().ImguiIniSize <= BX_COUNTOF(GameInstance::ImguiIni)); bx::memCopy( diff --git a/src/game/rendering/Rendering.h b/src/game/rendering/Rendering.h index 621fcd7..89c3690 100644 --- a/src/game/rendering/Rendering.h +++ b/src/game/rendering/Rendering.h @@ -4,6 +4,9 @@ #include #include +#include "../Global.h" +#include "imgui.h" + union SDL_Event; namespace Game @@ -62,6 +65,21 @@ namespace Game Debug, }; + struct DitherData + { + static constexpr uint32_t BrightnessBucketCount = 256; + Vec2 Points[1024]; + uint32_t PointCount = 0; + Vec4 DitherTex[64 * 64 * 16]; + uint32_t DitherTexWH = 0; + uint32_t DitherTexDepth = 0; + int32_t BrightnessBuckets[BrightnessBucketCount]; + bgfx::TextureHandle PreviewTex = BGFX_INVALID_HANDLE; + bgfx::TextureHandle FinalTex = BGFX_INVALID_HANDLE; + bgfx::UniformHandle Sampler = BGFX_INVALID_HANDLE; + ImTextureID PreviewID = 0; + }; + class GameRendering { public: @@ -70,6 +88,7 @@ namespace Game public: UIVisibilityState UIVisible = UIVisibilityState::Game; + DitherData DitherTextures; private: bgfx::UniformHandle DefaultSampler; @@ -81,6 +100,7 @@ namespace Game int32_t LastHeight = 0; uint32_t ResetFlags = BGFX_RESET_VSYNC; uint16_t MainViewID = 10; + float LastShaderLoadTime = 0.0f; public: void Setup(); diff --git a/src/game/shaders/frag.sc b/src/game/shaders/frag.sc index b2a7c18..11b841f 100644 --- a/src/game/shaders/frag.sc +++ b/src/game/shaders/frag.sc @@ -6,19 +6,10 @@ $input v_wpos #include "common.sh" SAMPLER2D(s_texColor, 0); +SAMPLER3D(s_ditherSampler, 1); uniform vec4 u_time; uniform vec4 u_testColor; -float circle(vec2 uv, float radius) -{ - float distSq = uv.x * uv.x + uv.y * uv.y; - // float result = sqrt(distSq) / radius * 0.8; - float result = sqrt(distSq) / radius; - // float clamped = clamp(1.0 - result, 0.0, 1.0); - float clamped = clamp(1.5 - result, 0.0, 1.0); - return clamped; -} - float calcBrightness(vec3 lightPos, vec3 vertPos, vec3 normal) { vec3 lightDir = normalize(lightPos - vertPos); @@ -31,28 +22,6 @@ float calcBrightnessDirectional(vec3 sunDir, vec3 normal) return max(0.0, dot(sunDir, normal)); } -float circles(vec2 uv, float level, float subLevel, float brightness) -{ - vec2 offsetUv = uv + 0.5; - vec2 baseUv = (offsetUv % 1.0) - 0.5; - vec2 step1Uv = ((offsetUv + vec2(0.5, 0.5)) % 1.0) - 0.5; - vec2 step2Uv = ((offsetUv + vec2(0.5, 0.0)) % 1.0) - 0.5; - vec2 step3Uv = ((offsetUv + vec2(0.0, 0.5)) % 1.0) - 0.5; - - float step = subLevel * 3.0; - float step1 = clamp(step, 0.0, 1.0); - float step2 = clamp(step - 1, 0.0, 1.0); - float step3 = clamp(step - 2, 0.0, 1.0); - - float sum = 0.0; - sum = circle(baseUv, lerp(0.5, 0.25, subLevel) * brightness); - sum = max(sum, circle(step1Uv, 0.25 * step1 * brightness)); - sum = max(sum, circle(step2Uv, 0.25 * step2 * brightness)); - sum = max(sum, circle(step3Uv, 0.25 * step3 * brightness)); - - return min(sum, 1.0); -} - vec3 desaturate(vec3 color) { return vec3_splat(dot(color, vec3(0.33, 0.34, 0.33))); @@ -66,11 +35,11 @@ void main() float3 lightPos = vec3(sin(u_time.x * testSpeed) * testRadius, 5.0, cos(u_time.x * testSpeed) * testRadius); // float brightness = calcBrightness(lightPos, v_wpos, v_normal); float brightness = calcBrightnessDirectional(vec3(0.5, 0.3, 1.0), v_normal); - // brightness = 1.0; + brightness = 1.0; // brightness = sin(u_time.x) * 0.5 + 0.5; // Magic dot frequency calculation - float baseScale = 2.0; + float baseScale = 8.0; float2 dx = ddx(v_uv0 * baseScale); float2 dy = ddy(v_uv0 * baseScale); float2x2 mat = float2x2(dx, dy); @@ -89,20 +58,16 @@ void main() int patternScaleLevel = floor(spacingLog); float patternFractional = spacingLog - patternScaleLevel; vec2 uv = v_uv0 * exp2(patternScaleLevel); + + float dotsTotal = 4; + float subLayer = lerp(0.25 * dotsTotal, dotsTotal, patternFractional); + subLayer = (subLayer - 0.5) / dotsTotal; + + vec4 circleSample = texture3D(s_ditherSampler, vec3(uv, subLayer)); + float circleVal = circleSample.x < 0.75 ? 0.1 : 0.9; // Coloring vec3 texColor = u_testColor.x > 0.1 ? u_testColor.xyz : texture2D(s_texColor, v_uv0).xyz; - vec3 color; - color.r = circles(uv, patternScaleLevel, patternFractional, brightness * texColor.r); - color.g = circles(uv, patternScaleLevel, patternFractional, brightness * texColor.g); - color.b = circles(uv, patternScaleLevel, patternFractional, brightness * texColor.b); - // color = circles(uv, patternScaleLevel, patternFractional, brightness) * texColor; - gl_FragColor = vec4(color, 1.0); - // vec3 smoothColor = brightness * u_testColor.xyz; - // gl_FragColor = brightness; - // gl_FragColor = dither; - // gl_FragColor = u_testColor; - // gl_FragColor = vec4(texColor, 1.0); - // gl_FragColor = vec4(v_normal, 1.0); - // gl_FragColor = vec4(uv, 0.0, 1.0); + vec3 finalColor = texColor * vec3(circleVal, circleVal, circleVal); + gl_FragColor = vec4(finalColor, 1.0); } diff --git a/src/imgui.ini b/src/imgui.ini new file mode 100644 index 0000000..39ebc3c --- /dev/null +++ b/src/imgui.ini @@ -0,0 +1,21 @@ +[Window][WindowOverViewport_11111111] +Pos=0,0 +Size=1920,1080 +Collapsed=0 + +[Window][Rendering] +Pos=1595,0 +Size=325,1080 +Collapsed=0 +DockId=0x00000002,0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,0 Size=1920,1080 Split=X + DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=1593,1009 CentralNode=1 + DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=325,1009 Selected=0xCEB1220F + diff --git a/src/models/w straight.glb b/src/models/w straight.glb index a0ded79..ff48717 100644 --- a/src/models/w straight.glb +++ b/src/models/w straight.glb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bca71fef2436990460135dc4a57af9ed189d144cc611db4478b19d3c6707782d +oid sha256:b548df1c97326fb565cd5d398fa80d8f8d1009d3eb30e341b0130e851a61165d size 2260