mirror of https://github.com/Poikilos/b3view
260 lines
9.1 KiB
C++
260 lines
9.1 KiB
C++
#include "View.h"
|
|
#include "Engine.h"
|
|
#include <iostream>
|
|
|
|
using namespace irr;
|
|
using namespace irr::core;
|
|
using namespace irr::scene;
|
|
|
|
void View::setNewCameraPosition()
|
|
{
|
|
setNewCameraPosition(m_zUp);
|
|
}
|
|
|
|
void View::setNewCameraPosition(bool zUp)
|
|
{
|
|
vector3d<f32> newCameraPosition;
|
|
ICameraSceneNode* camera = m_Engine->m_Scene->getActiveCamera();
|
|
|
|
if (zUp) {
|
|
camera->setUpVector(vector3df(0, 0, 1));
|
|
} else {
|
|
camera->setUpVector(vector3df(0, 1, 0));
|
|
}
|
|
|
|
vector3df oldCamPos = camera->getPosition();
|
|
// vector3df oldCamRot = camera->getRotation();
|
|
// NOTE: rotationToDirection converts a rotation to a vec3 direction.
|
|
// vector3df oldCamRot = m_Engine->tmpPosVec3f.?(m_Engine->tmpTargetVec3f);
|
|
matrix4 yawMatrix;
|
|
if (m_zUp != zUp) {
|
|
float z;
|
|
z = oldCamPos.Y;
|
|
oldCamPos.Y = oldCamPos.Z;
|
|
oldCamPos.Z = z;
|
|
z = m_Engine->m_CamPos.Y;
|
|
m_Engine->m_CamPos.Y = m_Engine->m_CamPos.Z;
|
|
m_Engine->m_CamPos.Z = z;
|
|
z = m_Engine->m_CamTarget.Y;
|
|
m_Engine->m_CamTarget.Y = m_Engine->m_CamTarget.Z;
|
|
m_Engine->m_CamTarget.Z = z;
|
|
camera->setPosition(m_Engine->m_CamPos);
|
|
camera->setTarget(m_Engine->m_CamTarget);
|
|
}
|
|
if (zUp) {
|
|
newCameraPosition.X = 0;
|
|
newCameraPosition.Y = m_CameraDistance * cos(m_Pitch);
|
|
newCameraPosition.Z = m_CameraDistance * sin(m_Pitch);
|
|
yawMatrix.setRotationRadians(vector3df(0, 0, m_Yaw));
|
|
} else {
|
|
newCameraPosition.X = 0;
|
|
newCameraPosition.Y = m_CameraDistance * sin(m_Pitch);
|
|
newCameraPosition.Z = m_CameraDistance * cos(m_Pitch);
|
|
yawMatrix.setRotationRadians(vector3df(0, m_Yaw, 0));
|
|
}
|
|
|
|
yawMatrix.transformVect(newCameraPosition);
|
|
|
|
if (zUp) {
|
|
//camera->setUpVector(vector3df(0, 0, 1));
|
|
//newCameraPosition.Z = oldCamPos.Z;
|
|
} else {
|
|
//camera->setUpVector(vector3df(0, 1, 0));
|
|
//newCameraPosition.Y = oldCamPos.Y;
|
|
}
|
|
camera->setPosition(newCameraPosition);
|
|
// vector3df newRotation();
|
|
// camera->setRotation();
|
|
camera->setTarget(m_Engine->m_CamTarget);
|
|
|
|
// Set Light direction
|
|
setNewLightDirection(newCameraPosition);
|
|
m_zUp = zUp;
|
|
// std::wcerr << L" setCameraPosition pitch: " << m_Pitch << endl;
|
|
}
|
|
|
|
void View::setNewLightDirection(const vector3df& cameraPosition)
|
|
{
|
|
ILightSceneNode* light = static_cast<ILightSceneNode*>(m_Engine->m_Scene->getSceneNodeFromId(SIID_LIGHT));
|
|
|
|
matrix4 m;
|
|
m.buildRotateFromTo(vector3df(0, 0, 1), vector3df(cameraPosition).invert().normalize());
|
|
|
|
light->setRotation(m.getRotationDegrees());
|
|
}
|
|
|
|
View::View(Engine* engine)
|
|
{
|
|
m_zUp = false;
|
|
m_Engine = engine;
|
|
m_LastMousePosition = new vector2d<int>();
|
|
m_RotMouse = false;
|
|
|
|
m_Pitch = PI;
|
|
|
|
// Set Camera Distance
|
|
// m_CameraDistance = 10;
|
|
// m_CameraDistance = engine->m_CamTarget.getDistanceFrom(engine->m_CamPos);
|
|
// Calculate offsetVec3 manually, since the object is needed later
|
|
// (Vectors for angle are opposite, since camera revolves around center):
|
|
vector3df offsetVec3(
|
|
engine->m_CamPos.X - engine->m_CamTarget.X,
|
|
engine->m_CamPos.Y - engine->m_CamTarget.Y,
|
|
engine->m_CamPos.Z - engine->m_CamTarget.Z);
|
|
m_CameraDistance = offsetVec3.getLength();
|
|
|
|
// NOTE: rotationToDirection converts a rotation to a vec3 direction
|
|
// vector3df rotationVec3 = engine->tmpPosVec3f.?(engine->tmpTargetVec3f);
|
|
// vector3df rotationVec3 = engine->tmpTargetVec3f.?(engine->tmpPosVec3f);
|
|
|
|
// see rogerborg on <http://irrlicht.sourceforge.net/forum/viewtopic.php?f=1&t=30477>
|
|
// const f32 dot = engine->tmpTargetVec3f.dotProduct(engine->tmpPosVec3f); // to...(from) // angle only
|
|
|
|
m_Yaw = atan2(offsetVec3.X, offsetVec3.Z);
|
|
m_Pitch = asin(-offsetVec3.Y);
|
|
|
|
// m_Yaw = rotationVec3.Y;
|
|
// m_Pitch = rotationVec3.X;
|
|
|
|
debug() << "Yaw: " << radToDeg(m_Yaw) << endl;
|
|
debug() << "Pitch: " << radToDeg(m_Pitch) << endl;
|
|
}
|
|
|
|
View::~View()
|
|
{
|
|
delete m_LastMousePosition;
|
|
}
|
|
|
|
void View::setZUp(bool zUp)
|
|
{
|
|
if (zUp != m_zUp) {
|
|
setNewCameraPosition(zUp);
|
|
}
|
|
}
|
|
|
|
void View::setCameraDistance(float cameraDistance)
|
|
{
|
|
m_CameraDistance = cameraDistance;
|
|
}
|
|
|
|
bool View::zUp()
|
|
{
|
|
return m_zUp;
|
|
}
|
|
|
|
// IEventReceiver
|
|
bool View::OnEvent(const SEvent& event)
|
|
{
|
|
// If it's not a mouse event or window resize event, return
|
|
if (event.EventType != EET_MOUSE_INPUT_EVENT && !(event.EventType == EET_USER_EVENT && event.UserEvent.UserData1 == UEI_WINDOWSIZECHANGED))
|
|
return false;
|
|
|
|
// Handle window resize
|
|
if (event.EventType == EET_USER_EVENT && event.UserEvent.UserData1 == UEI_WINDOWSIZECHANGED) {
|
|
dimension2d<u32> windowSize = m_Engine->m_Driver->getScreenSize();
|
|
f32 aspectRatio = static_cast<f32>(windowSize.Width) / static_cast<f32>(windowSize.Height);
|
|
debug() << "Setting aspect to: " << aspectRatio << endl;
|
|
m_Engine->m_Scene->getActiveCamera()->setAspectRatio(aspectRatio);
|
|
}
|
|
|
|
// Handle mouse event
|
|
const SEvent::SMouseInput* mouseEvent = &(event.MouseInput);
|
|
|
|
if (mouseEvent->Event == EMIE_MMOUSE_PRESSED_DOWN) {
|
|
m_RotMouse = true;
|
|
m_LastMousePosition->X = mouseEvent->X;
|
|
m_LastMousePosition->Y = mouseEvent->Y;
|
|
} else if (mouseEvent->Event == EMIE_MMOUSE_LEFT_UP) {
|
|
m_RotMouse = false;
|
|
} else if (mouseEvent->Event == EMIE_MOUSE_WHEEL) {
|
|
f32 distanceDelta = mouseEvent->Wheel / 2.5f;
|
|
if (m_CameraDistance - distanceDelta > 0.1f)
|
|
m_CameraDistance -= distanceDelta;
|
|
|
|
setNewCameraPosition();
|
|
} else if (m_RotMouse) {
|
|
int dx = mouseEvent->X - m_LastMousePosition->X;
|
|
int dy = mouseEvent->Y - m_LastMousePosition->Y;
|
|
|
|
m_LastMousePosition->X = mouseEvent->X;
|
|
m_LastMousePosition->Y = mouseEvent->Y;
|
|
if (m_Engine->KeyIsDown[irr::KEY_RSHIFT] || m_Engine->KeyIsDown[irr::KEY_LSHIFT]) {
|
|
// Pan camera.
|
|
float yDelta = (dy / 400.0f) * m_CameraDistance;
|
|
ICameraSceneNode* camera = m_Engine->m_Scene->getActiveCamera();
|
|
vector3df rotationVec3;
|
|
rotationVec3 = camera->getRotation();
|
|
vector3df forwards(0, 0, 1);
|
|
vector3df dirVec3 = camera->getUpVector();
|
|
// vector3df camRot = camera->getRotation();
|
|
vector3df camRot(0, 0, 0);
|
|
// TODO: fix this (pitch becomes flat)
|
|
camRot.X = m_Pitch;
|
|
if (m_zUp) {
|
|
camRot.Z = m_Yaw;
|
|
forwards = vector3df(0, 1, 0);
|
|
dirVec3.rotateYZBy(camRot.X);
|
|
dirVec3.rotateXYBy(camRot.Z);
|
|
} else {
|
|
camRot.Z = m_Pitch;
|
|
dirVec3.rotateYZBy(camRot.X);
|
|
dirVec3.rotateXYBy(camRot.Y);
|
|
}
|
|
// vector3df dirVec3 = rotationVec3.rotationToDirection(forwards);
|
|
// // move up and down, not in and out:
|
|
// float z = dirVec3.Z;
|
|
// dirVec3.Z = dirVec3.Y;
|
|
// dirVec3.Z = z;
|
|
dirVec3.X *= yDelta;
|
|
dirVec3.Y *= yDelta;
|
|
dirVec3.Z *= yDelta;
|
|
m_Engine->m_CamPos.X += dirVec3.X;
|
|
m_Engine->m_CamPos.Y += dirVec3.Y;
|
|
m_Engine->m_CamPos.Z += dirVec3.Z;
|
|
m_Engine->m_CamTarget.X += dirVec3.X;
|
|
m_Engine->m_CamTarget.Y += dirVec3.Y;
|
|
m_Engine->m_CamTarget.Z += dirVec3.Z;
|
|
if (m_zUp) {
|
|
//m_Engine->m_CamPos.Z += yDelta;
|
|
//m_Engine->m_CamTarget.Z += yDelta;
|
|
} else {
|
|
//m_Engine->m_CamPos.Y += yDelta;
|
|
//m_Engine->m_CamTarget.Y += yDelta;
|
|
}
|
|
camera->setPosition(m_Engine->m_CamPos);
|
|
camera->setTarget(m_Engine->m_CamTarget);
|
|
vector3df offsetVec3(
|
|
m_Engine->m_CamPos.X - m_Engine->m_CamTarget.X,
|
|
m_Engine->m_CamPos.Y - m_Engine->m_CamTarget.Y,
|
|
m_Engine->m_CamPos.Z - m_Engine->m_CamTarget.Z);
|
|
m_CameraDistance = offsetVec3.getLength();
|
|
|
|
m_Yaw = atan2(offsetVec3.X, offsetVec3.Z);
|
|
m_Pitch = asin(-offsetVec3.Y);
|
|
setNewCameraPosition();
|
|
} else {
|
|
// Revolve camera around object.
|
|
// increments of 120 pixels * PI are equal to 180 deg (PI radians):
|
|
f32 pitchDelta = dy / 120.0f;
|
|
// (This old code which may make assumptions about view tends to lock on min/max)
|
|
// if ((m_Pitch - pitchDelta > (PI - (PI / 2))) && (m_Pitch - pitchDelta < PI + (PI/2)))
|
|
// m_Pitch -= dy / 120.0f;
|
|
m_Pitch += pitchDelta;
|
|
float minPitch = -PI / 2.0f + PI / 1000.0f;
|
|
float maxPitch = PI / 2.0f - PI / 1000.0f;
|
|
if (m_Pitch < minPitch)
|
|
m_Pitch = minPitch;
|
|
else if (m_Pitch > maxPitch)
|
|
m_Pitch = maxPitch;
|
|
// std::wcerr << "pitch = " << m_Pitch << endl;
|
|
|
|
m_Yaw += dx / 120.0f;
|
|
|
|
// Set Camera to new rotation
|
|
setNewCameraPosition();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|