[Solved] Rendering to an existing window paints different color from expected Topic is solved

Discussion area about developing with Ogre-Next (2.1, 2.2 and beyond)


knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

[Solved] Rendering to an existing window paints different color from expected

Post by knn217 »

Hello, I've been doing some small excercises to familiarize myself with ogre-next. In this excercise, I'm trying to create my own window, and then have ogre render to it so that I have more control over the wndproc. I've been studying from the code in Sample_Tutorial00_Basic and the code from this post: viewtopic.php?t=67402. Here's the entire code:

Code: Select all

#include "OgreAbiUtils.h"
#include "OgreArchiveManager.h"
#include "OgreCamera.h"
#include "OgreConfigFile.h"
#include "OgreRoot.h"
#include "OgreWindow.h"

#include "OgreHlmsManager.h"
#include "OgreHlmsPbs.h"
#include "OgreHlmsUnlit.h"

#include "Compositor/OgreCompositorManager2.h"

#include "OgreWindowEventUtilities.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#    include "OSX/macUtils.h"
#endif


static void registerHlms()
{
    using namespace Ogre;

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
    // Note:  macBundlePath works for iOS too. It's misnamed.
    const String resourcePath = Ogre::macResourcesPath();
#elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
    const String resourcePath = Ogre::macBundlePath() + "/";
#else
    String resourcePath = "";
#endif

ConfigFile cf;
cf.load(resourcePath + "resources2.cfg");

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS
    String rootHlmsFolder = macBundlePath() + '/' + cf.getSetting("DoNotUseAsResource", "Hlms", "");
#else
    String rootHlmsFolder = resourcePath + cf.getSetting("DoNotUseAsResource", "Hlms", "");
#endif

if (rootHlmsFolder.empty())
    rootHlmsFolder = "./";
else if (*(rootHlmsFolder.end() - 1) != '/')
    rootHlmsFolder += "/";

// At this point rootHlmsFolder should be a valid path to the Hlms data folder

HlmsUnlit* hlmsUnlit = 0;
HlmsPbs* hlmsPbs = 0;

// For retrieval of the paths to the different folders needed
String mainFolderPath;
StringVector libraryFoldersPaths;
StringVector::const_iterator libraryFolderPathIt;
StringVector::const_iterator libraryFolderPathEn;

ArchiveManager& archiveManager = ArchiveManager::getSingleton();

{
    // Create & Register HlmsUnlit
    // Get the path to all the subdirectories used by HlmsUnlit
    HlmsUnlit::getDefaultPaths(mainFolderPath, libraryFoldersPaths);
    Archive* archiveUnlit =
        archiveManager.load(rootHlmsFolder + mainFolderPath, "FileSystem", true);
    ArchiveVec archiveUnlitLibraryFolders;
    libraryFolderPathIt = libraryFoldersPaths.begin();
    libraryFolderPathEn = libraryFoldersPaths.end();
    while (libraryFolderPathIt != libraryFolderPathEn)
    {
        Archive* archiveLibrary =
            archiveManager.load(rootHlmsFolder + *libraryFolderPathIt, "FileSystem", true);
        archiveUnlitLibraryFolders.push_back(archiveLibrary);
        ++libraryFolderPathIt;
    }

    // Create and register the unlit Hlms
    hlmsUnlit = OGRE_NEW HlmsUnlit(archiveUnlit, &archiveUnlitLibraryFolders);
    Root::getSingleton().getHlmsManager()->registerHlms(hlmsUnlit);
}

{
    // Create & Register HlmsPbs
    // Do the same for HlmsPbs:
    HlmsPbs::getDefaultPaths(mainFolderPath, libraryFoldersPaths);
    Archive* archivePbs = archiveManager.load(rootHlmsFolder + mainFolderPath, "FileSystem", true);

    // Get the library archive(s)
    ArchiveVec archivePbsLibraryFolders;
    libraryFolderPathIt = libraryFoldersPaths.begin();
    libraryFolderPathEn = libraryFoldersPaths.end();
    while (libraryFolderPathIt != libraryFolderPathEn)
    {
        Archive* archiveLibrary =
            archiveManager.load(rootHlmsFolder + *libraryFolderPathIt, "FileSystem", true);
        archivePbsLibraryFolders.push_back(archiveLibrary);
        ++libraryFolderPathIt;
    }

    // Create and register
    hlmsPbs = OGRE_NEW HlmsPbs(archivePbs, &archivePbsLibraryFolders);
    Root::getSingleton().getHlmsManager()->registerHlms(hlmsPbs);
}

RenderSystem* renderSystem = Root::getSingletonPtr()->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);
    }
}
}


