[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Форум » Игровые движки » IrrLicht Engine » Туториал №9 Просмотрщик моделей
Туториал №9 Просмотрщик моделей
MerGC_TeamДата: Четверг, 03.04.2014, 16:50 | Сообщение # 1
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
И так, в этом уроке мы создадим полноценное приложение во всех смыслах этой фразы. Мы создадим прогу для загрузки и просмотра 3D моделей используя движок IrrLicht, его API, GUI и менеджер сцены. В этом туториале мы научимся использовать кнопки, окна, панели кнопок, меню, выпадающие списки, табулированные панели, поля, изображения, диалоговые сообщения, скайбокс, а так же загружать XML файлы.
Начнем как обычно: подключим заголовочный файл, объявим пространства имен движка включенными по умолчанию.

Код
#include < irrlicht.h >
#include "driverChoice.h"

using namespace irr;
using namespace gui;

Глобальные переменные, которые мы будем использовать далее по коду
Код
IrrlichtDevice *Device = 0;
core::stringc StartUpModelFile;
core::stringw MessageText;
core::stringw Caption;
scene::ISceneNode* Model = 0;
scene::ISceneNode* SkyBox = 0;
bool Octree=false;
bool UseLight=false;

scene::ICameraSceneNode* Camera[2] = {0, 0};

// идентификаторы GUI элементов, по которым будем определять назначение элементов.
enum
{
   GUI_ID_DIALOG_ROOT_WINDOW  = 0x10000,

   GUI_ID_X_SCALE,
   GUI_ID_Y_SCALE,
   GUI_ID_Z_SCALE,

   GUI_ID_OPEN_MODEL,
   GUI_ID_SET_MODEL_ARCHIVE,
   GUI_ID_LOAD_AS_OCTREE,

   GUI_ID_SKY_BOX_VISIBLE,
   GUI_ID_TOGGLE_DEBUG_INFO,

   GUI_ID_DEBUG_OFF,
   GUI_ID_DEBUG_BOUNDING_BOX,
   GUI_ID_DEBUG_NORMALS,
   GUI_ID_DEBUG_SKELETON,
   GUI_ID_DEBUG_WIRE_OVERLAY,
   GUI_ID_DEBUG_HALF_TRANSPARENT,
   GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES,
   GUI_ID_DEBUG_ALL,

   GUI_ID_MODEL_MATERIAL_SOLID,
   GUI_ID_MODEL_MATERIAL_TRANSPARENT,
   GUI_ID_MODEL_MATERIAL_REFLECTION,

   GUI_ID_CAMERA_MAYA,
   GUI_ID_CAMERA_FIRST_PERSON,

   GUI_ID_POSITION_TEXT,

   GUI_ID_ABOUT,
   GUI_ID_QUIT,

   GUI_ID_TEXTUREFILTER,
   GUI_ID_SKIN_TRANSPARENCY,
   GUI_ID_SKIN_ANIMATION_FPS,

   GUI_ID_BUTTON_SET_SCALE,
   GUI_ID_BUTTON_SCALE_MUL10,
   GUI_ID_BUTTON_SCALE_DIV10,
   GUI_ID_BUTTON_OPEN_MODEL,
   GUI_ID_BUTTON_SHOW_ABOUT,
   GUI_ID_BUTTON_SHOW_TOOLBOX,
   GUI_ID_BUTTON_SELECT_ARCHIVE,

   // пара "волшебных" циферок
   MAX_FRAMERATE = 1000,
   DEFAULT_FRAMERATE = 30
};

Переключатель между камерами (у нас их будет две)

Код
void setActiveCamera(scene::ICameraSceneNode* newActive)
{
   if (0 == Device) return;

   scene::ICameraSceneNode * active = Device->getSceneManager()->getActiveCamera();
   active->setInputReceiverEnabled(false);

   newActive->setInputReceiverEnabled(true);
   Device->getSceneManager()->setActiveCamera(newActive);
}

Установка уровня прозрачности для элементов интерфейса

Код
void SetSkinTransparency(s32 alpha, irr::gui::IGUISkin * skin)
{
   for (s32 i=0; i<irr::gui::EGDC_COUNT ; ++i)
   {
  video::SColor col = skin->getColor((EGUI_DEFAULT_COLOR)i);
  col.setAlpha(alpha);
  skin->setColor((EGUI_DEFAULT_COLOR)i, col);
   }
}

Обновить масштаб модели на экране

Код
Обновить масштаб модели на экране

void UpdateScaleInfo(scene::ISceneNode* model)
{
   IGUIElement* toolboxWnd =
Device->getGUIEnvironment()->getRootGUIElement()->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true);
   if (!toolboxWnd)
  return;
   if (!model)
   {
  toolboxWnd->getElementFromId(GUI_ID_X_SCALE, true)->setText( L"-" );
  toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText( L"-" );
  toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText( L"-" );
   }
   else
   {
  core::vector3df scale = model->getScale();
  toolboxWnd->getElementFromId(GUI_ID_X_SCALE, true)->setText( core::stringw(scale.X).c_str() );
  toolboxWnd->getElementFromId(GUI_ID_Y_SCALE, true)->setText( core::stringw(scale.Y).c_str() );
  toolboxWnd->getElementFromId(GUI_ID_Z_SCALE, true)->setText( core::stringw(scale.Z).c_str() );
   }
}

