2019-04-10 23:30:48 -07:00
|
|
|
#include <string>
|
2021-02-18 06:31:03 -08:00
|
|
|
#include <filesystem>
|
|
|
|
// See https://stackoverflow.com/questions/22201663/find-and-move-files-in-c
|
2019-04-10 23:30:48 -07:00
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
#include "Engine.h"
|
|
|
|
|
2019-03-09 12:42:40 -08:00
|
|
|
#include "UserInterface.h"
|
2019-04-10 23:41:14 -07:00
|
|
|
#include "Utility.h"
|
2019-04-11 01:31:04 -07:00
|
|
|
#include "View.h"
|
2020-01-30 08:46:24 -08:00
|
|
|
#include <cerrno>
|
|
|
|
// _chdir (not chdir--see):
|
|
|
|
#include <unistd.h>
|
2019-03-09 12:42:40 -08:00
|
|
|
|
2019-03-07 19:18:07 -08:00
|
|
|
using std::cout;
|
|
|
|
using std::endl;
|
2019-04-11 01:31:04 -07:00
|
|
|
using std::wcerr;
|
2019-03-07 19:18:07 -08:00
|
|
|
using std::wstring;
|
|
|
|
using std::wstringstream;
|
|
|
|
|
|
|
|
using namespace irr;
|
|
|
|
using namespace irr::core;
|
|
|
|
using namespace irr::scene;
|
|
|
|
using namespace irr::video;
|
|
|
|
using namespace irr::gui;
|
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
/* //////////////////////////////////////////////////////////////////////////
|
|
|
|
PRIVATE METHODS
|
|
|
|
/////////////////////////////////////////////////////////////////////// */
|
|
|
|
|
2019-07-03 12:15:44 -07:00
|
|
|
bool Engine::getEnableWireframe() const
|
|
|
|
{
|
|
|
|
return m_EnableWireframe;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Engine::getEnableLighting() const
|
|
|
|
{
|
|
|
|
return m_EnableLighting;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Engine::getEnableTextureInterpolation() const
|
|
|
|
{
|
|
|
|
return m_EnableTextureInterpolation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::setEnableWireframe(bool EnableWireframe)
|
|
|
|
{
|
|
|
|
if (this->m_EnableWireframe != EnableWireframe) {
|
|
|
|
this->setMeshDisplayMode(EnableWireframe, this->m_EnableLighting,
|
|
|
|
this->m_EnableTextureInterpolation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::setEnableLighting(bool EnableLighting)
|
|
|
|
{
|
|
|
|
if (this->m_EnableLighting != EnableLighting) {
|
|
|
|
this->setMeshDisplayMode(this->m_EnableWireframe, EnableLighting,
|
|
|
|
this->m_EnableTextureInterpolation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::setEnableTextureInterpolation(bool EnableTextureInterpolation)
|
|
|
|
{
|
|
|
|
if (this->m_EnableTextureInterpolation != EnableTextureInterpolation)
|
|
|
|
debug() << "setEnableTextureInterpolation(..., setEnableTextureInterpolation:"
|
|
|
|
<< (EnableTextureInterpolation?"true":"false") << ")" << endl;
|
|
|
|
|
|
|
|
if (this->m_EnableTextureInterpolation != EnableTextureInterpolation) {
|
|
|
|
this->setMeshDisplayMode(this->m_EnableWireframe, this->m_EnableLighting,
|
|
|
|
EnableTextureInterpolation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 06:31:03 -08:00
|
|
|
void Engine::addRecent(std::string path)
|
|
|
|
{
|
|
|
|
int count = this->countRecent();
|
|
|
|
std::string name = "recent" + std::to_string(count);
|
|
|
|
this->settings.set(name, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::addRecentPaths(std::vector<std::string> paths)
|
|
|
|
{
|
|
|
|
for (std::vector<std::string>::iterator it = paths.begin() ; it != paths.end(); ++it) {
|
|
|
|
this->addRecent(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int Engine::countRecent()
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
while (this->settings.exists("recent" + std::to_string(count))) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> Engine::recentPaths()
|
|
|
|
{
|
|
|
|
std::vector<std::string> results;
|
|
|
|
int count = 0;
|
|
|
|
while (true) {
|
|
|
|
bool found;
|
|
|
|
std::string value = this->settings.get("recent" + std::to_string(count), found);
|
|
|
|
if (found) {
|
|
|
|
results.push_back(value);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
void Engine::setupScene()
|
|
|
|
{
|
|
|
|
// Setup Light
|
2010-08-16 05:23:20 -07:00
|
|
|
m_SceneLight = m_Scene->addLightSceneNode();
|
2019-04-11 01:31:04 -07:00
|
|
|
m_SceneLight->setID(SIID_LIGHT);
|
|
|
|
m_SceneLight->setLightType(ELT_DIRECTIONAL);
|
|
|
|
m_SceneLight->getLightData().AmbientColor = SColorf(0.2f, 0.2f, 0.2f);
|
|
|
|
m_SceneLight->getLightData().DiffuseColor = SColorf(0.8f, 0.8f, 0.8f);
|
|
|
|
m_Scene->setAmbientLight(SColorf(0.2f, 0.2f, 0.2f));
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
// Setup Camera
|
2019-04-19 14:13:58 -07:00
|
|
|
// (so z-forward characters face camera partially
|
|
|
|
// (formerly vector3df(0, 0, -10), vector3df())
|
2019-04-19 12:29:30 -07:00
|
|
|
m_CamPos = vector3df(4.5, 3.5, 9);
|
2019-03-09 13:41:56 -08:00
|
|
|
m_CamTarget = vector3df(0, 3, 0);
|
2019-04-19 14:13:58 -07:00
|
|
|
// Below will be overridden by View m_Yaw and m_Pitch--see "calculate m_Yaw"
|
|
|
|
// further down.
|
|
|
|
ICameraSceneNode* camera = m_Scene->addCameraSceneNode(nullptr, m_CamPos,
|
|
|
|
m_CamTarget);
|
2020-03-10 11:12:16 -07:00
|
|
|
camera->setAspectRatio(
|
|
|
|
static_cast<f32>(m_Driver->getScreenSize().Width)
|
|
|
|
/ static_cast<f32>(m_Driver->getScreenSize().Height)
|
|
|
|
);
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
|
2019-04-11 01:31:04 -07:00
|
|
|
IGUIEnvironment* Engine::getGUIEnvironment() const
|
2010-04-21 07:48:36 -07:00
|
|
|
{
|
|
|
|
return m_Device->getGUIEnvironment();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::drawAxisLines()
|
|
|
|
{
|
2019-04-19 12:29:30 -07:00
|
|
|
SMaterial xMaterial;
|
|
|
|
xMaterial.Lighting = false;
|
|
|
|
xMaterial.EmissiveColor = SColor(255, 255, 0, 0);
|
|
|
|
xMaterial.Thickness = 1.0f;
|
2010-04-21 07:48:36 -07:00
|
|
|
|
2019-04-19 12:29:30 -07:00
|
|
|
SMaterial yMaterial(xMaterial);
|
|
|
|
yMaterial.EmissiveColor = SColor(255, 0, 255, 0);
|
2010-04-21 07:48:36 -07:00
|
|
|
|
2019-04-19 12:29:30 -07:00
|
|
|
SMaterial zMaterial(xMaterial);
|
|
|
|
zMaterial.EmissiveColor = SColor(255, 0, 0, 255);
|
|
|
|
|
|
|
|
SMaterial descenderMaterialVert(xMaterial);
|
2019-04-19 12:50:06 -07:00
|
|
|
descenderMaterialVert.EmissiveColor = SColor(128, 100, 140, 190); // ARGB
|
2019-04-19 12:29:30 -07:00
|
|
|
SMaterial descenderMaterialHorz(xMaterial);
|
|
|
|
descenderMaterialHorz.EmissiveColor = SColor(255, 255, 255, 255);
|
|
|
|
|
|
|
|
vector3df descend3df(0, 0, 0);
|
|
|
|
// vector3df target = m_View->c
|
2019-04-19 12:50:06 -07:00
|
|
|
bool enableAxisWidget = true;
|
2019-04-11 01:31:04 -07:00
|
|
|
m_Driver->setTransform(ETS_WORLD, matrix4());
|
2019-04-19 12:29:30 -07:00
|
|
|
if (m_View != nullptr) {
|
2019-04-19 14:13:58 -07:00
|
|
|
if (this->m_UserInterface->viewMenu->isItemChecked(
|
|
|
|
this->m_UserInterface->viewTargetIdx)) {
|
2019-04-19 12:29:30 -07:00
|
|
|
if (m_View->zUp()) {
|
|
|
|
descend3df.Z = this->m_CamTarget.Z;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
descend3df.Y = this->m_CamTarget.Y;
|
|
|
|
}
|
|
|
|
vector3df descendSideways3df(descend3df);
|
|
|
|
descendSideways3df.X = this->m_CamTarget.X;
|
|
|
|
vector3df descendSidewaysForward3df(descendSideways3df);
|
|
|
|
if (m_View->zUp()) {
|
|
|
|
descendSidewaysForward3df.Y = this->m_CamTarget.Y;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
descendSidewaysForward3df.Z = this->m_CamTarget.Z;
|
|
|
|
}
|
|
|
|
m_Driver->setMaterial(descenderMaterialVert);
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Driver->draw3DLine(vector3df(), descend3df,
|
|
|
|
descenderMaterialVert.EmissiveColor);
|
2019-04-19 12:29:30 -07:00
|
|
|
m_Driver->setMaterial(descenderMaterialHorz);
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Driver->draw3DLine(descend3df, descendSideways3df,
|
|
|
|
descenderMaterialHorz.EmissiveColor);
|
|
|
|
m_Driver->draw3DLine(descendSideways3df, descendSidewaysForward3df,
|
|
|
|
descenderMaterialHorz.EmissiveColor);
|
2019-04-19 12:29:30 -07:00
|
|
|
f32 arrowDirection = 1.0f;
|
|
|
|
vector3df arrowLeft3df(descendSidewaysForward3df);
|
|
|
|
vector3df arrowRight3df(descendSidewaysForward3df);
|
|
|
|
f32 arrowSize = this->m_View->cameraDistance() / 30;
|
|
|
|
if (m_View->zUp()) {
|
|
|
|
if (descendSidewaysForward3df.Y > descendSideways3df.Y)
|
|
|
|
arrowDirection = -1.0f;
|
|
|
|
arrowLeft3df.X += arrowSize;
|
|
|
|
arrowLeft3df.Y += arrowSize * arrowDirection;
|
|
|
|
arrowRight3df.X -= arrowSize;
|
|
|
|
arrowRight3df.Y += arrowSize * arrowDirection;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (descendSidewaysForward3df.Z > descendSideways3df.Z)
|
|
|
|
arrowDirection = -1.0f;
|
|
|
|
arrowLeft3df.X += arrowSize;
|
|
|
|
arrowLeft3df.Z += arrowSize * arrowDirection;
|
|
|
|
arrowRight3df.X -= arrowSize;
|
|
|
|
arrowRight3df.Z += arrowSize * arrowDirection;
|
|
|
|
}
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Driver->draw3DLine(descendSidewaysForward3df, arrowLeft3df,
|
|
|
|
descenderMaterialHorz.EmissiveColor);
|
|
|
|
m_Driver->draw3DLine(descendSidewaysForward3df, arrowRight3df,
|
|
|
|
descenderMaterialHorz.EmissiveColor);
|
|
|
|
// position2d<s32> targetPos2d = m_Scene->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(
|
|
|
|
// this->m_CamTarget
|
|
|
|
// );
|
2019-04-19 12:29:30 -07:00
|
|
|
// dimension2d<u32> textSize;
|
|
|
|
// if (m_AxisFont != nullptr) {
|
|
|
|
// textSize = m_AxisFont->getDimension(L"target");
|
2019-04-19 14:13:58 -07:00
|
|
|
// m_AxisFont->draw(L"target", rect<s32>(targetPos2d, textSize),
|
|
|
|
// descenderMaterial.EmissiveColor, true,
|
|
|
|
// true);
|
2019-04-19 12:29:30 -07:00
|
|
|
// }
|
|
|
|
}
|
2019-04-19 14:13:58 -07:00
|
|
|
enableAxisWidget = this->m_UserInterface->viewMenu->isItemChecked(
|
|
|
|
this->m_UserInterface->viewAxisWidgetIdx
|
|
|
|
);
|
2019-04-19 12:29:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-19 12:50:06 -07:00
|
|
|
if (enableAxisWidget) {
|
|
|
|
m_Driver->setMaterial(xMaterial);
|
2020-03-10 11:12:16 -07:00
|
|
|
m_Driver->draw3DLine(vector3df(), vector3df(m_AxisLength, 0, 0),
|
2019-04-19 14:13:58 -07:00
|
|
|
SColor(255, 255, 0, 0));
|
|
|
|
position2d<s32> textPos = m_Scene->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(
|
2020-03-10 11:12:16 -07:00
|
|
|
vector3df(m_AxisLength + m_AxisLength*.1f, 0, 0)
|
2019-04-19 14:13:58 -07:00
|
|
|
);
|
2019-04-19 12:50:06 -07:00
|
|
|
dimension2d<u32> textSize;
|
|
|
|
if (m_AxisFont != nullptr) {
|
|
|
|
textSize = m_AxisFont->getDimension(L"X+");
|
2019-04-19 14:13:58 -07:00
|
|
|
m_AxisFont->draw(L"X+", rect<s32>(textPos, textSize),
|
|
|
|
SColor(255, 255, 0, 0), true, true);
|
2019-04-19 12:50:06 -07:00
|
|
|
}
|
2019-04-19 12:29:30 -07:00
|
|
|
|
2019-04-19 12:50:06 -07:00
|
|
|
m_Driver->setMaterial(yMaterial);
|
2020-03-10 11:12:16 -07:00
|
|
|
m_Driver->draw3DLine(vector3df(), vector3df(0, m_AxisLength, 0),
|
2019-04-19 14:13:58 -07:00
|
|
|
SColor(255, 0, 255, 0));
|
|
|
|
textPos = m_Scene->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(
|
2020-03-10 11:12:16 -07:00
|
|
|
vector3df(0, m_AxisLength + m_AxisLength*.1f, 0)
|
2019-04-19 14:13:58 -07:00
|
|
|
);
|
2019-04-19 12:50:06 -07:00
|
|
|
if (m_AxisFont != nullptr) {
|
|
|
|
textSize = m_AxisFont->getDimension(L"Y+");
|
2019-04-19 14:13:58 -07:00
|
|
|
m_AxisFont->draw(L"Y+", rect<s32>(textPos, textSize),
|
|
|
|
SColor(255, 0, 255, 0), true, true);
|
2019-04-19 12:50:06 -07:00
|
|
|
}
|
2019-04-19 12:29:30 -07:00
|
|
|
|
2019-04-19 12:50:06 -07:00
|
|
|
m_Driver->setMaterial(zMaterial);
|
2020-03-10 11:12:16 -07:00
|
|
|
m_Driver->draw3DLine(vector3df(), vector3df(0, 0, m_AxisLength),
|
2019-04-19 14:13:58 -07:00
|
|
|
SColor(255, 0, 0, 255));
|
|
|
|
textPos = m_Scene->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(
|
2020-03-10 11:12:16 -07:00
|
|
|
vector3df(0, 0, m_AxisLength + m_AxisLength*.1f)
|
2019-04-19 14:13:58 -07:00
|
|
|
);
|
2019-04-19 12:50:06 -07:00
|
|
|
if (m_AxisFont != nullptr) {
|
|
|
|
textSize = m_AxisFont->getDimension(L"Z+");
|
2019-04-19 14:13:58 -07:00
|
|
|
m_AxisFont->draw(L"Z+", rect<s32>(textPos, textSize),
|
|
|
|
SColor(255, 0, 0, 255), true, true);
|
2019-04-19 12:50:06 -07:00
|
|
|
}
|
2019-03-07 19:18:07 -08:00
|
|
|
}
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::drawBackground()
|
|
|
|
{
|
|
|
|
dimension2d<u32> screenSize = m_Driver->getScreenSize();
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Driver->draw2DRectangle(
|
|
|
|
rect<s32>(0, 0, static_cast<s32>(screenSize.Width),
|
|
|
|
static_cast<s32>(screenSize.Height)),
|
2019-04-11 01:31:04 -07:00
|
|
|
SColor(255, 128, 128, 255),
|
|
|
|
SColor(255, 128, 128, 255),
|
|
|
|
SColor(255, 224, 224, 255),
|
2019-04-19 14:13:58 -07:00
|
|
|
SColor(255, 224, 224, 255)
|
|
|
|
);
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::checkResize()
|
|
|
|
{
|
2019-04-19 14:13:58 -07:00
|
|
|
if ((m_WindowSize.Width != m_Driver->getScreenSize().Width)
|
|
|
|
|| (m_WindowSize.Height != m_Driver->getScreenSize().Height)) {
|
2019-04-11 01:31:04 -07:00
|
|
|
m_WindowSize.Width = m_Driver->getScreenSize().Width;
|
|
|
|
m_WindowSize.Height = m_Driver->getScreenSize().Height;
|
2010-04-21 07:48:36 -07:00
|
|
|
|
2010-04-23 00:28:59 -07:00
|
|
|
// Send custom event
|
2019-04-11 01:31:04 -07:00
|
|
|
IEventReceiver* eventReceiver = m_Device->getEventReceiver();
|
2010-04-23 00:28:59 -07:00
|
|
|
|
|
|
|
SEvent event;
|
|
|
|
event.EventType = EET_USER_EVENT;
|
|
|
|
event.UserEvent.UserData1 = UEI_WINDOWSIZECHANGED;
|
2019-04-11 01:31:04 -07:00
|
|
|
eventReceiver->OnEvent(event);
|
2019-04-10 23:30:48 -07:00
|
|
|
//m_UserInterface->
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-23 00:28:59 -07:00
|
|
|
s32 Engine::getNumberOfVertices()
|
|
|
|
{
|
2019-04-11 01:31:04 -07:00
|
|
|
IMesh* mesh = m_LoadedMesh->getMesh()->getMesh(0, 255, -1, -1);
|
2010-04-23 00:28:59 -07:00
|
|
|
|
|
|
|
int vertices = 0;
|
2019-04-11 01:31:04 -07:00
|
|
|
for (irr::u32 bufferIndex = 0; bufferIndex < mesh->getMeshBufferCount(); bufferIndex++)
|
|
|
|
vertices += mesh->getMeshBuffer(bufferIndex)->getVertexCount();
|
2010-04-23 00:28:59 -07:00
|
|
|
|
|
|
|
cout << vertices << endl;
|
|
|
|
|
|
|
|
return vertices;
|
|
|
|
}
|
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
/* //////////////////////////////////////////////////////////////////////////
|
|
|
|
PUBLIC METHODS
|
|
|
|
/////////////////////////////////////////////////////////////////////// */
|
|
|
|
|
|
|
|
Engine::Engine()
|
|
|
|
{
|
2021-02-17 15:55:39 -08:00
|
|
|
settings.set_int("max_recent", 10);
|
2021-02-18 06:31:03 -08:00
|
|
|
std::string profile = std::getenv("HOME");
|
|
|
|
std::string appdataParent;
|
|
|
|
std::string appdatas;
|
|
|
|
std::string myAppData;
|
|
|
|
if (profile.length() == 0) {
|
|
|
|
profile = std::getenv("USERPROFILE");
|
|
|
|
appdataParent = profile + path_separator_s + "AppData";
|
|
|
|
appdatas = appdataParent + path_separator_s + "Local";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
appdataParent = profile;
|
|
|
|
appdatas = appdataParent + path_separator_s + ".config";
|
|
|
|
}
|
|
|
|
if (appdatas.length() > 0) {
|
|
|
|
myAppData = appdatas + path_separator_s + std::string("b3view");
|
|
|
|
}
|
|
|
|
std::string settingsName = "settings.conf";
|
|
|
|
std::string settingsPath = settingsName;
|
|
|
|
if (myAppData.length() > 0) {
|
|
|
|
settingsPath = myAppData + path_separator_s + settingsName;
|
|
|
|
}
|
|
|
|
settings.load(settingsPath);
|
|
|
|
// For monitoring single press: See
|
2019-03-10 06:55:31 -07:00
|
|
|
// <http://irrlicht.sourceforge.net/forum/viewtopic.php?p=210744>
|
2019-04-11 01:31:04 -07:00
|
|
|
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
|
2019-03-10 06:55:31 -07:00
|
|
|
KeyIsDown[i] = false;
|
2019-04-11 01:31:04 -07:00
|
|
|
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
|
2019-03-10 06:55:31 -07:00
|
|
|
keyState[i] = 0;
|
|
|
|
LMouseState = 0;
|
|
|
|
RMouseState = 0;
|
2019-07-03 12:15:44 -07:00
|
|
|
this->m_EnableWireframe = false;
|
|
|
|
this->m_EnableLighting = false;
|
|
|
|
this->m_EnableTextureInterpolation = true;
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_AxisLength = 10;
|
|
|
|
this->m_WorldFPS = 60;
|
|
|
|
this->m_PrevFPS = 30;
|
|
|
|
this->m_TextureExtensions.push_back(L"png");
|
|
|
|
this->m_TextureExtensions.push_back(L"jpg");
|
|
|
|
this->m_TextureExtensions.push_back(L"bmp");
|
2010-04-22 01:44:10 -07:00
|
|
|
#if WIN32
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(1024, 768), 32,
|
|
|
|
false, false, false, nullptr);
|
2010-04-22 01:44:10 -07:00
|
|
|
#else
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Device = createDevice(EDT_OPENGL, dimension2d<u32>(1024, 768), 32,
|
|
|
|
false, false, false, nullptr);
|
2010-04-22 01:44:10 -07:00
|
|
|
#endif
|
2019-04-11 01:31:04 -07:00
|
|
|
m_Device->setResizable(true);
|
2010-04-21 07:48:36 -07:00
|
|
|
|
2019-04-11 01:31:04 -07:00
|
|
|
m_EventHandler = new EventHandler(m_Device);
|
|
|
|
m_Device->setEventReceiver(m_EventHandler);
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
m_Driver = m_Device->getVideoDriver();
|
|
|
|
m_Scene = m_Device->getSceneManager();
|
|
|
|
|
2019-03-07 10:23:54 -08:00
|
|
|
wstringstream windowTitle;
|
2019-04-19 14:13:58 -07:00
|
|
|
windowTitle << L"b3view (Blitz3D/Irrlicht Viewer) [" << m_Driver->getName()
|
|
|
|
<< L"]";
|
2019-04-11 01:31:04 -07:00
|
|
|
m_Device->setWindowCaption(windowTitle.str().c_str());
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
setupScene();
|
|
|
|
|
|
|
|
// Setup User Interface
|
2019-04-11 01:31:04 -07:00
|
|
|
m_UserInterface = new UserInterface(this);
|
|
|
|
m_EventHandler->addEventReceiver(ERT_USERINTERFACE, m_UserInterface);
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
// Setup 3D View
|
2019-04-11 01:31:04 -07:00
|
|
|
m_View = new View(this);
|
|
|
|
m_EventHandler->addEventReceiver(ERT_3DVIEW, m_View);
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
// Load font for displaying Axis names
|
2010-04-23 01:13:44 -07:00
|
|
|
m_AxisFontFace = new CGUITTFace();
|
2019-04-19 14:13:58 -07:00
|
|
|
// NOTE: m_FontPath is modified y UserInterface constructor above if font
|
|
|
|
// was missing
|
2019-03-09 13:41:56 -08:00
|
|
|
if (m_AxisFontFace->load(m_FontPath.c_str())) {
|
2019-04-11 01:31:04 -07:00
|
|
|
m_AxisFont = new CGUITTFont(m_UserInterface->getGUIEnvironment());
|
|
|
|
m_AxisFont->attach(m_AxisFontFace, 14);
|
2019-03-07 19:18:07 -08:00
|
|
|
m_AxisFont->AntiAlias = false;
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-03-07 19:18:07 -08:00
|
|
|
delete m_AxisFontFace;
|
|
|
|
m_AxisFontFace = nullptr;
|
|
|
|
}
|
2010-04-21 07:48:36 -07:00
|
|
|
// Set Engine enabled
|
|
|
|
m_RunEngine = true;
|
2019-03-07 10:23:54 -08:00
|
|
|
m_LoadedMesh = nullptr;
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
// Store actual window size
|
2019-04-11 01:31:04 -07:00
|
|
|
m_WindowSize.Width = m_Driver->getScreenSize().Width;
|
|
|
|
m_WindowSize.Height = m_Driver->getScreenSize().Height;
|
2019-03-09 12:42:40 -08:00
|
|
|
|
2019-03-10 06:55:31 -07:00
|
|
|
// (do not calculate m_Yaw and m_Pitch here--see View constructor)
|
2019-03-09 12:42:40 -08:00
|
|
|
|
2019-03-07 21:52:29 -08:00
|
|
|
this->playAnimation();
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Engine::~Engine()
|
|
|
|
{
|
|
|
|
m_Device->drop();
|
2010-04-23 01:13:44 -07:00
|
|
|
delete m_AxisFont;
|
|
|
|
delete m_AxisFontFace;
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
|
2019-04-19 12:29:30 -07:00
|
|
|
vector3df Engine::camTarget()
|
|
|
|
{
|
|
|
|
return m_CamTarget;
|
|
|
|
}
|
|
|
|
|
2019-05-16 09:33:53 -07:00
|
|
|
bool Engine::loadMesh(const wstring& fileName)
|
2010-04-22 05:16:15 -07:00
|
|
|
{
|
2019-05-16 09:33:53 -07:00
|
|
|
bool ret = false;
|
2010-04-22 05:16:15 -07:00
|
|
|
|
2019-04-11 01:31:04 -07:00
|
|
|
irr::scene::IAnimatedMesh* mesh = m_Scene->getMesh(fileName.c_str());
|
2019-03-09 05:56:23 -08:00
|
|
|
if (mesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_LoadedTexturePath = L"";
|
|
|
|
this->m_LoadedMeshPath = fileName; // even if bad, set this
|
|
|
|
// to allow F5 to reload
|
|
|
|
|
|
|
|
if (m_LoadedMesh != nullptr)
|
|
|
|
m_LoadedMesh->remove();
|
|
|
|
this->m_LoadedMesh = nullptr;
|
|
|
|
|
2019-04-19 14:13:58 -07:00
|
|
|
m_Device->setWindowCaption((wstring(L"b3view - ") + fileName).c_str());
|
2019-04-11 01:31:04 -07:00
|
|
|
m_LoadedMesh = m_Scene->addAnimatedMeshSceneNode(mesh);
|
|
|
|
Utility::dumpMeshInfoToConsole(m_LoadedMesh);
|
2020-03-10 11:12:16 -07:00
|
|
|
std::cerr << "Arranging scene..." << std::flush;
|
2019-03-10 06:55:31 -07:00
|
|
|
if (Utility::toLower(Utility::extensionOf(fileName)) == L"3ds") {
|
|
|
|
m_View->setZUp(true);
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-03-10 06:55:31 -07:00
|
|
|
m_View->setZUp(false);
|
|
|
|
}
|
|
|
|
if (m_LoadedMesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
std::cerr << "unloading old mesh..." << std::flush;
|
2019-05-16 09:33:53 -07:00
|
|
|
ret = true;
|
2019-04-19 14:13:58 -07:00
|
|
|
this->m_UserInterface->playbackFPSEditBox->setText(
|
|
|
|
Utility::toWstring(m_LoadedMesh->getAnimationSpeed()).c_str()
|
|
|
|
);
|
2019-04-11 01:31:04 -07:00
|
|
|
ICameraSceneNode* camera = this->m_Scene->getActiveCamera();
|
2019-03-10 06:55:31 -07:00
|
|
|
aabbox3d<f32> box = m_LoadedMesh->getTransformedBoundingBox();
|
2019-04-10 23:30:48 -07:00
|
|
|
//vector3d<float> extents = box.getExtent();
|
2019-03-10 06:55:31 -07:00
|
|
|
if (m_View->zUp()) {
|
|
|
|
float oldDist = m_CamPos.getDistanceFrom(m_CamTarget);
|
|
|
|
float newDist = oldDist;
|
2019-04-11 01:31:04 -07:00
|
|
|
if (Utility::equalsApprox(oldDist, 0.0f)) {
|
2019-03-10 06:55:31 -07:00
|
|
|
vector3d<float> center = box.getCenter();
|
|
|
|
vector3df edges[8];
|
|
|
|
box.getEdges(edges);
|
|
|
|
/*
|
|
|
|
/3--------/7
|
|
|
|
/ | / |
|
|
|
|
/ | / |
|
|
|
|
1---------5 |
|
|
|
|
| 2- - -| -6
|
|
|
|
| / | /
|
|
|
|
|/ | /
|
|
|
|
0---------4/
|
|
|
|
*/
|
|
|
|
newDist = 0;
|
2019-04-11 01:31:04 -07:00
|
|
|
for (int i = 0; i < 8; i++) {
|
2019-03-10 06:55:31 -07:00
|
|
|
float tryDist = center.getDistanceFrom(edges[i]);
|
2019-04-11 01:31:04 -07:00
|
|
|
if (tryDist > newDist)
|
|
|
|
newDist = tryDist;
|
2019-03-10 06:55:31 -07:00
|
|
|
}
|
2019-04-11 01:31:04 -07:00
|
|
|
newDist *= 2; // so camera doesn't touch model
|
2019-03-10 06:55:31 -07:00
|
|
|
if (!Utility::equalsApprox<float>(newDist, oldDist)) {
|
2019-04-11 01:31:04 -07:00
|
|
|
float scale = newDist / oldDist; // already checked 0
|
2019-03-10 06:55:31 -07:00
|
|
|
vector3df oldCamPos = camera->getPosition();
|
|
|
|
m_CamPos = oldCamPos;
|
|
|
|
m_CamPos.X = m_CamPos.X * scale;
|
|
|
|
m_CamPos.Y = m_CamPos.Y * scale;
|
|
|
|
m_CamPos.Z = m_CamPos.Z * scale;
|
|
|
|
oldCamPos = m_CamPos;
|
2019-04-19 14:13:58 -07:00
|
|
|
m_View->setCameraDistance(
|
|
|
|
m_CamPos.getDistanceFrom(m_CamTarget)
|
|
|
|
);
|
2019-03-10 06:55:31 -07:00
|
|
|
camera->setPosition(m_CamPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-19 14:13:58 -07:00
|
|
|
m_LoadedMesh->setMaterialType(
|
|
|
|
video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF
|
|
|
|
);
|
2019-04-08 19:52:18 -07:00
|
|
|
// EMT_TRANSPARENT_ALPHA_CHANNEL: constant transparency
|
2020-03-10 11:12:16 -07:00
|
|
|
|
2019-03-10 06:55:31 -07:00
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
std::cerr << "setting display mode..." << std::flush;
|
|
|
|
this->setMeshDisplayMode(this->m_EnableWireframe, this->m_EnableLighting,
|
|
|
|
this->m_EnableTextureInterpolation);
|
|
|
|
std::cerr << "preparing UI..." << std::flush;
|
|
|
|
if (this->m_UserInterface != nullptr)
|
|
|
|
this->m_UserInterface->OnSelectMesh();
|
|
|
|
std::cerr << "checking for textures..." << std::flush;
|
|
|
|
std::cerr << "OK" << std::endl;
|
|
|
|
if (Utility::getTextureCount(m_LoadedMesh) == 0) {
|
|
|
|
// NOTE: getMaterialCount doesn't work, since there may not
|
|
|
|
// be loaded textures in any material.
|
|
|
|
if (this->m_UserInterface != nullptr) {
|
|
|
|
this->m_UserInterface->loadNextTexture(0);
|
|
|
|
}
|
|
|
|
}
|
2020-07-30 20:40:17 -07:00
|
|
|
std::cerr << "detecting last frame..." << std::flush;
|
|
|
|
std::wstring prevStartStr;
|
|
|
|
std::wstring prevEndStr;
|
|
|
|
if (this->m_UserInterface->playbackMenu->getItemText(UIE_PLAYBACKSTARTFRAMEEDITBOX) != nullptr)
|
|
|
|
prevStartStr = std::wstring(this->m_UserInterface->playbackMenu->getItemText(UIE_PLAYBACKSTARTFRAMEEDITBOX));
|
|
|
|
if (this->m_UserInterface->playbackMenu->getItemText(UIE_PLAYBACKENDFRAMEEDITBOX) != nullptr)
|
|
|
|
prevEndStr = std::wstring(this->m_UserInterface->playbackMenu->getItemText(UIE_PLAYBACKENDFRAMEEDITBOX));
|
|
|
|
f32 prevStart = -1;
|
|
|
|
f32 prevEnd = -1;
|
|
|
|
if (prevStartStr.length() > 0)
|
|
|
|
prevStart = Utility::toF32(prevStartStr);
|
|
|
|
// std::cerr << prevStart << "..." << std::flush;
|
|
|
|
if (prevEndStr.length() > 0)
|
|
|
|
prevEnd = Utility::toF32(prevEndStr);
|
|
|
|
// std::cerr << prevEnd << "..." << std::flush;
|
|
|
|
f32 endFrameF32 = static_cast<f32>(m_LoadedMesh->getEndFrame());
|
|
|
|
std::cerr << endFrameF32 << "..." << std::flush;
|
|
|
|
if (prevEnd < 0 || prevEnd > endFrameF32) {
|
|
|
|
std::cerr << "showing End Frame..." << std::flush;
|
|
|
|
this->m_UserInterface->setPlaybackText(
|
|
|
|
UIE_PLAYBACKENDFRAMEEDITBOX,
|
|
|
|
Utility::toWstring(endFrameF32).c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (prevStart < 0 || prevStart > endFrameF32) {
|
|
|
|
std::cerr << "showing Start Frame..." << std::flush;
|
|
|
|
this->m_UserInterface->setPlaybackText(
|
|
|
|
UIE_PLAYBACKSTARTFRAMEEDITBOX,
|
|
|
|
L"0.0"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
//this->m_UserInterface->playbackMenu->setItemText(UIE_PLAYBACKSTARTFRAMEEDITBOX, );
|
|
|
|
//;
|
|
|
|
std::cerr << "OK" << std::endl;
|
2019-03-09 05:56:23 -08:00
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
// Don't do anything outside of the mesh != nullptr case that will try to
|
|
|
|
// use mesh!
|
2019-05-16 09:33:53 -07:00
|
|
|
return ret;
|
2010-04-22 05:16:15 -07:00
|
|
|
}
|
|
|
|
|
2019-05-16 09:33:53 -07:00
|
|
|
bool Engine::reloadMesh()
|
2019-03-07 19:18:07 -08:00
|
|
|
{
|
2019-05-16 09:33:53 -07:00
|
|
|
bool ret = false;
|
2020-03-10 11:12:16 -07:00
|
|
|
if (this->m_LoadedMeshPath.length() > 0) {
|
|
|
|
ret = loadMesh(this->m_LoadedMeshPath);
|
2019-03-07 19:18:07 -08:00
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
if (this->m_UserInterface != nullptr)
|
|
|
|
this->m_UserInterface->OnSelectMesh();
|
2019-05-16 09:33:53 -07:00
|
|
|
return ret;
|
2019-03-07 19:18:07 -08:00
|
|
|
}
|
|
|
|
|
2019-05-16 09:33:53 -07:00
|
|
|
std::wstring Engine::saveMesh(const io::path path, const std::string& nameOrBlank, const std::string& extension)
|
2019-05-02 18:17:24 -07:00
|
|
|
{
|
2019-05-16 09:33:53 -07:00
|
|
|
wstring ret = L"";
|
2019-05-02 18:17:24 -07:00
|
|
|
// see also https://bitbucket.org/mzeilfelder/irr-playground-micha/src/default/obj_readwrite.cpp (saves scene::EMWT_OBJ)
|
|
|
|
scene::ISceneManager* smgr = m_Device->getSceneManager();
|
2019-05-16 09:33:53 -07:00
|
|
|
scene::IMeshWriter* meshWriter = nullptr;
|
2019-07-03 12:15:44 -07:00
|
|
|
// this->m_FileName = "";
|
2019-05-16 09:33:53 -07:00
|
|
|
io::path fileName = io::path();
|
2020-01-30 08:46:24 -08:00
|
|
|
io::path mtlName = io::path();
|
2019-05-16 09:33:53 -07:00
|
|
|
std::string beginning = "export-";
|
2020-01-30 08:46:24 -08:00
|
|
|
std::string mtlTryName = "export.mtl";
|
2019-05-16 09:33:53 -07:00
|
|
|
if (nameOrBlank.length() > 0) {
|
2019-06-13 05:57:32 -07:00
|
|
|
beginning = nameOrBlank + "#" + Utility::toString(static_cast<int>(round(m_LoadedMesh->getFrameNr()))) + "-";
|
2020-01-30 08:46:24 -08:00
|
|
|
mtlTryName = nameOrBlank + ".mtl";
|
2019-05-16 09:33:53 -07:00
|
|
|
}
|
2020-01-30 08:46:24 -08:00
|
|
|
mtlName = mtlTryName.c_str();
|
2019-05-16 09:33:53 -07:00
|
|
|
std::string partial = beginning + Utility::dateTimeNowPathString();
|
|
|
|
if (extension == "dae") {
|
|
|
|
fileName = (partial + ".dae").c_str();
|
|
|
|
meshWriter = smgr->createMeshWriter(scene::EMWT_COLLADA);
|
|
|
|
}
|
|
|
|
else if (extension == "obj") {
|
|
|
|
fileName = (partial + ".obj").c_str();
|
|
|
|
meshWriter = smgr->createMeshWriter(scene::EMWT_OBJ);
|
|
|
|
}
|
|
|
|
else if (extension == "irrmesh") {
|
|
|
|
fileName = (partial + ".irrmesh").c_str();
|
|
|
|
meshWriter = smgr->createMeshWriter(scene::EMWT_IRR_MESH);
|
2019-05-02 18:17:24 -07:00
|
|
|
}
|
2019-05-16 09:33:53 -07:00
|
|
|
else if (extension == "stl") {
|
|
|
|
fileName = (partial + ".stl").c_str();
|
|
|
|
meshWriter = smgr->createMeshWriter(scene::EMWT_STL);
|
|
|
|
}
|
|
|
|
if (meshWriter != nullptr) {
|
2019-07-03 12:15:44 -07:00
|
|
|
// io::path filePath = path + fileName;
|
2019-05-16 09:33:53 -07:00
|
|
|
io::path filePath = path + "/" + fileName;
|
2020-01-30 08:46:24 -08:00
|
|
|
io::path mtlDestPath = path + "/" + mtlName;
|
|
|
|
// TODO: chdir is deprecated due to not following POSIX naming rules--see
|
|
|
|
// <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/chdir?redirectedfrom=MSDN&view=vs-2019>.
|
|
|
|
// Therefore, normally use _chdir or _wchdir instead.
|
|
|
|
// However, it is undeclared while using gcc even after including unistd.h.
|
|
|
|
chdir(path.c_str());
|
2019-05-16 09:33:53 -07:00
|
|
|
io::IWriteFile* meshFile = m_Device->getFileSystem()->createAndWriteFile(filePath);
|
|
|
|
if (!meshWriter->writeMesh(meshFile, m_LoadedMesh->getMesh())) {
|
|
|
|
debug() << "saving failed" << endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
debug() << "saving ok" << endl;
|
|
|
|
ret = Utility::toWstring(filePath.c_str());
|
2020-01-30 08:46:24 -08:00
|
|
|
debug() << "checking for " << mtlTryName << "..." << std::flush;
|
|
|
|
if (Utility::isFile(mtlDestPath.c_str())){
|
|
|
|
debug() << "chdir succeeded, so file is in " << mtlDestPath.c_str() << "." << endl;
|
|
|
|
ret += L";\n" + Utility::toWstring(mtlDestPath.c_str());
|
|
|
|
}
|
|
|
|
else if (Utility::isFile(mtlTryName)) {
|
|
|
|
// NOTE: std::filesystem::rename
|
|
|
|
// requires: C++17 (on gcc 8.0.1, link against -lstdc++fs and #include <filesystem>)
|
|
|
|
// (See https://stackoverflow.com/questions/22201663/find-and-move-files-in-c),
|
|
|
|
// so use std::rename and <cerrno> instead:
|
|
|
|
if (std::rename(mtlTryName.c_str(), mtlDestPath.c_str()) < 0) {
|
|
|
|
ret += L";\n<unmovable mtl file in current directory:>" + Utility::toWstring(mtlTryName.c_str());
|
|
|
|
std::cerr << strerror(errno) << std::endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ret += L";\n" + Utility::toWstring(mtlDestPath.c_str());
|
|
|
|
debug() << "moved to " << mtlDestPath.c_str() << "." << endl;
|
|
|
|
}
|
|
|
|
// try {
|
|
|
|
// std::filesystem::rename(mtlTryName.c_str(), mtlDestPath.c_str())
|
|
|
|
// ret += L";" + Utility::toWstring(mtlDestPath.c_str());
|
|
|
|
// } catch (std::filesystem::filesystem_error& e) {
|
|
|
|
// std::cerr << e.what() << '\n';
|
|
|
|
// ret += L";<unmovable mtl file in current directory:>" + Utility::toWstring(mtlTryName.c_str());
|
|
|
|
// }
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
debug() << "not found." << endl;
|
|
|
|
ret += L";\n<unknown mtl file in current directory>";
|
|
|
|
}
|
2019-05-16 09:33:53 -07:00
|
|
|
}
|
|
|
|
meshFile->drop();
|
|
|
|
meshWriter->drop();
|
|
|
|
}
|
|
|
|
else if (extension == "irr") {
|
|
|
|
fileName = (partial + ".irr").c_str();
|
|
|
|
io::path filePath = path + "/" + fileName;
|
|
|
|
if (!smgr->saveScene(filePath)) {
|
|
|
|
debug() << "saving failed" << endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
debug() << "saving ok" << endl;
|
|
|
|
ret = Utility::toWstring(filePath.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2019-05-02 18:17:24 -07:00
|
|
|
}
|
|
|
|
|
2019-03-09 04:43:36 -08:00
|
|
|
void Engine::reloadTexture()
|
|
|
|
{
|
2020-03-10 11:12:16 -07:00
|
|
|
if (this->m_LoadedTexturePath.length() > 0) {
|
2019-04-10 23:30:48 -07:00
|
|
|
if (wcslen(this->m_UserInterface->texturePathEditBox->getText()) == 0)
|
2019-04-08 19:52:18 -07:00
|
|
|
loadTexture(this->m_UserInterface->texturePathEditBox->getText());
|
|
|
|
else
|
2020-03-10 11:12:16 -07:00
|
|
|
loadTexture(this->m_LoadedTexturePath);
|
2019-03-09 04:43:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-11 01:31:04 -07:00
|
|
|
bool Engine::loadTexture(const wstring& fileName)
|
2019-03-07 14:17:42 -08:00
|
|
|
{
|
2019-03-07 23:30:06 -08:00
|
|
|
bool ret = false;
|
2019-04-19 12:29:30 -07:00
|
|
|
if (m_LoadedMesh != nullptr) {
|
|
|
|
ITexture* texture = this->m_Driver->getTexture(fileName.c_str());
|
|
|
|
if (texture != nullptr) {
|
|
|
|
m_LoadedMesh->setMaterialTexture(0, texture);
|
|
|
|
ret = true;
|
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_LoadedTexturePath = fileName;
|
|
|
|
std::cerr << "Setting texture path box to " << Utility::toString(this->m_LoadedTexturePath) << std::endl;
|
2019-04-19 14:13:58 -07:00
|
|
|
this->m_UserInterface->texturePathEditBox->setText(
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_LoadedTexturePath.c_str()
|
2019-04-19 14:13:58 -07:00
|
|
|
);
|
2019-03-07 23:30:06 -08:00
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
else {
|
|
|
|
std::cerr << "NOT Setting texture path box to " << Utility::toString(this->m_LoadedTexturePath) << std::endl;
|
|
|
|
}
|
2019-03-07 23:30:06 -08:00
|
|
|
return ret;
|
2019-03-07 14:17:42 -08:00
|
|
|
}
|
|
|
|
|
2019-04-19 14:13:58 -07:00
|
|
|
void Engine::setMeshDisplayMode(bool wireframe, bool lighting,
|
|
|
|
bool textureInterpolation)
|
2010-08-16 05:23:20 -07:00
|
|
|
{
|
2019-07-03 12:15:44 -07:00
|
|
|
this->m_EnableWireframe = wireframe;
|
|
|
|
this->m_EnableLighting = lighting;
|
|
|
|
this->m_EnableTextureInterpolation = textureInterpolation;
|
2019-04-08 19:52:18 -07:00
|
|
|
if (m_LoadedMesh != nullptr) {
|
2019-04-11 01:31:04 -07:00
|
|
|
for (u32 materialIndex = 0; materialIndex < m_LoadedMesh->getMaterialCount(); materialIndex++) {
|
2019-04-08 19:52:18 -07:00
|
|
|
// Set Wireframe display
|
|
|
|
m_LoadedMesh->getMaterial(materialIndex).Wireframe = wireframe;
|
|
|
|
|
|
|
|
// Set Lighting
|
2019-04-11 01:31:04 -07:00
|
|
|
if (!lighting) {
|
2019-04-08 19:52:18 -07:00
|
|
|
m_LoadedMesh->getMaterial(materialIndex).Lighting = false;
|
2019-04-19 14:13:58 -07:00
|
|
|
m_LoadedMesh->getMaterial(materialIndex).EmissiveColor = SColor(
|
|
|
|
255,
|
|
|
|
255,
|
|
|
|
255,
|
|
|
|
255
|
|
|
|
);
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-04-08 19:52:18 -07:00
|
|
|
m_LoadedMesh->getMaterial(materialIndex).Lighting = true;
|
2019-04-19 14:13:58 -07:00
|
|
|
m_LoadedMesh->getMaterial(materialIndex).EmissiveColor = SColor(
|
|
|
|
255,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0
|
|
|
|
);
|
2019-04-08 19:52:18 -07:00
|
|
|
}
|
2019-04-19 14:13:58 -07:00
|
|
|
// m_LoadedMesh->setMaterialType(
|
|
|
|
// video::EMT_TRANSPARENT_ALPHA_CHANNEL
|
2019-07-03 12:15:44 -07:00
|
|
|
// ); // already done on load
|
2019-04-19 14:13:58 -07:00
|
|
|
// // requires EMT_ONETEXTURE:
|
|
|
|
// m_LoadedMesh->setMaterialFlag(video::E_ALPHA_SOURCE, true);
|
2019-04-08 19:52:18 -07:00
|
|
|
if (textureInterpolation) {
|
|
|
|
m_LoadedMesh->setMaterialFlag(video::EMF_BILINEAR_FILTER, true);
|
2019-04-19 14:13:58 -07:00
|
|
|
m_LoadedMesh->setMaterialFlag(video::EMF_TRILINEAR_FILTER,
|
|
|
|
true);
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-04-19 14:13:58 -07:00
|
|
|
m_LoadedMesh->setMaterialFlag(video::EMF_BILINEAR_FILTER,
|
|
|
|
false);
|
|
|
|
m_LoadedMesh->setMaterialFlag(video::EMF_TRILINEAR_FILTER,
|
|
|
|
false);
|
2019-07-03 14:13:37 -07:00
|
|
|
// m_LoadedMesh->setMaterialFlag(video::E_ALPHA_SOURCE, true);
|
2019-04-08 19:52:18 -07:00
|
|
|
|
|
|
|
// below doesn't work for some reason:
|
2019-04-19 14:13:58 -07:00
|
|
|
// video::SMaterial mat = m_LoadedMesh->getMaterial(
|
|
|
|
// materialIndex
|
|
|
|
// );
|
2019-04-08 19:52:18 -07:00
|
|
|
// mat.UseMipMaps = false;
|
|
|
|
// mat.setFlag(video::EMF_BILINEAR_FILTER, false);
|
|
|
|
// mat.setFlag(video::EMF_TRILINEAR_FILTER, false);
|
|
|
|
|
|
|
|
// below would require patching Irrlicht:
|
|
|
|
// GLint filteringMipMaps = GL_NEAREST_MIPMAP_NEAREST
|
2019-04-19 14:13:58 -07:00
|
|
|
// // above is used by glTexParameteri(GL_TEXTURE_2D,
|
|
|
|
// // GL_TEXTURE_MIN_FILTER,
|
|
|
|
// // filteringMipMaps);
|
2019-04-08 19:52:18 -07:00
|
|
|
}
|
2010-08-16 05:23:20 -07:00
|
|
|
}
|
2019-04-11 01:31:04 -07:00
|
|
|
} else
|
|
|
|
debug() << "WARNING in setMeshDisplayMode: No mesh is loaded " << endl;
|
2010-08-16 05:23:20 -07:00
|
|
|
}
|
|
|
|
|
2019-03-07 21:52:29 -08:00
|
|
|
bool Engine::isAnimating()
|
|
|
|
{
|
2020-03-10 11:12:16 -07:00
|
|
|
return this->m_IsPlaying;
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::playAnimation()
|
|
|
|
{
|
|
|
|
if (this->animationFPS() < 1) {
|
|
|
|
this->setAnimationFPS(5);
|
|
|
|
}
|
|
|
|
if (!this->isAnimating()) {
|
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
if (this->m_PrevFPS < 1)
|
|
|
|
this->m_PrevFPS = 5;
|
|
|
|
this->m_LoadedMesh->setAnimationSpeed(this->m_PrevFPS);
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_IsPlaying = true;
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::pauseAnimation()
|
|
|
|
{
|
|
|
|
if (this->isAnimating()) {
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_PrevFPS = animationFPS();
|
2019-03-07 21:52:29 -08:00
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_PrevFPS = this->m_LoadedMesh->getAnimationSpeed();
|
2019-03-07 21:52:29 -08:00
|
|
|
this->m_LoadedMesh->setAnimationSpeed(0);
|
|
|
|
}
|
|
|
|
}
|
2020-03-10 11:12:16 -07:00
|
|
|
this->m_IsPlaying = false;
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::toggleAnimation()
|
|
|
|
{
|
|
|
|
if (this->isAnimating()) {
|
|
|
|
this->pauseAnimation();
|
|
|
|
debug() << "paused " << this->animationFPS() << "fps" << endl;
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-03-07 21:52:29 -08:00
|
|
|
this->playAnimation();
|
|
|
|
debug() << "unpaused " << this->animationFPS() << "fps" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::setAnimationFPS(u32 animationFPS)
|
|
|
|
{
|
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
if (animationFPS > 0) this->m_IsPlaying = true;
|
2019-04-19 14:13:58 -07:00
|
|
|
// Do NOT call playAnimation, otherwise infinite recursion occurs
|
|
|
|
// (it calls setAnimationFPS).
|
2019-03-07 21:52:29 -08:00
|
|
|
this->m_LoadedMesh->setAnimationSpeed(animationFPS);
|
2019-04-19 14:13:58 -07:00
|
|
|
this->m_UserInterface->playbackFPSEditBox->setText(
|
|
|
|
Utility::toWstring(this->m_LoadedMesh->getAnimationSpeed()).c_str()
|
|
|
|
);
|
2019-04-19 12:29:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Engine::incrementAnimationFPS(irr::f32 by)
|
|
|
|
{
|
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
|
|
|
if (by < 0) {
|
2019-04-19 14:13:58 -07:00
|
|
|
if (this->m_LoadedMesh->getAnimationSpeed() + by >= 0.999999f)
|
|
|
|
// don't use this->animationFPS() above--its unsigned!
|
|
|
|
this->setAnimationFPS(this->m_LoadedMesh->getAnimationSpeed()
|
|
|
|
+ by);
|
2019-04-19 12:29:30 -07:00
|
|
|
else
|
|
|
|
this->setAnimationFPS(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->setAnimationFPS(this->animationFPS() + by);
|
|
|
|
}
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 06:55:31 -07:00
|
|
|
void Engine::setZUp(bool zUp)
|
|
|
|
{
|
|
|
|
if (this->m_View != nullptr) {
|
|
|
|
this->m_View->setZUp(zUp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-07 21:52:29 -08:00
|
|
|
u32 Engine::animationFPS()
|
|
|
|
{
|
2019-04-19 12:29:30 -07:00
|
|
|
f32 ret = 0;
|
2019-03-07 21:52:29 -08:00
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
|
|
|
ret = this->m_LoadedMesh->getAnimationSpeed();
|
|
|
|
}
|
2019-04-19 12:29:30 -07:00
|
|
|
return static_cast<u32>(ret);
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
void Engine::run()
|
|
|
|
{
|
2019-03-07 21:52:29 -08:00
|
|
|
u32 timePerFrame = 1000.0f;
|
2020-03-10 11:12:16 -07:00
|
|
|
if (this->m_WorldFPS > 0) {
|
|
|
|
timePerFrame = static_cast<u32>(1000.0f / this->m_WorldFPS);
|
2019-03-07 21:52:29 -08:00
|
|
|
}
|
2019-04-11 01:31:04 -07:00
|
|
|
ITimer* timer = m_Device->getTimer();
|
2010-04-21 07:48:36 -07:00
|
|
|
|
2019-03-07 21:52:29 -08:00
|
|
|
// Run the Device with fps frames/sec
|
2019-04-11 01:31:04 -07:00
|
|
|
while (m_Device->run() && m_RunEngine) {
|
2010-04-21 07:48:36 -07:00
|
|
|
u32 startTime = timer->getRealTime();
|
|
|
|
|
|
|
|
checkResize();
|
2019-03-07 21:52:29 -08:00
|
|
|
if (this->m_LoadedMesh != nullptr) {
|
2020-03-10 11:12:16 -07:00
|
|
|
if (m_IsPlaying) {
|
2019-03-07 21:52:29 -08:00
|
|
|
this->m_LoadedMesh->setLoopMode(true);
|
2019-04-19 14:13:58 -07:00
|
|
|
this->m_UserInterface->playbackSetFrameEditBox->setText(
|
|
|
|
Utility::toWstring(this->m_LoadedMesh->getFrameNr()).c_str()
|
|
|
|
);
|
2019-04-11 01:31:04 -07:00
|
|
|
} else {
|
2019-03-07 21:52:29 -08:00
|
|
|
this->m_LoadedMesh->setLoopMode(false);
|
|
|
|
}
|
|
|
|
}
|
2010-04-21 07:48:36 -07:00
|
|
|
m_Driver->beginScene();
|
2019-04-11 01:31:04 -07:00
|
|
|
drawBackground(); // Draw Background
|
|
|
|
drawAxisLines(); // Draw XYZ Axis
|
|
|
|
m_Scene->drawAll(); // Draw Scenegraph
|
2010-04-23 00:28:59 -07:00
|
|
|
|
2010-04-21 07:48:36 -07:00
|
|
|
m_UserInterface->getGUIEnvironment()->drawAll();
|
2010-04-23 00:28:59 -07:00
|
|
|
m_UserInterface->drawStatusLine();
|
2010-04-21 07:48:36 -07:00
|
|
|
|
|
|
|
m_Driver->endScene();
|
|
|
|
|
2019-04-11 01:31:04 -07:00
|
|
|
u32 sleepTime = timePerFrame - (timer->getRealTime() - startTime);
|
|
|
|
if (sleepTime > 0 && sleepTime < timePerFrame)
|
|
|
|
m_Device->sleep(sleepTime, false);
|
2010-04-21 07:48:36 -07:00
|
|
|
}
|
|
|
|
}
|
2021-02-18 06:31:03 -08:00
|
|
|
|
|
|
|
bool Engine::loadScene(const std::wstring &fileName)
|
|
|
|
{
|
|
|
|
scene::ISceneManager* smgr = this->m_Device->getSceneManager();
|
|
|
|
bool result = smgr->loadScene(fileName.c_str());
|
|
|
|
return result;
|
|
|
|
}
|