'The Ogre Startup Sequence'에 해당되는 글 1건

  1. 2010.03.27 기초 튜토리얼6
2010.03.27 17:26

입문자 튜토리얼 6: The Ogre Startup Sequence

튜토리얼 진행중 문제가 발생한다면 Help 포럼 문의하세요.

 

Contents

*                               1 미리 알아두어야

*                               2 소개

*                               3 시작하기

*                                       3.1 초기화 코드

*                                       3.2 구동 프로세스의 내부

*                               4 오우거 구동하기

*                                       4.1 루트 객체 만들기

*                                       4.2 리소스

*                                       4.3 렌더시스템 만들기

*                                       4.4 렌더윈도우 만들기

*                                       4.5 리소스 초기화

*                                       4.6 장면 만들기

*                               5 써드파티 라이브러리 구동하기

*                                       5.1 OIS

*                                               5.1.1 셋업 비버퍼

*                                               5.1.2 Framelistener 구동하기

*                                               5.1.3 버퍼방식 입력에서의 문제점 해결

*                                       5.2 CEGUI

*                               6 구동 마무리짓기와 Render 루프

*                                       6.1 Frame Listener

*                                       6.2 Render 루프

*                               7 메모리 해제

*                               8 Mac OS X

 

미리 알아두어야

튜토리얼은 독자가 C++ 프로그래밍이 가능하고 오우거 어플리케이션 설정 컴파일이 가능하다는 가정하에 진행됩니다. 튜토리얼은 이전 튜토리얼을 기초로 작성되었으며 독자는 이전 튜토리얼들을 거쳐왔다고 가정합니다.

 

소개

이번 튜토리얼에서는 예제용프레임워크(example framework) 사용하지 않고 오우거를 구동시키는 법을 다룹니다. 튜토리얼을 끝마칠 쯔음이면 ExampleApplication 또는 ExampleFrameListener 클래스를 사용하지 않는 유저만의 오우거 어플리케이션을 만들 있게 것입니다.

튜토리얼을 위한 코드를 여기(http://www.ogre3d.org/wiki/index.php/BasicTutorial6Source) 찾을 있습니다. 코드를 천천히 입력하면서 나오는 결과물을 직접 눈으로 확인하세요.

 

시작하기

 

초기화 코드

튜토리얼에서는 미리 작성된 코드로 부터 시작 것입니다. 지금까지 튜토리얼을 진행해 처럼 이러한 방식은 익숙하리라 생각합니다. 프로젝트를 생성하고 아래 소스코드를 입력하세요 :

#include <Ogre.h>

#include <OIS/OIS.h>

#include <CEGUI/CEGUI.h>

#include <OgreCEGUIRenderer.h>

 

using namespace Ogre;

 

class ExitListener : public FrameListener

{

public:

    ExitListener(OIS::Keyboard *keyboard)

        : mKeyboard(keyboard)

    {

    }

 

    bool frameStarted(const FrameEvent& evt)

    {

        mKeyboard->capture();

        return !mKeyboard->isKeyDown(OIS::KC_ESCAPE);

    }

 

private:

    OIS::Keyboard *mKeyboard;

};

 

class Application

{

public:

    void go()

    {

        createRoot();

        defineResources();

        setupRenderSystem();

        createRenderWindow();

        initializeResourceGroups();

        setupScene();

        setupInputSystem();

        setupCEGUI();

        createFrameListener();

        startRenderLoop();

    }

 

    ~Application()

    {

    }

 

private:

    Root *mRoot;

    OIS::Keyboard *mKeyboard;

    OIS::InputManager *mInputManager;

    CEGUI::OgreCEGUIRenderer *mRenderer;

    CEGUI::System *mSystem;

    ExitListener *mListener;

 

    void createRoot()

    {

    }

   

    void defineResources()

    {

    }

   

    void setupRenderSystem()

    {

    }

   

    void createRenderWindow()

    {

    }

 

    void initializeResourceGroups()

    {

    }

 

    void setupScene()

    {

    }

 

    void setupInputSystem()

    {

    }

 

    void setupCEGUI()

    {

    }

 

    void createFrameListener()

    {

    }

 

    void startRenderLoop()

    {

    }

};

 

#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32

#define WIN32_LEAN_AND_MEAN

#include "windows.h"

 

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)

