在这一部分,将解释对于一个实际的基于Ogre的程序而言,是如何构建的。
代码
main()函数
main.cpp
#include "input.h"
#include "simulation.h"
#include "Ogre.h"
#include "OgreWindowEventUtilities.h"
#if defined(WIN32)
#include "windows.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
#else
int main (int argc, char *argv[]) {
#endif
Ogre::Root *ogre;
Ogre::RenderWindow *window;
Ogre::SceneManager *sceneMgr;
Ogre::Camera *camera;
// fire up an Ogre rendering window. Clearing the first two (of three) params will let us
// specify plugins and resources in code instead of via text file
ogre = new Ogre::Root("", "");
// This is a VERY minimal rendersystem loading example; we are hardcoding the OpenGL
// renderer, instead of loading GL and D3D9. We will add renderer selection support in a
// future article.
// I separate the debug and release versions of my plugins using the same "_d" suffix that
// the Ogre main libraries use; you may need to remove the "_d" in your code, depending on the
// naming convention you use
// EIHORT NOTE: All Ogre DLLs use this suffix convention now -- #ifdef on the basis of the _DEBUG
// define
#if defined(_DEBUG)
ogre->loadPlugin("RenderSystem_GL_d");
#else
ogre->loadPlugin("RenderSystem_GL");
#endif
Ogre::RenderSystemList *renderSystems = NULL;
Ogre::RenderSystemList::iterator r_it;
// we do this step just to get an iterator that we can use with setRenderSystem. In a future article
// we actually will iterate the list to display which renderers are available.
renderSystems = ogre->getAvailableRenderers();
r_it = renderSystems->begin();
ogre->setRenderSystem(*r_it);
ogre->initialise(false);
// load common plugins
#if defined(_DEBUG)
ogre->loadPlugin("Plugin_CgProgramManager_d");
ogre->loadPlugin("Plugin_OctreeSceneManager_d");
#else
ogre->loadPlugin("Plugin_CgProgramManager");
ogre->loadPlugin("Plugin_OctreeSceneManager");
#endif
// load the basic resource location(s)
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"resource", "FileSystem", "General");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"resource/gui.zip", "Zip", "GUI");
#if defined(WIN32)
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"c:\\windows\\fonts", "FileSystem", "GUI");
#endif
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("General");
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("GUI");
// setup main window; hardcode some defaults for the sake of presentation
Ogre::NameValuePairList opts;
opts["resolution"] = "1024x768";
opts["fullscreen"] = "false";
opts["vsync"] = "false";
// create a rendering window with the title "CDK"
window = ogre->createRenderWindow("CDK", 1024, 768, false, &opts);
// since this is basically a CEGUI app, we can use the ST_GENERIC scene manager for now; in a later article
// we'll see how to change this
sceneMgr = ogre->createSceneManager(Ogre::ST_GENERIC);
camera = sceneMgr->createCamera("camera");
camera->setNearClipDistance(5);
Ogre::Viewport* vp = window->addViewport(camera);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));
// most examples get the viewport size to calculate this; for now, we'll just
// set it to 4:3 the easy way
camera->setAspectRatio((Ogre::Real)1.333333);
// this next bit is for the sake of the input handler
unsigned long hWnd;
window->getCustomAttribute("WINDOW", &hWnd);
// set up the input handlers
Simulation *sim = new Simulation();
InputHandler *handler = new InputHandler(sim, hWnd);
sim->requestStateChange(SIMULATION);
while (sim->getCurrentState() != SHUTDOWN) {
handler->capture();
// run the message pump (Eihort)
Ogre::WindowEventUtilities::messagePump();
ogre->renderOneFrame();
}
// clean up after ourselves
delete handler;
delete sim;
delete ogre;
return 0;
}
这是最小的程序,它与Ogre教程的第一个教程是一样的。
对于这段代码的快速扫描,可以看到initialization, resource location setup,
and the main loop. 在编译这个程序之前,需要加上下面的这些文件"Simulation"
declaration (.h) and definition (.cpp) files:
Simulation
simulation.h
#pragma once
#include <vector>
#include <map>
typedef enum {
STARTUP,
GUI,
LOADING,
CANCEL_LOADING,
SIMULATION,
SHUTDOWN
} SimulationState;
class Simulation {
public:
Simulation();
virtual ~Simulation();
public:
bool requestStateChange(SimulationState state);
bool lockState();
bool unlockState();
SimulationState getCurrentState();
void setFrameTime(float ms);
inline float getFrameTime() { return m_frame_time; }
protected:
SimulationState m_state;
bool m_locked;
float m_frame_time;
};
simulation.cpp
#include "simulation.h"
#include "OgreStringConverter.h"
Simulation::Simulation() {
m_state = STARTUP;
}
Simulation::~Simulation() {
}
SimulationState Simulation::getCurrentState() {
return m_state;
}
// for the sake of clarity, I am not using actual thread synchronization
// objects to serialize access to this resource. You would want to protect
// this block with a mutex or critical section, etc.
bool Simulation::lockState() {
if (m_locked == false) {
m_locked = true;
return true;
}
else
return false;
}
bool Simulation::unlockState() {
if (m_locked == true) {
m_locked = false;
return true;
}
else
return false;
}
bool Simulation::requestStateChange(SimulationState newState) {
if (m_state == STARTUP) {
m_locked = false;
m_state = newState;
return true;
}
// this state cannot be changed once initiated
if (m_state == SHUTDOWN) {
return false;
}
if ((m_state == GUI || m_state == SIMULATION || m_state == LOADING || m_state == CANCEL_LOADING) &&
(newState != STARTUP) && (newState != m_state)) {
m_state = newState;
return true;
}
else
return false;
}
void Simulation::setFrameTime(float ms) {
m_frame_time = ms;
}
"Simulation"类是一个非常简单的“State
Manager”类的例子。Simulation (or game) 状态只是执行的上下文(contexts). States并没有统一的标准,这与你的应用程序有关,
SHUTDOWN, SIMULATION and GUI 是三个典型的状态.
对于输入,选取OIS,OIS对应的输入文件如下input.h/.cpp:
InputHandler
input.h
#pragma once
#include "OISEvents.h"
#include "OISInputManager.h"
#include "OISMouse.h"
#include "OISKeyboard.h"
#include "OISJoyStick.h"
class Simulation;
class InputHandler :
public OIS::MouseListener,
public OIS::KeyListener,
public OIS::JoyStickListener
{
private:
OIS::InputManager *m_ois;
OIS::Mouse *mMouse;
OIS::Keyboard *mKeyboard;
unsigned long m_hWnd;
Simulation *m_simulation;
public:
InputHandler(Simulation *sim, unsigned long hWnd);
~InputHandler();
void setWindowExtents(int width, int height) ;
void capture();
// MouseListener
bool mouseMoved(const OIS::MouseEvent &evt);
bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID);
bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID);
// KeyListener
bool keyPressed(const OIS::KeyEvent &evt);
bool keyReleased(const OIS::KeyEvent &evt);
// JoyStickListener
bool buttonPressed(const OIS::JoyStickEvent &evt, int index);
bool buttonReleased(const OIS::JoyStickEvent &evt, int index);
bool axisMoved(const OIS::JoyStickEvent &evt, int index);
bool povMoved(const OIS::JoyStickEvent &evt, int index);
};
input.cpp
#include "input.h"
#include "OgreStringConverter.h"
#include "simulation.h"
InputHandler::InputHandler(Simulation *sim, unsigned long hWnd) {
OIS::ParamList pl;
pl.insert(OIS::ParamList::value_type("WINDOW", Ogre::StringConverter::toString(hWnd)));
m_hWnd = hWnd;
m_ois = OIS::InputManager::createInputSystem( pl );
mMouse = static_cast<OIS::Mouse*>(m_ois->createInputObject( OIS::OISMouse, true ));
mKeyboard = static_cast<OIS::Keyboard*>(m_ois->createInputObject( OIS::OISKeyboard, true));
mMouse->setEventCallback(this);
mKeyboard->setEventCallback(this);
m_simulation = sim;
}
InputHandler::~InputHandler() {
if (mMouse)
delete mMouse;
if (mKeyboard)
delete mKeyboard;
OIS::InputManager::destroyInputSystem(m_ois);
}
void InputHandler::capture() {
mMouse->capture();
mKeyboard->capture();
}
void InputHandler::setWindowExtents(int width, int height){
//Set Mouse Region.. if window resizes, we should alter this to reflect as well
const OIS::MouseState &ms = mMouse->getMouseState();
ms.width = width;
ms.height = height;
}
// MouseListener
bool InputHandler::mouseMoved(const OIS::MouseEvent &evt) {
return true;
}
bool InputHandler::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
return true;
}
bool InputHandler::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) {
return true;
}
// KeyListener
bool InputHandler::keyPressed(const OIS::KeyEvent &evt) {
return true;
}
bool InputHandler::keyReleased(const OIS::KeyEvent &evt) {
if (evt.key == OIS::KC_ESCAPE)
m_simulation->requestStateChange(SHUTDOWN);
return true;
}
// JoyStickListener
bool InputHandler::buttonPressed(const OIS::JoyStickEvent &evt, int index) {
return true;
}
bool InputHandler::buttonReleased(const OIS::JoyStickEvent &evt, int index) {
return true;
}
bool InputHandler::axisMoved(const OIS::JoyStickEvent &evt, int index) {
return true;
}
bool InputHandler::povMoved(const OIS::JoyStickEvent &evt, int index) {
return true;
}
这里,我们对OIS的处理,使用缓存模式(buffered mode),因此我们可以避免遗漏掉输入事件。而用InputHandler::capture()只取即时事件,会清空它们的缓存。
编译与运行代码
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"resource", "FileSystem", "General");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"resource/gui.zip", "Zip", "GUI");
如上所述,在初始化中,我们定义了两个资源组(resource groups): General and GUI.
General 是一直都存在的,也是默认的资源组。GUI 是我们创建用于存放GUI内容的,在gui.zip中的文件都会导入这个资源组。