diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/rigidbody/CMakeLists.txt | 36 | ||||
-rw-r--r-- | source/blender/rigidbody/RBI_api.h | 309 | ||||
-rw-r--r-- | source/blender/rigidbody/SConscript | 38 | ||||
-rw-r--r-- | source/blender/rigidbody/rb_bullet_api.cpp | 948 | ||||
-rw-r--r-- | source/blenderplayer/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/creator/CMakeLists.txt | 1 |
7 files changed, 1334 insertions, 0 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index ae3f3dce396..9c6dd0235c5 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -105,6 +105,7 @@ add_subdirectory(nodes) add_subdirectory(modifiers) add_subdirectory(makesdna) add_subdirectory(makesrna) +add_subdirectory(rigidbody) if(WITH_COMPOSITOR) add_subdirectory(opencl) # later on this may be used more generally diff --git a/source/blender/rigidbody/CMakeLists.txt b/source/blender/rigidbody/CMakeLists.txt new file mode 100644 index 00000000000..cf91cd6638c --- /dev/null +++ b/source/blender/rigidbody/CMakeLists.txt @@ -0,0 +1,36 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# ***** END GPL LICENSE BLOCK ***** + +SET(INC + . + ../blenlib + ../../../extern/bullet2/src +) + +set(SRC + rb_bullet_api.cpp + + RBI_api.h +) + +blender_add_lib(bf_rigidbody "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/rigidbody/RBI_api.h b/source/blender/rigidbody/RBI_api.h new file mode 100644 index 00000000000..ee5006f2838 --- /dev/null +++ b/source/blender/rigidbody/RBI_api.h @@ -0,0 +1,309 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation, + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RBI_api.h + * \ingroup RigidBody + * \brief Rigid Body API for interfacing with external Physics Engines + */ + +#ifndef __RB_API_H__ +#define __RB_API_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* API Notes: + * Currently, this API is optimised for Bullet RigidBodies, and doesn't + * take into account other Physics Engines. Some tweaking may be necessary + * to allow other systems to be used, in particular there may be references + * to datatypes that aren't used here... + * + * -- Joshua Leung (22 June 2010) + */ + +/* ********************************** */ +/* Partial Type Defines - Aliases for the type of data we store */ + +// ---------- + +/* Dynamics World */ +typedef struct rbDynamicsWorld rbDynamicsWorld; + +/* Rigid Body */ +typedef struct rbRigidBody rbRigidBody; + +/* Collision Shape */ +typedef struct rbCollisionShape rbCollisionShape; + +/* Mesh Data (for Collision Shapes of Meshes) */ +typedef struct rbMeshData rbMeshData; + +/* Constraint */ +typedef struct rbConstraint rbConstraint; + +/* ********************************** */ +/* Dynamics World Methods */ + +/* Setup ---------------------------- */ + +/* Create a new dynamics world instance */ +// TODO: add args to set the type of constraint solvers, etc. +extern rbDynamicsWorld *RB_dworld_new(const float gravity[3]); + +/* Delete the given dynamics world, and free any extra data it may require */ +extern void RB_dworld_delete(rbDynamicsWorld *world); + +/* Settings ------------------------- */ + +/* Gravity */ +extern void RB_dworld_get_gravity(rbDynamicsWorld *world, float g_out[3]); +extern void RB_dworld_set_gravity(rbDynamicsWorld *world, const float g_in[3]); + +/* Constraint Solver */ +extern void RB_dworld_set_solver_iterations(rbDynamicsWorld *world, int num_solver_iterations); +/* Split Impulse */ +extern void RB_dworld_set_split_impulse(rbDynamicsWorld *world, int split_impulse); + +/* Simulation ----------------------- */ + +/* Step the simulation by the desired amount (in seconds) with extra controls on substep sizes and maximum substeps */ +extern void RB_dworld_step_simulation(rbDynamicsWorld *world, float timeStep, int maxSubSteps, float timeSubStep); + +/* Export -------------------------- */ + +/* Exports the dynamics world to physics simulator's serialisation format */ +void RB_dworld_export(rbDynamicsWorld *world, const char *filename); + +/* ********************************** */ +/* Rigid Body Methods */ + +/* Setup ---------------------------- */ + +/* Add RigidBody to dynamics world */ +extern void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *body, int col_groups); + +/* Remove RigidBody from dynamics world */ +extern void RB_dworld_remove_body(rbDynamicsWorld *world, rbRigidBody *body); + +/* ............ */ + +/* Create new RigidBody instance */ +extern rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const float rot[4]); + +/* Delete the given RigidBody instance */ +extern void RB_body_delete(rbRigidBody *body); + +/* Settings ------------------------- */ + +/* 'Type' */ +extern void RB_body_set_type(rbRigidBody *body, int type, float mass); + +/* ............ */ + +/* Collision Shape */ +extern void RB_body_set_collision_shape(rbRigidBody *body, rbCollisionShape *shape); + +/* ............ */ + +/* Mass */ +extern float RB_body_get_mass(rbRigidBody *body); +extern void RB_body_set_mass(rbRigidBody *body, float value); + +/* Friction */ +extern float RB_body_get_friction(rbRigidBody *body); +extern void RB_body_set_friction(rbRigidBody *body, float value); + +/* Restitution */ +extern float RB_body_get_restitution(rbRigidBody *body); +extern void RB_body_set_restitution(rbRigidBody *body, float value); + +/* Damping */ +extern float RB_body_get_linear_damping(rbRigidBody *body); +extern void RB_body_set_linear_damping(rbRigidBody *body, float value); + +extern float RB_body_get_angular_damping(rbRigidBody *body); +extern void RB_body_set_angular_damping(rbRigidBody *body, float value); + +extern void RB_body_set_damping(rbRigidBody *object, float linear, float angular); + +/* Sleeping Thresholds */ +extern float RB_body_get_linear_sleep_thresh(rbRigidBody *body); +extern void RB_body_set_linear_sleep_thresh(rbRigidBody *body, float value); + +extern float RB_body_get_angular_sleep_thresh(rbRigidBody *body); +extern void RB_body_set_angular_sleep_thresh(rbRigidBody *body, float value); + +extern void RB_body_set_sleep_thresh(rbRigidBody *body, float linear, float angular); + +/* Linear Velocity */ +extern void RB_body_get_linear_velocity(rbRigidBody *body, float v_out[3]); +extern void RB_body_set_linear_velocity(rbRigidBody *body, const float v_in[3]); + +/* Angular Velocity */ +extern void RB_body_get_angular_velocity(rbRigidBody *body, float v_out[3]); +extern void RB_body_set_angular_velocity(rbRigidBody *body, const float v_in[3]); + +/* Linear/Angular Factor, used to lock translation/roation axes */ +extern void RB_body_set_linear_factor(rbRigidBody *object, float x, float y, float z); +extern void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z); + +/* Kinematic State */ +extern void RB_body_set_kinematic_state(rbRigidBody *body, int kinematic); + +/* RigidBody Interface - Rigid Body Activation States */ +extern int RB_body_get_activation_state(rbRigidBody *body); +extern void RB_body_set_activation_state(rbRigidBody *body, int use_deactivation); +extern void RB_body_activate(rbRigidBody *body); +extern void RB_body_deactivate(rbRigidBody *body); + + +/* Simulation ----------------------- */ + +/* Get current transform matrix of RigidBody to use in Blender (OpenGL format) */ +extern void RB_body_get_transform_matrix(rbRigidBody *body, float m_out[4][4]); + +/* Set RigidBody's location and rotation */ +extern void RB_body_set_loc_rot(rbRigidBody *body, const float loc[3], const float rot[4]); +/* Set RigidBody's local scaling */ +extern void RB_body_set_scale(rbRigidBody *body, const float scale[3]); + +/* ............ */ + +/* Get RigidBody's position as vector */ +void RB_body_get_position(rbRigidBody *body, float v_out[3]); +/* Get RigidBody's orientation as quaternion */ +void RB_body_get_orientation(rbRigidBody *body, float v_out[4]); + +/* ............ */ + +extern void RB_body_apply_central_force(rbRigidBody *body, const float v_in[3]); + +/* ********************************** */ +/* Collision Shape Methods */ + +/* Setup (Standard Shapes) ----------- */ + +extern rbCollisionShape *RB_shape_new_box(float x, float y, float z); +extern rbCollisionShape *RB_shape_new_sphere(float radius); +extern rbCollisionShape *RB_shape_new_capsule(float radius, float height); +extern rbCollisionShape *RB_shape_new_cone(float radius, float height); +extern rbCollisionShape *RB_shape_new_cylinder(float radius, float height); + +/* Setup (Convex Hull) ------------ */ + +extern rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int count, float margin, bool *can_embed); + +/* Setup (Triangle Mesh) ---------- */ + +/* 1 */ +extern rbMeshData *RB_trimesh_data_new(void); +extern void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]); +/* 2a - Triangle Meshes */ +extern rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh); +/* 2b - GImpact Meshes */ +extern rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh); + + +/* Cleanup --------------------------- */ + +extern void RB_shape_delete(rbCollisionShape *shape); + +/* Settings --------------------------- */ + +/* Collision Margin */ +extern float RB_shape_get_margin(rbCollisionShape *shape); +extern void RB_shape_set_margin(rbCollisionShape *shape, float value); + +/* ********************************** */ +/* Constraints */ + +/* Setup ----------------------------- */ + +/* Add Rigid Body Constraint to simulation world */ +extern void RB_dworld_add_constraint(rbDynamicsWorld *world, rbConstraint *con, int disable_collisions); + +/* Remove Rigid Body Constraint from simulation world */ +extern void RB_dworld_remove_constraint(rbDynamicsWorld *world, rbConstraint *con); + +extern rbConstraint *RB_constraint_new_point(float pivot[3], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_fixed(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_hinge(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_slider(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_piston(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_6dof(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); +extern rbConstraint *RB_constraint_new_6dof_spring(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2); + +/* ............ */ + +/* Cleanup --------------------------- */ + +extern void RB_constraint_delete(rbConstraint *con); + +/* Settings --------------------------- */ + +/* Enable or disable constraint */ +extern void RB_constraint_set_enabled(rbConstraint *con, int enabled); + +/* Limits */ +#define RB_LIMIT_LIN_X 0 +#define RB_LIMIT_LIN_Y 1 +#define RB_LIMIT_LIN_Z 2 +#define RB_LIMIT_ANG_X 3 +#define RB_LIMIT_ANG_Y 4 +#define RB_LIMIT_ANG_Z 5 +/* Bullet uses the following convention: + * - lower limit == upper limit -> axis is locked + * - lower limit > upper limit -> axis is free + * - lower limit < upper limit -> axis is limited in given range + */ +extern void RB_constraint_set_limits_hinge(rbConstraint *con, float lower, float upper); +extern void RB_constraint_set_limits_slider(rbConstraint *con, float lower, float upper); +extern void RB_constraint_set_limits_piston(rbConstraint *con, float lin_lower, float lin_upper, float ang_lower, float ang_upper); +extern void RB_constraint_set_limits_6dof(rbConstraint *con, float axis, float lower, float upper); + +/* 6dof spring specific */ +extern void RB_constraint_set_stiffness_6dof_spring(rbConstraint *con, float axis, float stiffness); +extern void RB_constraint_set_damping_6dof_spring(rbConstraint *con, float axis, float damping); +extern void RB_constraint_set_spring_6dof_spring(rbConstraint *con, float axis, int enable); +extern void RB_constraint_set_equilibrium_6dof_spring(rbConstraint *con); + +/* Set number of constraint solver iterations made per step, this overrided world setting + * To use default set it to -1 */ +extern void RB_constraint_set_solver_iterations(rbConstraint *con, int num_solver_iterations); + +/* Set breaking impulse threshold, if constraint shouldn't break it can be set to FLT_MAX */ +extern void RB_constraint_set_breaking_threshold(rbConstraint *con, float threshold); + +/* ********************************** */ + +#ifdef __cplusplus +} +#endif + +#endif /* __RB_API_H__ */ + diff --git a/source/blender/rigidbody/SConscript b/source/blender/rigidbody/SConscript new file mode 100644 index 00000000000..26a3688f4f9 --- /dev/null +++ b/source/blender/rigidbody/SConscript @@ -0,0 +1,38 @@ +#!/usr/bin/python +# $Id: SConscript $ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2010, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Joshua Leung +# +# ***** END GPL LICENSE BLOCK ***** + +Import ('env') + +# XXX: we need a contingency plan for when not compiling with Bullet, +# since this module will always get included... +# This problem will also apply to other engines at a later date too... +sources = env.Glob('*.cpp') + +incs = '../blenlib ../../../intern/guardedalloc ../../../extern/bullet2/src' + +env.BlenderLib ('bf_rigidbody', sources, Split(incs), [], libtype='core', priority=180 ) + diff --git a/source/blender/rigidbody/rb_bullet_api.cpp b/source/blender/rigidbody/rb_bullet_api.cpp new file mode 100644 index 00000000000..c0d75a73b6a --- /dev/null +++ b/source/blender/rigidbody/rb_bullet_api.cpp @@ -0,0 +1,948 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joshua Leung, Sergej Reich + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file rb_bullet_api.cpp + * \ingroup RigidBody + * \brief Rigid Body API implementation for Bullet + */ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +/* This file defines the "RigidBody interface" for the + * Bullet Physics Engine. This API is designed to be used + * from C-code in Blender as part of the Rigid Body simulation + * system. + * + * It is based on the Bullet C-API, but is heavily modified to + * give access to more data types and to offer a nicer interface. + * + * -- Joshua Leung, June 2010 + */ + +#include <stdio.h> + +#include "RBI_api.h" + +#include "BLI_math.h" + +#include "btBulletDynamicsCommon.h" + +#include "LinearMath/btVector3.h" +#include "LinearMath/btScalar.h" +#include "LinearMath/btMatrix3x3.h" +#include "LinearMath/btTransform.h" +#include "LinearMath/btConvexHullComputer.h" + +#include "BulletCollision/Gimpact/btGImpactShape.h" +#include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h" +#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" + +struct rbDynamicsWorld { + btDiscreteDynamicsWorld *dynamicsWorld; + btDefaultCollisionConfiguration *collisionConfiguration; + btDispatcher *dispatcher; + btBroadphaseInterface *pairCache; + btConstraintSolver *constraintSolver; + btOverlapFilterCallback *filterCallback; +}; +struct rbRigidBody { + btRigidBody *body; + int col_groups; +}; + +struct rbCollisionShape { + btCollisionShape *cshape; + btTriangleMesh *mesh; +}; + +struct rbFilterCallback : public btOverlapFilterCallback +{ + virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const + { + rbRigidBody *rb0 = (rbRigidBody*)((btRigidBody*)proxy0->m_clientObject)->getUserPointer(); + rbRigidBody *rb1 = (rbRigidBody*)((btRigidBody*)proxy1->m_clientObject)->getUserPointer(); + + bool collides; + collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + collides = collides && (rb0->col_groups & rb1->col_groups); + + return collides; + } +}; + +static inline void copy_v3_btvec3(float vec[3], const btVector3 &btvec) +{ + vec[0] = (float)btvec[0]; + vec[1] = (float)btvec[1]; + vec[2] = (float)btvec[2]; +} +static inline void copy_quat_btquat(float quat[3], const btQuaternion &btquat) +{ + quat[0] = btquat.getW(); + quat[1] = btquat.getX(); + quat[2] = btquat.getY(); + quat[3] = btquat.getZ(); +} + +/* ********************************** */ +/* Dynamics World Methods */ + +/* Setup ---------------------------- */ + +rbDynamicsWorld *RB_dworld_new(const float gravity[3]) +{ + rbDynamicsWorld *world = new rbDynamicsWorld; + + /* collision detection/handling */ + world->collisionConfiguration = new btDefaultCollisionConfiguration(); + + world->dispatcher = new btCollisionDispatcher(world->collisionConfiguration); + btGImpactCollisionAlgorithm::registerAlgorithm((btCollisionDispatcher*)world->dispatcher); // XXX: experimental + + world->pairCache = new btDbvtBroadphase(); + + world->filterCallback = new rbFilterCallback(); + world->pairCache->getOverlappingPairCache()->setOverlapFilterCallback(world->filterCallback); + + /* constraint solving */ + world->constraintSolver = new btSequentialImpulseConstraintSolver(); + + /* world */ + world->dynamicsWorld = new btDiscreteDynamicsWorld(world->dispatcher,world->pairCache,world->constraintSolver,world->collisionConfiguration); + + RB_dworld_set_gravity(world, gravity); + + return world; +} + +void RB_dworld_delete(rbDynamicsWorld *world) +{ + /* bullet doesn't like if we free these in a different order */ + delete world->dynamicsWorld; + delete world->constraintSolver; + delete world->pairCache; + delete world->dispatcher; + delete world->collisionConfiguration; + delete world->filterCallback; + delete world; +} + +/* Settings ------------------------- */ + +/* Gravity */ +void RB_dworld_get_gravity(rbDynamicsWorld *world, float g_out[3]) +{ + copy_v3_btvec3(g_out, world->dynamicsWorld->getGravity()); +} + +void RB_dworld_set_gravity(rbDynamicsWorld *world, const float g_in[3]) +{ + world->dynamicsWorld->setGravity(btVector3(g_in[0], g_in[1], g_in[2])); +} + +/* Constraint Solver */ +void RB_dworld_set_solver_iterations(rbDynamicsWorld *world, int num_solver_iterations) +{ + btContactSolverInfo& info = world->dynamicsWorld->getSolverInfo(); + + info.m_numIterations = num_solver_iterations; +} + +/* Split Impulse */ +void RB_dworld_set_split_impulse(rbDynamicsWorld *world, int split_impulse) +{ + btContactSolverInfo& info = world->dynamicsWorld->getSolverInfo(); + + info.m_splitImpulse = split_impulse; +} + +/* Simulation ----------------------- */ + +void RB_dworld_step_simulation(rbDynamicsWorld *world, float timeStep, int maxSubSteps, float timeSubStep) +{ + world->dynamicsWorld->stepSimulation(timeStep, maxSubSteps, timeSubStep); +} + +/* Export -------------------------- */ + +/* Exports entire dynamics world to Bullet's "*.bullet" binary format + * which is similar to Blender's SDNA system... + * < rbDynamicsWorld: dynamics world to write to file + * < filename: assumed to be a valid filename, with .bullet extension + */ +void RB_dworld_export(rbDynamicsWorld *world, const char *filename) +{ + //create a large enough buffer. There is no method to pre-calculate the buffer size yet. + int maxSerializeBufferSize = 1024*1024*5; + + btDefaultSerializer *serializer = new btDefaultSerializer(maxSerializeBufferSize); + world->dynamicsWorld->serialize(serializer); + + FILE *file = fopen(filename, "wb"); + fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file); + fclose(file); +} + +/* ********************************** */ +/* Rigid Body Methods */ + +/* Setup ---------------------------- */ + +void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *object, int col_groups) +{ + btRigidBody *body = object->body; + object->col_groups = col_groups; + + world->dynamicsWorld->addRigidBody(body); +} + +void RB_dworld_remove_body(rbDynamicsWorld *world, rbRigidBody *object) +{ + btRigidBody *body = object->body; + + world->dynamicsWorld->removeRigidBody(body); +} + +/* ............ */ + +rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const float rot[4]) +{ + rbRigidBody *object = new rbRigidBody; + /* current transform */ + btTransform trans; + trans.setOrigin(btVector3(loc[0], loc[1], loc[2])); + trans.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0])); + + /* create motionstate, which is necessary for interpolation (includes reverse playback) */ + btDefaultMotionState *motionState = new btDefaultMotionState(trans); + + /* make rigidbody */ + btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->cshape); + + object->body = new btRigidBody(rbInfo); + + object->body->setUserPointer(object); + + return object; +} + +void RB_body_delete(rbRigidBody *object) +{ + btRigidBody *body = object->body; + + /* motion state */ + btMotionState *ms = body->getMotionState(); + if (ms) + delete ms; + + /* collision shape is done elsewhere... */ + + /* body itself */ + + /* manually remove constraint refs of the rigid body, normally this happens when removing constraints from the world + * but since we delete everything when the world is rebult, we need to do it manually here */ + for (int i = body->getNumConstraintRefs() - 1; i >= 0; i--) { + btTypedConstraint* con = body->getConstraintRef(i); + body->removeConstraintRef(con); + } + + delete body; + delete object; +} + +/* Settings ------------------------- */ + +void RB_body_set_collision_shape(rbRigidBody *object, rbCollisionShape *shape) +{ + btRigidBody *body = object->body; + + /* set new collision shape */ + body->setCollisionShape(shape->cshape); + + /* recalculate inertia, since that depends on the collision shape... */ + RB_body_set_mass(object, RB_body_get_mass(object)); +} + +/* ............ */ + +float RB_body_get_mass(rbRigidBody *object) +{ + btRigidBody *body = object->body; + + /* there isn't really a mass setting, but rather 'inverse mass' + * which we convert back to mass by taking the reciprocal again + */ + float value = (float)body->getInvMass(); + + if (value) + value = 1.0 / value; + + return value; +} + +void RB_body_set_mass(rbRigidBody *object, float value) +{ + btRigidBody *body = object->body; + btVector3 localInertia(0,0,0); + + /* calculate new inertia if non-zero mass */ + if (value) { + btCollisionShape *shape = body->getCollisionShape(); + shape->calculateLocalInertia(value, localInertia); + } + + body->setMassProps(value, localInertia); + body->updateInertiaTensor(); +} + + +float RB_body_get_friction(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getFriction(); +} + +void RB_body_set_friction(rbRigidBody *object, float value) +{ + btRigidBody *body = object->body; + body->setFriction(value); +} + + +float RB_body_get_restitution(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getRestitution(); +} + +void RB_body_set_restitution(rbRigidBody *object, float value) +{ + btRigidBody *body = object->body; + body->setRestitution(value); +} + + +float RB_body_get_linear_damping(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getLinearDamping(); +} + +void RB_body_set_linear_damping(rbRigidBody *object, float value) +{ + RB_body_set_damping(object, value, RB_body_get_linear_damping(object)); +} + +float RB_body_get_angular_damping(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getAngularDamping(); +} + +void RB_body_set_angular_damping(rbRigidBody *object, float value) +{ + RB_body_set_damping(object, RB_body_get_linear_damping(object), value); +} + +void RB_body_set_damping(rbRigidBody *object, float linear, float angular) +{ + btRigidBody *body = object->body; + body->setDamping(linear, angular); +} + + +float RB_body_get_linear_sleep_thresh(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getLinearSleepingThreshold(); +} + +void RB_body_set_linear_sleep_thresh(rbRigidBody *object, float value) +{ + RB_body_set_sleep_thresh(object, value, RB_body_get_angular_sleep_thresh(object)); +} + +float RB_body_get_angular_sleep_thresh(rbRigidBody *object) +{ + btRigidBody *body = object->body; + return body->getAngularSleepingThreshold(); +} + +void RB_body_set_angular_sleep_thresh(rbRigidBody *object, float value) +{ + RB_body_set_sleep_thresh(object, RB_body_get_linear_sleep_thresh(object), value); +} + +void RB_body_set_sleep_thresh(rbRigidBody *object, float linear, float angular) +{ + btRigidBody *body = object->body; + body->setSleepingThresholds(linear, angular); +} + +/* ............ */ + +void RB_body_get_linear_velocity(rbRigidBody *object, float v_out[3]) +{ + btRigidBody *body = object->body; + + copy_v3_btvec3(v_out, body->getLinearVelocity()); +} + +void RB_body_set_linear_velocity(rbRigidBody *object, const float v_in[3]) +{ + btRigidBody *body = object->body; + + body->setLinearVelocity(btVector3(v_in[0], v_in[1], v_in[2])); +} + + +void RB_body_get_angular_velocity(rbRigidBody *object, float v_out[3]) +{ + btRigidBody *body = object->body; + + copy_v3_btvec3(v_out, body->getAngularVelocity()); +} + +void RB_body_set_angular_velocity(rbRigidBody *object, const float v_in[3]) +{ + btRigidBody *body = object->body; + + body->setAngularVelocity(btVector3(v_in[0], v_in[1], v_in[2])); +} + +void RB_body_set_linear_factor(rbRigidBody *object, float x, float y, float z) +{ + btRigidBody *body = object->body; + body->setLinearFactor(btVector3(x, y, z)); +} + +void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z) +{ + btRigidBody *body = object->body; + body->setAngularFactor(btVector3(x, y, z)); +} + +/* ............ */ + +void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic) +{ + btRigidBody *body = object->body; + if (kinematic) + body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + else + body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT); +} + +/* ............ */ + +void RB_body_set_activation_state(rbRigidBody *object, int use_deactivation) +{ + btRigidBody *body = object->body; + if (use_deactivation) + body->forceActivationState(ACTIVE_TAG); + else + body->setActivationState(DISABLE_DEACTIVATION); +} +void RB_body_activate(rbRigidBody *object) +{ + btRigidBody *body = object->body; + body->setActivationState(ACTIVE_TAG); +} +void RB_body_deactivate(rbRigidBody *object) +{ + btRigidBody *body = object->body; + body->setActivationState(ISLAND_SLEEPING); +} + +/* ............ */ + + + +/* Simulation ----------------------- */ + +/* The transform matrices Blender uses are OpenGL-style matrices, + * while Bullet uses the Right-Handed coordinate system style instead. + */ + +void RB_body_get_transform_matrix(rbRigidBody *object, float m_out[4][4]) +{ + btRigidBody *body = object->body; + btMotionState *ms = body->getMotionState(); + + btTransform trans; + ms->getWorldTransform(trans); + + trans.getOpenGLMatrix((btScalar*)m_out); +} + +void RB_body_set_loc_rot(rbRigidBody *object, const float loc[3], const float rot[4]) +{ + btRigidBody *body = object->body; + btMotionState *ms = body->getMotionState(); + + /* set transform matrix */ + btTransform trans; + trans.setOrigin(btVector3(loc[0], loc[1], loc[2])); + trans.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0])); + + ms->setWorldTransform(trans); +} + +void RB_body_set_scale(rbRigidBody *object, const float scale[3]) +{ + btRigidBody *body = object->body; + + /* apply scaling factor from matrix above to the collision shape */ + btCollisionShape *cshape = body->getCollisionShape(); + if (cshape) { + cshape->setLocalScaling(btVector3(scale[0], scale[1], scale[2])); + + /* GIimpact shapes have to be updated to take scaling into account */ + if (cshape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) + ((btGImpactMeshShape *)cshape)->updateBound(); + } +} + +/* ............ */ +/* Read-only state info about status of simulation */ + +void RB_body_get_position(rbRigidBody *object, float v_out[3]) +{ + btRigidBody *body = object->body; + + copy_v3_btvec3(v_out, body->getWorldTransform().getOrigin()); +} + +void RB_body_get_orientation(rbRigidBody *object, float v_out[4]) +{ + btRigidBody *body = object->body; + + copy_quat_btquat(v_out, body->getWorldTransform().getRotation()); +} + +/* ............ */ +/* Overrides for simulation */ + +void RB_body_apply_central_force(rbRigidBody *object, const float v_in[3]) +{ + btRigidBody *body = object->body; + + body->applyCentralForce(btVector3(v_in[0], v_in[1], v_in[2])); +} + +/* ********************************** */ +/* Collision Shape Methods */ + +/* Setup (Standard Shapes) ----------- */ + +rbCollisionShape *RB_shape_new_box(float x, float y, float z) +{ + rbCollisionShape *shape = new rbCollisionShape; + shape->cshape = new btBoxShape(btVector3(x, y, z)); + shape->mesh = NULL; + return shape; +} + +rbCollisionShape *RB_shape_new_sphere(float radius) +{ + rbCollisionShape *shape = new rbCollisionShape; + shape->cshape = new btSphereShape(radius); + shape->mesh = NULL; + return shape; +} + +rbCollisionShape *RB_shape_new_capsule(float radius, float height) +{ + rbCollisionShape *shape = new rbCollisionShape; + shape->cshape = new btCapsuleShapeZ(radius, height); + shape->mesh = NULL; + return shape; +} + +rbCollisionShape *RB_shape_new_cone(float radius, float height) +{ + rbCollisionShape *shape = new rbCollisionShape; + shape->cshape = new btConeShapeZ(radius, height); + shape->mesh = NULL; + return shape; +} + +rbCollisionShape *RB_shape_new_cylinder(float radius, float height) +{ + rbCollisionShape *shape = new rbCollisionShape; + shape->cshape = new btCylinderShapeZ(btVector3(radius, radius, height)); + shape->mesh = NULL; + return shape; +} + +/* Setup (Convex Hull) ------------ */ + +rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int count, float margin, bool *can_embed) +{ + btConvexHullComputer hull_computer = btConvexHullComputer(); + + // try to embed the margin, if that fails don't shrink the hull + if (hull_computer.compute(verts, stride, count, margin, 0.0f) < 0.0f) { + hull_computer.compute(verts, stride, count, 0.0f, 0.0f); + *can_embed = false; + } + + rbCollisionShape *shape = new rbCollisionShape; + btConvexHullShape *hull_shape = new btConvexHullShape(&(hull_computer.vertices[0].getX()), hull_computer.vertices.size()); + + shape->cshape = hull_shape; + shape->mesh = NULL; + return shape; +} + +/* Setup (Triangle Mesh) ---------- */ + +/* Need to call rbTriMeshNewData() followed by rbTriMeshAddTriangle() several times + * to set up the mesh buffer BEFORE calling rbShapeNewTriMesh(). Otherwise, + * we get nasty crashes... + */ + +rbMeshData *RB_trimesh_data_new() +{ + // XXX: welding threshold? + return (rbMeshData*) new btTriangleMesh(true, false); +} + +void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]) +{ + btTriangleMesh *meshData = reinterpret_cast<btTriangleMesh*>(mesh); + + /* cast vertices to usable forms for Bt-API */ + btVector3 vtx1((btScalar)v1[0], (btScalar)v1[1], (btScalar)v1[2]); + btVector3 vtx2((btScalar)v2[0], (btScalar)v2[1], (btScalar)v2[2]); + btVector3 vtx3((btScalar)v3[0], (btScalar)v3[1], (btScalar)v3[2]); + + /* add to the mesh + * - remove duplicated verts is enabled + */ + meshData->addTriangle(vtx1, vtx2, vtx3, false); +} + +rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh) +{ + rbCollisionShape *shape = new rbCollisionShape; + btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh); + + /* triangle-mesh we create is a BVH wrapper for triangle mesh data (for faster lookups) */ + // RB_TODO perhaps we need to allow saving out this for performance when rebuilding? + btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(tmesh, true, true); + + shape->cshape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f,1.0f,1.0f)); + shape->mesh = tmesh; + return shape; +} + +rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh) +{ + rbCollisionShape *shape = new rbCollisionShape; + /* interpret mesh buffer as btTriangleIndexVertexArray (i.e. an impl of btStridingMeshInterface) */ + btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh); + + btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(tmesh); + gimpactShape->updateBound(); // TODO: add this to the update collision margin call? + + shape->cshape = gimpactShape; + shape->mesh = tmesh; + return shape; +} + +/* Cleanup --------------------------- */ + +void RB_shape_delete(rbCollisionShape *shape) +{ + if (shape->cshape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) { + btBvhTriangleMeshShape *child_shape = ((btScaledBvhTriangleMeshShape*)shape->cshape)->getChildShape(); + if (child_shape) + delete child_shape; + } + if (shape->mesh) + delete shape->mesh; + delete shape->cshape; + delete shape; +} + +/* Settings --------------------------- */ + +float RB_shape_get_margin(rbCollisionShape *shape) +{ + return shape->cshape->getMargin(); +} + +void RB_shape_set_margin(rbCollisionShape *shape, float value) +{ + shape->cshape->setMargin(value); +} + +/* ********************************** */ +/* Constraints */ + +/* Setup ----------------------------- */ + +void RB_dworld_add_constraint(rbDynamicsWorld *world, rbConstraint *con, int disable_collisions) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + + world->dynamicsWorld->addConstraint(constraint, disable_collisions); +} + +void RB_dworld_remove_constraint(rbDynamicsWorld *world, rbConstraint *con) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + + world->dynamicsWorld->removeConstraint(constraint); +} + +/* ............ */ + +static void make_constraint_transforms(btTransform &transform1, btTransform &transform2, btRigidBody *body1, btRigidBody *body2, float pivot[3], float orn[4]) +{ + btTransform pivot_transform = btTransform(); + pivot_transform.setOrigin(btVector3(pivot[0], pivot[1], pivot[2])); + pivot_transform.setRotation(btQuaternion(orn[1], orn[2], orn[3], orn[0])); + + transform1 = body1->getWorldTransform().inverse() * pivot_transform; + transform2 = body2->getWorldTransform().inverse() * pivot_transform; +} + +rbConstraint *RB_constraint_new_point(float pivot[3], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + + btVector3 pivot1 = body1->getWorldTransform().inverse() * btVector3(pivot[0], pivot[1], pivot[2]); + btVector3 pivot2 = body2->getWorldTransform().inverse() * btVector3(pivot[0], pivot[1], pivot[2]); + + btTypedConstraint *con = new btPoint2PointConstraint(*body1, *body2, pivot1, pivot2); + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_fixed(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btGeneric6DofConstraint *con = new btGeneric6DofConstraint(*body1, *body2, transform1, transform2, true); + + /* lock all axes */ + for (int i = 0; i < 6; i++) + con->setLimit(i, 0, 0); + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_hinge(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btHingeConstraint *con = new btHingeConstraint(*body1, *body2, transform1, transform2); + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_slider(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btSliderConstraint *con = new btSliderConstraint(*body1, *body2, transform1, transform2, true); + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_piston(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btSliderConstraint *con = new btSliderConstraint(*body1, *body2, transform1, transform2, true); + con->setUpperAngLimit(-1.0f); // unlock rotation axis + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_6dof(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btTypedConstraint *con = new btGeneric6DofConstraint(*body1, *body2, transform1, transform2, true); + + return (rbConstraint*)con; +} + +rbConstraint *RB_constraint_new_6dof_spring(float pivot[3], float orn[4], rbRigidBody *rb1, rbRigidBody *rb2) +{ + btRigidBody *body1 = rb1->body; + btRigidBody *body2 = rb2->body; + btTransform transform1; + btTransform transform2; + + make_constraint_transforms(transform1, transform2, body1, body2, pivot, orn); + + btTypedConstraint *con = new btGeneric6DofSpringConstraint(*body1, *body2, transform1, transform2, true); + + return (rbConstraint*)con; +} + +/* Cleanup ----------------------------- */ + +void RB_constraint_delete(rbConstraint *con) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + delete constraint; +} + +/* Settings ------------------------- */ + +void RB_constraint_set_enabled(rbConstraint *con, int enabled) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + + constraint->setEnabled(enabled); +} + +void RB_constraint_set_limits_hinge(rbConstraint *con, float lower, float upper) +{ + btHingeConstraint *constraint = reinterpret_cast<btHingeConstraint*>(con); + + // RB_TODO expose these + float softness = 0.9f; + float bias_factor = 0.3f; + float relaxation_factor = 1.0f; + + constraint->setLimit(lower, upper, softness, bias_factor, relaxation_factor); +} + +void RB_constraint_set_limits_slider(rbConstraint *con, float lower, float upper) +{ + btSliderConstraint *constraint = reinterpret_cast<btSliderConstraint*>(con); + + constraint->setLowerLinLimit(lower); + constraint->setUpperLinLimit(upper); +} + +void RB_constraint_set_limits_piston(rbConstraint *con, float lin_lower, float lin_upper, float ang_lower, float ang_upper) +{ + btSliderConstraint *constraint = reinterpret_cast<btSliderConstraint*>(con); + + constraint->setLowerLinLimit(lin_lower); + constraint->setUpperLinLimit(lin_upper); + constraint->setLowerAngLimit(ang_lower); + constraint->setUpperAngLimit(ang_upper); +} + +void RB_constraint_set_limits_6dof(rbConstraint *con, float axis, float lower, float upper) +{ + btGeneric6DofConstraint *constraint = reinterpret_cast<btGeneric6DofConstraint*>(con); + + constraint->setLimit(axis, lower, upper); +} + +void RB_constraint_set_stiffness_6dof_spring(rbConstraint *con, float axis, float stiffness) +{ + btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con); + + constraint->setStiffness(axis, stiffness); +} + +void RB_constraint_set_damping_6dof_spring(rbConstraint *con, float axis, float damping) +{ + btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con); + + constraint->setDamping(axis, damping); +} + +void RB_constraint_set_spring_6dof_spring(rbConstraint *con, float axis, int enable) +{ + btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con); + + constraint->enableSpring(axis, enable); +} + +void RB_constraint_set_equilibrium_6dof_spring(rbConstraint *con) +{ + btGeneric6DofSpringConstraint *constraint = reinterpret_cast<btGeneric6DofSpringConstraint*>(con); + + constraint->setEquilibriumPoint(); +} + +void RB_constraint_set_solver_iterations(rbConstraint *con, int num_solver_iterations) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + + constraint->setOverrideNumSolverIterations(num_solver_iterations); +} + +void RB_constraint_set_breaking_threshold(rbConstraint *con, float threshold) +{ + btTypedConstraint *constraint = reinterpret_cast<btTypedConstraint*>(con); + + constraint->setBreakingImpulseThreshold(threshold); +} + +/* ********************************** */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index d606605e8d5..b2a47115630 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -95,6 +95,7 @@ endif() bf_rna bf_bmesh bf_blenkernel + bf_rigidbody bf_blenloader ge_blen_routines bf_editor_datafiles diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 72f11326af7..7362745f412 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -856,6 +856,7 @@ endif() bf_modifiers bf_bmesh bf_blenkernel + bf_rigidbody bf_nodes bf_gpu bf_blenloader |