ege/ege/widget/Scene.cpp

382 lines
12 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license BSD v3 (see license file)
*/
#include <ege/debug.h>
#include <ege/widget/Scene.h>
#include <math.h>
#include <ege/debug.h>
#include <ewol/ewol.h>
#include <ewol/openGL/openGL.h>
#include <etk/math/Matrix4.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__ "Scene"
ege::widget::Scene::Scene() :
signalPlayTimeChange(*this, "time-change"),
signalKillEnemy(*this, "kill-ennemy"),
m_gameTime(0),
m_angleView(M_PI/3.0),
m_dynamicsWorld(nullptr),
m_camera(nullptr),
m_isRunning(*this, "status", gameStart, "Satus of the activity of the Scene"),
m_debugMode(false),
m_debugDrawing(nullptr) {
addObjectType("ege::widget::Scene");
}
void ege::widget::Scene::init(bool _setAutoBullet, bool _setAutoCamera) {
ewol::Widget::init();
setKeyboardRepeate(false);
setCanHaveFocus(true);
periodicCallEnable();
m_isRunning.add(gameStart, "start", "Scene is started");
m_isRunning.add(gameStop, "stop", "Scene is stopped");
m_debugDrawing = ewol::resource::Colored3DObject::create();
m_ratioTime = 1.0f;
if (_setAutoBullet == true) {
setBulletConfig();
}
if (_setAutoCamera == true) {
setCamera();
}
}
void ege::widget::Scene::setBulletConfig(btDefaultCollisionConfiguration* _collisionConfiguration,
btCollisionDispatcher* _dispatcher,
btBroadphaseInterface* _broadphase,
btConstraintSolver* _solver,
btDynamicsWorld* _dynamicsWorld) {
if (nullptr != _collisionConfiguration) {
m_collisionConfiguration = _collisionConfiguration;
} else {
m_collisionConfiguration = new btDefaultCollisionConfiguration();
}
///use the default collision dispatcher.
if (nullptr != _dispatcher) {
m_dispatcher = _dispatcher;
} else {
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
}
if (nullptr != _broadphase) {
m_broadphase = _broadphase;
} else {
m_broadphase = new btDbvtBroadphase();
}
///the default constraint solver.
if (nullptr != _solver) {
m_solver = _solver;
} else {
m_solver = new btSequentialImpulseConstraintSolver();
}
if (nullptr != _dynamicsWorld) {
m_dynamicsWorld = _dynamicsWorld;
} else {
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
// By default we set no gravity
m_dynamicsWorld->setGravity(btVector3(0,0,0));
}
m_env.setDynamicWorld(m_dynamicsWorld);
}
void ege::widget::Scene::setCamera(ege::Camera* _camera) {
if (nullptr != _camera) {
m_camera = _camera;
} else {
m_camera = new ege::Camera(vec3(0,0,0), 0, DEG_TO_RAD(45) ,50);
// SET THE STATION ..
m_camera->setEye(vec3(0,0,0));
}
}
ege::widget::Scene::~Scene() {
/*
ewol::resource::release(m_directDrawObject);
//cleanup in the reverse order of creation/initialization
//remove the rigidbodies from the dynamics world and delete them
for (int32_t iii=m_dynamicsWorld->getNumCollisionObjects()-1; iii >= 0 ;iii--) {
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[iii];
btRigidBody* body = btRigidBody::upcast(obj);
if (body && body->getMotionState()) {
delete body->getMotionState();
}
m_dynamicsWorld->removeCollisionObject( obj );
delete obj;
}
delete m_dynamicsWorld;
delete m_solver;
delete m_broadphase;
delete m_dispatcher;
delete m_collisionConfiguration;
*/
}
void ege::widget::Scene::onRegenerateDisplay() {
if (true == needRedraw()) {
}
}
void ege::widget::Scene::pause() {
EGE_DEBUG("Set pause");
m_isRunning.set(gameStop);
}
void ege::widget::Scene::resume() {
EGE_DEBUG("Set resume");
m_isRunning.set(gameStart);
}
void ege::widget::Scene::pauseToggle() {
if(m_isRunning.get() == gameStart) {
EGE_DEBUG("Set Toggle: pause");
m_isRunning.set(gameStop);
} else {
EGE_DEBUG("Set Toggle: resume");
m_isRunning.set(gameStart);
}
}
//#define SCENE_DISPLAY_SPEED
//////////////////////////////////////////////////////////////////////////////////////////////
#ifdef SCENE_DISPLAY_SPEED
static int64_t g_startTime = 0;
static int32_t g_counterNbTimeDisplay = 0;
#endif
#define NUMBER_OF_SUB_PASS (0)
void ege::widget::Scene::onDraw() {
#ifdef SCENE_DISPLAY_SPEED
g_counterNbTimeDisplay++;
g_startTime = ewol::getTime();
#endif
//EGE_DEBUG("Draw (start)");
mat4 tmpMatrix;
if (m_dynamicsWorld) {
m_env.getOrderedElementForDisplay(m_displayElementOrdered, m_camera->getOrigin(), m_camera->getViewVector());
//EGE_DEBUG("DRAW : " << m_displayElementOrdered.size() << " elements");
// TODO : remove this == > no more needed ==> checked in the generate the list of the element ordered
for (size_t iii=0; iii<m_displayElementOrdered.size(); iii++) {
m_displayElementOrdered[iii].element->preCalculationDraw(*m_camera);
}
// note : the first pass is done at the reverse way to prevent multiple display od the same point in the screen
// (and we remember that the first pass is to display all the non transparent elements)
#if 0
// note : We keep this one for the test only ...
for (int32_t iii=0; iii<m_displayElementOrdered.size(); iii++) {
#else
for (int32_t iii=m_displayElementOrdered.size()-1; iii >= 0; iii--) {
#endif
m_displayElementOrdered[iii].element->draw(0);
}
// for the other pass the user can draw transparent elements ...
for (int32_t pass=1; pass <= NUMBER_OF_SUB_PASS+1; pass++) {
for (size_t iii=0; iii<m_displayElementOrdered.size(); iii++) {
m_displayElementOrdered[iii].element->draw(pass);
}
}
for (size_t iii=0; iii<m_displayElementOrdered.size(); iii++) {
m_displayElementOrdered[iii].element->drawLife(m_debugDrawing, *m_camera);
}
#ifdef DEBUG
if (true == m_debugMode) {
for (size_t iii=0; iii<m_displayElementOrdered.size(); iii++) {
m_displayElementOrdered[iii].element->drawDebug(m_debugDrawing, *m_camera);
}
}
#endif
}
if (nullptr!=m_camera) {
m_env.getParticuleEngine().draw(*m_camera);
}
#ifdef SCENE_DISPLAY_SPEED
float localTime = (float)(ewol::getTime() - g_startTime) / 1000.0f;
if (localTime>1) {
EWOL_ERROR(" scene : " << localTime << "ms " << g_counterNbTimeDisplay);
} else {
EWOL_DEBUG(" scene : " << localTime << "ms " << g_counterNbTimeDisplay);
}
#endif
//EGE_DEBUG("Draw (stop)");
}
// I really does not know what is this ...
btRigidBody& btActionInterface::getFixedBody() {
static btRigidBody s_fixed(0, 0,0);
s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.)));
return s_fixed;
}
void ege::widget::Scene::periodicCall(const ewol::event::Time& _event) {
float curentDelta=_event.getDeltaCall();
// small hack to change speed ...
if (m_ratioTime != 1) {
curentDelta *= m_ratioTime;
}
// check if the processing is availlable
if (m_isRunning.get() == gameStart) {
markToRedraw();
return;
}
// update game time:
int32_t lastGameTime = m_gameTime;
m_gameTime += curentDelta;
if (lastGameTime != (int32_t)m_gameTime) {
signalPlayTimeChange.emit(shared_from_this(), m_gameTime);
}
//EWOL_DEBUG("Time: m_lastCallTime=" << m_lastCallTime << " deltaTime=" << deltaTime);
// update camera positions:
if (nullptr != m_camera) {
m_camera->periodicCall(curentDelta);
}
//EGE_DEBUG("stepSimulation (start)");
///step the simulation
if (m_dynamicsWorld) {
m_dynamicsWorld->stepSimulation(curentDelta);
//optional but useful: debug drawing
m_dynamicsWorld->debugDrawWorld();
}
m_env.getParticuleEngine().update(curentDelta);
// remove all element that requested it ...
{
int32_t numberEnnemyKilled=0;
int32_t victoryPoint=0;
std::vector<ege::ElementGame*>& elementList = m_env.getElementGame();
for (int32_t iii=elementList.size()-1; iii >= 0; --iii) {
if(nullptr != elementList[iii]) {
if (true == elementList[iii]->needToRemove()) {
if (elementList[iii]->getGroup() > 1) {
numberEnnemyKilled++;
victoryPoint++;
}
EGE_DEBUG("[" << elementList[iii]->getUID() << "] element Removing ... " << elementList[iii]->getType());
m_env.rmElementGame(elementList[iii]);
}
}
}
if (0 != numberEnnemyKilled) {
signalKillEnemy.emit(shared_from_this(), numberEnnemyKilled);
}
}
markToRedraw();
}
#define GAME_Z_NEAR (1)
#define GAME_Z_FAR (4000)
//#define SCENE_BRUT_PERFO_TEST
void ege::widget::Scene::systemDraw(const ewol::DrawProperty& _displayProp)
{
#ifdef SCENE_BRUT_PERFO_TEST
int64_t tmp___startTime0 = ewol::getTime();
#endif
ewol::openGL::push();
// here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left
glViewport( m_origin.x(),
m_origin.y(),
m_size.x(),
m_size.y());
#ifdef SCENE_BRUT_PERFO_TEST
float tmp___localTime0 = (float)(ewol::getTime() - tmp___startTime0) / 1000.0f;
EWOL_DEBUG(" SCENE000 : " << tmp___localTime0 << "ms ");
int64_t tmp___startTime1 = ewol::getTime();
#endif
float ratio = m_size.x() / m_size.y();
//EWOL_INFO("ratio : " << ratio);
mat4 tmpProjection = etk::matPerspective(m_angleView, ratio, GAME_Z_NEAR, GAME_Z_FAR);
#ifdef SCENE_BRUT_PERFO_TEST
float tmp___localTime1 = (float)(ewol::getTime() - tmp___startTime1) / 1000.0f;
EWOL_DEBUG(" SCENE111 : " << tmp___localTime1 << "ms ");
int64_t tmp___startTime2 = ewol::getTime();
#endif
ewol::openGL::setCameraMatrix(m_camera->getMatrix());
//mat4 tmpMat = tmpProjection * m_camera->getMatrix();
// set internal matrix system :
//ewol::openGL::setMatrix(tmpMat);
ewol::openGL::setMatrix(tmpProjection);
#ifdef SCENE_BRUT_PERFO_TEST
float tmp___localTime2 = (float)(ewol::getTime() - tmp___startTime2) / 1000.0f;
EWOL_DEBUG(" SCENE222 : " << tmp___localTime2 << "ms ");
#endif
#ifdef SCENE_BRUT_PERFO_TEST
int64_t tmp___startTime3 = ewol::getTime();
#endif
onDraw();
#ifdef SCENE_BRUT_PERFO_TEST
float tmp___localTime3 = (float)(ewol::getTime() - tmp___startTime3) / 1000.0f;
EWOL_DEBUG(" SCENE333 : " << tmp___localTime3 << "ms ");
int64_t tmp___startTime4 = ewol::getTime();
#endif
ewol::openGL::pop();
#ifdef SCENE_BRUT_PERFO_TEST
float tmp___localTime4 = (float)(ewol::getTime() - tmp___startTime4) / 1000.0f;
EWOL_DEBUG(" SCENE444 : " << tmp___localTime4 << "ms ");
#endif
}
vec2 ege::widget::Scene::calculateDeltaAngle(const vec2& _posScreen) {
double ratio = m_size.x() / m_size.y();
vec2 pos = vec2(m_size.x()/-2.0, m_size.y()/-2.0) + _posScreen;
double xmax = tan(m_angleView/2.0);
double ymax = xmax / ratio;
double newX = pos.x() * xmax / m_size.x()*2.0;
double newY = pos.y() * ymax / m_size.y()*2.0;
double angleX = atan(newX);
double angleY = atan(newY);
return vec2(angleX,
angleY);
}
vec3 ege::widget::Scene::convertScreenPositionInMapPosition(const vec2& _posScreen) {
return m_camera->projectOnZGround(calculateDeltaAngle(_posScreen));
}
void ege::widget::Scene::onParameterChangeValue(const ewol::object::ParameterRef& _paramPointer) {
ewol::Widget::onParameterChangeValue(_paramPointer);
if (_paramPointer == m_isRunning) {
// nothing to do ...
}
}