123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- /****************************************************************************
- Copyright (c) 2014-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- http://www.cocos2d-x.org
-
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
-
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- Code based GamePlay3D's Camera: http://gameplay3d.org
- ****************************************************************************/
- #include "2d/CCCamera.h"
- #include "2d/CCCameraBackgroundBrush.h"
- #include "base/CCDirector.h"
- #include "platform/CCGLView.h"
- #include "2d/CCScene.h"
- #include "renderer/CCRenderer.h"
- #include "renderer/CCQuadCommand.h"
- #include "renderer/CCGLProgramCache.h"
- #include "renderer/ccGLStateCache.h"
- #include "renderer/CCFrameBuffer.h"
- #include "renderer/CCRenderState.h"
- NS_CC_BEGIN
- Camera* Camera::_visitingCamera = nullptr;
- experimental::Viewport Camera::_defaultViewport;
- // start static methods
- Camera* Camera::create()
- {
- Camera* camera = new (std::nothrow) Camera();
- camera->initDefault();
- camera->autorelease();
- camera->setDepth(0.f);
-
- return camera;
- }
- Camera* Camera::createPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
- {
- auto ret = new (std::nothrow) Camera();
- if (ret)
- {
- ret->initPerspective(fieldOfView, aspectRatio, nearPlane, farPlane);
- ret->autorelease();
- return ret;
- }
- CC_SAFE_DELETE(ret);
- return nullptr;
- }
- Camera* Camera::createOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane)
- {
- auto ret = new (std::nothrow) Camera();
- if (ret)
- {
- ret->initOrthographic(zoomX, zoomY, nearPlane, farPlane);
- ret->autorelease();
- return ret;
- }
- CC_SAFE_DELETE(ret);
- return nullptr;
- }
- Camera* Camera::getDefaultCamera()
- {
- auto scene = Director::getInstance()->getRunningScene();
- if(scene)
- {
- return scene->getDefaultCamera();
- }
- return nullptr;
- }
- const experimental::Viewport& Camera::getDefaultViewport()
- {
- return _defaultViewport;
- }
- void Camera::setDefaultViewport(const experimental::Viewport& vp)
- {
- _defaultViewport = vp;
- }
- const Camera* Camera::getVisitingCamera()
- {
- return _visitingCamera;
- }
- // end static methods
- Camera::Camera()
- : _scene(nullptr)
- , _viewProjectionDirty(true)
- , _cameraFlag(1)
- , _frustumDirty(true)
- , _viewProjectionUpdated(false)
- , _depth(-1)
- , _fbo(nullptr)
- {
- _frustum.setClipZ(true);
- _clearBrush = CameraBackgroundBrush::createDepthBrush(1.f);
- _clearBrush->retain();
- }
- Camera::~Camera()
- {
- CC_SAFE_RELEASE_NULL(_fbo);
- CC_SAFE_RELEASE(_clearBrush);
- }
- const Mat4& Camera::getProjectionMatrix() const
- {
- return _projection;
- }
- const Mat4& Camera::getViewMatrix() const
- {
- Mat4 viewInv(getNodeToWorldTransform());
- static int count = sizeof(float) * 16;
- if (memcmp(viewInv.m, _viewInv.m, count) != 0)
- {
- _viewProjectionDirty = true;
- _frustumDirty = true;
- _viewInv = viewInv;
- _view = viewInv.getInversed();
- }
- return _view;
- }
- void Camera::lookAt(const Vec3& lookAtPos, const Vec3& up)
- {
- Vec3 upv = up;
- upv.normalize();
- Vec3 zaxis;
- Vec3::subtract(this->getPosition3D(), lookAtPos, &zaxis);
- zaxis.normalize();
-
- Vec3 xaxis;
- Vec3::cross(upv, zaxis, &xaxis);
- xaxis.normalize();
-
- Vec3 yaxis;
- Vec3::cross(zaxis, xaxis, &yaxis);
- yaxis.normalize();
- Mat4 rotation;
- rotation.m[0] = xaxis.x;
- rotation.m[1] = xaxis.y;
- rotation.m[2] = xaxis.z;
- rotation.m[3] = 0;
-
- rotation.m[4] = yaxis.x;
- rotation.m[5] = yaxis.y;
- rotation.m[6] = yaxis.z;
- rotation.m[7] = 0;
- rotation.m[8] = zaxis.x;
- rotation.m[9] = zaxis.y;
- rotation.m[10] = zaxis.z;
- rotation.m[11] = 0;
-
- Quaternion quaternion;
- Quaternion::createFromRotationMatrix(rotation,&quaternion);
- quaternion.normalize();
- setRotationQuat(quaternion);
- }
- const Mat4& Camera::getViewProjectionMatrix() const
- {
- getViewMatrix();
- if (_viewProjectionDirty)
- {
- _viewProjectionDirty = false;
- Mat4::multiply(_projection, _view, &_viewProjection);
- }
-
- return _viewProjection;
- }
- void Camera::setAdditionalProjection(const Mat4& mat)
- {
- _projection = mat * _projection;
- getViewProjectionMatrix();
- }
- bool Camera::initDefault()
- {
- auto size = Director::getInstance()->getWinSize();
- //create default camera
- auto projection = Director::getInstance()->getProjection();
- switch (projection)
- {
- case Director::Projection::_2D:
- {
- initOrthographic(size.width, size.height, -1024, 1024);
- setPosition3D(Vec3(0.0f, 0.0f, 0.0f));
- setRotation3D(Vec3(0.f, 0.f, 0.f));
- break;
- }
- case Director::Projection::_3D:
- {
- float zeye = Director::getInstance()->getZEye();
- initPerspective(60, (GLfloat)size.width / size.height, 10, zeye + size.height / 2.0f);
- Vec3 eye(size.width/2, size.height/2.0f, zeye), center(size.width/2, size.height/2, 0.0f), up(0.0f, 1.0f, 0.0f);
- setPosition3D(eye);
- lookAt(center, up);
- break;
- }
- default:
- CCLOG("unrecognized projection");
- break;
- }
- return true;
- }
- bool Camera::initPerspective(float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
- {
- _fieldOfView = fieldOfView;
- _aspectRatio = aspectRatio;
- _nearPlane = nearPlane;
- _farPlane = farPlane;
- Mat4::createPerspective(_fieldOfView, _aspectRatio, _nearPlane, _farPlane, &_projection);
- _viewProjectionDirty = true;
- _frustumDirty = true;
- _type = Type::PERSPECTIVE;
-
- return true;
- }
- bool Camera::initOrthographic(float zoomX, float zoomY, float nearPlane, float farPlane)
- {
- _zoom[0] = zoomX;
- _zoom[1] = zoomY;
- _nearPlane = nearPlane;
- _farPlane = farPlane;
- Mat4::createOrthographicOffCenter(0, _zoom[0], 0, _zoom[1], _nearPlane, _farPlane, &_projection);
- _viewProjectionDirty = true;
- _frustumDirty = true;
- _type = Type::ORTHOGRAPHIC;
-
- return true;
- }
- Vec2 Camera::project(const Vec3& src) const
- {
- Vec2 screenPos;
-
- auto viewport = Director::getInstance()->getWinSize();
- Vec4 clipPos;
- getViewProjectionMatrix().transformVector(Vec4(src.x, src.y, src.z, 1.0f), &clipPos);
-
- CCASSERT(clipPos.w != 0.0f, "clipPos.w can't be 0.0f!");
- float ndcX = clipPos.x / clipPos.w;
- float ndcY = clipPos.y / clipPos.w;
-
- screenPos.x = (ndcX + 1.0f) * 0.5f * viewport.width;
- screenPos.y = (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
- return screenPos;
- }
- Vec2 Camera::projectGL(const Vec3& src) const
- {
- Vec2 screenPos;
-
- auto viewport = Director::getInstance()->getWinSize();
- Vec4 clipPos;
- getViewProjectionMatrix().transformVector(Vec4(src.x, src.y, src.z, 1.0f), &clipPos);
-
- CCASSERT(clipPos.w != 0.0f, "clipPos.w can't be 0.0f!");
- float ndcX = clipPos.x / clipPos.w;
- float ndcY = clipPos.y / clipPos.w;
-
- screenPos.x = (ndcX + 1.0f) * 0.5f * viewport.width;
- screenPos.y = (ndcY + 1.0f) * 0.5f * viewport.height;
- return screenPos;
- }
- Vec3 Camera::unproject(const Vec3& src) const
- {
- Vec3 dst;
- unproject(Director::getInstance()->getWinSize(), &src, &dst);
- return dst;
- }
- Vec3 Camera::unprojectGL(const Vec3& src) const
- {
- Vec3 dst;
- unprojectGL(Director::getInstance()->getWinSize(), &src, &dst);
- return dst;
- }
- void Camera::unproject(const Size& viewport, const Vec3* src, Vec3* dst) const
- {
- CCASSERT(src && dst, "vec3 can not be null");
-
- Vec4 screen(src->x / viewport.width, ((viewport.height - src->y)) / viewport.height, src->z, 1.0f);
- screen.x = screen.x * 2.0f - 1.0f;
- screen.y = screen.y * 2.0f - 1.0f;
- screen.z = screen.z * 2.0f - 1.0f;
-
- getViewProjectionMatrix().getInversed().transformVector(screen, &screen);
- 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::unprojectGL(const Size& viewport, const Vec3* src, Vec3* dst) const
- {
- CCASSERT(src && dst, "vec3 can not be null");
-
- Vec4 screen(src->x / viewport.width, src->y / viewport.height, src->z, 1.0f);
- screen.x = screen.x * 2.0f - 1.0f;
- screen.y = screen.y * 2.0f - 1.0f;
- screen.z = screen.z * 2.0f - 1.0f;
-
- getViewProjectionMatrix().getInversed().transformVector(screen, &screen);
- 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);
- }
- bool Camera::isVisibleInFrustum(const AABB* aabb) const
- {
- if (_frustumDirty)
- {
- _frustum.initFrustum(this);
- _frustumDirty = false;
- }
- return !_frustum.isOutOfFrustum(*aabb);
- }
- float Camera::getDepthInView(const Mat4& transform) const
- {
- Mat4 camWorldMat = getNodeToWorldTransform();
- const Mat4 &viewMat = camWorldMat.getInversed();
- float depth = -(viewMat.m[2] * transform.m[12] + viewMat.m[6] * transform.m[13] + viewMat.m[10] * transform.m[14] + viewMat.m[14]);
- return depth;
- }
- void Camera::setDepth(int8_t depth)
- {
- if (_depth != depth)
- {
- _depth = depth;
- if (_scene)
- {
- //notify scene that the camera order is dirty
- _scene->setCameraOrderDirty();
- }
- }
- }
- void Camera::onEnter()
- {
- if (_scene == nullptr)
- {
- auto scene = getScene();
- if (scene)
- {
- setScene(scene);
- }
- }
- Node::onEnter();
- }
- void Camera::onExit()
- {
- // remove this camera from scene
- setScene(nullptr);
- Node::onExit();
- }
- void Camera::setScene(Scene* scene)
- {
- if (_scene != scene)
- {
- //remove old scene
- if (_scene)
- {
- auto& cameras = _scene->_cameras;
- auto it = std::find(cameras.begin(), cameras.end(), this);
- if (it != cameras.end())
- cameras.erase(it);
- _scene = nullptr;
- }
- //set new scene
- if (scene)
- {
- _scene = scene;
- auto& cameras = _scene->_cameras;
- auto it = std::find(cameras.begin(), cameras.end(), this);
- if (it == cameras.end())
- {
- _scene->_cameras.push_back(this);
- //notify scene that the camera order is dirty
- _scene->setCameraOrderDirty();
- }
- }
- }
- }
- void Camera::clearBackground()
- {
- if (_clearBrush)
- {
- _clearBrush->drawBackground(this);
- }
- }
- void Camera::setFrameBufferObject(experimental::FrameBuffer *fbo)
- {
- CC_SAFE_RETAIN(fbo);
- CC_SAFE_RELEASE_NULL(_fbo);
- _fbo = fbo;
- if(_scene)
- {
- _scene->setCameraOrderDirty();
- }
- }
- void Camera::apply()
- {
- _viewProjectionUpdated = _transformUpdated;
- applyFrameBufferObject();
- applyViewport();
- }
- void Camera::applyFrameBufferObject()
- {
- if(nullptr == _fbo)
- {
- // inherit from context if it doesn't have a FBO
- // don't call apply the default one
- // experimental::FrameBuffer::applyDefaultFBO();
- }
- else
- {
- _fbo->applyFBO();
- }
- }
- void Camera::applyViewport()
- {
- glGetIntegerv(GL_VIEWPORT, _oldViewport);
- if(nullptr == _fbo)
- {
- glViewport(getDefaultViewport()._left, getDefaultViewport()._bottom, getDefaultViewport()._width, getDefaultViewport()._height);
- }
- else
- {
- glViewport(_viewport._left * _fbo->getWidth(), _viewport._bottom * _fbo->getHeight(),
- _viewport._width * _fbo->getWidth(), _viewport._height * _fbo->getHeight());
- }
- }
- void Camera::setViewport(const experimental::Viewport& vp)
- {
- _viewport = vp;
- }
- void Camera::restore()
- {
- restoreFrameBufferObject();
- restoreViewport();
- }
- void Camera::restoreFrameBufferObject()
- {
- if(nullptr == _fbo)
- {
- // it was inherited from context if it doesn't have a FBO
- // don't call restore the default one... just keep using the previous one
- // experimental::FrameBuffer::applyDefaultFBO();
- }
- else
- {
- _fbo->restoreFBO();
- }
- }
- void Camera::restoreViewport()
- {
- glViewport(_oldViewport[0], _oldViewport[1], _oldViewport[2], _oldViewport[3]);
- }
- int Camera::getRenderOrder() const
- {
- int result(0);
- if(_fbo)
- {
- result = _fbo->getFID()<<8;
- }
- else
- {
- result = 127 <<8;
- }
- result += _depth;
- return result;
- }
- void Camera::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
- {
- _viewProjectionUpdated = _transformUpdated;
- return Node::visit(renderer, parentTransform, parentFlags);
- }
- void Camera::setBackgroundBrush(CameraBackgroundBrush* clearBrush)
- {
- CC_SAFE_RETAIN(clearBrush);
- CC_SAFE_RELEASE(_clearBrush);
- _clearBrush = clearBrush;
- }
- bool Camera::isBrushValid()
- {
- return _clearBrush != nullptr && _clearBrush->isValid();
- }
- NS_CC_END
|