diff --git a/Content/logo_small.png b/Content/logo_small.png index 9f69ce056..d495bdade 100644 Binary files a/Content/logo_small.png and b/Content/logo_small.png differ diff --git a/Editor/PaintToolWindow.cpp b/Editor/PaintToolWindow.cpp index 5435a48a2..804500565 100644 --- a/Editor/PaintToolWindow.cpp +++ b/Editor/PaintToolWindow.cpp @@ -16,7 +16,7 @@ void PaintToolWindow::Create(EditorComponent* editor) wi::gui::Window::Create("Paint Tool Window"); SetSize(XMFLOAT2(410, 610)); - float x = 100; + float x = 105; float y = 0; float hei = 20; float step = hei + 4; @@ -38,8 +38,6 @@ void PaintToolWindow::Create(EditorComponent* editor) modeComboBox.AddItem("Wind weight (Alpha)"); modeComboBox.SetSelected(0); modeComboBox.OnSelect([&](wi::gui::EventArgs args) { - textureSlotComboBox.SetEnabled(false); - saveTextureButton.SetEnabled(false); switch (args.iValue) { case MODE_DISABLED: @@ -47,8 +45,6 @@ void PaintToolWindow::Create(EditorComponent* editor) break; case MODE_TEXTURE: infoLabel.SetText("In texture paint mode, you can paint on textures. Brush will be applied in texture space.\nREMEMBER to save texture when finished to save texture file!\nREMEMBER to save scene to retain new texture bindings on materials!"); - textureSlotComboBox.SetEnabled(true); - saveTextureButton.SetEnabled(true); break; case MODE_VERTEXCOLOR: infoLabel.SetText("In vertex color mode, you can paint colors on selected geometry (per vertex). \"Use vertex colors\" will be automatically enabled for the selected material, or all materials if the whole object is selected. If there is no vertexcolors vertex buffer, one will be created with white as default for every vertex."); @@ -135,6 +131,12 @@ void PaintToolWindow::Create(EditorComponent* editor) pressureCheckBox.SetCheck(false); AddWidget(&pressureCheckBox); + colorPicker.Create("Color", false); + colorPicker.SetPos(XMFLOAT2(10, y += step)); + AddWidget(&colorPicker); + + y += colorPicker.GetScale().y; + textureSlotComboBox.Create("Texture Slot: "); textureSlotComboBox.SetTooltip("Choose texture slot of the selected material to paint (texture paint mode only)"); textureSlotComboBox.SetPos(XMFLOAT2(x, y += step)); @@ -152,14 +154,12 @@ void PaintToolWindow::Create(EditorComponent* editor) textureSlotComboBox.AddItem("ClearcoatRoughMap (R)", MaterialComponent::CLEARCOATROUGHNESSMAP); textureSlotComboBox.AddItem("ClearcoatNormMap (R)", MaterialComponent::CLEARCOATNORMALMAP); textureSlotComboBox.SetSelected(0); - textureSlotComboBox.SetEnabled(false); AddWidget(&textureSlotComboBox); saveTextureButton.Create("Save Texture"); saveTextureButton.SetTooltip("Save edited texture."); saveTextureButton.SetSize(XMFLOAT2(200, hei)); saveTextureButton.SetPos(XMFLOAT2(x, y += step)); - saveTextureButton.SetEnabled(false); saveTextureButton.OnClick([this] (wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); @@ -192,9 +192,67 @@ void PaintToolWindow::Create(EditorComponent* editor) }); AddWidget(&saveTextureButton); - colorPicker.Create("Color", false); - colorPicker.SetPos(XMFLOAT2(10, y += step)); - AddWidget(&colorPicker); + brushTextureButton.Create(""); + brushTextureButton.SetDescription("Brush tex: "); + brushTextureButton.SetTooltip("Open an image to use as brush texture (splatting mode).\nSplat mode means that the texture will be relative to the brush position"); + brushTextureButton.SetSize(XMFLOAT2(hei*2, hei*2)); + brushTextureButton.SetPos(XMFLOAT2(x, y += step)); + brushTextureButton.sprites[wi::gui::IDLE].params.color = wi::Color::White(); + brushTextureButton.sprites[wi::gui::FOCUS].params.color = wi::Color::Gray(); + brushTextureButton.sprites[wi::gui::ACTIVE].params.color = wi::Color::White(); + brushTextureButton.sprites[wi::gui::DEACTIVATING].params.color = wi::Color::Gray(); + brushTextureButton.OnClick([this](wi::gui::EventArgs args) { + if (brushTex.IsValid()) + { + brushTex = {}; + brushTextureButton.SetImage({}); + } + else + { + wi::helper::FileDialogParams params; + params.type = wi::helper::FileDialogParams::OPEN; + params.description = "Texture"; + params.extensions = wi::resourcemanager::GetSupportedImageExtensions(); + wi::helper::FileDialog(params, [this](std::string fileName) { + wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { + brushTex = wi::resourcemanager::Load(fileName); + brushTextureButton.SetImage(brushTex); + }); + }); + } + }); + AddWidget(&brushTextureButton); + + revealTextureButton.Create(""); + revealTextureButton.SetDescription("Reveal tex: "); + revealTextureButton.SetTooltip("Open an image to use as reveal mode texture.\nReveal mode means that the texture will use the UV of the mesh. It will be multiplied by brush tex."); + revealTextureButton.SetSize(XMFLOAT2(hei * 2, hei * 2)); + revealTextureButton.SetPos(XMFLOAT2(x + 150, y)); + revealTextureButton.sprites[wi::gui::IDLE].params.color = wi::Color::White(); + revealTextureButton.sprites[wi::gui::FOCUS].params.color = wi::Color::Gray(); + revealTextureButton.sprites[wi::gui::ACTIVE].params.color = wi::Color::White(); + revealTextureButton.sprites[wi::gui::DEACTIVATING].params.color = wi::Color::Gray(); + revealTextureButton.OnClick([this](wi::gui::EventArgs args) { + if (revealTex.IsValid()) + { + revealTex = {}; + revealTextureButton.SetImage({}); + } + else + { + wi::helper::FileDialogParams params; + params.type = wi::helper::FileDialogParams::OPEN; + params.description = "Texture"; + params.extensions = wi::resourcemanager::GetSupportedImageExtensions(); + wi::helper::FileDialog(params, [this](std::string fileName) { + wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { + revealTex = wi::resourcemanager::Load(fileName); + revealTextureButton.SetImage(revealTex); + }); + }); + } + }); + AddWidget(&revealTextureButton); Translate(XMFLOAT3((float)editor->GetLogicalWidth() - 550, 50, 0)); SetVisible(false); @@ -204,6 +262,21 @@ void PaintToolWindow::Update(float dt) { RecordHistory(false); + if (GetMode() == MODE_TEXTURE) + { + textureSlotComboBox.SetVisible(true); + saveTextureButton.SetVisible(true); + brushTextureButton.SetVisible(true); + revealTextureButton.SetVisible(true); + } + else + { + textureSlotComboBox.SetVisible(false); + saveTextureButton.SetVisible(false); + brushTextureButton.SetVisible(false); + revealTextureButton.SetVisible(false); + } + rot -= dt; // by default, paint tool is on center of screen, this makes it easy to tweak radius with GUI: XMFLOAT2 posNew; @@ -308,7 +381,22 @@ void PaintToolWindow::Update(float dt) device->BindComputeShader(wi::renderer::GetShader(wi::enums::CSTYPE_PAINT_TEXTURE), cmd); - device->BindResource(wi::texturehelper::getWhite(), 0, cmd); + if (brushTex.IsValid()) + { + device->BindResource(&brushTex.GetTexture(), 0, cmd); + } + else + { + device->BindResource(wi::texturehelper::getWhite(), 0, cmd); + } + if (revealTex.IsValid()) + { + device->BindResource(&revealTex.GetTexture(), 1, cmd); + } + else + { + device->BindResource(wi::texturehelper::getWhite(), 1, cmd); + } device->BindUAV(&editTexture, 0, cmd); PaintTextureCB cb; @@ -317,6 +405,7 @@ void PaintToolWindow::Update(float dt) cb.xPaintBrushAmount = amount; cb.xPaintBrushFalloff = falloff; cb.xPaintBrushColor = color.rgba; + cb.xPaintReveal = revealTex.IsValid() ? 1 : 0; device->PushConstants(&cb, sizeof(cb), cmd); const uint diameter = cb.xPaintBrushRadius * 2; @@ -992,6 +1081,7 @@ void PaintToolWindow::RecordHistory(bool start, CommandList cmd) Texture newTex; TextureDesc desc = editTexture.GetDesc(); desc.format = Format::R8G8B8A8_UNORM; // force format to one that is writable by GPU + desc.bind_flags |= BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS; device->CreateTexture(&desc, nullptr, &newTex); for (uint32_t i = 0; i < newTex.GetDesc().mip_levels; ++i) { diff --git a/Editor/PaintToolWindow.h b/Editor/PaintToolWindow.h index 0f47d4318..857539a9d 100644 --- a/Editor/PaintToolWindow.h +++ b/Editor/PaintToolWindow.h @@ -22,6 +22,9 @@ class PaintToolWindow : public wi::gui::Window wi::vector sculpting_indices; XMFLOAT3 sculpting_normal = XMFLOAT3(0, 0, 0); + wi::Resource brushTex; + wi::Resource revealTex; + public: void Create(EditorComponent* editor); @@ -41,6 +44,8 @@ public: wi::gui::ColorPicker colorPicker; wi::gui::ComboBox textureSlotComboBox; wi::gui::Button saveTextureButton; + wi::gui::Button brushTextureButton; + wi::gui::Button revealTextureButton; void Update(float dt); void DrawBrush() const; diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index 532823a97..91c983375 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -779,7 +779,8 @@ struct PaintTextureCB float xPaintBrushFalloff; uint xPaintBrushColor; - uint2 padding0; + uint xPaintReveal; + uint padding0; }; CBUFFER(PaintRadiusCB, CBSLOT_RENDERER_MISC) diff --git a/WickedEngine/shaders/paint_textureCS.hlsl b/WickedEngine/shaders/paint_textureCS.hlsl index eda31bbb7..9e9b29b38 100644 --- a/WickedEngine/shaders/paint_textureCS.hlsl +++ b/WickedEngine/shaders/paint_textureCS.hlsl @@ -4,6 +4,7 @@ PUSHCONSTANT(push, PaintTextureCB); Texture2D texture_brush : register(t0); +Texture2D texture_reveal : register(t1); RWTexture2D output : register(u0); @@ -11,12 +12,31 @@ RWTexture2D output : register(u0); void main( uint3 DTid : SV_DispatchThreadID ) { const uint2 pixel = push.xPaintBrushCenter + DTid.xy - push.xPaintBrushRadius.xx; - const float2 uv = (DTid.xy + 0.5f) / push.xPaintBrushRadius.xx; - const float4 color = texture_brush.SampleLevel(sampler_linear_clamp, uv, 0) * unpack_rgba(push.xPaintBrushColor); + + const float2 brush_uv = (DTid.xy + 0.5) / (push.xPaintBrushRadius.xx * 2); + const float2 brush_uv_quad_x = QuadReadAcrossX(brush_uv); + const float2 brush_uv_quad_y = QuadReadAcrossY(brush_uv); + const float2 brush_uv_dx = brush_uv - brush_uv_quad_x; + const float2 brush_uv_dy = brush_uv - brush_uv_quad_y; + float4 brush_color = texture_brush.SampleGrad(sampler_linear_clamp, brush_uv, brush_uv_dx, brush_uv_dy) * unpack_rgba(push.xPaintBrushColor); + + float2 dim; + output.GetDimensions(dim.x, dim.y); + const float2 reveal_uv = (pixel + 0.5) / dim; + const float2 reveal_uv_quad_x = QuadReadAcrossX(reveal_uv); + const float2 reveal_uv_quad_y = QuadReadAcrossY(reveal_uv); + const float2 reveal_uv_dx = reveal_uv - reveal_uv_quad_x; + const float2 reveal_uv_dy = reveal_uv - reveal_uv_quad_y; + float4 reveal_color = texture_reveal.SampleGrad(sampler_linear_clamp, reveal_uv, reveal_uv_dx, reveal_uv_dy); + const float dist = distance((float2)pixel, (float2)push.xPaintBrushCenter); const float affection = push.xPaintBrushAmount * pow(1 - saturate(dist / (float)push.xPaintBrushRadius), push.xPaintBrushFalloff); if (affection > 0 && dist < (float)push.xPaintBrushRadius) { - output[pixel] = lerp(output[pixel], color, affection); + if (push.xPaintReveal) + { + brush_color *= reveal_color; + } + output[pixel] = lerp(output[pixel], brush_color, affection); } } diff --git a/WickedEngine/wiFont.cpp b/WickedEngine/wiFont.cpp index fb20b9572..096bb972d 100644 --- a/WickedEngine/wiFont.cpp +++ b/WickedEngine/wiFont.cpp @@ -134,7 +134,6 @@ namespace wi::font } }; - cursor.size.y = LINEBREAK_SIZE; int code_prev = 0; for (size_t i = 0; i < text_length; ++i) { @@ -213,7 +212,7 @@ namespace wi::font } cursor.size.x = std::max(cursor.size.x, cursor.pos.x); - cursor.size.y = std::max(cursor.size.y, cursor.pos.y); + cursor.size.y = std::max(cursor.size.y, cursor.pos.y + LINEBREAK_SIZE); } word_wrap(); diff --git a/WickedEngine/wiGUI.cpp b/WickedEngine/wiGUI.cpp index 8daf657aa..7b6cd6ba8 100644 --- a/WickedEngine/wiGUI.cpp +++ b/WickedEngine/wiGUI.cpp @@ -560,6 +560,9 @@ namespace wi::gui font.params.h_align = wi::font::WIFALIGN_CENTER; font.params.v_align = wi::font::WIFALIGN_CENTER; + + font_description.params = font.params; + font_description.params.h_align = wi::font::WIFALIGN_RIGHT; } void Button::Update(const wi::Canvas& canvas, float dt) { @@ -679,6 +682,9 @@ namespace wi::gui font.params.posY = translation.y + scale.y * 0.5f; break; } + + font_description.params.posX = translation.x - 2; + font_description.params.posY = translation.y + scale.y * 0.5f; } void Button::Render(const wi::Canvas& canvas, CommandList cmd) const { @@ -687,7 +693,7 @@ namespace wi::gui return; } - wi::Color color = GetColor(); + font_description.Draw(cmd); ApplyScissor(canvas, scissorRect, cmd); @@ -1118,8 +1124,6 @@ namespace wi::gui return; } - wi::Color color = GetColor(); - font_description.Draw(cmd); ApplyScissor(canvas, scissorRect, cmd); diff --git a/WickedEngine/wiGUI.h b/WickedEngine/wiGUI.h index d67967927..10a4d40f1 100644 --- a/WickedEngine/wiGUI.h +++ b/WickedEngine/wiGUI.h @@ -143,6 +143,9 @@ namespace wi::gui public: void Create(const std::string& name); + wi::SpriteFont font_description; + void SetDescription(const std::string& desc) { font_description.SetText(desc); } + void Update(const wi::Canvas& canvas, float dt) override; void Render(const wi::Canvas& canvas, wi::graphics::CommandList cmd) const override; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index fa11f9f19..36871e139 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 60; // minor bug fixes, alterations, refactors, updates - const int revision = 72; + const int revision = 73; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);