Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Physics/bulletobject.cpp')
-rw-r--r--Source/Physics/bulletobject.cpp588
1 files changed, 588 insertions, 0 deletions
diff --git a/Source/Physics/bulletobject.cpp b/Source/Physics/bulletobject.cpp
new file mode 100644
index 00000000..33a9bdf0
--- /dev/null
+++ b/Source/Physics/bulletobject.cpp
@@ -0,0 +1,588 @@
+//-----------------------------------------------------------------------------
+// Name: bulletobject.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include <Physics/bulletobject.h>
+#include <Physics/physics.h>
+
+#include <Math/vec3math.h>
+#include <Math/vec4math.h>
+#include <Math/quaternions.h>
+
+#include <Graphics/geometry.h>
+#include <Graphics/graphics.h>
+
+#include <Internal/timer.h>
+#include <LinearMath/btTransformUtil.h>
+#include <Objects/object.h>
+#include <Logging/logdata.h>
+#include <Utility/assert.h>
+
+#include <btBulletDynamicsCommon.h>
+
+extern Timer game_timer;
+
+mat4 SafeGetOpenGLMatrix(const btTransform& bt_transform) {
+ // Make sure that transform mat4 is 16-byte aligned
+ // since Bullet may be reading to it from SSE intrinsics
+ char aligned_mem[sizeof(mat4)+16];
+ uintptr_t first = ((uintptr_t)aligned_mem)%16;
+ mat4* mat = (mat4*)&aligned_mem[16-first];
+ bt_transform.getOpenGLMatrix(mat->entries);
+ return *mat;
+}
+
+void ValidateTransform(const btTransform &bt_transform) {
+ /*const btMatrix3x3& basis = bt_transform.getBasis();
+ for(int i=0; i<3; ++i){
+ const btVector3& row = basis[i];
+ for(int j=0; j<3; ++j){
+ const btScalar &val = row[j];
+ if(val != val){
+ DisplayError("Error", "Invalid transform!");
+ }
+ }
+ }
+ const btVector3& origin = bt_transform.getOrigin();
+ for(int j=0; j<3; ++j){
+ const btScalar &val = origin[j];
+ if(val != val){
+ DisplayError("Error", "Invalid transform!");
+ }
+ }*/
+}
+
+void BulletObject::SetPosition( const vec3 &position) {
+ btTransform bt_transform = body->getWorldTransform();
+ vec3 new_pos = position + GetRotation() * com_offset;
+ bt_transform.setOrigin(btVector3(new_pos[0],
+ new_pos[1],
+ new_pos[2]));
+ ValidateTransform(bt_transform);
+ body->setWorldTransform(bt_transform);
+}
+
+void BulletObject::SetMargin( float _margin ) {
+ shape->setMargin(_margin);
+}
+
+float BulletObject::GetMargin( ) {
+ return shape->getMargin();
+}
+
+void BulletObject::SetRotation( const mat4 &rotation) {
+ btVector3 old_origin = body->getWorldTransform().getOrigin();
+ btTransform new_transform;
+ new_transform.setFromOpenGLMatrix(rotation.entries);
+ new_transform.setOrigin(old_origin);
+ ValidateTransform(new_transform);
+ body->setWorldTransform(new_transform);
+}
+
+void BulletObject::SetRotation( const quaternion &rotation) {
+ btVector3 old_origin = body->getWorldTransform().getOrigin();
+ btTransform new_transform;
+ new_transform.setRotation(btQuaternion(rotation.entries[0],rotation.entries[1],rotation.entries[2],rotation.entries[3]));
+ new_transform.setOrigin(old_origin);
+ ValidateTransform(new_transform);
+ body->setWorldTransform(new_transform);
+}
+
+void BulletObject::SetPositionAndVel( const vec3 &position, int frames) {
+ vec3 vel = (position - GetPosition())/game_timer.timestep;
+ vel /= (float)frames;
+ //SetPosition(position);
+ SetLinearVelocity(vel);
+}
+
+void BulletObject::SetRotationAndVel( const mat4 &rotation, int frames) {
+ btVector3 old_origin = body->getWorldTransform().getOrigin();
+ btTransform new_transform;
+ new_transform.setFromOpenGLMatrix(rotation.entries);
+ new_transform.setOrigin(old_origin);
+
+ btVector3 axis;
+ btScalar angle;
+ btTransformUtil::calculateDiffAxisAngle(body->getWorldTransform(),
+ new_transform,
+ axis,
+ angle);
+ btVector3 angVel = axis * angle / game_timer.timestep;
+ angVel /= (float)frames;
+
+ body->setAngularVelocity(angVel);
+
+ //body->setWorldTransform(new_transform);
+}
+
+void BulletObject::SetRotationAndVel( const quaternion &rotation, int frames) {
+ btVector3 old_origin = body->getWorldTransform().getOrigin();
+ btTransform new_transform;
+ new_transform.setRotation(btQuaternion(rotation.entries[0], rotation.entries[1], rotation.entries[2], rotation.entries[3]));
+ new_transform.setOrigin(old_origin);
+
+ btVector3 axis;
+ btScalar angle;
+ btTransformUtil::calculateDiffAxisAngle(body->getWorldTransform(),
+ new_transform,
+ axis,
+ angle);
+ btVector3 angVel = axis * angle / game_timer.timestep;
+ angVel /= (float)frames;
+
+ body->setAngularVelocity(angVel);
+
+ //body->setWorldTransform(new_transform);
+}
+
+
+void BulletObject::SetTransform( const vec4 &position, const mat4 &rotation, const vec4 &scale ) {
+ btTransform bt_transform;
+ bt_transform.setIdentity();
+ bt_transform.setFromOpenGLMatrix((btScalar*)rotation.entries);
+ vec3 new_pos = position.xyz() + GetRotation() * com_offset;
+ bt_transform.setOrigin(btVector3(new_pos[0],
+ new_pos[1],
+ new_pos[2]));
+ shape->setLocalScaling(btVector3(scale[0],
+ scale[1],
+ scale[2]));
+ ValidateTransform(bt_transform);
+ body->setWorldTransform(bt_transform);
+}
+
+void BulletObject::SetTransform( const mat4 &transform ) {
+ btTransform bt_transform;
+ bt_transform.setFromOpenGLMatrix((btScalar*)transform.entries);
+ ValidateTransform(bt_transform);
+ body->setWorldTransform(bt_transform);
+}
+
+void BulletObject::ApplyTransform( const mat4& transform ) {
+ mat4 old_transform_mat4 = SafeGetOpenGLMatrix(body->getWorldTransform());
+ old_transform_mat4 = transform * old_transform_mat4;
+ btTransform new_transform;
+ new_transform.setFromOpenGLMatrix(old_transform_mat4.entries);
+ ValidateTransform(new_transform);
+ body->setWorldTransform(new_transform);
+
+}
+
+void BulletObject::SetGravity( bool gravity ) {
+ if(!gravity){
+ body->setGravity(btVector3(0.0f,0.0f,0.0f));
+ } else {
+ const vec3& grav = Physics::Instance()->gravity;
+ body->setGravity(btVector3(grav[0],grav[1],grav[2]));
+ }
+}
+
+vec3 BulletObject::GetVelocityAtLocalPoint(const vec3& point) {
+ btVector3 vel = body->getVelocityInLocalPoint(
+ btVector3(point[0], point[1], point[2]));
+ return vec3(vel[0], vel[1], vel[2]);
+}
+
+void BulletObject::SetDamping( float damping ) {
+ body->setDamping(damping,damping);
+}
+
+void BulletObject::SetDamping( float lin_damping, float ang_damping ) {
+ body->setDamping(lin_damping,ang_damping);
+}
+
+
+vec3 BulletObject::GetInterpPosition() {
+ return mix(old_transform.GetTranslationPart(),
+ transform.GetTranslationPart(),
+ game_timer.GetInterpWeight());
+}
+
+mat4 BulletObject::GetInterpRotation() {
+ return mix(old_transform.GetRotationPart(),
+ transform.GetRotationPart(),
+ game_timer.GetInterpWeight());
+}
+
+vec3 BulletObject::GetInterpWeightPosition(float weight) {
+ return mix(old_transform.GetTranslationPart(),
+ transform.GetTranslationPart(),
+ weight);
+}
+
+mat4 BulletObject::GetInterpWeightRotation(float weight) {
+ return mix(old_transform.GetRotationPart(),
+ transform.GetRotationPart(),
+ weight);
+}
+
+vec3 BulletObject::GetInterpPositionX( int num, int progress ) {
+ return mix(old_transform.GetTranslationPart(),
+ transform.GetTranslationPart(),
+ game_timer.GetInterpWeightX(num, progress));
+}
+
+mat4 BulletObject::GetInterpRotationX( int num, int progress ) {
+ return mix(old_transform.GetRotationPart(),
+ transform.GetRotationPart(),
+ game_timer.GetInterpWeightX(num, progress));
+}
+
+
+vec3 BulletObject::GetHistoryInterpPositionX( int num, int progress, float offset ) {
+ float t_e = game_timer.timestep_error - offset;
+ float mult = (1.0f/(float)num);
+ float temp_timestep_error = mult*(float)progress + t_e*mult;
+ unsigned base = 0;
+ while(temp_timestep_error < 0){
+ ++base;
+ temp_timestep_error += 1.0f;
+ }
+ if(base+1>=transform_history.size()){
+ transform_history.resize(base+2, transform_history.back());
+ }
+ return transform_history[base].GetTranslationPart()*temp_timestep_error+transform_history[base+1].GetTranslationPart()*(1.0f-temp_timestep_error);
+}
+
+mat4 BulletObject::GetHistoryInterpRotationX( int num, int progress, float offset ) {
+ float t_e = game_timer.timestep_error - offset;
+ float mult = (1.0f/(float)num);
+ float temp_timestep_error = mult*(float)progress + t_e*mult;
+ unsigned base = 0;
+ while(temp_timestep_error < 0){
+ ++base;
+ temp_timestep_error += 1.0f;
+ }
+ if(base+1>=transform_history.size()){
+ transform_history.resize(base+2, transform_history.back());
+ }
+ return transform_history[base].GetRotationPart()*temp_timestep_error+transform_history[base+1].GetRotationPart()*(1.0f-temp_timestep_error);
+}
+
+void BulletObject::ClearVelocities() {
+ body->setLinearVelocity(btVector3(0.0f,0.0f,0.0f));
+ body->setAngularVelocity(btVector3(0.0f,0.0f,0.0f));
+}
+
+void BulletObject::SetAngularVelocity( const vec3& vel ) {
+ body->setAngularVelocity(btVector3(vel[0],vel[1],vel[2]));
+}
+
+void BulletObject::SetLinearVelocity( const vec3& vel ) {
+ body->setLinearVelocity(btVector3(vel[0],vel[1],vel[2]));
+}
+
+void BulletObject::AddAngularVelocity( const vec3& vel ) {
+ body->setAngularVelocity(body->getAngularVelocity() +
+ btVector3(vel[0],vel[1],vel[2]));
+}
+
+void BulletObject::AddLinearVelocity( const vec3& vel ) {
+ body->setLinearVelocity(body->getLinearVelocity() +
+ btVector3(vel[0],vel[1],vel[2]));
+}
+
+vec3 BulletObject::GetPosition() const {
+ btVector3 bt_origin = body->getWorldTransform().getOrigin();
+ vec3 com_display_offset = GetRotation() * -com_offset;
+ return vec3(bt_origin[0],bt_origin[1],bt_origin[2])+com_display_offset;
+}
+
+float BulletObject::GetMass() {
+ return 1.0f/body->getInvMass();
+}
+
+
+vec3 BulletObject::GetLinearVelocity() const {
+ btVector3 vec = body->getLinearVelocity();
+ return vec3(vec[0],vec[1],vec[2]);
+}
+
+mat4 BulletObject::GetRotation() const {
+ mat4 rotation = SafeGetOpenGLMatrix(body->getWorldTransform());
+ return rotation.GetRotationPart();
+}
+
+mat4 BulletObject::GetTransform() const {
+ return SafeGetOpenGLMatrix(body->getWorldTransform());
+}
+
+quaternion BulletObject::GetQuatRotation() {
+ btQuaternion quat = body->getWorldTransform().getRotation();
+ return quaternion(vec4(quat.getX(), quat.getY(), quat.getZ(), quat.getW()));
+}
+
+vec3 BulletObject::ObjectToWorld( const vec3 &point ) {
+ transform = SafeGetOpenGLMatrix(body->getWorldTransform());
+ return transform*point;
+}
+
+void BulletObject::ApplyForceAtWorldPoint( const vec3 &point, const vec3 &impulse ) {
+ vec3 local_point = WorldToObject(point);
+ body->applyForce(btVector3(impulse[0], impulse[1], impulse[2]),
+ btVector3(local_point[0], local_point[1], local_point[2]));
+ body->activate();
+}
+
+vec3 BulletObject::WorldToObject(const vec3 &world_point) {
+ transform = SafeGetOpenGLMatrix(body->getWorldTransform());
+ return invert(transform) * world_point;
+}
+
+void BulletObject::SetVisibility( const bool _visible ) {
+ visible = _visible;
+}
+
+bool BulletObject::IsVisible() const {
+ return visible;
+}
+
+void BulletObject::Activate() {
+ body->activate();
+}
+
+void BulletObject::Freeze() {
+ body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT |
+ btCollisionObject::CF_NO_CONTACT_RESPONSE);
+ body->setActivationState(ISLAND_SLEEPING);
+}
+
+
+void BulletObject::Sleep() {
+ body->setActivationState(ISLAND_SLEEPING);
+}
+
+void BulletObject::NoSleep() {
+ body->setActivationState(DISABLE_DEACTIVATION);
+}
+
+void BulletObject::CanSleep() {
+ body->forceActivationState(ACTIVE_TAG);
+ body->activate(true);
+}
+
+void BulletObject::UnFreeze() {
+ body->setCollisionFlags(0);
+ body->activate();
+}
+
+void BulletObject::FixDiscontinuity() {
+ btTransform bt_transform;
+ GetDisplayTransform(&bt_transform);
+ transform = SafeGetOpenGLMatrix(bt_transform);
+ old_transform = transform;
+}
+
+void BulletObject::Dispose() {
+ if(body->getMotionState()){
+ delete body->getMotionState();
+ }
+ delete body;
+ body = NULL;
+ shape.reset();
+}
+
+void BulletObject::SetShape(SharedShapePtr _shape) {
+ shape = _shape;
+ body->setCollisionShape(shape.get());
+}
+
+BulletObject::BulletObject():
+ body(NULL),
+ com_offset(0.0f),
+ owner_object(NULL),
+ color(1.0f),
+ keep_history(false)
+{}
+
+BulletObject::~BulletObject() {
+ LOG_ASSERT(body == NULL);
+ // These should be NULL if Dispose() was called correctly
+}
+
+void BulletObject::CopyObjectTransform( const BulletObject* other ) {
+ //btTransform transform = other->body->getWorldTransform();
+ //transform.setOrigin(transform.getOrigin()*0.5f);
+ //body->setWorldTransform(transform);
+ ValidateTransform(other->body->getWorldTransform());
+ body->setWorldTransform(other->body->getWorldTransform());
+}
+
+
+void BulletObject::MixObjectTransform( const BulletObject* other,
+ float how_much )
+{
+ const btTransform &other_transform = other->body->getWorldTransform();
+ btTransform this_transform = body->getWorldTransform();
+ /*
+ btQuaternion q1 = this_transform.getRotation();
+ btQuaternion q2 = other_transform.getRotation();
+ */
+ btQuaternion result = slerp(this_transform.getRotation(),
+ other_transform.getRotation(),
+ how_much);
+ if(result[0] != result[0]){
+ /*
+ btQuaternion result = slerp(this_transform.getRotation(),
+ other_transform.getRotation(),
+ how_much);
+ */
+ return;
+ }
+ this_transform.setRotation(result);
+ this_transform.setOrigin(lerp(this_transform.getOrigin(),
+ other_transform.getOrigin(),
+ how_much));
+ ValidateTransform(this_transform);
+ body->setWorldTransform(this_transform);
+}
+
+void BulletObject::MixObjectVel( const BulletObject* other,
+ float how_much )
+{
+ const btVector3 &other_lin_vel = other->body->getLinearVelocity();
+ const btVector3 &other_ang_vel = other->body->getAngularVelocity();
+ const btVector3 &this_lin_vel = body->getLinearVelocity();
+ const btVector3 &this_ang_vel = body->getAngularVelocity();
+
+ body->setLinearVelocity(this_lin_vel * (1.0f - how_much) + other_lin_vel * how_much);
+ body->setAngularVelocity(this_ang_vel * (1.0f - how_much) + other_ang_vel * how_much);
+}
+
+
+void BulletObject::CopyObjectVel( const BulletObject* other ) {
+ body->setLinearVelocity(other->body->getLinearVelocity());
+ body->setAngularVelocity(other->body->getAngularVelocity());
+}
+
+
+void BulletObject::GetDisplayTransform(btTransform* display_transform) {
+ (*display_transform) = body->getWorldTransform();
+ btVector3 scale = shape->getLocalScaling();
+ scale[0] = fabs(scale[0]);
+ scale[1] = fabs(scale[1]);
+ scale[2] = fabs(scale[2]);
+ vec3 com_display_offset = GetRotation() * -com_offset;
+ display_transform->setOrigin(display_transform->getOrigin() +
+ btVector3(com_display_offset[0],
+ com_display_offset[1],
+ com_display_offset[2]));
+ /*btMatrix3x3 basis = display_transform->getBasis();
+ basis[0] *= scale[0];
+ basis[4] *= scale[1];
+ basis[8] *= scale[2];
+ display_transform->setBasis(basis);*/
+ display_transform->setBasis(display_transform->getBasis().scaled(scale));
+}
+
+vec3 BulletObject::GetAngularVelocity() const {
+ btVector3 vec = body->getAngularVelocity();
+ return vec3(vec[0],vec[1],vec[2]);
+}
+
+void BulletObject::ApplyTorque( const vec3 &torque ) {
+ btVector3 bt_torque(torque[0], torque[1], torque[2]);
+ body->applyTorque(bt_torque);
+}
+
+void BulletObject::UpdateTransform() {
+ btTransform bt_transform;
+ GetDisplayTransform(&bt_transform);
+ old_transform = transform;
+ transform = SafeGetOpenGLMatrix(bt_transform);
+ if(keep_history){
+ if(transform_history.empty()){
+ transform_history.resize(1);
+ }
+ const size_t _history_size = transform_history.size();
+ for(size_t i=0; i<_history_size-1; ++i){
+ transform_history[_history_size-1-i] = transform_history[_history_size-2-i];
+ }
+ transform_history[0] = transform;
+ }
+}
+
+void BulletObject::CheckForNAN() {
+ btTransform bt_transform;
+ GetDisplayTransform(&bt_transform);
+ mat4 test_mat = SafeGetOpenGLMatrix(body->getWorldTransform());
+ for(unsigned i=0; i<16; ++i){
+ if(test_mat.entries[i] != test_mat.entries[i]){
+ LOGE << "NAN found in BulletObject" << std::endl;
+ break;
+ }
+ }
+ btMatrix3x3 mat = bt_transform.getBasis().inverse();
+ if(mat.getColumn(0)[0] != mat.getColumn(0)[0]){
+ LOGE << "NAN found in BulletObject" << std::endl;
+ }
+ const btVector3& vel = body->getLinearVelocity();
+ for(unsigned i=0; i<3; ++i){
+ if(vel[i] != vel[i]){
+ LOGE << "NAN found in BulletObject" << std::endl;
+ break;
+ }
+ }
+ const btVector3& vel2 = body->getAngularVelocity();
+ for(unsigned i=0; i<3; ++i){
+ if(vel2[i] != vel2[i]){
+ LOGE << "NAN found in BulletObject" << std::endl;
+ break;
+ }
+ }
+}
+
+float BulletObject::GetMomentOfInertia( const vec3& axis ) {
+ btVector3 bt_axis(axis[0], axis[1], axis[2]);
+ //bt_axis = quatRotate(body->getWorldTransform().getRotation().inverse(),bt_axis);
+ return 1.0f/((body->getInvInertiaTensorWorld() * bt_axis * body->getAngularFactor()).dot(bt_axis));
+}
+
+bool BulletObject::IsActive() {
+ int activation_state = body->getActivationState();
+ return (activation_state==ACTIVE_TAG || activation_state==DISABLE_DEACTIVATION);
+}
+
+void BulletObject::Collided( const vec3& pos, float impulse, const CollideInfo &collide_info ) {
+ if(owner_object){
+ owner_object->Collided(pos, impulse, collide_info, this);
+ }
+}
+
+void BulletObject::SetMass( float mass ) {
+ btVector3 inv_inertia = body->getInvInertiaDiagLocal();
+ inv_inertia[0] = 1.0f / inv_inertia[0];
+ inv_inertia[1] = 1.0f / inv_inertia[1];
+ inv_inertia[2] = 1.0f / inv_inertia[2];
+ body->setMassProps(mass, inv_inertia);
+ const vec3& grav = Physics::Instance()->gravity;
+ body->setGravity(btVector3(grav[0],grav[1],grav[2]));
+}
+
+ShapeDisposalData::ShapeDisposalData():
+ index_vert_array(NULL),
+ triangle_info_map(NULL)
+{}
+
+ShapeDisposalData::~ShapeDisposalData() {
+ delete index_vert_array;
+ delete triangle_info_map;
+}