#else

int main(int argc, char **argv)

#endif

{

    try

    {

        Application app;

        app.go();

    }

    catch(Exception& e)

    {

#if OGRE_PLATFORM == PLATFORM_WIN32 || OGRE_PLATFORM == OGRE_PLATFORM_WIN32

        MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL);

#else

        fprintf(stderr, "An exception has occurred: %s\n",

            e.getFullDescription().c_str());

#endif

    }

 

    return 0;

}

컴파일이 제대로 되는지 확인하세요. CEGUISingleton.h 같은 CEGUI 관련파일들을 찾을 없다는 에러가 발생한다면 컴파일러 헤더파일 검색 디렉토리에 $(OGRE_HOME)\include\CEGUI 추가해 주세요; 윈도우즈 이용자는 아마 'C:\OgreSDK\include\CEGUI' 것입니다.

 

구동 프로세스의 내부

오우거가 실제로 구동되는 내부를 이해하기는 사실 별로 어렵지 않습니다. 예제 프레임워크는 실제 프로그램에서 필요없을지도 모르는 많은 부분을 다루기 때문에 어렵게 보일지도 모릅니다. 튜토리얼을 끝낸다면 유저가 프로그램을 작성할때 필요한 부분만을 골라서 빌드할 있게 것입니다. 코드로 접어들기전에 어떻게 구동프로세스가 실행되는지 추상적으로 살펴보도록 합시다.

기본적인 오우거 라이프싸이클은 다음과 같습니다 :

1.    루트 객체를 만든다.

2.    오우거가 사용할 리소스를 정의한다.

3.    렌더시스템을 선택한다. (DirectX, OpenGL, 기타등등)

4.    렌더윈도우를 만든다. (오우거가 표시될 )

5.    사용하게 리소스를 초기화 한다.

6.    초기화된 리소스를 이용해 장면을 생성한.

7.    써드파티 라이브러리와 플러그인을 설정한다.

8.    Frame listener 만든다.

9.    Render 루프를 돌기 시작한다.

튜토리얼에서는 각각의 항목을 자세하게 살펴볼 계획입니다.

1-4 반드시 순서대로 진행해야 하고 5, 6(리소스 초기화 장면 생성) 사용자의 초기화코드에 따라서 나중에 해도 됩니다. 써드파티 플러그인 초기화와 프레임리스너 생성은 5, 6 전에 수행될 수도 있습니다. 하지만 절대 4 스텝이 끝나기 전에 해서는 안됩니다. 프레임리스너/써드파티 라이브러리가 초기화되고 장면이 생성되기 전까지는 관련된 어떤 리소스들(카메라, 엔티티, 기타등등) 대한 접근이 불가능합니다. 간단하게 요약하자면 뭔가 순서를 바꿔서 어플리케이션에게 긍정적인 효과를 기대할 있다면 하셔도 됩니다. 하지만 이러한 일련적 과정들에 대한 확실한 이해가 있기 전까지는 이러한 순서를 지키는것을 권장합니다.

 

Trackback 0 : Comment 0

기초 튜토리얼 6-2

Ogre3D 삽질란/Basic Tutorial 6 2008/11/30 19:03

오우거 구동하기

 

루트객체 만들기

작업이 제일 간단합니다. 루트객체는 오우거 라이브러리에서의 핵심 입니다. 그리고 오우거엔진으로 뭔가를 하기전에 거의 최우선 순위로 생성되어져야 합니다. Application::createRoot 함수를 찾아 다음코드를 추가하세요 :

       mRoot = new Root();

했습니다. 루트 생성자는 3개의 매개변수를 가집니다. 첫째는 이름과 플러그인 config 파일의 위치입니다. 두번째는 오우거 config 파일(비디오 카드라던지 비쥬얼 셋팅값을 오우거에게 전달합니다) 위치입니다. 마지막은 오우거가 생성시킬 log파일의 이름과 위치입니다. 지금은 아무것도 바꿀 필요가 없으므로 기본값으로 놔둡니다.

 

리소스