class MyWindowEventListener final : public Ogre::WindowEventListener
{
    bool mQuit;

public:
    MyWindowEventListener() : mQuit(false) {}
    void windowClosed(Ogre::Window* rw) override { mQuit = true; }

bool getQuit() const { return mQuit; }
};


//------------------------------------------------------------------------------------
class LowLevelOgreNext
{
public:
    LowLevelOgreNext(void);
    LowLevelOgreNext(HWND h);
    virtual ~LowLevelOgreNext(void);
    Ogre::Root* go(HWND hwnd,
        const Ogre::String pluginsFolder,
        const Ogre::String writeAccessFolder,
        const char* pluginsFile);
protected:
    Ogre::Root* mRoot;
    Ogre::Camera* mCamera;
    Ogre::SceneManager* mSceneMgr;
    Ogre::Window* mWindow;
};


//-------------------------------------------------------------------------------------
LowLevelOgreNext::LowLevelOgreNext(HWND h) : mRoot(0), mCamera(0), mSceneMgr(0), mWindow(0) {}
LowLevelOgreNext::~LowLevelOgreNext(void) { delete mRoot; }
//-------------------------------------------------------------------------------------


Ogre::Root* LowLevelOgreNext::go(HWND hwnd,
    const Ogre::String pluginsFolder,
    const Ogre::String writeAccessFolder,
    const char* pluginsFile)
{

const Ogre::AbiCookie abiCookie = Ogre::generateAbiCookie();
mRoot = OGRE_NEW Ogre::Root(&abiCookie, pluginsFolder + pluginsFile,  //
    writeAccessFolder + "ogre.cfg",           //
    writeAccessFolder + "Ogre.log");

//--------------------------------------------------------------------------------------
if (!mRoot->showConfigDialog())
    return NULL;

// Initialize Root
mRoot->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes");

//***************************************************************
mRoot->initialise(false);
HWND hWnd = hwnd;  // Get the hWnd of the application!
Ogre::NameValuePairList misc;
misc["externalWindowHandle"] = Ogre::StringConverter::toString((int)hWnd);
mWindow = mRoot->createRenderWindow("Main RenderWindow", 800, 600, false, &misc);
//***************************************************************

registerHlms();

// Create SceneManager
const size_t numThreads = 1u;
mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, numThreads, "ExampleSMInstance");

// Create & setup camera
mCamera = mSceneMgr->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);

// Setup a basic compositor with a blue clear colour
Ogre::CompositorManager2* compositorManager = mRoot->getCompositorManager2();
const Ogre::String workspaceName("Demo Workspace");
const Ogre::ColourValue backgroundColour(0.2f, 0.4f, 0.6f);
compositorManager->createBasicWorkspaceDef(workspaceName, backgroundColour, Ogre::IdString());
compositorManager->addWorkspace(mSceneMgr, mWindow->getTexture(), mCamera, workspaceName, true);

return mRoot;
}


const wchar_t g_szClassName[] = L"myWindowClass";


// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    /*
    switch (uMsg)
    {
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
    */
    
if( uMsg == WM_CREATE ) { // Store pointer to Win32Window in user data area SetWindowLongPtr( hWnd, GWLP_USERDATA, (LONG_PTR)( ( (LPCREATESTRUCT)lParam )->lpCreateParams ) ); return 0; } // look up window instance // note: it is possible to get a WM_SIZE before WM_CREATE Ogre::Window *win = (Ogre::Window *)GetWindowLongPtr( hWnd, GWLP_USERDATA ); if( !win ) return DefWindowProc( hWnd, uMsg, wParam, lParam ); // LogManager* log = LogManager::getSingletonPtr(); // Iterator of all listeners registered to this Window Ogre::WindowEventUtilities::WindowEventListeners _msListeners; Ogre::WindowEventUtilities::WindowEventListeners::iterator index, start = _msListeners.lower_bound( win ), end = _msListeners.upper_bound( win ); switch( uMsg ) { case WM_ACTIVATE: { bool active = ( LOWORD( wParam ) != WA_INACTIVE ); win->setFocused( active ); for( ; start != end; ++start ) ( start->second )->windowFocusChange( win ); break; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint( hWnd, &ps ); win->_setVisible( !IsRectEmpty( &ps.rcPaint ) ); EndPaint( hWnd, &ps ); break; } case WM_SYSKEYDOWN: switch( wParam ) { case VK_CONTROL: case VK_SHIFT: case VK_MENU: // ALT // return zero to bypass defProc and signal we processed the message return 0; } break; case WM_SYSKEYUP: switch( wParam ) { case VK_CONTROL: case VK_SHIFT: case VK_MENU: // ALT case VK_F10: // return zero to bypass defProc and signal we processed the message return 0; } break; case WM_SYSCHAR: // return zero to bypass defProc and signal we processed the message, unless it's an // ALT-space if( wParam != VK_SPACE ) return 0; break; case WM_ENTERSIZEMOVE: // log->logMessage("WM_ENTERSIZEMOVE"); break; case WM_EXITSIZEMOVE: // log->logMessage("WM_EXITSIZEMOVE"); break; case WM_MOVE: // log->logMessage("WM_MOVE"); win->windowMovedOrResized(); for( index = start; index != end; ++index ) ( index->second )->windowMoved( win ); break; case WM_DISPLAYCHANGE: win->windowMovedOrResized(); for( index = start; index != end; ++index ) ( index->second )->windowResized( win ); break; case WM_SIZE: // log->logMessage("WM_SIZE"); win->windowMovedOrResized(); for( index = start; index != end; ++index ) ( index->second )->windowResized( win ); break; case WM_GETMINMAXINFO: // Prevent the window from going smaller than some minimu size ( (MINMAXINFO *)lParam )->ptMinTrackSize.x = 100; ( (MINMAXINFO *)lParam )->ptMinTrackSize.y = 100; break; case WM_CLOSE: { // log->logMessage("WM_CLOSE"); bool close = true; for( index = start; index != end; ++index ) { if( !( index->second )->windowClosing( win ) ) close = false; } if( !close ) return 0; for( index = _msListeners.lower_bound( win ); index != end; ++index ) ( index->second )->windowClosed( win ); win->destroy(); return 0; } } return DefWindowProc( hWnd, uMsg, wParam, lParam ); } #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow) #else int main(int argc, const char* argv[]) #endif { //using namespace Ogre; #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE const String pluginsFolder = macResourcesPath(); const String writeAccessFolder = macLogPath(); #else const Ogre::String pluginsFolder = "./"; const Ogre::String writeAccessFolder = pluginsFolder; #endif #ifndef OGRE_STATIC_LIB # 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 #else const char* pluginsFile = 0; // TODO #endif WNDCLASSEX wc; HWND hwnd; MSG Msg; //Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } // Step 2: Creating the Window hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, L"The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInst, NULL); if (hwnd == NULL) { MessageBox(NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } UpdateWindow(hwnd); LowLevelOgreNext app(hwnd);// Create application object Ogre::Root* m_Root = app.go(hwnd, pluginsFolder, writeAccessFolder, pluginsFile); if (m_Root == NULL) return 1; ShowWindow(hwnd, nCmdShow); // Step 3: The Message Loop while (GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); m_Root->renderOneFrame(); } return Msg.wParam; }

Ogre-next did render to the window but the color is a different shade of blue from Sample_Tutorial00_Basic. I even tried copy WindowEventUtilities::_WndProc to my wndproc to see if that's the issue. I've been going through Root::Initialise to see what setup I'm missing but i'm quite lost right now, anyone know what the issue is?

Last edited by knn217 on Sun Apr 16, 2023 10:14 am, edited 1 time in total.
Lax
Gnoll
Posts: 667
Joined: Mon Aug 06, 2007 12:53 pm
Location: Saarland, Germany
x 64

Re: Rendering to an existing window paints different color from expected

Post by Lax »

Hi,

do you have in the ogre.cfg the:

sRGB Gamma Conversion

enabled?

Best Regards
Lax

http://www.lukas-kalinowski.com/Homepage/?page_id=1631
Please support Second Earth Technic Base built of Lego bricks for Lego ideas: https://ideas.lego.com/projects/81b9bd1 ... b97b79be62

knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Rendering to an existing window paints different color from expected

Post by knn217 »

Lax wrote: Tue Apr 11, 2023 12:25 pm

do you have in the ogre.cfg the:

sRGB Gamma Conversion

enabled?

Yes, it is enabled, I think it was enabled in this line:

Code: Select all

// Initialize Root
mRoot->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes");
User avatar
dark_sylinc
OGRE Team Member
OGRE Team Member
Posts: 5477
Joined: Sat Jul 21, 2007 4:55 pm
Location: Buenos Aires, Argentina
x 1359

Re: Rendering to an existing window paints different color from expected

Post by dark_sylinc »

This is normal & expected when using sRGB (i.e. the default) because the color space is different.

You have multiple options:

  1. Don't use sRGB correction (NOT recommended)

  2. Use tools that are also sRGB and Linear-aware

    • Blender's colour picker gives you the same colours as we do

    • Set Photoshop to use sRGB (maybe it's here?)

    • Krita supports it too: Go to Specific Color Selector

      and then chose Profile -> scRGB (linear):

      You can also make the whole Krita to use scRGB (linear) when creating a new document:

      But beware that saving textures with a linear profile may cause banding on dark shades due to loss of precision. I recommend that only the colour picker should be in linear, but the document be saved in sRGB.

  3. Use sRGB values you are already used to but use Ogre::PixelFormatGpuUtils::toSRGB and Ogre::PixelFormatGpuUtils::fromSRGB to convert back and forth using code (this may be the path of least resistance)

    Code: Select all

    const Ogre::ColourValue backgroundColour( Ogre::PixelFormatGpuUtils::fromSRGB( 0.2f ), Ogre::PixelFormatGpuUtils::fromSRGB( 0.4f ), Ogre::PixelFormatGpuUtils::fromSRGB( 0.6f ) );
    

Cheers
Matias

knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Rendering to an existing window paints different color from expected

Post by knn217 »

dark_sylinc wrote: Wed Apr 12, 2023 12:34 am

This is normal & expected when using sRGB (i.e. the default) because the color space is different.

Good to know this is normal, since it looked different from Sample_Tutorial00_Basic's color I thought I missed loading a component like some sort of shader or something. I will load a mesh in to see how it looks.

One thing I'm still confused about is Sample_Tutorial00_Basic also has "sRGB Gamma Conversion" enabled, but the colors are still different.
Does Tutorial00 has a line that alters the color space somewhere, making it different from my code?

knn217
Halfling
Posts: 78
Joined: Wed Jan 25, 2023 9:04 am
x 5

Re: Rendering to an existing window paints different color from expected

Post by knn217 »

Solved it, turns out this line doesn't set the renderer to use "sRGB Gamma Conversion", more like setting it to yes on the config dialog:

Code: Select all

mRoot->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes");

Here's the new code to render into an existing window with custom wnproc (tested with a fullscreen toggle from Ramond Chen's devblog:https://devblogs.microsoft.com/oldnewth ... 20them%29.), with the correct color this time and also added in a simple text overlay:

Code: Select all

//---------------------------------------------------------------------------------------
// This tutorial shows nothing fancy. Only how to setup Ogre to render to
// a window, without any dependency.
//
// This samples has many hardcoded paths (e.g. it assumes the current working directory has R/W access)
// which means it will work in Windows and Linux, Mac may work.
//
// See the next tutorials on how to handles all OSes and how to properly setup a robust render loop
//---------------------------------------------------------------------------------------
#pragma comment(lib, "Comctl32.lib")
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <ole2.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <fstream>

#include "OgreAbiUtils.h"
#include "OgreArchiveManager.h"
#include "OgreCamera.h"
#include "OgreConfigFile.h"
#include "OgreRoot.h"
#include "OgreWindow.h"

#include "OgreHlmsManager.h"
#include "OgreHlmsPbs.h"
#include "OgreHlmsUnlit.h"
#include "OgreHlmsDiskCache.h"

#include "OgreOverlay.h"
#include "OgreOverlayContainer.h"
#include "OgreOverlayManager.h"
#include "OgreOverlaySystem.h"
#include "OgreTextAreaOverlayElement.h"

#include "OgreSingleton.h"
#include "OgreRenderSystem.h"

#include "OgreTextureGpuManager.h"

#include "OgreSceneManager.h"

#include "OgreGpuProgramManager.h"

#include "OgreLogManager.h"

#include "OgrePlatformInformation.h"

#include "Compositor/OgreCompositorManager2.h"

#include "OgreWindowEventUtilities.h"

#include "System/Android/AndroidSystems.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#    include "OSX/macUtils.h"
#endif

HWND g_hwndChild;                           /* Optional child window */

WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };


void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
    DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
    if (dwStyle & WS_OVERLAPPEDWINDOW) {MONITORINFO mi = { sizeof(mi) };
        if (GetWindowPlacement(hwnd, &g_wpPrev) && GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mi)) 
        {
            SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
            SetWindowPos(hwnd, HWND_TOP,
                mi.rcMonitor.left - 3, mi.rcMonitor.top - 3,
                mi.rcMonitor.right - mi.rcMonitor.left + 6,
                mi.rcMonitor.bottom - mi.rcMonitor.top + 6,
                SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
        }
    }
    else 
    {
        SetWindowLong(hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
        SetWindowPlacement(hwnd, &g_wpPrev);
        SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
            SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
}


void OnSize(HWND hwnd, UINT state, int cx, int cy)
{
    if (g_hwndChild) {
        MoveWindow(g_hwndChild, 0, 0, cx, cy, TRUE);
    }
}


BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
    return TRUE;
}


void OnDestroy(HWND hwnd)
{
    PostQuitMessage(0);
}


void PaintContent(HWND hwnd, PAINTSTRUCT* pps)
{
}


void OnPaint(HWND hwnd)
{
    PAINTSTRUCT ps;
    BeginPaint(hwnd, &ps);
    PaintContent(hwnd, &ps);
    EndPaint(hwnd, &ps);
}


void OnPrintClient(HWND hwnd, HDC hdc)
{
    PAINTSTRUCT ps;
    ps.hdc = hdc;
    GetClientRect(hwnd, &ps.rcPaint);
    PaintContent(hwnd, &ps);
}


class MyWindowEventListener final : public Ogre::WindowEventListener
{
    bool mQuit;

public:
    MyWindowEventListener() : mQuit(false) {}
    void windowClosed(Ogre::Window* rw) override { mQuit = true; }

bool getQuit() const { return mQuit; }
};


//------------------------------------------------------------------------------------
class LowLevelOgreNext
{
public:
    LowLevelOgreNext(void);
    LowLevelOgreNext(HWND h);
    virtual ~LowLevelOgreNext(void);
    
Ogre::Root* Init(HWND hwnd, const Ogre::String pluginsFolder, const Ogre::String writeAccessFolder, const char* pluginsFile, int &width, int &height, bool &fullscreen); void SetupResources(Ogre::String ResourcePath); void LoadResources(Ogre::String ResourcePath, const Ogre::String writeAccessFolder); void AddResourceLocation(const Ogre::String& archName, const Ogre::String& typeName, const Ogre::String& secName); void LoadTextureCache(const Ogre::String writeAccessFolder); void SaveTextureCache(const Ogre::String writeAccessFolder); void LoadHlmsDiskCache(const Ogre::String writeAccessFolder, bool UseMicrocodeCache, bool UseHlmsDiskCache); void SaveHlmsDiskCache(const Ogre::String writeAccessFolder, bool UseMicrocodeCache, bool UseHlmsDiskCache); void RegisterHlms(Ogre::String ResourcePath); void CreateTextOverlay(); void ChooseSceneManager(); void CreateCamera(); void initMiscParamsListener(Ogre::NameValuePairList& params) {} void GenerateDebugText(Ogre::String text); Ogre::Root* mRoot; Ogre::Camera* mCamera; Ogre::SceneManager* mSceneMgr; Ogre::Window* mWindow; Ogre::CompositorWorkspace* mWorkspace; Ogre::v1::OverlaySystem* mOverlaySystem; Ogre::CompositorManager2* mCompositorManager; Ogre::v1::TextAreaOverlayElement* mDebugText; Ogre::v1::TextAreaOverlayElement* mDebugTextShadow; Ogre::v1::OverlayManager* mOverlayManager; Ogre::v1::Overlay* mOverlay; Ogre::v1::OverlayContainer* mPanel; Ogre::String OutText; }; //------------------------------------------------------------------------------------- LowLevelOgreNext::LowLevelOgreNext(HWND h) : mRoot(0), mCamera(0), mSceneMgr(0), mWindow(0), mWorkspace(0), mOverlaySystem(0), mCompositorManager(0), mDebugText(0), mDebugTextShadow(0), mOverlayManager(0), mOverlay(0), OutText("1") {} LowLevelOgreNext::~LowLevelOgreNext(void) { delete mRoot; } //------------------------------------------------------------------------------------- Ogre::Root* LowLevelOgreNext::Init(HWND hwnd, const Ogre::String pluginsFolder, const Ogre::String writeAccessFolder, const char* pluginsFile, int &width, int &height, bool &fullscreen) { const Ogre::AbiCookie abiCookie = Ogre::generateAbiCookie(); mRoot = OGRE_NEW Ogre::Root(&abiCookie, pluginsFolder + pluginsFile, // writeAccessFolder + "ogre.cfg", // writeAccessFolder + "Ogre.log"); //-------------------------------------------------------------------------------------- if (!mRoot->showConfigDialog()) return NULL; mRoot->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes"); // Initialize Root mRoot->initialise(false); HWND hWnd = hwnd; // Get the hWnd of the application! Ogre::ConfigOptionMap& cfgOpts = mRoot->getRenderSystem()->getConfigOptions(); Ogre::ConfigOptionMap::iterator opt = cfgOpts.find("Video Mode"); if (opt != cfgOpts.end() && !opt->second.currentValue.empty()) { // Ignore leading space const Ogre::String::size_type start = opt->second.currentValue.find_first_of("012356789"); // Get the width and height Ogre::String::size_type widthEnd = opt->second.currentValue.find(' ', start); // we know that the height starts 3 characters after the width and goes until the next space Ogre::String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd + 3); // Now we can parse out the values width = Ogre::StringConverter::parseInt(opt->second.currentValue.substr(0, widthEnd)); height = Ogre::StringConverter::parseInt(opt->second.currentValue.substr(widthEnd + 3, heightEnd)); } fullscreen = Ogre::StringConverter::parseBool(cfgOpts["Full Screen"].currentValue); Ogre::NameValuePairList params; //params["externalWindowHandle"] = Ogre::StringConverter::toString((int)hWnd); params.insert(std::make_pair("externalWindowHandle", Ogre::StringConverter::toString((int)hWnd))); params.insert(std::make_pair("gamma", cfgOpts["sRGB Gamma Conversion"].currentValue)); if (cfgOpts.find("VSync Method") != cfgOpts.end()) params.insert(std::make_pair("vsync_method", cfgOpts["VSync Method"].currentValue)); params.insert(std::make_pair("FSAA", cfgOpts["FSAA"].currentValue)); params.insert(std::make_pair("vsync", cfgOpts["VSync"].currentValue)); params.insert(std::make_pair("reverse_depth", "Yes")); initMiscParamsListener(params); mWindow = mRoot->createRenderWindow("Main RenderWindow", static_cast<uint32_t>(width), static_cast<uint32_t>(height), fullscreen, &params); //*************************************************************** // Setup overlay system mOverlaySystem = OGRE_NEW Ogre::v1::OverlaySystem(); mOverlayManager = Ogre::v1::OverlayManager::getSingletonPtr(); mOverlay = mOverlayManager->create("DebugText"); Ogre::String ResourcePath = ""; SetupResources(ResourcePath); LoadResources(ResourcePath, writeAccessFolder); // Create SceneManager ChooseSceneManager(); // Create Overlay CreateTextOverlay(); // Create Camera CreateCamera(); // Setup a basic compositor with a blue clear colour mCompositorManager = mRoot->getCompositorManager2(); // Setup workspace const Ogre::String workspaceName("Demo Workspace"); const Ogre::ColourValue backgroundColour(0.2f, 0.4f, 0.6f); mCompositorManager->createBasicWorkspaceDef(workspaceName, backgroundColour, Ogre::IdString()); mWorkspace = mCompositorManager->addWorkspace(mSceneMgr, mWindow->getTexture(), mCamera, workspaceName, true); return mRoot; } void LowLevelOgreNext::SetupResources(Ogre::String ResourcePath) { // Load resource paths from config file Ogre::ConfigFile cf; cf.load(Demo::AndroidSystems::openFile(ResourcePath + "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 LowLevelOgreNext::LoadResources(Ogre::String ResourcePath, const Ogre::String writeAccessFolder) { RegisterHlms(ResourcePath); LoadTextureCache(writeAccessFolder); LoadHlmsDiskCache(writeAccessFolder, true, true); // 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 LowLevelOgreNext::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 LowLevelOgreNext::LoadTextureCache(const Ogre::String writeAccessFolder) { #if !OGRE_NO_JSON Ogre::ArchiveManager& archiveManager = Ogre::ArchiveManager::getSingleton(); Ogre::Archive* rwAccessFolderArchive = archiveManager.load(writeAccessFolder, "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 " + writeAccessFolder + "/textureMetadataCache.json"); } } catch (Ogre::Exception& e) { Ogre::LogManager::getSingleton().logMessage(e.getFullDescription()); } archiveManager.unload(rwAccessFolderArchive); #endif } //----------------------------------------------------------------------------------- void LowLevelOgreNext::SaveTextureCache(const Ogre::String writeAccessFolder) { if (mRoot->getRenderSystem()) { Ogre::TextureGpuManager* textureManager = mRoot->getRenderSystem()->getTextureGpuManager(); if (textureManager) { Ogre::String jsonString; textureManager->exportTextureMetadataCache(jsonString); const Ogre::String path = writeAccessFolder + "/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 LowLevelOgreNext::LoadHlmsDiskCache(const Ogre::String writeAccessFolder, bool UseMicrocodeCache, bool UseHlmsDiskCache) { if (!UseMicrocodeCache && !UseHlmsDiskCache) return; Ogre::HlmsManager* hlmsManager = mRoot->getHlmsManager(); Ogre::HlmsDiskCache diskCache(hlmsManager); Ogre::ArchiveManager& archiveManager = Ogre::ArchiveManager::getSingleton(); Ogre::Archive* rwAccessFolderArchive = archiveManager.load(writeAccessFolder, "FileSystem", true); if (UseMicrocodeCache) { // 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 (UseHlmsDiskCache) { 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 " + writeAccessFolder + "/" + filename + "! If you have issues, try deleting the file " "and restarting the app"); } } } } archiveManager.unload(writeAccessFolder); } //----------------------------------------------------------------------------------- void LowLevelOgreNext::SaveHlmsDiskCache(const Ogre::String writeAccessFolder, bool UseMicrocodeCache, bool UseHlmsDiskCache) { if (mRoot->getRenderSystem() && Ogre::GpuProgramManager::getSingletonPtr() && (UseMicrocodeCache || UseHlmsDiskCache)) { Ogre::HlmsManager* hlmsManager = mRoot->getHlmsManager(); Ogre::HlmsDiskCache diskCache(hlmsManager); Ogre::ArchiveManager& archiveManager = Ogre::ArchiveManager::getSingleton(); Ogre::Archive* rwAccessFolderArchive = archiveManager.load(writeAccessFolder, "FileSystem", false); if (UseHlmsDiskCache) { 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() && UseMicrocodeCache) { const Ogre::String filename = "microcodeCodeCache.cache"; Ogre::DataStreamPtr shaderCacheFile = rwAccessFolderArchive->create(filename); Ogre::GpuProgramManager::getSingleton().saveMicrocodeCache(shaderCacheFile); } archiveManager.unload(writeAccessFolder); } } void LowLevelOgreNext::RegisterHlms(Ogre::String ResourcePath) { //using namespace Ogre; #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE // Note: macBundlePath works for iOS too. It's misnamed. const String resourcePath = Ogre::macResourcesPath(); #elif OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS const String resourcePath = Ogre::macBundlePath() + "/"; #else
#endif Ogre::ConfigFile cf; cf.load(ResourcePath + "resources2.cfg"); #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE || OGRE_PLATFORM == OGRE_PLATFORM_APPLE_IOS String rootHlmsFolder = macBundlePath() + '/' + cf.getSetting("DoNotUseAsResource", "Hlms", ""); #else Ogre::String rootHlmsFolder = ResourcePath + cf.getSetting("DoNotUseAsResource", "Hlms", ""); #endif if (rootHlmsFolder.empty()) rootHlmsFolder = "./"; 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(); { // 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, "FileSystem", true); Ogre::ArchiveVec archiveUnlitLibraryFolders; libraryFolderPathIt = libraryFoldersPaths.begin(); libraryFolderPathEn = libraryFoldersPaths.end(); while (libraryFolderPathIt != libraryFolderPathEn) { Ogre::Archive* archiveLibrary = archiveManager.load(rootHlmsFolder + *libraryFolderPathIt, "FileSystem", 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, "FileSystem", 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, "FileSystem", 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 = Ogre::Root::getSingletonPtr()->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 LowLevelOgreNext::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 mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, numThreads, "ExampleSMInstance"); mSceneMgr->addRenderQueueListener(mOverlaySystem); mSceneMgr->getRenderQueue()->setSortRenderQueue( Ogre::v1::OverlayManager::getSingleton().mDefaultRenderQueueId, Ogre::RenderQueue::StableSort); // Set sane defaults for proper shadow mapping mSceneMgr->setShadowDirectionalLightExtrusionDistance(500.0f); mSceneMgr->setShadowFarDistance(500.0f); } void LowLevelOgreNext::CreateTextOverlay() { mPanel = static_cast<Ogre::v1::OverlayContainer*>(mOverlayManager->createOverlayElement("Panel", "DebugPanel")); mPanel->setMetricsMode(Ogre::v1::GuiMetricsMode::GMM_RELATIVE); mPanel->setDimensions(1, 1); mPanel->setPosition(0, 0); mDebugText = static_cast<Ogre::v1::TextAreaOverlayElement*>(mOverlayManager->createOverlayElement("TextArea", "DebugText")); mDebugText->setMetricsMode(Ogre::v1::GuiMetricsMode::GMM_RELATIVE); mDebugText->setPosition(0, 0); mDebugText->setFontName("DebugFont"); mDebugText->setCharHeight(0.025f); mDebugTextShadow = static_cast<Ogre::v1::TextAreaOverlayElement*>(mOverlayManager->createOverlayElement("TextArea", "0DebugTextShadow")); mDebugTextShadow->setFontName("DebugFont"); mDebugTextShadow->setCharHeight(0.025f); mDebugTextShadow->setColour(Ogre::ColourValue::Black); mDebugTextShadow->setPosition(0.002f, 0.002f); mPanel->addChild(mDebugTextShadow); mPanel->addChild(mDebugText); mOverlay->add2D(mPanel); mOverlay->show(); } void LowLevelOgreNext::CreateCamera() { // Create & setup camera mCamera = mSceneMgr->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); } void LowLevelOgreNext::GenerateDebugText(Ogre::String text) { OutText.reserve(128); OutText = text; mDebugText->setCaption(OutText); mDebugTextShadow->setCaption(OutText); } const wchar_t g_szClassName[] = L"myWindowClass"; // Step 4: the Window Procedure LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_SIZE, OnSize); HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy); HANDLE_MSG(hwnd, WM_PAINT, OnPaint); HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp); case WM_PRINTCLIENT: OnPrintClient(hwnd, (HDC)wParam); return 0; } return DefWindowProc(hwnd, uiMsg, wParam, lParam); } BOOL InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); return FALSE; } InitCommonControls(); /* In case we use a common control */ return TRUE; } #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR strCmdLine, INT nCmdShow) #else int main(int argc, const char* argv[]) #endif { //using namespace Ogre; #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE const String pluginsFolder = macResourcesPath(); const String writeAccessFolder = macLogPath(); #else const Ogre::String pluginsFolder = "./"; const Ogre::String writeAccessFolder = pluginsFolder; #endif #ifndef OGRE_STATIC_LIB # 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 #else const char* pluginsFile = 0; // TODO #endif HWND hwnd; MSG Msg; int width, height; bool fullscreen; //Step 1: Registering the Window Class if (!InitApp(hInst)) return 0; // Step 2: Creating the Window hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, L"The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInst, NULL); if (hwnd == NULL) { MessageBox(NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } UpdateWindow(hwnd); LowLevelOgreNext app(hwnd);// Create application object Ogre::Root* m_Root = app.Init(hwnd, pluginsFolder, writeAccessFolder, pluginsFile, width, height, fullscreen); if (m_Root == NULL) return 1; //Ogre::ConfigOptionMap& cfgOpts = m_Root->getRenderSystem()->getConfigOptions(); //Ogre::ConfigOptionMap::iterator opt = cfgOpts.find("Video Mode"); // //if (opt != cfgOpts.end() && !opt->second.currentValue.empty()) //{ // // Ignore leading space // const Ogre::String::size_type start = opt->second.currentValue.find_first_of("012356789"); // // Get the width and height // Ogre::String::size_type widthEnd = opt->second.currentValue.find(' ', start); // // we know that the height starts 3 characters after the width and goes until the next space // Ogre::String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd + 3); // // Now we can parse out the values // width = Ogre::StringConverter::parseInt(opt->second.currentValue.substr(0, widthEnd)); // height = Ogre::StringConverter::parseInt(opt->second.currentValue.substr(widthEnd + 3, heightEnd)); //} //bool fullscreen = Ogre::StringConverter::parseBool(cfgOpts["Full Screen"].currentValue); // Set the window to config options: fullscreen, wifth, height DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE); MONITORINFO mi = { sizeof(mi) }; if (GetWindowPlacement(hwnd, &g_wpPrev) && GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mi)) { SetWindowPos(hwnd, HWND_TOP, (mi.rcMonitor.right - mi.rcMonitor.left - width) / 2, (mi.rcMonitor.bottom - mi.rcMonitor.top - height) / 2, width, height, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } if (fullscreen) { if (dwStyle & WS_OVERLAPPEDWINDOW) { if (GetWindowPlacement(hwnd, &g_wpPrev) && GetMonitorInfo(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mi)) { SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); SetWindowPos(hwnd, HWND_TOP, mi.rcMonitor.left - 3, mi.rcMonitor.top - 3, mi.rcMonitor.right - mi.rcMonitor.left + 6, mi.rcMonitor.bottom - mi.rcMonitor.top + 6, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } } else { SetWindowLong(hwnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW); SetWindowPlacement(hwnd, &g_wpPrev); SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); } } ShowWindow(hwnd, nCmdShow); // Step 3: The Message Loop while (GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); app.GenerateDebugText("2"); m_Root->renderOneFrame(); } return Msg.wParam; }