Add keyboard control of movement of the balance wheel

master
Andrey2470T 2021-03-02 01:35:00 +03:00
parent 4890cccd14
commit 8be6741d7a
6 changed files with 534 additions and 77 deletions

View File

@ -12,6 +12,8 @@ CXXFLAGS += -std=c++17
LIBS += -L$(IRRLICHT_PATH)/lib/Linux -lIrrlicht -L/usr/X11R6/lib64 -lGL -lXxf86vm -lXext -lX11
SOURCES = main.cpp
TARGET = balance_wheel
.PHONY : all clean
@ -19,7 +21,7 @@ TARGET = balance_wheel
all : clean $(TARGET)
$(TARGET) :
g++ $(CPPFLAGS) $(CXXFLAGS) main.cpp -o $(TARGET) $(LIBS)
g++ $(CPPFLAGS) $(CXXFLAGS) $(SOURCES) -o $(TARGET) $(LIBS)
clean :
rm -f $(TARGET).o

Binary file not shown.

190
custom_camera.cpp Normal file
View File

@ -0,0 +1,190 @@
#include "custom_camera.h"
AppCameraSceneNode::AppCameraSceneNode(s32 id, scene::ISceneManager* smgr, scene::ISceneNode* parent,
f32 rot_speed, f32 zoom_speed, const core::vector3df& target,
const core::vector3df& pos, const core::vector3df& rot, const core::vector3df& scale)
: scene::ICameraSceneNode(parent, smgr, id, pos, rot, scale),
rotSpeed(rot_speed), zoomSpeed(zoom_speed), cursorPosDelta(0.0f, 0.0f), lastCursorPos(0.0f, 0.0f), mouseInputEvent(EMIE_COUNT), wheel(0.0f), isMiddlePressedDown(false)
{
setTarget(target);
}
void AppCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)
{
}
const core::matrix4& AppCameraSceneNode::getProjectionMatrix() const
{
return core::matrix4();
}
const core::matrix4& AppCameraSceneNode::getViewMatrix() const
{
return core::matrix4();
}
void AppCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)
{
}
const core::matrix4& AppCameraSceneNode::getViewMatrixAffector() const
{
return core::matrix4();
}
bool AppCameraSceneNode::OnEvent(const SEvent& event)
{
mouseInputEvent = EMIE_COUNT;
wheel = 0.0f;
isMiddlePressedDown = false;
if (event.EventType == EET_MOUSE_INPUT_EVENT)
switch (event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
mouseInputEvent = EMIE_MOUSE_WHEEL;
wheel = event.MouseInput.Wheel;
break;
case EMIE_MMOUSE_PRESSED_DOWN:
mouseInputEvent = EMIE_MMOUSE_PRESSED_DOWN;
lastCursorPos = core::vector2df((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
break;
case EMIE_MOUSE_MOVED:
mouseInputEvent = EMIE_MOUSE_MOVED;
core::vector2df cur_cursor_pos = core::vector2df((f32)event.MouseInput.X, (f32)event.MouseInput.Y);
cursorPosDelta = core::vector2df(cur_cursor_pos - lastCursorPos);
lastCursorPos = cur_cursor_pos;
isMiddlePressedDown = true;
break;
}
return false;
}
void AppCameraSceneNode::setRotation(const core::vector3df& rotation)
{
scene::ISceneNode::setRotation(rotation);
}
void AppCameraSceneNode::setTarget(const core::vector3df& pos)
{
targetPos = pos;
core::vector3df rel_target = pos - getPosition();
core::vector3df angles = rel_target.getHorizontalAngle();
setRotation(angles);
}
const core::vector3df& AppCameraSceneNode::getTarget() const
{
return targetPos;
}
void AppCameraSceneNode::setUpVector(const core::vector3df& pos)
{
}
const core::vector3df& AppCameraSceneNode::getUpVector() const
{
return core::vector3df(0);
}
f32 AppCameraSceneNode::getNearValue() const
{
return 0;
}
f32 AppCameraSceneNode::getFarValue() const
{
return 0;
}
f32 AppCameraSceneNode::getAspectRatio() const
{
return 0;
}
f32 AppCameraSceneNode::getFOV() const
{
return 0;
}
void AppCameraSceneNode::setNearValue(f32 zn)
{
}
void AppCameraSceneNode::setFarValue(f32 zf)
{
}
void AppCameraSceneNode::setAspectRatio(f32 aspect)
{
}
void AppCameraSceneNode::setFOV(f32 fovy)
{
}
const scene::SViewFrustum* AppCameraSceneNode::getViewFrustum() const
{
return nullptr;
}
void AppCameraSceneNode::setInputReceiverEnabled(bool enabled)
{
}
bool AppCameraSceneNode::isInputReceiverEnabled() const
{
return true;
}
void AppCameraSceneNode::bindTargetAndRotation(bool bound)
{
}
bool AppCameraSceneNode::getTargetAndRotationBinding(void) const
{
return true;
}
core::aabbox3df& AppCameraSceneNode::getBoundingBox() const
{
core::aabbox3df bounding_box;
return bounding_box;
}
void AppCameraSceneNode::render()
{
}
void AppCameraSceneNode::OnRegisterSceneNode()
{
SceneManager->registerNodeForRendering(this, scene::ESNRP_CAMERA);
scene::ISceneNode::OnRegisterSceneNode();
}
void AppCameraSceneNode::updateTarget()
{
setTarget(getTarget());
}
f32 AppCameraSceneNode::getRotationSpeed() const
{
return rotSpeed;
}
f32 AppCameraSceneNode::getZoomSpeed() const
{
return zoomSpeed;
}
EMOUSE_INPUT_EVENT AppCameraSceneNode::getMouseInputEvent() const
{
return mouseInputEvent;
}
f32 AppCameraSceneNode::getWheel() const
{
return wheel;
}

94
custom_camera.h Normal file
View File

@ -0,0 +1,94 @@
#include <irrlicht.h>
using namespace std;
using namespace irr;
class AppCameraSceneNode : public scene::ICameraSceneNode
{
public:
AppCameraSceneNode(s32 id, scene::ISceneManager* smgr, scene::ISceneNode* parent = 0,
f32 rot_speed = 30.0f, f32 zoom_speed = 3.0f, const core::vector3df& target = core::vector3df(0.0f, 0.0f, 0.0f),
const core::vector3df& pos = core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df& rot = core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)
);
virtual void setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal=false) override;
virtual const core::matrix4& getProjectionMatrix() const override;
virtual const core::matrix4& getViewMatrix() const override;
virtual void setViewMatrixAffector(const core::matrix4& affector) override;
virtual const core::matrix4& getViewMatrixAffector() const override;
virtual bool OnEvent(const SEvent& event) override;
virtual void setRotation(const core::vector3df& rotation) override;
virtual void setTarget(const core::vector3df& pos) override;
virtual const core::vector3df& getTarget() const override;
virtual void setUpVector(const core::vector3df& pos) override;
virtual const core::vector3df& getUpVector() const override;
virtual f32 getNearValue() const override;
virtual f32 getFarValue() const override;
virtual f32 getAspectRatio() const override;
virtual f32 getFOV() const override;
virtual void setNearValue(f32 zn) override;
virtual void setFarValue(f32 zf) override;
virtual void setAspectRatio(f32 aspect) override;
virtual void setFOV(f32 fovy) override;
virtual const scene::SViewFrustum* getViewFrustum() const override;
virtual void setInputReceiverEnabled(bool enabled) override;
virtual bool isInputReceiverEnabled() const override;
virtual void bindTargetAndRotation(bool bound) override;
virtual bool getTargetAndRotationBinding(void) const override;
virtual core::aabbox3df& getBoundingBox() const override;
virtual void render() override;
virtual void OnRegisterSceneNode() override;
void updateTarget();
f32 getRotationSpeed() const;
f32 getZoomSpeed() const;
EMOUSE_INPUT_EVENT getMouseInputEvent() const;
f32 getWheel() const;
bool getMiddlePressedDown() const
{
return isMiddlePressedDown;
}
core::vector2df cursorPosDelta;
private:
f32 rotSpeed;
f32 zoomSpeed;
EMOUSE_INPUT_EVENT mouseInputEvent;
f32 wheel;
bool isMiddlePressedDown;
core::vector2df lastCursorPos;
core::vector3df targetPos;
};

