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; } Ну вот и все, наше приложение готово, можно запускать и пользоваться.
|
|
| |