Следующие три функции - это первая showAboutText() отображающая окно сообщения с заголовком и текстом. Тексты хранятся в переменных MessageText и Caption с момента загрузки

Код
void showAboutText()
{
   // модальное окно с сообщением
   // сообщения предварительно загружены из xml файла.
   Device->getGUIEnvironment()->addMessageBox( Caption.c_str(), MessageText.c_str() );
}

вторая loadModel() - загружает модель и отображает ее на экране, используя addAnimatedMeshSceneNode. Если модель не загружена, выводит окно с сообщением об этом.

Код
void loadModel(const c8* fn)
{
   // по расширению определяем тип файла

   core::stringc filename(fn);

   core::stringc extension;
   core::getFileNameExtension(extension, filename);
   extension.make_lower();

   // если запрошена текструра, то грузим и применяем ее к модели, если конечно модель загружена и выходим.
   if (extension == ".jpg" || extension == ".pcx" ||
  extension == ".png" || extension == ".ppm" ||
  extension == ".pgm" || extension == ".pbm" ||
  extension == ".psd" || extension == ".tga" ||
  extension == ".bmp" || extension == ".wal" ||
  extension == ".rgb" || extension == ".rgba")
   {
  video::ITexture * texture = Device->getVideoDriver()->getTexture( filename );
  if ( texture && Model )
  {
// текстуру перегружаем в любом случае
Device->getVideoDriver()->removeTexture(texture);
texture = Device->getVideoDriver()->getTexture( filename );

Model->setMaterialTexture(0, texture);
  }
  return;
   }
   // если запрошен архив, то добавляем архив в список архивов (FileArchive) и выходим.
   else if (extension == ".pk3" || extension == ".zip" || extension == ".pak" || extension == ".npk")
   {
  Device->getFileSystem()->addFileArchive(filename.c_str());
  return;
   }

   // Выгружаем модель. Если грузиться .irr (модель сцены),
   // то грузим сцену и выходим или грузим файл как обычную модель

   if (Model) Model->remove();

   Model = 0;

   if (extension==".irr")
   {
  core::array outNodes;
  Device->getSceneManager()->loadScene(filename);
  Device->getSceneManager()->getSceneNodesFromType(scene::ESNT_ANIMATED_MESH, outNodes);
  if (outNodes.size()) Model = outNodes[0];
  return;
   }

   scene::IAnimatedMesh* m = Device->getSceneManager()->getMesh( filename.c_str() );

   if (!m)
   {
  // модель не загружена

  if (StartUpModelFile != filename)
Device->getGUIEnvironment()->addMessageBox(  
Caption.c_str(),
L"The model could not be loaded.n Maybe it is not a supported file format.");
  return;
   }

   // опции материала для модели по умолчанию

   if (Octree)
  Model = Device->getSceneManager()->addOctreeSceneNode(m->getMesh(0));
   else
   {
  scene::IAnimatedMeshSceneNode* animModel =  
   Device->getSceneManager()->addAnimatedMeshSceneNode(m);
  animModel->setAnimationSpeed(30);
  Model = animModel;
   }
   Model->setMaterialFlag(video::EMF_LIGHTING, UseLight);
   Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, UseLight);
//Model->setMaterialFlag(video::EMF_BACK_FACE_CULLING, false);
   Model->setDebugDataVisible(scene::EDS_OFF);

   // мы должны сбросить все выбранные пункты в меню,
   // было бы не плохо организовать это через события,
   // но это сложновато, поэтому не будет огород городить
   gui::IGUIContextMenu* menu =  
  (gui::IGUIContextMenu*)
  Device->getGUIEnvironment()->
