diff options
author | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
---|---|---|
committer | Hans Lambermont <hans@lambermont.dyndns.org> | 2002-10-12 15:37:38 +0400 |
commit | 12315f4d0e0ae993805f141f64cb8c73c5297311 (patch) | |
tree | 59b45827cd8293cfb727758989c7a74b40183974 /source/gameengine/Physics/Sumo |
Initial revisionv2.25
Diffstat (limited to 'source/gameengine/Physics/Sumo')
25 files changed, 4436 insertions, 0 deletions
diff --git a/source/gameengine/Physics/Sumo/Fuzzics/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/Makefile new file mode 100644 index 00000000000..d721a416862 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/Makefile @@ -0,0 +1,9 @@ +# +# $Id$ +# Copyright (C) 2001 NaN Technologies B.V. +# Bounce make to subdirectories. + +SOURCEDIR = source/sumo/Fuzzics +DIRS = src + +include nan_subdirs.mk diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h new file mode 100644 index 00000000000..a43ddbec483 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Callback.h @@ -0,0 +1,10 @@ +#ifndef SM_CALLBACK_H +#define SM_CALLBACK_H + +class SM_Callback { +public: + virtual void do_me() = 0; +}; + +#endif + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h new file mode 100644 index 00000000000..2063892e671 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_ClientObjectInfo.h @@ -0,0 +1,15 @@ +#ifndef __SM_CLIENTOBJECT_INFO_H +#define __SM_CLIENTOBJECT_INFO_H + +/** + * Client Type and Additional Info. This structure can be use instead of a bare void* pointer, for safeness, and additional info for callbacks + */ + +struct SM_ClientObjectInfo +{ + int m_type; + void* m_clientobject; + void* m_auxilary_info; +}; + +#endif //__SM_CLIENTOBJECT_INFO_H diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h new file mode 100644 index 00000000000..4aac43f6712 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_FhObject.h @@ -0,0 +1,36 @@ +#ifndef SM_FHOBJECT_H +#define SM_FHOBJECT_H + +#include "SM_Object.h" + +class SM_FhObject : public SM_Object { +public: + SM_FhObject() {} + SM_FhObject(const MT_Vector3& ray, SM_Object *client_object) : + SM_Object(DT_Ray(ray[0], ray[1], ray[2]), 0, 0, 0), + m_ray(ray), + m_ray_direction(ray.normalized()), + m_client_object(client_object) {} + + const MT_Vector3& getRay() const { return m_ray; } + MT_Point3 getSpot() const { return m_pos + m_ray; } + const MT_Vector3& getRayDirection() const { return m_ray_direction; } + SM_Object *getClientObject() const { return m_client_object; } + + static void ray_hit(void *client_data, + void *object1, + void *object2, + const DT_CollData *coll_data); + +private: + MT_Vector3 m_ray; + MT_Vector3 m_ray_direction; + SM_Object *m_client_object; +}; + +#endif + + + + + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h new file mode 100644 index 00000000000..9c6a9ddaec2 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_MotionState.h @@ -0,0 +1,36 @@ +#ifndef SM_MOTIONSTATE_H +#define SM_MOTIONSTATE_H + +#include "MT_Transform.h" + +class SM_MotionState { +public: + SM_MotionState() : + m_pos(0.0, 0.0, 0.0), + m_orn(0.0, 0.0, 0.0, 1.0), + m_lin_vel(0.0, 0.0, 0.0), + m_ang_vel(0.0, 0.0, 0.0) + {} + + void setPosition(const MT_Point3& pos) { m_pos = pos; } + void setOrientation(const MT_Quaternion& orn) { m_orn = orn; } + void setLinearVelocity(const MT_Vector3& lin_vel) { m_lin_vel = lin_vel; } + void setAngularVelocity(const MT_Vector3& ang_vel) { m_ang_vel = ang_vel; } + + const MT_Point3& getPosition() const { return m_pos; } + const MT_Quaternion& getOrientation() const { return m_orn; } + const MT_Vector3& getLinearVelocity() const { return m_lin_vel; } + const MT_Vector3& getAngularVelocity() const { return m_ang_vel; } + + virtual MT_Transform getTransform() const { + return MT_Transform(m_pos, m_orn); + } + +protected: + MT_Point3 m_pos; + MT_Quaternion m_orn; + MT_Vector3 m_lin_vel; + MT_Vector3 m_ang_vel; +}; + +#endif diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h new file mode 100644 index 00000000000..670da6e71db --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Object.h @@ -0,0 +1,280 @@ +#ifndef SM_OBJECT_H +#define SM_OBJECT_H + +#include <vector> + +#include "solid.h" + +#include "SM_Callback.h" +#include "SM_MotionState.h" +#include <stdio.h> + + +class SM_FhObject; + + +// Properties of dynamic objects +struct SM_ShapeProps { + MT_Scalar m_mass; // Total mass + MT_Scalar m_inertia; // Inertia, should be a tensor some time + MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum + MT_Scalar m_ang_drag; // Angular drag + MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] + bool m_do_anisotropic; // Should I do anisotropic friction? + bool m_do_fh; // Should the object have a linear Fh spring? + bool m_do_rot_fh; // Should the object have an angular Fh spring? +}; + + +// Properties of collidable objects (non-ghost objects) +struct SM_MaterialProps { + MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic + MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force) + MT_Scalar m_fh_spring; // Spring constant (both linear and angular) + MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1] + MT_Scalar m_fh_distance; // The range above the surface where Fh is active. + bool m_fh_normal; // Should the object slide off slopes? +}; + + +class SM_Object : public SM_MotionState { +public: + SM_Object() ; + SM_Object( + DT_ShapeHandle shape, + const SM_MaterialProps *materialProps, + const SM_ShapeProps *shapeProps, + SM_Object *dynamicParent + ); + + virtual ~SM_Object(); + + bool isDynamic() const; + + /* nzc experimental. There seem to be two places where kinematics + * are evaluated: proceedKinematic (called from SM_Scene) and + * proceed() in this object. I'll just try and bunge these out for + * now. */ + + void suspend(void); + void resume(void); + + void suspendDynamics(); + + void restoreDynamics(); + + bool isGhost() const; + + void suspendMaterial(); + + void restoreMaterial(); + + SM_FhObject *getFhObject() const; + + void registerCallback(SM_Callback& callback); + + void calcXform(); + void notifyClient(); + + // Save the current state information for use in the + // velocity computation in the next frame. + + void proceedKinematic(MT_Scalar timeStep); + + void saveReactionForce(MT_Scalar timeStep) ; + + void clearForce() ; + + void clearMomentum() ; + + void setMargin(MT_Scalar margin) ; + + MT_Scalar getMargin() const ; + + const SM_MaterialProps *getMaterialProps() const ; + + const SM_ShapeProps *getShapeProps() const ; + + void setPosition(const MT_Point3& pos); + void setOrientation(const MT_Quaternion& orn); + void setScaling(const MT_Vector3& scaling); + + + /** + * set an external velocity. This velocity complements + * the physics velocity. So setting it does not override the + * physics velocity. It is your responsibility to clear + * this external velocity. This velocity is not subject to + * friction or damping. + */ + + + void setExternalLinearVelocity(const MT_Vector3& lin_vel) ; + void addExternalLinearVelocity(const MT_Vector3& lin_vel) ; + + /** Override the physics velocity */ + + void addLinearVelocity(const MT_Vector3& lin_vel); + void setLinearVelocity(const MT_Vector3& lin_vel); + + /** + * Set an external angular velocity. This velocity complemetns + * the physics angular velocity so does not override it. It is + * your responsibility to clear this velocity. This velocity + * is not subject to friction or damping. + */ + + void setExternalAngularVelocity(const MT_Vector3& ang_vel) ; + void addExternalAngularVelocity(const MT_Vector3& ang_vel); + + /** Override the physics angular velocity */ + + void addAngularVelocity(const MT_Vector3& ang_vel); + void setAngularVelocity(const MT_Vector3& ang_vel); + + /** Clear the external velocities */ + + void clearCombinedVelocities(); + + /** + * Tell the physics system to combine the external velocity + * with the physics velocity. + */ + + void resolveCombinedVelocities( + const MT_Vector3 & lin_vel, + const MT_Vector3 & ang_vel + ) ; + + + + MT_Scalar getInvMass() const; + + MT_Scalar getInvInertia() const ; + + void applyForceField(const MT_Vector3& accel) ; + + void applyCenterForce(const MT_Vector3& force) ; + + void applyTorque(const MT_Vector3& torque) ; + + void applyImpulse(const MT_Point3& attach, const MT_Vector3& impulse) ; + + void applyCenterImpulse(const MT_Vector3& impulse); + + void applyAngularImpulse(const MT_Vector3& impulse); + + MT_Point3 getWorldCoord(const MT_Point3& local) const; + + MT_Vector3 getVelocity(const MT_Point3& local) const; + + + const MT_Vector3& getReactionForce() const ; + + void getMatrix(double *m) const ; + + const double *getMatrix() const ; + + // Still need this??? + const MT_Transform& getScaledTransform() const; + + DT_ObjectHandle getObjectHandle() const ; + DT_ShapeHandle getShapeHandle() const ; + + void setClientObject(void *clientobj) ; + void *getClientObject() ; + + SM_Object *getDynamicParent() ; + + void integrateForces(MT_Scalar timeStep); + void integrateMomentum(MT_Scalar timeSteo); + + void setRigidBody(bool is_rigid_body) ; + + bool isRigidBody() const ; + + + // This is the callback for handling collisions of dynamic objects + static + void + boing( + void *client_data, + void *object1, + void *object2, + const DT_CollData *coll_data + ); + +private: + + // return the actual linear_velocity of this object this + // is the addition of m_combined_lin_vel and m_lin_vel. + + const + MT_Vector3 + actualLinVelocity( + ) const ; + + const + MT_Vector3 + actualAngVelocity( + ) const ; + + typedef std::vector<SM_Callback *> T_CallbackList; + + + T_CallbackList m_callbackList; // Each object can have multiple callbacks from the client (=game engine) + SM_Object *m_dynamicParent; // Collisions between parent and children are ignored + + // as the collision callback now has only information + // on an SM_Object, there must be a way that the SM_Object client + // can identify it's clientdata after a collision + void *m_client_object; + + DT_ShapeHandle m_shape; // Shape for collision detection + + // Material and shape properties are not owned by this class. + + const SM_MaterialProps *m_materialProps; + const SM_MaterialProps *m_materialPropsBackup; // Backup in case the object temporarily becomes a ghost. + const SM_ShapeProps *m_shapeProps; + const SM_ShapeProps *m_shapePropsBackup; // Backup in case the object's dynamics is temporarily suspended + DT_ObjectHandle m_object; // A handle to the corresponding object in SOLID. + MT_Scalar m_margin; // Offset for the object's shape (also for collision detection) + MT_Vector3 m_scaling; // Non-uniform scaling of the object's shape + + double m_ogl_matrix[16]; // An OpenGL-type 4x4 matrix + MT_Transform m_xform; // The object's local coordinate system + MT_Transform m_prev_xform; // The object's local coordinate system in the previous frame + SM_MotionState m_prev_state; // The object's motion state in the previous frame + MT_Scalar m_timeStep; // The duration of the last frame + + MT_Vector3 m_reaction_impulse; // The accumulated impulse resulting from collisions + MT_Vector3 m_reaction_force; // The reaction force derived from the reaction impulse + + unsigned int m_kinematic : 1; // Have I been displaced (translated, rotated, scaled) in this frame? + unsigned int m_prev_kinematic : 1; // Have I been displaced (translated, rotated, scaled) in the previous frame? + unsigned int m_is_rigid_body : 1; // Should friction give me a change in angular momentum? + + MT_Vector3 m_lin_mom; // Linear momentum (linear velocity times mass) + MT_Vector3 m_ang_mom; // Angular momentum (angualr velocity times inertia) + MT_Vector3 m_force; // Force on center of mass (afffects linear momentum) + MT_Vector3 m_torque; // Torque around center of mass (affects angualr momentum) + + // Here are the values of externally set linear and angular + // velocity. These are updated from the outside + // (actuators and python) each frame and combined with the + // physics values. At the end of each frame (at the end of a + // call to proceed) they are set to zero. This allows the + // outside world to contribute to the velocity of an object + // but still have it react to physics. + + MT_Vector3 m_combined_lin_vel; + MT_Vector3 m_combined_ang_vel; + + // The force and torque are the accumulated forces and torques applied by the client (game logic, python). + + SM_FhObject *m_fh_object; // The ray object used for Fh + bool m_suspended; // Is this object frozen? +}; + +#endif diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h new file mode 100644 index 00000000000..0b2efacac2a --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Props.h @@ -0,0 +1,60 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef SM_PROPSH +#define SM_PROPSH + +#include <MT_Scalar.h> + +// Properties of dynamic objects +struct SM_ShapeProps { + MT_Scalar m_mass; // Total mass + MT_Scalar m_inertia; // Inertia, should be a tensor some time + MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum + MT_Scalar m_ang_drag; // Angular drag + MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] + bool m_do_anisotropic; // Should I do anisotropic friction? + bool m_do_fh; // Should the object have a linear Fh spring? + bool m_do_rot_fh; // Should the object have an angular Fh spring? +}; + + +// Properties of collidable objects (non-ghost objects) +struct SM_MaterialProps { + MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic + MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force) + MT_Scalar m_fh_spring; // Spring constant (both linear and angular) + MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1] + MT_Scalar m_fh_distance; // The range above the surface where Fh is active. + bool m_fh_normal; // Should the object slide off slopes? +}; + +#endif //SM_PROPSH diff --git a/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h new file mode 100644 index 00000000000..761e6c7c449 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/include/SM_Scene.h @@ -0,0 +1,129 @@ +/** + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * The physics scene. + */ + +#ifndef SM_SCENE_H +#define SM_SCENE_H + +#pragma warning (disable : 4786) + +#include <vector> +#include <set> +#include <utility> //needed for pair + +#include "solid.h" + +#include "MT_Vector3.h" +#include "MT_Point3.h" + +class SM_Object; + +class SM_Scene { +public: + SM_Scene() : + m_scene(DT_CreateScene()), + m_respTable(DT_CreateRespTable()), + m_secondaryRespTable(0), + m_forceField(0.0, 0.0, 0.0) + {} + + ~SM_Scene() { + DT_DeleteRespTable(m_respTable); + DT_DeleteScene(m_scene); + } + + DT_RespTableHandle getRespTableHandle() const { + return m_respTable; + } + + const MT_Vector3& getForceField() const { + return m_forceField; + } + + MT_Vector3& getForceField() { + return m_forceField; + } + + void setForceField(const MT_Vector3& forceField) { + m_forceField = forceField; + } + + void add(SM_Object& object); + void remove(SM_Object& object); + + void addPair(SM_Object *obj1, SM_Object *obj2) { + m_pairList.insert(std::make_pair(obj1, obj2)); + } + + void clearPairs() { + m_pairList.clear(); + } + + void setSecondaryRespTable(DT_RespTableHandle secondaryRespTable) { + m_secondaryRespTable = secondaryRespTable; + } + + + // Perform an integration step of duration 'timeStep'. + // 'subSampling' is the maximum duration of a substep, i.e., + // The maximum time interval between two collision checks. + // 'subSampling' can be used to control aliasing effects + // (fast moving objects traversing through walls and such). + void proceed(MT_Scalar timeStep, MT_Scalar subSampling); + + /** + * Test whether any objects lie on the line defined by from and + * to. The search returns the first such bject starting at from, + * or NULL if there was none. + * @returns A reference to the object, or NULL if there was none. + * @param ignore_client Do not look for collisions with this + * object. This can be useful to avoid self-hits if + * starting from the location of an object. + * @param from The start point, in world coordinates, of the search. + * @param to The end point, in world coordinates, of the search. + * @param result A store to return the point where intersection + * took place (if there was an intersection). + * @param normal A store to return the normal of the hit object on + * the location of the intersection, if it took place. + */ + SM_Object *rayTest(void *ignore_client, + const MT_Point3& from, const MT_Point3& to, + MT_Point3& result, MT_Vector3& normal) const; + +private: + + // Clear the user set velocities. + void clearObjectCombinedVelocities(); + + /** internal type */ + typedef std::vector<SM_Object *> T_ObjectList; + /** internal type */ + typedef std::set<std::pair<SM_Object *, SM_Object *> > T_PairList; + + /** Handle to the scene in SOLID */ + DT_SceneHandle m_scene; + /** Following response table contains the callbacks for the dynmics */ + DT_RespTableHandle m_respTable; + /** + * Following response table contains callbacks for the client (= + * game engine) */ + DT_RespTableHandle m_secondaryRespTable; // Handle + + /** The acceleration from the force field */ + MT_Vector3 m_forceField; + + /** + * The list of objects that receive motion updates and do + * collision tests. */ + T_ObjectList m_objectList; + + /** + * A list with pairs of objects that collided the previous + * timestep. The list is built during the proceed(). During that + * time, it is not valid. */ + T_PairList m_pairList; +}; + +#endif diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile new file mode 100644 index 00000000000..672dff39028 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/Makefile @@ -0,0 +1,25 @@ +# +# $Id$ +# Copyright (C) 2001 NaN Technologies B.V. + +DIR = $(OCGDIR)/sumo +ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)particle $(DIR)/$(DEBUG_DIR)particle0 + +include nan_compile.mk + +CPPFLAGS = -I../../include -I../include -I$(NAN_MOTO)/include +CPPFLAGS += -I$(OPENGL_HEADERS) + +clean:: + @$(RM) $(DIR)/particle $(DIR)/particle0 + @$(RM) $(DIR)/debug/particle $(DIR)/debug/particle0 + +LDFLAGS = -L$(DIR) -L/usr/X11R6/lib +OGL_LDLIBS = -lglut -lGLU -lGL -pthread +LDLIBS = -lfuzzics -lsolid $(NAN_MOTO)/lib/libmoto.a $(OGL_LDLIBS) + +$(DIR)/$(DEBUG_DIR)particle: particle.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a + $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) + +$(DIR)/$(DEBUG_DIR)particle0: particle0.o $(DIR)/$(DEBUG_DIR)libfuzzics.a $(DIR)/$(DEBUG_DIR)libsolid.a + $(CCC) $(CCFLAGS) $(CPPFLAGS) $(LDFLAGS) $< -o $@ $(LDLIBS) diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp new file mode 100644 index 00000000000..e8e78d89a4e --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle.cpp @@ -0,0 +1,705 @@ +//#define FAKE_IT +#define USE_COMPLEX +#define QUADS + +#include <algorithm> +#include <new> +#include <GL/glut.h> + +#include "MT_MinMax.h" +#include "MT_Point3.h" +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix3x3.h" +#include "MT_Transform.h" + +#include "SM_Object.h" +#include "SM_FhObject.h" +#include "SM_Scene.h" + +#include "solid.h" + +const MT_Scalar bowl_curv = 0.10; +const MT_Scalar timeStep = 0.02; +const MT_Scalar ground_margin = 0.0; +const MT_Scalar sphere_radius = 0.5; + +const MT_Vector3 gravity(0, -9.8, 0); + +static MT_Scalar DISTANCE = 5; + +static MT_Scalar ele = 0, azi = 0; +static MT_Point3 eye(0, 0, DISTANCE); +static MT_Point3 center(0, 0, 0); + +inline double irnd() { return 2 * MT_random() - 1; } + +static const double SCALE_BOTTOM = 0.5; +static const double SCALE_FACTOR = 2.0; + +SM_ShapeProps g_shapeProps = { + 1.0, // mass + 1.0, // inertia + 0.1, // linear drag + 0.1, // angular drag + { 1.0, 0.0, 0.0 }, // anisotropic friction + false, // do anisotropic friction? + true, // do fh? + true // do rot fh? +}; + +SM_MaterialProps g_materialProps = { + 0.7, // restitution + 0.0, // friction + 10.0, // Fh spring constant + 1.0, // Fh damping + 0.5, // Fh distance + true // Fh leveling +}; + + +void toggleIdle(); + + +void newRandom(); + +void coordSystem() { + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glColor3f(1, 0, 0); + glVertex3d(0, 0, 0); + glVertex3d(10, 0, 0); + glColor3f(0, 1, 0); + glVertex3d(0, 0, 0); + glVertex3d(0, 10, 0); + glColor3f(0, 0, 1); + glVertex3d(0, 0, 0); + glVertex3d(0, 0, 10); + glEnd(); + glEnable(GL_LIGHTING); +} + + +void display_bbox(const MT_Point3& min, const MT_Point3& max) { + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glColor3f(0, 1, 1); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glBegin(GL_QUAD_STRIP); + glVertex3d(min[0], min[1], min[2]); + glVertex3d(min[0], min[1], max[2]); + glVertex3d(max[0], min[1], min[2]); + glVertex3d(max[0], min[1], max[2]); + glVertex3d(max[0], max[1], min[2]); + glVertex3d(max[0], max[1], max[2]); + glVertex3d(min[0], max[1], min[2]); + glVertex3d(min[0], max[1], max[2]); + glVertex3d(min[0], min[1], min[2]); + glVertex3d(min[0], min[1], max[2]); + glEnd(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + + + + +class GLShape { +public: + virtual void paint(GLdouble *m) const = 0; +}; + + +class GLSphere : public GLShape { + MT_Scalar radius; +public: + GLSphere(MT_Scalar r) : radius(r) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + glutSolidSphere(radius, 20, 20); + glPopMatrix(); + } +}; + + +class GLBox : public GLShape { + MT_Vector3 extent; +public: + GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) : + extent(x, y, z) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + glPushMatrix(); + glScaled(extent[0], extent[1], extent[2]); + glutSolidCube(1.0); + glPopMatrix(); + glPopMatrix(); + } +}; + + +class GLCone : public GLShape { + MT_Scalar bottomRadius; + MT_Scalar height; + mutable GLuint displayList; + +public: + GLCone(MT_Scalar r, MT_Scalar h) : + bottomRadius(r), + height(h), + displayList(0) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + if (displayList) glCallList(displayList); + else { + GLUquadricObj *quadObj = gluNewQuadric(); + displayList = glGenLists(1); + glNewList(displayList, GL_COMPILE_AND_EXECUTE); + glPushMatrix(); + glRotatef(-90.0, 1.0, 0.0, 0.0); + glTranslatef(0.0, 0.0, -1.0); + gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); + gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); + gluCylinder(quadObj, bottomRadius, 0, height, 15, 10); + glPopMatrix(); + glEndList(); + } + glPopMatrix(); + } +}; + +class GLCylinder : public GLShape { + MT_Scalar radius; + MT_Scalar height; + mutable GLuint displayList; + +public: + GLCylinder(MT_Scalar r, MT_Scalar h) : + radius(r), + height(h), + displayList(0) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + if (displayList) glCallList(displayList); + else { + GLUquadricObj *quadObj = gluNewQuadric(); + displayList = glGenLists(1); + glNewList(displayList, GL_COMPILE_AND_EXECUTE); + glPushMatrix(); + glRotatef(-90.0, 1.0, 0.0, 0.0); + glTranslatef(0.0, 0.0, -1.0); + gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); + gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); + gluCylinder(quadObj, radius, radius, height, 15, 10); + glPopMatrix (); + glEndList(); + } + glPopMatrix(); + } +}; + +class Object; + +class Callback : public SM_Callback { +public: + Callback(Object& object) : m_object(object) {} + + virtual void do_me(); + +private: + Object& m_object; +}; + + +class Object { +public: + Object(GLShape *gl_shape, SM_Object& object) : + m_gl_shape(gl_shape), + m_object(object), + m_callback(*this) + { + m_object.registerCallback(m_callback); + } + + ~Object() {} + + void paint() { + if (m_gl_shape) { + m_gl_shape->paint(m); + // display_bbox(m_bbox.lower(), m_bbox.upper()); + } + } + + void print_reaction_force() const { + std::cout << m_object.getReactionForce() << std::endl; + } + + MT_Vector3 getAhead() { + return MT_Vector3(&m[4]); + } + + MT_Vector3 getUp() { + return MT_Vector3(&m[8]); + } + + void clearMomentum() { + m_object.clearMomentum(); + } + + void setMargin(MT_Scalar margin) { + m_object.setMargin(margin); + } + + void setScaling(const MT_Vector3& scaling) { + m_object.setScaling(scaling); + } + + const MT_Point3& getPosition() { + return m_object.getPosition(); + } + + void setPosition(const MT_Point3& pos) { + m_object.setPosition(pos); + } + + void setOrientation(const MT_Quaternion& orn) { + m_object.setOrientation(orn); + } + + void applyCenterForce(const MT_Vector3& force) { + m_object.applyCenterForce(force); + } + + void applyTorque(const MT_Vector3& torque) { + m_object.applyTorque(torque); + } + + MT_Point3 getWorldCoord(const MT_Point3& local) const { + return m_object.getWorldCoord(local); + } + + MT_Vector3 getLinearVelocity() const { + return m_object.getLinearVelocity(); + } + + MT_Vector3 getAngularVelocity() const { + return m_object.getAngularVelocity(); + } + + void setMatrix() { + m_object.calcXform(); + m_object.getMatrix(m); + } + + const double *getMatrix() { + m_object.calcXform(); + return m_object.getMatrix(); + } + +private: + GLShape *m_gl_shape; + SM_Object& m_object; + DT_Scalar m[16]; + Callback m_callback; +}; + + + +const MT_Scalar SPACE_SIZE = 2; + +static GLSphere gl_sphere(sphere_radius); +static GLBox gl_ground(50.0, 0.0, 50.0); + + + +#ifdef USE_COMPLEX + +const int GRID_SCALE = 10; +const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE; + +DT_ShapeHandle createComplex() { + DT_ShapeHandle shape = DT_NewComplexShape(); + for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) { + for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) { + int i1 = i0 + 1; + int j1 = j0 + 1; +#ifdef QUADS + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0); + DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0); + DT_End(); +#else + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); + DT_End(); + + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0); + DT_End(); +#endif + + } + } + DT_EndComplexShape(); + return shape; +} + + +static DT_ShapeHandle ground_shape = createComplex(); + +#else + +static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50); + +#endif + +static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0); +static Object ground(&gl_ground, sm_ground); + +static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0); +static Object object(&gl_sphere, sm_sphere); + + +static SM_Scene g_scene; + + +bool g_hit = false; +MT_Point3 g_spot; +MT_Vector3 g_normal; + + +void Callback::do_me() +{ + m_object.setMatrix(); + m_object.print_reaction_force(); +} + +void myinit(void) { + + GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; + GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; + + /* light_position is NOT default value */ + GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 }; + GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 }; + + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // glEnable(GL_CULL_FACE); + // glCullFace(GL_BACK); + + ground.setPosition(MT_Point3(0, -10, 0)); + ground.setOrientation(MT_Quaternion(0, 0, 0, 1)); + ground.setMatrix(); + center.setValue(0.0, 0.0, 0.0); + sm_ground.setMargin(ground_margin); + + g_scene.setForceField(gravity); + g_scene.add(sm_ground); + + object.setMargin(sphere_radius); + + g_scene.add(sm_sphere); + + + newRandom(); +} + + +//MT_Point3 cp1, cp2; +//bool intersection; + +void display(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ground.paint(); + object.paint(); + + if (g_hit) { + glDisable(GL_LIGHTING); + glColor3f(1, 0, 0); + + glPointSize(5); + glBegin(GL_POINTS); + glVertex3d(g_spot[0], g_spot[1], g_spot[2]); + glEnd(); + glPointSize(1); + + glColor3f(1, 1, 0); + glBegin(GL_LINES); + glVertex3d(g_spot[0], g_spot[1], g_spot[2]); + glVertex3d(g_spot[0] + g_normal[0], + g_spot[1] + g_normal[1], + g_spot[2] + g_normal[2]); + glEnd(); + glEnable(GL_LIGHTING); + } + + + +#ifdef COLLISION + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glColor3f(1, 1, 0); + if (intersection) { + glPointSize(5); + glBegin(GL_POINTS); + glVertex3d(cp1[0], cp1[1], cp1[2]); + glEnd(); + glPointSize(1); + } + else { + glBegin(GL_LINES); + glVertex3d(cp1[0], cp1[1], cp1[2]); + glVertex3d(cp2[0], cp2[1], cp2[2]); + glEnd(); + } + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +#endif + + glFlush(); + glutSwapBuffers(); +} + + + + + +void newRandom() { + object.setPosition(MT_Point3(0, 0, 0)); + object.setOrientation(MT_Quaternion::random()); + object.clearMomentum(); + object.setMatrix(); + + display(); +} + +void moveAndDisplay() { + g_scene.proceed(timeStep, 0.01); + + display(); + g_hit = false; +} + + +void turn_left() { + object.applyTorque(5.0 * object.getUp()); +} + +void turn_right() { + object.applyTorque(-5.0 * object.getUp()); +} + +void forward() { + object.applyCenterForce(10.0 * object.getAhead()); +} + +void backward() { + object.applyCenterForce(-10.0 * object.getAhead()); +} + +void jump() { + object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0)); +} + + +void toggleIdle() { + static bool idle = true; + if (idle) { + glutIdleFunc(moveAndDisplay); + idle = false; + } + else { + glutIdleFunc(NULL); + idle = true; + } +} + + +void setCamera() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0); + MT_Scalar rele = MT_radians(ele); + MT_Scalar razi = MT_radians(azi); + eye.setValue(DISTANCE * sin(razi) * cos(rele), + DISTANCE * sin(rele), + DISTANCE * cos(razi) * cos(rele)); + gluLookAt(eye[0], eye[1], eye[2], + center[0], center[1], center[2], + 0, 1, 0); + glMatrixMode(GL_MODELVIEW); + display(); +} + +const MT_Scalar STEPSIZE = 5; + +void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } +void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } +void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } +void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } +void zoomIn() { DISTANCE -= 1; setCamera(); } +void zoomOut() { DISTANCE += 1; setCamera(); } + + +void myReshape(int w, int h) { + glViewport(0, 0, w, h); + setCamera(); +} + +void myKeyboard(unsigned char key, int x, int y) +{ + switch (key) + { + case 'w': forward(); break; + case 's': backward(); break; + case 'a': turn_left(); break; + case 'd': turn_right(); break; + case 'e': jump(); break; + case 'l' : stepLeft(); break; + case 'r' : stepRight(); break; + case 'f' : stepFront(); break; + case 'b' : stepBack(); break; + case 'z' : zoomIn(); break; + case 'x' : zoomOut(); break; + case 'i' : toggleIdle(); break; + case ' ' : newRandom(); break; + default: +// std::cout << "unused key : " << key << std::endl; + break; + } +} + +void mySpecial(int key, int x, int y) +{ + switch (key) + { + case GLUT_KEY_LEFT : stepLeft(); break; + case GLUT_KEY_RIGHT : stepRight(); break; + case GLUT_KEY_UP : stepFront(); break; + case GLUT_KEY_DOWN : stepBack(); break; + case GLUT_KEY_PAGE_UP : zoomIn(); break; + case GLUT_KEY_PAGE_DOWN : zoomOut(); break; + case GLUT_KEY_HOME : toggleIdle(); break; + default: +// std::cout << "unused (special) key : " << key << std::endl; + break; + } +} + +void goodbye( void) +{ + g_scene.remove(sm_ground); + g_scene.remove(sm_sphere); + + std::cout << "goodbye ..." << std::endl; + exit(0); +} + +void menu(int choice) +{ + + static int fullScreen = 0; + static int px, py, sx, sy; + + switch(choice) { + case 1: + if (fullScreen == 1) { + glutPositionWindow(px,py); + glutReshapeWindow(sx,sy); + glutChangeToMenuEntry(1,"Full Screen",1); + fullScreen = 0; + } else { + px=glutGet((GLenum)GLUT_WINDOW_X); + py=glutGet((GLenum)GLUT_WINDOW_Y); + sx=glutGet((GLenum)GLUT_WINDOW_WIDTH); + sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT); + glutFullScreen(); + glutChangeToMenuEntry(1,"Close Full Screen",1); + fullScreen = 1; + } + break; + case 2: + toggleIdle(); + break; + case 3: + goodbye(); + break; + default: + break; + } +} + +void createMenu() +{ + glutCreateMenu(menu); + glutAddMenuEntry("Full Screen", 1); + glutAddMenuEntry("Toggle Idle (Start/Stop)", 2); + glutAddMenuEntry("Quit", 3); + glutAttachMenu(GLUT_RIGHT_BUTTON); +} + +int main(int argc, char **argv) { + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowPosition(0, 0); + glutInitWindowSize(500, 500); + glutCreateWindow("Physics demo"); + + myinit(); + glutKeyboardFunc(myKeyboard); + glutSpecialFunc(mySpecial); + glutReshapeFunc(myReshape); + createMenu(); + glutIdleFunc(NULL); + + glutDisplayFunc(display); + glutMainLoop(); + return 0; +} + + + + + + + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp new file mode 100644 index 00000000000..1c03621f530 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/sample/particle0.cpp @@ -0,0 +1,691 @@ +//#define FAKE_IT +#define USE_COMPLEX +#define QUADS + +#include <algorithm> +#include <new> +#include <GL/glut.h> + +#include "MT_MinMax.h" +#include "MT_Point3.h" +#include "MT_Vector3.h" +#include "MT_Quaternion.h" +#include "MT_Matrix3x3.h" +#include "MT_Transform.h" + +#include "SM_Object.h" +#include "SM_Scene.h" + +#include "solid.h" + +const MT_Scalar bowl_curv = 0.10; +const MT_Scalar timeStep = 0.04; +const MT_Scalar ground_margin = 0.0; +const MT_Scalar sphere_radius = 0.5; + +const MT_Vector3 gravity(0, -9.8, 0); + +static MT_Scalar DISTANCE = 5; + +static MT_Scalar ele = 0, azi = 0; +static MT_Point3 eye(0, 0, DISTANCE); +static MT_Point3 center(0, 0, 0); + +inline double irnd() { return 2 * MT_random() - 1; } + +static const double SCALE_BOTTOM = 0.5; +static const double SCALE_FACTOR = 2.0; + +SM_ShapeProps g_shapeProps = { + 1.0, // mass + 1.0, // inertia + 0.9, // linear drag + 0.9 // angular drag +}; + +SM_MaterialProps g_materialProps = { + 0.7, // restitution + 0.0, // friction + 0.0, // spring constant + 0.0 // damping +}; + + +void toggleIdle(); + + +void newRandom(); + +void coordSystem() { + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glColor3f(1, 0, 0); + glVertex3d(0, 0, 0); + glVertex3d(10, 0, 0); + glColor3f(0, 1, 0); + glVertex3d(0, 0, 0); + glVertex3d(0, 10, 0); + glColor3f(0, 0, 1); + glVertex3d(0, 0, 0); + glVertex3d(0, 0, 10); + glEnd(); + glEnable(GL_LIGHTING); +} + + +void display_bbox(const MT_Point3& min, const MT_Point3& max) { + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glColor3f(0, 1, 1); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glBegin(GL_QUAD_STRIP); + glVertex3d(min[0], min[1], min[2]); + glVertex3d(min[0], min[1], max[2]); + glVertex3d(max[0], min[1], min[2]); + glVertex3d(max[0], min[1], max[2]); + glVertex3d(max[0], max[1], min[2]); + glVertex3d(max[0], max[1], max[2]); + glVertex3d(min[0], max[1], min[2]); + glVertex3d(min[0], max[1], max[2]); + glVertex3d(min[0], min[1], min[2]); + glVertex3d(min[0], min[1], max[2]); + glEnd(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +} + + + + +class GLShape { +public: + virtual void paint(GLdouble *m) const = 0; +}; + + +class GLSphere : public GLShape { + MT_Scalar radius; +public: + GLSphere(MT_Scalar r) : radius(r) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + glutSolidSphere(radius, 20, 20); + glPopMatrix(); + } +}; + + +class GLBox : public GLShape { + MT_Vector3 extent; +public: + GLBox(MT_Scalar x, MT_Scalar y, MT_Scalar z) : + extent(x, y, z) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + glPushMatrix(); + glScaled(extent[0], extent[1], extent[2]); + glutSolidCube(1.0); + glPopMatrix(); + glPopMatrix(); + } +}; + + +class GLCone : public GLShape { + MT_Scalar bottomRadius; + MT_Scalar height; + mutable GLuint displayList; + +public: + GLCone(MT_Scalar r, MT_Scalar h) : + bottomRadius(r), + height(h), + displayList(0) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + if (displayList) glCallList(displayList); + else { + GLUquadricObj *quadObj = gluNewQuadric(); + displayList = glGenLists(1); + glNewList(displayList, GL_COMPILE_AND_EXECUTE); + glPushMatrix(); + glRotatef(-90.0, 1.0, 0.0, 0.0); + glTranslatef(0.0, 0.0, -1.0); + gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); + gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); + gluCylinder(quadObj, bottomRadius, 0, height, 15, 10); + glPopMatrix(); + glEndList(); + } + glPopMatrix(); + } +}; + +class GLCylinder : public GLShape { + MT_Scalar radius; + MT_Scalar height; + mutable GLuint displayList; + +public: + GLCylinder(MT_Scalar r, MT_Scalar h) : + radius(r), + height(h), + displayList(0) {} + + void paint(GLdouble *m) const { + glPushMatrix(); + glLoadMatrixd(m); + coordSystem(); + if (displayList) glCallList(displayList); + else { + GLUquadricObj *quadObj = gluNewQuadric(); + displayList = glGenLists(1); + glNewList(displayList, GL_COMPILE_AND_EXECUTE); + glPushMatrix(); + glRotatef(-90.0, 1.0, 0.0, 0.0); + glTranslatef(0.0, 0.0, -1.0); + gluQuadricDrawStyle(quadObj, (GLenum)GLU_FILL); + gluQuadricNormals(quadObj, (GLenum)GLU_SMOOTH); + gluCylinder(quadObj, radius, radius, height, 15, 10); + glPopMatrix (); + glEndList(); + } + glPopMatrix(); + } +}; + +class Object; + +class Callback : public SM_Callback { +public: + Callback(Object& object) : m_object(object) {} + + virtual void do_me(); + +private: + Object& m_object; +}; + + +class Object { +public: + Object(GLShape *gl_shape, SM_Object& object) : + m_gl_shape(gl_shape), + m_object(object), + m_callback(*this) + { + m_object.registerCallback(m_callback); + } + + ~Object() {} + + void paint() { + m_gl_shape->paint(m); + // display_bbox(m_bbox.lower(), m_bbox.upper()); + } + + MT_Vector3 getAhead() { + return MT_Vector3(-m[8], -m[9], -m[10]); + } + + void clearMomentum() { + m_object.clearMomentum(); + } + + void setMargin(MT_Scalar margin) { + m_object.setMargin(margin); + } + + void setScaling(const MT_Vector3& scaling) { + m_object.setScaling(scaling); + } + + void setPosition(const MT_Point3& pos) { + m_object.setPosition(pos); + } + + void setOrientation(const MT_Quaternion& orn) { + m_object.setOrientation(orn); + } + + void applyCenterForce(const MT_Vector3& force) { + m_object.applyCenterForce(force); + } + + void applyTorque(const MT_Vector3& torque) { + m_object.applyTorque(torque); + } + + MT_Point3 getWorldCoord(const MT_Point3& local) const { + return m_object.getWorldCoord(local); + } + + MT_Vector3 getLinearVelocity() const { + return m_object.getLinearVelocity(); + } + + void setMatrix() { + m_object.getMatrix(m); + } + +private: + GLShape *m_gl_shape; + SM_Object& m_object; + DT_Scalar m[16]; + Callback m_callback; +}; + + +void Callback::do_me() +{ + m_object.setMatrix(); +} + + +const MT_Scalar SPACE_SIZE = 2; + +static GLSphere gl_sphere(sphere_radius); +static GLBox gl_ground(50.0, 0.0, 50.0); + + + +#ifdef USE_COMPLEX + +const int GRID_SCALE = 10; +const MT_Scalar GRID_UNIT = 25.0 / GRID_SCALE; + +DT_ShapeHandle createComplex() { + DT_ShapeHandle shape = DT_NewComplexShape(); + for (int i0 = -GRID_SCALE; i0 != GRID_SCALE; ++i0) { + for (int j0 = -GRID_SCALE; j0 != GRID_SCALE; ++j0) { + int i1 = i0 + 1; + int j1 = j0 + 1; +#ifdef QUADS + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j0); + DT_Vertex(GRID_UNIT * i0, bowl_curv * i0*i0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, bowl_curv * i1*i1, GRID_UNIT * j0); + DT_End(); +#else + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j0); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); + DT_End(); + + DT_Begin(); + DT_Vertex(GRID_UNIT * i0, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j1); + DT_Vertex(GRID_UNIT * i1, 0, GRID_UNIT * j0); + DT_End(); +#endif + + } + } + DT_EndComplexShape(); + return shape; +} + + +static DT_ShapeHandle ground_shape = createComplex(); + +#else + +static DT_ShapeHandle ground_shape = DT_Box(50, 0, 50); + +#endif + +static SM_Object sm_ground(ground_shape, &g_materialProps, 0, 0); +static Object ground(&gl_ground, sm_ground); + +static SM_Object sm_sphere(DT_Sphere(0.0), &g_materialProps, &g_shapeProps, 0); +static Object object(&gl_sphere, sm_sphere); + + +static SM_Object sm_ray(DT_Ray(0.0, -1.0, 0.0), 0, 0, 0); + +static SM_Scene g_scene; + + +void myinit(void) { + + GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 }; + GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; + GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 }; + + /* light_position is NOT default value */ + GLfloat light_position0[] = { 1.0, 1.0, 1.0, 0.0 }; + GLfloat light_position1[] = { -1.0, -1.0, -1.0, 0.0 }; + + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + + glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + + + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + // glEnable(GL_CULL_FACE); + // glCullFace(GL_BACK); + + g_scene.setForceField(gravity); + g_scene.add(sm_ground); + sm_ground.setMargin(ground_margin); + + new(&object) Object(&gl_sphere, sm_sphere); + + + object.setMargin(sphere_radius); + + g_scene.add(sm_sphere); + + ground.setPosition(MT_Point3(0, -10, 0)); + ground.setOrientation(MT_Quaternion(0, 0, 0, 1)); + ground.setMatrix(); + center.setValue(0.0, 0.0, 0.0); + + newRandom(); +} + + +//MT_Point3 cp1, cp2; +//bool intersection; + +bool g_hit = false; +MT_Point3 g_spot; +MT_Vector3 g_normal; + + +void display(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ground.paint(); + object.paint(); + + if (g_hit) { + glPointSize(5); + glBegin(GL_POINTS); + glVertex3d(g_spot[0], g_spot[1], g_spot[2]); + glEnd(); + glPointSize(1); + } + + + +#ifdef COLLISION + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glColor3f(1, 1, 0); + if (intersection) { + glPointSize(5); + glBegin(GL_POINTS); + glVertex3d(cp1[0], cp1[1], cp1[2]); + glEnd(); + glPointSize(1); + } + else { + glBegin(GL_LINES); + glVertex3d(cp1[0], cp1[1], cp1[2]); + glVertex3d(cp2[0], cp2[1], cp2[2]); + glEnd(); + } + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +#endif + + glFlush(); + glutSwapBuffers(); +} + + + + + +void newRandom() { + object.setPosition(MT_Point3(0, 0, 0)); + object.clearMomentum(); + object.setMatrix(); + + display(); +} + +void moveAndDisplay() { + g_scene.proceed(timeStep, 0.01); + + MT_Vector3 normal(0, 1, 0); + + MT_Point3 from = object.getWorldCoord(MT_Point3(0, 0, 0)); + MT_Point3 to = from - normal * 10.0; + + g_hit = DT_ObjectRayTest(sm_ground.getObjectHandle(), + from.getValue(), + to.getValue(), g_spot.getValue(), + g_normal.getValue()); + + // Scrap +#define DO_FH +#ifdef DO_FH + MT_Scalar dist = MT_distance(from, g_spot); + if (dist < 5.0) { + MT_Vector3 lin_vel = object.getLinearVelocity(); + MT_Scalar lin_vel_normal = lin_vel.dot(normal); + + MT_Scalar spring_extent = dist + lin_vel_normal * (timeStep * 0.5); + + MT_Scalar f_spring = (5.0 - spring_extent) * 3.0; + object.applyCenterForce(normal * f_spring); + object.applyCenterForce(-lin_vel_normal * normal); + } + +#endif + + + display(); +} + + +void turn_left() { + object.applyTorque(MT_Vector3(0.0, 10.0, 0.0)); +} + +void turn_right() { + object.applyTorque(MT_Vector3(0.0, -10.0, 0.0)); +} + +void forward() { + object.applyCenterForce(20.0 * object.getAhead()); +} + +void backward() { + object.applyCenterForce(-20.0 * object.getAhead()); +} + +void jump() { + object.applyCenterForce(MT_Vector3(0.0, 200.0, 0.0)); +} + + +void toggleIdle() { + static bool idle = true; + if (idle) { + glutIdleFunc(moveAndDisplay); + idle = false; + } + else { + glutIdleFunc(NULL); + idle = true; + } +} + + +void setCamera() { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 200.0); + MT_Scalar rele = MT_radians(ele); + MT_Scalar razi = MT_radians(azi); + eye.setValue(DISTANCE * sin(razi) * cos(rele), + DISTANCE * sin(rele), + DISTANCE * cos(razi) * cos(rele)); + gluLookAt(eye[0], eye[1], eye[2], + center[0], center[1], center[2], + 0, 1, 0); + glMatrixMode(GL_MODELVIEW); + display(); +} + +const MT_Scalar STEPSIZE = 5; + +void stepLeft() { azi -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } +void stepRight() { azi += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } +void stepFront() { ele += STEPSIZE; if (azi >= 360) azi -= 360; setCamera(); } +void stepBack() { ele -= STEPSIZE; if (azi < 0) azi += 360; setCamera(); } +void zoomIn() { DISTANCE -= 1; setCamera(); } +void zoomOut() { DISTANCE += 1; setCamera(); } + + +void myReshape(int w, int h) { + glViewport(0, 0, w, h); + setCamera(); +} + +void myKeyboard(unsigned char key, int x, int y) +{ + switch (key) + { + case 'w': forward(); break; + case 's': backward(); break; + case 'a': turn_left(); break; + case 'd': turn_right(); break; + case 'e': jump(); break; + case 'l' : stepLeft(); break; + case 'r' : stepRight(); break; + case 'f' : stepFront(); break; + case 'b' : stepBack(); break; + case 'z' : zoomIn(); break; + case 'x' : zoomOut(); break; + case 'i' : toggleIdle(); break; + case ' ' : newRandom(); break; + default: +// std::cout << "unused key : " << key << std::endl; + break; + } +} + +void mySpecial(int key, int x, int y) +{ + switch (key) + { + case GLUT_KEY_LEFT : stepLeft(); break; + case GLUT_KEY_RIGHT : stepRight(); break; + case GLUT_KEY_UP : stepFront(); break; + case GLUT_KEY_DOWN : stepBack(); break; + case GLUT_KEY_PAGE_UP : zoomIn(); break; + case GLUT_KEY_PAGE_DOWN : zoomOut(); break; + case GLUT_KEY_HOME : toggleIdle(); break; + default: +// std::cout << "unused (special) key : " << key << std::endl; + break; + } +} + +void goodbye( void) +{ + g_scene.remove(sm_ground); + g_scene.remove(sm_sphere); + + std::cout << "goodbye ..." << std::endl; + exit(0); +} + +void menu(int choice) +{ + + static int fullScreen = 0; + static int px, py, sx, sy; + + switch(choice) { + case 1: + if (fullScreen == 1) { + glutPositionWindow(px,py); + glutReshapeWindow(sx,sy); + glutChangeToMenuEntry(1,"Full Screen",1); + fullScreen = 0; + } else { + px=glutGet((GLenum)GLUT_WINDOW_X); + py=glutGet((GLenum)GLUT_WINDOW_Y); + sx=glutGet((GLenum)GLUT_WINDOW_WIDTH); + sy=glutGet((GLenum)GLUT_WINDOW_HEIGHT); + glutFullScreen(); + glutChangeToMenuEntry(1,"Close Full Screen",1); + fullScreen = 1; + } + break; + case 2: + toggleIdle(); + break; + case 3: + goodbye(); + break; + default: + break; + } +} + +void createMenu() +{ + glutCreateMenu(menu); + glutAddMenuEntry("Full Screen", 1); + glutAddMenuEntry("Toggle Idle (Start/Stop)", 2); + glutAddMenuEntry("Quit", 3); + glutAttachMenu(GLUT_RIGHT_BUTTON); +} + +int main(int argc, char **argv) { + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowPosition(0, 0); + glutInitWindowSize(500, 500); + glutCreateWindow("Physics demo"); + + myinit(); + glutKeyboardFunc(myKeyboard); + glutSpecialFunc(mySpecial); + glutReshapeFunc(myReshape); + createMenu(); + glutIdleFunc(NULL); + + glutDisplayFunc(display); + glutMainLoop(); + return 0; +} + + + + + + + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile b/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile new file mode 100644 index 00000000000..5e3b35f6cf4 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/src/Makefile @@ -0,0 +1,13 @@ +# +# $Id$ +# Copyright (C) 2001 NaN Technologies B.V. + +LIBNAME = fuzzics +DIR = $(OCGDIR)/sumo + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I../include -I$(NAN_MOTO)/include -I../../include + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp new file mode 100644 index 00000000000..f8be49aa126 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_FhObject.cpp @@ -0,0 +1,115 @@ +#include "SM_FhObject.h" +#include "MT_MinMax.h" + +void SM_FhObject::ray_hit(void *client_data, + void *client_object1, + void *client_object2, + const DT_CollData *coll_data) { + + SM_Object *hit_object = (SM_Object *)client_object1; + const SM_MaterialProps *matProps = hit_object->getMaterialProps(); + + if ((matProps == 0) || (matProps->m_fh_distance < MT_EPSILON)) { + return; + } + + SM_FhObject *fh_object = (SM_FhObject *)client_object2; + SM_Object *cl_object = fh_object->getClientObject(); + + if (hit_object == cl_object) { + // Shot myself in the foot... + return; + } + + const SM_ShapeProps *shapeProps = cl_object->getShapeProps(); + + // Exit if the client object is not dynamic. + if (shapeProps == 0) { + return; + } + + MT_Point3 lspot; + MT_Vector3 normal; + + if (DT_ObjectRayTest(hit_object->getObjectHandle(), + fh_object->getPosition().getValue(), + fh_object->getSpot().getValue(), + lspot.getValue(), normal.getValue())) { + + const MT_Vector3& ray_dir = fh_object->getRayDirection(); + MT_Scalar dist = MT_distance(fh_object->getPosition(), + hit_object->getWorldCoord(lspot)) - + cl_object->getMargin(); + + normal.normalize(); + + if (dist < matProps->m_fh_distance) { + + if (shapeProps->m_do_fh) { + MT_Vector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocity(lspot); + MT_Scalar rel_vel_ray = ray_dir.dot(rel_vel); + MT_Scalar spring_extent = 1.0 - dist / matProps->m_fh_distance; + + MT_Scalar i_spring = spring_extent * matProps->m_fh_spring; + MT_Scalar i_damp = rel_vel_ray * matProps->m_fh_damping; + + cl_object->addLinearVelocity(-(i_spring + i_damp) * ray_dir); + if (matProps->m_fh_normal) { + cl_object->addLinearVelocity( + (i_spring + i_damp) * + (normal - normal.dot(ray_dir) * ray_dir)); + } + + MT_Vector3 lateral = rel_vel - rel_vel_ray * ray_dir; + const SM_ShapeProps *shapeProps = cl_object->getShapeProps(); + + if (shapeProps->m_do_anisotropic) { + MT_Matrix3x3 lcs(cl_object->getOrientation()); + MT_Vector3 loc_lateral = lateral * lcs; + const MT_Vector3& friction_scaling = + shapeProps->m_friction_scaling; + + loc_lateral.scale(friction_scaling[0], + friction_scaling[1], + friction_scaling[2]); + lateral = lcs * loc_lateral; + } + + + MT_Scalar rel_vel_lateral = lateral.length(); + + if (rel_vel_lateral > MT_EPSILON) { + MT_Scalar friction_factor = matProps->m_friction; + MT_Scalar max_friction = friction_factor * MT_max(0.0, i_spring); + + MT_Scalar rel_mom_lateral = rel_vel_lateral / + cl_object->getInvMass(); + + MT_Vector3 friction = + (rel_mom_lateral > max_friction) ? + -lateral * (max_friction / rel_vel_lateral) : + -lateral; + + cl_object->applyCenterImpulse(friction); + } + } + + if (shapeProps->m_do_rot_fh) { + const double *ogl_mat = cl_object->getMatrix(); + MT_Vector3 up(&ogl_mat[8]); + MT_Vector3 t_spring = up.cross(normal) * matProps->m_fh_spring; + MT_Vector3 ang_vel = cl_object->getAngularVelocity(); + + // only rotations that tilt relative to the normal are damped + ang_vel -= ang_vel.dot(normal) * normal; + + MT_Vector3 t_damp = ang_vel * matProps->m_fh_damping; + + cl_object->addAngularVelocity(t_spring - t_damp); + } + } + } +} + + + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp new file mode 100644 index 00000000000..655590c2086 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Object.cpp @@ -0,0 +1,953 @@ +/** + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * The basic physics object. + */ + +#ifdef WIN32 +// This warning tells us about truncation of __long__ stl-generated names. +// It can occasionally cause DevStudio to have internal compiler warnings. +#pragma warning( disable : 4786 ) +#endif + +#include "SM_Object.h" +#include "SM_Scene.h" +#include "SM_FhObject.h" + +#include "MT_MinMax.h" + + +// Tweak parameters +static MT_Scalar ImpulseThreshold = 0.5; + +SM_Object::SM_Object( + DT_ShapeHandle shape, + const SM_MaterialProps *materialProps, + const SM_ShapeProps *shapeProps, + SM_Object *dynamicParent +) : + m_shape(shape), + m_materialProps(materialProps), + m_materialPropsBackup(0), + m_shapeProps(shapeProps), + m_shapePropsBackup(0), + m_dynamicParent(dynamicParent), + m_object(DT_CreateObject(this, shape)), + m_margin(0.0), + m_scaling(1.0, 1.0, 1.0), + m_reaction_impulse(0.0, 0.0, 0.0), + m_reaction_force(0.0, 0.0, 0.0), + m_kinematic(false), + m_prev_kinematic(false), + m_is_rigid_body(false), + m_lin_mom(0.0, 0.0, 0.0), + m_ang_mom(0.0, 0.0, 0.0), + m_force(0.0, 0.0, 0.0), + m_torque(0.0, 0.0, 0.0), + m_client_object(0), + m_fh_object(0), + + m_combined_lin_vel (0.0, 0.0, 0.0), + m_combined_ang_vel (0.0, 0.0, 0.0) +{ + m_xform.setIdentity(); + m_xform.getValue(m_ogl_matrix); + if (shapeProps && + (shapeProps->m_do_fh || shapeProps->m_do_rot_fh)) { + MT_Vector3 ray(0.0, 0.0, -10.0); + m_fh_object = new SM_FhObject(ray, this); + } + m_suspended = false; +} + + + void +SM_Object:: +integrateForces( + MT_Scalar timeStep +){ + if (!m_suspended) { + m_prev_state = *this; + m_prev_state.setLinearVelocity(actualLinVelocity()); + m_prev_state.setAngularVelocity(actualAngVelocity()); + if (isDynamic()) { + // Integrate momentum (forward Euler) + m_lin_mom += m_force * timeStep; + m_ang_mom += m_torque * timeStep; + // Drain momentum because of air/water resistance + m_lin_mom *= pow(m_shapeProps->m_lin_drag, timeStep); + m_ang_mom *= pow(m_shapeProps->m_ang_drag, timeStep); + // Set velocities according momentum + m_lin_vel = m_lin_mom / m_shapeProps->m_mass; + m_ang_vel = m_ang_mom / m_shapeProps->m_inertia; + } + } + +}; + + void +SM_Object:: +integrateMomentum( + MT_Scalar timeStep +){ + // Integrate position and orientation + + // only do it for objects with linear and/or angular velocity + // else clients with hierarchies may get into trouble + if (!actualLinVelocity().fuzzyZero() || !actualAngVelocity().fuzzyZero()) + { + + // those MIDPOINT and BACKWARD integration methods are + // in this form not ok with some testfiles ! + // For a release build please use forward euler unless completely tested +[ +//#define MIDPOINT +//#define BACKWARD +#ifdef MIDPOINT +// Midpoint rule + m_pos += (m_prev_state.getLinearVelocity() + actualLinVelocity()) * (timeStep * 0.5); + m_orn += (m_prev_state.getAngularVelocity() * m_prev_state.getOrientation() + actualAngVelocity() * m_orn) * (timeStep * 0.25); +#elif defined BACKWARD +// Backward Euler + m_pos += actualLinVelocity() * timeStep; + m_orn += actualAngVelocity() * m_orn * (timeStep * 0.5); +#else +// Forward Euler + + m_pos += m_prev_state.getLinearVelocity() * timeStep; + m_orn += m_prev_state.getAngularVelocity() * m_orn * (timeStep * 0.5); +#endif + m_orn.normalize(); // I might not be necessary to do this every call + + calcXform(); + notifyClient(); + + } +} + + +void SM_Object::boing( + void *client_data, + void *object1, + void *object2, + const DT_CollData *coll_data +){ + SM_Scene *scene = (SM_Scene *)client_data; + SM_Object *obj1 = (SM_Object *)object1; + SM_Object *obj2 = (SM_Object *)object2; + + scene->addPair(obj1, obj2); // Record this collision for client callbacks + + + // If one of the objects is a ghost then ignore it for the dynamics + if (obj1->isGhost() || obj2->isGhost()) { + return; + } + + + if (!obj2->isDynamic()) { + std::swap(obj1, obj2); + } + + if (!obj2->isDynamic()) { + return; + } + + // obj1 points to a dynamic object + + + // This distinction between dynamic and non-dynamic objects should not be + // necessary. Non-dynamic objects are assumed to have infinite mass. + + if (obj1->isDynamic()) { + // normal to the contact plane + MT_Vector3 normal = obj2->m_pos - obj1->m_pos; + MT_Scalar dist = normal.length(); + + if (MT_EPSILON < dist && dist <= obj1->getMargin() + obj2->getMargin()) + { + normal /= dist; + // relative velocity of the contact points + MT_Vector3 rel_vel = obj2->actualLinVelocity() - obj1->actualLinVelocity(); + // relative velocity projected onto the normal + MT_Scalar rel_vel_normal = normal.dot(rel_vel); + + // if the objects are approaching eachother... + if (rel_vel_normal < 0.0) { + MT_Scalar restitution; + // ...and the approaching velocity is large enough... + if (-rel_vel_normal > ImpulseThreshold) { + // ...this must be a true collision. + restitution = + MT_min(obj1->getMaterialProps()->m_restitution, + obj2->getMaterialProps()->m_restitution); + } + else { + // otherwise, it is a resting contact, and thus the + // relative velocity must be made zero + restitution = 0.0; + // We also need to interfere with the positions of the + // objects, otherwise they might drift into eachother. + MT_Vector3 penalty = normal * + (0.5 * (obj1->getMargin() + obj2->getMargin() - dist)); + obj1->m_pos -= penalty; + obj2->m_pos += penalty; + } + + // Compute the impulse necessary to yield the desired relative velocity... + MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal / + (obj1->getInvMass() + obj2->getInvMass()); + + // ... and apply it. + obj1->applyCenterImpulse(-impulse * normal); + obj2->applyCenterImpulse( impulse * normal); + } + } + } + else { + // Same again but now obj1 is non-dynamic + + // Compute the point on obj1 closest to obj2 (= sphere with radius = 0) + MT_Point3 local1, local2; + MT_Scalar dist = DT_GetClosestPair(obj1->m_object, obj2->m_object, + local1.getValue(), local2.getValue()); + + // local1 is th point closest to obj2 + // local2 is the local origin of obj2 + + if (MT_EPSILON < dist && dist <= obj2->getMargin()) { + MT_Point3 world1 = obj1->getWorldCoord(local1); + MT_Point3 world2 = obj2->getWorldCoord(local2); + MT_Vector3 vel1 = obj1->getVelocity(local1) + obj1->m_combined_lin_vel; + MT_Vector3 vel2 = obj2->getVelocity(local2) + obj2->m_combined_lin_vel; + + // the normal to the contact plane + MT_Vector3 normal = world2 - world1; + normal /= dist; + + // wr2 points from obj2's origin to the global contact point + // wr2 is only needed for rigid bodies (objects for which the + // friction can change the angular momentum). + // vel2 is adapted to denote the velocity of the contact point + MT_Vector3 wr2; + if (obj2->isRigidBody()) { + wr2 = -obj2->getMargin() * normal; + vel2 += obj2->actualAngVelocity().cross(wr2); + } + + + // This should look familiar.... + MT_Vector3 rel_vel = vel2 - vel1; + MT_Scalar rel_vel_normal = normal.dot(rel_vel); + + if (rel_vel_normal < 0.0) { + MT_Scalar restitution; + if (-rel_vel_normal > ImpulseThreshold) { + restitution = + MT_min(obj1->getMaterialProps()->m_restitution, + obj2->getMaterialProps()->m_restitution); + } + else { + restitution = 0.0; + // We fix drift by moving obj2 only, since obj1 was + // non-dynamic. + obj2->m_pos += normal * (obj2->getMargin() - dist); + + } + + MT_Scalar impulse = -(1.0 + restitution) * rel_vel_normal / + (obj1->getInvMass() + obj2->getInvMass()); + + + obj2->applyCenterImpulse( impulse * normal); + +// The friction part starts here!!!!!!!! + + // Compute the lateral component of the relative velocity + // lateral actually points in the opposite direction, i.e., + // into the direction of the friction force. + +#if 1 + // test - only do friction on the physics part of the + // velocity. + vel1 -= obj1->m_combined_lin_vel; + vel2 -= obj2->m_combined_lin_vel; + + // This should look familiar.... + rel_vel = vel2 - vel1; + rel_vel_normal = normal.dot(rel_vel); +#endif + + MT_Vector3 lateral = normal * rel_vel_normal - rel_vel; + + const SM_ShapeProps *shapeProps = obj2->getShapeProps(); + + if (shapeProps->m_do_anisotropic) { + + // For anisotropic friction we scale the lateral component, + // rather than compute a direction-dependent fricition + // factor. For this the lateral component is transformed to + // local coordinates. + + MT_Matrix3x3 lcs(obj2->m_orn); + // We cannot use m_xform.getBasis() for the matrix, since + // it might contain a non-uniform scaling. + // OPT: it's a bit daft to compute the matrix since the + // quaternion itself can be used to do the transformation. + + MT_Vector3 loc_lateral = lateral * lcs; + // lcs is orthogonal so lcs.inversed() == lcs.transposed(), + // and lcs.transposed() * lateral == lateral * lcs. + + const MT_Vector3& friction_scaling = + shapeProps->m_friction_scaling; + + // Scale the local lateral... + loc_lateral.scale(friction_scaling[0], + friction_scaling[1], + friction_scaling[2]); + // ... and transform it back to global coordinates + lateral = lcs * loc_lateral; + } + + // A tiny Coulomb friction primer: + // The Coulomb friction law states that the magnitude of the + // maximum possible friction force depends linearly on the + // magnitude of the normal force. + // + // F_max_friction = friction_factor * F_normal + // + // (NB: independent of the contact area!!) + // + // The friction factor depends on the material. + // We use impulses rather than forces but let us not be + // bothered by this. + + + MT_Scalar rel_vel_lateral = lateral.length(); + + if (rel_vel_lateral > MT_EPSILON) { + lateral /= rel_vel_lateral; + + MT_Scalar friction_factor = + MT_min(obj1->getMaterialProps()->m_friction, + obj2->getMaterialProps()->m_friction); + + // Compute the maximum friction impulse + + MT_Scalar max_friction = + friction_factor * MT_max(0.0, impulse); + + // I guess the GEN_max is not necessary, so let's check it + + assert(impulse >= 0.0); + + // Here's the trick. We compute the impulse to make the + // lateral velocity zero. (Make the objects stick together + // at the contact point. If this impulse is larger than + // the maximum possible friction impulse, then shrink its + // magnitude to the maximum friction. + + if (obj2->isRigidBody()) { + + // For rigid bodies we take the inertia into account, + // since the friciton impulse is going to change the + // angular momentum as well. + MT_Scalar impulse_lateral = rel_vel_lateral / + (obj1->getInvMass() + obj2->getInvMass() + + ((obj2->getInvInertia() * wr2.cross(lateral)).cross(wr2)).dot(lateral)); + MT_Scalar friction = MT_min(impulse_lateral, max_friction); + obj2->applyImpulse(world2 + wr2, friction * lateral); + } + else { + MT_Scalar impulse_lateral = rel_vel_lateral / + (obj1->getInvMass() + obj2->getInvMass()); + + MT_Scalar friction = MT_min(impulse_lateral, max_friction); + obj2->applyCenterImpulse( friction * lateral); + } + } + + obj2->calcXform(); + obj2->notifyClient(); + } + } + } +} + + + +SM_Object::SM_Object( +) { + // warning no initialization of variables done by moto. +} + +SM_Object:: +~SM_Object() { + delete m_fh_object; + DT_DeleteObject(m_object); +} + + bool +SM_Object:: +isDynamic( +) const { + return m_shapeProps != 0; +} + +/* nzc experimental. There seem to be two places where kinematics + * are evaluated: proceedKinematic (called from SM_Scene) and + * proceed() in this object. I'll just try and bunge these out for + * now. */ + void +SM_Object:: +suspend( +){ + if (!m_suspended) { + m_suspended = true; + suspendDynamics(); + } +} + + void +SM_Object:: +resume( +) { + if (m_suspended) { + m_suspended = false; + restoreDynamics(); + } +} + + void +SM_Object:: +suspendDynamics( +) { + if (m_shapeProps) { + m_shapePropsBackup = m_shapeProps; + m_shapeProps = 0; + } +} + + void +SM_Object:: +restoreDynamics( +) { + if (m_shapePropsBackup) { + m_shapeProps = m_shapePropsBackup; + m_shapePropsBackup = 0; + } +} + + bool +SM_Object:: +isGhost( +) const { + return m_materialProps == 0; +} + + void +SM_Object:: +suspendMaterial( +) { + if (m_materialProps) { + m_materialPropsBackup = m_materialProps; + m_materialProps = 0; + } +} + + void +SM_Object:: +restoreMaterial( +) { + if (m_materialPropsBackup) { + m_materialProps = m_materialPropsBackup; + m_materialPropsBackup = 0; + } +} + + SM_FhObject * +SM_Object:: +getFhObject( +) const { + return m_fh_object; +} + + void +SM_Object:: +registerCallback( + SM_Callback& callback +) { + m_callbackList.push_back(&callback); +} + +// Set the local coordinate system according to the current state + void +SM_Object:: +calcXform() { + m_xform.setOrigin(m_pos); + m_xform.setBasis(MT_Matrix3x3(m_orn, m_scaling)); + m_xform.getValue(m_ogl_matrix); + DT_SetMatrixd(m_object, m_ogl_matrix); + if (m_fh_object) { + m_fh_object->setPosition(m_pos); + m_fh_object->calcXform(); + } +} + +// Call callbacks to notify the client of a change of placement + void +SM_Object:: +notifyClient() { + T_CallbackList::iterator i; + for (i = m_callbackList.begin(); i != m_callbackList.end(); ++i) { + (*i)->do_me(); + } +} + + +// Save the current state information for use in the velocity computation in the next frame. + void +SM_Object:: +proceedKinematic( + MT_Scalar timeStep +) { + /* nzc: need to bunge this for the logic bubbling as well? */ + if (!m_suspended) { + m_prev_kinematic = m_kinematic; + if (m_kinematic) { + m_prev_xform = m_xform; + m_timeStep = timeStep; + calcXform(); + m_kinematic = false; + } + } +} + + void +SM_Object:: +saveReactionForce( + MT_Scalar timeStep +) { + if (isDynamic()) { + m_reaction_force = m_reaction_impulse / timeStep; + m_reaction_impulse.setValue(0.0, 0.0, 0.0); + } +} + + void +SM_Object:: +clearForce( +) { + m_force.setValue(0.0, 0.0, 0.0); + m_torque.setValue(0.0, 0.0, 0.0); +} + + void +SM_Object:: +clearMomentum( +) { + m_lin_mom.setValue(0.0, 0.0, 0.0); + m_ang_mom.setValue(0.0, 0.0, 0.0); +} + + void +SM_Object:: +setMargin( + MT_Scalar margin +) { + m_margin = margin; + DT_SetMargin(m_object, margin); +} + + MT_Scalar +SM_Object:: +getMargin( +) const { + return m_margin; +} + +const + SM_MaterialProps * +SM_Object:: +getMaterialProps( +) const { + return m_materialProps; +} + +const + SM_ShapeProps * +SM_Object:: +getShapeProps( +) const { + return m_shapeProps; +} + + void +SM_Object:: +setPosition( + const MT_Point3& pos +){ + m_kinematic = true; + m_pos = pos; +} + + void +SM_Object:: +setOrientation( + const MT_Quaternion& orn +){ + assert(!orn.fuzzyZero()); + m_kinematic = true; + m_orn = orn; +} + + void +SM_Object:: +setScaling( + const MT_Vector3& scaling +){ + m_kinematic = true; + m_scaling = scaling; +} + +/** + * Functions to handle linear velocity + */ + + void +SM_Object:: +setExternalLinearVelocity( + const MT_Vector3& lin_vel +) { + m_combined_lin_vel=lin_vel; +} + + void +SM_Object:: +addExternalLinearVelocity( + const MT_Vector3& lin_vel +) { + m_combined_lin_vel+=lin_vel; +} + + void +SM_Object:: +addLinearVelocity( + const MT_Vector3& lin_vel +){ + m_lin_vel += lin_vel; + if (m_shapeProps) { + m_lin_mom = m_lin_vel * m_shapeProps->m_mass; + } +} + + void +SM_Object:: +setLinearVelocity( + const MT_Vector3& lin_vel +){ + m_lin_vel = lin_vel; + if (m_shapeProps) { + m_lin_mom = m_lin_vel * m_shapeProps->m_mass; + } +} + +/** + * Functions to handle angular velocity + */ + + void +SM_Object:: +setExternalAngularVelocity( + const MT_Vector3& ang_vel +) { + m_combined_ang_vel = ang_vel; +} + + void +SM_Object:: +addExternalAngularVelocity( + const MT_Vector3& ang_vel +) { + m_combined_ang_vel += ang_vel; +} + + void +SM_Object:: +setAngularVelocity( + const MT_Vector3& ang_vel +) { + m_ang_vel = ang_vel; + if (m_shapeProps) { + m_ang_mom = m_ang_vel * m_shapeProps->m_inertia; + } +} + + void +SM_Object:: +addAngularVelocity( + const MT_Vector3& ang_vel +) { + m_ang_vel += ang_vel; + if (m_shapeProps) { + m_ang_mom = m_ang_vel * m_shapeProps->m_inertia; + } +} + + + void +SM_Object:: +clearCombinedVelocities( +) { + m_combined_lin_vel = MT_Vector3(0,0,0); + m_combined_ang_vel = MT_Vector3(0,0,0); +} + + void +SM_Object:: +resolveCombinedVelocities( + const MT_Vector3 & lin_vel, + const MT_Vector3 & ang_vel +) { + + // Different behaviours for dynamic and non-dynamic + // objects. For non-dynamic we just set the velocity to + // zero. For dynmic the physics velocity has to be + // taken into account. We must make an arbitrary decision + // on how to resolve the 2 velocities. Choices are + // Add the physics velocity to the linear velocity. Objects + // will just keep on moving in the direction they were + // last set in - untill external forces affect them. + // Set the combinbed linear and physics velocity to zero. + // Set the physics velocity in the direction of the set velocity + // zero. + if (isDynamic()) { + +#if 1 + m_lin_vel += lin_vel; + m_ang_vel += ang_vel; +#else + + //compute the component of the physics velocity in the + // direction of the set velocity and set it to zero. + MT_Vector3 lin_vel_norm = lin_vel.normalized(); + + m_lin_vel -= (m_lin_vel.dot(lin_vel_norm) * lin_vel_norm); +#endif + m_lin_mom = m_lin_vel * m_shapeProps->m_mass; + m_ang_mom = m_ang_vel * m_shapeProps->m_inertia; + clearCombinedVelocities(); + + } + +} + + + MT_Scalar +SM_Object:: +getInvMass( +) const { + return m_shapeProps ? 1.0 / m_shapeProps->m_mass : 0.0; + // OPT: cache the result of this division rather than compute it each call +} + + MT_Scalar +SM_Object:: +getInvInertia( +) const { + return m_shapeProps ? 1.0 / m_shapeProps->m_inertia : 0.0; + // OPT: cache the result of this division rather than compute it each call +} + + void +SM_Object:: +applyForceField( + const MT_Vector3& accel +) { + if (m_shapeProps) { + m_force += m_shapeProps->m_mass * accel; // F = m * a + } +} + + void +SM_Object:: +applyCenterForce( + const MT_Vector3& force +) { + m_force += force; +} + + void +SM_Object:: +applyTorque( + const MT_Vector3& torque +) { + m_torque += torque; +} + + void +SM_Object:: +applyImpulse( + const MT_Point3& attach, const MT_Vector3& impulse +) { + applyCenterImpulse(impulse); // Change in linear momentum + applyAngularImpulse((attach - m_pos).cross(impulse)); // Change in angular momentump +} + + void +SM_Object:: +applyCenterImpulse( + const MT_Vector3& impulse +) { + if (m_shapeProps) { + m_lin_mom += impulse; + m_reaction_impulse += impulse; + m_lin_vel = m_lin_mom / m_shapeProps->m_mass; + + // The linear velocity is immedialtely updated since otherwise + // simultaneous collisions will get a double impulse. + } +} + + void +SM_Object:: +applyAngularImpulse( + const MT_Vector3& impulse +) { + if (m_shapeProps) { + m_ang_mom += impulse; + m_ang_vel = m_ang_mom / m_shapeProps->m_inertia; + } +} + + MT_Point3 +SM_Object:: +getWorldCoord( + const MT_Point3& local +) const { + return m_xform(local); +} + + MT_Vector3 +SM_Object:: +getVelocity( + const MT_Point3& local +) const { + // For displaced objects the velocity is faked using the previous state. + // Dynamic objects get their own velocity, not the faked velocity. + // (Dynamic objects shouldn't be displaced in the first place!!) + + return m_prev_kinematic && !isDynamic() ? + (m_xform(local) - m_prev_xform(local)) / m_timeStep : + m_lin_vel + m_ang_vel.cross(m_xform.getBasis() * local); + + // NB: m_xform.getBasis() * local == m_xform(local) - m_xform.getOrigin() + +} + + +const + MT_Vector3& +SM_Object:: +getReactionForce( +) const { + return m_reaction_force; +} + + void +SM_Object:: +getMatrix( + double *m +) const { + std::copy(&m_ogl_matrix[0], &m_ogl_matrix[16], &m[0]); +} + +const + double * +SM_Object:: +getMatrix( +) const { + return m_ogl_matrix; +} + +// Still need this??? +const + MT_Transform& +SM_Object:: +getScaledTransform( +) const { + return m_xform; +} + + DT_ObjectHandle +SM_Object:: +getObjectHandle( +) const { + return m_object; +} + + DT_ShapeHandle +SM_Object:: +getShapeHandle( +) const { + return m_shape; +} + + void +SM_Object:: +setClientObject( + void *clientobj +) { + m_client_object = clientobj; +} + + void * +SM_Object:: +getClientObject( +){ + return m_client_object; +} + + SM_Object * +SM_Object:: +getDynamicParent( +) { + return m_dynamicParent; +} + + void +SM_Object:: +setRigidBody( + bool is_rigid_body +) { + m_is_rigid_body = is_rigid_body; +} + + bool +SM_Object:: +isRigidBody( +) const { + return m_is_rigid_body; +} + +const + MT_Vector3 +SM_Object:: +actualLinVelocity( +) const { + return m_combined_lin_vel + m_lin_vel; +}; + +const + MT_Vector3 +SM_Object:: +actualAngVelocity( +) const { + return m_combined_ang_vel + m_ang_vel; +}; + + + + + diff --git a/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp new file mode 100644 index 00000000000..e3eb7e5c5ea --- /dev/null +++ b/source/gameengine/Physics/Sumo/Fuzzics/src/SM_Scene.cpp @@ -0,0 +1,179 @@ +/** + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * The physics scene. + */ + +#ifdef WIN32 +#pragma warning(disable : 4786) // shut off 255 char limit debug template warning +#endif + +#include "SM_Scene.h" +#include "SM_Object.h" +#include "SM_FhObject.h" + +#include <algorithm> + +void SM_Scene::add(SM_Object& object) { + object.calcXform(); + m_objectList.push_back(&object); + DT_AddObject(m_scene, object.getObjectHandle()); + if (object.isDynamic()) { + DT_SetObjectResponse(m_respTable, object.getObjectHandle(), + SM_Object::boing, DT_SIMPLE_RESPONSE, this); + } + + if (object.getDynamicParent()) { + DT_SetPairResponse(m_respTable, object.getObjectHandle(), + object.getDynamicParent()->getObjectHandle(), + 0, DT_NO_RESPONSE, 0); + } + SM_FhObject *fh_object = object.getFhObject(); + + if (fh_object) { + DT_AddObject(m_scene, fh_object->getObjectHandle()); + DT_SetObjectResponse(m_respTable, fh_object->getObjectHandle(), + SM_FhObject::ray_hit, DT_SIMPLE_RESPONSE, this); + } +} + +void SM_Scene::remove(SM_Object& object) { + T_ObjectList::iterator i = + std::find(m_objectList.begin(), m_objectList.end(), &object); + if (!(i == m_objectList.end())) + { + std::swap(*i, m_objectList.back()); + m_objectList.pop_back(); + DT_RemoveObject(m_scene, object.getObjectHandle()); + if (object.isDynamic()) { + DT_ClearObjectResponse(m_respTable, object.getObjectHandle()); + } + + if (object.getDynamicParent()) { + DT_ClearPairResponse(m_respTable, object.getObjectHandle(), + object.getDynamicParent()->getObjectHandle()); + } + + SM_FhObject *fh_object = object.getFhObject(); + + if (fh_object) { + DT_RemoveObject(m_scene, fh_object->getObjectHandle()); + DT_ClearObjectResponse(m_respTable, + fh_object->getObjectHandle()); + } + } + else { + // tried to remove an object that is not in the scene + //assert(false); + } +} + +void SM_Scene::proceed(MT_Scalar timeStep, MT_Scalar subSampling) { + // Don't waste time...but it's OK to spill a little. + if (timeStep < 0.001) + return; + + // Divide the timeStep into a number of subsamples of size roughly + // equal to subSampling (might be a little smaller). + int num_samples = (int)ceil(timeStep / subSampling); + + + MT_Scalar subStep = timeStep / num_samples; + T_ObjectList::iterator i; + + // Apply a forcefield (such as gravity) + for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { + (*i)->applyForceField(m_forceField); + } + + // Do the integration steps per object. + int step; + for (step = 0; step != num_samples; ++step) { + + for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { + (*i)->integrateForces(subStep); + } + + // And second we update the object positions by performing + // an integration step for each object + for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { + (*i)->integrateMomentum(subStep); + } +#if 0 + // I changed the order of the next 2 statements. + // Originally objects were first integrated with a call + // to proceed(). However if external objects were + // directly manipulating the velocities etc of physics + // objects then the physics environment would not be able + // to react before object positions were updated. --- Laurence. + + // So now first we let the physics scene respond to + // new forces, velocities set externally. +#endif + // The collsion and friction impulses are computed here. + DT_Test(m_scene, m_respTable); + + } + + + // clear the user set velocities. +#if 0 + clearObjectCombinedVelocities(); +#endif + // Finish this timestep by saving al state information for the next + // timestep and clearing the accumulated forces. + + for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { + (*i)->proceedKinematic(timeStep); + (*i)->saveReactionForce(timeStep); + (*i)->clearForce(); + } + + // For each pair of object that collided, call the corresponding callback. + // Additional collisions of a pair within the same time step are ignored. + + if (m_secondaryRespTable) { + T_PairList::iterator p; + for (p = m_pairList.begin(); p != m_pairList.end(); ++p) { + DT_CallResponse(m_secondaryRespTable, + (*p).first->getObjectHandle(), + (*p).second->getObjectHandle(), + 0); + } + } + + clearPairs(); +} + +SM_Object *SM_Scene::rayTest(void *ignore_client, + const MT_Point3& from, const MT_Point3& to, + MT_Point3& result, MT_Vector3& normal) const { + MT_Point3 local; + + SM_Object *hit_object = (SM_Object *) + DT_RayTest(m_scene, ignore_client, from.getValue(), to.getValue(), + local.getValue(), normal.getValue()); + + if (hit_object) { + result = hit_object->getWorldCoord(local); + } + + return hit_object; +} + +void SM_Scene::clearObjectCombinedVelocities() { + + T_ObjectList::iterator i; + + for (i = m_objectList.begin(); i != m_objectList.end(); ++i) { + + (*i)->clearCombinedVelocities(); + + } + +} + + + + + diff --git a/source/gameengine/Physics/Sumo/Makefile b/source/gameengine/Physics/Sumo/Makefile new file mode 100644 index 00000000000..3e5aca1d577 --- /dev/null +++ b/source/gameengine/Physics/Sumo/Makefile @@ -0,0 +1,47 @@ +# +# $Id$ +# +# ***** BEGIN GPL/BL DUAL 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. The Blender +# Foundation also sells licenses for use in proprietary software under +# the Blender License. See http://www.blender.org/BL/ for information +# about this. +# +# 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) 2001-2002 by NaN Holding BV. +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL/BL DUAL LICENSE BLOCK ***** +# +# + +LIBNAME = sumo +DIR = $(OCGDIR)/gameengine/blphys/$(LIBNAME) + +include nan_compile.mk + +CCFLAGS += $(LEVEL_1_CPP_WARNINGS) + +CPPFLAGS += -I$(OPENGL_HEADERS) +CPPFLAGS += -I$(NAN_STRING)/include +CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION) +CPPFLAGS += -I$(NAN_FUZZICS)/include -I$(NAN_SUMO)/include -I$(NAN_MOTO)/include +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include +CPPFLAGS += -I../../Physics/common +CPPFLAGS += -I../../Physics/Dummy diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp new file mode 100644 index 00000000000..2b2c5b81856 --- /dev/null +++ b/source/gameengine/Physics/Sumo/SumoPhysicsController.cpp @@ -0,0 +1,462 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include "SumoPhysicsController.h" +#include "PHY_IMotionState.h" +#include "SM_Object.h" +#include "MT_Quaternion.h" + + +SumoPhysicsController::SumoPhysicsController( + class SM_Scene* sumoScene, + DT_SceneHandle solidscene, + class SM_Object* sumoObj, + class PHY_IMotionState* motionstate, + + bool dyna) + : + m_sumoScene(sumoScene), + m_solidscene(solidscene), + m_sumoObj(sumoObj) , + m_bFirstTime(true), + m_MotionState(motionstate), + m_bDyna(dyna) +{ + if (m_sumoObj) + { + m_sumoObj->setClientObject(this); + //if it is a dyna, register for a callback + m_sumoObj->registerCallback(*this); + } +}; + + + +SumoPhysicsController::~SumoPhysicsController() +{ + if (m_sumoObj) + { + m_sumoScene->remove(*m_sumoObj); + + + DT_ObjectHandle objhandle = (DT_ObjectHandle) m_sumoObj->getObjectHandle(); + if (objhandle) + { + DT_RemoveObject(m_solidscene,objhandle); + } + delete m_sumoObj; + } +} + +float SumoPhysicsController::getMass() +{ + if (m_sumoObj) + { + const SM_ShapeProps *shapeprops = m_sumoObj->getShapeProps(); + return shapeprops->m_mass; + } + return 0.f; +} + +bool SumoPhysicsController::SynchronizeMotionStates(float time) +{ + + if (m_bFirstTime) + { + setSumoTransform(false); + m_bFirstTime = false; + } + + if (!m_bDyna) + { + if (m_sumoObj) + { + MT_Point3 pos; + GetWorldPosition(pos); + + m_sumoObj->setPosition(pos); + if (m_bDyna) + { + m_sumoObj->setScaling(MT_Vector3(1,1,1)); + } else + { + MT_Vector3 scaling; + GetWorldScaling(scaling); + m_sumoObj->setScaling(scaling); + } + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + m_sumoObj->setOrientation(orn.getRotation()); + m_sumoObj->calcXform(); + } + } + return false; // physics object are not part of + // hierarchy, or ignore it ?? +} + + + + +void SumoPhysicsController::GetWorldOrientation(MT_Matrix3x3& mat) +{ + float orn[4]; + m_MotionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); + MT_Quaternion quat(orn); + mat.setRotation(quat); + +} + +void SumoPhysicsController::GetWorldPosition(MT_Point3& pos) +{ + float worldpos[3]; + m_MotionState->getWorldPosition(worldpos[0],worldpos[1],worldpos[2]); + pos[0]=worldpos[0]; + pos[1]=worldpos[1]; + pos[2]=worldpos[2]; +} + +void SumoPhysicsController::GetWorldScaling(MT_Vector3& scale) +{ + float worldscale[3]; + m_MotionState->getWorldScaling(worldscale[0],worldscale[1],worldscale[2]); + scale[0]=worldscale[0]; + scale[1]=worldscale[1]; + scale[2]=worldscale[2]; +} + + + // kinematic methods +void SumoPhysicsController::RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local) +{ + + + if (m_sumoObj) + { + MT_Matrix3x3 mat; + GetWorldOrientation(mat); + MT_Vector3 dloc(dlocX,dlocY,dlocZ); + + MT_Point3 newpos = m_sumoObj->getPosition(); + newpos += (local ? mat * dloc : dloc); + m_sumoObj->setPosition(newpos); + } + +} +void SumoPhysicsController::RelativeRotate(const float drot[9],bool local) +{ + + if (m_sumoObj ) + { + MT_Matrix3x3 drotmat(drot); + MT_Matrix3x3 currentOrn; + GetWorldOrientation(currentOrn); + + m_sumoObj->setOrientation(m_sumoObj->getOrientation()*(local ? + drotmat.getRotation() : (currentOrn.inverse() * drotmat * currentOrn)).getRotation()); + } + +} +void SumoPhysicsController::setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal) +{ + float orn [4]={quatImag0,quatImag1,quatImag2,quatReal}; + MT_Quaternion quat(orn); + m_sumoObj->setOrientation(orn); +} + +void SumoPhysicsController::getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal) +{ + const MT_Quaternion& q = m_sumoObj->getOrientation(); + quatImag0 = q[0]; + quatImag1 = q[1]; + quatImag2 = q[2]; + quatReal = q[3]; +} + +void SumoPhysicsController::setPosition(float posX,float posY,float posZ) +{ + m_sumoObj->setPosition(MT_Point3(posX,posY,posZ)); +} +void SumoPhysicsController::setScaling(float scaleX,float scaleY,float scaleZ) +{ + m_sumoObj->setScaling(MT_Vector3(scaleX,scaleY,scaleZ)); +} + + // physics methods +void SumoPhysicsController::ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local) +{ + if (m_sumoObj) + { + MT_Vector3 torque(torqueX,torqueY,torqueZ); + + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + m_sumoObj->applyTorque(local ? + orn * torque : + torque); + } + +} + +void SumoPhysicsController::ApplyForce(float forceX,float forceY,float forceZ,bool local) +{ + if (m_sumoObj) + { + MT_Vector3 force(forceX,forceY,forceZ); + + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + + m_sumoObj->applyCenterForce(local ? + orn * force : + force); + + } + +} + +void SumoPhysicsController::SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local) +{ + if (m_sumoObj) + { + MT_Vector3 ang_vel(ang_velX,ang_velY,ang_velZ); + + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + + m_sumoObj->setAngularVelocity(local ? + orn * ang_vel : + ang_vel); + + } +} + +void SumoPhysicsController::SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local) +{ + if (m_sumoObj ) + { + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + + MT_Vector3 lin_vel(lin_velX,lin_velY,lin_velZ); + m_sumoObj->setLinearVelocity(local ? + orn * lin_vel : + lin_vel); + } +} + +void SumoPhysicsController::applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ) +{ + if (m_sumoObj) + { + MT_Point3 attach(attachX,attachY,attachZ); + MT_Vector3 impulse(impulseX,impulseY,impulseZ); + m_sumoObj->applyImpulse(attach,impulse); + } + +} + +void SumoPhysicsController::SuspendDynamics() +{ + m_suspendDynamics=true; + + if (m_sumoObj) + { + m_sumoObj->suspendDynamics(); + m_sumoObj->setLinearVelocity(MT_Vector3(0,0,0)); + m_sumoObj->setAngularVelocity(MT_Vector3(0,0,0)); + m_sumoObj->calcXform(); + } +} + +void SumoPhysicsController::RestoreDynamics() +{ + m_suspendDynamics=false; + + if (m_sumoObj) + { + m_sumoObj->restoreDynamics(); + } + + +} + + + /** + reading out information from physics + */ +void SumoPhysicsController::GetLinearVelocity(float& linvX,float& linvY,float& linvZ) +{ + if (m_sumoObj) + { + // get velocity from the physics object (m_sumoObj) + const MT_Vector3& vel = m_sumoObj->getLinearVelocity(); + linvX = vel[0]; + linvY = vel[1]; + linvZ = vel[2]; + } + else + { + linvX = 0.f; + linvY = 0.f; + linvZ = 0.f; + } +} + /** + GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). + */ +void SumoPhysicsController::GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ) +{ + if (m_sumoObj) + { + MT_Point3 pos(posX,posY,posZ); + // get velocity from the physics object (m_sumoObj) + const MT_Vector3& vel = m_sumoObj->getVelocity(pos); + linvX = vel[0]; + linvY = vel[1]; + linvZ = vel[2]; + } + else + { + linvX = 0.f; + linvY = 0.f; + linvZ = 0.f; + + } +} + + +void SumoPhysicsController::getReactionForce(float& forceX,float& forceY,float& forceZ) +{ + const MT_Vector3& force = m_sumoObj->getReactionForce(); + forceX = force[0]; + forceY = force[1]; + forceZ = force[2]; + + +} +void SumoPhysicsController::setRigidBody(bool rigid) +{ + m_sumoObj->setRigidBody(rigid); +} + + +void SumoPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) +{ + m_MotionState = motionstate; + + SM_Object* dynaparent=0; + SumoPhysicsController* sumoparentctrl = (SumoPhysicsController* )parentctrl; + + if (sumoparentctrl) + { + dynaparent = sumoparentctrl->GetSumoObject(); + } + + SM_Object* orgsumoobject = m_sumoObj; + + + m_sumoObj = new SM_Object( + orgsumoobject->getShapeHandle(), + orgsumoobject->getMaterialProps(), + orgsumoobject->getShapeProps(), + dynaparent); + + m_sumoObj->setRigidBody(orgsumoobject->isRigidBody()); + + double radius = orgsumoobject->getMargin(); + m_sumoObj->setMargin(orgsumoobject->getMargin()); + m_sumoObj->setPosition(orgsumoobject->getPosition()); + m_sumoObj->setOrientation(orgsumoobject->getOrientation()); + m_sumoScene->add(* (m_sumoObj)); + + if (m_sumoObj) + { + m_sumoObj->setClientObject(this); + //if it is a dyna, register for a callback + m_sumoObj->registerCallback(*this); + } + + + DT_AddObject(m_solidscene,m_sumoObj->getObjectHandle()); + +} + +void SumoPhysicsController::SetSimulatedTime(float time) +{ +} + + +void SumoPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) +{ + +} +// this is the actual callback from sumo, and the position/orientation +//is written to the scenegraph, using the motionstate abstraction + +void SumoPhysicsController::do_me() +{ + + const MT_Point3& pos = m_sumoObj->getPosition(); + const MT_Quaternion& orn = m_sumoObj->getOrientation(); + + m_MotionState->setWorldPosition(pos[0],pos[1],pos[2]); + m_MotionState->setWorldOrientation(orn[0],orn[1],orn[2],orn[3]); + +} + + +void SumoPhysicsController::setSumoTransform(bool nondynaonly) +{ + if (!nondynaonly || !m_bDyna) + { + if (m_sumoObj) + { + MT_Point3 pos; + GetWorldPosition(pos); + + m_sumoObj->setPosition(pos); + if (m_bDyna) + { + m_sumoObj->setScaling(MT_Vector3(1,1,1)); + } else + { + MT_Vector3 scale; + GetWorldScaling(scale); + m_sumoObj->setScaling(scale); + } + MT_Matrix3x3 orn; + GetWorldOrientation(orn); + m_sumoObj->setOrientation(orn.getRotation()); + m_sumoObj->calcXform(); + } + } +} diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsController.h b/source/gameengine/Physics/Sumo/SumoPhysicsController.h new file mode 100644 index 00000000000..d78c21dbd1b --- /dev/null +++ b/source/gameengine/Physics/Sumo/SumoPhysicsController.h @@ -0,0 +1,171 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef __SUMO_PHYSICSCONTROLLER_H +#define __SUMO_PHYSICSCONTROLLER_H + + +#include "PHY_IPhysicsController.h" +#include "SM_Scene.h" +#include "SM_Callback.h" + + +/** + Sumo Physics Controller, a special kind of a PhysicsController. + A Physics Controller is a special kind of Scene Graph Transformation Controller. + Each time the scene graph get's updated, the controller get's a chance + in the 'Update' method to reflect changes. +*/ + +class SumoPhysicsController : public PHY_IPhysicsController , public SM_Callback + + +{ + + class SM_Object* m_sumoObj; + class SM_Scene* m_sumoScene; // needed for replication + DT_SceneHandle m_solidscene; + bool m_bFirstTime; + bool m_bDyna; + + float m_friction; + float m_restitution; + + + bool m_suspendDynamics; + +public: + SumoPhysicsController( + class SM_Scene* sumoScene, + DT_SceneHandle solidscene, + class SM_Object* sumoObj, + class PHY_IMotionState* motionstate, + bool dyna); + + virtual ~SumoPhysicsController(); + + // kinematic methods + virtual void RelativeTranslate(float dlocX,float dlocY,float dlocZ,bool local); + virtual void RelativeRotate(const float drot[9],bool local); + virtual void getOrientation(float &quatImag0,float &quatImag1,float &quatImag2,float &quatReal); + virtual void setOrientation(float quatImag0,float quatImag1,float quatImag2,float quatReal); + virtual void setPosition(float posX,float posY,float posZ); + virtual void setScaling(float scaleX,float scaleY,float scaleZ); + + // physics methods + virtual void ApplyTorque(float torqueX,float torqueY,float torqueZ,bool local); + virtual void ApplyForce(float forceX,float forceY,float forceZ,bool local); + virtual void SetAngularVelocity(float ang_velX,float ang_velY,float ang_velZ,bool local); + virtual void SetLinearVelocity(float lin_velX,float lin_velY,float lin_velZ,bool local); + virtual void applyImpulse(float attachX,float attachY,float attachZ, float impulseX,float impulseY,float impulseZ); + virtual void SetActive(bool active){}; + virtual void SuspendDynamics(); + virtual void RestoreDynamics(); + + + /** + reading out information from physics + */ + virtual void GetLinearVelocity(float& linvX,float& linvY,float& linvZ); + /** + GetVelocity parameters are in geometric coordinates (Origin is not center of mass!). + */ + virtual void GetVelocity(const float posX,const float posY,const float posZ,float& linvX,float& linvY,float& linvZ); + virtual float getMass(); + virtual void getReactionForce(float& forceX,float& forceY,float& forceZ); + virtual void setRigidBody(bool rigid); + + + virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); + + // todo: remove next line ! + virtual void SetSimulatedTime(float time); + + + virtual void WriteDynamicsToMotionState() {}; + virtual void WriteMotionStateToDynamics(bool nondynaonly); + + /** + call from Scene Graph Node to 'update'. + */ + virtual bool SynchronizeMotionStates(float time); + + // clientinfo for raycasts for example + virtual void* getClientInfo() { return m_clientInfo;} + virtual void setClientInfo(void* clientinfo) {m_clientInfo = clientinfo;}; + void* m_clientInfo; + + + float getFriction() { return m_friction;} + float getRestitution() { return m_restitution;} + + // sumo callback + virtual void do_me(); + + class SM_Object* GetSumoObject () + { + return m_sumoObj; + }; + + void GetWorldOrientation(class MT_Matrix3x3& mat); + void GetWorldPosition(MT_Point3& pos); + void GetWorldScaling(MT_Vector3& scale); + + +// void SetSumoObject(class SM_Object* sumoObj) { +// m_sumoObj = sumoObj; +// } +// void SetSumoScene(class SM_Scene* sumoScene) { +// m_sumoScene = sumoScene; +// } + + void setSumoTransform(bool nondynaonly); + + +private: + + bool m_firstTime; + bool m_bFullRigidBody; + bool m_bPhantom; // special flag for objects that are not affected by physics 'resolver' + + // data to calculate fake velocities for kinematic objects (non-dynas) + bool m_bKinematic; + bool m_bPrevKinematic; + + float m_lastTime; + + class PHY_IMotionState* m_MotionState; + +}; + +#endif //__SUMO_PHYSICSCONTROLLER_H + + diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp new file mode 100644 index 00000000000..05b88fcb06b --- /dev/null +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.cpp @@ -0,0 +1,103 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#include "SumoPhysicsEnvironment.h" +#include "PHY_IMotionState.h" +#include "SumoPhysicsController.h" +#include "SM_Scene.h" + + +const MT_Scalar UpperBoundForFuzzicsIntegrator = 0.01; +// At least 100Hz (isn't this CPU hungry ?) + + +SumoPhysicsEnvironment::SumoPhysicsEnvironment() +{ + // seperate collision scene for events + m_solidScene = DT_CreateScene(); + m_respTable = DT_CreateRespTable(); + + m_sumoScene = new SM_Scene(); + m_sumoScene->setSecondaryRespTable(m_respTable); + +} + + + +SumoPhysicsEnvironment::~SumoPhysicsEnvironment() +{ + delete m_sumoScene; + + DT_DeleteScene(m_solidScene); + DT_DeleteRespTable(m_respTable); +} + +void SumoPhysicsEnvironment::proceed(double timeStep) +{ + m_sumoScene->proceed(timeStep,UpperBoundForFuzzicsIntegrator); +} + +void SumoPhysicsEnvironment::setGravity(float x,float y,float z) +{ + m_sumoScene->setForceField(MT_Vector3(x,y,z)); + +} + + + + + +int SumoPhysicsEnvironment::createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, + float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ) +{ + + int constraintid = 0; + return constraintid; + +} + +void SumoPhysicsEnvironment::removeConstraint(int constraintid) +{ + if (constraintid) + { + } +} + +PHY_IPhysicsController* SumoPhysicsEnvironment::rayTest(void* ignoreClient, float fromX,float fromY,float fromZ, float toX,float toY,float toZ, + float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +{ + //collision detection / raytesting + //m_sumoScene->rayTest(ignoreclient,from,to,result,normal); + + return NULL; +} + + diff --git a/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h new file mode 100644 index 00000000000..0e28b855833 --- /dev/null +++ b/source/gameengine/Physics/Sumo/SumoPhysicsEnvironment.h @@ -0,0 +1,88 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ +#ifndef _SUMOPhysicsEnvironment +#define _SUMOPhysicsEnvironment + + +#include "PHY_IPhysicsEnvironment.h" + +#include "solid.h" + +/** +* Physics Environment takes care of stepping the simulation and is a container for physics entities (rigidbodies,constraints, materials etc.) +* A derived class may be able to 'construct' entities by loading and/or converting +*/ +class SumoPhysicsEnvironment : public PHY_IPhysicsEnvironment +{ + + class SM_Scene* m_sumoScene; + + DT_SceneHandle m_solidScene; + DT_RespTableHandle m_respTable; + +public: + SumoPhysicsEnvironment(); + virtual ~SumoPhysicsEnvironment(); +// Perform an integration step of duration 'timeStep'. + virtual void proceed(double timeStep); + virtual void setGravity(float x,float y,float z); + virtual int createConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, + float pivotX,float pivotY,float pivotZ, + float axisX,float axisY,float axisZ); + + virtual void removeConstraint(int constraintid); + virtual PHY_IPhysicsController* rayTest(void* ignoreClient,float fromX,float fromY,float fromZ, float toX,float toY,float toZ, + float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + + + // sumo specific + SM_Scene* GetSumoScene() + { + return m_sumoScene; + } + + DT_SceneHandle GetSolidScene() + { + return m_solidScene; + } + +private: + + + + +}; + +#endif //_SUMOPhysicsEnvironment + + + diff --git a/source/gameengine/Physics/Sumo/convert.txt b/source/gameengine/Physics/Sumo/convert.txt new file mode 100644 index 00000000000..81f8f602cde --- /dev/null +++ b/source/gameengine/Physics/Sumo/convert.txt @@ -0,0 +1,35 @@ +static DT_ShapeHandle CreateShapeFromMesh(RAS_MeshObject* meshobj) +{ + DT_ShapeHandle shape = DT_NewComplexShape(); + int numpolys = meshobj->NumPolygons(); + int numvalidpolys = 0; + + for (int p=0; p<numpolys; p++) + { + RAS_Polygon* poly = meshobj->GetPolygon(p); + + // only add polygons that have the collisionflag set + if (poly->IsCollider()) + { + DT_Begin(); + for (int v=0; v<poly->VertexCount(); v++) { + MT_Point3 pt = meshobj->GetVertex(poly->GetVertexIndexBase().m_vtxarray, + poly->GetVertexIndexBase().m_indexarray[v], + poly->GetMaterial()->GetPolyMaterial())->xyz(); + DT_Vertex(pt[0],pt[1],pt[2]); + } + DT_End(); + + numvalidpolys++; + } + } + + DT_EndComplexShape(); + + if (numvalidpolys==0) { + delete shape; + return NULL; + } else { + return shape; + } +} diff --git a/source/gameengine/Physics/Sumo/include/interpolator.h b/source/gameengine/Physics/Sumo/include/interpolator.h new file mode 100644 index 00000000000..055c242edc7 --- /dev/null +++ b/source/gameengine/Physics/Sumo/include/interpolator.h @@ -0,0 +1,27 @@ +#ifndef INTERPOLATOR_H +#define INTERPOLATOR_H + +#include "solid_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DT_DECLARE_HANDLE(IP_IpoHandle); + +typedef struct IP_ControlPoint { + DT_Scalar m_key; + DT_Scalar m_keyValue; +} IP_ControlPoint; + +IP_IpoHandle IP_CreateLinear(const IP_ControlPoint *cpoints, int num_cpoints); + +void IP_DeleteInterpolator(IP_IpoHandle ipo); + +DT_Scalar IP_GetValue(IP_IpoHandle ipo, DT_Scalar key); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/gameengine/Physics/Sumo/include/solid.h b/source/gameengine/Physics/Sumo/include/solid.h new file mode 100644 index 00000000000..985014a2a46 --- /dev/null +++ b/source/gameengine/Physics/Sumo/include/solid.h @@ -0,0 +1,195 @@ +#ifndef SOLID_H +#define SOLID_H + +#include "solid_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DT_DECLARE_HANDLE(DT_ObjectHandle); +DT_DECLARE_HANDLE(DT_SceneHandle); +DT_DECLARE_HANDLE(DT_ShapeHandle); +DT_DECLARE_HANDLE(DT_RespTableHandle); + +typedef enum DT_ScalarType { + DT_FLOAT, + DT_DOUBLE +} DT_ScalarType; + +typedef enum DT_ResponseType { + DT_NO_RESPONSE, + DT_SIMPLE_RESPONSE, + DT_WITNESSED_RESPONSE, + DT_DEPTH_RESPONSE, +} DT_ResponseType; + +typedef struct DT_CollData { + DT_Vector3 point1; + DT_Vector3 point2; + DT_Vector3 normal; +} DT_CollData; + +typedef void (*DT_ResponseCallback)( + void *client_data, + void *client_object1, + void *client_object2, + const DT_CollData *coll_data); + +/* Shape definition, similar to OpenGL */ + +extern DT_ShapeHandle DT_Box(DT_Scalar x, DT_Scalar y, DT_Scalar z); +extern DT_ShapeHandle DT_Cone(DT_Scalar radius, DT_Scalar height); +extern DT_ShapeHandle DT_Cylinder(DT_Scalar radius, DT_Scalar height); +extern DT_ShapeHandle DT_Sphere(DT_Scalar radius); +extern DT_ShapeHandle DT_Ray(DT_Scalar x, DT_Scalar y, DT_Scalar z); + +extern DT_ShapeHandle DT_NewComplexShape(); +extern void DT_EndComplexShape(); + +extern DT_ShapeHandle DT_NewPolyhedron(); +extern void DT_EndPolyhedron(); + +extern void DT_Begin(); +extern void DT_End(); + +extern void DT_Vertex(DT_Scalar x, DT_Scalar y, DT_Scalar z); + +/* Vertex arrays maintained by the client application can be accessed directly + by SUMO. For instance, you have a vertex struct in the client of the form: + + struct Vertex { + float xyz[3]; + float uv[2]; + float normal[3]; + }; + + And maintain vertex arrays e.g. as + + struct Vertex vertices[328]; + + Within a Polyhedron or a ComplexShape you can use this data by specifying + + DT_VertexBase(vertices, DT_FLOAT, sizeof(struct Vertex)); + + and refer to vertices in the array using + + DT_VertexIndex(10); + + or + + DT_Index indices[5] = { 6, 4, 8, 1, 3 }; + DT_VertexIndices(5, indices); + + or even + + DT_VertexRange(8, 4); + + for the range 8, 9, 10, 11. +*/ + + +extern void DT_SetVertexBase(const void *base, DT_ScalarType type, + DT_Size stride); +extern void DT_VertexIndex(DT_Index index); +extern void DT_VertexIndices(DT_Count count, const DT_Index *indices); +extern void DT_VertexRange(DT_Index first, DT_Count count); + + +/* currently not implemented */ +extern void DT_ChangeVertexBase(DT_ShapeHandle shape, const void *base); + +extern void DT_DeleteShape(DT_ShapeHandle shape); + +/* Scene */ + +extern DT_SceneHandle DT_CreateScene(); +extern void DT_DeleteScene(DT_SceneHandle scene); + +extern void DT_AddObject(DT_SceneHandle scene, DT_ObjectHandle object); +extern void DT_RemoveObject(DT_SceneHandle scene, DT_ObjectHandle object); + + + +/* Object */ + +extern DT_ObjectHandle DT_CreateObject( + void *client_object, /* pointer to object in client memory */ + DT_ShapeHandle shape /* the shape or geometry of the object */ + ); + +extern void DT_DeleteObject(DT_ObjectHandle object); + +extern void DT_SetScaling(DT_ObjectHandle object, const DT_Vector3 scaling); +extern void DT_SetPosition(DT_ObjectHandle object, const DT_Vector3 position); +extern void DT_SetOrientation(DT_ObjectHandle object, const DT_Quaternion orientation); + +extern void DT_SetMargin(DT_ObjectHandle object, DT_Scalar margin); + +extern void DT_SetMatrixf(DT_ObjectHandle object, const float *m); +extern void DT_GetMatrixf(DT_ObjectHandle object, float *m); + +extern void DT_SetMatrixd(DT_ObjectHandle object, const double *m); +extern void DT_GetMatrixd(DT_ObjectHandle object, double *m); + +extern void DT_GetWorldCoord(DT_ObjectHandle object, + const DT_Vector3 local, + DT_Vector3 world); + +extern DT_Scalar DT_GetClosestPair(DT_ObjectHandle object1, DT_ObjectHandle object2, + DT_Vector3 point1, DT_Vector3 point2); + + +/* Response, see SOLID user manual */ + +extern DT_RespTableHandle DT_CreateRespTable(); +extern void DT_DeleteRespTable(DT_RespTableHandle respTable); + +extern void DT_CallResponse(DT_RespTableHandle respTable, + DT_ObjectHandle object1, + DT_ObjectHandle object2, + const DT_CollData *coll_data); + +extern void DT_SetDefaultResponse(DT_RespTableHandle respTable, + DT_ResponseCallback response, + DT_ResponseType type, + void *client_data); + +extern void DT_ClearDefaultResponse(DT_RespTableHandle respTable); + +extern void DT_SetObjectResponse(DT_RespTableHandle respTable, + DT_ObjectHandle object, + DT_ResponseCallback response, + DT_ResponseType type, void *client_data); +extern void DT_ClearObjectResponse(DT_RespTableHandle respTable, + DT_ObjectHandle object); + +extern void DT_SetPairResponse(DT_RespTableHandle respTable, + DT_ObjectHandle object1, + DT_ObjectHandle object2, + DT_ResponseCallback response, + DT_ResponseType type, + void *client_data); +extern void DT_ClearPairResponse(DT_RespTableHandle respTable, + DT_ObjectHandle object1, + DT_ObjectHandle object2); + + + +/* Perform a collision test for a given scene, using a response table */ + +extern DT_Count DT_Test(DT_SceneHandle scene, DT_RespTableHandle respTable); + +extern void *DT_RayTest(DT_SceneHandle scene, void *ignore_client, + const DT_Vector3 from, const DT_Vector3 to, + DT_Vector3 spot, DT_Vector3 normal); + +extern int DT_ObjectRayTest(DT_ObjectHandle object, + const DT_Vector3 from, const DT_Vector3 to, + DT_Vector3 spot, DT_Vector3 normal); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/gameengine/Physics/Sumo/include/solid_broadphase.h b/source/gameengine/Physics/Sumo/include/solid_broadphase.h new file mode 100644 index 00000000000..d5d05e8a243 --- /dev/null +++ b/source/gameengine/Physics/Sumo/include/solid_broadphase.h @@ -0,0 +1,38 @@ +#ifndef SOLID_BROADPHASE_H +#define SOLID_BROADPHASE_H + +#include "solid_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +DT_DECLARE_HANDLE(BP_SceneHandle); +DT_DECLARE_HANDLE(BP_ProxyHandle); + +typedef void (*BP_Callback)(void *client_data, + void *object1, + void *object2); + +extern BP_SceneHandle BP_CreateScene(void *client_data, + BP_Callback beginOverlap, + BP_Callback endOverlap); + +extern void BP_DeleteScene(BP_SceneHandle scene); + +extern BP_ProxyHandle BP_CreateProxy(BP_SceneHandle scene, void *object, + const DT_Vector3 lower, + const DT_Vector3 upper); + +extern void BP_DeleteProxy(BP_SceneHandle scene, + BP_ProxyHandle proxy); + +extern void BP_SetBBox(BP_ProxyHandle proxy, + const DT_Vector3 lower, + const DT_Vector3 upper); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/gameengine/Physics/Sumo/include/solid_types.h b/source/gameengine/Physics/Sumo/include/solid_types.h new file mode 100644 index 00000000000..537bbcb5826 --- /dev/null +++ b/source/gameengine/Physics/Sumo/include/solid_types.h @@ -0,0 +1,14 @@ +#ifndef SOLID_TYPES_H +#define SOLID_TYPES_H + +#define DT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +typedef double DT_Scalar; +typedef unsigned int DT_Count; +typedef unsigned int DT_Index; +typedef unsigned int DT_Size; + +typedef DT_Scalar DT_Vector3[3]; +typedef DT_Scalar DT_Quaternion[4]; + +#endif |