Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
Editor.cpp
Go to the documentation of this file.
1
2
3#include "Headers/Editor.h"
4
5#include "Headers/Utils.h"
11
34
35#include <IconsForkAwesome.h>
36#include <imgui_memory_editor/imgui_memory_editor.h>
37#include <imgui_internal.h>
38
39namespace Divide
40{
41 namespace
42 {
43 const string g_editorFontFile{ "Roboto-Medium.ttf" };
44 const string g_editorFontFileBold{ "OpenSans-Bold.ttf" };
45 const string g_editorIconFile{ FONT_ICON_FILE_NAME_FK };
46 const string g_editorSaveFile{ "Editor.xml" };
47 const string g_editorSaveFileBak{ "Editor.xml.bak" };
48
50
52 {
53 DisplayWindow* _window = nullptr;
54 bool _windowOwned = false;
55 };
56
58
59 inline void Reset( Editor::FocusedWindowState& state ) noexcept
60 {
61 state = {};
62 }
63
64 [[nodiscard]] inline bool SetFocus( Editor::FocusedWindowState& state ) noexcept
65 {
66 bool ret = false;
67 if ( state._hoveredNodePreview != state._focusedNodePreview )
68 {
69 state._focusedNodePreview = state._hoveredNodePreview;
70 ret = true;
71 }
72 if ( state._hoveredScenePreview != state._focusedScenePreview )
73 {
74 state._focusedScenePreview = state._hoveredScenePreview;
75 ret = true;
76 }
77
78 return ret;
79 }
80
81 [[nodiscard]] inline bool Hovered( const Editor::FocusedWindowState& state ) noexcept
82 {
83 return state._hoveredNodePreview || state._hoveredScenePreview;
84 }
85
86 [[nodiscard]] inline bool Focused( const Editor::FocusedWindowState& state ) noexcept
87 {
88 return state._focusedNodePreview || state._focusedScenePreview;
89 }
90 } // namespace
91
92 namespace ImGuiCustom
93 {
95 {
97 };
98
99 FORCE_INLINE void* MallocWrapper( const size_t size, [[maybe_unused]] void* user_data ) noexcept
100 {
101 // PlatformContext* user_data;
102 return mi_new( size );
103 }
104
105 FORCE_INLINE void FreeWrapper( void* ptr, [[maybe_unused]] void* user_data ) noexcept
106 {
107 // PlatformContext* user_data;
108 mi_free( ptr );
109 }
110
111 static ImGuiMemAllocFunc g_ImAllocatorAllocFunc = MallocWrapper;
112 static ImGuiMemFreeFunc g_ImAllocatorFreeFunc = FreeWrapper;
114 }; // namespace ImGuiCustom
115
116 ImTextureID to_TexID( Handle<Texture> handle )
117 {
118 const U32 texData = handle._data;
119 return ImTextureID(intptr_t(texData));
120 }
121
122 Handle<Texture> from_TexID( ImTextureID texID )
123 {
124 const intptr_t texData = intptr_t(texID);
125 return Handle<Texture>{ ._data = to_U32(texData) };
126 }
127
128 void InitBasicImGUIState( ImGuiIO& io ) noexcept
129 {
130 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
131 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
132 io.SetClipboardTextFn = [](void* user_data, const char* text)
133 {
134 if ( user_data != nullptr )
135 {
136 SetClipboardText( text );
137 }
138 };
139
140 io.GetClipboardTextFn = [](void* user_data )
141 {
142 if ( user_data != nullptr)
143 {
144 return GetClipboardText();
145 }
146
147 return "";
148 };
149
150 static bool enable_clipboard = true;
151 io.ClipboardUserData = &enable_clipboard;
152 }
153
154 std::array<Input::MouseButton, 5> Editor::g_oisButtons = {
160 };
161
162 std::array<const char*, 3> Editor::g_supportedExportPlatforms = { "Windows",
163 "Linux",
164 "macOS" };
165
167 {
168
169 PushConstantsStruct pushConstants{};
170 pushConstants.data[0]._vec[0] = data._colourData;
171 pushConstants.data[0]._vec[1].xy = data._depthRange;
172 pushConstants.data[0]._vec[1].z = to_F32( data._arrayLayer );
173 pushConstants.data[0]._vec[1].w = to_F32( data._mip );
174 pushConstants.data[0]._vec[2].x = isArrayTexture ? 1.f : 0.f;
175 pushConstants.data[0]._vec[2].y = data._isDepthTexture ? 1.f : 0.f;
176 pushConstants.data[0]._vec[2].z = data._flip ? 1.f : 0.f;
177 pushConstants.data[0]._vec[2].w = data._srgb ? 1.f : 0.f;
178 return pushConstants;
179 }
180
182 : PlatformContextComponent( context )
183 , FrameListener( "Editor", context.kernel().frameListenerMgr(), 9999 )
184 , _editorUpdateTimer( Time::ADD_TIMER( "Editor Update Timer" ) )
185 , _editorRenderTimer( Time::ADD_TIMER( "Editor Render Timer" ) )
186 , _currentTheme( theme )
187 {
188 ImGui::SetAllocatorFunctions( ImGuiCustom::g_ImAllocatorAllocFunc,
191
192 ImGuiFs::Dialog::ExtraWindowFlags |= ImGuiWindowFlags_NoSavedSettings;
193
194 _menuBar = std::make_unique<MenuBar>( context, true );
195 _statusBar = std::make_unique<StatusBar>( context );
196 _optionsWindow = std::make_unique<EditorOptionsWindow>( context );
197
198 _undoManager = std::make_unique<UndoManager>( 25 );
199 g_windowManager = &context.app().windowManager();
200 _memoryEditorData = std::make_pair( nullptr, 0 );
201 _nodePreviewBGColour = { 0.35f, 0.32f, 0.45f };
202 }
203
205 {
206 close();
207 g_windowManager = nullptr;
208 }
209
210 void Editor::idle() noexcept
211 {
212 NOP();
213 }
214
215 void Editor::createFontTexture( const F32 DPIScaleFactor )
216 {
217 constexpr F32 fontSize = 13.f;
218 constexpr F32 fontSizeBold = 16.f;
219 constexpr F32 iconSize = 16.f;
220
221 if ( _fontTexture == INVALID_HANDLE<Texture> )
222 {
223
224 ResourceDescriptor<Texture> resDescriptor( "IMGUI_font_texture" );
225 TextureDescriptor& texDescriptor = resDescriptor._propertyDescriptor;
227
228 _fontTexture = CreateResource( resDescriptor );
229 }
230 DIVIDE_ASSERT( _fontTexture != INVALID_HANDLE<Texture> );
231
232 ImGuiIO& io = _imguiContexts[to_base( ImGuiContextType::Editor )]->IO;
233 U8* pPixels = nullptr;
234 I32 iWidth = 0;
235 I32 iHeight = 0;
236 const string textFontPath = ( Paths::g_fontsPath / g_editorFontFile ).string();
237 const string textFontBoldPath = ( Paths::g_fontsPath / g_editorFontFileBold ).string();
238 const string iconFontPath = ( Paths::g_fontsPath / g_editorIconFile ).string();
239
240 ImFontConfig font_cfg;
241 font_cfg.OversampleH = font_cfg.OversampleV = 1;
242 font_cfg.PixelSnapH = true;
243 font_cfg.SizePixels = fontSize * DPIScaleFactor;
244 font_cfg.EllipsisChar = (ImWchar)0x0085;
245 font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC( font_cfg.SizePixels / fontSize ); // Add +1 offset per fontSize units
246 ImFormatString( font_cfg.Name,
247 IM_ARRAYSIZE( font_cfg.Name ),
248 "%s, %dpx",
249 g_editorFontFile.c_str(),
250 (int)font_cfg.SizePixels );
251
252 io.Fonts->Clear();
253 io.Fonts->AddFontFromFileTTF( textFontPath.c_str(), fontSize * DPIScaleFactor, &font_cfg );
254
255 font_cfg.MergeMode = true;
256 font_cfg.SizePixels = iconSize * DPIScaleFactor;
257 font_cfg.GlyphOffset.y = 1.0f * IM_TRUNC( font_cfg.SizePixels / iconSize ); // Add +1 offset per 16 units
258
259 static const ImWchar icons_ranges[] = { ICON_MIN_FK, ICON_MAX_FK, 0 };
260 io.Fonts->AddFontFromFileTTF( iconFontPath.c_str(), iconSize * DPIScaleFactor, &font_cfg, icons_ranges );
261
262 font_cfg.MergeMode = false;
263 font_cfg.SizePixels = fontSizeBold * DPIScaleFactor;
264 font_cfg.GlyphOffset.y = 0.f; // 1.0f * IM_TRUNC(font_cfg.SizePixels / fontSizeBold); // Add +1
265 // offset per fontSize units
266 io.Fonts->AddFontFromFileTTF( textFontBoldPath.c_str(), fontSizeBold * DPIScaleFactor, &font_cfg );
267
268 io.Fonts->GetTexDataAsRGBA32( &pPixels, &iWidth, &iHeight );
269 Get(_fontTexture)->createWithData( (Byte*)pPixels, iWidth * iHeight * 4u, vec2<U16>( iWidth, iHeight ), {});
270 // Store our identifier as reloading data may change the handle!
271 io.Fonts->SetTexID( to_TexID(_fontTexture) );
272 }
273
274 bool Editor::init( const vec2<U16> renderResolution )
275 {
276 if ( isInit() )
277 {
278 return false;
279 }
280
281 if ( createDirectory( Paths::g_saveLocation / Paths::Editor::g_saveLocation ) != FileError::NONE )
282 {
284 }
285
288 _editorCamera = Camera::CreateCamera( "Editor Camera", Camera::Mode::FREE_FLY );
289 _editorCamera->fromCamera( *Camera::GetUtilityCamera( Camera::UtilityCamera::DEFAULT ) );
290 _editorCamera->setFixedYawAxis( true );
291 _editorCamera->setEye( 60.f, 45.f, 60.f );
292 _editorCamera->setEuler( -15.f, 40.f, 0.f );
293 _editorCamera->speedFactor().turn = 45.f;
294
295 _nodePreviewCamera = Camera::CreateCamera( "Node Preview Camera", Camera::Mode::ORBIT );
296 _nodePreviewCamera->fromCamera( *Camera::GetUtilityCamera( Camera::UtilityCamera::DEFAULT ) );
297 _nodePreviewCamera->setFixedYawAxis( true );
298 _nodePreviewCamera->speedFactor().turn = 125.f;
299 _nodePreviewCamera->speedFactor().zoom = 175.f;
300
301 IMGUI_CHECKVERSION();
302 assert( _imguiContexts[to_base( ImGuiContextType::Editor )] == nullptr );
303
305
306 _imguiContexts[to_base( ImGuiContextType::Editor )] = ImGui::CreateContext();
307 ImGuiIO& io = _imguiContexts[to_base( ImGuiContextType::Editor )]->IO;
308
309 const vector<WindowManager::MonitorData>& monitors = g_windowManager->monitorData();
310 const WindowManager::MonitorData& mainMonitor = monitors[_mainWindow->initialDisplay()];
311
312 createFontTexture( mainMonitor.dpi / PlatformDefaultDPI() );
313
314 {
315 ShaderModuleDescriptor vertModule = {};
316 vertModule._moduleType = ShaderType::VERTEX;
317 vertModule._sourceFile = "IMGUI.glsl";
318
319 ShaderModuleDescriptor fragModule = {};
321 fragModule._sourceFile = "IMGUI.glsl";
322
323 ResourceDescriptor<ShaderProgram> shaderResDescriptor( "IMGUI" );
324 ShaderProgramDescriptor& shaderDescriptor = shaderResDescriptor._propertyDescriptor;
325 shaderDescriptor._modules.push_back( vertModule );
326 shaderDescriptor._modules.push_back( fragModule );
327 shaderDescriptor._globalDefines.emplace_back("toggleChannel ivec4(PushData0[0])");
328 shaderDescriptor._globalDefines.emplace_back("depthRange PushData0[1].xy");
329 shaderDescriptor._globalDefines.emplace_back("layer uint(PushData0[1].z)");
330 shaderDescriptor._globalDefines.emplace_back("mip uint(PushData0[1].w)");
331 shaderDescriptor._globalDefines.emplace_back("textureType uint(PushData0[2].x)");
332 shaderDescriptor._globalDefines.emplace_back("depthTexture uint(PushData0[2].y)");
333 shaderDescriptor._globalDefines.emplace_back("flip uint(PushData0[2].z)");
334 shaderDescriptor._globalDefines.emplace_back("convertToSRGB (uint(PushData0[2].w) == 1)");
335
336 _imguiProgram = CreateResource( shaderResDescriptor );
337 }
338 {
342
343 ShaderModuleDescriptor vertModule = {};
344 vertModule._moduleType = ShaderType::VERTEX;
345 vertModule._sourceFile = "InfiniteGrid.glsl";
346
347 ShaderModuleDescriptor fragModule = {};
349 fragModule._sourceFile = "InfiniteGrid.glsl";
350 fragModule._defines.emplace_back( "axisWidth PushData0[0].x" );
351 fragModule._defines.emplace_back( "gridScale PushData0[0].y" );
352
353
354 ResourceDescriptor<ShaderProgram> shaderResDescriptor( "InfiniteGrid.Colour" );
355 ShaderProgramDescriptor& shaderDescriptor = shaderResDescriptor._propertyDescriptor;
356 shaderDescriptor._modules.push_back( vertModule );
357 shaderDescriptor._modules.push_back( fragModule );
358
359 _infiniteGridProgram = CreateResource( shaderResDescriptor );
362 blend.enabled( true );
363 blend.blendSrc( BlendProperty::SRC_ALPHA );
364 blend.blendDest( BlendProperty::INV_SRC_ALPHA );
365 blend.blendOp( BlendOperation::ADD );
366
368 _axisGizmoPipelineDesc._shaderProgramHandle = _context.gfx().imShaders()->imWorldShaderNoTexture();
369 }
370
371 _infiniteGridPrimitive = _context.gfx().newIMP( "Editor Infinite Grid" );
373
374 _infiniteGridPrimitive->beginBatch( true, 6, 0 );
376 _infiniteGridPrimitive->vertex( 1.f, 1.f, 0.f );
377 _infiniteGridPrimitive->vertex( -1.f, -1.f, 0.f );
378 _infiniteGridPrimitive->vertex( -1.f, 1.f, 0.f );
379 _infiniteGridPrimitive->vertex( -1.f, -1.f, 0.f );
380 _infiniteGridPrimitive->vertex( 1.f, 1.f, 0.f );
381 _infiniteGridPrimitive->vertex( 1.f, -1.f, 0.f );
384
385 PipelineDescriptor pipelineDesc = {};
386 pipelineDesc._stateBlock._cullMode = CullMode::NONE;
387 pipelineDesc._stateBlock._depthTestEnabled = false;
388 pipelineDesc._stateBlock._depthWriteEnabled = false;
389 pipelineDesc._stateBlock._scissorTestEnabled = true;
391 pipelineDesc._vertexFormat._vertexBindings.emplace_back()._strideInBytes = sizeof( ImDrawVert );
395
396 descPos._vertexBindingIndex = descUV._vertexBindingIndex = descColour._vertexBindingIndex = 0u;
397 descPos._componentsPerElement = descUV._componentsPerElement = 2u;
399
400 descColour._componentsPerElement = 4u;
402 descColour._normalized = true;
403
404 descPos._strideInBytes = to_U32( offsetof( ImDrawVert, pos ) );
405 descUV._strideInBytes = to_U32( offsetof( ImDrawVert, uv ) );
406 descColour._strideInBytes = to_U32( offsetof( ImDrawVert, col ) );
407
408 pipelineDesc._shaderProgramHandle = _imguiProgram;
409
411 blend.enabled( true );
412 blend.blendSrc( BlendProperty::SRC_ALPHA );
413 blend.blendDest( BlendProperty::INV_SRC_ALPHA );
414 blend.blendOp( BlendOperation::ADD );
415 _editorPipeline = _context.gfx().newPipeline( pipelineDesc );
416
418
419 io.ConfigViewportsNoDecoration = true;
420 io.ConfigViewportsNoTaskBarIcon = true;
421 io.ConfigDockingTransparentPayload = true;
422 io.ConfigViewportsNoAutoMerge = false;
423
424 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
425 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
426
427 io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
428 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
429 io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports;
430 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
431 io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
432
433 io.BackendPlatformName = Config::ENGINE_NAME;
434 io.BackendRendererName = _context.gfx().renderAPI() == RenderAPI::Vulkan ? "Vulkan" : "OpenGL";
435 io.ConfigWindowsMoveFromTitleBarOnly = true;
436
438
439 io.DisplaySize.x = to_F32( _mainWindow->getDimensions().width );
440 io.DisplaySize.y = to_F32( _mainWindow->getDimensions().height );
441
442 const vec2<U16> display_size = _mainWindow->getDrawableSize();
443 io.DisplayFramebufferScale.x = io.DisplaySize.x > 0 ? (F32)display_size.width / io.DisplaySize.x : 0.f;
444 io.DisplayFramebufferScale.y = io.DisplaySize.y > 0 ? (F32)display_size.height / io.DisplaySize.y : 0.f;
445
446 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
447 main_viewport->PlatformHandle = _mainWindow;
448
449 ImGuiPlatformIO& platform_io = _imguiContexts[to_base( ImGuiContextType::Editor )]->PlatformIO;
450 platform_io.Platform_CreateWindow = []( ImGuiViewport* viewport )
451 {
452 if ( g_windowManager != nullptr )
453 {
454 const DisplayWindow& window = g_windowManager->getWindow( 0u );
455 WindowDescriptor winDescriptor = {};
456 winDescriptor.title = "No Title Yet";
457 winDescriptor.parentWindow = g_windowManager->mainWindow();
458 winDescriptor.targetDisplay = to_U16( window.currentDisplayIndex() );
460
461 winDescriptor.flags |= viewport->Flags & ImGuiViewportFlags_NoDecoration
462 ? 0
464 winDescriptor.flags |= viewport->Flags & ImGuiViewportFlags_NoDecoration
465 ? 0
467 winDescriptor.flags |= viewport->Flags & ImGuiViewportFlags_TopMost
469 : 0;
470 winDescriptor.flags |= viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon
472 : 0;
473
474 winDescriptor.dimensions.set( viewport->Size.x, viewport->Size.y );
475 winDescriptor.position.set( viewport->Pos.x, viewport->Pos.y );
476 winDescriptor.externalClose = true;
477 winDescriptor.targetAPI = window.context().gfx().renderAPI();
478
480 DisplayWindow* newWindow = g_windowManager->createWindow( winDescriptor, err );
481 if ( err == ErrorCode::NO_ERR )
482 {
483 DIVIDE_ASSERT( newWindow != nullptr );
484
485 newWindow->hidden( false );
486 newWindow->bringToFront();
487
488 newWindow->addEventListener(
490 [viewport]( [[maybe_unused]] const DisplayWindow::WindowEventArgs&
491 args ) noexcept
492 {
493 viewport->PlatformRequestClose = true;
494 return true;
495 } );
496
497 newWindow->addEventListener(
499 [viewport]( [[maybe_unused]] const DisplayWindow::WindowEventArgs&
500 args ) noexcept
501 {
502 viewport->PlatformRequestMove = true;
503 return true;
504 } );
505
506 newWindow->addEventListener(
508 [viewport]( [[maybe_unused]] const DisplayWindow::WindowEventArgs&
509 args ) noexcept
510 {
511 viewport->PlatformRequestResize = true;
512 return true;
513 } );
514
515 viewport->PlatformHandle = (void*)newWindow;
516 viewport->PlatformUserData = IM_NEW( ImGuiViewportData )
517 {
518 newWindow, true
519 };
520 }
521 else
522 {
523 DIVIDE_UNEXPECTED_CALL_MSG( "Editor::Platform_CreateWindow failed!" );
524 g_windowManager->destroyWindow( newWindow );
525 }
526 }
527 };
528
529 platform_io.Platform_DestroyWindow = []( ImGuiViewport* viewport )
530 {
531 if ( g_windowManager != nullptr )
532 {
533 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
534 {
535 if ( data->_window && data->_windowOwned )
536 {
537 g_windowManager->destroyWindow( data->_window );
538 }
539 data->_window = nullptr;
540 IM_DELETE( data );
541 }
542 viewport->PlatformUserData = viewport->PlatformHandle = nullptr;
543 }
544 };
545
546 platform_io.Platform_ShowWindow = []( ImGuiViewport* viewport )
547 {
548 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
549 {
550 data->_window->hidden( false );
551 }
552 };
553
554 platform_io.Platform_SetWindowPos = []( ImGuiViewport* viewport,
555 const ImVec2 pos )
556 {
557 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
558 {
559 data->_window->setPosition( (I32)pos.x, (I32)pos.y );
560 }
561 };
562
563 platform_io.Platform_GetWindowPos = []( ImGuiViewport* viewport ) -> ImVec2
564 {
565 if ( const ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
566 {
567 const vec2<I32> pos = data->_window->getPosition();
568 return ImVec2( (F32)pos.x, (F32)pos.y );
569 }
570 DIVIDE_UNEXPECTED_CALL_MSG( "Editor::Platform_GetWindowPos failed!" );
571 return {};
572 };
573
574 platform_io.Platform_GetWindowSize = []( ImGuiViewport* viewport ) -> ImVec2
575 {
576 if ( const ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
577 {
578 const vec2<U16> dim = data->_window->getDimensions();
579 return ImVec2( (F32)dim.width, (F32)dim.height );
580 }
581 DIVIDE_UNEXPECTED_CALL_MSG( "Editor::Platform_GetWindowSize failed!" );
582 return {};
583 };
584
585 platform_io.Platform_GetWindowFocus = []( ImGuiViewport* viewport ) -> bool
586 {
587 if ( const ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
588 {
589 return data->_window->hasFocus();
590 }
591 DIVIDE_UNEXPECTED_CALL_MSG( "Editor::Platform_GetWindowFocus failed!" );
592 return false;
593 };
594
595 platform_io.Platform_SetWindowAlpha = []( ImGuiViewport* viewport,
596 const float alpha )
597 {
598 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
599 {
600 data->_window->opacity( to_U8( alpha * 255 ) );
601 }
602 };
603
604 platform_io.Platform_SetWindowSize = []( ImGuiViewport* viewport,
605 ImVec2 size )
606 {
607 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
608 {
609 WAIT_FOR_CONDITION( data->_window->setDimensions( to_U16( size.x ), to_U16( size.y ) ) );
610 }
611 };
612
613 platform_io.Platform_SetWindowFocus = []( ImGuiViewport* viewport )
614 {
615 if ( const ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
616 {
617 data->_window->bringToFront();
618 }
619 };
620
621 platform_io.Platform_SetWindowTitle = []( ImGuiViewport* viewport,
622 const char* title )
623 {
624 if ( const ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
625 {
626 data->_window->title( title );
627 }
628 };
629
630 platform_io.Platform_RenderWindow = []( ImGuiViewport* viewport,
631 void* platformContext )
632 {
633 if ( PlatformContext* context = (PlatformContext*)platformContext )
634 {
635 DisplayWindow* targetWindow = (DisplayWindow*)viewport->PlatformHandle;
636
637 DIVIDE_ASSERT(targetWindow != nullptr);
638
639 context->app().windowManager().drawToWindow( *targetWindow );
640 }
641 };
642
643 platform_io.Renderer_RenderWindow = []( ImGuiViewport* viewport,
644 void* platformContext )
645 {
646 if ( PlatformContext* context = (PlatformContext*)platformContext )
647 {
648 PROFILE_SCOPE("Editor:: Render Platform Window", Profiler::Category::GUI);
649
650 DisplayWindow* targetWindow = (DisplayWindow*)viewport->PlatformHandle;
651 DIVIDE_ASSERT( targetWindow != nullptr );
652
653 Editor* editor = &context->editor();
654
655 ImGui::SetCurrentContext(editor->_imguiContexts[to_base( ImGuiContextType::Editor )] );
656 ImDrawData* pDrawData = viewport->DrawData;
657 const I32 fb_width = to_I32( pDrawData->DisplaySize.x * ImGui::GetIO().DisplayFramebufferScale.x );
658 const I32 fb_height = to_I32( pDrawData->DisplaySize.y * ImGui::GetIO().DisplayFramebufferScale.y );
659 const Rect<I32> targetViewport{0, 0, fb_width, fb_height};
660
661 Handle<GFX::CommandBuffer> buffer = GFX::AllocateCommandBuffer("IMGUI Render Window");
662
663 GFX::CommandBuffer& buf = *GFX::Get( buffer );
664
666 editor->renderDrawList(pDrawData,
667 2 + targetWindow->getGUID(),
668 targetViewport,
669 true,
670 buf,
671 memCmd);
672 GFX::EnqueueCommand( buf, memCmd );
673
674 context->gfx().flushCommandBuffer( MOV(buffer) );
675 }
676 };
677
678 platform_io.Platform_SwapBuffers = []( ImGuiViewport* viewport,
679 void* platformContext )
680 {
681 if ( g_windowManager != nullptr )
682 {
683 PlatformContext* context = (PlatformContext*)platformContext;
684 DIVIDE_ASSERT( context != nullptr );
685 DisplayWindow* targetWindow = (DisplayWindow*)viewport->PlatformHandle;
686 DIVIDE_ASSERT( targetWindow != nullptr );
687
689 }
690 };
691
692 platform_io.Platform_OnChangedViewport = []( ImGuiViewport* viewport )
693 {
694 static F32 previousDPIScale = 1.f;
695 if ( ImGuiViewportData* data = (ImGuiViewportData*)viewport->PlatformUserData )
696 {
697 if ( viewport->DpiScale != previousDPIScale )
698 {
699 previousDPIScale = viewport->DpiScale;
700 ImGui::GetStyle().ScaleAllSizes( previousDPIScale );
701 data->_window->context().editor()._queuedDPIValue = previousDPIScale;
702 }
703 }
704 };
705
706 const I32 monitorCount = to_I32( monitors.size() );
707
708 platform_io.Monitors.resize( monitorCount );
709
710 for ( I32 i = 0; i < monitorCount; ++i )
711 {
712 const WindowManager::MonitorData& monitor = monitors[i];
713 ImGuiPlatformMonitor& imguiMonitor = platform_io.Monitors[i];
714
715 // Warning: the validity of monitor DPI information on Windows depends on
716 // the application DPI awareness settings, which generally needs to be set
717 // in the manifest or at runtime.
718 imguiMonitor.MainPos = ImVec2( to_F32( monitor.viewport.x ), to_F32( monitor.viewport.y ) );
719 imguiMonitor.WorkPos = ImVec2( to_F32( monitor.drawableArea.x ), to_F32( monitor.drawableArea.y ) );
720
721 imguiMonitor.MainSize = ImVec2( to_F32( monitor.viewport.z ), to_F32( monitor.viewport.w ) );
722 imguiMonitor.WorkSize = ImVec2( to_F32( monitor.drawableArea.z ), to_F32( monitor.drawableArea.w ) );
723 imguiMonitor.DpiScale = monitor.dpi / PlatformDefaultDPI();
724 }
725 ImGuiViewportData* data = IM_NEW( ImGuiViewportData )();
726 data->_window = _mainWindow;
727 data->_windowOwned = false;
728 main_viewport->PlatformUserData = data;
729
730 ImGuiContext*& gizmoContext = _imguiContexts[to_base( ImGuiContextType::Gizmo )];
731 gizmoContext = ImGui::CreateContext( io.Fonts );
732 InitBasicImGUIState( gizmoContext->IO );
733 gizmoContext->Viewports[0]->PlatformHandle = _mainWindow;
734 _gizmo = std::make_unique<Gizmo>( *this, gizmoContext );
735
736 SDL_SetHint( SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1" );
737
738 DockedWindow::Descriptor descriptor = {};
739 descriptor.position = ImVec2( 0, 0 );
740 descriptor.size = ImVec2( 300, 550 );
741 descriptor.minSize = ImVec2( 200, 200 );
742 descriptor.name = ICON_FK_HUBZILLA " Solution Explorer";
743 descriptor.showCornerButton = true;
744 _dockedWindows[to_base( WindowType::SolutionExplorer )] = std::make_unique<SolutionExplorerWindow>( *this, _context, descriptor );
745
746 descriptor.position = ImVec2( 0, 0 );
747 descriptor.minSize = ImVec2( 200, 200 );
748 descriptor.name = ICON_FK_PICTURE_O " PostFX Settings";
749 _dockedWindows[to_base( WindowType::PostFX )] = std::make_unique<PostFXWindow>( *this, _context, descriptor );
750
751 descriptor.showCornerButton = false;
752 descriptor.position = ImVec2( to_F32( renderResolution.width ) - 300, 0 );
753 descriptor.name = ICON_FK_PENCIL_SQUARE_O " Property Explorer";
754 _dockedWindows[to_base( WindowType::Properties )] = std::make_unique<PropertyWindow>( *this, _context, descriptor );
755
756 descriptor.position = ImVec2( 0, 550.0f );
757 descriptor.size = ImVec2( to_F32( renderResolution.width * 0.5f ),
758 to_F32( renderResolution.height ) - 550 - 3 );
759 descriptor.name = ICON_FK_FOLDER_OPEN " Content Explorer";
760 descriptor.flags |= ImGuiWindowFlags_NoTitleBar;
761 _dockedWindows[to_base( WindowType::ContentExplorer )] = std::make_unique<ContentExplorerWindow>( *this, descriptor );
762
763 descriptor.position = ImVec2( to_F32( renderResolution.width * 0.5f ), 550 );
764 descriptor.size = ImVec2( to_F32( renderResolution.width * 0.5f ),
765 to_F32( renderResolution.height ) - 550 - 3 );
766 descriptor.name = ICON_FK_PRINT " Application Output";
767 _dockedWindows[to_base( WindowType::Output )] = std::make_unique<OutputWindow>( *this, descriptor );
768
769 descriptor.position = ImVec2( 150, 150 );
770 descriptor.size = ImVec2( 640, 480 );
771 descriptor.name = ICON_FK_EYE " Node Preview";
772 descriptor.minSize = ImVec2( 100, 100 );
773 descriptor.flags = 0;
774 _dockedWindows[to_base( WindowType::NodePreview )] = std::make_unique<NodePreviewWindow>( *this, descriptor );
775
776 descriptor.name = "Scene View ###AnimatedTitlePlayState";
777 _dockedWindows[to_base( WindowType::SceneView )] = std::make_unique<SceneViewWindow>( *this, descriptor );
778
783
784 TextureDescriptor editorDescriptor
785 {
787 };
788
789
790 RenderTargetDescriptor editorDesc = {};
791 editorDesc._attachments =
792 {
794 };
795
796 editorDesc._resolution = renderResolution;
797 editorDesc._name = "Node_Preview";
798
799 TextureDescriptor depthDescriptor
800 {
802 ._packing = GFXImagePacking::DEPTH,
803 ._baseFormat = GFXImageFormat::RED,
804 ._mipMappingState = MipMappingState::OFF
805 };
806
807 editorDesc._attachments.emplace_back(InternalRTAttachmentDescriptor
808 {
810 });
811
813
814 return loadFromXML();
815 }
816
818 {
819 if ( saveToXML() )
820 {
821 _context.config().save();
822 }
824 {
825 DebugBreak();
826 }
828 {
829 DebugBreak();
830 }
834
835 _gizmo.reset();
836 _imguiBuffers.clear();
837
838 for ( ImGuiContext* context : _imguiContexts )
839 {
840 if ( context == nullptr )
841 {
842 continue;
843 }
844
845 ImGui::SetCurrentContext( context );
846 ImGui::DestroyPlatformWindows();
847 ImGui::DestroyContext( context );
848 }
849 _imguiContexts.fill( nullptr );
850
851 for ( auto& window : _dockedWindows)
852 {
853 window.reset();
854 }
855
857 {
859 }
860
861 Camera::DestroyCamera( _editorCamera );
862 Camera::DestroyCamera( _nodePreviewCamera );
863 }
864
866 {
867 const bool editorHasFocus = hasFocus();
868
869 ImGuiIO& io = ImGui::GetIO();
870 if ( editorHasFocus )
871 {
872 io.ConfigFlags &= ~ImGuiConfigFlags_NavNoCaptureKeyboard;
873 }
874 else
875 {
876 io.ConfigFlags |= ImGuiConfigFlags_NavNoCaptureKeyboard;
877 }
878
879 _context.kernel().projectManager()->onChangeFocus( !editorHasFocus );
880 Attorney::GizmoEditor::onSceneFocus( _gizmo.get(), !editorHasFocus );
881 }
882
883 void Editor::toggle( const bool state )
884 {
885 if ( running() == state )
886 {
887 return;
888 }
889
890 auto& sMgr = _context.kernel().projectManager();
891 Scene* activeScene = sMgr->activeProject()->getActiveScene();
892
893 running( state );
894 Reset( _windowFocusState );
896
897 SceneStatePerPlayer& playerState = activeScene->state()->playerState( sMgr->playerPass() );
898 if ( !state )
899 {
900 _context.config().save();
901 playerState.overrideCamera( nullptr );
902 sceneGizmoEnabled( false );
903 activeScene->state()->renderState().disableOption( SceneRenderState::RenderOptions::SELECTION_GIZMO );
904 activeScene->state()->renderState().disableOption( SceneRenderState::RenderOptions::ALL_GIZMOS );
905 if ( !_context.kernel().projectManager()->resetSelection( 0, true ) )
906 {
907 NOP();
908 }
909 }
910 else
911 {
912 _stepQueue = 0;
913 playerState.overrideCamera( editorCamera() );
914 sceneGizmoEnabled( true );
915 activeScene->state()->renderState().enableOption( SceneRenderState::RenderOptions::SELECTION_GIZMO );
917 /*const Selections& selections = activeScene->getCurrentSelection();
918 if (selections._selectionCount == 0)
919 {
920 SceneGraphNode* root = activeScene->sceneGraph().getRoot();
921 _context.kernel().projectManager()->setSelected(0, { &root });
922 }*/
923 }
924 if ( !_axisGizmo )
925 {
926 _axisGizmo = _context.gfx().newIMP( "Editor Device Axis Gizmo" );
928
929 const auto addValAnd10Percent = []( const F32 val )
930 {
931 return val + ((val * 10) / 100.f);
932 };
933 const auto addValMinus20Percent = []( const F32 val )
934 {
935 return val - ((val * 20) / 100.f);
936 };
937
938 std::array<IM::ConeDescriptor, 6> descriptors;
939 for ( IM::ConeDescriptor& descriptor : descriptors )
940 {
941 descriptor.slices = 4u;
942 descriptor.noCull = true;
943 }
944
945 // Shafts
946 descriptors[0].direction = WORLD_X_NEG_AXIS;
947 descriptors[1].direction = WORLD_Y_NEG_AXIS;
948 descriptors[2].direction = WORLD_Z_NEG_AXIS;
949
950 descriptors[0].length = 2.0f;
951 descriptors[1].length = 1.5f;
952 descriptors[2].length = 2.0f;
953
954 descriptors[0].root = VECTOR3_ZERO + vec3<F32>( addValAnd10Percent( descriptors[0].length ), 0.f, 0.f );
955 descriptors[1].root = VECTOR3_ZERO + vec3<F32>( 0.f, addValAnd10Percent( descriptors[1].length ), 0.f );
956 descriptors[2].root = VECTOR3_ZERO + vec3<F32>( 0.f, 0.f, addValAnd10Percent( descriptors[2].length ) );
957
958 descriptors[0].radius = 0.05f;
959 descriptors[1].radius = 0.05f;
960 descriptors[2].radius = 0.05f;
961
962 descriptors[0].colour = UColour4( 255, 0, 0, 255 );
963 descriptors[1].colour = UColour4( 0, 255, 0, 255 );
964 descriptors[2].colour = UColour4( 0, 0, 255, 255 );
965
966 // Arrow heads
967 descriptors[3].direction = WORLD_X_NEG_AXIS;
968 descriptors[4].direction = WORLD_Y_NEG_AXIS;
969 descriptors[5].direction = WORLD_Z_NEG_AXIS;
970
971 descriptors[3].length = 0.5f;
972 descriptors[4].length = 0.5f;
973 descriptors[5].length = 0.5f;
974
975 descriptors[3].root = VECTOR3_ZERO + vec3<F32>( addValMinus20Percent( descriptors[0].length ) + 0.50f, 0.f, 0.f );
976 descriptors[4].root = VECTOR3_ZERO + vec3<F32>( 0.f, addValMinus20Percent( descriptors[1].length ) + 0.50f, 0.f );
977 descriptors[5].root = VECTOR3_ZERO + vec3<F32>( 0.f, 0.f, addValMinus20Percent( descriptors[2].length ) + 0.50f );
978
979 descriptors[3].radius = 0.15f;
980 descriptors[4].radius = 0.15f;
981 descriptors[5].radius = 0.15f;
982
983 descriptors[3].colour = UColour4( 255, 0, 0, 255 );
984 descriptors[4].colour = UColour4( 0, 255, 0, 255 );
985 descriptors[5].colour = UColour4( 0, 0, 255, 255 );
986
987 _axisGizmo->fromCones( descriptors );
988 }
989 }
990
991 void Editor::update( const U64 deltaTimeUS )
992 {
994
995 static bool allGizmosEnabled = false;
996
998
999 for ( ImGuiContext* context : _imguiContexts )
1000 {
1001 ImGui::SetCurrentContext( context );
1002
1003 ImGuiIO& io = context->IO;
1004 io.DeltaTime = Time::MicrosecondsToSeconds<F32>( deltaTimeUS );
1005
1006 ToggleCursor( !io.MouseDrawCursor );
1007 if ( io.MouseDrawCursor || ImGui::GetMouseCursor() == ImGuiMouseCursor_None )
1008 {
1010 }
1011 else if ( !COMPARE( io.MousePos.x, -1.f ) && !COMPARE( io.MousePos.y, -1.f ) )
1012 {
1013 switch ( ImGui::GetCurrentContext()->MouseCursor )
1014 {
1015 default:
1016 case ImGuiMouseCursor_Arrow:
1018 break;
1019 case ImGuiMouseCursor_TextInput: // When hovering over InputText, etc.
1021 break;
1022 case ImGuiMouseCursor_ResizeAll: // Unused
1024 break;
1025 case ImGuiMouseCursor_ResizeNS: // Unused
1027 break;
1028 case ImGuiMouseCursor_ResizeEW: // When hovering over a column
1030 break;
1031 case ImGuiMouseCursor_ResizeNESW: // Unused
1033 break;
1034 case ImGuiMouseCursor_ResizeNWSE: // When hovering over the
1035 // bottom-right corner of a window
1037 break;
1038 case ImGuiMouseCursor_Hand:
1040 break;
1041 }
1042 }
1043 }
1044
1045 nodePreviewWindowVisible(false);
1046
1047 Attorney::GizmoEditor::update( _gizmo.get(), deltaTimeUS );
1048 if ( running() )
1049 {
1050 nodePreviewWindowVisible( _dockedWindows[to_base( WindowType::NodePreview )]->visible() );
1051
1052 _statusBar->update( deltaTimeUS );
1053 _optionsWindow->update( deltaTimeUS );
1054
1055 static_cast<ContentExplorerWindow*>(_dockedWindows[to_base( WindowType::ContentExplorer )].get())->update( deltaTimeUS );
1056
1057 auto& sMgr = _context.kernel().projectManager();
1058 const bool scenePaused = (simulationPaused() && _stepQueue == 0);
1059
1060 Scene* activeScene = sMgr->activeProject()->getActiveScene();
1061 const PlayerIndex idx = sMgr->playerPass();
1062 SceneStatePerPlayer& playerState = activeScene->state()->playerState( idx );
1063
1064 if ( _isScenePaused != scenePaused )
1065 {
1066 _isScenePaused = scenePaused;
1067
1068 _gizmo->enable( _isScenePaused );
1069 // ToDo: Find a way to keep current selection between running and editing
1070 // states. Maybe have 2 different selections flags?(i.e. in-editor and
1071 // in-game) - Ionut
1072 if ( !sMgr->resetSelection( 0, true ) )
1073 {
1074 NOP();
1075 }
1076 if ( _isScenePaused )
1077 {
1078 activeScene->state()->renderState().enableOption( SceneRenderState::RenderOptions::SELECTION_GIZMO );
1079 if ( allGizmosEnabled )
1080 {
1081 activeScene->state()->renderState().enableOption( SceneRenderState::RenderOptions::ALL_GIZMOS );
1082 }
1083 sceneGizmoEnabled( true );
1084 }
1085 else
1086 {
1087 allGizmosEnabled = activeScene->state()->renderState().isEnabledOption( SceneRenderState::RenderOptions::ALL_GIZMOS );
1088 activeScene->state()->renderState().disableOption( SceneRenderState::RenderOptions::SELECTION_GIZMO );
1089 activeScene->state()->renderState().disableOption( SceneRenderState::RenderOptions::ALL_GIZMOS );
1090 sceneGizmoEnabled( false );
1091 }
1092 }
1093
1094 static bool movedToNode = false;
1095 if ( !_isScenePaused || stepQueue() > 0 )
1096 {
1098 playerState.overrideCamera( nullptr );
1099 nodePreviewCamera()->setTarget( nullptr );
1100 movedToNode = false;
1101 }
1102 else
1103 {
1104 if ( nodePreviewWindowVisible() )
1105 {
1106 playerState.overrideCamera( nodePreviewCamera() );
1108 if ( !movedToNode && _previewNode != nullptr )
1109 {
1110 teleportToNode( nodePreviewCamera(), _previewNode );
1111 nodePreviewCamera()->setTarget( _previewNode->get<TransformComponent>() );
1112 const F32 radius = SceneGraph::GetBounds( _previewNode ).getRadius();
1113 nodePreviewCamera()->minRadius( radius * 0.75f );
1114 nodePreviewCamera()->maxRadius( radius * 10.f );
1115 nodePreviewCamera()->curRadius( radius );
1116 movedToNode = true;
1117 }
1118 }
1119 else
1120 {
1121 playerState.overrideCamera( editorCamera() );
1123 nodePreviewCamera()->setTarget( nullptr );
1124 movedToNode = false;
1125 }
1126 }
1127
1128 if ( _gridSettingsDirty )
1129 {
1130 PushConstantsStruct fastData{};
1131 fastData.data[0]._vec[0].xy.set( infiniteGridAxisWidth(), infiniteGridScale() );
1133 _gridSettingsDirty = false;
1134 }
1135 }
1136 }
1137
1139 {
1141
1142 const ImGuiViewport* viewport = ImGui::GetMainViewport();
1143 ImGui::SetNextWindowPos( viewport->WorkPos );
1144 ImGui::SetNextWindowSize( viewport->WorkSize );
1145 ImGui::SetNextWindowViewport( viewport->ID );
1146 ImGui::PushStyleVar( ImGuiStyleVar_WindowRounding, 0.0f );
1147 ImGui::PushStyleVar( ImGuiStyleVar_WindowBorderSize, 0.0f );
1148 ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2( 0.0f, 0.0f ) );
1149
1150 constexpr ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
1151 ImGui::Begin( "Editor", nullptr, windowFlags );
1152 ImGui::PopStyleVar( 3 );
1153
1154 ImGuiStyle& style = ImGui::GetStyle();
1155 const F32 originalSize = style.WindowMinSize.x;
1156 style.WindowMinSize.x = 300.f;
1157 const ImGuiID dockspace_id = ImGui::GetID( "EditorDockspace" );
1158 ImGui::DockSpace( dockspace_id, ImVec2( 0.0f, 0.0f ), ImGuiDockNodeFlags_PassthruCentralNode );
1159 style.WindowMinSize.x = originalSize;
1160
1161 const bool readOnly = Focused( _windowFocusState ) || _showOptionsWindow;
1162
1163 if ( readOnly ) { PushReadOnly( false ); }
1164 _menuBar->draw();
1165
1166 if ( readOnly ) { PushReadOnly(true); }
1167 for ( auto& window : _dockedWindows )
1168 {
1169 window->draw();
1170 }
1171 if ( readOnly ) { PopReadOnly( ); }
1172
1173 _statusBar->draw( );
1174 if ( readOnly ) { PopReadOnly( ); }
1175
1176
1177 if ( readOnly ) { PushReadOnly( true ); }
1179 {
1180 if ( _memoryEditorData.first != nullptr && _memoryEditorData.second > 0 )
1181 {
1182 static MemoryEditor memEditor;
1183 memEditor.DrawWindow( "Memory Editor", _memoryEditorData.first, _memoryEditorData.second );
1184 if ( !memEditor.Open )
1185 {
1186 _memoryEditorData = { nullptr, 0 };
1187 }
1188 }
1189 }
1190 if ( readOnly ) { PopReadOnly(); }
1191
1193 {
1194 ImGui::SetNextWindowPos( ImVec2( 650, 20 ), ImGuiCond_FirstUseEver );
1195 ImGui::ShowDemoWindow( &_showSampleWindow );
1196 }
1197
1200
1201 ImGui::End();
1202
1203 return true;
1204 }
1205 void Editor::infiniteGridAxisWidth( const F32 value ) noexcept
1206 {
1207 _infiniteGridAxisWidth = value;
1208 _gridSettingsDirty = true;
1209 }
1210
1211 void Editor::infiniteGridScale( const F32 value ) noexcept
1212 {
1213 _infiniteGridScale = value;
1214 _gridSettingsDirty = true;
1215 }
1216
1217 bool Editor::isNodeInView( const SceneGraphNode& node ) const noexcept
1218 {
1220
1221 const I64 targetGUID = node.getGUID();
1222
1223 const auto& visibleNodes = _context.kernel().projectManager()->getRenderedNodeList();
1224 const size_t nodeCount = visibleNodes.size();
1225 for ( size_t i = 0u; i < nodeCount; ++i )
1226 {
1227 if ( visibleNodes.node( i )._node->getGUID() == targetGUID )
1228 {
1229 return true;
1230 }
1231 }
1232
1233 return false;
1234 }
1235
1237 const CameraSnapshot& cameraSnapshot,
1238 const RenderTargetID target,
1239 GFX::CommandBuffer& bufferInOut,
1240 GFX::MemoryBarrierCommand& memCmdInOut )
1241 {
1243
1244 const bool infiniteGridEnabled = stage == RenderStage::NODE_PREVIEW
1245 ? infiniteGridEnabledNode()
1246 : infiniteGridEnabledScene();
1247
1248 if ( !sceneGizmoEnabled() && !infiniteGridEnabled )
1249 {
1250 return;
1251 }
1252
1253 if ( running() && infiniteGridEnabled && _infiniteGridPrimitive && _isScenePaused )
1254 {
1255 _infiniteGridPrimitive->getCommandBuffer( bufferInOut, memCmdInOut );
1256 }
1257
1258 // Debug axis form the axis arrow gizmo in the corner of the screen
1259 // This is toggleable, so check if it's actually requested
1260 if ( sceneGizmoEnabled() && _axisGizmo )
1261 {
1262 // Apply the inverse view matrix so that it cancels out in the shader
1263 // Submit the draw command, rendering it in a tiny viewport in the lower right corner
1264 const auto& rt = _context.gfx().renderTargetPool().getRenderTarget( target );
1265 const U16 windowWidth = rt->getWidth();
1266 //const U16 windowHeight = rt->getHeight();
1267
1268 // We need to transform the gizmo so that it always remains axis aligned
1269 // Create a world matrix using a look at function with the eye position
1270 // backed up from the camera's view direction
1271 const mat4<F32>& viewMatrix = cameraSnapshot._viewMatrix;
1272 const mat4<F32> worldMatrix( Camera::LookAt( -viewMatrix.getForwardVec() * 5, VECTOR3_ZERO, viewMatrix.getUpVec() ) * cameraSnapshot._invViewMatrix );
1273
1274 constexpr I32 viewportDim = 256;
1275 constexpr I32 viewportPadding = 6;
1276
1277 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut)->_viewport =
1278 {
1279 windowWidth - (viewportDim - viewportPadding),
1280 viewportPadding,
1281 viewportDim,
1282 viewportDim
1283 };
1284
1285 _axisGizmo->getCommandBuffer( worldMatrix, bufferInOut, memCmdInOut );
1286 }
1287 }
1288
1289 void Editor::drawScreenOverlay( const Camera* camera, const Rect<I32>& targetViewport, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut ) const
1290 {
1292 Attorney::GizmoEditor::render( _gizmo.get(), camera, targetViewport, bufferInOut, memCmdInOut );
1293 }
1294
1295 bool Editor::framePostRender( [[maybe_unused]] const FrameEvent& evt )
1296 {
1297 return true;
1298 }
1299
1301 {
1303
1304 for ( auto& window : _dockedWindows )
1305 {
1306 window->backgroundUpdate();
1307 }
1308
1309 if ( !running() )
1310 {
1311 return;
1312 }
1313
1315 ImGui::SetCurrentContext( _imguiContexts[to_base( ImGuiContextType::Editor )] );
1316
1317 const ImGuiIO& io = ImGui::GetIO();
1318 if ( io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) [[likely]]
1319 {
1320 bool found = false;
1321 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1322 for ( I32 n = 0; n < platform_io.Viewports.Size; n++ )
1323 {
1324 const ImGuiViewport* viewport = platform_io.Viewports[n];
1325 const DisplayWindow* window = static_cast<DisplayWindow*>(viewport->PlatformHandle);
1326 if ( window != nullptr && window->isHovered() && !(viewport->Flags & ImGuiViewportFlags_NoInputs) )
1327 {
1328 ImGui::GetIO().AddMouseViewportEvent( viewport->ID );
1329 found = true;
1330 }
1331 }
1332 if ( !found )
1333 {
1334 ImGui::GetIO().AddMouseViewportEvent( 0 );
1335 }
1336 }
1337
1338 if ( _queuedDPIValue >= 0.f )
1339 {
1341 _queuedDPIValue = -1.f;
1342 }
1343
1344 ImGui::NewFrame();
1345
1346 if ( render() ) [[likely]]
1347 {
1348 ImGui::Render();
1349
1350 ImDrawData* pDrawData = ImGui::GetDrawData();
1351 const I32 fb_width = to_I32( pDrawData->DisplaySize.x * ImGui::GetIO().DisplayFramebufferScale.x );
1352 const I32 fb_height = to_I32( pDrawData->DisplaySize.y * ImGui::GetIO().DisplayFramebufferScale.y );
1353 const Rect<I32> targetViewport{0, 0, fb_width, fb_height};
1354
1355 pDrawData->ScaleClipRects( ImGui::GetIO().DisplayFramebufferScale );
1356
1357 renderDrawList( pDrawData,
1358 0,
1359 targetViewport,
1360 true,
1361 bufferInOut,
1362 memCmdInOut );
1363
1364 if ( io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) [[likely]]
1365 {
1366 ImGui::UpdatePlatformWindows();
1367 ImGui::RenderPlatformWindowsDefault( &context(), &context() );
1368 }
1369 }
1370 }
1371
1372 bool Editor::frameEnded( [[maybe_unused]] const FrameEvent& evt ) noexcept
1373 {
1374 if ( running() && _stepQueue > 0 )
1375 {
1376 --_stepQueue;
1377 }
1378
1379 return true;
1380 }
1381
1382 Rect<I32> Editor::scenePreviewRect( const bool globalCoords ) const noexcept
1383 {
1384 if ( !isInit() )
1385 {
1386 return {};
1387 }
1388
1389 const WindowType type = _windowFocusState._focusedNodePreview ? WindowType::NodePreview : WindowType::SceneView;
1390 const NodePreviewWindow* viewWindow = static_cast<NodePreviewWindow*>(_dockedWindows[to_base( type )].get());
1391 return viewWindow->sceneRect( globalCoords );
1392 }
1393
1394 GenericVertexData* Editor::getOrCreateIMGUIBuffer( const I64 bufferGUID, const U32 maxVertices, GFX::MemoryBarrierCommand& memCmdInOut )
1395 {
1396 for (const auto&[id, ptr] : _imguiBuffers)
1397 {
1398 if (id == bufferGUID)
1399 {
1400 GenericVertexData* buffer = ptr.get();
1401 buffer->incQueue();
1402 return buffer;
1403 }
1404 }
1405
1406 auto& newBuffer = _imguiBuffers.emplace_back(std::make_pair(bufferGUID, nullptr)).second;
1407
1408 newBuffer = _context.gfx().newGVD( Config::MAX_FRAMES_IN_FLIGHT + 1u, Util::StringFormat("IMGUI_{}", bufferGUID).c_str() );
1409
1411 idxBuff.smallIndices = sizeof( ImDrawIdx ) == sizeof( U16 );
1412 idxBuff.dynamic = true;
1413 idxBuff.count = maxVertices * 3;
1414
1415
1417 params._bindConfig = { 0u, 0u };
1418 params._useRingBuffer = true;
1419 params._initialData = { nullptr, 0 };
1420
1421 params._bufferParams._elementCount = maxVertices;
1422 params._bufferParams._elementSize = sizeof( ImDrawVert );
1425
1426 memCmdInOut._bufferLocks.push_back( newBuffer->setBuffer( params )); //Pos, UV and Colour
1427 memCmdInOut._bufferLocks.push_back( newBuffer->setIndexBuffer( idxBuff ));
1428
1429 return newBuffer.get();
1430 }
1431
1432 // Needs to be rendered immediately. *IM*GUI. IMGUI::NewFrame invalidates this data
1433 void Editor::renderDrawList( ImDrawData* pDrawData,
1434 I64 bufferGUID,
1435 const Rect<I32>& targetViewport,
1436 const bool editorPass,
1437 GFX::CommandBuffer& bufferInOut,
1438 GFX::MemoryBarrierCommand& memCmdInOut )
1439 {
1441
1442 constexpr U32 MaxVertices = (1 << 16);
1443 constexpr U32 MaxIndices = MaxVertices * 3u;
1444 static ImDrawVert vertices[MaxVertices];
1445 static ImDrawIdx indices[MaxIndices];
1446
1447 DIVIDE_ASSERT( bufferGUID != -1 );
1448
1449 const I32 fb_width = targetViewport.sizeX;
1450 const I32 fb_height = targetViewport.sizeY;
1451
1452 // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
1453 if ( pDrawData->CmdListsCount == 0 || fb_width <= 0 || fb_height <= 0 )
1454 {
1455 return;
1456 }
1457
1458 GenericVertexData* buffer = getOrCreateIMGUIBuffer( bufferGUID, MaxVertices, memCmdInOut);
1459 assert( buffer != nullptr );
1460
1461 // ref: https://gist.github.com/floooh/10388a0afbe08fce9e617d8aefa7d302
1462 U32 numVertices = 0, numIndices = 0;
1463 for ( I32 n = 0; n < pDrawData->CmdListsCount; ++n )
1464 {
1465 const ImDrawList* cl = pDrawData->CmdLists[n];
1466 const U32 clNumVertices = to_U32(cl->VtxBuffer.size());
1467 const U32 clNumIndices = to_U32(cl->IdxBuffer.size());
1468
1469 if ( (numVertices + clNumVertices) > MaxVertices || (numIndices + clNumIndices) > MaxIndices )
1470 {
1471 break;
1472 }
1473
1474 memcpy( &vertices[numVertices], cl->VtxBuffer.Data, clNumVertices * sizeof( ImDrawVert ) );
1475 memcpy( &indices[numIndices], cl->IdxBuffer.Data, clNumIndices * sizeof( ImDrawIdx ) );
1476
1477 numVertices += clNumVertices;
1478 numIndices += clNumIndices;
1479 }
1480
1481 memCmdInOut._bufferLocks.emplace_back(buffer->updateBuffer( 0u, 0u, numVertices, vertices ));
1482
1484 idxBuffer.smallIndices = sizeof( ImDrawIdx ) == sizeof( U16 );
1485 idxBuffer.dynamic = true;
1486 idxBuffer.count = numIndices;
1487 idxBuffer.data = indices;
1488 memCmdInOut._bufferLocks.emplace_back(buffer->setIndexBuffer( idxBuffer ));
1489
1490 if ( editorPass )
1491 {
1492 const ImVec4 windowBGColour = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
1493
1494 auto beginRenderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>( bufferInOut );
1495 beginRenderPassCmd->_target = SCREEN_TARGET_ID;
1496 beginRenderPassCmd->_name = "Render IMGUI [ External ]";
1497 beginRenderPassCmd->_clearDescriptor[to_base( RTColourAttachmentSlot::SLOT_0 )] = {{windowBGColour.x, windowBGColour.y, windowBGColour.z, 1.f}, true};
1498 beginRenderPassCmd->_descriptor._drawMask[to_base( RTColourAttachmentSlot::SLOT_0 )] = true;
1499 }
1500 else
1501 {
1502 auto scopeCmd = GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut );
1503 scopeCmd->_scopeName = "Render IMGUI [ Internal ]";
1504 scopeCmd->_scopeId = numVertices;
1505 }
1506
1507 GFX::EnqueueCommand<GFX::BindPipelineCommand>( bufferInOut)->_pipeline = _editorPipeline;
1508
1509 static IMGUICallbackData defaultData{
1510 ._flip = false
1511 };
1512
1513 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut )->_fastData = IMGUICallbackToPushConstants( defaultData, false );
1514 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut)->_viewport = targetViewport;
1515
1516 const F32 scale[] = {
1517 2.f / pDrawData->DisplaySize.x,
1518 2.f / pDrawData->DisplaySize.y
1519 };
1520
1521 const F32 translate[] = {
1522 -1.f - pDrawData->DisplayPos.x * scale[0],
1523 1.f + pDrawData->DisplayPos.y * scale[1]
1524 };
1525
1526 CameraSnapshot& snapshot = GFX::EnqueueCommand<GFX::SetCameraCommand>( bufferInOut)->_cameraSnapshot;
1527 snapshot = _render2DSnapshot;
1528
1529 mat4<F32>& projection = snapshot._projectionMatrix;
1530 projection.m[0][0] = scale[0];
1531 projection.m[1][1] = -scale[1];
1532 projection.m[2][2] = -1.f;
1533 projection.m[3][0] = translate[0];
1534 projection.m[3][1] = translate[1];
1535
1536 const ImVec2 clip_off = pDrawData->DisplayPos; // (0,0) unless using multi-viewports
1537 const ImVec2 clip_scale = pDrawData->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
1538
1539 const bool flipClipY = _context.gfx().renderAPI() == RenderAPI::OpenGL;
1540
1541 ImTextureID crtImguiTexID = nullptr;
1542
1543 U32 baseVertex = 0u;
1544 U32 indexOffset = 0u;
1545
1546 GFX::DrawCommand* drawCommand = nullptr;
1547 Rect<I32> prevClipRect{-1};
1548
1549 bool newCommand = true;
1550 for ( I32 n = 0; n < pDrawData->CmdListsCount; ++n )
1551 {
1552 const ImDrawList* cmd_list = pDrawData->CmdLists[n];
1553 for ( const ImDrawCmd& pcmd : cmd_list->CmdBuffer )
1554 {
1555 if ( pcmd.UserCallback )
1556 {
1557 static_cast<IMGUICallbackData*>(pcmd.UserCallbackData)->_cmdBuffer = &bufferInOut;
1558 pcmd.UserCallback( cmd_list, &pcmd );
1559 newCommand = true;
1560 }
1561 else
1562 {
1563 ImVec2 clip_min( (pcmd.ClipRect.x - clip_off.x)* clip_scale.x, (pcmd.ClipRect.y - clip_off.y)* clip_scale.y );
1564 ImVec2 clip_max( (pcmd.ClipRect.z - clip_off.x)* clip_scale.x, (pcmd.ClipRect.w - clip_off.y)* clip_scale.y );
1565
1566 // Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
1567 if (clip_min.x < 0.f) { clip_min.x = 0.f; }
1568 if (clip_min.y < 0.f) { clip_min.y = 0.f; }
1569 if (clip_max.x > fb_width) { clip_max.x = to_F32(fb_width); }
1570 if (clip_max.y > fb_height) { clip_max.y = to_F32(fb_height); }
1571 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
1572 {
1573 continue;
1574 }
1575
1576 Rect<I32> clipRect;
1577 clipRect.sizeX = to_I32( clip_max.x - clip_min.x );
1578 clipRect.sizeY = to_I32( clip_max.y - clip_min.y );
1579 clipRect.offsetX = to_I32( clip_min.x );
1580 clipRect.offsetY = flipClipY ? to_I32( fb_height - clip_max.y ) : to_I32( clip_min.y );
1581
1582 if ( prevClipRect != clipRect )
1583 {
1584 prevClipRect = clipRect;
1585 GFX::EnqueueCommand<GFX::SetScissorCommand>( bufferInOut )->_rect = clipRect;
1586 newCommand = true;
1587 }
1588 else
1589 {
1590 NOP();
1591 }
1592
1593 ImTextureID imguiTexID = pcmd.GetTexID();
1594
1595 if ( imguiTexID != crtImguiTexID )
1596 {
1597 const Handle<Texture> tex = from_TexID( imguiTexID );
1598
1599 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
1600 cmd->_usage = DescriptorSetUsage::PER_DRAW;
1601
1602 {
1604 Set(binding._data, (tex == INVALID_HANDLE<Texture> ? Texture::DefaultTexture2D() : tex), _editorSampler );
1605 }
1606 {
1609 }
1610 crtImguiTexID = imguiTexID;
1611 newCommand = true;
1612 }
1613
1614 if ( newCommand )
1615 {
1616 drawCommand = GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut );
1617 newCommand = false;
1618 }
1619
1620 auto drawCmd = &drawCommand->_drawCommands.emplace_back();
1621 drawCmd->_sourceBuffer = buffer->handle();
1622 drawCmd->_cmd.indexCount = pcmd.ElemCount;
1623 drawCmd->_cmd.firstIndex = indexOffset + pcmd.IdxOffset;
1624 drawCmd->_cmd.baseVertex = baseVertex + pcmd.VtxOffset;
1625
1626 }
1627 }
1628
1629 indexOffset += cmd_list->IdxBuffer.size();
1630 baseVertex += cmd_list->VtxBuffer.size();
1631 }
1632
1633 if ( editorPass )
1634 {
1635 GFX::EnqueueCommand<GFX::EndRenderPassCommand>( bufferInOut );
1636 }
1637 else
1638 {
1639 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
1640 }
1641 }
1642
1644 {
1645 if ( idx != 0 )
1646 {
1647 return;
1648 }
1649
1651 }
1652
1654 {
1655 _editorCamera->fromCamera( *Attorney::ProjectManagerEditor::playerCamera( _context.kernel().projectManager().get(), 0, true ) );
1656 }
1657
1659 const vec3<F32>& fwd,
1660 const vec3<F32>& up )
1661 {
1662 _editorCamera->lookAt( eye, fwd, up );
1663 }
1664
1665 void Editor::setEditorCameraSpeed( const vec3<F32>& speed ) noexcept
1666 {
1667 _editorCamera->speedFactor( speed );
1668 }
1669
1670 bool Editor::Undo() const
1671 {
1672 if ( _undoManager->Undo() )
1673 {
1675 Util::StringFormat( "Undo: {}", _undoManager->lasActionName().c_str() ),
1676 Time::SecondsToMilliseconds<F32>( 2.0f ),
1677 false );
1678 return true;
1679 }
1680
1681 showStatusMessage( "Nothing to Undo", Time::SecondsToMilliseconds<F32>( 2.0f ), true );
1682 return false;
1683 }
1684
1685 bool Editor::Redo() const
1686 {
1687 if ( _undoManager->Redo() )
1688 {
1690 Util::StringFormat( "Redo: {}", _undoManager->lasActionName().c_str() ),
1691 Time::SecondsToMilliseconds<F32>( 2.0f ),
1692 false );
1693 return true;
1694 }
1695
1696 showStatusMessage( "Nothing to Redo", Time::SecondsToMilliseconds<F32>( 2.0f ), true );
1697 return false;
1698 }
1699
1702 {
1703 if ( !hasFocus() || !simulationPaused() )
1704 {
1705 return false;
1706 }
1707
1708 if ( _gizmo->onKey( true, key ) )
1709 {
1710 return true;
1711 }
1712
1713 ImGuiIO& io = _imguiContexts[to_base( ImGuiContextType::Editor )]->IO;
1714
1716 {
1717 io.AddKeyEvent( ImGuiMod_Ctrl, true );
1718 }
1720 {
1721 io.AddKeyEvent( ImGuiMod_Shift, true );
1722 }
1724 {
1725 io.AddKeyEvent( ImGuiMod_Alt, true );
1726 }
1728 {
1729 io.AddKeyEvent( ImGuiMod_Super, true );
1730 }
1731 const ImGuiKey imguiKey = DivideKeyToImGuiKey( key._key );
1732 io.AddKeyEvent( imguiKey, true );
1733 io.SetKeyEventNativeData( imguiKey, key.sym, key.scancode, key.scancode );
1734
1735 return wantsKeyboard();
1736 }
1737
1738 // Key released: return true if input was consumed
1740 {
1741 if ( !hasFocus() || !simulationPaused() )
1742 {
1743 return false;
1744 }
1745
1746 if ( _gizmo->onKey( false, key ) )
1747 {
1748 return true;
1749 }
1750
1751 ImGuiIO& io = _imguiContexts[to_base( ImGuiContextType::Editor )]->IO;
1752
1753 bool ret = false;
1754 if ( io.KeyCtrl )
1755 {
1756 if ( key._key == Input::KeyCode::KC_Z )
1757 {
1758 if ( Undo() )
1759 {
1760 ret = true;
1761 }
1762 }
1763 else if ( key._key == Input::KeyCode::KC_Y )
1764 {
1765 if ( Redo() )
1766 {
1767 ret = true;
1768 }
1769 }
1770 }
1771
1773 {
1774 io.AddKeyEvent( ImGuiMod_Ctrl, false );
1775 }
1777 {
1778 io.AddKeyEvent( ImGuiMod_Shift, false );
1779 }
1781 {
1782 io.AddKeyEvent( ImGuiMod_Alt, false );
1783 }
1785 {
1786 io.AddKeyEvent( ImGuiMod_Super, false );
1787 }
1788 const ImGuiKey imguiKey = DivideKeyToImGuiKey( key._key );
1789 io.AddKeyEvent( imguiKey, false );
1790 io.SetKeyEventNativeData( imguiKey, key.sym, key.scancode, key.scancode );
1791
1792 return wantsKeyboard() || ret;
1793 }
1794
1795 ImGuiViewport* Editor::FindViewportByPlatformHandle( ImGuiContext* context, const DisplayWindow* window )
1796 {
1797 if ( window != nullptr )
1798 {
1799 for ( I32 i = 0; i != context->Viewports.Size; i++ )
1800 {
1801 const DisplayWindow* it = static_cast<DisplayWindow*>(context->Viewports[i]->PlatformHandleRaw);
1802
1803 if ( it != nullptr && it->getGUID() == window->getGUID() )
1804 {
1805 return context->Viewports[i];
1806 }
1807 }
1808 }
1809
1810 return nullptr;
1811 }
1812
1813 void Editor::updateFocusState( const ImVec2 mousePos )
1814 {
1815 DisplayWindow* focusedWindow = g_windowManager->getFocusedWindow();
1816 if ( focusedWindow == nullptr )
1817 {
1818 focusedWindow = g_windowManager->mainWindow();
1819 assert( focusedWindow != nullptr );
1820 }
1821
1822 Rect<I32> viewportSize( -1 );
1823
1824 ImGuiViewport* viewport = FindViewportByPlatformHandle( _imguiContexts[to_base( ImGuiContextType::Editor )], focusedWindow );
1825 if ( viewport == nullptr )
1826 {
1827 viewportSize =
1828 {
1829 0u,
1830 0u,
1831 focusedWindow->getDrawableSize().x,
1832 focusedWindow->getDrawableSize().y
1833 };
1834 }
1835 else
1836 {
1837 viewportSize =
1838 {
1839 viewport->Pos.x,
1840 viewport->Pos.y,
1841 viewport->Size.x,
1842 viewport->Size.y
1843 };
1844 }
1845
1846 const SceneViewWindow* sceneView = static_cast<SceneViewWindow*>(_dockedWindows[to_base( WindowType::SceneView )].get());
1847 _windowFocusState._hoveredScenePreview = sceneView->hovered() && sceneView->sceneRect( true ).contains( mousePos.x, mousePos.y );
1848
1849 const NodePreviewWindow* nodeView = static_cast<SceneViewWindow*>(_dockedWindows[to_base( WindowType::NodePreview )].get());
1850 _windowFocusState._hoveredNodePreview = nodeView->hovered() && nodeView->sceneRect( true ).contains( mousePos.x, mousePos.y );
1851
1852 _windowFocusState._globalMousePos = mousePos;
1853
1854 const vec2<F32> tempMousePos = COORD_REMAP( vec2<I32>( mousePos.x, mousePos.y ),
1855 scenePreviewRect( true ),
1856 Rect<I32>( 0, 0, viewportSize.z, viewportSize.w ) );
1857 _windowFocusState._scaledMousePos = ImVec2( tempMousePos.x, tempMousePos.y );
1858 }
1859
1862 {
1863 if ( !isInit() || !running() )
1864 {
1866 return false;
1867 }
1868
1869 if ( !arg._wheelEvent )
1870 {
1872 {
1873 return false;
1874 }
1875
1876 ImVec2 tempCoords{};
1877
1878 bool positionOverride = false;
1879 for ( const ImGuiContext* ctx : _imguiContexts )
1880 {
1881 if ( ctx->IO.WantSetMousePos )
1882 {
1883 // Only one override at a time per context
1884 assert( !positionOverride );
1885
1886 positionOverride = true;
1887 tempCoords = ctx->IO.MousePos;
1889 to_I32( tempCoords.y ) );
1890 break;
1891 }
1892 }
1893 if ( !positionOverride )
1894 {
1895 vec2<I32> posGlobal{};
1896 WindowManager::GetMouseState( posGlobal, true );
1897 tempCoords = { to_F32( posGlobal.x ), to_F32( posGlobal.y ) };
1898 }
1899
1900 WindowManager::SetCaptureMouse( positionOverride ? ImGui::IsAnyMouseDown() : false );
1901
1902 updateFocusState( tempCoords );
1903
1904 ImGuiContext* ctx = nullptr;
1905 { // Update Editor State
1907 if ( !ctx->IO.WantSetMousePos )
1908 {
1909 ImGui::SetCurrentContext( ctx );
1910 ctx->IO.AddMousePosEvent( _windowFocusState._globalMousePos.x,
1911 _windowFocusState._globalMousePos.y );
1912 }
1913 }
1914 { // Update Gizmo State
1916 if ( !ctx->IO.WantSetMousePos )
1917 {
1918 ImGui::SetCurrentContext( ctx );
1919 ctx->IO.AddMousePosEvent( _windowFocusState._scaledMousePos.x,
1920 _windowFocusState._scaledMousePos.y );
1921 }
1922 }
1923 }
1924 else
1925 {
1926 for ( ImGuiContext* ctx : _imguiContexts )
1927 {
1928 ImGui::SetCurrentContext( ctx );
1929 if ( arg.state().HWheel > 0 )
1930 {
1931 ctx->IO.AddMouseWheelEvent( ctx->IO.MouseWheelH + 1, ctx->IO.MouseWheel );
1932 }
1933 if ( arg.state().HWheel < 0 )
1934 {
1935 ctx->IO.AddMouseWheelEvent( ctx->IO.MouseWheelH - 1, ctx->IO.MouseWheel );
1936 }
1937 if ( arg.state().VWheel > 0 )
1938 {
1939 ctx->IO.AddMouseWheelEvent( ctx->IO.MouseWheelH, ctx->IO.MouseWheel + 1 );
1940 }
1941 if ( arg.state().VWheel < 0 )
1942 {
1943 ctx->IO.AddMouseWheelEvent( ctx->IO.MouseWheelH, ctx->IO.MouseWheel - 1 );
1944 }
1945 }
1946 }
1947
1948 ImGui::SetCurrentContext( _imguiContexts[to_base( ImGuiContextType::Editor )] );
1949
1950 if ( _windowFocusState._focusedNodePreview )
1951 {
1952 return false;
1953 }
1954
1955 return wantsMouse() || _gizmo->hovered();
1956 }
1957
1960 {
1961 if ( !isInit() || !running() || WindowManager::IsRelativeMouseMode() )
1962 {
1963 return false;
1964 }
1965
1967 {
1968 ImGui::SetCurrentContext( _imguiContexts[to_base( ImGuiContextType::Editor )] );
1969 };
1970
1971 for ( ImGuiContext* ctx : _imguiContexts )
1972 {
1973 ImGui::SetCurrentContext( ctx );
1974 for ( size_t i = 0; i < g_oisButtons.size(); ++i )
1975 {
1976 if ( arg.button() == g_oisButtons[i] )
1977 {
1978 ctx->IO.AddMouseButtonEvent( to_I32( i ), true );
1979 break;
1980 }
1981 }
1982 }
1983
1984 if ( !hasFocus() )
1985 {
1986 _gizmo->onMouseButton( true );
1987 }
1988
1989 // ToDo: Need a more generic way of handling this!
1990 if ( arg.button() == Input::MouseButton::MB_Left && _windowFocusState._focusedNodePreview )
1991 {
1992 return true;
1993 }
1994
1995 return wantsMouse();
1996 }
1997
2000 {
2001 if ( !isInit() || !running() || WindowManager::IsRelativeMouseMode() )
2002 {
2003 return false;
2004 }
2005
2007 {
2008 ImGui::SetCurrentContext( _imguiContexts[to_base( ImGuiContextType::Editor )] );
2009 };
2010
2011 if ( SetFocus( _windowFocusState ) )
2012 {
2014 }
2015
2016 for ( ImGuiContext* ctx : _imguiContexts )
2017 {
2018 ImGui::SetCurrentContext( ctx );
2019 for ( size_t i = 0; i < g_oisButtons.size(); ++i )
2020 {
2021 if ( arg.button() == g_oisButtons[i] )
2022 {
2023 ctx->IO.AddMouseButtonEvent( to_I32( i ), false );
2024 break;
2025 }
2026 }
2027 }
2028
2029 _gizmo->onMouseButton( false );
2030
2031 // ToDo: Need a more generic way of handling this!
2032 if ( arg.button() == Input::MouseButton::MB_Left && _windowFocusState._focusedNodePreview )
2033 {
2034 return true;
2035 }
2036
2037 return wantsMouse();
2038 }
2039
2040 bool Editor::joystickButtonPressed( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2041 {
2042 return wantsJoystick();
2043 }
2044
2045 bool Editor::joystickButtonReleased( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2046 {
2047 return wantsJoystick();
2048 }
2049
2050 bool Editor::joystickAxisMoved( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2051 {
2052 return wantsJoystick();
2053 }
2054
2055 bool Editor::joystickPovMoved( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2056 {
2057 return wantsJoystick();
2058 }
2059
2060 bool Editor::joystickBallMoved( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2061 {
2062 return wantsJoystick();
2063 }
2064
2065 bool Editor::joystickAddRemove( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2066 {
2067 return wantsJoystick();
2068 }
2069
2070 bool Editor::joystickRemap( [[maybe_unused]] const Input::JoystickEvent& arg ) noexcept
2071 {
2072 return wantsJoystick();
2073 }
2074
2075 bool Editor::wantsJoystick() const noexcept
2076 {
2077 if ( !isInit() || !running() )
2078 {
2079 return false;
2080 }
2081
2082 return hasFocus();
2083 }
2084
2086 {
2087 if ( hasFocus() )
2088 {
2089 for ( const ImGuiContext* ctx : _imguiContexts )
2090 {
2091 if ( ctx->IO.WantCaptureMouseUnlessPopupClose )
2092 {
2093 return true;
2094 }
2095 }
2096 }
2097
2098 if ( simulationPaused() )
2099 {
2100 return _gizmo->needsMouse();
2101 }
2102
2103 return false;
2104 }
2105
2106 bool Editor::wantsKeyboard() const noexcept
2107 {
2108 if ( hasFocus() )
2109 {
2110 for ( const ImGuiContext* ctx : _imguiContexts )
2111 {
2112 if ( ctx->IO.WantCaptureKeyboard )
2113 {
2114 return true;
2115 }
2116 }
2117 }
2118
2119 return _windowFocusState._focusedNodePreview;
2120 }
2121
2122 bool Editor::hasFocus() const
2123 {
2124 return isInit() && running() && !Focused( _windowFocusState );
2125 }
2126
2128 {
2129 return isInit() && running() && !Hovered( _windowFocusState );
2130 }
2131
2133 {
2134 if ( !hasFocus() )
2135 {
2136 return false;
2137 }
2138
2139 bool wantsCapture = false;
2140 for ( ImGuiContext* ctx : _imguiContexts )
2141 {
2142 ImGui::SetCurrentContext( ctx );
2143 ctx->IO.AddInputCharactersUTF8( arg._text.c_str() );
2144 wantsCapture = ctx->IO.WantCaptureKeyboard || wantsCapture;
2145 }
2146 ImGui::SetCurrentContext( _imguiContexts[to_base( ImGuiContextType::Editor )] );
2147
2148 return wantsCapture;
2149 }
2150
2152 {
2154
2155 if ( !isInit() )
2156 {
2157 return;
2158 }
2159
2160 const U16 w = params.width;
2161 const U16 h = params.height;
2162
2163 if ( w < 1 || h < 1 || !params.isMainWindow )
2164 {
2165 return;
2166 }
2167
2168 const vec2<U16> displaySize = _mainWindow->getDrawableSize();
2169
2170 for ( ImGuiContext* ctx : _imguiContexts )
2171 {
2172 ctx->IO.DisplaySize.x = to_F32( params.width );
2173 ctx->IO.DisplaySize.y = to_F32( params.height );
2174 ctx->IO.DisplayFramebufferScale = ImVec2(
2175 params.width > 0u ? to_F32( displaySize.width ) / params.width : 0.f,
2176 params.height > 0u ? to_F32( displaySize.height ) / params.height : 0.f );
2177 }
2178 }
2179
2181 {
2182 if ( !isInit() )
2183 {
2184 return;
2185 }
2186
2187 const U16 w = params.width;
2188 const U16 h = params.height;
2189
2190 // Avoid resolution change on minimize so we don't thrash render targets
2191 if ( w < 1 || h < 1 || _nodePreviewRTHandle._rt->getResolution() == vec2<U16>( w, h ) )
2192 {
2193 return;
2194 }
2195
2198 }
2199
2200 bool Editor::saveSceneChanges( const DELEGATE<void, std::string_view>& msgCallback, const DELEGATE<void, bool>& finishCallback ) const
2201 {
2202 if ( _context.kernel().projectManager()->saveActiveScene( false, true, msgCallback, finishCallback ) )
2203 {
2204 if ( saveToXML() )
2205 {
2206 _context.config().save();
2207 return true;
2208 }
2209 }
2210
2211 return false;
2212 }
2213
2214 bool Editor::openProject(const ProjectID& projectID)
2215 {
2216 return _context.kernel().projectManager()->loadProject(projectID, true) == ErrorCode::NO_ERR;
2217 }
2218
2219 bool Editor::switchScene( const SceneEntry& scene, bool createIfNotExists )
2220 {
2222
2223 static CircularBuffer<SceneEntry, 10> tempBuffer;
2224
2225 if ( Util::IsEmptyOrNull( scene._name.c_str() ) )
2226 {
2227 return false;
2228 }
2229
2230 SwitchSceneTarget target
2231 {
2232 ._targetScene = scene,
2233 ._unloadPreviousScene = true,
2234 ._loadInSeparateThread = true,
2235 ._deferToStartOfFrame = true,
2236 ._createIfNotExist = createIfNotExists
2237 };
2238
2239 if ( !_context.kernel().projectManager()->activeProject()->switchScene( target ) )
2240 {
2241 Console::errorfn( LOCALE_STR( "ERROR_SCENE_LOAD" ), scene._name.c_str() );
2242 showStatusMessage( Util::StringFormat( LOCALE_STR( "ERROR_SCENE_LOAD" ), scene._name.c_str() ),
2243 Time::SecondsToMilliseconds<F32>( 3.f ),
2244 true );
2245 return false;
2246 }
2247
2248 tempBuffer.reset();
2249 for ( size_t i = 0u; i < _recentSceneList.size(); ++i )
2250 {
2251 const SceneEntry& crtEntry = _recentSceneList.get( i );
2252 if ( crtEntry != scene )
2253 {
2254 tempBuffer.put( crtEntry );
2255 }
2256 }
2257 tempBuffer.put( scene );
2258 _recentSceneList.reset();
2259 size_t i = tempBuffer.size();
2260 while ( i-- )
2261 {
2262 _recentSceneList.put( tempBuffer.get( i ) );
2263 }
2264
2265 return true;
2266 }
2267
2269 {
2270 _lastOpenSceneName = newScene == nullptr ? "" : newScene->resourceName().c_str();
2271 }
2272
2274 {
2275 U32 ret = 10u; // All of the scene stuff (settings, music, etc)
2276
2277 const auto& graph = _context.kernel().projectManager()->activeProject()->getActiveScene()->sceneGraph();
2278 ret += to_U32( graph->getTotalNodeCount() );
2279
2280 return ret;
2281 }
2282
2283 bool Editor::isDefaultScene() const noexcept
2284 {
2285 Scene* activeScene = _context.kernel().projectManager()->activeProject()->getActiveScene();
2286 return activeScene->getGUID() == Scene::DEFAULT_SCENE_GUID;
2287 }
2288
2289 bool Editor::modalTextureView( const std::string_view modalName,
2290 const Handle<Texture> tex,
2291 const vec2<F32> dimensions,
2292 const bool preserveAspect,
2293 const bool useModal ) const
2294 {
2295 if ( tex == INVALID_HANDLE<Texture> )
2296 {
2297 return false;
2298 }
2299
2301
2302 static std::array<bool, 4> state = { true, true, true, true };
2303
2304 const ImDrawCallback toggleColours = []( [[maybe_unused]] const ImDrawList* parent_list, const ImDrawCmd* imCmd ) -> void
2305 {
2306 static SamplerDescriptor defaultSampler {};
2307
2308 IMGUICallbackData* data = static_cast<IMGUICallbackData*>(imCmd->UserCallbackData);
2309
2310 assert( data->_cmdBuffer != nullptr );
2311 GFX::CommandBuffer& buffer = *(data->_cmdBuffer);
2312
2313 bool isArrayTexture = false;
2314 if ( data->_texture != INVALID_HANDLE<Texture> )
2315 {
2316 Texture* tex = Get(data->_texture);
2317
2318 const TextureType texType = tex->descriptor()._texType;
2319 const bool isTextureArray = IsArrayTexture( texType );
2320 const bool isTextureCube = IsCubeTexture( texType );
2321
2322 if ( isTextureArray || isTextureCube )
2323 {
2324 isArrayTexture = true;
2325
2326 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( buffer );
2327 cmd->_usage = DescriptorSetUsage::PER_DRAW;
2328 {
2331 { 0u, 1u },
2332 { 0u, 1u });
2333 Set( binding._data, texView, Texture::DefaultSampler() );
2334 }
2335 {
2337
2338 if ( isTextureCube )
2339 {
2340 const ImageView texView = tex->getView( TextureType::TEXTURE_2D_ARRAY,
2341 { 0u, tex->mipCount() },
2342 { 0u, to_U16( tex->depth() * 6u) });
2343
2344 Set( binding._data, texView, defaultSampler );
2345 }
2346 else
2347 {
2348 Set( binding._data, tex->getView(), defaultSampler );
2349 }
2350 }
2351 }
2352 }
2353
2354 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( buffer )->_fastData = IMGUICallbackToPushConstants( *data, isArrayTexture );
2355 };
2356
2357 bool closed = false;
2358 bool opened = false;
2359
2360 DIVIDE_ASSERT( !modalName.empty() );
2361
2362 if ( useModal )
2363 {
2364 Util::OpenCenteredPopup( modalName.data() );
2365 opened = ImGui::BeginPopupModal( modalName.data(), nullptr, ImGuiWindowFlags_AlwaysAutoResize );
2366 }
2367 else
2368 {
2370 opened = ImGui::Begin( modalName.data(), nullptr, ImGuiWindowFlags_AlwaysAutoResize );
2371 }
2372
2373 if ( opened )
2374 {
2375 assert( tex != INVALID_HANDLE<Texture> );
2376
2377 static IMGUICallbackData defaultData{
2378 ._flip = false
2379 };
2380
2381 Texture* texPtr = Get(tex);
2382
2383 g_modalTextureData._texture = tex;
2384 g_modalTextureData._isDepthTexture = IsDepthTexture( texPtr->descriptor()._packing );
2385
2386 const U8 numChannels = NumChannels( texPtr->descriptor()._baseFormat );
2387
2388 assert( numChannels > 0 );
2389
2390 bool isArray = false;
2391 if ( g_modalTextureData._isDepthTexture )
2392 {
2393 ImGui::Text( "Depth: " );
2394 ImGui::SameLine();
2395 ImGui::ToggleButton( "Depth", &state[0] );
2396 ImGui::SameLine();
2397 ImGui::Text( "Range: " );
2398 ImGui::SameLine();
2399 ImGui::DragFloatRange2( "",
2400 &g_modalTextureData._depthRange[0],
2401 &g_modalTextureData._depthRange[1],
2402 0.005f,
2403 0.f,
2404 1.f );
2405 }
2406 else
2407 {
2408 ImGui::Text( "R: " );
2409 ImGui::SameLine();
2410 ImGui::ToggleButton( "R", &state[0] );
2411
2412 if ( numChannels > 1 )
2413 {
2414 ImGui::SameLine();
2415 ImGui::Text( "G: " );
2416 ImGui::SameLine();
2417 ImGui::ToggleButton( "G", &state[1] );
2418
2419 if ( numChannels > 2 )
2420 {
2421 ImGui::SameLine();
2422 ImGui::Text( "B: " );
2423 ImGui::SameLine();
2424 ImGui::ToggleButton( "B", &state[2] );
2425 }
2426
2427 if ( numChannels > 3 )
2428 {
2429 ImGui::SameLine();
2430 ImGui::Text( "A: " );
2431 ImGui::SameLine();
2432 ImGui::ToggleButton( "A", &state[3] );
2433 }
2434 }
2435 }
2436 ImGui::SameLine();
2437 ImGui::Text( "Flip: " );
2438 ImGui::SameLine();
2439 ImGui::ToggleButton( "Flip", &g_modalTextureData._flip );
2440 if ( IsArrayTexture( texPtr->descriptor()._texType ) )
2441 {
2442 isArray = true;
2443 U32 maxLayers = texPtr->depth();
2444 if ( IsCubeTexture( texPtr->descriptor()._texType ) )
2445 {
2446 maxLayers *= 6u;
2447 }
2448 maxLayers -= 1u;
2449 U32 minLayers = 0u;
2450 ImGui::Text( "Layer: " );
2451 ImGui::SameLine();
2452 ImGui::SliderScalar( "##modalTextureLayerSelect",
2453 ImGuiDataType_U32,
2454 &g_modalTextureData._arrayLayer,
2455 &minLayers,
2456 &maxLayers );
2457 }
2458 U16 maxMip = texPtr->mipCount();
2459 if ( maxMip > 1u )
2460 {
2461 maxMip -= 1u;
2462 U16 minMip = 0u;
2463 ImGui::Text( "Mip: " );
2464 ImGui::SameLine();
2465 ImGui::SliderScalar( "##modalTextureMipSelect",
2466 ImGuiDataType_U16,
2467 &g_modalTextureData._mip,
2468 &minMip,
2469 &maxMip );
2470 }
2471
2472 const bool nonDefaultColours = g_modalTextureData._isDepthTexture || !state[0] || !state[1] || !state[2] || !state[3] || g_modalTextureData._flip || isArray;
2473 g_modalTextureData._colourData.set( state[0] ? 1 : 0, state[1] ? 1 : 0, state[2] ? 1 : 0, state[3] ? 1 : 0 );
2474
2475 if ( nonDefaultColours )
2476 {
2477 ImGui::GetWindowDrawList()->AddCallback( toggleColours, &g_modalTextureData );
2478 }
2479
2480 F32 aspect = 1.0f;
2481 if ( preserveAspect )
2482 {
2483 const U16 w = texPtr->width();
2484 const U16 h = texPtr->height();
2485 aspect = w / to_F32( h );
2486 }
2487
2488 static F32 zoom = 1.0f;
2489 static ImVec2 zoomCenter( 0.5f, 0.5f );
2491 ImVec2( dimensions.width, dimensions.height / aspect ),
2492 aspect,
2493 zoom,
2494 zoomCenter,
2495 2,
2496 3,
2497 ImVec2( 16.f, 1.025f ) );
2498
2499 if ( nonDefaultColours )
2500 {
2501 // Reset draw data
2502 ImGui::GetWindowDrawList()->AddCallback( toggleColours, &defaultData );
2503 }
2504
2505 ImGui::Text( "Mouse: Wheel = scroll | CTRL + Wheel = zoom | Hold Wheel "
2506 "Button = pan" );
2507
2508 if ( ImGui::Button( "Close" ) )
2509 {
2510 zoom = 1.0f;
2511 zoomCenter = ImVec2( 0.5f, 0.5f );
2512 if ( useModal )
2513 {
2514 ImGui::CloseCurrentPopup();
2515 }
2516 g_modalTextureData._texture = INVALID_HANDLE<Texture>;
2517 closed = true;
2518 }
2519
2520 if ( useModal )
2521 {
2522 ImGui::EndPopup();
2523 }
2524 else
2525 {
2526 ImGui::End();
2527 }
2528 }
2529 else if ( !useModal )
2530 {
2531 ImGui::End();
2532 }
2533
2534 return closed;
2535 }
2536
2538 const bool quick,
2539 const vec3<F32>& scale,
2540 const vec3<F32>& position )
2541 {
2542 if ( mesh == INVALID_HANDLE<Mesh> )
2543 {
2544 return false;
2545 }
2546
2548
2549 if ( quick )
2550 {
2551 const Camera* playerCam = Attorney::ProjectManagerCameraAccessor::playerCamera( _context.kernel().projectManager().get() );
2552 if ( !spawnGeometry( mesh,
2553 scale,
2554 playerCam->snapshot()._eye,
2555 position,
2556 Get(mesh)->resourceName().c_str() ) )
2557 {
2559 }
2560 return true;
2561 }
2562
2563 if ( _queuedModelSpawn._mesh == INVALID_HANDLE<Mesh> )
2564 {
2565 _queuedModelSpawn._mesh = mesh;
2566 _queuedModelSpawn._position = position;
2567 _queuedModelSpawn._scale = scale;
2568 return true;
2569 }
2570
2571 return false;
2572 }
2573
2575 {
2576 if ( _queuedModelSpawn._mesh == INVALID_HANDLE<Mesh> )
2577 {
2578 return;
2579 }
2580
2582
2583 static bool wasClosed = false;
2584 static vec3<F32> rotation( 0.0f );
2585
2586 using ReturnTypeOfName = std::remove_cvref_t<std::invoke_result_t<decltype(&Resource::resourceName), Resource>>;
2587 static char inputBuf[ReturnTypeOfName::kMaxSize + 2] = {};
2588
2589 Util::OpenCenteredPopup( "Spawn Entity" );
2590 if ( ImGui::BeginPopupModal( "Spawn Entity", nullptr, ImGuiWindowFlags_AlwaysAutoResize ) )
2591 {
2592 if ( wasClosed )
2593 {
2594 wasClosed = false;
2595 }
2596
2597 DIVIDE_ASSERT( _queuedModelSpawn._mesh != INVALID_HANDLE<Mesh> );
2598 if ( Util::IsEmptyOrNull( inputBuf ) )
2599 {
2600 strcpy( &inputBuf[0], Get(_queuedModelSpawn._mesh)->resourceName().c_str() );
2601 }
2602 ImGui::Text( "Spawn [ %s ]?", inputBuf );
2603 ImGui::Separator();
2604
2605 ImGui::Text( "Scale:" ); ImGui::SameLine();
2606 if ( ImGui::InputFloat3( "##Scale:", _queuedModelSpawn._scale._v ) )
2607 {
2608 }
2609 ImGui::Text( "Position:" ); ImGui::SameLine();
2610 if ( ImGui::InputFloat3( "##Position:", _queuedModelSpawn._position._v ) )
2611 {
2612 }
2613 ImGui::Text( "Rotation (euler):" ); ImGui::SameLine();
2614 if ( ImGui::InputFloat3( "##Rotation (euler):", rotation._v ) )
2615 {
2616 }
2617 ImGui::Text( "Name:" ); ImGui::SameLine();
2618 if ( ImGui::InputText( "##Name:",
2619 inputBuf,
2620 IM_ARRAYSIZE( inputBuf ),
2621 ImGuiInputTextFlags_EnterReturnsTrue ) )
2622 {
2623 }
2624
2625 ImGui::Separator();
2626 if ( ImGui::Button( "Cancel", ImVec2( 120, 0 ) ) )
2627 {
2628 ImGui::CloseCurrentPopup();
2629 wasClosed = true;
2630 rotation.set( 0.f );
2631 inputBuf[0] = '\0';
2632 }
2633
2634 ImGui::SetItemDefaultFocus();
2635 ImGui::SameLine();
2636 if ( ImGui::Button( "Yes", ImVec2( 120, 0 ) ) )
2637 {
2638 ImGui::CloseCurrentPopup();
2639 wasClosed = true;
2643 rotation,
2644 inputBuf ) )
2645 {
2647 }
2648 rotation.set( 0.f );
2649 inputBuf[0] = '\0';
2650 }
2651 if ( wasClosed )
2652 {
2653 _queuedModelSpawn._mesh = INVALID_HANDLE<Mesh>;
2654 }
2655 ImGui::EndPopup();
2656 }
2657 }
2658
2659 void Editor::showStatusMessage( const string& message,
2660 const F32 durationMS,
2661 bool error ) const
2662 {
2663 _statusBar->showMessage( message, durationMS, error );
2664 }
2665
2667 const vec3<F32>& scale,
2668 const vec3<F32>& position,
2669 const vec3<Angle::DEGREES<F32>>& rotation,
2670 const std::string_view name) const
2671 {
2673
2674 SceneGraphNodeDescriptor nodeDescriptor = {};
2675 nodeDescriptor._name = name;
2676 nodeDescriptor._componentMask = normalMask;
2677 nodeDescriptor._nodeHandle = FromHandle(mesh);
2678
2679 Scene* activeScene = _context.kernel().projectManager()->activeProject()->getActiveScene();
2680 const SceneGraphNode* node = activeScene->sceneGraph()->getRoot()->addChildNode( nodeDescriptor );
2681 if ( node != nullptr )
2682 {
2683 TransformComponent* tComp = node->get<TransformComponent>();
2684 tComp->setPosition( position );
2685 tComp->rotate( rotation );
2686 tComp->setScale( scale );
2687
2688 return true;
2689 }
2690
2691 return false;
2692 }
2693
2694 const ProjectIDs& Editor::getProjectList() const noexcept
2695 {
2696 return _context.kernel().projectManager()->availableProjects();
2697 }
2698
2699 const SceneEntries& Editor::getSceneList() const noexcept
2700 {
2701 return _context.kernel().projectManager()->activeProject()->getSceneEntries();
2702 }
2703
2705 {
2706 Scene* activeScene = _context.kernel().projectManager()->activeProject()->getActiveScene();
2707 return *activeScene->lightPool();
2708 }
2709
2711 {
2712 return Attorney::ProjectManagerEditor::getEnvProbes( _context.kernel().projectManager().get() );
2713 }
2714
2716 {
2717 return Attorney::ProjectManagerCameraAccessor::moveCameraToNode( _context.kernel().projectManager().get(), camera, sgn );
2718 }
2719
2721 {
2722 for ( auto& window : _dockedWindows )
2723 {
2724 window->onRemoveComponent( comp );
2725 }
2726 }
2727
2728 void Editor::saveNode( const SceneGraphNode* sgn ) const
2729 {
2730 if ( Attorney::ProjectManagerEditor::saveNode( _context.kernel().projectManager().get(), sgn ) )
2731 {
2732 bool savedParent = false, savedScene = false;
2733 // Save the parent as well (if it isn't the root node) as this node may be
2734 // one that's been newly added
2735 if ( sgn->parent() != nullptr && sgn->parent()->parent() != nullptr )
2736 {
2737 savedParent = Attorney::ProjectManagerEditor::saveNode( _context.kernel().projectManager().get(), sgn->parent() );
2738 }
2739 if ( unsavedSceneChanges() )
2740 {
2741 savedScene = saveSceneChanges( {}, {} );
2742 }
2743
2746 "Saved node [ {} ] to file! (Saved parent: {}) (Saved scene: {})",
2747 sgn->name().c_str(),
2748 savedParent ? "Yes" : "No",
2749 savedScene ? "Yes" : "No" ),
2750 Time::SecondsToMilliseconds<F32>( 3 ),
2751 false );
2752 }
2753 }
2754
2756 {
2757 if ( Attorney::ProjectManagerEditor::loadNode( _context.kernel().projectManager().get(), sgn ) )
2758 {
2759 showStatusMessage( Util::StringFormat( "Reloaded node [ {} ] from file!",
2760 sgn->name().c_str() ),
2761 Time::SecondsToMilliseconds<F32>( 3 ),
2762 false );
2763 }
2764 }
2765
2766 void Editor::queueRemoveNode( const I64 nodeGUID )
2767 {
2768 Scene* activeScene = _context.kernel().projectManager()->activeProject()->getActiveScene();
2769 activeScene->sceneGraph()->removeNode( nodeGUID );
2770 unsavedSceneChanges( true );
2771 }
2772
2774 const ComponentType newComponentType ) const
2775 {
2776 if ( selection != nullptr && newComponentType != ComponentType::COUNT )
2777 {
2778 selection->AddComponents( to_U32( newComponentType ), true );
2779 return selection->componentMask() & to_U32( newComponentType );
2780 }
2781
2782 return false;
2783 }
2784
2785 bool Editor::addComponent( const Selections& selections,
2786 const ComponentType newComponentType ) const
2787 {
2788 bool ret = false;
2789 if ( selections._selectionCount > 0 )
2790 {
2791 Scene* activeScene = context().kernel().projectManager()->activeProject()->getActiveScene();
2792
2793 for ( U8 i = 0; i < selections._selectionCount; ++i )
2794 {
2795 SceneGraphNode* sgn = activeScene->sceneGraph()->findNode( selections._selections[i] );
2796 ret = addComponent( sgn, newComponentType ) || ret;
2797 }
2798 }
2799
2800 return ret;
2801 }
2802
2804 const ComponentType newComponentType ) const
2805 {
2806 if ( selection != nullptr && newComponentType != ComponentType::COUNT )
2807 {
2808 selection->RemoveComponents( to_U32( newComponentType ) );
2809 return !( selection->componentMask() & to_U32( newComponentType ) );
2810 }
2811
2812 return false;
2813 }
2814
2815 bool Editor::removeComponent( const Selections& selections,
2816 const ComponentType newComponentType ) const
2817 {
2818 bool ret = false;
2819 if ( selections._selectionCount > 0 )
2820 {
2821 Scene* activeScene = context().kernel().projectManager()->activeProject()->getActiveScene();
2822
2823 for ( U8 i = 0; i < selections._selectionCount; ++i )
2824 {
2825 SceneGraphNode* sgn = activeScene->sceneGraph()->findNode( selections._selections[i] );
2826 ret = removeComponent( sgn, newComponentType ) || ret;
2827 }
2828 }
2829
2830 return ret;
2831 }
2832
2834 {
2835 boost::property_tree::ptree pt;
2836 const ResourcePath editorPath = Paths::g_xmlDataLocation / Paths::Editor::g_saveLocation;
2837
2838 pt.put( "editor.showMemEditor", _showMemoryEditor );
2839 pt.put( "editor.showSampleWindow", _showSampleWindow );
2840 pt.put( "editor.themeIndex", to_I32( _currentTheme ) );
2841 pt.put( "editor.textEditor", _externalTextEditorPath.string() );
2842 pt.put( "editor.lastOpenSceneName", _lastOpenSceneName );
2843 pt.put( "editor.grid.<xmlattr>.enabled_scene", infiniteGridEnabledScene() );
2844 pt.put( "editor.grid.<xmlattr>.enabled_node", infiniteGridEnabledNode() );
2845 pt.put( "editor.grid.<xmlattr>.axisWidth", infiniteGridAxisWidth() );
2846 pt.put( "editor.grid.<xmlattr>.scale", infiniteGridScale() );
2847 pt.put( "editor.nodeBGColour.<xmlattr>.r", nodePreviewBGColour().r );
2848 pt.put( "editor.nodeBGColour.<xmlattr>.g", nodePreviewBGColour().g );
2849 pt.put( "editor.nodeBGColour.<xmlattr>.b", nodePreviewBGColour().b );
2850
2851 if ( _editorCamera )
2852 {
2853 _editorCamera->saveToXML( pt, "editor" );
2854 }
2855 if ( _nodePreviewCamera )
2856 {
2857 _nodePreviewCamera->saveToXML( pt, "editor" );
2858 }
2859 for ( size_t i = 0u; i < _recentSceneList.size(); ++i )
2860 {
2861 pt.add( "editor.recentScene.entry", _recentSceneList.get( i )._name.c_str() );
2862 }
2863
2864 if ( createDirectory( editorPath ) == FileError::NONE )
2865 {
2866 if ( copyFile( editorPath,
2867 g_editorSaveFile,
2868 editorPath,
2869 g_editorSaveFileBak,
2870 true )
2871 == FileError::NONE )
2872 {
2873 XML::writeXML( editorPath / g_editorSaveFile, pt );
2874 return true;
2875 }
2876 }
2877
2878 return false;
2879 }
2880
2882 {
2883 static boost::property_tree::ptree g_emptyPtree;
2884
2885 boost::property_tree::ptree pt;
2886 const ResourcePath editorPath = Paths::g_xmlDataLocation / Paths::Editor::g_saveLocation;
2887 if ( !fileExists( editorPath / g_editorSaveFile ) )
2888 {
2889 if ( fileExists( editorPath / g_editorSaveFileBak ) )
2890 {
2891 if ( copyFile( editorPath,
2892 g_editorSaveFileBak,
2893 editorPath,
2894 g_editorSaveFile,
2895 true )
2896 != FileError::NONE )
2897 {
2898 return false;
2899 }
2900 }
2901 }
2902
2903 if ( fileExists( editorPath / g_editorSaveFile ) )
2904 {
2905 XML::readXML(editorPath / g_editorSaveFile, pt );
2906 _showMemoryEditor = pt.get( "editor.showMemEditor", false );
2907 _showSampleWindow = pt.get( "editor.showSampleWindow", false );
2908 _currentTheme = static_cast<ImGuiStyleEnum>(pt.get( "themeIndex", to_I32( _currentTheme ) ));
2910 _externalTextEditorPath = ResourcePath { pt.get<string>( "editor.textEditor", "notepad" ) };
2911 if ( _lastOpenSceneName == pt.get<string>( "editor.lastOpenSceneName", "" ) )
2912 {
2913 NOP();
2914 }
2915 else
2916 {
2917 NOP();
2918 }
2919 for ( const auto& [tag, data] :
2920 pt.get_child( "editor.recentScene", g_emptyPtree ) )
2921 {
2922 if ( tag == "<xmlcomment>" )
2923 {
2924 continue;
2925 }
2926 const std::string name = data.get_value<std::string>();
2927 if ( !name.empty() )
2928 {
2929 _recentSceneList.put( SceneEntry { ._name = name.c_str() } );
2930 }
2931 }
2932
2933 if ( _editorCamera )
2934 {
2935 _editorCamera->loadFromXML( pt, "editor" );
2936 }
2937 if ( _nodePreviewCamera )
2938 {
2939 _nodePreviewCamera->loadFromXML( pt, "editor" );
2940 }
2941 infiniteGridEnabledScene( pt.get( "editor.grid.<xmlattr>.enabled_scene",
2942 infiniteGridEnabledScene() ) );
2943 infiniteGridEnabledNode( pt.get( "editor.grid.<xmlattr>.enabled_node", infiniteGridEnabledNode() ) );
2944 infiniteGridAxisWidth( pt.get( "editor.grid.<xmlattr>.axisWidth", infiniteGridAxisWidth() ) );
2945 infiniteGridScale( pt.get( "editor.grid.<xmlattr>.scale", infiniteGridScale() ) );
2946 _nodePreviewBGColour.set(
2947 pt.get( "editor.nodeBGColour.<xmlattr>.r", nodePreviewBGColour().r ),
2948 pt.get( "editor.nodeBGColour.<xmlattr>.g", nodePreviewBGColour().g ),
2949 pt.get( "editor.nodeBGColour.<xmlattr>.b", nodePreviewBGColour().b ) );
2950 return true;
2951 }
2952
2953 return false;
2954 }
2955
2956 namespace Util::detail
2957 {
2958 static std::stack<bool> g_readOnlyFaded;
2959 }; // namespace Util::detail
2960
2961 void PushReadOnly( const bool fade )
2962 {
2963 ImGui::PushItemFlag( ImGuiItemFlags_Disabled, true );
2964 if ( fade )
2965 {
2966 ImGui::PushStyleVar( ImGuiStyleVar_Alpha, std::max(0.5f, ImGui::GetStyle().Alpha - 0.35f) );
2967 }
2969 }
2970
2972 {
2974 {
2975 ImGui::PopStyleVar();
2976 }
2977 ImGui::PopItemFlag();
2979 }
2980} // namespace Divide
#define WAIT_FOR_CONDITION(...)
#define LOCALE_STR(X)
Definition: Localization.h:91
#define MOV(...)
#define SCOPE_EXIT
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define NOP()
#define DIVIDE_UNEXPECTED_CALL_MSG(X)
#define FORCE_INLINE
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_SCOPE(NAME, CATEGORY)
Definition: Profiler.h:86
WindowManager & windowManager() noexcept
Definition: Application.inl:77
static void updateSelection(Gizmo *gizmo, const vector< SceneGraphNode * > &nodes)
Definition: Gizmo.h:145
static void render(Gizmo *gizmo, const Camera *camera, const Rect< I32 > &targetViewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: Gizmo.h:141
static void onSceneFocus(Gizmo *gizmo, const bool state) noexcept
Definition: Gizmo.h:161
static void update(Gizmo *gizmo, const U64 deltaTimeUS)
Definition: Gizmo.h:149
static BoundingSphere moveCameraToNode(const Divide::ProjectManager *mgr, Camera *camera, const SceneGraphNode *targetNode)
static Camera * playerCamera(const Divide::ProjectManager *mgr, const bool skipOverride=false) noexcept
static bool saveNode(const Divide::ProjectManager *mgr, const SceneGraphNode *targetNode)
static bool loadNode(const Divide::ProjectManager *mgr, SceneGraphNode *targetNode)
static void editorPreviewNode(Divide::ProjectManager *mgr, const I64 editorPreviewNode)
static Camera * playerCamera(const Divide::ProjectManager *mgr, bool skipOverride=false) noexcept
static SceneEnvironmentProbePool * getEnvProbes(const Divide::ProjectManager *manager) noexcept
F32 getRadius() const noexcept
static Camera * GetUtilityCamera(const UtilityCamera type)
Definition: Camera.cpp:120
static Camera * CreateCamera(const Str< 256 > &cameraName, Mode cameraMode)
Definition: Camera.cpp:147
const CameraSnapshot & snapshot() const noexcept
Returns the internal camera snapshot data (eye, orientation, etc)
Definition: Camera.inl:43
static mat4< F32 > LookAt(const vec3< F32 > &eye, const vec3< F32 > &target, const vec3< F32 > &up) noexcept
Definition: Camera.cpp:938
static bool DestroyCamera(Camera *&camera)
Definition: Camera.cpp:175
size_t size() const noexcept
void put(const T &item)
const T & get(const size_t idx) const
void bringToFront() const noexcept
vec2< U16 > getDrawableSize() const noexcept
bool hidden() const noexcept
bool isHovered() const noexcept
I32 currentDisplayIndex() const noexcept
vec2< U16 > getDimensions() const noexcept
void addEventListener(WindowEvent windowEvent, const EventListener &listener)
void selectionChangeCallback(PlayerIndex idx, const vector< SceneGraphNode * > &nodes) const
Definition: Editor.cpp:1643
bool joystickAxisMoved(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2050
Handle< ShaderProgram > _infiniteGridProgram
Definition: Editor.h:352
void createFontTexture(F32 DPIScaleFactor)
Destroys the old font, if any, before loading the new one.
Definition: Editor.cpp:215
PipelineDescriptor _axisGizmoPipelineDesc
Definition: Editor.h:356
DisplayWindow * _mainWindow
Definition: Editor.h:349
void showStatusMessage(const string &message, F32 durationMS, bool error) const
Definition: Editor.cpp:2659
void updateFocusState(ImVec2 mousePos)
Definition: Editor.cpp:1813
bool mouseButtonReleased(const Input::MouseButtonEvent &arg) override
Mouse button released: return true if input was consumed.
Definition: Editor.cpp:1999
EditorOptionsWindow_uptr _optionsWindow
Definition: Editor.h:345
UndoManager_uptr _undoManager
Definition: Editor.h:346
static ImGuiViewport * FindViewportByPlatformHandle(ImGuiContext *context, const DisplayWindow *window)
Definition: Editor.cpp:1795
SceneGraphNode * _previewNode
Definition: Editor.h:337
bool mouseMoved(const Input::MouseMoveEvent &arg) override
Mouse moved: return true if input was consumed.
Definition: Editor.cpp:1861
bool onKeyDown(const Input::KeyEvent &key) override
Key pressed: return true if input was consumed.
Definition: Editor.cpp:1701
IMPrimitive * _axisGizmo
Definition: Editor.h:357
bool wantsKeyboard() const noexcept
Definition: Editor.cpp:2106
std::pair< bufferPtr, size_t > _memoryEditorData
Definition: Editor.h:362
eastl::fixed_vector< std::pair< I64, GenericVertexData_ptr >, 5, true > _imguiBuffers
Definition: Editor.h:360
RenderTargetHandle _nodePreviewRTHandle
Definition: Editor.h:382
bool addComponent(SceneGraphNode *selection, ComponentType newComponentType) const
Definition: Editor.cpp:2773
bool joystickButtonPressed(const Input::JoystickEvent &arg) noexcept override
Joystick or Gamepad: return true if input was consumed.
Definition: Editor.cpp:2040
bool joystickRemap(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2070
void onChangeScene(Scene *newScene)
Definition: Editor.cpp:2268
bool modalModelSpawn(Handle< Mesh > mesh, bool quick, const vec3< F32 > &scale=VECTOR3_UNIT, const vec3< F32 > &position=VECTOR3_ZERO)
Returns true if the model was queued.
Definition: Editor.cpp:2537
U32 stepQueue() const noexcept
Definition: Editor.inl:53
void onWindowSizeChange(const SizeChangeParams &params)
Definition: Editor.cpp:2151
bool isHovered() const
Definition: Editor.cpp:2127
bool init(const vec2< U16 > renderResolution)
Definition: Editor.cpp:274
bool modalTextureView(std::string_view modalName, Handle< Texture > tex, vec2< F32 > dimensions, bool preserveAspect, bool useModal) const
Returns true if the window was closed.
Definition: Editor.cpp:2289
std::array< ImGuiContext *, to_base(ImGuiContextType::COUNT)> _imguiContexts
Definition: Editor.h:363
void drawScreenOverlay(const Camera *camera, const Rect< I32 > &targetViewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut) const
Render any editor specific element that needs to be part of the scene (e.g. Control Gizmo)
Definition: Editor.cpp:1289
bool Redo() const
Definition: Editor.cpp:1685
bool saveToXML() const
Definition: Editor.cpp:2833
Gizmo_uptr _gizmo
Definition: Editor.h:347
void close()
Definition: Editor.cpp:817
bool mouseButtonPressed(const Input::MouseButtonEvent &arg) override
Mouse button pressed: return true if input was consumed.
Definition: Editor.cpp:1959
void renderModelSpawnModal()
Definition: Editor.cpp:2574
U32 _stepQueue
Definition: Editor.h:371
void renderDrawList(ImDrawData *pDrawData, I64 bufferGUID, const Rect< I32 > &targetViewport, bool editorPass, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: Editor.cpp:1433
LightPool & getActiveLightPool() const
Definition: Editor.cpp:2704
bool Undo() const
Definition: Editor.cpp:1670
bool joystickAddRemove(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2065
Time::ProfileTimer & _editorUpdateTimer
Definition: Editor.h:340
U32 saveItemCount() const noexcept
Definition: Editor.cpp:2273
StatusBar_uptr _statusBar
Definition: Editor.h:344
void postRender(RenderStage stage, const CameraSnapshot &cameraSnapshot, RenderTargetID target, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: Editor.cpp:1236
bool spawnGeometry(Handle< Mesh > mesh, const vec3< F32 > &scale, const vec3< F32 > &position, const vec3< Angle::DEGREES< F32 > > &rotation, std::string_view name) const
Return true if the model was spawned as a scene node.
Definition: Editor.cpp:2666
bool isInit() const noexcept
Definition: Editor.inl:37
Pipeline * _editorPipeline
Definition: Editor.h:358
const ProjectIDs & getProjectList() const noexcept
Definition: Editor.cpp:2694
void infiniteGridScale(const F32 value) noexcept
Definition: Editor.cpp:1211
bool joystickBallMoved(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2060
void copyPlayerCamToEditorCam() noexcept
Definition: Editor.cpp:1653
ImGuiStyleEnum _currentTheme
Definition: Editor.h:374
void update(U64 deltaTimeUS)
Definition: Editor.cpp:991
bool _showMemoryEditor
Definition: Editor.h:377
std::array< std::unique_ptr< DockedWindow >, to_base(WindowType::COUNT)> _dockedWindows
Definition: Editor.h:364
struct Divide::Editor::QueueModelSpawn _queuedModelSpawn
IMPrimitive * _infiniteGridPrimitive
Definition: Editor.h:354
void toggle(bool state)
Definition: Editor.cpp:883
static std::array< Input::MouseButton, 5 > g_oisButtons
Definition: Editor.h:156
bool render()
Definition: Editor.cpp:1138
SamplerDescriptor _editorSampler
Definition: Editor.h:368
bool removeComponent(SceneGraphNode *selection, ComponentType newComponentType) const
Definition: Editor.cpp:2803
bool isNodeInView(const SceneGraphNode &node) const noexcept
Return true if the specified node passed frustum culling during the main render pass.
Definition: Editor.cpp:1217
CircularBuffer< SceneEntry, 10 > _recentSceneList
Definition: Editor.h:380
static std::array< const char *, 3 > g_supportedExportPlatforms
Definition: Editor.h:157
MenuBar_uptr _menuBar
Definition: Editor.h:343
void loadNode(SceneGraphNode *sgn) const
Definition: Editor.cpp:2755
void onRemoveComponent(const EditorComponent &comp) const
Definition: Editor.cpp:2720
bool onTextEvent(const Input::TextEvent &arg) override
Definition: Editor.cpp:2132
void updateEditorFocus()
Definition: Editor.cpp:865
bool wantsMouse() const
Definition: Editor.cpp:2085
bool wantsJoystick() const noexcept
Definition: Editor.cpp:2075
BoundingSphere teleportToNode(Camera *camera, const SceneGraphNode *sgn) const
Definition: Editor.cpp:2715
bool onKeyUp(const Input::KeyEvent &key) override
Key released: return true if input was consumed.
Definition: Editor.cpp:1739
void setEditorCamLookAt(const vec3< F32 > &eye, const vec3< F32 > &fwd, const vec3< F32 > &up)
Definition: Editor.cpp:1658
bool hasFocus() const
Definition: Editor.cpp:2122
bool _isScenePaused
Definition: Editor.h:378
void saveNode(const SceneGraphNode *sgn) const
Definition: Editor.cpp:2728
bool switchScene(const SceneEntry &scene, bool createIfNotExists=false)
Definition: Editor.cpp:2219
bool frameEnded(const FrameEvent &evt) noexcept override
frameEnded is called after the buffers have been swapped
Definition: Editor.cpp:1372
bool framePostRender(const FrameEvent &evt) override
Definition: Editor.cpp:1295
const SceneEntries & getSceneList() const noexcept
Definition: Editor.cpp:2699
ResourcePath _externalTextEditorPath
Definition: Editor.h:366
GenericVertexData * getOrCreateIMGUIBuffer(I64 bufferGUID, U32 maxVertices, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: Editor.cpp:1394
bool _showSampleWindow
Definition: Editor.h:375
bool simulationPaused() const noexcept
Definition: Editor.inl:57
void getCommandBuffer(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: Editor.cpp:1300
SceneEnvironmentProbePool * getActiveEnvProbePool() const noexcept
Definition: Editor.cpp:2710
bool joystickButtonReleased(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2045
void setEditorCameraSpeed(const vec3< F32 > &speed) noexcept
Definition: Editor.cpp:1665
bool _showOptionsWindow
Definition: Editor.h:376
bool saveSceneChanges(const DELEGATE< void, std::string_view > &msgCallback, const DELEGATE< void, bool > &finishCallback) const
Saves all new changes to the current scene and uses the provided callbacks to return progress message...
Definition: Editor.cpp:2200
void onResolutionChange(const SizeChangeParams &params)
Definition: Editor.cpp:2180
Handle< Texture > _fontTexture
Definition: Editor.h:350
bool joystickPovMoved(const Input::JoystickEvent &arg) noexcept override
Definition: Editor.cpp:2055
~Editor() override
Definition: Editor.cpp:204
Time::ProfileTimer & _editorRenderTimer
Definition: Editor.h:341
void queueRemoveNode(I64 nodeGUID)
Definition: Editor.cpp:2766
CameraSnapshot _render2DSnapshot
Definition: Editor.h:381
bool isDefaultScene() const noexcept
Definition: Editor.cpp:2283
bool openProject(const ProjectID &projectID)
Definition: Editor.cpp:2214
bool loadFromXML()
Definition: Editor.cpp:2881
void infiniteGridAxisWidth(const F32 value) noexcept
Definition: Editor.cpp:1205
string _lastOpenSceneName
Definition: Editor.h:370
PipelineDescriptor _infiniteGridPipelineDesc
Definition: Editor.h:355
Handle< ShaderProgram > _imguiProgram
Definition: Editor.h:351
F32 _queuedDPIValue
Definition: Editor.h:372
bool _gridSettingsDirty
Definition: Editor.h:379
void idle() noexcept
Definition: Editor.cpp:210
Rect< I32 > scenePreviewRect(bool globalCoords) const noexcept
Definition: Editor.cpp:1382
IMPrimitive * newIMP(std::string_view name)
Create and return a new immediate mode emulation primitive.
Definition: GFXDevice.cpp:3055
GFXRTPool & renderTargetPool() noexcept
Definition: GFXDevice.inl:133
const RenderStateBlock & getNoDepthTestBlock() const noexcept
returns the standard state block
Definition: GFXDevice.inl:128
bool destroyIMP(IMPrimitive *&primitive)
Definition: GFXDevice.cpp:3061
Pipeline * newPipeline(const PipelineDescriptor &descriptor)
Create and return a new graphics pipeline. This is only used for caching and doesn't use the object a...
Definition: GFXDevice.cpp:3074
GenericVertexData_ptr newGVD(U32 ringBufferLength, std::string_view name)
Definition: GFXDevice.inl:219
void flushCommandBuffer(Handle< GFX::CommandBuffer > &&commandBuffer)
Definition: GFXDevice.cpp:2120
RenderTarget * getRenderTarget(const RenderTargetID target) const
Definition: GFXRTPool.cpp:50
RenderTargetHandle allocateRT(const RenderTargetDescriptor &descriptor)
Definition: GFXRTPool.cpp:17
bool deallocateRT(RenderTargetHandle &handle)
Definition: GFXRTPool.cpp:33
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
virtual BufferLock updateBuffer(U32 buffer, U32 elementCountOffset, U32 elementCountRange, bufferPtr data)=0
virtual BufferLock setIndexBuffer(const IndexBuffer &indices)=0
void getCommandBuffer(GFX::CommandBuffer &commandBufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
void beginBatch(bool reserveBuffers, U32 vertexCount, U32 attributeCount)
Definition: IMPrimitive.cpp:96
void vertex(F32 x, F32 y, F32 z)
void fromCones(const IM::ConeDescriptor *cones, size_t count)
void setPipelineDescriptor(const PipelineDescriptor &descriptor)
void setPushConstants(const PushConstantsStruct &fastData)
void begin(PrimitiveTopology type)
void endBatch() noexcept
const Rect< I32 > & sceneRect(bool globalCoords) const noexcept
PlatformContext & context() noexcept
Application & app() noexcept
Kernel & kernel() noexcept
Editor & editor() noexcept
GFXDevice & gfx() noexcept
Configuration & config() noexcept
bool contains(U xIn, U yIn) const noexcept
Definition: MathVectors.h:1465
bool resize(U16 width, U16 height)
Resize all attachments.
U16 getWidth() const noexcept
void incQueue() noexcept
Definition: RingBuffer.h:118
static BoundingSphere GetBounds(const SceneGraphNode *sgn)
Definition: SceneGraph.cpp:36
void RemoveComponents(U32 componentMask)
FORCE_INLINE T * get() const
Returns a pointer to a specific component. Returns null if the SGN does not have the component reques...
void AddComponents(U32 componentMask, bool allowDuplicates)
static I64 DEFAULT_SCENE_GUID
Definition: Scene.h:131
An API-independent representation of a texture.
Definition: Texture.h:83
static Handle< Texture > DefaultTexture2DArray() noexcept
Definition: Texture.cpp:95
static const SamplerDescriptor DefaultSampler() noexcept
Definition: Texture.cpp:100
static Handle< Texture > DefaultTexture2D() noexcept
Definition: Texture.cpp:90
ImageView getView() const noexcept
Definition: Texture.cpp:597
void setPosition(const vec3< F32 > &position) override
Component <-> Transform interface.
void rotate(const vec3< F32 > &axis, Angle::DEGREES< F32 > degrees) override
void setScale(const vec3< F32 > &amount) override
Set the local X,Y and Z scale factors.
static bool IsRelativeMouseMode() noexcept
static U32 GetMouseState(vec2< I32 > &pos, bool global) noexcept
DisplayWindow * getFocusedWindow() noexcept
static void SetCaptureMouse(bool state) noexcept
DisplayWindow * createWindow(const WindowDescriptor &descriptor, ErrorCode &err)
const vector< MonitorData > & monitorData() const noexcept
static void SetCursorStyle(CursorStyle style)
bool destroyWindow(DisplayWindow *&window)
static bool SetGlobalCursorPosition(I32 x, I32 y) noexcept
DisplayWindow & getWindow(I64 guid)
void drawToWindow(DisplayWindow &window)
vec3< T > getForwardVec() const noexcept
Alias for -getCol(2). Assumes -Z fwd.
vec4< T > _vec[4]
Definition: MathMatrices.h:709
vec3< T > getUpVec() const noexcept
Alias for getCol(1)
void set(const T *v) noexcept
set the 2 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:335
T length() const noexcept
return the vector's length
Definition: MathVectors.h:747
vec3 direction(const vec3 &u) const noexcept
get the direction vector to the specified point
void set(const T *v) noexcept
set the 3 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:707
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:1241
vec2< T > xy
Definition: MathVectors.h:1366
static size_t ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
#define IM_ARRAYSIZE(_ARR)
ImGuiStyleEnum
constexpr U8 MAX_FRAMES_IN_FLIGHT
Maximum number of active frames until we start waiting on a fence/sync.
Definition: config.h:100
constexpr char ENGINE_NAME[]
Definition: config.h:200
CommandBuffer * Get(Handle< CommandBuffer > handle)
FORCE_INLINE T * EnqueueCommand(CommandBuffer &buffer)
Handle< CommandBuffer > AllocateCommandBuffer(const char *name, const size_t reservedCmdCount)
FORCE_INLINE void FreeWrapper(void *ptr, void *user_data) noexcept
Definition: Editor.cpp:105
static ImGuiAllocatorUserData g_ImAllocatorUserData
Definition: Editor.cpp:113
FORCE_INLINE void * MallocWrapper(const size_t size, void *user_data) noexcept
Definition: Editor.cpp:99
static ImGuiMemAllocFunc g_ImAllocatorAllocFunc
Definition: Editor.cpp:111
static ImGuiMemFreeFunc g_ImAllocatorFreeFunc
Definition: Editor.cpp:112
constexpr Optick::Category::Type GUI
Definition: Profiler.h:64
static std::stack< bool > g_readOnlyFaded
Definition: Editor.cpp:2958
Str StringFormat(const char *fmt, Args &&...args)
void CenterNextWindow()
Definition: Utils.cpp:406
bool IsEmptyOrNull(const char *str) noexcept
void OpenCenteredPopup(const char *name, ImGui::ImGuiPopupFlags popup_flags=0)
void writeXML(const ResourcePath &path, const boost::property_tree::ptree &tree)
void readXML(const ResourcePath &path, boost::property_tree::ptree &tree)
void Reset(Editor::FocusedWindowState &state) noexcept
Definition: Editor.cpp:59
bool Hovered(const Editor::FocusedWindowState &state) noexcept
Definition: Editor.cpp:81
bool Focused(const Editor::FocusedWindowState &state) noexcept
Definition: Editor.cpp:86
IMGUICallbackData g_modalTextureData
Definition: Editor.cpp:57
bool SetFocus(Editor::FocusedWindowState &state) noexcept
Definition: Editor.cpp:64
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
ImTextureID to_TexID(Handle< Texture > handle)
Definition: Editor.cpp:116
void SetClipboardText(const char *text) noexcept
void InitBasicImGUIState(ImGuiIO &io) noexcept
Definition: Editor.cpp:128
DELEGATE_STD< Ret, Args... > DELEGATE
F32 PlatformDefaultDPI() noexcept
std::byte Byte
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
vector< SceneEntry > SceneEntries
Definition: Scene.h:116
static const vec3< F32 > WORLD_X_NEG_AXIS
Definition: MathVectors.h:1442
PushConstantsStruct IMGUICallbackToPushConstants(const IMGUICallbackData &data, const bool isArrayTexture)
Definition: Editor.cpp:166
constexpr U16 to_U16(const T value)
constexpr RenderTargetID SCREEN_TARGET_ID
void PushReadOnly(const bool fade)
Definition: Editor.cpp:2961
int32_t I32
vector< ProjectID > ProjectIDs
uint8_t U8
ImGuiKey DivideKeyToImGuiKey(const Input::KeyCode key) noexcept
Definition: Utils.cpp:66
bool DebugBreak(const bool condition) noexcept
static const vec3< F32 > WORLD_Y_NEG_AXIS
Definition: MathVectors.h:1443
constexpr F32 to_F32(const T value)
const char * GetClipboardText() noexcept
bool IsCubeTexture(TextureType texType) noexcept
bool IsArrayTexture(TextureType texType) noexcept
FileError createDirectory(const ResourcePath &path)
eastl::vector< Type > vector
Definition: Vector.h:42
bool IsDepthTexture(GFXImagePacking packing) noexcept
FileError copyFile(const ResourcePath &sourcePath, const std::string_view sourceName, const ResourcePath &targetPath, const std::string_view targetName, const bool overwrite)
void PopReadOnly()
Definition: Editor.cpp:2971
uint16_t U16
void Set(DescriptorSetBindingData &dataInOut, ShaderBuffer *buffer, const BufferRange range) noexcept
DescriptorSetBinding & AddBinding(DescriptorSet &setInOut, U8 slot, U16 stageVisibilityMask)
vec2< T > COORD_REMAP(vec2< T > input, const Rect< T > &in_rect, const Rect< T > &out_rect) noexcept
Definition: MathHelper.h:172
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
@ Vulkan
not supported yet
constexpr U8 to_U8(const T value)
static const vec3< F32 > WORLD_Z_NEG_AXIS
Definition: MathVectors.h:1444
SceneNodeHandle FromHandle(const Handle< T > handle)
Handle< Texture > from_TexID(ImTextureID texID)
Definition: Editor.cpp:122
bool COMPARE(T X, U Y) noexcept
void ToggleCursor(bool state) noexcept
bool fileExists(const ResourcePath &filePathAndName)
vec4< U8 > UColour4
Definition: MathHelper.h:72
constexpr I32 to_I32(const T value)
static const vec3< F32 > VECTOR3_ZERO
Definition: MathVectors.h:1434
U32 RenderTargetID
U8 NumChannels(GFXImageFormat format) noexcept
int64_t I64
FORCE_INLINE T * Get(const Handle< T > handle)
uint32_t U32
uint64_t U64
constexpr auto to_base(const Type value) -> Type
bool ImageZoomAndPan(ImTextureID user_texture_id, const ImVec2 &size, float aspectRatio, float &zoom, ImVec2 &zoomCenter, int panMouseButtonDrag, int resetZoomAndPanMouseButton, const ImVec2 &zoomMaxAndZoomStep)
bool ToggleButton(const char *str_id, bool *v)
bool ResetStyle(int styleEnum, ImGuiStyle &style)
VertexBindings _vertexBindings
BufferUpdateUsage _updateUsage
Definition: BufferParams.h:40
BufferUpdateFrequency _updateFrequency
Definition: BufferParams.h:39
size_t _elementSize
Buffer primitive size in bytes.
Definition: BufferParams.h:50
BufferFlags _flags
Definition: BufferParams.h:48
mat4< F32 > _invViewMatrix
mat4< F32 > _projectionMatrix
static NO_INLINE void errorfn(const char *format, T &&... args)
DescriptorSetBindingData _data
GenericDrawCommandContainer _drawCommands
Definition: Commands.inl:81
static constexpr RTColourAttachmentSlot ALBEDO
Definition: GFXDevice.h:228
std::pair< bufferPtr, size_t > _initialData
vec2< F32 > _depthRange
Definition: Editor.h:124
Handle< Texture > _texture
Definition: Editor.h:122
GFX::CommandBuffer * _cmdBuffer
Definition: Editor.h:121
vec4< I32 > _colourData
Definition: Editor.h:123
const MouseState & state() const noexcept
PrimitiveTopology _primitiveTopology
Definition: Pipeline.h:48
AttributeMap _vertexFormat
Definition: Pipeline.h:49
Handle< ShaderProgram > _shaderProgramHandle
Definition: Pipeline.h:47
RTBlendStates _blendStates
Definition: Pipeline.h:45
RenderStateBlock _stateBlock
Definition: Pipeline.h:46
vector< ShaderModuleDescriptor > _modules
std::array< BlendingSettings, to_base(RTColourAttachmentSlot::COUNT)> _settings
InternalRTAttachmentDescriptors _attachments
Definition: RenderTarget.h:52
PropertyDescriptor< T > _propertyDescriptor
Definition: Resource.h:151
StringReturnType< N > string() const noexcept
Definition: ResourcePath.h:64
TextureWrap _wrapU
Texture wrap mode (Or S-R-T)
U8 _anisotropyLevel
The value must be in the range [0...255] and is automatically clamped by the max HW supported level.
Definition: Scene.h:112
Str< 256 > _name
Definition: Scene.h:113
std::array< I64, MAX_SELECTIONS > _selections
Definition: Scene.h:100
U16 width
The new width and height.
DisplayWindow * parentWindow
static ImGuiWindowFlags ExtraWindowFlags