getRootGUIElement()->getElementFromId(GUI_ID_TOGGLE_DEBUG_INFO, true);
   if (menu)
  for(int item = 1; item < 6; ++item)
menu->setItemChecked(item, false);
   UpdateScaleInfo(Model);
}

Третья функция создает окно для инструментов. Окно будет включать в себя табулированные панели с интерфейсными элементы, позволяюще манипулировать характеристиками модели на экране.

Код
void createToolBox()
{
   // удаляем окно иструментов, если оно уже создано
   IGUIEnvironment* env = Device->getGUIEnvironment();
   IGUIElement* root = env->getRootGUIElement();
   IGUIElement* e = root->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true);
   if (e) e->remove();

   // создаем новое окно
   IGUIWindow* wnd =  
  env->addWindow(core::rect< s32 >(600,45,800,480), false, L"Toolset", 0, GUI_ID_DIALOG_ROOT_WINDOW);

   // создаем табулируемую панель и с помощью addTab вкладки на ней
   IGUITabControl* tab = env->addTabControl( core::rect< s32 >(2,20,800-602,480-7), wnd, true, true );

   IGUITab* t1 = tab->addTab(L"Config");

   // добавляем на вкладку управляющие элементы и метки к ним
   env->addStaticText(L"Scale:", core::rect< s32 >(10,20,60,45), false, false, t1);
   env->addStaticText(L"X:", core::rect< s32 >(22,48,40,66), false, false, t1);
   env->addEditBox(L"1.0", core::rect< s32 >(40,46,130,66), true, t1, GUI_ID_X_SCALE);
   env->addStaticText(L"Y:", core::rect< s32 >(22,82,40,GUI_ID_OPEN_MODEL), false, false, t1);
   env->addEditBox(L"1.0", core::rect< s32 >(40,76,130,96), true, t1, GUI_ID_Y_SCALE);
   env->addStaticText(L"Z:", core::rect< s32 >(22,108,40,126), false, false, t1);
   env->addEditBox(L"1.0", core::rect< s32 >(40,106,130,126), true, t1, GUI_ID_Z_SCALE);

   env->addButton(core::rect< s32 >(10,134,85,165), t1, GUI_ID_BUTTON_SET_SCALE, L"Set");

   // кнопки 10и кратного маштабирования в плюс и минус
   env->addButton(core::rect< s32 >(65,20,95,40), t1, GUI_ID_BUTTON_SCALE_MUL10, L"* 10");
   env->addButton(core::rect< s32 >(100,20,130,40), t1, GUI_ID_BUTTON_SCALE_DIV10, L"* 0.1");

   UpdateScaleInfo(Model);

   // элемент контроля прозрачности
   env->addStaticText(L"GUI Transparency Control:", core::rect< s32 >(10,200,150,225), true, false, t1);
   IGUIScrollBar* scrollbar =  
   env->addScrollBar(true, core::rect< s32 >(10,225,150,240), t1, GUI_ID_SKIN_TRANSPARENCY);
   scrollbar->setMax(255);
   scrollbar->setPos(255);

   // контроль частоты кадров
   env->addStaticText(L"Framerate:", core::rect< s32 >(10,240,150,265), true, false, t1);
   scrollbar = env->addScrollBar(true, core::rect< s32 >(10,265,150,280), t1, GUI_ID_SKIN_ANIMATION_FPS);
   scrollbar->setMax(MAX_FRAMERATE);
   scrollbar->setMin(-MAX_FRAMERATE);
   scrollbar->setPos(DEFAULT_FRAMERATE);

   // вытаскиваем лого IrrLicht-а на поверхность
   // т.к. вновь созданное окно перекроет его
   root->bringToFront(root->getElementFromId(666, true));
}

Пишем обработчик событий. Если событие возникает, мы по идентификатору элемента (список идентификторов мы объявили чуть ранее) определяем как обрабатывает событие. Для примера, если будет выбран пункт меню с идентификтором GUI_ID_OPEN_MODEL, то мы вызовем функцию создающую диалоговое окно для выбора файлов.

