diff --git a/WickedEngine/LightWindow.cpp b/WickedEngine/LightWindow.cpp index 60e4b89e9..7cd33ac74 100644 --- a/WickedEngine/LightWindow.cpp +++ b/WickedEngine/LightWindow.cpp @@ -10,16 +10,17 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) float screenH = (float)wiRenderer::GetDevice()->GetScreenHeight(); lightWindow = new wiWindow(GUI, "Light Window"); - lightWindow->SetSize(XMFLOAT2(400, 300)); + lightWindow->SetSize(XMFLOAT2(400, 420)); //lightWindow->SetEnabled(false); GUI->AddWidget(lightWindow); float x = 200; float y = 0; + float step = 35; energySlider = new wiSlider(0.1f, 64, 0, 100000, "Energy: "); energySlider->SetSize(XMFLOAT2(100, 30)); - energySlider->SetPos(XMFLOAT2(x, y += 30)); + energySlider->SetPos(XMFLOAT2(x, y += step)); energySlider->OnSlide([&](wiEventArgs args) { if (light != nullptr) { @@ -27,11 +28,12 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); energySlider->SetEnabled(false); + energySlider->SetTooltip("Adjust the light radiation amount inside the maximum range"); lightWindow->AddWidget(energySlider); distanceSlider = new wiSlider(1, 1000, 0, 100000, "Distance: "); distanceSlider->SetSize(XMFLOAT2(100, 30)); - distanceSlider->SetPos(XMFLOAT2(x, y += 30)); + distanceSlider->SetPos(XMFLOAT2(x, y += step)); distanceSlider->OnSlide([&](wiEventArgs args) { if (light != nullptr) { @@ -39,11 +41,12 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); distanceSlider->SetEnabled(false); + distanceSlider->SetTooltip("Adjust the maximum range the light can affect."); lightWindow->AddWidget(distanceSlider); fovSlider = new wiSlider(0.1f, XM_PI - 0.01f, 0, 100000, "FOV: "); fovSlider->SetSize(XMFLOAT2(100, 30)); - fovSlider->SetPos(XMFLOAT2(x, y += 30)); + fovSlider->SetPos(XMFLOAT2(x, y += step)); fovSlider->OnSlide([&](wiEventArgs args) { if (light != nullptr) { @@ -51,11 +54,12 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); fovSlider->SetEnabled(false); + fovSlider->SetTooltip("Adjust the cone aperture for spotlight."); lightWindow->AddWidget(fovSlider); biasSlider = new wiSlider(0.0f, 0.01f, 0, 100000, "ShadowBias: "); biasSlider->SetSize(XMFLOAT2(100, 30)); - biasSlider->SetPos(XMFLOAT2(x, y += 30)); + biasSlider->SetPos(XMFLOAT2(x, y += step)); biasSlider->OnSlide([&](wiEventArgs args) { if (light != nullptr) { @@ -63,10 +67,11 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); biasSlider->SetEnabled(false); + biasSlider->SetTooltip("Adjust the shadow bias if shadow artifacts occur."); lightWindow->AddWidget(biasSlider); shadowCheckBox = new wiCheckBox("Shadow: "); - shadowCheckBox->SetPos(XMFLOAT2(x, y += 30)); + shadowCheckBox->SetPos(XMFLOAT2(x, y += step)); shadowCheckBox->OnClick([&](wiEventArgs args) { if (light != nullptr) { @@ -74,10 +79,11 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); shadowCheckBox->SetEnabled(false); + shadowCheckBox->SetTooltip("Set light as shadow caster. Many shadow casters can affect performance!"); lightWindow->AddWidget(shadowCheckBox); haloCheckBox = new wiCheckBox("Halo: "); - haloCheckBox->SetPos(XMFLOAT2(x, y += 30)); + haloCheckBox->SetPos(XMFLOAT2(x, y += step)); haloCheckBox->OnClick([&](wiEventArgs args) { if (light != nullptr) { @@ -85,10 +91,11 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) } }); haloCheckBox->SetEnabled(false); + haloCheckBox->SetTooltip("Visualize light source emission"); lightWindow->AddWidget(haloCheckBox); addLightButton = new wiButton("Add Light"); - addLightButton->SetPos(XMFLOAT2(x, y += 30)); + addLightButton->SetPos(XMFLOAT2(x, y += step)); addLightButton->SetSize(XMFLOAT2(180, 30)); addLightButton->OnClick([&](wiEventArgs args) { Model* model = new Model; @@ -99,14 +106,16 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) model->lights.push_back(light); wiRenderer::AddModel(model); }); + addLightButton->SetTooltip("Add a light to the scene. It will be added to the origin."); lightWindow->AddWidget(addLightButton); colorPickerToggleButton = new wiButton("Color"); - colorPickerToggleButton->SetPos(XMFLOAT2(x, y += 30)); + colorPickerToggleButton->SetPos(XMFLOAT2(x, y += step)); colorPickerToggleButton->OnClick([&](wiEventArgs args) { colorPicker->SetVisible(!colorPicker->IsVisible()); }); + colorPickerToggleButton->SetTooltip("Toggle the light color picker."); lightWindow->AddWidget(colorPickerToggleButton); @@ -118,9 +127,27 @@ LightWindow::LightWindow(wiGUI* gui) : GUI(gui), light(nullptr) }); GUI->AddWidget(colorPicker); + typeSelectorComboBox = new wiComboBox("Type: "); + typeSelectorComboBox->SetPos(XMFLOAT2(x, y += step)); + typeSelectorComboBox->OnSelect([&](wiEventArgs args) { + if (light != nullptr && args.iValue >= 0) + { + light->type = (Light::LightType)args.iValue; + SetLightType(light->type); // for the gui changes to apply to the new type + } + }); + typeSelectorComboBox->SetEnabled(false); + typeSelectorComboBox->AddItem("Directional"); + typeSelectorComboBox->AddItem("Point"); + typeSelectorComboBox->AddItem("Spot"); + typeSelectorComboBox->SetTooltip("Choose the light source type..."); + lightWindow->AddWidget(typeSelectorComboBox); + lightWindow->Translate(XMFLOAT3(30, 30, 0)); lightWindow->SetVisible(false); + + SetLight(nullptr); } @@ -136,6 +163,7 @@ LightWindow::~LightWindow() SAFE_DELETE(addLightButton); SAFE_DELETE(colorPickerToggleButton); SAFE_DELETE(colorPicker); + SAFE_DELETE(typeSelectorComboBox); } void LightWindow::SetLight(Light* light) @@ -146,38 +174,50 @@ void LightWindow::SetLight(Light* light) //lightWindow->SetEnabled(true); energySlider->SetEnabled(true); energySlider->SetValue(light->enerDis.x); - if (light->type == Light::DIRECTIONAL) - { - distanceSlider->SetEnabled(false); - fovSlider->SetEnabled(false); - } - else - { - distanceSlider->SetEnabled(true); - distanceSlider->SetValue(light->enerDis.y); - if (light->type == Light::SPOT) - { - fovSlider->SetEnabled(true); - fovSlider->SetValue(light->enerDis.z); - } - else - { - fovSlider->SetEnabled(false); - } - } + distanceSlider->SetValue(light->enerDis.y); + fovSlider->SetValue(light->enerDis.z); biasSlider->SetEnabled(true); biasSlider->SetValue(light->shadowBias); + shadowCheckBox->SetEnabled(true); shadowCheckBox->SetCheck(light->shadow); + haloCheckBox->SetEnabled(true); haloCheckBox->SetCheck(!light->noHalo); colorPicker->SetEnabled(true); + typeSelectorComboBox->SetEnabled(true); + typeSelectorComboBox->SetSelected((int)light->type); + + SetLightType(light->type); } else { distanceSlider->SetEnabled(false); fovSlider->SetEnabled(false); biasSlider->SetEnabled(false); + shadowCheckBox->SetEnabled(false); + haloCheckBox->SetEnabled(false); energySlider->SetEnabled(false); - //lightWindow->SetEnabled(false); colorPicker->SetEnabled(false); + typeSelectorComboBox->SetEnabled(false); + //lightWindow->SetEnabled(false); + } +} +void LightWindow::SetLightType(Light::LightType type) +{ + if (type == Light::DIRECTIONAL) + { + distanceSlider->SetEnabled(false); + fovSlider->SetEnabled(false); + } + else + { + distanceSlider->SetEnabled(true); + if (type == Light::SPOT) + { + fovSlider->SetEnabled(true); + } + else + { + fovSlider->SetEnabled(false); + } } } diff --git a/WickedEngine/LightWindow.h b/WickedEngine/LightWindow.h index 2613be2ff..0c72e7617 100644 --- a/WickedEngine/LightWindow.h +++ b/WickedEngine/LightWindow.h @@ -8,6 +8,7 @@ class wiCheckBox; class wiSlider; class wiButton; class wiColorPicker; +class wiComboBox; struct Light; @@ -20,6 +21,7 @@ public: wiGUI* GUI; void SetLight(Light* light); + void SetLightType(Light::LightType type); Light* light; @@ -33,5 +35,6 @@ public: wiButton* addLightButton; wiButton* colorPickerToggleButton; wiColorPicker* colorPicker; + wiComboBox* typeSelectorComboBox; }; diff --git a/WickedEngine/wiWidget.cpp b/WickedEngine/wiWidget.cpp index a768086c1..1f19e6f38 100644 --- a/WickedEngine/wiWidget.cpp +++ b/WickedEngine/wiWidget.cpp @@ -661,6 +661,247 @@ bool wiCheckBox::GetCheck() + +wiComboBox::wiComboBox(const string& name) :wiWidget() +, selected(-1), combostate(COMBOSTATE_INACTIVE), hovered(-1) +{ + SetName(name); + SetText(fastName.GetString()); + OnSelect([](wiEventArgs args) {}); + SetSize(XMFLOAT2(100, 20)); +} +wiComboBox::~wiComboBox() +{ + +} +const float wiComboBox::_GetItemOffset(int index) const +{ + return scale.y * (index + 1) + 1; +} +void wiComboBox::Update(wiGUI* gui) +{ + wiWidget::Update(gui); + + if (!IsEnabled()) + { + return; + } + + if (gui->IsWidgetDisabled(this)) + { + return; + } + + if (state == FOCUS) + { + state = IDLE; + } + if (state == DEACTIVATING) + { + state = IDLE; + } + if (state == ACTIVE && combostate == COMBOSTATE_SELECTING) + { + gui->DeactivateWidget(this); + } + + hitBox.pos.x = Transform::translation.x; + hitBox.pos.y = Transform::translation.y; + hitBox.siz.x = Transform::scale.x + scale.y + 1; // + drop-down indicator arrow + little offset + hitBox.siz.y = Transform::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 (wiInputManager::GetInstance()->press(VK_LBUTTON, wiInputManager::KEYBOARD)) + { + // activate + clicked = true; + } + + if (wiInputManager::GetInstance()->down(VK_LBUTTON, wiInputManager::KEYBOARD)) + { + if (state == DEACTIVATING) + { + // Keep pressed until mouse is released + gui->ActivateWidget(this); + } + } + + + if (clicked && state == FOCUS) + { + gui->ActivateWidget(this); + } + + + if (state == ACTIVE) + { + if (combostate == COMBOSTATE_INACTIVE) + { + combostate = COMBOSTATE_HOVER; + } + else if (combostate == COMBOSTATE_SELECTING) + { + gui->DeactivateWidget(this); + combostate = COMBOSTATE_INACTIVE; + } + else + { + hovered = -1; + for (size_t i = 0; i < items.size(); ++i) + { + Hitbox2D itembox; + itembox.pos.x = Transform::translation.x; + itembox.pos.y = Transform::translation.y + _GetItemOffset((int)i); + itembox.siz.x = Transform::scale.x; + itembox.siz.y = Transform::scale.y; + if (pointerHitbox.intersects(itembox)) + { + hovered = (int)i; + break; + } + } + + if (clicked) + { + combostate = COMBOSTATE_SELECTING; + if (hovered >= 0) + { + SetSelected(hovered); + } + } + } + } + +} +void wiComboBox::Render(wiGUI* gui) +{ + assert(gui != nullptr && "Ivalid GUI!"); + + if (!IsVisible()) + { + return; + } + + wiColor color = GetColor(); + if (combostate != COMBOSTATE_INACTIVE) + { + color = colors[FOCUS]; + } + + // control-base + wiImage::Draw(wiTextureHelper::getInstance()->getColor(color) + , wiImageEffects(translation.x, translation.y, scale.x, scale.y), gui->GetGraphicsThread()); + // control-arrow + wiImage::Draw(wiTextureHelper::getInstance()->getColor(color) + , wiImageEffects(translation.x+scale.x+1, translation.y, scale.y, scale.y), gui->GetGraphicsThread()); + wiFont("V", wiFontProps((int)(translation.x+scale.x+scale.y*0.5f), (int)(translation.y + scale.y*0.5f), -1, WIFALIGN_CENTER, WIFALIGN_CENTER)).Draw(gui->GetGraphicsThread(), false); + + + if (parent != nullptr) + { + wiRenderer::GetDevice()->SetScissorRects(1, &scissorRect, gui->GetGraphicsThread()); + } + wiFont(text, wiFontProps((int)(translation.x), (int)(translation.y + scale.y*0.5f), -1, WIFALIGN_RIGHT, WIFALIGN_CENTER)).Draw(gui->GetGraphicsThread(), parent != nullptr); + + if (selected >= 0) + { + wiFont(items[selected], wiFontProps((int)(translation.x + scale.x*0.5f), (int)(translation.y + scale.y*0.5f), -1, WIFALIGN_CENTER, WIFALIGN_CENTER)).Draw(gui->GetGraphicsThread(), parent != nullptr); + } + + // drop-down + if (state == ACTIVE) + { + // control-list + int i = 0; + for (auto& x : items) + { + wiColor col = colors[IDLE]; + if (hovered == i) + { + if (combostate == COMBOSTATE_HOVER) + { + col = colors[FOCUS]; + } + else if (combostate == COMBOSTATE_SELECTING) + { + col = colors[ACTIVE]; + } + } + wiImage::Draw(wiTextureHelper::getInstance()->getColor(col) + , wiImageEffects(translation.x, translation.y + _GetItemOffset(i), scale.x, scale.y), gui->GetGraphicsThread()); + wiFont(x, wiFontProps((int)(translation.x + scale.x*0.5f), (int)(translation.y + scale.y*0.5f +_GetItemOffset(i)), -1, WIFALIGN_CENTER, WIFALIGN_CENTER)).Draw(gui->GetGraphicsThread(), false); + i++; + } + } +} +void wiComboBox::OnSelect(function func) +{ + onSelect = move(func); +} +void wiComboBox::AddItem(const string& item) +{ + items.push_back(item); + + if (selected < 0) + { + selected = 0; + } +} +void wiComboBox::RemoveItem(int index) +{ + vector newItems(0); + newItems.reserve(items.size()); + for (size_t i = 0; i < items.size(); ++i) + { + if (i != index) + { + newItems.push_back(items[i]); + } + } + items = newItems; + + if (items.empty()) + { + selected = -1; + } + else if (selected > index) + { + selected--; + } +} +void wiComboBox::ClearItems() +{ + items.clear(); + + selected = -1; +} +void wiComboBox::SetSelected(int index) +{ + selected = index; + + wiEventArgs args; + args.iValue = selected; + onSelect(args); +} +int wiComboBox::GetSelected() +{ + return selected; +} + + + + static const float windowcontrolSize = 20.0f; wiWindow::wiWindow(wiGUI* gui, const string& name) :wiWidget() , gui(gui) diff --git a/WickedEngine/wiWidget.h b/WickedEngine/wiWidget.h index 447478684..39e87370e 100644 --- a/WickedEngine/wiWidget.h +++ b/WickedEngine/wiWidget.h @@ -16,6 +16,7 @@ struct wiEventArgs XMFLOAT2 endPos; float fValue; bool bValue; + int iValue; XMFLOAT4 color; }; @@ -160,6 +161,47 @@ public: void OnClick(function func); }; +// Drop-down list +class wiComboBox :public wiWidget +{ +protected: + function onSelect; + Hitbox2D hitBox; + int selected; + + // While the widget is active (rolled down) these are the inner states that control behaviour + enum COMBOSTATE + { + // When the list is just being dropped down, or the widget is not active + COMBOSTATE_INACTIVE, + // The widget is in drop-down state with the last item hovered highlited + COMBOSTATE_HOVER, + // The hovered item is clicked + COMBOSTATE_SELECTING, + COMBOSTATE_COUNT, + } combostate; + int hovered; + + vector items; + + const float _GetItemOffset(int index) const; +public: + wiComboBox(const string& name = ""); + virtual ~wiComboBox(); + + void AddItem(const string& item); + void RemoveItem(int index); + void ClearItems(); + + void SetSelected(int index); + int GetSelected(); + + virtual void Update(wiGUI* gui) override; + virtual void Render(wiGUI* gui) override; + + void OnSelect(function func); +}; + // Widget container class wiWindow :public wiWidget {