392 lines
12 KiB
C++
392 lines
12 KiB
C++
/**
|
|
* @author Edouard DUPIN
|
|
*
|
|
* @copyright 2011, Edouard DUPIN, all right reserved
|
|
*
|
|
* @license BSD v3 (see license file)
|
|
*/
|
|
|
|
#include <etk/types.h>
|
|
#include <ege/debug.h>
|
|
#include <ege/ElementGame.h>
|
|
#include <ege/Environement.h>
|
|
#include <ewol/renderer/ResourceManager.h>
|
|
#include <BulletDynamics/Dynamics/btRigidBody.h>
|
|
#include <LinearMath/btDefaultMotionState.h>
|
|
#include <BulletDynamics/Dynamics/btDynamicsWorld.h>
|
|
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
|
|
#include <LinearMath/btIDebugDraw.h>
|
|
#include <btBulletCollisionCommon.h>
|
|
#include <BulletCollision/CollisionShapes/btConvexPolyhedron.h>
|
|
#include <BulletCollision/CollisionShapes/btShapeHull.h>
|
|
#include <LinearMath/btTransformUtil.h>
|
|
#include <LinearMath/btIDebugDraw.h>
|
|
#include <btBulletDynamicsCommon.h>
|
|
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
|
|
|
|
#undef __class__
|
|
#define __class__ "ElementGame"
|
|
|
|
const etk::UString& ege::ElementGame::GetType(void) const
|
|
{
|
|
static const etk::UString nameType("----");
|
|
return nameType;
|
|
}
|
|
|
|
|
|
ege::ElementGame::ElementGame(ege::Environement& _env) :
|
|
m_env(_env),
|
|
m_body(NULL),
|
|
m_shape(NULL),
|
|
m_life(100),
|
|
m_lifeMax(100),
|
|
m_group(0),
|
|
m_fixe(true),
|
|
m_radius(0),
|
|
m_elementInPhysicsSystem(false),
|
|
m_IA(NULL)
|
|
{
|
|
static uint32_t unique=0;
|
|
m_uID = unique;
|
|
EGE_DEBUG("Create element : uId=" << m_uID);
|
|
unique++;
|
|
}
|
|
|
|
ege::ElementGame::~ElementGame(void)
|
|
{
|
|
// in every case remove IA
|
|
IADisable();
|
|
// same ...
|
|
DynamicDisable();
|
|
EGE_DEBUG("Destroy element : uId=" << m_uID);
|
|
}
|
|
|
|
|
|
float ege::ElementGame::GetLifeRatio(void)
|
|
{
|
|
if (0>=m_life) {
|
|
return 0;
|
|
}
|
|
return m_life/m_lifeMax;
|
|
}
|
|
|
|
|
|
void ege::ElementGame::SetFireOn(int32_t groupIdSource, int32_t type, float power, const vec3& center)
|
|
{
|
|
float previousLife = m_life;
|
|
m_life += power;
|
|
m_life = etk_avg(0, m_life, m_lifeMax);
|
|
if (m_life<=0) {
|
|
EGE_DEBUG("[" << GetUID() << "] element is killed ..." << GetType());
|
|
}
|
|
if (m_life!=previousLife) {
|
|
OnLifeChange();
|
|
}
|
|
}
|
|
|
|
void ege::ElementGame::SetPosition(const vec3& pos)
|
|
{
|
|
if (NULL!=m_body) {
|
|
btTransform transformation = m_body->getCenterOfMassTransform();
|
|
transformation.setOrigin(pos);
|
|
m_body->setCenterOfMassTransform(transformation);
|
|
}
|
|
}
|
|
|
|
const vec3& ege::ElementGame::GetPosition(void)
|
|
{
|
|
// this is to prevent error like segmentation fault ...
|
|
static vec3 emptyPosition(-1000000,-1000000,-1000000);
|
|
if (NULL!=m_body) {
|
|
return m_body->getCenterOfMassPosition();
|
|
}
|
|
return emptyPosition;
|
|
};
|
|
|
|
const vec3& ege::ElementGame::GetSpeed(void)
|
|
{
|
|
// this is to prevent error like segmentation fault ...
|
|
static vec3 emptySpeed(0,0,0);
|
|
if (NULL!=m_body) {
|
|
return m_body->getLinearVelocity();
|
|
}
|
|
return emptySpeed;
|
|
};
|
|
|
|
const float ege::ElementGame::GetInvMass(void)
|
|
{
|
|
if (NULL!=m_body) {
|
|
return m_body->getInvMass();
|
|
}
|
|
return 0.0000000001f;
|
|
};
|
|
|
|
|
|
static void DrawSphere(ewol::Colored3DObject* _draw,
|
|
btScalar _radius,
|
|
int _lats,
|
|
int _longs,
|
|
mat4& _transformationMatrix,
|
|
etk::Color<float>& _tmpColor)
|
|
{
|
|
int i, j;
|
|
etk::Vector<vec3> EwolVertices;
|
|
for(i = 0; i <= _lats; i++) {
|
|
btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / _lats);
|
|
btScalar z0 = _radius*sin(lat0);
|
|
btScalar zr0 = _radius*cos(lat0);
|
|
|
|
btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / _lats);
|
|
btScalar z1 = _radius*sin(lat1);
|
|
btScalar zr1 = _radius*cos(lat1);
|
|
|
|
//glBegin(GL_QUAD_STRIP);
|
|
for(j = 0; j < _longs; j++) {
|
|
btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / _longs;
|
|
btScalar x = cos(lng);
|
|
btScalar y = sin(lng);
|
|
vec3 v1 = vec3(x * zr1, y * zr1, z1);
|
|
vec3 v4 = vec3(x * zr0, y * zr0, z0);
|
|
|
|
lng = 2 * SIMD_PI * (btScalar) (j) / _longs;
|
|
x = cos(lng);
|
|
y = sin(lng);
|
|
vec3 v2 = vec3(x * zr1, y * zr1, z1);
|
|
vec3 v3 = vec3(x * zr0, y * zr0, z0);
|
|
|
|
EwolVertices.PushBack(v1);
|
|
EwolVertices.PushBack(v2);
|
|
EwolVertices.PushBack(v3);
|
|
|
|
EwolVertices.PushBack(v1);
|
|
EwolVertices.PushBack(v3);
|
|
EwolVertices.PushBack(v4);
|
|
}
|
|
}
|
|
_draw->Draw(EwolVertices, _tmpColor, _transformationMatrix);
|
|
}
|
|
|
|
const float lifeBorder = 0.1f;
|
|
const float lifeHeight = 0.3f;
|
|
const float lifeWidth = 2.0f;
|
|
const float lifeYPos = 1.7f;
|
|
|
|
void ege::ElementGame::DrawLife(ewol::Colored3DObject* _draw, const ege::Camera& _camera)
|
|
{
|
|
if (NULL==_draw) {
|
|
return;
|
|
}
|
|
float ratio = GetLifeRatio();
|
|
if (ratio == 1.0f) {
|
|
return;
|
|
}
|
|
mat4 transformationMatrix = etk::matTranslate(GetPosition())
|
|
* etk::matRotate(vec3(0,0,1),_camera.GetAngleZ())
|
|
* etk::matRotate(vec3(1,0,0),(M_PI/2.0f-_camera.GetAngleTeta()));
|
|
etk::Vector<vec3> localVertices;
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0-lifeBorder,lifeYPos -lifeBorder,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0-lifeBorder,lifeYPos+lifeHeight+lifeBorder,0));
|
|
localVertices.PushBack(vec3( lifeWidth/2.0+lifeBorder,lifeYPos+lifeHeight+lifeBorder,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0-lifeBorder,lifeYPos -lifeBorder,0));
|
|
localVertices.PushBack(vec3( lifeWidth/2.0+lifeBorder,lifeYPos+lifeHeight+lifeBorder,0));
|
|
localVertices.PushBack(vec3( lifeWidth/2.0+lifeBorder,lifeYPos -lifeBorder,0));
|
|
etk::Color<float> myColor(0x0000FF99);
|
|
_draw->Draw(localVertices, myColor, transformationMatrix, false, false);
|
|
localVertices.Clear();
|
|
/** Bounding box ==> model shape **/
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0 ,lifeYPos,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0 ,lifeYPos + lifeHeight,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0+lifeWidth*ratio,lifeYPos + lifeHeight,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0 ,lifeYPos,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0+lifeWidth*ratio,lifeYPos + lifeHeight,0));
|
|
localVertices.PushBack(vec3(-lifeWidth/2.0+lifeWidth*ratio,lifeYPos,0));
|
|
myColor =0x00FF00FF;
|
|
if (ratio < 0.2f) {
|
|
myColor = 0xFF0000FF;
|
|
} else if (ratio < 0.4f) {
|
|
myColor = 0xDA7B00FF;
|
|
}
|
|
_draw->Draw(localVertices, myColor, transformationMatrix, false, false);
|
|
}
|
|
|
|
static void DrawShape(const btCollisionShape* _shape,
|
|
ewol::Colored3DObject* _draw,
|
|
mat4 _transformationMatrix,
|
|
etk::Vector<vec3> _tmpVertices)
|
|
{
|
|
if( NULL == _draw
|
|
|| NULL == _shape) {
|
|
return;
|
|
}
|
|
etk::Color<float> tmpColor(1.0, 0.0, 0.0, 0.3);
|
|
|
|
//EGE_DEBUG(" Draw (6): !btIDebugDraw::DBG_DrawWireframe");
|
|
int shapetype=_shape->getShapeType();
|
|
switch (shapetype) {
|
|
case SPHERE_SHAPE_PROXYTYPE: {
|
|
// Sphere collision shape ...
|
|
//EGE_DEBUG(" Draw (01): SPHERE_SHAPE_PROXYTYPE");
|
|
const btSphereShape* sphereShape = static_cast<const btSphereShape*>(_shape);
|
|
float radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin
|
|
DrawSphere(_draw, radius, 10, 10, _transformationMatrix, tmpColor);
|
|
break;
|
|
}
|
|
case BOX_SHAPE_PROXYTYPE: {
|
|
// Box collision shape ...
|
|
//EGE_DEBUG(" Draw (02): BOX_SHAPE_PROXYTYPE");
|
|
const btBoxShape* boxShape = static_cast<const btBoxShape*>(_shape);
|
|
btVector3 halfExtent = boxShape->getHalfExtentsWithMargin();
|
|
static int indices[36] = { 0,1,2, 3,2,1, 4,0,6,
|
|
6,0,2, 5,1,4, 4,1,0,
|
|
7,3,1, 7,1,5, 5,4,7,
|
|
7,4,6, 7,2,3, 7,6,2};
|
|
vec3 vertices[8]={ vec3(halfExtent[0],halfExtent[1],halfExtent[2]),
|
|
vec3(-halfExtent[0],halfExtent[1],halfExtent[2]),
|
|
vec3(halfExtent[0],-halfExtent[1],halfExtent[2]),
|
|
vec3(-halfExtent[0],-halfExtent[1],halfExtent[2]),
|
|
vec3(halfExtent[0],halfExtent[1],-halfExtent[2]),
|
|
vec3(-halfExtent[0],halfExtent[1],-halfExtent[2]),
|
|
vec3(halfExtent[0],-halfExtent[1],-halfExtent[2]),
|
|
vec3(-halfExtent[0],-halfExtent[1],-halfExtent[2])};
|
|
_tmpVertices.Clear();
|
|
for (int32_t iii=0 ; iii<36 ; iii+=3) {
|
|
// normal calculation :
|
|
//btVector3 normal = (vertices[indices[iii+2]]-vertices[indices[iii]]).cross(vertices[indices[iii+1]]-vertices[indices[iii]]);
|
|
//normal.normalize ();
|
|
_tmpVertices.PushBack(vertices[indices[iii]]);
|
|
_tmpVertices.PushBack(vertices[indices[iii+1]]);
|
|
_tmpVertices.PushBack(vertices[indices[iii+2]]);
|
|
}
|
|
_draw->Draw(_tmpVertices, tmpColor, _transformationMatrix);
|
|
break;
|
|
}
|
|
case CONE_SHAPE_PROXYTYPE: {
|
|
// Cone collision shape ...
|
|
EGE_DEBUG(" Draw (03): CONE_SHAPE_PROXYTYPE");
|
|
break;
|
|
}
|
|
case CAPSULE_SHAPE_PROXYTYPE: {
|
|
// Capsule collision shape ...
|
|
EGE_DEBUG(" Draw (04): CAPSULE_SHAPE_PROXYTYPE");
|
|
break;
|
|
}
|
|
case CYLINDER_SHAPE_PROXYTYPE: {
|
|
// Cylinder collision shape ...
|
|
EGE_DEBUG(" Draw (05): CYLINDER_SHAPE_PROXYTYPE");
|
|
break;
|
|
}
|
|
case CONVEX_HULL_SHAPE_PROXYTYPE: {
|
|
// Convex Hull collision shape ...
|
|
EGE_DEBUG(" Draw (06): CYLINDER_SHAPE_PROXYTYPE");
|
|
break;
|
|
}
|
|
case COMPOUND_SHAPE_PROXYTYPE: {
|
|
// Multiple sub element collision shape ...
|
|
//EGE_DEBUG(" Draw (07): COMPOUND_SHAPE_PROXYTYPE");
|
|
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(_shape);
|
|
for (int32_t iii=compoundShape->getNumChildShapes()-1;iii>=0;iii--) {
|
|
btTransform childTrans = compoundShape->getChildTransform(iii);
|
|
const btCollisionShape* colShape = compoundShape->getChildShape(iii);
|
|
btScalar mmm[16];
|
|
childTrans.getOpenGLMatrix(mmm);
|
|
mat4 transformationMatrix(mmm);
|
|
transformationMatrix.Transpose();
|
|
transformationMatrix = _transformationMatrix * transformationMatrix;
|
|
DrawShape(colShape, _draw, transformationMatrix, _tmpVertices);
|
|
}
|
|
break;
|
|
}
|
|
case EMPTY_SHAPE_PROXYTYPE: {
|
|
// No collision shape ...
|
|
//EGE_DEBUG(" Draw (08): EMPTY_SHAPE_PROXYTYPE");
|
|
// nothing to display ...
|
|
break;
|
|
}
|
|
default: {
|
|
// must be done later ...
|
|
EGE_DEBUG(" Draw (09): default");
|
|
}
|
|
}
|
|
}
|
|
|
|
void ege::ElementGame::DrawDebug(ewol::Colored3DObject* _draw, const ege::Camera& _camera)
|
|
{
|
|
m_debugText.Clear();
|
|
m_debugText.SetFontSize(12);
|
|
m_debugText.SetColor(0x00FF00FF);
|
|
m_debugText.SetPos(vec3(-20,32,0));
|
|
m_debugText.Print(GetType());
|
|
m_debugText.SetPos(vec3(-20,20,0));
|
|
m_debugText.Print(etk::UString("life=(")+etk::UString(GetLifeRatio()));
|
|
//m_debugText.Print(etk::UString("Axe=(")+etk::UString(m_tmpAxe.x())+etk::UString(",")+etk::UString(m_tmpAxe.y())+etk::UString(",")+etk::UString(m_tmpAxe.z())+etk::UString(")"));
|
|
btScalar mmm[16];
|
|
btDefaultMotionState* myMotionState = (btDefaultMotionState*)m_body->getMotionState();
|
|
myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(mmm);
|
|
|
|
mat4 transformationMatrix(mmm);
|
|
transformationMatrix.Transpose();
|
|
|
|
// note : set the vertice here to prevent multiple allocations...
|
|
etk::Vector<vec3> EwolVertices;
|
|
DrawShape(m_shape, _draw, transformationMatrix, EwolVertices);
|
|
|
|
m_debugText.Draw( etk::matTranslate(GetPosition())
|
|
* etk::matRotate(vec3(0,0,1),_camera.GetAngleZ())
|
|
* etk::matRotate(vec3(1,0,0),(M_PI/2.0f-_camera.GetAngleTeta()))
|
|
* etk::matScale(vec3(0.05,0.05,0.05)));
|
|
}
|
|
|
|
|
|
void ege::ElementGame::DynamicEnable(void)
|
|
{
|
|
if (false == m_elementInPhysicsSystem) {
|
|
if(NULL!=m_body) {
|
|
m_env.GetDynamicWorld()->addRigidBody(m_body);
|
|
}
|
|
m_elementInPhysicsSystem = true;
|
|
}
|
|
}
|
|
|
|
void ege::ElementGame::DynamicDisable(void)
|
|
{
|
|
if (true == m_elementInPhysicsSystem) {
|
|
if(NULL!=m_body) {
|
|
// Unlink element from the engine
|
|
m_env.GetDynamicWorld()->removeRigidBody(m_body);
|
|
m_env.GetDynamicWorld()->removeCollisionObject(m_body);
|
|
}
|
|
m_elementInPhysicsSystem = false;
|
|
}
|
|
}
|
|
|
|
void ege::ElementGame::IAEnable(void)
|
|
{
|
|
if (NULL != m_IA) {
|
|
// IA already started ...
|
|
return;
|
|
}
|
|
DynamicEnable();
|
|
m_IA = new localIA(*this);
|
|
if (NULL == m_IA) {
|
|
EGE_ERROR("Can not start the IA ==> allocation error");
|
|
return;
|
|
}
|
|
m_env.GetDynamicWorld()->addAction(m_IA);
|
|
}
|
|
|
|
void ege::ElementGame::IADisable(void)
|
|
{
|
|
if (NULL == m_IA) {
|
|
// IA already stopped ...
|
|
return;
|
|
}
|
|
m_env.GetDynamicWorld()->removeAction(m_IA);
|
|
// Remove IA :
|
|
delete(m_IA);
|
|
m_IA = NULL;
|
|
}
|
|
|
|
|
|
|
|
|