Код
class MyEventReceiver : public IEventReceiver
{
public:
   virtual bool OnEvent(const SEvent& event)
   {
  // Если произошло событие клавиатуры и это было отжатие кнопки,
  // то вызываем обработчик клавиатуры OnKeyUp
  if (event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown == false)
  {
if ( OnKeyUp(event.KeyInput.Key) ) return true;
  }

  if (event.EventType == EET_GUI_EVENT)
  {
s32 id = event.GUIEvent.Caller->getID();
IGUIEnvironment* env = Device->getGUIEnvironment();

switch(event.GUIEvent.EventType)
{
case EGET_MENU_ITEM_SELECTED:
  // событие при котором был выбран пункт меню,
  // вызываем обработчик OnMenuItemSelect
  OnMenuItemSelected( (IGUIContextMenu*)event.GUIEvent.Caller );
   break;

case EGET_FILE_SELECTED:
   {
  // в открытом ранее окне диалога выбора файлов был выбран файл
  IGUIFileOpenDialog* dialog = (IGUIFileOpenDialog*)event.GUIEvent.Caller;
  loadModel(core::stringc(dialog->getFileName()).c_str());
   }
   break;

case EGET_SCROLL_BAR_CHANGED:

   // событие полосы прогрутки, отвечающей за прозрачность интерфейса
   if (id == GUI_ID_SKIN_TRANSPARENCY)
   {
  const s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
  SetSkinTransparency(pos, env->getSkin());
   }
   // событие полосы прокрутки, отвечающей за скорость проигрывания анимации
   else if (id == GUI_ID_SKIN_ANIMATION_FPS)
   {
  const s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
  if (scene::ESNT_ANIMATED_MESH == Model->getType())
((scene::IAnimatedMeshSceneNode*)Model)->setAnimationSpeed((f32)pos);
   }
   break;

case EGET_COMBO_BOX_CHANGED:

   // событие выпадающего списка, вызываем обработчик
   // отвечающий за выбор фильтрации текстур
   if (id == GUI_ID_TEXTUREFILTER)
   {
  OnTextureFilterSelected( (IGUIComboBox*)event.GUIEvent.Caller );
   }
   break;

case EGET_BUTTON_CLICKED:

   switch(id)
   {
   case GUI_ID_BUTTON_SET_SCALE:
  {
// были нажаты кнопки маштабирования
gui::IGUIElement* root = env->getRootGUIElement();
core::vector3df scale;
core::stringc s;

s = root->getElementFromId(GUI_ID_X_SCALE, true)->getText();
scale.X = (f32)atof(s.c_str());
s = root->getElementFromId(GUI_ID_Y_SCALE, true)->getText();
scale.Y = (f32)atof(s.c_str());
s = root->getElementFromId(GUI_ID_Z_SCALE, true)->getText();
scale.Z = (f32)atof(s.c_str());

if (Model) Model->setScale(scale);
UpdateScaleInfo(Model);
  }
  break;
   case GUI_ID_BUTTON_SCALE_MUL10:
  if (Model) Model->setScale(Model->getScale()*10.f);
  UpdateScaleInfo(Model);
  break;
   case GUI_ID_BUTTON_SCALE_DIV10:
  if (Model) Model->setScale(Model->getScale()*0.1f);
  UpdateScaleInfo(Model);
  break;
   case GUI_ID_BUTTON_OPEN_MODEL:
  env->addFileOpenDialog(L"Please select a model file to open");
  break;
   case GUI_ID_BUTTON_SHOW_ABOUT:
  showAboutText();
  break;
   case GUI_ID_BUTTON_SHOW_TOOLBOX:
  createToolBox();
  break;
   case GUI_ID_BUTTON_SELECT_ARCHIVE:
  env->addFileOpenDialog(L"Please select your game archive/directory");
  break;
   }

   break;
default:
   break;
}
  }

  return false;
   }

***
 
MerGC_TeamДата: Четверг, 03.04.2014, 16:51 | Сообщение # 2
Веселый админ
Группа: Администраторы
Сообщений: 32
Статус: Оффлайн
***
Обрабатываем события клавиатуры

Код
bool OnKeyUp(irr::EKEY_CODE keyCode)
   {
  if (keyCode == irr::KEY_ESCAPE)
  {
if (Device)
{
   scene::ICameraSceneNode * camera = Device->getSceneManager()->getActiveCamera();
   if (camera)
   {
  camera->setInputReceiverEnabled( !camera->isInputReceiverEnabled() );
   }
   return true;
}
  }
  else if (keyCode == irr::KEY_F1)
  {
if (Device)
{
   IGUIElement* elem =  
  Device->getGUIEnvironment()->
  getRootGUIElement()->getElementFromId(GUI_ID_POSITION_TEXT);
   if (elem) elem->setVisible(!elem->isVisible());
}
  }
  else if (keyCode == irr::KEY_KEY_M)
  {
if (Device) Device->minimizeWindow();
  }
  else if (keyCode == irr::KEY_KEY_L)
  {
UseLight=!UseLight;
if (Model)
{
   Model->setMaterialFlag(video::EMF_LIGHTING, UseLight);
   Model->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, UseLight);
}
  }
  return false;
   }