31
custom_event_receiver.h Normal file
View File

@ -0,0 +1,31 @@
#include <irrlicht.h>
using namespace std;
using namespace irr;
class AppEventReceiver : public IEventReceiver
{
public:
AppEventReceiver() : isEscPressed(false), camera_input(nullptr)
{
}
virtual bool OnEvent(const SEvent& event)
{
if (camera_input)
camera_input->OnEvent(event);
if (event.EventType == EET_KEY_INPUT_EVENT &&
event.KeyInput.Key == KEY_ESCAPE &&
event.KeyInput.PressedDown
)
{
isEscPressed = true;
}
return false;
}
bool isEscPressed;
scene::ICameraSceneNode* camera_input;
};

292
main.cpp
View File

@ -5,29 +5,122 @@
using namespace std;
using namespace irr;
namespace irr
{
namespace core
{
typedef vector3df position3df;
}
}
struct BalanceWheelParams
{
const f32 gravity = -9.8;
f32 original_len = 40.f;
f32 mass = 1.f;
f32 elasticity = 1000.f;
f32 friction_coef = 0.00f;
f32 string_friction_coef = 50.0f;
const f32 original_start_ang = 30.f; // in degrees
const core::position3df pos = core::position3df(0.f, 0.f, 0.f);
f32 elasticity = 100.f;
f32 friction_coef = 0.1f;
f32 string_friction_coef = 1.0f;
const f32 original_start_ang = 60.f; // in degrees
const core::vector3df pos = core::vector3df(0.f, 0.f, 0.f);
const core::vector3df scale = core::vector3df(0.5, 1.f, 1.f);
const f32 radius = 5.f;
const f32 original_vel = 0.f;
const f32 push_force = 500.0f;
};
struct CameraParams
{
f32 offset = 3.0f;
f32 rot_speed = 30.0f;
};
enum ObjectID
{
OBJECT_ID_BALANCE_WHEEL = 0,
OBJECT_ID_PLATFORM,
OBJECT_ID_LIGHT,
OBJECT_ID_CAMERA
};
gui::IGUIWindow *exit_wnd = nullptr;
class AppEventReceiver : public IEventReceiver
{
public:
AppEventReceiver() : isEscPressed(false), isMiddleMousePressed(false), wheel(0.0f), mousePosDelta(0.0f, 0.0f, 0.0f), lastMousePos(0.0f, 0.0f, 0.0f),
isUpPressed(false), isDownPressed(false), isLeftPressed(false), isRightPressed(false)
{
}
virtual bool OnEvent(const SEvent& event)
{
switch (event.EventType)
{
case EET_KEY_INPUT_EVENT:
if (event.KeyInput.Key == KEY_ESCAPE)
{
isEscPressed = true;
break;
}
if (exit_wnd != nullptr)
return false;
switch (event.KeyInput.Key)
{
case KEY_UP:
isUpPressed = true;
break;
case KEY_DOWN:
isDownPressed = true;
break;
case KEY_LEFT:
isLeftPressed = true;
break;
case KEY_RIGHT:
isRightPressed = true;
break;
default:
break;
}
break;
case EET_MOUSE_INPUT_EVENT:
if (exit_wnd != nullptr)
return false;
switch (event.MouseInput.Event)
{
case EMIE_MOUSE_WHEEL:
wheel = event.MouseInput.Wheel;
break;
case EMIE_MMOUSE_PRESSED_DOWN:
isMiddleMousePressed = true;
lastMousePos = core::vector3df((f32)event.MouseInput.X, (f32)event.MouseInput.Y, 0.0f);
mousePosDelta = core::vector3df(0.0f, 0.0f, 0.0f);
break;
case EMIE_MMOUSE_LEFT_UP:
isMiddleMousePressed = false;
break;
case EMIE_MOUSE_MOVED:
mousePosDelta = core::vector3df((f32)event.MouseInput.X, (f32)event.MouseInput.Y, 0.0f) - lastMousePos;
lastMousePos = core::vector3df((f32)event.MouseInput.X, (f32)event.MouseInput.Y, 0.0f);
break;
default:
break;
}
break;
default:
break;
}
return false;
}
bool isEscPressed;
bool isMiddleMousePressed;
bool isUpPressed;
bool isDownPressed;
bool isLeftPressed;
bool isRightPressed;
f32 wheel;
core::vector3df mousePosDelta;
core::vector3df lastMousePos;
};
/*class AppEventReceiver : public IEventReceiver
{
public:
@ -68,37 +161,6 @@ public:
gui::IGUIElement* pressed_btn;
};*/
class AppEventReceiver : public IEventReceiver
{
public:
AppEventReceiver() : isEscPressed(false)
{
}
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_KEY_INPUT_EVENT &&
event.KeyInput.Key == KEY_ESCAPE &&
event.KeyInput.PressedDown
)
{
isEscPressed = true;
}
else if (event.EventType == EET_MOUSE_INPUT_EVENT)
if (event.MouseInput.Event == EMIE_MOUSE_WHEEL)
{
isMouseWheelChanged = true;
wheel = event.MouseInput.Wheel;
}
return false;
}
bool isEscPressed;
bool isMouseWheelChanged;
f32 wheel;
};
void createExitDialogueWindow(gui::IGUIEnvironment* env)
{
if (env == nullptr)
@ -107,9 +169,9 @@ void createExitDialogueWindow(gui::IGUIEnvironment* env)
gui::IGUISkin* skin = env->getSkin();
skin->setColor(gui::EGDC_3D_DARK_SHADOW, video::SColor(255, 255, 255, 255));
core::recti exit_w_rect(core::position2di(256, 192), core::dimension2di(512, 384));
gui::IGUIWindow* exit_w = env->addWindow(exit_w_rect, true, 0, 0, 1);
exit_wnd = env->addWindow(exit_w_rect, true, 0, 0, 1);
if (exit_w == nullptr)
if (exit_wnd == nullptr)
{
std::cout << "The exit window fails to be created!" << std::endl;
return;
@ -117,7 +179,7 @@ void createExitDialogueWindow(gui::IGUIEnvironment* env)
gui::IGUIButton* cbut = env->addButton(core::recti(
core::position2di(512/2-128, 384/2-384/4-64), core::dimension2di(2*128, 64)
), exit_w, 2, L"Continue");
), exit_wnd, 2, L"Continue");
if (cbut == nullptr)
{
@ -129,7 +191,7 @@ void createExitDialogueWindow(gui::IGUIEnvironment* env)
gui::IGUIButton* exit_but = env->addButton(core::recti(
core::position2di(512/2-128, 384/2+384/4-64), core::dimension2di(2*128, 64)
), exit_w, 3, L"Exit");
), exit_wnd, 3, L"Exit");
if (exit_but == nullptr)
{
@ -152,24 +214,24 @@ int main()
scene::ISceneManager* smgr = device->getSceneManager();
video::IVideoDriver* vdrv = device->getVideoDriver();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
io::IFileSystem* fsys = device->getFileSystem();
AppEventReceiver receiver;
device->setEventReceiver(&receiver);
BalanceWheelParams params;
BalanceWheelParams bw_params;
CameraParams c_params;
core::position3df end(
params.original_len*std::sin(core::degToRad(params.original_start_ang)),
-params.original_len*std::cos(core::degToRad(params.original_start_ang)),
core::vector3df end(
bw_params.original_len*std::sin(core::degToRad(bw_params.original_start_ang)),
-bw_params.original_len*std::cos(core::degToRad(bw_params.original_start_ang)),
0.f
);
core::line3df beam(params.pos, params.pos + end);
core::line3df beam(bw_params.pos, bw_params.pos + end);
std::cout << "end: X: " << end.X << ", Y: " << end.Y << ", Z: " << end.Z << std::endl;
std::cout << "beam.end: X: " << beam.end.X << ", Y: " << beam.end.Y << ", Z: " << beam.end.Z << std::endl;
scene::IMeshSceneNode* bal_wheel = smgr->addSphereSceneNode(params.radius, 32, 0, 1);
scene::IMeshSceneNode* bal_wheel = smgr->addSphereSceneNode(bw_params.radius, 32, 0, OBJECT_ID_BALANCE_WHEEL);
if (bal_wheel == nullptr)
{
@ -178,8 +240,8 @@ int main()
}
bal_wheel->setPosition(beam.end);
bal_wheel->setScale(params.scale);
bal_wheel->setRotation(core::vector3df(0.f, 0.f, params.original_start_ang));
bal_wheel->setScale(bw_params.scale);
bal_wheel->setRotation(core::vector3df(0.f, 0.f, bw_params.original_start_ang));
video::SMaterial material;
material.MaterialType = video::EMT_LIGHTMAP_LIGHTING;
@ -195,7 +257,7 @@ int main()
scene::IMeshSceneNode* platform = smgr->addMeshSceneNode(
smgr->getMesh(fsys->getAbsolutePath("./models/stone_square.b3d")),
0, 2
0, OBJECT_ID_PLATFORM
);
if (platform == nullptr)
@ -204,14 +266,14 @@ int main()
return 1;
}
platform->setPosition(core::position3df(params.pos.X, params.pos.Y - params.original_len - params.radius - 3.f, 0.f));
platform->setPosition(core::vector3df(bw_params.pos.X, bw_params.pos.Y - bw_params.original_len - bw_params.radius - 3.f, 0.f));
platform->getMaterial(0) = material;
platform->setMaterialTexture(0, vdrv->getTexture(fsys->getAbsolutePath("./textures/stone2.jpg")));
platform->addShadowVolumeSceneNode();
scene::ILightSceneNode* light = smgr->addLightSceneNode(0, core::position3df(params.pos.X + 10.f, params.pos.Y, 0.f), video::SColorf(255.f, 255.f, 255.f, 255.f), 50.f, 3);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 100.f, 0.5f, 4);
camera->setPosition(core::position3df(0.f, params.pos.Y+10.f, 30.f));
scene::ILightSceneNode* light = smgr->addLightSceneNode(0, core::vector3df(bw_params.pos.X + 10.f, bw_params.pos.Y, 0.f), video::SColorf(255.f, 255.f, 255.f, 255.f), 50.f, OBJECT_ID_LIGHT);
scene::ICameraSceneNode* camera = smgr->addCameraSceneNode(0, core::vector3df(0.0f, -bw_params.original_len/2, bw_params.original_len), core::vector3df(0.0f, -bw_params.original_len, 0.0f), OBJECT_ID_CAMERA, true);
camera->bindTargetAndRotation(true);
if (light == nullptr)
{
@ -219,21 +281,95 @@ int main()
return 1;
}
f32 cam_offset_dist = 2.5f;
smgr->addTextSceneNode(env->getBuiltInFont(), L"X", video::SColor(255, 255, 255, 255), 0, core::vector3df(55.0f, 0.0f, 0.0f), 5);
smgr->addTextSceneNode(env->getBuiltInFont(), L"Y", video::SColor(255, 255, 255, 255), 0, core::vector3df(0.0f, 55.0f, 0.0f), 6);
smgr->addTextSceneNode(env->getBuiltInFont(), L"Z", video::SColor(255, 255, 255, 255), 0, core::vector3df(0.0f, 0.0f, 55.0f), 7);
core::vector3df cur_vel(params.original_vel);
core::position3df cur_rel_pos(end);
core::vector3df cur_vel(bw_params.original_vel);
core::vector3df cur_rel_pos(end);
core::vector3df cur_push_force(0.0f, 0.0f, 0.0f);
while(device->run())
{
if (device->isWindowActive())
{
cur_push_force = core::vector3df(0.0f, 0.0f, 0.0f);
if (receiver.isEscPressed)
{
device->closeDevice();
/*createExitDialogueWindow(device->getGUIEnvironment());
receiver.isEscPressed = false;*/
}
else if (receiver.isMouseWheelChanged)
else if (receiver.wheel != 0.0f)
{
core::vector3df cur_target = camera->getTarget();
const core::vector3df& cur_pos = camera->getPosition();
core::vector3df rel_target = cur_target - cur_pos;
s16 sign = receiver.wheel/std::fabs(receiver.wheel);
if (sign > 0)
std::cout << "Camera has offset forward" << std::endl;
else if (sign < 0)
std::cout << "Camera has offset backward" << std::endl;
core::vector3df cam_offset = rel_target.normalize()*(f32)sign*c_params.offset;
core::vector3df new_pos = cur_pos + cam_offset;
camera->setPosition(new_pos);
receiver.wheel = 0.0f;
}
else if (receiver.isMiddleMousePressed && receiver.mousePosDelta != core::vector3df(0.0f, 0.0f, 0.0f))
{
const core::vector3df& cur_pos = camera->getPosition();
core::vector3df cur_target = camera->getTarget();
core::vector3df new_rot = (cur_pos - cur_target).getHorizontalAngle() + core::vector3df(-receiver.mousePosDelta.Y/10.0f, -receiver.mousePosDelta.X/10.0f, 0.0f);
core::matrix4 matrix;
matrix.setRotationDegrees(new_rot);
core::vector3df original_camera_pos(0.0f, 0.0f, (cur_target - cur_pos).getLength());
matrix.rotateVect(original_camera_pos);
camera->setPosition(cur_target + original_camera_pos);
receiver.mousePosDelta = core::vector3df(0.0f, 0.0f, 0.0f);
}
else if (receiver.isUpPressed)
{
core::vector3df nmlzed_target = -camera->getPosition();
nmlzed_target.normalize();
cur_push_force = nmlzed_target * bw_params.push_force;
receiver.isUpPressed = false;
}
else if (receiver.isDownPressed)
{
core::vector3df nmlzed_target = -camera->getPosition();
nmlzed_target.normalize();
cur_push_force = nmlzed_target * -bw_params.push_force;
receiver.isDownPressed = false;
}
else if (receiver.isLeftPressed)
{
core::vector3df nmlzed_target = -camera->getPosition();
nmlzed_target.normalize();
nmlzed_target.rotateXZBy(90.0f);
cur_push_force = nmlzed_target * bw_params.push_force;
receiver.isLeftPressed = false;
}
else if (receiver.isRightPressed)
{
core::vector3df nmlzed_target = -camera->getPosition();
nmlzed_target.normalize();
nmlzed_target.rotateXZBy(-90.0f);
cur_push_force = nmlzed_target * bw_params.push_force;
receiver.isRightPressed = false;
}
/*else if (receiver.isMouseWheelChanged)
{
core::vector3df cur_target = camera->getTarget();
core::vector3df cur_pos = camera->getPosition();
@ -253,7 +389,7 @@ int main()
receiver.isMouseWheelChanged = false;
receiver.wheel = 0.f;
}
}*/
/*else if (receiver.pressed_btn != nullptr)
{
std::cout << "The button is clicked!" << std::endl;
@ -270,26 +406,30 @@ int main()
receiver.pressed_btn = nullptr;
}*/
core::vector3df elastic_force = cur_rel_pos/(-cur_rel_pos.getLength()) * params.elasticity * (cur_rel_pos.getLength() - params.original_len);
core::vector3df friction_force = -cur_vel*params.friction_coef;
core::vector3df elastic_force = (cur_rel_pos.getLength() > bw_params.original_len)? cur_rel_pos/(-cur_rel_pos.getLength()) * bw_params.elasticity * (cur_rel_pos.getLength() - bw_params.original_len) :
core::vector3df(0.0f, 0.0f, 0.0f);
core::vector3df friction_force = -cur_vel*bw_params.friction_coef;
f32 pos_len_sqr = cur_rel_pos.dotProduct(cur_rel_pos);
core::vector3df string_friction_force;
if (std::fabs(pos_len_sqr) > 0.01)
string_friction_force = -(cur_vel.dotProduct(cur_rel_pos))/(pos_len_sqr)*cur_rel_pos/std::sqrt(std::fabs(pos_len_sqr))*params.string_friction_coef;
core::vector3df res_force = core::vector3df(0.0f, params.gravity*params.mass, 0.0f) + elastic_force + friction_force + string_friction_force;
string_friction_force = -(cur_vel.dotProduct(cur_rel_pos))/(pos_len_sqr)*cur_rel_pos/std::sqrt(std::fabs(pos_len_sqr))*bw_params.string_friction_coef;
core::vector3df res_force = core::vector3df(0.0f, bw_params.gravity*bw_params.mass, 0.0f) + elastic_force + friction_force + string_friction_force + cur_push_force;
cur_rel_pos += cur_vel*0.001;
cur_vel += res_force*0.001/params.mass;
cur_vel += res_force*0.001/bw_params.mass;
bal_wheel->setPosition(params.pos + cur_rel_pos);
bal_wheel->setPosition(bw_params.pos + cur_rel_pos);
vdrv->beginScene(true, true, video::SColor(0, 0, 0, 255));
vdrv->setTransform(video::ETS_WORLD, core::IdentityMatrix);
vdrv->draw3DLine(beam.start, params.pos + cur_rel_pos, video::SColor(255, 255, 255, 255));
vdrv->draw3DLine(core::vector3df(-50.0f, 0.0f, 0.0f), core::vector3df(50.0f, 0.0f, 0.0f), video::SColor(252, 0, 20, 255));
vdrv->draw3DLine(core::vector3df(0.0f, -50.0f, 0.0f), core::vector3df(0.0f, 50.0f, 0.0f), video::SColor(10, 0, 234, 255));
vdrv->draw3DLine(core::vector3df(0.0f, 0.0f, -50.0f), core::vector3df(0.0f, 0.0f, 50.0f), video::SColor(0, 217, 0, 255));
vdrv->draw3DLine(beam.start, bw_params.pos + cur_rel_pos, video::SColor(255, 255, 255, 255));
smgr->drawAll();
device->getGUIEnvironment()->drawAll();
env->drawAll();
vdrv->endScene();
core::stringw caption = L"[Irrlicht Engine] Balance Wheel Demo [";