IrrlichtСтатьи

2 часть перевода Example 009 Mesh Viewer

Автор:

Итак, большая часть тяжёлой работы выполнена. Мы только лишь должны создать устройства Движка Иррлихт и все кнопки, меню и панели инструментов. Мы запускаем движок как обычно, используя createDevice(). Чтобы научить наше приложение перехватывать события, мы установим наш eventreceiver (получатель событий) как параметр. Как вы видите, здесь имеется вызов IrrlichtDevice::setResizeable(). Эта функция разрешает пользователю изменять размер окна рендеринга, что является весьма полезным для нашего просмотрщика сеток.

int main(int argc, char* argv[])
{
  //Спросить пользователя про драйвер
  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));
  //Добавить нашу медиа директорию как "search path"(путь поиска)
  Device->getFileSystem()->addFolderFileArchive("../../media/");

  /*
  Следующим шагом будет прочитать файл конфигурации. Информация 
  хранится в формате xml и выглядит похожей на это:

  @verbatim
  <?xml version="1.0"?>
  <config>
    <startUpModel file="some filename" />
    <messageText caption="Irrlicht Engine Mesh Viewer">
      Hello!
    </messageText>
  </config>
  @endverbatim

  Нам необходимо данные хранящиеся там записать в глобальные переменные
  StartUpModelFile, MessageText и Caption. Сейчас мы сделаем это с помощь
  интегрированного вДвижок Иррлихт XML парсера:
  */

  //Считать конфигурацию из XML файла

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

  while(xml && xml->read())
  {
    switch(xml->getNodeType())
    {
    case io::EXN_TEXT:
      //В этом xml файле,только текст, который нужен для
      //messageText
      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(); // не забудьте удалить xml ридер

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

  /*
  Это было не сложно. Теперь мы установим симпатичный шрифт 
  и создадим меню.
  Возможно создавать подменю для каждого пункта меню. Вызов
  menu->addItem(L"File", -1, true, true); для пример добавляет новый 
  пункт меню с именем "File" и id(идентификатором) -1. Следующий
  параметр говорит что пункт меню enabled(активен), и последний 
  парметр говорит, что этот пункт следует как подменю. Подменю
  теперь доступно по обращению 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);

  /*
  Ниже меню мы создадим панель инструментов, на которой мы 
  можем разместить цветные кнопки и смотрящиеся важными 
  вещи, такие как бессмысленный combobox(выпадающий список).
  */

  //Создать панель инструментов

  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);

  //Создать combobox(выпадающий список) с некоторым бессмысленным текстом

  gui::IGUIComboBox* box = env->addComboBox(core::rect<s32>(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");

  /*
  Чтобы смастерить редактор выглядящим немного получше, мы отключим
  прозрачность GUI элементов меню, и добавим логотип Движка Иррлихт. 
  В добавок, создадим текст с указанием текущего кадра в секунду(FPS)
  и установим его в заголовке окна.
  */

  // disable alpha

  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();

  //Создать FPS текст

  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());

  /*
  Это уже почти всё приложение. Мы просто покажем окно с
  сообщением при запуске, и загрузим 1 модель. Чтобы всё 
  смотрелось получше, создадим skybox(небесный ящик) и 
  и контролируемую пользователем камеру, чтобы сделать
  приложение немного более интерактивным. Наконец, всё 
  отрисовываем в стандартном цикле отрисовки.
  */

  //Показать message box(окошко сообщения) 
  //и загрузить модель по умолчанию
  if (argc==1)
    showAboutText();
  loadModel(StartUpModelFile.c_str());

  //Добавить skybox(небесный ящик)

  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]);

  //Загрузить логотип Движка Иррлихт
  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;
}

20 августа 2010 (Обновление: 19 янв 2011)