2014-08-15 16:15:29 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2014 Chukong Technologies Inc.
|
|
|
|
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "3d/CCBillBoard.h"
|
|
|
|
#include "2d/CCSpriteFrameCache.h"
|
|
|
|
#include "base/CCDirector.h"
|
2014-10-20 16:25:24 +08:00
|
|
|
#include "2d/CCCamera.h"
|
2014-08-15 16:15:29 +08:00
|
|
|
#include "renderer/CCRenderer.h"
|
2014-08-28 19:22:01 +08:00
|
|
|
#include "renderer/CCGLProgramCache.h"
|
2014-08-15 16:15:29 +08:00
|
|
|
|
|
|
|
NS_CC_BEGIN
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard::BillBoard()
|
2015-01-13 12:17:00 +08:00
|
|
|
: _mode(Mode::VIEW_POINT_ORIENTED)
|
2014-09-04 16:26:11 +08:00
|
|
|
, _modeDirty(false)
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2014-09-17 18:01:18 +08:00
|
|
|
Node::setAnchorPoint(Vec2(0.5f,0.5f));
|
2014-08-15 16:15:29 +08:00
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard::~BillBoard()
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard* BillBoard::createWithTexture(Texture2D *texture, Mode mode)
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard *billborad = new (std::nothrow) BillBoard();
|
2014-08-15 16:15:29 +08:00
|
|
|
if (billborad && billborad->initWithTexture(texture))
|
|
|
|
{
|
2014-09-03 18:04:48 +08:00
|
|
|
billborad->_mode = mode;
|
2014-08-15 16:15:29 +08:00
|
|
|
billborad->autorelease();
|
|
|
|
return billborad;
|
|
|
|
}
|
|
|
|
CC_SAFE_DELETE(billborad);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard* BillBoard::create(const std::string& filename, Mode mode)
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard *billborad = new (std::nothrow) BillBoard();
|
2014-08-15 16:15:29 +08:00
|
|
|
if (billborad && billborad->initWithFile(filename))
|
|
|
|
{
|
2014-09-03 18:04:48 +08:00
|
|
|
billborad->_mode = mode;
|
2014-08-15 16:15:29 +08:00
|
|
|
billborad->autorelease();
|
|
|
|
return billborad;
|
|
|
|
}
|
|
|
|
CC_SAFE_DELETE(billborad);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard* BillBoard::create(const std::string& filename, const Rect& rect, Mode mode)
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard *billborad = new (std::nothrow) BillBoard();
|
2014-08-15 16:15:29 +08:00
|
|
|
if (billborad && billborad->initWithFile(filename, rect))
|
|
|
|
{
|
2014-09-03 18:04:48 +08:00
|
|
|
billborad->_mode = mode;
|
2014-08-15 16:15:29 +08:00
|
|
|
billborad->autorelease();
|
|
|
|
return billborad;
|
|
|
|
}
|
|
|
|
CC_SAFE_DELETE(billborad);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard* BillBoard::create(Mode mode)
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard *billborad = new (std::nothrow) BillBoard();
|
2014-08-15 16:15:29 +08:00
|
|
|
if (billborad && billborad->init())
|
|
|
|
{
|
2014-09-03 18:04:48 +08:00
|
|
|
billborad->_mode = mode;
|
2014-08-15 16:15:29 +08:00
|
|
|
billborad->autorelease();
|
|
|
|
return billborad;
|
|
|
|
}
|
|
|
|
CC_SAFE_DELETE(billborad);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-01-13 10:17:47 +08:00
|
|
|
void BillBoard::visit(Renderer *renderer, const Mat4& parentTransform, uint32_t parentFlags)
|
|
|
|
{
|
|
|
|
// quick return if not visible. children won't be drawn.
|
|
|
|
if (!_visible)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2015-01-28 15:21:57 +08:00
|
|
|
bool visibleByCamera = isVisitableByVisitingCamera();
|
|
|
|
if (!visibleByCamera && _children.empty())
|
|
|
|
return;
|
2015-01-13 10:17:47 +08:00
|
|
|
|
|
|
|
uint32_t flags = processParentFlags(parentTransform, parentFlags);
|
|
|
|
|
2015-01-13 12:06:50 +08:00
|
|
|
//Add 3D flag so all the children will be rendered as 3D object
|
|
|
|
flags |= FLAGS_RENDER_AS_3D;
|
|
|
|
|
2015-01-13 10:17:47 +08:00
|
|
|
//Update Billboard transform
|
2015-01-13 12:06:50 +08:00
|
|
|
bool dirty = calculateBillbaordTransform();
|
|
|
|
if(dirty)
|
|
|
|
{
|
|
|
|
flags |= FLAGS_TRANSFORM_DIRTY;
|
|
|
|
}
|
2015-01-13 10:17:47 +08:00
|
|
|
|
|
|
|
Director* director = Director::getInstance();
|
|
|
|
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
|
|
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);
|
|
|
|
|
2015-01-28 15:21:57 +08:00
|
|
|
|
2015-01-13 10:17:47 +08:00
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if(!_children.empty())
|
|
|
|
{
|
|
|
|
sortAllChildren();
|
|
|
|
// draw children zOrder < 0
|
|
|
|
for( ; i < _children.size(); i++ )
|
|
|
|
{
|
|
|
|
auto node = _children.at(i);
|
|
|
|
|
|
|
|
if (node && node->getLocalZOrder() < 0)
|
2015-01-13 12:06:50 +08:00
|
|
|
node->visit(renderer, _modelViewTransform, flags);
|
2015-01-13 10:17:47 +08:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// self draw
|
|
|
|
if (visibleByCamera)
|
2015-01-13 12:06:50 +08:00
|
|
|
this->draw(renderer, _modelViewTransform, flags);
|
2015-01-13 10:17:47 +08:00
|
|
|
|
|
|
|
for(auto it=_children.cbegin()+i; it != _children.cend(); ++it)
|
2015-01-13 12:06:50 +08:00
|
|
|
(*it)->visit(renderer, _modelViewTransform, flags);
|
2015-01-13 10:17:47 +08:00
|
|
|
}
|
|
|
|
else if (visibleByCamera)
|
|
|
|
{
|
2015-01-13 12:06:50 +08:00
|
|
|
this->draw(renderer, _modelViewTransform, flags);
|
2015-01-13 10:17:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
|
|
|
}
|
|
|
|
|
2015-01-13 12:06:50 +08:00
|
|
|
bool BillBoard::calculateBillbaordTransform()
|
2014-08-15 16:15:29 +08:00
|
|
|
{
|
2015-01-13 10:17:47 +08:00
|
|
|
//Get camera world position
|
2014-08-28 19:22:01 +08:00
|
|
|
auto camera = Camera::getVisitingCamera();
|
2014-09-03 15:28:15 +08:00
|
|
|
const Mat4& camWorldMat = camera->getNodeToWorldTransform();
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2015-01-13 12:06:50 +08:00
|
|
|
//TODO: use math lib to calculate math lib Make it easier to read and maintain
|
2015-01-28 15:21:57 +08:00
|
|
|
if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || memcmp(_mvTransform.m, _modelViewTransform.m, sizeof(float) * 16) != 0 || _modeDirty || true)
|
2014-08-29 17:11:18 +08:00
|
|
|
{
|
2015-01-13 10:17:47 +08:00
|
|
|
//Rotate based on anchor point
|
2014-10-14 15:08:36 +08:00
|
|
|
Vec3 anchorPoint(_anchorPointInPoints.x , _anchorPointInPoints.y , 0.0f);
|
2015-01-13 10:17:47 +08:00
|
|
|
Mat4 localToWorld = _modelViewTransform;
|
2014-10-14 15:08:36 +08:00
|
|
|
localToWorld.translate(anchorPoint);
|
2015-01-13 10:17:47 +08:00
|
|
|
|
|
|
|
//Decide billboard mode
|
2014-09-03 17:17:57 +08:00
|
|
|
Vec3 camDir;
|
2014-09-03 18:04:48 +08:00
|
|
|
switch (_mode)
|
|
|
|
{
|
2015-01-13 10:17:47 +08:00
|
|
|
case Mode::VIEW_POINT_ORIENTED:
|
|
|
|
camDir = Vec3(localToWorld.m[12] - camWorldMat.m[12], localToWorld.m[13] - camWorldMat.m[13], localToWorld.m[14] - camWorldMat.m[14]);
|
|
|
|
break;
|
|
|
|
case Mode::VIEW_PLANE_ORIENTED:
|
|
|
|
camWorldMat.transformVector(Vec3(0.0f, 0.0f, -1.0f), &camDir);
|
|
|
|
break;
|
|
|
|
default:
|
2014-09-05 14:59:14 +08:00
|
|
|
CCASSERT(false, "invalid billboard mode");
|
2015-01-13 10:17:47 +08:00
|
|
|
break;
|
2014-09-03 18:04:48 +08:00
|
|
|
}
|
2014-09-04 16:26:11 +08:00
|
|
|
_modeDirty = false;
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2014-09-03 15:28:15 +08:00
|
|
|
if (camDir.length() < MATH_TOLERANCE)
|
|
|
|
{
|
|
|
|
camDir.set(camWorldMat.m[8], camWorldMat.m[9], camWorldMat.m[10]);
|
|
|
|
}
|
|
|
|
camDir.normalize();
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2014-12-04 15:19:41 +08:00
|
|
|
Quaternion rotationQuaternion;
|
|
|
|
this->getNodeToWorldTransform().getRotation(&rotationQuaternion);
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2015-01-28 15:21:57 +08:00
|
|
|
|
2014-12-04 15:19:41 +08:00
|
|
|
Mat4 rotationMatrix;
|
|
|
|
rotationMatrix.setIdentity();
|
2015-01-28 15:21:57 +08:00
|
|
|
///FIXME: maybe should keep rotation along z axis
|
|
|
|
// if (rotationQuaternion.z > 0)
|
|
|
|
// {
|
|
|
|
// //rotate z only, keep it
|
|
|
|
// // fetch the rotation angle of z
|
|
|
|
// float rotationZ = atan2(2*(rotationQuaternion.w*rotationQuaternion.z + rotationQuaternion.x*rotationQuaternion.y),
|
|
|
|
// (1 - 2* (rotationQuaternion.y*rotationQuaternion.y + rotationQuaternion.z *rotationQuaternion.z)));
|
|
|
|
// rotationMatrix.rotateZ(rotationZ);
|
|
|
|
// }
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2014-12-04 15:19:41 +08:00
|
|
|
Vec3 upAxis = Vec3(rotationMatrix.m[4],rotationMatrix.m[5],rotationMatrix.m[6]);
|
2014-10-14 15:08:36 +08:00
|
|
|
Vec3 x, y;
|
|
|
|
camWorldMat.transformVector(upAxis, &y);
|
|
|
|
Vec3::cross(camDir, y, &x);
|
|
|
|
x.normalize();
|
|
|
|
Vec3::cross(x, camDir, &y);
|
|
|
|
y.normalize();
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2014-10-14 15:08:36 +08:00
|
|
|
float xlen = sqrtf(localToWorld.m[0] * localToWorld.m[0] + localToWorld.m[1] * localToWorld.m[1] + localToWorld.m[2] * localToWorld.m[2]);
|
|
|
|
float ylen = sqrtf(localToWorld.m[4] * localToWorld.m[4] + localToWorld.m[5] * localToWorld.m[5] + localToWorld.m[6] * localToWorld.m[6]);
|
|
|
|
float zlen = sqrtf(localToWorld.m[8] * localToWorld.m[8] + localToWorld.m[9] * localToWorld.m[9] + localToWorld.m[10] * localToWorld.m[10]);
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2015-01-13 12:06:50 +08:00
|
|
|
Mat4 billboardTransform;
|
|
|
|
|
|
|
|
billboardTransform.m[0] = x.x * xlen; billboardTransform.m[1] = x.y * xlen; billboardTransform.m[2] = x.z * xlen;
|
|
|
|
billboardTransform.m[4] = y.x * ylen; billboardTransform.m[5] = y.y * ylen; billboardTransform.m[6] = y.z * ylen;
|
|
|
|
billboardTransform.m[8] = -camDir.x * zlen; billboardTransform.m[9] = -camDir.y * zlen; billboardTransform.m[10] = -camDir.z * zlen;
|
|
|
|
billboardTransform.m[12] = localToWorld.m[12]; billboardTransform.m[13] = localToWorld.m[13]; billboardTransform.m[14] = localToWorld.m[14];
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2015-01-13 12:06:50 +08:00
|
|
|
billboardTransform.translate(-anchorPoint);
|
2015-01-28 15:21:57 +08:00
|
|
|
_mvTransform = _modelViewTransform = billboardTransform;
|
2015-01-13 10:17:47 +08:00
|
|
|
|
2014-09-03 15:28:15 +08:00
|
|
|
_camWorldMat = camWorldMat;
|
2015-01-13 12:06:50 +08:00
|
|
|
|
|
|
|
return true;
|
2014-08-29 17:11:18 +08:00
|
|
|
}
|
2015-01-13 12:06:50 +08:00
|
|
|
|
|
|
|
return false;
|
2015-01-13 10:17:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
|
|
|
|
{
|
2014-09-03 09:02:32 +08:00
|
|
|
//FIXME: frustum culling here
|
2015-01-16 06:00:49 +08:00
|
|
|
_quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _modelViewTransform, flags);
|
2015-01-13 12:06:50 +08:00
|
|
|
_quadCommand.setTransparent(true);
|
|
|
|
_quadCommand.setSkipBatching(true);
|
|
|
|
renderer->addCommand(&_quadCommand);
|
2014-08-15 16:15:29 +08:00
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
void BillBoard::setMode( Mode mode )
|
2014-09-03 18:04:48 +08:00
|
|
|
{
|
|
|
|
_mode = mode;
|
2014-09-04 16:26:11 +08:00
|
|
|
_modeDirty = true;
|
2014-09-03 18:04:48 +08:00
|
|
|
}
|
|
|
|
|
2014-09-04 16:26:11 +08:00
|
|
|
BillBoard::Mode BillBoard::getMode() const
|
2014-09-03 18:04:48 +08:00
|
|
|
{
|
|
|
|
return _mode;
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:43:04 +08:00
|
|
|
NS_CC_END
|