dark_sylinc wrote: Tue Apr 22, 2025 2:36 am
What are the problems when using "externalWindowHandle" ?
On Windows, when using "externalWindowHandle", Ogre won't render to my app, leaving the app to have the last rendered Gui from IMGUI after I clicked to choose rendering device (I wanted to use ImGUI to pick device instead of the Ogre's window).

Here's my code for graphics system class:
Code: Select all
#include "graph_sys_3d.h"
#include "GameState.h"
#include "GameEntity.h"
#include "OgreAbiUtils.h"
#include "OgreConfigFile.h"
#include "OgreException.h"
#include "OgreRoot.h"
#include "OgreCamera.h"
#include "OgreItem.h"
#include "OgreArchiveManager.h"
#include "OgreHlmsManager.h"
#include "OgreHlmsPbs.h"
#include "OgreHlmsUnlit.h"
#include "Compositor/OgreCompositorManager2.h"
#include "OgreOverlayManager.h"
#include "OgreOverlaySystem.h"
#include "OgreTextureGpuManager.h"
#include "OgreWindow.h"
#include "OgreWindowEventUtilities.h"
#include "OgreFileSystemLayer.h"
#include "OgreGpuProgramManager.h"
#include "OgreHlmsDiskCache.h"
#include "OgreLogManager.h"
#include "OgrePlatformInformation.h"
#include "System/Android/AndroidSystems.h"
#include "OgreAtmosphereComponent.h"
#ifdef OGRE_BUILD_COMPONENT_ATMOSPHERE
# include "OgreAtmosphereNpr.h"
#endif
#include <fstream>
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
# include "OSX/macUtils.h"
# if OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
# include "System/iOS/iOSUtils.h"
# else
# include "System/OSX/OSXUtils.h"
# endif
#endif
#include <cstdint>
#include <SDL3/SDL.h>
#if defined(__linux__)
#include <X11/Xlib.h>
#endif
//using namespace Demo;
GraphSys3D::GraphSys3D(
const Ogre::String& resourcePath,
const Ogre::String& writeAccessFolder,
Ogre::ColourValue backgroundColour ) :
GraphSys(),
mRoot( 0 ),
mRenderWindow( 0 ),
mSceneManager( 0 ),
mCamera( 0 ),
mWorkspace( 0 ),
mPluginsFolder( "" ),
mResourcePath( resourcePath ),
mWriteAccessFolder( writeAccessFolder ),
mOverlaySystem( 0 ),
mAccumTimeSinceLastLogicFrame( 0 ),
mCurrentTransformIdx( 0 ),
mThreadWeight( 0 ),
mAlwaysAskForConfig( true ),
mUseHlmsDiskCache( true ),
mUseMicrocodeCache( true ),
mBackgroundColour( backgroundColour )
{}
//-----------------------------------------------------------------------------------
GraphSys3D::~GraphSys3D()
{
if( mRoot )
{
Ogre::LogManager::getSingleton().logMessage(
"WARNING: GraphSys3D::deinitialize() not called!!!", Ogre::LML_CRITICAL );
}
}
//-----------------------------------------------------------------------------------
bool GraphSys3D::isWriteAccessFolder( const Ogre::String &folderPath,
const Ogre::String &fileToSave )
{
if( !Ogre::FileSystemLayer::createDirectory( folderPath ) )
return false;
std::ofstream of( ( folderPath + fileToSave ).c_str(),
std::ios::out | std::ios::binary | std::ios::app );
if( !of )
return false;
return true;
}
//---------------------------------------------------------------------------------------
std::vector<std::string> GraphSys3D::selectGraphics(const std::string& pluginsFile)
{
const Ogre::String windowTitle = "Window's Title";
const Ogre::AbiCookie abiCookie = Ogre::generateAbiCookie();
this->mRoot = OGRE_NEW Ogre::Root(&abiCookie,
this->mPluginsFolder + pluginsFile,
this->mWriteAccessFolder + "ogre.cfg",
this->mWriteAccessFolder + "Ogre.log",
windowTitle);
this->mStaticPluginLoader.install(this->mRoot);
// std::string renderSys_name = "OpenGL 3+ Rendering Subsystem";
std::string renderSys_name = "Vulkan Rendering Subsystem";
Ogre::RenderSystem* rs = this->mRoot->getRenderSystemByName(renderSys_name); // get the renderer by hard name, we will only use Vulkan
Ogre::String error = rs->validateConfigOptions(); // validate render system
if (error.length() > 0)
{
this->mQuit = true;
return std::vector<std::string>();
}
this->mRoot->setRenderSystem(rs);
// enable sRGB Gamma Conversion
rs->setConfigOption("sRGB Gamma Conversion", "Yes");
this->mRoot->initialise(false);
Ogre::ConfigOptionMap& config_options = rs->getConfigOptions();
Ogre::StringVector possible_devices = config_options["Device"].possibleValues;
return possible_devices;
}
//---------------------------------------------------------------------------------------
void GraphSys3D::init(const std::string& device_choice, const std::string& win_handle,
void* xdisplay, const unsigned long &xwindow,
const std::uint32_t& wdth, const std::uint32_t& hght, const bool& fullscreen)
{
Ogre::NameValuePairList config_params;
// params.insert(std::make_pair("external_device", win_handle)); // for vulkan on linux
config_params.insert(std::make_pair("title", "window title"));
config_params.insert(std::make_pair("gamma", "Yes"));
config_params.insert(std::make_pair("vsync", "No"));
config_params.insert(std::make_pair("vsync_interval", "1"));
config_params.insert(std::make_pair("vsync_method", "Render Ahead / FIFO"));
config_params.insert(std::make_pair("FSAA", "1"));
config_params.insert(std::make_pair("reverse_depth", "Yes"));
// config_params.insert(std::make_pair("externalGLContext", std::to_string(winGlContext)));
// config_params.insert(std::make_pair("externalGLControl", "True"));
#if defined(_WIN32) || defined(_WIN64)
#elif defined(__linux__)
struct
{
Display *display; /**< The X11 display */
Window window; /**< The X11 window */
} x11;
x11.display = (Display *)xdisplay;
x11.window = (Window)xwindow;
config_params.insert(std::make_pair("SDL2x11", Ogre::StringConverter::toString((uintptr_t)&x11)));
#endif
// config_params.insert(std::make_pair("externalWindowHandle", win_handle));
config_params.insert(std::make_pair("parentWindowHandle", win_handle));
this->initMiscParamsListener(config_params);
this->mRenderWindow = this->mRoot->createRenderWindow(
"Main RenderWindow",
wdth, hght,
false, &config_params);
this->mOverlaySystem = OGRE_NEW Ogre::v1::OverlaySystem();
this->setupResources();
this->loadResources(); // registerHlms is called in this function
this->chooseSceneManager();
this->createCamera();
this->mWorkspace = this->setupCompositor();
return;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::deinitialize()
{
this->saveTextureCache();
this->saveHlmsDiskCache();
if( mSceneManager )
{
Ogre::AtmosphereComponent *atmosphere = mSceneManager->getAtmosphereRaw();
OGRE_DELETE atmosphere;
mSceneManager->removeRenderQueueListener( mOverlaySystem );
}
OGRE_DELETE mOverlaySystem;
mOverlaySystem = 0;
OGRE_DELETE mRoot;
mRoot = 0;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::initImgui()
{
// Register imgui for rendering
this->mRoot->addFrameListener(new ImguiFrameListener);
//initialise with your target workspace.
ImguiManager::getSingleton().init(this->getCompositorWorkspace());
return;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::deinitImgui()
{
ImguiManager::getSingleton().shutdown();
return;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::updateImgui()
{
//Calculate the frame delta time using SDL's helper functions.
static std::uint64_t g_Time = 0;
static std::uint64_t frequency = SDL_GetPerformanceFrequency();
std::uint64_t current_time = SDL_GetPerformanceCounter();
float deltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
g_Time = current_time;
ImguiManager::getSingletonPtr()->newFrame(deltaTime);
return;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::update( float timeSinceLast )
{
this->mRoot->renderOneFrame();
this->update3D(timeSinceLast);
return;
}
//-----------------------------------------------------------------------------------
void GraphSys3D::addResourceLocation( const Ogre::String &archName, const Ogre::String &typeName,
const Ogre::String &secName )
{
#if( OGRE_PLATFORM == OGRE_PLATFORM_APPLE ) || ( OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS )
// OS X does not set the working directory relative to the app,
// In order to make things portable on OS X we need to provide
// the loading with it's own bundle path location
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
Ogre::String( Ogre::macBundlePath() + "/" + archName ), typeName, secName );
#else
Ogre::ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName );
#endif
}
//-----------------------------------------------------------------------------------
void GraphSys3D::loadTextureCache()
{
#if !OGRE_NO_JSON
Ogre::ArchiveManager &archiveManager = Ogre::ArchiveManager::getSingleton();
Ogre::Archive *rwAccessFolderArchive =
archiveManager.load( mWriteAccessFolder, "FileSystem", true );
try
{
const Ogre::String filename = "textureMetadataCache.json";
if( rwAccessFolderArchive->exists( filename ) )
{
Ogre::DataStreamPtr stream = rwAccessFolderArchive->open( filename );
std::vector<char> fileData;
fileData.resize( stream->size() + 1 );
if( !fileData.empty() )
{
stream->read( &fileData[0], stream->size() );
// Add null terminator just in case (to prevent bad input)
fileData.back() = '\0';
Ogre::TextureGpuManager *textureManager =
mRoot->getRenderSystem()->getTextureGpuManager();
textureManager->importTextureMetadataCache( stream->getName(), &fileData[0], false );
}
}
else
{
Ogre::LogManager::getSingleton().logMessage( "[INFO] Texture cache not found at " +
mWriteAccessFolder +
"/textureMetadataCache.json" );
}
}
catch( Ogre::Exception &e )
{
Ogre::LogManager::getSingleton().logMessage( e.getFullDescription() );
}
archiveManager.unload( rwAccessFolderArchive );
#endif
}
//-----------------------------------------------------------------------------------
void GraphSys3D::saveTextureCache()
{
if( mRoot->getRenderSystem() )
{
Ogre::TextureGpuManager *textureManager = mRoot->getRenderSystem()->getTextureGpuManager();
if( textureManager )
{
Ogre::String jsonString;
textureManager->exportTextureMetadataCache( jsonString );
const Ogre::String path = mWriteAccessFolder + "/textureMetadataCache.json";
std::ofstream file( path.c_str(), std::ios::binary | std::ios::out );
if( file.is_open() )
file.write( jsonString.c_str(), static_cast<std::streamsize>( jsonString.size() ) );
file.close();
}
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::loadHlmsDiskCache()
{
if( !mUseMicrocodeCache && !mUseHlmsDiskCache )
return;
Ogre::HlmsManager *hlmsManager = mRoot->getHlmsManager();
Ogre::HlmsDiskCache diskCache( hlmsManager );
Ogre::ArchiveManager &archiveManager = Ogre::ArchiveManager::getSingleton();
Ogre::Archive *rwAccessFolderArchive =
archiveManager.load( mWriteAccessFolder, "FileSystem", true );
if( mUseMicrocodeCache )
{
// Make sure the microcode cache is enabled.
Ogre::GpuProgramManager::getSingleton().setSaveMicrocodesToCache( true );
const Ogre::String filename = "microcodeCodeCache.cache";
if( rwAccessFolderArchive->exists( filename ) )
{
Ogre::DataStreamPtr shaderCacheFile = rwAccessFolderArchive->open( filename );
Ogre::GpuProgramManager::getSingleton().loadMicrocodeCache( shaderCacheFile );
}
}
if( mUseHlmsDiskCache )
{
for( size_t i = Ogre::HLMS_LOW_LEVEL + 1u; i < Ogre::HLMS_MAX; ++i )
{
Ogre::Hlms *hlms = hlmsManager->getHlms( static_cast<Ogre::HlmsTypes>( i ) );
if( hlms )
{
Ogre::String filename =
"hlmsDiskCache" + Ogre::StringConverter::toString( i ) + ".bin";
try
{
if( rwAccessFolderArchive->exists( filename ) )
{
Ogre::DataStreamPtr diskCacheFile = rwAccessFolderArchive->open( filename );
diskCache.loadFrom( diskCacheFile );
diskCache.applyTo( hlms );
}
}
catch( Ogre::Exception & )
{
Ogre::LogManager::getSingleton().logMessage(
"Error loading cache from " + mWriteAccessFolder + "/" + filename +
"! If you have issues, try deleting the file "
"and restarting the app" );
}
}
}
}
archiveManager.unload( mWriteAccessFolder );
}
//-----------------------------------------------------------------------------------
void GraphSys3D::saveHlmsDiskCache()
{
if( mRoot->getRenderSystem() && Ogre::GpuProgramManager::getSingletonPtr() &&
( mUseMicrocodeCache || mUseHlmsDiskCache ) )
{
Ogre::HlmsManager *hlmsManager = mRoot->getHlmsManager();
Ogre::HlmsDiskCache diskCache( hlmsManager );
Ogre::ArchiveManager &archiveManager = Ogre::ArchiveManager::getSingleton();
Ogre::Archive *rwAccessFolderArchive =
archiveManager.load( mWriteAccessFolder, "FileSystem", false );
if( mUseHlmsDiskCache )
{
for( size_t i = Ogre::HLMS_LOW_LEVEL + 1u; i < Ogre::HLMS_MAX; ++i )
{
Ogre::Hlms *hlms = hlmsManager->getHlms( static_cast<Ogre::HlmsTypes>( i ) );
if( hlms )
{
diskCache.copyFrom( hlms );
Ogre::DataStreamPtr diskCacheFile = rwAccessFolderArchive->create(
"hlmsDiskCache" + Ogre::StringConverter::toString( i ) + ".bin" );
diskCache.saveTo( diskCacheFile );
}
}
}
if( Ogre::GpuProgramManager::getSingleton().isCacheDirty() && mUseMicrocodeCache )
{
const Ogre::String filename = "microcodeCodeCache.cache";
Ogre::DataStreamPtr shaderCacheFile = rwAccessFolderArchive->create( filename );
Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache( shaderCacheFile );
}
archiveManager.unload( mWriteAccessFolder );
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::setupResources()
{
// Load resource paths from config file
Ogre::ConfigFile cf;
cf.load( AndroidSystems::openFile( mResourcePath + "resources2.cfg" ) );
// Go through all sections & settings in the file
Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();
Ogre::String secName, typeName, archName;
while( seci.hasMoreElements() )
{
secName = seci.peekNextKey();
Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
if( secName != "Hlms" )
{
Ogre::ConfigFile::SettingsMultiMap::iterator i;
for( i = settings->begin(); i != settings->end(); ++i )
{
typeName = i->first;
archName = i->second;
addResourceLocation( archName, typeName, secName );
}
}
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::registerHlms()
{
Ogre::ConfigFile cf;
cf.load( AndroidSystems::openFile( mResourcePath + "resources2.cfg" ) );
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
Ogre::String rootHlmsFolder =
Ogre::macBundlePath() + '/' + cf.getSetting( "DoNotUseAsResource", "Hlms", "" );
#else
Ogre::String rootHlmsFolder = mResourcePath + cf.getSetting( "DoNotUseAsResource", "Hlms", "" );
#endif
if( rootHlmsFolder.empty() )
rootHlmsFolder = AndroidSystems::isAndroid() ? "/" : "./";
else if( *( rootHlmsFolder.end() - 1 ) != '/' )
rootHlmsFolder += "/";
// At this point rootHlmsFolder should be a valid path to the Hlms data folder
Ogre::HlmsUnlit *hlmsUnlit = 0;
Ogre::HlmsPbs *hlmsPbs = 0;
// For retrieval of the paths to the different folders needed
Ogre::String mainFolderPath;
Ogre::StringVector libraryFoldersPaths;
Ogre::StringVector::const_iterator libraryFolderPathIt;
Ogre::StringVector::const_iterator libraryFolderPathEn;
Ogre::ArchiveManager &archiveManager = Ogre::ArchiveManager::getSingleton();
const Ogre::String &archiveType = getMediaReadArchiveType();
{
// Create & Register HlmsUnlit
// Get the path to all the subdirectories used by HlmsUnlit
Ogre::HlmsUnlit::getDefaultPaths( mainFolderPath, libraryFoldersPaths );
Ogre::Archive *archiveUnlit =
archiveManager.load( rootHlmsFolder + mainFolderPath, archiveType, true );
Ogre::ArchiveVec archiveUnlitLibraryFolders;
libraryFolderPathIt = libraryFoldersPaths.begin();
libraryFolderPathEn = libraryFoldersPaths.end();
while( libraryFolderPathIt != libraryFolderPathEn )
{
Ogre::Archive *archiveLibrary =
archiveManager.load( rootHlmsFolder + *libraryFolderPathIt, archiveType, true );
archiveUnlitLibraryFolders.push_back( archiveLibrary );
++libraryFolderPathIt;
}
// Create and register the unlit Hlms
hlmsUnlit = OGRE_NEW Ogre::HlmsUnlit( archiveUnlit, &archiveUnlitLibraryFolders );
Ogre::Root::getSingleton().getHlmsManager()->registerHlms( hlmsUnlit );
}
{
// Create & Register HlmsPbs
// Do the same for HlmsPbs:
Ogre::HlmsPbs::getDefaultPaths( mainFolderPath, libraryFoldersPaths );
Ogre::Archive *archivePbs =
archiveManager.load( rootHlmsFolder + mainFolderPath, archiveType, true );
// Get the library archive(s)
Ogre::ArchiveVec archivePbsLibraryFolders;
libraryFolderPathIt = libraryFoldersPaths.begin();
libraryFolderPathEn = libraryFoldersPaths.end();
while( libraryFolderPathIt != libraryFolderPathEn )
{
Ogre::Archive *archiveLibrary =
archiveManager.load( rootHlmsFolder + *libraryFolderPathIt, archiveType, true );
archivePbsLibraryFolders.push_back( archiveLibrary );
++libraryFolderPathIt;
}
// Create and register
hlmsPbs = OGRE_NEW Ogre::HlmsPbs( archivePbs, &archivePbsLibraryFolders );
Ogre::Root::getSingleton().getHlmsManager()->registerHlms( hlmsPbs );
}
Ogre::RenderSystem *renderSystem = mRoot->getRenderSystem();
if( renderSystem->getName() == "Direct3D11 Rendering Subsystem" )
{
// Set lower limits 512kb instead of the default 4MB per Hlms in D3D 11.0
// and below to avoid saturating AMD's discard limit (8MB) or
// saturate the PCIE bus in some low end machines.
bool supportsNoOverwriteOnTextureBuffers;
renderSystem->getCustomAttribute( "MapNoOverwriteOnDynamicBufferSRV",
&supportsNoOverwriteOnTextureBuffers );
if( !supportsNoOverwriteOnTextureBuffers )
{
hlmsPbs->setTextureBufferDefaultSize( 512 * 1024 );
hlmsUnlit->setTextureBufferDefaultSize( 512 * 1024 );
}
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::loadResources()
{
registerHlms();
loadTextureCache();
loadHlmsDiskCache();
// Initialise, parse scripts etc
Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups( true );
// Initialize resources for LTC area lights and accurate specular reflections (IBL)
Ogre::Hlms *hlms = mRoot->getHlmsManager()->getHlms( Ogre::HLMS_PBS );
OGRE_ASSERT_HIGH( dynamic_cast<Ogre::HlmsPbs *>( hlms ) );
Ogre::HlmsPbs *hlmsPbs = static_cast<Ogre::HlmsPbs *>( hlms );
try
{
hlmsPbs->loadLtcMatrix();
}
catch( Ogre::FileNotFoundException &e )
{
Ogre::LogManager::getSingleton().logMessage( e.getFullDescription(), Ogre::LML_CRITICAL );
Ogre::LogManager::getSingleton().logMessage(
"WARNING: LTC matrix textures could not be loaded. Accurate specular IBL reflections "
"and LTC area lights won't be available or may not function properly!",
Ogre::LML_CRITICAL );
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::chooseSceneManager()
{
#if OGRE_DEBUG_MODE >= OGRE_DEBUG_HIGH
// Debugging multithreaded code is a PITA, disable it.
const size_t numThreads = 1;
#else
// getNumLogicalCores() may return 0 if couldn't detect
const size_t numThreads = std::max<size_t>( 1, Ogre::PlatformInformation::getNumLogicalCores() );
#endif
// Create the SceneManager, in this case a generic one
mSceneManager = mRoot->createSceneManager( Ogre::ST_GENERIC, numThreads, "ExampleSMInstance" );
mSceneManager->addRenderQueueListener( mOverlaySystem );
mSceneManager->getRenderQueue()->setSortRenderQueue(
Ogre::v1::OverlayManager::getSingleton().mDefaultRenderQueueId,
Ogre::RenderQueue::StableSort );
// Set sane defaults for proper shadow mapping
mSceneManager->setShadowDirectionalLightExtrusionDistance( 500.0f );
mSceneManager->setShadowFarDistance( 500.0f );
}
//-----------------------------------------------------------------------------------
void GraphSys3D::createCamera()
{
mCamera = mSceneManager->createCamera( "Main Camera" );
// Position it at 500 in Z direction
mCamera->setPosition( Ogre::Vector3( 0, 5, 15 ) );
// Look back along -Z
mCamera->lookAt( Ogre::Vector3( 0, 0, 0 ) );
mCamera->setNearClipDistance( 0.2f );
mCamera->setFarClipDistance( 1000.0f );
mCamera->setAutoAspectRatio( true );
}
//-----------------------------------------------------------------------------------
Ogre::CompositorWorkspace *GraphSys3D::setupCompositor()
{
Ogre::CompositorManager2 *compositorManager = mRoot->getCompositorManager2();
const Ogre::String workspaceName( "Demo Workspace" );
if( !compositorManager->hasWorkspaceDefinition( workspaceName ) )
{
compositorManager->createBasicWorkspaceDef( workspaceName, mBackgroundColour,
Ogre::IdString() );
}
return compositorManager->addWorkspace( mSceneManager, mRenderWindow->getTexture(), mCamera,
workspaceName, true );
}
//-----------------------------------------------------------------------------------
void GraphSys3D::initMiscParamsListener( Ogre::NameValuePairList ¶ms ) {}
//-----------------------------------------------------------------------------------
void GraphSys3D::createAtmosphere( Ogre::Light *sunLight )
{
#ifdef OGRE_BUILD_COMPONENT_ATMOSPHERE
{
Ogre::AtmosphereComponent *atmosphere = mSceneManager->getAtmosphereRaw();
OGRE_DELETE atmosphere;
}
Ogre::AtmosphereNpr *atmosphere =
OGRE_NEW Ogre::AtmosphereNpr( mRoot->getRenderSystem()->getVaoManager() );
{
// Preserve the Power Scale explicitly set by the sample
Ogre::AtmosphereNpr::Preset preset = atmosphere->getPreset();
preset.linkedLightPower = sunLight->getPowerScale();
atmosphere->setPreset( preset );
}
atmosphere->setSunDir(
sunLight->getDirection(),
std::asin( Ogre::Math::Clamp( -sunLight->getDirection().y, -1.0f, 1.0f ) ) /
Ogre::Math::PI );
atmosphere->setLight( sunLight );
atmosphere->setSky( mSceneManager, true );
#endif
}
//-----------------------------------------------------------------------------------
void GraphSys3D::setAlwaysAskForConfig( bool alwaysAskForConfig )
{
mAlwaysAskForConfig = alwaysAskForConfig;
}
//-----------------------------------------------------------------------------------
const char *GraphSys3D::getMediaReadArchiveType() const
{
#if OGRE_PLATFORM != OGRE_PLATFORM_ANDROID
return "FileSystem";
#else
return "APKFileSystem";
#endif
}
//-----------------------------------------------------------------------------------
void GraphSys3D::stopCompositor()
{
if( mWorkspace )
{
Ogre::CompositorManager2 *compositorManager = mRoot->getCompositorManager2();
compositorManager->removeWorkspace( mWorkspace );
mWorkspace = 0;
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::restartCompositor()
{
stopCompositor();
mWorkspace = setupCompositor();
}
//-----------------------------------------------------------------------------------
void GraphSys3D::loadScene(std::uint16_t index)
{
Ogre::Item *item = mSceneManager->createItem(
"Cube_d.mesh", Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
Ogre::SCENE_DYNAMIC );
mSceneNode = mSceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )
->createChildSceneNode( Ogre::SCENE_DYNAMIC );
mSceneNode->attachObject( item );
}
//-----------------------------------------------------------------------------------
void GraphSys3D::update3D( float timeSinceLast )
{
static float mDisplacement;
const Ogre::Vector3 origin( -5.0f, 0.0f, 0.0f );
mDisplacement += timeSinceLast * 4.0f;
mDisplacement = fmodf( mDisplacement, 10.0f );
mSceneNode->setPosition( origin + Ogre::Vector3::UNIT_X * mDisplacement );
}
//-----------------------------------------------------------------------------------
void GraphSys3D::requestResize(const std::uint32_t& wdth, const std::uint32_t& hght, const bool& fullscreen)
{
if (this->ready()){
this->mResizedOrMoved = true;
this->mRequestedWdth = wdth;
this->mRequestedHght = hght;
}
}
//-----------------------------------------------------------------------------------
void GraphSys3D::checkResize()
{
if (this->ready() && this->mResizedOrMoved){
this->mRenderWindow->requestResolution(this->mRequestedWdth, this->mRequestedHght);
this->mResizedOrMoved = false;
}
}
And here's how my app uses it:
Code: Select all
#include "Threading/YieldTimer.h"
#include "OgreTimer.h"
#include <iostream>
#include "app.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#elif defined(__linux__)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <unistd.h>
#endif
#include <stdexcept>
std::string SDL_getWinHandle(SDL_Window* window, void* &xdisplay, unsigned long &xwindow)
{
std::string win_handle{"Default Handle"};
#if defined(_WIN32) || defined(_WIN64)
HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
if (hwnd) {
win_handle = std::to_string((unsigned long long)hwnd);
}
#elif defined(__linux__)
if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "x11") == 0) {
xdisplay = (void *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
xwindow = (unsigned long)SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
win_handle = std::to_string(xwindow);
} else if (SDL_strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) {
struct wl_display *display = (struct wl_display *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
struct wl_surface *surface = (struct wl_surface *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
// Wayland not implemented
throw std::logic_error( "wayland not implemented!" );
}
#endif
return win_handle;
}
// ------------------------------------
bool App::init()
{
this->mDone = false;
this->mFullScreen = false;
// Init SDL window
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS |
SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD))
return false;
//SDL_SetHint(SDL_HINT_WINDOWS_GAMEINPUT, "1");
#if defined(_WIN32) || defined(_WIN64)
SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");
#elif defined(__linux__)
#define USE_XINPUT2_KEYBOARD
#define SDL_VIDEO_DRIVER_X11_XINPUT2
#define SDL_VIDEO_DRIVER_X11
//SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "wayland");
SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "x11");
#endif
this->mWindow = SDL_CreateWindow("SDL3 window", this->getWdth(), this->getHght(),
SDL_WINDOW_OCCLUDED |
SDL_WINDOW_KEYBOARD_GRABBED |
// SDL_WINDOW_BORDERLESS |
SDL_WINDOW_VULKAN
);
SDL_SetWindowPosition(this->mWindow, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
this->mRenderer = SDL_CreateRenderer(mWindow, NULL);
if (!this->mWindow || !this->mRenderer)
return false;
this->mWinHandle = SDL_getWinHandle(this->mWindow, this->mXdisplay, this->mXwindow);
// Show SDL window
SDL_ShowWindow(this->mWindow);
this->mGui = new Gui();
this->mGui->init(this->mWindow, this->mRenderer, this->mFullScreen);
this->mGui->setDebug(this->mWinHandle);
return true;
}
// ------------------------------------
void App::keyPress(SDL_Keycode code, SDL_KeyboardID id)
{
switch (code)
{
default:
break;
}
}
// ------------------------------------
void App::keyRelease(SDL_Keycode code, SDL_KeyboardID id)
{
switch (code)
{
case SDLK_ESCAPE:
this->done();
break;
case SDLK_F4:
this->togFullScreen();
break;
default:
break;
}
}
// ------------------------------------
void App::togFullScreen()
{
this->mFullScreen ^= true; // XOR for toggling between true and false
SDL_SetWindowSize(this->mWindow, this->getWdth(), this->getHght());
SDL_SetWindowPosition(this->mWindow, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
if (nullptr != this->mGraphSys) {
this->mGraphSys->requestResize(this->getWdth(), this->getHght(), this->mFullScreen);
}
this->mGui->togFullScreen();
}
// ------------------------------------
void App::event(SDL_Event &event)
{
int count;
switch (event.type)
{
case SDL_EVENT_QUIT:
this->done(); // end the program
break;
case SDL_EVENT_KEY_DOWN:
keyPress(event.key.key, event.key.which);
SDL_GetKeyboards(&count);
mMessage = SDL_GetKeyName(event.key.key) + std::string(" ") + std::to_string(count) + ":" + std::to_string(event.key.which);
break;
case SDL_EVENT_KEY_UP:
keyRelease(event.key.key, event.key.which);
SDL_GetKeyboards(&count);
mMessage = SDL_GetKeyName(event.key.key) + std::string(" ") + std::to_string(count) + ":" + std::to_string(event.key.which);
break;
default:
break;
}
}
// ------------------------------------
void App::loop()
{
while (!this->mDone.load()){
SDL_Event event;
while (SDL_PollEvent(&event)) { // poll until all events are handled!
ImGui_ImplSDL3_ProcessEvent(&event);
// decide what to do with this event.
this->event(event);
}
this->changeGui();
}
}
// ------------------------------------
void App::deInit()
{
this->mThreadMgr->joinThreads();
this->mGui->deInit();
// Deinit SDL window
SDL_DestroyRenderer(mRenderer);
SDL_DestroyWindow(mWindow);
SDL_Quit();
delete this->mThreadMgr;
delete this->mGui;
}
// ------------------------------------
void App::changeGui()
{
switch(mGui->getCurrent())
{
case e_render_config:
this->mGui->update(this->mRenderer); // update since this gui is still in main thread
break;
case e_start_2d:
break;
case e_config_3d:
if (this->mGui->getEdge()){ this->initRender3D(); }
this->mGui->update(this->mRenderer); // update since this gui is still in main thread
break;
case e_start_3d:
if (this->mGui->getEdge()){
this->mGui->update(this->mRenderer); // update to reset Gui's edge
this->mThreadMgr = new ThreadManager();
this->mThreadMgr->poolThreads();
this->mThreadMgr->mPause = false;
this->mThreadMgr->submit(&App::threadRender3D, this);
}
break;
case e_exit:
this->done();
break;
default:
break;
}
// this->mGui->update(mRenderer);
}
// ------------------------------------
void App::initRender2D()
{
}
// ------------------------------------
void App::initRender3D()
{
//==========================================================================================
const Ogre::String pluginsFolder = "./";
const Ogre::String writeAccessFolder = "./";
Ogre::String resourcePath = "";
#if OGRE_DEBUG_MODE && !( ( OGRE_PLATFORM == OGRE_PLATFORM_APPLE ) || ( OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS ) )
const char* pluginsFile = "plugins_d.cfg";
#else
const char* pluginsFile = "plugins.cfg";
#endif
this->mGui->setDebug("3d");
this->mGraphSys = new GraphSys3D();
// this->mGraphSys->initialize("win title", this->mWinHandle);
this->mDevices = this->mGraphSys->selectGraphics(pluginsFile);
this->mGui->setDevices(&this->mDevices);
}
// ------------------------------------
void App::threadRender3D()
{
// this->setDebug("Hello from thread 3d");
Ogre::Timer timer;
Ogre::uint64 startTime{ timer.getMicroseconds() };
Demo::YieldTimer yieldTimer(&timer); // Create yield timer for fixed frame rate
std::size_t render_count{ 0 };
std::uint8_t FPS{ 60 };
std::double_t render_FrameTime{ 1.0 / FPS };
std::string device_choice = this->mGui->getDeviceChoice();
this->mGraphSys->init(device_choice, this->mWinHandle, this->mXdisplay, this->mXwindow,
this->getWdth(), this->getHght(), this->mFullScreen);
this->mGraphSys->initImgui();
this->mGraphSys->loadScene(1);
while (!this->mDone.load()) {
this->mGraphSys->updateImgui();
this->mGui->update(this->mRenderer, true);
this->mGraphSys->update(render_FrameTime);
//std::cout << "Rendering 3D\n";
startTime = yieldTimer.yield(render_FrameTime, startTime);
this->setDebug(mMessage);
this->mGraphSys->checkResize();
}
this->mGraphSys->deinitialize();
delete this->mGraphSys;
}