Instruction:
(1) In the main.cpp file:
Edit the #define's to the respective folders:
#define IRRLICHT_DIR "..."
#define AIRPLANE_FILE "..."
#define AIRPLANE_TEX_FILE "..."
(2) Keyboard binding:
Keys A and D => turn airplane by rolling left / right
Keys W and S => pitch airplane up / down
Key Z => slow down airplane
Key X => stop airplane
Key C => speed up airplane
F1 => bring camera nearer to airplane
F3 => toggle focus / grab
F5 => toggle between fps camera and follow camera
Escape => quit
main.cpp
Code: Select all
#include <irrlicht.h>
#include <iostream>
#include "simple_flight_control.h"
#include "trajectory.h"
using namespace irr;
#ifndef MAIN_CPP_PROPERTIES
#define MAIN_CPP_PROPERTIES
#define IRRLICHT_DIR "/home/smso/downloads/irrlicht/irrlicht-1.7.2/"
#define AIRPLANE_FILE "/home/smso/downloads/irrlicht/irrlicht-1.7.2/media/dwarf.x"
#define AIRPLANE_TEX_FILE ""
#endif
IrrlichtDevice* device = 0;
scene::ISceneManager* smgr = 0;
scene::ICameraSceneNode* camera = 0;
scene::ICameraSceneNode* followCamera = 0;
scene::ISceneNode* airplane = 0;
SimpleFlightControl* flightControl = 0;
Trajectory* trajectory = 0;
////////////////////////////////////////////////////////////////////////////////
// some utility functions:
void updateFollowCamera
(
scene::ICameraSceneNode* camera,
scene::ISceneNode* node,
f32 minDist = 250.0f
)
{
camera->updateAbsolutePosition();
node->updateAbsolutePosition();
core::vector3df pos = camera->getAbsolutePosition();
core::vector3df target = node->getAbsolutePosition();
camera->setTarget(target);
if (minDist < 10.0f)
minDist = 10.0f;
core::vector3df vectorTC = pos - target;
if (vectorTC.getLengthSQ() < (minDist * minDist))
return;
vectorTC.normalize();
camera->setPosition(target + vectorTC * minDist);
camera->updateAbsolutePosition();
}
void rotateCameraTowardsNodeAroundYAxis
(
scene::ICameraSceneNode* camera,
scene::ISceneNode* node,
f32 minDist = 1.0f,
bool rotateCameraBy90Deg = false
)
{
node->updateAbsolutePosition();
core::vector3df pos = node->getAbsolutePosition();
camera->updateAbsolutePosition();
core::vector3df cameraPos = camera->getAbsolutePosition();
core::vector3df delta = pos - cameraPos;
core::vector3df rot = delta.getHorizontalAngle();
rot.X = 0.0f;
rot.Z = 0.0f;
if (rotateCameraBy90Deg)
rot.Y -= 90.0f;
camera->setRotation(rot);
// bring camera nearer to node:
if (minDist <= 1.0f)
return;
if (delta.getLengthSQ() < (minDist * minDist))
return;
delta *= 0.5f;
camera->setPosition(core::vector3df
(
cameraPos.X + delta.X,
cameraPos.Y + delta.Y,
cameraPos.Z + delta.Z
));
}
////////////////////////////////////////////////////////////////////////////////
class EventReceiver: public IEventReceiver
{
public:
bool OnEvent(const SEvent& event)
{
if (flightControl)
flightControl->OnEvent(event);
if
(
(event.EventType == EET_KEY_INPUT_EVENT)
&& (event.KeyInput.PressedDown == true)
)
{
if (event.KeyInput.Key == irr::KEY_ESCAPE)
{
device->closeDevice();
device->run();
return true;
}
else if (event.KeyInput.Key == irr::KEY_F1)
{
if (airplane)
{
scene::ICameraSceneNode* cam = smgr->getActiveCamera();
rotateCameraTowardsNodeAroundYAxis(cam, airplane, 5.0f);
}
}
else if (event.KeyInput.Key == irr::KEY_F2)
{
}
else if (event.KeyInput.Key == irr::KEY_F3)
{
bool enabled = camera->isInputReceiverEnabled();
camera->setInputReceiverEnabled(!enabled);
device->getCursorControl()->setVisible(enabled);
}
else if (event.KeyInput.Key == irr::KEY_F4)
{
}
else if (event.KeyInput.Key == irr::KEY_F5)
{
if (smgr->getActiveCamera() == followCamera)
{
smgr->setActiveCamera(camera);
if (airplane)
rotateCameraTowardsNodeAroundYAxis(camera, airplane, 5.0f);
}
else
{
smgr->setActiveCamera(followCamera);
}
}
else if (event.KeyInput.Key == irr::KEY_F6)
{
}
else if (event.KeyInput.Key == irr::KEY_F7)
{
}
else if (event.KeyInput.Key == irr::KEY_F8)
{
}
else if (event.KeyInput.Key == irr::KEY_F9)
{
}
else if (event.KeyInput.Key == irr::KEY_F10)
{
}
else if (event.KeyInput.Key == irr::KEY_F11)
{
}
else if (event.KeyInput.Key == irr::KEY_F12)
{
}
}
else
{
}
return false;
}
};
int main()
{
device = createDevice
(
video::EDT_OPENGL, core::dimension2d<u32>(1024, 768),
32,
false, false, false
);
if (device == 0)
return 1;
EventReceiver receiver;
device->setEventReceiver(&receiver);
video::IVideoDriver* driver = device->getVideoDriver();
smgr = device->getSceneManager();
io::IFileSystem* fs = device->getFileSystem();
fs->addFileArchive(IRRLICHT_DIR);
// load building:
scene::IMeshSceneNode* q3node = 0;
c8* filename = "media/map-20kdm2.pk3";
bool fileOk = fs->addZipFileArchive(filename);
if (!fileOk)
{
printf("Error adding file:\n%s\nto the file system\n\n", filename);
return -1;
}
io::path bspPath = "20kdm2.bsp";
scene::IAnimatedMesh* q3levelmesh = smgr->getMesh(bspPath);
if (q3levelmesh)
q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0));
if (q3node)
q3node->setPosition(core::vector3df(-1350.0f, -130.0f, -1400.0f));
////////////////////////////////////////////////////////////////////////////
// setup airplane:
// correct airplane mesh or rotate airplane node so that forward is in z-dir
scene::IAnimatedMesh* mesh = smgr->getMesh(AIRPLANE_FILE);
// FIXME
// work with mesh but does NOT work with animated mesh
//core::matrix4 mat;
//mat.setRotationDegrees(core::vector3df(0.0f, 180.0f, 0.0f));
//smgr->getMeshManipulator()->transform(mesh, mat);
airplane = smgr->addAnimatedMeshSceneNode(mesh);
for (u32 n=0; n<airplane->getMaterialCount(); ++n)
airplane->getMaterial(n).setFlag(video::EMF_LIGHTING, false);
airplane->setRotation(core::vector3df(0.0f, 180.0f, 0.0f));
f32 scale = 2.5f;
airplane->setScale(core::vector3df(scale));
// workaround for pivot not at the center of bbox:
core::vector3df center = airplane->getTransformedBoundingBox().getCenter();
airplane->setPosition(center * (-1.0f) * scale);
io::path texfile = AIRPLANE_TEX_FILE;
if (texfile.size() != 0)
airplane->setMaterialTexture(0, driver->getTexture(texfile));
// setup flight control:
flightControl = new SimpleFlightControl(smgr, airplane);
flightControl->getRootEmpty()->setPosition(core::vector3df(0.0f, 1000.0f, 0.0f));
trajectory = new Trajectory(device, flightControl->getRootEmpty());
trajectory->setColor(0x80FF0000);
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// setup camera:
f32 camRotateSpeed = 100.0f;
f32 camMoveSpeed = 0.5f;
f32 camJumpSpeed = 3.0f;
camera = smgr->addCameraSceneNodeFPS(0, camRotateSpeed, camMoveSpeed, -1, 0, 0, false, camJumpSpeed);
//camera->setPosition(core::vector3df(50.0f, 50.0f, -60.0f));
//camera->setTarget(core::vector3df(-70.0f, 30.0f, -60.0f));
camera->setFarValue(5000.0f);
camera->setPosition(airplane->getPosition() + core::vector3df(100.0f, 50.0f, 100.0f));
camera->setTarget(airplane->getPosition());
followCamera = smgr->addCameraSceneNode();
followCamera->setFarValue(5000.0f);
followCamera->bindTargetAndRotation(false);
smgr->setActiveCamera(followCamera);
////////////////////////////////////////////////////////////////////////////
// create skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
smgr->addSkyBoxSceneNode
(
driver->getTexture("media/irrlicht2_up.jpg"),
driver->getTexture("media/irrlicht2_dn.jpg"),
driver->getTexture("media/irrlicht2_lf.jpg"),
driver->getTexture("media/irrlicht2_rt.jpg"),
driver->getTexture("media/irrlicht2_ft.jpg"),
driver->getTexture("media/irrlicht2_bk.jpg")
);
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
////////////////////////////////////////////////////////////////////////////
device->getCursorControl()->setVisible(false);
// ----------------------------------------------------
u32 currentTime;
while (device->run())
if (device->isWindowActive())
{
currentTime = device->getTimer()->getTime();
updateFollowCamera(followCamera, airplane);
flightControl->update(currentTime);
trajectory->update();
driver->beginScene(true, true, 0);
smgr->drawAll();
trajectory->draw();
driver->endScene();
}
else { device->yield(); }
if (flightControl) { delete flightControl; flightControl = 0; }
if (trajectory) { delete trajectory; trajectory = 0; }
if (device) { device->drop(); }
return 0;
}
simple_flight_control.h
Code: Select all
#ifndef _SIMPLE_FLIGHT_CONTROL_H_
#define _SIMPLE_FLIGHT_CONTROL_H_
#include <vector>
#include <irrlicht.h>
using namespace irr;
#ifndef SIMPLE_FLIGHT_CONTROL_PROPERTIES
#define SIMPLE_FLIGHT_CONTROL_PROPERTIES
#define YAW_RATE 40.0f
#define MAX_SPEED 0.5f
#define MIN_SPEED 0.01f
#define ACCELERATION 0.01f
#define DECELERATION 0.02f
#endif
class SimpleFlightControl: public IEventReceiver
{
public:
SimpleFlightControl
(
scene::ISceneManager* smgr,
scene::ISceneNode* node,
f32 speed = 0.2f
);
virtual ~SimpleFlightControl();
virtual bool OnEvent(const SEvent& event);
void resetRotation(); //for debugging
void showDebugInfo();
void update(u32 time);
// movement:
void move(f32 distance);
void rotate(scene::ISceneNode* node, const core::vector3df& rot);
void yaw(f32 degs);
void pitch(f32 degs);
void roll(f32 degs);
void accelerate();
void brake();
void stop() { Speed = 0.0f; }
bool isStopped()
{
return core::iszero(Speed);
}
// getters and setters:
void setNode(scene::ISceneNode* node) { Node = node; }
void setRootEmpty(scene::ISceneNode* rootEmpty) { RootEmpty = rootEmpty; }
void setYawEmpty(scene::ISceneNode* yawEmpty) { YawEmpty = yawEmpty; }
void setPitchEmpty(scene::ISceneNode* pitchEmpty) { PitchEmpty = pitchEmpty; }
void setRollEmpty(scene::ISceneNode* rollEmpty) { RollEmpty = rollEmpty; }
scene::ISceneNode* getNode() const { return Node; }
scene::ISceneNode* getRootEmpty() const { return RootEmpty; }
scene::ISceneNode* getYawEmpty() const { return YawEmpty; }
scene::ISceneNode* getPitchEmpty() const { return PitchEmpty; }
scene::ISceneNode* getRollEmpty() const { return RollEmpty; }
core::vector3df getVelocity();
const core::vector3df& getNodeRotation() { return Node->getRotation(); }
void updateAbsolutePosition();
void setSpeed(f32 speed)
{
Speed = speed;
}
f32 getSpeed() const { return Speed; }
f32 getRollAngleDegs() const;
bool isInverted();
protected:
private:
scene::ISceneManager* Smgr;
scene::ISceneNode* Node;
scene::ISceneNode* RootEmpty;
scene::ISceneNode* YawEmpty;
scene::ISceneNode* PitchEmpty;
scene::ISceneNode* RollEmpty;
f32 PitchChange;
f32 Speed;
u32 LastTime;
};
#endif // _SIMPLE_FLIGHT_CONTROL_H_
simple_flight_control.cpp
Code: Select all
#include "simple_flight_control.h"
using namespace irr;
SimpleFlightControl::SimpleFlightControl
(
scene::ISceneManager* smgr,
scene::ISceneNode* node,
f32 speed
)
: Smgr(smgr),
Node(node),
RootEmpty(0),
YawEmpty(0),
PitchEmpty(0),
RollEmpty(0),
PitchChange(0.0f),
Speed(speed),
LastTime(0)
{
RootEmpty = Smgr->addEmptySceneNode(0);
YawEmpty = Smgr->addEmptySceneNode(RootEmpty);
PitchEmpty = Smgr->addEmptySceneNode(YawEmpty);
RollEmpty = Smgr->addEmptySceneNode(PitchEmpty);
Node->setParent(RollEmpty);
//RollEmpty = Smgr->addEmptySceneNode(YawEmpty);
//PitchEmpty = Smgr->addEmptySceneNode(RollEmpty);
//Node->setParent(PitchEmpty);
Node->setVisible(true);
}
SimpleFlightControl::~SimpleFlightControl()
{
}
bool SimpleFlightControl::OnEvent(const SEvent& event)
{
if
(
(event.EventType == EET_KEY_INPUT_EVENT)
&& (event.KeyInput.PressedDown == true)
)
{
if (event.KeyInput.Key == KEY_KEY_Q)
{
}
else if (event.KeyInput.Key == KEY_KEY_E)
{
}
else if (event.KeyInput.Key == KEY_KEY_A)
{
this->roll(3.99f);
}
else if (event.KeyInput.Key == KEY_KEY_D)
{
this->roll(-3.99f);
}
else if (event.KeyInput.Key == KEY_KEY_W)
{
this->pitch(1.99f);
}
else if (event.KeyInput.Key == KEY_KEY_S)
{
this->pitch(-1.99f);
}
else if (event.KeyInput.Key == KEY_KEY_Z)
{
this->brake();
}
else if (event.KeyInput.Key == KEY_KEY_X)
{
this->stop();
}
else if (event.KeyInput.Key == KEY_KEY_C)
{
this->accelerate();
}
}
return false;
}
void SimpleFlightControl::resetRotation()
{
Node->setRotation(core::vector3df(0.0f));
RootEmpty->setRotation(core::vector3df(0.0f));
YawEmpty->setRotation(core::vector3df(0.0f));
PitchEmpty->setRotation(core::vector3df(0.0f));
RollEmpty->setRotation(core::vector3df(0.0f));
}
void SimpleFlightControl::showDebugInfo()
{
f32 x = PitchEmpty->getRotation().X;
f32 z = RollEmpty->getRotation().Z;
printf("PitchRotX=%f, RollRotZ=%f\n", x, z);
}
////////////////////////////////////////////////////////////////////////////////
void SimpleFlightControl::update(u32 time)
{
f32 deltaTime = f32(time - LastTime);
f32 yawDegs = 0.0f;
f32 pitchEmptyRotX = PitchEmpty->getRotation().X;
if ((pitchEmptyRotX > 90.0f) && (pitchEmptyRotX < 270.0f)) // inverted
yawDegs = sin(RollEmpty->getRotation().Z * core::DEGTORAD) * deltaTime * 0.001f * YAW_RATE;
else
yawDegs = - sin(RollEmpty->getRotation().Z * core::DEGTORAD) * deltaTime * 0.001f * YAW_RATE;
this->yaw(yawDegs);
if (core::isnotzero(Speed))
move(deltaTime * Speed);
LastTime = time;
}
////////////////////////////////////////////////////////////////////////////////
void SimpleFlightControl::move(f32 distance)
{
updateAbsolutePosition();
core::matrix4 matrix = RollEmpty->getAbsoluteTransformation();
core::vector3df vect(0.0f, 0.0f, 1.0f);
matrix.rotateVect(vect);
vect.setLength(distance);
core::vector3df pos = RootEmpty->getPosition() + vect;
RootEmpty->setPosition(pos);
}
void SimpleFlightControl::rotate(scene::ISceneNode* node, const core::vector3df& rot)
{
core::matrix4 m;
m.setRotationDegrees(node->getRotation());
core::matrix4 n;
n.setRotationDegrees(rot);
m *= n;
node->setRotation(m.getRotationDegrees());
}
void SimpleFlightControl::yaw(f32 degs)
{
rotate(YawEmpty, core::vector3df(0.0f, degs, 0.0f));
//printf("YawEmpty->getRotation().Y=%f\n", YawEmpty->getRotation().Y);
}
void SimpleFlightControl::pitch(f32 degs)
{
f32 z = RollEmpty->getRotation().Z;
if ((z>90.0f) && (z<270.0f))
rotate(PitchEmpty, core::vector3df(degs, 0.0f, 0.0f));
else
rotate(PitchEmpty, core::vector3df(-degs, 0.0f, 0.0f));
//printf("PitchEmpty->getRotation().X=%f\n", PitchEmpty->getRotation().X);
}
void SimpleFlightControl::roll(f32 degs)
{
rotate(RollEmpty, core::vector3df(0.0f, 0.0f, degs));
//printf("RollEmpty->getRotation().Z=%f\n", RollEmpty->getRotation().Z);
}
void SimpleFlightControl::accelerate()
{
Speed += ACCELERATION;
if (Speed > MAX_SPEED)
Speed = MAX_SPEED;
}
void SimpleFlightControl::brake()
{
if (core::iszero(Speed))
{
Speed = MIN_SPEED;
return;
}
Speed -= DECELERATION;
if (Speed < MIN_SPEED)
Speed = MIN_SPEED;
}
core::vector3df SimpleFlightControl::getVelocity()
{
core::matrix4 matrix = RollEmpty->getAbsoluteTransformation();
core::vector3df heading(0.0f, 0.0f, 1.0f);
matrix.rotateVect(heading);
return Speed * heading;
}
void SimpleFlightControl::updateAbsolutePosition()
{
Node->updateAbsolutePosition();
RootEmpty->updateAbsolutePosition();
YawEmpty->updateAbsolutePosition();
PitchEmpty->updateAbsolutePosition();
RollEmpty->updateAbsolutePosition();
}
f32 SimpleFlightControl::getRollAngleDegs() const
{
return RollEmpty->getRotation().Z;
}
bool SimpleFlightControl::isInverted()
{
core::vector3df yaxis(0.0f, 1.0f, 0.0f);
core::matrix4 matrix = Node->getAbsoluteTransformation();
matrix.rotateVect(yaxis);
return (yaxis.Y < 0.0f);
}
trajectory.h
Code: Select all
#ifndef _TRAJECTORY_H_
#define _TRAJECTORY_H_
#include <vector>
#include <irrlicht.h>
#include <string>
#include <vector>
#include <deque>
using namespace irr;
#ifndef TRAJECTORY_PROPERTIES
#define TRAJECTORY_PROPERTIES
#define UPDATE_INTERVAL 200
#define POINT_COUNT_MAX 250
#endif
class Trajectory
{
public:
Trajectory
(
IrrlichtDevice* device,
scene::ISceneNode* node
);
virtual ~Trajectory();
void showDebugInfo();
void update();
void draw();
void setColor(video::SColor color) { Color = color; }
void addTrajectoryPoint
(
scene::ISceneNode* node,
std::deque<core::vector3df>& points,
u32 pointCountMax
);
void drawTrajectory(IrrlichtDevice* device, const std::deque<core::vector3df>& points, video::SColor color);
protected:
private:
IrrlichtDevice* Device;
scene::ISceneNode* Node;
video::SColor Color;
u32 LastUpdateTime;
std::deque<core::vector3df> Points;
};
#endif // _TRAJECTORY_H_
trajectory.cpp
Code: Select all
#include "trajectory.h"
using namespace irr;
Trajectory::Trajectory
(
IrrlichtDevice* device,
scene::ISceneNode* node
)
: Device(device),
Node(node),
Color(0x800000FF),
LastUpdateTime(0)
{
}
Trajectory::~Trajectory()
{
}
void Trajectory::showDebugInfo()
{
}
////////////////////////////////////////////////////////////////////////////////
void Trajectory::update()
{
u32 time = Device->getTimer()->getTime();
if (time > LastUpdateTime + UPDATE_INTERVAL)
{
addTrajectoryPoint(Node, Points, POINT_COUNT_MAX);
LastUpdateTime = time;
}
}
void Trajectory::draw()
{
drawTrajectory(Device, Points, Color);
}
void Trajectory::addTrajectoryPoint
(
scene::ISceneNode* node,
std::deque<core::vector3df>& points,
u32 pointCountMax
)
{
u32 pointCount = points.size();
if (pointCount >= pointCountMax)
{
points.pop_front();
}
node->updateAbsolutePosition();
core::vector3df pos = node->getAbsolutePosition();
if (!points.empty())
{
core::vector3df lastPoint = points[points.size()-1];
if (core::iszero(pos.getDistanceFromSQ(lastPoint)))
return;
}
points.push_back(pos);
}
void Trajectory::drawTrajectory(IrrlichtDevice* device, const std::deque<core::vector3df>& points, video::SColor color)
{
if (points.size() <= 1)
return;
//video::SColor blue(128, 0, 0, 255);
// set mat:
video::SMaterial lineMaterial;
lineMaterial.Lighting = false;
lineMaterial.Thickness = 3.0f;
lineMaterial.FrontfaceCulling = false;
lineMaterial.BackfaceCulling = false;
//lineMaterial.MaterialType = video::EMT_SOLID;
lineMaterial.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
video::IVideoDriver* driver = device->getVideoDriver();
driver->setMaterial(lineMaterial);
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
for (u32 n=0; n<(points.size()-1); ++n)
{
core::vector3df p1 = points[n];
core::vector3df p2 = points[n+1];
if (p1.equals(p2))
continue;
//driver->draw3DLine(p1, p2, blue);
driver->draw3DLine(p1, p2, color);
}
}
Regards
smso