Note: 진행하기에 앞서 “resources.cfg” 파일을 미리 열어보시면 앞으로의 내용에 대한 이해에 도움이 것입니다. 지금 한번 파일을 열어보세요. SDK bin/release 폴더에 위치합니다.

다음으로 해야 일은 어플리케이션에서 사용될 리소스들을 정의하는 입니다. 리소스는 텍스쳐, 모델, 스크립트, 기타등등 여러가지들을 포함합니다. 지금 튜토리얼에서 모든 리소스들의 종류들을 다루지는 않을 입니다. 지금은 그냥 프로그램에서 쓰일 모든 리소스들을 정의하고 사용되기전에 초기화 시켜야 있다는 마음속에 염두해 두세요. 지금 단계에서는 튜토리얼을 진행하면서 쓰일만한 리소스들을 모두 정의합니다.

그러기 위해서 리소스가 담긴 각각의 폴더들을 ResourceGroupManager 추가합니다. defineResources 함수를 찾아서 다음코드를 추가하세요 :

       String secName, typeName, archName;

       ConfigFile cf;

       cf.load("resources.cfg");

“resources.cfg” 파일을 오우거의 ConfigFile 클래스로 파싱하여 내용을 읽어들이긴 합니다만 오우거 내부로 읽어들이는 것은 아닙니다( 과정은 수동으로 해줘야 합니다). 오우거에서 제공하는 config 파일을 따를 필요없이 자신만의 config 파일형식을 만들고 그것을 읽어들이는 파서를 제작해도 됩니다. 리소스를 읽어들이는 방식에는 정해진 규칙이 없습니다. 그냥 단지 ResourceGroupManager 리소스를 추가하기만 하면 됩니다. 어쨌든 지금은 config 파일을 해석했으며 ResourceGroupManager 섹션을 추가해야 합니다. 다음 코드는 해석된 config 파일을 순차적으로 읽기 시작합니다 :

       ConfigFile::SectionIterator seci = cf.getSectionIterator();

       while (seci.hasMoreElements())

       {

각각의 섹션에서 루프를 다시 돌면서 모든 내용을 읽어들입니다 :

           secName = seci.peekNextKey();

           ConfigFile::SettingsMultiMap *settings = seci.getNext();

           ConfigFile::SettingsMultiMap::iterator i;

섹션(리소스의 그룹)이름, 리소스의 타입(zip형식인지 폴더인지 아니면 또다른 형식인지..), 그리고 마지막에서 리소스의 파일이름과 함께 ResourceGroupManager 추가합니다 :

           for (i = settings->begin(); i != settings->end(); ++i)

           {

               typeName = i->first;

               archName = i->second;

               ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);

           }

       }

함수는 config 파일에 적혀있는 모든 리소스를 오우거에 등록시켰습니다. 하지만 과정은 오우거에게 리소스들이 어디에 위치하고 있는지에 대한 통보수준일 뿐입니다. 어떤 리소스를 사용하기 전에는 그에 해당하는 리소스그룹을 초기화 시키던지 또는 모든 리소스를 초기화시켜 줘야 합니다. 이러한 작업에 대해서는 리소스 초기화부분의 함수에서 다뤄질 것입니다.

 

렌더시스템 만들기

이번 순서에서는 렌더시스템(DirectX 또는 OpenGL 대표적 입니다) 선택하고 설정해야 합니다. 대부분의 오우거데모 프로그램들은 config 대화상자를 사용합니다. 방법은 프로그램을 사용자의 환경에 알맞게 설정하는 가장 좋은 방법입니다. 게다가 한번 설정한 값을 다시 사용할 수도 있습니다. 최초실행시 한번만 설정 주면 다음부터는 환경설정을 하지 않아도 된다는 입니다. setupRenderSystem 함수를 찾아서 다음 코드를 추가하세요 :

if (!mRoot->restoreConfig() && !mRoot->showConfigDialog())

           throw Exception(52, "User canceled the config dialog!", "Application::setupRenderSystem()");

if 문장의 첫번째 조건식에서 config 설정내용을 읽어들입니다. 만약 여기서 false 값이 리턴된다면 미리 설정된 config값이 없다는 의미므로 config 대화상자를 출력해야 합니다. 그것이 바로 2번째 조건식 입니다. 만약 대화상자에서도 false 리턴한다면 config 대화상자를 취소시킨 경우(프로그램 종료) 입니다. 예제에서는 예외처리로 이어집니다. 그러나 사실 이런 경우에는 예외처리로 넘기는 보단 깔끔하게 프로그램을 종료시키는 것이 나은 방법이라 생각됩니다. 어떤 이유에서 보자면 restoreConfigshowConfigDialog 에서도 예외가 발생될 있습니다. 그렇게 된다면 실제적인 에러처리를 위해서 예외를 처리해야 필요성도 있을 있습니다. 그러나 그렇게 일일이 처리한다면 튜토리얼만 불필요하게 복잡해 지기 때문에 여기서 예외처리를 하나만 두었습니다.

이런 예외처리를 실제에 적용하시고 싶으시다면 한가지 방법을 제시하겠습니다. 오우거 셋업과정에서 예외가 발생된다면 catch 블럭에 ogre.cfg 파일을 지우게끔 하세요. Config 대화상자를 통해서 설정되었던 설정값에서 에러가 발생되었고 다시 설정할 필요성이 있기 때문이죠. 프로그램 배포를 위해서 이런 방법을 쓰지 않는다 해도 config 대화상자를 놓는것은 프로그램 실행시 마다 물어보는 확인작업을 생략할 있으므로 개발 시간을 아낄 있을겁니다.

오우거에서 제공하는 config 대화상자를 거치지 않고 수동으로 렌더시스템을 선택할 수도 있습니다. 기본적인 사용법은 다음과 같습니다 :

       // Do not add this to the application

       RenderSystem *rs = mRoot->getRenderSystemByName("Direct3D9 Rendering Subsystem");

                                             // or use "OpenGL Rendering Subsystem"

       mRoot->setRenderSystem(rs);

       rs->setConfigOption("Full Screen", "No");

       rs->setConfigOption("Video Mode", "800 x 600 @ 32-bit colour");

Root::getAvailableRenderers 함수를 이용하면 현재 시스템에서 어떤 렌더시스템이 사용 가능한지를 체크할 있습니다. RenderSystem 얻고 나면 RenderSystem::getConfigOptions 통해서 어떤 선택가능한 옵션들이 있는지 알아볼 있습니다. 2개의 함수들을 섞으면 유저만의 config 대화상자를 만들 있게 됩니다.

 

RenderWindow 만들기

렌더시스템을 선택했습니다. 이제 오우거가 출력하기위한 윈도우가 필요합니다. 어떻게 윈도우를 생성하는 방법에는 정말 다양한 방법들이 존재합니다. 하지만 여기서는 간단하게 2가지 방법만 집고 넘어갑니다.

간단하게 오우거용 윈도우를 만들 있습니다. createRenderWindow함수를 찾아서 다음 코드를 추가하세요 :

       mRoot->initialise(true, "Tutorial Render Window");

이전 섹션에서 선택한 RenderSystem 초기화 시키는 코드입니다. 첫번째 매개변수는 렌더윈도우를 만들지의 여부입니다. true 값으로 설정해서 만들수 있지만 win32 API, wxWidgets, 또는 윈도우나 리눅스의 GUI 시스템을 통해서 창을 생성할 수도 있습니다. 윈도우즈에서 어떻게 수동으로 창을 생성하는지에 대한 개략적인 짧은 예제입니다 :

       // Do not add this to the application

       mRoot->initialise(false);

       HWND hWnd = 0;  // Get the hWnd of the application!

       NameValuePairList misc;

       misc["externalWindowHandle"] = StringConverter::toString((int)hWnd);

       RenderWindow *win = mRoot->createRenderWindow("Main RenderWindow", 800, 600, false, &misc);

주의깊게 보셔야 점은 여전히 Root::initialise 함수를 호출해 줘야 한다는 것입니다. 그러나 매개변수값은 false 입니다. 다음은 오우거가 윈도우의 HWND 값을 구해야 합니다. 방법은 유저가 어떤 GUI 툴킷을 써서 윈도우를 생성했는지에 따라 완전히 달라집니다(리눅스였다고 해도 역시 달라질 것입니다). 과정을 마친후에는 NameValuePairList 써서 핸들값을 “externalWindowHandle” 대입시켜야 합니다. 다음 Root::createRenderWindow 함수를 사용하여 이미 생성된 윈도우를 렌더윈도우로 있게끔 줍니다. 자세한 정보는 API 문서를 참고하세요.

 

리소스 초기화

지금까지 루트객체, 렌더시스템, 렌더윈도우를 만들고 사용할 준비가 되었습니다. 이제 장면출력을 위한 준비가 거의 끝나갑니다. 한가지 남은 작업이 있다면 사용할 리소스를 초기화 하는 입니다. 규모의 게임이나 어플리케이션에서는 어쩌면 수백에서 수천가지의 리소스들이 쓰일지도 모릅니다. 메쉬부터 텍스쳐, 스크립트 전부를 포함합니다. 아마도 실행하는 동안에는 항상 모든 리소스가 사용되는 것이 아닌 리소스의 일부분만 사용될 것입니다. 메모리 요구치를 낮추기 위해서 사용될 리소스만 메모리에 적재시킬 있습니다. 리소스를 섹션으로 나누고 사용될 것들만 초기화 시키는 방법으로 실현합니다. 튜토리얼에서는 방법을 다루지 않습니다. 그러나 여기(http://www.ogre3d.org/wiki/index.php/Advanced_Tutorial_1) 그에 관련된 완전한 튜토리얼이 있습니다.

리소스를 초기화 하기 전에 텍스쳐가 사용할 기본치 밉맵(mipmap)값을 설정해야 합니다. 반드시 리소스 초기화가 되기전에 설정해야 합니다. initializeResourceGroups 함수를 찾아서 다음 코드를 추가하세요 :

       TextureManager::getSingleton().setDefaultNumMipmaps(5);

       ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

이제 어플리케이션은 모든 리소스를 사용할 준비가 되었습니다.

 

장면 만들기

이제 장면을 생성해야 합니다. 단계는 다른 튜토리얼에서도 많이 해본 작업입니다. 그렇기 때문에 화면상에 아무것도 추가하지 않을 입니다. 대신에 화면상에 출력하기 위한 3가지 준비사항은 알아두세요 : SceneManager 만든다, 카메라를 만든다, 뷰포트를 만든다. setupScene 찾아서 다음 코드를 추가시켜 주세요 :

       SceneManager *mgr = mRoot->createSceneManager(ST_GENERIC, "Default SceneManager");

       Camera *cam = mgr->createCamera("Camera");

       Viewport *vp = mRoot->getAutoCreatedWindow()->addViewport(cam);

원하는 만큼 SceneManager 카메라를 생성해도 됩니다. 그러나 카메라를 통해서 화면에 뭔가를 그리고 싶다면 뷰포트가 추가되어야 합니다. 과정은 렌더윈도우 만들기에서 만들어진 RenderWindow 통해서 이루어 집니다. 렌더윈도우의 포인터를 가지고 있지 않기때문에 Root::getAutoCreatedWindow함수를 통해서 접근합니다.

3가지가 끝나면 화면에 객체를 추가할 있게 됩니다.

 

써드파티 라이브러리 구동하기

 

OIS

OIS 오우거의 유일한 입력용 옵션은 아니지만 최고중 하나입니다. OIS 어플리케이션에서 구동시키는 방법을 간단하게 집고 넘어가도록 하겠습니다. 라이브러리를 실제로 쓰기위해 다양한 튜토리얼(OIS 사용되는 부분들) OIS 문서를 참고하세요.

 

셋업과 비버퍼 입력

OIS 일반 InputManager 사용합니다. 설정하기가 까다롭지만 한번 생성하고 나면 사용하기는 쉽습니다. OIS 오우거에 통합되지 않았습니다. 이것은 독립적인 라이브러리이며 제대로 동작하기 위해 OIS에게 적절한 정보를 전달해 줘야 합니다. 실사용시 오우거가 렌더링에 쓰일 윈도우 핸들값만 필요합니다. 편의를 위해서 자동으로 윈도우가 생성될 경우 사용하기 쉽게 오우거가 도와줍니다. setupInputSystem 함수에 다음 코드를 추가하세요 :

       size_t windowHnd = 0;

       std::ostringstream windowHndStr;

       OIS::ParamList pl;

       RenderWindow *win = mRoot->getAutoCreatedWindow();

 

       win->getCustomAttribute("WINDOW", &windowHnd);

       windowHndStr << windowHnd;

       pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));

       mInputManager = OIS::InputManager::createInputSystem(pl);

InputManager 사용하기 위해 설정하는 코드 입니다만 실제로 OIS 통해서 키보드, 마우스, 조이스틱을 입력받으려면 다음 객체들을 생성해 줘야 합니다 :

       try

       {

           mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, false));

           //mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, false));

           //mJoy = static_cast<OIS::JoyStick*>(mInputManager->createInputObject(OIS::OISJoyStick, false));

       }

       catch (const OIS::Exception &e)

       {

           throw Exception(42, e.eText, "Application::setupInputSystem");

       }

마우스와 조이스틱부분은 튜토리얼에서 안쓰이기 때문에 주석처리를 했습니다. 하지만 어떻게 생성하는지를 보여주고 있습니다. InputManager::createInputObject에서 두번째 매개변수는 버퍼방식(지난 최근 2개의 튜토리얼에서 다뤘던 내용) 사용할지 여부입니다. 튜토리얼에서는 두번째 매개변수를 false 설정해서 비버퍼방식을 사용합니다.

Note: 만약 버퍼방식을 쓰고 싶다면 (이벤트가 콜백 형식으로 mouseMoved, mousePressed, keyReleased, 기타등등.. 으로 전달되는 방식) createInputObject 2번째 매개변수를 true 설정해 주세요.

 

Framelistener 구동하기

버퍼방식이나 비버퍼방식을 어느것을 쓰더라도 프레임마다 모든 입력장치들에대한 가로채기 함수를 호출해야 합니다. 튜토리얼의 처음 코드에 이미 해당코드가 작성되어 있습니다. 비버퍼 입력방식에 있어서는 이것들만 하면 됩니다. 프레임마다 다양한 키보드 마우스 함수들을 이용해 객체들의 상태를 쿼리할 있습니다. 버퍼방식에서는 작성해야 코드가 약간 많습니다.

버퍼방식 입력을 위해서 입력처리용 클래스를 추가해야 합니다(또는 생성했던 FrameListener 직접 코드를 추가하는 방법도 있습니다). 버퍼방식 입력을 위해서 2가지 작업(createInputObject함수에서 true값을 넘기는 말고도 해야하는) 필요합니다. Listener 인터페이스를 구현하고 이벤트 콜백을 위해 생성한 클래스를 등록하는 입니다. 이전 튜토리얼에서 이러한 버퍼방식 입력을 위한 예제를 참고하실 있습니다. 코드가 바로 모든게 구현된 클래스 입니다 :

// Don't add this to the project

class BufferedInputHandler : public OIS::KeyListener, public OIS::MouseListener, public OIS::JoyStickListener

{

public:

    BufferedInputHandler(OIS::Keyboard *keyboard = 0, OIS::Mouse *mouse = 0, OIS::JoyStick *joystick = 0)

    {

        if (keyboard)

            keyboard->setEventCallback(this);

 

        if (mouse)

            mouse->setEventCallback(this);

 

        if (joystick)

            joystick->setEventCallback(this);

    }

 

    // KeyListener

    virtual bool keyPressed(const OIS::KeyEvent &arg) { return true; }

    virtual bool keyReleased(const OIS::KeyEvent &arg) { return true; }

 

    // MouseListener

    virtual bool mouseMoved(const OIS::MouseEvent &arg) { return true; }

    virtual bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; }

    virtual bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { return true; }

 

    // JoystickListener

    virtual bool buttonPressed(const OIS::JoyStickEvent &arg, int button) { return true; }

    virtual bool buttonReleased(const OIS::JoyStickEvent &arg, int button) { return true; }

    virtual bool axisMoved(const OIS::JoyStickEvent &arg, int axis) { return true; }

};

실제로 사용하게 부분만 Listener에서 구현해 쓰는 것을 권장합니다.

 

버퍼방식 입력에서의 문제점 해결

프로그램이 입력을 버퍼방식으로 입력받는게 생각처럼 안된다면 다음 사항들을 체크해 보세요 :