Обрабатываем события для пунктов меню.

Код
void OnMenuItemSelected( IGUIContextMenu* menu )
   {
  s32 id = menu->getItemCommandId(menu->getSelectedItem());
  IGUIEnvironment* env = Device->getGUIEnvironment();

  switch(id)
  {
  case GUI_ID_OPEN_MODEL: // File -> Open Model (диалог выбора модели для загрузки)
env->addFileOpenDialog(L"Please select a model file to open");
break;
  case GUI_ID_SET_MODEL_ARCHIVE: // File -> Set Model Archive (диалог выбора архива с моделями)
env->addFileOpenDialog(L"Please select your game archive/directory");
break;
  case GUI_ID_LOAD_AS_OCTREE: // File -> LoadAsOctree (Флаг: загружать модели как Octree)
Octree = !Octree;
menu->setItemChecked(menu->getSelectedItem(), Octree);
break;
  case GUI_ID_QUIT: // File -> Quit (выход из программы)
Device->closeDevice();
break;
  case GUI_ID_SKY_BOX_VISIBLE: // View -> Skybox (флаг видимости скайбокса)
menu->setItemChecked(menu->getSelectedItem(),  
!menu->isItemChecked(menu->getSelectedItem()));
SkyBox->setVisible(!SkyBox->isVisible());
break;
  case GUI_ID_DEBUG_OFF: // View -> Debug Information (флаг скрывающий отладочное инфо)
menu->setItemChecked(menu->getSelectedItem()+1, false);
menu->setItemChecked(menu->getSelectedItem()+2, false);
menu->setItemChecked(menu->getSelectedItem()+3, false);
menu->setItemChecked(menu->getSelectedItem()+4, false);
menu->setItemChecked(menu->getSelectedItem()+5, false);
menu->setItemChecked(menu->getSelectedItem()+6, false);
if (Model) Model->setDebugDataVisible(scene::EDS_OFF);
break;
  case GUI_ID_DEBUG_BOUNDING_BOX: // View -> Debug Information (видимость boundingbox модели)
menu->setItemChecked(menu->getSelectedItem(),  
  !menu->isItemChecked(menu->getSelectedItem()));
if (Model) Model->setDebugDataVisible(
(scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_BBOX));
break;
  case GUI_ID_DEBUG_NORMALS: // View -> Debug Information (флаг видимости нормалей)
menu->setItemChecked(menu->getSelectedItem(),  
  !menu->isItemChecked(menu->getSelectedItem()));
if (Model) Model->setDebugDataVisible(
  (scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_NORMALS));
break;
  case GUI_ID_DEBUG_SKELETON: // View -> Debug Information (флаг видимости скелета модели)
menu->setItemChecked(menu->getSelectedItem(),  
  !menu->isItemChecked(menu->getSelectedItem()));
if (Model) Model->setDebugDataVisible(
  (scene::E_DEBUG_SCENE_TYPE)(Model->isDebugDataVisible()^scene::EDS_SKELETON));
break;
  case GUI_ID_DEBUG_WIRE_OVERLAY: // View -> Debug Information (проволочный режим wireframe)
menu->setItemChecked(menu->getSelectedItem(),  
  !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
  Model->setDebugDataVisible(
   (scene::E_DEBUG_SCENE_TYPE)
(Model->isDebugDataVisible()^scene::EDS_MESH_WIRE_OVERLAY));
break;
  case GUI_ID_DEBUG_HALF_TRANSPARENT: // View -> Debug Information (использование прозрачности)
menu->setItemChecked(menu->getSelectedItem(),
   !menu->isItemChecked(menu->getSelectedItem()));
if (Model)
  Model->setDebugDataVisible(
   (scene::E_DEBUG_SCENE_TYPE)
(Model->isDebugDataVisible()^scene::EDS_HALF_TRANSPARENCY));
break;
  case GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES: // View -> Debug Info (boundingbox верш. буферов)
menu->setItemChecked(menu->getSelectedItem(),
  !menu->isItemChecked(menu->getSelectedItem()));
if (Model) Model->setDebugDataVisible(
   (scene::E_DEBUG_SCENE_TYPE)
(Model->isDebugDataVisible()^scene::EDS_BBOX_BUFFERS));
break;
  case GUI_ID_DEBUG_ALL: // View -> Debug Information (флаг вывода всей отладочной инфы)
menu->setItemChecked(menu->getSelectedItem()-1, true);
menu->setItemChecked(menu->getSelectedItem()-2, true);
menu->setItemChecked(menu->getSelectedItem()-3, true);
menu->setItemChecked(menu->getSelectedItem()-4, true);
menu->setItemChecked(menu->getSelectedItem()-5, true);
menu->setItemChecked(menu->getSelectedItem()-6, true);
if (Model) Model->setDebugDataVisible(scene::EDS_FULL);
break;
  case GUI_ID_ABOUT: // Help->About (о программе)
showAboutText();
break;
  case GUI_ID_MODEL_MATERIAL_SOLID: // View -> Material -> Solid (сплошной материал)
if (Model) Model->setMaterialType(video::EMT_SOLID);
break;
  case GUI_ID_MODEL_MATERIAL_TRANSPARENT: // View -> Material -> Transparent (прозрачный материал)
if (Model) Model->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
break;
  case GUI_ID_MODEL_MATERIAL_REFLECTION: // View -> Material -> Reflection (отражающий материал)
if (Model) Model->setMaterialType(video::EMT_SPHERE_MAP);
break;

  case GUI_ID_CAMERA_MAYA:
setActiveCamera(Camera[0]);
break;
  case GUI_ID_CAMERA_FIRST_PERSON:
setActiveCamera(Camera[1]);
break;
  }
   }

Обрабатываем событие выбора фильтрации текстур.

Код
void OnTextureFilterSelected( IGUIComboBox* combo )
   {
  s32 pos = combo->getSelected();
  switch (pos)
  {
case 0:
if (Model)
{
   Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
   Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false);
   Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false);
}
break;
case 1:
if (Model)
{
   Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
   Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, false);
}
break;
case 2:
if (Model)
{
   Model->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
   Model->setMaterialFlag(video::EMF_TRILINEAR_FILTER, true);
}
break;
case 3:
if (Model)
{
   Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, true);
}
break;
case 4:
if (Model)
{
   Model->setMaterialFlag(video::EMF_ANISOTROPIC_FILTER, false);
}
break;
  }
   }
};

