Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
GUI.cpp
Go to the documentation of this file.
1
2
3#include "Headers/GUI.h"
5
6#include "Headers/GUIButton.h"
9#include "Headers/GUIText.h"
11
14
18#include "Core/Headers/Kernel.h"
21
23
28
29#define FONTSTASH_IMPLEMENTATION
31
32namespace Divide
33{
34 struct DVDFONSContext final : private NonCopyable
35 {
36 DVDFONSContext() = default;
38 {
39 if ( _impl != nullptr )
40 {
42 }
43 }
44
47 bool _bufferNeedsResize = false;
48
49 GFXDevice* _parent{ nullptr };
50 GenericVertexData_ptr _fontRenderingBuffer{};
51 Handle<Texture> _fontRenderingTexture{INVALID_HANDLE<Texture>};
52 I32 _width{ 1u };
53
56
57 FONScontext* _impl{ nullptr };
58 };
59
60 namespace
61 {
63
65 {
67 params._bindConfig = { 0u, 0u };
68 params._useRingBuffer = true;
69 params._initialData = { nullptr, 0 };
70
72 params._bufferParams._elementSize = sizeof( FONSvert );
75
76 const auto lock = dvd->_fontRenderingBuffer->setBuffer( params ); //Pos, UV and Colour
77 DIVIDE_UNUSED( lock );
78 }
79
80
81 I32 FONSRenderCreate( void* userPtr, int width, int height )
82 {
83 DVDFONSContext* dvd = (DVDFONSContext*)userPtr;
84
85 dvd->_fontRenderingBuffer = dvd->_parent->newGVD( Config::MAX_FRAMES_IN_FLIGHT + 1u, "GUIFontBuffer" );
86
88
89 ResourceDescriptor<Texture> resDescriptor( "FONTSTASH_font_texture" );
90 TextureDescriptor& texDescriptor = resDescriptor._propertyDescriptor;
91 texDescriptor._baseFormat = GFXImageFormat::RED;
93 texDescriptor._allowRegionUpdates = true;
94
95 dvd->_fontRenderingTexture = CreateResource( resDescriptor );
96 if ( dvd->_fontRenderingTexture != INVALID_HANDLE<Texture>)
97 {
98 Get(dvd->_fontRenderingTexture)->createWithData( nullptr, 0u, vec2<U16>( width, height), {});
99
100 if ( dvd->_fontRenderingBuffer )
101 {
102 return 1;
103 }
104 }
105
106 return 0;
107 }
108 }
109
110 void DIVIDE_ASSERT_MSG_BOX( const char* failMessage ) noexcept
111 {
113 {
114 if ( g_assertMsgBox )
115 {
116 g_assertMsgBox->setTitle( "Assertion Failed!" );
117 g_assertMsgBox->setMessage( failMessage );
119 g_assertMsgBox->show();
120 }
121 }
122 }
123
125 : GUIInterface( *this )
127 , FrameListener( "GUI", parent.frameListenerMgr(), 2 )
128 , _textRenderInterval( Time::MillisecondsToMicroseconds( 10 ) )
129 , _ceguiInput( *this )
130 {
131 // 500ms
133 }
134
136 {
137 destroy();
138 }
139
140 void GUI::onChangeScene( Scene* newScene )
141 {
142 assert( newScene != nullptr );
144 if ( _activeScene != nullptr && _activeScene->getGUID() != newScene->getGUID() )
145 {
146 const GUIMapPerScene::const_iterator it = _guiStack.find( _activeScene->getGUID() );
147 if ( it != std::cend( _guiStack ) )
148 {
149 it->second->onDisable();
150 }
151 }
152
153 const GUIMapPerScene::const_iterator it = _guiStack.find( newScene->getGUID() );
154 if ( it != std::cend( _guiStack ) )
155 {
156 it->second->onEnable();
157 }
158 else
159 {
161 insert( _guiStack, newScene->getGUID(), elements );
162 elements->onEnable();
163 }
164
165 _activeScene = newScene;
167 }
168
169 void GUI::onUnloadScene( Scene* const scene )
170 {
171 assert( scene != nullptr );
173 const GUIMapPerScene::const_iterator it = _guiStack.find( scene->getGUID() );
174 if ( it != std::cend( _guiStack ) )
175 {
176 _guiStack.erase( it );
177 }
178 }
179
180 void GUI::drawText( const TextElementBatch& batch, const Rect<I32>& targetViewport, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut, const bool pushCamera )
181 {
183
184 if ( _fonsContext == nullptr )
185 {
186 return;
187 }
188
189 _fonsContext->_commandBuffer = &bufferInOut;
190 _fonsContext->_memCmd = &memCmdInOut;
191
192 static const SamplerDescriptor sampler = {
194 ._magFilter = TextureFilter::LINEAR,
195 ._mipSampling = TextureMipSampling::NONE,
199 ._anisotropyLevel = 0u
200 };
201
202 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Draw Text";
203
204 if ( pushCamera )
205 {
206 GFX::EnqueueCommand<GFX::PushCameraCommand>( bufferInOut )->_cameraSnapshot = Camera::GetUtilityCamera( Camera::UtilityCamera::_2D )->snapshot();
207 }
208
209 GFX::EnqueueCommand<GFX::BindPipelineCommand>( bufferInOut )->_pipeline = _textRenderPipeline;
210
211 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
212 cmd->_usage = DescriptorSetUsage::PER_DRAW;
214 Set( binding._data, _fonsContext->_fontRenderingTexture, sampler );
215
216 size_t drawCount = 0;
217 size_t previousStyle = 0;
218
219
221 for ( const TextElement& entry : batch.data() )
222 {
223 if ( previousStyle != entry.textLabelStyleHash() )
224 {
225 const TextLabelStyle& textLabelStyle = TextLabelStyle::get( entry.textLabelStyleHash() );
226 const UColour4& colour = textLabelStyle.colour();
227 // Retrieve the font from the font cache
228 const I32 font = getFont( TextLabelStyle::fontName( textLabelStyle.font() ) );
229 // The font may be invalid, so skip this text label
230 if ( font != FONS_INVALID )
231 {
232 fonsSetFont( _fonsContext->_impl, font );
233 }
234 fonsSetBlur( _fonsContext->_impl, textLabelStyle.blurAmount() );
235 fonsSetBlur( _fonsContext->_impl, textLabelStyle.spacing() );
236 fonsSetAlign( _fonsContext->_impl, textLabelStyle.alignFlag() );
237 fonsSetSize( _fonsContext->_impl, to_F32( textLabelStyle.fontSize() ) );
238 fonsSetColour( _fonsContext->_impl, colour.r, colour.g, colour.b, colour.a );
239 previousStyle = entry.textLabelStyleHash();
240 }
241
242 F32 textX = entry.position()._x._scale * targetViewport.sizeX + entry.position()._x._offset;
243 F32 textY = targetViewport.sizeY - (entry.position()._y._scale * targetViewport.sizeY + entry.position()._y._offset);
244
245 textX += targetViewport.offsetX;
246 textY += targetViewport.offsetY;
247
248 F32 lh = 0;
249 fonsVertMetrics( _fonsContext->_impl, nullptr, nullptr, &lh );
250
251 const TextElement::TextType& text = entry.text();
252 const size_t lineCount = text.size();
253
254
255 for ( size_t i = 0; i < lineCount; ++i )
256 {
258 textX,
259 textY - lh * i,
260 text[i].c_str(),
261 nullptr );
262 }
263 drawCount += lineCount;
264
265 // Register each label rendered as a draw call
266 _fonsContext->_parent->registerDrawCalls( to_U32( drawCount ) );
267 }
268
269 if ( pushCamera )
270 {
272 }
273
274 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
275 }
276
277 void GUI::preDraw( [[maybe_unused]] GFXDevice& context, [[maybe_unused]] const Rect<I32>& viewport, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut )
278 {
279 if ( !_init || !_activeScene )
280 {
281 return;
282 }
283
285
286 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Pre-Render GUI";
287 if ( _ceguiRenderer != nullptr )
288 {
289 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Render CEGUI";
290
291 _ceguiRenderer->beginRendering( bufferInOut, memCmdInOut );
293 _ceguiContext->draw();
295
296 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
297 }
298
299 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
300 }
301
302 void GUI::draw( GFXDevice& context, const Rect<I32>& viewport, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut )
303 {
304 thread_local TextElementBatch textBatch;
305
306 if ( !_init || !_activeScene )
307 {
308 return;
309 }
310
312
313 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Render GUI";
314
315 //Set a 2D camera for rendering
316 GFX::EnqueueCommand<GFX::SetCameraCommand>( bufferInOut )->_cameraSnapshot = Camera::GetUtilityCamera( Camera::UtilityCamera::_2D )->snapshot();
317
318 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut )->_viewport = viewport;
319
320 const GUIMap& elements = _guiElements[to_base( GUIType::GUI_TEXT )];
321
322 efficient_clear(textBatch.data());
323
324 textBatch.data().reserve( elements.size() );
325 for ( const GUIMap::value_type& guiStackIterator : elements )
326 {
327 const GUIText& textLabel = static_cast<GUIText&>(*guiStackIterator.second.first);
328 if ( textLabel.visible() && !textLabel.text().empty() )
329 {
330 textBatch.data().push_back( textLabel );
331 }
332 }
333
334 {
336 // scene specific
337 const GUIMapPerScene::const_iterator it = _guiStack.find( _activeScene->getGUID() );
338 if ( it != std::cend( _guiStack ) )
339 {
340 const auto& batch = it->second->updateAndGetText();
341 textBatch.data().insert(textBatch.data().cend(), batch.data().cbegin(), batch.data().cend());
342 }
343 }
344
345 if ( !textBatch.data().empty() )
346 {
347 drawText( textBatch, viewport, bufferInOut, memCmdInOut );
348 }
349
350 if ( _ceguiRenderer != nullptr )
351 {
352 context.drawTextureInViewport( Get(_renderTextureTarget->getAttachmentTex())->getView(), _renderTextureTarget->getSampler(), viewport, false, false, true, bufferInOut);
353 }
354
355 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
356 }
357
358 void GUI::update( const U64 deltaTimeUS )
359 {
360 if ( !_init )
361 {
362 return;
363 }
364
366
367 if ( _ceguiRenderer != nullptr )
368 {
369 _ceguiInput.update( deltaTimeUS );
370 auto& ceguiSystem = CEGUI::System::getSingleton();
371 ceguiSystem.injectTimePulse( Time::MicrosecondsToSeconds<F32>( deltaTimeUS ) );
372 ceguiSystem.getDefaultGUIContext().injectTimePulse( Time::MicrosecondsToSeconds<F32>( deltaTimeUS ) );
373 }
374
375 if ( _console )
376 {
377 _console->update( deltaTimeUS );
378 }
379 }
380
381 bool GUI::frameStarted( [[maybe_unused]] const FrameEvent& evt )
382 {
383 if ( _fonsContext != nullptr )
384 {
385 _fonsContext->_fontRenderingBuffer->incQueue();
386 _fonsContext->_writeOffset = 0u;
387
388 if ( _fonsContext->_bufferNeedsResize )
389 {
390 ++_fonsContext->_bufferSizeFactor;
391 RefreshBufferSize( _fonsContext.get() );
392 _fonsContext->_bufferNeedsResize = false;
393 }
394 }
395
396 return true;
397 }
398
400 {
401 if ( _init )
402 {
403 Console::d_errorfn( LOCALE_STR( "ERROR_GUI_DOUBLE_INIT" ) );
405 }
406
407
408 _ceguiInput.init( parent().platformContext().config() );
409
410 _console = std::make_unique<GUIConsole>( *this, context );
411
412 GUIButton::soundCallback( [&context]( const Handle<AudioDescriptor>& sound )
413 {
414 context.sfx().playSound( sound );
415 } );
416
417
418 _fonsContext = std::make_unique<DVDFONSContext>();
419 _fonsContext->_width = 512;
420 _fonsContext->_parent = &context.gfx();
421
422 FONSparams params;
423 memset( &params, 0, sizeof params );
424 params.width = _fonsContext->_width;
425 params.height = 512;
426 params.renderCreate = FONSRenderCreate;
427 params.renderResize = []( void* userPtr, int width, int height )
428 {
429 const DVDFONSContext* dvd = (DVDFONSContext*)userPtr;
430
431 if ( dvd->_fontRenderingTexture != INVALID_HANDLE<Texture>)
432 {
433 Get(dvd->_fontRenderingTexture)->createWithData( nullptr, 0u, vec2<U16>( width, height), {} );
434 return 1;
435 }
436
437 return FONSRenderCreate( userPtr, width, height );
438 };
439 params.renderUpdate = []( void* userPtr, int* rect, const unsigned char* data )
440 {
441 const DVDFONSContext* dvd = (DVDFONSContext*)userPtr;
442
443 if ( dvd->_fontRenderingTexture == INVALID_HANDLE<Texture> )
444 {
445 FONSRenderCreate( userPtr, dvd->_width, dvd->_width );
446 }
447
448 const I32 w = rect[2] - rect[0];
449 const I32 h = rect[3] - rect[1];
450
451 const PixelAlignment pixelUnpackAlignment =
452 {
453 ._alignment = 1u,
454 ._rowLength = to_size( dvd->_width ),
455 ._skipPixels = to_size( rect[0] ),
456 ._skipRows = to_size( rect[1] )
457 };
458
459 Get(dvd->_fontRenderingTexture)->replaceData( (const Divide::Byte*)data, sizeof( U8 ) * w * h, vec3<U16>{rect[0], rect[1], 0}, vec3<U16>{w, h, 1u}, pixelUnpackAlignment );
460 };
461 params.renderDraw = []( void* userPtr, const FONSvert* verts, int nverts )
462 {
463 DVDFONSContext* dvd = (DVDFONSContext*)userPtr;
464 if ( dvd->_fontRenderingTexture == INVALID_HANDLE<Texture> || !dvd->_fontRenderingBuffer || !dvd->_commandBuffer )
465 {
466 return;
467 }
468
469 dvd->_writeOffset = (dvd->_writeOffset + 1u) % dvd->_bufferSizeFactor;
470 if ( dvd->_writeOffset == 0u )
471 {
472 // Wrapped around. Dangerous to write data. Wait till next frame
473 dvd->_bufferNeedsResize = true;
474 return;
475 }
476
477 const U32 elementOffset = dvd->_writeOffset * FONS_VERTEX_COUNT;
478
479 const BufferLock lock = dvd->_fontRenderingBuffer->updateBuffer( 0u, elementOffset, nverts, (Divide::bufferPtr)verts );
480 dvd->_memCmd->_bufferLocks.emplace_back( lock );
481
482 GenericDrawCommand& drawCmd = GFX::EnqueueCommand<GFX::DrawCommand>( *dvd->_commandBuffer )->_drawCommands.emplace_back();
483 drawCmd._sourceBuffer = dvd->_fontRenderingBuffer->handle();
484 drawCmd._cmd.vertexCount = nverts;
485 drawCmd._cmd.baseVertex = elementOffset;
486
487 };
488 params.renderDelete = [](void* userPtr)
489 {
490 DVDFONSContext* dvd = (DVDFONSContext*)userPtr;
491 dvd->_fontRenderingBuffer.reset();
493 };
494 params.userPtr = _fonsContext.get();
495
496 _fonsContext->_impl = fonsCreateInternal( &params );
497
498 std::atomic_uint loadTasks = 0;
499 {
500 ShaderModuleDescriptor vertModule = {};
501 vertModule._moduleType = ShaderType::VERTEX;
502 vertModule._sourceFile = "ImmediateModeEmulation.glsl";
503 vertModule._variant = "GUI";
504 ShaderModuleDescriptor fragModule = {};
506 fragModule._sourceFile = "ImmediateModeEmulation.glsl";
507 fragModule._variant = "GUI";
508
509 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulationGUI" );
510 immediateModeShader.waitForReady( true );
511 ShaderProgramDescriptor& shaderDescriptor = immediateModeShader._propertyDescriptor;
512 shaderDescriptor._modules.push_back( vertModule );
513 shaderDescriptor._modules.push_back( fragModule );
514
515 _textRenderShader = CreateResource( immediateModeShader, loadTasks );
516 PipelineDescriptor descriptor = {};
518 descriptor._stateBlock = context.gfx().get2DStateBlock();
520 descriptor._vertexFormat._vertexBindings.emplace_back()._strideInBytes = 2 * sizeof( F32 ) + 2 * sizeof( F32 ) + 4 * sizeof( U8 );
524
525 descPos._vertexBindingIndex = 0u;
526 descPos._componentsPerElement = 2u;
528
529 descUV._vertexBindingIndex = 0u;
530 descUV._componentsPerElement = 2u;
532
533 descColour._vertexBindingIndex = 0u;
534 descColour._componentsPerElement = 4u;
535 descColour._normalized = true;
536
537 descPos._strideInBytes = 0u;
538 descUV._strideInBytes = 2 * sizeof( F32 );
539 descColour._strideInBytes = 2 * sizeof( F32 ) + 2 * sizeof( F32 );
540
541 BlendingSettings& blend = descriptor._blendStates._settings[0u];
543
544 blend.enabled( true );
545 blend.blendSrc( BlendProperty::SRC_ALPHA );
546 blend.blendDest( BlendProperty::INV_SRC_ALPHA );
547 blend.blendOp( BlendOperation::ADD );
548 blend.blendSrcAlpha( BlendProperty::ONE );
549 blend.blendDestAlpha( BlendProperty::ZERO );
550 blend.blendOpAlpha( BlendOperation::COUNT );
551
552 _textRenderPipeline = context.gfx().newPipeline( descriptor );
553 }
554 {
555 ShaderModuleDescriptor vertModule = {};
556 vertModule._moduleType = ShaderType::VERTEX;
557 vertModule._sourceFile = "ImmediateModeEmulation.glsl";
558 vertModule._variant = "CEGUI";
559 ShaderModuleDescriptor fragModule = {};
561 fragModule._sourceFile = "ImmediateModeEmulation.glsl";
562 fragModule._variant = "CEGUI";
563
564
565 ResourceDescriptor<ShaderProgram> ceguiShader( "CEGUIShader" );
566 ceguiShader.waitForReady( true );
567
568 ShaderProgramDescriptor& shaderDescriptor = ceguiShader._propertyDescriptor;
569 shaderDescriptor._modules.push_back( fragModule );
570 shaderDescriptor._modules.push_back( vertModule );
571 _ceguiRenderShader = CreateResource( ceguiShader, loadTasks );
572 }
573
574 const Configuration::GUI& guiConfig = parent().platformContext().config().gui;
575 if ( guiConfig.cegui.enabled )
576 {
577 const vec2<U16> renderSize = context.gfx().renderingResolution();
578 const CEGUI::Sizef size( static_cast<float>(renderSize.width), static_cast<float>(renderSize.height) );
580
581 const string logFile = (Paths::g_logPath / "CEGUI.log").string();
582 CEGUI::System::create( *_ceguiRenderer, nullptr, nullptr, nullptr, nullptr, "", logFile.c_str() );
583 if constexpr ( Config::Build::IS_DEBUG_BUILD )
584 {
585 CEGUI::Logger::getSingleton().setLoggingLevel( CEGUI::Informative );
586 }
587
588 CEGUI::DefaultResourceProvider* rp = static_cast<CEGUI::DefaultResourceProvider*>(CEGUI::System::getSingleton().getResourceProvider());
589
590 const CEGUI::String CEGUIInstallSharePath( (Paths::g_GUILocation.string() + Paths::g_pathSeparator).c_str() );
591 rp->setResourceGroupDirectory( "schemes", CEGUIInstallSharePath + "schemes/" );
592 rp->setResourceGroupDirectory( "imagesets", CEGUIInstallSharePath + "imagesets/" );
593 rp->setResourceGroupDirectory( "fonts", CEGUIInstallSharePath + "fonts/" );
594 rp->setResourceGroupDirectory( "layouts", CEGUIInstallSharePath + "layouts/" );
595 rp->setResourceGroupDirectory( "looknfeels", CEGUIInstallSharePath + "looknfeel/" );
596 rp->setResourceGroupDirectory( "lua_scripts", CEGUIInstallSharePath + "lua_scripts/" );
597 rp->setResourceGroupDirectory( "schemas", CEGUIInstallSharePath + "xml_schemas/" );
598 rp->setResourceGroupDirectory( "animations", CEGUIInstallSharePath + "animations/" );
599
600 // set the default resource groups to be used
601 CEGUI::ImageManager::setImagesetDefaultResourceGroup( "imagesets" );
602 CEGUI::Font::setDefaultResourceGroup( "fonts" );
603 CEGUI::Scheme::setDefaultResourceGroup( "schemes" );
604 CEGUI::WidgetLookManager::setDefaultResourceGroup( "looknfeels" );
605 CEGUI::WindowManager::setDefaultResourceGroup( "layouts" );
606 CEGUI::ScriptModule::setDefaultResourceGroup( "lua_scripts" );
607 // setup default group for validation schemas
608 CEGUI::XMLParser* parser = CEGUI::System::getSingleton().getXMLParser();
609 if ( parser->isPropertyPresent( "SchemaDefaultResourceGroup" ) )
610 {
611 parser->setProperty( "SchemaDefaultResourceGroup", "schemas" );
612 }
613 CEGUI::FontManager::getSingleton().createFromFile( "DejaVuSans-10.font" );
614 CEGUI::FontManager::getSingleton().createFromFile( "DejaVuSans-12.font" );
615 CEGUI::FontManager::getSingleton().createFromFile( "DejaVuSans-10-NoScale.font" );
616 CEGUI::FontManager::getSingleton().createFromFile( "DejaVuSans-12-NoScale.font" );
617 CEGUI::SchemeManager::getSingleton().createFromFile( (defaultGUIScheme() + ".scheme").c_str() );
618
621
622 _ceguiContext = &CEGUI::System::getSingleton().createGUIContext( *_renderTextureTarget );
623 _rootSheet = CEGUI::WindowManager::getSingleton().createWindow( "DefaultWindow", "root_window" );
624 _rootSheet->setMousePassThroughEnabled( true );
625 _rootSheet->setUsingAutoRenderingSurface( false );
626 _rootSheet->setPixelAligned( false );
627
628 _ceguiContext->setRootWindow( _rootSheet );
629 _ceguiContext->setDefaultTooltipType( (defaultGUIScheme() + "/Tooltip").c_str() );
630
631 _console->createCEGUIWindow();
632 CEGUI::System::getSingleton().notifyDisplaySizeChanged( size );
633 }
634
636
637 _init = true;
638 if ( _fonsContext == nullptr )
639 {
640 Console::errorfn( LOCALE_STR( "ERROR_FONT_INIT" ) );
642 }
643
644 return ErrorCode::NO_ERR;
645 }
646
648 {
649 _defaultMsgBox.reset();
650
651 if ( _ceguiRenderer != nullptr )
652 {
653 _defaultMsgBox = std::make_unique<GUIMessageBox>( "AssertMsgBox",
654 "Assertion failure",
655 "Assertion failed with message: ",
656 vec2<I32>( 0 ),
657 _context->rootSheet() );
658 }
659 g_assertMsgBox = _defaultMsgBox.get();
660 }
661
663 {
664 if ( _init )
665 {
666
667 _fonsContext.reset();
668 _fonts.clear();
669
670 Console::printfn( LOCALE_STR( "STOP_GUI" ) );
671 _console.reset();
672 _defaultMsgBox.reset();
673 g_assertMsgBox = nullptr;
674
675 {
677 assert( _guiStack.empty() );
678 for ( U8 i = 0; i < to_base( GUIType::COUNT ); ++i )
679 {
680 for ( auto& [nameHash, entry] : _guiElements[i] )
681 {
682 delete entry.first;
683 }
684 _guiElements[i].clear();
685 }
686 }
687
688 if ( _ceguiRenderer != nullptr )
689 {
690 // Close CEGUI
691 try
692 {
693 CEGUI::System::destroy();
694 }
695 catch ( ... )
696 {
697 Console::d_errorfn( LOCALE_STR( "ERROR_CEGUI_DESTROY" ) );
698 }
700 _ceguiRenderer = nullptr;
701 }
702
705 _init = false;
706 }
707 }
708
709 void GUI::showDebugCursor( const bool state )
710 {
711 _showDebugCursor = state;
712
713 if ( _rootSheet != nullptr )
714 {
715 _rootSheet->setMouseCursor( state ? "GWEN/Tree.Plus" : "" );
716 }
717 }
718
720 {
721 if ( !params.isMainWindow )
722 {
723 return;
724 }
725
726 if ( _ceguiRenderer != nullptr )
727 {
728 const CEGUI::Sizef windowSize( params.width, params.height );
729 CEGUI::System::getSingleton().notifyDisplaySizeChanged( windowSize );
730 if ( _rootSheet )
731 {
732 const Rect<I32>& renderViewport = { 0, 0, params.width, params.height };
733 _rootSheet->setSize( CEGUI::USize( CEGUI::UDim( 0.0f, to_F32( renderViewport.z ) ),
734 CEGUI::UDim( 0.0f, to_F32( renderViewport.w ) ) ) );
735 _rootSheet->setPosition( CEGUI::UVector2( CEGUI::UDim( 0.0f, to_F32( renderViewport.x ) ),
736 CEGUI::UDim( 0.0f, to_F32( renderViewport.y ) ) ) );
737 }
738 }
739 }
740
741 void GUI::setCursorPosition( const I32 x, const I32 y )
742 {
743 if ( _ceguiRenderer != nullptr )
744 {
745 getCEGUIContext()->injectMousePosition( to_F32( x ), to_F32( y ) );
746 }
747 }
748
749 // Return true if input was consumed
751 {
752 return _ceguiInput.onKeyDown( key );
753 }
754
755 // Return true if input was consumed
756 bool GUI::onKeyUp( const Input::KeyEvent& key )
757 {
758 return _ceguiInput.onKeyUp( key );
759 }
760
761 // Return true if input was consumed
763 {
764 return _ceguiInput.mouseMoved( arg );
765 }
766
767 // Return true if input was consumed
769 {
770 return _ceguiInput.mouseButtonPressed( arg );
771 }
772
773 // Return true if input was consumed
775 {
776 return _ceguiInput.mouseButtonReleased( arg );
777 }
778
779 // Return true if input was consumed
781 {
782 return _ceguiInput.joystickAxisMoved( arg );
783 }
784
785 // Return true if input was consumed
787 {
788 return _ceguiInput.joystickPovMoved( arg );
789 }
790
791 // Return true if input was consumed
793 {
795 }
796
797 // Return true if input was consumed
799 {
801 }
802
803 // Return true if input was consumed
805 {
806 return _ceguiInput.joystickBallMoved( arg );
807 }
808
809 // Return true if input was consumed
811 {
812 return _ceguiInput.joystickAddRemove( arg );
813 }
814
816 {
817 return _ceguiInput.joystickRemap( arg );
818 }
819
820 bool GUI::onTextEvent( [[maybe_unused]] const Input::TextEvent& arg ) noexcept
821 {
822 return false;
823 }
824
825 GUIElement* GUI::getSceneGUIElementImpl( const I64 sceneID, const U64 elementName, const GUIType type ) const
826 {
827 if ( sceneID != 0 )
828 {
830 const GUIMapPerScene::const_iterator it = _guiStack.find( sceneID );
831 if ( it != std::cend( _guiStack ) )
832 {
833 return it->second->getGUIElement<GUIElement>( elementName );
834 }
835 }
836 else
837 {
838 return GUIInterface::getGUIElementImpl( elementName, type );
839 }
840
841 return nullptr;
842 }
843
844 GUIElement* GUI::getSceneGUIElementImpl( const I64 sceneID, const I64 elementID, const GUIType type ) const
845 {
846 if ( sceneID != 0 )
847 {
849 const GUIMapPerScene::const_iterator it = _guiStack.find( sceneID );
850 if ( it != std::cend( _guiStack ) )
851 {
852 return it->second->getGUIElement<GUIElement>( elementID );
853 }
854 }
855 else
856 {
857 return GUIInterface::getGUIElementImpl( elementID, type );
858 }
859
860 return nullptr;
861 }
862 CEGUI::GUIContext* GUI::getCEGUIContext() noexcept
863 {
864 return _ceguiContext;
865 }
866
868 I32 GUI::getFont( const Str<64>& fontName )
869 {
870 if ( _fontCache.first.compare( fontName ) != 0 )
871 {
872 _fontCache.first = fontName;
873 const U64 fontNameHash = _ID( fontName.c_str() );
874 // Search for the requested font by name
875 const auto& it = _fonts.find( fontNameHash );
876 // If we failed to find it, it wasn't loaded yet
877 if ( it == std::cend( _fonts ) )
878 {
879 // Fonts are stored in the general asset directory -> in the GUI
880 // subfolder -> in the fonts subfolder
881 const string fontPath = (Paths::g_fontsPath / fontName.c_str()).string();
882 // We use FontStash to load the font file
883 _fontCache.second = fonsAddFont( _fonsContext->_impl, fontName.c_str(), fontPath.c_str());
884 // If the font is invalid, inform the user, but map it anyway, to avoid
885 // loading an invalid font file on every request
886 if ( _fontCache.second == FONS_INVALID )
887 {
888 Console::errorfn( LOCALE_STR( "ERROR_FONT_FILE" ), fontName.c_str() );
889 }
890 // Save the font in the font cache
891 hashAlg::insert( _fonts, fontNameHash, _fontCache.second );
892
893 }
894 else
895 {
896 _fontCache.second = it->second;
897 }
898 }
899
900 // Return the font
901 return _fontCache.second;
902 }
903
904};
#define LOCALE_STR(X)
Definition: Localization.h:91
#define DIVIDE_UNUSED(X)
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
void beginRendering() override
TextureTarget * createTextureTarget() override
void endRendering() override
static void destroy(CEGUIRenderer &renderer)
static CEGUIRenderer & create(Divide::GFXDevice &context, Divide::Handle< Divide::ShaderProgram > shader, CEGUI::Sizef resolution, int abi=CEGUI_VERSION_ABI)
Divide::Handle< Divide::Texture > getAttachmentTex() const
Divide::SamplerDescriptor getSampler() const noexcept
void declareRenderSize(const Sizef &sz) override
static SceneGUIElements * guiElements(Scene *scene) noexcept
Definition: Scene.h:512
bool joystickButtonPressed(const Input::JoystickEvent &arg) override
Joystick button pressed: return true if input was consumed.
Definition: CEGUIInput.cpp:355
bool joystickRemap(const Input::JoystickEvent &arg) override
Definition: CEGUIInput.cpp:386
bool mouseButtonReleased(const Input::MouseButtonEvent &arg) override
Mouse button released: return true if input was consumed.
Definition: CEGUIInput.cpp:296
bool joystickButtonReleased(const Input::JoystickEvent &arg) override
Joystick button released: return true if input was consumed.
Definition: CEGUIInput.cpp:363
bool joystickPovMoved(const Input::JoystickEvent &arg) override
Joystick direction change: return true if input was consumed.
Definition: CEGUIInput.cpp:347
bool onKeyUp(const Input::KeyEvent &key) override
Key released: return true if input was consumed.
Definition: CEGUIInput.cpp:233
bool joystickBallMoved(const Input::JoystickEvent &arg) override
Definition: CEGUIInput.cpp:371
bool onKeyDown(const Input::KeyEvent &key) override
Key pressed: return true if input was consumed.
Definition: CEGUIInput.cpp:227
void init(const Configuration &config) noexcept
Definition: CEGUIInput.cpp:178
bool mouseButtonPressed(const Input::MouseButtonEvent &arg) override
Mouse button pressed: return true if input was consumed.
Definition: CEGUIInput.cpp:255
bool joystickAxisMoved(const Input::JoystickEvent &arg) override
Joystick axis change: return true if input was consumed.
Definition: CEGUIInput.cpp:339
bool joystickAddRemove(const Input::JoystickEvent &arg) override
Definition: CEGUIInput.cpp:379
bool mouseMoved(const Input::MouseMoveEvent &arg) override
Mouse moved: return true if input was consumed.
Definition: CEGUIInput.cpp:239
static Camera * GetUtilityCamera(const UtilityCamera type)
Definition: Camera.cpp:120
const CameraSnapshot & snapshot() const noexcept
Returns the internal camera snapshot data (eye, orientation, etc)
Definition: Camera.inl:43
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
void drawTextureInViewport(const ImageView &texture, SamplerDescriptor sampler, const Rect< I32 > &viewport, bool convertToSrgb, bool drawToDepthOnly, bool drawBlend, GFX::CommandBuffer &bufferInOut)
Definition: GFXDevice.cpp:2435
vec2< U16 > renderingResolution() const noexcept
Definition: GFXDevice.inl:174
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
const RenderStateBlock & get2DStateBlock() const noexcept
Definition: GFXDevice.inl:123
static bool soundCallback(const AudioCallback &cbk)
Definition: GUIButton.cpp:143
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
CEGUI::GUIContext * getCEGUIContext() noexcept
Provides direct access to the CEGUI context. Used by plugins (e.g. GUIConsole, GUIInput,...
Definition: GUI.cpp:862
CEGUI::Window * _rootSheet
The root window into which CEGUI anchors all of its elements.
Definition: GUI.h:175
CEGUI::Window * rootSheet() const noexcept
Get a pointer to the root sheet that CEGUI renders into.
Definition: GUI.h:118
bool joystickPovMoved(const Input::JoystickEvent &arg) override
Joystick direction change: return true if input was consumed.
Definition: GUI.cpp:786
void destroy()
Definition: GUI.cpp:662
bool onKeyUp(const Input::KeyEvent &key) override
Key released: return true if input was consumed.
Definition: GUI.cpp:756
std::unique_ptr< GUIConsole > _console
Our custom in-game console (for logs and commands. A la Quake's ~-console)
Definition: GUI.h:189
ErrorCode init(PlatformContext &context)
Create the GUI.
Definition: GUI.cpp:399
bool onTextEvent(const Input::TextEvent &arg) noexcept override
Called when text input was detected.
Definition: GUI.cpp:820
bool joystickButtonReleased(const Input::JoystickEvent &arg) override
Joystick button released: return true if input was consumed.
Definition: GUI.cpp:798
~GUI() override
Definition: GUI.cpp:135
std::unique_ptr< GUIMessageBox > _defaultMsgBox
Pointer to a default message box used for general purpose messages.
Definition: GUI.h:191
CEGUIInput _ceguiInput
Used to implement key repeat.
Definition: GUI.h:183
void recreateDefaultMessageBox()
Used to recreate and re-register the default message box if needed (usually on scene change)
Definition: GUI.cpp:647
CEGUI::GUIContext * _ceguiContext
The CEGUI context as returned by the library upon creation.
Definition: GUI.h:177
void setCursorPosition(I32 x, I32 y)
Mouse cursor forced to a certain position.
Definition: GUI.cpp:741
DVDFONSContext_uptr _fonsContext
We use Font Stash (https://github.com/memononen/fontstash) for rendering basic text on the screen....
Definition: GUI.h:199
Handle< ShaderProgram > _textRenderShader
The text rendering shaderProgram we used to draw Font Stash text.
Definition: GUI.h:207
void preDraw(GFXDevice &context, const Rect< I32 > &viewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Render all elements that need their own internal render targets (e.g. CEGUI)
Definition: GUI.cpp:277
bool mouseButtonPressed(const Input::MouseButtonEvent &arg) override
Mouse button pressed: return true if input was consumed.
Definition: GUI.cpp:768
bool joystickAddRemove(const Input::JoystickEvent &arg) override
Definition: GUI.cpp:810
bool joystickBallMoved(const Input::JoystickEvent &arg) override
Definition: GUI.cpp:804
void draw(GFXDevice &context, const Rect< I32 > &viewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Go through all of the registered scene gui elements and gather all of the render commands.
Definition: GUI.cpp:302
Pipeline * _textRenderPipeline
The text rendering pipeline we used to draw Font Stash text.
Definition: GUI.h:205
void showDebugCursor(bool state)
Toggle debug cursor rendering on or off.
Definition: GUI.cpp:709
void onUnloadScene(Scene *scene)
When we unload a scene, we unload all of its GUI elements. ToDo: Scene should own these and scene sho...
Definition: GUI.cpp:169
void onChangeScene(Scene *newScene)
When we change a scene, we want to toggle our current scene GUI elements off and toggle the new scene...
Definition: GUI.cpp:140
bool joystickRemap(const Input::JoystickEvent &arg) override
Definition: GUI.cpp:815
void onResolutionChange(const SizeChangeParams &params)
Mostly used by CEGUI to keep track of screen dimensions.
Definition: GUI.cpp:719
GUI(Kernel &parent)
Definition: GUI.cpp:124
bool joystickAxisMoved(const Input::JoystickEvent &arg) override
Joystick axis change: return true if input was consumed.
Definition: GUI.cpp:780
I32 getFont(const Str< 64 > &fontName)
Try to find the requested font in the font cache. Load on cache miss.
Definition: GUI.cpp:868
bool mouseMoved(const Input::MouseMoveEvent &arg) override
Mouse moved: return true if input was consumed.
Definition: GUI.cpp:762
bool joystickButtonPressed(const Input::JoystickEvent &arg) override
Joystick button pressed: return true if input was consumed.
Definition: GUI.cpp:792
GUIMapPerScene _guiStack
All the GUI elements created per scene.
Definition: GUI.h:195
bool onKeyDown(const Input::KeyEvent &key) override
Key pressed: return true if input was consumed.
Definition: GUI.cpp:750
bool frameStarted(const FrameEvent &evt) override
Definition: GUI.cpp:381
T * getSceneGUIElementImpl(const I64 sceneID, const U64 elementName)
Find a return a gui element by name.
Definition: GUI.h:109
bool mouseButtonReleased(const Input::MouseButtonEvent &arg) override
Mouse button released: return true if input was consumed.
Definition: GUI.cpp:774
void update(U64 deltaTimeUS)
Main update call. Used to tick gui elements (cursors, animations, etc)
Definition: GUI.cpp:358
bool _init
Set to true when the GUI has finished loading.
Definition: GUI.h:181
SharedMutex _guiStackLock
A lock to protect access to _guiStack.
Definition: GUI.h:197
CEGUI::CEGUIRenderer * _ceguiRenderer
Used to render CEGUI to a texture; We want to port this to the Divide::GFX interface.
Definition: GUI.h:185
hashMap< U64, I32 > _fonts
A cache of all font IDs used by Font Stash stored by name ID.
Definition: GUI.h:201
Scene * _activeScene
Each scene has its own gui elements! (0 = global). We keep a pointer to the scene but we really shoul...
Definition: GUI.h:193
CEGUI::DVDTextureTarget * _renderTextureTarget
Used to render CEGUI elements into. We blit this on top of our scene target.
Definition: GUI.h:187
Handle< ShaderProgram > _ceguiRenderShader
Definition: GUI.h:208
hashAlg::pair< Str< 64 >, I32 > _fontCache
A cache of the last requested font by name to avoid a lookup in the fonts map.
Definition: GUI.h:203
void drawText(const TextElementBatch &batch, const Rect< I32 > &targetViewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut, bool pushCamera=true)
Text rendering is handled exclusively by Mikko Mononen's FontStash library (https://github....
Definition: GUI.cpp:180
virtual GUIElement * getGUIElementImpl(U64 elementName, GUIType type) const
hashMap< U64, std::pair< GUIElement *, bool > > GUIMap
Definition: GUIInterface.h:53
std::array< GUIMap, to_base(GUIType::COUNT)> _guiElements
Definition: GUIInterface.h:112
void setMessage(const string &message)
void show() noexcept
Definition: GUIMessageBox.h:66
void setTitle(const string &titleText)
void setMessageType(MessageType type)
void setInitialDelay(const D64 initialDelay) noexcept
Adjust the initial delay before we start injecting key repeats.
Definition: AutoKeyRepeat.h:73
void update(U64 deltaTimeUS)
Update the internal time interval between frames (microseconds)
Kernel & parent() noexcept
The kernel is the main system that connects all of our various systems: windows, gfx,...
Definition: Kernel.h:81
FORCE_INLINE PlatformContext & platformContext() noexcept
Definition: Kernel.h:129
SFXDevice & sfx() noexcept
GFXDevice & gfx() noexcept
Configuration & config() noexcept
static const TextLabelStyle & get(size_t textLabelStyleHash)
Definition: TextLabel.cpp:58
static const Str< 64 > & fontName(size_t fontNameHash)
Definition: TextLabel.cpp:79
void fonsSetAlign(FONScontext *s, int align)
void fonsVertMetrics(FONScontext *s, float *ascender, float *descender, float *lineh)
void fonsSetBlur(FONScontext *s, float blur)
void fonsSetColour(FONScontext *s, unsigned char colourR, unsigned char colourG, unsigned char colourB, unsigned char colourA)
#define FONS_VERTEX_COUNT
Definition: fontstash.h:200
FONScontext * fonsCreateInternal(FONSparams *params)
int fonsAddFont(FONScontext *s, const char *name, const char *path)
void fonsSetSize(FONScontext *s, float size)
float fonsDrawText(FONScontext *s, float x, float y, const char *string, const char *end)
#define FONS_INVALID
Definition: fontstash.h:36
void fonsDeleteInternal(FONScontext *s)
void fonsClearState(FONScontext *s)
struct FONScontext FONScontext
Definition: fontstash.h:119
void fonsSetFont(FONScontext *s, int font)
constexpr bool SHOW_MESSAGE_BOX
Popup a GUI Message Box on asserts;.
Definition: config.h:76
constexpr bool IS_DEBUG_BUILD
Definition: config.h:55
constexpr U8 MAX_FRAMES_IN_FLIGHT
Maximum number of active frames until we start waiting on a fence/sync.
Definition: config.h:100
FORCE_INLINE T * EnqueueCommand(CommandBuffer &buffer)
constexpr Optick::Category::Type GUI
Definition: Profiler.h:64
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
I32 FONSRenderCreate(void *userPtr, int width, int height)
Definition: GUI.cpp:81
void RefreshBufferSize(DVDFONSContext *dvd)
Definition: GUI.cpp:64
GUIMessageBox * g_assertMsgBox
Definition: GUI.cpp:62
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
std::byte Byte
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
void insert(eastl::vector< T, A1 > &target, const eastl::vector< T, A2 > &source)
Definition: Vector.h:97
int32_t I32
uint8_t U8
void DIVIDE_ASSERT_MSG_BOX(const char *failMessage) noexcept
Definition: GUI.cpp:110
constexpr F32 to_F32(const T value)
@ COUNT
Place all properties above this.
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
Project & parent
Definition: DefaultScene.h:41
void Set(DescriptorSetBindingData &dataInOut, ShaderBuffer *buffer, const BufferRange range) noexcept
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
DescriptorSetBinding & AddBinding(DescriptorSet &setInOut, U8 slot, U16 stageVisibilityMask)
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
void efficient_clear(eastl::fixed_vector< T, nodeCount, bEnableOverflow, OverflowAllocator > &fixed_vector)
Definition: Vector.h:52
constexpr size_t to_size(const T value)
int64_t I64
FORCE_INLINE T * Get(const Handle< T > handle)
uint32_t U32
Project const SceneEntry & entry
Definition: DefaultScene.h:41
void * bufferPtr
uint64_t U64
constexpr auto to_base(const Type value) -> Type
Divide::hashPairReturn< K, V, HashFun > insert(Divide::hashMap< K, V, HashFun, Predicate > &map, const pair< K, V > &valuePair)
Definition: HashMap.h:133
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
struct Divide::Configuration::GUI::CEGUI cegui
struct Divide::Configuration::GUI gui
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
static NO_INLINE void d_errorfn(const char *format, T &&... args)
bool _bufferNeedsResize
Definition: GUI.cpp:47
GenericVertexData_ptr _fontRenderingBuffer
Definition: GUI.cpp:50
Handle< Texture > _fontRenderingTexture
Definition: GUI.cpp:51
GFX::CommandBuffer * _commandBuffer
Definition: GUI.cpp:54
FONScontext * _impl
Definition: GUI.cpp:57
GFXDevice * _parent
Definition: GUI.cpp:49
GFX::MemoryBarrierCommand * _memCmd
Definition: GUI.cpp:55
DescriptorSetBindingData _data
IndirectIndexedDrawCommand _cmd
std::pair< bufferPtr, size_t > _initialData
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
PropertyDescriptor< T > _propertyDescriptor
Definition: Resource.h:151
TextureFilter _minFilter
Texture filtering mode.
U16 width
The new width and height.
vector< eastl::string > TextType
Definition: TextLabel.h:82
void text(const char *text, const bool multiLine)
Definition: TextLabel.cpp:94
int(* renderCreate)(void *uptr, int width, int height)
Definition: fontstash.h:77
void(* renderDelete)(void *uptr)
Definition: fontstash.h:81
void * userPtr
Definition: fontstash.h:76
int(* renderResize)(void *uptr, int width, int height)
Definition: fontstash.h:78
void(* renderDraw)(void *uptr, const FONSvert *verts, int nverts)
Definition: fontstash.h:80
int height
Definition: fontstash.h:74
void(* renderUpdate)(void *uptr, int *rect, const unsigned char *data)
Definition: fontstash.h:79
int width
Definition: fontstash.h:74