#include "CCameraSceneNode.h"
#include "ISceneManager.h"
#include "IVideoDriver.h"
#include "os.h"
namespace irr
{
namespace scene
{
CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
const core::vector3df& position, const core::vector3df& lookat)
: ICameraSceneNode(parent, mgr, id, position),
Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),
InputReceiverEnabled(true), TargetAndRotationAreBound(false)
{
#ifdef _DEBUG
setDebugName("CCameraSceneNode");
#endif
Fovy = core::PI / 2.5f;
const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0;
if (d)
Aspect = (f32)d->getCurrentRenderTargetSize().Width /
(f32)d->getCurrentRenderTargetSize().Height;
else
Aspect = 4.0f / 3.0f;
recalculateProjectionMatrix();
recalculateViewArea();
}
void CCameraSceneNode::setInputReceiverEnabled(bool enabled)
{
InputReceiverEnabled = enabled;
}
bool CCameraSceneNode::isInputReceiverEnabled() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return InputReceiverEnabled;
}
void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)
{
IsOrthogonal = isOrthogonal;
ViewArea.getTransform ( video::ETS_PROJECTION ) = projection;
}
const core::matrix4& CCameraSceneNode::getProjectionMatrix() const
{
return ViewArea.getTransform ( video::ETS_PROJECTION );
}
const core::matrix4& CCameraSceneNode::getViewMatrix() const
{
return ViewArea.getTransform ( video::ETS_VIEW );
}
void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)
{
Affector = affector;
}
const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const
{
return Affector;
}
bool CCameraSceneNode::OnEvent(const SEvent& event)
{
if (!InputReceiverEnabled)
return false;
ISceneNodeAnimatorList::Iterator ait = Animators.begin();
for (; ait != Animators.end(); ++ait)
if ((*ait)->isEventReceiverEnabled() && (*ait)->OnEvent(event))
return true;
return false;
}
void CCameraSceneNode::setTarget(const core::vector3df& pos)
{
Target = pos;
if(TargetAndRotationAreBound)
{
const core::vector3df toTarget = Target - getAbsolutePosition();
ISceneNode::setRotation(toTarget.getHorizontalAngle());
}
}
void CCameraSceneNode::setRotation(const core::vector3df& rotation)
{
if(TargetAndRotationAreBound)
Target = getAbsolutePosition() + rotation.rotationToDirection();
ISceneNode::setRotation(rotation);
}
const core::vector3df& CCameraSceneNode::getTarget() const
{
return Target;
}
void CCameraSceneNode::setUpVector(const core::vector3df& pos)
{
UpVector = pos;
}
const core::vector3df& CCameraSceneNode::getUpVector() const
{
return UpVector;
}
f32 CCameraSceneNode::getNearValue() const
{
return ZNear;
}
f32 CCameraSceneNode::getFarValue() const
{
return ZFar;
}
f32 CCameraSceneNode::getAspectRatio() const
{
return Aspect;
}
f32 CCameraSceneNode::getFOV() const
{
return Fovy;
}
void CCameraSceneNode::setNearValue(f32 f)
{
ZNear = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setFarValue(f32 f)
{
ZFar = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setAspectRatio(f32 f)
{
Aspect = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::setFOV(f32 f)
{
Fovy = f;
recalculateProjectionMatrix();
}
void CCameraSceneNode::recalculateProjectionMatrix()
{
ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar);
}
void CCameraSceneNode::OnRegisterSceneNode()
{
if ( SceneManager->getActiveCamera () == this )
SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);
ISceneNode::OnRegisterSceneNode();
}
void CCameraSceneNode::render()
{
core::vector3df pos = getAbsolutePosition();
core::vector3df tgtv = Target - pos;
tgtv.normalize();
core::vector3df up = UpVector;
up.normalize();
f32 dp = tgtv.dotProduct(up);
if ( core::equals(core::abs_<f32>(dp), 1.f) )
{
up.X += 0.5f;
}
ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up);
ViewArea.getTransform(video::ETS_VIEW) *= Affector;
recalculateViewArea();
video::IVideoDriver* driver = SceneManager->getVideoDriver();
if ( driver)
{
driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) );
driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) );
}
}
const core::aabbox3d<f32>& CCameraSceneNode::getBoundingBox() const
{
return ViewArea.getBoundingBox();
}
const SViewFrustum* CCameraSceneNode::getViewFrustum() const
{
return &ViewArea;
}
void CCameraSceneNode::recalculateViewArea()
{
ViewArea.cameraPosition = getAbsolutePosition();
core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION),
ViewArea.getTransform(video::ETS_VIEW));
ViewArea.setFrom(m);
}
void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
{
ISceneNode::serializeAttributes(out, options);
out->addVector3d("Target", Target);
out->addVector3d("UpVector", UpVector);
out->addFloat("Fovy", Fovy);
out->addFloat("Aspect", Aspect);
out->addFloat("ZNear", ZNear);
out->addFloat("ZFar", ZFar);
out->addBool("Binding", TargetAndRotationAreBound);
}
void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
{
ISceneNode::deserializeAttributes(in, options);
Target = in->getAttributeAsVector3d("Target");
UpVector = in->getAttributeAsVector3d("UpVector");
Fovy = in->getAttributeAsFloat("Fovy");
Aspect = in->getAttributeAsFloat("Aspect");
ZNear = in->getAttributeAsFloat("ZNear");
ZFar = in->getAttributeAsFloat("ZFar");
TargetAndRotationAreBound = in->getAttributeAsBool("Binding");
recalculateProjectionMatrix();
recalculateViewArea();
}
void CCameraSceneNode::bindTargetAndRotation(bool bound)
{
TargetAndRotationAreBound = bound;
}
bool CCameraSceneNode::getTargetAndRotationBinding(void) const
{
return TargetAndRotationAreBound;
}
ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
{
if (!newParent)
newParent = Parent;
if (!newManager)
newManager = SceneManager;
CCameraSceneNode* nb = new CCameraSceneNode(newParent,
newManager, ID, RelativeTranslation, Target);
nb->cloneMembers(this, newManager);
if ( newParent )
nb->drop();
return nb;
}
}
}