Основная работа завершена. Теперь как обычно создаем движок, создаем интерфейс, присваеваем наш обработчик событий. Из новенького вызов IrrlichtDevice::setResizeable(), который позволяет менять размер окна приложения.

Код
int main(int argc, char* argv[])
{
   // Запрашиваем драйвер (DirectX, OpenGL и т.д.)
   video::E_DRIVER_TYPE driverType=driverChoiceConsole();
   if (driverType==video::EDT_COUNT) return 1;

   // создаем корневой объект(движок) с указанием обработчика событий
   MyEventReceiver receiver;
   Device = createDevice(driverType, core::dimension2d< u32 >(800, 600), 16, false, false, false, &receiver);

   if (Device == 0) return 1; // ошибка при создании движка, выходим.

   Device->setResizable(true);

   Device->setWindowCaption(L"Irrlicht Engine - Loading...");

   video::IVideoDriver* driver = Device->getVideoDriver();
   IGUIEnvironment* env = Device->getGUIEnvironment();
   scene::ISceneManager* smgr = Device->getSceneManager();
   smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true);

   driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);

   smgr->addLightSceneNode(0, core::vector3df(200,200,200), video::SColorf(1.0f,1.0f,1.0f),2000);
   smgr->setAmbientLight(video::SColorf(0.3f,0.3f,0.3f));
   // добавляем путь к медиаконтенту приложения
   Device->getFileSystem()->addFolderFileArchive("../../media/");

Грузим конфигурационный файл, который выглядит примерно так:

Код
< ?xml version="1.0"? >
< config >
< startUpModel file="some filename" / >

< messageText caption="Irrlicht Engine Mesh Viewer" >
Hello!
< /messageText >
< /config >

И переписываем значения из файла конфигурации в наши глобальные переменные:

Код
// читаем конфиг в xml формате

   io::IXMLReader* xml = Device->getFileSystem()->createXMLReader( L"config.xml");

   while(xml && xml->read())
   {
  switch(xml->getNodeType())
  {
  case io::EXN_TEXT:
// текстовые собщения
MessageText = xml->getNodeData();
break;
  case io::EXN_ELEMENT:
{
   if (core::stringw("startUpModel") == xml->getNodeName())
  StartUpModelFile = xml->getAttributeValue(L"file");
   else
   if (core::stringw("messageText") == xml->getNodeName())
  Caption = xml->getAttributeValue(L"caption");
}
break;
  default:
break;
  }
   }

   if (xml) xml->drop(); // удаляем загручик/парсер конфигурационного файла

   if (argc > 1) StartUpModelFile = argv[1];

