From 69616149e5de6bc015b39347b2dd185581b8d740 Mon Sep 17 00:00:00 2001 From: turanszkij Date: Fri, 10 Apr 2020 17:09:04 +0100 Subject: [PATCH] gui: blurred transparency and usability improvements --- Documentation/ScriptingAPI-Documentation.md | 3 + Documentation/WickedEngine-Documentation.md | 2 +- Editor/Editor.cpp | 71 +- Editor/Editor.h | 1 + Tests/Tests.cpp | 10 +- WickedEngine/RenderPath2D.cpp | 1 + WickedEngine/RenderPath2D.h | 1 + WickedEngine/RenderPath3D.cpp | 24 + WickedEngine/RenderPath3D.h | 2 + WickedEngine/ResourceMapping.h | 5 + WickedEngine/ShaderInterop_Image.h | 16 +- WickedEngine/WickedEngine_SHADERS.vcxproj | 9 + .../WickedEngine_SHADERS.vcxproj.filters | 15 +- WickedEngine/downsample4xCS.hlsl | 23 + WickedEngine/imageHF.hlsli | 12 +- WickedEngine/imagePS_backgroundblur.hlsl | 9 + .../imagePS_backgroundblur_bicubic.hlsl | 9 + WickedEngine/imageVS.hlsl | 1 + WickedEngine/wiColor.h | 2 + WickedEngine/wiEnums.h | 1 + WickedEngine/wiFont.h | 2 +- WickedEngine/wiFont_BindLua.cpp | 4 +- WickedEngine/wiGUI.cpp | 27 +- WickedEngine/wiGUI.h | 1 + WickedEngine/wiImage.cpp | 28 +- WickedEngine/wiImage.h | 25 +- WickedEngine/wiImageParams_BindLua.cpp | 32 +- WickedEngine/wiImageParams_BindLua.h | 3 + WickedEngine/wiRenderer.cpp | 41 + WickedEngine/wiRenderer.h | 6 + WickedEngine/wiSprite.cpp | 5 +- WickedEngine/wiVersion.cpp | 2 +- WickedEngine/wiWidget.cpp | 1729 +++++++++-------- WickedEngine/wiWidget.h | 64 +- 34 files changed, 1221 insertions(+), 965 deletions(-) create mode 100644 WickedEngine/downsample4xCS.hlsl create mode 100644 WickedEngine/imagePS_backgroundblur.hlsl create mode 100644 WickedEngine/imagePS_backgroundblur_bicubic.hlsl diff --git a/Documentation/ScriptingAPI-Documentation.md b/Documentation/ScriptingAPI-Documentation.md index c9d975e1b..8ba4ff8c8 100644 --- a/Documentation/ScriptingAPI-Documentation.md +++ b/Documentation/ScriptingAPI-Documentation.md @@ -182,6 +182,7 @@ Specify Sprite properties, like position, size, etc. - IsDrawRectEnabled() : bool result - IsDrawRect2Enabled() : bool result - IsMirrorEnabled() : bool result +- IsBackgroundBlurEnabled() : bool result - SetPos(Vector pos) - SetSize(Vector size) - SetPivot(Vector value) @@ -203,6 +204,8 @@ Specify Sprite properties, like position, size, etc. - DisableDrawRect2() - EnableMirror() - DisableMirror() +- EnableBackgroundBlur(opt float mip = 0) +- DisableBackgroundBlur() - [outer]STENCILMODE_DISABLED : int - [outer]STENCILMODE_EQUAL : int diff --git a/Documentation/WickedEngine-Documentation.md b/Documentation/WickedEngine-Documentation.md index f14bc3047..609675747 100644 --- a/Documentation/WickedEngine-Documentation.md +++ b/Documentation/WickedEngine-Documentation.md @@ -771,7 +771,7 @@ This can render fonts to the screen in a simple manner. You can render a font as ```cpp wiFont("write this!", wiFontParams(10, 20)).Draw(cmd); ``` -Which will write the text write this! to 10, 20 pixel position onto the screen. There are many other parameters to describe the font's position, size, color, etc. See the wiFontParams structure for more details. +Which will write the text write this! to 10, 20 pixel position onto the screen. There are many other parameters to describe the font's position, size, color, etc. See the wiFontParams structure for more details. Note that wiFont internally does string conversion, so it is recommended to avoid repeatedly creating wiFont resources during the frame! - wiFontParams
Describe all parameters of how and where to draw the font on the screen. diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index e71ce210a..9c73955e2 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -220,8 +220,8 @@ void EditorComponent::Load() float screenH = (float)wiRenderer::GetDevice()->GetScreenHeight(); XMFLOAT2 option_size = XMFLOAT2(100, 28); - float step = (option_size.y + 5) * -1, x = screenW - option_size.x, y = screenH - option_size.y; - float hstep = (option_size.x + 5) * -1; + float step = (option_size.y + 2) * -1, x = screenW - option_size.x, y = screenH - option_size.y; + float hstep = (option_size.x + 2) * -1; wiButton* paintToolWnd_Toggle = new wiButton("Paint Tool"); @@ -429,7 +429,7 @@ void EditorComponent::Load() saveButton->SetTooltip("Save the current scene"); saveButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5, 0)); saveButton->SetSize(XMFLOAT2(100, 40)); - saveButton->SetColor(wiColor(0, 198, 101, 200), wiWidget::WIDGETSTATE::IDLE); + saveButton->SetColor(wiColor(0, 198, 101, 180), wiWidget::WIDGETSTATE::IDLE); saveButton->SetColor(wiColor(0, 255, 140, 255), wiWidget::WIDGETSTATE::FOCUS); saveButton->OnClick([=](wiEventArgs args) { @@ -468,7 +468,7 @@ void EditorComponent::Load() modelButton->SetTooltip("Load a scene / import model into the editor..."); modelButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 4, 0)); modelButton->SetSize(XMFLOAT2(100, 40)); - modelButton->SetColor(wiColor(0, 89, 255, 200), wiWidget::WIDGETSTATE::IDLE); + modelButton->SetColor(wiColor(0, 89, 255, 180), wiWidget::WIDGETSTATE::IDLE); modelButton->SetColor(wiColor(112, 155, 255, 255), wiWidget::WIDGETSTATE::FOCUS); modelButton->OnClick([=](wiEventArgs args) { thread([&] { @@ -529,7 +529,7 @@ void EditorComponent::Load() scriptButton->SetTooltip("Load a Lua script..."); scriptButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 3, 0)); scriptButton->SetSize(XMFLOAT2(100, 40)); - scriptButton->SetColor(wiColor(255, 33, 140, 200), wiWidget::WIDGETSTATE::IDLE); + scriptButton->SetColor(wiColor(255, 33, 140, 180), wiWidget::WIDGETSTATE::IDLE); scriptButton->SetColor(wiColor(255, 100, 140, 255), wiWidget::WIDGETSTATE::FOCUS); scriptButton->OnClick([=](wiEventArgs args) { thread([&] { @@ -555,7 +555,7 @@ void EditorComponent::Load() shaderButton->SetTooltip("Reload shaders from the default directory..."); shaderButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 2, 0)); shaderButton->SetSize(XMFLOAT2(100, 40)); - shaderButton->SetColor(wiColor(255, 33, 140, 200), wiWidget::WIDGETSTATE::IDLE); + shaderButton->SetColor(wiColor(255, 33, 140, 180), wiWidget::WIDGETSTATE::IDLE); shaderButton->SetColor(wiColor(255, 100, 140, 255), wiWidget::WIDGETSTATE::FOCUS); shaderButton->OnClick([=](wiEventArgs args) { @@ -571,7 +571,7 @@ void EditorComponent::Load() clearButton->SetTooltip("Delete every model from the scene"); clearButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 1, 0)); clearButton->SetSize(XMFLOAT2(100, 40)); - clearButton->SetColor(wiColor(255, 205, 43, 200), wiWidget::WIDGETSTATE::IDLE); + clearButton->SetColor(wiColor(255, 205, 43, 180), wiWidget::WIDGETSTATE::IDLE); clearButton->SetColor(wiColor(255, 235, 173, 255), wiWidget::WIDGETSTATE::FOCUS); clearButton->OnClick([&](wiEventArgs args) { translator.selected.clear(); @@ -596,7 +596,7 @@ void EditorComponent::Load() helpButton->SetTooltip("Help"); helpButton->SetPos(XMFLOAT2(screenW - 50 - 55, 0)); helpButton->SetSize(XMFLOAT2(50, 40)); - helpButton->SetColor(wiColor(34, 158, 214, 200), wiWidget::WIDGETSTATE::IDLE); + helpButton->SetColor(wiColor(34, 158, 214, 180), wiWidget::WIDGETSTATE::IDLE); helpButton->SetColor(wiColor(113, 183, 214, 255), wiWidget::WIDGETSTATE::FOCUS); helpButton->OnClick([=](wiEventArgs args) { static wiLabel* helpLabel = nullptr; @@ -646,7 +646,7 @@ void EditorComponent::Load() exitButton->SetTooltip("Exit"); exitButton->SetPos(XMFLOAT2(screenW - 50, 0)); exitButton->SetSize(XMFLOAT2(50, 40)); - exitButton->SetColor(wiColor(190, 0, 0, 200), wiWidget::WIDGETSTATE::IDLE); + exitButton->SetColor(wiColor(190, 0, 0, 180), wiWidget::WIDGETSTATE::IDLE); exitButton->SetColor(wiColor(255, 0, 0, 255), wiWidget::WIDGETSTATE::FOCUS); exitButton->OnClick([this](wiEventArgs args) { exit(0); @@ -1766,7 +1766,10 @@ void EditorComponent::Compose(CommandList cmd) const Scene& scene = wiScene::GetScene(); - const XMFLOAT4 selectedEntityColor = wiMath::Lerp(wiMath::Lerp(XMFLOAT4(1, 1, 1, 1), selectionColor, 0.4f), selectionColor, selectionColorIntensity); + const wiColor inactiveEntityColor = wiColor::fromFloat4(XMFLOAT4(1, 1, 1, 0.5f)); + const wiColor hoveredEntityColor = wiColor::fromFloat4(XMFLOAT4(1, 1, 1, 1)); + const XMFLOAT4 glow = wiMath::Lerp(wiMath::Lerp(XMFLOAT4(1, 1, 1, 1), selectionColor, 0.4f), selectionColor, selectionColorIntensity); + const wiColor selectedEntityColor = wiColor::fromFloat4(glow); if (rendererWnd->GetPickType() & PICK_LIGHT) { @@ -1783,17 +1786,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -1831,17 +1834,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -1866,17 +1869,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -1901,17 +1904,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -1935,17 +1938,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -1969,17 +1972,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -2003,17 +2006,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } @@ -2037,17 +2040,17 @@ void EditorComponent::Compose(CommandList cmd) const fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); - fx.col = XMFLOAT4(1, 1, 1, 0.5f); + fx.color = inactiveEntityColor; if (hovered.entity == entity) { - fx.col = XMFLOAT4(1, 1, 1, 1); + fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { - fx.col = selectedEntityColor; + fx.color = selectedEntityColor; break; } } diff --git a/Editor/Editor.h b/Editor/Editor.h index 28992b852..d69a35fe8 100644 --- a/Editor/Editor.h +++ b/Editor/Editor.h @@ -72,6 +72,7 @@ public: RENDERPATH_PATHTRACING, }; void ChangeRenderPath(RENDERPATH path); + const wiGraphics::Texture* GetGUIBlurredBackground() const override { return renderPath->GetGUIBlurredBackground(); } void ResizeBuffers() override; void Load() override; diff --git a/Tests/Tests.cpp b/Tests/Tests.cpp index a7981c431..c0e0709ff 100644 --- a/Tests/Tests.cpp +++ b/Tests/Tests.cpp @@ -74,10 +74,12 @@ void TestsRenderer::Load() wiSlider* volume = new wiSlider(0, 100, 50, 100, "Volume"); volume->SetText("Volume: "); - volume->SetSize(XMFLOAT2(95, 20)); + volume->SetSize(XMFLOAT2(100, 20)); volume->SetPos(XMFLOAT2(65, 110)); - volume->SetColor(wiColor(255, 205, 43, 200), wiWidget::WIDGETSTATE::IDLE); - volume->SetColor(wiColor(255, 235, 173, 255), wiWidget::WIDGETSTATE::FOCUS); + volume->sprites_knob[wiWidget::WIDGETSTATE::IDLE].params.color = wiColor(255, 205, 43, 200); + volume->sprites_knob[wiWidget::WIDGETSTATE::FOCUS].params.color = wiColor(255, 235, 173, 255); + volume->sprites[wiWidget::WIDGETSTATE::IDLE].params.color = wiMath::Lerp(wiColor::Transparent(), volume->sprites_knob[wiWidget::WIDGETSTATE::IDLE].params.color, 0.5f); + volume->sprites[wiWidget::WIDGETSTATE::FOCUS].params.color = wiMath::Lerp(wiColor::Transparent(), volume->sprites_knob[wiWidget::WIDGETSTATE::FOCUS].params.color, 0.5f); volume->OnSlide([](wiEventArgs args) { wiAudio::SetVolume(args.fValue / 100.0f, &soundinstance); }); @@ -549,7 +551,7 @@ void TestsRenderer::RunSpriteTest() sprite.params.pos = params.pos; sprite.params.siz = params.siz; sprite.params.pivot = params.pivot; - sprite.params.col = XMFLOAT4(2, 2, 2, 1); // increase brightness a bit + sprite.params.color = XMFLOAT4(2, 2, 2, 1); // increase brightness a bit sprite.params.sampleFlag = SAMPLEMODE_MIRROR; // texcoords will be scrolled out of bounds, so set up a wrap mode other than clamp sprite.anim.movingTexAnim.speedX = 0; sprite.anim.movingTexAnim.speedY = 2; // scroll the texture vertically. This value is pixels/second. So because our texture here is 1x2 pixels, just scroll it once fully per second with a value of 2 diff --git a/WickedEngine/RenderPath2D.cpp b/WickedEngine/RenderPath2D.cpp index f287e7303..2cc04236c 100644 --- a/WickedEngine/RenderPath2D.cpp +++ b/WickedEngine/RenderPath2D.cpp @@ -132,6 +132,7 @@ void RenderPath2D::Render() const GraphicsDevice* device = wiRenderer::GetDevice(); CommandList cmd = device->BeginCommandList(); + wiRenderer::GetDevice()->BindResource(PS, GetGUIBlurredBackground(), TEXSLOT_IMAGE_BACKGROUND, cmd); // Special care for internal resolution, because stencil buffer is of internal resolution, // so we might need to render stencil sprites to separate render target that matches internal resolution! diff --git a/WickedEngine/RenderPath2D.h b/WickedEngine/RenderPath2D.h index d0b4768ea..db4cba2e0 100644 --- a/WickedEngine/RenderPath2D.h +++ b/WickedEngine/RenderPath2D.h @@ -53,6 +53,7 @@ public: const wiGraphics::Texture& GetRenderResult() const { return rtFinal; } virtual const wiGraphics::Texture* GetDepthStencil() const { return nullptr; } + virtual const wiGraphics::Texture* GetGUIBlurredBackground() const { return nullptr; } void AddSprite(wiSprite* sprite, const std::string& layer = ""); void RemoveSprite(wiSprite* sprite); diff --git a/WickedEngine/RenderPath3D.cpp b/WickedEngine/RenderPath3D.cpp index 4288e1b52..991925390 100644 --- a/WickedEngine/RenderPath3D.cpp +++ b/WickedEngine/RenderPath3D.cpp @@ -186,6 +186,19 @@ void RenderPath3D::ResizeBuffers() device->SetName(&rtPostprocess_LDR[0], "rtPostprocess_LDR[0]"); device->CreateTexture(&desc, nullptr, &rtPostprocess_LDR[1]); device->SetName(&rtPostprocess_LDR[1], "rtPostprocess_LDR[1]"); + + desc.Width /= 4; + desc.Height /= 4; + desc.BindFlags = BIND_UNORDERED_ACCESS | BIND_SHADER_RESOURCE; + device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[0]); + device->SetName(&rtGUIBlurredBackground[0], "rtGUIBlurredBackground[0]"); + + desc.Width /= 4; + desc.Height /= 4; + device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[1]); + device->SetName(&rtGUIBlurredBackground[1], "rtGUIBlurredBackground[1]"); + device->CreateTexture(&desc, nullptr, &rtGUIBlurredBackground[2]); + device->SetName(&rtGUIBlurredBackground[2], "rtGUIBlurredBackground[2]"); } // Depth buffers: @@ -759,5 +772,16 @@ void RenderPath3D::RenderPostprocessChain(const Texture& srcSceneRT, const Textu std::swap(rt_read, rt_write); device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd); } + + // GUI Background blurring: + { + auto range = wiProfiler::BeginRangeGPU("GUI Background Blur", cmd); + device->EventBegin("GUI Background Blur", cmd); + wiRenderer::Postprocess_Downsample4x(*rt_read, rtGUIBlurredBackground[0], cmd); + wiRenderer::Postprocess_Downsample4x(rtGUIBlurredBackground[0], rtGUIBlurredBackground[2], cmd); + wiRenderer::Postprocess_Blur_Gaussian(rtGUIBlurredBackground[2], rtGUIBlurredBackground[1], rtGUIBlurredBackground[2], cmd); + device->EventEnd(cmd); + wiProfiler::EndRange(range); + } } } diff --git a/WickedEngine/RenderPath3D.h b/WickedEngine/RenderPath3D.h index db73d1465..ddd801141 100644 --- a/WickedEngine/RenderPath3D.h +++ b/WickedEngine/RenderPath3D.h @@ -73,6 +73,7 @@ protected: wiGraphics::Texture rtAO; // full res AO wiGraphics::Texture rtSun[2]; // 0: sun render target used for lightshafts (can be MSAA), 1: radial blurred lightshafts wiGraphics::Texture rtSun_resolved; // sun render target, but the resolved version if MSAA is enabled + wiGraphics::Texture rtGUIBlurredBackground[3]; // downsampled, gaussian blurred scene for GUI wiGraphics::Texture rtPostprocess_HDR; // ping-pong with main scene RT in HDR post-process chain wiGraphics::Texture rtPostprocess_LDR[2]; // ping-pong with itself in LDR post-process chain @@ -122,6 +123,7 @@ protected: public: const wiGraphics::Texture* GetDepthStencil() const override { return &depthBuffer; } + const wiGraphics::Texture* GetGUIBlurredBackground() const override { return &rtGUIBlurredBackground[2]; } constexpr float getExposure() const { return exposure; } constexpr float getBloomThreshold() const { return bloomThreshold; } diff --git a/WickedEngine/ResourceMapping.h b/WickedEngine/ResourceMapping.h index 53cc1c2af..9303d836c 100644 --- a/WickedEngine/ResourceMapping.h +++ b/WickedEngine/ResourceMapping.h @@ -101,5 +101,10 @@ #define TEXSLOT_RENDERPATH_AO TEXSLOT_ONDEMAND8 #define TEXSLOT_RENDERPATH_SSR TEXSLOT_ONDEMAND9 +// wiImage: +#define TEXSLOT_IMAGE_BASE TEXSLOT_ONDEMAND0 +#define TEXSLOT_IMAGE_MASK TEXSLOT_ONDEMAND1 +#define TEXSLOT_IMAGE_BACKGROUND TEXSLOT_ONDEMAND2 + #endif // WI_RESOURCE_MAPPING_H diff --git a/WickedEngine/ShaderInterop_Image.h b/WickedEngine/ShaderInterop_Image.h index ea0398152..3d18d32e3 100644 --- a/WickedEngine/ShaderInterop_Image.h +++ b/WickedEngine/ShaderInterop_Image.h @@ -4,13 +4,15 @@ CBUFFER(ImageCB, CBSLOT_IMAGE) { - float4 xCorners[4]; - float4 xTexMulAdd; - float4 xTexMulAdd2; - float4 xColor; - float2 padding_imageCB; - uint xMirror; - float xMipLevel; + float4 xCorners[4]; + float4 xTexMulAdd; + float4 xTexMulAdd2; + float4 xColor; + + uint xMirror; + float xMipLevel; + float xMipLevel_Background; + float padding_ImageCB; }; diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj b/WickedEngine/WickedEngine_SHADERS.vcxproj index e2ebb95e5..a4e9cedf0 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj @@ -45,6 +45,9 @@ Compute + + Compute + Compute 5.0 @@ -400,6 +403,12 @@ Compute 5.0 + + Pixel + + + Pixel + Pixel 5.0 diff --git a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters index e16e03364..70a225e46 100644 --- a/WickedEngine/WickedEngine_SHADERS.vcxproj.filters +++ b/WickedEngine/WickedEngine_SHADERS.vcxproj.filters @@ -726,9 +726,6 @@ CS - - CS - CS @@ -957,6 +954,18 @@ PS + + PS + + + PS + + + CS + + + CS + diff --git a/WickedEngine/downsample4xCS.hlsl b/WickedEngine/downsample4xCS.hlsl new file mode 100644 index 000000000..24eef111f --- /dev/null +++ b/WickedEngine/downsample4xCS.hlsl @@ -0,0 +1,23 @@ +#include "globals.hlsli" +#include "ShaderInterop_Postprocess.h" + +TEXTURE2D(input, float4, TEXSLOT_ONDEMAND0); + +RWTEXTURE2D(output, float4, 0); + +[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)] +void main(uint3 DTid : SV_DispatchThreadID) +{ + const float2 uv = DTid.xy + 0.5f; + + float3 color = 0; + + color += input.SampleLevel(sampler_linear_clamp, (uv + float2(-1, -1)) * xPPResolution_rcp, 0).rgb; + color += input.SampleLevel(sampler_linear_clamp, (uv + float2(1, -1)) * xPPResolution_rcp, 0).rgb; + color += input.SampleLevel(sampler_linear_clamp, (uv + float2(-1, 1)) * xPPResolution_rcp, 0).rgb; + color += input.SampleLevel(sampler_linear_clamp, (uv + float2(1, 1)) * xPPResolution_rcp, 0).rgb; + + color /= 4.0f; + + output[DTid.xy] = float4(color, 1); +} diff --git a/WickedEngine/imageHF.hlsli b/WickedEngine/imageHF.hlsli index 6d14d8207..5469f234d 100644 --- a/WickedEngine/imageHF.hlsli +++ b/WickedEngine/imageHF.hlsli @@ -3,16 +3,18 @@ #include "globals.hlsli" #include "ShaderInterop_Image.h" -TEXTURE2D(texture_base, float4, TEXSLOT_ONDEMAND0); -TEXTURE2D(texture_mask, float4, TEXSLOT_ONDEMAND1); +TEXTURE2D(texture_base, float4, TEXSLOT_IMAGE_BASE); +TEXTURE2D(texture_mask, float4, TEXSLOT_IMAGE_MASK); +TEXTURE2D(texture_background, float4, TEXSLOT_IMAGE_BACKGROUND); SAMPLERSTATE(Sampler, SSLOT_ONDEMAND0); struct VertextoPixel { - float4 pos : SV_POSITION; - float2 uv0 : TEXCOORD0; - float2 uv1 : TEXCOORD1; + float4 pos : SV_POSITION; + float2 uv0 : TEXCOORD0; + float2 uv1 : TEXCOORD1; + float4 uv_screen : TEXCOORD2; }; #endif // WI_IMAGE_HF diff --git a/WickedEngine/imagePS_backgroundblur.hlsl b/WickedEngine/imagePS_backgroundblur.hlsl new file mode 100644 index 000000000..d61ab0b19 --- /dev/null +++ b/WickedEngine/imagePS_backgroundblur.hlsl @@ -0,0 +1,9 @@ +#include "imageHF.hlsli" + +float4 main(VertextoPixel input) : SV_TARGET +{ + float4 color = texture_base.SampleLevel(Sampler, input.uv0, xMipLevel) * xColor; + float3 background = texture_background.SampleLevel(Sampler, (input.uv_screen.xy * float2(0.5f, -0.5f) + 0.5f) / input.uv_screen.w, xMipLevel_Background).rgb; + + return float4(lerp(background, color.rgb, color.a), 1); +} diff --git a/WickedEngine/imagePS_backgroundblur_bicubic.hlsl b/WickedEngine/imagePS_backgroundblur_bicubic.hlsl new file mode 100644 index 000000000..92dc388d0 --- /dev/null +++ b/WickedEngine/imagePS_backgroundblur_bicubic.hlsl @@ -0,0 +1,9 @@ +#include "imageHF.hlsli" + +float4 main(VertextoPixel input) : SV_TARGET +{ + float4 color = SampleTextureCatmullRom(texture_base, input.uv0, xMipLevel) * xColor; + float3 background = texture_background.SampleLevel(Sampler, (input.uv_screen.xy * float2(0.5f, -0.5f) + 0.5f) / input.uv_screen.w, xMipLevel_Background).rgb; + + return float4(lerp(background, color.rgb, color.a), 1); +} diff --git a/WickedEngine/imageVS.hlsl b/WickedEngine/imageVS.hlsl index 0450e1051..668074d68 100644 --- a/WickedEngine/imageVS.hlsl +++ b/WickedEngine/imageVS.hlsl @@ -18,6 +18,7 @@ VertextoPixel main(uint vI : SV_VERTEXID) Out.uv1 = Out.uv0; Out.uv0 = Out.uv0 * xTexMulAdd.xy + xTexMulAdd.zw; Out.uv1 = Out.uv1 * xTexMulAdd2.xy + xTexMulAdd2.zw; + Out.uv_screen = Out.pos; return Out; } diff --git a/WickedEngine/wiColor.h b/WickedEngine/wiColor.h index 118a5e1d5..7c71045ae 100644 --- a/WickedEngine/wiColor.h +++ b/WickedEngine/wiColor.h @@ -36,6 +36,8 @@ struct wiColor ((rgba >> 24) & 0xFF) / 255.0f ); } + constexpr operator XMFLOAT3() const { return toFloat3(); } + constexpr operator XMFLOAT4() const { return toFloat4(); } static constexpr wiColor fromFloat4(const XMFLOAT4& value) { diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index c8e71326e..0451e0d12 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -364,6 +364,7 @@ enum CSTYPES CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UNORM1, CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_FLOAT4, CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UNORM4, + CSTYPE_POSTPROCESS_DOWNSAMPLE4X, CSTYPE_COUNT }; diff --git a/WickedEngine/wiFont.h b/WickedEngine/wiFont.h index 2ee1ca6da..b163b1846 100644 --- a/WickedEngine/wiFont.h +++ b/WickedEngine/wiFont.h @@ -27,7 +27,7 @@ struct wiFontParams wiColor shadowColor; int h_wrap = -1; // wrap start in pixels (-1 default for no wrap) - wiFontParams(int posX = 0, int posY = 0, int size = 16, wiFontAlign h_align = WIFALIGN_LEFT, wiFontAlign v_align = WIFALIGN_TOP + wiFontParams(int posX = 0, int posY = 0, int size = WIFONTSIZE_DEFAULT, wiFontAlign h_align = WIFALIGN_LEFT, wiFontAlign v_align = WIFALIGN_TOP , int spacingX = 0, int spacingY = 0, wiColor color = wiColor(255, 255, 255, 255), wiColor shadowColor = wiColor(0,0,0,0)) :posX(posX), posY(posY), size(size), h_align(h_align), v_align(v_align), spacingX(spacingX), spacingY(spacingY), color(color), shadowColor(shadowColor) {} diff --git a/WickedEngine/wiFont_BindLua.cpp b/WickedEngine/wiFont_BindLua.cpp index 81d1f88e7..5e9db69ff 100644 --- a/WickedEngine/wiFont_BindLua.cpp +++ b/WickedEngine/wiFont_BindLua.cpp @@ -149,7 +149,7 @@ int wiFont_BindLua::SetColor(lua_State* L) } } else - wiLua::SError(L, "SetColor(Vector pos) not enough arguments!"); + wiLua::SError(L, "SetColor(Vector value) not enough arguments!"); return 0; } int wiFont_BindLua::SetShadowColor(lua_State* L) @@ -171,7 +171,7 @@ int wiFont_BindLua::SetShadowColor(lua_State* L) } } else - wiLua::SError(L, "SetShadowColor(Vector pos) not enough arguments!"); + wiLua::SError(L, "SetShadowColor(Vector value) not enough arguments!"); return 0; } diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 608e1ecab..12ba00513 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -108,6 +108,13 @@ void wiGUI::Update(float dt) } } + for (auto& widget : priorityChangeQueue) + { + widgets.remove(widget); + widgets.push_front(widget); + } + priorityChangeQueue.clear(); + scissorRect.bottom = (int32_t)(wiRenderer::GetDevice()->GetScreenHeight()); scissorRect.left = (int32_t)(0); scissorRect.right = (int32_t)(wiRenderer::GetDevice()->GetScreenWidth()); @@ -122,18 +129,19 @@ void wiGUI::Render(CommandList cmd) const } wiRenderer::GetDevice()->EventBegin("GUI", cmd); - for (auto&x : widgets) + for (auto it = widgets.rbegin(); it != widgets.rend(); ++it) { - if (x->parent == this && x != activeWidget) + const wiWidget* widget = (*it); + if (widget->parent == this && widget != activeWidget) { // the contained child widgets will be rendered by the containers ApplyScissor(scissorRect, cmd); - x->Render(this, cmd); + widget->Render(this, cmd); } } if (activeWidget != nullptr) { - // render the active widget on top of everything + // Active widget is always on top! ApplyScissor(scissorRect, cmd); activeWidget->Render(this, cmd); } @@ -174,8 +182,15 @@ wiWidget* wiGUI::GetWidget(const wiHashString& name) void wiGUI::ActivateWidget(wiWidget* widget) { - activeWidget = widget; - activeWidget->Activate(); + if (std::find(widgets.begin(), widgets.end(), widget) != widgets.end()) + { + priorityChangeQueue.push_back(widget); + } + if (activeWidget == nullptr) + { + activeWidget = widget; + activeWidget->Activate(); + } } void wiGUI::DeactivateWidget(wiWidget* widget) { diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index 3616d41f7..e8d9567d9 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -26,6 +26,7 @@ class wiGUI : public wiGUIElement friend class wiWidget; private: std::list widgets; + std::vector priorityChangeQueue; wiWidget* activeWidget = nullptr; bool focus = false; bool visible = true; diff --git a/WickedEngine/wiImage.cpp b/WickedEngine/wiImage.cpp index 35cbc1869..963cd3ee4 100644 --- a/WickedEngine/wiImage.cpp +++ b/WickedEngine/wiImage.cpp @@ -21,6 +21,7 @@ namespace wiImage IMAGE_SHADER_STANDARD, IMAGE_SHADER_SEPARATENORMALMAP, IMAGE_SHADER_MASKED, + IMAGE_SHADER_BACKGROUNDBLUR, IMAGE_SHADER_FULLSCREEN, IMAGE_SHADER_COUNT }; @@ -53,9 +54,7 @@ namespace wiImage GraphicsDevice* device = wiRenderer::GetDevice(); device->EventBegin("Image", cmd); - bool fullScreenEffect = false; - - device->BindResource(PS, texture, TEXSLOT_ONDEMAND0, cmd); + device->BindResource(PS, texture, TEXSLOT_IMAGE_BASE, cmd); uint32_t stencilRef = params.stencilRef; if (params.stencilRefMode == STENCILREFMODE_USER) @@ -95,7 +94,7 @@ namespace wiImage } ImageCB cb; - cb.xColor = params.col; + cb.xColor = params.color; const float darken = 1 - params.fade; cb.xColor.x *= darken; cb.xColor.y *= darken; @@ -103,6 +102,7 @@ namespace wiImage cb.xColor.w *= params.opacity; cb.xMirror = params.isMirrorEnabled() ? 1 : 0; cb.xMipLevel = params.mipLevel; + cb.xMipLevel_Background = params.mipLevel_Background; if (params.isFullScreenEnabled()) { @@ -201,8 +201,9 @@ namespace wiImage // Determine relevant image rendering pixel shader: IMAGE_SHADER targetShader; - bool NormalmapSeparate = params.isExtractNormalMapEnabled(); - bool Mask = params.maskMap != nullptr; + const bool NormalmapSeparate = params.isExtractNormalMapEnabled(); + const bool Mask = params.maskMap != nullptr; + const bool background_blur = params.isBackgroundBlurEnabled(); if (NormalmapSeparate) { targetShader = IMAGE_SHADER_SEPARATENORMALMAP; @@ -215,7 +216,14 @@ namespace wiImage } else { - targetShader = IMAGE_SHADER_STANDARD; + if (background_blur) + { + targetShader = IMAGE_SHADER_BACKGROUNDBLUR; + } + else + { + targetShader = IMAGE_SHADER_STANDARD; + } } } @@ -224,7 +232,7 @@ namespace wiImage device->BindConstantBuffer(VS, &constantBuffer, CB_GETBINDSLOT(ImageCB), cmd); device->BindConstantBuffer(PS, &constantBuffer, CB_GETBINDSLOT(ImageCB), cmd); - device->BindResource(PS, params.maskMap, TEXSLOT_ONDEMAND1, cmd); + device->BindResource(PS, params.maskMap, TEXSLOT_IMAGE_MASK, cmd); device->Draw(4, 0, cmd); @@ -241,11 +249,13 @@ namespace wiImage wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_STANDARD][IMAGE_SAMPLING_SIMPLE], "imagePS.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_SEPARATENORMALMAP][IMAGE_SAMPLING_SIMPLE], "imagePS_separatenormalmap.cso"); - wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_MASKED][IMAGE_SAMPLING_SIMPLE],"imagePS_masked.cso"); + wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_MASKED][IMAGE_SAMPLING_SIMPLE], "imagePS_masked.cso"); + wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_BACKGROUNDBLUR][IMAGE_SAMPLING_SIMPLE], "imagePS_backgroundblur.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_FULLSCREEN][IMAGE_SAMPLING_SIMPLE], "screenPS.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_STANDARD][IMAGE_SAMPLING_BICUBIC], "imagePS_bicubic.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_SEPARATENORMALMAP][IMAGE_SAMPLING_BICUBIC], "imagePS_separatenormalmap_bicubic.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_MASKED][IMAGE_SAMPLING_BICUBIC], "imagePS_masked_bicubic.cso"); + wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_BACKGROUNDBLUR][IMAGE_SAMPLING_BICUBIC], "imagePS_backgroundblur_bicubic.cso"); wiRenderer::LoadShader(PS, imagePS[IMAGE_SHADER_FULLSCREEN][IMAGE_SAMPLING_BICUBIC], "screenPS_bicubic.cso"); diff --git a/WickedEngine/wiImage.h b/WickedEngine/wiImage.h index 07b9731d1..f191d15fb 100644 --- a/WickedEngine/wiImage.h +++ b/WickedEngine/wiImage.h @@ -2,6 +2,7 @@ #include "CommonInclude.h" #include "wiGraphicsDevice.h" #include "wiEnums.h" +#include "wiColor.h" struct wiImageParams; @@ -64,13 +65,14 @@ struct wiImageParams MIRROR = 1 << 2, EXTRACT_NORMALMAP = 1 << 3, FULLSCREEN = 1 << 4, + BACKGROUND_BLUR = 1 << 5, }; uint32_t _flags = EMPTY; XMFLOAT3 pos; XMFLOAT2 siz; XMFLOAT2 scale; - XMFLOAT4 col; + XMFLOAT4 color; XMFLOAT4 drawRect; XMFLOAT4 drawRect2; XMFLOAT4 lookAt; //(x,y,z) : direction, (w) :isenabled? @@ -79,6 +81,7 @@ struct wiImageParams XMFLOAT2 pivot; // (0,0) : upperleft, (0.5,0.5) : center, (1,1) : bottomright float rotation; float mipLevel; + float mipLevel_Background; // can blur background with this if > 0 and the background texture has mip levels float fade; float opacity; XMFLOAT2 corners[4]; // you can deform the image by its corners (0: top left, 1: top right, 2: bottom left, 3: bottom right) @@ -100,17 +103,19 @@ struct wiImageParams _flags = EMPTY; pos = XMFLOAT3(0, 0, 0); siz = XMFLOAT2(1, 1); - col = XMFLOAT4(1, 1, 1, 1); scale = XMFLOAT2(1, 1); + color = XMFLOAT4(1, 1, 1, 1); drawRect = XMFLOAT4(0, 0, 0, 0); drawRect2 = XMFLOAT4(0, 0, 0, 0); texOffset = XMFLOAT2(0, 0); texOffset2 = XMFLOAT2(0, 0); lookAt = XMFLOAT4(0, 0, 0, 0); pivot = XMFLOAT2(0, 0); - fade = rotation = 0.0f; - opacity = 1.0f; - mipLevel = 0.f; + fade = 0; + rotation = 0; + opacity = 1; + mipLevel = 0; + mipLevel_Background = 0; stencilRef = 0; stencilComp = STENCILMODE_DISABLED; stencilRefMode = STENCILREFMODE_ALL; @@ -130,6 +135,7 @@ struct wiImageParams constexpr bool isMirrorEnabled() const { return _flags & MIRROR; } constexpr bool isExtractNormalMapEnabled() const { return _flags & EXTRACT_NORMALMAP; } constexpr bool isFullScreenEnabled() const { return _flags & FULLSCREEN; } + constexpr bool isBackgroundBlurEnabled() const { return _flags & BACKGROUND_BLUR; } // enables draw rectangle for base texture (cutout texture outside draw rectangle) void enableDrawRect(const XMFLOAT4& rect) { _flags |= DRAWRECT; drawRect = rect; } @@ -141,6 +147,9 @@ struct wiImageParams void enableExtractNormalMap() { _flags |= EXTRACT_NORMALMAP; } // enable full screen override. It just draws texture onto the full screen, disabling any other setup except sampler and stencil) void enableFullScreen() { _flags |= FULLSCREEN; } + // enable background blur, which samples a background screen texture on a specified mip level on transparent areas instead of alpha blending + // the background tex should be bound to resource slot: TEXSLOT_IMAGE_BACKGROUND beforehand! + void enableBackgroundBlur(float mip) { _flags |= BACKGROUND_BLUR; mipLevel_Background = mip; } // disable draw rectangle for base texture (whole texture will be drawn, no cutout) void disableDrawRect() { _flags &= ~DRAWRECT; } @@ -152,6 +161,8 @@ struct wiImageParams void disableExtractNormalMap() { _flags &= ~EXTRACT_NORMALMAP; } // disable full screen override void disableFullScreen() { _flags &= ~FULLSCREEN; } + // disable background blur + void disableBackgroundBlur() { _flags &= ~BACKGROUND_BLUR; } wiImageParams() @@ -163,12 +174,12 @@ struct wiImageParams init(); siz = XMFLOAT2(width, height); } - wiImageParams(float posX, float posY, float width, float height, const XMFLOAT4& color = XMFLOAT4(1, 1, 1, 1)) + wiImageParams(float posX, float posY, float width, float height, const XMFLOAT4& _color = XMFLOAT4(1, 1, 1, 1)) { init(); pos.x = posX; pos.y = posY; siz = XMFLOAT2(width, height); - col = color; + color = _color; } }; diff --git a/WickedEngine/wiImageParams_BindLua.cpp b/WickedEngine/wiImageParams_BindLua.cpp index 0e7e89854..d51fed493 100644 --- a/WickedEngine/wiImageParams_BindLua.cpp +++ b/WickedEngine/wiImageParams_BindLua.cpp @@ -19,6 +19,7 @@ Luna::FunctionType wiImageParams_BindLua::methods[] = { lunamethod(wiImageParams_BindLua, IsDrawRectEnabled), lunamethod(wiImageParams_BindLua, IsDrawRect2Enabled), lunamethod(wiImageParams_BindLua, IsMirrorEnabled), + lunamethod(wiImageParams_BindLua, IsBackgroundBlurEnabled), lunamethod(wiImageParams_BindLua, SetPos), lunamethod(wiImageParams_BindLua, SetSize), @@ -41,6 +42,8 @@ Luna::FunctionType wiImageParams_BindLua::methods[] = { lunamethod(wiImageParams_BindLua, DisableDrawRect2), lunamethod(wiImageParams_BindLua, EnableMirror), lunamethod(wiImageParams_BindLua, DisableMirror), + lunamethod(wiImageParams_BindLua, EnableBackgroundBlur), + lunamethod(wiImageParams_BindLua, DisableBackgroundBlur), { NULL, NULL } }; Luna::PropertyType wiImageParams_BindLua::properties[] = { @@ -69,7 +72,7 @@ int wiImageParams_BindLua::GetPivot(lua_State* L) } int wiImageParams_BindLua::GetColor(lua_State* L) { - Luna::push(L, new Vector_BindLua(XMLoadFloat4(¶ms.col))); + Luna::push(L, new Vector_BindLua(XMLoadFloat4(¶ms.color))); return 1; } int wiImageParams_BindLua::GetOpacity(lua_State* L) @@ -127,6 +130,11 @@ int wiImageParams_BindLua::IsMirrorEnabled(lua_State* L) wiLua::SSetBool(L, params.isMirrorEnabled()); return 1; } +int wiImageParams_BindLua::IsBackgroundBlurEnabled(lua_State* L) +{ + wiLua::SSetBool(L, params.isBackgroundBlurEnabled()); + return 1; +} int wiImageParams_BindLua::SetPos(lua_State* L) { @@ -184,10 +192,10 @@ int wiImageParams_BindLua::SetColor(lua_State* L) int argc = wiLua::SGetArgCount(L); if (argc > 0) { - Vector_BindLua* vector = Luna::lightcheck(L, 1); - if (vector != nullptr) + Vector_BindLua* param = Luna::lightcheck(L, 1); + if (param != nullptr) { - XMStoreFloat4(¶ms.col, vector->vector); + XMStoreFloat4(¶ms.color, param->vector); } } else @@ -406,6 +414,22 @@ int wiImageParams_BindLua::DisableMirror(lua_State* L) params.disableMirror(); return 0; } +int wiImageParams_BindLua::EnableBackgroundBlur(lua_State* L) +{ + float mip = 0; + int argc = wiLua::SGetArgCount(L); + if (argc > 0) + { + mip = wiLua::SGetFloat(L, 1); + } + params.enableBackgroundBlur(mip); + return 0; +} +int wiImageParams_BindLua::DisableBackgroundBlur(lua_State* L) +{ + params.disableBackgroundBlur(); + return 0; +} wiImageParams_BindLua::wiImageParams_BindLua(lua_State *L) { diff --git a/WickedEngine/wiImageParams_BindLua.h b/WickedEngine/wiImageParams_BindLua.h index 19c585abb..721f45773 100644 --- a/WickedEngine/wiImageParams_BindLua.h +++ b/WickedEngine/wiImageParams_BindLua.h @@ -30,6 +30,7 @@ public: int IsDrawRectEnabled(lua_State* L); int IsDrawRect2Enabled(lua_State* L); int IsMirrorEnabled(lua_State* L); + int IsBackgroundBlurEnabled(lua_State* L); int SetPos(lua_State* L); int SetSize(lua_State* L); @@ -52,6 +53,8 @@ public: int DisableDrawRect2(lua_State* L); int EnableMirror(lua_State* L); int DisableMirror(lua_State* L); + int EnableBackgroundBlur(lua_State* L); + int DisableBackgroundBlur(lua_State* L); static void Bind(); }; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 554cd7339..f981707a6 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -1402,6 +1402,7 @@ void LoadShaders() wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UNORM1], "upsample_bilateral_unorm1CS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_FLOAT4], "upsample_bilateral_float4CS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_UPSAMPLE_BILATERAL_UNORM4], "upsample_bilateral_unorm4CS.cso"); }); + wiJobSystem::Execute(ctx, [] { LoadShader(CS, computeShaders[CSTYPE_POSTPROCESS_DOWNSAMPLE4X], "downsample4xCS.cso"); }); wiJobSystem::Execute(ctx, [] { LoadShader(HS, hullShaders[HSTYPE_OBJECT], "objectHS.cso"); }); @@ -11037,6 +11038,46 @@ void Postprocess_Upsample_Bilateral( device->EventEnd(cmd); } +void Postprocess_Downsample4x( + const Texture& input, + const Texture& output, + CommandList cmd +) +{ + GraphicsDevice* device = GetDevice(); + + device->EventBegin("Postprocess_Downsample4x", cmd); + + const TextureDesc& desc = output.GetDesc(); + + PostProcessCB cb; + cb.xPPResolution.x = desc.Width; + cb.xPPResolution.y = desc.Height; + cb.xPPResolution_rcp.x = 1.0f / cb.xPPResolution.x; + cb.xPPResolution_rcp.y = 1.0f / cb.xPPResolution.y; + device->UpdateBuffer(&constantBuffers[CBTYPE_POSTPROCESS], &cb, cmd); + device->BindConstantBuffer(CS, &constantBuffers[CBTYPE_POSTPROCESS], CB_GETBINDSLOT(PostProcessCB), cmd); + + device->BindComputeShader(&computeShaders[CSTYPE_POSTPROCESS_DOWNSAMPLE4X], cmd); + + device->BindResource(CS, &input, TEXSLOT_ONDEMAND0, cmd); + + const GPUResource* uavs[] = { + &output, + }; + device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd); + + device->Dispatch( + (desc.Width + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, + (desc.Height + POSTPROCESS_BLOCKSIZE - 1) / POSTPROCESS_BLOCKSIZE, + 1, + cmd + ); + + device->Barrier(&GPUBarrier::Memory(), 1, cmd); + device->UnbindUAVs(0, arraysize(uavs), cmd); + device->EventEnd(cmd); +} const XMFLOAT4& GetWaterPlane() { diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index eb3f86cb7..bfe360bce 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -157,6 +157,7 @@ namespace wiRenderer // Compute the luminance for the source image and return the texture containing the luminance value in pixel [0,0] const wiGraphics::Texture* ComputeLuminance(const wiGraphics::Texture& sourceImage, wiGraphics::CommandList cmd); + void DeferredComposition( const wiGraphics::Texture& gbuffer0, const wiGraphics::Texture& gbuffer1, @@ -313,6 +314,11 @@ namespace wiRenderer bool is_pixelshader = false, float threshold = 1.0f ); + void Postprocess_Downsample4x( + const wiGraphics::Texture& input, + const wiGraphics::Texture& output, + wiGraphics::CommandList cmd + ); // Build the scene BVH on GPU that can be used by ray traced rendering void BuildSceneBVH(wiGraphics::CommandList cmd); diff --git a/WickedEngine/wiSprite.cpp b/WickedEngine/wiSprite.cpp index c958f8b9b..592c02900 100644 --- a/WickedEngine/wiSprite.cpp +++ b/WickedEngine/wiSprite.cpp @@ -2,6 +2,7 @@ #include "wiImage.h" #include "wiRenderer.h" #include "wiRandom.h" +#include "wiTextureHelper.h" using namespace wiGraphics; @@ -22,7 +23,7 @@ wiSprite::wiSprite(const std::string& newTexture, const std::string& newMask) void wiSprite::Draw(CommandList cmd) const { - wiImage::Draw(textureResource->texture, params, cmd); + wiImage::Draw(textureResource != nullptr ? textureResource->texture : wiTextureHelper::getWhite(), params, cmd); } void wiSprite::DrawNormal(CommandList cmd) const { @@ -31,7 +32,7 @@ void wiSprite::DrawNormal(CommandList cmd) const wiImageParams effectsMod(params); effectsMod.blendFlag = BLENDMODE_ADDITIVE; effectsMod.enableExtractNormalMap(); - wiImage::Draw(textureResource->texture, effectsMod, cmd); + wiImage::Draw(textureResource != nullptr ? textureResource->texture : wiTextureHelper::getWhite(), effectsMod, cmd); } } diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 1f76a83de..35e19af64 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 39; // minor bug fixes, alterations, refactors, updates - const int revision = 44; + const int revision = 45; long GetVersion() diff --git a/WickedEngine/wiWidget.cpp b/WickedEngine/wiWidget.cpp index 574dd49dd..7fb518961 100644 --- a/WickedEngine/wiWidget.cpp +++ b/WickedEngine/wiWidget.cpp @@ -19,6 +19,20 @@ using namespace wiScene; static wiGraphics::PipelineState PSO_colored; +wiWidget::wiWidget() +{ + sprites[IDLE].params.color = wiColor::Booger(); + sprites[FOCUS].params.color = wiColor::Gray(); + sprites[ACTIVE].params.color = wiColor::White(); + sprites[DEACTIVATING].params.color = wiColor::Gray(); + font.params.shadowColor = wiColor::Black(); + + for (int i = IDLE; i < WIDGETSTATE_COUNT; ++i) + { + sprites[i].params.enableBackgroundBlur(0); // enable gui background blur by default, use mip = 0 + } +} + void wiWidget::Update(wiGUI* gui, float dt) { assert(gui != nullptr && "Ivalid GUI!"); @@ -51,6 +65,17 @@ void wiWidget::Update(wiGUI* gui, float dt) scissorRect.left = (int32_t)(translation.x); scissorRect.right = (int32_t)(translation.x + scale.x); scissorRect.top = (int32_t)(translation.y); + + // default sprite and font placement: + for (int i = IDLE; i < WIDGETSTATE_COUNT; ++i) + { + sprites[i].params.pos.x = translation.x; + sprites[i].params.pos.y = translation.y; + sprites[i].params.siz.x = scale.x; + sprites[i].params.siz.y = scale.y; + } + font.params.posX = (int)translation.x; + font.params.posY = (int)translation.y; } void wiWidget::RenderTooltip(const wiGUI* gui, CommandList cmd) const { @@ -90,7 +115,7 @@ void wiWidget::RenderTooltip(const wiGUI* gui, CommandList cmd) const static const float _border = 2; float fontWidth = (float)tooltipFont.textWidth() + _border * 2; float fontHeight = (float)tooltipFont.textHeight() + _border * 2; - wiImage::Draw(wiTextureHelper::getWhite(), wiImageParams(tooltipPos.x - _border, tooltipPos.y - _border, fontWidth, fontHeight, wiColor(255, 234, 165).toFloat4()), cmd); + wiImage::Draw(wiTextureHelper::getWhite(), wiImageParams(tooltipPos.x - _border, tooltipPos.y - _border, fontWidth, fontHeight, wiColor(255, 234, 165)), cmd); tooltipFont.SetText(tooltip); tooltipFont.Draw(cmd); if (!scriptTip.empty()) @@ -121,13 +146,13 @@ void wiWidget::SetName(const std::string& value) } } -const string& wiWidget::GetText() const +const string wiWidget::GetText() const { - return text; + return font.GetTextA(); } void wiWidget::SetText(const std::string& value) { - text = value; + font.SetText(value); } void wiWidget::SetTooltip(const std::string& value) { @@ -189,21 +214,17 @@ void wiWidget::SetColor(wiColor color, WIDGETSTATE state) { for (int i = 0; i < WIDGETSTATE_COUNT; ++i) { - colors[i] = color; + sprites[i].params.color = color; } } else { - colors[state] = color; + sprites[state].params.color = color; } } wiColor wiWidget::GetColor() const { - wiColor retVal = colors[GetState()]; - if (!IsEnabled()) { - retVal = wiColor::lerp(wiColor::Transparent(), retVal, 0.5f); - } - return retVal; + return wiColor::fromFloat4(sprites[GetState()].params.color); } void wiWidget::LoadShaders() { @@ -229,8 +250,8 @@ wiButton::wiButton(const std::string& name) :wiWidget() OnDragEnd([](wiEventArgs args) {}); SetSize(XMFLOAT2(100, 30)); - fontParams.h_align = WIFALIGN_CENTER; - fontParams.v_align = WIFALIGN_CENTER; + font.params.h_align = WIFALIGN_CENTER; + font.params.v_align = WIFALIGN_CENTER; } wiButton::~wiButton() { @@ -240,95 +261,115 @@ void wiButton::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } + hitBox.pos.x = translation.x; + hitBox.pos.y = translation.y; + hitBox.siz.x = scale.x; + hitBox.siz.y = scale.y; - if (gui->IsWidgetDisabled(this)) - { - return; - } + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - hitBox.pos.x = translation.x; - hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x; - hitBox.siz.y = scale.y; - - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - wiEventArgs args; - args.clickPos = pointerHitbox.pos; - onDragEnd(args); - - if (pointerHitbox.intersects(hitBox)) - { - // Click occurs when the button is released within the bounds - onClick(args); - } - - state = IDLE; - } - if (state == ACTIVE) - { - gui->DeactivateWidget(this); - } - - bool clicked = false; - // hover the button - if (pointerHitbox.intersects(hitBox)) - { - if (state == IDLE) - { - state = FOCUS; - } - } - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == FOCUS) { - // activate - clicked = true; + state = IDLE; } - } - - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == DEACTIVATING) { - // Keep pressed until mouse is released - gui->ActivateWidget(this); - wiEventArgs args; args.clickPos = pointerHitbox.pos; - XMFLOAT3 posDelta; - posDelta.x = pointerHitbox.pos.x - prevPos.x; - posDelta.y = pointerHitbox.pos.y - prevPos.y; - posDelta.z = 0; - args.deltaPos = XMFLOAT2(posDelta.x, posDelta.y); - onDrag(args); + onDragEnd(args); + + if (pointerHitbox.intersects(hitBox)) + { + // Click occurs when the button is released within the bounds + onClick(args); + } + + state = IDLE; } + if (state == ACTIVE) + { + gui->DeactivateWidget(this); + } + + bool clicked = false; + // hover the button + if (pointerHitbox.intersects(hitBox)) + { + if (state == IDLE) + { + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == FOCUS) + { + // activate + clicked = true; + } + } + + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + + wiEventArgs args; + args.clickPos = pointerHitbox.pos; + XMFLOAT3 posDelta; + posDelta.x = pointerHitbox.pos.x - prevPos.x; + posDelta.y = pointerHitbox.pos.y - prevPos.y; + posDelta.z = 0; + args.deltaPos = XMFLOAT2(posDelta.x, posDelta.y); + onDrag(args); + } + } + + if (clicked) + { + wiEventArgs args; + args.clickPos = pointerHitbox.pos; + dragStart = args.clickPos; + args.startPos = dragStart; + onDragStart(args); + gui->ActivateWidget(this); + } + + prevPos.x = pointerHitbox.pos.x; + prevPos.y = pointerHitbox.pos.y; } - if (clicked) + switch (font.params.h_align) { - wiEventArgs args; - args.clickPos = pointerHitbox.pos; - dragStart = args.clickPos; - args.startPos = dragStart; - onDragStart(args); - gui->ActivateWidget(this); + case WIFALIGN_LEFT: + font.params.posX = (int)(translation.x + 2); + break; + case WIFALIGN_RIGHT: + font.params.posX = (int)(translation.x + scale.x - 2); + break; + case WIFALIGN_CENTER: + default: + font.params.posX = (int)(translation.x + scale.x * 0.5f); + break; + } + switch (font.params.v_align) + { + case WIFALIGN_TOP: + font.params.posY = (int)(translation.y + 2); + break; + case WIFALIGN_BOTTOM: + font.params.posY = (int)(translation.y + scale.y - 2); + break; + case WIFALIGN_CENTER: + default: + font.params.posY = (int)(translation.y + scale.y * 0.5f); + break; } - - prevPos.x = pointerHitbox.pos.x; - prevPos.y = pointerHitbox.pos.y; } void wiButton::Render(const wiGUI* gui, CommandList cmd) const { @@ -343,38 +384,8 @@ void wiButton::Render(const wiGUI* gui, CommandList cmd) const ApplyScissor(scissorRect, cmd); - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); - - wiFontParams fontparams = GetFontParams(); - switch (fontparams.h_align) - { - case WIFALIGN_LEFT: - fontparams.posX = (int)(translation.x + 2); - break; - case WIFALIGN_RIGHT: - fontparams.posX = (int)(translation.x + scale.x - 2); - break; - case WIFALIGN_CENTER: - default: - fontparams.posX = (int)(translation.x + scale.x * 0.5f); - break; - } - switch (fontparams.v_align) - { - case WIFALIGN_TOP: - fontparams.posY = (int)(translation.y + 2); - break; - case WIFALIGN_BOTTOM: - fontparams.posY = (int)(translation.y + scale.y - 2); - break; - case WIFALIGN_CENTER: - default: - fontparams.posY = (int)(translation.y + scale.y * 0.5f); - break; - } - wiFont(text, fontparams).Draw(cmd); - + sprites[state].Draw(cmd); + font.Draw(cmd); } void wiButton::OnClick(function func) { @@ -410,15 +421,14 @@ void wiLabel::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; + // ... } - if (gui->IsWidgetDisabled(this)) - { - return; - } + font.params.posX = (int)translation.x + 2; + font.params.posY = (int)translation.y + 2; + font.params.h_wrap = (int)scale.x; } void wiLabel::Render(const wiGUI* gui, CommandList cmd) const { @@ -433,26 +443,25 @@ void wiLabel::Render(const wiGUI* gui, CommandList cmd) const ApplyScissor(scissorRect, cmd); - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); - - wiFontParams params((int)translation.x + 2, (int)translation.y + 2, WIFONTSIZE_DEFAULT, WIFALIGN_LEFT, WIFALIGN_TOP, 0, 0, - fontParams.color, fontParams.shadowColor); - params.h_wrap = (int)scale.x; - wiFont(text, params).Draw(cmd); - + sprites[state].Draw(cmd); + font.Draw(cmd); } -string wiTextInputField::value_new = ""; +wiFont wiTextInputField::font_input; wiTextInputField::wiTextInputField(const std::string& name) { SetName(name); SetText(fastName.GetString()); OnInputAccepted([](wiEventArgs args) {}); SetSize(XMFLOAT2(100, 30)); + + font_description.params = font.params; + font_description.params.v_align = WIFALIGN_CENTER; + + font_input = font_description; } wiTextInputField::~wiTextInputField() { @@ -460,116 +469,115 @@ wiTextInputField::~wiTextInputField() } void wiTextInputField::SetValue(const std::string& newValue) { - value = newValue; + font.SetText(newValue); } void wiTextInputField::SetValue(int newValue) { stringstream ss(""); ss << newValue; - value = ss.str(); + font.SetText(ss.str()); } void wiTextInputField::SetValue(float newValue) { stringstream ss(""); ss << newValue; - value = ss.str(); + font.SetText(ss.str()); } -const std::string& wiTextInputField::GetValue() +const std::string wiTextInputField::GetValue() { - return value; + return font.GetTextA(); } void wiTextInputField::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } + hitBox.pos.x = translation.x; + hitBox.pos.y = translation.y; + hitBox.siz.x = scale.x; + hitBox.siz.y = scale.y; - if (gui->IsWidgetDisabled(this)) - { - return; - } + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); + bool intersectsPointer = pointerHitbox.intersects(hitBox); - hitBox.pos.x = translation.x; - hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x; - hitBox.siz.y = scale.y; - - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - bool intersectsPointer = pointerHitbox.intersects(hitBox); - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - state = IDLE; - } - - bool clicked = false; - // hover the button - if (intersectsPointer) - { - if (state == IDLE) - { - state = FOCUS; - } - } - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == FOCUS) { - // activate - clicked = true; + state = IDLE; } - } - - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == DEACTIVATING) { - // Keep pressed until mouse is released + state = IDLE; + } + + bool clicked = false; + // hover the button + if (intersectsPointer) + { + if (state == IDLE) + { + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == FOCUS) + { + // activate + clicked = true; + } + } + + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + } + } + + if (clicked) + { gui->ActivateWidget(this); + + font_input.SetText(font.GetText()); } - } - if (clicked) - { - gui->ActivateWidget(this); - - value_new = value; - } - - if (state == ACTIVE) - { - if (wiInput::Press(wiInput::KEYBOARD_BUTTON_ENTER)) + if (state == ACTIVE) { - // accept input... + font_input.params = font.params; - value = value_new; - value_new.clear(); + if (wiInput::Press(wiInput::KEYBOARD_BUTTON_ENTER)) + { + // accept input... - wiEventArgs args; - args.sValue = value; - args.iValue = atoi(value.c_str()); - args.fValue = (float)atof(value.c_str()); - onInputAccepted(args); + font.SetText(font_input.GetText()); + font_input.text.clear(); + + wiEventArgs args; + args.sValue = font.GetTextA(); + args.iValue = atoi(args.sValue.c_str()); + args.fValue = (float)atof(args.sValue.c_str()); + onInputAccepted(args); + + gui->DeactivateWidget(this); + } + else if ((wiInput::Press(wiInput::MOUSE_BUTTON_LEFT) && !intersectsPointer) || + wiInput::Press(wiInput::KEYBOARD_BUTTON_ESCAPE)) + { + // cancel input + font_input.text.clear(); + gui->DeactivateWidget(this); + } - gui->DeactivateWidget(this); } - else if ((wiInput::Press(wiInput::MOUSE_BUTTON_LEFT) && !intersectsPointer) || - wiInput::Press(wiInput::KEYBOARD_BUTTON_ESCAPE)) - { - // cancel input - value_new.clear(); - gui->DeactivateWidget(this); - } - } + + font.params.posX = (int)translation.x + 2; + font.params.posY = (int)(translation.y + scale.y * 0.5f); + font.params.v_align = WIFALIGN_CENTER; } void wiTextInputField::Render(const wiGUI* gui, CommandList cmd) const { @@ -582,25 +590,20 @@ void wiTextInputField::Render(const wiGUI* gui, CommandList cmd) const wiColor color = GetColor(); - wiFont(description, wiFontParams((int)(translation.x), (int)(translation.y + scale.y * 0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_RIGHT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font_description.Draw(cmd); ApplyScissor(scissorRect, cmd); - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); + sprites[state].Draw(cmd); - string activeText = text; if (state == ACTIVE) { - activeText = value_new; + font_input.Draw(cmd); } - else if (!value.empty()) + else { - activeText = value; + font.Draw(cmd); } - wiFont(activeText, wiFontParams((int)(translation.x + 2), (int)(translation.y + scale.y*0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_LEFT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); } void wiTextInputField::OnInputAccepted(function func) @@ -609,14 +612,18 @@ void wiTextInputField::OnInputAccepted(function func) } void wiTextInputField::AddInput(const char inputChar) { + string value_new = font_input.GetTextA(); value_new.push_back(inputChar); + font_input.SetText(value_new); } void wiTextInputField::DeleteFromInput() { + string value_new = font_input.GetTextA(); if (!value_new.empty()) { value_new.pop_back(); } + font_input.SetText(value_new); } @@ -650,6 +657,20 @@ wiSlider::wiSlider(float start, float end, float defaultValue, float step, const } onSlide(args); }); + + for (int i = IDLE; i < WIDGETSTATE_COUNT; ++i) + { + sprites_knob[i].params = sprites[i].params; + sprites_knob[i].params.siz.x = 16; + } + + sprites[IDLE].params.color = wiColor(60, 60, 60, 200); + sprites[FOCUS].params.color = wiColor(50, 50, 50, 200); + sprites[ACTIVE].params.color = wiColor(50, 50, 50, 200); + sprites[DEACTIVATING].params.color = wiColor(60, 60, 60, 200); + + font.params.h_align = WIFALIGN_RIGHT; + font.params.v_align = WIFALIGN_CENTER; } wiSlider::~wiSlider() { @@ -685,93 +706,97 @@ void wiSlider::Update(wiGUI* gui, float dt) for (int i = 0; i < WIDGETSTATE_COUNT; ++i) { - valueInputField->SetColor(this->colors[i], (WIDGETSTATE)i); + valueInputField->SetColor(wiColor::fromFloat4(this->sprites_knob[i].params.color), (WIDGETSTATE)i); } - valueInputField->SetTextColor(this->fontParams.color); - valueInputField->SetTextShadowColor(this->fontParams.shadowColor); + valueInputField->font.params.color = this->font.params.color; + valueInputField->font.params.shadowColor = this->font.params.shadowColor; valueInputField->SetEnabled(IsEnabled()); valueInputField->Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - if (gui->IsWidgetDisabled(this)) - { - return; - } + bool dragged = false; - bool dragged = false; - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - state = IDLE; - } - if (state == ACTIVE) - { - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + if (state == FOCUS) { - if (state == ACTIVE) + state = IDLE; + } + if (state == DEACTIVATING) + { + state = IDLE; + } + if (state == ACTIVE) + { + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) { - // continue drag if already grabbed wheter it is intersecting or not + if (state == ACTIVE) + { + // continue drag if already grabbed wheter it is intersecting or not + dragged = true; + } + } + else + { + gui->DeactivateWidget(this); + } + } + + const float knobWidth = sprites_knob[state].params.siz.x; + hitBox.pos.x = translation.x - knobWidth * 0.5f; + hitBox.pos.y = translation.y; + hitBox.siz.x = scale.x + knobWidth; + hitBox.siz.y = scale.y; + + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); + + + if (pointerHitbox.intersects(hitBox)) + { + // hover the slider + if (state == IDLE) + { + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == FOCUS) + { + // activate dragged = true; } } - else + + + if (dragged) { - gui->DeactivateWidget(this); + wiEventArgs args; + args.clickPos = pointerHitbox.pos; + value = wiMath::InverseLerp(translation.x, translation.x + scale.x, args.clickPos.x); + value = wiMath::Clamp(value, 0, 1); + value *= step; + value = floorf(value); + value /= step; + value = wiMath::Lerp(start, end, value); + args.fValue = value; + args.iValue = (int)value; + onSlide(args); + gui->ActivateWidget(this); } + + valueInputField->SetValue(value); } - hitBox.pos.x = translation.x - headWidth * 0.5f; - hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x + headWidth; - hitBox.siz.y = scale.y; + font.params.posY = (int)(translation.y + scale.y * 0.5f); - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - - - if (pointerHitbox.intersects(hitBox)) - { - // hover the slider - if (state == IDLE) - { - state = FOCUS; - } - } - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { - if (state == FOCUS) - { - // activate - dragged = true; - } - } - - - if (dragged) - { - wiEventArgs args; - args.clickPos = pointerHitbox.pos; - value = wiMath::InverseLerp(translation.x, translation.x + scale.x, args.clickPos.x); - value = wiMath::Clamp(value, 0, 1); - value *= step; - value = floorf(value); - value /= step; - value = wiMath::Lerp(start, end, value); - args.fValue = value; - args.iValue = (int)value; - onSlide(args); - gui->ActivateWidget(this); - } - - valueInputField->SetValue(value); + const float knobWidth = sprites_knob[state].params.siz.x; + const float knobWidthHalf = knobWidth * 0.5f; + sprites_knob[state].params.pos.x = wiMath::Lerp(translation.x + knobWidthHalf + 2, translation.x + scale.x - knobWidthHalf - 2, wiMath::Clamp(wiMath::InverseLerp(start, end, value), 0, 1)); + sprites_knob[state].params.pos.y = translation.y + 2; + sprites_knob[state].params.siz.y = scale.y - 4; + sprites_knob[state].params.pivot = XMFLOAT2(0.5f, 0); } void wiSlider::Render(const wiGUI* gui, CommandList cmd) const { @@ -782,22 +807,15 @@ void wiSlider::Render(const wiGUI* gui, CommandList cmd) const return; } - wiColor color = GetColor(); - - // text - wiFont(text, wiFontParams((int)(translation.x), (int)(translation.y + scale.y * 0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_RIGHT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.Draw(cmd); ApplyScissor(scissorRect, cmd); - // trail - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, colors_base[state].toFloat4()), cmd); - // head - float headPosX = wiMath::Lerp(translation.x + headWidth * 0.5f + 2, translation.x + scale.x - headWidth * 0.5f - 2, wiMath::Clamp(wiMath::InverseLerp(start, end, value), 0, 1)); - wiImageParams fx(headPosX, translation.y + 2, headWidth, scale.y - 4, color.toFloat4()); - fx.pivot = XMFLOAT2(0.5f, 0); - wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); + // base + sprites[state].Draw(cmd); + + // knob + sprites_knob[state].Draw(cmd); valueInputField->Render(gui, cmd); } @@ -806,20 +824,6 @@ void wiSlider::RenderTooltip(const wiGUI* gui, wiGraphics::CommandList cmd) cons wiWidget::RenderTooltip(gui, cmd); valueInputField->RenderTooltip(gui, cmd); } -void wiSlider::SetBaseColor(wiColor color, WIDGETSTATE state) -{ - if (state == WIDGETSTATE_COUNT) - { - for (int i = 0; i < WIDGETSTATE_COUNT; ++i) - { - colors_base[i] = color; - } - } - else - { - colors_base[state] = color; - } -} void wiSlider::OnSlide(function func) { onSlide = move(func); @@ -835,6 +839,15 @@ wiCheckBox::wiCheckBox(const std::string& name) SetText(fastName.GetString()); OnClick([](wiEventArgs args) {}); SetSize(XMFLOAT2(20, 20)); + + font.params.h_align = WIFALIGN_RIGHT; + font.params.v_align = WIFALIGN_CENTER; + + for (int i = IDLE; i < WIDGETSTATE_COUNT; ++i) + { + sprites_check[i].params = sprites[i].params; + sprites_check[i].params.color = wiMath::Lerp(sprites[i].params.color, wiColor::White().toFloat4(), 0.8f); + } } wiCheckBox::~wiCheckBox() { @@ -844,74 +857,73 @@ void wiCheckBox::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - if (gui->IsWidgetDisabled(this)) - { - return; - } - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - state = IDLE; - } - if (state == ACTIVE) - { - gui->DeactivateWidget(this); - } - - hitBox.pos.x = translation.x; - hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x; - hitBox.siz.y = scale.y; - - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - - bool clicked = false; - // hover the button - if (pointerHitbox.intersects(hitBox)) - { - if (state == IDLE) - { - state = FOCUS; - } - } - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == FOCUS) { - // activate - clicked = true; + state = IDLE; } - } - - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { if (state == DEACTIVATING) { - // Keep pressed until mouse is released + state = IDLE; + } + if (state == ACTIVE) + { + gui->DeactivateWidget(this); + } + + hitBox.pos.x = translation.x; + hitBox.pos.y = translation.y; + hitBox.siz.x = scale.x; + hitBox.siz.y = scale.y; + + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); + + bool clicked = false; + // hover the button + if (pointerHitbox.intersects(hitBox)) + { + if (state == IDLE) + { + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == FOCUS) + { + // activate + clicked = true; + } + } + + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + } + } + + if (clicked) + { + SetCheck(!GetCheck()); + wiEventArgs args; + args.clickPos = pointerHitbox.pos; + args.bValue = GetCheck(); + onClick(args); gui->ActivateWidget(this); } } - if (clicked) - { - SetCheck(!GetCheck()); - wiEventArgs args; - args.clickPos = pointerHitbox.pos; - args.bValue = GetCheck(); - onClick(args); - gui->ActivateWidget(this); - } + font.params.posY = (int)(translation.y + scale.y * 0.5f); + sprites_check[state].params.pos.x = translation.x + scale.x * 0.25f; + sprites_check[state].params.pos.y = translation.y + scale.y * 0.25f; + sprites_check[state].params.siz = XMFLOAT2(scale.x * 0.5f, scale.y * 0.5f); } void wiCheckBox::Render(const wiGUI* gui, CommandList cmd) const { @@ -922,23 +934,17 @@ void wiCheckBox::Render(const wiGUI* gui, CommandList cmd) const return; } - wiColor color = GetColor(); - - wiFont(text, wiFontParams((int)(translation.x), (int)(translation.y + scale.y * 0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_RIGHT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.Draw(cmd); ApplyScissor(scissorRect, cmd); // control - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); + sprites[state].Draw(cmd); // check if (GetCheck()) { - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x*0.25f, translation.y + scale.y*0.25f, scale.x*0.5f, scale.y*0.5f, wiColor::lerp(color, wiColor::White(), 0.8f).toFloat4()) - , cmd); + sprites_check[state].Draw(cmd); } } @@ -965,6 +971,9 @@ wiComboBox::wiComboBox(const std::string& name) SetText(fastName.GetString()); OnSelect([](wiEventArgs args) {}); SetSize(XMFLOAT2(100, 20)); + + font.params.h_align = WIFALIGN_RIGHT; + font.params.v_align = WIFALIGN_CENTER; } wiComboBox::~wiComboBox() { @@ -983,151 +992,147 @@ void wiComboBox::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - if (gui->IsWidgetDisabled(this)) - { - return; - } - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - state = IDLE; - } - if (state == ACTIVE && combostate == COMBOSTATE_SELECTING) - { - hovered = -1; - gui->DeactivateWidget(this); - } - if (state == IDLE && combostate == COMBOSTATE_SELECTING) - { - combostate = COMBOSTATE_INACTIVE; - } - - hitBox.pos.x = translation.x; - hitBox.pos.y = translation.y; - hitBox.siz.x = scale.x + scale.y + 1; // + drop-down indicator arrow + little offset - hitBox.siz.y = scale.y; - - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - - bool clicked = false; - // hover the button - if (pointerHitbox.intersects(hitBox)) - { - if (state == IDLE) + if (state == FOCUS) { - state = FOCUS; + state = IDLE; } - } - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { - // activate - clicked = true; - } - - bool click_down = false; - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { - click_down = true; if (state == DEACTIVATING) { - // Keep pressed until mouse is released - gui->ActivateWidget(this); + state = IDLE; } - } - - - if (clicked && state == FOCUS) - { - gui->ActivateWidget(this); - } - - const float scrollbar_begin = translation.y + scale.y + 1 + scale.y * 0.5f; - const float scrollbar_end = scrollbar_begin + std::max(0.0f, (float)std::min(maxVisibleItemCount, (int)items.size()) - 1) * scale.y; - - if (state == ACTIVE) - { - if (HasScrollbar()) - { - if (combostate != COMBOSTATE_SELECTING && combostate != COMBOSTATE_INACTIVE) - { - if (combostate == COMBOSTATE_SCROLLBAR_GRABBED || pointerHitbox.intersects(Hitbox2D(XMFLOAT2(translation.x + scale.x + 1, translation.y + scale.y + 1), XMFLOAT2(scale.y, (float)std::min(maxVisibleItemCount, (int)items.size()) * scale.y)))) - { - if (click_down) - { - combostate = COMBOSTATE_SCROLLBAR_GRABBED; - scrollbar_delta = wiMath::Clamp(pointerHitbox.pos.y, scrollbar_begin, scrollbar_end) - scrollbar_begin; - const float scrollbar_value = wiMath::InverseLerp(scrollbar_begin, scrollbar_end, scrollbar_begin + scrollbar_delta); - firstItemVisible = int(float(std::max(0, (int)items.size() - maxVisibleItemCount)) * scrollbar_value + 0.5f); - firstItemVisible = std::max(0, std::min((int)items.size() - maxVisibleItemCount, firstItemVisible)); - } - else - { - combostate = COMBOSTATE_SCROLLBAR_HOVER; - } - } - else if (!click_down) - { - combostate = COMBOSTATE_HOVER; - } - } - } - - if (combostate == COMBOSTATE_INACTIVE) - { - combostate = COMBOSTATE_HOVER; - } - else if (combostate == COMBOSTATE_SELECTING) + if (state == ACTIVE && combostate == COMBOSTATE_SELECTING) { + hovered = -1; gui->DeactivateWidget(this); + } + if (state == IDLE && combostate == COMBOSTATE_SELECTING) + { combostate = COMBOSTATE_INACTIVE; } - else if (combostate == COMBOSTATE_HOVER) - { - int scroll = (int)wiInput::GetPointer().z; - firstItemVisible -= scroll; - firstItemVisible = std::max(0, std::min((int)items.size() - maxVisibleItemCount, firstItemVisible)); - if (scroll) - { - const float scrollbar_value = wiMath::InverseLerp(0, float(std::max(0, (int)items.size() - maxVisibleItemCount)), float(firstItemVisible)); - scrollbar_delta = wiMath::Lerp(scrollbar_begin, scrollbar_end, scrollbar_value) - scrollbar_begin; - } - hovered = -1; - for (int i = firstItemVisible; i < (firstItemVisible + std::min(maxVisibleItemCount, (int)items.size())); ++i) + hitBox.pos.x = translation.x; + hitBox.pos.y = translation.y; + hitBox.siz.x = scale.x + scale.y + 1; // + drop-down indicator arrow + little offset + hitBox.siz.y = scale.y; + + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); + + bool clicked = false; + // hover the button + if (pointerHitbox.intersects(hitBox)) + { + if (state == IDLE) { - Hitbox2D itembox; - itembox.pos.x = translation.x; - itembox.pos.y = translation.y + GetItemOffset(i); - itembox.siz.x = scale.x; - itembox.siz.y = scale.y; - if (pointerHitbox.intersects(itembox)) + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + // activate + clicked = true; + } + + bool click_down = false; + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + click_down = true; + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + } + } + + + if (clicked && state == FOCUS) + { + gui->ActivateWidget(this); + } + + const float scrollbar_begin = translation.y + scale.y + 1 + scale.y * 0.5f; + const float scrollbar_end = scrollbar_begin + std::max(0.0f, (float)std::min(maxVisibleItemCount, (int)items.size()) - 1) * scale.y; + + if (state == ACTIVE) + { + if (HasScrollbar()) + { + if (combostate != COMBOSTATE_SELECTING && combostate != COMBOSTATE_INACTIVE) { - hovered = i; - break; + if (combostate == COMBOSTATE_SCROLLBAR_GRABBED || pointerHitbox.intersects(Hitbox2D(XMFLOAT2(translation.x + scale.x + 1, translation.y + scale.y + 1), XMFLOAT2(scale.y, (float)std::min(maxVisibleItemCount, (int)items.size()) * scale.y)))) + { + if (click_down) + { + combostate = COMBOSTATE_SCROLLBAR_GRABBED; + scrollbar_delta = wiMath::Clamp(pointerHitbox.pos.y, scrollbar_begin, scrollbar_end) - scrollbar_begin; + const float scrollbar_value = wiMath::InverseLerp(scrollbar_begin, scrollbar_end, scrollbar_begin + scrollbar_delta); + firstItemVisible = int(float(std::max(0, (int)items.size() - maxVisibleItemCount)) * scrollbar_value + 0.5f); + firstItemVisible = std::max(0, std::min((int)items.size() - maxVisibleItemCount, firstItemVisible)); + } + else + { + combostate = COMBOSTATE_SCROLLBAR_HOVER; + } + } + else if (!click_down) + { + combostate = COMBOSTATE_HOVER; + } } } - if (clicked) + if (combostate == COMBOSTATE_INACTIVE) { - combostate = COMBOSTATE_SELECTING; - if (hovered >= 0) + combostate = COMBOSTATE_HOVER; + } + else if (combostate == COMBOSTATE_SELECTING) + { + gui->DeactivateWidget(this); + combostate = COMBOSTATE_INACTIVE; + } + else if (combostate == COMBOSTATE_HOVER) + { + int scroll = (int)wiInput::GetPointer().z; + firstItemVisible -= scroll; + firstItemVisible = std::max(0, std::min((int)items.size() - maxVisibleItemCount, firstItemVisible)); + if (scroll) { - SetSelected(hovered); + const float scrollbar_value = wiMath::InverseLerp(0, float(std::max(0, (int)items.size() - maxVisibleItemCount)), float(firstItemVisible)); + scrollbar_delta = wiMath::Lerp(scrollbar_begin, scrollbar_end, scrollbar_value) - scrollbar_begin; + } + + hovered = -1; + for (int i = firstItemVisible; i < (firstItemVisible + std::min(maxVisibleItemCount, (int)items.size())); ++i) + { + Hitbox2D itembox; + itembox.pos.x = translation.x; + itembox.pos.y = translation.y + GetItemOffset(i); + itembox.siz.x = scale.x; + itembox.siz.y = scale.y; + if (pointerHitbox.intersects(itembox)) + { + hovered = i; + break; + } + } + + if (clicked) + { + combostate = COMBOSTATE_SELECTING; + if (hovered >= 0) + { + SetSelected(hovered); + } } } } } + font.params.posX = (int)translation.x + 2; + font.params.posY = (int)(translation.y + sprites[state].params.siz.y * 0.5f); } void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const { @@ -1142,11 +1147,10 @@ void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const wiColor color = GetColor(); if (combostate != COMBOSTATE_INACTIVE) { - color = colors[FOCUS]; + color = wiColor::fromFloat4(sprites[FOCUS].params.color); } - wiFont(text, wiFontParams((int)(translation.x), (int)(translation.y + scale.y * 0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_RIGHT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.Draw(cmd); struct Vertex { @@ -1172,15 +1176,17 @@ void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const const XMMATRIX Projection = device->GetScreenProjection(); // control-arrow-background - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x + 1, translation.y, scale.y, scale.y, color.toFloat4()), cmd); + wiImageParams fx = sprites[state].params; + fx.pos = XMFLOAT3(translation.x + scale.x + 1, translation.y, 0); + fx.siz = XMFLOAT2(scale.y, scale.y); + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); // control-arrow-triangle { device->BindPipelineState(&PSO_colored, cmd); MiscCB cb; - cb.g_xColor = colors[ACTIVE].toFloat4(); + cb.g_xColor = sprites[ACTIVE].params.color; XMStoreFloat4x4(&cb.g_xTransform, XMMatrixScaling(scale.y * 0.25f, scale.y * 0.25f, 1) * XMMatrixRotationZ(XM_PIDIV2) * XMMatrixTranslation(translation.x + scale.x + 1 + scale.y * 0.5f, translation.y + scale.y * 0.5f, 0) * @@ -1202,13 +1208,12 @@ void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const ApplyScissor(scissorRect, cmd); // control-base - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); + sprites[state].Draw(cmd); if (selected >= 0) { wiFont(items[selected], wiFontParams((int)(translation.x + scale.x*0.5f), (int)(translation.y + scale.y*0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_CENTER, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.params.color, font.params.shadowColor)).Draw(cmd); } // drop-down @@ -1225,24 +1230,26 @@ void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const // control-scrollbar-base { - wiColor col = wiColor(60, 60, 60, 255); - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x + 1, translation.y + scale.y + 1, scale.y, scale.y * maxVisibleItemCount, col.toFloat4()), cmd); + fx = sprites[state].params; + fx.pos = XMFLOAT3(translation.x + scale.x + 1, translation.y + scale.y + 1, 0); + fx.siz = XMFLOAT2(scale.y, scale.y * maxVisibleItemCount); + fx.color = wiMath::Lerp(wiColor::Transparent(), sprites[IDLE].params.color, 0.5f); + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); } // control-scrollbar-grab { - wiColor col = colors[IDLE]; + wiColor col = wiColor::fromFloat4(sprites[IDLE].params.color); if (combostate == COMBOSTATE_SCROLLBAR_HOVER) { - col = colors[FOCUS]; + col = wiColor::fromFloat4(sprites[FOCUS].params.color); } else if (combostate == COMBOSTATE_SCROLLBAR_GRABBED) { - col = colors[ACTIVE]; + col = wiColor::fromFloat4(sprites[ACTIVE].params.color); } wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x + 1, translation.y + scale.y + 1 + scrollbar_delta, scale.y, scale.y, col.toFloat4()), cmd); + , wiImageParams(translation.x + scale.x + 1, translation.y + scale.y + 1 + scrollbar_delta, scale.y, scale.y, col), cmd); } } @@ -1256,22 +1263,24 @@ void wiComboBox::Render(const wiGUI* gui, CommandList cmd) const // control-list for (int i = firstItemVisible; i < (firstItemVisible + std::min(maxVisibleItemCount, (int)items.size())); ++i) { - wiColor col = wiColor(60, 60, 60, 255); + fx = sprites[state].params; + fx.pos = XMFLOAT3(translation.x, translation.y + GetItemOffset(i), 0); + fx.siz = XMFLOAT2(scale.x, scale.y); + fx.color = wiMath::Lerp(wiColor::Transparent(), sprites[IDLE].params.color, 0.5f); if (hovered == i) { if (combostate == COMBOSTATE_HOVER) { - col = colors[FOCUS]; + fx.color = sprites[FOCUS].params.color; } else if (combostate == COMBOSTATE_SELECTING) { - col = colors[ACTIVE]; + fx.color = sprites[ACTIVE].params.color; } } - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y + GetItemOffset(i), scale.x, scale.y, col.toFloat4()), cmd); + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); wiFont(items[i], wiFontParams((int)(translation.x + scale.x*0.5f), (int)(translation.y + scale.y*0.5f + GetItemOffset(i)), WIFONTSIZE_DEFAULT, WIFALIGN_CENTER, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.params.color, font.params.shadowColor)).Draw(cmd); } } } @@ -1352,50 +1361,20 @@ wiWindow::wiWindow(wiGUI* gui, const std::string& name, bool window_controls) : { assert(gui != nullptr && "Ivalid GUI!"); + SetColor(wiColor::Ghost()); + SetName(name); SetText(fastName.GetString()); - SetSize(XMFLOAT2(640, 480)); + SetSize(XMFLOAT2(640, 480)); + + for (int i = IDLE + 1; i < WIDGETSTATE_COUNT; ++i) + { + sprites[i].params.color = sprites[IDLE].params.color; + } // Add controls if (window_controls) { - // Add a grabber onto the title bar - moveDragger = new wiButton(name + "_move_dragger"); - moveDragger->SetText(name); - wiFontParams fontparams = moveDragger->GetFontParams(); - fontparams.h_align = WIFALIGN_LEFT; - moveDragger->SetFontParams(fontparams); - moveDragger->OnDrag([this, gui](wiEventArgs args) { - auto saved_parent = this->parent; - this->Detach(); - this->Translate(XMFLOAT3(args.deltaPos.x, args.deltaPos.y, 0)); - this->wiWidget::Update(gui, 0); - for (auto& x : this->childrenWidgets) - { - x->wiWidget::Update(gui, 0); - } - this->AttachTo(saved_parent); - }); - AddWidget(moveDragger); - - // Add close button to the top right corner - closeButton = new wiButton(name + "_close_button"); - closeButton->SetText("x"); - closeButton->OnClick([this](wiEventArgs args) { - this->SetVisible(false); - }); - closeButton->SetTooltip("Close window"); - AddWidget(closeButton); - - // Add minimize button to the top right corner - minimizeButton = new wiButton(name + "_minimize_button"); - minimizeButton->SetText("-"); - minimizeButton->OnClick([this](wiEventArgs args) { - this->SetMinimized(!this->IsMinimized()); - }); - minimizeButton->SetTooltip("Minimize window"); - AddWidget(minimizeButton); - // Add a resizer control to the upperleft corner resizeDragger_UpperLeft = new wiButton(name + "_resize_dragger_upper_left"); resizeDragger_UpperLeft->SetText(""); @@ -1434,15 +1413,48 @@ wiWindow::wiWindow(wiGUI* gui, const std::string& name, bool window_controls) : this->AttachTo(saved_parent); }); AddWidget(resizeDragger_BottomRight); + + // Add a grabber onto the title bar + moveDragger = new wiButton(name + "_move_dragger"); + moveDragger->SetText(name); + moveDragger->font.params.h_align = WIFALIGN_LEFT; + moveDragger->OnDrag([this, gui](wiEventArgs args) { + auto saved_parent = this->parent; + this->Detach(); + this->Translate(XMFLOAT3(args.deltaPos.x, args.deltaPos.y, 0)); + this->wiWidget::Update(gui, 0); + for (auto& x : this->childrenWidgets) + { + x->wiWidget::Update(gui, 0); + } + this->AttachTo(saved_parent); + }); + AddWidget(moveDragger); + + // Add close button to the top right corner + closeButton = new wiButton(name + "_close_button"); + closeButton->SetText("x"); + closeButton->OnClick([this, gui](wiEventArgs args) { + this->SetVisible(false); + }); + closeButton->SetTooltip("Close window"); + AddWidget(closeButton); + + // Add minimize button to the top right corner + minimizeButton = new wiButton(name + "_minimize_button"); + minimizeButton->SetText("-"); + minimizeButton->OnClick([this, gui](wiEventArgs args) { + this->SetMinimized(!this->IsMinimized()); + }); + minimizeButton->SetTooltip("Minimize window"); + AddWidget(minimizeButton); } else { // Simple title bar label = new wiLabel(name); label->SetText(name); - wiFontParams fontparams = label->GetFontParams(); - fontparams.h_align = WIFALIGN_LEFT; - label->SetFontParams(fontparams); + label->font.params.h_align = WIFALIGN_LEFT; AddWidget(label); } @@ -1541,16 +1553,63 @@ void wiWindow::Update(wiGUI* gui, float dt) for (auto& x : childrenWidgets) { x->Update(gui, dt); + + if (x->GetState() == ACTIVE) + { + gui->ActivateWidget(this); + } } - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - if (gui->IsWidgetDisabled(this)) - { - return; + if (state == FOCUS) + { + state = IDLE; + } + if (state == DEACTIVATING) + { + state = IDLE; + } + if (state == ACTIVE) + { + gui->DeactivateWidget(this); + } + + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); + + bool clicked = false; + // hover the button + if (pointerHitbox.intersects(hitBox)) + { + if (state == IDLE) + { + state = FOCUS; + } + } + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == FOCUS) + { + // activate + clicked = true; + } + } + + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + } + } + + if (clicked) + { + gui->ActivateWidget(this); + } } } void wiWindow::Render(const wiGUI* gui, CommandList cmd) const @@ -1564,13 +1623,12 @@ void wiWindow::Render(const wiGUI* gui, CommandList cmd) const wiColor color = GetColor(); - ApplyScissor(scissorRect, cmd); - // body if (!IsMinimized()) { - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, scale.y, color.toFloat4()), cmd); + wiImageParams fx(translation.x-2, translation.y-2, scale.x+4, scale.y+4, wiColor(0, 0, 0, 100)); + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); // simple shadow under the window + sprites[state].Draw(cmd); } for (auto& x : childrenWidgets) @@ -1753,7 +1811,7 @@ rgb hsv2rgb(hsv in) wiColorPicker::wiColorPicker(wiGUI* gui, const std::string& name, bool window_controls) :wiWindow(gui, name, window_controls) { SetSize(XMFLOAT2(300, 260)); - SetColor(wiColor::Ghost()); + SetColor(wiColor(100, 100, 100, 100)); if (resizeDragger_BottomRight != nullptr) { @@ -1865,129 +1923,117 @@ void wiColorPicker::Update(wiGUI* gui, float dt) { wiWindow::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - //if (!gui->IsWidgetDisabled(this)) - //{ - // return; - //} - - if (state == DEACTIVATING) - { - state = IDLE; - } - - XMFLOAT2 center = XMFLOAT2(translation.x + colorpicker_center, translation.y + colorpicker_center); - XMFLOAT2 pointer = gui->GetPointerPos(); - float distance = wiMath::Distance(center, pointer); - bool hover_hue = (distance > colorpicker_radius) && (distance < colorpicker_radius + colorpicker_width); - - float distTri = 0; - XMFLOAT4 A, B, C; - wiMath::ConstructTriangleEquilateral(colorpicker_radius_triangle, A, B, C); - XMVECTOR _A = XMLoadFloat4(&A); - XMVECTOR _B = XMLoadFloat4(&B); - XMVECTOR _C = XMLoadFloat4(&C); - XMMATRIX _triTransform = XMMatrixRotationZ(-hue / 360.0f * XM_2PI) * XMMatrixTranslation(center.x, center.y, 0); - _A = XMVector4Transform(_A, _triTransform); - _B = XMVector4Transform(_B, _triTransform); - _C = XMVector4Transform(_C, _triTransform); - XMVECTOR O = XMVectorSet(pointer.x, pointer.y, 0, 0); - XMVECTOR D = XMVectorSet(0, 0, 1, 0); - bool hover_saturation = TriangleTests::Intersects(O, D, _A, _B, _C, distTri); - - if (hover_hue && state == IDLE) - { - state = FOCUS; - huefocus = true; - } - else if (hover_saturation && state == IDLE) - { - state = FOCUS; - huefocus = false; - } - else if (state == IDLE) - { - huefocus = false; - } - - bool dragged = false; - - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { - if (state == FOCUS) + if (state == DEACTIVATING) { - // activate - dragged = true; + state = IDLE; } - } - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { - if (state == ACTIVE) + XMFLOAT2 center = XMFLOAT2(translation.x + colorpicker_center, translation.y + colorpicker_center); + XMFLOAT2 pointer = gui->GetPointerPos(); + float distance = wiMath::Distance(center, pointer); + bool hover_hue = (distance > colorpicker_radius) && (distance < colorpicker_radius + colorpicker_width); + + float distTri = 0; + XMFLOAT4 A, B, C; + wiMath::ConstructTriangleEquilateral(colorpicker_radius_triangle, A, B, C); + XMVECTOR _A = XMLoadFloat4(&A); + XMVECTOR _B = XMLoadFloat4(&B); + XMVECTOR _C = XMLoadFloat4(&C); + XMMATRIX _triTransform = XMMatrixRotationZ(-hue / 360.0f * XM_2PI) * XMMatrixTranslation(center.x, center.y, 0); + _A = XMVector4Transform(_A, _triTransform); + _B = XMVector4Transform(_B, _triTransform); + _C = XMVector4Transform(_C, _triTransform); + XMVECTOR O = XMVectorSet(pointer.x, pointer.y, 0, 0); + XMVECTOR D = XMVectorSet(0, 0, 1, 0); + bool hover_saturation = TriangleTests::Intersects(O, D, _A, _B, _C, distTri); + + bool dragged = false; + + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) { - // continue drag if already grabbed whether it is intersecting or not - dragged = true; + if (hover_hue) + { + colorpickerstate = CPS_HUE; + dragged = true; + } + else if (hover_saturation) + { + colorpickerstate = CPS_SATURATION; + dragged = true; + } } - } - dragged = dragged && !gui->IsWidgetDisabled(this); - if (huefocus && dragged) - { - //hue pick - const float angle = wiMath::GetAngle(XMFLOAT2(pointer.x - center.x, pointer.y - center.y), XMFLOAT2(colorpicker_radius, 0)); - hue = angle / XM_2PI * 360.0f; - gui->ActivateWidget(this); - } - else if (!huefocus && dragged) - { - // saturation pick - float u, v, w; - wiMath::GetBarycentric(O, _A, _B, _C, u, v, w, true); - // u = saturated corner (color) - // v = desaturated corner (white) - // w = no luminosity corner (black) + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + if (colorpickerstate > CPS_IDLE) + { + // continue drag if already grabbed whether it is intersecting or not + dragged = true; + } + } + else + { + colorpickerstate = CPS_IDLE; + } - hsv source; - source.h = hue; - source.s = 1; - source.v = 1; - rgb result = hsv2rgb(source); + dragged = dragged && !gui->IsWidgetDisabled(this); + if (colorpickerstate == CPS_HUE && dragged) + { + //hue pick + const float angle = wiMath::GetAngle(XMFLOAT2(pointer.x - center.x, pointer.y - center.y), XMFLOAT2(colorpicker_radius, 0)); + hue = angle / XM_2PI * 360.0f; + gui->ActivateWidget(this); + } + else if (colorpickerstate == CPS_SATURATION && dragged) + { + // saturation pick + float u, v, w; + wiMath::GetBarycentric(O, _A, _B, _C, u, v, w, true); + // u = saturated corner (color) + // v = desaturated corner (white) + // w = no luminosity corner (black) - XMVECTOR color_corner = XMVectorSet(result.r, result.g, result.b, 1); - XMVECTOR white_corner = XMVectorSet(1, 1, 1, 1); - XMVECTOR black_corner = XMVectorSet(0, 0, 0, 1); - XMVECTOR inner_point = u * color_corner + v * white_corner + w * black_corner; + hsv source; + source.h = hue; + source.s = 1; + source.v = 1; + rgb result = hsv2rgb(source); - result.r = XMVectorGetX(inner_point); - result.g = XMVectorGetY(inner_point); - result.b = XMVectorGetZ(inner_point); - source = rgb2hsv(result); + XMVECTOR color_corner = XMVectorSet(result.r, result.g, result.b, 1); + XMVECTOR white_corner = XMVectorSet(1, 1, 1, 1); + XMVECTOR black_corner = XMVectorSet(0, 0, 0, 1); + XMVECTOR inner_point = u * color_corner + v * white_corner + w * black_corner; - saturation = source.s; - luminance = source.v; + result.r = XMVectorGetX(inner_point); + result.g = XMVectorGetY(inner_point); + result.b = XMVectorGetZ(inner_point); + source = rgb2hsv(result); - gui->ActivateWidget(this); - } - else if (state != IDLE) - { - gui->DeactivateWidget(this); - } + saturation = source.s; + luminance = source.v; - wiColor color = GetPickColor(); - text_R->SetValue((int)color.getR()); - text_G->SetValue((int)color.getG()); - text_B->SetValue((int)color.getB()); - text_H->SetValue(int(hue)); - text_S->SetValue(int(saturation * 100)); - text_V->SetValue(int(luminance * 100)); + gui->ActivateWidget(this); + } + else if (state != IDLE) + { + gui->DeactivateWidget(this); + } - if (dragged) - { - FireEvents(); + wiColor color = GetPickColor(); + text_R->SetValue((int)color.getR()); + text_G->SetValue((int)color.getG()); + text_B->SetValue((int)color.getB()); + text_H->SetValue(int(hue)); + text_S->SetValue(int(saturation * 100)); + text_V->SetValue(int(luminance * 100)); + + if (dragged) + { + FireEvents(); + } } } void wiColorPicker::Render(const wiGUI* gui, CommandList cmd) const @@ -2426,6 +2472,12 @@ wiTreeList::wiTreeList(const std::string& name) SetText(fastName.GetString()); OnSelect([](wiEventArgs args) {}); SetSize(XMFLOAT2(100, 20)); + + for (int i = FOCUS + 1; i < WIDGETSTATE_COUNT; ++i) + { + sprites[i].params.color = sprites[FOCUS].params.color; + } + font.params.v_align = WIFALIGN_CENTER; } wiTreeList::~wiTreeList() { @@ -2460,174 +2512,171 @@ void wiTreeList::Update(wiGUI* gui, float dt) { wiWidget::Update(gui, dt); - if (!IsEnabled()) + if (IsEnabled() && !gui->IsWidgetDisabled(this)) { - return; - } - - if (gui->IsWidgetDisabled(this)) - { - return; - } - - if (state == FOCUS) - { - state = IDLE; - } - if (state == DEACTIVATING) - { - state = IDLE; - } - if (state == ACTIVE) - { - gui->DeactivateWidget(this); - } - - Hitbox2D hitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y), XMFLOAT2(scale.x, scale.y)); - Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - - if (state == IDLE && hitbox.intersects(pointerHitbox)) - { - state = FOCUS; - } - - bool clicked = false; - if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) - { - clicked = true; - } - - bool click_down = false; - if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) - { - click_down = true; + if (state == FOCUS) + { + state = IDLE; + } if (state == DEACTIVATING) { - // Keep pressed until mouse is released - gui->ActivateWidget(this); + state = IDLE; } - } - - // compute control-list height - list_height = 0; - { - int visible_count = 0; - int parent_level = 0; - bool parent_open = true; - for (const Item& item : items) + if (state == ACTIVE) { - if (!parent_open && item.level > parent_level) - { - continue; - } - visible_count++; - parent_open = item.open; - parent_level = item.level; - list_height += item_height; + gui->DeactivateWidget(this); } - } - const float scrollbar_begin = translation.y + item_height; - const float scrollbar_end = scrollbar_begin + scale.y - item_height; - const float scrollbar_size = scrollbar_end - scrollbar_begin; - const float scrollbar_granularity = std::min(1.0f, scrollbar_size / list_height); - scrollbar_height = std::max(tree_scrollbar_width, scrollbar_size * scrollbar_granularity); + Hitbox2D hitbox = Hitbox2D(XMFLOAT2(translation.x, translation.y), XMFLOAT2(scale.x, scale.y)); + Hitbox2D pointerHitbox = Hitbox2D(gui->GetPointerPos(), XMFLOAT2(1, 1)); - if (!click_down) - { - scrollbar_state = SCROLLBAR_INACTIVE; - } - - Hitbox2D scroll_box; - scroll_box.pos = XMFLOAT2(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1); - scroll_box.siz = XMFLOAT2(tree_scrollbar_width, scale.y - item_height - 1); - if (scroll_box.intersects(pointerHitbox)) - { - if (clicked) + if (state == IDLE && hitbox.intersects(pointerHitbox)) { - scrollbar_state = SCROLLBAR_GRABBED; - } - else if(!click_down) - { - scrollbar_state = SCROLLBAR_HOVER; state = FOCUS; } - } - if (scrollbar_state == SCROLLBAR_GRABBED) - { - gui->ActivateWidget(this); - scrollbar_delta = pointerHitbox.pos.y - scrollbar_height * 0.5f - scrollbar_begin; - } - - if (state == FOCUS) - { - scrollbar_delta -= wiInput::GetPointer().z; - } - scrollbar_delta = wiMath::Clamp(scrollbar_delta, 0, scrollbar_size - scrollbar_height); - scrollbar_value = wiMath::InverseLerp(scrollbar_begin, scrollbar_end, scrollbar_begin + scrollbar_delta); - - list_offset = -scrollbar_value * list_height; - - Hitbox2D itemlist_box = GetHitbox_ListArea(); - - // control-list - item_highlight = -1; - opener_highlight = -1; - if (scrollbar_state == SCROLLBAR_INACTIVE) - { - int i = -1; - int visible_count = 0; - int parent_level = 0; - bool parent_open = true; - for (Item& item : items) + bool clicked = false; + if (wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) { - i++; - if (!parent_open && item.level > parent_level) - { - continue; - } - visible_count++; - parent_open = item.open; - parent_level = item.level; + clicked = true; + } - Hitbox2D open_box = GetHitbox_ItemOpener(visible_count, item.level); - if (!open_box.intersects(itemlist_box)) + bool click_down = false; + if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) + { + click_down = true; + if (state == FOCUS || state == DEACTIVATING) { - continue; + // Keep pressed until mouse is released + gui->ActivateWidget(this); } + } - if (open_box.intersects(pointerHitbox)) + // compute control-list height + list_height = 0; + { + int visible_count = 0; + int parent_level = 0; + bool parent_open = true; + for (const Item& item : items) { - // Opened flag box: - opener_highlight = i; - if (clicked) + if (!parent_open && item.level > parent_level) { - item.open = !item.open; - gui->ActivateWidget(this); + continue; } + visible_count++; + parent_open = item.open; + parent_level = item.level; + list_height += item_height; } - else + } + + const float scrollbar_begin = translation.y + item_height; + const float scrollbar_end = scrollbar_begin + scale.y - item_height; + const float scrollbar_size = scrollbar_end - scrollbar_begin; + const float scrollbar_granularity = std::min(1.0f, scrollbar_size / list_height); + scrollbar_height = std::max(tree_scrollbar_width, scrollbar_size * scrollbar_granularity); + + if (!click_down) + { + scrollbar_state = SCROLLBAR_INACTIVE; + } + + Hitbox2D scroll_box; + scroll_box.pos = XMFLOAT2(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1); + scroll_box.siz = XMFLOAT2(tree_scrollbar_width, scale.y - item_height - 1); + if (scroll_box.intersects(pointerHitbox)) + { + if (clicked) { - // Item name box: - Hitbox2D name_box = GetHitbox_Item(visible_count, item.level); - if (name_box.intersects(pointerHitbox)) + scrollbar_state = SCROLLBAR_GRABBED; + } + else if (!click_down) + { + scrollbar_state = SCROLLBAR_HOVER; + state = FOCUS; + } + } + + if (scrollbar_state == SCROLLBAR_GRABBED) + { + gui->ActivateWidget(this); + scrollbar_delta = pointerHitbox.pos.y - scrollbar_height * 0.5f - scrollbar_begin; + } + + if (state == FOCUS) + { + scrollbar_delta -= wiInput::GetPointer().z; + } + scrollbar_delta = wiMath::Clamp(scrollbar_delta, 0, scrollbar_size - scrollbar_height); + scrollbar_value = wiMath::InverseLerp(scrollbar_begin, scrollbar_end, scrollbar_begin + scrollbar_delta); + + list_offset = -scrollbar_value * list_height; + + Hitbox2D itemlist_box = GetHitbox_ListArea(); + + // control-list + item_highlight = -1; + opener_highlight = -1; + if (scrollbar_state == SCROLLBAR_INACTIVE) + { + int i = -1; + int visible_count = 0; + int parent_level = 0; + bool parent_open = true; + for (Item& item : items) + { + i++; + if (!parent_open && item.level > parent_level) { - item_highlight = i; + continue; + } + visible_count++; + parent_open = item.open; + parent_level = item.level; + + Hitbox2D open_box = GetHitbox_ItemOpener(visible_count, item.level); + if (!open_box.intersects(itemlist_box)) + { + continue; + } + + if (open_box.intersects(pointerHitbox)) + { + // Opened flag box: + opener_highlight = i; if (clicked) { - if (!wiInput::Down(wiInput::KEYBOARD_BUTTON_LCONTROL) && !wiInput::Down(wiInput::KEYBOARD_BUTTON_RCONTROL) - && !wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT) && !wiInput::Down(wiInput::KEYBOARD_BUTTON_RSHIFT)) - { - ClearSelection(); - } - Select(i); + item.open = !item.open; gui->ActivateWidget(this); } } + else + { + // Item name box: + Hitbox2D name_box = GetHitbox_Item(visible_count, item.level); + if (name_box.intersects(pointerHitbox)) + { + item_highlight = i; + if (clicked) + { + if (!wiInput::Down(wiInput::KEYBOARD_BUTTON_LCONTROL) && !wiInput::Down(wiInput::KEYBOARD_BUTTON_RCONTROL) + && !wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT) && !wiInput::Down(wiInput::KEYBOARD_BUTTON_RSHIFT)) + { + ClearSelection(); + } + Select(i); + gui->ActivateWidget(this); + } + } + } } } } + + sprites[state].params.siz.y = item_height; + font.params.posX = (int)translation.x + 2; + font.params.posY = (int)(translation.y + sprites[state].params.siz.y * 0.5f); } void wiTreeList::Render(const wiGUI* gui, CommandList cmd) const { @@ -2639,36 +2688,38 @@ void wiTreeList::Render(const wiGUI* gui, CommandList cmd) const } GraphicsDevice* device = wiRenderer::GetDevice(); + // control-base + sprites[state].Draw(cmd); + ApplyScissor(scissorRect, cmd); - // control-base - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x, translation.y, scale.x, item_height, colors[state == IDLE ? IDLE : FOCUS].toFloat4()), cmd); - - wiFont(text, wiFontParams((int)(translation.x) + 1, (int)(translation.y) + 1, WIFONTSIZE_DEFAULT, WIFALIGN_LEFT, WIFALIGN_TOP, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.Draw(cmd); // scrollbar background - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1, tree_scrollbar_width, scale.y - item_height - 1, colors[IDLE].toFloat4()), cmd); + wiImageParams fx = sprites[state].params; + fx.pos = XMFLOAT3(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1, 0); + fx.siz = XMFLOAT2(tree_scrollbar_width, scale.y - item_height - 1); + fx.color = sprites[IDLE].params.color; + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); // scrollbar - wiColor scrollbar_color = colors[IDLE]; + wiColor scrollbar_color = wiColor::fromFloat4(sprites[IDLE].params.color); if (scrollbar_state == SCROLLBAR_HOVER) { - scrollbar_color = colors[FOCUS]; + scrollbar_color = wiColor::fromFloat4(sprites[FOCUS].params.color); } else if (scrollbar_state == SCROLLBAR_GRABBED) { - scrollbar_color = colors[ACTIVE]; + scrollbar_color = wiColor::White(); } wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1 + scrollbar_delta, tree_scrollbar_width, scrollbar_height, scrollbar_color.toFloat4()), cmd); + , wiImageParams(translation.x + scale.x - tree_scrollbar_width, translation.y + item_height + 1 + scrollbar_delta, tree_scrollbar_width, scrollbar_height, scrollbar_color), cmd); // list background Hitbox2D itemlist_box = GetHitbox_ListArea(); - wiImage::Draw(wiTextureHelper::getWhite() - , wiImageParams(itemlist_box.pos.x, itemlist_box.pos.y, itemlist_box.siz.x, itemlist_box.siz.y, colors[IDLE].toFloat4()), cmd); + fx.pos = XMFLOAT3(itemlist_box.pos.x, itemlist_box.pos.y, 0); + fx.siz = XMFLOAT2(itemlist_box.siz.x, itemlist_box.siz.y); + wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); Rect rect_without_scrollbar; rect_without_scrollbar.left = (int)itemlist_box.pos.x; @@ -2729,7 +2780,7 @@ void wiTreeList::Render(const wiGUI* gui, CommandList cmd) const { wiImage::Draw(wiTextureHelper::getWhite() , wiImageParams(name_box.pos.x, name_box.pos.y, name_box.siz.x, name_box.siz.y, - colors[item.selected ? FOCUS : IDLE].toFloat4()), cmd); + sprites[item.selected ? FOCUS : IDLE].params.color), cmd); } // opened flag triangle: @@ -2737,7 +2788,7 @@ void wiTreeList::Render(const wiGUI* gui, CommandList cmd) const device->BindPipelineState(&PSO_colored, cmd); MiscCB cb; - cb.g_xColor = colors[opener_highlight == i ? ACTIVE : FOCUS].toFloat4(); + cb.g_xColor = opener_highlight == i ? wiColor::White().toFloat4() : sprites[FOCUS].params.color; XMStoreFloat4x4(&cb.g_xTransform, XMMatrixScaling(item_height * 0.3f, item_height * 0.3f, 1) * XMMatrixRotationZ(item.open ? XM_PIDIV2 : 0) * XMMatrixTranslation(open_box.pos.x + open_box.siz.x * 0.5f, open_box.pos.y + open_box.siz.y * 0.25f, 0) * @@ -2758,7 +2809,7 @@ void wiTreeList::Render(const wiGUI* gui, CommandList cmd) const // Item name text: wiFont(item.name, wiFontParams((int)name_box.pos.x + 1, (int)(name_box.pos.y + name_box.siz.y * 0.5f), WIFONTSIZE_DEFAULT, WIFALIGN_LEFT, WIFALIGN_CENTER, 0, 0, - fontParams.color, fontParams.shadowColor)).Draw(cmd); + font.params.color, font.params.shadowColor)).Draw(cmd); } } void wiTreeList::OnSelect(function func) diff --git a/WickedEngine/wiWidget.h b/WickedEngine/wiWidget.h index 4a593366d..2095b37e9 100644 --- a/WickedEngine/wiWidget.h +++ b/WickedEngine/wiWidget.h @@ -7,6 +7,7 @@ #include "wiIntersect.h" #include "wiScene.h" #include "wiFont.h" +#include "wiSprite.h" #include #include @@ -42,30 +43,22 @@ private: int tooltipTimer = 0; protected: wiHashString fastName; - std::string text; std::string tooltip; std::string scriptTip; bool enabled = true; bool visible = true; + uint32_t foregroundPriority = 0; WIDGETSTATE state = IDLE; void Activate(); void Deactivate(); - wiColor colors[WIDGETSTATE_COUNT] = { - wiColor::Booger(), - wiColor::Gray(), - wiColor::White(), - wiColor::Gray(), - }; - static_assert(arraysize(colors) == WIDGETSTATE_COUNT, "Every WIDGETSTATE needs a default color!"); - - wiFontParams fontParams = wiFontParams(0, 0, WIFONTSIZE_DEFAULT, WIFALIGN_LEFT, WIFALIGN_TOP, 0, 0, wiColor::White(), wiColor::Black()); - public: + wiWidget(); + const wiHashString& GetName() const; void SetName(const std::string& value); - const std::string& GetText() const; + const std::string GetText() const; void SetText(const std::string& value); void SetTooltip(const std::string& value); void SetScriptTip(const std::string& value); @@ -79,15 +72,14 @@ public: // last param default: set color for all states void SetColor(wiColor color, WIDGETSTATE state = WIDGETSTATE_COUNT); wiColor GetColor() const; - void SetTextColor(wiColor value) { fontParams.color = value; } - void SetTextShadowColor(wiColor value) { fontParams.shadowColor = value; } - void SetFontParams(wiFontParams params) { fontParams = params; } - const wiFontParams& GetFontParams() const { return fontParams; } virtual void Update(wiGUI* gui, float dt); virtual void Render(const wiGUI* gui, wiGraphics::CommandList cmd) const = 0; virtual void RenderTooltip(const wiGUI* gui, wiGraphics::CommandList cmd) const; + wiSprite sprites[WIDGETSTATE_COUNT]; + wiFont font; + XMFLOAT3 translation = XMFLOAT3(0, 0, 0); XMFLOAT3 scale = XMFLOAT3(1, 1, 1); @@ -136,21 +128,20 @@ class wiTextInputField : public wiWidget { protected: std::function onInputAccepted; + static wiFont font_input; - std::string value; - static std::string value_new; - - std::string description; public: wiTextInputField(const std::string& name = ""); virtual ~wiTextInputField(); + wiFont font_description; + void SetValue(const std::string& newValue); void SetValue(int newValue); void SetValue(float newValue); - const std::string& GetValue(); - void SetDescription(const std::string& desc) { description = desc; } - const std::string& GetDescription() const { return description; } + const std::string GetValue(); + void SetDescription(const std::string& desc) { font_description.SetText(desc); } + const std::string GetDescription() const { return font_description.GetTextA(); } // There can only be ONE active text input field, so these methods modify the active one static void AddInput(const char inputChar); @@ -171,17 +162,6 @@ protected: float step = 1000; float value = 0; - wiColor colors_base[WIDGETSTATE_COUNT] = { - wiColor(60, 60, 60, 200), - wiColor(50, 50, 50, 200), - wiColor(50, 50, 50, 200), - wiColor(60, 60, 60, 200), - }; - static_assert(arraysize(colors_base) == WIDGETSTATE_COUNT, "Every WIDGETSTATE needs a default color!"); - - // width of the head of the slider that can be grabbed: - float headWidth = 16; - wiTextInputField* valueInputField = nullptr; public: // start : slider minimum value @@ -191,6 +171,8 @@ public: wiSlider(float start = 0.0f, float end = 1.0f, float defaultValue = 0.5f, float step = 1000.0f, const std::string& name = ""); virtual ~wiSlider(); + wiSprite sprites_knob[WIDGETSTATE_COUNT]; + void SetValue(float value); float GetValue(); void SetRange(float start, float end); @@ -199,11 +181,6 @@ public: void Render(const wiGUI* gui, wiGraphics::CommandList cmd) const override; void RenderTooltip(const wiGUI* gui, wiGraphics::CommandList cmd) const override; - // Sets colors for the base (or "path") of the slider - // last param default: set color for all states - void SetBaseColor(wiColor color, WIDGETSTATE state = WIDGETSTATE_COUNT); - void SetHeadWidth(float value) { headWidth = value; } - void OnSlide(std::function func); }; @@ -217,6 +194,8 @@ public: wiCheckBox(const std::string& name = ""); virtual ~wiCheckBox(); + wiSprite sprites_check[WIDGETSTATE_COUNT]; + void SetCheck(bool value); bool GetCheck() const; @@ -307,7 +286,12 @@ class wiColorPicker : public wiWindow { protected: std::function onColorChanged; - bool huefocus = false; // whether the hue picker is in focus or the saturation + enum COLORPICKERSTATE + { + CPS_IDLE, + CPS_HUE, + CPS_SATURATION, + } colorpickerstate = CPS_IDLE; float hue = 0.0f; // [0, 360] degrees float saturation = 0.0f; // [0, 1] float luminance = 1.0f; // [0, 1]