lunes, 26 de mayo de 2008

Un ejemplo de IApplication

Con este artículo concluimos el bloque de la estructura de menus Irrlicht. Sin más preámbulos, vamos a ver el código y clases necesarias para tener una aplicación basica para nuestro proyecto.


Empezamos con el main, en la que instanciamos un objeto de tipo LSim.
#include <iostream>
#include "LSim.h"

using namespace std;

int main()
{
LSim *app = new LSim();
return app->mRun();
}


Yo no se vosotros, pero adoro los mains así de limpitos ;). La clase LSim es la encargada de instanciar el IrrlichtDevice. A su vez, instancia un objeto MainApplication (el menú principal) pasándole al constructor el device. A continuación vemos la declaracion de LSim.

class LSim
{
public:
LSim();
virtual ~LSim();
bool mRun();

protected methods:
bool mInit();
// bool Loop();

protected:
IrrlichtDevice *f_device;
MainApplication *mainApp;
};


Y su implementación. No pongo el constructor y destructor porque estan vacios.

bool
LSim::mRun()
{
if(!mInit()) return false;

mainApp = new MainApplication(f_device);
mainApp->mRun();
return true;
}

bool
LSim::mInit()
{
try
{
// create device and exit if creation failed
dimension2d<s32> resolucion(640,480);
bool fullScreen = false;
u32 bpp = 32;
f_device = createDevice(video::EDT_OPENGL, resolucion,bpp,fullScreen);
if (f_device == NULL) return false;
return true;
}
catch(std::exception &e)
{
std::cerr<<"Error: "<<e.what()<<std::endl;
}
return false;
}


Acabamos de ver cómo se llama a MainApplication. Veamos ahora la declaración de MainApplication.

class MainApplication : public IApplication
{
public:
MainApplication(IrrlichtDevice *device);
virtual ~MainApplication();
virtual bool mInit();
virtual bool mRemove();

//events
static void mButtonQuit_Click(void* o, const SEvent& event);
static void mButtonNewWindow_Click(void *o, const SEvent & event);
static void mButtonFileOpen_Click(void *o, const SEvent & event);
static void mScrollBar_Changed(void *o, const SEvent & event);

// static void mSubButton_Click(void *o, const SEvent & event);

static void mButtonAddLogo_Click(void* o, const SEvent& event);
static void mButtonRemoveLogo_Click(void *o, const SEvent & event);
static void mButtonLaunchEditor_Click(void *o, const SEvent & event);
static void mButtonLaunchSimulator_Click(void *o, const SEvent & event);

protected:
EditorApplication *f_editor;
SimulatorApplication *f_simulador;

//controls
IGUIContextMenu * f_menu;
IGUIButton *f_buttonQuit;
IGUIButton *f_buttonNewWindow;
IGUIButton *f_buttonFileOpen;
IGUIButton *f_buttonAddLogo;
IGUIButton *f_buttonRemoveLogo;
IGUIButton *f_buttonLaunchEditor;
IGUIButton *f_buttonLaunchSimulator;
IGUIStaticText *f_staticTextTransparentControl;
IGUIScrollBar *f_scrollbar;
IGUIStaticText *f_staticTextLogger;
IGUIListBox *f_listBoxLogger;
IGUISkin* f_skin;
IGUIFont* f_font;
IGUIImage* f_ImageLogo;
IGUIStaticText *f_staticTextFPS;
};


Observa como esta clase ya se asemeja a una formulario de M$Windows, con sus controles, eventos, etc. Además tiene dos objetos especialmente interesantes, el editor y el simulador, que también heredan de IApplication. De hecho, creo que tenia que haberlos declarado como IApplication, mea culpa. Veamos ahora la implementación. Sólo voy a poner los metodos importantes, mInit y mLoop, además de dos eventos importantes, los que lanzan al editor y al simulador respectivamente.

bool
MainApplication::mInit()
{
f_eventReceiver = new EventReceiver(this);
f_device->setEventReceiver(f_eventReceiver);

//Inicializacion de controles
f_menu = f_env->addMenu(0, f_genIDs->getNewID());
f_buttonQuit = f_env->addButton(rect<s32>(10,210,100,240), 0, f_genIDs->getNewID(), L"Quit");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonQuit->getID(), MainApplication::mButtonQuit_Click);
f_buttonNewWindow = f_env->addButton(rect<s32>(10,250,100,290), 0, f_genIDs->getNewID(), L"New Window");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonNewWindow->getID(), MainApplication::mButtonNewWindow_Click);
f_buttonFileOpen = f_env->addButton(rect<s32>(10,300,100,340), 0, f_genIDs->getNewID(), L"File Open");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonFileOpen->getID(), MainApplication::mButtonFileOpen_Click);

f_buttonAddLogo = f_env->addButton(rect<s32>(10,350,100,370), 0, f_genIDs->getNewID(), L"Add Logo");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonAddLogo->getID(), MainApplication::mButtonAddLogo_Click);
f_buttonRemoveLogo = f_env->addButton(rect<s32>(10,380,100,400), 0, f_genIDs->getNewID(), L"Remove Logo");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonRemoveLogo->getID(), MainApplication::mButtonRemoveLogo_Click);