Теперь грузим шрифты, создаем меню со всеми подменю. Памятка: меню добавляется вызовом menu->addItem(L"File", -1, true, true); который добавить меню "File" с идентификтором -1, доступное для выбора (первый true) и имеющий подменю (второй true). Чтобы получить список подменю в меню "File" надо вызвать menu->getSubMenu(0), т.к. идентификтор для меню "File" будет определенным по уполчанию и равным 0.
Код
// ставим шрифт по красивши встроенного

   IGUISkin* skin = env->getSkin();
   IGUIFont* font = env->getFont("fonthaettenschweiler.bmp");
   if (font) skin->setFont(font);

   // создаем меню
   gui::IGUIContextMenu* menu = env->addMenu();
   menu->addItem(L"File", -1, true, true);
   menu->addItem(L"View", -1, true, true);
   menu->addItem(L"Camera", -1, true, true);
   menu->addItem(L"Help", -1, true, true);

   gui::IGUIContextMenu* submenu;
   submenu = menu->getSubMenu(0);
   submenu->addItem(L"Open Model File & Texture...", GUI_ID_OPEN_MODEL);
   submenu->addItem(L"Set Model Archive...", GUI_ID_SET_MODEL_ARCHIVE);
   submenu->addItem(L"Load as Octree", GUI_ID_LOAD_AS_OCTREE);
   submenu->addSeparator();
   submenu->addItem(L"Quit", GUI_ID_QUIT);

   submenu = menu->getSubMenu(1);
   submenu->addItem(L"sky box visible", GUI_ID_SKY_BOX_VISIBLE, true, false, true);
   submenu->addItem(L"toggle model debug information", GUI_ID_TOGGLE_DEBUG_INFO, true, true);
   submenu->addItem(L"model material", -1, true, true );

   submenu = submenu->getSubMenu(1);
   submenu->addItem(L"Off", GUI_ID_DEBUG_OFF);
   submenu->addItem(L"Bounding Box", GUI_ID_DEBUG_BOUNDING_BOX);
   submenu->addItem(L"Normals", GUI_ID_DEBUG_NORMALS);
   submenu->addItem(L"Skeleton", GUI_ID_DEBUG_SKELETON);
   submenu->addItem(L"Wire overlay", GUI_ID_DEBUG_WIRE_OVERLAY);
   submenu->addItem(L"Half-Transparent", GUI_ID_DEBUG_HALF_TRANSPARENT);
   submenu->addItem(L"Buffers bounding boxes", GUI_ID_DEBUG_BUFFERS_BOUNDING_BOXES);
   submenu->addItem(L"All", GUI_ID_DEBUG_ALL);

   submenu = menu->getSubMenu(1)->getSubMenu(2);
   submenu->addItem(L"Solid", GUI_ID_MODEL_MATERIAL_SOLID);
   submenu->addItem(L"Transparent", GUI_ID_MODEL_MATERIAL_TRANSPARENT);
   submenu->addItem(L"Reflection", GUI_ID_MODEL_MATERIAL_REFLECTION);

   submenu = menu->getSubMenu(2);
   submenu->addItem(L"Maya Style", GUI_ID_CAMERA_MAYA);
   submenu->addItem(L"First Person", GUI_ID_CAMERA_FIRST_PERSON);

   submenu = menu->getSubMenu(3);
   submenu->addItem(L"About", GUI_ID_ABOUT);

Ниже меню создаем панель кнопок.
Код
// создаем панель и добавляем на нее кнопки

   gui::IGUIToolBar* bar = env->addToolBar();

   video::ITexture* image = driver->getTexture("open.png");
   bar->addButton(GUI_ID_BUTTON_OPEN_MODEL, 0, L"Open a model",image, 0, false, true);

   image = driver->getTexture("tools.png");
   bar->addButton(GUI_ID_BUTTON_SHOW_TOOLBOX, 0, L"Open Toolset",image, 0, false, true);

   image = driver->getTexture("zip.png");
   bar->addButton(GUI_ID_BUTTON_SELECT_ARCHIVE, 0, L"Set Model Archive",image, 0, false, true);

   image = driver->getTexture("help.png");
   bar->addButton(GUI_ID_BUTTON_SHOW_ABOUT, 0, L"Open Help", image, 0, false, true);

   // создаем выпадающий список для выбора режимов фильтрации текстур

   gui::IGUIComboBox* box = env->addComboBox(core::rect< 32 >(250,4,350,23), bar, GUI_ID_TEXTUREFILTER);
   box->addItem(L"No filtering");
   box->addItem(L"Bilinear");
   box->addItem(L"Trilinear");
   box->addItem(L"Anisotropic");
   box->addItem(L"Isotropic");