1.    InputManager::createInputObject 함수를 호출할때 버퍼방식설정(2번째 매개변수값) true값으로 설정 했습니까?

2.    각각의 입력객체들에 대해서 setEventCallback 함수를 호출해 줬습니까?

3.    다른 클래스에서 setEventCallback함수를 호출했습니까? (OIS 한개의 이벤트 콜백만 허용합니다. 하나의 입력객체를 위해 2 이상의 이벤트 콜백을 등록할 없습니다)

3가지 사항들을 체크했음에도 불구하고 문제가 발생한다면 help 포럼에 문의하세요.

 

CEGUI

CEGUI 오우거와 통합된 아주 유연한 GUI 라이브러리 입니다. 튜토리얼에서는 CEGUI 아무런 기능을 사용하지 않을 입니다. 단지 나중에 사용할때를 대비해서 어떻게 설정하는지만 간략하게 설명할 것입니다. CEGUI 그려져야 RenderWindow SceneManager 필요로 합니다. (NOTE: CEGUI 사용해서 에러메세지 없이 컴파일이 되기 위해서는 CEGUIBase_d.lib OgreGUIRenderer_d.lib linker>input>Additional Dependencies 추가하세요)

       SceneManager *mgr = mRoot->getSceneManager("Default SceneManager");

       RenderWindow *win = mRoot->getAutoCreatedWindow();

 

       // CEGUI setup

       mRenderer = new CEGUI::OgreCEGUIRenderer(win, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mgr);

       mSystem = new CEGUI::System(mRenderer);

했습니다. 이제 CEGUI 사용될 준비가 되었습니다. 만약 어플리케이션이 실행되는 도중에 SceneManager 바뀐다면(CEGUI 사용되는 도중에) CEGUI 새로운 SceneManager 이용해서 그릴 있도록 알려줘야 합니다. OgreCEGUIRenderer::setTargetSceneManager 그려질 SceneManager 바꿔줄 있습니다.

 

구동 마무리짓기와 Render 루프

Frame Listener

앞서서 우리는 렌더루프를 시작하고 프로그램을 실행시켰습니다. 그리고 프레임 리스너를 추가하고 프로그램에서 사용했습니다. 알아두실 지금까지는 아주 간단한 ExitListener 불리는 FrameListener 만들었다는 점입니다. 단순히 기다리다가 ESC키가 눌려지면 프로그램이 종료되었습니다. 실제 개발에 있어서는 아마도 많은 프레임리스너들이 복잡한 일들을 수행할 것입니다. ExitListener 훑어보시고 포함된 코드들이 어떤일을 수행하는지 모두 이해하셔야 합니다. 다음 아래코드를 createFrameListener함수에 추가하세요 :

       mListener = new ExitListener(mKeyboard);

       mRoot->addFrameListener(mListener);

 

The Render Loop

오우거가 시작되기위해 마지막으로 남은건 렌더 루프를 돌리는 일입니다. 작업은 무척 간단합니다. startRenderLoop함수를 찾아서 다음 코드를 추가하세요 :

       mRoot->startRendering();

FrameListener에서 false 리턴하기 전까지 계속해서 렌더링을 유지할 것입니다. 물론 한개 프레임만 뽑아낼 수도 있으며 원한다면 특정 프레임사이에서도 작업을 할수 있습니다. Root::renderOneFrame함수는 1개의 프레임을 그린 다음에 하나의 FrameListener에서라도 false 리턴한다면 false 리턴합니다 :

       // Do not add this to the application

       while (mRoot->renderOneFrame())

       {

           // Do some things here, like sleep for x milliseconds or perform other actions.

       }

그러나 생각으로는 당신은 어쩌면 while 루프안에 FrameListener 들어갈 코드를 여기에 대신 넣으려고 같습니다. 제가 생각하건데 이렇게 쓰는 방법으로는 밀리세컨동안 sleep시켜서 프레임재생율을 특정 수치로 임의적으로 낮추는 경우 입니다. 특별한 상황이 아닌 이상 그러한 작업을 FrameListener에서 하고 싶지는 않을겁니다. 왜냐하면 그렇게 하면 FrameEvent::timeSinceLastFrame 변수값이 엉망으로 꼬이거든요.

 

메모리 해제

이제 남은건 우리가 지금까지 만들었던모든 객체들을 프로그램종료와 동시에 깔끔히 치우는 일입니다. 기본적으로 객체들을 만들었던 순서의 반대순서로 삭제 또는 파괴시키면 됩니다. 작업은 OIS부터 시작합니다. OIS 입력용객체를 삭제시키는 특정한 함수를 가지고 있습니다. ~Application 함수에 다음 코드를 추가하세요 :

       mInputManager->destroyInputObject(mKeyboard);

       OIS::InputManager::destroyInputSystem(mInputManager);

CEGUI 해제시킬때는 객체만 지워주면 됩니다 :

       delete mRenderer;

       delete mSystem;

드디어 Root FrameListener 객체를 지울때 입니다. 다른 객체들 (SceneManager, RenderWindow, 기타등등) Root 삭제될때 같이 자동으로 삭제됩니다.

       delete mListener;

       delete mRoot;

입니다! 비록 아무런 객체도 추가되지 않은 검은화면뿐 이지만 이제 컴파일하고 실행시킬 있습니다. 컴파일시 Linker 에러가 발생되면 CEGUIBase_d.lib, OgreGUIRenderer_d.lib 파일들이 Linker 추가되었는지(디버그모드의 경우임. 릴리즈모드의 경우는 _d 부분을 빼고 추가) 확인하세요. 이제 여러분은 예제 프레임워크를 쓰지 않는 오우거의 Startup 프로세스에 익숙해 졌으리라 생각됩니다. 그러나 튜토리얼의 단순함을 위해 예제 프레임워크를 앞으로도 계속해서 사용할 계획입니다.

만약 예제 프레임워크의 다른부분에 궁금한 점이 있다면 심화 튜토리얼과정인 Example Framework Demystified(http://www.ogre3d.org/wiki/index.php/Example_Framework_Demystified) 참고하세요.

Trackback 0 : Comment 0

기초 튜토리얼 6-3 (마지막)

Ogre3D 삽질란/Basic Tutorial 6 2008/11/30 19:02

Mac OS X

Mac OS X 어플 번들(app bundles) 사용하므로 윈도우즈나 리눅스에서 쓰이는 코드와는 근본적으로 달라집니다. 위에서 설명한 코드들은 Mac OS X에서는 동작되지 않습니다.

*                   다음 코드를 추가하세요

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE

#include <CoreFoundation/CoreFoundation.h>

 

// This function will locate the path to our application on OS X,

// unlike windows you can not rely on the curent working directory

// for locating your configuration files and resources.

std::string macBundlePath()

{

    char path[1024];

    CFBundleRef mainBundle = CFBundleGetMainBundle();

    assert(mainBundle);

       

    CFURLRef mainBundleURL = CFBundleCopyBundleURL(mainBundle);

    assert(mainBundleURL);

       

    CFStringRef cfStringRef = CFURLCopyFileSystemPath( mainBundleURL, kCFURLPOSIXPathStyle);

    assert(cfStringRef);

       

    CFStringGetCString(cfStringRef, path, 1024, kCFStringEncodingASCII);

       

    CFRelease(mainBundleURL);

    CFRelease(cfStringRef);

       

    return std::string(path);

}

#endif

*                   부분을

mRoot = new Root();

이렇게 바꾸세요

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE

    mRoot = new Root(macBundlePath() + "/Contents/Resources/plugins.cfg");

#else

    mRoot = new Root();

#endif

*                   부분을

cf.load("resources.cfg");

이렇게 바꾸세요

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE

    cf.load(macBundlePath() + "/Contents/Resources/resources.cfg"); 

#else

    cf.load("resources.cfg");        

#endif

*                   부분을

ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName);

이렇게 바꾸세요

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE

    ResourceGroupManager::getSingleton().addResourceLocation( String(macBundlePath() + "/" + archName), typeName, secName);

#else

    ResourceGroupManager::getSingleton().addResourceLocation( archName, typeName, secName);

#endif

 

출처 : http://begin.pe.kr/category/Ogre3D%20삽질란/Basic%20Tutorial%206

신고
Posted by 우엉 여왕님!! ghostkyow