- fixed 1270 CR characters - fixed 56 trailing spaces - fixed 5085 tabslegacy
@@ -240,45 +240,45 @@ void EasyMesh::Rotate(float t, vec3 const &axis) | |||||
void EasyMesh::RadialJitter(float r) | void EasyMesh::RadialJitter(float r) | ||||
{ | { | ||||
Array<int> Welded; | Array<int> Welded; | ||||
Welded.Push(-1); | |||||
Welded.Push(-1); | |||||
for (int i = m_cursors.Last().m1 + 1; i < m_vert.Count(); i++) | for (int i = m_cursors.Last().m1 + 1; i < m_vert.Count(); i++) | ||||
{ | |||||
int j, k; | |||||
for (j = m_cursors.Last().m1, k = 0; j < i; j++, k++) | |||||
{ | |||||
if(Welded[k] < 0) | |||||
{ | |||||
vec3 diff = m_vert[i].m1 - m_vert[j].m1; | |||||
if(diff.x > 0.1f || diff.x < -0.1f) | |||||
continue; | |||||
if(diff.y > 0.1f || diff.y < -0.1f) | |||||
continue; | |||||
if(diff.z > 0.1f || diff.z < -0.1f) | |||||
continue; | |||||
break; | |||||
} | |||||
} | |||||
if(j == i) | |||||
Welded.Push(-1); | |||||
else | |||||
Welded.Push(j); | |||||
} | |||||
int i, j; | |||||
{ | |||||
int j, k; | |||||
for (j = m_cursors.Last().m1, k = 0; j < i; j++, k++) | |||||
{ | |||||
if(Welded[k] < 0) | |||||
{ | |||||
vec3 diff = m_vert[i].m1 - m_vert[j].m1; | |||||
if(diff.x > 0.1f || diff.x < -0.1f) | |||||
continue; | |||||
if(diff.y > 0.1f || diff.y < -0.1f) | |||||
continue; | |||||
if(diff.z > 0.1f || diff.z < -0.1f) | |||||
continue; | |||||
break; | |||||
} | |||||
} | |||||
if(j == i) | |||||
Welded.Push(-1); | |||||
else | |||||
Welded.Push(j); | |||||
} | |||||
int i, j; | |||||
for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++) | for (i = m_cursors.Last().m1, j = 0; i < m_vert.Count(); i++, j++) | ||||
{ | |||||
if(Welded[j] == -1) | |||||
m_vert[i].m1 *= 1.0f + RandF(r); | |||||
else | |||||
m_vert[i].m1 = m_vert[Welded[j]].m1; | |||||
} | |||||
{ | |||||
if(Welded[j] == -1) | |||||
m_vert[i].m1 *= 1.0f + RandF(r); | |||||
else | |||||
m_vert[i].m1 = m_vert[Welded[j]].m1; | |||||
} | |||||
ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2); | |||||
ComputeNormals(m_cursors.Last().m2, m_indices.Count() - m_cursors.Last().m2); | |||||
} | } | ||||
void EasyMesh::TaperX(float y, float z, float xoff) | void EasyMesh::TaperX(float y, float z, float xoff) | ||||
@@ -361,10 +361,10 @@ void EasyMesh::AppendCylinder(int nsides, float h, float r1, float r2, | |||||
vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n; | vec3 p1(r1, -h * .5f, 0.f), p2(r2, h * .5f, 0.f), n; | ||||
/* Construct normal */ | /* Construct normal */ | ||||
if (r2 != .0f) | |||||
n = vec3(r2, h * .5f, 0.f); | |||||
else | |||||
n = vec3(r1, h * .5f, 0.f); | |||||
if (r2 != .0f) | |||||
n = vec3(r2, h * .5f, 0.f); | |||||
else | |||||
n = vec3(r1, h * .5f, 0.f); | |||||
n.y = r1 * (r1 - r2) / h; | n.y = r1 * (r1 - r2) / h; | ||||
if (!smooth) | if (!smooth) | ||||
n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n; | n = mat3::rotate(180.0f / nsides, 0.f, 1.f, 0.f) * n; | ||||
@@ -850,7 +850,7 @@ void EasyMesh::Chamfer(float f) | |||||
for (int i = 0; i < ilen / 3; i++) | for (int i = 0; i < ilen / 3; i++) | ||||
{ | { | ||||
} | } | ||||
/* Fun shit: reduce all triangles */ | /* Fun shit: reduce all triangles */ | ||||
@@ -45,11 +45,11 @@ protected: | |||||
{ | { | ||||
GAMEGROUP_BEFORE = 0, | GAMEGROUP_BEFORE = 0, | ||||
GAMEGROUP_DEFAULT, | GAMEGROUP_DEFAULT, | ||||
GAMEGROUP_AFTER, | |||||
GAMEGROUP_AFTER_0, | |||||
GAMEGROUP_AFTER_1, | |||||
GAMEGROUP_AFTER, | |||||
GAMEGROUP_AFTER_0, | |||||
GAMEGROUP_AFTER_1, | |||||
// Must be the last element | |||||
// Must be the last element | |||||
GAMEGROUP_END | GAMEGROUP_END | ||||
} | } | ||||
m_gamegroup; | m_gamegroup; | ||||
@@ -31,7 +31,7 @@ namespace lol | |||||
* Input implementation class | * Input implementation class | ||||
*/ | */ | ||||
InputTracker* Input::m_input_tracker = NULL; | |||||
InputTracker* Input::m_input_tracker = NULL; | |||||
static class InputData | static class InputData | ||||
{ | { | ||||
@@ -66,10 +66,10 @@ static InputData * const data = &inputdata; | |||||
int ButtonSetting::GetActionSettingIdx(ACTION_TYPE SearchAction) | int ButtonSetting::GetActionSettingIdx(ACTION_TYPE SearchAction) | ||||
{ | { | ||||
for (int i = 0; i < m_associated_action_list.Count(); i++) | |||||
if (ACTION_CMP(m_associated_action_list[i].m_action, SearchAction)) | |||||
return i; | |||||
return -1; | |||||
for (int i = 0; i < m_associated_action_list.Count(); i++) | |||||
if (ACTION_CMP(m_associated_action_list[i].m_action, SearchAction)) | |||||
return i; | |||||
return -1; | |||||
} | } | ||||
/* | /* | ||||
@@ -78,37 +78,37 @@ int ButtonSetting::GetActionSettingIdx(ACTION_TYPE SearchAction) | |||||
InputTracker::InputTracker() | InputTracker::InputTracker() | ||||
{ | { | ||||
m_gamegroup = GAMEGROUP_BEFORE; | |||||
m_gamegroup = GAMEGROUP_BEFORE; | |||||
for (int i = 0; i < Key::Last * 2; ++i) | |||||
m_input_status << 0; | |||||
for (int i = 0; i < Key::Last * 2; ++i) | |||||
m_input_status << 0; | |||||
Ticker::Ref(this); | |||||
Ticker::Ref(this); | |||||
} | } | ||||
//Internal | //Internal | ||||
int InputTracker::GetButtonSettingIdx(Key Button) | int InputTracker::GetButtonSettingIdx(Key Button) | ||||
{ | { | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
if (m_input_assocation_list[i].m_raw_button == Button) | |||||
return i; | |||||
return -1; | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
if (m_input_assocation_list[i].m_raw_button == Button) | |||||
return i; | |||||
return -1; | |||||
} | } | ||||
//----- | //----- | ||||
int InputTracker::GetCurrentButtonStatus(Key Button) | int InputTracker::GetCurrentButtonStatus(Key Button) | ||||
{ | { | ||||
if (Button < m_input_status.Count()) | |||||
return m_input_status[Button]; | |||||
return 0; | |||||
if (Button < m_input_status.Count()) | |||||
return m_input_status[Button]; | |||||
return 0; | |||||
} | } | ||||
//----- | //----- | ||||
int InputTracker::GetPreviousButtonStatus(Key Button) | int InputTracker::GetPreviousButtonStatus(Key Button) | ||||
{ | { | ||||
if (Button < m_input_status.Count()) | |||||
return m_input_status[(int)Button + (int)Key::Last]; | |||||
return 0; | |||||
if (Button < m_input_status.Count()) | |||||
return m_input_status[(int)Button + (int)Key::Last]; | |||||
return 0; | |||||
} | } | ||||
//Internal : Updates the action status & timers | //Internal : Updates the action status & timers | ||||
@@ -116,146 +116,146 @@ void InputTracker::UpdateActionStatus(float seconds) | |||||
{ | { | ||||
#if defined USE_SDL | #if defined USE_SDL | ||||
#if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3 | #if SDL_MAJOR_VERSION == 1 && SDL_MINOR_VERSION >= 3 | ||||
Uint8 *keystate = SDL_GetKeyboardState(NULL); | |||||
Uint8 *keystate = SDL_GetKeyboardState(NULL); | |||||
#else | #else | ||||
Uint8 *keystate = SDL_GetKeyState(NULL); | |||||
Uint8 *keystate = SDL_GetKeyState(NULL); | |||||
#endif | #endif | ||||
//SOOOoooo ugly. | |||||
for (int i = 0; i < Key::Last; ++i) | |||||
{ | |||||
m_input_status[i + Key::Last] = m_input_status[i]; | |||||
m_input_status[i] = keystate[i]; | |||||
} | |||||
//SOOOoooo ugly. | |||||
for (int i = 0; i < Key::Last; ++i) | |||||
{ | |||||
m_input_status[i + Key::Last] = m_input_status[i]; | |||||
m_input_status[i] = keystate[i]; | |||||
} | |||||
#endif | #endif | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++) | |||||
{ | |||||
ActionSetting &CurAS = CurIT.m_associated_action_list[j]; | |||||
for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++) | |||||
{ | |||||
ActionSetting &CurAS = CurIT.m_associated_action_list[j]; | |||||
if (CurAS.m_buffered_since <= CurAS.m_buffering_time) | |||||
CurAS.m_buffered_since += seconds; | |||||
if (CurAS.m_buffered_since <= CurAS.m_buffering_time) | |||||
CurAS.m_buffered_since += seconds; | |||||
if (GetCurrentButtonStatus(CurIT.m_raw_button) && | |||||
CurAS.m_buffering_time >= .0f) | |||||
CurAS.m_buffered_since = .0f; | |||||
} | |||||
} | |||||
if (GetCurrentButtonStatus(CurIT.m_raw_button) && | |||||
CurAS.m_buffering_time >= .0f) | |||||
CurAS.m_buffered_since = .0f; | |||||
} | |||||
} | |||||
} | } | ||||
//Helps link a software input Action-Id to an hardware input Button-Id. | //Helps link a software input Action-Id to an hardware input Button-Id. | ||||
void InputTracker::LinkActionToKey(ACTION_TYPE Action, Key Button) | void InputTracker::LinkActionToKey(ACTION_TYPE Action, Key Button) | ||||
{ | { | ||||
int ITIdx = GetButtonSettingIdx(Button); | |||||
if (ITIdx == -1) | |||||
{ | |||||
ITIdx = m_input_assocation_list.Count(); | |||||
m_input_assocation_list << ButtonSetting(Button); | |||||
} | |||||
int ITIdx = GetButtonSettingIdx(Button); | |||||
if (ITIdx == -1) | |||||
{ | |||||
ITIdx = m_input_assocation_list.Count(); | |||||
m_input_assocation_list << ButtonSetting(Button); | |||||
} | |||||
ButtonSetting &CurIT = m_input_assocation_list[ITIdx]; | |||||
ButtonSetting &CurIT = m_input_assocation_list[ITIdx]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx == -1) | |||||
{ | |||||
ASIdx = CurIT.m_associated_action_list.Count(); | |||||
CurIT.m_associated_action_list << ActionSetting(Action); | |||||
} | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx == -1) | |||||
{ | |||||
ASIdx = CurIT.m_associated_action_list.Count(); | |||||
CurIT.m_associated_action_list << ActionSetting(Action); | |||||
} | |||||
} | } | ||||
//Helps unlink a software input Action-Id to an hardware input Button-Id. | //Helps unlink a software input Action-Id to an hardware input Button-Id. | ||||
void InputTracker::UnlinkAction(ACTION_TYPE Action) | void InputTracker::UnlinkAction(ACTION_TYPE Action) | ||||
{ | { | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
CurIT.m_associated_action_list.Remove(ASIdx); | |||||
} | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
CurIT.m_associated_action_list.Remove(ASIdx); | |||||
} | |||||
} | } | ||||
//Returns the current status of a given action | //Returns the current status of a given action | ||||
int InputTracker::GetStatus(ACTION_TYPE Action) | int InputTracker::GetStatus(ACTION_TYPE Action) | ||||
{ | { | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx]; | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx]; | |||||
if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
} | |||||
return 0; | |||||
if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time) | |||||
return 1; | |||||
return 0; | |||||
} | |||||
} | |||||
return 0; | |||||
} | } | ||||
//Returns TRUE if action status went from Active to Inactive this frame | //Returns TRUE if action status went from Active to Inactive this frame | ||||
bool InputTracker::WasReleased(ACTION_TYPE Action) | bool InputTracker::WasReleased(ACTION_TYPE Action) | ||||
{ | { | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
if (GetPreviousButtonStatus(CurIT.m_raw_button) && | |||||
!GetCurrentButtonStatus(CurIT.m_raw_button)) | |||||
return true; | |||||
return false; | |||||
} | |||||
} | |||||
return false; | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
if (GetPreviousButtonStatus(CurIT.m_raw_button) && | |||||
!GetCurrentButtonStatus(CurIT.m_raw_button)) | |||||
return true; | |||||
return false; | |||||
} | |||||
} | |||||
return false; | |||||
} | } | ||||
//Returns TRUE if action status went from Inactive to Active this frame | //Returns TRUE if action status went from Inactive to Active this frame | ||||
bool InputTracker::WasPressed(ACTION_TYPE Action) | bool InputTracker::WasPressed(ACTION_TYPE Action) | ||||
{ | { | ||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
if (!GetPreviousButtonStatus(CurIT.m_raw_button) && | |||||
GetCurrentButtonStatus(CurIT.m_raw_button)) | |||||
return true; | |||||
return false; | |||||
} | |||||
} | |||||
return false; | |||||
for (int i = 0; i < m_input_assocation_list.Count(); i++) | |||||
{ | |||||
ButtonSetting &CurIT = m_input_assocation_list[i]; | |||||
int ASIdx = CurIT.GetActionSettingIdx(Action); | |||||
if (ASIdx != -1) | |||||
{ | |||||
if (!GetPreviousButtonStatus(CurIT.m_raw_button) && | |||||
GetCurrentButtonStatus(CurIT.m_raw_button)) | |||||
return true; | |||||
return false; | |||||
} | |||||
} | |||||
return false; | |||||
} | } | ||||
//Returns the current status of a given action | //Returns the current status of a given action | ||||
int InputTracker::GetStatus(Key Button) | int InputTracker::GetStatus(Key Button) | ||||
{ | { | ||||
return GetCurrentButtonStatus(Button); | |||||
return GetCurrentButtonStatus(Button); | |||||
} | } | ||||
//Returns TRUE if action status went from Active to Inactive this frame | //Returns TRUE if action status went from Active to Inactive this frame | ||||
bool InputTracker::WasReleased(Key Button) | bool InputTracker::WasReleased(Key Button) | ||||
{ | { | ||||
if (GetPreviousButtonStatus(Button) && | |||||
!GetCurrentButtonStatus(Button)) | |||||
return true; | |||||
return false; | |||||
if (GetPreviousButtonStatus(Button) && | |||||
!GetCurrentButtonStatus(Button)) | |||||
return true; | |||||
return false; | |||||
} | } | ||||
//Returns TRUE if action status went from Inactive to Active this frame | //Returns TRUE if action status went from Inactive to Active this frame | ||||
bool InputTracker::WasPressed(Key Button) | bool InputTracker::WasPressed(Key Button) | ||||
{ | { | ||||
if (!GetPreviousButtonStatus(Button) && | |||||
GetCurrentButtonStatus(Button)) | |||||
return true; | |||||
return false; | |||||
if (!GetPreviousButtonStatus(Button) && | |||||
GetCurrentButtonStatus(Button)) | |||||
return true; | |||||
return false; | |||||
} | } | ||||
/* | /* | ||||
@@ -316,63 +316,63 @@ int Input::GetButtonState(int button) | |||||
//Helps link a software input Action-Id to an hardware input Button-Id. | //Helps link a software input Action-Id to an hardware input Button-Id. | ||||
void Input::LinkActionToKey(ACTION_TYPE Action, struct Key Button) | void Input::LinkActionToKey(ACTION_TYPE Action, struct Key Button) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
Input::m_input_tracker->LinkActionToKey(Action, Button); | |||||
if (CheckInputTrackerInit()) | |||||
Input::m_input_tracker->LinkActionToKey(Action, Button); | |||||
} | } | ||||
//Helps unlink a software input Action-Id to an hardware input Button-Id. | //Helps unlink a software input Action-Id to an hardware input Button-Id. | ||||
void Input::UnlinkAction(ACTION_TYPE Action) | void Input::UnlinkAction(ACTION_TYPE Action) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
Input::m_input_tracker->UnlinkAction(Action); | |||||
if (CheckInputTrackerInit()) | |||||
Input::m_input_tracker->UnlinkAction(Action); | |||||
} | } | ||||
//Returns the current status of a given action | //Returns the current status of a given action | ||||
int Input::GetStatus(ACTION_TYPE Action) | int Input::GetStatus(ACTION_TYPE Action) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->GetStatus(Action); | |||||
return 0; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->GetStatus(Action); | |||||
return 0; | |||||
} | } | ||||
//Returns TRUE if action status when from Active to Inactive this frame | //Returns TRUE if action status when from Active to Inactive this frame | ||||
bool Input::WasPressed(ACTION_TYPE Action) | bool Input::WasPressed(ACTION_TYPE Action) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasPressed(Action); | |||||
return false; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasPressed(Action); | |||||
return false; | |||||
} | } | ||||
//Returns TRUE if action status when from Active to Inactive this frame | //Returns TRUE if action status when from Active to Inactive this frame | ||||
bool Input::WasReleased(ACTION_TYPE Action) | bool Input::WasReleased(ACTION_TYPE Action) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasReleased(Action); | |||||
return false; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasReleased(Action); | |||||
return false; | |||||
} | } | ||||
//Returns the current status of a given action | //Returns the current status of a given action | ||||
int Input::GetStatus(Key Button) | int Input::GetStatus(Key Button) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->GetStatus(Button); | |||||
return 0; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->GetStatus(Button); | |||||
return 0; | |||||
} | } | ||||
//Returns TRUE if action status when from Active to Inactive this frame | //Returns TRUE if action status when from Active to Inactive this frame | ||||
bool Input::WasPressed(Key Button) | bool Input::WasPressed(Key Button) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasPressed(Button); | |||||
return false; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasPressed(Button); | |||||
return false; | |||||
} | } | ||||
//Returns TRUE if action status when from Active to Inactive this frame | //Returns TRUE if action status when from Active to Inactive this frame | ||||
bool Input::WasReleased(Key Button) | bool Input::WasReleased(Key Button) | ||||
{ | { | ||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasReleased(Button); | |||||
return false; | |||||
if (CheckInputTrackerInit()) | |||||
return Input::m_input_tracker->WasReleased(Button); | |||||
return false; | |||||
} | } | ||||
//-- | //-- | ||||
@@ -409,7 +409,7 @@ public: | |||||
static ivec2 GetMousePos(); | static ivec2 GetMousePos(); | ||||
static ivec3 GetMouseButtons(); | static ivec3 GetMouseButtons(); | ||||
//BH : Shouldn't use this | |||||
//BH : Shouldn't use this | |||||
static int GetButtonState(int button); | static int GetButtonState(int button); | ||||
/* Action management */ | /* Action management */ | ||||
@@ -66,11 +66,11 @@ static inline void sincos(float const &x, float *s, float *c) | |||||
static inline double lerp(double const &a, double const &b, double const &x) | static inline double lerp(double const &a, double const &b, double const &x) | ||||
{ | { | ||||
return a + (b - a) * x; | |||||
return a + (b - a) * x; | |||||
} | } | ||||
static inline float lerp(float const &a, float const &b, float const &x) | static inline float lerp(float const &a, float const &b, float const &x) | ||||
{ | { | ||||
return a + (b - a) * x; | |||||
return a + (b - a) * x; | |||||
} | } | ||||
@@ -55,8 +55,8 @@ template <typename T> static inline T PotUp(T val) | |||||
//Lerp for float | //Lerp for float | ||||
template <typename T1, typename T2, typename Tf> static inline T1 damp(const T1 &a, const T2 &b, const Tf &x, const Tf &dt) | template <typename T1, typename T2, typename Tf> static inline T1 damp(const T1 &a, const T2 &b, const Tf &x, const Tf &dt) | ||||
{ | { | ||||
if (dt <= .0f) | |||||
return a; | |||||
if (dt <= .0f) | |||||
return a; | |||||
return lol::lerp(a, b, dt / (dt + x)); | return lol::lerp(a, b, dt / (dt + x)); | ||||
} | } | ||||
@@ -28,7 +28,7 @@ WorldEntity::WorldEntity() | |||||
m_position = vec3(0); | m_position = vec3(0); | ||||
m_rotation = quat(1); | m_rotation = quat(1); | ||||
m_velocity = vec3(0); | m_velocity = vec3(0); | ||||
m_rotation_velocity = vec3(0); | |||||
m_rotation_velocity = vec3(0); | |||||
m_bbox[0] = m_bbox[1] = vec3(0); | m_bbox[0] = m_bbox[1] = vec3(0); | ||||
m_mousepos = ivec2(0); | m_mousepos = ivec2(0); | ||||
@@ -49,25 +49,25 @@ using namespace lol::phys; | |||||
int gNumObjects = 64; | int gNumObjects = 64; | ||||
#define USE_WALL 1 | |||||
#define USE_PLATFORM 1 | |||||
#define USE_ROPE 0 | |||||
#define USE_BODIES 1 | |||||
#define USE_ROTATION 0 | |||||
#define USE_CHARACTER 1 | |||||
#define USE_STAIRS 1 | |||||
#define IPT_MOVE_FORWARD "Move_Forward" | |||||
#define IPT_MOVE_BACKWARD "Move_Backward" | |||||
#define IPT_MOVE_LEFT "Move_Left" | |||||
#define IPT_MOVE_RIGHT "Move_Right" | |||||
#define IPT_MOVE_UP "Move_Up" | |||||
#define IPT_MOVE_DOWN "Move_Down" | |||||
#define IPT_MOVE_JUMP "Move_Jump" | |||||
#define USE_WALL 1 | |||||
#define USE_PLATFORM 1 | |||||
#define USE_ROPE 0 | |||||
#define USE_BODIES 1 | |||||
#define USE_ROTATION 0 | |||||
#define USE_CHARACTER 1 | |||||
#define USE_STAIRS 1 | |||||
#define IPT_MOVE_FORWARD "Move_Forward" | |||||
#define IPT_MOVE_BACKWARD "Move_Backward" | |||||
#define IPT_MOVE_LEFT "Move_Left" | |||||
#define IPT_MOVE_RIGHT "Move_Right" | |||||
#define IPT_MOVE_UP "Move_Up" | |||||
#define IPT_MOVE_DOWN "Move_Down" | |||||
#define IPT_MOVE_JUMP "Move_Jump" | |||||
BtPhysTest::BtPhysTest(bool editor) | BtPhysTest::BtPhysTest(bool editor) | ||||
{ | { | ||||
m_loop_value = .0f; | |||||
m_loop_value = .0f; | |||||
/* Create a camera that matches the settings of XNA BtPhysTest */ | /* Create a camera that matches the settings of XNA BtPhysTest */ | ||||
m_camera = new Camera(vec3(0.f, 600.f, 0.f), | m_camera = new Camera(vec3(0.f, 600.f, 0.f), | ||||
@@ -75,191 +75,191 @@ BtPhysTest::BtPhysTest(bool editor) | |||||
vec3(0, 1, 0)); | vec3(0, 1, 0)); | ||||
m_camera->SetRotation(quat::fromeuler_xyz(0.f, 0.f, 0.f)); | m_camera->SetRotation(quat::fromeuler_xyz(0.f, 0.f, 0.f)); | ||||
m_camera->SetPerspective(45.f, 1280.f, 960.f, .1f, 1000.f); | m_camera->SetPerspective(45.f, 1280.f, 960.f, .1f, 1000.f); | ||||
//m_camera->SetOrtho(1280.f / 6, 960.f / 6, -1000.f, 1000.f); | |||||
//m_camera->SetOrtho(1280.f / 6, 960.f / 6, -1000.f, 1000.f); | |||||
Ticker::Ref(m_camera); | Ticker::Ref(m_camera); | ||||
m_ready = false; | m_ready = false; | ||||
m_simulation = new Simulation(); | |||||
m_simulation->SetWorldLimit(vec3(-1000.0f, -1000.0f, -1000.0f), vec3(1000.0f, 1000.0f, 1000.0f)); | |||||
m_simulation->Init(); | |||||
vec3 NewGravity = vec3(.0f, -10.0f, .0f); | |||||
m_simulation->SetGravity(NewGravity); | |||||
m_simulation->SetContinuousDetection(true); | |||||
m_simulation->SetTimestep(1.f / 120.f); | |||||
m_simulation = new Simulation(); | |||||
m_simulation->SetWorldLimit(vec3(-1000.0f, -1000.0f, -1000.0f), vec3(1000.0f, 1000.0f, 1000.0f)); | |||||
m_simulation->Init(); | |||||
vec3 NewGravity = vec3(.0f, -10.0f, .0f); | |||||
m_simulation->SetGravity(NewGravity); | |||||
m_simulation->SetContinuousDetection(true); | |||||
m_simulation->SetTimestep(1.f / 120.f); | |||||
Ticker::Ref(m_simulation); | Ticker::Ref(m_simulation); | ||||
float offset = 29.5f; | |||||
vec3 pos_offset = vec3(.0f, 30.f, .0f); | |||||
if (USE_STAIRS) | |||||
{ | |||||
vec3 new_offset = vec3(1.0f, .125f, .0f); | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(5.0f, -29.f, 15.0f); | |||||
{ | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 30.f); | |||||
NewPosition += vec3(4.0f, .0f, -4.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
{ | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 40.f); | |||||
NewPosition += vec3(4.0f, .0f, -4.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
NewPosition = pos_offset + vec3(5.0f, -29.5f, 15.0f); | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
for (int i=0; i < 15; i++) | |||||
{ | |||||
NewPosition += new_offset; | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
} | |||||
if (USE_WALL) | |||||
{ | |||||
for (int i=0; i < 6; i++) | |||||
{ | |||||
vec3 NewPosition = vec3(.0f); | |||||
quat NewRotation = quat(1.f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation); | |||||
int idx = i/2; | |||||
NewPosition = pos_offset; | |||||
NewPosition[idx] += offset; | |||||
offset *= -1.f; | |||||
if (idx != 1) | |||||
{ | |||||
vec3 NewAxis = vec3(.0f); | |||||
NewAxis[2 - idx] = 1; | |||||
NewRotation = quat::rotate(90.f, NewAxis); | |||||
} | |||||
NewPhyobj->SetTransform(NewPosition, NewRotation); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_ground_list << NewPhyobj; | |||||
} | |||||
} | |||||
PhysicsObject* BasePhyobj = NULL; | |||||
if (USE_PLATFORM) | |||||
{ | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(5.0f, -25.0f, -15.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
NewPosition = pos_offset + vec3(-15.0f, -25.0f, 5.0f); | |||||
NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
BasePhyobj = NewPhyobj; | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 90.f); | |||||
NewPosition = pos_offset + vec3(-20.0f, -25.0f, 5.0f); | |||||
NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), true, true); | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
//NewPosition += vec3(-0.0f, .0f, .0f); | |||||
//NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
//NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), true, false); | |||||
//m_platform_list << NewPhyobj; | |||||
//Ticker::Ref(NewPhyobj); | |||||
//NewPosition += vec3(-2.0f, .0f, .0f); | |||||
//NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
//NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), false, false); | |||||
//m_platform_list << NewPhyobj; | |||||
//Ticker::Ref(NewPhyobj); | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(-5.0f, -10.0f, 15.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 2); | |||||
m_character_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
Input::LinkActionToKey(IPT_MOVE_FORWARD, Key::Up); | |||||
Input::LinkActionToKey(IPT_MOVE_BACKWARD, Key::Down); | |||||
Input::LinkActionToKey(IPT_MOVE_LEFT, Key::Left); | |||||
Input::LinkActionToKey(IPT_MOVE_RIGHT, Key::Right); | |||||
Input::LinkActionToKey(IPT_MOVE_JUMP, Key::Space); | |||||
Input::LinkActionToKey(IPT_MOVE_UP, Key::PageUp); | |||||
Input::LinkActionToKey(IPT_MOVE_DOWN, Key::PageDown); | |||||
//NewPhyobj->GetCharacter()->AttachTo(BasePhyobj->GetPhysic(), true, true); | |||||
} | |||||
if (USE_BODIES) | |||||
{ | |||||
for (int x=0; x < 6; x++) | |||||
{ | |||||
for (int y=0; y < 6; y++) | |||||
{ | |||||
for (int z=0; z < 5; z++) | |||||
{ | |||||
PhysicsObject* new_physobj = new PhysicsObject(m_simulation, 1000.f, | |||||
vec3(-20.f, 15.f, -20.f) + | |||||
vec3(8.f * (float)x, 8.f * (float)y, 8.f * (float)z)); | |||||
m_physobj_list << new_physobj; | |||||
Ticker::Ref(new_physobj); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (USE_ROPE) | |||||
{ | |||||
Array<PhysicsObject*> RopeElements; | |||||
for (int i = 0; i < 14; i++) | |||||
{ | |||||
PhysicsObject* new_physobj = new PhysicsObject(m_simulation, 1000.f, | |||||
vec3(0.f, 15.f, -20.f) + | |||||
vec3(0.f, 0.f, 2.f * (float)i), 1); | |||||
RopeElements << new_physobj; | |||||
m_physobj_list << new_physobj; | |||||
Ticker::Ref(new_physobj); | |||||
if (RopeElements.Count() > 1) | |||||
{ | |||||
EasyConstraint* new_constraint = new EasyConstraint(); | |||||
vec3 A2B = .5f * (RopeElements[i]->GetPhysic()->GetTransform().v3.xyz - | |||||
RopeElements[i - 1]->GetPhysic()->GetTransform().v3.xyz); | |||||
new_constraint->SetPhysObjA(RopeElements[i - 1]->GetPhysic(), lol::mat4::translate(A2B)); | |||||
new_constraint->SetPhysObjB(RopeElements[i]->GetPhysic(), lol::mat4::translate(-A2B)); | |||||
new_constraint->InitConstraintToPoint2Point(); | |||||
new_constraint->DisableCollisionBetweenObjs(true); | |||||
new_constraint->AddToSimulation(m_simulation); | |||||
m_constraint_list << new_constraint; | |||||
} | |||||
} | |||||
} | |||||
float offset = 29.5f; | |||||
vec3 pos_offset = vec3(.0f, 30.f, .0f); | |||||
if (USE_STAIRS) | |||||
{ | |||||
vec3 new_offset = vec3(1.0f, .125f, .0f); | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(5.0f, -29.f, 15.0f); | |||||
{ | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 30.f); | |||||
NewPosition += vec3(4.0f, .0f, -4.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
{ | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 40.f); | |||||
NewPosition += vec3(4.0f, .0f, -4.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
NewPosition = pos_offset + vec3(5.0f, -29.5f, 15.0f); | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
for (int i=0; i < 15; i++) | |||||
{ | |||||
NewPosition += new_offset; | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 3); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_stairs_list << NewPhyobj; | |||||
} | |||||
} | |||||
if (USE_WALL) | |||||
{ | |||||
for (int i=0; i < 6; i++) | |||||
{ | |||||
vec3 NewPosition = vec3(.0f); | |||||
quat NewRotation = quat(1.f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation); | |||||
int idx = i/2; | |||||
NewPosition = pos_offset; | |||||
NewPosition[idx] += offset; | |||||
offset *= -1.f; | |||||
if (idx != 1) | |||||
{ | |||||
vec3 NewAxis = vec3(.0f); | |||||
NewAxis[2 - idx] = 1; | |||||
NewRotation = quat::rotate(90.f, NewAxis); | |||||
} | |||||
NewPhyobj->SetTransform(NewPosition, NewRotation); | |||||
Ticker::Ref(NewPhyobj); | |||||
m_ground_list << NewPhyobj; | |||||
} | |||||
} | |||||
PhysicsObject* BasePhyobj = NULL; | |||||
if (USE_PLATFORM) | |||||
{ | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(5.0f, -25.0f, -15.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
NewPosition = pos_offset + vec3(-15.0f, -25.0f, 5.0f); | |||||
NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
BasePhyobj = NewPhyobj; | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
NewRotation = quat::fromeuler_xyz(0.f, 0.f, 90.f); | |||||
NewPosition = pos_offset + vec3(-20.0f, -25.0f, 5.0f); | |||||
NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), true, true); | |||||
m_platform_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
//NewPosition += vec3(-0.0f, .0f, .0f); | |||||
//NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
//NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), true, false); | |||||
//m_platform_list << NewPhyobj; | |||||
//Ticker::Ref(NewPhyobj); | |||||
//NewPosition += vec3(-2.0f, .0f, .0f); | |||||
//NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 1); | |||||
//NewPhyobj->GetPhysic()->AttachTo(BasePhyobj->GetPhysic(), false, false); | |||||
//m_platform_list << NewPhyobj; | |||||
//Ticker::Ref(NewPhyobj); | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
quat NewRotation = quat::fromeuler_xyz(0.f, 0.f, 0.f); | |||||
vec3 NewPosition = pos_offset + vec3(-5.0f, -10.0f, 15.0f); | |||||
PhysicsObject* NewPhyobj = new PhysicsObject(m_simulation, NewPosition, NewRotation, 2); | |||||
m_character_list << NewPhyobj; | |||||
Ticker::Ref(NewPhyobj); | |||||
Input::LinkActionToKey(IPT_MOVE_FORWARD, Key::Up); | |||||
Input::LinkActionToKey(IPT_MOVE_BACKWARD, Key::Down); | |||||
Input::LinkActionToKey(IPT_MOVE_LEFT, Key::Left); | |||||
Input::LinkActionToKey(IPT_MOVE_RIGHT, Key::Right); | |||||
Input::LinkActionToKey(IPT_MOVE_JUMP, Key::Space); | |||||
Input::LinkActionToKey(IPT_MOVE_UP, Key::PageUp); | |||||
Input::LinkActionToKey(IPT_MOVE_DOWN, Key::PageDown); | |||||
//NewPhyobj->GetCharacter()->AttachTo(BasePhyobj->GetPhysic(), true, true); | |||||
} | |||||
if (USE_BODIES) | |||||
{ | |||||
for (int x=0; x < 6; x++) | |||||
{ | |||||
for (int y=0; y < 6; y++) | |||||
{ | |||||
for (int z=0; z < 5; z++) | |||||
{ | |||||
PhysicsObject* new_physobj = new PhysicsObject(m_simulation, 1000.f, | |||||
vec3(-20.f, 15.f, -20.f) + | |||||
vec3(8.f * (float)x, 8.f * (float)y, 8.f * (float)z)); | |||||
m_physobj_list << new_physobj; | |||||
Ticker::Ref(new_physobj); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (USE_ROPE) | |||||
{ | |||||
Array<PhysicsObject*> RopeElements; | |||||
for (int i = 0; i < 14; i++) | |||||
{ | |||||
PhysicsObject* new_physobj = new PhysicsObject(m_simulation, 1000.f, | |||||
vec3(0.f, 15.f, -20.f) + | |||||
vec3(0.f, 0.f, 2.f * (float)i), 1); | |||||
RopeElements << new_physobj; | |||||
m_physobj_list << new_physobj; | |||||
Ticker::Ref(new_physobj); | |||||
if (RopeElements.Count() > 1) | |||||
{ | |||||
EasyConstraint* new_constraint = new EasyConstraint(); | |||||
vec3 A2B = .5f * (RopeElements[i]->GetPhysic()->GetTransform().v3.xyz - | |||||
RopeElements[i - 1]->GetPhysic()->GetTransform().v3.xyz); | |||||
new_constraint->SetPhysObjA(RopeElements[i - 1]->GetPhysic(), lol::mat4::translate(A2B)); | |||||
new_constraint->SetPhysObjB(RopeElements[i]->GetPhysic(), lol::mat4::translate(-A2B)); | |||||
new_constraint->InitConstraintToPoint2Point(); | |||||
new_constraint->DisableCollisionBetweenObjs(true); | |||||
new_constraint->AddToSimulation(m_simulation); | |||||
m_constraint_list << new_constraint; | |||||
} | |||||
} | |||||
} | |||||
} | } | ||||
void BtPhysTest::TickGame(float seconds) | void BtPhysTest::TickGame(float seconds) | ||||
@@ -269,143 +269,143 @@ void BtPhysTest::TickGame(float seconds) | |||||
if (Input::WasReleased(Key::Escape)) | if (Input::WasReleased(Key::Escape)) | ||||
Ticker::Shutdown(); | Ticker::Shutdown(); | ||||
m_loop_value += seconds; | |||||
if (m_loop_value > M_PI * 2.0f) | |||||
m_loop_value -= M_PI * 2.0f; | |||||
vec3 GroundBarycenter = vec3(.0f); | |||||
vec3 PhysObjBarycenter = vec3(.0f); | |||||
float factor = .0f; | |||||
if (USE_WALL) | |||||
{ | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
GroundBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
GroundBarycenter /= factor; | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
vec3 CenterToGround = GroundMat.v3.xyz - GroundBarycenter; | |||||
vec3 CenterToCam = m_camera->m_position - GroundBarycenter; | |||||
if (dot(normalize(CenterToCam - CenterToGround), | |||||
normalize(CenterToGround)) > 0.f) | |||||
PhysObj->SetRender(false); | |||||
else | |||||
PhysObj->SetRender(true); | |||||
} | |||||
} | |||||
if (USE_ROTATION) | |||||
{ | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
mat4 CenterMx = mat4::translate(GroundBarycenter); | |||||
GroundMat = inverse(CenterMx) * GroundMat; | |||||
GroundMat = CenterMx * | |||||
mat4(quat::fromeuler_xyz(vec3(.0f, 20.f, 20.0f) * seconds)) | |||||
* GroundMat; | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
} | |||||
if (USE_PLATFORM) | |||||
{ | |||||
for (int i = 0; i < m_platform_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_platform_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
if (i == 0) | |||||
{ | |||||
GroundMat = GroundMat * mat4(quat::fromeuler_xyz(vec3(20.f, .0f, .0f) * seconds)); | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
else if (i == 1) | |||||
{ | |||||
GroundMat = | |||||
mat4::translate(vec3(-15.0f, 5.0f, lol::cos(m_loop_value) * 8.f)) * | |||||
mat4(quat::fromeuler_xyz(vec3(.0f, lol::cos(m_loop_value) * 20.f, .0f))); | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
} | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
for (int i = 0; i < m_character_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_character_list[i]; | |||||
EasyCharacterController* Character = (EasyCharacterController*)PhysObj->GetCharacter(); | |||||
mat4 CtlrMx = Character->GetTransform(); | |||||
int HMovement = Input::GetStatus(IPT_MOVE_RIGHT) - Input::GetStatus(IPT_MOVE_LEFT); | |||||
int VMovement = Input::GetStatus(IPT_MOVE_FORWARD) - Input::GetStatus(IPT_MOVE_BACKWARD); | |||||
int RMovement = Input::GetStatus(IPT_MOVE_UP) - Input::GetStatus(IPT_MOVE_DOWN); | |||||
vec3 CharMove = vec3((float)VMovement * seconds * 4.f, (float)RMovement * seconds * 10.f, (float)HMovement * seconds * 4.f); | |||||
if (Input::WasReleased(IPT_MOVE_JUMP)) | |||||
Character->Jump(); | |||||
Character->SetMovementForFrame(CharMove); | |||||
RayCastResult HitResult; | |||||
if (m_simulation->RayHits(HitResult, ERT_Closest, Character->GetTransform().v3.xyz, (Character->GetTransform().v3.xyz + vec3(.0f, -1.f, .0f)), Character)) | |||||
Character->AttachTo(HitResult.m_collider_list[0], true, true); | |||||
else | |||||
Character->AttachTo(NULL); | |||||
} | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
PhysObjBarycenter = vec3(.0f); | |||||
factor = .0f; | |||||
for (int i = 0; i < m_character_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_character_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
PhysObjBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
PhysObjBarycenter /= factor; | |||||
m_camera->SetTarget(m_camera->GetTarget() + (seconds / (seconds + 0.18f)) * (PhysObjBarycenter - m_camera->GetTarget())); | |||||
vec3 CamPosCenter = m_camera->GetTarget() + vec3(.0f, 5.0f, .0f); | |||||
m_camera->SetPosition(CamPosCenter + normalize(m_camera->GetPosition() - CamPosCenter) * 20.0f); | |||||
} | |||||
else | |||||
{ | |||||
PhysObjBarycenter = vec3(.0f); | |||||
for (int i = 0; i < m_physobj_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_physobj_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
PhysObjBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
PhysObjBarycenter /= factor; | |||||
m_camera->SetTarget(PhysObjBarycenter); | |||||
m_camera->SetPosition(GroundBarycenter + normalize(GroundBarycenter - PhysObjBarycenter) * 60.0f); | |||||
} | |||||
m_loop_value += seconds; | |||||
if (m_loop_value > M_PI * 2.0f) | |||||
m_loop_value -= M_PI * 2.0f; | |||||
vec3 GroundBarycenter = vec3(.0f); | |||||
vec3 PhysObjBarycenter = vec3(.0f); | |||||
float factor = .0f; | |||||
if (USE_WALL) | |||||
{ | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
GroundBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
GroundBarycenter /= factor; | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
vec3 CenterToGround = GroundMat.v3.xyz - GroundBarycenter; | |||||
vec3 CenterToCam = m_camera->m_position - GroundBarycenter; | |||||
if (dot(normalize(CenterToCam - CenterToGround), | |||||
normalize(CenterToGround)) > 0.f) | |||||
PhysObj->SetRender(false); | |||||
else | |||||
PhysObj->SetRender(true); | |||||
} | |||||
} | |||||
if (USE_ROTATION) | |||||
{ | |||||
for (int i = 0; i < m_ground_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_ground_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
mat4 CenterMx = mat4::translate(GroundBarycenter); | |||||
GroundMat = inverse(CenterMx) * GroundMat; | |||||
GroundMat = CenterMx * | |||||
mat4(quat::fromeuler_xyz(vec3(.0f, 20.f, 20.0f) * seconds)) | |||||
* GroundMat; | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
} | |||||
if (USE_PLATFORM) | |||||
{ | |||||
for (int i = 0; i < m_platform_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_platform_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
if (i == 0) | |||||
{ | |||||
GroundMat = GroundMat * mat4(quat::fromeuler_xyz(vec3(20.f, .0f, .0f) * seconds)); | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
else if (i == 1) | |||||
{ | |||||
GroundMat = | |||||
mat4::translate(vec3(-15.0f, 5.0f, lol::cos(m_loop_value) * 8.f)) * | |||||
mat4(quat::fromeuler_xyz(vec3(.0f, lol::cos(m_loop_value) * 20.f, .0f))); | |||||
PhysObj->SetTransform(GroundMat.v3.xyz, quat(GroundMat)); | |||||
} | |||||
} | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
for (int i = 0; i < m_character_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_character_list[i]; | |||||
EasyCharacterController* Character = (EasyCharacterController*)PhysObj->GetCharacter(); | |||||
mat4 CtlrMx = Character->GetTransform(); | |||||
int HMovement = Input::GetStatus(IPT_MOVE_RIGHT) - Input::GetStatus(IPT_MOVE_LEFT); | |||||
int VMovement = Input::GetStatus(IPT_MOVE_FORWARD) - Input::GetStatus(IPT_MOVE_BACKWARD); | |||||
int RMovement = Input::GetStatus(IPT_MOVE_UP) - Input::GetStatus(IPT_MOVE_DOWN); | |||||
vec3 CharMove = vec3((float)VMovement * seconds * 4.f, (float)RMovement * seconds * 10.f, (float)HMovement * seconds * 4.f); | |||||
if (Input::WasReleased(IPT_MOVE_JUMP)) | |||||
Character->Jump(); | |||||
Character->SetMovementForFrame(CharMove); | |||||
RayCastResult HitResult; | |||||
if (m_simulation->RayHits(HitResult, ERT_Closest, Character->GetTransform().v3.xyz, (Character->GetTransform().v3.xyz + vec3(.0f, -1.f, .0f)), Character)) | |||||
Character->AttachTo(HitResult.m_collider_list[0], true, true); | |||||
else | |||||
Character->AttachTo(NULL); | |||||
} | |||||
} | |||||
if (USE_CHARACTER) | |||||
{ | |||||
PhysObjBarycenter = vec3(.0f); | |||||
factor = .0f; | |||||
for (int i = 0; i < m_character_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_character_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
PhysObjBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
PhysObjBarycenter /= factor; | |||||
m_camera->SetTarget(m_camera->GetTarget() + (seconds / (seconds + 0.18f)) * (PhysObjBarycenter - m_camera->GetTarget())); | |||||
vec3 CamPosCenter = m_camera->GetTarget() + vec3(.0f, 5.0f, .0f); | |||||
m_camera->SetPosition(CamPosCenter + normalize(m_camera->GetPosition() - CamPosCenter) * 20.0f); | |||||
} | |||||
else | |||||
{ | |||||
PhysObjBarycenter = vec3(.0f); | |||||
for (int i = 0; i < m_physobj_list.Count(); i++) | |||||
{ | |||||
PhysicsObject* PhysObj = m_physobj_list[i]; | |||||
mat4 GroundMat = PhysObj->GetTransform(); | |||||
PhysObjBarycenter += GroundMat.v3.xyz; | |||||
factor += 1.f; | |||||
} | |||||
PhysObjBarycenter /= factor; | |||||
m_camera->SetTarget(PhysObjBarycenter); | |||||
m_camera->SetPosition(GroundBarycenter + normalize(GroundBarycenter - PhysObjBarycenter) * 60.0f); | |||||
} | |||||
} | } | ||||
@@ -425,50 +425,50 @@ void BtPhysTest::TickDraw(float seconds) | |||||
BtPhysTest::~BtPhysTest() | BtPhysTest::~BtPhysTest() | ||||
{ | { | ||||
Ticker::Unref(m_camera); | |||||
while (m_constraint_list.Count()) | |||||
{ | |||||
EasyConstraint* CurPop = m_constraint_list.Last(); | |||||
m_constraint_list.Pop(); | |||||
CurPop->RemoveFromSimulation(m_simulation); | |||||
delete CurPop; | |||||
} | |||||
while (m_ground_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_ground_list.Last(); | |||||
m_ground_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_stairs_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_stairs_list.Last(); | |||||
m_stairs_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_character_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_character_list.Last(); | |||||
m_character_list.Pop(); | |||||
CurPop->GetCharacter()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_platform_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_platform_list.Last(); | |||||
m_platform_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_physobj_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_physobj_list.Last(); | |||||
m_physobj_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
Ticker::Unref(m_camera); | |||||
while (m_constraint_list.Count()) | |||||
{ | |||||
EasyConstraint* CurPop = m_constraint_list.Last(); | |||||
m_constraint_list.Pop(); | |||||
CurPop->RemoveFromSimulation(m_simulation); | |||||
delete CurPop; | |||||
} | |||||
while (m_ground_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_ground_list.Last(); | |||||
m_ground_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_stairs_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_stairs_list.Last(); | |||||
m_stairs_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_character_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_character_list.Last(); | |||||
m_character_list.Pop(); | |||||
CurPop->GetCharacter()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_platform_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_platform_list.Last(); | |||||
m_platform_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
while (m_physobj_list.Count()) | |||||
{ | |||||
PhysicsObject* CurPop = m_physobj_list.Last(); | |||||
m_physobj_list.Pop(); | |||||
CurPop->GetPhysic()->RemoveFromSimulation(m_simulation); | |||||
Ticker::Unref(CurPop); | |||||
} | |||||
Ticker::Unref(m_simulation); | Ticker::Unref(m_simulation); | ||||
} | } | ||||
@@ -21,18 +21,18 @@ protected: | |||||
virtual void TickDraw(float seconds); | virtual void TickDraw(float seconds); | ||||
private: | private: | ||||
Camera* m_camera; | |||||
bool m_ready; | |||||
lol::phys::Simulation* m_simulation; | |||||
Array<EasyConstraint*> m_constraint_list; | |||||
Array<PhysicsObject*> m_physobj_list; | |||||
Array<PhysicsObject*> m_ground_list; | |||||
Array<PhysicsObject*> m_platform_list; | |||||
Array<PhysicsObject*> m_character_list; | |||||
Array<PhysicsObject*> m_stairs_list; | |||||
float m_loop_value; | |||||
Camera* m_camera; | |||||
bool m_ready; | |||||
lol::phys::Simulation* m_simulation; | |||||
Array<EasyConstraint*> m_constraint_list; | |||||
Array<PhysicsObject*> m_physobj_list; | |||||
Array<PhysicsObject*> m_ground_list; | |||||
Array<PhysicsObject*> m_platform_list; | |||||
Array<PhysicsObject*> m_character_list; | |||||
Array<PhysicsObject*> m_stairs_list; | |||||
float m_loop_value; | |||||
}; | }; | ||||
#endif // __BTPHYSTEST_H__ | #endif // __BTPHYSTEST_H__ | ||||
@@ -23,279 +23,279 @@ using namespace lol::phys; | |||||
class PhysicsObject : public WorldEntity | class PhysicsObject : public WorldEntity | ||||
{ | { | ||||
public: | public: | ||||
PhysicsObject(Simulation* new_sim, const vec3 &base_location, const quat &base_rotation) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#ddd afcb60 1 60 -.1]"); | |||||
vec3 BoxSize = vec3(60.f, 1.f, 60.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
PhysicsObject(Simulation* new_sim, const vec3 &base_location, const quat &base_rotation, int dummy) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
if (dummy == 1) //for platform purpose | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#ddd afcb20 1 20 -.1]"); | |||||
vec3 BoxSize = vec3(20.f, 1.f, 20.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
else if (dummy == 2) //for character purpose | |||||
{ | |||||
m_character = new EasyCharacterController(this); | |||||
m_is_character = true; | |||||
//m_mesh.Compile("[sc#f00 afcb10 10 10 -.1]"); | |||||
m_mesh.Compile( | |||||
"[sc#000 scb#000" | |||||
//"[sc#aaa scb#aaa" | |||||
"[ad8 2 0 rx180 ty-1]" | |||||
"[asph8 .5 .5 .5 ty1]" | |||||
"[ac32 2 .5 .5 0 0]" | |||||
"[asph6 .1 .1 .1 ty.9 tx.5 tz.15]" | |||||
"[asph6 .1 .1 .1 ty.9 tx.5 tz-.15]" | |||||
"[asph8 .05 .5 .05 ty.6 tz.5]" | |||||
"[asph8 .05 .5 .05 ty.6 tz-.5]" | |||||
"]" | |||||
"[sc#fd0 scb#fd0" | |||||
"[ac8 .4 .1 0 0 0 ty.25 rz-90 ty.7 tx.5]" | |||||
"]" | |||||
"[" | |||||
"[sc#fff scb#fff" | |||||
"[ad8 2 0 rx180 ty-1]" | |||||
"[asph8 .5 .5 .5 ty1]" | |||||
"[ac32 1.9 .5 .5 0 0]" | |||||
"]" | |||||
" ty-.1 tx.05]" | |||||
); | |||||
vec3 BoxSize = vec3(1.f, 2.f, 1.f); | |||||
m_character->SetCollisionChannel(0, 0xFF); | |||||
m_character->SetShapeToCapsule(BoxSize.x, BoxSize.y); | |||||
m_character->SetMass(.0f); | |||||
//m_character->SetStepHeight(1.f); | |||||
m_character->SetTransform(base_location, base_rotation); | |||||
m_character->InitBodyToGhost(); | |||||
m_character->AddToSimulation(new_sim); | |||||
} | |||||
else if (dummy == 3) //for Stairs purpose | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#aae afcb4 .25 4 -.01]"); | |||||
vec3 BoxSize = vec3(4.f, .25f, 4.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
} | |||||
PhysicsObject(Simulation* new_sim, float base_mass, const vec3 &base_location, int RandValue = -1) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
Array<char const *> MeshRand; | |||||
//MeshRand << "[sc#add afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#dad afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#dda afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#daa afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#ada afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#aad afcb2 2 2 -.1]"; | |||||
MeshRand << "[sc#add afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#dad afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#dda afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#daa afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#ada afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#aad afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
int SphereLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add asph1 2 2 2]"; | |||||
MeshRand << "[sc#dad asph1 2 2 2]"; | |||||
MeshRand << "[sc#dda asph1 2 2 2]"; | |||||
MeshRand << "[sc#daa asph1 2 2 2]"; | |||||
MeshRand << "[sc#ada asph1 2 2 2]"; | |||||
MeshRand << "[sc#aad asph1 2 2 2]"; | |||||
int ConeLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#dad scb#dad ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#dda scb#dda ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#daa scb#daa ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#ada scb#ada ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#aad scb#aad ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
int CylLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#dad scb#dad ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#dda scb#dda ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#daa scb#daa ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#ada scb#ada ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#aad scb#aad ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
int CapsLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add acap1 2 1]"; | |||||
MeshRand << "[sc#dad scb#dad acap1 2 1]"; | |||||
MeshRand << "[sc#dda scb#dda acap1 2 1]"; | |||||
MeshRand << "[sc#daa scb#daa acap1 2 1]"; | |||||
MeshRand << "[sc#ada scb#ada acap1 2 1]"; | |||||
MeshRand << "[sc#aad scb#aad acap1 2 1]"; | |||||
switch (RandValue) | |||||
{ | |||||
case 0: | |||||
{ | |||||
RandValue = (int)(lol::RandF() * (SphereLimit - 1)); | |||||
break; | |||||
} | |||||
case 1: | |||||
{ | |||||
RandValue = SphereLimit + (int)(lol::RandF() * ((ConeLimit - SphereLimit) - 1)); | |||||
break; | |||||
} | |||||
case 2: | |||||
{ | |||||
RandValue = ConeLimit + (int)(lol::RandF() * ((CylLimit - ConeLimit) - 1)); | |||||
break; | |||||
} | |||||
case 3: | |||||
{ | |||||
RandValue = CylLimit + (int)(lol::RandF() * ((CapsLimit - CylLimit) - 1)); | |||||
break; | |||||
} | |||||
case 4: | |||||
{ | |||||
RandValue = CapsLimit + (int)(lol::RandF() * ((MeshRand.Count() - CapsLimit) - 1)); | |||||
break; | |||||
} | |||||
default: | |||||
{ | |||||
RandValue = (int)(lol::RandF() * (MeshRand.Count() - 1)); | |||||
} | |||||
} | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile(MeshRand[RandValue]); | |||||
vec3 BoxSize = vec3(2.0f); | |||||
int ColGroup = 1; | |||||
if (RandValue < SphereLimit) | |||||
{ | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
ColGroup += 0; | |||||
} | |||||
else if (RandValue < ConeLimit) | |||||
{ | |||||
m_physics->SetShapeToSphere(BoxSize.x * 2.f); | |||||
ColGroup += 1; | |||||
} | |||||
else if (RandValue < CylLimit) | |||||
{ | |||||
m_physics->SetShapeToCone(BoxSize.x, BoxSize.y); | |||||
ColGroup += 2; | |||||
} | |||||
else if (RandValue < CapsLimit) | |||||
{ | |||||
m_physics->SetShapeToCylinder(BoxSize); | |||||
ColGroup += 3; | |||||
} | |||||
else | |||||
{ | |||||
m_physics->SetShapeToCapsule(BoxSize.x, BoxSize.y); | |||||
ColGroup += 4; | |||||
} | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
//m_physics->SetCollisionChannel(ColGroup, (1<<ColGroup)|(1)); | |||||
m_physics->SetMass(base_mass); | |||||
m_physics->SetTransform(base_location); | |||||
m_physics->InitBodyToRigid(); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))) | |||||
{ | |||||
if (m_is_character) | |||||
m_character->SetTransform(base_location, base_rotation); | |||||
else | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
} | |||||
lol::mat4 GetTransform() | |||||
{ | |||||
if (m_is_character) | |||||
return m_character->GetTransform(); | |||||
else | |||||
return m_physics->GetTransform(); | |||||
} | |||||
void SetRender(bool should_render) | |||||
{ | |||||
m_should_render = should_render; | |||||
} | |||||
EasyMesh *GetMesh() { return &m_mesh; } | |||||
EasyPhysic *GetPhysic() { return m_physics; } | |||||
EasyCharacterController *GetCharacter() { return m_character; } | |||||
~PhysicsObject() | |||||
{ | |||||
} | |||||
char const *GetName() { return "<PhysicsObject>"; } | |||||
PhysicsObject(Simulation* new_sim, const vec3 &base_location, const quat &base_rotation) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#ddd afcb60 1 60 -.1]"); | |||||
vec3 BoxSize = vec3(60.f, 1.f, 60.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
PhysicsObject(Simulation* new_sim, const vec3 &base_location, const quat &base_rotation, int dummy) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
if (dummy == 1) //for platform purpose | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#ddd afcb20 1 20 -.1]"); | |||||
vec3 BoxSize = vec3(20.f, 1.f, 20.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
else if (dummy == 2) //for character purpose | |||||
{ | |||||
m_character = new EasyCharacterController(this); | |||||
m_is_character = true; | |||||
//m_mesh.Compile("[sc#f00 afcb10 10 10 -.1]"); | |||||
m_mesh.Compile( | |||||
"[sc#000 scb#000" | |||||
//"[sc#aaa scb#aaa" | |||||
"[ad8 2 0 rx180 ty-1]" | |||||
"[asph8 .5 .5 .5 ty1]" | |||||
"[ac32 2 .5 .5 0 0]" | |||||
"[asph6 .1 .1 .1 ty.9 tx.5 tz.15]" | |||||
"[asph6 .1 .1 .1 ty.9 tx.5 tz-.15]" | |||||
"[asph8 .05 .5 .05 ty.6 tz.5]" | |||||
"[asph8 .05 .5 .05 ty.6 tz-.5]" | |||||
"]" | |||||
"[sc#fd0 scb#fd0" | |||||
"[ac8 .4 .1 0 0 0 ty.25 rz-90 ty.7 tx.5]" | |||||
"]" | |||||
"[" | |||||
"[sc#fff scb#fff" | |||||
"[ad8 2 0 rx180 ty-1]" | |||||
"[asph8 .5 .5 .5 ty1]" | |||||
"[ac32 1.9 .5 .5 0 0]" | |||||
"]" | |||||
" ty-.1 tx.05]" | |||||
); | |||||
vec3 BoxSize = vec3(1.f, 2.f, 1.f); | |||||
m_character->SetCollisionChannel(0, 0xFF); | |||||
m_character->SetShapeToCapsule(BoxSize.x, BoxSize.y); | |||||
m_character->SetMass(.0f); | |||||
//m_character->SetStepHeight(1.f); | |||||
m_character->SetTransform(base_location, base_rotation); | |||||
m_character->InitBodyToGhost(); | |||||
m_character->AddToSimulation(new_sim); | |||||
} | |||||
else if (dummy == 3) //for Stairs purpose | |||||
{ | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile("[sc#aae afcb4 .25 4 -.01]"); | |||||
vec3 BoxSize = vec3(4.f, .25f, 4.f); | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
m_physics->SetMass(.0f); | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
m_physics->InitBodyToRigid(true); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
} | |||||
PhysicsObject(Simulation* new_sim, float base_mass, const vec3 &base_location, int RandValue = -1) | |||||
: m_ready(false), m_should_render(true), m_is_character(false) | |||||
{ | |||||
Array<char const *> MeshRand; | |||||
//MeshRand << "[sc#add afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#dad afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#dda afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#daa afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#ada afcb2 2 2 -.1]"; | |||||
//MeshRand << "[sc#aad afcb2 2 2 -.1]"; | |||||
MeshRand << "[sc#add afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#dad afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#dda afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#daa afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#ada afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
MeshRand << "[sc#aad afcb1.7 1.7 1.7 0][sc#000 afcb1.9 1.9 1.9 0 sx-1 sy-1 sz-1]"; | |||||
int SphereLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add asph1 2 2 2]"; | |||||
MeshRand << "[sc#dad asph1 2 2 2]"; | |||||
MeshRand << "[sc#dda asph1 2 2 2]"; | |||||
MeshRand << "[sc#daa asph1 2 2 2]"; | |||||
MeshRand << "[sc#ada asph1 2 2 2]"; | |||||
MeshRand << "[sc#aad asph1 2 2 2]"; | |||||
int ConeLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#dad scb#dad ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#dda scb#dda ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#daa scb#daa ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#ada scb#ada ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
MeshRand << "[sc#aad scb#aad ad1 2 0 rx180 ty-1 ac4 2 2 0 0 0]"; | |||||
int CylLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#dad scb#dad ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#dda scb#dda ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#daa scb#daa ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#ada scb#ada ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
MeshRand << "[sc#aad scb#aad ad1 2 0 rx180 ty-1 my ac4 2 2 2 0 0]"; | |||||
int CapsLimit = MeshRand.Count(); | |||||
MeshRand << "[sc#add scb#add acap1 2 1]"; | |||||
MeshRand << "[sc#dad scb#dad acap1 2 1]"; | |||||
MeshRand << "[sc#dda scb#dda acap1 2 1]"; | |||||
MeshRand << "[sc#daa scb#daa acap1 2 1]"; | |||||
MeshRand << "[sc#ada scb#ada acap1 2 1]"; | |||||
MeshRand << "[sc#aad scb#aad acap1 2 1]"; | |||||
switch (RandValue) | |||||
{ | |||||
case 0: | |||||
{ | |||||
RandValue = (int)(lol::RandF() * (SphereLimit - 1)); | |||||
break; | |||||
} | |||||
case 1: | |||||
{ | |||||
RandValue = SphereLimit + (int)(lol::RandF() * ((ConeLimit - SphereLimit) - 1)); | |||||
break; | |||||
} | |||||
case 2: | |||||
{ | |||||
RandValue = ConeLimit + (int)(lol::RandF() * ((CylLimit - ConeLimit) - 1)); | |||||
break; | |||||
} | |||||
case 3: | |||||
{ | |||||
RandValue = CylLimit + (int)(lol::RandF() * ((CapsLimit - CylLimit) - 1)); | |||||
break; | |||||
} | |||||
case 4: | |||||
{ | |||||
RandValue = CapsLimit + (int)(lol::RandF() * ((MeshRand.Count() - CapsLimit) - 1)); | |||||
break; | |||||
} | |||||
default: | |||||
{ | |||||
RandValue = (int)(lol::RandF() * (MeshRand.Count() - 1)); | |||||
} | |||||
} | |||||
m_physics = new EasyPhysic(this); | |||||
m_mesh.Compile(MeshRand[RandValue]); | |||||
vec3 BoxSize = vec3(2.0f); | |||||
int ColGroup = 1; | |||||
if (RandValue < SphereLimit) | |||||
{ | |||||
m_physics->SetShapeToBox(BoxSize); | |||||
ColGroup += 0; | |||||
} | |||||
else if (RandValue < ConeLimit) | |||||
{ | |||||
m_physics->SetShapeToSphere(BoxSize.x * 2.f); | |||||
ColGroup += 1; | |||||
} | |||||
else if (RandValue < CylLimit) | |||||
{ | |||||
m_physics->SetShapeToCone(BoxSize.x, BoxSize.y); | |||||
ColGroup += 2; | |||||
} | |||||
else if (RandValue < CapsLimit) | |||||
{ | |||||
m_physics->SetShapeToCylinder(BoxSize); | |||||
ColGroup += 3; | |||||
} | |||||
else | |||||
{ | |||||
m_physics->SetShapeToCapsule(BoxSize.x, BoxSize.y); | |||||
ColGroup += 4; | |||||
} | |||||
m_physics->SetCollisionChannel(0, 0xFF); | |||||
//m_physics->SetCollisionChannel(ColGroup, (1<<ColGroup)|(1)); | |||||
m_physics->SetMass(base_mass); | |||||
m_physics->SetTransform(base_location); | |||||
m_physics->InitBodyToRigid(); | |||||
m_physics->AddToSimulation(new_sim); | |||||
} | |||||
void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))) | |||||
{ | |||||
if (m_is_character) | |||||
m_character->SetTransform(base_location, base_rotation); | |||||
else | |||||
m_physics->SetTransform(base_location, base_rotation); | |||||
} | |||||
lol::mat4 GetTransform() | |||||
{ | |||||
if (m_is_character) | |||||
return m_character->GetTransform(); | |||||
else | |||||
return m_physics->GetTransform(); | |||||
} | |||||
void SetRender(bool should_render) | |||||
{ | |||||
m_should_render = should_render; | |||||
} | |||||
EasyMesh *GetMesh() { return &m_mesh; } | |||||
EasyPhysic *GetPhysic() { return m_physics; } | |||||
EasyCharacterController *GetCharacter() { return m_character; } | |||||
~PhysicsObject() | |||||
{ | |||||
} | |||||
char const *GetName() { return "<PhysicsObject>"; } | |||||
protected: | protected: | ||||
virtual void TickGame(float seconds) | |||||
{ | |||||
WorldEntity::TickGame(seconds); | |||||
} | |||||
virtual void TickDraw(float seconds) | |||||
{ | |||||
WorldEntity::TickDraw(seconds); | |||||
if (!m_ready) | |||||
{ | |||||
m_mesh.MeshConvert(); | |||||
m_ready = true; | |||||
} | |||||
if (m_should_render) | |||||
{ | |||||
if (m_is_character) | |||||
m_mesh.Render(m_character->GetTransform()); | |||||
else | |||||
m_mesh.Render(m_physics->GetTransform()); | |||||
} | |||||
} | |||||
virtual void TickGame(float seconds) | |||||
{ | |||||
WorldEntity::TickGame(seconds); | |||||
} | |||||
virtual void TickDraw(float seconds) | |||||
{ | |||||
WorldEntity::TickDraw(seconds); | |||||
if (!m_ready) | |||||
{ | |||||
m_mesh.MeshConvert(); | |||||
m_ready = true; | |||||
} | |||||
if (m_should_render) | |||||
{ | |||||
if (m_is_character) | |||||
m_mesh.Render(m_character->GetTransform()); | |||||
else | |||||
m_mesh.Render(m_physics->GetTransform()); | |||||
} | |||||
} | |||||
private: | private: | ||||
//Base datas | |||||
EasyMesh m_mesh; | |||||
EasyPhysic* m_physics; | |||||
EasyCharacterController* m_character; | |||||
bool m_ready; | |||||
bool m_should_render; | |||||
bool m_is_character; | |||||
//Base datas | |||||
EasyMesh m_mesh; | |||||
EasyPhysic* m_physics; | |||||
EasyCharacterController* m_character; | |||||
bool m_ready; | |||||
bool m_should_render; | |||||
bool m_is_character; | |||||
}; | }; | ||||
#endif /* __PHYSICOBJECT_H__ */ | #endif /* __PHYSICOBJECT_H__ */ | ||||
@@ -29,259 +29,259 @@ | |||||
namespace lol | namespace lol | ||||
{ | { | ||||
namespace phys | |||||
{ | |||||
namespace phys | |||||
{ | |||||
#ifdef USE_LOL_CTRLR_CHARAC | #ifdef USE_LOL_CTRLR_CHARAC | ||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
//SweepCallback used for Swweep Tests. | |||||
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback | |||||
{ | |||||
public: | |||||
ClosestNotMeConvexResultCallback(btCollisionObject* NewMe, const vec3& NewUp, float MinSlopeDot) : | |||||
btCollisionWorld::ClosestConvexResultCallback(LOL2BTU_VEC3(vec3(.0f)), LOL2BTU_VEC3(vec3(.0f))), | |||||
m_me(NewMe), | |||||
m_up(NewUp), | |||||
m_min_slope_dot(MinSlopeDot) { } | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& ConvexResult, bool NormalInWorld) | |||||
{ | |||||
//We hit ourselves, FAIL | |||||
if (ConvexResult.m_hitCollisionObject == m_me) | |||||
return btScalar(1.f); | |||||
vec3 WorldHitNomal(.0f); | |||||
if (NormalInWorld) | |||||
WorldHitNomal = BT2LOL_VEC3(ConvexResult.m_hitNormalLocal); | |||||
else //need to transform Normal into worldspace | |||||
{ | |||||
btVector3 TmpWorldHitNormal = ConvexResult.m_hitCollisionObject->getWorldTransform().getBasis() * ConvexResult.m_hitNormalLocal; | |||||
WorldHitNomal = BT2LOL_VEC3(TmpWorldHitNormal); | |||||
} | |||||
float DotUp = dot(m_up, WorldHitNomal); | |||||
//We hit below the accepted slope_dot, FAIL | |||||
if (DotUp < m_min_slope_dot) | |||||
return btScalar(1.f); | |||||
//Continue to next. | |||||
return ClosestConvexResultCallback::addSingleResult(ConvexResult, NormalInWorld); | |||||
} | |||||
protected: | |||||
btCollisionObject* m_me; | |||||
const vec3 m_up; | |||||
float m_min_slope_dot; | |||||
}; | |||||
///BulletKinematicCharacterController is an object that supports a sliding motion in a world. | |||||
///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. | |||||
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. | |||||
class BulletKinematicCharacterController : public btActionInterface | |||||
{ | |||||
public: | |||||
BulletKinematicCharacterController(btPairCachingGhostObject* NewGhostObject, btConvexShape* NewConvexShape, float NewStepHeight, int NewUpAxis=1) | |||||
{ | |||||
m_convex_shape = NewConvexShape; | |||||
m_i_up_axis = NewUpAxis; | |||||
m_ghost_object = NewGhostObject; | |||||
m_step_height = NewStepHeight; | |||||
m_added_margin = 0.02f; | |||||
m_walk_direction = vec3(.0f, .0f, .0f); | |||||
m_do_gobject_sweep_test = true; | |||||
m_turn_angle = .0f; | |||||
m_use_walk_direction = false; // Should remove walk direction, this doesn't work correctly. | |||||
m_velocity_time_interval = .0f; | |||||
m_vertical_velocity = .0f; | |||||
m_vertical_offset = .0f; | |||||
m_f_gravity = 9.8f * 3.f; // 3G acceleration. | |||||
m_fall_speed = 55.f; // Terminal velocity of a sky diver in m/s. | |||||
m_jump_speed = 10.f; // ? | |||||
m_was_on_ground = false; | |||||
m_was_jumping = false; | |||||
SetMaxSlope(45.f); | |||||
} | |||||
~BulletKinematicCharacterController() { } | |||||
protected: | |||||
static vec3* GetUpAxisDirections() | |||||
{ | |||||
static vec3 sUpAxisDirection[3] = { vec3(1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f) }; | |||||
return sUpAxisDirection; | |||||
} | |||||
//-------------------------- | |||||
//CONVENIENCE FUNCTIONS | |||||
//-- | |||||
//Returns the reflection Direction of a ray going 'Direction' hitting a surface with Normal 'Normal' from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html | |||||
vec3 GetReflectedDir(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Direction - (2.f * dot(Direction, Normal) * Normal); | |||||
} | |||||
//Returns the portion of 'direction' that is parallel to 'normal' | |||||
vec3 ProjectDirOnNorm(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Normal * dot(Direction, Normal); | |||||
} | |||||
//Returns the portion of 'Direction' that is perpindicular to 'Normal' | |||||
vec3 ProjectDirOnNormPerpindicular(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Direction - ProjectDirOnNorm(Direction, Normal); | |||||
} | |||||
//Returns Ghost Object. -duh- | |||||
btPairCachingGhostObject* GetGhostObject() | |||||
{ | |||||
return m_ghost_object; | |||||
} | |||||
//"Real" war functions | |||||
bool RecoverFromPenetration(btCollisionWorld* CollisionWorld); | |||||
void UpdateTargetOnHit(const vec3& hit_normal, float TangentMag = .0f, float NormalMag = 1.f); | |||||
void DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime); | |||||
public: | |||||
///btActionInterface interface : KEEP IN camelCase | |||||
virtual void updateAction(btCollisionWorld* CollisionWorld, float deltaTime) | |||||
{ | |||||
PreStep(CollisionWorld); | |||||
PlayerStep(CollisionWorld, deltaTime); | |||||
} | |||||
//not in the interface, but called above | |||||
void PreStep(btCollisionWorld* CollisionWorld); | |||||
void PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime); | |||||
///btActionInterface interface : KEEP IN camelCase | |||||
void debugDraw(btIDebugDraw* debugDrawer) { } | |||||
void SetUpAxis(int NewAxis) | |||||
{ | |||||
if (NewAxis < 0) | |||||
NewAxis = 0; | |||||
if (NewAxis > 2) | |||||
NewAxis = 2; | |||||
m_i_up_axis = NewAxis; | |||||
} | |||||
//!!!!!! SHOULD DITCH THAT !!!!!! | |||||
//This should probably be called setPositionIncrementPerSimulatorStep. | |||||
//This is neither a Direction nor a velocity, but the amount to | |||||
//increment the position each simulation iteration, regardless | |||||
//of DeltaTime. | |||||
//This call will Reset any velocity set by SetVelocityForTimeInterval(). | |||||
virtual void SetWalkDirection(const vec3& walkDirection) | |||||
{ | |||||
m_use_walk_direction = true; | |||||
m_walk_direction = walkDirection; | |||||
m_normalized_direction = normalize(m_walk_direction); | |||||
} | |||||
//Caller provides a velocity with which the character should MoveStep for | |||||
//the given time period. After the time period, velocity is Reset | |||||
//to zero. | |||||
//This call will Reset any walk Direction set by SetWalkDirection(). | |||||
//Negative time intervals will result in no motion. | |||||
virtual void SetVelocityForTimeInterval(const vec3& velocity, float timeInterval) | |||||
{ | |||||
m_use_walk_direction = false; | |||||
m_walk_direction = velocity; | |||||
m_normalized_direction = normalize(m_walk_direction); | |||||
m_velocity_time_interval = timeInterval; | |||||
} | |||||
//Usefulness ? | |||||
void Reset() { } | |||||
void Warp(const vec3& NewOrigin) | |||||
{ | |||||
btTransform NewTransform; | |||||
NewTransform.setIdentity(); | |||||
NewTransform.setOrigin(LOL2BTU_VEC3(NewOrigin)); | |||||
m_ghost_object->setWorldTransform(NewTransform); | |||||
} | |||||
//External Setup | |||||
//-- | |||||
void SetFallSpeed(float NewFallSpeed) { m_fall_speed = NewFallSpeed; } | |||||
void SetJumpSpeed(float NewJumpSpeed) { m_jump_speed = NewJumpSpeed; } | |||||
void SetMaxJumpHeight(float NewMaxJumpHeight) { m_max_jump_height = NewMaxJumpHeight; } | |||||
//Jump logic will go in EasyCC | |||||
bool CanJump() const { return OnGround(); } | |||||
void Jump(); | |||||
//NewGravity functions | |||||
void SetGravity(float NewGravity) { m_f_gravity = NewGravity; } | |||||
float GetGravity() const { return m_f_gravity; } | |||||
//The max slope determines the maximum angle that the controller can walk up. | |||||
//The slope angle is measured in radians. | |||||
void SetMaxSlope(float NewSlopeRadians) { m_max_slope_radians = NewSlopeRadians; m_max_slope_cosine = lol::cos(NewSlopeRadians); } | |||||
float GetMaxSlope() const { return m_max_slope_radians; } | |||||
void SetUseGhostSweepTest(bool UseGObjectSweepTest) { m_do_gobject_sweep_test = UseGObjectSweepTest; } | |||||
bool OnGround() const { return m_vertical_velocity == .0f && m_vertical_offset == .0f; } | |||||
private: | |||||
btPairCachingGhostObject* m_ghost_object; | |||||
btConvexShape* m_convex_shape; //is also in m_ghost_object, but it needs to be convex, so we store it here to avoid upcast | |||||
//keep track of the contact manifolds | |||||
btManifoldArray m_manifold_array; | |||||
float m_half_height; | |||||
float m_velocity_time_interval; | |||||
float m_vertical_velocity; | |||||
float m_vertical_offset; | |||||
float m_fall_speed; | |||||
float m_jump_speed; | |||||
float m_max_jump_height; | |||||
float m_max_slope_radians; // Slope angle that is set (used for returning the exact value) | |||||
float m_max_slope_cosine; // Cosine equivalent of m_max_slope_radians (calculated once when set, for optimization) | |||||
float m_f_gravity; | |||||
float m_turn_angle; | |||||
float m_step_height; | |||||
float m_added_margin;//@todo: remove this and fix the code | |||||
///this is the desired walk Direction, set by the user | |||||
vec3 m_walk_direction; | |||||
vec3 m_normalized_direction; | |||||
//some internal variables | |||||
vec3 m_current_position; | |||||
float m_current_step_offset; | |||||
vec3 m_target_position; | |||||
vec3 m_touching_normal; | |||||
bool m_touching_contact; | |||||
bool m_was_on_ground; | |||||
bool m_was_jumping; | |||||
bool m_do_gobject_sweep_test; | |||||
bool m_use_walk_direction; | |||||
int m_i_up_axis; | |||||
//--------------------------------------------------------------------- | |||||
//NEW INTERNAL VARS | |||||
//--------------------------------------------------------------------- | |||||
//Gravity in vec3 | |||||
vec3 m_gravity; | |||||
//Current Velocity | |||||
vec3 m_velocity; | |||||
}; | |||||
//SweepCallback used for Swweep Tests. | |||||
class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback | |||||
{ | |||||
public: | |||||
ClosestNotMeConvexResultCallback(btCollisionObject* NewMe, const vec3& NewUp, float MinSlopeDot) : | |||||
btCollisionWorld::ClosestConvexResultCallback(LOL2BTU_VEC3(vec3(.0f)), LOL2BTU_VEC3(vec3(.0f))), | |||||
m_me(NewMe), | |||||
m_up(NewUp), | |||||
m_min_slope_dot(MinSlopeDot) { } | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& ConvexResult, bool NormalInWorld) | |||||
{ | |||||
//We hit ourselves, FAIL | |||||
if (ConvexResult.m_hitCollisionObject == m_me) | |||||
return btScalar(1.f); | |||||
vec3 WorldHitNomal(.0f); | |||||
if (NormalInWorld) | |||||
WorldHitNomal = BT2LOL_VEC3(ConvexResult.m_hitNormalLocal); | |||||
else //need to transform Normal into worldspace | |||||
{ | |||||
btVector3 TmpWorldHitNormal = ConvexResult.m_hitCollisionObject->getWorldTransform().getBasis() * ConvexResult.m_hitNormalLocal; | |||||
WorldHitNomal = BT2LOL_VEC3(TmpWorldHitNormal); | |||||
} | |||||
float DotUp = dot(m_up, WorldHitNomal); | |||||
//We hit below the accepted slope_dot, FAIL | |||||
if (DotUp < m_min_slope_dot) | |||||
return btScalar(1.f); | |||||
//Continue to next. | |||||
return ClosestConvexResultCallback::addSingleResult(ConvexResult, NormalInWorld); | |||||
} | |||||
protected: | |||||
btCollisionObject* m_me; | |||||
const vec3 m_up; | |||||
float m_min_slope_dot; | |||||
}; | |||||
///BulletKinematicCharacterController is an object that supports a sliding motion in a world. | |||||
///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. | |||||
///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. | |||||
class BulletKinematicCharacterController : public btActionInterface | |||||
{ | |||||
public: | |||||
BulletKinematicCharacterController(btPairCachingGhostObject* NewGhostObject, btConvexShape* NewConvexShape, float NewStepHeight, int NewUpAxis=1) | |||||
{ | |||||
m_convex_shape = NewConvexShape; | |||||
m_i_up_axis = NewUpAxis; | |||||
m_ghost_object = NewGhostObject; | |||||
m_step_height = NewStepHeight; | |||||
m_added_margin = 0.02f; | |||||
m_walk_direction = vec3(.0f, .0f, .0f); | |||||
m_do_gobject_sweep_test = true; | |||||
m_turn_angle = .0f; | |||||
m_use_walk_direction = false; // Should remove walk direction, this doesn't work correctly. | |||||
m_velocity_time_interval = .0f; | |||||
m_vertical_velocity = .0f; | |||||
m_vertical_offset = .0f; | |||||
m_f_gravity = 9.8f * 3.f; // 3G acceleration. | |||||
m_fall_speed = 55.f; // Terminal velocity of a sky diver in m/s. | |||||
m_jump_speed = 10.f; // ? | |||||
m_was_on_ground = false; | |||||
m_was_jumping = false; | |||||
SetMaxSlope(45.f); | |||||
} | |||||
~BulletKinematicCharacterController() { } | |||||
protected: | |||||
static vec3* GetUpAxisDirections() | |||||
{ | |||||
static vec3 sUpAxisDirection[3] = { vec3(1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f) }; | |||||
return sUpAxisDirection; | |||||
} | |||||
//-------------------------- | |||||
//CONVENIENCE FUNCTIONS | |||||
//-- | |||||
//Returns the reflection Direction of a ray going 'Direction' hitting a surface with Normal 'Normal' from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html | |||||
vec3 GetReflectedDir(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Direction - (2.f * dot(Direction, Normal) * Normal); | |||||
} | |||||
//Returns the portion of 'direction' that is parallel to 'normal' | |||||
vec3 ProjectDirOnNorm(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Normal * dot(Direction, Normal); | |||||
} | |||||
//Returns the portion of 'Direction' that is perpindicular to 'Normal' | |||||
vec3 ProjectDirOnNormPerpindicular(const vec3& Direction, const vec3& Normal) | |||||
{ | |||||
return Direction - ProjectDirOnNorm(Direction, Normal); | |||||
} | |||||
//Returns Ghost Object. -duh- | |||||
btPairCachingGhostObject* GetGhostObject() | |||||
{ | |||||
return m_ghost_object; | |||||
} | |||||
//"Real" war functions | |||||
bool RecoverFromPenetration(btCollisionWorld* CollisionWorld); | |||||
void UpdateTargetOnHit(const vec3& hit_normal, float TangentMag = .0f, float NormalMag = 1.f); | |||||
void DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime); | |||||
public: | |||||
///btActionInterface interface : KEEP IN camelCase | |||||
virtual void updateAction(btCollisionWorld* CollisionWorld, float deltaTime) | |||||
{ | |||||
PreStep(CollisionWorld); | |||||
PlayerStep(CollisionWorld, deltaTime); | |||||
} | |||||
//not in the interface, but called above | |||||
void PreStep(btCollisionWorld* CollisionWorld); | |||||
void PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime); | |||||
///btActionInterface interface : KEEP IN camelCase | |||||
void debugDraw(btIDebugDraw* debugDrawer) { } | |||||
void SetUpAxis(int NewAxis) | |||||
{ | |||||
if (NewAxis < 0) | |||||
NewAxis = 0; | |||||
if (NewAxis > 2) | |||||
NewAxis = 2; | |||||
m_i_up_axis = NewAxis; | |||||
} | |||||
//!!!!!! SHOULD DITCH THAT !!!!!! | |||||
//This should probably be called setPositionIncrementPerSimulatorStep. | |||||
//This is neither a Direction nor a velocity, but the amount to | |||||
//increment the position each simulation iteration, regardless | |||||
//of DeltaTime. | |||||
//This call will Reset any velocity set by SetVelocityForTimeInterval(). | |||||
virtual void SetWalkDirection(const vec3& walkDirection) | |||||
{ | |||||
m_use_walk_direction = true; | |||||
m_walk_direction = walkDirection; | |||||
m_normalized_direction = normalize(m_walk_direction); | |||||
} | |||||
//Caller provides a velocity with which the character should MoveStep for | |||||
//the given time period. After the time period, velocity is Reset | |||||
//to zero. | |||||
//This call will Reset any walk Direction set by SetWalkDirection(). | |||||
//Negative time intervals will result in no motion. | |||||
virtual void SetVelocityForTimeInterval(const vec3& velocity, float timeInterval) | |||||
{ | |||||
m_use_walk_direction = false; | |||||
m_walk_direction = velocity; | |||||
m_normalized_direction = normalize(m_walk_direction); | |||||
m_velocity_time_interval = timeInterval; | |||||
} | |||||
//Usefulness ? | |||||
void Reset() { } | |||||
void Warp(const vec3& NewOrigin) | |||||
{ | |||||
btTransform NewTransform; | |||||
NewTransform.setIdentity(); | |||||
NewTransform.setOrigin(LOL2BTU_VEC3(NewOrigin)); | |||||
m_ghost_object->setWorldTransform(NewTransform); | |||||
} | |||||
//External Setup | |||||
//-- | |||||
void SetFallSpeed(float NewFallSpeed) { m_fall_speed = NewFallSpeed; } | |||||
void SetJumpSpeed(float NewJumpSpeed) { m_jump_speed = NewJumpSpeed; } | |||||
void SetMaxJumpHeight(float NewMaxJumpHeight) { m_max_jump_height = NewMaxJumpHeight; } | |||||
//Jump logic will go in EasyCC | |||||
bool CanJump() const { return OnGround(); } | |||||
void Jump(); | |||||
//NewGravity functions | |||||
void SetGravity(float NewGravity) { m_f_gravity = NewGravity; } | |||||
float GetGravity() const { return m_f_gravity; } | |||||
//The max slope determines the maximum angle that the controller can walk up. | |||||
//The slope angle is measured in radians. | |||||
void SetMaxSlope(float NewSlopeRadians) { m_max_slope_radians = NewSlopeRadians; m_max_slope_cosine = lol::cos(NewSlopeRadians); } | |||||
float GetMaxSlope() const { return m_max_slope_radians; } | |||||
void SetUseGhostSweepTest(bool UseGObjectSweepTest) { m_do_gobject_sweep_test = UseGObjectSweepTest; } | |||||
bool OnGround() const { return m_vertical_velocity == .0f && m_vertical_offset == .0f; } | |||||
private: | |||||
btPairCachingGhostObject* m_ghost_object; | |||||
btConvexShape* m_convex_shape; //is also in m_ghost_object, but it needs to be convex, so we store it here to avoid upcast | |||||
//keep track of the contact manifolds | |||||
btManifoldArray m_manifold_array; | |||||
float m_half_height; | |||||
float m_velocity_time_interval; | |||||
float m_vertical_velocity; | |||||
float m_vertical_offset; | |||||
float m_fall_speed; | |||||
float m_jump_speed; | |||||
float m_max_jump_height; | |||||
float m_max_slope_radians; // Slope angle that is set (used for returning the exact value) | |||||
float m_max_slope_cosine; // Cosine equivalent of m_max_slope_radians (calculated once when set, for optimization) | |||||
float m_f_gravity; | |||||
float m_turn_angle; | |||||
float m_step_height; | |||||
float m_added_margin;//@todo: remove this and fix the code | |||||
///this is the desired walk Direction, set by the user | |||||
vec3 m_walk_direction; | |||||
vec3 m_normalized_direction; | |||||
//some internal variables | |||||
vec3 m_current_position; | |||||
float m_current_step_offset; | |||||
vec3 m_target_position; | |||||
vec3 m_touching_normal; | |||||
bool m_touching_contact; | |||||
bool m_was_on_ground; | |||||
bool m_was_jumping; | |||||
bool m_do_gobject_sweep_test; | |||||
bool m_use_walk_direction; | |||||
int m_i_up_axis; | |||||
//--------------------------------------------------------------------- | |||||
//NEW INTERNAL VARS | |||||
//--------------------------------------------------------------------- | |||||
//Gravity in vec3 | |||||
vec3 m_gravity; | |||||
//Current Velocity | |||||
vec3 m_velocity; | |||||
}; | |||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||
#endif // USE_LOL_CTRLR_CHARAC | #endif // USE_LOL_CTRLR_CHARAC | ||||
} /* namespace phys */ | |||||
} /* namespace phys */ | |||||
} /* namespace lol */ | } /* namespace lol */ | ||||
@@ -34,81 +34,81 @@ namespace phys | |||||
{ | { | ||||
class EasyCharacterController : public EasyPhysic, | class EasyCharacterController : public EasyPhysic, | ||||
public Entity | |||||
public Entity | |||||
{ | { | ||||
friend class Simulation; | |||||
friend class EasyPhysic; | |||||
friend class Simulation; | |||||
friend class EasyPhysic; | |||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
public: | public: | ||||
EasyCharacterController(WorldEntity* NewOwnerEntity) : | |||||
EasyPhysic(NewOwnerEntity), | |||||
m_pair_caching_object(NULL), | |||||
m_character(NULL), | |||||
m_step_height(.0f), | |||||
m_base_is_updating(false), | |||||
m_base_cached_movement(vec3(0.f)), | |||||
m_frame_cached_movement(vec3(0.f)), | |||||
m_walk_velocity(vec3(0.f)), | |||||
m_current_velocity(vec3(0.f)) | |||||
{ | |||||
m_gamegroup = GAMEGROUP_EZP_CHAR_CTRLR; | |||||
m_up_axis = 1; | |||||
m_gravity = vec3(.0f, -9.81f, .0f); | |||||
m_walk_velocity_damping = 0.2f; | |||||
} | |||||
~EasyCharacterController() | |||||
{ | |||||
delete m_character; | |||||
} | |||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false); | |||||
virtual void InitBodyToGhost(); | |||||
virtual void AddToSimulation(class Simulation* current_simulation); | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation); | |||||
virtual void SetMovementForFrame(vec3 const &MoveQuantity); | |||||
virtual void Jump(); | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation); | |||||
EasyCharacterController(WorldEntity* NewOwnerEntity) : | |||||
EasyPhysic(NewOwnerEntity), | |||||
m_pair_caching_object(NULL), | |||||
m_character(NULL), | |||||
m_step_height(.0f), | |||||
m_base_is_updating(false), | |||||
m_base_cached_movement(vec3(0.f)), | |||||
m_frame_cached_movement(vec3(0.f)), | |||||
m_walk_velocity(vec3(0.f)), | |||||
m_current_velocity(vec3(0.f)) | |||||
{ | |||||
m_gamegroup = GAMEGROUP_EZP_CHAR_CTRLR; | |||||
m_up_axis = 1; | |||||
m_gravity = vec3(.0f, -9.81f, .0f); | |||||
m_walk_velocity_damping = 0.2f; | |||||
} | |||||
~EasyCharacterController() | |||||
{ | |||||
delete m_character; | |||||
} | |||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false); | |||||
virtual void InitBodyToGhost(); | |||||
virtual void AddToSimulation(class Simulation* current_simulation); | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation); | |||||
virtual void SetMovementForFrame(vec3 const &MoveQuantity); | |||||
virtual void Jump(); | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation); | |||||
protected: | protected: | ||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix); | |||||
virtual char const *GetName(); | |||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix); | |||||
virtual char const *GetName(); | |||||
public: | public: | ||||
virtual void TickGame(float seconds); | |||||
virtual void TickGame(float seconds); | |||||
protected: | protected: | ||||
virtual btGhostObject* GetGhostObjectInstance(); | |||||
virtual btGhostObject* GetGhostObjectInstance(); | |||||
btPairCachingGhostObject* m_pair_caching_object; | |||||
//btKinematicCharacterController* m_character; | |||||
BulletKinematicCharacterController* m_character; | |||||
btPairCachingGhostObject* m_pair_caching_object; | |||||
//btKinematicCharacterController* m_character; | |||||
BulletKinematicCharacterController* m_character; | |||||
float m_step_height; | |||||
int m_up_axis; | |||||
bool m_base_is_updating; | |||||
vec3 m_base_cached_movement; | |||||
vec3 m_frame_cached_movement; | |||||
float m_step_height; | |||||
int m_up_axis; | |||||
bool m_base_is_updating; | |||||
vec3 m_base_cached_movement; | |||||
vec3 m_frame_cached_movement; | |||||
//---- | |||||
float m_walk_velocity_damping; | |||||
//---- | |||||
float m_walk_velocity_damping; | |||||
//---- | |||||
vec3 m_gravity; | |||||
//---- | |||||
vec3 m_gravity; | |||||
//---- | |||||
vec3 m_walk_velocity; | |||||
vec3 m_current_velocity; | |||||
//---- | |||||
vec3 m_walk_velocity; | |||||
vec3 m_current_velocity; | |||||
#else // NO PHYSIC IMPLEMENTATION | #else // NO PHYSIC IMPLEMENTATION | ||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false) { } | |||||
virtual void InitBodyToGhost() { } | |||||
virtual void AddToSimulation(class Simulation* current_simulation) { } | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
virtual void SetMovementForFrame(vec3 const &MoveQuantity) { } | |||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false) { } | |||||
virtual void InitBodyToGhost() { } | |||||
virtual void AddToSimulation(class Simulation* current_simulation) { } | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
virtual void SetMovementForFrame(vec3 const &MoveQuantity) { } | |||||
#endif // PHYSIC IMPLEMENTATION | #endif // PHYSIC IMPLEMENTATION | ||||
@@ -31,180 +31,180 @@ namespace phys | |||||
class EasyConstraint | class EasyConstraint | ||||
{ | { | ||||
friend class Simulation; | |||||
friend class EasyPhysic; | |||||
friend class Simulation; | |||||
friend class EasyPhysic; | |||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
public: | public: | ||||
EasyConstraint() : | |||||
m_typed_constraint(NULL), | |||||
m_p2p_constraint(NULL), | |||||
m_hinge_constraint(NULL), | |||||
m_slider_constraint(NULL), | |||||
m_cone_twist_constraint(NULL), | |||||
m_6dof_constraint(NULL), | |||||
m_owner_simulation(NULL), | |||||
m_a_physobj(NULL), | |||||
m_b_physobj(NULL), | |||||
m_a_transform(lol::mat4(1.f)), | |||||
m_b_transform(lol::mat4(1.f)), | |||||
m_using_ref_a(false), | |||||
m_disable_a2b_collision(false) | |||||
{ | |||||
} | |||||
~EasyConstraint() | |||||
{ | |||||
delete m_typed_constraint; | |||||
m_p2p_constraint = NULL; | |||||
m_hinge_constraint = NULL; | |||||
m_slider_constraint = NULL; | |||||
m_cone_twist_constraint = NULL; | |||||
m_6dof_constraint = NULL; | |||||
} | |||||
void AddToSimulation(class Simulation* current_simulation); | |||||
void RemoveFromSimulation(class Simulation* current_simulation); | |||||
EasyConstraint() : | |||||
m_typed_constraint(NULL), | |||||
m_p2p_constraint(NULL), | |||||
m_hinge_constraint(NULL), | |||||
m_slider_constraint(NULL), | |||||
m_cone_twist_constraint(NULL), | |||||
m_6dof_constraint(NULL), | |||||
m_owner_simulation(NULL), | |||||
m_a_physobj(NULL), | |||||
m_b_physobj(NULL), | |||||
m_a_transform(lol::mat4(1.f)), | |||||
m_b_transform(lol::mat4(1.f)), | |||||
m_using_ref_a(false), | |||||
m_disable_a2b_collision(false) | |||||
{ | |||||
} | |||||
~EasyConstraint() | |||||
{ | |||||
delete m_typed_constraint; | |||||
m_p2p_constraint = NULL; | |||||
m_hinge_constraint = NULL; | |||||
m_slider_constraint = NULL; | |||||
m_cone_twist_constraint = NULL; | |||||
m_6dof_constraint = NULL; | |||||
} | |||||
void AddToSimulation(class Simulation* current_simulation); | |||||
void RemoveFromSimulation(class Simulation* current_simulation); | |||||
private: | private: | ||||
//check if Init can be done | |||||
bool CanProceedWithInit() | |||||
{ | |||||
if (!m_a_physobj || !m_b_physobj) | |||||
return false; | |||||
if (!m_a_physobj->m_rigid_body || !m_b_physobj->m_rigid_body) | |||||
return false; | |||||
return true; | |||||
} | |||||
//------------------------------------------------------------------------- | |||||
//Init constraint functions | |||||
//-- | |||||
void CustomInitConstraintToPoint2Point() | |||||
{ | |||||
m_p2p_constraint = new btPoint2PointConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)); | |||||
m_typed_constraint = m_p2p_constraint; | |||||
} | |||||
void CustomInitConstraintToHinge() | |||||
{ | |||||
m_hinge_constraint = new btHingeConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_hinge_constraint; | |||||
} | |||||
void CustomInitConstraintToSlider() | |||||
{ | |||||
m_slider_constraint = new btSliderConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_slider_constraint; | |||||
} | |||||
void CustomInitConstraintToConeTwist() | |||||
{ | |||||
m_cone_twist_constraint = new btConeTwistConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT))); | |||||
m_typed_constraint = m_cone_twist_constraint; | |||||
} | |||||
void CustomInitConstraintTo6Dof() | |||||
{ | |||||
m_6dof_constraint = new btGeneric6DofConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_6dof_constraint; | |||||
} | |||||
btTypedConstraint* m_typed_constraint; | |||||
btPoint2PointConstraint* m_p2p_constraint; | |||||
btHingeConstraint* m_hinge_constraint; | |||||
btSliderConstraint* m_slider_constraint; | |||||
btConeTwistConstraint* m_cone_twist_constraint; | |||||
btGeneric6DofConstraint* m_6dof_constraint; | |||||
//check if Init can be done | |||||
bool CanProceedWithInit() | |||||
{ | |||||
if (!m_a_physobj || !m_b_physobj) | |||||
return false; | |||||
if (!m_a_physobj->m_rigid_body || !m_b_physobj->m_rigid_body) | |||||
return false; | |||||
return true; | |||||
} | |||||
//------------------------------------------------------------------------- | |||||
//Init constraint functions | |||||
//-- | |||||
void CustomInitConstraintToPoint2Point() | |||||
{ | |||||
m_p2p_constraint = new btPoint2PointConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)); | |||||
m_typed_constraint = m_p2p_constraint; | |||||
} | |||||
void CustomInitConstraintToHinge() | |||||
{ | |||||
m_hinge_constraint = new btHingeConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_hinge_constraint; | |||||
} | |||||
void CustomInitConstraintToSlider() | |||||
{ | |||||
m_slider_constraint = new btSliderConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_slider_constraint; | |||||
} | |||||
void CustomInitConstraintToConeTwist() | |||||
{ | |||||
m_cone_twist_constraint = new btConeTwistConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT))); | |||||
m_typed_constraint = m_cone_twist_constraint; | |||||
} | |||||
void CustomInitConstraintTo6Dof() | |||||
{ | |||||
m_6dof_constraint = new btGeneric6DofConstraint(*m_a_physobj->m_rigid_body, *m_b_physobj->m_rigid_body, | |||||
btTransform(LOL2BT_QUAT(quat(m_a_transform)), LOL2BT_VEC3(m_a_transform.v3.xyz * LOL2BT_UNIT)), | |||||
btTransform(LOL2BT_QUAT(quat(m_b_transform)), LOL2BT_VEC3(m_b_transform.v3.xyz * LOL2BT_UNIT)), | |||||
m_using_ref_a); | |||||
m_typed_constraint = m_6dof_constraint; | |||||
} | |||||
btTypedConstraint* m_typed_constraint; | |||||
btPoint2PointConstraint* m_p2p_constraint; | |||||
btHingeConstraint* m_hinge_constraint; | |||||
btSliderConstraint* m_slider_constraint; | |||||
btConeTwistConstraint* m_cone_twist_constraint; | |||||
btGeneric6DofConstraint* m_6dof_constraint; | |||||
#else // NO PHYSIC IMPLEMENTATION | #else // NO PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
EasyConstraint() : | |||||
m_a_physobj(NULL), | |||||
m_b_physobj(NULL), | |||||
m_a_transform(lol::mat4(1.f)), | |||||
m_b_transform(lol::mat4(1.f)), | |||||
m_using_ref_a(false), | |||||
m_disable_a2b_collision(false) | |||||
{ | |||||
} | |||||
EasyConstraint() : | |||||
m_a_physobj(NULL), | |||||
m_b_physobj(NULL), | |||||
m_a_transform(lol::mat4(1.f)), | |||||
m_b_transform(lol::mat4(1.f)), | |||||
m_using_ref_a(false), | |||||
m_disable_a2b_collision(false) | |||||
{ | |||||
} | |||||
private: | private: | ||||
void AddToSimulation(class Simulation* current_simulation) { } | |||||
void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
void AddToSimulation(class Simulation* current_simulation) { } | |||||
void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
//check if Init can be done | |||||
bool CanProceedWithInit() { return false; } | |||||
void CustomInitConstraintToPoint2Point() { } | |||||
void CustomInitConstraintToHinge() { } | |||||
void CustomInitConstraintToSlider() { } | |||||
void CustomInitConstraintToConeTwist() { } | |||||
void CustomInitConstraintTo6Dof() { } | |||||
//check if Init can be done | |||||
bool CanProceedWithInit() { return false; } | |||||
void CustomInitConstraintToPoint2Point() { } | |||||
void CustomInitConstraintToHinge() { } | |||||
void CustomInitConstraintToSlider() { } | |||||
void CustomInitConstraintToConeTwist() { } | |||||
void CustomInitConstraintTo6Dof() { } | |||||
#endif // PHYSIC IMPLEMENTATION | #endif // PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
void InitConstraintToPoint2Point() { if (CanProceedWithInit()) CustomInitConstraintToPoint2Point(); } | |||||
void InitConstraintToHinge() { if (CanProceedWithInit()) CustomInitConstraintToHinge(); } | |||||
void InitConstraintToSlider() { if (CanProceedWithInit()) CustomInitConstraintToSlider(); } | |||||
void InitConstraintToConeTwist() { if (CanProceedWithInit()) CustomInitConstraintToConeTwist(); } | |||||
void InitConstraintTo6Dof() { if (CanProceedWithInit()) CustomInitConstraintTo6Dof(); } | |||||
//Set given physic object to the proper slot. | |||||
void SetPhysObjA(EasyPhysic* NewPhysObj, lol::mat4 NewTransform) { SetPhysObj(false, NewPhysObj, NewTransform); } | |||||
void SetPhysObjB(EasyPhysic* NewPhysObj, lol::mat4 NewTransform) { SetPhysObj(true, NewPhysObj, NewTransform); } | |||||
void SetPhysObj(bool SetToB, EasyPhysic* NewPhysObj, lol::mat4 NewTransform) | |||||
{ | |||||
if (SetToB) | |||||
{ | |||||
m_b_physobj = NewPhysObj; | |||||
m_b_transform = NewTransform; | |||||
} | |||||
else | |||||
{ | |||||
m_a_physobj = NewPhysObj; | |||||
m_a_transform = NewTransform; | |||||
} | |||||
} | |||||
//Set whether or not the physic engine should use the A object as the reference (most constraint transform are local). | |||||
void SetRefAsA(bool NewUseRefA) | |||||
{ | |||||
m_using_ref_a = NewUseRefA; | |||||
} | |||||
//Set whether or not to disable the collision between the bodies | |||||
void DisableCollisionBetweenObjs(bool DisableCollision) | |||||
{ | |||||
m_disable_a2b_collision = DisableCollision; | |||||
} | |||||
void InitConstraintToPoint2Point() { if (CanProceedWithInit()) CustomInitConstraintToPoint2Point(); } | |||||
void InitConstraintToHinge() { if (CanProceedWithInit()) CustomInitConstraintToHinge(); } | |||||
void InitConstraintToSlider() { if (CanProceedWithInit()) CustomInitConstraintToSlider(); } | |||||
void InitConstraintToConeTwist() { if (CanProceedWithInit()) CustomInitConstraintToConeTwist(); } | |||||
void InitConstraintTo6Dof() { if (CanProceedWithInit()) CustomInitConstraintTo6Dof(); } | |||||
//Set given physic object to the proper slot. | |||||
void SetPhysObjA(EasyPhysic* NewPhysObj, lol::mat4 NewTransform) { SetPhysObj(false, NewPhysObj, NewTransform); } | |||||
void SetPhysObjB(EasyPhysic* NewPhysObj, lol::mat4 NewTransform) { SetPhysObj(true, NewPhysObj, NewTransform); } | |||||
void SetPhysObj(bool SetToB, EasyPhysic* NewPhysObj, lol::mat4 NewTransform) | |||||
{ | |||||
if (SetToB) | |||||
{ | |||||
m_b_physobj = NewPhysObj; | |||||
m_b_transform = NewTransform; | |||||
} | |||||
else | |||||
{ | |||||
m_a_physobj = NewPhysObj; | |||||
m_a_transform = NewTransform; | |||||
} | |||||
} | |||||
//Set whether or not the physic engine should use the A object as the reference (most constraint transform are local). | |||||
void SetRefAsA(bool NewUseRefA) | |||||
{ | |||||
m_using_ref_a = NewUseRefA; | |||||
} | |||||
//Set whether or not to disable the collision between the bodies | |||||
void DisableCollisionBetweenObjs(bool DisableCollision) | |||||
{ | |||||
m_disable_a2b_collision = DisableCollision; | |||||
} | |||||
private: | private: | ||||
Simulation* m_owner_simulation; | |||||
EasyPhysic* m_a_physobj; | |||||
EasyPhysic* m_b_physobj; | |||||
lol::mat4 m_a_transform; | |||||
lol::mat4 m_b_transform; | |||||
bool m_using_ref_a; | |||||
bool m_disable_a2b_collision; | |||||
Simulation* m_owner_simulation; | |||||
EasyPhysic* m_a_physobj; | |||||
EasyPhysic* m_b_physobj; | |||||
lol::mat4 m_a_transform; | |||||
lol::mat4 m_b_transform; | |||||
bool m_using_ref_a; | |||||
bool m_disable_a2b_collision; | |||||
}; | }; | ||||
@@ -33,136 +33,136 @@ namespace phys | |||||
class EasyPhysic | class EasyPhysic | ||||
{ | { | ||||
friend class Simulation; | |||||
friend class EasyConstraint; | |||||
friend class Simulation; | |||||
friend class EasyConstraint; | |||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
public: | public: | ||||
EasyPhysic(WorldEntity* NewOwnerEntity); | |||||
~EasyPhysic(); | |||||
virtual void SetShapeToBox(lol::vec3& box_size); | |||||
virtual void SetShapeToSphere(float radius); | |||||
virtual void SetShapeToCone(float radius, float height); | |||||
virtual void SetShapeToCylinder(lol::vec3& cyl_size); | |||||
virtual void SetShapeToCapsule(float radius, float height); | |||||
virtual bool CanChangeCollisionChannel() { return (m_rigid_body == NULL); } | |||||
virtual mat4 GetTransform(); | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))); | |||||
EasyPhysic(WorldEntity* NewOwnerEntity); | |||||
~EasyPhysic(); | |||||
virtual void SetShapeToBox(lol::vec3& box_size); | |||||
virtual void SetShapeToSphere(float radius); | |||||
virtual void SetShapeToCone(float radius, float height); | |||||
virtual void SetShapeToCylinder(lol::vec3& cyl_size); | |||||
virtual void SetShapeToCapsule(float radius, float height); | |||||
virtual bool CanChangeCollisionChannel() { return (m_rigid_body == NULL); } | |||||
virtual mat4 GetTransform(); | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))); | |||||
protected: | protected: | ||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix); | |||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix); | |||||
public: | public: | ||||
virtual void SetMass(float mass); | |||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false); | |||||
virtual void InitBodyToGhost(); | |||||
virtual void AddToSimulation(class Simulation* current_simulation); | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation); | |||||
virtual void SetMass(float mass); | |||||
virtual void InitBodyToRigid(bool ZeroMassIsKinematic=false); | |||||
virtual void InitBodyToGhost(); | |||||
virtual void AddToSimulation(class Simulation* current_simulation); | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation); | |||||
protected: | protected: | ||||
virtual void SetLocalInertia(float mass); | |||||
virtual void SetShapeTo(btCollisionShape* collision_shape); | |||||
virtual void SetLocalInertia(float mass); | |||||
virtual void SetShapeTo(btCollisionShape* collision_shape); | |||||
virtual btGhostObject* GetGhostObjectInstance(); | |||||
virtual btGhostObject* GetGhostObjectInstance(); | |||||
btCollisionObject* m_collision_object; | |||||
btCollisionObject* m_collision_object; | |||||
btGhostObject* m_ghost_object; | |||||
btGhostObject* m_ghost_object; | |||||
btRigidBody* m_rigid_body; | |||||
btVector3 m_local_inertia; | |||||
btRigidBody* m_rigid_body; | |||||
btVector3 m_local_inertia; | |||||
btCollisionShape* m_collision_shape; | |||||
btConvexShape* m_convex_shape; | |||||
btMotionState* m_motion_state; | |||||
btCollisionShape* m_collision_shape; | |||||
btConvexShape* m_convex_shape; | |||||
btMotionState* m_motion_state; | |||||
#else // NO PHYSIC IMPLEMENTATION | #else // NO PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
EasyPhysic(WorldEntity* NewOwnerEntity) { m_owner_entity = NewOwnerEntity; } | |||||
EasyPhysic(WorldEntity* NewOwnerEntity) { m_owner_entity = NewOwnerEntity; } | |||||
virtual void SetShapeToBox(lol::vec3& BoxSize) { } | |||||
virtual void SetShapeToSphere(float radius) { } | |||||
virtual void SetShapeToCone(float radius, float height) { } | |||||
virtual void SetShapeToCylinder(lol::vec3& cyl_size) { } | |||||
virtual void SetShapeToCapsule(float radius, float height) { } | |||||
virtual void SetShapeToBox(lol::vec3& BoxSize) { } | |||||
virtual void SetShapeToSphere(float radius) { } | |||||
virtual void SetShapeToCone(float radius, float height) { } | |||||
virtual void SetShapeToCylinder(lol::vec3& cyl_size) { } | |||||
virtual void SetShapeToCapsule(float radius, float height) { } | |||||
virtual bool CanChangeCollisionChannel() { return true; } | |||||
virtual mat4 GetTransform() { return mat4(1.0f); } | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))) { } | |||||
virtual bool CanChangeCollisionChannel() { return true; } | |||||
virtual mat4 GetTransform() { return mat4(1.0f); } | |||||
virtual void SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation=lol::quat(lol::mat4(1.0f))) { } | |||||
private: | private: | ||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) { } | |||||
virtual void BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) { } | |||||
public: | public: | ||||
virtual void SetMass(float mass) { } | |||||
virtual void InitBodyToRigid() { } | |||||
virtual void InitBodyToGhost() { } | |||||
virtual void AddToSimulation(class Simulation* current_simulation) { } | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
virtual void SetMass(float mass) { } | |||||
virtual void InitBodyToRigid() { } | |||||
virtual void InitBodyToGhost() { } | |||||
virtual void AddToSimulation(class Simulation* current_simulation) { } | |||||
virtual void RemoveFromSimulation(class Simulation* current_simulation) { } | |||||
virtual void InitBodyToGhost() { } | |||||
virtual void InitBodyToGhost() { } | |||||
#endif // PHYSIC IMPLEMENTATION | #endif // PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
//Sets the collision Group & Mask. | |||||
//Mask can change at runtime, not group ! | |||||
virtual bool SetCollisionChannel(int NewGroup, int NewMask) | |||||
{ | |||||
if (CanChangeCollisionChannel()) | |||||
{ | |||||
m_collision_group = (1<<NewGroup); | |||||
m_collision_mask = NewMask; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
int GetCollisionGroup() { return m_collision_group; } | |||||
int GetCollisionMask() { return m_collision_mask; } | |||||
//Base/Attachment logic | |||||
virtual void AttachTo(EasyPhysic* NewBase, bool NewBaseLockLocation = true, bool NewBaseLockRotation = true) | |||||
{ | |||||
if (NewBase == this || (NewBase && NewBase->m_base_physic == this)) | |||||
return; | |||||
if (NewBase) | |||||
{ | |||||
bool bAlreadyExists = false; | |||||
for (int i = 0; i < NewBase->m_based_physic_list.Count(); ++i) | |||||
if (NewBase->m_based_physic_list[i] == this) | |||||
bAlreadyExists = true; | |||||
if (!bAlreadyExists) | |||||
NewBase->m_based_physic_list << this; | |||||
m_base_physic = NewBase; | |||||
m_base_lock_location = NewBaseLockLocation; | |||||
m_base_lock_rotation = NewBaseLockRotation; | |||||
} | |||||
else if (m_base_physic) | |||||
{ | |||||
for (int i = 0; i < m_base_physic->m_based_physic_list.Count(); ++i) | |||||
if (m_base_physic->m_based_physic_list[i] == this) | |||||
m_base_physic->m_based_physic_list.Remove(i--); | |||||
m_base_physic = NULL; | |||||
} | |||||
} | |||||
//Sets the collision Group & Mask. | |||||
//Mask can change at runtime, not group ! | |||||
virtual bool SetCollisionChannel(int NewGroup, int NewMask) | |||||
{ | |||||
if (CanChangeCollisionChannel()) | |||||
{ | |||||
m_collision_group = (1<<NewGroup); | |||||
m_collision_mask = NewMask; | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
int GetCollisionGroup() { return m_collision_group; } | |||||
int GetCollisionMask() { return m_collision_mask; } | |||||
//Base/Attachment logic | |||||
virtual void AttachTo(EasyPhysic* NewBase, bool NewBaseLockLocation = true, bool NewBaseLockRotation = true) | |||||
{ | |||||
if (NewBase == this || (NewBase && NewBase->m_base_physic == this)) | |||||
return; | |||||
if (NewBase) | |||||
{ | |||||
bool bAlreadyExists = false; | |||||
for (int i = 0; i < NewBase->m_based_physic_list.Count(); ++i) | |||||
if (NewBase->m_based_physic_list[i] == this) | |||||
bAlreadyExists = true; | |||||
if (!bAlreadyExists) | |||||
NewBase->m_based_physic_list << this; | |||||
m_base_physic = NewBase; | |||||
m_base_lock_location = NewBaseLockLocation; | |||||
m_base_lock_rotation = NewBaseLockRotation; | |||||
} | |||||
else if (m_base_physic) | |||||
{ | |||||
for (int i = 0; i < m_base_physic->m_based_physic_list.Count(); ++i) | |||||
if (m_base_physic->m_based_physic_list[i] == this) | |||||
m_base_physic->m_based_physic_list.Remove(i--); | |||||
m_base_physic = NULL; | |||||
} | |||||
} | |||||
protected: | protected: | ||||
lol::mat4 m_local_to_world; | |||||
float m_mass; | |||||
int m_collision_group; | |||||
int m_collision_mask; | |||||
WorldEntity* m_owner_entity; | |||||
Simulation* m_owner_simulation; | |||||
//Base/Attachment logic | |||||
Array<EasyPhysic*> m_based_physic_list; //List of objects based on this : this object moves, its based object MoveStep with it. | |||||
EasyPhysic* m_base_physic; //Base for this object : The base moves, the object moves with it. | |||||
bool m_base_lock_location; //when this is TRUE, location moves with rotation change. | |||||
bool m_base_lock_rotation; //when this is TRUE, rotation moves with rotation change. | |||||
//Touch logic | |||||
Array<EasyPhysic*> m_touching_physic; //Maintained by ghost objects | |||||
lol::mat4 m_local_to_world; | |||||
float m_mass; | |||||
int m_collision_group; | |||||
int m_collision_mask; | |||||
WorldEntity* m_owner_entity; | |||||
Simulation* m_owner_simulation; | |||||
//Base/Attachment logic | |||||
Array<EasyPhysic*> m_based_physic_list; //List of objects based on this : this object moves, its based object MoveStep with it. | |||||
EasyPhysic* m_base_physic; //Base for this object : The base moves, the object moves with it. | |||||
bool m_base_lock_location; //when this is TRUE, location moves with rotation change. | |||||
bool m_base_lock_rotation; //when this is TRUE, rotation moves with rotation change. | |||||
//Touch logic | |||||
Array<EasyPhysic*> m_touching_physic; //Maintained by ghost objects | |||||
}; | }; | ||||
} /* namespace phys */ | } /* namespace phys */ | ||||
@@ -19,32 +19,32 @@ | |||||
namespace lol | namespace lol | ||||
{ | { | ||||
//Override Gamegroups names for Physic-useage | |||||
//"_ENT_" means that this is a group for Entities that use EasyPhysic primitives. | |||||
//"_EZP_" means that this is a group for EasyPhysic primitives. | |||||
#define GAMEGROUP_ENT_INPUT GAMEGROUP_BEFORE | |||||
#define GAMEGROUP_ENT_PLATFORM GAMEGROUP_DEFAULT | |||||
#define GAMEGROUP_ENT_MAIN GAMEGROUP_AFTER | |||||
#define GAMEGROUP_EZP_CHAR_CTRLR GAMEGROUP_AFTER_0 | |||||
#define GAMEGROUP_SIMULATION GAMEGROUP_AFTER_1 | |||||
//Override Gamegroups names for Physic-useage | |||||
//"_ENT_" means that this is a group for Entities that use EasyPhysic primitives. | |||||
//"_EZP_" means that this is a group for EasyPhysic primitives. | |||||
#define GAMEGROUP_ENT_INPUT GAMEGROUP_BEFORE | |||||
#define GAMEGROUP_ENT_PLATFORM GAMEGROUP_DEFAULT | |||||
#define GAMEGROUP_ENT_MAIN GAMEGROUP_AFTER | |||||
#define GAMEGROUP_EZP_CHAR_CTRLR GAMEGROUP_AFTER_0 | |||||
#define GAMEGROUP_SIMULATION GAMEGROUP_AFTER_1 | |||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
#define LOL2BT_UNIT 1.0f | |||||
#define BT2LOL_UNIT 1.0f | |||||
#define LOL2BT_UNIT 1.0f | |||||
#define BT2LOL_UNIT 1.0f | |||||
#define LOL2BT_SIZE 0.5f | |||||
#define BT2LOL_SIZE 2.0f | |||||
#define LOL2BT_SIZE 0.5f | |||||
#define BT2LOL_SIZE 2.0f | |||||
#define LOL2BT_VEC3(ELEMENT) btVector3((ELEMENT).x, (ELEMENT).y, (ELEMENT).z) | |||||
#define BT2LOL_VEC3(ELEMENT) (*(lol::vec3*)(&(ELEMENT))) | |||||
#define LOL2BT_VEC3(ELEMENT) btVector3((ELEMENT).x, (ELEMENT).y, (ELEMENT).z) | |||||
#define BT2LOL_VEC3(ELEMENT) (*(lol::vec3*)(&(ELEMENT))) | |||||
//Same as above with Unit taken into account | //Same as above with Unit taken into account | ||||
#define LOL2BTU_VEC3(ELEMENT) btVector3((ELEMENT).x * LOL2BT_UNIT, (ELEMENT).y * LOL2BT_UNIT, (ELEMENT).z * LOL2BT_UNIT) | |||||
#define BT2LOLU_VEC3(ELEMENT) (*(lol::vec3*)(&(ELEMENT))) * BT2LOL_UNIT | |||||
#define LOL2BTU_VEC3(ELEMENT) btVector3((ELEMENT).x * LOL2BT_UNIT, (ELEMENT).y * LOL2BT_UNIT, (ELEMENT).z * LOL2BT_UNIT) | |||||
#define BT2LOLU_VEC3(ELEMENT) (*(lol::vec3*)(&(ELEMENT))) * BT2LOL_UNIT | |||||
#define LOL2BT_QUAT(ELEMENT) btQuaternion((ELEMENT).x, (ELEMENT).y, (ELEMENT).z, (ELEMENT).w) | |||||
#define BT2LOL_QUAT(ELEMENT) lol::quat((ELEMENT).getW(), BT2LOL_VEC3((ELEMENT).getAxis()) | |||||
#define LOL2BT_QUAT(ELEMENT) btQuaternion((ELEMENT).x, (ELEMENT).y, (ELEMENT).z, (ELEMENT).w) | |||||
#define BT2LOL_QUAT(ELEMENT) lol::quat((ELEMENT).getW(), BT2LOL_VEC3((ELEMENT).getAxis()) | |||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||
@@ -26,406 +26,406 @@ namespace phys | |||||
enum eRaycastType | enum eRaycastType | ||||
{ | { | ||||
ERT_Closest, | |||||
ERT_AllHit, | |||||
ERT_AnyHit, //Will stop at the first hit. Hit data are supposed to be irrelevant | |||||
ERT_Closest, | |||||
ERT_AllHit, | |||||
ERT_AnyHit, //Will stop at the first hit. Hit data are supposed to be irrelevant | |||||
ERT_MAX | |||||
ERT_MAX | |||||
}; | }; | ||||
struct RayCastResult | struct RayCastResult | ||||
{ | { | ||||
RayCastResult(int CollisionFilterGroup=1, int CollisionFilterMask=(0xFF)) | |||||
{ | |||||
memset(this, 0, sizeof(RayCastResult)); | |||||
m_collision_filter_group = CollisionFilterGroup; | |||||
m_collision_filter_mask = CollisionFilterMask; | |||||
} | |||||
void Reset() | |||||
{ | |||||
m_collider_list.Empty(); | |||||
m_hit_normal_list.Empty(); | |||||
m_hit_point_list.Empty(); | |||||
m_hit_fraction_list.Empty(); | |||||
} | |||||
Array<EasyPhysic*> m_collider_list; | |||||
Array<vec3> m_hit_normal_list; | |||||
Array<vec3> m_hit_point_list; | |||||
Array<float> m_hit_fraction_list; | |||||
short int m_collision_filter_group; | |||||
short int m_collision_filter_mask; | |||||
unsigned int m_flags; //??? | |||||
RayCastResult(int CollisionFilterGroup=1, int CollisionFilterMask=(0xFF)) | |||||
{ | |||||
memset(this, 0, sizeof(RayCastResult)); | |||||
m_collision_filter_group = CollisionFilterGroup; | |||||
m_collision_filter_mask = CollisionFilterMask; | |||||
} | |||||
void Reset() | |||||
{ | |||||
m_collider_list.Empty(); | |||||
m_hit_normal_list.Empty(); | |||||
m_hit_point_list.Empty(); | |||||
m_hit_fraction_list.Empty(); | |||||
} | |||||
Array<EasyPhysic*> m_collider_list; | |||||
Array<vec3> m_hit_normal_list; | |||||
Array<vec3> m_hit_point_list; | |||||
Array<float> m_hit_fraction_list; | |||||
short int m_collision_filter_group; | |||||
short int m_collision_filter_mask; | |||||
unsigned int m_flags; //??? | |||||
}; | }; | ||||
class Simulation : public Entity | class Simulation : public Entity | ||||
{ | { | ||||
public: | public: | ||||
Simulation() : | |||||
m_broadphase(0), | |||||
m_collision_configuration(0), | |||||
m_dispatcher(0), | |||||
m_solver(0), | |||||
m_dynamics_world(0), | |||||
m_timestep(1.f/60.f) | |||||
{ | |||||
m_gamegroup = GAMEGROUP_SIMULATION; | |||||
} | |||||
~Simulation() | |||||
{ | |||||
Exit(); | |||||
} | |||||
char const *GetName() { return "<Simulation>"; } | |||||
Simulation() : | |||||
m_broadphase(0), | |||||
m_collision_configuration(0), | |||||
m_dispatcher(0), | |||||
m_solver(0), | |||||
m_dynamics_world(0), | |||||
m_timestep(1.f/60.f) | |||||
{ | |||||
m_gamegroup = GAMEGROUP_SIMULATION; | |||||
} | |||||
~Simulation() | |||||
{ | |||||
Exit(); | |||||
} | |||||
char const *GetName() { return "<Simulation>"; } | |||||
#ifdef HAVE_PHYS_USE_BULLET | #ifdef HAVE_PHYS_USE_BULLET | ||||
public: | public: | ||||
void Init() | |||||
{ | |||||
// Build the broadphase | |||||
if (1) | |||||
{ | |||||
m_Sweep_broadphase = new btAxisSweep3(LOL2BT_VEC3(m_world_min), LOL2BT_VEC3(m_world_max)); | |||||
m_Sweep_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback()); | |||||
m_broadphase = m_Sweep_broadphase; | |||||
} | |||||
else | |||||
m_broadphase = new btDbvtBroadphase(); | |||||
// Set up the collision configuration and dispatcher | |||||
m_collision_configuration = new btDefaultCollisionConfiguration(); | |||||
m_dispatcher = new btCollisionDispatcher(m_collision_configuration); | |||||
// The actual physics solver | |||||
m_solver = new btSequentialImpulseConstraintSolver; | |||||
// The world. | |||||
m_dynamics_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collision_configuration); | |||||
} | |||||
virtual void TickGame(float seconds) | |||||
{ | |||||
Entity::TickGame(seconds); | |||||
//step the simulation | |||||
if (m_dynamics_world) | |||||
{ | |||||
//the "+1" is to have at least one Timestep and to ensure float to int .5f conversion. | |||||
int steps = (int)(seconds / m_timestep) + 1; | |||||
m_dynamics_world->stepSimulation(seconds, steps, m_timestep); | |||||
} | |||||
} | |||||
//Rip-Off of the btKinematicClosestNotMeRayResultCallback | |||||
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback | |||||
{ | |||||
public: | |||||
ClosestNotMeRayResultCallback(btCollisionObject* Me, const btVector3& rayFromWorld, const btVector3& rayToWorld) : | |||||
btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld) | |||||
{ | |||||
m_me = Me; | |||||
} | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) | |||||
{ | |||||
if (rayResult.m_collisionObject == m_me) | |||||
return 1.0; | |||||
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); | |||||
} | |||||
protected: | |||||
btCollisionObject* m_me; | |||||
}; | |||||
//Will stop at the first hit. Hit data are supposed to be irrelevant | |||||
class AnyHitRayResultCallback : public btCollisionWorld::ClosestRayResultCallback | |||||
{ | |||||
public: | |||||
AnyHitRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld) : | |||||
btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld) | |||||
{ | |||||
} | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) | |||||
{ | |||||
return .0f; | |||||
} | |||||
}; | |||||
//Returns true when hitting something. If SourceCaster is set, it will be ignored by Raycast. | |||||
bool RayHits(RayCastResult& HitResult, eRaycastType RaycastType, const vec3& RayFrom, const vec3& RayTo, EasyPhysic* SourceCaster=NULL) | |||||
{ | |||||
bool bResult = false; | |||||
btCollisionWorld::RayResultCallback* BtRayResult = NULL; | |||||
btCollisionWorld::ClosestRayResultCallback* BtRayResult_Closest; | |||||
btCollisionWorld::AllHitsRayResultCallback* BtRayResult_AllHits; | |||||
switch (RaycastType) | |||||
{ | |||||
case ERT_Closest: | |||||
{ | |||||
if (SourceCaster) | |||||
BtRayResult_Closest = new ClosestNotMeRayResultCallback(SourceCaster->m_collision_object, LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
else | |||||
BtRayResult_Closest = new btCollisionWorld::ClosestRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_Closest; | |||||
break; | |||||
} | |||||
case ERT_AllHit: | |||||
{ | |||||
BtRayResult_AllHits = new btCollisionWorld::AllHitsRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_AllHits; | |||||
break; | |||||
} | |||||
case ERT_AnyHit: | |||||
{ | |||||
BtRayResult_Closest = new AnyHitRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_Closest; | |||||
break; | |||||
} | |||||
} | |||||
m_dynamics_world->rayTest(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo), *BtRayResult); | |||||
if (BtRayResult->hasHit()) | |||||
{ | |||||
bResult = true; | |||||
switch (RaycastType) | |||||
{ | |||||
case ERT_Closest: | |||||
{ | |||||
HitResult.m_collider_list << (EasyPhysic*)BtRayResult_Closest->m_collisionObject->getUserPointer(); | |||||
HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitNormalWorld); | |||||
HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitPointWorld); | |||||
HitResult.m_hit_fraction_list << BtRayResult_Closest->m_closestHitFraction; | |||||
break; | |||||
} | |||||
case ERT_AllHit: | |||||
{ | |||||
for (int i = 0; i < BtRayResult_AllHits->m_collisionObjects.size(); i++) | |||||
{ | |||||
HitResult.m_collider_list << (EasyPhysic*)BtRayResult_AllHits->m_collisionObjects[i]->getUserPointer(); | |||||
HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitNormalWorld[i]); | |||||
HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitPointWorld[i]); | |||||
HitResult.m_hit_fraction_list << BtRayResult_AllHits->m_hitFractions[i]; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
delete BtRayResult; | |||||
return bResult; | |||||
} | |||||
void Exit() | |||||
{ | |||||
delete m_dynamics_world; | |||||
delete m_solver; | |||||
delete m_dispatcher; | |||||
delete m_collision_configuration; | |||||
delete m_broadphase; | |||||
} | |||||
btDiscreteDynamicsWorld* GetWorld() | |||||
{ | |||||
return m_dynamics_world; | |||||
} | |||||
void Init() | |||||
{ | |||||
// Build the broadphase | |||||
if (1) | |||||
{ | |||||
m_Sweep_broadphase = new btAxisSweep3(LOL2BT_VEC3(m_world_min), LOL2BT_VEC3(m_world_max)); | |||||
m_Sweep_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback()); | |||||
m_broadphase = m_Sweep_broadphase; | |||||
} | |||||
else | |||||
m_broadphase = new btDbvtBroadphase(); | |||||
// Set up the collision configuration and dispatcher | |||||
m_collision_configuration = new btDefaultCollisionConfiguration(); | |||||
m_dispatcher = new btCollisionDispatcher(m_collision_configuration); | |||||
// The actual physics solver | |||||
m_solver = new btSequentialImpulseConstraintSolver; | |||||
// The world. | |||||
m_dynamics_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collision_configuration); | |||||
} | |||||
virtual void TickGame(float seconds) | |||||
{ | |||||
Entity::TickGame(seconds); | |||||
//step the simulation | |||||
if (m_dynamics_world) | |||||
{ | |||||
//the "+1" is to have at least one Timestep and to ensure float to int .5f conversion. | |||||
int steps = (int)(seconds / m_timestep) + 1; | |||||
m_dynamics_world->stepSimulation(seconds, steps, m_timestep); | |||||
} | |||||
} | |||||
//Rip-Off of the btKinematicClosestNotMeRayResultCallback | |||||
class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback | |||||
{ | |||||
public: | |||||
ClosestNotMeRayResultCallback(btCollisionObject* Me, const btVector3& rayFromWorld, const btVector3& rayToWorld) : | |||||
btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld) | |||||
{ | |||||
m_me = Me; | |||||
} | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) | |||||
{ | |||||
if (rayResult.m_collisionObject == m_me) | |||||
return 1.0; | |||||
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); | |||||
} | |||||
protected: | |||||
btCollisionObject* m_me; | |||||
}; | |||||
//Will stop at the first hit. Hit data are supposed to be irrelevant | |||||
class AnyHitRayResultCallback : public btCollisionWorld::ClosestRayResultCallback | |||||
{ | |||||
public: | |||||
AnyHitRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld) : | |||||
btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld) | |||||
{ | |||||
} | |||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) | |||||
{ | |||||
return .0f; | |||||
} | |||||
}; | |||||
//Returns true when hitting something. If SourceCaster is set, it will be ignored by Raycast. | |||||
bool RayHits(RayCastResult& HitResult, eRaycastType RaycastType, const vec3& RayFrom, const vec3& RayTo, EasyPhysic* SourceCaster=NULL) | |||||
{ | |||||
bool bResult = false; | |||||
btCollisionWorld::RayResultCallback* BtRayResult = NULL; | |||||
btCollisionWorld::ClosestRayResultCallback* BtRayResult_Closest; | |||||
btCollisionWorld::AllHitsRayResultCallback* BtRayResult_AllHits; | |||||
switch (RaycastType) | |||||
{ | |||||
case ERT_Closest: | |||||
{ | |||||
if (SourceCaster) | |||||
BtRayResult_Closest = new ClosestNotMeRayResultCallback(SourceCaster->m_collision_object, LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
else | |||||
BtRayResult_Closest = new btCollisionWorld::ClosestRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_Closest; | |||||
break; | |||||
} | |||||
case ERT_AllHit: | |||||
{ | |||||
BtRayResult_AllHits = new btCollisionWorld::AllHitsRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_AllHits; | |||||
break; | |||||
} | |||||
case ERT_AnyHit: | |||||
{ | |||||
BtRayResult_Closest = new AnyHitRayResultCallback(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo)); | |||||
BtRayResult = BtRayResult_Closest; | |||||
break; | |||||
} | |||||
} | |||||
m_dynamics_world->rayTest(LOL2BTU_VEC3(RayFrom), LOL2BTU_VEC3(RayTo), *BtRayResult); | |||||
if (BtRayResult->hasHit()) | |||||
{ | |||||
bResult = true; | |||||
switch (RaycastType) | |||||
{ | |||||
case ERT_Closest: | |||||
{ | |||||
HitResult.m_collider_list << (EasyPhysic*)BtRayResult_Closest->m_collisionObject->getUserPointer(); | |||||
HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitNormalWorld); | |||||
HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_Closest->m_hitPointWorld); | |||||
HitResult.m_hit_fraction_list << BtRayResult_Closest->m_closestHitFraction; | |||||
break; | |||||
} | |||||
case ERT_AllHit: | |||||
{ | |||||
for (int i = 0; i < BtRayResult_AllHits->m_collisionObjects.size(); i++) | |||||
{ | |||||
HitResult.m_collider_list << (EasyPhysic*)BtRayResult_AllHits->m_collisionObjects[i]->getUserPointer(); | |||||
HitResult.m_hit_normal_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitNormalWorld[i]); | |||||
HitResult.m_hit_point_list << BT2LOLU_VEC3(BtRayResult_AllHits->m_hitPointWorld[i]); | |||||
HitResult.m_hit_fraction_list << BtRayResult_AllHits->m_hitFractions[i]; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
delete BtRayResult; | |||||
return bResult; | |||||
} | |||||
void Exit() | |||||
{ | |||||
delete m_dynamics_world; | |||||
delete m_solver; | |||||
delete m_dispatcher; | |||||
delete m_collision_configuration; | |||||
delete m_broadphase; | |||||
} | |||||
btDiscreteDynamicsWorld* GetWorld() | |||||
{ | |||||
return m_dynamics_world; | |||||
} | |||||
private: | private: | ||||
void CustomSetContinuousDetection(bool ShouldUseCCD) | |||||
{ | |||||
if (m_dynamics_world) | |||||
m_dynamics_world->getDispatchInfo().m_useContinuous = ShouldUseCCD; | |||||
} | |||||
void CustomSetGravity(vec3 &NewGravity) | |||||
{ | |||||
if (m_dynamics_world) | |||||
m_dynamics_world->setGravity(LOL2BT_VEC3(NewGravity * LOL2BT_UNIT)); | |||||
} | |||||
void CustomSetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax) | |||||
{ | |||||
} | |||||
void CustomSetTimestep(float NewTimestep) { } | |||||
//broadphase | |||||
btBroadphaseInterface* m_broadphase; | |||||
btAxisSweep3* m_Sweep_broadphase; | |||||
// Set up the collision configuration and dispatc | |||||
btDefaultCollisionConfiguration* m_collision_configuration; | |||||
btCollisionDispatcher* m_dispatcher; | |||||
// The actual physics solver | |||||
btSequentialImpulseConstraintSolver* m_solver; | |||||
// The world. | |||||
btDiscreteDynamicsWorld* m_dynamics_world; | |||||
void CustomSetContinuousDetection(bool ShouldUseCCD) | |||||
{ | |||||
if (m_dynamics_world) | |||||
m_dynamics_world->getDispatchInfo().m_useContinuous = ShouldUseCCD; | |||||
} | |||||
void CustomSetGravity(vec3 &NewGravity) | |||||
{ | |||||
if (m_dynamics_world) | |||||
m_dynamics_world->setGravity(LOL2BT_VEC3(NewGravity * LOL2BT_UNIT)); | |||||
} | |||||
void CustomSetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax) | |||||
{ | |||||
} | |||||
void CustomSetTimestep(float NewTimestep) { } | |||||
//broadphase | |||||
btBroadphaseInterface* m_broadphase; | |||||
btAxisSweep3* m_Sweep_broadphase; | |||||
// Set up the collision configuration and dispatc | |||||
btDefaultCollisionConfiguration* m_collision_configuration; | |||||
btCollisionDispatcher* m_dispatcher; | |||||
// The actual physics solver | |||||
btSequentialImpulseConstraintSolver* m_solver; | |||||
// The world. | |||||
btDiscreteDynamicsWorld* m_dynamics_world; | |||||
#else // NO PHYSIC IMPLEMENTATION | #else // NO PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
void Init() { } | |||||
void TickGame(float seconds) { } | |||||
bool RayHits(RayCastResult& HitResult, eRaycastType RaycastType, const vec3& RayFrom, const vec3& RayTo, EasyPhysic* SourceCaster=NULL) { return false; } | |||||
void Exit() { } | |||||
void Init() { } | |||||
void TickGame(float seconds) { } | |||||
bool RayHits(RayCastResult& HitResult, eRaycastType RaycastType, const vec3& RayFrom, const vec3& RayTo, EasyPhysic* SourceCaster=NULL) { return false; } | |||||
void Exit() { } | |||||
private: | private: | ||||
void CustomSetContinuousDetection(bool ShouldUseCCD) { } | |||||
void CustomSetGravity(vec3 &NewGravity) { } | |||||
void CustomSetWorldLimit(vec3 &NewWorldMin, vec3 &NewWorldMax) { } | |||||
void CustomSetTimestep(float NewTimestep) { } | |||||
void CustomSetContinuousDetection(bool ShouldUseCCD) { } | |||||
void CustomSetGravity(vec3 &NewGravity) { } | |||||
void CustomSetWorldLimit(vec3 &NewWorldMin, vec3 &NewWorldMax) { } | |||||
void CustomSetTimestep(float NewTimestep) { } | |||||
#endif // PHYSIC IMPLEMENTATION | #endif // PHYSIC IMPLEMENTATION | ||||
public: | public: | ||||
//Main logic : | |||||
//The Set*() functions do the all-lib-independent data storage. | |||||
//And then it calls the CustomSet*() which are the specialized versions. | |||||
//Sets the continuous collision detection flag. | |||||
void SetContinuousDetection(bool ShouldUseCCD) | |||||
{ | |||||
m_using_CCD = ShouldUseCCD; | |||||
CustomSetContinuousDetection(ShouldUseCCD); | |||||
} | |||||
//Sets the simulation gravity. | |||||
void SetGravity(vec3 &NewGravity) | |||||
{ | |||||
m_gravity = NewGravity; | |||||
CustomSetGravity(NewGravity); | |||||
} | |||||
//Sets the simulation gravity. | |||||
void SetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax) | |||||
{ | |||||
m_world_min = NewWorldMin; | |||||
m_world_max = NewWorldMax; | |||||
CustomSetWorldLimit(NewWorldMin, NewWorldMax); | |||||
} | |||||
//Sets the simulation fixed timestep. | |||||
void SetTimestep(float NewTimestep) | |||||
{ | |||||
if (NewTimestep > .0f) | |||||
{ | |||||
m_timestep = NewTimestep; | |||||
CustomSetTimestep(NewTimestep); | |||||
} | |||||
} | |||||
//Main logic : | |||||
//The Set*() functions do the all-lib-independent data storage. | |||||
//And then it calls the CustomSet*() which are the specialized versions. | |||||
//Sets the continuous collision detection flag. | |||||
void SetContinuousDetection(bool ShouldUseCCD) | |||||
{ | |||||
m_using_CCD = ShouldUseCCD; | |||||
CustomSetContinuousDetection(ShouldUseCCD); | |||||
} | |||||
//Sets the simulation gravity. | |||||
void SetGravity(vec3 &NewGravity) | |||||
{ | |||||
m_gravity = NewGravity; | |||||
CustomSetGravity(NewGravity); | |||||
} | |||||
//Sets the simulation gravity. | |||||
void SetWorldLimit(vec3 const &NewWorldMin, vec3 const &NewWorldMax) | |||||
{ | |||||
m_world_min = NewWorldMin; | |||||
m_world_max = NewWorldMax; | |||||
CustomSetWorldLimit(NewWorldMin, NewWorldMax); | |||||
} | |||||
//Sets the simulation fixed timestep. | |||||
void SetTimestep(float NewTimestep) | |||||
{ | |||||
if (NewTimestep > .0f) | |||||
{ | |||||
m_timestep = NewTimestep; | |||||
CustomSetTimestep(NewTimestep); | |||||
} | |||||
} | |||||
private: | private: | ||||
friend class EasyPhysic; | |||||
friend class EasyCharacterController; | |||||
friend class EasyConstraint; | |||||
enum eEasyPhysicType | |||||
{ | |||||
EEPT_Dynamic, | |||||
EEPT_Static, | |||||
EEPT_Ghost, | |||||
EEPT_CollisionObject, | |||||
EEPT_CharacterController, | |||||
EEPT_MAX | |||||
}; | |||||
//m_owner_simulation | |||||
//Adds the given EasyPhysic to the correct list. | |||||
void ObjectRegistration(bool AddObject, EasyPhysic* NewEP, eEasyPhysicType CurType) | |||||
{ | |||||
Array<EasyPhysic*>* SearchList = NULL; | |||||
switch(CurType) | |||||
{ | |||||
case EEPT_Dynamic: | |||||
{ | |||||
SearchList = &m_dynamic_list; | |||||
break; | |||||
} | |||||
case EEPT_Static: | |||||
{ | |||||
SearchList = &m_static_list; | |||||
break; | |||||
} | |||||
case EEPT_Ghost: | |||||
{ | |||||
SearchList = &m_ghost_list; | |||||
break; | |||||
} | |||||
case EEPT_CollisionObject: | |||||
{ | |||||
SearchList = &m_collision_object_list; | |||||
break; | |||||
} | |||||
case EEPT_CharacterController: | |||||
{ | |||||
SearchList = &m_character_controller_list; | |||||
break; | |||||
} | |||||
} | |||||
if (AddObject) | |||||
{ | |||||
NewEP->m_owner_simulation = this; | |||||
(*SearchList) << NewEP; | |||||
} | |||||
else | |||||
{ | |||||
NewEP->m_owner_simulation = NULL; | |||||
for (int i = 0; i < SearchList->Count(); ++i) | |||||
{ | |||||
if ((*SearchList)[i] == NewEP) | |||||
{ | |||||
SearchList->Remove(i--); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void ObjectRegistration(bool AddObject, EasyConstraint* NewEC) | |||||
{ | |||||
Array<EasyConstraint*>* SearchList = NULL; | |||||
SearchList = &m_constraint_list; | |||||
if (AddObject) | |||||
{ | |||||
NewEC->m_owner_simulation = this; | |||||
(*SearchList) << NewEC; | |||||
} | |||||
else | |||||
{ | |||||
NewEC->m_owner_simulation = NULL; | |||||
for (int i = 0; i < SearchList->Count(); ++i) | |||||
{ | |||||
if ((*SearchList)[i] == NewEC) | |||||
{ | |||||
SearchList->Remove(i--); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
//Easy Physics body List | |||||
Array<EasyPhysic*> m_dynamic_list; | |||||
Array<EasyPhysic*> m_static_list; | |||||
Array<EasyPhysic*> m_ghost_list; | |||||
Array<EasyPhysic*> m_collision_object_list; | |||||
Array<EasyPhysic*> m_character_controller_list; | |||||
Array<EasyConstraint*> m_constraint_list; | |||||
//Easy Physics data storage | |||||
float m_timestep; | |||||
bool m_using_CCD; | |||||
vec3 m_gravity; | |||||
vec3 m_world_min; | |||||
vec3 m_world_max; | |||||
friend class EasyPhysic; | |||||
friend class EasyCharacterController; | |||||
friend class EasyConstraint; | |||||
enum eEasyPhysicType | |||||
{ | |||||
EEPT_Dynamic, | |||||
EEPT_Static, | |||||
EEPT_Ghost, | |||||
EEPT_CollisionObject, | |||||
EEPT_CharacterController, | |||||
EEPT_MAX | |||||
}; | |||||
//m_owner_simulation | |||||
//Adds the given EasyPhysic to the correct list. | |||||
void ObjectRegistration(bool AddObject, EasyPhysic* NewEP, eEasyPhysicType CurType) | |||||
{ | |||||
Array<EasyPhysic*>* SearchList = NULL; | |||||
switch(CurType) | |||||
{ | |||||
case EEPT_Dynamic: | |||||
{ | |||||
SearchList = &m_dynamic_list; | |||||
break; | |||||
} | |||||
case EEPT_Static: | |||||
{ | |||||
SearchList = &m_static_list; | |||||
break; | |||||
} | |||||
case EEPT_Ghost: | |||||
{ | |||||
SearchList = &m_ghost_list; | |||||
break; | |||||
} | |||||
case EEPT_CollisionObject: | |||||
{ | |||||
SearchList = &m_collision_object_list; | |||||
break; | |||||
} | |||||
case EEPT_CharacterController: | |||||
{ | |||||
SearchList = &m_character_controller_list; | |||||
break; | |||||
} | |||||
} | |||||
if (AddObject) | |||||
{ | |||||
NewEP->m_owner_simulation = this; | |||||
(*SearchList) << NewEP; | |||||
} | |||||
else | |||||
{ | |||||
NewEP->m_owner_simulation = NULL; | |||||
for (int i = 0; i < SearchList->Count(); ++i) | |||||
{ | |||||
if ((*SearchList)[i] == NewEP) | |||||
{ | |||||
SearchList->Remove(i--); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void ObjectRegistration(bool AddObject, EasyConstraint* NewEC) | |||||
{ | |||||
Array<EasyConstraint*>* SearchList = NULL; | |||||
SearchList = &m_constraint_list; | |||||
if (AddObject) | |||||
{ | |||||
NewEC->m_owner_simulation = this; | |||||
(*SearchList) << NewEC; | |||||
} | |||||
else | |||||
{ | |||||
NewEC->m_owner_simulation = NULL; | |||||
for (int i = 0; i < SearchList->Count(); ++i) | |||||
{ | |||||
if ((*SearchList)[i] == NewEC) | |||||
{ | |||||
SearchList->Remove(i--); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
//Easy Physics body List | |||||
Array<EasyPhysic*> m_dynamic_list; | |||||
Array<EasyPhysic*> m_static_list; | |||||
Array<EasyPhysic*> m_ghost_list; | |||||
Array<EasyPhysic*> m_collision_object_list; | |||||
Array<EasyPhysic*> m_character_controller_list; | |||||
Array<EasyConstraint*> m_constraint_list; | |||||
//Easy Physics data storage | |||||
float m_timestep; | |||||
bool m_using_CCD; | |||||
vec3 m_gravity; | |||||
vec3 m_world_min; | |||||
vec3 m_world_max; | |||||
}; | }; | ||||
} /* namespace phys */ | } /* namespace phys */ | ||||
@@ -45,202 +45,202 @@ namespace phys | |||||
//When called, will try to remove Character controller from its collision. | //When called, will try to remove Character controller from its collision. | ||||
bool BulletKinematicCharacterController::RecoverFromPenetration(btCollisionWorld* CollisionWorld) | bool BulletKinematicCharacterController::RecoverFromPenetration(btCollisionWorld* CollisionWorld) | ||||
{ | { | ||||
bool HasPenetration = false; | |||||
//Retrieve all pair with us colliding. | |||||
CollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghost_object->getOverlappingPairCache(), CollisionWorld->getDispatchInfo(), CollisionWorld->getDispatcher()); | |||||
m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); | |||||
float MaxPen = .0f; | |||||
for (int i = 0; i < m_ghost_object->getOverlappingPairCache()->getNumOverlappingPairs(); i++) | |||||
{ | |||||
m_manifold_array.resize(0); | |||||
//this is the equivalent of the "Touch algorithm". Maybe refactor ? | |||||
btBroadphasePair* CollisionPair = &m_ghost_object->getOverlappingPairCache()->getOverlappingPairArray()[i]; | |||||
if (CollisionPair->m_algorithm) | |||||
CollisionPair->m_algorithm->getAllContactManifolds(m_manifold_array); | |||||
for (int j = 0; j < m_manifold_array.size(); ++j) | |||||
{ | |||||
btPersistentManifold* CurMfold = m_manifold_array[j]; | |||||
//Normal direction differs if we're Body0 | |||||
float DirSign = CurMfold->getBody0() == m_ghost_object ? -1.f : 1.f; | |||||
for (int k = 0; k < CurMfold->getNumContacts(); k++) | |||||
{ | |||||
const btManifoldPoint& MfPoint = CurMfold->getContactPoint(k); | |||||
float Dist = MfPoint.getDistance(); | |||||
if (Dist < .0f) | |||||
{ | |||||
if (Dist < MaxPen) | |||||
{ | |||||
MaxPen = Dist; | |||||
m_touching_normal = BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign; | |||||
} | |||||
m_current_position += BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign * Dist * .2f; | |||||
HasPenetration = true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
btTransform GObjMx = m_ghost_object->getWorldTransform(); | |||||
GObjMx.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
m_ghost_object->setWorldTransform(GObjMx); | |||||
return HasPenetration; | |||||
bool HasPenetration = false; | |||||
//Retrieve all pair with us colliding. | |||||
CollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghost_object->getOverlappingPairCache(), CollisionWorld->getDispatchInfo(), CollisionWorld->getDispatcher()); | |||||
m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); | |||||
float MaxPen = .0f; | |||||
for (int i = 0; i < m_ghost_object->getOverlappingPairCache()->getNumOverlappingPairs(); i++) | |||||
{ | |||||
m_manifold_array.resize(0); | |||||
//this is the equivalent of the "Touch algorithm". Maybe refactor ? | |||||
btBroadphasePair* CollisionPair = &m_ghost_object->getOverlappingPairCache()->getOverlappingPairArray()[i]; | |||||
if (CollisionPair->m_algorithm) | |||||
CollisionPair->m_algorithm->getAllContactManifolds(m_manifold_array); | |||||
for (int j = 0; j < m_manifold_array.size(); ++j) | |||||
{ | |||||
btPersistentManifold* CurMfold = m_manifold_array[j]; | |||||
//Normal direction differs if we're Body0 | |||||
float DirSign = CurMfold->getBody0() == m_ghost_object ? -1.f : 1.f; | |||||
for (int k = 0; k < CurMfold->getNumContacts(); k++) | |||||
{ | |||||
const btManifoldPoint& MfPoint = CurMfold->getContactPoint(k); | |||||
float Dist = MfPoint.getDistance(); | |||||
if (Dist < .0f) | |||||
{ | |||||
if (Dist < MaxPen) | |||||
{ | |||||
MaxPen = Dist; | |||||
m_touching_normal = BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign; | |||||
} | |||||
m_current_position += BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign * Dist * .2f; | |||||
HasPenetration = true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
btTransform GObjMx = m_ghost_object->getWorldTransform(); | |||||
GObjMx.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
m_ghost_object->setWorldTransform(GObjMx); | |||||
return HasPenetration; | |||||
} | } | ||||
//When the Controller hits a wall, we modify the target so the controller will MoveStep along the wall. | //When the Controller hits a wall, we modify the target so the controller will MoveStep along the wall. | ||||
void BulletKinematicCharacterController::UpdateTargetOnHit(const vec3& HitNormal, float TangentMag, float NormalMag) | void BulletKinematicCharacterController::UpdateTargetOnHit(const vec3& HitNormal, float TangentMag, float NormalMag) | ||||
{ | { | ||||
vec3 Movedir = m_target_position - m_current_position; | |||||
float MoveLength = (float)length(Movedir); | |||||
vec3 Movedir = m_target_position - m_current_position; | |||||
float MoveLength = (float)length(Movedir); | |||||
if (MoveLength > SIMD_EPSILON) | |||||
{ | |||||
Movedir = normalize(Movedir); | |||||
if (MoveLength > SIMD_EPSILON) | |||||
{ | |||||
Movedir = normalize(Movedir); | |||||
vec3 ReflectDir = normalize(GetReflectedDir(Movedir, HitNormal)); | |||||
vec3 ParallelDir = ProjectDirOnNorm(ReflectDir, HitNormal); | |||||
vec3 PerpindicularDir = ProjectDirOnNormPerpindicular(ReflectDir, HitNormal); | |||||
vec3 ReflectDir = normalize(GetReflectedDir(Movedir, HitNormal)); | |||||
vec3 ParallelDir = ProjectDirOnNorm(ReflectDir, HitNormal); | |||||
vec3 PerpindicularDir = ProjectDirOnNormPerpindicular(ReflectDir, HitNormal); | |||||
m_target_position = m_current_position; | |||||
m_target_position = m_current_position; | |||||
if (NormalMag != .0f) | |||||
m_target_position += PerpindicularDir * NormalMag * MoveLength; | |||||
} | |||||
if (NormalMag != .0f) | |||||
m_target_position += PerpindicularDir * NormalMag * MoveLength; | |||||
} | |||||
} | } | ||||
//Handles the actual Movement. It actually moves in the 3 dimensions, function name is confusing. | //Handles the actual Movement. It actually moves in the 3 dimensions, function name is confusing. | ||||
void BulletKinematicCharacterController::DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime) | void BulletKinematicCharacterController::DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime) | ||||
{ | { | ||||
// phase 2: forward and strafe | |||||
m_target_position = m_current_position + MoveStep; | |||||
btTransform SweepStart, SweepEnd; | |||||
SweepStart.setIdentity(); | |||||
SweepEnd.setIdentity(); | |||||
float Fraction = 1.f; | |||||
float SqDist = .0f; | |||||
if (m_touching_contact && dot(m_normalized_direction, m_touching_normal) > .0f) | |||||
UpdateTargetOnHit(m_touching_normal); | |||||
//Let's loop on movement, until Movement fraction if below 0.01, which means we've reached our destination. | |||||
//Or until we'tried 10 times. | |||||
int MaxMoveLoop = 10; | |||||
while (Fraction > .01f && MaxMoveLoop-- > 0) | |||||
{ | |||||
SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position)); | |||||
vec3 SweepDirNeg(m_current_position - m_target_position); | |||||
ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, SweepDirNeg, .0f); | |||||
SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; | |||||
SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; | |||||
//The sweep test is done with an added margin, so we use it and then discard it | |||||
float SavedMargin = m_convex_shape->getMargin(); | |||||
m_convex_shape->setMargin(SavedMargin + m_added_margin); //Apply Added Margin | |||||
if (m_do_gobject_sweep_test) | |||||
m_ghost_object->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); | |||||
else | |||||
CollisionWorld->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); | |||||
m_convex_shape->setMargin(SavedMargin); //Restore saved margin | |||||
Fraction -= SweepCallback.m_closestHitFraction; | |||||
if (SweepCallback.hasHit()) | |||||
{ | |||||
//We moved only a Fraction | |||||
float HitDist = (float)length(BT2LOLU_VEC3(SweepCallback.m_hitPointWorld) - m_current_position); | |||||
UpdateTargetOnHit(BT2LOL_VEC3(SweepCallback.m_hitNormalWorld)); | |||||
vec3 NewDir = m_target_position - m_current_position; | |||||
SqDist = sqlength(NewDir); | |||||
if (SqDist > SIMD_EPSILON) | |||||
{ | |||||
NewDir = normalize(NewDir); | |||||
//See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." | |||||
if (dot(NewDir, m_normalized_direction) <= .0f) | |||||
break; | |||||
} | |||||
else | |||||
break; | |||||
} | |||||
else //We moved whole way | |||||
m_current_position = m_target_position; | |||||
} | |||||
// phase 2: forward and strafe | |||||
m_target_position = m_current_position + MoveStep; | |||||
btTransform SweepStart, SweepEnd; | |||||
SweepStart.setIdentity(); | |||||
SweepEnd.setIdentity(); | |||||
float Fraction = 1.f; | |||||
float SqDist = .0f; | |||||
if (m_touching_contact && dot(m_normalized_direction, m_touching_normal) > .0f) | |||||
UpdateTargetOnHit(m_touching_normal); | |||||
//Let's loop on movement, until Movement fraction if below 0.01, which means we've reached our destination. | |||||
//Or until we'tried 10 times. | |||||
int MaxMoveLoop = 10; | |||||
while (Fraction > .01f && MaxMoveLoop-- > 0) | |||||
{ | |||||
SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position)); | |||||
vec3 SweepDirNeg(m_current_position - m_target_position); | |||||
ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, SweepDirNeg, .0f); | |||||
SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; | |||||
SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; | |||||
//The sweep test is done with an added margin, so we use it and then discard it | |||||
float SavedMargin = m_convex_shape->getMargin(); | |||||
m_convex_shape->setMargin(SavedMargin + m_added_margin); //Apply Added Margin | |||||
if (m_do_gobject_sweep_test) | |||||
m_ghost_object->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); | |||||
else | |||||
CollisionWorld->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration); | |||||
m_convex_shape->setMargin(SavedMargin); //Restore saved margin | |||||
Fraction -= SweepCallback.m_closestHitFraction; | |||||
if (SweepCallback.hasHit()) | |||||
{ | |||||
//We moved only a Fraction | |||||
float HitDist = (float)length(BT2LOLU_VEC3(SweepCallback.m_hitPointWorld) - m_current_position); | |||||
UpdateTargetOnHit(BT2LOL_VEC3(SweepCallback.m_hitNormalWorld)); | |||||
vec3 NewDir = m_target_position - m_current_position; | |||||
SqDist = sqlength(NewDir); | |||||
if (SqDist > SIMD_EPSILON) | |||||
{ | |||||
NewDir = normalize(NewDir); | |||||
//See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." | |||||
if (dot(NewDir, m_normalized_direction) <= .0f) | |||||
break; | |||||
} | |||||
else | |||||
break; | |||||
} | |||||
else //We moved whole way | |||||
m_current_position = m_target_position; | |||||
} | |||||
} | } | ||||
//The PreStepis done in order to recover from any HasPenetration. | //The PreStepis done in order to recover from any HasPenetration. | ||||
void BulletKinematicCharacterController::PreStep(btCollisionWorld* CollisionWorld) | void BulletKinematicCharacterController::PreStep(btCollisionWorld* CollisionWorld) | ||||
{ | { | ||||
int MaxPenetrationLoop = 0; | |||||
m_touching_contact = false; | |||||
while (RecoverFromPenetration(CollisionWorld)) | |||||
{ | |||||
MaxPenetrationLoop++; | |||||
m_touching_contact = true; | |||||
if (MaxPenetrationLoop > 4) | |||||
break; | |||||
} | |||||
m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); | |||||
m_target_position = m_current_position; | |||||
int MaxPenetrationLoop = 0; | |||||
m_touching_contact = false; | |||||
while (RecoverFromPenetration(CollisionWorld)) | |||||
{ | |||||
MaxPenetrationLoop++; | |||||
m_touching_contact = true; | |||||
if (MaxPenetrationLoop > 4) | |||||
break; | |||||
} | |||||
m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin()); | |||||
m_target_position = m_current_position; | |||||
} | } | ||||
//And so we step : | //And so we step : | ||||
//StepUpfirst, then movement, then StepDownon the ground. | //StepUpfirst, then movement, then StepDownon the ground. | ||||
void BulletKinematicCharacterController::PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime) | void BulletKinematicCharacterController::PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime) | ||||
{ | { | ||||
// quick check... | |||||
if (!m_use_walk_direction && m_velocity_time_interval <= .0f) | |||||
return; // no motion | |||||
// Update fall velocity. | |||||
//m_velocity -= m_gravity * DeltaTime; | |||||
btTransform NewTransform; | |||||
NewTransform = m_ghost_object->getWorldTransform(); | |||||
vec3 MoveStep(.0f); | |||||
if (m_use_walk_direction) | |||||
MoveStep = m_walk_direction; | |||||
else | |||||
{ | |||||
//Still have some time left for moving! | |||||
float dtMoving = (DeltaTime < m_velocity_time_interval) ? DeltaTime : m_velocity_time_interval; | |||||
m_velocity_time_interval -= DeltaTime; | |||||
// how far will we MoveStep while we are moving? | |||||
MoveStep = m_walk_direction * dtMoving; | |||||
} | |||||
//Okay, step ! | |||||
DoMove(CollisionWorld, MoveStep, DeltaTime); | |||||
//Movement finished, update World transform | |||||
NewTransform.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
m_ghost_object->setWorldTransform(NewTransform); | |||||
// quick check... | |||||
if (!m_use_walk_direction && m_velocity_time_interval <= .0f) | |||||
return; // no motion | |||||
// Update fall velocity. | |||||
//m_velocity -= m_gravity * DeltaTime; | |||||
btTransform NewTransform; | |||||
NewTransform = m_ghost_object->getWorldTransform(); | |||||
vec3 MoveStep(.0f); | |||||
if (m_use_walk_direction) | |||||
MoveStep = m_walk_direction; | |||||
else | |||||
{ | |||||
//Still have some time left for moving! | |||||
float dtMoving = (DeltaTime < m_velocity_time_interval) ? DeltaTime : m_velocity_time_interval; | |||||
m_velocity_time_interval -= DeltaTime; | |||||
// how far will we MoveStep while we are moving? | |||||
MoveStep = m_walk_direction * dtMoving; | |||||
} | |||||
//Okay, step ! | |||||
DoMove(CollisionWorld, MoveStep, DeltaTime); | |||||
//Movement finished, update World transform | |||||
NewTransform.setOrigin(LOL2BTU_VEC3(m_current_position)); | |||||
m_ghost_object->setWorldTransform(NewTransform); | |||||
} | } | ||||
//should MoveStep Jump logic in EasyCC | //should MoveStep Jump logic in EasyCC | ||||
void BulletKinematicCharacterController::Jump() | void BulletKinematicCharacterController::Jump() | ||||
{ | { | ||||
if (!CanJump()) | |||||
return; | |||||
if (!CanJump()) | |||||
return; | |||||
m_vertical_velocity = m_jump_speed; | |||||
m_was_jumping = true; | |||||
m_vertical_velocity = m_jump_speed; | |||||
m_was_jumping = true; | |||||
} | } | ||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||
#endif // USE_LOL_CTRLR_CHARAC | #endif // USE_LOL_CTRLR_CHARAC | ||||
} /* namespace phys */ | |||||
} /* namespace phys */ | |||||
} /* namespace lol */ | } /* namespace lol */ |
@@ -38,68 +38,68 @@ void EasyCharacterController::InitBodyToRigid(bool ZeroMassIsKinematic) | |||||
//Return correct Ghost Object | //Return correct Ghost Object | ||||
btGhostObject* EasyCharacterController::GetGhostObjectInstance() | btGhostObject* EasyCharacterController::GetGhostObjectInstance() | ||||
{ | { | ||||
return new btPairCachingGhostObject(); | |||||
return new btPairCachingGhostObject(); | |||||
} | } | ||||
//Init to Pair caching ghost object, since Character uses that one. | //Init to Pair caching ghost object, since Character uses that one. | ||||
void EasyCharacterController::InitBodyToGhost() | void EasyCharacterController::InitBodyToGhost() | ||||
{ | { | ||||
EasyPhysic::InitBodyToGhost(); | |||||
EasyPhysic::InitBodyToGhost(); | |||||
m_pair_caching_object = (btPairCachingGhostObject*)m_ghost_object; | |||||
m_ghost_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT | m_ghost_object->getCollisionFlags()); | |||||
m_pair_caching_object = (btPairCachingGhostObject*)m_ghost_object; | |||||
m_ghost_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT | m_ghost_object->getCollisionFlags()); | |||||
} | } | ||||
//Add Physic object to the simulation | //Add Physic object to the simulation | ||||
void EasyCharacterController::AddToSimulation(class Simulation* current_simulation) | void EasyCharacterController::AddToSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
EasyPhysic::AddToSimulation(current_simulation); | |||||
EasyPhysic::AddToSimulation(current_simulation); | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_character) | |||||
delete m_character; | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_character) | |||||
delete m_character; | |||||
//m_character = new btKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); | |||||
m_character = new BulletKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); | |||||
//m_character = new btKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); | |||||
m_character = new BulletKinematicCharacterController(m_pair_caching_object, m_convex_shape, m_step_height, m_up_axis); | |||||
//Deactivate Character controller basic behaviour. | |||||
//m_character->setGravity(.0f); | |||||
//m_character->setFallSpeed(.0f); | |||||
//Deactivate Character controller basic behaviour. | |||||
//m_character->setGravity(.0f); | |||||
//m_character->setFallSpeed(.0f); | |||||
dynamics_world->addAction(m_character); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_CharacterController); | |||||
Ticker::Ref(this); | |||||
} | |||||
dynamics_world->addAction(m_character); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_CharacterController); | |||||
Ticker::Ref(this); | |||||
} | |||||
} | } | ||||
//Remove Physic object to the simulation | //Remove Physic object to the simulation | ||||
void EasyCharacterController::RemoveFromSimulation(class Simulation* current_simulation) | void EasyCharacterController::RemoveFromSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
EasyPhysic::RemoveFromSimulation(current_simulation); | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_character) | |||||
{ | |||||
dynamics_world->removeAction(m_character); | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_CharacterController); | |||||
Ticker::Unref(this); | |||||
} | |||||
} | |||||
EasyPhysic::RemoveFromSimulation(current_simulation); | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_character) | |||||
{ | |||||
dynamics_world->removeAction(m_character); | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_CharacterController); | |||||
Ticker::Unref(this); | |||||
} | |||||
} | |||||
} | } | ||||
void EasyCharacterController::Jump() | void EasyCharacterController::Jump() | ||||
{ | { | ||||
m_character->Jump(); | |||||
m_character->Jump(); | |||||
} | } | ||||
//Set movement for this frame | //Set movement for this frame | ||||
void EasyCharacterController::SetMovementForFrame(vec3 const &MoveQuantity) | void EasyCharacterController::SetMovementForFrame(vec3 const &MoveQuantity) | ||||
{ | { | ||||
m_frame_cached_movement = MoveQuantity; | |||||
m_frame_cached_movement = MoveQuantity; | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -107,43 +107,43 @@ void EasyCharacterController::SetMovementForFrame(vec3 const &MoveQuantity) | |||||
//-- | //-- | ||||
void EasyCharacterController::SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation) | void EasyCharacterController::SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation) | ||||
{ | { | ||||
if (m_base_is_updating) | |||||
{ | |||||
m_base_cached_movement = base_location - m_local_to_world.v3.xyz; | |||||
m_local_to_world = lol::mat4::translate(m_local_to_world.v3.xyz) * lol::mat4(base_rotation); | |||||
if (m_ghost_object) | |||||
m_ghost_object->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * m_local_to_world.v3.xyz))); | |||||
} | |||||
else | |||||
EasyPhysic::SetTransform(base_location, base_rotation); | |||||
if (m_base_is_updating) | |||||
{ | |||||
m_base_cached_movement = base_location - m_local_to_world.v3.xyz; | |||||
m_local_to_world = lol::mat4::translate(m_local_to_world.v3.xyz) * lol::mat4(base_rotation); | |||||
if (m_ghost_object) | |||||
m_ghost_object->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * m_local_to_world.v3.xyz))); | |||||
} | |||||
else | |||||
EasyPhysic::SetTransform(base_location, base_rotation); | |||||
} | } | ||||
//Internal callback when Base transform has changed. | //Internal callback when Base transform has changed. | ||||
void EasyCharacterController::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) | void EasyCharacterController::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) | ||||
{ | { | ||||
m_base_is_updating = true; | |||||
EasyPhysic::BaseTransformChanged(PreviousMatrix, NewMatrix); | |||||
m_base_is_updating = false; | |||||
m_base_is_updating = true; | |||||
EasyPhysic::BaseTransformChanged(PreviousMatrix, NewMatrix); | |||||
m_base_is_updating = false; | |||||
} | } | ||||
//--- | //--- | ||||
char const *EasyCharacterController::GetName() | char const *EasyCharacterController::GetName() | ||||
{ | { | ||||
return "<EasyCharacterController>"; | |||||
return "<EasyCharacterController>"; | |||||
} | } | ||||
//Physic Tick | //Physic Tick | ||||
void EasyCharacterController::TickGame(float seconds) | void EasyCharacterController::TickGame(float seconds) | ||||
{ | { | ||||
Entity::TickGame(seconds); | |||||
//Send final velocity in Bullet | |||||
{ | |||||
int IterationsNb = (int)(seconds / m_owner_simulation->m_timestep); | |||||
float NewSeconds = IterationsNb * m_owner_simulation->m_timestep; | |||||
m_character->SetVelocityForTimeInterval((m_base_cached_movement + m_frame_cached_movement) / NewSeconds, NewSeconds); | |||||
m_base_cached_movement = vec3(.0f); | |||||
} | |||||
Entity::TickGame(seconds); | |||||
//Send final velocity in Bullet | |||||
{ | |||||
int IterationsNb = (int)(seconds / m_owner_simulation->m_timestep); | |||||
float NewSeconds = IterationsNb * m_owner_simulation->m_timestep; | |||||
m_character->SetVelocityForTimeInterval((m_base_cached_movement + m_frame_cached_movement) / NewSeconds, NewSeconds); | |||||
m_base_cached_movement = vec3(.0f); | |||||
} | |||||
} | } | ||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||
@@ -21,22 +21,22 @@ namespace phys | |||||
void EasyConstraint::AddToSimulation(class Simulation* current_simulation) | void EasyConstraint::AddToSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world && m_typed_constraint) | |||||
{ | |||||
dynamics_world->addConstraint(m_typed_constraint, m_disable_a2b_collision); | |||||
current_simulation->ObjectRegistration(true, this); | |||||
} | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world && m_typed_constraint) | |||||
{ | |||||
dynamics_world->addConstraint(m_typed_constraint, m_disable_a2b_collision); | |||||
current_simulation->ObjectRegistration(true, this); | |||||
} | |||||
} | } | ||||
void EasyConstraint::RemoveFromSimulation(class Simulation* current_simulation) | void EasyConstraint::RemoveFromSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world && m_typed_constraint) | |||||
{ | |||||
dynamics_world->removeConstraint(m_typed_constraint); | |||||
current_simulation->ObjectRegistration(false, this); | |||||
} | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world && m_typed_constraint) | |||||
{ | |||||
dynamics_world->removeConstraint(m_typed_constraint); | |||||
current_simulation->ObjectRegistration(false, this); | |||||
} | |||||
} | } | ||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||
@@ -29,29 +29,29 @@ namespace phys | |||||
//EASY_PHYSIC | //EASY_PHYSIC | ||||
//-- | //-- | ||||
EasyPhysic::EasyPhysic(WorldEntity* NewOwnerEntity) : | |||||
m_collision_object(NULL), | |||||
m_ghost_object(NULL), | |||||
m_rigid_body(NULL), | |||||
m_local_inertia(btVector3(.0f, .0f, .0f)), | |||||
m_collision_shape(NULL), | |||||
m_convex_shape(NULL), | |||||
m_motion_state(NULL), | |||||
m_mass(.0f), | |||||
m_collision_group(1), | |||||
m_collision_mask(1), | |||||
m_owner_entity(NewOwnerEntity), | |||||
m_owner_simulation(NULL), | |||||
m_base_physic(NULL) | |||||
EasyPhysic::EasyPhysic(WorldEntity* NewOwnerEntity) : | |||||
m_collision_object(NULL), | |||||
m_ghost_object(NULL), | |||||
m_rigid_body(NULL), | |||||
m_local_inertia(btVector3(.0f, .0f, .0f)), | |||||
m_collision_shape(NULL), | |||||
m_convex_shape(NULL), | |||||
m_motion_state(NULL), | |||||
m_mass(.0f), | |||||
m_collision_group(1), | |||||
m_collision_mask(1), | |||||
m_owner_entity(NewOwnerEntity), | |||||
m_owner_simulation(NULL), | |||||
m_base_physic(NULL) | |||||
{ | { | ||||
} | } | ||||
EasyPhysic::~EasyPhysic() | EasyPhysic::~EasyPhysic() | ||||
{ | { | ||||
m_rigid_body = NULL; | |||||
delete m_collision_object; | |||||
delete m_collision_shape; | |||||
delete m_motion_state; | |||||
m_rigid_body = NULL; | |||||
delete m_collision_object; | |||||
delete m_collision_shape; | |||||
delete m_motion_state; | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -60,55 +60,55 @@ EasyPhysic::~EasyPhysic() | |||||
void EasyPhysic::SetShapeTo(btCollisionShape* collision_shape) | void EasyPhysic::SetShapeTo(btCollisionShape* collision_shape) | ||||
{ | { | ||||
bool bReinitToRigidBody = false; | |||||
if (m_rigid_body) | |||||
{ | |||||
bReinitToRigidBody = true; | |||||
delete m_rigid_body; | |||||
} | |||||
if (m_collision_shape) | |||||
delete m_collision_shape; | |||||
m_collision_shape = collision_shape; | |||||
if (bReinitToRigidBody) | |||||
InitBodyToRigid(); | |||||
bool bReinitToRigidBody = false; | |||||
if (m_rigid_body) | |||||
{ | |||||
bReinitToRigidBody = true; | |||||
delete m_rigid_body; | |||||
} | |||||
if (m_collision_shape) | |||||
delete m_collision_shape; | |||||
m_collision_shape = collision_shape; | |||||
if (bReinitToRigidBody) | |||||
InitBodyToRigid(); | |||||
} | } | ||||
//Box Shape support | //Box Shape support | ||||
void EasyPhysic::SetShapeToBox(lol::vec3& box_size) | void EasyPhysic::SetShapeToBox(lol::vec3& box_size) | ||||
{ | { | ||||
vec3 new_box_size = box_size * LOL2BT_UNIT * LOL2BT_SIZE; | |||||
m_convex_shape = new btBoxShape(LOL2BT_VEC3(new_box_size)); | |||||
SetShapeTo(m_convex_shape); | |||||
vec3 new_box_size = box_size * LOL2BT_UNIT * LOL2BT_SIZE; | |||||
m_convex_shape = new btBoxShape(LOL2BT_VEC3(new_box_size)); | |||||
SetShapeTo(m_convex_shape); | |||||
} | } | ||||
void EasyPhysic::SetShapeToSphere(float radius) | void EasyPhysic::SetShapeToSphere(float radius) | ||||
{ | { | ||||
m_convex_shape = new btSphereShape(radius * LOL2BT_UNIT * LOL2BT_SIZE); | |||||
SetShapeTo(m_convex_shape); | |||||
m_convex_shape = new btSphereShape(radius * LOL2BT_UNIT * LOL2BT_SIZE); | |||||
SetShapeTo(m_convex_shape); | |||||
} | } | ||||
void EasyPhysic::SetShapeToCone(float radius, float height) | void EasyPhysic::SetShapeToCone(float radius, float height) | ||||
{ | { | ||||
m_convex_shape = new btConeShape( radius * LOL2BT_UNIT, | |||||
height * LOL2BT_UNIT); | |||||
SetShapeTo(m_convex_shape); | |||||
m_convex_shape = new btConeShape( radius * LOL2BT_UNIT, | |||||
height * LOL2BT_UNIT); | |||||
SetShapeTo(m_convex_shape); | |||||
} | } | ||||
void EasyPhysic::SetShapeToCylinder(lol::vec3& cyl_size) | void EasyPhysic::SetShapeToCylinder(lol::vec3& cyl_size) | ||||
{ | { | ||||
vec3 new_cyl_size = cyl_size * LOL2BT_UNIT; | |||||
new_cyl_size.y *= LOL2BT_SIZE; | |||||
m_convex_shape = new btCylinderShape(LOL2BT_VEC3(new_cyl_size)); | |||||
SetShapeTo(m_convex_shape); | |||||
vec3 new_cyl_size = cyl_size * LOL2BT_UNIT; | |||||
new_cyl_size.y *= LOL2BT_SIZE; | |||||
m_convex_shape = new btCylinderShape(LOL2BT_VEC3(new_cyl_size)); | |||||
SetShapeTo(m_convex_shape); | |||||
} | } | ||||
void EasyPhysic::SetShapeToCapsule(float radius, float height) | void EasyPhysic::SetShapeToCapsule(float radius, float height) | ||||
{ | { | ||||
m_convex_shape = new btCapsuleShape(radius * LOL2BT_UNIT * LOL2BT_SIZE, | |||||
height * LOL2BT_UNIT * LOL2BT_SIZE); | |||||
SetShapeTo(m_convex_shape); | |||||
m_convex_shape = new btCapsuleShape(radius * LOL2BT_UNIT * LOL2BT_SIZE, | |||||
height * LOL2BT_UNIT * LOL2BT_SIZE); | |||||
SetShapeTo(m_convex_shape); | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -118,57 +118,57 @@ void EasyPhysic::SetShapeToCapsule(float radius, float height) | |||||
//Getter | //Getter | ||||
mat4 EasyPhysic::GetTransform() | mat4 EasyPhysic::GetTransform() | ||||
{ | { | ||||
m_local_to_world = lol::mat4(1.0f); | |||||
if (m_rigid_body && m_motion_state) | |||||
{ | |||||
btTransform CurTransform; | |||||
m_motion_state->getWorldTransform(CurTransform); | |||||
CurTransform.getOpenGLMatrix(&m_local_to_world[0][0]); | |||||
} | |||||
else if (m_collision_object) | |||||
m_collision_object->getWorldTransform().getOpenGLMatrix(&m_local_to_world[0][0]); | |||||
return m_local_to_world; | |||||
m_local_to_world = lol::mat4(1.0f); | |||||
if (m_rigid_body && m_motion_state) | |||||
{ | |||||
btTransform CurTransform; | |||||
m_motion_state->getWorldTransform(CurTransform); | |||||
CurTransform.getOpenGLMatrix(&m_local_to_world[0][0]); | |||||
} | |||||
else if (m_collision_object) | |||||
m_collision_object->getWorldTransform().getOpenGLMatrix(&m_local_to_world[0][0]); | |||||
return m_local_to_world; | |||||
} | } | ||||
//Setter | //Setter | ||||
void EasyPhysic::SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation) | void EasyPhysic::SetTransform(const lol::vec3& base_location, const lol::quat& base_rotation) | ||||
{ | { | ||||
lol::mat4 PreviousMatrix = m_local_to_world; | |||||
m_local_to_world = lol::mat4::translate(base_location) * lol::mat4(base_rotation); | |||||
if (m_ghost_object) | |||||
m_ghost_object->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
else | |||||
{ | |||||
if (m_motion_state) | |||||
m_motion_state->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
else | |||||
m_motion_state = new btDefaultMotionState(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
} | |||||
for (int i = 0; i < m_based_physic_list.Count(); i++) | |||||
{ | |||||
if (m_based_physic_list[i]) | |||||
m_based_physic_list[i]->BaseTransformChanged(PreviousMatrix, m_local_to_world); | |||||
else | |||||
m_based_physic_list.Remove(i--); | |||||
} | |||||
lol::mat4 PreviousMatrix = m_local_to_world; | |||||
m_local_to_world = lol::mat4::translate(base_location) * lol::mat4(base_rotation); | |||||
if (m_ghost_object) | |||||
m_ghost_object->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
else | |||||
{ | |||||
if (m_motion_state) | |||||
m_motion_state->setWorldTransform(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
else | |||||
m_motion_state = new btDefaultMotionState(btTransform(LOL2BT_QUAT(base_rotation), LOL2BT_VEC3(LOL2BT_UNIT * base_location))); | |||||
} | |||||
for (int i = 0; i < m_based_physic_list.Count(); i++) | |||||
{ | |||||
if (m_based_physic_list[i]) | |||||
m_based_physic_list[i]->BaseTransformChanged(PreviousMatrix, m_local_to_world); | |||||
else | |||||
m_based_physic_list.Remove(i--); | |||||
} | |||||
} | } | ||||
//Internal callback when Base transform has changed. | //Internal callback when Base transform has changed. | ||||
void EasyPhysic::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) | void EasyPhysic::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol::mat4& NewMatrix) | ||||
{ | { | ||||
mat4 PreviousMatrixLoc = ((m_base_lock_location)?(PreviousMatrix):(lol::mat4::translate(PreviousMatrix.v3.xyz))); | |||||
mat4 PreviousMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(PreviousMatrix))):(lol::mat4(1.f))); | |||||
mat4 NewMatrixLoc = ((m_base_lock_location)?(NewMatrix):(lol::mat4::translate(NewMatrix.v3.xyz))); | |||||
mat4 NewMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(NewMatrix))):(lol::mat4(1.f))); | |||||
if (m_ghost_object || (m_rigid_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT)) | |||||
{ | |||||
mat4 ThisMatrixLoc = NewMatrixLoc * inverse(PreviousMatrixLoc) * lol::mat4::translate(m_local_to_world.v3.xyz); | |||||
mat4 ThisMatrixRot = NewMatrixRot * inverse(PreviousMatrixRot) * lol::mat4(lol::quat(m_local_to_world)); | |||||
SetTransform(ThisMatrixLoc.v3.xyz, lol::mat4(lol::quat(ThisMatrixRot))); | |||||
} | |||||
mat4 PreviousMatrixLoc = ((m_base_lock_location)?(PreviousMatrix):(lol::mat4::translate(PreviousMatrix.v3.xyz))); | |||||
mat4 PreviousMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(PreviousMatrix))):(lol::mat4(1.f))); | |||||
mat4 NewMatrixLoc = ((m_base_lock_location)?(NewMatrix):(lol::mat4::translate(NewMatrix.v3.xyz))); | |||||
mat4 NewMatrixRot = ((m_base_lock_rotation)?(lol::mat4(lol::quat(NewMatrix))):(lol::mat4(1.f))); | |||||
if (m_ghost_object || (m_rigid_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT)) | |||||
{ | |||||
mat4 ThisMatrixLoc = NewMatrixLoc * inverse(PreviousMatrixLoc) * lol::mat4::translate(m_local_to_world.v3.xyz); | |||||
mat4 ThisMatrixRot = NewMatrixRot * inverse(PreviousMatrixRot) * lol::mat4(lol::quat(m_local_to_world)); | |||||
SetTransform(ThisMatrixLoc.v3.xyz, lol::mat4(lol::quat(ThisMatrixRot))); | |||||
} | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -177,13 +177,13 @@ void EasyPhysic::BaseTransformChanged(const lol::mat4& PreviousMatrix, const lol | |||||
//Set Shape functions | //Set Shape functions | ||||
void EasyPhysic::SetMass(float mass) | void EasyPhysic::SetMass(float mass) | ||||
{ | { | ||||
m_mass = mass; | |||||
m_mass = mass; | |||||
if (m_rigid_body) | |||||
{ | |||||
SetLocalInertia(m_mass); | |||||
m_rigid_body->setMassProps(mass, m_local_inertia); | |||||
} | |||||
if (m_rigid_body) | |||||
{ | |||||
SetLocalInertia(m_mass); | |||||
m_rigid_body->setMassProps(mass, m_local_inertia); | |||||
} | |||||
} | } | ||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
@@ -193,49 +193,49 @@ void EasyPhysic::SetMass(float mass) | |||||
//Init to rigid body | //Init to rigid body | ||||
void EasyPhysic::InitBodyToRigid(bool SetToKinematic) | void EasyPhysic::InitBodyToRigid(bool SetToKinematic) | ||||
{ | { | ||||
if (m_collision_object) | |||||
delete m_collision_object; | |||||
if (!m_motion_state) | |||||
SetTransform(vec3(.0f)); | |||||
btRigidBody::btRigidBodyConstructionInfo NewInfos(m_mass, m_motion_state, m_collision_shape, m_local_inertia); | |||||
m_rigid_body = new btRigidBody(NewInfos); | |||||
m_collision_object = m_rigid_body; | |||||
m_collision_object->setUserPointer(this); | |||||
if (m_mass == .0f) | |||||
{ | |||||
if (SetToKinematic) | |||||
{ | |||||
m_rigid_body->setActivationState(DISABLE_DEACTIVATION); | |||||
m_rigid_body->setCollisionFlags(m_rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); | |||||
} | |||||
} | |||||
else | |||||
SetMass(m_mass); | |||||
if (m_collision_object) | |||||
delete m_collision_object; | |||||
if (!m_motion_state) | |||||
SetTransform(vec3(.0f)); | |||||
btRigidBody::btRigidBodyConstructionInfo NewInfos(m_mass, m_motion_state, m_collision_shape, m_local_inertia); | |||||
m_rigid_body = new btRigidBody(NewInfos); | |||||
m_collision_object = m_rigid_body; | |||||
m_collision_object->setUserPointer(this); | |||||
if (m_mass == .0f) | |||||
{ | |||||
if (SetToKinematic) | |||||
{ | |||||
m_rigid_body->setActivationState(DISABLE_DEACTIVATION); | |||||
m_rigid_body->setCollisionFlags(m_rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); | |||||
} | |||||
} | |||||
else | |||||
SetMass(m_mass); | |||||
} | } | ||||
//Return correct Ghost Object | //Return correct Ghost Object | ||||
btGhostObject* EasyPhysic::GetGhostObjectInstance() | btGhostObject* EasyPhysic::GetGhostObjectInstance() | ||||
{ | { | ||||
return new btGhostObject(); | |||||
return new btGhostObject(); | |||||
} | } | ||||
//Init to Ghost object, for Overlap/Sweep Test/Touching logic | //Init to Ghost object, for Overlap/Sweep Test/Touching logic | ||||
void EasyPhysic::InitBodyToGhost() | void EasyPhysic::InitBodyToGhost() | ||||
{ | { | ||||
if (m_collision_object) | |||||
delete m_collision_object; | |||||
if (m_collision_object) | |||||
delete m_collision_object; | |||||
m_ghost_object = GetGhostObjectInstance(); | |||||
m_ghost_object->setCollisionShape(m_collision_shape); | |||||
m_collision_object = m_ghost_object; | |||||
m_collision_object->setUserPointer(this); | |||||
m_ghost_object = GetGhostObjectInstance(); | |||||
m_ghost_object->setCollisionShape(m_collision_shape); | |||||
m_collision_object = m_ghost_object; | |||||
m_collision_object->setUserPointer(this); | |||||
SetTransform(m_local_to_world.v3.xyz, lol::quat(m_local_to_world)); | |||||
SetTransform(m_local_to_world.v3.xyz, lol::quat(m_local_to_world)); | |||||
m_ghost_object->setCollisionFlags(m_ghost_object->getCollisionFlags()); | |||||
m_ghost_object->setCollisionFlags(m_ghost_object->getCollisionFlags()); | |||||
} | } | ||||
//------------- | //------------- | ||||
@@ -250,7 +250,7 @@ void EasyPhysic::InitBodyToGhost() | |||||
// manifoldArray.clear(); | // manifoldArray.clear(); | ||||
// const btBroadphasePair& pair = pairArray[i]; | // const btBroadphasePair& pair = pairArray[i]; | ||||
// | |||||
// | |||||
// //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: | // //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: | ||||
// btBroadphasePair* collisionPair = dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1); | // btBroadphasePair* collisionPair = dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1); | ||||
// if (!collisionPair) | // if (!collisionPair) | ||||
@@ -265,14 +265,14 @@ void EasyPhysic::InitBodyToGhost() | |||||
// btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); | // btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); | ||||
// for (int p=0;p<manifold->getNumContacts();p++) | // for (int p=0;p<manifold->getNumContacts();p++) | ||||
// { | // { | ||||
// const btManifoldPoint&pt = manifold->getContactPoint(p); | |||||
// const btManifoldPoint&pt = manifold->getContactPoint(p); | |||||
// if (pt.getDistance()<0.f) | // if (pt.getDistance()<0.f) | ||||
//{ | |||||
// const btVector3& ptA = pt.getPositionWorldOnA(); | |||||
// const btVector3& ptB = pt.getPositionWorldOnB(); | |||||
// const btVector3& normalOnB = pt.m_normalWorldOnB; | |||||
// /// work here | |||||
//} | |||||
//{ | |||||
// const btVector3& ptA = pt.getPositionWorldOnA(); | |||||
// const btVector3& ptB = pt.getPositionWorldOnB(); | |||||
// const btVector3& normalOnB = pt.m_normalWorldOnB; | |||||
// /// work here | |||||
//} | |||||
// } | // } | ||||
// } | // } | ||||
// } | // } | ||||
@@ -281,61 +281,61 @@ void EasyPhysic::InitBodyToGhost() | |||||
//Add Physic object to the simulation | //Add Physic object to the simulation | ||||
void EasyPhysic::AddToSimulation(class Simulation* current_simulation) | void EasyPhysic::AddToSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_ghost_object) | |||||
{ | |||||
dynamics_world->addCollisionObject(m_ghost_object, m_collision_group, m_collision_mask); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Ghost); | |||||
} | |||||
else if (m_rigid_body) | |||||
{ | |||||
dynamics_world->addRigidBody(m_rigid_body, m_collision_group, m_collision_mask); | |||||
if (m_mass != .0f) | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Dynamic); | |||||
else | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Static); | |||||
} | |||||
else | |||||
{ | |||||
dynamics_world->addCollisionObject(m_collision_object, m_collision_group, m_collision_mask); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_CollisionObject); | |||||
} | |||||
} | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_ghost_object) | |||||
{ | |||||
dynamics_world->addCollisionObject(m_ghost_object, m_collision_group, m_collision_mask); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Ghost); | |||||
} | |||||
else if (m_rigid_body) | |||||
{ | |||||
dynamics_world->addRigidBody(m_rigid_body, m_collision_group, m_collision_mask); | |||||
if (m_mass != .0f) | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Dynamic); | |||||
else | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_Static); | |||||
} | |||||
else | |||||
{ | |||||
dynamics_world->addCollisionObject(m_collision_object, m_collision_group, m_collision_mask); | |||||
current_simulation->ObjectRegistration(true, this, Simulation::EEPT_CollisionObject); | |||||
} | |||||
} | |||||
} | } | ||||
//Remove Physic object to the simulation | //Remove Physic object to the simulation | ||||
void EasyPhysic::RemoveFromSimulation(class Simulation* current_simulation) | void EasyPhysic::RemoveFromSimulation(class Simulation* current_simulation) | ||||
{ | { | ||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_rigid_body) | |||||
{ | |||||
dynamics_world->removeRigidBody(m_rigid_body); | |||||
if (m_mass != .0f) | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Dynamic); | |||||
else | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Static); | |||||
} | |||||
else | |||||
{ | |||||
dynamics_world->removeCollisionObject(m_collision_object); | |||||
if (m_ghost_object) | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Ghost); | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_CollisionObject); | |||||
} | |||||
} | |||||
btDiscreteDynamicsWorld* dynamics_world = current_simulation->GetWorld(); | |||||
if (dynamics_world) | |||||
{ | |||||
if (m_rigid_body) | |||||
{ | |||||
dynamics_world->removeRigidBody(m_rigid_body); | |||||
if (m_mass != .0f) | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Dynamic); | |||||
else | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Static); | |||||
} | |||||
else | |||||
{ | |||||
dynamics_world->removeCollisionObject(m_collision_object); | |||||
if (m_ghost_object) | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_Ghost); | |||||
current_simulation->ObjectRegistration(false, this, Simulation::EEPT_CollisionObject); | |||||
} | |||||
} | |||||
} | } | ||||
//Set Local Inertia | //Set Local Inertia | ||||
void EasyPhysic::SetLocalInertia(float mass) | void EasyPhysic::SetLocalInertia(float mass) | ||||
{ | { | ||||
if (mass != .0f) | |||||
m_collision_shape->calculateLocalInertia(mass, m_local_inertia); | |||||
else | |||||
m_local_inertia = btVector3(.0f, .0f, .0f); | |||||
if (mass != .0f) | |||||
m_collision_shape->calculateLocalInertia(mass, m_local_inertia); | |||||
else | |||||
m_local_inertia = btVector3(.0f, .0f, .0f); | |||||
} | } | ||||
#endif // HAVE_PHYS_USE_BULLET | #endif // HAVE_PHYS_USE_BULLET | ||||