Отключаем прозрачность интерфейса (меняя альфа канал его элементов), помещаем на экран логотип движка и начинаем в заголовке отображать частоту кадров.

Код
// отключаем прозрачность

   for (s32 i=0; i<gui::EGDC_COUNT ; ++i)
   {
  video::SColor col = env->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
  col.setAlpha(255);
  env->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
   }

   // добавляем окно(панель) инструментов

   createToolBox();

   // добавляем метку в которой будем отображать частоту кадров и метку для координат камеры и ее цели
   IGUIStaticText* fpstext = env->addStaticText(L"", core::rect< s32 >(400,4,570,23), true, false, bar);
   IGUIStaticText* postext =  
  env->addStaticText(L"", core::rect< s32 >(10,50,470,80),false, false, 0, GUI_ID_POSITION_TEXT);
   postext->setVisible(false);

   // заголовок окна (имя используемого драйвера + текст загруженный из конфига)

   Caption += " - [";
   Caption += driver->getName();
   Caption += "]";
   Device->setWindowCaption(Caption.c_str());

Ну вот - последние штрихи.

Код
// отображаем сообщение "о программе..." и грузим модель по умолчанию
   if (argc==1) showAboutText();
   loadModel(StartUpModelFile.c_str());

   // добавляем скайбокс

   SkyBox = smgr->addSkyBoxSceneNode(
  driver->getTexture("irrlicht2_up.jpg"),
  driver->getTexture("irrlicht2_dn.jpg"),
  driver->getTexture("irrlicht2_lf.jpg"),
  driver->getTexture("irrlicht2_rt.jpg"),
  driver->getTexture("irrlicht2_ft.jpg"),
  driver->getTexture("irrlicht2_bk.jpg"));

   // добавляем пару камер и активной делаем камеру Майя-типа
   Camera[0] = smgr->addCameraSceneNodeMaya();
   Camera[0]->setFarValue(20000.f);
   // Камера Maya позиционирует себя относительно своей цели
   // т.е. места где находиться модель.
   Camera[0]->setTarget(core::vector3df(0,30,0));

   Camera[1] = smgr->addCameraSceneNodeFPS();
   Camera[1]->setFarValue(20000.f);
   Camera[1]->setPosition(core::vector3df(0,0,-70));
   Camera[1]->setTarget(core::vector3df(0,30,0));

   setActiveCamera(Camera[0]);

   // грузим логотип irrlicht и добавляем на сцену
   IGUIImage *img = env->addImage(
driver->getTexture("irrlichtlogo2.png"), core::position2d< s32 >(10, driver->getScreenSize().Height - 128));

   // "магнитим" логотип к нижнему левому углу экрана
   img->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);

   // начинаем рисовать в цикле сцену

   while(Device->run() && driver)
   {
  if (Device->isWindowActive())
  {
driver->beginScene(true, true, video::SColor(150,50,50,50));

smgr->drawAll();
env->drawAll();

driver->endScene();

core::stringw str(L"FPS: ");
str.append(core::stringw(driver->getFPS()));
str += L" Tris: ";
str.append(core::stringw(driver->getPrimitiveCountDrawn()));
fpstext->setText(str.c_str());

scene::ICameraSceneNode* cam = Device->getSceneManager()->getActiveCamera();
str = L"Pos: ";
str.append(core::stringw(cam->getPosition().X));
str += L" ";
str.append(core::stringw(cam->getPosition().Y));
str += L" ";
str.append(core::stringw(cam->getPosition().Z));
str += L" Tgt: ";
str.append(core::stringw(cam->getTarget().X));
str += L" ";
str.append(core::stringw(cam->getTarget().Y));
str += L" ";
str.append(core::stringw(cam->getTarget().Z));
postext->setText(str.c_str());
  }
  else
Device->yield();
   }

   Device->drop();
   return 0;
}

  Ну вот и все, наше приложение готово, можно запускать и пользоваться.
 
Форум » Игровые движки » IrrLicht Engine » Туториал №9 Просмотрщик моделей
  • Страница 1 из 1
  • 1
Поиск: