Skip to main content
Simple Win32 Program         Petzold style Ogre program

Intention

I wanted to create an archetype program that would be able
to handle multiple key combinations. Say, the right shift key and the
the key character 'X'. My options available were OIS, MFC, or WxWindows.
MFC and WxWindows would be a lot overhead and dll version management for
what is a simple program. After unsuccseful attempts at making OIS work,
I decided that the Petzold style of program would minimize the windows
"portion" and show how ogre would need to interact. When finished, this program
would show the classic orgehead mesh, respond to a few key inputs and
adjust to camera position in response to the mouse or the keyboard.

Starting point

First this program was created with Microsoft Visual Studio 2003 and links to
the Eihort version 1.3.0 of OGRE. The easiest way to start off is to use the
wizard to create a simple windows application ogre32, which should give you the following files:

Copy to clipboard
ogre32.cpp ogre32.h ogre32.ico ogre32.ncb ogre32.rc ogre32.sln ogre32.vcproj ReadMe.txt Resource.h small.ico stdafx.cpp stdafx.h


Before modifying the code that the wizard created, you will need to
get the media files and scripts necessary to display the ogrehead.mesh
file. To do this you will need to create the directory 'media' under your
main project and copy the following files into this directory.
The png and jpg files can be found in the textures directory.
The Ogre.material file is a modified version of the Ogre.material
file that comes with the OGRE source code. The original one can be found
at .\ogrenew\Samples\Media\materials\scripts.

Copy to clipboard
cursor.png dirt01.jpg GreenSkin.jpg Ogre.material ogreborder.png ogreborderUp.png ogrehead.mesh spheremap.png WeirdEye.png


You will need to create three configuration files:

{CODE(wrap="1"}ogre.cfg
Plugins.cfg
resources.cfg
{CODE}

ogre.cfg

Copy to clipboard
Render System=Direct3D9 Rendering Subsystem [Direct3D9 Rendering Subsystem] Allow NVPerfHUD=No FSAA=0 Floating-point mode=Fastest Full Screen=No Rendering Device=NVIDIA GeForce FX 5200 VSync=No Video Mode=800 x 600 @ 32-bit colour [OpenGL Rendering Subsystem] Colour Depth=32 Display Frequency=60 FSAA=0 Full Screen=Yes RTT Preferred Mode=FBO VSync=No Video Mode=1024 x 768


Note: If you hear your graphics card squealing when showing the Ogre head, turn Vsync to "yes" in ogre.cfg! Your graphics card will squeal when there are too many frames per second being rendered.

Plugins.cfg

Copy to clipboard
# Defines plugins to load # Define plugin folder PluginFolder=. # Define plugins Plugin=RenderSystem_Direct3D9

resources.cfg

Copy to clipboard
# Resource locations to be added to the default path [General] FileSystem=./media


You will need to edit the follow files:

Copy to clipboard
stdafx.h ogre32.cpp

stdafx.h

Copy to clipboard
#pragma once #define WIN32_LEAN_AND_MEAN #include <windows.h> // C RunTime Header Files #include <stdlib.h> #include <malloc.h> #include <memory.h> #include <tchar.h> #include <Ogre.h> //brings in almost everything

ogre32.cpp

The following is the original ogre32.cpp file
This will create a simple project that displays the ogrehead mesh file.

Copy to clipboard
// ogre32.cpp : Defines the entry point for the application. // #include "stdafx.h" #include "ogre32.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name using namespace Ogre; // <-- ultimate in lazy


The most important of the following variables is mRoot.
As the "Root class represents a starting point for the client application.
From here, the application can gain access to the fundamentals of the system ...
and Root must be created before any other Ogre operations are called.
Once an instance has been created, the same instance is accessible throughout the life of that
object by using Root::getSingleton (as a reference) or Root::getSingletonPtr (as a pointer). "
See http://www.ogre3d.org/docs/api/html/classOgre_1_1Root.html#_details for more details.

Please consult the wiki for more
detailed reasons on why we added each of
these variables.

Copy to clipboard
Root *mRoot = 0; // SceneManager *mSceneMgr = 0; // Camera *mCamera = 0; // Viewport* mViewPort = 0; RenderWindow* mRenderWindow=0; // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { // TODO: Place code here. MSG msg; HACCEL hAccelTable; HWND hWnd; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_OGRE32, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; }


create the root ogre system

Copy to clipboard
mRoot = new Root();


load the configuration file

Copy to clipboard
ConfigFile cf; cf.load("resources.cfg"); ConfigFile::SectionIterator seci = cf.getSectionIterator(); String secName, typeName, archName; while (seci.hasMoreElements()) { secName = seci.peekNextKey(); ConfigFile::SettingsMultiMap *settings = seci.getNext(); ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName); } }


