editor: paint tool - vertexpaint, hairlength #94; hairparticle update;
This commit is contained in:
+6
-191
@@ -793,6 +793,7 @@ void EditorComponent::Update(float dt)
|
||||
|
||||
animWnd->Update();
|
||||
weatherWnd->Update();
|
||||
paintToolWnd->Update(dt);
|
||||
|
||||
selectionOutlineTimer += dt;
|
||||
|
||||
@@ -888,16 +889,8 @@ void EditorComponent::Update(float dt)
|
||||
cinemaModeCheckBox->SetCheck(false);
|
||||
}
|
||||
|
||||
// by default, paint tool is on center of screen, this makes it easy to tweak radius with GUI:
|
||||
paintToolWnd->pos.x = wiRenderer::GetDevice()->GetScreenWidth() * 0.5f;
|
||||
paintToolWnd->pos.y = wiRenderer::GetDevice()->GetScreenHeight() * 0.5f;
|
||||
|
||||
if (!wiBackLog::isActive() && !GetGUI().HasFocus())
|
||||
{
|
||||
XMFLOAT4 currentMouse = wiInput::GetPointer();
|
||||
paintToolWnd->pos.x = currentMouse.x;
|
||||
paintToolWnd->pos.y = currentMouse.y;
|
||||
|
||||
// Camera control:
|
||||
static XMFLOAT4 originalMouse = XMFLOAT4(0, 0, 0, 0);
|
||||
static bool camControlStart = true;
|
||||
@@ -906,6 +899,7 @@ void EditorComponent::Update(float dt)
|
||||
originalMouse = wiInput::GetPointer();
|
||||
}
|
||||
|
||||
XMFLOAT4 currentMouse = wiInput::GetPointer();
|
||||
float xDif = 0, yDif = 0;
|
||||
|
||||
if (wiInput::Down(wiInput::MOUSE_BUTTON_MIDDLE))
|
||||
@@ -1195,189 +1189,8 @@ void EditorComponent::Update(float dt)
|
||||
|
||||
}
|
||||
|
||||
// Use Paint Tool or interact, but not both:
|
||||
if (paintToolWnd->GetMode() != PaintToolWindow::MODE_DISABLED)
|
||||
{
|
||||
auto mode = paintToolWnd->GetMode();
|
||||
switch (mode)
|
||||
{
|
||||
case PaintToolWindow::MODE_SOFTBODY_PINNING:
|
||||
case PaintToolWindow::MODE_SOFTBODY_PHYSICS:
|
||||
{
|
||||
for (size_t i = 0; i < scene.softbodies.GetCount(); ++i)
|
||||
{
|
||||
SoftBodyPhysicsComponent& softbody = scene.softbodies[i];
|
||||
if (softbody.vertex_positions_simulation.empty())
|
||||
continue;
|
||||
|
||||
// Painting:
|
||||
if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
const float radius = paintToolWnd->GetRadius();
|
||||
const XMVECTOR C = XMLoadFloat2(&paintToolWnd->pos);
|
||||
const XMMATRIX VP = camera.GetViewProjection();
|
||||
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
|
||||
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
|
||||
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
|
||||
size_t j = 0;
|
||||
for (auto& ind : softbody.physicsToGraphicsVertexMapping)
|
||||
{
|
||||
XMVECTOR P = softbody.vertex_positions_simulation[ind].LoadPOS();
|
||||
P = XMVector3TransformCoord(P, VP);
|
||||
P = P * MUL + ADD;
|
||||
P = P * SCREEN;
|
||||
const float z = XMVectorGetZ(P);
|
||||
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
|
||||
{
|
||||
softbody.weights[j] = (mode == PaintToolWindow::MODE_SOFTBODY_PINNING ? 0.0f : 1.0f);
|
||||
softbody._flags |= SoftBodyPhysicsComponent::FORCE_RESET;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// Visualizing:
|
||||
Entity entity = scene.softbodies.GetEntity(i);
|
||||
const MeshComponent& mesh = *scene.meshes.GetComponent(entity);
|
||||
const XMMATRIX W = XMLoadFloat4x4(&softbody.worldMatrix);
|
||||
for (size_t j = 0; j < mesh.indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t graphicsIndex0 = mesh.indices[j + 0];
|
||||
const uint32_t graphicsIndex1 = mesh.indices[j + 1];
|
||||
const uint32_t graphicsIndex2 = mesh.indices[j + 2];
|
||||
const uint32_t physicsIndex0 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex0];
|
||||
const uint32_t physicsIndex1 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex1];
|
||||
const uint32_t physicsIndex2 = softbody.graphicsToPhysicsVertexMapping[graphicsIndex2];
|
||||
const float weight0 = softbody.weights[physicsIndex0];
|
||||
const float weight1 = softbody.weights[physicsIndex1];
|
||||
const float weight2 = softbody.weights[physicsIndex2];
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
if (softbody.vertex_positions_simulation.empty())
|
||||
{
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex0]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex1]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh.vertex_positions[graphicsIndex2]), W));
|
||||
}
|
||||
else
|
||||
{
|
||||
tri.positionA = softbody.vertex_positions_simulation[graphicsIndex0].pos;
|
||||
tri.positionB = softbody.vertex_positions_simulation[graphicsIndex1].pos;
|
||||
tri.positionC = softbody.vertex_positions_simulation[graphicsIndex2].pos;
|
||||
}
|
||||
if (weight0 == 0)
|
||||
tri.colorA = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorA = XMFLOAT4(1, 1, 1, 0.5f);
|
||||
if (weight1 == 0)
|
||||
tri.colorB = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorB = XMFLOAT4(1, 1, 1, 0.5f);
|
||||
if (weight2 == 0)
|
||||
tri.colorC = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorC = XMFLOAT4(1, 1, 1, 0.5f);
|
||||
wiRenderer::DrawTriangle(tri, true);
|
||||
if (weight0 == 0 && weight1 == 0 && weight2 == 0)
|
||||
{
|
||||
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 0, 0.8f);
|
||||
wiRenderer::DrawTriangle(tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PaintToolWindow::MODE_HAIRPARTICLE_ADD_TRIANGLE:
|
||||
case PaintToolWindow::MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
|
||||
{
|
||||
for (size_t i = 0; i < scene.hairs.GetCount(); ++i)
|
||||
{
|
||||
wiHairParticle& hair = scene.hairs[i];
|
||||
if (hair.meshID == INVALID_ENTITY)
|
||||
continue;
|
||||
|
||||
MeshComponent* mesh = scene.meshes.GetComponent(hair.meshID);
|
||||
if (mesh == nullptr)
|
||||
continue;
|
||||
|
||||
Entity entity = scene.hairs.GetEntity(i);
|
||||
const TransformComponent* transform = scene.transforms.GetComponent(entity);
|
||||
if (transform == nullptr)
|
||||
continue;
|
||||
|
||||
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
|
||||
const bool painting = wiInput::Down(wiInput::MOUSE_BUTTON_LEFT);
|
||||
|
||||
const float radius = paintToolWnd->GetRadius();
|
||||
const XMVECTOR C = XMLoadFloat2(&paintToolWnd->pos);
|
||||
const XMMATRIX VP = camera.GetViewProjection();
|
||||
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
|
||||
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
|
||||
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
|
||||
for (size_t j = 0; j < mesh->indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t triangle[] = {
|
||||
mesh->indices[j + 0],
|
||||
mesh->indices[j + 1],
|
||||
mesh->indices[j + 2],
|
||||
};
|
||||
|
||||
if (painting)
|
||||
{
|
||||
bool hit = false;
|
||||
for (int k = 0; k < arraysize(triangle); ++k)
|
||||
{
|
||||
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
|
||||
XMVECTOR P = XMLoadFloat3(&pos);
|
||||
P = XMVector3Transform(P, W);
|
||||
P = XMVector3TransformCoord(P, VP);
|
||||
P = P * MUL + ADD;
|
||||
P = P * SCREEN;
|
||||
const float z = XMVectorGetZ(P);
|
||||
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
|
||||
{
|
||||
if (mode == PaintToolWindow::MODE_HAIRPARTICLE_ADD_TRIANGLE)
|
||||
{
|
||||
hair.vertex_lengths[triangle[k]] = 1.0f;
|
||||
}
|
||||
else if (mode == PaintToolWindow::MODE_HAIRPARTICLE_REMOVE_TRIANGLE)
|
||||
{
|
||||
hair.vertex_lengths[triangle[k]] = 0;
|
||||
}
|
||||
hair._flags |= wiHairParticle::REBUILD_BUFFERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
|
||||
wiRenderer::DrawTriangle(tri, true);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < hair.indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t triangle[] = {
|
||||
hair.indices[j + 0],
|
||||
hair.indices[j + 1],
|
||||
hair.indices[j + 2],
|
||||
};
|
||||
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
|
||||
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 1, 0.9f);
|
||||
wiRenderer::DrawTriangle(tri, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
// Interactions only when paint tool is disabled:
|
||||
if (paintToolWnd->GetMode() == PaintToolWindow::MODE_DISABLED)
|
||||
{
|
||||
// Interact:
|
||||
if (hovered.entity != INVALID_ENTITY)
|
||||
@@ -1625,6 +1438,7 @@ void EditorComponent::Update(float dt)
|
||||
envProbeWnd->SetEntity(INVALID_ENTITY);
|
||||
forceFieldWnd->SetEntity(INVALID_ENTITY);
|
||||
cameraWnd->SetEntity(INVALID_ENTITY);
|
||||
paintToolWnd->SetEntity(INVALID_ENTITY);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1650,6 +1464,7 @@ void EditorComponent::Update(float dt)
|
||||
envProbeWnd->SetEntity(picked.entity);
|
||||
forceFieldWnd->SetEntity(picked.entity);
|
||||
cameraWnd->SetEntity(picked.entity);
|
||||
paintToolWnd->SetEntity(picked.entity);
|
||||
|
||||
if (picked.subsetIndex >= 0)
|
||||
{
|
||||
|
||||
@@ -158,17 +158,6 @@ MaterialWindow::MaterialWindow(wiGUI* gui) : GUI(gui)
|
||||
});
|
||||
materialWindow->AddWidget(metalnessSlider);
|
||||
|
||||
alphaSlider = new wiSlider(0, 1, 1.0f, 1000, "Alpha: ");
|
||||
alphaSlider->SetTooltip("Adjusts the overall transparency of the surface. No effect when BlendMode is set to OPAQUE.");
|
||||
alphaSlider->SetSize(XMFLOAT2(100, 30));
|
||||
alphaSlider->SetPos(XMFLOAT2(x, y += step));
|
||||
alphaSlider->OnSlide([&](wiEventArgs args) {
|
||||
MaterialComponent* material = wiScene::GetScene().materials.GetComponent(entity);
|
||||
if (material != nullptr)
|
||||
material->SetOpacity(args.fValue);
|
||||
});
|
||||
materialWindow->AddWidget(alphaSlider);
|
||||
|
||||
alphaRefSlider = new wiSlider(0, 1, 1.0f, 1000, "AlphaRef: ");
|
||||
alphaRefSlider->SetTooltip("Adjust the alpha cutoff threshold. Some performance optimizations will be disabled.");
|
||||
alphaRefSlider->SetSize(XMFLOAT2(100, 30));
|
||||
@@ -311,8 +300,7 @@ MaterialWindow::MaterialWindow(wiGUI* gui) : GUI(gui)
|
||||
MaterialComponent* material = wiScene::GetScene().materials.GetComponent(entity);
|
||||
if (material != nullptr)
|
||||
{
|
||||
XMFLOAT3 col = args.color.toFloat3();
|
||||
material->SetBaseColor(XMFLOAT4(col.x, col.y, col.z, material->GetOpacity()));
|
||||
material->SetBaseColor(args.color.toFloat4());
|
||||
}
|
||||
});
|
||||
materialWindow->AddWidget(baseColorPicker);
|
||||
@@ -791,7 +779,6 @@ void MaterialWindow::SetEntity(Entity entity)
|
||||
roughnessSlider->SetValue(material->roughness);
|
||||
reflectanceSlider->SetValue(material->reflectance);
|
||||
metalnessSlider->SetValue(material->metalness);
|
||||
alphaSlider->SetValue(material->GetOpacity());
|
||||
refractionIndexSlider->SetValue(material->refractionIndex);
|
||||
emissiveSlider->SetValue(material->emissiveColor.w);
|
||||
sssSlider->SetValue(material->subsurfaceScattering);
|
||||
@@ -807,7 +794,7 @@ void MaterialWindow::SetEntity(Entity entity)
|
||||
baseColorPicker->SetEnabled(true);
|
||||
baseColorPicker->SetPickColor(wiColor::fromFloat4(material->baseColor));
|
||||
emissiveColorPicker->SetEnabled(true);
|
||||
emissiveColorPicker->SetPickColor(wiColor::fromFloat4(material->emissiveColor));
|
||||
emissiveColorPicker->SetPickColor(wiColor::fromFloat3(XMFLOAT3(material->emissiveColor.x, material->emissiveColor.y, material->emissiveColor.z)));
|
||||
blendModeComboBox->SetSelected((int)material->userBlendMode);
|
||||
shaderTypeComboBox->SetSelected(max(0, material->GetCustomShaderID() + 1));
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
wiSlider* roughnessSlider;
|
||||
wiSlider* reflectanceSlider;
|
||||
wiSlider* metalnessSlider;
|
||||
wiSlider* alphaSlider;
|
||||
wiSlider* refractionIndexSlider;
|
||||
wiSlider* emissiveSlider;
|
||||
wiSlider* sssSlider;
|
||||
|
||||
+345
-9
@@ -1,7 +1,8 @@
|
||||
#include "stdafx.h"
|
||||
#include "PaintToolWindow.h"
|
||||
#include "wiRenderer.h"
|
||||
|
||||
using namespace wiECS;
|
||||
using namespace wiScene;
|
||||
using namespace wiGraphics;
|
||||
|
||||
PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
|
||||
@@ -9,7 +10,7 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
|
||||
assert(GUI && "Invalid GUI!");
|
||||
|
||||
window = new wiWindow(GUI, "Paint Tool Window");
|
||||
window->SetSize(XMFLOAT2(400, 300));
|
||||
window->SetSize(XMFLOAT2(400, 500));
|
||||
GUI->AddWidget(window);
|
||||
|
||||
float x = 100;
|
||||
@@ -21,10 +22,12 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
|
||||
modeComboBox->SetPos(XMFLOAT2(x, y += step));
|
||||
modeComboBox->SetSize(XMFLOAT2(200, 28));
|
||||
modeComboBox->AddItem("Disabled");
|
||||
modeComboBox->AddItem("Vertexcolor");
|
||||
modeComboBox->AddItem("Softbody - Pinning");
|
||||
modeComboBox->AddItem("Softbody - Physics");
|
||||
modeComboBox->AddItem("Hairparticle - Add Triangle");
|
||||
modeComboBox->AddItem("Hairparticle - Remove Triangle");
|
||||
modeComboBox->AddItem("Hairparticle - Length (Alpha)");
|
||||
modeComboBox->SetSelected(0);
|
||||
window->AddWidget(modeComboBox);
|
||||
|
||||
@@ -36,6 +39,27 @@ PaintToolWindow::PaintToolWindow(wiGUI* gui) : GUI(gui)
|
||||
radiusSlider->SetPos(XMFLOAT2(x, y += step));
|
||||
window->AddWidget(radiusSlider);
|
||||
|
||||
amountSlider = new wiSlider(0, 1, 1, 10000, "Brush Amount: ");
|
||||
amountSlider->SetTooltip("Set the brush amount. 0 = minimum affection, 1 = maximum affection");
|
||||
amountSlider->SetSize(XMFLOAT2(200, 20));
|
||||
amountSlider->SetPos(XMFLOAT2(x, y += step));
|
||||
window->AddWidget(amountSlider);
|
||||
|
||||
falloffSlider = new wiSlider(0, 16, 0, 10000, "Brush Falloff: ");
|
||||
falloffSlider->SetTooltip("Set the brush power. 0 = no falloff, 1 = linear falloff, more = falloff power");
|
||||
falloffSlider->SetSize(XMFLOAT2(200, 20));
|
||||
falloffSlider->SetPos(XMFLOAT2(x, y += step));
|
||||
window->AddWidget(falloffSlider);
|
||||
|
||||
backfaceCheckBox = new wiCheckBox("Backfaces: ");
|
||||
backfaceCheckBox->SetTooltip("Set whether to paint on backfaces of geometry or not");
|
||||
backfaceCheckBox->SetPos(XMFLOAT2(x, y += step));
|
||||
window->AddWidget(backfaceCheckBox);
|
||||
|
||||
colorPicker = new wiColorPicker(GUI, "Color", false);
|
||||
colorPicker->SetPos(XMFLOAT2(10, y += step));
|
||||
window->AddWidget(colorPicker);
|
||||
|
||||
window->Translate(XMFLOAT3((float)wiRenderer::GetDevice()->GetScreenWidth() - 550, 50, 0));
|
||||
window->SetVisible(false);
|
||||
}
|
||||
@@ -46,12 +70,326 @@ PaintToolWindow::~PaintToolWindow()
|
||||
delete window;
|
||||
}
|
||||
|
||||
void PaintToolWindow::DrawBrush() const
|
||||
void PaintToolWindow::Update(float dt)
|
||||
{
|
||||
if (GetMode() == MODE_DISABLED)
|
||||
rot -= dt;
|
||||
// by default, paint tool is on center of screen, this makes it easy to tweak radius with GUI:
|
||||
pos.x = wiRenderer::GetDevice()->GetScreenWidth() * 0.5f;
|
||||
pos.y = wiRenderer::GetDevice()->GetScreenHeight() * 0.5f;
|
||||
if (GUI->HasFocus() || wiBackLog::isActive() || entity == INVALID_ENTITY)
|
||||
return;
|
||||
|
||||
const float radius = GetRadius();
|
||||
auto pointer = wiInput::GetPointer();
|
||||
pos.x = pointer.x;
|
||||
pos.y = pointer.y;
|
||||
|
||||
const bool pointer_moved = wiMath::Distance(pos, posPrev) > 1.0f;
|
||||
const bool painting = pointer_moved && wiInput::Down(wiInput::MOUSE_BUTTON_LEFT);
|
||||
|
||||
if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
posPrev = pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
posPrev = XMFLOAT2(0, 0);
|
||||
}
|
||||
|
||||
const MODE mode = GetMode();
|
||||
const float radius = radiusSlider->GetValue();
|
||||
const float amount = amountSlider->GetValue();
|
||||
const float falloff = falloffSlider->GetValue();
|
||||
const wiColor color = colorPicker->GetPickColor();
|
||||
const XMFLOAT4 color_float = color.toFloat4();
|
||||
const bool backfaces = backfaceCheckBox->GetCheck();
|
||||
|
||||
Scene& scene = wiScene::GetScene();
|
||||
const CameraComponent& camera = wiRenderer::GetCamera();
|
||||
const XMVECTOR C = XMLoadFloat2(&pos);
|
||||
const XMMATRIX VP = camera.GetViewProjection();
|
||||
const XMVECTOR MUL = XMVectorSet(0.5f, -0.5f, 1, 1);
|
||||
const XMVECTOR ADD = XMVectorSet(0.5f, 0.5f, 0, 0);
|
||||
const XMVECTOR SCREEN = XMVectorSet((float)wiRenderer::GetDevice()->GetScreenWidth(), (float)wiRenderer::GetDevice()->GetScreenHeight(), 1, 1);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MODE_VERTEXCOLOR:
|
||||
{
|
||||
ObjectComponent* object = scene.objects.GetComponent(entity);
|
||||
if (object == nullptr || object->meshID == INVALID_ENTITY)
|
||||
break;
|
||||
|
||||
MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
|
||||
if (mesh == nullptr)
|
||||
break;
|
||||
|
||||
const TransformComponent* transform = scene.transforms.GetComponent(entity);
|
||||
if (transform == nullptr)
|
||||
break;
|
||||
|
||||
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
|
||||
|
||||
bool rebuild = false;
|
||||
for (size_t j = 0; j < mesh->indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t triangle[] = {
|
||||
mesh->indices[j + 0],
|
||||
mesh->indices[j + 1],
|
||||
mesh->indices[j + 2],
|
||||
};
|
||||
|
||||
if (painting)
|
||||
{
|
||||
XMVECTOR P[arraysize(triangle)];
|
||||
for (int k = 0; k < arraysize(triangle); ++k)
|
||||
{
|
||||
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
|
||||
P[k] = XMLoadFloat3(&pos);
|
||||
P[k] = XMVector3Transform(P[k], W);
|
||||
P[k] = XMVector3TransformCoord(P[k], VP);
|
||||
P[k] = P[k] * MUL + ADD;
|
||||
P[k] = P[k] * SCREEN;
|
||||
}
|
||||
|
||||
bool culled = false;
|
||||
if (!backfaces)
|
||||
{
|
||||
const XMVECTOR N = XMVector3Normalize(XMVector3Cross(P[1] - P[0], P[2] - P[1]));
|
||||
culled = XMVectorGetZ(N) > 0;
|
||||
}
|
||||
|
||||
if (!culled)
|
||||
{
|
||||
for (int k = 0; k < arraysize(triangle); ++k)
|
||||
{
|
||||
const float z = XMVectorGetZ(P[k]);
|
||||
const float dist = XMVectorGetX(XMVector2Length(C - P[k]));
|
||||
if (z >= 0 && z <= 1 && dist <= radius)
|
||||
{
|
||||
if (mesh->vertex_colors.empty())
|
||||
{
|
||||
mesh->vertex_colors.resize(mesh->vertex_positions.size());
|
||||
std::fill(mesh->vertex_colors.begin(), mesh->vertex_colors.end(), 0xFFFFFFFF); // fill white
|
||||
}
|
||||
wiColor vcol = mesh->vertex_colors[triangle[k]];
|
||||
const float affection = amount * std::powf(1 - (dist / radius), falloff);
|
||||
vcol = wiColor::lerp(vcol, color, affection);
|
||||
mesh->vertex_colors[triangle[k]] = vcol.rgba;
|
||||
rebuild = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
|
||||
tri.colorA.w = 0.8f;
|
||||
tri.colorB.w = 0.8f;
|
||||
tri.colorC.w = 0.8f;
|
||||
wiRenderer::DrawTriangle(tri, true);
|
||||
}
|
||||
|
||||
if (rebuild)
|
||||
{
|
||||
mesh->CreateRenderData();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_SOFTBODY_PINNING:
|
||||
case MODE_SOFTBODY_PHYSICS:
|
||||
{
|
||||
ObjectComponent* object = scene.objects.GetComponent(entity);
|
||||
if (object == nullptr || object->meshID == INVALID_ENTITY)
|
||||
break;
|
||||
|
||||
const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID);
|
||||
if (mesh == nullptr)
|
||||
break;
|
||||
|
||||
SoftBodyPhysicsComponent* softbody = scene.softbodies.GetComponent(object->meshID);
|
||||
if (softbody == nullptr || softbody->vertex_positions_simulation.empty())
|
||||
break;
|
||||
|
||||
// Painting:
|
||||
if (pointer_moved && wiInput::Down(wiInput::MOUSE_BUTTON_LEFT))
|
||||
{
|
||||
size_t j = 0;
|
||||
for (auto& ind : softbody->physicsToGraphicsVertexMapping)
|
||||
{
|
||||
XMVECTOR P = softbody->vertex_positions_simulation[ind].LoadPOS();
|
||||
P = XMVector3TransformCoord(P, VP);
|
||||
P = P * MUL + ADD;
|
||||
P = P * SCREEN;
|
||||
const float z = XMVectorGetZ(P);
|
||||
if (z >= 0 && z <= 1 && XMVectorGetX(XMVector2Length(C - P)) <= radius)
|
||||
{
|
||||
softbody->weights[j] = (mode == MODE_SOFTBODY_PINNING ? 0.0f : 1.0f);
|
||||
softbody->_flags |= SoftBodyPhysicsComponent::FORCE_RESET;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
// Visualizing:
|
||||
const XMMATRIX W = XMLoadFloat4x4(&softbody->worldMatrix);
|
||||
for (size_t j = 0; j < mesh->indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t graphicsIndex0 = mesh->indices[j + 0];
|
||||
const uint32_t graphicsIndex1 = mesh->indices[j + 1];
|
||||
const uint32_t graphicsIndex2 = mesh->indices[j + 2];
|
||||
const uint32_t physicsIndex0 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex0];
|
||||
const uint32_t physicsIndex1 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex1];
|
||||
const uint32_t physicsIndex2 = softbody->graphicsToPhysicsVertexMapping[graphicsIndex2];
|
||||
const float weight0 = softbody->weights[physicsIndex0];
|
||||
const float weight1 = softbody->weights[physicsIndex1];
|
||||
const float weight2 = softbody->weights[physicsIndex2];
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
if (softbody->vertex_positions_simulation.empty())
|
||||
{
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex0]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex1]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[graphicsIndex2]), W));
|
||||
}
|
||||
else
|
||||
{
|
||||
tri.positionA = softbody->vertex_positions_simulation[graphicsIndex0].pos;
|
||||
tri.positionB = softbody->vertex_positions_simulation[graphicsIndex1].pos;
|
||||
tri.positionC = softbody->vertex_positions_simulation[graphicsIndex2].pos;
|
||||
}
|
||||
if (weight0 == 0)
|
||||
tri.colorA = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorA = XMFLOAT4(1, 1, 1, 1);
|
||||
if (weight1 == 0)
|
||||
tri.colorB = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorB = XMFLOAT4(1, 1, 1, 1);
|
||||
if (weight2 == 0)
|
||||
tri.colorC = XMFLOAT4(1, 1, 0, 1);
|
||||
else
|
||||
tri.colorC = XMFLOAT4(1, 1, 1, 1);
|
||||
wiRenderer::DrawTriangle(tri, true);
|
||||
if (weight0 == 0 && weight1 == 0 && weight2 == 0)
|
||||
{
|
||||
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 0, 0.8f);
|
||||
wiRenderer::DrawTriangle(tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MODE_HAIRPARTICLE_ADD_TRIANGLE:
|
||||
case MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
|
||||
case MODE_HAIRPARTICLE_LENGTH:
|
||||
{
|
||||
wiHairParticle* hair = scene.hairs.GetComponent(entity);
|
||||
if (hair == nullptr || hair->meshID == INVALID_ENTITY)
|
||||
break;
|
||||
|
||||
MeshComponent* mesh = scene.meshes.GetComponent(hair->meshID);
|
||||
if (mesh == nullptr)
|
||||
break;
|
||||
|
||||
const TransformComponent* transform = scene.transforms.GetComponent(entity);
|
||||
if (transform == nullptr)
|
||||
break;
|
||||
|
||||
const XMMATRIX W = XMLoadFloat4x4(&transform->world);
|
||||
|
||||
for (size_t j = 0; j < mesh->indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t triangle[] = {
|
||||
mesh->indices[j + 0],
|
||||
mesh->indices[j + 1],
|
||||
mesh->indices[j + 2],
|
||||
};
|
||||
|
||||
if (painting)
|
||||
{
|
||||
XMVECTOR P[arraysize(triangle)];
|
||||
for (int k = 0; k < arraysize(triangle); ++k)
|
||||
{
|
||||
const XMFLOAT3& pos = mesh->vertex_positions[triangle[k]];
|
||||
P[k] = XMLoadFloat3(&pos);
|
||||
P[k] = XMVector3Transform(P[k], W);
|
||||
P[k] = XMVector3TransformCoord(P[k], VP);
|
||||
P[k] = P[k] * MUL + ADD;
|
||||
P[k] = P[k] * SCREEN;
|
||||
}
|
||||
|
||||
bool culled = false;
|
||||
if (!backfaces)
|
||||
{
|
||||
const XMVECTOR N = XMVector3Normalize(XMVector3Cross(P[1] - P[0], P[2] - P[1]));
|
||||
culled = XMVectorGetZ(N) > 0;
|
||||
}
|
||||
|
||||
if (!culled)
|
||||
{
|
||||
for (int k = 0; k < arraysize(triangle); ++k)
|
||||
{
|
||||
const float z = XMVectorGetZ(P[k]);
|
||||
const float dist = XMVectorGetX(XMVector2Length(C - P[k]));
|
||||
if (z >= 0 && z <= 1 && dist <= radius)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case MODE_HAIRPARTICLE_ADD_TRIANGLE:
|
||||
hair->vertex_lengths[triangle[k]] = 1.0f;
|
||||
break;
|
||||
case MODE_HAIRPARTICLE_REMOVE_TRIANGLE:
|
||||
hair->vertex_lengths[triangle[k]] = 0;
|
||||
break;
|
||||
case MODE_HAIRPARTICLE_LENGTH:
|
||||
const float affection = amount * std::powf(1 - (dist / radius), falloff);
|
||||
hair->vertex_lengths[triangle[k]] = wiMath::Lerp(hair->vertex_lengths[triangle[k]], color_float.w, affection);
|
||||
// don't let it "remove" the vertex by keeping its length above zero:
|
||||
// (because if removed, distribution also changes which might be distracting)
|
||||
hair->vertex_lengths[triangle[k]] = wiMath::Clamp(hair->vertex_lengths[triangle[k]], 1.0f / 255.0f, 1.0f);
|
||||
break;
|
||||
}
|
||||
hair->_flags |= wiHairParticle::REBUILD_BUFFERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
|
||||
wiRenderer::DrawTriangle(tri, true);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < hair->indices.size(); j += 3)
|
||||
{
|
||||
const uint32_t triangle[] = {
|
||||
hair->indices[j + 0],
|
||||
hair->indices[j + 1],
|
||||
hair->indices[j + 2],
|
||||
};
|
||||
|
||||
wiRenderer::RenderableTriangle tri;
|
||||
XMStoreFloat3(&tri.positionA, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[0]]), W));
|
||||
XMStoreFloat3(&tri.positionB, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[1]]), W));
|
||||
XMStoreFloat3(&tri.positionC, XMVector3Transform(XMLoadFloat3(&mesh->vertex_positions[triangle[2]]), W));
|
||||
tri.colorA = tri.colorB = tri.colorC = XMFLOAT4(1, 0, 1, 0.9f);
|
||||
wiRenderer::DrawTriangle(tri, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
void PaintToolWindow::DrawBrush() const
|
||||
{
|
||||
if (GetMode() == MODE_DISABLED || entity == INVALID_ENTITY || wiBackLog::isActive())
|
||||
return;
|
||||
|
||||
const float radius = radiusSlider->GetValue();
|
||||
const int segmentcount = 36;
|
||||
for (int i = 0; i < segmentcount; i += 1)
|
||||
{
|
||||
@@ -66,8 +404,6 @@ void PaintToolWindow::DrawBrush() const
|
||||
wiRenderer::DrawLine(line);
|
||||
}
|
||||
|
||||
static float rot = 0;
|
||||
rot -= 0.008f;
|
||||
for (int i = 0; i < segmentcount; i += 2)
|
||||
{
|
||||
const float angle0 = rot + (float)i / (float)segmentcount * XM_2PI;
|
||||
@@ -85,7 +421,7 @@ PaintToolWindow::MODE PaintToolWindow::GetMode() const
|
||||
{
|
||||
return (MODE)modeComboBox->GetSelected();
|
||||
}
|
||||
float PaintToolWindow::GetRadius() const
|
||||
void PaintToolWindow::SetEntity(wiECS::Entity value)
|
||||
{
|
||||
return radiusSlider->GetValue();
|
||||
entity = value;
|
||||
}
|
||||
|
||||
@@ -12,16 +12,24 @@ class wiButton;
|
||||
|
||||
class PaintToolWindow
|
||||
{
|
||||
float rot = 0;
|
||||
XMFLOAT2 posPrev = XMFLOAT2(0, 0);
|
||||
public:
|
||||
PaintToolWindow(wiGUI* gui);
|
||||
~PaintToolWindow();
|
||||
|
||||
wiGUI* GUI;
|
||||
wiECS::Entity entity = wiECS::INVALID_ENTITY;
|
||||
|
||||
wiWindow* window;
|
||||
wiComboBox* modeComboBox;
|
||||
wiSlider* radiusSlider;
|
||||
wiSlider* amountSlider;
|
||||
wiSlider* falloffSlider;
|
||||
wiCheckBox* backfaceCheckBox;
|
||||
wiColorPicker* colorPicker;
|
||||
|
||||
void Update(float dt);
|
||||
void DrawBrush() const;
|
||||
|
||||
XMFLOAT2 pos = XMFLOAT2(0, 0);
|
||||
@@ -29,11 +37,13 @@ public:
|
||||
enum MODE
|
||||
{
|
||||
MODE_DISABLED,
|
||||
MODE_VERTEXCOLOR,
|
||||
MODE_SOFTBODY_PINNING,
|
||||
MODE_SOFTBODY_PHYSICS,
|
||||
MODE_HAIRPARTICLE_ADD_TRIANGLE,
|
||||
MODE_HAIRPARTICLE_REMOVE_TRIANGLE,
|
||||
MODE_HAIRPARTICLE_LENGTH,
|
||||
};
|
||||
MODE GetMode() const;
|
||||
float GetRadius() const;
|
||||
void SetEntity(wiECS::Entity value);
|
||||
};
|
||||
|
||||
@@ -57,7 +57,6 @@ VertexToPixel main(uint fakeIndex : SV_VERTEXID)
|
||||
|
||||
float len = (binormal_length >> 24) & 0x000000FF;
|
||||
len /= 255.0f;
|
||||
len += 1;
|
||||
len *= xLength;
|
||||
|
||||
// expand the particle into a billboard cross section, the patch:
|
||||
|
||||
@@ -6,6 +6,7 @@ RWSTRUCTUREDBUFFER(simulationBuffer, PatchSimulationData, 1);
|
||||
|
||||
TYPEDBUFFER(meshIndexBuffer, uint, TEXSLOT_ONDEMAND0);
|
||||
RAWBUFFER(meshVertexBuffer_POS, TEXSLOT_ONDEMAND1);
|
||||
TYPEDBUFFER(meshVertexBuffer_length, float, TEXSLOT_ONDEMAND2);
|
||||
|
||||
#define NUM_LDS_FORCEFIELDS 32
|
||||
struct LDS_ForceField
|
||||
@@ -55,6 +56,9 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
|
||||
float3 nor0 = unpack_unitvector(asuint(pos_nor0.w));
|
||||
float3 nor1 = unpack_unitvector(asuint(pos_nor1.w));
|
||||
float3 nor2 = unpack_unitvector(asuint(pos_nor2.w));
|
||||
float length0 = meshVertexBuffer_length[i0];
|
||||
float length1 = meshVertexBuffer_length[i1];
|
||||
float length2 = meshVertexBuffer_length[i2];
|
||||
|
||||
// random barycentric coords:
|
||||
float f = rand(seed, uv);
|
||||
@@ -71,6 +75,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
|
||||
float3 target = normalize(nor0 + f * (nor1 - nor0) + g * (nor2 - nor0));
|
||||
float3 tangent = normalize((rand(seed, uv) < 0.5f ? pos_nor0.xyz : pos_nor2.xyz) - pos_nor1.xyz);
|
||||
float3 binormal = cross(target, tangent);
|
||||
float strand_length = length0 + f * (length1 - length0) + g * (length2 - length0);
|
||||
|
||||
uint tangent_random = 0;
|
||||
tangent_random |= (uint)((uint)(tangent.x * 127.5f + 127.5f) << 0);
|
||||
@@ -82,7 +87,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint groupIn
|
||||
binormal_length |= (uint)((uint)(binormal.x * 127.5f + 127.5f) << 0);
|
||||
binormal_length |= (uint)((uint)(binormal.y * 127.5f + 127.5f) << 8);
|
||||
binormal_length |= (uint)((uint)(binormal.z * 127.5f + 127.5f) << 16);
|
||||
binormal_length |= (uint)(rand(seed, uv) * 255 * saturate(xHairRandomness)) << 24;
|
||||
binormal_length |= (uint)(lerp(1, rand(seed, uv), saturate(xHairRandomness)) * strand_length * 255) << 24;
|
||||
|
||||
// Identifies the hair strand root particle:
|
||||
const uint strandID = DTid.x * xHairSegmentCount;
|
||||
|
||||
@@ -107,8 +107,27 @@ void wiHairParticle::UpdateCPU(const TransformComponent& transform, const MeshCo
|
||||
}
|
||||
}
|
||||
|
||||
if (!vertex_lengths.empty())
|
||||
{
|
||||
std::vector<uint8_t> ulengths;
|
||||
ulengths.reserve(vertex_lengths.size());
|
||||
for (auto& x : vertex_lengths)
|
||||
{
|
||||
ulengths.push_back(uint8_t(wiMath::Clamp(x, 0, 1) * 255.0f));
|
||||
}
|
||||
|
||||
bd.MiscFlags = 0;
|
||||
bd.BindFlags = BIND_SHADER_RESOURCE;
|
||||
bd.Format = FORMAT_R8_UNORM;
|
||||
bd.StructureByteStride = sizeof(uint8_t);
|
||||
bd.ByteWidth = bd.StructureByteStride * (uint32_t)ulengths.size();
|
||||
SubresourceData initData;
|
||||
initData.pSysMem = ulengths.data();
|
||||
device->CreateBuffer(&bd, &initData, &vertexBuffer_length);
|
||||
}
|
||||
if (!indices.empty())
|
||||
{
|
||||
bd.MiscFlags = 0;
|
||||
bd.BindFlags = BIND_SHADER_RESOURCE;
|
||||
bd.Format = FORMAT_R32_UINT;
|
||||
bd.StructureByteStride = sizeof(uint32_t);
|
||||
@@ -163,6 +182,7 @@ void wiHairParticle::UpdateGPU(const MeshComponent& mesh, const MaterialComponen
|
||||
const GPUResource* res[] = {
|
||||
indexBuffer.IsValid() ? &indexBuffer : &mesh.indexBuffer,
|
||||
mesh.streamoutBuffer_POS.IsValid() ? &mesh.streamoutBuffer_POS : &mesh.vertexBuffer_POS,
|
||||
&vertexBuffer_length
|
||||
};
|
||||
device->BindResources(CS, res, TEXSLOT_ONDEMAND0, arraysize(res), cmd);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
XMFLOAT4X4 world;
|
||||
XMFLOAT4X4 worldPrev;
|
||||
AABB aabb;
|
||||
std::vector<uint32_t> indices;
|
||||
std::vector<uint32_t> indices; // it is dependent on vertex_lengths and contains triangles with non-zero lengths
|
||||
|
||||
void Serialize(wiArchive& archive, uint32_t seed = 0);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 39;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 27;
|
||||
const int revision = 28;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
@@ -1800,6 +1800,16 @@ wiColorPicker::wiColorPicker(wiGUI* gui, const std::string& name, bool window_co
|
||||
FireEvents();
|
||||
});
|
||||
AddWidget(text_V);
|
||||
|
||||
alphaSlider = new wiSlider(0, 255, 255, 255, "");
|
||||
alphaSlider->SetPos(XMFLOAT2(20, 230));
|
||||
alphaSlider->SetSize(XMFLOAT2(150, 18));
|
||||
alphaSlider->SetText("A: ");
|
||||
alphaSlider->SetTooltip("Value for ALPHA - TRANSPARENCY channel (0-255)");
|
||||
alphaSlider->OnSlide([this](wiEventArgs args) {
|
||||
FireEvents();
|
||||
});
|
||||
AddWidget(alphaSlider);
|
||||
}
|
||||
static const float colorpicker_center = 120;
|
||||
static const float colorpicker_radius_triangle = 68;
|
||||
@@ -2132,11 +2142,9 @@ void wiColorPicker::Render(const wiGUI* gui, CommandList cmd) const
|
||||
float _width = 20;
|
||||
Vertex vertices[] = {
|
||||
{ XMFLOAT4(-_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(-_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(-_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(_width, _width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
{ XMFLOAT4(_width, -_width, 0, 1),XMFLOAT4(1,1,1,1) },
|
||||
};
|
||||
|
||||
GPUBufferDesc desc;
|
||||
@@ -2326,7 +2334,7 @@ wiColor wiColorPicker::GetPickColor() const
|
||||
source.s = saturation;
|
||||
source.v = luminance;
|
||||
rgb result = hsv2rgb(source);
|
||||
return wiColor::fromFloat3(XMFLOAT3(result.r, result.g, result.b));
|
||||
return wiColor::fromFloat4(XMFLOAT4(result.r, result.g, result.b, alphaSlider->GetValue() / 255.0f));
|
||||
}
|
||||
void wiColorPicker::SetPickColor(wiColor value)
|
||||
{
|
||||
@@ -2344,9 +2352,12 @@ void wiColorPicker::SetPickColor(wiColor value)
|
||||
}
|
||||
saturation = result.s;
|
||||
luminance = result.v;
|
||||
alphaSlider->SetValue((float)value.getA());
|
||||
}
|
||||
void wiColorPicker::FireEvents()
|
||||
{
|
||||
if (onColorChanged == nullptr)
|
||||
return;
|
||||
wiEventArgs args;
|
||||
args.color = GetPickColor();
|
||||
onColorChanged(args);
|
||||
|
||||
@@ -317,6 +317,7 @@ protected:
|
||||
wiTextInputField* text_H = nullptr;
|
||||
wiTextInputField* text_S = nullptr;
|
||||
wiTextInputField* text_V = nullptr;
|
||||
wiSlider* alphaSlider = nullptr;
|
||||
|
||||
void FireEvents();
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user