Code: Select all
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
IrrlichtDevice *Device = 0;
IVideoDriver *driver = 0;
ISceneManager *smgr = 0;
IGUIEnvironment *env = 0;
ICameraSceneNode *camera = 0;
ISceneCollisionManager *CollMan = 0;
IMetaTriangleSelector * meta = 0;
#define ID_TRANSLATE 102
#define ID_ROTATE 103
#define ID_SCALE 104
#define ID_ADDBOX 105
enum
{
// I use this ISceneNode ID to indicate a scene node that is
// not pickable by getSceneNodeAndCollisionPointFromRay()
ID_IsNotPickable = 0,
// I use this flag in ISceneNode IDs to indicate that the
// scene node can be picked by ray selection.
IDFlag_IsPickable = 1 << 0,
// I use this flag in ISceneNode IDs to indicate that the
// scene node can be highlighted. In this example, the
// homonids can be highlighted, but the level mesh can't.
IDFlag_IsHighlightable = 1 << 1
};
enum EditorMode
{
MODE_NONE,
MODE_QUIT,
MODE_TRANSLATE,
MODE_ROTATE,
MODE_SCALE,
};
position2di initialCursorPosition; // where mouse cursor started
position2di initialObjectPosition; // where ray from camera to object intersected screen
ISceneNode* SelectedNode = 0; // the selected node
bool ShiftIsPressed = 0; // is the shift key pressed?
bool LMouseButtonDown = 0; // is the left mouse button down?
EditorMode Mode = MODE_NONE;
float RotateSpeed = 0.01f;
float ScaleSpeed = 0.01f;
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(const SEvent& event)
{
switch(event.EventType)
{
case EET_GUI_EVENT:
{
switch (event.GUIEvent.EventType)
{
case EGET_BUTTON_CLICKED:
{
switch (event.GUIEvent.Caller->getID())
{
case ID_TRANSLATE : { Mode = MODE_TRANSLATE; } break;
case ID_ROTATE : { Mode = MODE_ROTATE; } break;
case ID_SCALE : { Mode = MODE_SCALE; } break;
case ID_ADDBOX :
{
ISceneNode* box = smgr->addCubeSceneNode();
box->setMaterialTexture(0, driver->getTexture("fire.bmp"));
box->setMaterialFlag(video::EMF_LIGHTING, false);
box->setMaterialFlag(video::EMF_FOG_ENABLE,false);
ITriangleSelector * selector = smgr->createTriangleSelectorFromBoundingBox(box);;
meta->addTriangleSelector(selector);
} break;
}
} break;
}
} break;
case EET_KEY_INPUT_EVENT :
{
//check if "Shift" key is pressed
if (event.KeyInput.Shift)
ShiftIsPressed = true;
else
ShiftIsPressed = false;
switch (event.KeyInput.Char)
{
case 'm':
Mode = MODE_TRANSLATE;
break;
case 'r':
Mode = MODE_ROTATE;
break;
case 's':
Mode = MODE_SCALE;
break;
}
} break;
// if it is a mouse event
case EET_MOUSE_INPUT_EVENT :
{
// based upon the mouse event type
switch (event.MouseInput.Event)
{
case EMIE_LMOUSE_PRESSED_DOWN :
{
if (Mode == MODE_NONE) return false;
LMouseButtonDown = true;
// check for a node being selected
SelectedNode = CollMan->getSceneNodeFromScreenCoordinatesBB(Device->getCursorControl()->getPosition(),0,true);
//!need to check the node type
// If we selected a node
if(SelectedNode)
{
// Remember where the node and cursor were when it was clicked on
initialCursorPosition = Device->getCursorControl()->getPosition();
initialObjectPosition = CollMan->getScreenCoordinatesFrom3DPosition(SelectedNode->getAbsolutePosition(), camera);
SelectedNode->setDebugDataVisible(scene::EDS_BBOX);
SMaterial m;
m.setTexture(0,0);
m.Lighting=false;
driver->setMaterial(m);
driver->setTransform(video::ETS_WORLD, core::matrix4());
driver->draw3DLine(SelectedNode->getAbsolutePosition(), SelectedNode->getAbsolutePosition() + vector3df(0,500,0), SColor(255,255,0,0));
}
return false;
} break;
case EMIE_LMOUSE_LEFT_UP :
{
LMouseButtonDown = false;
if (SelectedNode) SelectedNode->setDebugDataVisible(scene::EDS_OFF);
SelectedNode = 0;
return false;
} break;
case EMIE_RMOUSE_LEFT_UP :
{
if (camera)
{
camera->setInputReceiverEnabled(!camera->isInputReceiverEnabled());
Device->getCursorControl()->setVisible(!camera->isInputReceiverEnabled());
if (camera->isInputReceiverEnabled()) Mode = MODE_NONE;
}
} break;
case EMIE_MOUSE_MOVED :
{
if (!LMouseButtonDown) return false;
if (Mode == MODE_TRANSLATE)
{
if (SelectedNode)
{
vector3df p = SelectedNode->getPosition();
if (ShiftIsPressed)
{
plane3df const planeXY(SelectedNode->getAbsolutePosition(), vector3df(0.f, 0.f, 1.f));
position2di currentCursorPosition(Device->getCursorControl()->getPosition());
position2di effectiveObjectPosition = initialObjectPosition + currentCursorPosition - initialCursorPosition;
line3df ray(CollMan->getRayFromScreenCoordinates(effectiveObjectPosition, camera));
vector3df intersectWithPlane;
vector3df oldPos = SelectedNode->getAbsolutePosition();
if(planeXY.getIntersectionWithLine(ray.start, ray.getVector(), intersectWithPlane))
{
intersectWithPlane.X = oldPos.X;
intersectWithPlane.Z = oldPos.Z;
SelectedNode->setPosition(intersectWithPlane);
}
}
else
{
plane3df const planeXZ(SelectedNode->getAbsolutePosition(), vector3df(0.f, 1.f, 0.f));
position2di currentCursorPosition(Device->getCursorControl()->getPosition());
position2di effectiveObjectPosition = initialObjectPosition + currentCursorPosition - initialCursorPosition;
line3df ray(CollMan->getRayFromScreenCoordinates(effectiveObjectPosition, camera));
vector3df intersectWithPlane;
if(planeXZ.getIntersectionWithLine(ray.start, ray.getVector(), intersectWithPlane))
{
SelectedNode->setPosition(intersectWithPlane);
}
}
}
} // end mode translate
else
if (Mode == MODE_ROTATE)
{
if (SelectedNode)
{
vector3df rot = SelectedNode->getRotation();
position2di currentCursorPosition(Device->getCursorControl()->getPosition());
if (ShiftIsPressed)
{
if (initialObjectPosition.X < currentCursorPosition.X) rot.X -= RotateSpeed;
if (initialObjectPosition.X > currentCursorPosition.X) rot.X += RotateSpeed;
}
else
{
// if (initialObjectPosition.X < currentCursorPosition.X) rot.Y -= RotateSpeed;
//if (initialObjectPosition.X > currentCursorPosition.X) rot.Y += RotateSpeed;
if (initialObjectPosition.X < currentCursorPosition.X) rot.Y -= 1;
if (initialObjectPosition.X > currentCursorPosition.X) rot.Y += 1;
if (initialObjectPosition.Y < currentCursorPosition.Y) rot.X -= 1;
if (initialObjectPosition.Y > currentCursorPosition.Y) rot.X += 1;
}
initialObjectPosition = currentCursorPosition;
SelectedNode->setRotation(rot);
}
}
else
if (Mode == MODE_SCALE)
{
if (SelectedNode)
{
vector3df scale = SelectedNode->getScale();
position2di currentCursorPosition(Device->getCursorControl()->getPosition());
if (initialObjectPosition.X > currentCursorPosition.X)
{
scale.X -= ScaleSpeed;
scale.Y -= ScaleSpeed;
scale.Z -= ScaleSpeed;
}
if (initialObjectPosition.X < currentCursorPosition.X)
{
scale.X += ScaleSpeed;
scale.Y += ScaleSpeed;
scale.Z += ScaleSpeed;
}
initialObjectPosition = currentCursorPosition;
SelectedNode->setScale(scale);
}
}
} break;
}
}
}
return false;
}
};
enum
{
GUI_ID_DIALOG_ROOT_WINDOW = 0x10000,
GUI_ID_X_SCALE,
GUI_ID_Y_SCALE,
GUI_ID_Z_SCALE,
GUI_ID_NEW_MODEL,
GUI_ID_LOAD_FLOOR_PLAN,
GUI_ID_SAVE_FLOOR_PLAN,
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,
// And some magic numbers
MAX_FRAMERATE = 1000,
DEFAULT_FRAMERATE = 30
};
void createToolBox()
{
// remove tool box if already there
IGUIElement* root = env->getRootGUIElement();
IGUIElement* e = root->getElementFromId(GUI_ID_DIALOG_ROOT_WINDOW, true);
if (e)
e->remove();
// create the toolbox window
IGUIWindow* wnd = env->addWindow(core::rect<s32>(700,95,900,530),
false, L"Toolset", 0, GUI_ID_DIALOG_ROOT_WINDOW);
// create tab control and tabs
IGUITabControl* tab = env->addTabControl(
core::rect<s32>(2,20,800-602,480-7), wnd, true, true);
IGUITab* t1 = tab->addTab(L"Config");
// add some edit boxes and a button to tab one
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_NEW_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");
// quick scale buttons
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);
// add transparency control
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);
// add framerate control
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);
// bring irrlicht engine logo to front, because it
// now may be below the newly created toolbox
root->bringToFront(root->getElementFromId(666, true));
}
void GUI()
{
// add my little plug
int x = 10;
int y = 60;
int width = 100;
int height = 20;
int space = 5;
env->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_TRANSLATE,L"Translate");
y += height + space;
env->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_ROTATE,L"Rotate");
y += height + space;
env->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_SCALE,L"Scale");
y += height + space;
env->addButton(core::rect<s32>(x,y,x+width,y+height),0,ID_ADDBOX,L"Add A Box");
// set a nicer font
IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
// create menu
gui::IGUIContextMenu* menu = env->addMenu();
menu->addItem(L"File", -1, true, true);
menu->addItem(L"Edit", -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"New project", GUI_ID_NEW_MODEL);
submenu->addItem(L"Load 3D floor plan", GUI_ID_LOAD_FLOOR_PLAN);
submenu->addItem(L"Save 3D floor plan", GUI_ID_SAVE_FLOOR_PLAN);
submenu->addSeparator();
submenu->addItem(L"Quit", GUI_ID_QUIT);
submenu = menu->getSubMenu(2);
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(2)->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(3);
submenu->addItem(L"Maya Style", GUI_ID_CAMERA_MAYA);
submenu->addItem(L"First Person", GUI_ID_CAMERA_FIRST_PERSON);
submenu = menu->getSubMenu(4);
submenu->addItem(L"About", GUI_ID_ABOUT);
/*
Below the menu we want a toolbar, onto which we can place colored
buttons and important looking stuff like a senseless combobox.
*/
// create toolbar
gui::IGUIToolBar* bar = env->addToolBar();
IVideoDriver* driver = Device->getVideoDriver();
video::ITexture* image = driver->getTexture("open.png");
bar->addButton(GUI_ID_BUTTON_OPEN_MODEL, 0, L"Open a model",image, 0, true, 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);
// create a combobox with some senseless text
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");
/*
To make the editor look a little bit better, we disable transparent gui
elements, and add an Irrlicht Engine logo. In addition, a text showing
the current frames per second value is created and the window caption is
changed.
*/
// 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);
}
// add a tabcontrol
createToolBox();
}
int main(int argc, char* argv[])
{
// create device and exit if creation failed
MyEventReceiver receiver;
Device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(1024, 768),
16, false, false, false, &receiver);
if (Device == 0)
return 1; // could not create selected driver.
Device->setResizable(true);
Device->setWindowCaption(L"3D Floor Plan Creator");
driver = Device->getVideoDriver();
env = Device->getGUIEnvironment();
smgr = Device->getSceneManager();
smgr->getParameters()->setAttribute(scene::COLLADA_CREATE_SCENE_INSTANCES, true);
CollMan = smgr->getSceneCollisionManager();
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));
// add media directory as "search path"
Device->getFileSystem()->addFolderFileArchive("../../media/");
GUI();
// add a camera
camera = smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, ID_IsNotPickable, 0, 0, false, 3.f);
camera->setPosition(vector3df(0,40,-40));
camera->setTarget(vector3df(0,0,0));
camera->setIsDebugObject(true);
camera->setInputReceiverEnabled(false);
//smgr->loadScene("zzz.irr");
// Create a meta triangle selector to hold several triangle selectors.
meta = smgr->createMetaTriangleSelector();
/*
Now we will find all the nodes in the scene and create triangle
selectors for all suitable nodes. Typically, you would want to make a
more informed decision about which nodes to performs collision checks
on; you could capture that information in the node name or Id.
*/
core::array<scene::ISceneNode *> nodes;
smgr->getSceneNodesFromType(scene::ESNT_ANY, nodes); // Find all nodes
for (u32 i=0; i < nodes.size(); ++i)
{
ISceneNode * node = nodes[i];
ITriangleSelector * selector = 0;
switch(node->getType())
{
case ESNT_CUBE:
case ESNT_ANIMATED_MESH:
// Because the selector won't animate with the mesh,
// and is only being used for camera collision, we'll just use an approximate
// bounding box instead of ((scene::IAnimatedMeshSceneNode*)node)->getMesh(0)
selector = smgr->createTriangleSelectorFromBoundingBox(node);
break;
case ESNT_MESH:
case ESNT_SPHERE: // Derived from IMeshSceneNode
selector = smgr->createTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node);
break;
case ESNT_TERRAIN:
selector = smgr->createTerrainTriangleSelector((scene::ITerrainSceneNode*)node);
break;
case ESNT_OCTREE:
selector = smgr->createOctreeTriangleSelector(((scene::IMeshSceneNode*)node)->getMesh(), node);
break;
default:
// Don't create a selector for this node type
break;
}
if(selector)
{
// Add it to the meta selector, which will take a reference to it
meta->addTriangleSelector(selector);
// And drop my reference to it, so that the meta selector owns it.
selector->drop();
}
}
/*
Now that the mesh scene nodes have had triangle selectors created and added
to the meta selector, create a collision response animator from that meta selector.
*/
ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
meta, camera, core::vector3df(5,5,5),
core::vector3df(0,0,0));
meta->drop();
camera->addAnimator(anim);
anim->drop();
while(Device->run())
{
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
env->drawAll();
driver->endScene();
}
Device->drop();
return 0;
}
For example, if I move my mouse to right, the box is not rotating around the y axis entirely.
Also, if you right click the mouse and move the camera to another position, then rotate the box again, you will notice that the rotation is not correct.
My question is:
Is there any way to rotate a scene node to a direction according to the camera?