Load the directx rendering system we dont have
to Display the configuration dialog.

Copy to clipboard
RenderSystemList *rsList = mRoot->getAvailableRenderers(); int c=0; bool foundit = false; RenderSystem *selectedRenderSystem=0; while(c < (int) rsList->size()) { selectedRenderSystem = rsList->at(c); String rname = selectedRenderSystem->getName(); if(rname.compare("Direct3D9 Rendering Subsystem")==0) { foundit=true; break; } c++; // <-- oh how clever } if(!foundit) return FALSE; //we didn't find it... //we found it, we might as well use it! mRoot->setRenderSystem(selectedRenderSystem); selectedRenderSystem->setConfigOption("Full Screen","No"); selectedRenderSystem->setConfigOption("Video Mode","800 x 600 @ 16-bit colour"); //retrieve the config option map ConfigOptionMap comap = selectedRenderSystem->getConfigOptions(); //and now we need to run through all of it ConfigOptionMap::const_iterator start = comap.begin(); ConfigOptionMap::const_iterator end = comap.end(); while(start != end) { String OptionName = start->first; String CurrentValue = start->second.currentValue; StringVector PossibleValues = start->second.possibleValues; int c=0; while (c < (int) PossibleValues.size()) { String OneValue = PossibleValues.at(c); c++; } start++; } //end boilerplate


this is the magic! here is where we take the window that has been previously
been created and attach ogre to it.

Copy to clipboard
mRoot->initialise(false,"Some Window Title"); NameValuePairList misc; misc["externalWindowHandle"] = StringConverter::toString( (size_t)hWnd); mRenderWindow = mRoot->createRenderWindow( "My sub render window", 800, 600, false, &misc );


create a scene manager

Copy to clipboard
// choose sm mSceneMgr = mRoot->createSceneManager(ST_GENERIC, "mSceneMgr"); mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));


This is so we can have scripts work and the mesh is properly rendered.

Copy to clipboard
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();


Load a mesh that is located in the ./media directory.

Copy to clipboard
Entity *ent1 = mSceneMgr->createEntity( "ogre", "ogrehead.mesh" ); SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode" ); node1->attachObject( ent1 );


Create a camera so we can look at his lovely mug.

Copy to clipboard
// -------------------- // Create the camera mCamera = mSceneMgr->createCamera("PlayerCam"); // Position it at 500 in Z direction mCamera->setPosition(Ogre::Vector3(0,0,500)); // Look back along -Z mCamera->lookAt(Ogre::Vector3(0,0,-300)); mCamera->setNearClipDistance(5); // Set the viewport mViewPort = mRenderWindow->addViewport(mCamera); mViewPort->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f, 1.0f)); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_OGRE32); // Main message loop: while (GetMessage(&msg, NULL, 0, 0)) { //placing renderOneFrame seems to allow for a clean shutdown. //thanks to user lakin for that hint. if (mRoot->renderOneFrame()) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_OGRE32); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_EXIT:

I was told to do this. This may or may not be necessary.

Copy to clipboard
mRoot->detachRenderTarget(mRenderWindow); DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: Add any drawing code here... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break;


Returning 1 will cause the screen not flicker when the
window is being resized.

Copy to clipboard
case WM_ERASEBKGND: return 1;


Handle resizing the window.
one of the things this program does not do
is display full screen. This should be relatively
simple to implement. Also the section is
direct translation of the WxWindows code that
was posted to forum.

Copy to clipboard
case WM_SIZE: if (mCamera) { RECT rect; GetClientRect(hWnd,&rect); // notify "render window" instance mRenderWindow->windowMovedOrResized(); // Adjust camera's aspect ratio, too if ((rect.bottom - rect.top) != 0 && mCamera != 0) mCamera->setAspectRatio((Ogre::Real)mRenderWindow->getWidth() / (Ogre::Real)mRenderWindow->getHeight()); mCamera->yaw(Radian(0)); Root::getSingletonPtr()->renderOneFrame(); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } #endif

Alias: Simple_Win32_Program