f_buttonLaunchEditor = f_env->addButton(rect<s32>(10,410,100,430), 0, f_genIDs->getNewID(), L"Editor");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonLaunchEditor->getID(), MainApplication::mButtonLaunchEditor_Click);
f_buttonLaunchSimulator = f_env->addButton(rect<s32>(10,440,100,460), 0, f_genIDs->getNewID(), L"Simulator");
f_eventReceiver->mAddGuiEvent(EGET_BUTTON_CLICKED, f_buttonLaunchSimulator->getID(), MainApplication::mButtonLaunchSimulator_Click);

f_staticTextTransparentControl = f_env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true,true,0,f_genIDs->getNewID(),false);

f_scrollbar = f_env->addScrollBar(true,rect<s32>(150, 45, 350, 60), 0, f_genIDs->getNewID());
f_scrollbar->setMax(255);
f_scrollbar->setPos(127);
f_eventReceiver->mAddGuiEvent(EGET_SCROLL_BAR_CHANGED, f_scrollbar->getID(), MainApplication::mScrollBar_Changed);
f_staticTextLogger = f_env->addStaticText(L"Logging ListBox:", rect<s32>(50,80,250,100), true,true,0,f_genIDs->getNewID());

f_listBoxLogger = f_env->addListBox(rect<s32>(50, 110, 250, 180),0,f_genIDs->getNewID());

f_skin = f_env->getSkin();
f_font = f_env->getFont("media/fonthaettenschweiler.bmp");
if (f_font) f_skin->setFont(f_font);
f_ImageLogo= f_env->addImage(
f_driver->getTexture("media/irrlichtlogo.png"),
position2d<int>(f_driver->getScreenSize().Width - 128,f_driver->getScreenSize().Height- 105));

//Anyadimos el texto de los fps
f_staticTextFPS = f_env->addStaticText(L"", core::rect<s32>(10,10,100,26), true, false, 0,f_genIDs->getNewID());

// IGUIWindow* subventana = f_env->addWindow(rect<s32>(0,0,800,600), true,L"titulo de la subventana",0,2000);
// IGUIButton *subboton = f_env->addButton(rect<s32>(50,50,50+100,50+32), subventana, 2001, L"Quit");
return true;
}

bool
MainApplication::mRemove()
{
f_menu->remove();
f_buttonLaunchSimulator->remove();
f_buttonLaunchEditor->remove();
f_buttonQuit->remove();
f_buttonNewWindow->remove();
f_buttonFileOpen->remove();
f_buttonAddLogo->remove();
f_buttonRemoveLogo->remove();
f_staticTextTransparentControl->remove();
f_scrollbar->remove();
f_staticTextLogger->remove();
f_listBoxLogger->remove();
if(f_ImageLogo) f_ImageLogo->remove();
f_staticTextFPS->remove();
return true;
}

void
MainApplication::mButtonLaunchEditor_Click(void *o, const SEvent & event)
{
MainApplication* me = (MainApplication*)o;
me->mRemove();
me->f_editor = new EditorApplication(me->f_device);
me->f_editor->mRun();
me->mInit();
}

void
MainApplication::mButtonLaunchSimulator_Click(void *o, const SEvent & event)
{
MainApplication* me = (MainApplication*)o;
me->mRemove();
me->f_simulador = new SimulatorApplication(me->f_device);
me->f_simulador->mRun();
me->mInit();
}

El método mInit es el encargado de inicializar los controles y configurar a f_eventReceiver. Después de él, viene mRemove, encargado de retirar todos los controles y de asear el IrrlichtDevice. Esto lo hacemos así porque no podemos eliminar ni reasignar el objeto IGUIEnvironment del IrrlichtDevice, con lo que cada objeto IAplicación que recibe el IrrlichtDevice, pone sus controles y eventos y al terminar los quita del mismo.

Fijaos en los eventos que lanzan al editor y al simulador. Antes de instanciar, por ejemplo, el editor, se invoca a mRemove de MainApplication, para que al instanciar el editor, éste reciba el IrrlichrtDevice limpio y aseado. Tambien puede ocurrir que no sea necesario quitar todos los controles o incluso mantener algunos.

El EditorApplication y SimulatorApplication son parecidos a MainApplication, salvo que cada uno tendrá sus controles y funcionalidad.

Bueno, con esto hemos terminado el bloque de Estructura de menus Irrlicht. Conforme he ido escribiendo estas dos últimas entradas me he ido dando cuenta de algunos defetos de diseño, como el tema de IApplication como interfaz pura y otras interfaces que se podrían implementar. Será cuestion de corregislas.

Se me olvidaba deciros que en la cajita que tenemos de Box.Net hay un ejemplo que pusimos al principio de tener el blog. si lo pruebas podrás ver el menu principal y te permitira pasar al simulador o al editor. en el simulador presiona la tecla 'c' para liberar el puntero del raton y poder pulsar en el boton para volver al menú principal.

Un saludo.

No hay comentarios: