/hsp3dish/gameplay/src/Camera.cpp
C++ | 445 lines | 342 code | 82 blank | 21 comment | 44 complexity | 544bfbf371ebcd2f95b5501ba392edda MD5 | raw file
Possible License(s): LGPL-3.0
- #include "Base.h"
- #include "Camera.h"
- #include "Game.h"
- #include "Node.h"
- #include "Game.h"
- #include "PhysicsController.h"
-
- // Camera dirty bits
- #define CAMERA_DIRTY_VIEW 1
- #define CAMERA_DIRTY_PROJ 2
- #define CAMERA_DIRTY_VIEW_PROJ 4
- #define CAMERA_DIRTY_INV_VIEW 8
- #define CAMERA_DIRTY_INV_VIEW_PROJ 16
- #define CAMERA_DIRTY_BOUNDS 32
- #define CAMERA_DIRTY_ALL (CAMERA_DIRTY_VIEW | CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS)
-
- // Other misc camera bits
- #define CAMERA_CUSTOM_PROJECTION 64
-
- namespace gameplay
- {
-
- Camera::Camera(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
- : _type(PERSPECTIVE), _fieldOfView(fieldOfView), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
- _bits(CAMERA_DIRTY_ALL), _node(NULL)
- {
- }
-
- Camera::Camera(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
- : _type(ORTHOGRAPHIC), _aspectRatio(aspectRatio), _nearPlane(nearPlane), _farPlane(farPlane),
- _bits(CAMERA_DIRTY_ALL), _node(NULL)
- {
- // Orthographic camera.
- _zoom[0] = zoomX;
- _zoom[1] = zoomY;
- }
-
- Camera::~Camera()
- {
- }
-
- Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
- {
- return new Camera(fieldOfView, aspectRatio, nearPlane, farPlane);
- }
-
- Camera* Camera::createOrthographic(float zoomX, float zoomY, float aspectRatio, float nearPlane, float farPlane)
- {
- return new Camera(zoomX, zoomY, aspectRatio, nearPlane, farPlane);
- }
-
- Camera* Camera::create(Properties* properties)
- {
- GP_ASSERT(properties);
-
- // Read camera type
- std::string typeStr;
- if (properties->exists("type"))
- typeStr = properties->getString("type");
- Camera::Type type;
- if (typeStr == "PERSPECTIVE")
- {
- type = Camera::PERSPECTIVE;
- }
- else if (typeStr == "ORTHOGRAPHIC")
- {
- type = Camera::ORTHOGRAPHIC;
- }
- else
- {
- GP_ERROR("Invalid 'type' parameter for camera definition.");
- return NULL;
- }
-
- // Read common parameters
- float aspectRatio, nearPlane, farPlane;
- if (properties->exists("aspectRatio"))
- {
- aspectRatio = properties->getFloat("aspectRatio");
- }
- else
- {
- // Use default aspect ratio
- aspectRatio = (float)Game::getInstance()->getWidth() / Game::getInstance()->getHeight();
- }
-
- if (properties->exists("nearPlane"))
- nearPlane = properties->getFloat("nearPlane");
- else
- nearPlane = 0.2f; // use some reasonable default value
-
- if (properties->exists("farPlane"))
- farPlane = properties->getFloat("farPlane");
- else
- farPlane = 100; // use some reasonable default value
-
- Camera* camera = NULL;
-
- switch (type)
- {
- case Camera::PERSPECTIVE:
- // If field of view is not specified, use a default of 60 degrees
- camera = createPerspective(
- properties->exists("fieldOfView") ? properties->getFloat("fieldOfView") : 60.0f,
- aspectRatio, nearPlane, farPlane);
- break;
-
- case Camera::ORTHOGRAPHIC:
- // If zoomX and zoomY are not specified, use screen width/height
- camera = createOrthographic(
- properties->exists("zoomX") ? properties->getFloat("zoomX") : Game::getInstance()->getWidth(),
- properties->exists("zoomY") ? properties->getFloat("zoomY") : Game::getInstance()->getHeight(),
- aspectRatio, nearPlane, farPlane);
- break;
- }
-
- return camera;
- }
-
- Camera::Type Camera::getCameraType() const
- {
- return _type;
- }
-
- float Camera::getFieldOfView() const
- {
- GP_ASSERT(_type == Camera::PERSPECTIVE);
-
- return _fieldOfView;
- }
-
- void Camera::setFieldOfView(float fieldOfView)
- {
- GP_ASSERT(_type == Camera::PERSPECTIVE);
-
- _fieldOfView = fieldOfView;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- float Camera::getZoomX() const
- {
- GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
- return _zoom[0];
- }
-
- void Camera::setZoomX(float zoomX)
- {
- GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
- _zoom[0] = zoomX;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- float Camera::getZoomY() const
- {
- GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
- return _zoom[1];
- }
-
- void Camera::setZoomY(float zoomY)
- {
- GP_ASSERT(_type == Camera::ORTHOGRAPHIC);
-
- _zoom[1] = zoomY;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- float Camera::getAspectRatio() const
- {
- return _aspectRatio;
- }
-
- void Camera::setAspectRatio(float aspectRatio)
- {
- _aspectRatio = aspectRatio;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- float Camera::getNearPlane() const
- {
- return _nearPlane;
- }
-
- void Camera::setNearPlane(float nearPlane)
- {
- _nearPlane = nearPlane;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- float Camera::getFarPlane() const
- {
- return _farPlane;
- }
-
- void Camera::setFarPlane(float farPlane)
- {
- _farPlane = farPlane;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- Node* Camera::getNode() const
- {
- return _node;
- }
-
- void Camera::setNode(Node* node)
- {
- if (_node != node)
- {
- if (_node)
- {
- _node->removeListener(this);
- }
-
- // Connect the new node.
- _node = node;
-
- if (_node)
- {
- _node->addListener(this);
- }
-
- _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
- }
-
- const Matrix& Camera::getViewMatrix() const
- {
- if (_bits & CAMERA_DIRTY_VIEW)
- {
- if (_node)
- {
- // The view matrix is the inverse of our transform matrix.
- _node->getWorldMatrix().invert(&_view);
- }
- else
- {
- _view.setIdentity();
- }
-
- _bits &= ~CAMERA_DIRTY_VIEW;
- }
-
- return _view;
- }
-
- const Matrix& Camera::getInverseViewMatrix() const
- {
- if (_bits & CAMERA_DIRTY_INV_VIEW)
- {
- getViewMatrix().invert(&_inverseView);
-
- _bits &= ~CAMERA_DIRTY_INV_VIEW;
- }
-
- return _inverseView;
- }
-
- const Matrix& Camera::getProjectionMatrix() const
- {
- if (!(_bits & CAMERA_CUSTOM_PROJECTION) && (_bits & CAMERA_DIRTY_PROJ))
- {
- if (_type == PERSPECTIVE)
- {
- Matrix::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
- }
- else
- {
- Matrix::createOrthographic(_zoom[0], _zoom[1], _nearPlane, _farPlane, &_projection);
- }
-
- _bits &= ~CAMERA_DIRTY_PROJ;
- }
-
- return _projection;
- }
-
- void Camera::setProjectionMatrix(const Matrix& matrix)
- {
- _projection = matrix;
- _bits |= CAMERA_CUSTOM_PROJECTION;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- void Camera::resetProjectionMatrix()
- {
- if (_bits & CAMERA_CUSTOM_PROJECTION)
- {
- _bits &= ~CAMERA_CUSTOM_PROJECTION;
- _bits |= CAMERA_DIRTY_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
- }
-
- const Matrix& Camera::getViewProjectionMatrix() const
- {
- if (_bits & CAMERA_DIRTY_VIEW_PROJ)
- {
- Matrix::multiply(getProjectionMatrix(), getViewMatrix(), &_viewProjection);
-
- _bits &= ~CAMERA_DIRTY_VIEW_PROJ;
- }
-
- return _viewProjection;
- }
-
- const Matrix& Camera::getInverseViewProjectionMatrix() const
- {
- if (_bits & CAMERA_DIRTY_INV_VIEW_PROJ)
- {
- getViewProjectionMatrix().invert(&_inverseViewProjection);
-
- _bits &= ~CAMERA_DIRTY_INV_VIEW_PROJ;
- }
-
- return _inverseViewProjection;
- }
-
- const Frustum& Camera::getFrustum() const
- {
- if (_bits & CAMERA_DIRTY_BOUNDS)
- {
- // Update our bounding frustum from our view projection matrix.
- _bounds.set(getViewProjectionMatrix());
-
- _bits &= ~CAMERA_DIRTY_BOUNDS;
- }
-
- return _bounds;
- }
-
- void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth) const
- {
- GP_ASSERT(x);
- GP_ASSERT(y);
-
- // Transform the point to clip-space.
- Vector4 clipPos;
- getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
-
- // Compute normalized device coordinates.
- GP_ASSERT(clipPos.w != 0.0f);
- float ndcX = clipPos.x / clipPos.w;
- float ndcY = clipPos.y / clipPos.w;
-
- // Compute screen coordinates by applying our viewport transformation.
- *x = viewport.x + (ndcX + 1.0f) * 0.5f * viewport.width;
- *y = viewport.y + (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
- if (depth)
- {
- float ndcZ = clipPos.z / clipPos.w;
- *depth = ndcZ + 1.0f / 2.0f;
- }
- }
-
- void Camera::project(const Rectangle& viewport, const Vector3& position, Vector2* out) const
- {
- GP_ASSERT(out);
- float x, y;
- project(viewport, position, &x, &y);
- out->set(x, y);
- }
-
- void Camera::project(const Rectangle& viewport, const Vector3& position, Vector3* out) const
- {
- GP_ASSERT(out);
- float x, y, depth;
- project(viewport, position, &x, &y, &depth);
- out->set(x, y, depth);
- }
-
- void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst) const
- {
- GP_ASSERT(dst);
-
- // Create our screen space position in NDC.
- GP_ASSERT(viewport.width != 0.0f && viewport.height != 0.0f);
- Vector4 screen((x - viewport.x) / viewport.width, ((viewport.height - y) - viewport.y) / viewport.height, depth, 1.0f);
-
- // Map to range -1 to 1.
- screen.x = screen.x * 2.0f - 1.0f;
- screen.y = screen.y * 2.0f - 1.0f;
- screen.z = screen.z * 2.0f - 1.0f;
-
- // Transform the screen-space NDC by our inverse view projection matrix.
- getInverseViewProjectionMatrix().transformVector(screen, &screen);
-
- // Divide by our W coordinate.
- if (screen.w != 0.0f)
- {
- screen.x /= screen.w;
- screen.y /= screen.w;
- screen.z /= screen.w;
- }
-
- dst->set(screen.x, screen.y, screen.z);
- }
-
- void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst) const
- {
- GP_ASSERT(dst);
-
- // Get the world-space position at the near clip plane.
- Vector3 nearPoint;
- unproject(viewport, x, y, 0.0f, &nearPoint);
-
- // Get the world-space position at the far clip plane.
- Vector3 farPoint;
- unproject(viewport, x, y, 1.0f, &farPoint);
-
- // Set the direction of the ray.
- Vector3 direction;
- Vector3::subtract(farPoint, nearPoint, &direction);
- direction.normalize();
-
- dst->set(nearPoint, direction);
- }
-
- Camera* Camera::clone(NodeCloneContext &context) const
- {
- Camera* cameraClone = NULL;
- if (getCameraType() == PERSPECTIVE)
- {
- cameraClone = createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane);
- }
- else if (getCameraType() == ORTHOGRAPHIC)
- {
- cameraClone = createOrthographic(getZoomX(), getZoomY(), getAspectRatio(), _nearPlane, _farPlane);
- }
- GP_ASSERT(cameraClone);
-
- if (Node* node = context.findClonedNode(getNode()))
- {
- cameraClone->setNode(node);
- }
- return cameraClone;
- }
-
- void Camera::transformChanged(Transform* transform, long cookie)
- {
- _bits |= CAMERA_DIRTY_VIEW | CAMERA_DIRTY_INV_VIEW | CAMERA_DIRTY_INV_VIEW_PROJ | CAMERA_DIRTY_VIEW_PROJ | CAMERA_DIRTY_BOUNDS;
- }
-
- }