#include "stdafx.h" #include "Editor.h" #include "wiRenderer.h" #include "ModelImporter.h" #include "Translator.h" #include #ifdef PLATFORM_UWP #include #include using namespace concurrency; using namespace Platform; using namespace Windows::Storage; using namespace Windows::Storage::Pickers; using namespace Windows::Storage::AccessCache; using namespace Windows::Foundation::Collections; void copy_folder(StorageFolder^ src, StorageFolder^ dst) { create_task(src->GetItemsAsync()).then([=](IVectorView^ items) { for (IStorageItem^ item : items) { if (item->IsOfType(StorageItemTypes::File)) { StorageFile^ file = (StorageFile^)item; try { file->CopyAsync(dst); } catch (...) { // file already exists, we don't want to overwrite } } else if (item->IsOfType(StorageItemTypes::Folder)) { StorageFolder^ src_child = (StorageFolder^)item; create_task(dst->CreateFolderAsync(item->Name, CreationCollisionOption::OpenIfExists)).then([=](StorageFolder^ dst_child) { if (dst_child) { copy_folder(src_child, dst_child); } }); } } }); }; #endif // PLATFORM_UWP using namespace std; using namespace wiGraphics; using namespace wiRectPacker; using namespace wiScene; using namespace wiECS; void Editor::Initialize() { __super::Initialize(); infoDisplay.active = true; infoDisplay.watermark = true; infoDisplay.fpsinfo = true; infoDisplay.resolution = true; infoDisplay.heap_allocation_counter = true; wiRenderer::GetDevice()->SetVSyncEnabled(true); wiRenderer::SetOcclusionCullingEnabled(true); renderComponent = std::make_unique(); loader = std::make_unique(); loader->Load(); renderComponent->main = this; loader->addLoadingComponent(renderComponent.get(), this, 0.2f); ActivatePath(loader.get(), 0.2f); } void EditorLoadingScreen::Load() { font = wiSpriteFont("Loading...", wiFontParams(wiRenderer::GetDevice()->GetScreenWidth()*0.5f, wiRenderer::GetDevice()->GetScreenHeight()*0.5f, 36, WIFALIGN_CENTER, WIFALIGN_CENTER)); AddFont(&font); sprite = wiSprite("images/logo_small.png"); sprite.anim.opa = 1; sprite.anim.repeatable = true; sprite.params.pos = XMFLOAT3(wiRenderer::GetDevice()->GetScreenWidth()*0.5f, wiRenderer::GetDevice()->GetScreenHeight()*0.5f - font.textHeight(), 0); sprite.params.siz = XMFLOAT2(128, 128); sprite.params.pivot = XMFLOAT2(0.5f, 1.0f); sprite.params.quality = QUALITY_LINEAR; sprite.params.blendFlag = BLENDMODE_ALPHA; AddSprite(&sprite); __super::Load(); } void EditorLoadingScreen::Update(float dt) { font.params.posX = wiRenderer::GetDevice()->GetScreenWidth()*0.5f; font.params.posY = wiRenderer::GetDevice()->GetScreenHeight()*0.5f; sprite.params.pos = XMFLOAT3(wiRenderer::GetDevice()->GetScreenWidth()*0.5f, wiRenderer::GetDevice()->GetScreenHeight()*0.5f - font.textHeight(), 0); __super::Update(dt); } void EditorComponent::ChangeRenderPath(RENDERPATH path) { switch (path) { case EditorComponent::RENDERPATH_FORWARD: renderPath = std::make_unique(); break; case EditorComponent::RENDERPATH_DEFERRED: renderPath = std::make_unique(); break; case EditorComponent::RENDERPATH_TILEDFORWARD: renderPath = std::make_unique(); break; case EditorComponent::RENDERPATH_TILEDDEFERRED: renderPath = std::make_unique(); break; case EditorComponent::RENDERPATH_PATHTRACING: renderPath = std::make_unique(); break; default: assert(0); break; } renderPath->setShadowsEnabled(true); renderPath->setReflectionsEnabled(true); renderPath->setAO(RenderPath3D::AO_DISABLED); renderPath->setSSREnabled(false); renderPath->setMotionBlurEnabled(false); renderPath->setColorGradingEnabled(false); renderPath->setEyeAdaptionEnabled(false); renderPath->setFXAAEnabled(false); renderPath->setDepthOfFieldEnabled(false); renderPath->setLightShaftsEnabled(false); renderPath->Load(); materialWnd = std::make_unique(this); postprocessWnd = std::make_unique(this); weatherWnd = std::make_unique(this); objectWnd = std::make_unique(this); meshWnd = std::make_unique(this); cameraWnd = std::make_unique(this); rendererWnd = std::make_unique(this); envProbeWnd = std::make_unique(this); soundWnd = std::make_unique(this); decalWnd = std::make_unique(this); lightWnd = std::make_unique(this); animWnd = std::make_unique(this); emitterWnd = std::make_unique(this); hairWnd = std::make_unique(this); forceFieldWnd = std::make_unique(this); paintToolWnd = std::make_unique(this); springWnd = std::make_unique(this); ikWnd = std::make_unique(this); transformWnd = std::make_unique(this); layerWnd = std::make_unique(this); nameWnd = std::make_unique(this); ResizeBuffers(); } void EditorComponent::ResizeBuffers() { __super::ResizeBuffers(); GraphicsDevice* device = wiRenderer::GetDevice(); HRESULT hr; if(renderPath != nullptr && renderPath->GetDepthStencil() != nullptr) { TextureDesc desc; desc.Width = wiRenderer::GetInternalResolution().x; desc.Height = wiRenderer::GetInternalResolution().y; desc.Format = FORMAT_R8_UNORM; desc.BindFlags = BIND_RENDER_TARGET | BIND_SHADER_RESOURCE; if (renderPath->getMSAASampleCount() > 1) { desc.SampleCount = renderPath->getMSAASampleCount(); hr = device->CreateTexture(&desc, nullptr, &rt_selectionOutline_MSAA); assert(SUCCEEDED(hr)); desc.SampleCount = 1; } hr = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[0]); assert(SUCCEEDED(hr)); hr = device->CreateTexture(&desc, nullptr, &rt_selectionOutline[1]); assert(SUCCEEDED(hr)); { RenderPassDesc desc; desc.attachments.push_back(RenderPassAttachment::RenderTarget(&rt_selectionOutline[0], RenderPassAttachment::LOADOP_CLEAR)); if (renderPath->getMSAASampleCount() > 1) { desc.attachments[0].texture = &rt_selectionOutline_MSAA; desc.attachments.push_back(RenderPassAttachment::Resolve(&rt_selectionOutline[0])); } desc.attachments.push_back( RenderPassAttachment::DepthStencil( renderPath->GetDepthStencil(), RenderPassAttachment::LOADOP_LOAD, RenderPassAttachment::STOREOP_STORE, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY, IMAGE_LAYOUT_DEPTHSTENCIL_READONLY ) ); hr = device->CreateRenderPass(&desc, &renderpass_selectionOutline[0]); assert(SUCCEEDED(hr)); if (renderPath->getMSAASampleCount() == 1) { desc.attachments[0].texture = &rt_selectionOutline[1]; // rendertarget } else { desc.attachments[1].texture = &rt_selectionOutline[1]; // resolve } hr = device->CreateRenderPass(&desc, &renderpass_selectionOutline[1]); assert(SUCCEEDED(hr)); } } } void EditorComponent::ResizeLayout() { __super::ResizeLayout(); // GUI elements scaling: float screenW = wiRenderer::GetDevice()->GetScreenWidth(); float screenH = wiRenderer::GetDevice()->GetScreenHeight(); XMFLOAT2 option_size = XMFLOAT2(100, 34); float x = screenW - option_size.x; float y = screenH - option_size.y; float step = (option_size.y + 2) * -1; float hstep = (option_size.x + 2) * -1; rendererWnd_Toggle->SetPos(XMFLOAT2(x += hstep, y)); rendererWnd_Toggle->SetSize(option_size); postprocessWnd_Toggle->SetPos(XMFLOAT2(x += hstep, y)); postprocessWnd_Toggle->SetSize(option_size); paintToolWnd_Toggle->SetPos(XMFLOAT2(x += hstep, y)); paintToolWnd_Toggle->SetSize(option_size); ///////////////////////// option_size.y = 16; step = (option_size.y + 2) * -1; x = screenW - option_size.x; y = screenH - option_size.y; weatherWnd_Toggle->SetPos(XMFLOAT2(x, y)); weatherWnd_Toggle->SetSize(option_size); objectWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); objectWnd_Toggle->SetSize(option_size); meshWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); meshWnd_Toggle->SetSize(option_size); materialWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); materialWnd_Toggle->SetSize(option_size); cameraWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); cameraWnd_Toggle->SetSize(option_size); envProbeWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); envProbeWnd_Toggle->SetSize(option_size); decalWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); decalWnd_Toggle->SetSize(option_size); soundWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); soundWnd_Toggle->SetSize(option_size); lightWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); lightWnd_Toggle->SetSize(option_size); animWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); animWnd_Toggle->SetSize(option_size); emitterWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); emitterWnd_Toggle->SetSize(option_size); hairWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); hairWnd_Toggle->SetSize(option_size); forceFieldWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); forceFieldWnd_Toggle->SetSize(option_size); springWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); springWnd_Toggle->SetSize(option_size); ikWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); ikWnd_Toggle->SetSize(option_size); transformWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); transformWnd_Toggle->SetSize(option_size); layerWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); layerWnd_Toggle->SetSize(option_size); nameWnd_Toggle->SetPos(XMFLOAT2(x, y += step)); nameWnd_Toggle->SetSize(option_size); //////////////////////////////////////////////////////////////////////////////////// translatorCheckBox->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5 - 25, 0)); translatorCheckBox->SetSize(XMFLOAT2(18, 18)); isScalatorCheckBox->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5 - 25 - 40 * 2, 22)); isScalatorCheckBox->SetSize(XMFLOAT2(18, 18)); isRotatorCheckBox->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5 - 25 - 40 * 1, 22)); isRotatorCheckBox->SetSize(XMFLOAT2(18, 18)); isTranslatorCheckBox->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5 - 25, 22)); isTranslatorCheckBox->SetSize(XMFLOAT2(18, 18)); saveButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 5, 0)); saveButton->SetSize(XMFLOAT2(100, 40)); modelButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 4, 0)); modelButton->SetSize(XMFLOAT2(100, 40)); scriptButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 3, 0)); scriptButton->SetSize(XMFLOAT2(100, 40)); shaderButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 2, 0)); shaderButton->SetSize(XMFLOAT2(100, 40)); clearButton->SetPos(XMFLOAT2(screenW - 50 - 55 - 105 * 1, 0)); clearButton->SetSize(XMFLOAT2(100, 40)); helpButton->SetPos(XMFLOAT2(screenW - 50 - 55, 0)); helpButton->SetSize(XMFLOAT2(50, 40)); helpLabel->SetSize(XMFLOAT2(screenW / 2.0f, screenH / 1.5f)); helpLabel->SetPos(XMFLOAT2(screenW / 2.0f - helpLabel->scale.x / 2.0f, screenH / 2.0f - helpLabel->scale.y / 2.0f)); exitButton->SetPos(XMFLOAT2(screenW - 50, 0)); exitButton->SetSize(XMFLOAT2(50, 40)); profilerEnabledCheckBox->SetSize(XMFLOAT2(20, 20)); profilerEnabledCheckBox->SetPos(XMFLOAT2(screenW - 520, 45)); physicsEnabledCheckBox->SetSize(XMFLOAT2(20, 20)); physicsEnabledCheckBox->SetPos(XMFLOAT2(screenW - 370, 45)); cinemaModeCheckBox->SetSize(XMFLOAT2(20, 20)); cinemaModeCheckBox->SetPos(XMFLOAT2(screenW - 240, 45)); renderPathComboBox->SetSize(XMFLOAT2(100, 20)); renderPathComboBox->SetPos(XMFLOAT2(screenW - 120, 45)); sceneGraphView->SetSize(XMFLOAT2(260, 300)); sceneGraphView->SetPos(XMFLOAT2(0, screenH - sceneGraphView->scale_local.y)); } void EditorComponent::Load() { #ifdef PLATFORM_UWP // On UWP we will copy the base content from application folder to 3D Objects directory // for easy access to the user: StorageFolder^ location = KnownFolders::Objects3D; // Objects3D/WickedEngine create_task(location->CreateFolderAsync("WickedEngine", CreationCollisionOption::OpenIfExists)).then([=](StorageFolder^ destfolder) { string rootdir = wiHelper::ExpandPath(wiHelper::GetOriginalWorkingDirectory()); wstring wstr; // scripts: wiHelper::StringConvert(rootdir + "scripts\\", wstr); create_task(StorageFolder::GetFolderFromPathAsync(ref new String(wstr.c_str()))).then([=](StorageFolder^ src) { if (src) { create_task(destfolder->CreateFolderAsync("scripts", CreationCollisionOption::OpenIfExists)).then([=](StorageFolder^ dst) { if (dst) { copy_folder(src, dst); } }); } }); // models: wiHelper::StringConvert(rootdir + "models\\", wstr); create_task(StorageFolder::GetFolderFromPathAsync(ref new String(wstr.c_str()))).then([=](StorageFolder^ src) { if (src) { create_task(destfolder->CreateFolderAsync("models", CreationCollisionOption::OpenIfExists)).then([=](StorageFolder^ dst) { if (dst) { copy_folder(src, dst); } }); } }); // Documentation: wiHelper::StringConvert(rootdir + "Documentation\\", wstr); create_task(StorageFolder::GetFolderFromPathAsync(ref new String(wstr.c_str()))).then([=](StorageFolder^ src) { if (src) { create_task(destfolder->CreateFolderAsync("Documentation", CreationCollisionOption::OpenIfExists)).then([=](StorageFolder^ dst) { if (dst) { copy_folder(src, dst); } }); } }); }); #endif // PLATFORM_UWP wiJobSystem::context ctx; wiJobSystem::Execute(ctx, [this](wiJobArgs args) { pointLightTex = wiResourceManager::Load("images/pointlight.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { spotLightTex = wiResourceManager::Load("images/spotlight.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { dirLightTex = wiResourceManager::Load("images/directional_light.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { areaLightTex = wiResourceManager::Load("images/arealight.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { decalTex = wiResourceManager::Load("images/decal.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { forceFieldTex = wiResourceManager::Load("images/forcefield.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { emitterTex = wiResourceManager::Load("images/emitter.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { hairTex = wiResourceManager::Load("images/hair.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { cameraTex = wiResourceManager::Load("images/camera.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { armatureTex = wiResourceManager::Load("images/armature.dds"); }); wiJobSystem::Execute(ctx, [this](wiJobArgs args) { soundTex = wiResourceManager::Load("images/sound.dds"); }); // wait for ctx is at the end of this function! translator.enabled = false; rendererWnd_Toggle = new wiButton("Renderer"); rendererWnd_Toggle->SetTooltip("Renderer settings window"); rendererWnd_Toggle->OnClick([=](wiEventArgs args) { rendererWnd->rendererWindow->SetVisible(!rendererWnd->rendererWindow->IsVisible()); }); GetGUI().AddWidget(rendererWnd_Toggle); postprocessWnd_Toggle = new wiButton("PostProcess"); postprocessWnd_Toggle->SetTooltip("Postprocess settings window"); postprocessWnd_Toggle->OnClick([=](wiEventArgs args) { postprocessWnd->ppWindow->SetVisible(!postprocessWnd->ppWindow->IsVisible()); }); GetGUI().AddWidget(postprocessWnd_Toggle); paintToolWnd_Toggle = new wiButton("Paint Tool"); paintToolWnd_Toggle->SetTooltip("Paint tool window"); paintToolWnd_Toggle->OnClick([=](wiEventArgs args) { paintToolWnd->window->SetVisible(!paintToolWnd->window->IsVisible()); }); GetGUI().AddWidget(paintToolWnd_Toggle); /////////////////////// wiColor option_color_idle = wiColor(255, 145, 145, 100); wiColor option_color_focus = wiColor(255, 197, 193, 200); weatherWnd_Toggle = new wiButton("Weather"); weatherWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); weatherWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); weatherWnd_Toggle->SetTooltip("Weather settings window"); weatherWnd_Toggle->OnClick([=](wiEventArgs args) { weatherWnd->weatherWindow->SetVisible(!weatherWnd->weatherWindow->IsVisible()); }); GetGUI().AddWidget(weatherWnd_Toggle); objectWnd_Toggle = new wiButton("Object"); objectWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); objectWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); objectWnd_Toggle->SetTooltip("Object settings window"); objectWnd_Toggle->OnClick([=](wiEventArgs args) { objectWnd->objectWindow->SetVisible(!objectWnd->objectWindow->IsVisible()); }); GetGUI().AddWidget(objectWnd_Toggle); meshWnd_Toggle = new wiButton("Mesh"); meshWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); meshWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); meshWnd_Toggle->SetTooltip("Mesh settings window"); meshWnd_Toggle->OnClick([=](wiEventArgs args) { meshWnd->meshWindow->SetVisible(!meshWnd->meshWindow->IsVisible()); }); GetGUI().AddWidget(meshWnd_Toggle); materialWnd_Toggle = new wiButton("Material"); materialWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); materialWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); materialWnd_Toggle->SetTooltip("Material settings window"); materialWnd_Toggle->OnClick([=](wiEventArgs args) { materialWnd->materialWindow->SetVisible(!materialWnd->materialWindow->IsVisible()); }); GetGUI().AddWidget(materialWnd_Toggle); cameraWnd_Toggle = new wiButton("Camera"); cameraWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); cameraWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); cameraWnd_Toggle->SetTooltip("Camera settings window"); cameraWnd_Toggle->OnClick([=](wiEventArgs args) { cameraWnd->cameraWindow->SetVisible(!cameraWnd->cameraWindow->IsVisible()); }); GetGUI().AddWidget(cameraWnd_Toggle); envProbeWnd_Toggle = new wiButton("EnvProbe"); envProbeWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); envProbeWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); envProbeWnd_Toggle->SetTooltip("Environment probe settings window"); envProbeWnd_Toggle->OnClick([=](wiEventArgs args) { envProbeWnd->envProbeWindow->SetVisible(!envProbeWnd->envProbeWindow->IsVisible()); }); GetGUI().AddWidget(envProbeWnd_Toggle); decalWnd_Toggle = new wiButton("Decal"); decalWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); decalWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); decalWnd_Toggle->SetTooltip("Decal settings window"); decalWnd_Toggle->OnClick([=](wiEventArgs args) { decalWnd->decalWindow->SetVisible(!decalWnd->decalWindow->IsVisible()); }); GetGUI().AddWidget(decalWnd_Toggle); soundWnd_Toggle = new wiButton("Sound"); soundWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); soundWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); soundWnd_Toggle->SetTooltip("Sound settings window"); soundWnd_Toggle->OnClick([=](wiEventArgs args) { soundWnd->soundWindow->SetVisible(!soundWnd->soundWindow->IsVisible()); }); GetGUI().AddWidget(soundWnd_Toggle); lightWnd_Toggle = new wiButton("Light"); lightWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); lightWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); lightWnd_Toggle->SetTooltip("Light settings window"); lightWnd_Toggle->OnClick([=](wiEventArgs args) { lightWnd->lightWindow->SetVisible(!lightWnd->lightWindow->IsVisible()); }); GetGUI().AddWidget(lightWnd_Toggle); animWnd_Toggle = new wiButton("Animation"); animWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); animWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); animWnd_Toggle->SetTooltip("Animation inspector window"); animWnd_Toggle->OnClick([=](wiEventArgs args) { animWnd->animWindow->SetVisible(!animWnd->animWindow->IsVisible()); }); GetGUI().AddWidget(animWnd_Toggle); emitterWnd_Toggle = new wiButton("Emitter"); emitterWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); emitterWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); emitterWnd_Toggle->SetTooltip("Emitter Particle System properties"); emitterWnd_Toggle->OnClick([=](wiEventArgs args) { emitterWnd->emitterWindow->SetVisible(!emitterWnd->emitterWindow->IsVisible()); }); GetGUI().AddWidget(emitterWnd_Toggle); hairWnd_Toggle = new wiButton("HairParticle"); hairWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); hairWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); hairWnd_Toggle->SetTooltip("Hair Particle System properties"); hairWnd_Toggle->OnClick([=](wiEventArgs args) { hairWnd->hairWindow->SetVisible(!hairWnd->hairWindow->IsVisible()); }); GetGUI().AddWidget(hairWnd_Toggle); forceFieldWnd_Toggle = new wiButton("ForceField"); forceFieldWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); forceFieldWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); forceFieldWnd_Toggle->SetTooltip("Force Field properties"); forceFieldWnd_Toggle->OnClick([=](wiEventArgs args) { forceFieldWnd->forceFieldWindow->SetVisible(!forceFieldWnd->forceFieldWindow->IsVisible()); }); GetGUI().AddWidget(forceFieldWnd_Toggle); springWnd_Toggle = new wiButton("Spring"); springWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); springWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); springWnd_Toggle->SetTooltip("Spring properties"); springWnd_Toggle->OnClick([=](wiEventArgs args) { springWnd->window->SetVisible(!springWnd->window->IsVisible()); }); GetGUI().AddWidget(springWnd_Toggle); ikWnd_Toggle = new wiButton("IK"); ikWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); ikWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); ikWnd_Toggle->SetTooltip("Inverse Kinematics properties"); ikWnd_Toggle->OnClick([=](wiEventArgs args) { ikWnd->window->SetVisible(!ikWnd->window->IsVisible()); }); GetGUI().AddWidget(ikWnd_Toggle); transformWnd_Toggle = new wiButton("Transform"); transformWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); transformWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); transformWnd_Toggle->SetTooltip("Transform properties"); transformWnd_Toggle->OnClick([=](wiEventArgs args) { transformWnd->window->SetVisible(!transformWnd->window->IsVisible()); }); GetGUI().AddWidget(transformWnd_Toggle); layerWnd_Toggle = new wiButton("Layer"); layerWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); layerWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); layerWnd_Toggle->SetTooltip("Layer Component"); layerWnd_Toggle->OnClick([=](wiEventArgs args) { layerWnd->window->SetVisible(!layerWnd->window->IsVisible()); }); GetGUI().AddWidget(layerWnd_Toggle); nameWnd_Toggle = new wiButton("Name"); nameWnd_Toggle->SetColor(option_color_idle, wiWidget::IDLE); nameWnd_Toggle->SetColor(option_color_focus, wiWidget::FOCUS); nameWnd_Toggle->SetTooltip("Name Component"); nameWnd_Toggle->OnClick([=](wiEventArgs args) { nameWnd->window->SetVisible(!nameWnd->window->IsVisible()); }); GetGUI().AddWidget(nameWnd_Toggle); //////////////////////////////////////////////////////////////////////////////////// translatorCheckBox = new wiCheckBox("Translator: "); translatorCheckBox->SetTooltip("Enable the translator tool"); translatorCheckBox->OnClick([&](wiEventArgs args) { translator.enabled = args.bValue; }); GetGUI().AddWidget(translatorCheckBox); isScalatorCheckBox = new wiCheckBox("S: "); isRotatorCheckBox = new wiCheckBox("R: "); isTranslatorCheckBox = new wiCheckBox("T: "); { isScalatorCheckBox->SetTooltip("Scale"); isScalatorCheckBox->OnClick([&](wiEventArgs args) { translator.isScalator = args.bValue; translator.isTranslator = false; translator.isRotator = false; isTranslatorCheckBox->SetCheck(false); isRotatorCheckBox->SetCheck(false); }); isScalatorCheckBox->SetCheck(translator.isScalator); GetGUI().AddWidget(isScalatorCheckBox); isRotatorCheckBox->SetTooltip("Rotate"); isRotatorCheckBox->OnClick([&](wiEventArgs args) { translator.isRotator = args.bValue; translator.isScalator = false; translator.isTranslator = false; isScalatorCheckBox->SetCheck(false); isTranslatorCheckBox->SetCheck(false); }); isRotatorCheckBox->SetCheck(translator.isRotator); GetGUI().AddWidget(isRotatorCheckBox); isTranslatorCheckBox->SetTooltip("Translate"); isTranslatorCheckBox->OnClick([&](wiEventArgs args) { translator.isTranslator = args.bValue; translator.isScalator = false; translator.isRotator = false; isScalatorCheckBox->SetCheck(false); isRotatorCheckBox->SetCheck(false); }); isTranslatorCheckBox->SetCheck(translator.isTranslator); GetGUI().AddWidget(isTranslatorCheckBox); } saveButton = new wiButton("Save"); saveButton->SetTooltip("Save the current scene"); saveButton->SetColor(wiColor(0, 198, 101, 180), wiWidget::WIDGETSTATE::IDLE); saveButton->SetColor(wiColor(0, 255, 140, 255), wiWidget::WIDGETSTATE::FOCUS); saveButton->OnClick([=](wiEventArgs args) { wiHelper::FileDialogParams params; params.type = wiHelper::FileDialogParams::SAVE; params.description = "Wicked Scene"; params.extensions.push_back("wiscene"); wiHelper::FileDialog(params, [this](std::string fileName) { wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { std::string filename = fileName; if (filename.substr(filename.length() - 8).compare(".wiscene") != 0) { filename += ".wiscene"; } wiArchive archive(fileName, false); if (archive.IsOpen()) { Scene& scene = wiScene::GetScene(); scene.Serialize(archive); ResetHistory(); } else { wiHelper::messageBox("Could not create " + fileName + "!"); } }); }); }); GetGUI().AddWidget(saveButton); modelButton = new wiButton("Load Model"); modelButton->SetTooltip("Load a scene / import model into the editor..."); modelButton->SetColor(wiColor(0, 89, 255, 180), wiWidget::WIDGETSTATE::IDLE); modelButton->SetColor(wiColor(112, 155, 255, 255), wiWidget::WIDGETSTATE::FOCUS); modelButton->OnClick([=](wiEventArgs args) { wiHelper::FileDialogParams params; params.type = wiHelper::FileDialogParams::OPEN; params.description = "Model formats (.wiscene, .obj, .gltf, .glb)"; params.extensions.push_back("wiscene"); params.extensions.push_back("obj"); params.extensions.push_back("gltf"); params.extensions.push_back("glb"); wiHelper::FileDialog(params, [&](std::string fileName) { wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { main->loader->addLoadingFunction([=](wiJobArgs args) { string extension = wiHelper::toUpper(wiHelper::GetExtensionFromFileName(fileName)); if (!extension.compare("WISCENE")) // engine-serialized { wiScene::LoadModel(fileName); } else if (!extension.compare("OBJ")) // wavefront-obj { Scene scene; ImportModel_OBJ(fileName, scene); wiScene::GetScene().Merge(scene); } else if (!extension.compare("GLTF")) // text-based gltf { Scene scene; ImportModel_GLTF(fileName, scene); wiScene::GetScene().Merge(scene); } else if (!extension.compare("GLB")) // binary gltf { Scene scene; ImportModel_GLTF(fileName, scene); wiScene::GetScene().Merge(scene); } }); main->loader->onFinished([=] { main->ActivatePath(this, 0.2f, wiColor::Black()); weatherWnd->Update(); }); main->ActivatePath(main->loader.get(), 0.2f, wiColor::Black()); ResetHistory(); }); }); }); GetGUI().AddWidget(modelButton); scriptButton = new wiButton("Load Script"); scriptButton->SetTooltip("Load a Lua script..."); scriptButton->SetColor(wiColor(255, 33, 140, 180), wiWidget::WIDGETSTATE::IDLE); scriptButton->SetColor(wiColor(255, 100, 140, 255), wiWidget::WIDGETSTATE::FOCUS); scriptButton->OnClick([=](wiEventArgs args) { wiHelper::FileDialogParams params; params.type = wiHelper::FileDialogParams::OPEN; params.description = "Lua script"; params.extensions.push_back("lua"); wiHelper::FileDialog(params, [](std::string fileName) { wiEvent::Subscribe_Once(SYSTEM_EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { wiLua::RunFile(fileName); }); }); }); GetGUI().AddWidget(scriptButton); shaderButton = new wiButton("Reload Shaders"); shaderButton->SetTooltip("Reload shaders from the default directory..."); shaderButton->SetColor(wiColor(255, 33, 140, 180), wiWidget::WIDGETSTATE::IDLE); shaderButton->SetColor(wiColor(255, 100, 140, 255), wiWidget::WIDGETSTATE::FOCUS); shaderButton->font.params.size -= 2; shaderButton->OnClick([=](wiEventArgs args) { wiRenderer::ReloadShaders(); }); GetGUI().AddWidget(shaderButton); clearButton = new wiButton("Clear World"); clearButton->SetTooltip("Delete every model from the scene"); 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(); wiRenderer::ClearWorld(); objectWnd->SetEntity(INVALID_ENTITY); meshWnd->SetEntity(INVALID_ENTITY); lightWnd->SetEntity(INVALID_ENTITY); soundWnd->SetEntity(INVALID_ENTITY); decalWnd->SetEntity(INVALID_ENTITY); envProbeWnd->SetEntity(INVALID_ENTITY); materialWnd->SetEntity(INVALID_ENTITY); emitterWnd->SetEntity(INVALID_ENTITY); hairWnd->SetEntity(INVALID_ENTITY); forceFieldWnd->SetEntity(INVALID_ENTITY); cameraWnd->SetEntity(INVALID_ENTITY); paintToolWnd->SetEntity(INVALID_ENTITY); springWnd->SetEntity(INVALID_ENTITY); ikWnd->SetEntity(INVALID_ENTITY); transformWnd->SetEntity(INVALID_ENTITY); layerWnd->SetEntity(INVALID_ENTITY); nameWnd->SetEntity(INVALID_ENTITY); }); GetGUI().AddWidget(clearButton); helpButton = new wiButton("?"); helpButton->SetTooltip("Help"); helpButton->SetColor(wiColor(34, 158, 214, 180), wiWidget::WIDGETSTATE::IDLE); helpButton->SetColor(wiColor(113, 183, 214, 255), wiWidget::WIDGETSTATE::FOCUS); helpButton->OnClick([=](wiEventArgs args) { helpLabel->SetVisible(!helpLabel->IsVisible()); }); GetGUI().AddWidget(helpButton); { stringstream ss(""); ss << "Help:" << endl; ss << "Move camera: WASD, or Contoller left stick or D-pad" << endl; ss << "Look: Middle mouse button / arrow keys / controller right stick" << endl; ss << "Select: Right mouse button" << endl; ss << "Place decal, interact with water: Left mouse button when nothing is selected" << endl; ss << "Camera speed: SHIFT button or controller R2/RT" << endl; ss << "Camera up: E, down: Q" << endl; ss << "Duplicate entity: Ctrl + D" << endl; ss << "Select All: Ctrl + A" << endl; ss << "Undo: Ctrl + Z" << endl; ss << "Redo: Ctrl + Y" << endl; ss << "Copy: Ctrl + C" << endl; ss << "Paste: Ctrl + V" << endl; ss << "Delete: DELETE button" << endl; ss << "Place Instances: Ctrl + Shift + Left mouse click (place clipboard onto clicked surface)" << endl; ss << "Script Console / backlog: HOME button" << endl; ss << endl; ss << "You can find sample scenes in the models directory. Try to load one." << endl; ss << "You can also import models from .OBJ, .GLTF, .GLB files." << endl; ss << "You can find a program configuration file at Editor/config.ini" << endl; ss << "You can find sample LUA scripts in the scripts directory. Try to load one." << endl; ss << "You can find a startup script at Editor/startup.lua (this will be executed on program start)" << endl; ss << endl << "For questions, bug reports, feedback, requests, please open an issue at:" << endl; ss << "https://github.com/turanszkij/WickedEngine" << endl; ss << endl << "Devblog: https://wickedengine.net/" << endl; ss << "Discord: https://discord.gg/CFjRYmE" << endl; helpLabel = new wiLabel("HelpLabel"); helpLabel->SetText(ss.str()); helpLabel->SetVisible(false); GetGUI().AddWidget(helpLabel); } exitButton = new wiButton("X"); exitButton->SetTooltip("Exit"); 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) { wiPlatform::Exit(); }); GetGUI().AddWidget(exitButton); profilerEnabledCheckBox = new wiCheckBox("Profiler Enabled: "); profilerEnabledCheckBox->SetTooltip("Toggle Profiler On/Off"); profilerEnabledCheckBox->OnClick([&](wiEventArgs args) { wiProfiler::SetEnabled(args.bValue); }); profilerEnabledCheckBox->SetCheck(wiProfiler::IsEnabled()); GetGUI().AddWidget(profilerEnabledCheckBox); physicsEnabledCheckBox = new wiCheckBox("Physics Enabled: "); physicsEnabledCheckBox->SetTooltip("Toggle Physics Engine On/Off"); physicsEnabledCheckBox->OnClick([&](wiEventArgs args) { wiPhysicsEngine::SetEnabled(args.bValue); }); physicsEnabledCheckBox->SetCheck(wiPhysicsEngine::IsEnabled()); GetGUI().AddWidget(physicsEnabledCheckBox); cinemaModeCheckBox = new wiCheckBox("Cinema Mode: "); cinemaModeCheckBox->SetTooltip("Toggle Cinema Mode (All HUD disabled). Press ESC to exit."); cinemaModeCheckBox->OnClick([&](wiEventArgs args) { if (renderPath != nullptr) { renderPath->GetGUI().SetVisible(false); } GetGUI().SetVisible(false); wiProfiler::SetEnabled(false); main->infoDisplay.active = false; }); GetGUI().AddWidget(cinemaModeCheckBox); sceneGraphView = new wiTreeList("Scene graph view"); sceneGraphView->OnSelect([this](wiEventArgs args) { translator.selected.clear(); for (int i = 0; i < sceneGraphView->GetItemCount(); ++i) { const wiTreeList::Item& item = sceneGraphView->GetItem(i); if (item.selected) { wiScene::PickResult pick; pick.entity = (Entity)item.userdata; AddSelected(pick); } } }); GetGUI().AddWidget(sceneGraphView); renderPathComboBox = new wiComboBox("Render Path: "); renderPathComboBox->AddItem("Forward"); renderPathComboBox->AddItem("Deferred"); renderPathComboBox->AddItem("Tiled Forward"); renderPathComboBox->AddItem("Tiled Deferred"); renderPathComboBox->AddItem("Path Tracing"); renderPathComboBox->OnSelect([&](wiEventArgs args) { switch (args.iValue) { case 0: ChangeRenderPath(RENDERPATH_FORWARD); break; case 1: ChangeRenderPath(RENDERPATH_DEFERRED); break; case 2: ChangeRenderPath(RENDERPATH_TILEDFORWARD); break; case 3: ChangeRenderPath(RENDERPATH_TILEDDEFERRED); break; case 4: ChangeRenderPath(RENDERPATH_PATHTRACING); break; default: break; } }); renderPathComboBox->SetSelected(2); renderPathComboBox->SetEnabled(true); renderPathComboBox->SetTooltip("Choose a render path..."); GetGUI().AddWidget(renderPathComboBox); cameraWnd->ResetCam(); wiJobSystem::Wait(ctx); __super::Load(); } void EditorComponent::Start() { __super::Start(); } void EditorComponent::FixedUpdate() { __super::FixedUpdate(); renderPath->FixedUpdate(); } void EditorComponent::PushToSceneGraphView(wiECS::Entity entity, int level) { if (scenegraphview_added_items.count(entity) != 0) { return; } const Scene& scene = wiScene::GetScene(); wiTreeList::Item item; item.level = level; item.userdata = entity; item.selected = IsSelected(entity); item.open = scenegraphview_opened_items.count(entity) != 0; const NameComponent* name = scene.names.GetComponent(entity); item.name = name == nullptr ? std::to_string(entity) : name->name; sceneGraphView->AddItem(item); scenegraphview_added_items.insert(entity); for (size_t i = 0; i < scene.hierarchy.GetCount(); ++i) { if (scene.hierarchy[i].parentID == entity) { PushToSceneGraphView(scene.hierarchy.GetEntity(i), level + 1); } } } void EditorComponent::Update(float dt) { wiProfiler::range_id profrange = wiProfiler::BeginRangeCPU("Editor Update"); Scene& scene = wiScene::GetScene(); CameraComponent& camera = wiRenderer::GetCamera(); animWnd->Update(); weatherWnd->Update(); paintToolWnd->Update(dt); selectionOutlineTimer += dt; // Update scene graph view: if(sceneGraphView != nullptr) { for (int i = 0; i < sceneGraphView->GetItemCount(); ++i) { const wiTreeList::Item& item = sceneGraphView->GetItem(i); if (item.open) { scenegraphview_opened_items.insert((Entity)item.userdata); } } sceneGraphView->ClearItems(); // Add hierarchy: for (size_t i = 0; i < scene.hierarchy.GetCount(); ++i) { PushToSceneGraphView(scene.hierarchy[i].parentID, 0); } // Any transform left that is not part of a hierarchy: for (size_t i = 0; i < scene.transforms.GetCount(); ++i) { PushToSceneGraphView(scene.transforms.GetEntity(i), 0); } // Add materials: for (size_t i = 0; i < scene.materials.GetCount(); ++i) { Entity entity = scene.materials.GetEntity(i); if (scenegraphview_added_items.count(entity) != 0) { continue; } wiTreeList::Item item; item.userdata = entity; item.selected = IsSelected(entity); item.open = scenegraphview_opened_items.count(entity) != 0; const NameComponent* name = scene.names.GetComponent(entity); item.name = name == nullptr ? std::to_string(entity) : name->name; sceneGraphView->AddItem(item); scenegraphview_added_items.insert(entity); } // Add meshes: for (size_t i = 0; i < scene.meshes.GetCount(); ++i) { Entity entity = scene.meshes.GetEntity(i); if (scenegraphview_added_items.count(entity) != 0) { continue; } wiTreeList::Item item; item.userdata = entity; item.selected = IsSelected(entity); item.open = scenegraphview_opened_items.count(entity) != 0; const NameComponent* name = scene.names.GetComponent(entity); item.name = name == nullptr ? std::to_string(entity) : name->name; sceneGraphView->AddItem(item); scenegraphview_added_items.insert(entity); } scenegraphview_added_items.clear(); scenegraphview_opened_items.clear(); } // Exit cinema mode: if (wiInput::Down(wiInput::KEYBOARD_BUTTON_ESCAPE)) { if (renderPath != nullptr) { renderPath->GetGUI().SetVisible(true); } GetGUI().SetVisible(true); main->infoDisplay.active = true; cinemaModeCheckBox->SetCheck(false); } // Camera control: static XMFLOAT4 originalMouse = XMFLOAT4(0, 0, 0, 0); static bool camControlStart = true; if (camControlStart) { originalMouse = wiInput::GetPointer(); } XMFLOAT4 currentMouse = wiInput::GetPointer(); float xDif = 0, yDif = 0; if (wiInput::Down(wiInput::MOUSE_BUTTON_MIDDLE)) { camControlStart = false; #if 0 // Mouse delta from previous frame: xDif = currentMouse.x - originalMouse.x; yDif = currentMouse.y - originalMouse.y; #else // Mouse delta from hardware read: xDif = wiInput::GetMouseState().delta_position.x; yDif = wiInput::GetMouseState().delta_position.y; #endif xDif = 0.1f * xDif * (1.0f / 60.0f); yDif = 0.1f * yDif * (1.0f / 60.0f); wiInput::SetPointer(originalMouse); wiInput::HidePointer(true); } else { camControlStart = true; wiInput::HidePointer(false); } const float buttonrotSpeed = 2.0f / 60.0f; if (wiInput::Down(wiInput::KEYBOARD_BUTTON_LEFT)) { xDif -= buttonrotSpeed; } if (wiInput::Down(wiInput::KEYBOARD_BUTTON_RIGHT)) { xDif += buttonrotSpeed; } if (wiInput::Down(wiInput::KEYBOARD_BUTTON_UP)) { yDif -= buttonrotSpeed; } if (wiInput::Down(wiInput::KEYBOARD_BUTTON_DOWN)) { yDif += buttonrotSpeed; } const XMFLOAT4 leftStick = wiInput::GetAnalog(wiInput::GAMEPAD_ANALOG_THUMBSTICK_L, 0); const XMFLOAT4 rightStick = wiInput::GetAnalog(wiInput::GAMEPAD_ANALOG_THUMBSTICK_R, 0); const XMFLOAT4 rightTrigger = wiInput::GetAnalog(wiInput::GAMEPAD_ANALOG_TRIGGER_R, 0); const float jostickrotspeed = 0.05f; xDif += rightStick.x * jostickrotspeed; yDif += rightStick.y * jostickrotspeed; xDif *= cameraWnd->rotationspeedSlider->GetValue(); yDif *= cameraWnd->rotationspeedSlider->GetValue(); if (cameraWnd->fpsCheckBox->GetCheck()) { // FPS Camera const float clampedDT = min(dt, 0.1f); // if dt > 100 millisec, don't allow the camera to jump too far... const float speed = ((wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT) ? 10.0f : 1.0f) + rightTrigger.x * 10.0f) * cameraWnd->movespeedSlider->GetValue() * clampedDT; static XMVECTOR move = XMVectorSet(0, 0, 0, 0); XMVECTOR moveNew = XMVectorSet(leftStick.x, 0, leftStick.y, 0); if (!wiInput::Down(wiInput::KEYBOARD_BUTTON_LCONTROL)) { // Only move camera if control not pressed if (wiInput::Down((wiInput::BUTTON)'A') || wiInput::Down(wiInput::GAMEPAD_BUTTON_LEFT)) { moveNew += XMVectorSet(-1, 0, 0, 0); } if (wiInput::Down((wiInput::BUTTON)'D') || wiInput::Down(wiInput::GAMEPAD_BUTTON_RIGHT)) { moveNew += XMVectorSet(1, 0, 0, 0); } if (wiInput::Down((wiInput::BUTTON)'W') || wiInput::Down(wiInput::GAMEPAD_BUTTON_UP)) { moveNew += XMVectorSet(0, 0, 1, 0); } if (wiInput::Down((wiInput::BUTTON)'S') || wiInput::Down(wiInput::GAMEPAD_BUTTON_DOWN)) { moveNew += XMVectorSet(0, 0, -1, 0); } if (wiInput::Down((wiInput::BUTTON)'E') || wiInput::Down(wiInput::GAMEPAD_BUTTON_2)) { moveNew += XMVectorSet(0, 1, 0, 0); } if (wiInput::Down((wiInput::BUTTON)'Q') || wiInput::Down(wiInput::GAMEPAD_BUTTON_1)) { moveNew += XMVectorSet(0, -1, 0, 0); } moveNew += XMVector3Normalize(moveNew); } moveNew *= speed; move = XMVectorLerp(move, moveNew, 0.18f * clampedDT / 0.0166f); // smooth the movement a bit float moveLength = XMVectorGetX(XMVector3Length(move)); if (moveLength < 0.0001f) { move = XMVectorSet(0, 0, 0, 0); } if (abs(xDif) + abs(yDif) > 0 || moveLength > 0.0001f) { XMMATRIX camRot = XMMatrixRotationQuaternion(XMLoadFloat4(&cameraWnd->camera_transform.rotation_local)); XMVECTOR move_rot = XMVector3TransformNormal(move, camRot); XMFLOAT3 _move; XMStoreFloat3(&_move, move_rot); cameraWnd->camera_transform.Translate(_move); cameraWnd->camera_transform.RotateRollPitchYaw(XMFLOAT3(yDif, xDif, 0)); camera.SetDirty(); } cameraWnd->camera_transform.UpdateTransform(); } else { // Orbital Camera if (wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT)) { XMVECTOR V = XMVectorAdd(camera.GetRight() * xDif, camera.GetUp() * yDif) * 10; XMFLOAT3 vec; XMStoreFloat3(&vec, V); cameraWnd->camera_target.Translate(vec); } else if (wiInput::Down(wiInput::KEYBOARD_BUTTON_LCONTROL) || currentMouse.z != 0.0f) { cameraWnd->camera_transform.Translate(XMFLOAT3(0, 0, yDif * 4 + currentMouse.z)); cameraWnd->camera_transform.translation_local.z = std::min(0.0f, cameraWnd->camera_transform.translation_local.z); camera.SetDirty(); } else if (abs(xDif) + abs(yDif) > 0) { cameraWnd->camera_target.RotateRollPitchYaw(XMFLOAT3(yDif * 2, xDif * 2, 0)); camera.SetDirty(); } cameraWnd->camera_target.UpdateTransform(); cameraWnd->camera_transform.UpdateTransform_Parented(cameraWnd->camera_target); } if (!wiBackLog::isActive() && !GetGUI().HasFocus()) { // Begin picking: UINT pickMask = rendererWnd->GetPickType(); RAY pickRay = wiRenderer::GetPickRay((long)currentMouse.x, (long)currentMouse.y); { hovered = wiScene::PickResult(); // Try to pick objects-meshes: if (pickMask & PICK_OBJECT) { hovered = wiScene::Pick(pickRay, pickMask); } if (pickMask & PICK_LIGHT) { for (size_t i = 0; i < scene.lights.GetCount(); ++i) { Entity entity = scene.lights.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_DECAL) { for (size_t i = 0; i < scene.decals.GetCount(); ++i) { Entity entity = scene.decals.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_FORCEFIELD) { for (size_t i = 0; i < scene.forces.GetCount(); ++i) { Entity entity = scene.forces.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_EMITTER) { for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { Entity entity = scene.emitters.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_HAIR) { for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { Entity entity = scene.hairs.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_ENVPROBE) { for (size_t i = 0; i < scene.probes.GetCount(); ++i) { Entity entity = scene.probes.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); if (SPHERE(transform.GetPosition(), 1).intersects(pickRay)) { float dis = wiMath::Distance(transform.GetPosition(), pickRay.origin); if (dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } } if (pickMask & PICK_CAMERA) { for (size_t i = 0; i < scene.cameras.GetCount(); ++i) { Entity entity = scene.cameras.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_ARMATURE) { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { Entity entity = scene.armatures.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } if (pickMask & PICK_SOUND) { for (size_t i = 0; i < scene.sounds.GetCount(); ++i) { Entity entity = scene.sounds.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); XMVECTOR disV = XMVector3LinePointDistance(XMLoadFloat3(&pickRay.origin), XMLoadFloat3(&pickRay.origin) + XMLoadFloat3(&pickRay.direction), transform.GetPositionV()); float dis = XMVectorGetX(disV); if (dis < wiMath::Distance(transform.GetPosition(), pickRay.origin) * 0.05f && dis < hovered.distance) { hovered = wiScene::PickResult(); hovered.entity = entity; hovered.distance = dis; } } } } // Interactions only when paint tool is disabled: if (paintToolWnd->GetMode() == PaintToolWindow::MODE_DISABLED) { // Interact: if (hovered.entity != INVALID_ENTITY) { const ObjectComponent* object = scene.objects.GetComponent(hovered.entity); if (object != nullptr) { if (translator.selected.empty() && object->GetRenderTypes() & RENDERTYPE_WATER) { if (wiInput::Down(wiInput::MOUSE_BUTTON_LEFT)) { // if water, then put a water ripple onto it: wiRenderer::PutWaterRipple(wiHelper::GetOriginalWorkingDirectory() + "images/ripple.png", hovered.position); } } else if (translator.selected.empty() && wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) { // if not water or softbody, put a decal on it: static int decalselector = 0; decalselector = (decalselector + 1) % 2; Entity entity = scene.Entity_CreateDecal("editorDecal", wiHelper::GetOriginalWorkingDirectory() + (decalselector == 0 ? "images/leaf.dds" : "images/blood1.png")); TransformComponent& transform = *scene.transforms.GetComponent(entity); transform.MatrixTransform(hovered.orientation); transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV2, 0, 0)); transform.Scale(XMFLOAT3(2, 2, 2)); scene.Component_Attach(entity, hovered.entity); } } } } // Select... static bool selectAll = false; if (wiInput::Press(wiInput::MOUSE_BUTTON_RIGHT) || selectAll) { wiArchive& archive = AdvanceHistory(); archive << HISTORYOP_SELECTION; // record PREVIOUS selection state... archive << translator.selected.size(); for (auto& x : translator.selected) { archive << x.entity; archive << x.position; archive << x.normal; archive << x.subsetIndex; archive << x.distance; } if (selectAll) { // Add everything to selection: selectAll = false; for (size_t i = 0; i < scene.transforms.GetCount(); ++i) { Entity entity = scene.transforms.GetEntity(i); if (scene.hierarchy.Contains(entity)) { // Parented animated objects don't work properly when attached to translator in bulk continue; } wiScene::PickResult picked; picked.entity = entity; AddSelected(picked); } } else if (hovered.entity != INVALID_ENTITY) { // Add the hovered item to the selection: if (!translator.selected.empty() && wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT)) { // Union selection: list saved = translator.selected; translator.selected.clear(); for (const wiScene::PickResult& picked : saved) { AddSelected(picked); } AddSelected(hovered); } else { // Replace selection: translator.selected.clear(); AddSelected(hovered); } } else { // Clear selection: translator.selected.clear(); } // record NEW selection state... archive << translator.selected.size(); for (auto& x : translator.selected) { archive << x.entity; archive << x.position; archive << x.normal; archive << x.subsetIndex; archive << x.distance; } } // Control operations... if (wiInput::Down(wiInput::KEYBOARD_BUTTON_LCONTROL)) { // Select All if (wiInput::Press((wiInput::BUTTON)'A')) { selectAll = true; } // Copy if (wiInput::Press((wiInput::BUTTON)'C')) { auto prevSel = translator.selected; clipboard.SetReadModeAndResetPos(false); clipboard << prevSel.size(); for (auto& x : prevSel) { scene.Entity_Serialize(clipboard, x.entity, 0); } } // Paste if (wiInput::Press((wiInput::BUTTON)'V')) { auto prevSel = translator.selected; translator.selected.clear(); clipboard.SetReadModeAndResetPos(true); size_t count; clipboard >> count; for (size_t i = 0; i < count; ++i) { wiScene::PickResult picked; picked.entity = scene.Entity_Serialize(clipboard, INVALID_ENTITY, CreateEntity(), false); AddSelected(picked); } } // Duplicate Instances if (wiInput::Press((wiInput::BUTTON)'D')) { auto prevSel = translator.selected; translator.selected.clear(); for (auto& x : prevSel) { wiScene::PickResult picked; picked.entity = scene.Entity_Duplicate(x.entity); AddSelected(picked); } } // Put Instances if (clipboard.IsOpen() && hovered.subsetIndex >= 0 && wiInput::Down(wiInput::KEYBOARD_BUTTON_LSHIFT) && wiInput::Press(wiInput::MOUSE_BUTTON_LEFT)) { TransformComponent parent_transform; parent_transform.MatrixTransform(hovered.orientation); parent_transform.UpdateTransform(); clipboard.SetReadModeAndResetPos(true); size_t count; clipboard >> count; for (size_t i = 0; i < count; ++i) { Entity entity = scene.Entity_Serialize(clipboard, INVALID_ENTITY, CreateEntity(), false); TransformComponent* transform = scene.transforms.GetComponent(entity); if (transform != nullptr) { transform->UpdateTransform_Parented(parent_transform); } } } // Undo if (wiInput::Press((wiInput::BUTTON)'Z')) { ConsumeHistoryOperation(true); } // Redo if (wiInput::Press((wiInput::BUTTON)'Y')) { ConsumeHistoryOperation(false); } } } // Delete if (wiInput::Press(wiInput::KEYBOARD_BUTTON_DELETE)) { wiArchive& archive = AdvanceHistory(); archive << HISTORYOP_DELETE; archive << translator.selected.size(); for (auto& x : translator.selected) { archive << x.entity; } for (auto& x : translator.selected) { scene.Entity_Serialize(archive, x.entity); } for (auto& x : translator.selected) { scene.Entity_Remove(x.entity); } translator.selected.clear(); } // Update window data bindings... if (translator.selected.empty()) { objectWnd->SetEntity(INVALID_ENTITY); emitterWnd->SetEntity(INVALID_ENTITY); hairWnd->SetEntity(INVALID_ENTITY); meshWnd->SetEntity(INVALID_ENTITY); materialWnd->SetEntity(INVALID_ENTITY); lightWnd->SetEntity(INVALID_ENTITY); soundWnd->SetEntity(INVALID_ENTITY); decalWnd->SetEntity(INVALID_ENTITY); envProbeWnd->SetEntity(INVALID_ENTITY); forceFieldWnd->SetEntity(INVALID_ENTITY); cameraWnd->SetEntity(INVALID_ENTITY); paintToolWnd->SetEntity(INVALID_ENTITY); springWnd->SetEntity(INVALID_ENTITY); ikWnd->SetEntity(INVALID_ENTITY); transformWnd->SetEntity(INVALID_ENTITY); layerWnd->SetEntity(INVALID_ENTITY); nameWnd->SetEntity(INVALID_ENTITY); } else { const wiScene::PickResult& picked = translator.selected.back(); assert(picked.entity != INVALID_ENTITY); objectWnd->SetEntity(INVALID_ENTITY); for (auto& x : translator.selected) { if (scene.objects.GetComponent(x.entity) != nullptr) { objectWnd->SetEntity(x.entity); break; } } emitterWnd->SetEntity(picked.entity); hairWnd->SetEntity(picked.entity); lightWnd->SetEntity(picked.entity); soundWnd->SetEntity(picked.entity); decalWnd->SetEntity(picked.entity); envProbeWnd->SetEntity(picked.entity); forceFieldWnd->SetEntity(picked.entity); cameraWnd->SetEntity(picked.entity); paintToolWnd->SetEntity(picked.entity, picked.subsetIndex); springWnd->SetEntity(picked.entity); ikWnd->SetEntity(picked.entity); transformWnd->SetEntity(picked.entity); layerWnd->SetEntity(picked.entity); nameWnd->SetEntity(picked.entity); if (picked.subsetIndex >= 0) { const ObjectComponent* object = scene.objects.GetComponent(picked.entity); if (object != nullptr) // maybe it was deleted... { meshWnd->SetEntity(object->meshID); const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); if (mesh != nullptr && (int)mesh->subsets.size() > picked.subsetIndex) { materialWnd->SetEntity(mesh->subsets[picked.subsetIndex].materialID); } } } else { meshWnd->SetEntity(picked.entity); materialWnd->SetEntity(picked.entity); } } // Clear highlite state: for (size_t i = 0; i < scene.materials.GetCount(); ++i) { scene.materials[i].SetUserStencilRef(EDITORSTENCILREF_CLEAR); } for (size_t i = 0; i < scene.objects.GetCount(); ++i) { scene.objects[i].SetUserStencilRef(EDITORSTENCILREF_CLEAR); } for (auto& x : translator.selected) { ObjectComponent* object = scene.objects.GetComponent(x.entity); if (object != nullptr) // maybe it was deleted... { object->SetUserStencilRef(EDITORSTENCILREF_HIGHLIGHT_OBJECT); if (x.subsetIndex >= 0) { const MeshComponent* mesh = scene.meshes.GetComponent(object->meshID); if (mesh != nullptr && (int)mesh->subsets.size() > x.subsetIndex) { MaterialComponent* material = scene.materials.GetComponent(mesh->subsets[x.subsetIndex].materialID); if (material != nullptr) { material->SetUserStencilRef(EDITORSTENCILREF_HIGHLIGHT_MATERIAL); } } } } } translator.Update(); if (translator.IsDragEnded()) { wiArchive& archive = AdvanceHistory(); archive << HISTORYOP_TRANSLATOR; archive << translator.GetDragDeltaMatrix(); } emitterWnd->UpdateData(); hairWnd->UpdateData(); // Follow camera proxy: if (cameraWnd->followCheckBox->IsEnabled() && cameraWnd->followCheckBox->GetCheck()) { TransformComponent* proxy = scene.transforms.GetComponent(cameraWnd->proxy); if (proxy != nullptr) { cameraWnd->camera_transform.Lerp(cameraWnd->camera_transform, *proxy, 1.0f - cameraWnd->followSlider->GetValue()); cameraWnd->camera_transform.UpdateTransform(); } } camera.TransformCamera(cameraWnd->camera_transform); camera.UpdateCamera(); wiProfiler::EndRange(profrange); __super::Update(dt); renderPath->Update(dt); } void EditorComponent::Render() const { Scene& scene = wiScene::GetScene(); // Hovered item boxes: if (!cinemaModeCheckBox->GetCheck()) { if (hovered.entity != INVALID_ENTITY) { const ObjectComponent* object = scene.objects.GetComponent(hovered.entity); if (object != nullptr) { const AABB& aabb = *scene.aabb_objects.GetComponent(hovered.entity); XMFLOAT4X4 hoverBox; XMStoreFloat4x4(&hoverBox, aabb.getAsBoxMatrix()); wiRenderer::DrawBox(hoverBox, XMFLOAT4(0.5f, 0.5f, 0.5f, 0.5f)); } const LightComponent* light = scene.lights.GetComponent(hovered.entity); if (light != nullptr) { const AABB& aabb = *scene.aabb_lights.GetComponent(hovered.entity); XMFLOAT4X4 hoverBox; XMStoreFloat4x4(&hoverBox, aabb.getAsBoxMatrix()); wiRenderer::DrawBox(hoverBox, XMFLOAT4(0.5f, 0.5f, 0, 0.5f)); } const DecalComponent* decal = scene.decals.GetComponent(hovered.entity); if (decal != nullptr) { wiRenderer::DrawBox(decal->world, XMFLOAT4(0.5f, 0, 0.5f, 0.5f)); } const EnvironmentProbeComponent* probe = scene.probes.GetComponent(hovered.entity); if (probe != nullptr) { const AABB& aabb = *scene.aabb_probes.GetComponent(hovered.entity); XMFLOAT4X4 hoverBox; XMStoreFloat4x4(&hoverBox, aabb.getAsBoxMatrix()); wiRenderer::DrawBox(hoverBox, XMFLOAT4(0.5f, 0.5f, 0.5f, 0.5f)); } const wiHairParticle* hair = scene.hairs.GetComponent(hovered.entity); if (hair != nullptr) { XMFLOAT4X4 hoverBox; XMStoreFloat4x4(&hoverBox, hair->aabb.getAsBoxMatrix()); wiRenderer::DrawBox(hoverBox, XMFLOAT4(0, 0.5f, 0, 0.5f)); } } // Spring visualizer: if (springWnd->debugCheckBox->GetCheck()) { for (size_t i = 0; i < scene.springs.GetCount(); ++i) { const SpringComponent& spring = scene.springs[i]; wiRenderer::RenderablePoint point; point.position = spring.center_of_mass; point.size = 0.05f; point.color = XMFLOAT4(1, 1, 0, 1); wiRenderer::DrawPoint(point); } } } // Selected items box: if (!cinemaModeCheckBox->GetCheck() && !translator.selected.empty()) { AABB selectedAABB = AABB(XMFLOAT3(FLT_MAX, FLT_MAX, FLT_MAX), XMFLOAT3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); for (auto& picked : translator.selected) { if (picked.entity != INVALID_ENTITY) { const ObjectComponent* object = scene.objects.GetComponent(picked.entity); if (object != nullptr) { const AABB& aabb = *scene.aabb_objects.GetComponent(picked.entity); selectedAABB = AABB::Merge(selectedAABB, aabb); } const LightComponent* light = scene.lights.GetComponent(picked.entity); if (light != nullptr) { const AABB& aabb = *scene.aabb_lights.GetComponent(picked.entity); selectedAABB = AABB::Merge(selectedAABB, aabb); } const DecalComponent* decal = scene.decals.GetComponent(picked.entity); if (decal != nullptr) { const AABB& aabb = *scene.aabb_decals.GetComponent(picked.entity); selectedAABB = AABB::Merge(selectedAABB, aabb); // also display decal OBB: XMFLOAT4X4 selectionBox; selectionBox = decal->world; wiRenderer::DrawBox(selectionBox, XMFLOAT4(1, 0, 1, 1)); } const EnvironmentProbeComponent* probe = scene.probes.GetComponent(picked.entity); if (probe != nullptr) { const AABB& aabb = *scene.aabb_probes.GetComponent(picked.entity); selectedAABB = AABB::Merge(selectedAABB, aabb); } const wiHairParticle* hair = scene.hairs.GetComponent(picked.entity); if (hair != nullptr) { selectedAABB = AABB::Merge(selectedAABB, hair->aabb); } } } XMFLOAT4X4 selectionBox; XMStoreFloat4x4(&selectionBox, selectedAABB.getAsBoxMatrix()); wiRenderer::DrawBox(selectionBox, XMFLOAT4(1, 1, 1, 1)); } paintToolWnd->DrawBrush(); renderPath->Render(); // Selection outline: if(renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) { GraphicsDevice* device = wiRenderer::GetDevice(); CommandList cmd = device->BeginCommandList(); device->EventBegin("Editor - Selection Outline Mask", cmd); Viewport vp; vp.Width = (float)rt_selectionOutline[0].GetDesc().Width; vp.Height = (float)rt_selectionOutline[0].GetDesc().Height; device->BindViewports(1, &vp, cmd); wiImageParams fx; fx.enableFullScreen(); fx.stencilComp = STENCILMODE::STENCILMODE_EQUAL; // We will specify the stencil ref in user-space, don't care about engine stencil refs here: // Otherwise would need to take into account engine ref and draw multiple permutations of stencil refs. fx.stencilRefMode = STENCILREFMODE_USER; // Materials outline: { device->RenderPassBegin(&renderpass_selectionOutline[0], cmd); // Draw solid blocks of selected materials fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_MATERIAL; wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); device->RenderPassEnd(cmd); } // Objects outline: { device->UnbindResources(TEXSLOT_ONDEMAND0, 1, cmd); device->RenderPassBegin(&renderpass_selectionOutline[1], cmd); // Draw solid blocks of selected objects fx.stencilRef = EDITORSTENCILREF_HIGHLIGHT_OBJECT; wiImage::Draw(wiTextureHelper::getWhite(), fx, cmd); device->RenderPassEnd(cmd); } device->EventEnd(cmd); } __super::Render(); } void EditorComponent::Compose(CommandList cmd) const { renderPath->Compose(cmd); if (cinemaModeCheckBox->GetCheck()) { return; } // Draw selection outline to the screen: const float selectionColorIntensity = std::sinf(selectionOutlineTimer * XM_2PI * 0.8f) * 0.5f + 0.5f; if (renderPath->GetDepthStencil() != nullptr && !translator.selected.empty()) { GraphicsDevice* device = wiRenderer::GetDevice(); device->EventBegin("Editor - Selection Outline", cmd); wiRenderer::BindCommonResources(cmd); float opacity = wiMath::Lerp(0.4f, 1.0f, selectionColorIntensity); XMFLOAT4 col = selectionColor2; col.w *= opacity; wiRenderer::Postprocess_Outline(rt_selectionOutline[0], cmd, 0.1f, 1, col); col = selectionColor; col.w *= opacity; wiRenderer::Postprocess_Outline(rt_selectionOutline[1], cmd, 0.1f, 1, col); device->EventEnd(cmd); } const CameraComponent& camera = wiRenderer::GetCamera(); Scene& scene = wiScene::GetScene(); 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) { for (size_t i = 0; i < scene.lights.GetCount(); ++i) { const LightComponent& light = scene.lights[i]; Entity entity = scene.lights.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } switch (light.GetType()) { case LightComponent::POINT: wiImage::Draw(pointLightTex->texture, fx, cmd); break; case LightComponent::SPOT: wiImage::Draw(spotLightTex->texture, fx, cmd); break; case LightComponent::DIRECTIONAL: wiImage::Draw(dirLightTex->texture, fx, cmd); break; default: wiImage::Draw(areaLightTex->texture, fx, cmd); break; } } } if (rendererWnd->GetPickType() & PICK_DECAL) { for (size_t i = 0; i < scene.decals.GetCount(); ++i) { Entity entity = scene.decals.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(decalTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_FORCEFIELD) { for (size_t i = 0; i < scene.forces.GetCount(); ++i) { Entity entity = scene.forces.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(forceFieldTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_CAMERA) { for (size_t i = 0; i < scene.cameras.GetCount(); ++i) { Entity entity = scene.cameras.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(cameraTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_ARMATURE) { for (size_t i = 0; i < scene.armatures.GetCount(); ++i) { Entity entity = scene.armatures.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(armatureTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_EMITTER) { for (size_t i = 0; i < scene.emitters.GetCount(); ++i) { Entity entity = scene.emitters.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(emitterTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_HAIR) { for (size_t i = 0; i < scene.hairs.GetCount(); ++i) { Entity entity = scene.hairs.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(hairTex->texture, fx, cmd); } } if (rendererWnd->GetPickType() & PICK_SOUND) { for (size_t i = 0; i < scene.sounds.GetCount(); ++i) { Entity entity = scene.sounds.GetEntity(i); const TransformComponent& transform = *scene.transforms.GetComponent(entity); float dist = wiMath::Distance(transform.GetPosition(), camera.Eye) * 0.08f; wiImageParams fx; fx.pos = transform.GetPosition(); fx.siz = XMFLOAT2(dist, dist); fx.typeFlag = ImageType::WORLD; fx.pivot = XMFLOAT2(0.5f, 0.5f); fx.color = inactiveEntityColor; if (hovered.entity == entity) { fx.color = hoveredEntityColor; } for (auto& picked : translator.selected) { if (picked.entity == entity) { fx.color = selectedEntityColor; break; } } wiImage::Draw(soundTex->texture, fx, cmd); } } if (translator.enabled) { translator.Draw(camera, cmd); } __super::Compose(cmd); } void EditorComponent::ClearSelected() { translator.selected.clear(); } void EditorComponent::AddSelected(wiECS::Entity entity) { wiScene::PickResult res; res.entity = entity; AddSelected(res); } void EditorComponent::AddSelected(const wiScene::PickResult& picked) { for (auto it = translator.selected.begin(); it != translator.selected.end(); ++it) { if ((*it) == picked) { // If already selected, it will be deselected now: translator.selected.erase(it); return; } } translator.selected.push_back(picked); } bool EditorComponent::IsSelected(Entity entity) const { for (auto& x : translator.selected) { if (x.entity == entity) { return true; } } return false; } void EditorComponent::ResetHistory() { historyPos = -1; history.clear(); } wiArchive& EditorComponent::AdvanceHistory() { historyPos++; while (static_cast(history.size()) > historyPos) { history.pop_back(); } history.emplace_back(); history.back().SetReadModeAndResetPos(false); return history.back(); } void EditorComponent::ConsumeHistoryOperation(bool undo) { if ((undo && historyPos >= 0) || (!undo && historyPos < (int)history.size() - 1)) { if (!undo) { historyPos++; } Scene& scene = wiScene::GetScene(); wiArchive& archive = history[historyPos]; archive.SetReadModeAndResetPos(true); int temp; archive >> temp; HistoryOperationType type = (HistoryOperationType)temp; switch (type) { case HISTORYOP_TRANSLATOR: { XMFLOAT4X4 delta; archive >> delta; translator.enabled = true; translator.PreTranslate(); XMMATRIX W = XMLoadFloat4x4(&delta); if (undo) { W = XMMatrixInverse(nullptr, W); } W = W * XMLoadFloat4x4(&translator.transform.world); XMStoreFloat4x4(&translator.transform.world, W); translator.PostTranslate(); } break; case HISTORYOP_DELETE: { size_t count; archive >> count; vector deletedEntities(count); for (size_t i = 0; i < count; ++i) { archive >> deletedEntities[i]; } if (undo) { for (size_t i = 0; i < count; ++i) { scene.Entity_Serialize(archive); } } else { for (size_t i = 0; i < count; ++i) { scene.Entity_Remove(deletedEntities[i]); } } } break; case HISTORYOP_SELECTION: { // Read selections states from archive: list selectedBEFORE; size_t selectionCountBEFORE; archive >> selectionCountBEFORE; for (size_t i = 0; i < selectionCountBEFORE; ++i) { wiScene::PickResult sel; archive >> sel.entity; archive >> sel.position; archive >> sel.normal; archive >> sel.subsetIndex; archive >> sel.distance; selectedBEFORE.push_back(sel); } list selectedAFTER; size_t selectionCountAFTER; archive >> selectionCountAFTER; for (size_t i = 0; i < selectionCountAFTER; ++i) { wiScene::PickResult sel; archive >> sel.entity; archive >> sel.position; archive >> sel.normal; archive >> sel.subsetIndex; archive >> sel.distance; selectedAFTER.push_back(sel); } // Restore proper selection state: if (undo) { translator.selected = selectedBEFORE; } else { translator.selected = selectedAFTER; } } break; case HISTORYOP_PAINTTOOL: paintToolWnd->ConsumeHistoryOperation(archive, undo); break; case HISTORYOP_NONE: assert(0); break; default: break; } if (undo) { historyPos--; } } }