diff options
Diffstat (limited to 'libraries/ode-0.9\/ode/src')
73 files changed, 43201 insertions, 0 deletions
diff --git a/libraries/ode-0.9\/ode/src/Makefile.am b/libraries/ode-0.9\/ode/src/Makefile.am new file mode 100755 index 0000000..1b0cf19 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/Makefile.am | |||
@@ -0,0 +1,207 @@ | |||
1 | AM_CXXFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include -I$(top_builddir)/include | ||
2 | AM_CPPFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include -I$(top_builddir)/include | ||
3 | AM_CFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include -I$(top_builddir)/include | ||
4 | lib_LIBRARIES = libode.a | ||
5 | libode_a_CPPFLAGS = -O2 | ||
6 | |||
7 | libode_a_CPPFLAGS += -fPIC | ||
8 | |||
9 | # Fake an executable in order to get a shared library | ||
10 | # Note the elegant and cunning way to trick Autotools to install a program | ||
11 | # in a lib directory. --Rodrigo | ||
12 | traplibdir=$(libdir) | ||
13 | EXEEXT=@so_ext@ | ||
14 | traplib_PROGRAMS=libode | ||
15 | libode_SOURCES= | ||
16 | libode_DEPENDENCIES = libfast.a libode.a | ||
17 | libode_LDFLAGS= @SHARED_LDFLAGS@ | ||
18 | if USE_SONAME | ||
19 | libode_LDFLAGS+=-Wl,-soname,@ODE_SONAME@ | ||
20 | endif | ||
21 | libode_LDADD=$(libode_a_OBJECTS) $(libfast_a_OBJECTS) | ||
22 | |||
23 | if OPCODE | ||
24 | libode_DEPENDENCIES+= libOPCODE.a | ||
25 | libode_LDADD+=$(libOPCODE_a_OBJECTS) | ||
26 | endif | ||
27 | |||
28 | |||
29 | if GIMPACT | ||
30 | libode_DEPENDENCIES+= libGIMPACT.a | ||
31 | libode_LDADD+=$(libGIMPACT_a_OBJECTS) | ||
32 | endif | ||
33 | |||
34 | |||
35 | # convenience library to simulate per object cflags | ||
36 | noinst_LIBRARIES= libfast.a | ||
37 | libfast_a_CFLAGS= -O1 | ||
38 | libfast_a_SOURCES= fastldlt.c fastltsolve.c fastdot.c fastlsolve.c | ||
39 | |||
40 | libfast_a_CFLAGS += -fPIC | ||
41 | |||
42 | libode_a_DEPENDENCIES = libfast.a | ||
43 | libode_a_LIBADD= $(libfast_a_OBJECTS) | ||
44 | |||
45 | libode_a_SOURCES = objects.h \ | ||
46 | obstack.cpp \ | ||
47 | collision_util.cpp \ | ||
48 | obstack.h \ | ||
49 | array.cpp \ | ||
50 | collision_util.h \ | ||
51 | ode.cpp \ | ||
52 | array.h \ | ||
53 | error.cpp \ | ||
54 | odemath.cpp \ | ||
55 | collision_kernel.cpp \ | ||
56 | export-dif.cpp \ | ||
57 | quickstep.cpp \ | ||
58 | collision_kernel.h \ | ||
59 | quickstep.h \ | ||
60 | collision_quadtreespace.cpp \ | ||
61 | rotation.cpp \ | ||
62 | collision_space.cpp \ | ||
63 | collision_space_internal.h \ | ||
64 | collision_cylinder_box.cpp \ | ||
65 | collision_cylinder_sphere.cpp \ | ||
66 | collision_cylinder_plane.cpp \ | ||
67 | sphere.cpp \ | ||
68 | box.cpp \ | ||
69 | capsule.cpp \ | ||
70 | plane.cpp \ | ||
71 | ray.cpp \ | ||
72 | cylinder.cpp \ | ||
73 | convex.cpp \ | ||
74 | joint.cpp \ | ||
75 | stack.h \ | ||
76 | collision_std.h \ | ||
77 | joint.h \ | ||
78 | step.cpp \ | ||
79 | collision_transform.cpp \ | ||
80 | lcp.cpp \ | ||
81 | step.h \ | ||
82 | collision_transform.h \ | ||
83 | lcp.h \ | ||
84 | stepfast.cpp \ | ||
85 | mass.cpp \ | ||
86 | testing.cpp \ | ||
87 | mat.cpp \ | ||
88 | testing.h \ | ||
89 | mat.h \ | ||
90 | timer.cpp \ | ||
91 | matrix.cpp \ | ||
92 | util.cpp \ | ||
93 | memory.cpp \ | ||
94 | util.h \ | ||
95 | misc.cpp \ | ||
96 | heightfield.cpp \ | ||
97 | heightfield.h | ||
98 | |||
99 | |||
100 | |||
101 | ################################### | ||
102 | # G I M P A C T S T U F F | ||
103 | ################################### | ||
104 | |||
105 | |||
106 | if GIMPACT | ||
107 | noinst_LIBRARIES+= libGIMPACT.a | ||
108 | libGIMPACT_a_CPPFLAGS= -O2 -fno-strict-aliasing -fPIC | ||
109 | |||
110 | libode_a_SOURCES+= collision_trimesh_gimpact.cpp | ||
111 | |||
112 | libGIMPACT_a_SOURCES = \ | ||
113 | @TOPDIR@/GIMPACT/src/gim_boxpruning.cpp \ | ||
114 | @TOPDIR@/GIMPACT/src/gim_contact.cpp \ | ||
115 | @TOPDIR@/GIMPACT/src/gim_math.cpp \ | ||
116 | @TOPDIR@/GIMPACT/src/gim_memory.cpp \ | ||
117 | @TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp \ | ||
118 | @TOPDIR@/GIMPACT/src/gim_trimesh.cpp \ | ||
119 | @TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp \ | ||
120 | @TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp \ | ||
121 | @TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp \ | ||
122 | @TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp \ | ||
123 | @TOPDIR@/GIMPACT/src/gimpact.cpp | ||
124 | |||
125 | libode_a_DEPENDENCIES+=libGIMPACT.a | ||
126 | libode_a_LIBADD+= $(libGIMPACT_a_OBJECTS) | ||
127 | AM_CXXFLAGS += -I@TOPDIR@/GIMPACT/include -DdTRIMESH_ENABLED -DdTRIMESH_GIMPACT | ||
128 | AM_CFLAGS += -I@TOPDIR@/GIMPACT/include -DdTRIMESH_ENABLED -DdTRIMESH_GIMPACT | ||
129 | |||
130 | libode_a_SOURCES+= collision_trimesh_trimesh.cpp \ | ||
131 | collision_trimesh_sphere.cpp \ | ||
132 | collision_trimesh_ray.cpp \ | ||
133 | collision_trimesh_opcode.cpp \ | ||
134 | collision_trimesh_box.cpp \ | ||
135 | collision_trimesh_ccylinder.cpp \ | ||
136 | collision_trimesh_distance.cpp \ | ||
137 | collision_trimesh_internal.h \ | ||
138 | collision_cylinder_trimesh.cpp \ | ||
139 | collision_trimesh_plane.cpp | ||
140 | endif | ||
141 | |||
142 | |||
143 | |||
144 | ################################# | ||
145 | # O P C O D E S T U F F | ||
146 | ################################# | ||
147 | |||
148 | |||
149 | if OPCODE | ||
150 | noinst_LIBRARIES+= libOPCODE.a | ||
151 | libOPCODE_a_CPPFLAGS= -O2 -fno-strict-aliasing -fPIC | ||
152 | |||
153 | |||
154 | libOPCODE_a_SOURCES= @TOPDIR@/OPCODE/OPC_AABBCollider.cpp \ | ||
155 | @TOPDIR@/OPCODE/OPC_AABBTree.cpp \ | ||
156 | @TOPDIR@/OPCODE/OPC_BaseModel.cpp \ | ||
157 | @TOPDIR@/OPCODE/OPC_BoxPruning.cpp \ | ||
158 | @TOPDIR@/OPCODE/OPC_Collider.cpp \ | ||
159 | @TOPDIR@/OPCODE/OPC_Common.cpp \ | ||
160 | @TOPDIR@/OPCODE/OPC_HybridModel.cpp \ | ||
161 | @TOPDIR@/OPCODE/OPC_LSSCollider.cpp \ | ||
162 | @TOPDIR@/OPCODE/OPC_MeshInterface.cpp \ | ||
163 | @TOPDIR@/OPCODE/OPC_Model.cpp \ | ||
164 | @TOPDIR@/OPCODE/OPC_OBBCollider.cpp \ | ||
165 | @TOPDIR@/OPCODE/Opcode.cpp \ | ||
166 | @TOPDIR@/OPCODE/OPC_OptimizedTree.cpp \ | ||
167 | @TOPDIR@/OPCODE/OPC_Picking.cpp \ | ||
168 | @TOPDIR@/OPCODE/OPC_PlanesCollider.cpp \ | ||
169 | @TOPDIR@/OPCODE/OPC_RayCollider.cpp \ | ||
170 | @TOPDIR@/OPCODE/OPC_SphereCollider.cpp \ | ||
171 | @TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp \ | ||
172 | @TOPDIR@/OPCODE/OPC_TreeBuilders.cpp \ | ||
173 | @TOPDIR@/OPCODE/OPC_TreeCollider.cpp \ | ||
174 | @TOPDIR@/OPCODE/OPC_VolumeCollider.cpp \ | ||
175 | @TOPDIR@/OPCODE/Ice/IceAABB.cpp \ | ||
176 | @TOPDIR@/OPCODE/Ice/IceContainer.cpp \ | ||
177 | @TOPDIR@/OPCODE/Ice/IceHPoint.cpp \ | ||
178 | @TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp \ | ||
179 | @TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp \ | ||
180 | @TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp \ | ||
181 | @TOPDIR@/OPCODE/Ice/IceOBB.cpp \ | ||
182 | @TOPDIR@/OPCODE/Ice/IcePlane.cpp \ | ||
183 | @TOPDIR@/OPCODE/Ice/IcePoint.cpp \ | ||
184 | @TOPDIR@/OPCODE/Ice/IceRandom.cpp \ | ||
185 | @TOPDIR@/OPCODE/Ice/IceRay.cpp \ | ||
186 | @TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp \ | ||
187 | @TOPDIR@/OPCODE/Ice/IceSegment.cpp \ | ||
188 | @TOPDIR@/OPCODE/Ice/IceTriangle.cpp \ | ||
189 | @TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
190 | libode_a_DEPENDENCIES+=libOPCODE.a | ||
191 | |||
192 | libode_a_LIBADD+= $(libOPCODE_a_OBJECTS) | ||
193 | AM_CXXFLAGS += -I@TOPDIR@/OPCODE -I@TOPDIR@/OPCODE/Ice -DdTRIMESH_ENABLED -DdTRIMESH_OPCODE | ||
194 | AM_CFLAGS += -I@TOPDIR@/OPCODE -I@TOPDIR@/OPCODE/Ice -DdTRIMESH_ENABLED -DdTRIMESH_OPCODE | ||
195 | libode_a_SOURCES+= collision_trimesh_trimesh.cpp \ | ||
196 | collision_trimesh_sphere.cpp \ | ||
197 | collision_trimesh_ray.cpp \ | ||
198 | collision_trimesh_opcode.cpp \ | ||
199 | collision_trimesh_box.cpp \ | ||
200 | collision_trimesh_ccylinder.cpp \ | ||
201 | collision_trimesh_distance.cpp \ | ||
202 | collision_trimesh_internal.h \ | ||
203 | collision_cylinder_trimesh.cpp \ | ||
204 | collision_trimesh_plane.cpp | ||
205 | endif | ||
206 | |||
207 | |||
diff --git a/libraries/ode-0.9\/ode/src/Makefile.in b/libraries/ode-0.9\/ode/src/Makefile.in new file mode 100755 index 0000000..548f2e2 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/Makefile.in | |||
@@ -0,0 +1,2290 @@ | |||
1 | # Makefile.in generated by automake 1.10 from Makefile.am. | ||
2 | # @configure_input@ | ||
3 | |||
4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | ||
5 | # 2003, 2004, 2005, 2006 Free Software Foundation, Inc. | ||
6 | # This Makefile.in is free software; the Free Software Foundation | ||
7 | # gives unlimited permission to copy and/or distribute it, | ||
8 | # with or without modifications, as long as this notice is preserved. | ||
9 | |||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without | ||
12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
13 | # PARTICULAR PURPOSE. | ||
14 | |||
15 | @SET_MAKE@ | ||
16 | |||
17 | |||
18 | VPATH = @srcdir@ | ||
19 | pkgdatadir = $(datadir)/@PACKAGE@ | ||
20 | pkglibdir = $(libdir)/@PACKAGE@ | ||
21 | pkgincludedir = $(includedir)/@PACKAGE@ | ||
22 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd | ||
23 | install_sh_DATA = $(install_sh) -c -m 644 | ||
24 | install_sh_PROGRAM = $(install_sh) -c | ||
25 | install_sh_SCRIPT = $(install_sh) -c | ||
26 | INSTALL_HEADER = $(INSTALL_DATA) | ||
27 | transform = $(program_transform_name) | ||
28 | NORMAL_INSTALL = : | ||
29 | PRE_INSTALL = : | ||
30 | POST_INSTALL = : | ||
31 | NORMAL_UNINSTALL = : | ||
32 | PRE_UNINSTALL = : | ||
33 | POST_UNINSTALL = : | ||
34 | build_triplet = @build@ | ||
35 | host_triplet = @host@ | ||
36 | target_triplet = @target@ | ||
37 | traplib_PROGRAMS = libode$(EXEEXT) | ||
38 | @USE_SONAME_TRUE@am__append_1 = -Wl,-soname,@ODE_SONAME@ | ||
39 | @OPCODE_TRUE@am__append_2 = libOPCODE.a | ||
40 | @OPCODE_TRUE@am__append_3 = $(libOPCODE_a_OBJECTS) | ||
41 | @GIMPACT_TRUE@am__append_4 = libGIMPACT.a | ||
42 | @GIMPACT_TRUE@am__append_5 = $(libGIMPACT_a_OBJECTS) | ||
43 | |||
44 | ################################### | ||
45 | # G I M P A C T S T U F F | ||
46 | ################################### | ||
47 | @GIMPACT_TRUE@am__append_6 = libGIMPACT.a | ||
48 | @GIMPACT_TRUE@am__append_7 = collision_trimesh_gimpact.cpp \ | ||
49 | @GIMPACT_TRUE@ collision_trimesh_trimesh.cpp \ | ||
50 | @GIMPACT_TRUE@ collision_trimesh_sphere.cpp \ | ||
51 | @GIMPACT_TRUE@ collision_trimesh_ray.cpp \ | ||
52 | @GIMPACT_TRUE@ collision_trimesh_opcode.cpp \ | ||
53 | @GIMPACT_TRUE@ collision_trimesh_box.cpp \ | ||
54 | @GIMPACT_TRUE@ collision_trimesh_ccylinder.cpp \ | ||
55 | @GIMPACT_TRUE@ collision_trimesh_distance.cpp \ | ||
56 | @GIMPACT_TRUE@ collision_trimesh_internal.h \ | ||
57 | @GIMPACT_TRUE@ collision_cylinder_trimesh.cpp \ | ||
58 | @GIMPACT_TRUE@ collision_trimesh_plane.cpp | ||
59 | @GIMPACT_TRUE@am__append_8 = libGIMPACT.a | ||
60 | @GIMPACT_TRUE@am__append_9 = $(libGIMPACT_a_OBJECTS) | ||
61 | @GIMPACT_TRUE@am__append_10 = -I@TOPDIR@/GIMPACT/include -DdTRIMESH_ENABLED -DdTRIMESH_GIMPACT | ||
62 | @GIMPACT_TRUE@am__append_11 = -I@TOPDIR@/GIMPACT/include -DdTRIMESH_ENABLED -DdTRIMESH_GIMPACT | ||
63 | |||
64 | ################################# | ||
65 | # O P C O D E S T U F F | ||
66 | ################################# | ||
67 | @OPCODE_TRUE@am__append_12 = libOPCODE.a | ||
68 | @OPCODE_TRUE@am__append_13 = libOPCODE.a | ||
69 | @OPCODE_TRUE@am__append_14 = $(libOPCODE_a_OBJECTS) | ||
70 | @OPCODE_TRUE@am__append_15 = -I@TOPDIR@/OPCODE -I@TOPDIR@/OPCODE/Ice -DdTRIMESH_ENABLED -DdTRIMESH_OPCODE | ||
71 | @OPCODE_TRUE@am__append_16 = -I@TOPDIR@/OPCODE -I@TOPDIR@/OPCODE/Ice -DdTRIMESH_ENABLED -DdTRIMESH_OPCODE | ||
72 | @OPCODE_TRUE@am__append_17 = collision_trimesh_trimesh.cpp \ | ||
73 | @OPCODE_TRUE@ collision_trimesh_sphere.cpp \ | ||
74 | @OPCODE_TRUE@ collision_trimesh_ray.cpp \ | ||
75 | @OPCODE_TRUE@ collision_trimesh_opcode.cpp \ | ||
76 | @OPCODE_TRUE@ collision_trimesh_box.cpp \ | ||
77 | @OPCODE_TRUE@ collision_trimesh_ccylinder.cpp \ | ||
78 | @OPCODE_TRUE@ collision_trimesh_distance.cpp \ | ||
79 | @OPCODE_TRUE@ collision_trimesh_internal.h \ | ||
80 | @OPCODE_TRUE@ collision_cylinder_trimesh.cpp \ | ||
81 | @OPCODE_TRUE@ collision_trimesh_plane.cpp | ||
82 | |||
83 | subdir = ode/src | ||
84 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in | ||
85 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 | ||
86 | am__aclocal_m4_deps = $(top_srcdir)/configure.in | ||
87 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ | ||
88 | $(ACLOCAL_M4) | ||
89 | mkinstalldirs = $(install_sh) -d | ||
90 | CONFIG_HEADER = $(top_builddir)/include/ode/config.h | ||
91 | CONFIG_CLEAN_FILES = | ||
92 | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; | ||
93 | am__vpath_adj = case $$p in \ | ||
94 | $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ | ||
95 | *) f=$$p;; \ | ||
96 | esac; | ||
97 | am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; | ||
98 | am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(traplibdir)" | ||
99 | libLIBRARIES_INSTALL = $(INSTALL_DATA) | ||
100 | LIBRARIES = $(lib_LIBRARIES) $(noinst_LIBRARIES) | ||
101 | AR = ar | ||
102 | ARFLAGS = cru | ||
103 | libGIMPACT_a_AR = $(AR) $(ARFLAGS) | ||
104 | libGIMPACT_a_LIBADD = | ||
105 | am__libGIMPACT_a_SOURCES_DIST = \ | ||
106 | @TOPDIR@/GIMPACT/src/gim_boxpruning.cpp \ | ||
107 | @TOPDIR@/GIMPACT/src/gim_contact.cpp \ | ||
108 | @TOPDIR@/GIMPACT/src/gim_math.cpp \ | ||
109 | @TOPDIR@/GIMPACT/src/gim_memory.cpp \ | ||
110 | @TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp \ | ||
111 | @TOPDIR@/GIMPACT/src/gim_trimesh.cpp \ | ||
112 | @TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp \ | ||
113 | @TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp \ | ||
114 | @TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp \ | ||
115 | @TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp \ | ||
116 | @TOPDIR@/GIMPACT/src/gimpact.cpp | ||
117 | @GIMPACT_TRUE@am_libGIMPACT_a_OBJECTS = \ | ||
118 | @GIMPACT_TRUE@ libGIMPACT_a-gim_boxpruning.$(OBJEXT) \ | ||
119 | @GIMPACT_TRUE@ libGIMPACT_a-gim_contact.$(OBJEXT) \ | ||
120 | @GIMPACT_TRUE@ libGIMPACT_a-gim_math.$(OBJEXT) \ | ||
121 | @GIMPACT_TRUE@ libGIMPACT_a-gim_memory.$(OBJEXT) \ | ||
122 | @GIMPACT_TRUE@ libGIMPACT_a-gim_tri_tri_overlap.$(OBJEXT) \ | ||
123 | @GIMPACT_TRUE@ libGIMPACT_a-gim_trimesh.$(OBJEXT) \ | ||
124 | @GIMPACT_TRUE@ libGIMPACT_a-gim_trimesh_capsule_collision.$(OBJEXT) \ | ||
125 | @GIMPACT_TRUE@ libGIMPACT_a-gim_trimesh_ray_collision.$(OBJEXT) \ | ||
126 | @GIMPACT_TRUE@ libGIMPACT_a-gim_trimesh_sphere_collision.$(OBJEXT) \ | ||
127 | @GIMPACT_TRUE@ libGIMPACT_a-gim_trimesh_trimesh_collision.$(OBJEXT) \ | ||
128 | @GIMPACT_TRUE@ libGIMPACT_a-gimpact.$(OBJEXT) | ||
129 | libGIMPACT_a_OBJECTS = $(am_libGIMPACT_a_OBJECTS) | ||
130 | libOPCODE_a_AR = $(AR) $(ARFLAGS) | ||
131 | libOPCODE_a_LIBADD = | ||
132 | am__libOPCODE_a_SOURCES_DIST = @TOPDIR@/OPCODE/OPC_AABBCollider.cpp \ | ||
133 | @TOPDIR@/OPCODE/OPC_AABBTree.cpp \ | ||
134 | @TOPDIR@/OPCODE/OPC_BaseModel.cpp \ | ||
135 | @TOPDIR@/OPCODE/OPC_BoxPruning.cpp \ | ||
136 | @TOPDIR@/OPCODE/OPC_Collider.cpp \ | ||
137 | @TOPDIR@/OPCODE/OPC_Common.cpp \ | ||
138 | @TOPDIR@/OPCODE/OPC_HybridModel.cpp \ | ||
139 | @TOPDIR@/OPCODE/OPC_LSSCollider.cpp \ | ||
140 | @TOPDIR@/OPCODE/OPC_MeshInterface.cpp \ | ||
141 | @TOPDIR@/OPCODE/OPC_Model.cpp \ | ||
142 | @TOPDIR@/OPCODE/OPC_OBBCollider.cpp @TOPDIR@/OPCODE/Opcode.cpp \ | ||
143 | @TOPDIR@/OPCODE/OPC_OptimizedTree.cpp \ | ||
144 | @TOPDIR@/OPCODE/OPC_Picking.cpp \ | ||
145 | @TOPDIR@/OPCODE/OPC_PlanesCollider.cpp \ | ||
146 | @TOPDIR@/OPCODE/OPC_RayCollider.cpp \ | ||
147 | @TOPDIR@/OPCODE/OPC_SphereCollider.cpp \ | ||
148 | @TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp \ | ||
149 | @TOPDIR@/OPCODE/OPC_TreeBuilders.cpp \ | ||
150 | @TOPDIR@/OPCODE/OPC_TreeCollider.cpp \ | ||
151 | @TOPDIR@/OPCODE/OPC_VolumeCollider.cpp \ | ||
152 | @TOPDIR@/OPCODE/Ice/IceAABB.cpp \ | ||
153 | @TOPDIR@/OPCODE/Ice/IceContainer.cpp \ | ||
154 | @TOPDIR@/OPCODE/Ice/IceHPoint.cpp \ | ||
155 | @TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp \ | ||
156 | @TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp \ | ||
157 | @TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp \ | ||
158 | @TOPDIR@/OPCODE/Ice/IceOBB.cpp \ | ||
159 | @TOPDIR@/OPCODE/Ice/IcePlane.cpp \ | ||
160 | @TOPDIR@/OPCODE/Ice/IcePoint.cpp \ | ||
161 | @TOPDIR@/OPCODE/Ice/IceRandom.cpp \ | ||
162 | @TOPDIR@/OPCODE/Ice/IceRay.cpp \ | ||
163 | @TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp \ | ||
164 | @TOPDIR@/OPCODE/Ice/IceSegment.cpp \ | ||
165 | @TOPDIR@/OPCODE/Ice/IceTriangle.cpp \ | ||
166 | @TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
167 | @OPCODE_TRUE@am_libOPCODE_a_OBJECTS = \ | ||
168 | @OPCODE_TRUE@ libOPCODE_a-OPC_AABBCollider.$(OBJEXT) \ | ||
169 | @OPCODE_TRUE@ libOPCODE_a-OPC_AABBTree.$(OBJEXT) \ | ||
170 | @OPCODE_TRUE@ libOPCODE_a-OPC_BaseModel.$(OBJEXT) \ | ||
171 | @OPCODE_TRUE@ libOPCODE_a-OPC_BoxPruning.$(OBJEXT) \ | ||
172 | @OPCODE_TRUE@ libOPCODE_a-OPC_Collider.$(OBJEXT) \ | ||
173 | @OPCODE_TRUE@ libOPCODE_a-OPC_Common.$(OBJEXT) \ | ||
174 | @OPCODE_TRUE@ libOPCODE_a-OPC_HybridModel.$(OBJEXT) \ | ||
175 | @OPCODE_TRUE@ libOPCODE_a-OPC_LSSCollider.$(OBJEXT) \ | ||
176 | @OPCODE_TRUE@ libOPCODE_a-OPC_MeshInterface.$(OBJEXT) \ | ||
177 | @OPCODE_TRUE@ libOPCODE_a-OPC_Model.$(OBJEXT) \ | ||
178 | @OPCODE_TRUE@ libOPCODE_a-OPC_OBBCollider.$(OBJEXT) \ | ||
179 | @OPCODE_TRUE@ libOPCODE_a-Opcode.$(OBJEXT) \ | ||
180 | @OPCODE_TRUE@ libOPCODE_a-OPC_OptimizedTree.$(OBJEXT) \ | ||
181 | @OPCODE_TRUE@ libOPCODE_a-OPC_Picking.$(OBJEXT) \ | ||
182 | @OPCODE_TRUE@ libOPCODE_a-OPC_PlanesCollider.$(OBJEXT) \ | ||
183 | @OPCODE_TRUE@ libOPCODE_a-OPC_RayCollider.$(OBJEXT) \ | ||
184 | @OPCODE_TRUE@ libOPCODE_a-OPC_SphereCollider.$(OBJEXT) \ | ||
185 | @OPCODE_TRUE@ libOPCODE_a-OPC_SweepAndPrune.$(OBJEXT) \ | ||
186 | @OPCODE_TRUE@ libOPCODE_a-OPC_TreeBuilders.$(OBJEXT) \ | ||
187 | @OPCODE_TRUE@ libOPCODE_a-OPC_TreeCollider.$(OBJEXT) \ | ||
188 | @OPCODE_TRUE@ libOPCODE_a-OPC_VolumeCollider.$(OBJEXT) \ | ||
189 | @OPCODE_TRUE@ libOPCODE_a-IceAABB.$(OBJEXT) \ | ||
190 | @OPCODE_TRUE@ libOPCODE_a-IceContainer.$(OBJEXT) \ | ||
191 | @OPCODE_TRUE@ libOPCODE_a-IceHPoint.$(OBJEXT) \ | ||
192 | @OPCODE_TRUE@ libOPCODE_a-IceIndexedTriangle.$(OBJEXT) \ | ||
193 | @OPCODE_TRUE@ libOPCODE_a-IceMatrix3x3.$(OBJEXT) \ | ||
194 | @OPCODE_TRUE@ libOPCODE_a-IceMatrix4x4.$(OBJEXT) \ | ||
195 | @OPCODE_TRUE@ libOPCODE_a-IceOBB.$(OBJEXT) \ | ||
196 | @OPCODE_TRUE@ libOPCODE_a-IcePlane.$(OBJEXT) \ | ||
197 | @OPCODE_TRUE@ libOPCODE_a-IcePoint.$(OBJEXT) \ | ||
198 | @OPCODE_TRUE@ libOPCODE_a-IceRandom.$(OBJEXT) \ | ||
199 | @OPCODE_TRUE@ libOPCODE_a-IceRay.$(OBJEXT) \ | ||
200 | @OPCODE_TRUE@ libOPCODE_a-IceRevisitedRadix.$(OBJEXT) \ | ||
201 | @OPCODE_TRUE@ libOPCODE_a-IceSegment.$(OBJEXT) \ | ||
202 | @OPCODE_TRUE@ libOPCODE_a-IceTriangle.$(OBJEXT) \ | ||
203 | @OPCODE_TRUE@ libOPCODE_a-IceUtils.$(OBJEXT) | ||
204 | libOPCODE_a_OBJECTS = $(am_libOPCODE_a_OBJECTS) | ||
205 | libfast_a_AR = $(AR) $(ARFLAGS) | ||
206 | libfast_a_LIBADD = | ||
207 | am_libfast_a_OBJECTS = libfast_a-fastldlt.$(OBJEXT) \ | ||
208 | libfast_a-fastltsolve.$(OBJEXT) libfast_a-fastdot.$(OBJEXT) \ | ||
209 | libfast_a-fastlsolve.$(OBJEXT) | ||
210 | libfast_a_OBJECTS = $(am_libfast_a_OBJECTS) | ||
211 | libode_a_AR = $(AR) $(ARFLAGS) | ||
212 | am__libode_a_SOURCES_DIST = objects.h obstack.cpp collision_util.cpp \ | ||
213 | obstack.h array.cpp collision_util.h ode.cpp array.h error.cpp \ | ||
214 | odemath.cpp collision_kernel.cpp export-dif.cpp quickstep.cpp \ | ||
215 | collision_kernel.h quickstep.h collision_quadtreespace.cpp \ | ||
216 | rotation.cpp collision_space.cpp collision_space_internal.h \ | ||
217 | collision_cylinder_box.cpp collision_cylinder_sphere.cpp \ | ||
218 | collision_cylinder_plane.cpp sphere.cpp box.cpp capsule.cpp \ | ||
219 | plane.cpp ray.cpp cylinder.cpp convex.cpp joint.cpp stack.h \ | ||
220 | collision_std.h joint.h step.cpp collision_transform.cpp \ | ||
221 | lcp.cpp step.h collision_transform.h lcp.h stepfast.cpp \ | ||
222 | mass.cpp testing.cpp mat.cpp testing.h mat.h timer.cpp \ | ||
223 | matrix.cpp util.cpp memory.cpp util.h misc.cpp heightfield.cpp \ | ||
224 | heightfield.h collision_trimesh_gimpact.cpp \ | ||
225 | collision_trimesh_trimesh.cpp collision_trimesh_sphere.cpp \ | ||
226 | collision_trimesh_ray.cpp collision_trimesh_opcode.cpp \ | ||
227 | collision_trimesh_box.cpp collision_trimesh_ccylinder.cpp \ | ||
228 | collision_trimesh_distance.cpp collision_trimesh_internal.h \ | ||
229 | collision_cylinder_trimesh.cpp collision_trimesh_plane.cpp | ||
230 | @GIMPACT_TRUE@am__objects_1 = \ | ||
231 | @GIMPACT_TRUE@ libode_a-collision_trimesh_gimpact.$(OBJEXT) \ | ||
232 | @GIMPACT_TRUE@ libode_a-collision_trimesh_trimesh.$(OBJEXT) \ | ||
233 | @GIMPACT_TRUE@ libode_a-collision_trimesh_sphere.$(OBJEXT) \ | ||
234 | @GIMPACT_TRUE@ libode_a-collision_trimesh_ray.$(OBJEXT) \ | ||
235 | @GIMPACT_TRUE@ libode_a-collision_trimesh_opcode.$(OBJEXT) \ | ||
236 | @GIMPACT_TRUE@ libode_a-collision_trimesh_box.$(OBJEXT) \ | ||
237 | @GIMPACT_TRUE@ libode_a-collision_trimesh_ccylinder.$(OBJEXT) \ | ||
238 | @GIMPACT_TRUE@ libode_a-collision_trimesh_distance.$(OBJEXT) \ | ||
239 | @GIMPACT_TRUE@ libode_a-collision_cylinder_trimesh.$(OBJEXT) \ | ||
240 | @GIMPACT_TRUE@ libode_a-collision_trimesh_plane.$(OBJEXT) | ||
241 | @OPCODE_TRUE@am__objects_2 = \ | ||
242 | @OPCODE_TRUE@ libode_a-collision_trimesh_trimesh.$(OBJEXT) \ | ||
243 | @OPCODE_TRUE@ libode_a-collision_trimesh_sphere.$(OBJEXT) \ | ||
244 | @OPCODE_TRUE@ libode_a-collision_trimesh_ray.$(OBJEXT) \ | ||
245 | @OPCODE_TRUE@ libode_a-collision_trimesh_opcode.$(OBJEXT) \ | ||
246 | @OPCODE_TRUE@ libode_a-collision_trimesh_box.$(OBJEXT) \ | ||
247 | @OPCODE_TRUE@ libode_a-collision_trimesh_ccylinder.$(OBJEXT) \ | ||
248 | @OPCODE_TRUE@ libode_a-collision_trimesh_distance.$(OBJEXT) \ | ||
249 | @OPCODE_TRUE@ libode_a-collision_cylinder_trimesh.$(OBJEXT) \ | ||
250 | @OPCODE_TRUE@ libode_a-collision_trimesh_plane.$(OBJEXT) | ||
251 | am_libode_a_OBJECTS = libode_a-obstack.$(OBJEXT) \ | ||
252 | libode_a-collision_util.$(OBJEXT) libode_a-array.$(OBJEXT) \ | ||
253 | libode_a-ode.$(OBJEXT) libode_a-error.$(OBJEXT) \ | ||
254 | libode_a-odemath.$(OBJEXT) libode_a-collision_kernel.$(OBJEXT) \ | ||
255 | libode_a-export-dif.$(OBJEXT) libode_a-quickstep.$(OBJEXT) \ | ||
256 | libode_a-collision_quadtreespace.$(OBJEXT) \ | ||
257 | libode_a-rotation.$(OBJEXT) libode_a-collision_space.$(OBJEXT) \ | ||
258 | libode_a-collision_cylinder_box.$(OBJEXT) \ | ||
259 | libode_a-collision_cylinder_sphere.$(OBJEXT) \ | ||
260 | libode_a-collision_cylinder_plane.$(OBJEXT) \ | ||
261 | libode_a-sphere.$(OBJEXT) libode_a-box.$(OBJEXT) \ | ||
262 | libode_a-capsule.$(OBJEXT) libode_a-plane.$(OBJEXT) \ | ||
263 | libode_a-ray.$(OBJEXT) libode_a-cylinder.$(OBJEXT) \ | ||
264 | libode_a-convex.$(OBJEXT) libode_a-joint.$(OBJEXT) \ | ||
265 | libode_a-step.$(OBJEXT) libode_a-collision_transform.$(OBJEXT) \ | ||
266 | libode_a-lcp.$(OBJEXT) libode_a-stepfast.$(OBJEXT) \ | ||
267 | libode_a-mass.$(OBJEXT) libode_a-testing.$(OBJEXT) \ | ||
268 | libode_a-mat.$(OBJEXT) libode_a-timer.$(OBJEXT) \ | ||
269 | libode_a-matrix.$(OBJEXT) libode_a-util.$(OBJEXT) \ | ||
270 | libode_a-memory.$(OBJEXT) libode_a-misc.$(OBJEXT) \ | ||
271 | libode_a-heightfield.$(OBJEXT) $(am__objects_1) \ | ||
272 | $(am__objects_2) | ||
273 | libode_a_OBJECTS = $(am_libode_a_OBJECTS) | ||
274 | traplibPROGRAMS_INSTALL = $(INSTALL_PROGRAM) | ||
275 | PROGRAMS = $(traplib_PROGRAMS) | ||
276 | am_libode_OBJECTS = | ||
277 | libode_OBJECTS = $(am_libode_OBJECTS) | ||
278 | libode_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(libode_LDFLAGS) \ | ||
279 | $(LDFLAGS) -o $@ | ||
280 | DEFAULT_INCLUDES = -I. -I$(top_builddir)/include/ode@am__isrc@ | ||
281 | depcomp = $(SHELL) $(top_srcdir)/depcomp | ||
282 | am__depfiles_maybe = depfiles | ||
283 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ | ||
284 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) | ||
285 | CCLD = $(CC) | ||
286 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ | ||
287 | CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ | ||
288 | $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) | ||
289 | CXXLD = $(CXX) | ||
290 | CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ | ||
291 | -o $@ | ||
292 | SOURCES = $(libGIMPACT_a_SOURCES) $(libOPCODE_a_SOURCES) \ | ||
293 | $(libfast_a_SOURCES) $(libode_a_SOURCES) $(libode_SOURCES) | ||
294 | DIST_SOURCES = $(am__libGIMPACT_a_SOURCES_DIST) \ | ||
295 | $(am__libOPCODE_a_SOURCES_DIST) $(libfast_a_SOURCES) \ | ||
296 | $(am__libode_a_SOURCES_DIST) $(libode_SOURCES) | ||
297 | ETAGS = etags | ||
298 | CTAGS = ctags | ||
299 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) | ||
300 | ACLOCAL = @ACLOCAL@ | ||
301 | ALLOCA = @ALLOCA@ | ||
302 | AMTAR = @AMTAR@ | ||
303 | ARCHFLAGS = @ARCHFLAGS@ | ||
304 | AUTOCONF = @AUTOCONF@ | ||
305 | AUTOHEADER = @AUTOHEADER@ | ||
306 | AUTOMAKE = @AUTOMAKE@ | ||
307 | AWK = @AWK@ | ||
308 | CC = @CC@ | ||
309 | CCDEPMODE = @CCDEPMODE@ | ||
310 | CFLAGS = @CFLAGS@ | ||
311 | CPP = @CPP@ | ||
312 | CPPFLAGS = @CPPFLAGS@ | ||
313 | CXX = @CXX@ | ||
314 | CXXDEPMODE = @CXXDEPMODE@ | ||
315 | CXXFLAGS = @CXXFLAGS@ | ||
316 | CYGPATH_W = @CYGPATH_W@ | ||
317 | DEFS = @DEFS@ | ||
318 | DEPDIR = @DEPDIR@ | ||
319 | DRAWSTUFF = @DRAWSTUFF@ | ||
320 | ECHO_C = @ECHO_C@ | ||
321 | ECHO_N = @ECHO_N@ | ||
322 | ECHO_T = @ECHO_T@ | ||
323 | EGREP = @EGREP@ | ||
324 | EXEEXT = @so_ext@ | ||
325 | GL_LIBS = @GL_LIBS@ | ||
326 | GREP = @GREP@ | ||
327 | INSTALL = @INSTALL@ | ||
328 | INSTALL_DATA = @INSTALL_DATA@ | ||
329 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ | ||
330 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ | ||
331 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ | ||
332 | LDFLAGS = @LDFLAGS@ | ||
333 | LIBOBJS = @LIBOBJS@ | ||
334 | LIBS = @LIBS@ | ||
335 | LTLIBOBJS = @LTLIBOBJS@ | ||
336 | MAKEINFO = @MAKEINFO@ | ||
337 | MKDIR_P = @MKDIR_P@ | ||
338 | OBJEXT = @OBJEXT@ | ||
339 | ODE_AGE = @ODE_AGE@ | ||
340 | ODE_CURRENT = @ODE_CURRENT@ | ||
341 | ODE_RELEASE = @ODE_RELEASE@ | ||
342 | ODE_REVISION = @ODE_REVISION@ | ||
343 | ODE_SONAME = @ODE_SONAME@ | ||
344 | PACKAGE = @PACKAGE@ | ||
345 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ | ||
346 | PACKAGE_NAME = @PACKAGE_NAME@ | ||
347 | PACKAGE_STRING = @PACKAGE_STRING@ | ||
348 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ | ||
349 | PACKAGE_VERSION = @PACKAGE_VERSION@ | ||
350 | PATH_SEPARATOR = @PATH_SEPARATOR@ | ||
351 | RANLIB = @RANLIB@ | ||
352 | SET_MAKE = @SET_MAKE@ | ||
353 | SHARED_LDFLAGS = @SHARED_LDFLAGS@ | ||
354 | SHELL = @SHELL@ | ||
355 | STRIP = @STRIP@ | ||
356 | TOPDIR = @TOPDIR@ | ||
357 | VERSION = @VERSION@ | ||
358 | WINDRES = @WINDRES@ | ||
359 | XMKMF = @XMKMF@ | ||
360 | X_CFLAGS = @X_CFLAGS@ | ||
361 | X_EXTRA_LIBS = @X_EXTRA_LIBS@ | ||
362 | X_LIBS = @X_LIBS@ | ||
363 | X_PRE_LIBS = @X_PRE_LIBS@ | ||
364 | abs_builddir = @abs_builddir@ | ||
365 | abs_srcdir = @abs_srcdir@ | ||
366 | abs_top_builddir = @abs_top_builddir@ | ||
367 | abs_top_srcdir = @abs_top_srcdir@ | ||
368 | ac_ct_CC = @ac_ct_CC@ | ||
369 | ac_ct_CXX = @ac_ct_CXX@ | ||
370 | ac_ct_WINDRES = @ac_ct_WINDRES@ | ||
371 | am__include = @am__include@ | ||
372 | am__leading_dot = @am__leading_dot@ | ||
373 | am__quote = @am__quote@ | ||
374 | am__tar = @am__tar@ | ||
375 | am__untar = @am__untar@ | ||
376 | bindir = @bindir@ | ||
377 | build = @build@ | ||
378 | build_alias = @build_alias@ | ||
379 | build_cpu = @build_cpu@ | ||
380 | build_os = @build_os@ | ||
381 | build_vendor = @build_vendor@ | ||
382 | builddir = @builddir@ | ||
383 | datadir = @datadir@ | ||
384 | datarootdir = @datarootdir@ | ||
385 | docdir = @docdir@ | ||
386 | dvidir = @dvidir@ | ||
387 | exec_prefix = @exec_prefix@ | ||
388 | host = @host@ | ||
389 | host_alias = @host_alias@ | ||
390 | host_cpu = @host_cpu@ | ||
391 | host_os = @host_os@ | ||
392 | host_vendor = @host_vendor@ | ||
393 | htmldir = @htmldir@ | ||
394 | includedir = @includedir@ | ||
395 | infodir = @infodir@ | ||
396 | install_sh = @install_sh@ | ||
397 | libdir = @libdir@ | ||
398 | libexecdir = @libexecdir@ | ||
399 | localedir = @localedir@ | ||
400 | localstatedir = @localstatedir@ | ||
401 | mandir = @mandir@ | ||
402 | mkdir_p = @mkdir_p@ | ||
403 | oldincludedir = @oldincludedir@ | ||
404 | pdfdir = @pdfdir@ | ||
405 | prefix = @prefix@ | ||
406 | program_transform_name = @program_transform_name@ | ||
407 | psdir = @psdir@ | ||
408 | sbindir = @sbindir@ | ||
409 | sharedstatedir = @sharedstatedir@ | ||
410 | so_ext = @so_ext@ | ||
411 | srcdir = @srcdir@ | ||
412 | sysconfdir = @sysconfdir@ | ||
413 | target = @target@ | ||
414 | target_alias = @target_alias@ | ||
415 | target_cpu = @target_cpu@ | ||
416 | target_os = @target_os@ | ||
417 | target_vendor = @target_vendor@ | ||
418 | top_builddir = @top_builddir@ | ||
419 | top_srcdir = @top_srcdir@ | ||
420 | AM_CXXFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include \ | ||
421 | -I$(top_builddir)/include $(am__append_10) $(am__append_15) | ||
422 | AM_CPPFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include -I$(top_builddir)/include | ||
423 | AM_CFLAGS = @ARCHFLAGS@ -I$(top_srcdir)/include \ | ||
424 | -I$(top_builddir)/include $(am__append_11) $(am__append_16) | ||
425 | lib_LIBRARIES = libode.a | ||
426 | libode_a_CPPFLAGS = -O2 -fPIC | ||
427 | |||
428 | # Fake an executable in order to get a shared library | ||
429 | # Note the elegant and cunning way to trick Autotools to install a program | ||
430 | # in a lib directory. --Rodrigo | ||
431 | traplibdir = $(libdir) | ||
432 | libode_SOURCES = | ||
433 | libode_DEPENDENCIES = libfast.a libode.a $(am__append_2) \ | ||
434 | $(am__append_4) | ||
435 | libode_LDFLAGS = @SHARED_LDFLAGS@ $(am__append_1) | ||
436 | libode_LDADD = $(libode_a_OBJECTS) $(libfast_a_OBJECTS) \ | ||
437 | $(am__append_3) $(am__append_5) | ||
438 | |||
439 | # convenience library to simulate per object cflags | ||
440 | noinst_LIBRARIES = libfast.a $(am__append_6) $(am__append_12) | ||
441 | libfast_a_CFLAGS = -O1 -fPIC | ||
442 | libfast_a_SOURCES = fastldlt.c fastltsolve.c fastdot.c fastlsolve.c | ||
443 | libode_a_DEPENDENCIES = libfast.a $(am__append_8) $(am__append_13) | ||
444 | libode_a_LIBADD = $(libfast_a_OBJECTS) $(am__append_9) \ | ||
445 | $(am__append_14) | ||
446 | libode_a_SOURCES = objects.h obstack.cpp collision_util.cpp obstack.h \ | ||
447 | array.cpp collision_util.h ode.cpp array.h error.cpp \ | ||
448 | odemath.cpp collision_kernel.cpp export-dif.cpp quickstep.cpp \ | ||
449 | collision_kernel.h quickstep.h collision_quadtreespace.cpp \ | ||
450 | rotation.cpp collision_space.cpp collision_space_internal.h \ | ||
451 | collision_cylinder_box.cpp collision_cylinder_sphere.cpp \ | ||
452 | collision_cylinder_plane.cpp sphere.cpp box.cpp capsule.cpp \ | ||
453 | plane.cpp ray.cpp cylinder.cpp convex.cpp joint.cpp stack.h \ | ||
454 | collision_std.h joint.h step.cpp collision_transform.cpp \ | ||
455 | lcp.cpp step.h collision_transform.h lcp.h stepfast.cpp \ | ||
456 | mass.cpp testing.cpp mat.cpp testing.h mat.h timer.cpp \ | ||
457 | matrix.cpp util.cpp memory.cpp util.h misc.cpp heightfield.cpp \ | ||
458 | heightfield.h $(am__append_7) $(am__append_17) | ||
459 | @GIMPACT_TRUE@libGIMPACT_a_CPPFLAGS = -O2 -fno-strict-aliasing -fPIC | ||
460 | @GIMPACT_TRUE@libGIMPACT_a_SOURCES = \ | ||
461 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_boxpruning.cpp \ | ||
462 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_contact.cpp \ | ||
463 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_math.cpp \ | ||
464 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_memory.cpp \ | ||
465 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp \ | ||
466 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_trimesh.cpp \ | ||
467 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp \ | ||
468 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp \ | ||
469 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp \ | ||
470 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp \ | ||
471 | @GIMPACT_TRUE@ @TOPDIR@/GIMPACT/src/gimpact.cpp | ||
472 | |||
473 | @OPCODE_TRUE@libOPCODE_a_CPPFLAGS = -O2 -fno-strict-aliasing -fPIC | ||
474 | @OPCODE_TRUE@libOPCODE_a_SOURCES = @TOPDIR@/OPCODE/OPC_AABBCollider.cpp \ | ||
475 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_AABBTree.cpp \ | ||
476 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_BaseModel.cpp \ | ||
477 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_BoxPruning.cpp \ | ||
478 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_Collider.cpp \ | ||
479 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_Common.cpp \ | ||
480 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_HybridModel.cpp \ | ||
481 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_LSSCollider.cpp \ | ||
482 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_MeshInterface.cpp \ | ||
483 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_Model.cpp \ | ||
484 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_OBBCollider.cpp \ | ||
485 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Opcode.cpp \ | ||
486 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_OptimizedTree.cpp \ | ||
487 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_Picking.cpp \ | ||
488 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_PlanesCollider.cpp \ | ||
489 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_RayCollider.cpp \ | ||
490 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_SphereCollider.cpp \ | ||
491 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp \ | ||
492 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_TreeBuilders.cpp \ | ||
493 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_TreeCollider.cpp \ | ||
494 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/OPC_VolumeCollider.cpp \ | ||
495 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceAABB.cpp \ | ||
496 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceContainer.cpp \ | ||
497 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceHPoint.cpp \ | ||
498 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp \ | ||
499 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp \ | ||
500 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp \ | ||
501 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceOBB.cpp \ | ||
502 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IcePlane.cpp \ | ||
503 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IcePoint.cpp \ | ||
504 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceRandom.cpp \ | ||
505 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceRay.cpp \ | ||
506 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp \ | ||
507 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceSegment.cpp \ | ||
508 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceTriangle.cpp \ | ||
509 | @OPCODE_TRUE@ @TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
510 | |||
511 | all: all-am | ||
512 | |||
513 | .SUFFIXES: | ||
514 | .SUFFIXES: .c .cpp .o .obj | ||
515 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) | ||
516 | @for dep in $?; do \ | ||
517 | case '$(am__configure_deps)' in \ | ||
518 | *$$dep*) \ | ||
519 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ | ||
520 | && exit 0; \ | ||
521 | exit 1;; \ | ||
522 | esac; \ | ||
523 | done; \ | ||
524 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ode/src/Makefile'; \ | ||
525 | cd $(top_srcdir) && \ | ||
526 | $(AUTOMAKE) --foreign ode/src/Makefile | ||
527 | .PRECIOUS: Makefile | ||
528 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status | ||
529 | @case '$?' in \ | ||
530 | *config.status*) \ | ||
531 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ | ||
532 | *) \ | ||
533 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ | ||
534 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ | ||
535 | esac; | ||
536 | |||
537 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) | ||
538 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
539 | |||
540 | $(top_srcdir)/configure: $(am__configure_deps) | ||
541 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
542 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) | ||
543 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh | ||
544 | install-libLIBRARIES: $(lib_LIBRARIES) | ||
545 | @$(NORMAL_INSTALL) | ||
546 | test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" | ||
547 | @list='$(lib_LIBRARIES)'; for p in $$list; do \ | ||
548 | if test -f $$p; then \ | ||
549 | f=$(am__strip_dir) \ | ||
550 | echo " $(libLIBRARIES_INSTALL) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ | ||
551 | $(libLIBRARIES_INSTALL) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ | ||
552 | else :; fi; \ | ||
553 | done | ||
554 | @$(POST_INSTALL) | ||
555 | @list='$(lib_LIBRARIES)'; for p in $$list; do \ | ||
556 | if test -f $$p; then \ | ||
557 | p=$(am__strip_dir) \ | ||
558 | echo " $(RANLIB) '$(DESTDIR)$(libdir)/$$p'"; \ | ||
559 | $(RANLIB) "$(DESTDIR)$(libdir)/$$p"; \ | ||
560 | else :; fi; \ | ||
561 | done | ||
562 | |||
563 | uninstall-libLIBRARIES: | ||
564 | @$(NORMAL_UNINSTALL) | ||
565 | @list='$(lib_LIBRARIES)'; for p in $$list; do \ | ||
566 | p=$(am__strip_dir) \ | ||
567 | echo " rm -f '$(DESTDIR)$(libdir)/$$p'"; \ | ||
568 | rm -f "$(DESTDIR)$(libdir)/$$p"; \ | ||
569 | done | ||
570 | |||
571 | clean-libLIBRARIES: | ||
572 | -test -z "$(lib_LIBRARIES)" || rm -f $(lib_LIBRARIES) | ||
573 | |||
574 | clean-noinstLIBRARIES: | ||
575 | -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) | ||
576 | libGIMPACT.a: $(libGIMPACT_a_OBJECTS) $(libGIMPACT_a_DEPENDENCIES) | ||
577 | -rm -f libGIMPACT.a | ||
578 | $(libGIMPACT_a_AR) libGIMPACT.a $(libGIMPACT_a_OBJECTS) $(libGIMPACT_a_LIBADD) | ||
579 | $(RANLIB) libGIMPACT.a | ||
580 | libOPCODE.a: $(libOPCODE_a_OBJECTS) $(libOPCODE_a_DEPENDENCIES) | ||
581 | -rm -f libOPCODE.a | ||
582 | $(libOPCODE_a_AR) libOPCODE.a $(libOPCODE_a_OBJECTS) $(libOPCODE_a_LIBADD) | ||
583 | $(RANLIB) libOPCODE.a | ||
584 | libfast.a: $(libfast_a_OBJECTS) $(libfast_a_DEPENDENCIES) | ||
585 | -rm -f libfast.a | ||
586 | $(libfast_a_AR) libfast.a $(libfast_a_OBJECTS) $(libfast_a_LIBADD) | ||
587 | $(RANLIB) libfast.a | ||
588 | libode.a: $(libode_a_OBJECTS) $(libode_a_DEPENDENCIES) | ||
589 | -rm -f libode.a | ||
590 | $(libode_a_AR) libode.a $(libode_a_OBJECTS) $(libode_a_LIBADD) | ||
591 | $(RANLIB) libode.a | ||
592 | install-traplibPROGRAMS: $(traplib_PROGRAMS) | ||
593 | @$(NORMAL_INSTALL) | ||
594 | test -z "$(traplibdir)" || $(MKDIR_P) "$(DESTDIR)$(traplibdir)" | ||
595 | @list='$(traplib_PROGRAMS)'; for p in $$list; do \ | ||
596 | p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ | ||
597 | if test -f $$p \ | ||
598 | ; then \ | ||
599 | f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ | ||
600 | echo " $(INSTALL_PROGRAM_ENV) $(traplibPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(traplibdir)/$$f'"; \ | ||
601 | $(INSTALL_PROGRAM_ENV) $(traplibPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(traplibdir)/$$f" || exit 1; \ | ||
602 | else :; fi; \ | ||
603 | done | ||
604 | |||
605 | uninstall-traplibPROGRAMS: | ||
606 | @$(NORMAL_UNINSTALL) | ||
607 | @list='$(traplib_PROGRAMS)'; for p in $$list; do \ | ||
608 | f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ | ||
609 | echo " rm -f '$(DESTDIR)$(traplibdir)/$$f'"; \ | ||
610 | rm -f "$(DESTDIR)$(traplibdir)/$$f"; \ | ||
611 | done | ||
612 | |||
613 | clean-traplibPROGRAMS: | ||
614 | -test -z "$(traplib_PROGRAMS)" || rm -f $(traplib_PROGRAMS) | ||
615 | libode$(EXEEXT): $(libode_OBJECTS) $(libode_DEPENDENCIES) | ||
616 | @rm -f libode$(EXEEXT) | ||
617 | $(libode_LINK) $(libode_OBJECTS) $(libode_LDADD) $(LIBS) | ||
618 | |||
619 | mostlyclean-compile: | ||
620 | -rm -f *.$(OBJEXT) | ||
621 | |||
622 | distclean-compile: | ||
623 | -rm -f *.tab.c | ||
624 | |||
625 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_boxpruning.Po@am__quote@ | ||
626 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_contact.Po@am__quote@ | ||
627 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_math.Po@am__quote@ | ||
628 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_memory.Po@am__quote@ | ||
629 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Po@am__quote@ | ||
630 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_trimesh.Po@am__quote@ | ||
631 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Po@am__quote@ | ||
632 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Po@am__quote@ | ||
633 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Po@am__quote@ | ||
634 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Po@am__quote@ | ||
635 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libGIMPACT_a-gimpact.Po@am__quote@ | ||
636 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceAABB.Po@am__quote@ | ||
637 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceContainer.Po@am__quote@ | ||
638 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceHPoint.Po@am__quote@ | ||
639 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Po@am__quote@ | ||
640 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceMatrix3x3.Po@am__quote@ | ||
641 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceMatrix4x4.Po@am__quote@ | ||
642 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceOBB.Po@am__quote@ | ||
643 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IcePlane.Po@am__quote@ | ||
644 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IcePoint.Po@am__quote@ | ||
645 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceRandom.Po@am__quote@ | ||
646 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceRay.Po@am__quote@ | ||
647 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Po@am__quote@ | ||
648 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceSegment.Po@am__quote@ | ||
649 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceTriangle.Po@am__quote@ | ||
650 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-IceUtils.Po@am__quote@ | ||
651 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Po@am__quote@ | ||
652 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_AABBTree.Po@am__quote@ | ||
653 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_BaseModel.Po@am__quote@ | ||
654 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Po@am__quote@ | ||
655 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_Collider.Po@am__quote@ | ||
656 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_Common.Po@am__quote@ | ||
657 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_HybridModel.Po@am__quote@ | ||
658 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Po@am__quote@ | ||
659 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Po@am__quote@ | ||
660 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_Model.Po@am__quote@ | ||
661 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Po@am__quote@ | ||
662 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Po@am__quote@ | ||
663 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_Picking.Po@am__quote@ | ||
664 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Po@am__quote@ | ||
665 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_RayCollider.Po@am__quote@ | ||
666 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Po@am__quote@ | ||
667 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Po@am__quote@ | ||
668 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Po@am__quote@ | ||
669 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Po@am__quote@ | ||
670 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Po@am__quote@ | ||
671 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libOPCODE_a-Opcode.Po@am__quote@ | ||
672 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfast_a-fastdot.Po@am__quote@ | ||
673 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfast_a-fastldlt.Po@am__quote@ | ||
674 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfast_a-fastlsolve.Po@am__quote@ | ||
675 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfast_a-fastltsolve.Po@am__quote@ | ||
676 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-array.Po@am__quote@ | ||
677 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-box.Po@am__quote@ | ||
678 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-capsule.Po@am__quote@ | ||
679 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_cylinder_box.Po@am__quote@ | ||
680 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_cylinder_plane.Po@am__quote@ | ||
681 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_cylinder_sphere.Po@am__quote@ | ||
682 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_cylinder_trimesh.Po@am__quote@ | ||
683 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_kernel.Po@am__quote@ | ||
684 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_quadtreespace.Po@am__quote@ | ||
685 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_space.Po@am__quote@ | ||
686 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_transform.Po@am__quote@ | ||
687 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_box.Po@am__quote@ | ||
688 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_ccylinder.Po@am__quote@ | ||
689 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_distance.Po@am__quote@ | ||
690 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_gimpact.Po@am__quote@ | ||
691 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_opcode.Po@am__quote@ | ||
692 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_plane.Po@am__quote@ | ||
693 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_ray.Po@am__quote@ | ||
694 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_sphere.Po@am__quote@ | ||
695 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_trimesh_trimesh.Po@am__quote@ | ||
696 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-collision_util.Po@am__quote@ | ||
697 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-convex.Po@am__quote@ | ||
698 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-cylinder.Po@am__quote@ | ||
699 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-error.Po@am__quote@ | ||
700 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-export-dif.Po@am__quote@ | ||
701 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-heightfield.Po@am__quote@ | ||
702 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-joint.Po@am__quote@ | ||
703 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-lcp.Po@am__quote@ | ||
704 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-mass.Po@am__quote@ | ||
705 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-mat.Po@am__quote@ | ||
706 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-matrix.Po@am__quote@ | ||
707 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-memory.Po@am__quote@ | ||
708 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-misc.Po@am__quote@ | ||
709 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-obstack.Po@am__quote@ | ||
710 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-ode.Po@am__quote@ | ||
711 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-odemath.Po@am__quote@ | ||
712 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-plane.Po@am__quote@ | ||
713 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-quickstep.Po@am__quote@ | ||
714 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-ray.Po@am__quote@ | ||
715 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-rotation.Po@am__quote@ | ||
716 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-sphere.Po@am__quote@ | ||
717 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-step.Po@am__quote@ | ||
718 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-stepfast.Po@am__quote@ | ||
719 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-testing.Po@am__quote@ | ||
720 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-timer.Po@am__quote@ | ||
721 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libode_a-util.Po@am__quote@ | ||
722 | |||
723 | .c.o: | ||
724 | @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | ||
725 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
726 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
727 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
728 | @am__fastdepCC_FALSE@ $(COMPILE) -c $< | ||
729 | |||
730 | .c.obj: | ||
731 | @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` | ||
732 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
733 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
734 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
735 | @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` | ||
736 | |||
737 | libfast_a-fastldlt.o: fastldlt.c | ||
738 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastldlt.o -MD -MP -MF $(DEPDIR)/libfast_a-fastldlt.Tpo -c -o libfast_a-fastldlt.o `test -f 'fastldlt.c' || echo '$(srcdir)/'`fastldlt.c | ||
739 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastldlt.Tpo $(DEPDIR)/libfast_a-fastldlt.Po | ||
740 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastldlt.c' object='libfast_a-fastldlt.o' libtool=no @AMDEPBACKSLASH@ | ||
741 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
742 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastldlt.o `test -f 'fastldlt.c' || echo '$(srcdir)/'`fastldlt.c | ||
743 | |||
744 | libfast_a-fastldlt.obj: fastldlt.c | ||
745 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastldlt.obj -MD -MP -MF $(DEPDIR)/libfast_a-fastldlt.Tpo -c -o libfast_a-fastldlt.obj `if test -f 'fastldlt.c'; then $(CYGPATH_W) 'fastldlt.c'; else $(CYGPATH_W) '$(srcdir)/fastldlt.c'; fi` | ||
746 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastldlt.Tpo $(DEPDIR)/libfast_a-fastldlt.Po | ||
747 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastldlt.c' object='libfast_a-fastldlt.obj' libtool=no @AMDEPBACKSLASH@ | ||
748 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
749 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastldlt.obj `if test -f 'fastldlt.c'; then $(CYGPATH_W) 'fastldlt.c'; else $(CYGPATH_W) '$(srcdir)/fastldlt.c'; fi` | ||
750 | |||
751 | libfast_a-fastltsolve.o: fastltsolve.c | ||
752 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastltsolve.o -MD -MP -MF $(DEPDIR)/libfast_a-fastltsolve.Tpo -c -o libfast_a-fastltsolve.o `test -f 'fastltsolve.c' || echo '$(srcdir)/'`fastltsolve.c | ||
753 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastltsolve.Tpo $(DEPDIR)/libfast_a-fastltsolve.Po | ||
754 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastltsolve.c' object='libfast_a-fastltsolve.o' libtool=no @AMDEPBACKSLASH@ | ||
755 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
756 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastltsolve.o `test -f 'fastltsolve.c' || echo '$(srcdir)/'`fastltsolve.c | ||
757 | |||
758 | libfast_a-fastltsolve.obj: fastltsolve.c | ||
759 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastltsolve.obj -MD -MP -MF $(DEPDIR)/libfast_a-fastltsolve.Tpo -c -o libfast_a-fastltsolve.obj `if test -f 'fastltsolve.c'; then $(CYGPATH_W) 'fastltsolve.c'; else $(CYGPATH_W) '$(srcdir)/fastltsolve.c'; fi` | ||
760 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastltsolve.Tpo $(DEPDIR)/libfast_a-fastltsolve.Po | ||
761 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastltsolve.c' object='libfast_a-fastltsolve.obj' libtool=no @AMDEPBACKSLASH@ | ||
762 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
763 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastltsolve.obj `if test -f 'fastltsolve.c'; then $(CYGPATH_W) 'fastltsolve.c'; else $(CYGPATH_W) '$(srcdir)/fastltsolve.c'; fi` | ||
764 | |||
765 | libfast_a-fastdot.o: fastdot.c | ||
766 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastdot.o -MD -MP -MF $(DEPDIR)/libfast_a-fastdot.Tpo -c -o libfast_a-fastdot.o `test -f 'fastdot.c' || echo '$(srcdir)/'`fastdot.c | ||
767 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastdot.Tpo $(DEPDIR)/libfast_a-fastdot.Po | ||
768 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastdot.c' object='libfast_a-fastdot.o' libtool=no @AMDEPBACKSLASH@ | ||
769 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
770 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastdot.o `test -f 'fastdot.c' || echo '$(srcdir)/'`fastdot.c | ||
771 | |||
772 | libfast_a-fastdot.obj: fastdot.c | ||
773 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastdot.obj -MD -MP -MF $(DEPDIR)/libfast_a-fastdot.Tpo -c -o libfast_a-fastdot.obj `if test -f 'fastdot.c'; then $(CYGPATH_W) 'fastdot.c'; else $(CYGPATH_W) '$(srcdir)/fastdot.c'; fi` | ||
774 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastdot.Tpo $(DEPDIR)/libfast_a-fastdot.Po | ||
775 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastdot.c' object='libfast_a-fastdot.obj' libtool=no @AMDEPBACKSLASH@ | ||
776 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
777 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastdot.obj `if test -f 'fastdot.c'; then $(CYGPATH_W) 'fastdot.c'; else $(CYGPATH_W) '$(srcdir)/fastdot.c'; fi` | ||
778 | |||
779 | libfast_a-fastlsolve.o: fastlsolve.c | ||
780 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastlsolve.o -MD -MP -MF $(DEPDIR)/libfast_a-fastlsolve.Tpo -c -o libfast_a-fastlsolve.o `test -f 'fastlsolve.c' || echo '$(srcdir)/'`fastlsolve.c | ||
781 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastlsolve.Tpo $(DEPDIR)/libfast_a-fastlsolve.Po | ||
782 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastlsolve.c' object='libfast_a-fastlsolve.o' libtool=no @AMDEPBACKSLASH@ | ||
783 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
784 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastlsolve.o `test -f 'fastlsolve.c' || echo '$(srcdir)/'`fastlsolve.c | ||
785 | |||
786 | libfast_a-fastlsolve.obj: fastlsolve.c | ||
787 | @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -MT libfast_a-fastlsolve.obj -MD -MP -MF $(DEPDIR)/libfast_a-fastlsolve.Tpo -c -o libfast_a-fastlsolve.obj `if test -f 'fastlsolve.c'; then $(CYGPATH_W) 'fastlsolve.c'; else $(CYGPATH_W) '$(srcdir)/fastlsolve.c'; fi` | ||
788 | @am__fastdepCC_TRUE@ mv -f $(DEPDIR)/libfast_a-fastlsolve.Tpo $(DEPDIR)/libfast_a-fastlsolve.Po | ||
789 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='fastlsolve.c' object='libfast_a-fastlsolve.obj' libtool=no @AMDEPBACKSLASH@ | ||
790 | @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
791 | @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfast_a_CFLAGS) $(CFLAGS) -c -o libfast_a-fastlsolve.obj `if test -f 'fastlsolve.c'; then $(CYGPATH_W) 'fastlsolve.c'; else $(CYGPATH_W) '$(srcdir)/fastlsolve.c'; fi` | ||
792 | |||
793 | .cpp.o: | ||
794 | @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< | ||
795 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
796 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
797 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
798 | @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< | ||
799 | |||
800 | .cpp.obj: | ||
801 | @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` | ||
802 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po | ||
803 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ | ||
804 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
805 | @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` | ||
806 | |||
807 | libGIMPACT_a-gim_boxpruning.o: @TOPDIR@/GIMPACT/src/gim_boxpruning.cpp | ||
808 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_boxpruning.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Tpo -c -o libGIMPACT_a-gim_boxpruning.o `test -f '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp | ||
809 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Tpo $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Po | ||
810 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp' object='libGIMPACT_a-gim_boxpruning.o' libtool=no @AMDEPBACKSLASH@ | ||
811 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
812 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_boxpruning.o `test -f '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp | ||
813 | |||
814 | libGIMPACT_a-gim_boxpruning.obj: @TOPDIR@/GIMPACT/src/gim_boxpruning.cpp | ||
815 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_boxpruning.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Tpo -c -o libGIMPACT_a-gim_boxpruning.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; fi` | ||
816 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Tpo $(DEPDIR)/libGIMPACT_a-gim_boxpruning.Po | ||
817 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp' object='libGIMPACT_a-gim_boxpruning.obj' libtool=no @AMDEPBACKSLASH@ | ||
818 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
819 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_boxpruning.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_boxpruning.cpp'; fi` | ||
820 | |||
821 | libGIMPACT_a-gim_contact.o: @TOPDIR@/GIMPACT/src/gim_contact.cpp | ||
822 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_contact.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_contact.Tpo -c -o libGIMPACT_a-gim_contact.o `test -f '@TOPDIR@/GIMPACT/src/gim_contact.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_contact.cpp | ||
823 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_contact.Tpo $(DEPDIR)/libGIMPACT_a-gim_contact.Po | ||
824 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_contact.cpp' object='libGIMPACT_a-gim_contact.o' libtool=no @AMDEPBACKSLASH@ | ||
825 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
826 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_contact.o `test -f '@TOPDIR@/GIMPACT/src/gim_contact.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_contact.cpp | ||
827 | |||
828 | libGIMPACT_a-gim_contact.obj: @TOPDIR@/GIMPACT/src/gim_contact.cpp | ||
829 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_contact.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_contact.Tpo -c -o libGIMPACT_a-gim_contact.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_contact.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_contact.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_contact.cpp'; fi` | ||
830 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_contact.Tpo $(DEPDIR)/libGIMPACT_a-gim_contact.Po | ||
831 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_contact.cpp' object='libGIMPACT_a-gim_contact.obj' libtool=no @AMDEPBACKSLASH@ | ||
832 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
833 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_contact.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_contact.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_contact.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_contact.cpp'; fi` | ||
834 | |||
835 | libGIMPACT_a-gim_math.o: @TOPDIR@/GIMPACT/src/gim_math.cpp | ||
836 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_math.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_math.Tpo -c -o libGIMPACT_a-gim_math.o `test -f '@TOPDIR@/GIMPACT/src/gim_math.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_math.cpp | ||
837 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_math.Tpo $(DEPDIR)/libGIMPACT_a-gim_math.Po | ||
838 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_math.cpp' object='libGIMPACT_a-gim_math.o' libtool=no @AMDEPBACKSLASH@ | ||
839 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
840 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_math.o `test -f '@TOPDIR@/GIMPACT/src/gim_math.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_math.cpp | ||
841 | |||
842 | libGIMPACT_a-gim_math.obj: @TOPDIR@/GIMPACT/src/gim_math.cpp | ||
843 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_math.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_math.Tpo -c -o libGIMPACT_a-gim_math.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_math.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_math.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_math.cpp'; fi` | ||
844 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_math.Tpo $(DEPDIR)/libGIMPACT_a-gim_math.Po | ||
845 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_math.cpp' object='libGIMPACT_a-gim_math.obj' libtool=no @AMDEPBACKSLASH@ | ||
846 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
847 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_math.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_math.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_math.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_math.cpp'; fi` | ||
848 | |||
849 | libGIMPACT_a-gim_memory.o: @TOPDIR@/GIMPACT/src/gim_memory.cpp | ||
850 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_memory.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_memory.Tpo -c -o libGIMPACT_a-gim_memory.o `test -f '@TOPDIR@/GIMPACT/src/gim_memory.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_memory.cpp | ||
851 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_memory.Tpo $(DEPDIR)/libGIMPACT_a-gim_memory.Po | ||
852 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_memory.cpp' object='libGIMPACT_a-gim_memory.o' libtool=no @AMDEPBACKSLASH@ | ||
853 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
854 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_memory.o `test -f '@TOPDIR@/GIMPACT/src/gim_memory.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_memory.cpp | ||
855 | |||
856 | libGIMPACT_a-gim_memory.obj: @TOPDIR@/GIMPACT/src/gim_memory.cpp | ||
857 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_memory.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_memory.Tpo -c -o libGIMPACT_a-gim_memory.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_memory.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_memory.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_memory.cpp'; fi` | ||
858 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_memory.Tpo $(DEPDIR)/libGIMPACT_a-gim_memory.Po | ||
859 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_memory.cpp' object='libGIMPACT_a-gim_memory.obj' libtool=no @AMDEPBACKSLASH@ | ||
860 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
861 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_memory.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_memory.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_memory.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_memory.cpp'; fi` | ||
862 | |||
863 | libGIMPACT_a-gim_tri_tri_overlap.o: @TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp | ||
864 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_tri_tri_overlap.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Tpo -c -o libGIMPACT_a-gim_tri_tri_overlap.o `test -f '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp | ||
865 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Tpo $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Po | ||
866 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp' object='libGIMPACT_a-gim_tri_tri_overlap.o' libtool=no @AMDEPBACKSLASH@ | ||
867 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
868 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_tri_tri_overlap.o `test -f '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp | ||
869 | |||
870 | libGIMPACT_a-gim_tri_tri_overlap.obj: @TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp | ||
871 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_tri_tri_overlap.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Tpo -c -o libGIMPACT_a-gim_tri_tri_overlap.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; fi` | ||
872 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Tpo $(DEPDIR)/libGIMPACT_a-gim_tri_tri_overlap.Po | ||
873 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp' object='libGIMPACT_a-gim_tri_tri_overlap.obj' libtool=no @AMDEPBACKSLASH@ | ||
874 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
875 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_tri_tri_overlap.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_tri_tri_overlap.cpp'; fi` | ||
876 | |||
877 | libGIMPACT_a-gim_trimesh.o: @TOPDIR@/GIMPACT/src/gim_trimesh.cpp | ||
878 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh.Tpo -c -o libGIMPACT_a-gim_trimesh.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh.cpp | ||
879 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh.Po | ||
880 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh.cpp' object='libGIMPACT_a-gim_trimesh.o' libtool=no @AMDEPBACKSLASH@ | ||
881 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
882 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh.cpp | ||
883 | |||
884 | libGIMPACT_a-gim_trimesh.obj: @TOPDIR@/GIMPACT/src/gim_trimesh.cpp | ||
885 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh.Tpo -c -o libGIMPACT_a-gim_trimesh.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; fi` | ||
886 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh.Po | ||
887 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh.cpp' object='libGIMPACT_a-gim_trimesh.obj' libtool=no @AMDEPBACKSLASH@ | ||
888 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
889 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh.cpp'; fi` | ||
890 | |||
891 | libGIMPACT_a-gim_trimesh_capsule_collision.o: @TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp | ||
892 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_capsule_collision.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_capsule_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp | ||
893 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Po | ||
894 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp' object='libGIMPACT_a-gim_trimesh_capsule_collision.o' libtool=no @AMDEPBACKSLASH@ | ||
895 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
896 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_capsule_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp | ||
897 | |||
898 | libGIMPACT_a-gim_trimesh_capsule_collision.obj: @TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp | ||
899 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_capsule_collision.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_capsule_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; fi` | ||
900 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_capsule_collision.Po | ||
901 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp' object='libGIMPACT_a-gim_trimesh_capsule_collision.obj' libtool=no @AMDEPBACKSLASH@ | ||
902 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
903 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_capsule_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_capsule_collision.cpp'; fi` | ||
904 | |||
905 | libGIMPACT_a-gim_trimesh_ray_collision.o: @TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp | ||
906 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_ray_collision.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_ray_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp | ||
907 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Po | ||
908 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp' object='libGIMPACT_a-gim_trimesh_ray_collision.o' libtool=no @AMDEPBACKSLASH@ | ||
909 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
910 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_ray_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp | ||
911 | |||
912 | libGIMPACT_a-gim_trimesh_ray_collision.obj: @TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp | ||
913 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_ray_collision.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_ray_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; fi` | ||
914 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_ray_collision.Po | ||
915 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp' object='libGIMPACT_a-gim_trimesh_ray_collision.obj' libtool=no @AMDEPBACKSLASH@ | ||
916 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
917 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_ray_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_ray_collision.cpp'; fi` | ||
918 | |||
919 | libGIMPACT_a-gim_trimesh_sphere_collision.o: @TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp | ||
920 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_sphere_collision.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_sphere_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp | ||
921 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Po | ||
922 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp' object='libGIMPACT_a-gim_trimesh_sphere_collision.o' libtool=no @AMDEPBACKSLASH@ | ||
923 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
924 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_sphere_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp | ||
925 | |||
926 | libGIMPACT_a-gim_trimesh_sphere_collision.obj: @TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp | ||
927 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_sphere_collision.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_sphere_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; fi` | ||
928 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_sphere_collision.Po | ||
929 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp' object='libGIMPACT_a-gim_trimesh_sphere_collision.obj' libtool=no @AMDEPBACKSLASH@ | ||
930 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
931 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_sphere_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_sphere_collision.cpp'; fi` | ||
932 | |||
933 | libGIMPACT_a-gim_trimesh_trimesh_collision.o: @TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp | ||
934 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_trimesh_collision.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_trimesh_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp | ||
935 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Po | ||
936 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp' object='libGIMPACT_a-gim_trimesh_trimesh_collision.o' libtool=no @AMDEPBACKSLASH@ | ||
937 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
938 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_trimesh_collision.o `test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp | ||
939 | |||
940 | libGIMPACT_a-gim_trimesh_trimesh_collision.obj: @TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp | ||
941 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gim_trimesh_trimesh_collision.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Tpo -c -o libGIMPACT_a-gim_trimesh_trimesh_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; fi` | ||
942 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Tpo $(DEPDIR)/libGIMPACT_a-gim_trimesh_trimesh_collision.Po | ||
943 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp' object='libGIMPACT_a-gim_trimesh_trimesh_collision.obj' libtool=no @AMDEPBACKSLASH@ | ||
944 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
945 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gim_trimesh_trimesh_collision.obj `if test -f '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gim_trimesh_trimesh_collision.cpp'; fi` | ||
946 | |||
947 | libGIMPACT_a-gimpact.o: @TOPDIR@/GIMPACT/src/gimpact.cpp | ||
948 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gimpact.o -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gimpact.Tpo -c -o libGIMPACT_a-gimpact.o `test -f '@TOPDIR@/GIMPACT/src/gimpact.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gimpact.cpp | ||
949 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gimpact.Tpo $(DEPDIR)/libGIMPACT_a-gimpact.Po | ||
950 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gimpact.cpp' object='libGIMPACT_a-gimpact.o' libtool=no @AMDEPBACKSLASH@ | ||
951 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
952 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gimpact.o `test -f '@TOPDIR@/GIMPACT/src/gimpact.cpp' || echo '$(srcdir)/'`@TOPDIR@/GIMPACT/src/gimpact.cpp | ||
953 | |||
954 | libGIMPACT_a-gimpact.obj: @TOPDIR@/GIMPACT/src/gimpact.cpp | ||
955 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libGIMPACT_a-gimpact.obj -MD -MP -MF $(DEPDIR)/libGIMPACT_a-gimpact.Tpo -c -o libGIMPACT_a-gimpact.obj `if test -f '@TOPDIR@/GIMPACT/src/gimpact.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gimpact.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gimpact.cpp'; fi` | ||
956 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libGIMPACT_a-gimpact.Tpo $(DEPDIR)/libGIMPACT_a-gimpact.Po | ||
957 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/GIMPACT/src/gimpact.cpp' object='libGIMPACT_a-gimpact.obj' libtool=no @AMDEPBACKSLASH@ | ||
958 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
959 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libGIMPACT_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libGIMPACT_a-gimpact.obj `if test -f '@TOPDIR@/GIMPACT/src/gimpact.cpp'; then $(CYGPATH_W) '@TOPDIR@/GIMPACT/src/gimpact.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/GIMPACT/src/gimpact.cpp'; fi` | ||
960 | |||
961 | libOPCODE_a-OPC_AABBCollider.o: @TOPDIR@/OPCODE/OPC_AABBCollider.cpp | ||
962 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_AABBCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Tpo -c -o libOPCODE_a-OPC_AABBCollider.o `test -f '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_AABBCollider.cpp | ||
963 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Po | ||
964 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_AABBCollider.cpp' object='libOPCODE_a-OPC_AABBCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
965 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
966 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_AABBCollider.o `test -f '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_AABBCollider.cpp | ||
967 | |||
968 | libOPCODE_a-OPC_AABBCollider.obj: @TOPDIR@/OPCODE/OPC_AABBCollider.cpp | ||
969 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_AABBCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Tpo -c -o libOPCODE_a-OPC_AABBCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; fi` | ||
970 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_AABBCollider.Po | ||
971 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_AABBCollider.cpp' object='libOPCODE_a-OPC_AABBCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
972 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
973 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_AABBCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_AABBCollider.cpp'; fi` | ||
974 | |||
975 | libOPCODE_a-OPC_AABBTree.o: @TOPDIR@/OPCODE/OPC_AABBTree.cpp | ||
976 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_AABBTree.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Tpo -c -o libOPCODE_a-OPC_AABBTree.o `test -f '@TOPDIR@/OPCODE/OPC_AABBTree.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_AABBTree.cpp | ||
977 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Tpo $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Po | ||
978 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_AABBTree.cpp' object='libOPCODE_a-OPC_AABBTree.o' libtool=no @AMDEPBACKSLASH@ | ||
979 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
980 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_AABBTree.o `test -f '@TOPDIR@/OPCODE/OPC_AABBTree.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_AABBTree.cpp | ||
981 | |||
982 | libOPCODE_a-OPC_AABBTree.obj: @TOPDIR@/OPCODE/OPC_AABBTree.cpp | ||
983 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_AABBTree.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Tpo -c -o libOPCODE_a-OPC_AABBTree.obj `if test -f '@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; fi` | ||
984 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Tpo $(DEPDIR)/libOPCODE_a-OPC_AABBTree.Po | ||
985 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_AABBTree.cpp' object='libOPCODE_a-OPC_AABBTree.obj' libtool=no @AMDEPBACKSLASH@ | ||
986 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
987 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_AABBTree.obj `if test -f '@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_AABBTree.cpp'; fi` | ||
988 | |||
989 | libOPCODE_a-OPC_BaseModel.o: @TOPDIR@/OPCODE/OPC_BaseModel.cpp | ||
990 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_BaseModel.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Tpo -c -o libOPCODE_a-OPC_BaseModel.o `test -f '@TOPDIR@/OPCODE/OPC_BaseModel.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_BaseModel.cpp | ||
991 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Tpo $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Po | ||
992 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_BaseModel.cpp' object='libOPCODE_a-OPC_BaseModel.o' libtool=no @AMDEPBACKSLASH@ | ||
993 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
994 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_BaseModel.o `test -f '@TOPDIR@/OPCODE/OPC_BaseModel.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_BaseModel.cpp | ||
995 | |||
996 | libOPCODE_a-OPC_BaseModel.obj: @TOPDIR@/OPCODE/OPC_BaseModel.cpp | ||
997 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_BaseModel.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Tpo -c -o libOPCODE_a-OPC_BaseModel.obj `if test -f '@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; fi` | ||
998 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Tpo $(DEPDIR)/libOPCODE_a-OPC_BaseModel.Po | ||
999 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_BaseModel.cpp' object='libOPCODE_a-OPC_BaseModel.obj' libtool=no @AMDEPBACKSLASH@ | ||
1000 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1001 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_BaseModel.obj `if test -f '@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_BaseModel.cpp'; fi` | ||
1002 | |||
1003 | libOPCODE_a-OPC_BoxPruning.o: @TOPDIR@/OPCODE/OPC_BoxPruning.cpp | ||
1004 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_BoxPruning.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Tpo -c -o libOPCODE_a-OPC_BoxPruning.o `test -f '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_BoxPruning.cpp | ||
1005 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Tpo $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Po | ||
1006 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_BoxPruning.cpp' object='libOPCODE_a-OPC_BoxPruning.o' libtool=no @AMDEPBACKSLASH@ | ||
1007 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1008 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_BoxPruning.o `test -f '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_BoxPruning.cpp | ||
1009 | |||
1010 | libOPCODE_a-OPC_BoxPruning.obj: @TOPDIR@/OPCODE/OPC_BoxPruning.cpp | ||
1011 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_BoxPruning.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Tpo -c -o libOPCODE_a-OPC_BoxPruning.obj `if test -f '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; fi` | ||
1012 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Tpo $(DEPDIR)/libOPCODE_a-OPC_BoxPruning.Po | ||
1013 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_BoxPruning.cpp' object='libOPCODE_a-OPC_BoxPruning.obj' libtool=no @AMDEPBACKSLASH@ | ||
1014 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1015 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_BoxPruning.obj `if test -f '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_BoxPruning.cpp'; fi` | ||
1016 | |||
1017 | libOPCODE_a-OPC_Collider.o: @TOPDIR@/OPCODE/OPC_Collider.cpp | ||
1018 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Collider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Collider.Tpo -c -o libOPCODE_a-OPC_Collider.o `test -f '@TOPDIR@/OPCODE/OPC_Collider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Collider.cpp | ||
1019 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Collider.Tpo $(DEPDIR)/libOPCODE_a-OPC_Collider.Po | ||
1020 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Collider.cpp' object='libOPCODE_a-OPC_Collider.o' libtool=no @AMDEPBACKSLASH@ | ||
1021 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1022 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Collider.o `test -f '@TOPDIR@/OPCODE/OPC_Collider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Collider.cpp | ||
1023 | |||
1024 | libOPCODE_a-OPC_Collider.obj: @TOPDIR@/OPCODE/OPC_Collider.cpp | ||
1025 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Collider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Collider.Tpo -c -o libOPCODE_a-OPC_Collider.obj `if test -f '@TOPDIR@/OPCODE/OPC_Collider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Collider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Collider.cpp'; fi` | ||
1026 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Collider.Tpo $(DEPDIR)/libOPCODE_a-OPC_Collider.Po | ||
1027 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Collider.cpp' object='libOPCODE_a-OPC_Collider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1028 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1029 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Collider.obj `if test -f '@TOPDIR@/OPCODE/OPC_Collider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Collider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Collider.cpp'; fi` | ||
1030 | |||
1031 | libOPCODE_a-OPC_Common.o: @TOPDIR@/OPCODE/OPC_Common.cpp | ||
1032 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Common.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Common.Tpo -c -o libOPCODE_a-OPC_Common.o `test -f '@TOPDIR@/OPCODE/OPC_Common.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Common.cpp | ||
1033 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Common.Tpo $(DEPDIR)/libOPCODE_a-OPC_Common.Po | ||
1034 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Common.cpp' object='libOPCODE_a-OPC_Common.o' libtool=no @AMDEPBACKSLASH@ | ||
1035 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1036 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Common.o `test -f '@TOPDIR@/OPCODE/OPC_Common.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Common.cpp | ||
1037 | |||
1038 | libOPCODE_a-OPC_Common.obj: @TOPDIR@/OPCODE/OPC_Common.cpp | ||
1039 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Common.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Common.Tpo -c -o libOPCODE_a-OPC_Common.obj `if test -f '@TOPDIR@/OPCODE/OPC_Common.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Common.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Common.cpp'; fi` | ||
1040 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Common.Tpo $(DEPDIR)/libOPCODE_a-OPC_Common.Po | ||
1041 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Common.cpp' object='libOPCODE_a-OPC_Common.obj' libtool=no @AMDEPBACKSLASH@ | ||
1042 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1043 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Common.obj `if test -f '@TOPDIR@/OPCODE/OPC_Common.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Common.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Common.cpp'; fi` | ||
1044 | |||
1045 | libOPCODE_a-OPC_HybridModel.o: @TOPDIR@/OPCODE/OPC_HybridModel.cpp | ||
1046 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_HybridModel.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Tpo -c -o libOPCODE_a-OPC_HybridModel.o `test -f '@TOPDIR@/OPCODE/OPC_HybridModel.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_HybridModel.cpp | ||
1047 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Tpo $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Po | ||
1048 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_HybridModel.cpp' object='libOPCODE_a-OPC_HybridModel.o' libtool=no @AMDEPBACKSLASH@ | ||
1049 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1050 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_HybridModel.o `test -f '@TOPDIR@/OPCODE/OPC_HybridModel.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_HybridModel.cpp | ||
1051 | |||
1052 | libOPCODE_a-OPC_HybridModel.obj: @TOPDIR@/OPCODE/OPC_HybridModel.cpp | ||
1053 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_HybridModel.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Tpo -c -o libOPCODE_a-OPC_HybridModel.obj `if test -f '@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; fi` | ||
1054 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Tpo $(DEPDIR)/libOPCODE_a-OPC_HybridModel.Po | ||
1055 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_HybridModel.cpp' object='libOPCODE_a-OPC_HybridModel.obj' libtool=no @AMDEPBACKSLASH@ | ||
1056 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1057 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_HybridModel.obj `if test -f '@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_HybridModel.cpp'; fi` | ||
1058 | |||
1059 | libOPCODE_a-OPC_LSSCollider.o: @TOPDIR@/OPCODE/OPC_LSSCollider.cpp | ||
1060 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_LSSCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Tpo -c -o libOPCODE_a-OPC_LSSCollider.o `test -f '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_LSSCollider.cpp | ||
1061 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Po | ||
1062 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_LSSCollider.cpp' object='libOPCODE_a-OPC_LSSCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1063 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1064 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_LSSCollider.o `test -f '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_LSSCollider.cpp | ||
1065 | |||
1066 | libOPCODE_a-OPC_LSSCollider.obj: @TOPDIR@/OPCODE/OPC_LSSCollider.cpp | ||
1067 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_LSSCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Tpo -c -o libOPCODE_a-OPC_LSSCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; fi` | ||
1068 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_LSSCollider.Po | ||
1069 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_LSSCollider.cpp' object='libOPCODE_a-OPC_LSSCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1070 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1071 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_LSSCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_LSSCollider.cpp'; fi` | ||
1072 | |||
1073 | libOPCODE_a-OPC_MeshInterface.o: @TOPDIR@/OPCODE/OPC_MeshInterface.cpp | ||
1074 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_MeshInterface.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Tpo -c -o libOPCODE_a-OPC_MeshInterface.o `test -f '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_MeshInterface.cpp | ||
1075 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Tpo $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Po | ||
1076 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_MeshInterface.cpp' object='libOPCODE_a-OPC_MeshInterface.o' libtool=no @AMDEPBACKSLASH@ | ||
1077 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1078 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_MeshInterface.o `test -f '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_MeshInterface.cpp | ||
1079 | |||
1080 | libOPCODE_a-OPC_MeshInterface.obj: @TOPDIR@/OPCODE/OPC_MeshInterface.cpp | ||
1081 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_MeshInterface.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Tpo -c -o libOPCODE_a-OPC_MeshInterface.obj `if test -f '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; fi` | ||
1082 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Tpo $(DEPDIR)/libOPCODE_a-OPC_MeshInterface.Po | ||
1083 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_MeshInterface.cpp' object='libOPCODE_a-OPC_MeshInterface.obj' libtool=no @AMDEPBACKSLASH@ | ||
1084 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1085 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_MeshInterface.obj `if test -f '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_MeshInterface.cpp'; fi` | ||
1086 | |||
1087 | libOPCODE_a-OPC_Model.o: @TOPDIR@/OPCODE/OPC_Model.cpp | ||
1088 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Model.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Model.Tpo -c -o libOPCODE_a-OPC_Model.o `test -f '@TOPDIR@/OPCODE/OPC_Model.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Model.cpp | ||
1089 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Model.Tpo $(DEPDIR)/libOPCODE_a-OPC_Model.Po | ||
1090 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Model.cpp' object='libOPCODE_a-OPC_Model.o' libtool=no @AMDEPBACKSLASH@ | ||
1091 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1092 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Model.o `test -f '@TOPDIR@/OPCODE/OPC_Model.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Model.cpp | ||
1093 | |||
1094 | libOPCODE_a-OPC_Model.obj: @TOPDIR@/OPCODE/OPC_Model.cpp | ||
1095 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Model.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Model.Tpo -c -o libOPCODE_a-OPC_Model.obj `if test -f '@TOPDIR@/OPCODE/OPC_Model.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Model.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Model.cpp'; fi` | ||
1096 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Model.Tpo $(DEPDIR)/libOPCODE_a-OPC_Model.Po | ||
1097 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Model.cpp' object='libOPCODE_a-OPC_Model.obj' libtool=no @AMDEPBACKSLASH@ | ||
1098 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1099 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Model.obj `if test -f '@TOPDIR@/OPCODE/OPC_Model.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Model.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Model.cpp'; fi` | ||
1100 | |||
1101 | libOPCODE_a-OPC_OBBCollider.o: @TOPDIR@/OPCODE/OPC_OBBCollider.cpp | ||
1102 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_OBBCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Tpo -c -o libOPCODE_a-OPC_OBBCollider.o `test -f '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_OBBCollider.cpp | ||
1103 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Po | ||
1104 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_OBBCollider.cpp' object='libOPCODE_a-OPC_OBBCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1105 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1106 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_OBBCollider.o `test -f '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_OBBCollider.cpp | ||
1107 | |||
1108 | libOPCODE_a-OPC_OBBCollider.obj: @TOPDIR@/OPCODE/OPC_OBBCollider.cpp | ||
1109 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_OBBCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Tpo -c -o libOPCODE_a-OPC_OBBCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; fi` | ||
1110 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_OBBCollider.Po | ||
1111 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_OBBCollider.cpp' object='libOPCODE_a-OPC_OBBCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1112 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1113 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_OBBCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_OBBCollider.cpp'; fi` | ||
1114 | |||
1115 | libOPCODE_a-Opcode.o: @TOPDIR@/OPCODE/Opcode.cpp | ||
1116 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-Opcode.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-Opcode.Tpo -c -o libOPCODE_a-Opcode.o `test -f '@TOPDIR@/OPCODE/Opcode.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Opcode.cpp | ||
1117 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-Opcode.Tpo $(DEPDIR)/libOPCODE_a-Opcode.Po | ||
1118 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Opcode.cpp' object='libOPCODE_a-Opcode.o' libtool=no @AMDEPBACKSLASH@ | ||
1119 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1120 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-Opcode.o `test -f '@TOPDIR@/OPCODE/Opcode.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Opcode.cpp | ||
1121 | |||
1122 | libOPCODE_a-Opcode.obj: @TOPDIR@/OPCODE/Opcode.cpp | ||
1123 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-Opcode.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-Opcode.Tpo -c -o libOPCODE_a-Opcode.obj `if test -f '@TOPDIR@/OPCODE/Opcode.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Opcode.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Opcode.cpp'; fi` | ||
1124 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-Opcode.Tpo $(DEPDIR)/libOPCODE_a-Opcode.Po | ||
1125 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Opcode.cpp' object='libOPCODE_a-Opcode.obj' libtool=no @AMDEPBACKSLASH@ | ||
1126 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1127 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-Opcode.obj `if test -f '@TOPDIR@/OPCODE/Opcode.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Opcode.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Opcode.cpp'; fi` | ||
1128 | |||
1129 | libOPCODE_a-OPC_OptimizedTree.o: @TOPDIR@/OPCODE/OPC_OptimizedTree.cpp | ||
1130 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_OptimizedTree.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Tpo -c -o libOPCODE_a-OPC_OptimizedTree.o `test -f '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp | ||
1131 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Tpo $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Po | ||
1132 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp' object='libOPCODE_a-OPC_OptimizedTree.o' libtool=no @AMDEPBACKSLASH@ | ||
1133 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1134 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_OptimizedTree.o `test -f '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp | ||
1135 | |||
1136 | libOPCODE_a-OPC_OptimizedTree.obj: @TOPDIR@/OPCODE/OPC_OptimizedTree.cpp | ||
1137 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_OptimizedTree.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Tpo -c -o libOPCODE_a-OPC_OptimizedTree.obj `if test -f '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; fi` | ||
1138 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Tpo $(DEPDIR)/libOPCODE_a-OPC_OptimizedTree.Po | ||
1139 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp' object='libOPCODE_a-OPC_OptimizedTree.obj' libtool=no @AMDEPBACKSLASH@ | ||
1140 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1141 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_OptimizedTree.obj `if test -f '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_OptimizedTree.cpp'; fi` | ||
1142 | |||
1143 | libOPCODE_a-OPC_Picking.o: @TOPDIR@/OPCODE/OPC_Picking.cpp | ||
1144 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Picking.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Picking.Tpo -c -o libOPCODE_a-OPC_Picking.o `test -f '@TOPDIR@/OPCODE/OPC_Picking.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Picking.cpp | ||
1145 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Picking.Tpo $(DEPDIR)/libOPCODE_a-OPC_Picking.Po | ||
1146 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Picking.cpp' object='libOPCODE_a-OPC_Picking.o' libtool=no @AMDEPBACKSLASH@ | ||
1147 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1148 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Picking.o `test -f '@TOPDIR@/OPCODE/OPC_Picking.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_Picking.cpp | ||
1149 | |||
1150 | libOPCODE_a-OPC_Picking.obj: @TOPDIR@/OPCODE/OPC_Picking.cpp | ||
1151 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_Picking.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_Picking.Tpo -c -o libOPCODE_a-OPC_Picking.obj `if test -f '@TOPDIR@/OPCODE/OPC_Picking.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Picking.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Picking.cpp'; fi` | ||
1152 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_Picking.Tpo $(DEPDIR)/libOPCODE_a-OPC_Picking.Po | ||
1153 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_Picking.cpp' object='libOPCODE_a-OPC_Picking.obj' libtool=no @AMDEPBACKSLASH@ | ||
1154 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1155 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_Picking.obj `if test -f '@TOPDIR@/OPCODE/OPC_Picking.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_Picking.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_Picking.cpp'; fi` | ||
1156 | |||
1157 | libOPCODE_a-OPC_PlanesCollider.o: @TOPDIR@/OPCODE/OPC_PlanesCollider.cpp | ||
1158 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_PlanesCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Tpo -c -o libOPCODE_a-OPC_PlanesCollider.o `test -f '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp | ||
1159 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Po | ||
1160 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp' object='libOPCODE_a-OPC_PlanesCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1161 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1162 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_PlanesCollider.o `test -f '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp | ||
1163 | |||
1164 | libOPCODE_a-OPC_PlanesCollider.obj: @TOPDIR@/OPCODE/OPC_PlanesCollider.cpp | ||
1165 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_PlanesCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Tpo -c -o libOPCODE_a-OPC_PlanesCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; fi` | ||
1166 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_PlanesCollider.Po | ||
1167 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp' object='libOPCODE_a-OPC_PlanesCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1168 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1169 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_PlanesCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_PlanesCollider.cpp'; fi` | ||
1170 | |||
1171 | libOPCODE_a-OPC_RayCollider.o: @TOPDIR@/OPCODE/OPC_RayCollider.cpp | ||
1172 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_RayCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Tpo -c -o libOPCODE_a-OPC_RayCollider.o `test -f '@TOPDIR@/OPCODE/OPC_RayCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_RayCollider.cpp | ||
1173 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Po | ||
1174 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_RayCollider.cpp' object='libOPCODE_a-OPC_RayCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1175 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1176 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_RayCollider.o `test -f '@TOPDIR@/OPCODE/OPC_RayCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_RayCollider.cpp | ||
1177 | |||
1178 | libOPCODE_a-OPC_RayCollider.obj: @TOPDIR@/OPCODE/OPC_RayCollider.cpp | ||
1179 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_RayCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Tpo -c -o libOPCODE_a-OPC_RayCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; fi` | ||
1180 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_RayCollider.Po | ||
1181 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_RayCollider.cpp' object='libOPCODE_a-OPC_RayCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1182 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1183 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_RayCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_RayCollider.cpp'; fi` | ||
1184 | |||
1185 | libOPCODE_a-OPC_SphereCollider.o: @TOPDIR@/OPCODE/OPC_SphereCollider.cpp | ||
1186 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_SphereCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Tpo -c -o libOPCODE_a-OPC_SphereCollider.o `test -f '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_SphereCollider.cpp | ||
1187 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Po | ||
1188 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_SphereCollider.cpp' object='libOPCODE_a-OPC_SphereCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1189 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1190 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_SphereCollider.o `test -f '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_SphereCollider.cpp | ||
1191 | |||
1192 | libOPCODE_a-OPC_SphereCollider.obj: @TOPDIR@/OPCODE/OPC_SphereCollider.cpp | ||
1193 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_SphereCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Tpo -c -o libOPCODE_a-OPC_SphereCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; fi` | ||
1194 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_SphereCollider.Po | ||
1195 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_SphereCollider.cpp' object='libOPCODE_a-OPC_SphereCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1196 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1197 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_SphereCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_SphereCollider.cpp'; fi` | ||
1198 | |||
1199 | libOPCODE_a-OPC_SweepAndPrune.o: @TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp | ||
1200 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_SweepAndPrune.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Tpo -c -o libOPCODE_a-OPC_SweepAndPrune.o `test -f '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp | ||
1201 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Tpo $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Po | ||
1202 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp' object='libOPCODE_a-OPC_SweepAndPrune.o' libtool=no @AMDEPBACKSLASH@ | ||
1203 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1204 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_SweepAndPrune.o `test -f '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp | ||
1205 | |||
1206 | libOPCODE_a-OPC_SweepAndPrune.obj: @TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp | ||
1207 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_SweepAndPrune.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Tpo -c -o libOPCODE_a-OPC_SweepAndPrune.obj `if test -f '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; fi` | ||
1208 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Tpo $(DEPDIR)/libOPCODE_a-OPC_SweepAndPrune.Po | ||
1209 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp' object='libOPCODE_a-OPC_SweepAndPrune.obj' libtool=no @AMDEPBACKSLASH@ | ||
1210 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1211 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_SweepAndPrune.obj `if test -f '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_SweepAndPrune.cpp'; fi` | ||
1212 | |||
1213 | libOPCODE_a-OPC_TreeBuilders.o: @TOPDIR@/OPCODE/OPC_TreeBuilders.cpp | ||
1214 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_TreeBuilders.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Tpo -c -o libOPCODE_a-OPC_TreeBuilders.o `test -f '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp | ||
1215 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Tpo $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Po | ||
1216 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp' object='libOPCODE_a-OPC_TreeBuilders.o' libtool=no @AMDEPBACKSLASH@ | ||
1217 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1218 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_TreeBuilders.o `test -f '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp | ||
1219 | |||
1220 | libOPCODE_a-OPC_TreeBuilders.obj: @TOPDIR@/OPCODE/OPC_TreeBuilders.cpp | ||
1221 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_TreeBuilders.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Tpo -c -o libOPCODE_a-OPC_TreeBuilders.obj `if test -f '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; fi` | ||
1222 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Tpo $(DEPDIR)/libOPCODE_a-OPC_TreeBuilders.Po | ||
1223 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp' object='libOPCODE_a-OPC_TreeBuilders.obj' libtool=no @AMDEPBACKSLASH@ | ||
1224 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1225 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_TreeBuilders.obj `if test -f '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_TreeBuilders.cpp'; fi` | ||
1226 | |||
1227 | libOPCODE_a-OPC_TreeCollider.o: @TOPDIR@/OPCODE/OPC_TreeCollider.cpp | ||
1228 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_TreeCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Tpo -c -o libOPCODE_a-OPC_TreeCollider.o `test -f '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_TreeCollider.cpp | ||
1229 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Po | ||
1230 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_TreeCollider.cpp' object='libOPCODE_a-OPC_TreeCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1231 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1232 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_TreeCollider.o `test -f '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_TreeCollider.cpp | ||
1233 | |||
1234 | libOPCODE_a-OPC_TreeCollider.obj: @TOPDIR@/OPCODE/OPC_TreeCollider.cpp | ||
1235 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_TreeCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Tpo -c -o libOPCODE_a-OPC_TreeCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; fi` | ||
1236 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_TreeCollider.Po | ||
1237 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_TreeCollider.cpp' object='libOPCODE_a-OPC_TreeCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1238 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1239 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_TreeCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_TreeCollider.cpp'; fi` | ||
1240 | |||
1241 | libOPCODE_a-OPC_VolumeCollider.o: @TOPDIR@/OPCODE/OPC_VolumeCollider.cpp | ||
1242 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_VolumeCollider.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Tpo -c -o libOPCODE_a-OPC_VolumeCollider.o `test -f '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp | ||
1243 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Po | ||
1244 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp' object='libOPCODE_a-OPC_VolumeCollider.o' libtool=no @AMDEPBACKSLASH@ | ||
1245 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1246 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_VolumeCollider.o `test -f '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp | ||
1247 | |||
1248 | libOPCODE_a-OPC_VolumeCollider.obj: @TOPDIR@/OPCODE/OPC_VolumeCollider.cpp | ||
1249 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-OPC_VolumeCollider.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Tpo -c -o libOPCODE_a-OPC_VolumeCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; fi` | ||
1250 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Tpo $(DEPDIR)/libOPCODE_a-OPC_VolumeCollider.Po | ||
1251 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp' object='libOPCODE_a-OPC_VolumeCollider.obj' libtool=no @AMDEPBACKSLASH@ | ||
1252 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1253 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-OPC_VolumeCollider.obj `if test -f '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/OPC_VolumeCollider.cpp'; fi` | ||
1254 | |||
1255 | libOPCODE_a-IceAABB.o: @TOPDIR@/OPCODE/Ice/IceAABB.cpp | ||
1256 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceAABB.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceAABB.Tpo -c -o libOPCODE_a-IceAABB.o `test -f '@TOPDIR@/OPCODE/Ice/IceAABB.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceAABB.cpp | ||
1257 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceAABB.Tpo $(DEPDIR)/libOPCODE_a-IceAABB.Po | ||
1258 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceAABB.cpp' object='libOPCODE_a-IceAABB.o' libtool=no @AMDEPBACKSLASH@ | ||
1259 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1260 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceAABB.o `test -f '@TOPDIR@/OPCODE/Ice/IceAABB.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceAABB.cpp | ||
1261 | |||
1262 | libOPCODE_a-IceAABB.obj: @TOPDIR@/OPCODE/Ice/IceAABB.cpp | ||
1263 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceAABB.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceAABB.Tpo -c -o libOPCODE_a-IceAABB.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; fi` | ||
1264 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceAABB.Tpo $(DEPDIR)/libOPCODE_a-IceAABB.Po | ||
1265 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceAABB.cpp' object='libOPCODE_a-IceAABB.obj' libtool=no @AMDEPBACKSLASH@ | ||
1266 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1267 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceAABB.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceAABB.cpp'; fi` | ||
1268 | |||
1269 | libOPCODE_a-IceContainer.o: @TOPDIR@/OPCODE/Ice/IceContainer.cpp | ||
1270 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceContainer.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceContainer.Tpo -c -o libOPCODE_a-IceContainer.o `test -f '@TOPDIR@/OPCODE/Ice/IceContainer.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceContainer.cpp | ||
1271 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceContainer.Tpo $(DEPDIR)/libOPCODE_a-IceContainer.Po | ||
1272 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceContainer.cpp' object='libOPCODE_a-IceContainer.o' libtool=no @AMDEPBACKSLASH@ | ||
1273 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1274 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceContainer.o `test -f '@TOPDIR@/OPCODE/Ice/IceContainer.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceContainer.cpp | ||
1275 | |||
1276 | libOPCODE_a-IceContainer.obj: @TOPDIR@/OPCODE/Ice/IceContainer.cpp | ||
1277 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceContainer.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceContainer.Tpo -c -o libOPCODE_a-IceContainer.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; fi` | ||
1278 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceContainer.Tpo $(DEPDIR)/libOPCODE_a-IceContainer.Po | ||
1279 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceContainer.cpp' object='libOPCODE_a-IceContainer.obj' libtool=no @AMDEPBACKSLASH@ | ||
1280 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1281 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceContainer.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceContainer.cpp'; fi` | ||
1282 | |||
1283 | libOPCODE_a-IceHPoint.o: @TOPDIR@/OPCODE/Ice/IceHPoint.cpp | ||
1284 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceHPoint.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceHPoint.Tpo -c -o libOPCODE_a-IceHPoint.o `test -f '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceHPoint.cpp | ||
1285 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceHPoint.Tpo $(DEPDIR)/libOPCODE_a-IceHPoint.Po | ||
1286 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceHPoint.cpp' object='libOPCODE_a-IceHPoint.o' libtool=no @AMDEPBACKSLASH@ | ||
1287 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1288 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceHPoint.o `test -f '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceHPoint.cpp | ||
1289 | |||
1290 | libOPCODE_a-IceHPoint.obj: @TOPDIR@/OPCODE/Ice/IceHPoint.cpp | ||
1291 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceHPoint.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceHPoint.Tpo -c -o libOPCODE_a-IceHPoint.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; fi` | ||
1292 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceHPoint.Tpo $(DEPDIR)/libOPCODE_a-IceHPoint.Po | ||
1293 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceHPoint.cpp' object='libOPCODE_a-IceHPoint.obj' libtool=no @AMDEPBACKSLASH@ | ||
1294 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1295 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceHPoint.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceHPoint.cpp'; fi` | ||
1296 | |||
1297 | libOPCODE_a-IceIndexedTriangle.o: @TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp | ||
1298 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceIndexedTriangle.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Tpo -c -o libOPCODE_a-IceIndexedTriangle.o `test -f '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp | ||
1299 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Tpo $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Po | ||
1300 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp' object='libOPCODE_a-IceIndexedTriangle.o' libtool=no @AMDEPBACKSLASH@ | ||
1301 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1302 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceIndexedTriangle.o `test -f '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp | ||
1303 | |||
1304 | libOPCODE_a-IceIndexedTriangle.obj: @TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp | ||
1305 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceIndexedTriangle.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Tpo -c -o libOPCODE_a-IceIndexedTriangle.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; fi` | ||
1306 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Tpo $(DEPDIR)/libOPCODE_a-IceIndexedTriangle.Po | ||
1307 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp' object='libOPCODE_a-IceIndexedTriangle.obj' libtool=no @AMDEPBACKSLASH@ | ||
1308 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1309 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceIndexedTriangle.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceIndexedTriangle.cpp'; fi` | ||
1310 | |||
1311 | libOPCODE_a-IceMatrix3x3.o: @TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp | ||
1312 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceMatrix3x3.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Tpo -c -o libOPCODE_a-IceMatrix3x3.o `test -f '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp | ||
1313 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Tpo $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Po | ||
1314 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp' object='libOPCODE_a-IceMatrix3x3.o' libtool=no @AMDEPBACKSLASH@ | ||
1315 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1316 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceMatrix3x3.o `test -f '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp | ||
1317 | |||
1318 | libOPCODE_a-IceMatrix3x3.obj: @TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp | ||
1319 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceMatrix3x3.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Tpo -c -o libOPCODE_a-IceMatrix3x3.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; fi` | ||
1320 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Tpo $(DEPDIR)/libOPCODE_a-IceMatrix3x3.Po | ||
1321 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp' object='libOPCODE_a-IceMatrix3x3.obj' libtool=no @AMDEPBACKSLASH@ | ||
1322 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1323 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceMatrix3x3.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceMatrix3x3.cpp'; fi` | ||
1324 | |||
1325 | libOPCODE_a-IceMatrix4x4.o: @TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp | ||
1326 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceMatrix4x4.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Tpo -c -o libOPCODE_a-IceMatrix4x4.o `test -f '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp | ||
1327 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Tpo $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Po | ||
1328 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp' object='libOPCODE_a-IceMatrix4x4.o' libtool=no @AMDEPBACKSLASH@ | ||
1329 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1330 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceMatrix4x4.o `test -f '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp | ||
1331 | |||
1332 | libOPCODE_a-IceMatrix4x4.obj: @TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp | ||
1333 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceMatrix4x4.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Tpo -c -o libOPCODE_a-IceMatrix4x4.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; fi` | ||
1334 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Tpo $(DEPDIR)/libOPCODE_a-IceMatrix4x4.Po | ||
1335 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp' object='libOPCODE_a-IceMatrix4x4.obj' libtool=no @AMDEPBACKSLASH@ | ||
1336 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1337 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceMatrix4x4.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceMatrix4x4.cpp'; fi` | ||
1338 | |||
1339 | libOPCODE_a-IceOBB.o: @TOPDIR@/OPCODE/Ice/IceOBB.cpp | ||
1340 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceOBB.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceOBB.Tpo -c -o libOPCODE_a-IceOBB.o `test -f '@TOPDIR@/OPCODE/Ice/IceOBB.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceOBB.cpp | ||
1341 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceOBB.Tpo $(DEPDIR)/libOPCODE_a-IceOBB.Po | ||
1342 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceOBB.cpp' object='libOPCODE_a-IceOBB.o' libtool=no @AMDEPBACKSLASH@ | ||
1343 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1344 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceOBB.o `test -f '@TOPDIR@/OPCODE/Ice/IceOBB.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceOBB.cpp | ||
1345 | |||
1346 | libOPCODE_a-IceOBB.obj: @TOPDIR@/OPCODE/Ice/IceOBB.cpp | ||
1347 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceOBB.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceOBB.Tpo -c -o libOPCODE_a-IceOBB.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; fi` | ||
1348 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceOBB.Tpo $(DEPDIR)/libOPCODE_a-IceOBB.Po | ||
1349 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceOBB.cpp' object='libOPCODE_a-IceOBB.obj' libtool=no @AMDEPBACKSLASH@ | ||
1350 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1351 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceOBB.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceOBB.cpp'; fi` | ||
1352 | |||
1353 | libOPCODE_a-IcePlane.o: @TOPDIR@/OPCODE/Ice/IcePlane.cpp | ||
1354 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IcePlane.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IcePlane.Tpo -c -o libOPCODE_a-IcePlane.o `test -f '@TOPDIR@/OPCODE/Ice/IcePlane.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IcePlane.cpp | ||
1355 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IcePlane.Tpo $(DEPDIR)/libOPCODE_a-IcePlane.Po | ||
1356 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IcePlane.cpp' object='libOPCODE_a-IcePlane.o' libtool=no @AMDEPBACKSLASH@ | ||
1357 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1358 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IcePlane.o `test -f '@TOPDIR@/OPCODE/Ice/IcePlane.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IcePlane.cpp | ||
1359 | |||
1360 | libOPCODE_a-IcePlane.obj: @TOPDIR@/OPCODE/Ice/IcePlane.cpp | ||
1361 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IcePlane.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IcePlane.Tpo -c -o libOPCODE_a-IcePlane.obj `if test -f '@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; fi` | ||
1362 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IcePlane.Tpo $(DEPDIR)/libOPCODE_a-IcePlane.Po | ||
1363 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IcePlane.cpp' object='libOPCODE_a-IcePlane.obj' libtool=no @AMDEPBACKSLASH@ | ||
1364 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1365 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IcePlane.obj `if test -f '@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IcePlane.cpp'; fi` | ||
1366 | |||
1367 | libOPCODE_a-IcePoint.o: @TOPDIR@/OPCODE/Ice/IcePoint.cpp | ||
1368 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IcePoint.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IcePoint.Tpo -c -o libOPCODE_a-IcePoint.o `test -f '@TOPDIR@/OPCODE/Ice/IcePoint.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IcePoint.cpp | ||
1369 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IcePoint.Tpo $(DEPDIR)/libOPCODE_a-IcePoint.Po | ||
1370 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IcePoint.cpp' object='libOPCODE_a-IcePoint.o' libtool=no @AMDEPBACKSLASH@ | ||
1371 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1372 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IcePoint.o `test -f '@TOPDIR@/OPCODE/Ice/IcePoint.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IcePoint.cpp | ||
1373 | |||
1374 | libOPCODE_a-IcePoint.obj: @TOPDIR@/OPCODE/Ice/IcePoint.cpp | ||
1375 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IcePoint.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IcePoint.Tpo -c -o libOPCODE_a-IcePoint.obj `if test -f '@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; fi` | ||
1376 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IcePoint.Tpo $(DEPDIR)/libOPCODE_a-IcePoint.Po | ||
1377 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IcePoint.cpp' object='libOPCODE_a-IcePoint.obj' libtool=no @AMDEPBACKSLASH@ | ||
1378 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1379 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IcePoint.obj `if test -f '@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IcePoint.cpp'; fi` | ||
1380 | |||
1381 | libOPCODE_a-IceRandom.o: @TOPDIR@/OPCODE/Ice/IceRandom.cpp | ||
1382 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRandom.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRandom.Tpo -c -o libOPCODE_a-IceRandom.o `test -f '@TOPDIR@/OPCODE/Ice/IceRandom.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRandom.cpp | ||
1383 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRandom.Tpo $(DEPDIR)/libOPCODE_a-IceRandom.Po | ||
1384 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRandom.cpp' object='libOPCODE_a-IceRandom.o' libtool=no @AMDEPBACKSLASH@ | ||
1385 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1386 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRandom.o `test -f '@TOPDIR@/OPCODE/Ice/IceRandom.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRandom.cpp | ||
1387 | |||
1388 | libOPCODE_a-IceRandom.obj: @TOPDIR@/OPCODE/Ice/IceRandom.cpp | ||
1389 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRandom.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRandom.Tpo -c -o libOPCODE_a-IceRandom.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; fi` | ||
1390 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRandom.Tpo $(DEPDIR)/libOPCODE_a-IceRandom.Po | ||
1391 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRandom.cpp' object='libOPCODE_a-IceRandom.obj' libtool=no @AMDEPBACKSLASH@ | ||
1392 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1393 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRandom.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRandom.cpp'; fi` | ||
1394 | |||
1395 | libOPCODE_a-IceRay.o: @TOPDIR@/OPCODE/Ice/IceRay.cpp | ||
1396 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRay.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRay.Tpo -c -o libOPCODE_a-IceRay.o `test -f '@TOPDIR@/OPCODE/Ice/IceRay.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRay.cpp | ||
1397 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRay.Tpo $(DEPDIR)/libOPCODE_a-IceRay.Po | ||
1398 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRay.cpp' object='libOPCODE_a-IceRay.o' libtool=no @AMDEPBACKSLASH@ | ||
1399 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1400 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRay.o `test -f '@TOPDIR@/OPCODE/Ice/IceRay.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRay.cpp | ||
1401 | |||
1402 | libOPCODE_a-IceRay.obj: @TOPDIR@/OPCODE/Ice/IceRay.cpp | ||
1403 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRay.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRay.Tpo -c -o libOPCODE_a-IceRay.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRay.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRay.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRay.cpp'; fi` | ||
1404 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRay.Tpo $(DEPDIR)/libOPCODE_a-IceRay.Po | ||
1405 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRay.cpp' object='libOPCODE_a-IceRay.obj' libtool=no @AMDEPBACKSLASH@ | ||
1406 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1407 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRay.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRay.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRay.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRay.cpp'; fi` | ||
1408 | |||
1409 | libOPCODE_a-IceRevisitedRadix.o: @TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp | ||
1410 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRevisitedRadix.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Tpo -c -o libOPCODE_a-IceRevisitedRadix.o `test -f '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp | ||
1411 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Tpo $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Po | ||
1412 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp' object='libOPCODE_a-IceRevisitedRadix.o' libtool=no @AMDEPBACKSLASH@ | ||
1413 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1414 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRevisitedRadix.o `test -f '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp | ||
1415 | |||
1416 | libOPCODE_a-IceRevisitedRadix.obj: @TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp | ||
1417 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceRevisitedRadix.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Tpo -c -o libOPCODE_a-IceRevisitedRadix.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; fi` | ||
1418 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Tpo $(DEPDIR)/libOPCODE_a-IceRevisitedRadix.Po | ||
1419 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp' object='libOPCODE_a-IceRevisitedRadix.obj' libtool=no @AMDEPBACKSLASH@ | ||
1420 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1421 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceRevisitedRadix.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceRevisitedRadix.cpp'; fi` | ||
1422 | |||
1423 | libOPCODE_a-IceSegment.o: @TOPDIR@/OPCODE/Ice/IceSegment.cpp | ||
1424 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceSegment.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceSegment.Tpo -c -o libOPCODE_a-IceSegment.o `test -f '@TOPDIR@/OPCODE/Ice/IceSegment.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceSegment.cpp | ||
1425 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceSegment.Tpo $(DEPDIR)/libOPCODE_a-IceSegment.Po | ||
1426 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceSegment.cpp' object='libOPCODE_a-IceSegment.o' libtool=no @AMDEPBACKSLASH@ | ||
1427 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1428 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceSegment.o `test -f '@TOPDIR@/OPCODE/Ice/IceSegment.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceSegment.cpp | ||
1429 | |||
1430 | libOPCODE_a-IceSegment.obj: @TOPDIR@/OPCODE/Ice/IceSegment.cpp | ||
1431 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceSegment.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceSegment.Tpo -c -o libOPCODE_a-IceSegment.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; fi` | ||
1432 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceSegment.Tpo $(DEPDIR)/libOPCODE_a-IceSegment.Po | ||
1433 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceSegment.cpp' object='libOPCODE_a-IceSegment.obj' libtool=no @AMDEPBACKSLASH@ | ||
1434 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1435 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceSegment.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceSegment.cpp'; fi` | ||
1436 | |||
1437 | libOPCODE_a-IceTriangle.o: @TOPDIR@/OPCODE/Ice/IceTriangle.cpp | ||
1438 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceTriangle.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceTriangle.Tpo -c -o libOPCODE_a-IceTriangle.o `test -f '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceTriangle.cpp | ||
1439 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceTriangle.Tpo $(DEPDIR)/libOPCODE_a-IceTriangle.Po | ||
1440 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceTriangle.cpp' object='libOPCODE_a-IceTriangle.o' libtool=no @AMDEPBACKSLASH@ | ||
1441 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1442 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceTriangle.o `test -f '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceTriangle.cpp | ||
1443 | |||
1444 | libOPCODE_a-IceTriangle.obj: @TOPDIR@/OPCODE/Ice/IceTriangle.cpp | ||
1445 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceTriangle.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceTriangle.Tpo -c -o libOPCODE_a-IceTriangle.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; fi` | ||
1446 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceTriangle.Tpo $(DEPDIR)/libOPCODE_a-IceTriangle.Po | ||
1447 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceTriangle.cpp' object='libOPCODE_a-IceTriangle.obj' libtool=no @AMDEPBACKSLASH@ | ||
1448 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1449 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceTriangle.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceTriangle.cpp'; fi` | ||
1450 | |||
1451 | libOPCODE_a-IceUtils.o: @TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
1452 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceUtils.o -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceUtils.Tpo -c -o libOPCODE_a-IceUtils.o `test -f '@TOPDIR@/OPCODE/Ice/IceUtils.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
1453 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceUtils.Tpo $(DEPDIR)/libOPCODE_a-IceUtils.Po | ||
1454 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceUtils.cpp' object='libOPCODE_a-IceUtils.o' libtool=no @AMDEPBACKSLASH@ | ||
1455 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1456 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceUtils.o `test -f '@TOPDIR@/OPCODE/Ice/IceUtils.cpp' || echo '$(srcdir)/'`@TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
1457 | |||
1458 | libOPCODE_a-IceUtils.obj: @TOPDIR@/OPCODE/Ice/IceUtils.cpp | ||
1459 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libOPCODE_a-IceUtils.obj -MD -MP -MF $(DEPDIR)/libOPCODE_a-IceUtils.Tpo -c -o libOPCODE_a-IceUtils.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; fi` | ||
1460 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libOPCODE_a-IceUtils.Tpo $(DEPDIR)/libOPCODE_a-IceUtils.Po | ||
1461 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='@TOPDIR@/OPCODE/Ice/IceUtils.cpp' object='libOPCODE_a-IceUtils.obj' libtool=no @AMDEPBACKSLASH@ | ||
1462 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1463 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libOPCODE_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libOPCODE_a-IceUtils.obj `if test -f '@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; then $(CYGPATH_W) '@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; else $(CYGPATH_W) '$(srcdir)/@TOPDIR@/OPCODE/Ice/IceUtils.cpp'; fi` | ||
1464 | |||
1465 | libode_a-obstack.o: obstack.cpp | ||
1466 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-obstack.o -MD -MP -MF $(DEPDIR)/libode_a-obstack.Tpo -c -o libode_a-obstack.o `test -f 'obstack.cpp' || echo '$(srcdir)/'`obstack.cpp | ||
1467 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-obstack.Tpo $(DEPDIR)/libode_a-obstack.Po | ||
1468 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='obstack.cpp' object='libode_a-obstack.o' libtool=no @AMDEPBACKSLASH@ | ||
1469 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1470 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-obstack.o `test -f 'obstack.cpp' || echo '$(srcdir)/'`obstack.cpp | ||
1471 | |||
1472 | libode_a-obstack.obj: obstack.cpp | ||
1473 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-obstack.obj -MD -MP -MF $(DEPDIR)/libode_a-obstack.Tpo -c -o libode_a-obstack.obj `if test -f 'obstack.cpp'; then $(CYGPATH_W) 'obstack.cpp'; else $(CYGPATH_W) '$(srcdir)/obstack.cpp'; fi` | ||
1474 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-obstack.Tpo $(DEPDIR)/libode_a-obstack.Po | ||
1475 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='obstack.cpp' object='libode_a-obstack.obj' libtool=no @AMDEPBACKSLASH@ | ||
1476 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1477 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-obstack.obj `if test -f 'obstack.cpp'; then $(CYGPATH_W) 'obstack.cpp'; else $(CYGPATH_W) '$(srcdir)/obstack.cpp'; fi` | ||
1478 | |||
1479 | libode_a-collision_util.o: collision_util.cpp | ||
1480 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_util.o -MD -MP -MF $(DEPDIR)/libode_a-collision_util.Tpo -c -o libode_a-collision_util.o `test -f 'collision_util.cpp' || echo '$(srcdir)/'`collision_util.cpp | ||
1481 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_util.Tpo $(DEPDIR)/libode_a-collision_util.Po | ||
1482 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_util.cpp' object='libode_a-collision_util.o' libtool=no @AMDEPBACKSLASH@ | ||
1483 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1484 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_util.o `test -f 'collision_util.cpp' || echo '$(srcdir)/'`collision_util.cpp | ||
1485 | |||
1486 | libode_a-collision_util.obj: collision_util.cpp | ||
1487 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_util.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_util.Tpo -c -o libode_a-collision_util.obj `if test -f 'collision_util.cpp'; then $(CYGPATH_W) 'collision_util.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_util.cpp'; fi` | ||
1488 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_util.Tpo $(DEPDIR)/libode_a-collision_util.Po | ||
1489 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_util.cpp' object='libode_a-collision_util.obj' libtool=no @AMDEPBACKSLASH@ | ||
1490 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1491 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_util.obj `if test -f 'collision_util.cpp'; then $(CYGPATH_W) 'collision_util.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_util.cpp'; fi` | ||
1492 | |||
1493 | libode_a-array.o: array.cpp | ||
1494 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-array.o -MD -MP -MF $(DEPDIR)/libode_a-array.Tpo -c -o libode_a-array.o `test -f 'array.cpp' || echo '$(srcdir)/'`array.cpp | ||
1495 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-array.Tpo $(DEPDIR)/libode_a-array.Po | ||
1496 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='array.cpp' object='libode_a-array.o' libtool=no @AMDEPBACKSLASH@ | ||
1497 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1498 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-array.o `test -f 'array.cpp' || echo '$(srcdir)/'`array.cpp | ||
1499 | |||
1500 | libode_a-array.obj: array.cpp | ||
1501 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-array.obj -MD -MP -MF $(DEPDIR)/libode_a-array.Tpo -c -o libode_a-array.obj `if test -f 'array.cpp'; then $(CYGPATH_W) 'array.cpp'; else $(CYGPATH_W) '$(srcdir)/array.cpp'; fi` | ||
1502 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-array.Tpo $(DEPDIR)/libode_a-array.Po | ||
1503 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='array.cpp' object='libode_a-array.obj' libtool=no @AMDEPBACKSLASH@ | ||
1504 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1505 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-array.obj `if test -f 'array.cpp'; then $(CYGPATH_W) 'array.cpp'; else $(CYGPATH_W) '$(srcdir)/array.cpp'; fi` | ||
1506 | |||
1507 | libode_a-ode.o: ode.cpp | ||
1508 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-ode.o -MD -MP -MF $(DEPDIR)/libode_a-ode.Tpo -c -o libode_a-ode.o `test -f 'ode.cpp' || echo '$(srcdir)/'`ode.cpp | ||
1509 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-ode.Tpo $(DEPDIR)/libode_a-ode.Po | ||
1510 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ode.cpp' object='libode_a-ode.o' libtool=no @AMDEPBACKSLASH@ | ||
1511 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1512 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-ode.o `test -f 'ode.cpp' || echo '$(srcdir)/'`ode.cpp | ||
1513 | |||
1514 | libode_a-ode.obj: ode.cpp | ||
1515 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-ode.obj -MD -MP -MF $(DEPDIR)/libode_a-ode.Tpo -c -o libode_a-ode.obj `if test -f 'ode.cpp'; then $(CYGPATH_W) 'ode.cpp'; else $(CYGPATH_W) '$(srcdir)/ode.cpp'; fi` | ||
1516 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-ode.Tpo $(DEPDIR)/libode_a-ode.Po | ||
1517 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ode.cpp' object='libode_a-ode.obj' libtool=no @AMDEPBACKSLASH@ | ||
1518 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1519 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-ode.obj `if test -f 'ode.cpp'; then $(CYGPATH_W) 'ode.cpp'; else $(CYGPATH_W) '$(srcdir)/ode.cpp'; fi` | ||
1520 | |||
1521 | libode_a-error.o: error.cpp | ||
1522 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-error.o -MD -MP -MF $(DEPDIR)/libode_a-error.Tpo -c -o libode_a-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp | ||
1523 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-error.Tpo $(DEPDIR)/libode_a-error.Po | ||
1524 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='libode_a-error.o' libtool=no @AMDEPBACKSLASH@ | ||
1525 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1526 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp | ||
1527 | |||
1528 | libode_a-error.obj: error.cpp | ||
1529 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-error.obj -MD -MP -MF $(DEPDIR)/libode_a-error.Tpo -c -o libode_a-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi` | ||
1530 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-error.Tpo $(DEPDIR)/libode_a-error.Po | ||
1531 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='libode_a-error.obj' libtool=no @AMDEPBACKSLASH@ | ||
1532 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1533 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi` | ||
1534 | |||
1535 | libode_a-odemath.o: odemath.cpp | ||
1536 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-odemath.o -MD -MP -MF $(DEPDIR)/libode_a-odemath.Tpo -c -o libode_a-odemath.o `test -f 'odemath.cpp' || echo '$(srcdir)/'`odemath.cpp | ||
1537 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-odemath.Tpo $(DEPDIR)/libode_a-odemath.Po | ||
1538 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='odemath.cpp' object='libode_a-odemath.o' libtool=no @AMDEPBACKSLASH@ | ||
1539 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1540 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-odemath.o `test -f 'odemath.cpp' || echo '$(srcdir)/'`odemath.cpp | ||
1541 | |||
1542 | libode_a-odemath.obj: odemath.cpp | ||
1543 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-odemath.obj -MD -MP -MF $(DEPDIR)/libode_a-odemath.Tpo -c -o libode_a-odemath.obj `if test -f 'odemath.cpp'; then $(CYGPATH_W) 'odemath.cpp'; else $(CYGPATH_W) '$(srcdir)/odemath.cpp'; fi` | ||
1544 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-odemath.Tpo $(DEPDIR)/libode_a-odemath.Po | ||
1545 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='odemath.cpp' object='libode_a-odemath.obj' libtool=no @AMDEPBACKSLASH@ | ||
1546 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1547 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-odemath.obj `if test -f 'odemath.cpp'; then $(CYGPATH_W) 'odemath.cpp'; else $(CYGPATH_W) '$(srcdir)/odemath.cpp'; fi` | ||
1548 | |||
1549 | libode_a-collision_kernel.o: collision_kernel.cpp | ||
1550 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_kernel.o -MD -MP -MF $(DEPDIR)/libode_a-collision_kernel.Tpo -c -o libode_a-collision_kernel.o `test -f 'collision_kernel.cpp' || echo '$(srcdir)/'`collision_kernel.cpp | ||
1551 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_kernel.Tpo $(DEPDIR)/libode_a-collision_kernel.Po | ||
1552 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_kernel.cpp' object='libode_a-collision_kernel.o' libtool=no @AMDEPBACKSLASH@ | ||
1553 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1554 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_kernel.o `test -f 'collision_kernel.cpp' || echo '$(srcdir)/'`collision_kernel.cpp | ||
1555 | |||
1556 | libode_a-collision_kernel.obj: collision_kernel.cpp | ||
1557 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_kernel.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_kernel.Tpo -c -o libode_a-collision_kernel.obj `if test -f 'collision_kernel.cpp'; then $(CYGPATH_W) 'collision_kernel.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_kernel.cpp'; fi` | ||
1558 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_kernel.Tpo $(DEPDIR)/libode_a-collision_kernel.Po | ||
1559 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_kernel.cpp' object='libode_a-collision_kernel.obj' libtool=no @AMDEPBACKSLASH@ | ||
1560 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1561 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_kernel.obj `if test -f 'collision_kernel.cpp'; then $(CYGPATH_W) 'collision_kernel.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_kernel.cpp'; fi` | ||
1562 | |||
1563 | libode_a-export-dif.o: export-dif.cpp | ||
1564 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-export-dif.o -MD -MP -MF $(DEPDIR)/libode_a-export-dif.Tpo -c -o libode_a-export-dif.o `test -f 'export-dif.cpp' || echo '$(srcdir)/'`export-dif.cpp | ||
1565 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-export-dif.Tpo $(DEPDIR)/libode_a-export-dif.Po | ||
1566 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='export-dif.cpp' object='libode_a-export-dif.o' libtool=no @AMDEPBACKSLASH@ | ||
1567 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1568 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-export-dif.o `test -f 'export-dif.cpp' || echo '$(srcdir)/'`export-dif.cpp | ||
1569 | |||
1570 | libode_a-export-dif.obj: export-dif.cpp | ||
1571 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-export-dif.obj -MD -MP -MF $(DEPDIR)/libode_a-export-dif.Tpo -c -o libode_a-export-dif.obj `if test -f 'export-dif.cpp'; then $(CYGPATH_W) 'export-dif.cpp'; else $(CYGPATH_W) '$(srcdir)/export-dif.cpp'; fi` | ||
1572 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-export-dif.Tpo $(DEPDIR)/libode_a-export-dif.Po | ||
1573 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='export-dif.cpp' object='libode_a-export-dif.obj' libtool=no @AMDEPBACKSLASH@ | ||
1574 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1575 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-export-dif.obj `if test -f 'export-dif.cpp'; then $(CYGPATH_W) 'export-dif.cpp'; else $(CYGPATH_W) '$(srcdir)/export-dif.cpp'; fi` | ||
1576 | |||
1577 | libode_a-quickstep.o: quickstep.cpp | ||
1578 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-quickstep.o -MD -MP -MF $(DEPDIR)/libode_a-quickstep.Tpo -c -o libode_a-quickstep.o `test -f 'quickstep.cpp' || echo '$(srcdir)/'`quickstep.cpp | ||
1579 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-quickstep.Tpo $(DEPDIR)/libode_a-quickstep.Po | ||
1580 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='quickstep.cpp' object='libode_a-quickstep.o' libtool=no @AMDEPBACKSLASH@ | ||
1581 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1582 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-quickstep.o `test -f 'quickstep.cpp' || echo '$(srcdir)/'`quickstep.cpp | ||
1583 | |||
1584 | libode_a-quickstep.obj: quickstep.cpp | ||
1585 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-quickstep.obj -MD -MP -MF $(DEPDIR)/libode_a-quickstep.Tpo -c -o libode_a-quickstep.obj `if test -f 'quickstep.cpp'; then $(CYGPATH_W) 'quickstep.cpp'; else $(CYGPATH_W) '$(srcdir)/quickstep.cpp'; fi` | ||
1586 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-quickstep.Tpo $(DEPDIR)/libode_a-quickstep.Po | ||
1587 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='quickstep.cpp' object='libode_a-quickstep.obj' libtool=no @AMDEPBACKSLASH@ | ||
1588 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1589 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-quickstep.obj `if test -f 'quickstep.cpp'; then $(CYGPATH_W) 'quickstep.cpp'; else $(CYGPATH_W) '$(srcdir)/quickstep.cpp'; fi` | ||
1590 | |||
1591 | libode_a-collision_quadtreespace.o: collision_quadtreespace.cpp | ||
1592 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_quadtreespace.o -MD -MP -MF $(DEPDIR)/libode_a-collision_quadtreespace.Tpo -c -o libode_a-collision_quadtreespace.o `test -f 'collision_quadtreespace.cpp' || echo '$(srcdir)/'`collision_quadtreespace.cpp | ||
1593 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_quadtreespace.Tpo $(DEPDIR)/libode_a-collision_quadtreespace.Po | ||
1594 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_quadtreespace.cpp' object='libode_a-collision_quadtreespace.o' libtool=no @AMDEPBACKSLASH@ | ||
1595 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1596 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_quadtreespace.o `test -f 'collision_quadtreespace.cpp' || echo '$(srcdir)/'`collision_quadtreespace.cpp | ||
1597 | |||
1598 | libode_a-collision_quadtreespace.obj: collision_quadtreespace.cpp | ||
1599 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_quadtreespace.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_quadtreespace.Tpo -c -o libode_a-collision_quadtreespace.obj `if test -f 'collision_quadtreespace.cpp'; then $(CYGPATH_W) 'collision_quadtreespace.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_quadtreespace.cpp'; fi` | ||
1600 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_quadtreespace.Tpo $(DEPDIR)/libode_a-collision_quadtreespace.Po | ||
1601 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_quadtreespace.cpp' object='libode_a-collision_quadtreespace.obj' libtool=no @AMDEPBACKSLASH@ | ||
1602 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1603 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_quadtreespace.obj `if test -f 'collision_quadtreespace.cpp'; then $(CYGPATH_W) 'collision_quadtreespace.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_quadtreespace.cpp'; fi` | ||
1604 | |||
1605 | libode_a-rotation.o: rotation.cpp | ||
1606 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-rotation.o -MD -MP -MF $(DEPDIR)/libode_a-rotation.Tpo -c -o libode_a-rotation.o `test -f 'rotation.cpp' || echo '$(srcdir)/'`rotation.cpp | ||
1607 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-rotation.Tpo $(DEPDIR)/libode_a-rotation.Po | ||
1608 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='rotation.cpp' object='libode_a-rotation.o' libtool=no @AMDEPBACKSLASH@ | ||
1609 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1610 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-rotation.o `test -f 'rotation.cpp' || echo '$(srcdir)/'`rotation.cpp | ||
1611 | |||
1612 | libode_a-rotation.obj: rotation.cpp | ||
1613 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-rotation.obj -MD -MP -MF $(DEPDIR)/libode_a-rotation.Tpo -c -o libode_a-rotation.obj `if test -f 'rotation.cpp'; then $(CYGPATH_W) 'rotation.cpp'; else $(CYGPATH_W) '$(srcdir)/rotation.cpp'; fi` | ||
1614 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-rotation.Tpo $(DEPDIR)/libode_a-rotation.Po | ||
1615 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='rotation.cpp' object='libode_a-rotation.obj' libtool=no @AMDEPBACKSLASH@ | ||
1616 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1617 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-rotation.obj `if test -f 'rotation.cpp'; then $(CYGPATH_W) 'rotation.cpp'; else $(CYGPATH_W) '$(srcdir)/rotation.cpp'; fi` | ||
1618 | |||
1619 | libode_a-collision_space.o: collision_space.cpp | ||
1620 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_space.o -MD -MP -MF $(DEPDIR)/libode_a-collision_space.Tpo -c -o libode_a-collision_space.o `test -f 'collision_space.cpp' || echo '$(srcdir)/'`collision_space.cpp | ||
1621 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_space.Tpo $(DEPDIR)/libode_a-collision_space.Po | ||
1622 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_space.cpp' object='libode_a-collision_space.o' libtool=no @AMDEPBACKSLASH@ | ||
1623 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1624 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_space.o `test -f 'collision_space.cpp' || echo '$(srcdir)/'`collision_space.cpp | ||
1625 | |||
1626 | libode_a-collision_space.obj: collision_space.cpp | ||
1627 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_space.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_space.Tpo -c -o libode_a-collision_space.obj `if test -f 'collision_space.cpp'; then $(CYGPATH_W) 'collision_space.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_space.cpp'; fi` | ||
1628 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_space.Tpo $(DEPDIR)/libode_a-collision_space.Po | ||
1629 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_space.cpp' object='libode_a-collision_space.obj' libtool=no @AMDEPBACKSLASH@ | ||
1630 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1631 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_space.obj `if test -f 'collision_space.cpp'; then $(CYGPATH_W) 'collision_space.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_space.cpp'; fi` | ||
1632 | |||
1633 | libode_a-collision_cylinder_box.o: collision_cylinder_box.cpp | ||
1634 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_box.o -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_box.Tpo -c -o libode_a-collision_cylinder_box.o `test -f 'collision_cylinder_box.cpp' || echo '$(srcdir)/'`collision_cylinder_box.cpp | ||
1635 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_box.Tpo $(DEPDIR)/libode_a-collision_cylinder_box.Po | ||
1636 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_box.cpp' object='libode_a-collision_cylinder_box.o' libtool=no @AMDEPBACKSLASH@ | ||
1637 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1638 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_box.o `test -f 'collision_cylinder_box.cpp' || echo '$(srcdir)/'`collision_cylinder_box.cpp | ||
1639 | |||
1640 | libode_a-collision_cylinder_box.obj: collision_cylinder_box.cpp | ||
1641 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_box.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_box.Tpo -c -o libode_a-collision_cylinder_box.obj `if test -f 'collision_cylinder_box.cpp'; then $(CYGPATH_W) 'collision_cylinder_box.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_box.cpp'; fi` | ||
1642 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_box.Tpo $(DEPDIR)/libode_a-collision_cylinder_box.Po | ||
1643 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_box.cpp' object='libode_a-collision_cylinder_box.obj' libtool=no @AMDEPBACKSLASH@ | ||
1644 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1645 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_box.obj `if test -f 'collision_cylinder_box.cpp'; then $(CYGPATH_W) 'collision_cylinder_box.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_box.cpp'; fi` | ||
1646 | |||
1647 | libode_a-collision_cylinder_sphere.o: collision_cylinder_sphere.cpp | ||
1648 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_sphere.o -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_sphere.Tpo -c -o libode_a-collision_cylinder_sphere.o `test -f 'collision_cylinder_sphere.cpp' || echo '$(srcdir)/'`collision_cylinder_sphere.cpp | ||
1649 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_sphere.Tpo $(DEPDIR)/libode_a-collision_cylinder_sphere.Po | ||
1650 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_sphere.cpp' object='libode_a-collision_cylinder_sphere.o' libtool=no @AMDEPBACKSLASH@ | ||
1651 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1652 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_sphere.o `test -f 'collision_cylinder_sphere.cpp' || echo '$(srcdir)/'`collision_cylinder_sphere.cpp | ||
1653 | |||
1654 | libode_a-collision_cylinder_sphere.obj: collision_cylinder_sphere.cpp | ||
1655 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_sphere.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_sphere.Tpo -c -o libode_a-collision_cylinder_sphere.obj `if test -f 'collision_cylinder_sphere.cpp'; then $(CYGPATH_W) 'collision_cylinder_sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_sphere.cpp'; fi` | ||
1656 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_sphere.Tpo $(DEPDIR)/libode_a-collision_cylinder_sphere.Po | ||
1657 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_sphere.cpp' object='libode_a-collision_cylinder_sphere.obj' libtool=no @AMDEPBACKSLASH@ | ||
1658 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1659 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_sphere.obj `if test -f 'collision_cylinder_sphere.cpp'; then $(CYGPATH_W) 'collision_cylinder_sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_sphere.cpp'; fi` | ||
1660 | |||
1661 | libode_a-collision_cylinder_plane.o: collision_cylinder_plane.cpp | ||
1662 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_plane.o -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_plane.Tpo -c -o libode_a-collision_cylinder_plane.o `test -f 'collision_cylinder_plane.cpp' || echo '$(srcdir)/'`collision_cylinder_plane.cpp | ||
1663 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_plane.Tpo $(DEPDIR)/libode_a-collision_cylinder_plane.Po | ||
1664 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_plane.cpp' object='libode_a-collision_cylinder_plane.o' libtool=no @AMDEPBACKSLASH@ | ||
1665 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1666 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_plane.o `test -f 'collision_cylinder_plane.cpp' || echo '$(srcdir)/'`collision_cylinder_plane.cpp | ||
1667 | |||
1668 | libode_a-collision_cylinder_plane.obj: collision_cylinder_plane.cpp | ||
1669 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_plane.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_plane.Tpo -c -o libode_a-collision_cylinder_plane.obj `if test -f 'collision_cylinder_plane.cpp'; then $(CYGPATH_W) 'collision_cylinder_plane.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_plane.cpp'; fi` | ||
1670 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_plane.Tpo $(DEPDIR)/libode_a-collision_cylinder_plane.Po | ||
1671 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_plane.cpp' object='libode_a-collision_cylinder_plane.obj' libtool=no @AMDEPBACKSLASH@ | ||
1672 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1673 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_plane.obj `if test -f 'collision_cylinder_plane.cpp'; then $(CYGPATH_W) 'collision_cylinder_plane.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_plane.cpp'; fi` | ||
1674 | |||
1675 | libode_a-sphere.o: sphere.cpp | ||
1676 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-sphere.o -MD -MP -MF $(DEPDIR)/libode_a-sphere.Tpo -c -o libode_a-sphere.o `test -f 'sphere.cpp' || echo '$(srcdir)/'`sphere.cpp | ||
1677 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-sphere.Tpo $(DEPDIR)/libode_a-sphere.Po | ||
1678 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sphere.cpp' object='libode_a-sphere.o' libtool=no @AMDEPBACKSLASH@ | ||
1679 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1680 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-sphere.o `test -f 'sphere.cpp' || echo '$(srcdir)/'`sphere.cpp | ||
1681 | |||
1682 | libode_a-sphere.obj: sphere.cpp | ||
1683 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-sphere.obj -MD -MP -MF $(DEPDIR)/libode_a-sphere.Tpo -c -o libode_a-sphere.obj `if test -f 'sphere.cpp'; then $(CYGPATH_W) 'sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/sphere.cpp'; fi` | ||
1684 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-sphere.Tpo $(DEPDIR)/libode_a-sphere.Po | ||
1685 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sphere.cpp' object='libode_a-sphere.obj' libtool=no @AMDEPBACKSLASH@ | ||
1686 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1687 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-sphere.obj `if test -f 'sphere.cpp'; then $(CYGPATH_W) 'sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/sphere.cpp'; fi` | ||
1688 | |||
1689 | libode_a-box.o: box.cpp | ||
1690 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-box.o -MD -MP -MF $(DEPDIR)/libode_a-box.Tpo -c -o libode_a-box.o `test -f 'box.cpp' || echo '$(srcdir)/'`box.cpp | ||
1691 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-box.Tpo $(DEPDIR)/libode_a-box.Po | ||
1692 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='box.cpp' object='libode_a-box.o' libtool=no @AMDEPBACKSLASH@ | ||
1693 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1694 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-box.o `test -f 'box.cpp' || echo '$(srcdir)/'`box.cpp | ||
1695 | |||
1696 | libode_a-box.obj: box.cpp | ||
1697 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-box.obj -MD -MP -MF $(DEPDIR)/libode_a-box.Tpo -c -o libode_a-box.obj `if test -f 'box.cpp'; then $(CYGPATH_W) 'box.cpp'; else $(CYGPATH_W) '$(srcdir)/box.cpp'; fi` | ||
1698 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-box.Tpo $(DEPDIR)/libode_a-box.Po | ||
1699 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='box.cpp' object='libode_a-box.obj' libtool=no @AMDEPBACKSLASH@ | ||
1700 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1701 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-box.obj `if test -f 'box.cpp'; then $(CYGPATH_W) 'box.cpp'; else $(CYGPATH_W) '$(srcdir)/box.cpp'; fi` | ||
1702 | |||
1703 | libode_a-capsule.o: capsule.cpp | ||
1704 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-capsule.o -MD -MP -MF $(DEPDIR)/libode_a-capsule.Tpo -c -o libode_a-capsule.o `test -f 'capsule.cpp' || echo '$(srcdir)/'`capsule.cpp | ||
1705 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-capsule.Tpo $(DEPDIR)/libode_a-capsule.Po | ||
1706 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='capsule.cpp' object='libode_a-capsule.o' libtool=no @AMDEPBACKSLASH@ | ||
1707 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1708 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-capsule.o `test -f 'capsule.cpp' || echo '$(srcdir)/'`capsule.cpp | ||
1709 | |||
1710 | libode_a-capsule.obj: capsule.cpp | ||
1711 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-capsule.obj -MD -MP -MF $(DEPDIR)/libode_a-capsule.Tpo -c -o libode_a-capsule.obj `if test -f 'capsule.cpp'; then $(CYGPATH_W) 'capsule.cpp'; else $(CYGPATH_W) '$(srcdir)/capsule.cpp'; fi` | ||
1712 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-capsule.Tpo $(DEPDIR)/libode_a-capsule.Po | ||
1713 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='capsule.cpp' object='libode_a-capsule.obj' libtool=no @AMDEPBACKSLASH@ | ||
1714 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1715 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-capsule.obj `if test -f 'capsule.cpp'; then $(CYGPATH_W) 'capsule.cpp'; else $(CYGPATH_W) '$(srcdir)/capsule.cpp'; fi` | ||
1716 | |||
1717 | libode_a-plane.o: plane.cpp | ||
1718 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-plane.o -MD -MP -MF $(DEPDIR)/libode_a-plane.Tpo -c -o libode_a-plane.o `test -f 'plane.cpp' || echo '$(srcdir)/'`plane.cpp | ||
1719 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-plane.Tpo $(DEPDIR)/libode_a-plane.Po | ||
1720 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='plane.cpp' object='libode_a-plane.o' libtool=no @AMDEPBACKSLASH@ | ||
1721 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1722 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-plane.o `test -f 'plane.cpp' || echo '$(srcdir)/'`plane.cpp | ||
1723 | |||
1724 | libode_a-plane.obj: plane.cpp | ||
1725 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-plane.obj -MD -MP -MF $(DEPDIR)/libode_a-plane.Tpo -c -o libode_a-plane.obj `if test -f 'plane.cpp'; then $(CYGPATH_W) 'plane.cpp'; else $(CYGPATH_W) '$(srcdir)/plane.cpp'; fi` | ||
1726 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-plane.Tpo $(DEPDIR)/libode_a-plane.Po | ||
1727 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='plane.cpp' object='libode_a-plane.obj' libtool=no @AMDEPBACKSLASH@ | ||
1728 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1729 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-plane.obj `if test -f 'plane.cpp'; then $(CYGPATH_W) 'plane.cpp'; else $(CYGPATH_W) '$(srcdir)/plane.cpp'; fi` | ||
1730 | |||
1731 | libode_a-ray.o: ray.cpp | ||
1732 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-ray.o -MD -MP -MF $(DEPDIR)/libode_a-ray.Tpo -c -o libode_a-ray.o `test -f 'ray.cpp' || echo '$(srcdir)/'`ray.cpp | ||
1733 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-ray.Tpo $(DEPDIR)/libode_a-ray.Po | ||
1734 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ray.cpp' object='libode_a-ray.o' libtool=no @AMDEPBACKSLASH@ | ||
1735 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1736 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-ray.o `test -f 'ray.cpp' || echo '$(srcdir)/'`ray.cpp | ||
1737 | |||
1738 | libode_a-ray.obj: ray.cpp | ||
1739 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-ray.obj -MD -MP -MF $(DEPDIR)/libode_a-ray.Tpo -c -o libode_a-ray.obj `if test -f 'ray.cpp'; then $(CYGPATH_W) 'ray.cpp'; else $(CYGPATH_W) '$(srcdir)/ray.cpp'; fi` | ||
1740 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-ray.Tpo $(DEPDIR)/libode_a-ray.Po | ||
1741 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='ray.cpp' object='libode_a-ray.obj' libtool=no @AMDEPBACKSLASH@ | ||
1742 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1743 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-ray.obj `if test -f 'ray.cpp'; then $(CYGPATH_W) 'ray.cpp'; else $(CYGPATH_W) '$(srcdir)/ray.cpp'; fi` | ||
1744 | |||
1745 | libode_a-cylinder.o: cylinder.cpp | ||
1746 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-cylinder.o -MD -MP -MF $(DEPDIR)/libode_a-cylinder.Tpo -c -o libode_a-cylinder.o `test -f 'cylinder.cpp' || echo '$(srcdir)/'`cylinder.cpp | ||
1747 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-cylinder.Tpo $(DEPDIR)/libode_a-cylinder.Po | ||
1748 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cylinder.cpp' object='libode_a-cylinder.o' libtool=no @AMDEPBACKSLASH@ | ||
1749 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1750 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-cylinder.o `test -f 'cylinder.cpp' || echo '$(srcdir)/'`cylinder.cpp | ||
1751 | |||
1752 | libode_a-cylinder.obj: cylinder.cpp | ||
1753 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-cylinder.obj -MD -MP -MF $(DEPDIR)/libode_a-cylinder.Tpo -c -o libode_a-cylinder.obj `if test -f 'cylinder.cpp'; then $(CYGPATH_W) 'cylinder.cpp'; else $(CYGPATH_W) '$(srcdir)/cylinder.cpp'; fi` | ||
1754 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-cylinder.Tpo $(DEPDIR)/libode_a-cylinder.Po | ||
1755 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cylinder.cpp' object='libode_a-cylinder.obj' libtool=no @AMDEPBACKSLASH@ | ||
1756 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1757 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-cylinder.obj `if test -f 'cylinder.cpp'; then $(CYGPATH_W) 'cylinder.cpp'; else $(CYGPATH_W) '$(srcdir)/cylinder.cpp'; fi` | ||
1758 | |||
1759 | libode_a-convex.o: convex.cpp | ||
1760 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-convex.o -MD -MP -MF $(DEPDIR)/libode_a-convex.Tpo -c -o libode_a-convex.o `test -f 'convex.cpp' || echo '$(srcdir)/'`convex.cpp | ||
1761 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-convex.Tpo $(DEPDIR)/libode_a-convex.Po | ||
1762 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='convex.cpp' object='libode_a-convex.o' libtool=no @AMDEPBACKSLASH@ | ||
1763 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1764 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-convex.o `test -f 'convex.cpp' || echo '$(srcdir)/'`convex.cpp | ||
1765 | |||
1766 | libode_a-convex.obj: convex.cpp | ||
1767 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-convex.obj -MD -MP -MF $(DEPDIR)/libode_a-convex.Tpo -c -o libode_a-convex.obj `if test -f 'convex.cpp'; then $(CYGPATH_W) 'convex.cpp'; else $(CYGPATH_W) '$(srcdir)/convex.cpp'; fi` | ||
1768 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-convex.Tpo $(DEPDIR)/libode_a-convex.Po | ||
1769 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='convex.cpp' object='libode_a-convex.obj' libtool=no @AMDEPBACKSLASH@ | ||
1770 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1771 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-convex.obj `if test -f 'convex.cpp'; then $(CYGPATH_W) 'convex.cpp'; else $(CYGPATH_W) '$(srcdir)/convex.cpp'; fi` | ||
1772 | |||
1773 | libode_a-joint.o: joint.cpp | ||
1774 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-joint.o -MD -MP -MF $(DEPDIR)/libode_a-joint.Tpo -c -o libode_a-joint.o `test -f 'joint.cpp' || echo '$(srcdir)/'`joint.cpp | ||
1775 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-joint.Tpo $(DEPDIR)/libode_a-joint.Po | ||
1776 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='joint.cpp' object='libode_a-joint.o' libtool=no @AMDEPBACKSLASH@ | ||
1777 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1778 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-joint.o `test -f 'joint.cpp' || echo '$(srcdir)/'`joint.cpp | ||
1779 | |||
1780 | libode_a-joint.obj: joint.cpp | ||
1781 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-joint.obj -MD -MP -MF $(DEPDIR)/libode_a-joint.Tpo -c -o libode_a-joint.obj `if test -f 'joint.cpp'; then $(CYGPATH_W) 'joint.cpp'; else $(CYGPATH_W) '$(srcdir)/joint.cpp'; fi` | ||
1782 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-joint.Tpo $(DEPDIR)/libode_a-joint.Po | ||
1783 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='joint.cpp' object='libode_a-joint.obj' libtool=no @AMDEPBACKSLASH@ | ||
1784 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1785 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-joint.obj `if test -f 'joint.cpp'; then $(CYGPATH_W) 'joint.cpp'; else $(CYGPATH_W) '$(srcdir)/joint.cpp'; fi` | ||
1786 | |||
1787 | libode_a-step.o: step.cpp | ||
1788 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-step.o -MD -MP -MF $(DEPDIR)/libode_a-step.Tpo -c -o libode_a-step.o `test -f 'step.cpp' || echo '$(srcdir)/'`step.cpp | ||
1789 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-step.Tpo $(DEPDIR)/libode_a-step.Po | ||
1790 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='step.cpp' object='libode_a-step.o' libtool=no @AMDEPBACKSLASH@ | ||
1791 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1792 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-step.o `test -f 'step.cpp' || echo '$(srcdir)/'`step.cpp | ||
1793 | |||
1794 | libode_a-step.obj: step.cpp | ||
1795 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-step.obj -MD -MP -MF $(DEPDIR)/libode_a-step.Tpo -c -o libode_a-step.obj `if test -f 'step.cpp'; then $(CYGPATH_W) 'step.cpp'; else $(CYGPATH_W) '$(srcdir)/step.cpp'; fi` | ||
1796 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-step.Tpo $(DEPDIR)/libode_a-step.Po | ||
1797 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='step.cpp' object='libode_a-step.obj' libtool=no @AMDEPBACKSLASH@ | ||
1798 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1799 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-step.obj `if test -f 'step.cpp'; then $(CYGPATH_W) 'step.cpp'; else $(CYGPATH_W) '$(srcdir)/step.cpp'; fi` | ||
1800 | |||
1801 | libode_a-collision_transform.o: collision_transform.cpp | ||
1802 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_transform.o -MD -MP -MF $(DEPDIR)/libode_a-collision_transform.Tpo -c -o libode_a-collision_transform.o `test -f 'collision_transform.cpp' || echo '$(srcdir)/'`collision_transform.cpp | ||
1803 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_transform.Tpo $(DEPDIR)/libode_a-collision_transform.Po | ||
1804 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_transform.cpp' object='libode_a-collision_transform.o' libtool=no @AMDEPBACKSLASH@ | ||
1805 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1806 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_transform.o `test -f 'collision_transform.cpp' || echo '$(srcdir)/'`collision_transform.cpp | ||
1807 | |||
1808 | libode_a-collision_transform.obj: collision_transform.cpp | ||
1809 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_transform.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_transform.Tpo -c -o libode_a-collision_transform.obj `if test -f 'collision_transform.cpp'; then $(CYGPATH_W) 'collision_transform.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_transform.cpp'; fi` | ||
1810 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_transform.Tpo $(DEPDIR)/libode_a-collision_transform.Po | ||
1811 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_transform.cpp' object='libode_a-collision_transform.obj' libtool=no @AMDEPBACKSLASH@ | ||
1812 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1813 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_transform.obj `if test -f 'collision_transform.cpp'; then $(CYGPATH_W) 'collision_transform.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_transform.cpp'; fi` | ||
1814 | |||
1815 | libode_a-lcp.o: lcp.cpp | ||
1816 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-lcp.o -MD -MP -MF $(DEPDIR)/libode_a-lcp.Tpo -c -o libode_a-lcp.o `test -f 'lcp.cpp' || echo '$(srcdir)/'`lcp.cpp | ||
1817 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-lcp.Tpo $(DEPDIR)/libode_a-lcp.Po | ||
1818 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lcp.cpp' object='libode_a-lcp.o' libtool=no @AMDEPBACKSLASH@ | ||
1819 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1820 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-lcp.o `test -f 'lcp.cpp' || echo '$(srcdir)/'`lcp.cpp | ||
1821 | |||
1822 | libode_a-lcp.obj: lcp.cpp | ||
1823 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-lcp.obj -MD -MP -MF $(DEPDIR)/libode_a-lcp.Tpo -c -o libode_a-lcp.obj `if test -f 'lcp.cpp'; then $(CYGPATH_W) 'lcp.cpp'; else $(CYGPATH_W) '$(srcdir)/lcp.cpp'; fi` | ||
1824 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-lcp.Tpo $(DEPDIR)/libode_a-lcp.Po | ||
1825 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='lcp.cpp' object='libode_a-lcp.obj' libtool=no @AMDEPBACKSLASH@ | ||
1826 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1827 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-lcp.obj `if test -f 'lcp.cpp'; then $(CYGPATH_W) 'lcp.cpp'; else $(CYGPATH_W) '$(srcdir)/lcp.cpp'; fi` | ||
1828 | |||
1829 | libode_a-stepfast.o: stepfast.cpp | ||
1830 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-stepfast.o -MD -MP -MF $(DEPDIR)/libode_a-stepfast.Tpo -c -o libode_a-stepfast.o `test -f 'stepfast.cpp' || echo '$(srcdir)/'`stepfast.cpp | ||
1831 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-stepfast.Tpo $(DEPDIR)/libode_a-stepfast.Po | ||
1832 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='stepfast.cpp' object='libode_a-stepfast.o' libtool=no @AMDEPBACKSLASH@ | ||
1833 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1834 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-stepfast.o `test -f 'stepfast.cpp' || echo '$(srcdir)/'`stepfast.cpp | ||
1835 | |||
1836 | libode_a-stepfast.obj: stepfast.cpp | ||
1837 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-stepfast.obj -MD -MP -MF $(DEPDIR)/libode_a-stepfast.Tpo -c -o libode_a-stepfast.obj `if test -f 'stepfast.cpp'; then $(CYGPATH_W) 'stepfast.cpp'; else $(CYGPATH_W) '$(srcdir)/stepfast.cpp'; fi` | ||
1838 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-stepfast.Tpo $(DEPDIR)/libode_a-stepfast.Po | ||
1839 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='stepfast.cpp' object='libode_a-stepfast.obj' libtool=no @AMDEPBACKSLASH@ | ||
1840 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1841 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-stepfast.obj `if test -f 'stepfast.cpp'; then $(CYGPATH_W) 'stepfast.cpp'; else $(CYGPATH_W) '$(srcdir)/stepfast.cpp'; fi` | ||
1842 | |||
1843 | libode_a-mass.o: mass.cpp | ||
1844 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-mass.o -MD -MP -MF $(DEPDIR)/libode_a-mass.Tpo -c -o libode_a-mass.o `test -f 'mass.cpp' || echo '$(srcdir)/'`mass.cpp | ||
1845 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-mass.Tpo $(DEPDIR)/libode_a-mass.Po | ||
1846 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mass.cpp' object='libode_a-mass.o' libtool=no @AMDEPBACKSLASH@ | ||
1847 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1848 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-mass.o `test -f 'mass.cpp' || echo '$(srcdir)/'`mass.cpp | ||
1849 | |||
1850 | libode_a-mass.obj: mass.cpp | ||
1851 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-mass.obj -MD -MP -MF $(DEPDIR)/libode_a-mass.Tpo -c -o libode_a-mass.obj `if test -f 'mass.cpp'; then $(CYGPATH_W) 'mass.cpp'; else $(CYGPATH_W) '$(srcdir)/mass.cpp'; fi` | ||
1852 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-mass.Tpo $(DEPDIR)/libode_a-mass.Po | ||
1853 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mass.cpp' object='libode_a-mass.obj' libtool=no @AMDEPBACKSLASH@ | ||
1854 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1855 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-mass.obj `if test -f 'mass.cpp'; then $(CYGPATH_W) 'mass.cpp'; else $(CYGPATH_W) '$(srcdir)/mass.cpp'; fi` | ||
1856 | |||
1857 | libode_a-testing.o: testing.cpp | ||
1858 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-testing.o -MD -MP -MF $(DEPDIR)/libode_a-testing.Tpo -c -o libode_a-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp | ||
1859 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-testing.Tpo $(DEPDIR)/libode_a-testing.Po | ||
1860 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='libode_a-testing.o' libtool=no @AMDEPBACKSLASH@ | ||
1861 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1862 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-testing.o `test -f 'testing.cpp' || echo '$(srcdir)/'`testing.cpp | ||
1863 | |||
1864 | libode_a-testing.obj: testing.cpp | ||
1865 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-testing.obj -MD -MP -MF $(DEPDIR)/libode_a-testing.Tpo -c -o libode_a-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` | ||
1866 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-testing.Tpo $(DEPDIR)/libode_a-testing.Po | ||
1867 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='testing.cpp' object='libode_a-testing.obj' libtool=no @AMDEPBACKSLASH@ | ||
1868 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1869 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-testing.obj `if test -f 'testing.cpp'; then $(CYGPATH_W) 'testing.cpp'; else $(CYGPATH_W) '$(srcdir)/testing.cpp'; fi` | ||
1870 | |||
1871 | libode_a-mat.o: mat.cpp | ||
1872 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-mat.o -MD -MP -MF $(DEPDIR)/libode_a-mat.Tpo -c -o libode_a-mat.o `test -f 'mat.cpp' || echo '$(srcdir)/'`mat.cpp | ||
1873 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-mat.Tpo $(DEPDIR)/libode_a-mat.Po | ||
1874 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mat.cpp' object='libode_a-mat.o' libtool=no @AMDEPBACKSLASH@ | ||
1875 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1876 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-mat.o `test -f 'mat.cpp' || echo '$(srcdir)/'`mat.cpp | ||
1877 | |||
1878 | libode_a-mat.obj: mat.cpp | ||
1879 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-mat.obj -MD -MP -MF $(DEPDIR)/libode_a-mat.Tpo -c -o libode_a-mat.obj `if test -f 'mat.cpp'; then $(CYGPATH_W) 'mat.cpp'; else $(CYGPATH_W) '$(srcdir)/mat.cpp'; fi` | ||
1880 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-mat.Tpo $(DEPDIR)/libode_a-mat.Po | ||
1881 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mat.cpp' object='libode_a-mat.obj' libtool=no @AMDEPBACKSLASH@ | ||
1882 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1883 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-mat.obj `if test -f 'mat.cpp'; then $(CYGPATH_W) 'mat.cpp'; else $(CYGPATH_W) '$(srcdir)/mat.cpp'; fi` | ||
1884 | |||
1885 | libode_a-timer.o: timer.cpp | ||
1886 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-timer.o -MD -MP -MF $(DEPDIR)/libode_a-timer.Tpo -c -o libode_a-timer.o `test -f 'timer.cpp' || echo '$(srcdir)/'`timer.cpp | ||
1887 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-timer.Tpo $(DEPDIR)/libode_a-timer.Po | ||
1888 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='timer.cpp' object='libode_a-timer.o' libtool=no @AMDEPBACKSLASH@ | ||
1889 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1890 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-timer.o `test -f 'timer.cpp' || echo '$(srcdir)/'`timer.cpp | ||
1891 | |||
1892 | libode_a-timer.obj: timer.cpp | ||
1893 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-timer.obj -MD -MP -MF $(DEPDIR)/libode_a-timer.Tpo -c -o libode_a-timer.obj `if test -f 'timer.cpp'; then $(CYGPATH_W) 'timer.cpp'; else $(CYGPATH_W) '$(srcdir)/timer.cpp'; fi` | ||
1894 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-timer.Tpo $(DEPDIR)/libode_a-timer.Po | ||
1895 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='timer.cpp' object='libode_a-timer.obj' libtool=no @AMDEPBACKSLASH@ | ||
1896 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1897 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-timer.obj `if test -f 'timer.cpp'; then $(CYGPATH_W) 'timer.cpp'; else $(CYGPATH_W) '$(srcdir)/timer.cpp'; fi` | ||
1898 | |||
1899 | libode_a-matrix.o: matrix.cpp | ||
1900 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-matrix.o -MD -MP -MF $(DEPDIR)/libode_a-matrix.Tpo -c -o libode_a-matrix.o `test -f 'matrix.cpp' || echo '$(srcdir)/'`matrix.cpp | ||
1901 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-matrix.Tpo $(DEPDIR)/libode_a-matrix.Po | ||
1902 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='matrix.cpp' object='libode_a-matrix.o' libtool=no @AMDEPBACKSLASH@ | ||
1903 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1904 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-matrix.o `test -f 'matrix.cpp' || echo '$(srcdir)/'`matrix.cpp | ||
1905 | |||
1906 | libode_a-matrix.obj: matrix.cpp | ||
1907 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-matrix.obj -MD -MP -MF $(DEPDIR)/libode_a-matrix.Tpo -c -o libode_a-matrix.obj `if test -f 'matrix.cpp'; then $(CYGPATH_W) 'matrix.cpp'; else $(CYGPATH_W) '$(srcdir)/matrix.cpp'; fi` | ||
1908 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-matrix.Tpo $(DEPDIR)/libode_a-matrix.Po | ||
1909 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='matrix.cpp' object='libode_a-matrix.obj' libtool=no @AMDEPBACKSLASH@ | ||
1910 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1911 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-matrix.obj `if test -f 'matrix.cpp'; then $(CYGPATH_W) 'matrix.cpp'; else $(CYGPATH_W) '$(srcdir)/matrix.cpp'; fi` | ||
1912 | |||
1913 | libode_a-util.o: util.cpp | ||
1914 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-util.o -MD -MP -MF $(DEPDIR)/libode_a-util.Tpo -c -o libode_a-util.o `test -f 'util.cpp' || echo '$(srcdir)/'`util.cpp | ||
1915 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-util.Tpo $(DEPDIR)/libode_a-util.Po | ||
1916 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='util.cpp' object='libode_a-util.o' libtool=no @AMDEPBACKSLASH@ | ||
1917 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1918 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-util.o `test -f 'util.cpp' || echo '$(srcdir)/'`util.cpp | ||
1919 | |||
1920 | libode_a-util.obj: util.cpp | ||
1921 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-util.obj -MD -MP -MF $(DEPDIR)/libode_a-util.Tpo -c -o libode_a-util.obj `if test -f 'util.cpp'; then $(CYGPATH_W) 'util.cpp'; else $(CYGPATH_W) '$(srcdir)/util.cpp'; fi` | ||
1922 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-util.Tpo $(DEPDIR)/libode_a-util.Po | ||
1923 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='util.cpp' object='libode_a-util.obj' libtool=no @AMDEPBACKSLASH@ | ||
1924 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1925 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-util.obj `if test -f 'util.cpp'; then $(CYGPATH_W) 'util.cpp'; else $(CYGPATH_W) '$(srcdir)/util.cpp'; fi` | ||
1926 | |||
1927 | libode_a-memory.o: memory.cpp | ||
1928 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-memory.o -MD -MP -MF $(DEPDIR)/libode_a-memory.Tpo -c -o libode_a-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp | ||
1929 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-memory.Tpo $(DEPDIR)/libode_a-memory.Po | ||
1930 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='libode_a-memory.o' libtool=no @AMDEPBACKSLASH@ | ||
1931 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1932 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp | ||
1933 | |||
1934 | libode_a-memory.obj: memory.cpp | ||
1935 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-memory.obj -MD -MP -MF $(DEPDIR)/libode_a-memory.Tpo -c -o libode_a-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi` | ||
1936 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-memory.Tpo $(DEPDIR)/libode_a-memory.Po | ||
1937 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='libode_a-memory.obj' libtool=no @AMDEPBACKSLASH@ | ||
1938 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1939 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi` | ||
1940 | |||
1941 | libode_a-misc.o: misc.cpp | ||
1942 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-misc.o -MD -MP -MF $(DEPDIR)/libode_a-misc.Tpo -c -o libode_a-misc.o `test -f 'misc.cpp' || echo '$(srcdir)/'`misc.cpp | ||
1943 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-misc.Tpo $(DEPDIR)/libode_a-misc.Po | ||
1944 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='misc.cpp' object='libode_a-misc.o' libtool=no @AMDEPBACKSLASH@ | ||
1945 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1946 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-misc.o `test -f 'misc.cpp' || echo '$(srcdir)/'`misc.cpp | ||
1947 | |||
1948 | libode_a-misc.obj: misc.cpp | ||
1949 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-misc.obj -MD -MP -MF $(DEPDIR)/libode_a-misc.Tpo -c -o libode_a-misc.obj `if test -f 'misc.cpp'; then $(CYGPATH_W) 'misc.cpp'; else $(CYGPATH_W) '$(srcdir)/misc.cpp'; fi` | ||
1950 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-misc.Tpo $(DEPDIR)/libode_a-misc.Po | ||
1951 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='misc.cpp' object='libode_a-misc.obj' libtool=no @AMDEPBACKSLASH@ | ||
1952 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1953 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-misc.obj `if test -f 'misc.cpp'; then $(CYGPATH_W) 'misc.cpp'; else $(CYGPATH_W) '$(srcdir)/misc.cpp'; fi` | ||
1954 | |||
1955 | libode_a-heightfield.o: heightfield.cpp | ||
1956 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-heightfield.o -MD -MP -MF $(DEPDIR)/libode_a-heightfield.Tpo -c -o libode_a-heightfield.o `test -f 'heightfield.cpp' || echo '$(srcdir)/'`heightfield.cpp | ||
1957 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-heightfield.Tpo $(DEPDIR)/libode_a-heightfield.Po | ||
1958 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='heightfield.cpp' object='libode_a-heightfield.o' libtool=no @AMDEPBACKSLASH@ | ||
1959 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1960 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-heightfield.o `test -f 'heightfield.cpp' || echo '$(srcdir)/'`heightfield.cpp | ||
1961 | |||
1962 | libode_a-heightfield.obj: heightfield.cpp | ||
1963 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-heightfield.obj -MD -MP -MF $(DEPDIR)/libode_a-heightfield.Tpo -c -o libode_a-heightfield.obj `if test -f 'heightfield.cpp'; then $(CYGPATH_W) 'heightfield.cpp'; else $(CYGPATH_W) '$(srcdir)/heightfield.cpp'; fi` | ||
1964 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-heightfield.Tpo $(DEPDIR)/libode_a-heightfield.Po | ||
1965 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='heightfield.cpp' object='libode_a-heightfield.obj' libtool=no @AMDEPBACKSLASH@ | ||
1966 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1967 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-heightfield.obj `if test -f 'heightfield.cpp'; then $(CYGPATH_W) 'heightfield.cpp'; else $(CYGPATH_W) '$(srcdir)/heightfield.cpp'; fi` | ||
1968 | |||
1969 | libode_a-collision_trimesh_gimpact.o: collision_trimesh_gimpact.cpp | ||
1970 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_gimpact.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_gimpact.Tpo -c -o libode_a-collision_trimesh_gimpact.o `test -f 'collision_trimesh_gimpact.cpp' || echo '$(srcdir)/'`collision_trimesh_gimpact.cpp | ||
1971 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_gimpact.Tpo $(DEPDIR)/libode_a-collision_trimesh_gimpact.Po | ||
1972 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_gimpact.cpp' object='libode_a-collision_trimesh_gimpact.o' libtool=no @AMDEPBACKSLASH@ | ||
1973 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1974 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_gimpact.o `test -f 'collision_trimesh_gimpact.cpp' || echo '$(srcdir)/'`collision_trimesh_gimpact.cpp | ||
1975 | |||
1976 | libode_a-collision_trimesh_gimpact.obj: collision_trimesh_gimpact.cpp | ||
1977 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_gimpact.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_gimpact.Tpo -c -o libode_a-collision_trimesh_gimpact.obj `if test -f 'collision_trimesh_gimpact.cpp'; then $(CYGPATH_W) 'collision_trimesh_gimpact.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_gimpact.cpp'; fi` | ||
1978 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_gimpact.Tpo $(DEPDIR)/libode_a-collision_trimesh_gimpact.Po | ||
1979 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_gimpact.cpp' object='libode_a-collision_trimesh_gimpact.obj' libtool=no @AMDEPBACKSLASH@ | ||
1980 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1981 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_gimpact.obj `if test -f 'collision_trimesh_gimpact.cpp'; then $(CYGPATH_W) 'collision_trimesh_gimpact.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_gimpact.cpp'; fi` | ||
1982 | |||
1983 | libode_a-collision_trimesh_trimesh.o: collision_trimesh_trimesh.cpp | ||
1984 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_trimesh.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_trimesh.Tpo -c -o libode_a-collision_trimesh_trimesh.o `test -f 'collision_trimesh_trimesh.cpp' || echo '$(srcdir)/'`collision_trimesh_trimesh.cpp | ||
1985 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_trimesh.Tpo $(DEPDIR)/libode_a-collision_trimesh_trimesh.Po | ||
1986 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_trimesh.cpp' object='libode_a-collision_trimesh_trimesh.o' libtool=no @AMDEPBACKSLASH@ | ||
1987 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1988 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_trimesh.o `test -f 'collision_trimesh_trimesh.cpp' || echo '$(srcdir)/'`collision_trimesh_trimesh.cpp | ||
1989 | |||
1990 | libode_a-collision_trimesh_trimesh.obj: collision_trimesh_trimesh.cpp | ||
1991 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_trimesh.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_trimesh.Tpo -c -o libode_a-collision_trimesh_trimesh.obj `if test -f 'collision_trimesh_trimesh.cpp'; then $(CYGPATH_W) 'collision_trimesh_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_trimesh.cpp'; fi` | ||
1992 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_trimesh.Tpo $(DEPDIR)/libode_a-collision_trimesh_trimesh.Po | ||
1993 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_trimesh.cpp' object='libode_a-collision_trimesh_trimesh.obj' libtool=no @AMDEPBACKSLASH@ | ||
1994 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
1995 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_trimesh.obj `if test -f 'collision_trimesh_trimesh.cpp'; then $(CYGPATH_W) 'collision_trimesh_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_trimesh.cpp'; fi` | ||
1996 | |||
1997 | libode_a-collision_trimesh_sphere.o: collision_trimesh_sphere.cpp | ||
1998 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_sphere.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_sphere.Tpo -c -o libode_a-collision_trimesh_sphere.o `test -f 'collision_trimesh_sphere.cpp' || echo '$(srcdir)/'`collision_trimesh_sphere.cpp | ||
1999 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_sphere.Tpo $(DEPDIR)/libode_a-collision_trimesh_sphere.Po | ||
2000 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_sphere.cpp' object='libode_a-collision_trimesh_sphere.o' libtool=no @AMDEPBACKSLASH@ | ||
2001 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2002 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_sphere.o `test -f 'collision_trimesh_sphere.cpp' || echo '$(srcdir)/'`collision_trimesh_sphere.cpp | ||
2003 | |||
2004 | libode_a-collision_trimesh_sphere.obj: collision_trimesh_sphere.cpp | ||
2005 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_sphere.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_sphere.Tpo -c -o libode_a-collision_trimesh_sphere.obj `if test -f 'collision_trimesh_sphere.cpp'; then $(CYGPATH_W) 'collision_trimesh_sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_sphere.cpp'; fi` | ||
2006 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_sphere.Tpo $(DEPDIR)/libode_a-collision_trimesh_sphere.Po | ||
2007 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_sphere.cpp' object='libode_a-collision_trimesh_sphere.obj' libtool=no @AMDEPBACKSLASH@ | ||
2008 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2009 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_sphere.obj `if test -f 'collision_trimesh_sphere.cpp'; then $(CYGPATH_W) 'collision_trimesh_sphere.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_sphere.cpp'; fi` | ||
2010 | |||
2011 | libode_a-collision_trimesh_ray.o: collision_trimesh_ray.cpp | ||
2012 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_ray.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_ray.Tpo -c -o libode_a-collision_trimesh_ray.o `test -f 'collision_trimesh_ray.cpp' || echo '$(srcdir)/'`collision_trimesh_ray.cpp | ||
2013 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_ray.Tpo $(DEPDIR)/libode_a-collision_trimesh_ray.Po | ||
2014 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_ray.cpp' object='libode_a-collision_trimesh_ray.o' libtool=no @AMDEPBACKSLASH@ | ||
2015 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2016 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_ray.o `test -f 'collision_trimesh_ray.cpp' || echo '$(srcdir)/'`collision_trimesh_ray.cpp | ||
2017 | |||
2018 | libode_a-collision_trimesh_ray.obj: collision_trimesh_ray.cpp | ||
2019 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_ray.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_ray.Tpo -c -o libode_a-collision_trimesh_ray.obj `if test -f 'collision_trimesh_ray.cpp'; then $(CYGPATH_W) 'collision_trimesh_ray.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_ray.cpp'; fi` | ||
2020 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_ray.Tpo $(DEPDIR)/libode_a-collision_trimesh_ray.Po | ||
2021 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_ray.cpp' object='libode_a-collision_trimesh_ray.obj' libtool=no @AMDEPBACKSLASH@ | ||
2022 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2023 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_ray.obj `if test -f 'collision_trimesh_ray.cpp'; then $(CYGPATH_W) 'collision_trimesh_ray.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_ray.cpp'; fi` | ||
2024 | |||
2025 | libode_a-collision_trimesh_opcode.o: collision_trimesh_opcode.cpp | ||
2026 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_opcode.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_opcode.Tpo -c -o libode_a-collision_trimesh_opcode.o `test -f 'collision_trimesh_opcode.cpp' || echo '$(srcdir)/'`collision_trimesh_opcode.cpp | ||
2027 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_opcode.Tpo $(DEPDIR)/libode_a-collision_trimesh_opcode.Po | ||
2028 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_opcode.cpp' object='libode_a-collision_trimesh_opcode.o' libtool=no @AMDEPBACKSLASH@ | ||
2029 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2030 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_opcode.o `test -f 'collision_trimesh_opcode.cpp' || echo '$(srcdir)/'`collision_trimesh_opcode.cpp | ||
2031 | |||
2032 | libode_a-collision_trimesh_opcode.obj: collision_trimesh_opcode.cpp | ||
2033 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_opcode.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_opcode.Tpo -c -o libode_a-collision_trimesh_opcode.obj `if test -f 'collision_trimesh_opcode.cpp'; then $(CYGPATH_W) 'collision_trimesh_opcode.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_opcode.cpp'; fi` | ||
2034 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_opcode.Tpo $(DEPDIR)/libode_a-collision_trimesh_opcode.Po | ||
2035 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_opcode.cpp' object='libode_a-collision_trimesh_opcode.obj' libtool=no @AMDEPBACKSLASH@ | ||
2036 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2037 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_opcode.obj `if test -f 'collision_trimesh_opcode.cpp'; then $(CYGPATH_W) 'collision_trimesh_opcode.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_opcode.cpp'; fi` | ||
2038 | |||
2039 | libode_a-collision_trimesh_box.o: collision_trimesh_box.cpp | ||
2040 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_box.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_box.Tpo -c -o libode_a-collision_trimesh_box.o `test -f 'collision_trimesh_box.cpp' || echo '$(srcdir)/'`collision_trimesh_box.cpp | ||
2041 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_box.Tpo $(DEPDIR)/libode_a-collision_trimesh_box.Po | ||
2042 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_box.cpp' object='libode_a-collision_trimesh_box.o' libtool=no @AMDEPBACKSLASH@ | ||
2043 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2044 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_box.o `test -f 'collision_trimesh_box.cpp' || echo '$(srcdir)/'`collision_trimesh_box.cpp | ||
2045 | |||
2046 | libode_a-collision_trimesh_box.obj: collision_trimesh_box.cpp | ||
2047 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_box.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_box.Tpo -c -o libode_a-collision_trimesh_box.obj `if test -f 'collision_trimesh_box.cpp'; then $(CYGPATH_W) 'collision_trimesh_box.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_box.cpp'; fi` | ||
2048 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_box.Tpo $(DEPDIR)/libode_a-collision_trimesh_box.Po | ||
2049 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_box.cpp' object='libode_a-collision_trimesh_box.obj' libtool=no @AMDEPBACKSLASH@ | ||
2050 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2051 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_box.obj `if test -f 'collision_trimesh_box.cpp'; then $(CYGPATH_W) 'collision_trimesh_box.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_box.cpp'; fi` | ||
2052 | |||
2053 | libode_a-collision_trimesh_ccylinder.o: collision_trimesh_ccylinder.cpp | ||
2054 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_ccylinder.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Tpo -c -o libode_a-collision_trimesh_ccylinder.o `test -f 'collision_trimesh_ccylinder.cpp' || echo '$(srcdir)/'`collision_trimesh_ccylinder.cpp | ||
2055 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Tpo $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Po | ||
2056 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_ccylinder.cpp' object='libode_a-collision_trimesh_ccylinder.o' libtool=no @AMDEPBACKSLASH@ | ||
2057 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2058 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_ccylinder.o `test -f 'collision_trimesh_ccylinder.cpp' || echo '$(srcdir)/'`collision_trimesh_ccylinder.cpp | ||
2059 | |||
2060 | libode_a-collision_trimesh_ccylinder.obj: collision_trimesh_ccylinder.cpp | ||
2061 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_ccylinder.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Tpo -c -o libode_a-collision_trimesh_ccylinder.obj `if test -f 'collision_trimesh_ccylinder.cpp'; then $(CYGPATH_W) 'collision_trimesh_ccylinder.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_ccylinder.cpp'; fi` | ||
2062 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Tpo $(DEPDIR)/libode_a-collision_trimesh_ccylinder.Po | ||
2063 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_ccylinder.cpp' object='libode_a-collision_trimesh_ccylinder.obj' libtool=no @AMDEPBACKSLASH@ | ||
2064 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2065 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_ccylinder.obj `if test -f 'collision_trimesh_ccylinder.cpp'; then $(CYGPATH_W) 'collision_trimesh_ccylinder.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_ccylinder.cpp'; fi` | ||
2066 | |||
2067 | libode_a-collision_trimesh_distance.o: collision_trimesh_distance.cpp | ||
2068 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_distance.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_distance.Tpo -c -o libode_a-collision_trimesh_distance.o `test -f 'collision_trimesh_distance.cpp' || echo '$(srcdir)/'`collision_trimesh_distance.cpp | ||
2069 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_distance.Tpo $(DEPDIR)/libode_a-collision_trimesh_distance.Po | ||
2070 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_distance.cpp' object='libode_a-collision_trimesh_distance.o' libtool=no @AMDEPBACKSLASH@ | ||
2071 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2072 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_distance.o `test -f 'collision_trimesh_distance.cpp' || echo '$(srcdir)/'`collision_trimesh_distance.cpp | ||
2073 | |||
2074 | libode_a-collision_trimesh_distance.obj: collision_trimesh_distance.cpp | ||
2075 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_distance.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_distance.Tpo -c -o libode_a-collision_trimesh_distance.obj `if test -f 'collision_trimesh_distance.cpp'; then $(CYGPATH_W) 'collision_trimesh_distance.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_distance.cpp'; fi` | ||
2076 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_distance.Tpo $(DEPDIR)/libode_a-collision_trimesh_distance.Po | ||
2077 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_distance.cpp' object='libode_a-collision_trimesh_distance.obj' libtool=no @AMDEPBACKSLASH@ | ||
2078 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2079 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_distance.obj `if test -f 'collision_trimesh_distance.cpp'; then $(CYGPATH_W) 'collision_trimesh_distance.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_distance.cpp'; fi` | ||
2080 | |||
2081 | libode_a-collision_cylinder_trimesh.o: collision_cylinder_trimesh.cpp | ||
2082 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_trimesh.o -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_trimesh.Tpo -c -o libode_a-collision_cylinder_trimesh.o `test -f 'collision_cylinder_trimesh.cpp' || echo '$(srcdir)/'`collision_cylinder_trimesh.cpp | ||
2083 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_trimesh.Tpo $(DEPDIR)/libode_a-collision_cylinder_trimesh.Po | ||
2084 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_trimesh.cpp' object='libode_a-collision_cylinder_trimesh.o' libtool=no @AMDEPBACKSLASH@ | ||
2085 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2086 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_trimesh.o `test -f 'collision_cylinder_trimesh.cpp' || echo '$(srcdir)/'`collision_cylinder_trimesh.cpp | ||
2087 | |||
2088 | libode_a-collision_cylinder_trimesh.obj: collision_cylinder_trimesh.cpp | ||
2089 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_cylinder_trimesh.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_cylinder_trimesh.Tpo -c -o libode_a-collision_cylinder_trimesh.obj `if test -f 'collision_cylinder_trimesh.cpp'; then $(CYGPATH_W) 'collision_cylinder_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_trimesh.cpp'; fi` | ||
2090 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_cylinder_trimesh.Tpo $(DEPDIR)/libode_a-collision_cylinder_trimesh.Po | ||
2091 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_cylinder_trimesh.cpp' object='libode_a-collision_cylinder_trimesh.obj' libtool=no @AMDEPBACKSLASH@ | ||
2092 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2093 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_cylinder_trimesh.obj `if test -f 'collision_cylinder_trimesh.cpp'; then $(CYGPATH_W) 'collision_cylinder_trimesh.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_cylinder_trimesh.cpp'; fi` | ||
2094 | |||
2095 | libode_a-collision_trimesh_plane.o: collision_trimesh_plane.cpp | ||
2096 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_plane.o -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_plane.Tpo -c -o libode_a-collision_trimesh_plane.o `test -f 'collision_trimesh_plane.cpp' || echo '$(srcdir)/'`collision_trimesh_plane.cpp | ||
2097 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_plane.Tpo $(DEPDIR)/libode_a-collision_trimesh_plane.Po | ||
2098 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_plane.cpp' object='libode_a-collision_trimesh_plane.o' libtool=no @AMDEPBACKSLASH@ | ||
2099 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2100 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_plane.o `test -f 'collision_trimesh_plane.cpp' || echo '$(srcdir)/'`collision_trimesh_plane.cpp | ||
2101 | |||
2102 | libode_a-collision_trimesh_plane.obj: collision_trimesh_plane.cpp | ||
2103 | @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libode_a-collision_trimesh_plane.obj -MD -MP -MF $(DEPDIR)/libode_a-collision_trimesh_plane.Tpo -c -o libode_a-collision_trimesh_plane.obj `if test -f 'collision_trimesh_plane.cpp'; then $(CYGPATH_W) 'collision_trimesh_plane.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_plane.cpp'; fi` | ||
2104 | @am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/libode_a-collision_trimesh_plane.Tpo $(DEPDIR)/libode_a-collision_trimesh_plane.Po | ||
2105 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='collision_trimesh_plane.cpp' object='libode_a-collision_trimesh_plane.obj' libtool=no @AMDEPBACKSLASH@ | ||
2106 | @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | ||
2107 | @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libode_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libode_a-collision_trimesh_plane.obj `if test -f 'collision_trimesh_plane.cpp'; then $(CYGPATH_W) 'collision_trimesh_plane.cpp'; else $(CYGPATH_W) '$(srcdir)/collision_trimesh_plane.cpp'; fi` | ||
2108 | |||
2109 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) | ||
2110 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
2111 | unique=`for i in $$list; do \ | ||
2112 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
2113 | done | \ | ||
2114 | $(AWK) ' { files[$$0] = 1; } \ | ||
2115 | END { for (i in files) print i; }'`; \ | ||
2116 | mkid -fID $$unique | ||
2117 | tags: TAGS | ||
2118 | |||
2119 | TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
2120 | $(TAGS_FILES) $(LISP) | ||
2121 | tags=; \ | ||
2122 | here=`pwd`; \ | ||
2123 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
2124 | unique=`for i in $$list; do \ | ||
2125 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
2126 | done | \ | ||
2127 | $(AWK) ' { files[$$0] = 1; } \ | ||
2128 | END { for (i in files) print i; }'`; \ | ||
2129 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ | ||
2130 | test -n "$$unique" || unique=$$empty_fix; \ | ||
2131 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ | ||
2132 | $$tags $$unique; \ | ||
2133 | fi | ||
2134 | ctags: CTAGS | ||
2135 | CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ | ||
2136 | $(TAGS_FILES) $(LISP) | ||
2137 | tags=; \ | ||
2138 | here=`pwd`; \ | ||
2139 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ | ||
2140 | unique=`for i in $$list; do \ | ||
2141 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ | ||
2142 | done | \ | ||
2143 | $(AWK) ' { files[$$0] = 1; } \ | ||
2144 | END { for (i in files) print i; }'`; \ | ||
2145 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ | ||
2146 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ | ||
2147 | $$tags $$unique | ||
2148 | |||
2149 | GTAGS: | ||
2150 | here=`$(am__cd) $(top_builddir) && pwd` \ | ||
2151 | && cd $(top_srcdir) \ | ||
2152 | && gtags -i $(GTAGS_ARGS) $$here | ||
2153 | |||
2154 | distclean-tags: | ||
2155 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags | ||
2156 | |||
2157 | distdir: $(DISTFILES) | ||
2158 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | ||
2159 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ | ||
2160 | list='$(DISTFILES)'; \ | ||
2161 | dist_files=`for file in $$list; do echo $$file; done | \ | ||
2162 | sed -e "s|^$$srcdirstrip/||;t" \ | ||
2163 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ | ||
2164 | case $$dist_files in \ | ||
2165 | */*) $(MKDIR_P) `echo "$$dist_files" | \ | ||
2166 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ | ||
2167 | sort -u` ;; \ | ||
2168 | esac; \ | ||
2169 | for file in $$dist_files; do \ | ||
2170 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ | ||
2171 | if test -d $$d/$$file; then \ | ||
2172 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ | ||
2173 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ | ||
2174 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ | ||
2175 | fi; \ | ||
2176 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ | ||
2177 | else \ | ||
2178 | test -f $(distdir)/$$file \ | ||
2179 | || cp -p $$d/$$file $(distdir)/$$file \ | ||
2180 | || exit 1; \ | ||
2181 | fi; \ | ||
2182 | done | ||
2183 | check-am: all-am | ||
2184 | check: check-am | ||
2185 | all-am: Makefile $(LIBRARIES) $(PROGRAMS) | ||
2186 | installdirs: | ||
2187 | for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(traplibdir)"; do \ | ||
2188 | test -z "$$dir" || $(MKDIR_P) "$$dir"; \ | ||
2189 | done | ||
2190 | install: install-am | ||
2191 | install-exec: install-exec-am | ||
2192 | install-data: install-data-am | ||
2193 | uninstall: uninstall-am | ||
2194 | |||
2195 | install-am: all-am | ||
2196 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am | ||
2197 | |||
2198 | installcheck: installcheck-am | ||
2199 | install-strip: | ||
2200 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ | ||
2201 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ | ||
2202 | `test -z '$(STRIP)' || \ | ||
2203 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install | ||
2204 | mostlyclean-generic: | ||
2205 | |||
2206 | clean-generic: | ||
2207 | |||
2208 | distclean-generic: | ||
2209 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) | ||
2210 | |||
2211 | maintainer-clean-generic: | ||
2212 | @echo "This command is intended for maintainers to use" | ||
2213 | @echo "it deletes files that may require special tools to rebuild." | ||
2214 | clean: clean-am | ||
2215 | |||
2216 | clean-am: clean-generic clean-libLIBRARIES clean-noinstLIBRARIES \ | ||
2217 | clean-traplibPROGRAMS mostlyclean-am | ||
2218 | |||
2219 | distclean: distclean-am | ||
2220 | -rm -rf ./$(DEPDIR) | ||
2221 | -rm -f Makefile | ||
2222 | distclean-am: clean-am distclean-compile distclean-generic \ | ||
2223 | distclean-tags | ||
2224 | |||
2225 | dvi: dvi-am | ||
2226 | |||
2227 | dvi-am: | ||
2228 | |||
2229 | html: html-am | ||
2230 | |||
2231 | info: info-am | ||
2232 | |||
2233 | info-am: | ||
2234 | |||
2235 | install-data-am: install-traplibPROGRAMS | ||
2236 | |||
2237 | install-dvi: install-dvi-am | ||
2238 | |||
2239 | install-exec-am: install-libLIBRARIES | ||
2240 | |||
2241 | install-html: install-html-am | ||
2242 | |||
2243 | install-info: install-info-am | ||
2244 | |||
2245 | install-man: | ||
2246 | |||
2247 | install-pdf: install-pdf-am | ||
2248 | |||
2249 | install-ps: install-ps-am | ||
2250 | |||
2251 | installcheck-am: | ||
2252 | |||
2253 | maintainer-clean: maintainer-clean-am | ||
2254 | -rm -rf ./$(DEPDIR) | ||
2255 | -rm -f Makefile | ||
2256 | maintainer-clean-am: distclean-am maintainer-clean-generic | ||
2257 | |||
2258 | mostlyclean: mostlyclean-am | ||
2259 | |||
2260 | mostlyclean-am: mostlyclean-compile mostlyclean-generic | ||
2261 | |||
2262 | pdf: pdf-am | ||
2263 | |||
2264 | pdf-am: | ||
2265 | |||
2266 | ps: ps-am | ||
2267 | |||
2268 | ps-am: | ||
2269 | |||
2270 | uninstall-am: uninstall-libLIBRARIES uninstall-traplibPROGRAMS | ||
2271 | |||
2272 | .MAKE: install-am install-strip | ||
2273 | |||
2274 | .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ | ||
2275 | clean-libLIBRARIES clean-noinstLIBRARIES clean-traplibPROGRAMS \ | ||
2276 | ctags distclean distclean-compile distclean-generic \ | ||
2277 | distclean-tags distdir dvi dvi-am html html-am info info-am \ | ||
2278 | install install-am install-data install-data-am install-dvi \ | ||
2279 | install-dvi-am install-exec install-exec-am install-html \ | ||
2280 | install-html-am install-info install-info-am \ | ||
2281 | install-libLIBRARIES install-man install-pdf install-pdf-am \ | ||
2282 | install-ps install-ps-am install-strip install-traplibPROGRAMS \ | ||
2283 | installcheck installcheck-am installdirs maintainer-clean \ | ||
2284 | maintainer-clean-generic mostlyclean mostlyclean-compile \ | ||
2285 | mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ | ||
2286 | uninstall-am uninstall-libLIBRARIES uninstall-traplibPROGRAMS | ||
2287 | |||
2288 | # Tell versions [3.59,3.63) of GNU make to not export all variables. | ||
2289 | # Otherwise a system limit (for SysV at least) may be exceeded. | ||
2290 | .NOEXPORT: | ||
diff --git a/libraries/ode-0.9\/ode/src/array.cpp b/libraries/ode-0.9\/ode/src/array.cpp new file mode 100755 index 0000000..cbb1a6e --- /dev/null +++ b/libraries/ode-0.9\/ode/src/array.cpp | |||
@@ -0,0 +1,80 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/memory.h> | ||
25 | #include <ode/error.h> | ||
26 | #include "array.h" | ||
27 | |||
28 | |||
29 | static inline int roundUpToPowerOfTwo (int x) | ||
30 | { | ||
31 | int i = 1; | ||
32 | while (i < x) i <<= 1; | ||
33 | return i; | ||
34 | } | ||
35 | |||
36 | |||
37 | void dArrayBase::_freeAll (int sizeofT) | ||
38 | { | ||
39 | if (_data) { | ||
40 | if (_data == this+1) return; // if constructLocalArray() was called | ||
41 | dFree (_data,_anum * sizeofT); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | |||
46 | void dArrayBase::_setSize (int newsize, int sizeofT) | ||
47 | { | ||
48 | if (newsize < 0) return; | ||
49 | if (newsize > _anum) { | ||
50 | if (_data == this+1) { | ||
51 | // this is a no-no, because constructLocalArray() was called | ||
52 | dDebug (0,"setSize() out of space in LOCAL array"); | ||
53 | } | ||
54 | int newanum = roundUpToPowerOfTwo (newsize); | ||
55 | if (_data) _data = dRealloc (_data, _anum*sizeofT, newanum*sizeofT); | ||
56 | else _data = dAlloc (newanum*sizeofT); | ||
57 | _anum = newanum; | ||
58 | } | ||
59 | _size = newsize; | ||
60 | } | ||
61 | |||
62 | |||
63 | void * dArrayBase::operator new (size_t size) | ||
64 | { | ||
65 | return dAlloc (size); | ||
66 | } | ||
67 | |||
68 | |||
69 | void dArrayBase::operator delete (void *ptr, size_t size) | ||
70 | { | ||
71 | dFree (ptr,size); | ||
72 | } | ||
73 | |||
74 | |||
75 | void dArrayBase::constructLocalArray (int __anum) | ||
76 | { | ||
77 | _size = 0; | ||
78 | _anum = __anum; | ||
79 | _data = this+1; | ||
80 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/array.h b/libraries/ode-0.9\/ode/src/array.h new file mode 100755 index 0000000..307206c --- /dev/null +++ b/libraries/ode-0.9\/ode/src/array.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* this comes from the `reuse' library. copy any changes back to the source. | ||
24 | * | ||
25 | * Variable sized array template. The array is always stored in a contiguous | ||
26 | * chunk. The array can be resized. A size increase will cause more memory | ||
27 | * to be allocated, and may result in relocation of the array memory. | ||
28 | * A size decrease has no effect on the memory allocation. | ||
29 | * | ||
30 | * Array elements with constructors or destructors are not supported! | ||
31 | * But if you must have such elements, here's what to know/do: | ||
32 | * - Bitwise copy is used when copying whole arrays. | ||
33 | * - When copying individual items (via push(), insert() etc) the `=' | ||
34 | * (equals) operator is used. Thus you should define this operator to do | ||
35 | * a bitwise copy. You should probably also define the copy constructor. | ||
36 | */ | ||
37 | |||
38 | |||
39 | #ifndef _ODE_ARRAY_H_ | ||
40 | #define _ODE_ARRAY_H_ | ||
41 | |||
42 | #include <ode/config.h> | ||
43 | |||
44 | |||
45 | // this base class has no constructors or destructor, for your convenience. | ||
46 | |||
47 | class dArrayBase { | ||
48 | protected: | ||
49 | int _size; // number of elements in `data' | ||
50 | int _anum; // allocated number of elements in `data' | ||
51 | void *_data; // array data | ||
52 | |||
53 | void _freeAll (int sizeofT); | ||
54 | void _setSize (int newsize, int sizeofT); | ||
55 | // set the array size to `newsize', allocating more memory if necessary. | ||
56 | // if newsize>_anum and is a power of two then this is guaranteed to | ||
57 | // set _size and _anum to newsize. | ||
58 | |||
59 | public: | ||
60 | // not: dArrayBase () { _size=0; _anum=0; _data=0; } | ||
61 | |||
62 | int size() const { return _size; } | ||
63 | int allocatedSize() const { return _anum; } | ||
64 | void * operator new (size_t size); | ||
65 | void operator delete (void *ptr, size_t size); | ||
66 | |||
67 | void constructor() { _size=0; _anum=0; _data=0; } | ||
68 | // if this structure is allocated with malloc() instead of new, you can | ||
69 | // call this to set it up. | ||
70 | |||
71 | void constructLocalArray (int __anum); | ||
72 | // this helper function allows non-reallocating arrays to be constructed | ||
73 | // on the stack (or in the heap if necessary). this is something of a | ||
74 | // kludge and should be used with extreme care. this function acts like | ||
75 | // a constructor - it is called on uninitialized memory that will hold the | ||
76 | // Array structure and the data. __anum is the number of elements that | ||
77 | // are allocated. the memory MUST be allocated with size: | ||
78 | // sizeof(ArrayBase) + __anum*sizeof(T) | ||
79 | // arrays allocated this way will never try to reallocate or free the | ||
80 | // memory - that's your job. | ||
81 | }; | ||
82 | |||
83 | |||
84 | template <class T> class dArray : public dArrayBase { | ||
85 | public: | ||
86 | void equals (const dArray<T> &x) { | ||
87 | setSize (x.size()); | ||
88 | memcpy (_data,x._data,x._size * sizeof(T)); | ||
89 | } | ||
90 | |||
91 | dArray () { constructor(); } | ||
92 | dArray (const dArray<T> &x) { constructor(); equals (x); } | ||
93 | ~dArray () { _freeAll(sizeof(T)); } | ||
94 | void setSize (int newsize) { _setSize (newsize,sizeof(T)); } | ||
95 | T *data() const { return (T*) _data; } | ||
96 | T & operator[] (int i) const { return ((T*)_data)[i]; } | ||
97 | void operator = (const dArray<T> &x) { equals (x); } | ||
98 | |||
99 | void push (const T item) { | ||
100 | if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); | ||
101 | memcpy (&(((T*)_data)[_size-1]), &item, sizeof(T)); | ||
102 | } | ||
103 | |||
104 | void swap (dArray<T> &x) { | ||
105 | int tmp1; | ||
106 | void *tmp2; | ||
107 | tmp1=_size; _size=x._size; x._size=tmp1; | ||
108 | tmp1=_anum; _anum=x._anum; x._anum=tmp1; | ||
109 | tmp2=_data; _data=x._data; x._data=tmp2; | ||
110 | } | ||
111 | |||
112 | // insert the item at the position `i'. if i<0 then add the item to the | ||
113 | // start, if i >= size then add the item to the end of the array. | ||
114 | void insert (int i, const T item) { | ||
115 | if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); | ||
116 | if (i >= (_size-1)) i = _size-1; // add to end | ||
117 | else { | ||
118 | if (i < 0) i=0; // add to start | ||
119 | int n = _size-1-i; | ||
120 | if (n>0) memmove (((T*)_data) + i+1, ((T*)_data) + i, n*sizeof(T)); | ||
121 | } | ||
122 | ((T*)_data)[i] = item; | ||
123 | } | ||
124 | |||
125 | void remove (int i) { | ||
126 | if (i >= 0 && i < _size) { // passing this test guarantees size>0 | ||
127 | int n = _size-1-i; | ||
128 | if (n>0) memmove (((T*)_data) + i, ((T*)_data) + i+1, n*sizeof(T)); | ||
129 | _size--; | ||
130 | } | ||
131 | } | ||
132 | }; | ||
133 | |||
134 | |||
135 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/box.cpp b/libraries/ode-0.9\/ode/src/box.cpp new file mode 100755 index 0000000..f328651 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/box.cpp | |||
@@ -0,0 +1,847 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | //**************************************************************************** | ||
46 | // box public API | ||
47 | |||
48 | dxBox::dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz) : dxGeom (space,1) | ||
49 | { | ||
50 | dAASSERT (lx >= 0 && ly >= 0 && lz >= 0); | ||
51 | type = dBoxClass; | ||
52 | side[0] = lx; | ||
53 | side[1] = ly; | ||
54 | side[2] = lz; | ||
55 | } | ||
56 | |||
57 | |||
58 | void dxBox::computeAABB() | ||
59 | { | ||
60 | const dMatrix3& R = final_posr->R; | ||
61 | const dVector3& pos = final_posr->pos; | ||
62 | |||
63 | dReal xrange = REAL(0.5) * (dFabs (R[0] * side[0]) + | ||
64 | dFabs (R[1] * side[1]) + dFabs (R[2] * side[2])); | ||
65 | dReal yrange = REAL(0.5) * (dFabs (R[4] * side[0]) + | ||
66 | dFabs (R[5] * side[1]) + dFabs (R[6] * side[2])); | ||
67 | dReal zrange = REAL(0.5) * (dFabs (R[8] * side[0]) + | ||
68 | dFabs (R[9] * side[1]) + dFabs (R[10] * side[2])); | ||
69 | aabb[0] = pos[0] - xrange; | ||
70 | aabb[1] = pos[0] + xrange; | ||
71 | aabb[2] = pos[1] - yrange; | ||
72 | aabb[3] = pos[1] + yrange; | ||
73 | aabb[4] = pos[2] - zrange; | ||
74 | aabb[5] = pos[2] + zrange; | ||
75 | } | ||
76 | |||
77 | |||
78 | dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz) | ||
79 | { | ||
80 | return new dxBox (space,lx,ly,lz); | ||
81 | } | ||
82 | |||
83 | |||
84 | void dGeomBoxSetLengths (dGeomID g, dReal lx, dReal ly, dReal lz) | ||
85 | { | ||
86 | dUASSERT (g && g->type == dBoxClass,"argument not a box"); | ||
87 | dAASSERT (lx > 0 && ly > 0 && lz > 0); | ||
88 | dxBox *b = (dxBox*) g; | ||
89 | b->side[0] = lx; | ||
90 | b->side[1] = ly; | ||
91 | b->side[2] = lz; | ||
92 | dGeomMoved (g); | ||
93 | } | ||
94 | |||
95 | |||
96 | void dGeomBoxGetLengths (dGeomID g, dVector3 result) | ||
97 | { | ||
98 | dUASSERT (g && g->type == dBoxClass,"argument not a box"); | ||
99 | dxBox *b = (dxBox*) g; | ||
100 | result[0] = b->side[0]; | ||
101 | result[1] = b->side[1]; | ||
102 | result[2] = b->side[2]; | ||
103 | } | ||
104 | |||
105 | |||
106 | dReal dGeomBoxPointDepth (dGeomID g, dReal x, dReal y, dReal z) | ||
107 | { | ||
108 | dUASSERT (g && g->type == dBoxClass,"argument not a box"); | ||
109 | g->recomputePosr(); | ||
110 | dxBox *b = (dxBox*) g; | ||
111 | |||
112 | // Set p = (x,y,z) relative to box center | ||
113 | // | ||
114 | // This will be (0,0,0) if the point is at (side[0]/2,side[1]/2,side[2]/2) | ||
115 | |||
116 | dVector3 p,q; | ||
117 | |||
118 | p[0] = x - b->final_posr->pos[0]; | ||
119 | p[1] = y - b->final_posr->pos[1]; | ||
120 | p[2] = z - b->final_posr->pos[2]; | ||
121 | |||
122 | // Rotate p into box's coordinate frame, so we can | ||
123 | // treat the OBB as an AABB | ||
124 | |||
125 | dMULTIPLY1_331 (q,b->final_posr->R,p); | ||
126 | |||
127 | // Record distance from point to each successive box side, and see | ||
128 | // if the point is inside all six sides | ||
129 | |||
130 | dReal dist[6]; | ||
131 | int i; | ||
132 | |||
133 | bool inside = true; | ||
134 | |||
135 | for (i=0; i < 3; i++) { | ||
136 | dReal side = b->side[i] * REAL(0.5); | ||
137 | |||
138 | dist[i ] = side - q[i]; | ||
139 | dist[i+3] = side + q[i]; | ||
140 | |||
141 | if ((dist[i] < 0) || (dist[i+3] < 0)) { | ||
142 | inside = false; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | // If point is inside the box, the depth is the smallest positive distance | ||
147 | // to any side | ||
148 | |||
149 | if (inside) { | ||
150 | dReal smallest_dist = (dReal) (unsigned) -1; | ||
151 | |||
152 | for (i=0; i < 6; i++) { | ||
153 | if (dist[i] < smallest_dist) smallest_dist = dist[i]; | ||
154 | } | ||
155 | |||
156 | return smallest_dist; | ||
157 | } | ||
158 | |||
159 | // Otherwise, if point is outside the box, the depth is the largest | ||
160 | // distance to any side. This is an approximation to the 'proper' | ||
161 | // solution (the proper solution may be larger in some cases). | ||
162 | |||
163 | dReal largest_dist = 0; | ||
164 | |||
165 | for (i=0; i < 6; i++) { | ||
166 | if (dist[i] > largest_dist) largest_dist = dist[i]; | ||
167 | } | ||
168 | |||
169 | return -largest_dist; | ||
170 | } | ||
171 | |||
172 | //**************************************************************************** | ||
173 | // box-box collision utility | ||
174 | |||
175 | |||
176 | // find all the intersection points between the 2D rectangle with vertices | ||
177 | // at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]), | ||
178 | // (p[2],p[3]),(p[4],p[5]),(p[6],p[7]). | ||
179 | // | ||
180 | // the intersection points are returned as x,y pairs in the 'ret' array. | ||
181 | // the number of intersection points is returned by the function (this will | ||
182 | // be in the range 0 to 8). | ||
183 | |||
184 | static int intersectRectQuad (dReal h[2], dReal p[8], dReal ret[16]) | ||
185 | { | ||
186 | // q (and r) contain nq (and nr) coordinate points for the current (and | ||
187 | // chopped) polygons | ||
188 | int nq=4,nr; | ||
189 | dReal buffer[16]; | ||
190 | dReal *q = p; | ||
191 | dReal *r = ret; | ||
192 | for (int dir=0; dir <= 1; dir++) { | ||
193 | // direction notation: xy[0] = x axis, xy[1] = y axis | ||
194 | for (int sign=-1; sign <= 1; sign += 2) { | ||
195 | // chop q along the line xy[dir] = sign*h[dir] | ||
196 | dReal *pq = q; | ||
197 | dReal *pr = r; | ||
198 | nr = 0; | ||
199 | for (int i=nq; i > 0; i--) { | ||
200 | // go through all points in q and all lines between adjacent points | ||
201 | if (sign*pq[dir] < h[dir]) { | ||
202 | // this point is inside the chopping line | ||
203 | pr[0] = pq[0]; | ||
204 | pr[1] = pq[1]; | ||
205 | pr += 2; | ||
206 | nr++; | ||
207 | if (nr & 8) { | ||
208 | q = r; | ||
209 | goto done; | ||
210 | } | ||
211 | } | ||
212 | dReal *nextq = (i > 1) ? pq+2 : q; | ||
213 | if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) { | ||
214 | // this line crosses the chopping line | ||
215 | pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) / | ||
216 | (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]); | ||
217 | pr[dir] = sign*h[dir]; | ||
218 | pr += 2; | ||
219 | nr++; | ||
220 | if (nr & 8) { | ||
221 | q = r; | ||
222 | goto done; | ||
223 | } | ||
224 | } | ||
225 | pq += 2; | ||
226 | } | ||
227 | q = r; | ||
228 | r = (q==ret) ? buffer : ret; | ||
229 | nq = nr; | ||
230 | } | ||
231 | } | ||
232 | done: | ||
233 | if (q != ret) memcpy (ret,q,nr*2*sizeof(dReal)); | ||
234 | return nr; | ||
235 | } | ||
236 | |||
237 | |||
238 | // given n points in the plane (array p, of size 2*n), generate m points that | ||
239 | // best represent the whole set. the definition of 'best' here is not | ||
240 | // predetermined - the idea is to select points that give good box-box | ||
241 | // collision detection behavior. the chosen point indexes are returned in the | ||
242 | // array iret (of size m). 'i0' is always the first entry in the array. | ||
243 | // n must be in the range [1..8]. m must be in the range [1..n]. i0 must be | ||
244 | // in the range [0..n-1]. | ||
245 | |||
246 | void cullPoints (int n, dReal p[], int m, int i0, int iret[]) | ||
247 | { | ||
248 | // compute the centroid of the polygon in cx,cy | ||
249 | int i,j; | ||
250 | dReal a,cx,cy,q; | ||
251 | if (n==1) { | ||
252 | cx = p[0]; | ||
253 | cy = p[1]; | ||
254 | } | ||
255 | else if (n==2) { | ||
256 | cx = REAL(0.5)*(p[0] + p[2]); | ||
257 | cy = REAL(0.5)*(p[1] + p[3]); | ||
258 | } | ||
259 | else { | ||
260 | a = 0; | ||
261 | cx = 0; | ||
262 | cy = 0; | ||
263 | for (i=0; i<(n-1); i++) { | ||
264 | q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1]; | ||
265 | a += q; | ||
266 | cx += q*(p[i*2]+p[i*2+2]); | ||
267 | cy += q*(p[i*2+1]+p[i*2+3]); | ||
268 | } | ||
269 | q = p[n*2-2]*p[1] - p[0]*p[n*2-1]; | ||
270 | a = dRecip(REAL(3.0)*(a+q)); | ||
271 | cx = a*(cx + q*(p[n*2-2]+p[0])); | ||
272 | cy = a*(cy + q*(p[n*2-1]+p[1])); | ||
273 | } | ||
274 | |||
275 | // compute the angle of each point w.r.t. the centroid | ||
276 | dReal A[8]; | ||
277 | for (i=0; i<n; i++) A[i] = dAtan2(p[i*2+1]-cy,p[i*2]-cx); | ||
278 | |||
279 | // search for points that have angles closest to A[i0] + i*(2*pi/m). | ||
280 | int avail[8]; | ||
281 | for (i=0; i<n; i++) avail[i] = 1; | ||
282 | avail[i0] = 0; | ||
283 | iret[0] = i0; | ||
284 | iret++; | ||
285 | for (j=1; j<m; j++) { | ||
286 | a = dReal(j)*(2*M_PI/m) + A[i0]; | ||
287 | if (a > M_PI) a -= 2*M_PI; | ||
288 | dReal maxdiff=1e9,diff; | ||
289 | #ifndef dNODEBUG | ||
290 | *iret = i0; // iret is not allowed to keep this value | ||
291 | #endif | ||
292 | for (i=0; i<n; i++) { | ||
293 | if (avail[i]) { | ||
294 | diff = dFabs (A[i]-a); | ||
295 | if (diff > M_PI) diff = 2*M_PI - diff; | ||
296 | if (diff < maxdiff) { | ||
297 | maxdiff = diff; | ||
298 | *iret = i; | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | #ifndef dNODEBUG | ||
303 | dIASSERT (*iret != i0); // ensure iret got set | ||
304 | #endif | ||
305 | avail[*iret] = 0; | ||
306 | iret++; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | |||
311 | // given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and | ||
312 | // generate contact points. this returns 0 if there is no contact otherwise | ||
313 | // it returns the number of contacts generated. | ||
314 | // `normal' returns the contact normal. | ||
315 | // `depth' returns the maximum penetration depth along that normal. | ||
316 | // `return_code' returns a number indicating the type of contact that was | ||
317 | // detected: | ||
318 | // 1,2,3 = box 2 intersects with a face of box 1 | ||
319 | // 4,5,6 = box 1 intersects with a face of box 2 | ||
320 | // 7..15 = edge-edge contact | ||
321 | // `maxc' is the maximum number of contacts allowed to be generated, i.e. | ||
322 | // the size of the `contact' array. | ||
323 | // `contact' and `skip' are the contact array information provided to the | ||
324 | // collision functions. this function only fills in the position and depth | ||
325 | // fields. | ||
326 | |||
327 | |||
328 | int dBoxBox (const dVector3 p1, const dMatrix3 R1, | ||
329 | const dVector3 side1, const dVector3 p2, | ||
330 | const dMatrix3 R2, const dVector3 side2, | ||
331 | dVector3 normal, dReal *depth, int *return_code, | ||
332 | int flags, dContactGeom *contact, int skip) | ||
333 | { | ||
334 | const dReal fudge_factor = REAL(1.05); | ||
335 | dVector3 p,pp,normalC; | ||
336 | const dReal *normalR = 0; | ||
337 | dReal A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33, | ||
338 | Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l,expr1_val; | ||
339 | int i,j,invert_normal,code; | ||
340 | |||
341 | // get vector from centers of box 1 to box 2, relative to box 1 | ||
342 | p[0] = p2[0] - p1[0]; | ||
343 | p[1] = p2[1] - p1[1]; | ||
344 | p[2] = p2[2] - p1[2]; | ||
345 | dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 | ||
346 | |||
347 | // get side lengths / 2 | ||
348 | A[0] = side1[0]*REAL(0.5); | ||
349 | A[1] = side1[1]*REAL(0.5); | ||
350 | A[2] = side1[2]*REAL(0.5); | ||
351 | B[0] = side2[0]*REAL(0.5); | ||
352 | B[1] = side2[1]*REAL(0.5); | ||
353 | B[2] = side2[2]*REAL(0.5); | ||
354 | |||
355 | // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 | ||
356 | R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); | ||
357 | R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); | ||
358 | R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); | ||
359 | |||
360 | Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); | ||
361 | Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); | ||
362 | Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); | ||
363 | |||
364 | // for all 15 possible separating axes: | ||
365 | // * see if the axis separates the boxes. if so, return 0. | ||
366 | // * find the depth of the penetration along the separating axis (s2) | ||
367 | // * if this is the largest depth so far, record it. | ||
368 | // the normal vector will be set to the separating axis with the smallest | ||
369 | // depth. note: normalR is set to point to a column of R1 or R2 if that is | ||
370 | // the smallest depth normal so far. otherwise normalR is 0 and normalC is | ||
371 | // set to a vector relative to body 1. invert_normal is 1 if the sign of | ||
372 | // the normal should be flipped. | ||
373 | |||
374 | do { | ||
375 | #define TST(expr1,expr2,norm,cc) \ | ||
376 | expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \ | ||
377 | s2 = dFabs(expr1_val) - (expr2); \ | ||
378 | if (s2 > 0) return 0; \ | ||
379 | if (s2 > s) { \ | ||
380 | s = s2; \ | ||
381 | normalR = norm; \ | ||
382 | invert_normal = ((expr1_val) < 0); \ | ||
383 | code = (cc); \ | ||
384 | if (flags & CONTACTS_UNIMPORTANT) break; \ | ||
385 | } | ||
386 | |||
387 | s = -dInfinity; | ||
388 | invert_normal = 0; | ||
389 | code = 0; | ||
390 | |||
391 | // separating axis = u1,u2,u3 | ||
392 | TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1); | ||
393 | TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2); | ||
394 | TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3); | ||
395 | |||
396 | // separating axis = v1,v2,v3 | ||
397 | TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4); | ||
398 | TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5); | ||
399 | TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6); | ||
400 | |||
401 | // note: cross product axes need to be scaled when s is computed. | ||
402 | // normal (n1,n2,n3) is relative to box 1. | ||
403 | #undef TST | ||
404 | #define TST(expr1,expr2,n1,n2,n3,cc) \ | ||
405 | expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \ | ||
406 | s2 = dFabs(expr1_val) - (expr2); \ | ||
407 | if (s2 > 0) return 0; \ | ||
408 | l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ | ||
409 | if (l > 0) { \ | ||
410 | s2 /= l; \ | ||
411 | if (s2*fudge_factor > s) { \ | ||
412 | s = s2; \ | ||
413 | normalR = 0; \ | ||
414 | normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ | ||
415 | invert_normal = ((expr1_val) < 0); \ | ||
416 | code = (cc); \ | ||
417 | if (flags & CONTACTS_UNIMPORTANT) break; \ | ||
418 | } \ | ||
419 | } | ||
420 | |||
421 | // separating axis = u1 x (v1,v2,v3) | ||
422 | TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7); | ||
423 | TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8); | ||
424 | TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9); | ||
425 | |||
426 | // separating axis = u2 x (v1,v2,v3) | ||
427 | TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10); | ||
428 | TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11); | ||
429 | TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12); | ||
430 | |||
431 | // separating axis = u3 x (v1,v2,v3) | ||
432 | TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13); | ||
433 | TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14); | ||
434 | TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15); | ||
435 | #undef TST | ||
436 | } while (0); | ||
437 | |||
438 | if (!code) return 0; | ||
439 | |||
440 | // if we get to this point, the boxes interpenetrate. compute the normal | ||
441 | // in global coordinates. | ||
442 | if (normalR) { | ||
443 | normal[0] = normalR[0]; | ||
444 | normal[1] = normalR[4]; | ||
445 | normal[2] = normalR[8]; | ||
446 | } | ||
447 | else { | ||
448 | dMULTIPLY0_331 (normal,R1,normalC); | ||
449 | } | ||
450 | if (invert_normal) { | ||
451 | normal[0] = -normal[0]; | ||
452 | normal[1] = -normal[1]; | ||
453 | normal[2] = -normal[2]; | ||
454 | } | ||
455 | *depth = -s; | ||
456 | |||
457 | // compute contact point(s) | ||
458 | |||
459 | if (code > 6) { | ||
460 | // an edge from box 1 touches an edge from box 2. | ||
461 | // find a point pa on the intersecting edge of box 1 | ||
462 | dVector3 pa; | ||
463 | dReal sign; | ||
464 | for (i=0; i<3; i++) pa[i] = p1[i]; | ||
465 | for (j=0; j<3; j++) { | ||
466 | sign = (dDOT14(normal,R1+j) > 0) ? REAL(1.0) : REAL(-1.0); | ||
467 | for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j]; | ||
468 | } | ||
469 | |||
470 | // find a point pb on the intersecting edge of box 2 | ||
471 | dVector3 pb; | ||
472 | for (i=0; i<3; i++) pb[i] = p2[i]; | ||
473 | for (j=0; j<3; j++) { | ||
474 | sign = (dDOT14(normal,R2+j) > 0) ? REAL(-1.0) : REAL(1.0); | ||
475 | for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j]; | ||
476 | } | ||
477 | |||
478 | dReal alpha,beta; | ||
479 | dVector3 ua,ub; | ||
480 | for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4]; | ||
481 | for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4]; | ||
482 | |||
483 | dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta); | ||
484 | for (i=0; i<3; i++) pa[i] += ua[i]*alpha; | ||
485 | for (i=0; i<3; i++) pb[i] += ub[i]*beta; | ||
486 | |||
487 | for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); | ||
488 | contact[0].depth = *depth; | ||
489 | *return_code = code; | ||
490 | return 1; | ||
491 | } | ||
492 | |||
493 | // okay, we have a face-something intersection (because the separating | ||
494 | // axis is perpendicular to a face). define face 'a' to be the reference | ||
495 | // face (i.e. the normal vector is perpendicular to this) and face 'b' to be | ||
496 | // the incident face (the closest face of the other box). | ||
497 | |||
498 | const dReal *Ra,*Rb,*pa,*pb,*Sa,*Sb; | ||
499 | if (code <= 3) { | ||
500 | Ra = R1; | ||
501 | Rb = R2; | ||
502 | pa = p1; | ||
503 | pb = p2; | ||
504 | Sa = A; | ||
505 | Sb = B; | ||
506 | } | ||
507 | else { | ||
508 | Ra = R2; | ||
509 | Rb = R1; | ||
510 | pa = p2; | ||
511 | pb = p1; | ||
512 | Sa = B; | ||
513 | Sb = A; | ||
514 | } | ||
515 | |||
516 | // nr = normal vector of reference face dotted with axes of incident box. | ||
517 | // anr = absolute values of nr. | ||
518 | dVector3 normal2,nr,anr; | ||
519 | if (code <= 3) { | ||
520 | normal2[0] = normal[0]; | ||
521 | normal2[1] = normal[1]; | ||
522 | normal2[2] = normal[2]; | ||
523 | } | ||
524 | else { | ||
525 | normal2[0] = -normal[0]; | ||
526 | normal2[1] = -normal[1]; | ||
527 | normal2[2] = -normal[2]; | ||
528 | } | ||
529 | dMULTIPLY1_331 (nr,Rb,normal2); | ||
530 | anr[0] = dFabs (nr[0]); | ||
531 | anr[1] = dFabs (nr[1]); | ||
532 | anr[2] = dFabs (nr[2]); | ||
533 | |||
534 | // find the largest compontent of anr: this corresponds to the normal | ||
535 | // for the indident face. the other axis numbers of the indicent face | ||
536 | // are stored in a1,a2. | ||
537 | int lanr,a1,a2; | ||
538 | if (anr[1] > anr[0]) { | ||
539 | if (anr[1] > anr[2]) { | ||
540 | a1 = 0; | ||
541 | lanr = 1; | ||
542 | a2 = 2; | ||
543 | } | ||
544 | else { | ||
545 | a1 = 0; | ||
546 | a2 = 1; | ||
547 | lanr = 2; | ||
548 | } | ||
549 | } | ||
550 | else { | ||
551 | if (anr[0] > anr[2]) { | ||
552 | lanr = 0; | ||
553 | a1 = 1; | ||
554 | a2 = 2; | ||
555 | } | ||
556 | else { | ||
557 | a1 = 0; | ||
558 | a2 = 1; | ||
559 | lanr = 2; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | // compute center point of incident face, in reference-face coordinates | ||
564 | dVector3 center; | ||
565 | if (nr[lanr] < 0) { | ||
566 | for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr]; | ||
567 | } | ||
568 | else { | ||
569 | for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr]; | ||
570 | } | ||
571 | |||
572 | // find the normal and non-normal axis numbers of the reference box | ||
573 | int codeN,code1,code2; | ||
574 | if (code <= 3) codeN = code-1; else codeN = code-4; | ||
575 | if (codeN==0) { | ||
576 | code1 = 1; | ||
577 | code2 = 2; | ||
578 | } | ||
579 | else if (codeN==1) { | ||
580 | code1 = 0; | ||
581 | code2 = 2; | ||
582 | } | ||
583 | else { | ||
584 | code1 = 0; | ||
585 | code2 = 1; | ||
586 | } | ||
587 | |||
588 | // find the four corners of the incident face, in reference-face coordinates | ||
589 | dReal quad[8]; // 2D coordinate of incident face (x,y pairs) | ||
590 | dReal c1,c2,m11,m12,m21,m22; | ||
591 | c1 = dDOT14 (center,Ra+code1); | ||
592 | c2 = dDOT14 (center,Ra+code2); | ||
593 | // optimize this? - we have already computed this data above, but it is not | ||
594 | // stored in an easy-to-index format. for now it's quicker just to recompute | ||
595 | // the four dot products. | ||
596 | m11 = dDOT44 (Ra+code1,Rb+a1); | ||
597 | m12 = dDOT44 (Ra+code1,Rb+a2); | ||
598 | m21 = dDOT44 (Ra+code2,Rb+a1); | ||
599 | m22 = dDOT44 (Ra+code2,Rb+a2); | ||
600 | { | ||
601 | dReal k1 = m11*Sb[a1]; | ||
602 | dReal k2 = m21*Sb[a1]; | ||
603 | dReal k3 = m12*Sb[a2]; | ||
604 | dReal k4 = m22*Sb[a2]; | ||
605 | quad[0] = c1 - k1 - k3; | ||
606 | quad[1] = c2 - k2 - k4; | ||
607 | quad[2] = c1 - k1 + k3; | ||
608 | quad[3] = c2 - k2 + k4; | ||
609 | quad[4] = c1 + k1 + k3; | ||
610 | quad[5] = c2 + k2 + k4; | ||
611 | quad[6] = c1 + k1 - k3; | ||
612 | quad[7] = c2 + k2 - k4; | ||
613 | } | ||
614 | |||
615 | // find the size of the reference face | ||
616 | dReal rect[2]; | ||
617 | rect[0] = Sa[code1]; | ||
618 | rect[1] = Sa[code2]; | ||
619 | |||
620 | // intersect the incident and reference faces | ||
621 | dReal ret[16]; | ||
622 | int n = intersectRectQuad (rect,quad,ret); | ||
623 | if (n < 1) return 0; // this should never happen | ||
624 | |||
625 | // convert the intersection points into reference-face coordinates, | ||
626 | // and compute the contact position and depth for each point. only keep | ||
627 | // those points that have a positive (penetrating) depth. delete points in | ||
628 | // the 'ret' array as necessary so that 'point' and 'ret' correspond. | ||
629 | dReal point[3*8]; // penetrating contact points | ||
630 | dReal dep[8]; // depths for those points | ||
631 | dReal det1 = dRecip(m11*m22 - m12*m21); | ||
632 | m11 *= det1; | ||
633 | m12 *= det1; | ||
634 | m21 *= det1; | ||
635 | m22 *= det1; | ||
636 | int cnum = 0; // number of penetrating contact points found | ||
637 | for (j=0; j < n; j++) { | ||
638 | dReal k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2); | ||
639 | dReal k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2); | ||
640 | for (i=0; i<3; i++) point[cnum*3+i] = | ||
641 | center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2]; | ||
642 | dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3); | ||
643 | if (dep[cnum] >= 0) { | ||
644 | ret[cnum*2] = ret[j*2]; | ||
645 | ret[cnum*2+1] = ret[j*2+1]; | ||
646 | cnum++; | ||
647 | if ((cnum | CONTACTS_UNIMPORTANT) == (flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
648 | break; | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | if (cnum < 1) { | ||
653 | return 0; // this should not happen, yet does at times (demo_plane2d single precision). | ||
654 | } | ||
655 | |||
656 | // we can't generate more contacts than we actually have | ||
657 | int maxc = flags & NUMC_MASK; | ||
658 | if (maxc > cnum) maxc = cnum; | ||
659 | if (maxc < 1) maxc = 1; // Even though max count must not be zero this check is kept for backward compatibility as this is a public function | ||
660 | |||
661 | if (cnum <= maxc) { | ||
662 | // we have less contacts than we need, so we use them all | ||
663 | for (j=0; j < cnum; j++) { | ||
664 | dContactGeom *con = CONTACT(contact,skip*j); | ||
665 | for (i=0; i<3; i++) con->pos[i] = point[j*3+i] + pa[i]; | ||
666 | con->depth = dep[j]; | ||
667 | } | ||
668 | } | ||
669 | else { | ||
670 | dIASSERT(!(flags & CONTACTS_UNIMPORTANT)); // cnum should be generated not greater than maxc so that "then" clause is executed | ||
671 | // we have more contacts than are wanted, some of them must be culled. | ||
672 | // find the deepest point, it is always the first contact. | ||
673 | int i1 = 0; | ||
674 | dReal maxdepth = dep[0]; | ||
675 | for (i=1; i<cnum; i++) { | ||
676 | if (dep[i] > maxdepth) { | ||
677 | maxdepth = dep[i]; | ||
678 | i1 = i; | ||
679 | } | ||
680 | } | ||
681 | |||
682 | int iret[8]; | ||
683 | cullPoints (cnum,ret,maxc,i1,iret); | ||
684 | |||
685 | for (j=0; j < maxc; j++) { | ||
686 | dContactGeom *con = CONTACT(contact,skip*j); | ||
687 | for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i]; | ||
688 | con->depth = dep[iret[j]]; | ||
689 | } | ||
690 | cnum = maxc; | ||
691 | } | ||
692 | |||
693 | *return_code = code; | ||
694 | return cnum; | ||
695 | } | ||
696 | |||
697 | |||
698 | |||
699 | int dCollideBoxBox (dxGeom *o1, dxGeom *o2, int flags, | ||
700 | dContactGeom *contact, int skip) | ||
701 | { | ||
702 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
703 | dIASSERT (o1->type == dBoxClass); | ||
704 | dIASSERT (o2->type == dBoxClass); | ||
705 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
706 | |||
707 | dVector3 normal; | ||
708 | dReal depth; | ||
709 | int code; | ||
710 | dxBox *b1 = (dxBox*) o1; | ||
711 | dxBox *b2 = (dxBox*) o2; | ||
712 | int num = dBoxBox (o1->final_posr->pos,o1->final_posr->R,b1->side, o2->final_posr->pos,o2->final_posr->R,b2->side, | ||
713 | normal,&depth,&code,flags,contact,skip); | ||
714 | for (int i=0; i<num; i++) { | ||
715 | CONTACT(contact,i*skip)->normal[0] = -normal[0]; | ||
716 | CONTACT(contact,i*skip)->normal[1] = -normal[1]; | ||
717 | CONTACT(contact,i*skip)->normal[2] = -normal[2]; | ||
718 | CONTACT(contact,i*skip)->g1 = o1; | ||
719 | CONTACT(contact,i*skip)->g2 = o2; | ||
720 | } | ||
721 | return num; | ||
722 | } | ||
723 | |||
724 | |||
725 | int dCollideBoxPlane (dxGeom *o1, dxGeom *o2, | ||
726 | int flags, dContactGeom *contact, int skip) | ||
727 | { | ||
728 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
729 | dIASSERT (o1->type == dBoxClass); | ||
730 | dIASSERT (o2->type == dPlaneClass); | ||
731 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
732 | |||
733 | dxBox *box = (dxBox*) o1; | ||
734 | dxPlane *plane = (dxPlane*) o2; | ||
735 | |||
736 | contact->g1 = o1; | ||
737 | contact->g2 = o2; | ||
738 | int ret = 0; | ||
739 | |||
740 | //@@@ problem: using 4-vector (plane->p) as 3-vector (normal). | ||
741 | const dReal *R = o1->final_posr->R; // rotation of box | ||
742 | const dReal *n = plane->p; // normal vector | ||
743 | |||
744 | // project sides lengths along normal vector, get absolute values | ||
745 | dReal Q1 = dDOT14(n,R+0); | ||
746 | dReal Q2 = dDOT14(n,R+1); | ||
747 | dReal Q3 = dDOT14(n,R+2); | ||
748 | dReal A1 = box->side[0] * Q1; | ||
749 | dReal A2 = box->side[1] * Q2; | ||
750 | dReal A3 = box->side[2] * Q3; | ||
751 | dReal B1 = dFabs(A1); | ||
752 | dReal B2 = dFabs(A2); | ||
753 | dReal B3 = dFabs(A3); | ||
754 | |||
755 | // early exit test | ||
756 | dReal depth = plane->p[3] + REAL(0.5)*(B1+B2+B3) - dDOT(n,o1->final_posr->pos); | ||
757 | if (depth < 0) return 0; | ||
758 | |||
759 | // find number of contacts requested | ||
760 | int maxc = flags & NUMC_MASK; | ||
761 | // if (maxc < 1) maxc = 1; // an assertion is made on entry | ||
762 | if (maxc > 3) maxc = 3; // not more than 3 contacts per box allowed | ||
763 | |||
764 | // find deepest point | ||
765 | dVector3 p; | ||
766 | p[0] = o1->final_posr->pos[0]; | ||
767 | p[1] = o1->final_posr->pos[1]; | ||
768 | p[2] = o1->final_posr->pos[2]; | ||
769 | #define FOO(i,op) \ | ||
770 | p[0] op REAL(0.5)*box->side[i] * R[0+i]; \ | ||
771 | p[1] op REAL(0.5)*box->side[i] * R[4+i]; \ | ||
772 | p[2] op REAL(0.5)*box->side[i] * R[8+i]; | ||
773 | #define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) } | ||
774 | BAR(0,1); | ||
775 | BAR(1,2); | ||
776 | BAR(2,3); | ||
777 | #undef FOO | ||
778 | #undef BAR | ||
779 | |||
780 | // the deepest point is the first contact point | ||
781 | contact->pos[0] = p[0]; | ||
782 | contact->pos[1] = p[1]; | ||
783 | contact->pos[2] = p[2]; | ||
784 | contact->normal[0] = n[0]; | ||
785 | contact->normal[1] = n[1]; | ||
786 | contact->normal[2] = n[2]; | ||
787 | contact->depth = depth; | ||
788 | ret = 1; // ret is number of contact points found so far | ||
789 | if (maxc == 1) goto done; | ||
790 | |||
791 | // get the second and third contact points by starting from `p' and going | ||
792 | // along the two sides with the smallest projected length. | ||
793 | |||
794 | #define FOO(i,j,op) \ | ||
795 | CONTACT(contact,i*skip)->pos[0] = p[0] op box->side[j] * R[0+j]; \ | ||
796 | CONTACT(contact,i*skip)->pos[1] = p[1] op box->side[j] * R[4+j]; \ | ||
797 | CONTACT(contact,i*skip)->pos[2] = p[2] op box->side[j] * R[8+j]; | ||
798 | #define BAR(ctact,side,sideinc) \ | ||
799 | depth -= B ## sideinc; \ | ||
800 | if (depth < 0) goto done; \ | ||
801 | if (A ## sideinc > 0) { FOO(ctact,side,+); } else { FOO(ctact,side,-); } \ | ||
802 | CONTACT(contact,ctact*skip)->depth = depth; \ | ||
803 | ret++; | ||
804 | |||
805 | CONTACT(contact,skip)->normal[0] = n[0]; | ||
806 | CONTACT(contact,skip)->normal[1] = n[1]; | ||
807 | CONTACT(contact,skip)->normal[2] = n[2]; | ||
808 | if (maxc == 3) { | ||
809 | CONTACT(contact,2*skip)->normal[0] = n[0]; | ||
810 | CONTACT(contact,2*skip)->normal[1] = n[1]; | ||
811 | CONTACT(contact,2*skip)->normal[2] = n[2]; | ||
812 | } | ||
813 | |||
814 | if (B1 < B2) { | ||
815 | if (B3 < B1) goto use_side_3; else { | ||
816 | BAR(1,0,1); // use side 1 | ||
817 | if (maxc == 2) goto done; | ||
818 | if (B2 < B3) goto contact2_2; else goto contact2_3; | ||
819 | } | ||
820 | } | ||
821 | else { | ||
822 | if (B3 < B2) { | ||
823 | use_side_3: // use side 3 | ||
824 | BAR(1,2,3); | ||
825 | if (maxc == 2) goto done; | ||
826 | if (B1 < B2) goto contact2_1; else goto contact2_2; | ||
827 | } | ||
828 | else { | ||
829 | BAR(1,1,2); // use side 2 | ||
830 | if (maxc == 2) goto done; | ||
831 | if (B1 < B3) goto contact2_1; else goto contact2_3; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | contact2_1: BAR(2,0,1); goto done; | ||
836 | contact2_2: BAR(2,1,2); goto done; | ||
837 | contact2_3: BAR(2,2,3); goto done; | ||
838 | #undef FOO | ||
839 | #undef BAR | ||
840 | |||
841 | done: | ||
842 | for (int i=0; i<ret; i++) { | ||
843 | CONTACT(contact,i*skip)->g1 = o1; | ||
844 | CONTACT(contact,i*skip)->g2 = o2; | ||
845 | } | ||
846 | return ret; | ||
847 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/capsule.cpp b/libraries/ode-0.9\/ode/src/capsule.cpp new file mode 100755 index 0000000..5680baa --- /dev/null +++ b/libraries/ode-0.9\/ode/src/capsule.cpp | |||
@@ -0,0 +1,369 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | //**************************************************************************** | ||
46 | // capped cylinder public API | ||
47 | |||
48 | dxCapsule::dxCapsule (dSpaceID space, dReal _radius, dReal _length) : | ||
49 | dxGeom (space,1) | ||
50 | { | ||
51 | dAASSERT (_radius > 0 && _length > 0); | ||
52 | type = dCapsuleClass; | ||
53 | radius = _radius; | ||
54 | lz = _length; | ||
55 | } | ||
56 | |||
57 | |||
58 | void dxCapsule::computeAABB() | ||
59 | { | ||
60 | const dMatrix3& R = final_posr->R; | ||
61 | const dVector3& pos = final_posr->pos; | ||
62 | |||
63 | dReal xrange = dFabs(R[2] * lz) * REAL(0.5) + radius; | ||
64 | dReal yrange = dFabs(R[6] * lz) * REAL(0.5) + radius; | ||
65 | dReal zrange = dFabs(R[10] * lz) * REAL(0.5) + radius; | ||
66 | aabb[0] = pos[0] - xrange; | ||
67 | aabb[1] = pos[0] + xrange; | ||
68 | aabb[2] = pos[1] - yrange; | ||
69 | aabb[3] = pos[1] + yrange; | ||
70 | aabb[4] = pos[2] - zrange; | ||
71 | aabb[5] = pos[2] + zrange; | ||
72 | } | ||
73 | |||
74 | |||
75 | dGeomID dCreateCapsule (dSpaceID space, dReal radius, dReal length) | ||
76 | { | ||
77 | return new dxCapsule (space,radius,length); | ||
78 | } | ||
79 | |||
80 | |||
81 | void dGeomCapsuleSetParams (dGeomID g, dReal radius, dReal length) | ||
82 | { | ||
83 | dUASSERT (g && g->type == dCapsuleClass,"argument not a ccylinder"); | ||
84 | dAASSERT (radius > 0 && length > 0); | ||
85 | dxCapsule *c = (dxCapsule*) g; | ||
86 | c->radius = radius; | ||
87 | c->lz = length; | ||
88 | dGeomMoved (g); | ||
89 | } | ||
90 | |||
91 | |||
92 | void dGeomCapsuleGetParams (dGeomID g, dReal *radius, dReal *length) | ||
93 | { | ||
94 | dUASSERT (g && g->type == dCapsuleClass,"argument not a ccylinder"); | ||
95 | dxCapsule *c = (dxCapsule*) g; | ||
96 | *radius = c->radius; | ||
97 | *length = c->lz; | ||
98 | } | ||
99 | |||
100 | |||
101 | dReal dGeomCapsulePointDepth (dGeomID g, dReal x, dReal y, dReal z) | ||
102 | { | ||
103 | dUASSERT (g && g->type == dCapsuleClass,"argument not a ccylinder"); | ||
104 | g->recomputePosr(); | ||
105 | dxCapsule *c = (dxCapsule*) g; | ||
106 | |||
107 | const dReal* R = g->final_posr->R; | ||
108 | const dReal* pos = g->final_posr->pos; | ||
109 | |||
110 | dVector3 a; | ||
111 | a[0] = x - pos[0]; | ||
112 | a[1] = y - pos[1]; | ||
113 | a[2] = z - pos[2]; | ||
114 | dReal beta = dDOT14(a,R+2); | ||
115 | dReal lz2 = c->lz*REAL(0.5); | ||
116 | if (beta < -lz2) beta = -lz2; | ||
117 | else if (beta > lz2) beta = lz2; | ||
118 | a[0] = c->final_posr->pos[0] + beta*R[0*4+2]; | ||
119 | a[1] = c->final_posr->pos[1] + beta*R[1*4+2]; | ||
120 | a[2] = c->final_posr->pos[2] + beta*R[2*4+2]; | ||
121 | return c->radius - | ||
122 | dSqrt ((x-a[0])*(x-a[0]) + (y-a[1])*(y-a[1]) + (z-a[2])*(z-a[2])); | ||
123 | } | ||
124 | |||
125 | |||
126 | |||
127 | int dCollideCapsuleSphere (dxGeom *o1, dxGeom *o2, int flags, | ||
128 | dContactGeom *contact, int skip) | ||
129 | { | ||
130 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
131 | dIASSERT (o1->type == dCapsuleClass); | ||
132 | dIASSERT (o2->type == dSphereClass); | ||
133 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
134 | |||
135 | dxCapsule *ccyl = (dxCapsule*) o1; | ||
136 | dxSphere *sphere = (dxSphere*) o2; | ||
137 | |||
138 | contact->g1 = o1; | ||
139 | contact->g2 = o2; | ||
140 | |||
141 | // find the point on the cylinder axis that is closest to the sphere | ||
142 | dReal alpha = | ||
143 | o1->final_posr->R[2] * (o2->final_posr->pos[0] - o1->final_posr->pos[0]) + | ||
144 | o1->final_posr->R[6] * (o2->final_posr->pos[1] - o1->final_posr->pos[1]) + | ||
145 | o1->final_posr->R[10] * (o2->final_posr->pos[2] - o1->final_posr->pos[2]); | ||
146 | dReal lz2 = ccyl->lz * REAL(0.5); | ||
147 | if (alpha > lz2) alpha = lz2; | ||
148 | if (alpha < -lz2) alpha = -lz2; | ||
149 | |||
150 | // collide the spheres | ||
151 | dVector3 p; | ||
152 | p[0] = o1->final_posr->pos[0] + alpha * o1->final_posr->R[2]; | ||
153 | p[1] = o1->final_posr->pos[1] + alpha * o1->final_posr->R[6]; | ||
154 | p[2] = o1->final_posr->pos[2] + alpha * o1->final_posr->R[10]; | ||
155 | return dCollideSpheres (p,ccyl->radius,o2->final_posr->pos,sphere->radius,contact); | ||
156 | } | ||
157 | |||
158 | |||
159 | int dCollideCapsuleBox (dxGeom *o1, dxGeom *o2, int flags, | ||
160 | dContactGeom *contact, int skip) | ||
161 | { | ||
162 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
163 | dIASSERT (o1->type == dCapsuleClass); | ||
164 | dIASSERT (o2->type == dBoxClass); | ||
165 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
166 | |||
167 | dxCapsule *cyl = (dxCapsule*) o1; | ||
168 | dxBox *box = (dxBox*) o2; | ||
169 | |||
170 | contact->g1 = o1; | ||
171 | contact->g2 = o2; | ||
172 | |||
173 | // get p1,p2 = cylinder axis endpoints, get radius | ||
174 | dVector3 p1,p2; | ||
175 | dReal clen = cyl->lz * REAL(0.5); | ||
176 | p1[0] = o1->final_posr->pos[0] + clen * o1->final_posr->R[2]; | ||
177 | p1[1] = o1->final_posr->pos[1] + clen * o1->final_posr->R[6]; | ||
178 | p1[2] = o1->final_posr->pos[2] + clen * o1->final_posr->R[10]; | ||
179 | p2[0] = o1->final_posr->pos[0] - clen * o1->final_posr->R[2]; | ||
180 | p2[1] = o1->final_posr->pos[1] - clen * o1->final_posr->R[6]; | ||
181 | p2[2] = o1->final_posr->pos[2] - clen * o1->final_posr->R[10]; | ||
182 | dReal radius = cyl->radius; | ||
183 | |||
184 | // copy out box center, rotation matrix, and side array | ||
185 | dReal *c = o2->final_posr->pos; | ||
186 | dReal *R = o2->final_posr->R; | ||
187 | const dReal *side = box->side; | ||
188 | |||
189 | // get the closest point between the cylinder axis and the box | ||
190 | dVector3 pl,pb; | ||
191 | dClosestLineBoxPoints (p1,p2,c,R,side,pl,pb); | ||
192 | |||
193 | // generate contact point | ||
194 | return dCollideSpheres (pl,radius,pb,0,contact); | ||
195 | } | ||
196 | |||
197 | |||
198 | int dCollideCapsuleCapsule (dxGeom *o1, dxGeom *o2, | ||
199 | int flags, dContactGeom *contact, int skip) | ||
200 | { | ||
201 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
202 | dIASSERT (o1->type == dCapsuleClass); | ||
203 | dIASSERT (o2->type == dCapsuleClass); | ||
204 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
205 | |||
206 | int i; | ||
207 | const dReal tolerance = REAL(1e-5); | ||
208 | |||
209 | dxCapsule *cyl1 = (dxCapsule*) o1; | ||
210 | dxCapsule *cyl2 = (dxCapsule*) o2; | ||
211 | |||
212 | contact->g1 = o1; | ||
213 | contact->g2 = o2; | ||
214 | |||
215 | // copy out some variables, for convenience | ||
216 | dReal lz1 = cyl1->lz * REAL(0.5); | ||
217 | dReal lz2 = cyl2->lz * REAL(0.5); | ||
218 | dReal *pos1 = o1->final_posr->pos; | ||
219 | dReal *pos2 = o2->final_posr->pos; | ||
220 | dReal axis1[3],axis2[3]; | ||
221 | axis1[0] = o1->final_posr->R[2]; | ||
222 | axis1[1] = o1->final_posr->R[6]; | ||
223 | axis1[2] = o1->final_posr->R[10]; | ||
224 | axis2[0] = o2->final_posr->R[2]; | ||
225 | axis2[1] = o2->final_posr->R[6]; | ||
226 | axis2[2] = o2->final_posr->R[10]; | ||
227 | |||
228 | // if the cylinder axes are close to parallel, we'll try to detect up to | ||
229 | // two contact points along the body of the cylinder. if we can't find any | ||
230 | // points then we'll fall back to the closest-points algorithm. note that | ||
231 | // we are not treating this special case for reasons of degeneracy, but | ||
232 | // because we want two contact points in some situations. the closet-points | ||
233 | // algorithm is robust in all casts, but it can return only one contact. | ||
234 | |||
235 | dVector3 sphere1,sphere2; | ||
236 | dReal a1a2 = dDOT (axis1,axis2); | ||
237 | dReal det = REAL(1.0)-a1a2*a1a2; | ||
238 | if (det < tolerance) { | ||
239 | // the cylinder axes (almost) parallel, so we will generate up to two | ||
240 | // contacts. alpha1 and alpha2 (line position parameters) are related by: | ||
241 | // alpha2 = alpha1 + (pos1-pos2)'*axis1 (if axis1==axis2) | ||
242 | // or alpha2 = -(alpha1 + (pos1-pos2)'*axis1) (if axis1==-axis2) | ||
243 | // first compute where the two cylinders overlap in alpha1 space: | ||
244 | if (a1a2 < 0) { | ||
245 | axis2[0] = -axis2[0]; | ||
246 | axis2[1] = -axis2[1]; | ||
247 | axis2[2] = -axis2[2]; | ||
248 | } | ||
249 | dReal q[3]; | ||
250 | for (i=0; i<3; i++) q[i] = pos1[i]-pos2[i]; | ||
251 | dReal k = dDOT (axis1,q); | ||
252 | dReal a1lo = -lz1; | ||
253 | dReal a1hi = lz1; | ||
254 | dReal a2lo = -lz2 - k; | ||
255 | dReal a2hi = lz2 - k; | ||
256 | dReal lo = (a1lo > a2lo) ? a1lo : a2lo; | ||
257 | dReal hi = (a1hi < a2hi) ? a1hi : a2hi; | ||
258 | if (lo <= hi) { | ||
259 | int num_contacts = flags & NUMC_MASK; | ||
260 | if (num_contacts >= 2 && lo < hi) { | ||
261 | // generate up to two contacts. if one of those contacts is | ||
262 | // not made, fall back on the one-contact strategy. | ||
263 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + lo*axis1[i]; | ||
264 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + (lo+k)*axis2[i]; | ||
265 | int n1 = dCollideSpheres (sphere1,cyl1->radius, | ||
266 | sphere2,cyl2->radius,contact); | ||
267 | if (n1) { | ||
268 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + hi*axis1[i]; | ||
269 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + (hi+k)*axis2[i]; | ||
270 | dContactGeom *c2 = CONTACT(contact,skip); | ||
271 | int n2 = dCollideSpheres (sphere1,cyl1->radius, | ||
272 | sphere2,cyl2->radius, c2); | ||
273 | if (n2) { | ||
274 | c2->g1 = o1; | ||
275 | c2->g2 = o2; | ||
276 | return 2; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | // just one contact to generate, so put it in the middle of | ||
282 | // the range | ||
283 | dReal alpha1 = (lo + hi) * REAL(0.5); | ||
284 | dReal alpha2 = alpha1 + k; | ||
285 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
286 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
287 | return dCollideSpheres (sphere1,cyl1->radius, | ||
288 | sphere2,cyl2->radius,contact); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | // use the closest point algorithm | ||
293 | dVector3 a1,a2,b1,b2; | ||
294 | a1[0] = o1->final_posr->pos[0] + axis1[0]*lz1; | ||
295 | a1[1] = o1->final_posr->pos[1] + axis1[1]*lz1; | ||
296 | a1[2] = o1->final_posr->pos[2] + axis1[2]*lz1; | ||
297 | a2[0] = o1->final_posr->pos[0] - axis1[0]*lz1; | ||
298 | a2[1] = o1->final_posr->pos[1] - axis1[1]*lz1; | ||
299 | a2[2] = o1->final_posr->pos[2] - axis1[2]*lz1; | ||
300 | b1[0] = o2->final_posr->pos[0] + axis2[0]*lz2; | ||
301 | b1[1] = o2->final_posr->pos[1] + axis2[1]*lz2; | ||
302 | b1[2] = o2->final_posr->pos[2] + axis2[2]*lz2; | ||
303 | b2[0] = o2->final_posr->pos[0] - axis2[0]*lz2; | ||
304 | b2[1] = o2->final_posr->pos[1] - axis2[1]*lz2; | ||
305 | b2[2] = o2->final_posr->pos[2] - axis2[2]*lz2; | ||
306 | |||
307 | dClosestLineSegmentPoints (a1,a2,b1,b2,sphere1,sphere2); | ||
308 | return dCollideSpheres (sphere1,cyl1->radius,sphere2,cyl2->radius,contact); | ||
309 | } | ||
310 | |||
311 | |||
312 | int dCollideCapsulePlane (dxGeom *o1, dxGeom *o2, int flags, | ||
313 | dContactGeom *contact, int skip) | ||
314 | { | ||
315 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
316 | dIASSERT (o1->type == dCapsuleClass); | ||
317 | dIASSERT (o2->type == dPlaneClass); | ||
318 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
319 | |||
320 | dxCapsule *ccyl = (dxCapsule*) o1; | ||
321 | dxPlane *plane = (dxPlane*) o2; | ||
322 | |||
323 | // collide the deepest capping sphere with the plane | ||
324 | dReal sign = (dDOT14 (plane->p,o1->final_posr->R+2) > 0) ? REAL(-1.0) : REAL(1.0); | ||
325 | dVector3 p; | ||
326 | p[0] = o1->final_posr->pos[0] + o1->final_posr->R[2] * ccyl->lz * REAL(0.5) * sign; | ||
327 | p[1] = o1->final_posr->pos[1] + o1->final_posr->R[6] * ccyl->lz * REAL(0.5) * sign; | ||
328 | p[2] = o1->final_posr->pos[2] + o1->final_posr->R[10] * ccyl->lz * REAL(0.5) * sign; | ||
329 | |||
330 | dReal k = dDOT (p,plane->p); | ||
331 | dReal depth = plane->p[3] - k + ccyl->radius; | ||
332 | if (depth < 0) return 0; | ||
333 | contact->normal[0] = plane->p[0]; | ||
334 | contact->normal[1] = plane->p[1]; | ||
335 | contact->normal[2] = plane->p[2]; | ||
336 | contact->pos[0] = p[0] - plane->p[0] * ccyl->radius; | ||
337 | contact->pos[1] = p[1] - plane->p[1] * ccyl->radius; | ||
338 | contact->pos[2] = p[2] - plane->p[2] * ccyl->radius; | ||
339 | contact->depth = depth; | ||
340 | |||
341 | int ncontacts = 1; | ||
342 | if ((flags & NUMC_MASK) >= 2) { | ||
343 | // collide the other capping sphere with the plane | ||
344 | p[0] = o1->final_posr->pos[0] - o1->final_posr->R[2] * ccyl->lz * REAL(0.5) * sign; | ||
345 | p[1] = o1->final_posr->pos[1] - o1->final_posr->R[6] * ccyl->lz * REAL(0.5) * sign; | ||
346 | p[2] = o1->final_posr->pos[2] - o1->final_posr->R[10] * ccyl->lz * REAL(0.5) * sign; | ||
347 | |||
348 | k = dDOT (p,plane->p); | ||
349 | depth = plane->p[3] - k + ccyl->radius; | ||
350 | if (depth >= 0) { | ||
351 | dContactGeom *c2 = CONTACT(contact,skip); | ||
352 | c2->normal[0] = plane->p[0]; | ||
353 | c2->normal[1] = plane->p[1]; | ||
354 | c2->normal[2] = plane->p[2]; | ||
355 | c2->pos[0] = p[0] - plane->p[0] * ccyl->radius; | ||
356 | c2->pos[1] = p[1] - plane->p[1] * ccyl->radius; | ||
357 | c2->pos[2] = p[2] - plane->p[2] * ccyl->radius; | ||
358 | c2->depth = depth; | ||
359 | ncontacts = 2; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | for (int i=0; i < ncontacts; i++) { | ||
364 | CONTACT(contact,i*skip)->g1 = o1; | ||
365 | CONTACT(contact,i*skip)->g2 = o2; | ||
366 | } | ||
367 | return ncontacts; | ||
368 | } | ||
369 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_cylinder_box.cpp b/libraries/ode-0.9\/ode/src/collision_cylinder_box.cpp new file mode 100755 index 0000000..eb14c72 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_cylinder_box.cpp | |||
@@ -0,0 +1,1007 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | * Cylinder-box collider by Alen Ladavac | ||
25 | * Ported to ODE by Nguyen Binh | ||
26 | */ | ||
27 | |||
28 | #include <ode/collision.h> | ||
29 | #include <ode/matrix.h> | ||
30 | #include <ode/rotation.h> | ||
31 | #include <ode/odemath.h> | ||
32 | #include "collision_util.h" | ||
33 | |||
34 | static const int MAX_CYLBOX_CLIP_POINTS = 16; | ||
35 | static const int nCYLINDER_AXIS = 2; | ||
36 | // Number of segment of cylinder base circle. | ||
37 | // Must be divisible by 4. | ||
38 | static const int nCYLINDER_SEGMENT = 8; | ||
39 | |||
40 | #define MAX_FLOAT dInfinity | ||
41 | |||
42 | // Data that passed through the collider's functions | ||
43 | typedef struct _sCylinderBoxData | ||
44 | { | ||
45 | // cylinder parameters | ||
46 | dMatrix3 mCylinderRot; | ||
47 | dVector3 vCylinderPos; | ||
48 | dVector3 vCylinderAxis; | ||
49 | dReal fCylinderRadius; | ||
50 | dReal fCylinderSize; | ||
51 | dVector3 avCylinderNormals[nCYLINDER_SEGMENT]; | ||
52 | |||
53 | // box parameters | ||
54 | |||
55 | dMatrix3 mBoxRot; | ||
56 | dVector3 vBoxPos; | ||
57 | dVector3 vBoxHalfSize; | ||
58 | // box vertices array : 8 vertices | ||
59 | dVector3 avBoxVertices[8]; | ||
60 | |||
61 | // global collider data | ||
62 | dVector3 vDiff; | ||
63 | dVector3 vNormal; | ||
64 | dReal fBestDepth; | ||
65 | dReal fBestrb; | ||
66 | dReal fBestrc; | ||
67 | int iBestAxis; | ||
68 | |||
69 | // contact data | ||
70 | dVector3 vEp0, vEp1; | ||
71 | dReal fDepth0, fDepth1; | ||
72 | |||
73 | // ODE stuff | ||
74 | dGeomID gBox; | ||
75 | dGeomID gCylinder; | ||
76 | dContactGeom* gContact; | ||
77 | int iFlags; | ||
78 | int iSkip; | ||
79 | int nContacts; | ||
80 | |||
81 | } sCylinderBoxData; | ||
82 | |||
83 | |||
84 | // initialize collision data | ||
85 | void _cldInitCylinderBox(sCylinderBoxData& cData) | ||
86 | { | ||
87 | // get cylinder position, orientation | ||
88 | const dReal* pRotCyc = dGeomGetRotation(cData.gCylinder); | ||
89 | dMatrix3Copy(pRotCyc,cData.mCylinderRot); | ||
90 | |||
91 | const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(cData.gCylinder); | ||
92 | dVector3Copy(*pPosCyc,cData.vCylinderPos); | ||
93 | |||
94 | dMat3GetCol(cData.mCylinderRot,nCYLINDER_AXIS,cData.vCylinderAxis); | ||
95 | |||
96 | // get cylinder radius and size | ||
97 | dGeomCylinderGetParams(cData.gCylinder,&cData.fCylinderRadius,&cData.fCylinderSize); | ||
98 | |||
99 | // get box position, orientation, size | ||
100 | const dReal* pRotBox = dGeomGetRotation(cData.gBox); | ||
101 | dMatrix3Copy(pRotBox,cData.mBoxRot); | ||
102 | const dVector3* pPosBox = (const dVector3*)dGeomGetPosition(cData.gBox); | ||
103 | dVector3Copy(*pPosBox,cData.vBoxPos); | ||
104 | |||
105 | dGeomBoxGetLengths(cData.gBox, cData.vBoxHalfSize); | ||
106 | cData.vBoxHalfSize[0] *= REAL(0.5); | ||
107 | cData.vBoxHalfSize[1] *= REAL(0.5); | ||
108 | cData.vBoxHalfSize[2] *= REAL(0.5); | ||
109 | |||
110 | // vertex 0 | ||
111 | cData.avBoxVertices[0][0] = -cData.vBoxHalfSize[0]; | ||
112 | cData.avBoxVertices[0][1] = cData.vBoxHalfSize[1]; | ||
113 | cData.avBoxVertices[0][2] = -cData.vBoxHalfSize[2]; | ||
114 | |||
115 | // vertex 1 | ||
116 | cData.avBoxVertices[1][0] = cData.vBoxHalfSize[0]; | ||
117 | cData.avBoxVertices[1][1] = cData.vBoxHalfSize[1]; | ||
118 | cData.avBoxVertices[1][2] = -cData.vBoxHalfSize[2]; | ||
119 | |||
120 | // vertex 2 | ||
121 | cData.avBoxVertices[2][0] = -cData.vBoxHalfSize[0]; | ||
122 | cData.avBoxVertices[2][1] = -cData.vBoxHalfSize[1]; | ||
123 | cData.avBoxVertices[2][2] = -cData.vBoxHalfSize[2]; | ||
124 | |||
125 | // vertex 3 | ||
126 | cData.avBoxVertices[3][0] = cData.vBoxHalfSize[0]; | ||
127 | cData.avBoxVertices[3][1] = -cData.vBoxHalfSize[1]; | ||
128 | cData.avBoxVertices[3][2] = -cData.vBoxHalfSize[2]; | ||
129 | |||
130 | // vertex 4 | ||
131 | cData.avBoxVertices[4][0] = cData.vBoxHalfSize[0]; | ||
132 | cData.avBoxVertices[4][1] = cData.vBoxHalfSize[1]; | ||
133 | cData.avBoxVertices[4][2] = cData.vBoxHalfSize[2]; | ||
134 | |||
135 | // vertex 5 | ||
136 | cData.avBoxVertices[5][0] = cData.vBoxHalfSize[0]; | ||
137 | cData.avBoxVertices[5][1] = -cData.vBoxHalfSize[1]; | ||
138 | cData.avBoxVertices[5][2] = cData.vBoxHalfSize[2]; | ||
139 | |||
140 | // vertex 6 | ||
141 | cData.avBoxVertices[6][0] = -cData.vBoxHalfSize[0]; | ||
142 | cData.avBoxVertices[6][1] = -cData.vBoxHalfSize[1]; | ||
143 | cData.avBoxVertices[6][2] = cData.vBoxHalfSize[2]; | ||
144 | |||
145 | // vertex 7 | ||
146 | cData.avBoxVertices[7][0] = -cData.vBoxHalfSize[0]; | ||
147 | cData.avBoxVertices[7][1] = cData.vBoxHalfSize[1]; | ||
148 | cData.avBoxVertices[7][2] = cData.vBoxHalfSize[2]; | ||
149 | |||
150 | // temp index | ||
151 | int i = 0; | ||
152 | dVector3 vTempBoxVertices[8]; | ||
153 | // transform vertices in absolute space | ||
154 | for(i=0; i < 8; i++) | ||
155 | { | ||
156 | dMultiplyMat3Vec3(cData.mBoxRot,cData.avBoxVertices[i], vTempBoxVertices[i]); | ||
157 | dVector3Add(vTempBoxVertices[i], cData.vBoxPos, cData.avBoxVertices[i]); | ||
158 | } | ||
159 | |||
160 | // find relative position | ||
161 | dVector3Subtract(cData.vCylinderPos,cData.vBoxPos,cData.vDiff); | ||
162 | cData.fBestDepth = MAX_FLOAT; | ||
163 | cData.vNormal[0] = REAL(0.0); | ||
164 | cData.vNormal[1] = REAL(0.0); | ||
165 | cData.vNormal[2] = REAL(0.0); | ||
166 | |||
167 | // calculate basic angle for nCYLINDER_SEGMENT-gon | ||
168 | dReal fAngle = M_PI/nCYLINDER_SEGMENT; | ||
169 | |||
170 | // calculate angle increment | ||
171 | dReal fAngleIncrement = fAngle * REAL(2.0); | ||
172 | |||
173 | // calculate nCYLINDER_SEGMENT-gon points | ||
174 | for(i = 0; i < nCYLINDER_SEGMENT; i++) | ||
175 | { | ||
176 | cData.avCylinderNormals[i][0] = -dCos(fAngle); | ||
177 | cData.avCylinderNormals[i][1] = -dSin(fAngle); | ||
178 | cData.avCylinderNormals[i][2] = 0; | ||
179 | |||
180 | fAngle += fAngleIncrement; | ||
181 | } | ||
182 | |||
183 | cData.fBestrb = 0; | ||
184 | cData.fBestrc = 0; | ||
185 | cData.iBestAxis = 0; | ||
186 | cData.nContacts = 0; | ||
187 | |||
188 | } | ||
189 | |||
190 | // test for given separating axis | ||
191 | int _cldTestAxis(sCylinderBoxData& cData, dVector3& vInputNormal, int iAxis ) | ||
192 | { | ||
193 | // check length of input normal | ||
194 | dReal fL = dVector3Length(vInputNormal); | ||
195 | // if not long enough | ||
196 | if ( fL < REAL(1e-5) ) | ||
197 | { | ||
198 | // do nothing | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | // otherwise make it unit for sure | ||
203 | dNormalize3(vInputNormal); | ||
204 | |||
205 | // project box and Cylinder on mAxis | ||
206 | dReal fdot1 = dVector3Dot(cData.vCylinderAxis, vInputNormal); | ||
207 | |||
208 | dReal frc; | ||
209 | |||
210 | if (fdot1 > REAL(1.0)) | ||
211 | { | ||
212 | fdot1 = REAL(1.0); | ||
213 | frc = dFabs(cData.fCylinderSize*REAL(0.5)); | ||
214 | } | ||
215 | |||
216 | // project box and capsule on iAxis | ||
217 | frc = dFabs( fdot1 * (cData.fCylinderSize*REAL(0.5))) + cData.fCylinderRadius * dSqrt(REAL(1.0)-(fdot1*fdot1)); | ||
218 | |||
219 | dVector3 vTemp1; | ||
220 | dReal frb = REAL(0.0); | ||
221 | |||
222 | dMat3GetCol(cData.mBoxRot,0,vTemp1); | ||
223 | frb = dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[0]; | ||
224 | |||
225 | dMat3GetCol(cData.mBoxRot,1,vTemp1); | ||
226 | frb += dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[1]; | ||
227 | |||
228 | dMat3GetCol(cData.mBoxRot,2,vTemp1); | ||
229 | frb += dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[2]; | ||
230 | |||
231 | // project their distance on separating axis | ||
232 | dReal fd = dVector3Dot(cData.vDiff,vInputNormal); | ||
233 | |||
234 | // if they do not overlap exit, we have no intersection | ||
235 | if ( dFabs(fd) > frc+frb ) | ||
236 | { | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | // get depth | ||
241 | dReal fDepth = - dFabs(fd) + (frc+frb); | ||
242 | |||
243 | // get maximum depth | ||
244 | if ( fDepth < cData.fBestDepth ) | ||
245 | { | ||
246 | cData.fBestDepth = fDepth; | ||
247 | dVector3Copy(vInputNormal,cData.vNormal); | ||
248 | cData.iBestAxis = iAxis; | ||
249 | cData.fBestrb = frb; | ||
250 | cData.fBestrc = frc; | ||
251 | |||
252 | // flip normal if interval is wrong faced | ||
253 | if (fd > 0) | ||
254 | { | ||
255 | dVector3Inv(cData.vNormal); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | |||
263 | // check for separation between box edge and cylinder circle edge | ||
264 | int _cldTestEdgeCircleAxis( sCylinderBoxData& cData, | ||
265 | const dVector3 &vCenterPoint, | ||
266 | const dVector3 &vVx0, const dVector3 &vVx1, | ||
267 | int iAxis ) | ||
268 | { | ||
269 | // calculate direction of edge | ||
270 | dVector3 vDirEdge; | ||
271 | dVector3Subtract(vVx1,vVx0,vDirEdge); | ||
272 | dNormalize3(vDirEdge); | ||
273 | // starting point of edge | ||
274 | dVector3 vEStart; | ||
275 | dVector3Copy(vVx0,vEStart);; | ||
276 | |||
277 | // calculate angle cosine between cylinder axis and edge | ||
278 | dReal fdot2 = dVector3Dot (vDirEdge,cData.vCylinderAxis); | ||
279 | |||
280 | // if edge is perpendicular to cylinder axis | ||
281 | if(dFabs(fdot2) < REAL(1e-5)) | ||
282 | { | ||
283 | // this can't be separating axis, because edge is parallel to circle plane | ||
284 | return 1; | ||
285 | } | ||
286 | |||
287 | // find point of intersection between edge line and circle plane | ||
288 | dVector3 vTemp1; | ||
289 | dVector3Subtract(vCenterPoint,vEStart,vTemp1); | ||
290 | dReal fdot1 = dVector3Dot(vTemp1,cData.vCylinderAxis); | ||
291 | dVector3 vpnt; | ||
292 | vpnt[0]= vEStart[0] + vDirEdge[0] * (fdot1/fdot2); | ||
293 | vpnt[1]= vEStart[1] + vDirEdge[1] * (fdot1/fdot2); | ||
294 | vpnt[2]= vEStart[2] + vDirEdge[2] * (fdot1/fdot2); | ||
295 | |||
296 | // find tangent vector on circle with same center (vCenterPoint) that | ||
297 | // touches point of intersection (vpnt) | ||
298 | dVector3 vTangent; | ||
299 | dVector3Subtract(vCenterPoint,vpnt,vTemp1); | ||
300 | dVector3Cross(vTemp1,cData.vCylinderAxis,vTangent); | ||
301 | |||
302 | // find vector orthogonal both to tangent and edge direction | ||
303 | dVector3 vAxis; | ||
304 | dVector3Cross(vTangent,vDirEdge,vAxis); | ||
305 | |||
306 | // use that vector as separating axis | ||
307 | return _cldTestAxis( cData, vAxis, iAxis ); | ||
308 | } | ||
309 | |||
310 | // Test separating axis for collision | ||
311 | int _cldTestSeparatingAxes(sCylinderBoxData& cData) | ||
312 | { | ||
313 | // reset best axis | ||
314 | cData.fBestDepth = MAX_FLOAT; | ||
315 | cData.iBestAxis = 0; | ||
316 | cData.fBestrb = 0; | ||
317 | cData.fBestrc = 0; | ||
318 | cData.nContacts = 0; | ||
319 | |||
320 | dVector3 vAxis = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; | ||
321 | |||
322 | // Epsilon value for checking axis vector length | ||
323 | const dReal fEpsilon = REAL(1e-6); | ||
324 | |||
325 | // axis A0 | ||
326 | dMat3GetCol(cData.mBoxRot, 0 , vAxis); | ||
327 | if (!_cldTestAxis( cData, vAxis, 1 )) | ||
328 | { | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | // axis A1 | ||
333 | dMat3GetCol(cData.mBoxRot, 1 , vAxis); | ||
334 | if (!_cldTestAxis( cData, vAxis, 2 )) | ||
335 | { | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | // axis A2 | ||
340 | dMat3GetCol(cData.mBoxRot, 2 , vAxis); | ||
341 | if (!_cldTestAxis( cData, vAxis, 3 )) | ||
342 | { | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | // axis C - Cylinder Axis | ||
347 | //vAxis = vCylinderAxis; | ||
348 | dVector3Copy(cData.vCylinderAxis , vAxis); | ||
349 | if (!_cldTestAxis( cData, vAxis, 4 )) | ||
350 | { | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | // axis CxA0 | ||
355 | //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 0 )); | ||
356 | dVector3CrossMat3Col(cData.mBoxRot, 0 ,cData.vCylinderAxis, vAxis); | ||
357 | if(dVector3Length2( vAxis ) > fEpsilon ) | ||
358 | { | ||
359 | if (!_cldTestAxis( cData, vAxis, 5 )) | ||
360 | { | ||
361 | return 0; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | // axis CxA1 | ||
366 | //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 1 )); | ||
367 | dVector3CrossMat3Col(cData.mBoxRot, 1 ,cData.vCylinderAxis, vAxis); | ||
368 | if(dVector3Length2( vAxis ) > fEpsilon ) | ||
369 | { | ||
370 | if (!_cldTestAxis( cData, vAxis, 6 )) | ||
371 | { | ||
372 | return 0; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | // axis CxA2 | ||
377 | //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 2 )); | ||
378 | dVector3CrossMat3Col(cData.mBoxRot, 2 ,cData.vCylinderAxis, vAxis); | ||
379 | if(dVector3Length2( vAxis ) > fEpsilon ) | ||
380 | { | ||
381 | if (!_cldTestAxis( cData, vAxis, 7 )) | ||
382 | { | ||
383 | return 0; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | int i = 0; | ||
388 | dVector3 vTemp1; | ||
389 | dVector3 vTemp2; | ||
390 | // here we check box's vertices axis | ||
391 | for(i=0; i< 8; i++) | ||
392 | { | ||
393 | //vAxis = ( vCylinderAxis cross (cData.avBoxVertices[i] - vCylinderPos)); | ||
394 | dVector3Subtract(cData.avBoxVertices[i],cData.vCylinderPos,vTemp1); | ||
395 | dVector3Cross(cData.vCylinderAxis,vTemp1,vTemp2); | ||
396 | //vAxis = ( vCylinderAxis cross vAxis ); | ||
397 | dVector3Cross(cData.vCylinderAxis,vTemp2,vAxis); | ||
398 | if(dVector3Length2( vAxis ) > fEpsilon ) | ||
399 | { | ||
400 | if (!_cldTestAxis( cData, vAxis, 8 + i )) | ||
401 | { | ||
402 | return 0; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | // ************************************ | ||
408 | // this is defined for first 12 axes | ||
409 | // normal of plane that contains top circle of cylinder | ||
410 | // center of top circle of cylinder | ||
411 | dVector3 vcc; | ||
412 | vcc[0] = (cData.vCylinderPos)[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
413 | vcc[1] = (cData.vCylinderPos)[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
414 | vcc[2] = (cData.vCylinderPos)[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
415 | // ************************************ | ||
416 | |||
417 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[0], 16)) | ||
418 | { | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[3], 17)) | ||
423 | { | ||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[3], 18)) | ||
428 | { | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[0], 19)) | ||
433 | { | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | |||
438 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[1], 20)) | ||
439 | { | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[7], 21)) | ||
444 | { | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[0], cData.avBoxVertices[7], 22)) | ||
449 | { | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[3], 23)) | ||
454 | { | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[6], 24)) | ||
459 | { | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[6], 25)) | ||
464 | { | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[5], 26)) | ||
469 | { | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[6], cData.avBoxVertices[7], 27)) | ||
474 | { | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | // ************************************ | ||
479 | // this is defined for second 12 axes | ||
480 | // normal of plane that contains bottom circle of cylinder | ||
481 | // center of bottom circle of cylinder | ||
482 | // vcc = vCylinderPos - vCylinderAxis*(fCylinderSize*REAL(0.5)); | ||
483 | vcc[0] = (cData.vCylinderPos)[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
484 | vcc[1] = (cData.vCylinderPos)[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
485 | vcc[2] = (cData.vCylinderPos)[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
486 | // ************************************ | ||
487 | |||
488 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[0], 28)) | ||
489 | { | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[3], 29)) | ||
494 | { | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[3], 30)) | ||
499 | { | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[0], 31)) | ||
504 | { | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[1], 32)) | ||
509 | { | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[7], 33)) | ||
514 | { | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[0], cData.avBoxVertices[7], 34)) | ||
519 | { | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[3], 35)) | ||
524 | { | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[6], 36)) | ||
529 | { | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[6], 37)) | ||
534 | { | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[5], 38)) | ||
539 | { | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[6], cData.avBoxVertices[7], 39)) | ||
544 | { | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | return 1; | ||
549 | } | ||
550 | |||
551 | int _cldClipCylinderToBox(sCylinderBoxData& cData) | ||
552 | { | ||
553 | dIASSERT(cData.nContacts != (cData.iFlags & NUMC_MASK)); | ||
554 | |||
555 | // calculate that vector perpendicular to cylinder axis which closes lowest angle with collision normal | ||
556 | dVector3 vN; | ||
557 | dReal fTemp1 = dVector3Dot(cData.vCylinderAxis,cData.vNormal); | ||
558 | vN[0] = cData.vNormal[0] - cData.vCylinderAxis[0]*fTemp1; | ||
559 | vN[1] = cData.vNormal[1] - cData.vCylinderAxis[1]*fTemp1; | ||
560 | vN[2] = cData.vNormal[2] - cData.vCylinderAxis[2]*fTemp1; | ||
561 | |||
562 | // normalize that vector | ||
563 | dNormalize3(vN); | ||
564 | |||
565 | // translate cylinder end points by the vector | ||
566 | dVector3 vCposTrans; | ||
567 | vCposTrans[0] = cData.vCylinderPos[0] + vN[0] * cData.fCylinderRadius; | ||
568 | vCposTrans[1] = cData.vCylinderPos[1] + vN[1] * cData.fCylinderRadius; | ||
569 | vCposTrans[2] = cData.vCylinderPos[2] + vN[2] * cData.fCylinderRadius; | ||
570 | |||
571 | cData.vEp0[0] = vCposTrans[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
572 | cData.vEp0[1] = vCposTrans[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
573 | cData.vEp0[2] = vCposTrans[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
574 | |||
575 | cData.vEp1[0] = vCposTrans[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
576 | cData.vEp1[1] = vCposTrans[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
577 | cData.vEp1[2] = vCposTrans[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
578 | |||
579 | // transform edge points in box space | ||
580 | cData.vEp0[0] -= cData.vBoxPos[0]; | ||
581 | cData.vEp0[1] -= cData.vBoxPos[1]; | ||
582 | cData.vEp0[2] -= cData.vBoxPos[2]; | ||
583 | |||
584 | cData.vEp1[0] -= cData.vBoxPos[0]; | ||
585 | cData.vEp1[1] -= cData.vBoxPos[1]; | ||
586 | cData.vEp1[2] -= cData.vBoxPos[2]; | ||
587 | |||
588 | dVector3 vTemp1; | ||
589 | // clip the edge to box | ||
590 | dVector4 plPlane; | ||
591 | // plane 0 +x | ||
592 | dMat3GetCol(cData.mBoxRot,0,vTemp1); | ||
593 | dConstructPlane(vTemp1,cData.vBoxHalfSize[0],plPlane); | ||
594 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
595 | { | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | // plane 1 +y | ||
600 | dMat3GetCol(cData.mBoxRot,1,vTemp1); | ||
601 | dConstructPlane(vTemp1,cData.vBoxHalfSize[1],plPlane); | ||
602 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
603 | { | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | // plane 2 +z | ||
608 | dMat3GetCol(cData.mBoxRot,2,vTemp1); | ||
609 | dConstructPlane(vTemp1,cData.vBoxHalfSize[2],plPlane); | ||
610 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
611 | { | ||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | // plane 3 -x | ||
616 | dMat3GetCol(cData.mBoxRot,0,vTemp1); | ||
617 | dVector3Inv(vTemp1); | ||
618 | dConstructPlane(vTemp1,cData.vBoxHalfSize[0],plPlane); | ||
619 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
620 | { | ||
621 | return 0; | ||
622 | } | ||
623 | |||
624 | // plane 4 -y | ||
625 | dMat3GetCol(cData.mBoxRot,1,vTemp1); | ||
626 | dVector3Inv(vTemp1); | ||
627 | dConstructPlane(vTemp1,cData.vBoxHalfSize[1],plPlane); | ||
628 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
629 | { | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | // plane 5 -z | ||
634 | dMat3GetCol(cData.mBoxRot,2,vTemp1); | ||
635 | dVector3Inv(vTemp1); | ||
636 | dConstructPlane(vTemp1,cData.vBoxHalfSize[2],plPlane); | ||
637 | if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) | ||
638 | { | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | // calculate depths for both contact points | ||
643 | cData.fDepth0 = cData.fBestrb + dVector3Dot(cData.vEp0, cData.vNormal); | ||
644 | cData.fDepth1 = cData.fBestrb + dVector3Dot(cData.vEp1, cData.vNormal); | ||
645 | |||
646 | // clamp depths to 0 | ||
647 | if(cData.fDepth0<0) | ||
648 | { | ||
649 | cData.fDepth0 = REAL(0.0); | ||
650 | } | ||
651 | |||
652 | if(cData.fDepth1<0) | ||
653 | { | ||
654 | cData.fDepth1 = REAL(0.0); | ||
655 | } | ||
656 | |||
657 | // back transform edge points from box to absolute space | ||
658 | cData.vEp0[0] += cData.vBoxPos[0]; | ||
659 | cData.vEp0[1] += cData.vBoxPos[1]; | ||
660 | cData.vEp0[2] += cData.vBoxPos[2]; | ||
661 | |||
662 | cData.vEp1[0] += cData.vBoxPos[0]; | ||
663 | cData.vEp1[1] += cData.vBoxPos[1]; | ||
664 | cData.vEp1[2] += cData.vBoxPos[2]; | ||
665 | |||
666 | dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); | ||
667 | Contact0->depth = cData.fDepth0; | ||
668 | dVector3Copy(cData.vNormal,Contact0->normal); | ||
669 | dVector3Copy(cData.vEp0,Contact0->pos); | ||
670 | Contact0->g1 = cData.gCylinder; | ||
671 | Contact0->g2 = cData.gBox; | ||
672 | dVector3Inv(Contact0->normal); | ||
673 | cData.nContacts++; | ||
674 | |||
675 | if (cData.nContacts != (cData.iFlags & NUMC_MASK)) | ||
676 | { | ||
677 | dContactGeom* Contact1 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); | ||
678 | Contact1->depth = cData.fDepth1; | ||
679 | dVector3Copy(cData.vNormal,Contact1->normal); | ||
680 | dVector3Copy(cData.vEp1,Contact1->pos); | ||
681 | Contact1->g1 = cData.gCylinder; | ||
682 | Contact1->g2 = cData.gBox; | ||
683 | dVector3Inv(Contact1->normal); | ||
684 | cData.nContacts++; | ||
685 | } | ||
686 | |||
687 | return 1; | ||
688 | } | ||
689 | |||
690 | |||
691 | void _cldClipBoxToCylinder(sCylinderBoxData& cData ) | ||
692 | { | ||
693 | dIASSERT(cData.nContacts != (cData.iFlags & NUMC_MASK)); | ||
694 | |||
695 | dVector3 vCylinderCirclePos, vCylinderCircleNormal_Rel; | ||
696 | // check which circle from cylinder we take for clipping | ||
697 | if ( dVector3Dot(cData.vCylinderAxis, cData.vNormal) > REAL(0.0) ) | ||
698 | { | ||
699 | // get top circle | ||
700 | vCylinderCirclePos[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
701 | vCylinderCirclePos[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
702 | vCylinderCirclePos[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
703 | |||
704 | vCylinderCircleNormal_Rel[0] = REAL(0.0); | ||
705 | vCylinderCircleNormal_Rel[1] = REAL(0.0); | ||
706 | vCylinderCircleNormal_Rel[2] = REAL(0.0); | ||
707 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(-1.0); | ||
708 | } | ||
709 | else | ||
710 | { | ||
711 | // get bottom circle | ||
712 | vCylinderCirclePos[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
713 | vCylinderCirclePos[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
714 | vCylinderCirclePos[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
715 | |||
716 | vCylinderCircleNormal_Rel[0] = REAL(0.0); | ||
717 | vCylinderCircleNormal_Rel[1] = REAL(0.0); | ||
718 | vCylinderCircleNormal_Rel[2] = REAL(0.0); | ||
719 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(1.0); | ||
720 | } | ||
721 | |||
722 | // vNr is normal in Box frame, pointing from Cylinder to Box | ||
723 | dVector3 vNr; | ||
724 | dMatrix3 mBoxInv; | ||
725 | |||
726 | // Find a way to use quaternion | ||
727 | dMatrix3Inv(cData.mBoxRot,mBoxInv); | ||
728 | dMultiplyMat3Vec3(mBoxInv,cData.vNormal,vNr); | ||
729 | |||
730 | dVector3 vAbsNormal; | ||
731 | |||
732 | vAbsNormal[0] = dFabs( vNr[0] ); | ||
733 | vAbsNormal[1] = dFabs( vNr[1] ); | ||
734 | vAbsNormal[2] = dFabs( vNr[2] ); | ||
735 | |||
736 | // find which face in box is closest to cylinder | ||
737 | int iB0, iB1, iB2; | ||
738 | |||
739 | // Different from Croteam's code | ||
740 | if (vAbsNormal[1] > vAbsNormal[0]) | ||
741 | { | ||
742 | // 1 > 0 | ||
743 | if (vAbsNormal[0]> vAbsNormal[2]) | ||
744 | { | ||
745 | // 0 > 2 -> 1 > 0 >2 | ||
746 | iB0 = 1; iB1 = 0; iB2 = 2; | ||
747 | } | ||
748 | else | ||
749 | { | ||
750 | // 2 > 0-> Must compare 1 and 2 | ||
751 | if (vAbsNormal[1] > vAbsNormal[2]) | ||
752 | { | ||
753 | // 1 > 2 -> 1 > 2 > 0 | ||
754 | iB0 = 1; iB1 = 2; iB2 = 0; | ||
755 | } | ||
756 | else | ||
757 | { | ||
758 | // 2 > 1 -> 2 > 1 > 0; | ||
759 | iB0 = 2; iB1 = 1; iB2 = 0; | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | else | ||
764 | { | ||
765 | // 0 > 1 | ||
766 | if (vAbsNormal[1] > vAbsNormal[2]) | ||
767 | { | ||
768 | // 1 > 2 -> 0 > 1 > 2 | ||
769 | iB0 = 0; iB1 = 1; iB2 = 2; | ||
770 | } | ||
771 | else | ||
772 | { | ||
773 | // 2 > 1 -> Must compare 0 and 2 | ||
774 | if (vAbsNormal[0] > vAbsNormal[2]) | ||
775 | { | ||
776 | // 0 > 2 -> 0 > 2 > 1; | ||
777 | iB0 = 0; iB1 = 2; iB2 = 1; | ||
778 | } | ||
779 | else | ||
780 | { | ||
781 | // 2 > 0 -> 2 > 0 > 1; | ||
782 | iB0 = 2; iB1 = 0; iB2 = 1; | ||
783 | } | ||
784 | } | ||
785 | } | ||
786 | |||
787 | dVector3 vCenter; | ||
788 | // find center of box polygon | ||
789 | dVector3 vTemp; | ||
790 | if (vNr[iB0] > 0) | ||
791 | { | ||
792 | dMat3GetCol(cData.mBoxRot,iB0,vTemp); | ||
793 | vCenter[0] = cData.vBoxPos[0] - cData.vBoxHalfSize[iB0]*vTemp[0]; | ||
794 | vCenter[1] = cData.vBoxPos[1] - cData.vBoxHalfSize[iB0]*vTemp[1]; | ||
795 | vCenter[2] = cData.vBoxPos[2] - cData.vBoxHalfSize[iB0]*vTemp[2]; | ||
796 | } | ||
797 | else | ||
798 | { | ||
799 | dMat3GetCol(cData.mBoxRot,iB0,vTemp); | ||
800 | vCenter[0] = cData.vBoxPos[0] + cData.vBoxHalfSize[iB0]*vTemp[0]; | ||
801 | vCenter[1] = cData.vBoxPos[1] + cData.vBoxHalfSize[iB0]*vTemp[1]; | ||
802 | vCenter[2] = cData.vBoxPos[2] + cData.vBoxHalfSize[iB0]*vTemp[2]; | ||
803 | } | ||
804 | |||
805 | // find the vertices of box polygon | ||
806 | dVector3 avPoints[4]; | ||
807 | dVector3 avTempArray1[MAX_CYLBOX_CLIP_POINTS]; | ||
808 | dVector3 avTempArray2[MAX_CYLBOX_CLIP_POINTS]; | ||
809 | |||
810 | int i=0; | ||
811 | for(i=0; i<MAX_CYLBOX_CLIP_POINTS; i++) | ||
812 | { | ||
813 | avTempArray1[i][0] = REAL(0.0); | ||
814 | avTempArray1[i][1] = REAL(0.0); | ||
815 | avTempArray1[i][2] = REAL(0.0); | ||
816 | |||
817 | avTempArray2[i][0] = REAL(0.0); | ||
818 | avTempArray2[i][1] = REAL(0.0); | ||
819 | avTempArray2[i][2] = REAL(0.0); | ||
820 | } | ||
821 | |||
822 | dVector3 vAxis1, vAxis2; | ||
823 | |||
824 | dMat3GetCol(cData.mBoxRot,iB1,vAxis1); | ||
825 | dMat3GetCol(cData.mBoxRot,iB2,vAxis2); | ||
826 | |||
827 | avPoints[0][0] = vCenter[0] + cData.vBoxHalfSize[iB1] * vAxis1[0] - cData.vBoxHalfSize[iB2] * vAxis2[0]; | ||
828 | avPoints[0][1] = vCenter[1] + cData.vBoxHalfSize[iB1] * vAxis1[1] - cData.vBoxHalfSize[iB2] * vAxis2[1]; | ||
829 | avPoints[0][2] = vCenter[2] + cData.vBoxHalfSize[iB1] * vAxis1[2] - cData.vBoxHalfSize[iB2] * vAxis2[2]; | ||
830 | |||
831 | avPoints[1][0] = vCenter[0] - cData.vBoxHalfSize[iB1] * vAxis1[0] - cData.vBoxHalfSize[iB2] * vAxis2[0]; | ||
832 | avPoints[1][1] = vCenter[1] - cData.vBoxHalfSize[iB1] * vAxis1[1] - cData.vBoxHalfSize[iB2] * vAxis2[1]; | ||
833 | avPoints[1][2] = vCenter[2] - cData.vBoxHalfSize[iB1] * vAxis1[2] - cData.vBoxHalfSize[iB2] * vAxis2[2]; | ||
834 | |||
835 | avPoints[2][0] = vCenter[0] - cData.vBoxHalfSize[iB1] * vAxis1[0] + cData.vBoxHalfSize[iB2] * vAxis2[0]; | ||
836 | avPoints[2][1] = vCenter[1] - cData.vBoxHalfSize[iB1] * vAxis1[1] + cData.vBoxHalfSize[iB2] * vAxis2[1]; | ||
837 | avPoints[2][2] = vCenter[2] - cData.vBoxHalfSize[iB1] * vAxis1[2] + cData.vBoxHalfSize[iB2] * vAxis2[2]; | ||
838 | |||
839 | avPoints[3][0] = vCenter[0] + cData.vBoxHalfSize[iB1] * vAxis1[0] + cData.vBoxHalfSize[iB2] * vAxis2[0]; | ||
840 | avPoints[3][1] = vCenter[1] + cData.vBoxHalfSize[iB1] * vAxis1[1] + cData.vBoxHalfSize[iB2] * vAxis2[1]; | ||
841 | avPoints[3][2] = vCenter[2] + cData.vBoxHalfSize[iB1] * vAxis1[2] + cData.vBoxHalfSize[iB2] * vAxis2[2]; | ||
842 | |||
843 | // transform box points to space of cylinder circle | ||
844 | dMatrix3 mCylinderInv; | ||
845 | dMatrix3Inv(cData.mCylinderRot,mCylinderInv); | ||
846 | |||
847 | for(i=0; i<4; i++) | ||
848 | { | ||
849 | dVector3Subtract(avPoints[i],vCylinderCirclePos,vTemp); | ||
850 | dMultiplyMat3Vec3(mCylinderInv,vTemp,avPoints[i]); | ||
851 | } | ||
852 | |||
853 | int iTmpCounter1 = 0; | ||
854 | int iTmpCounter2 = 0; | ||
855 | dVector4 plPlane; | ||
856 | |||
857 | // plane of cylinder that contains circle for intersection | ||
858 | dConstructPlane(vCylinderCircleNormal_Rel,REAL(0.0),plPlane); | ||
859 | dClipPolyToPlane(avPoints, 4, avTempArray1, iTmpCounter1, plPlane); | ||
860 | |||
861 | |||
862 | // Body of base circle of Cylinder | ||
863 | int nCircleSegment = 0; | ||
864 | for (nCircleSegment = 0; nCircleSegment < nCYLINDER_SEGMENT; nCircleSegment++) | ||
865 | { | ||
866 | dConstructPlane(cData.avCylinderNormals[nCircleSegment],cData.fCylinderRadius,plPlane); | ||
867 | |||
868 | if (0 == (nCircleSegment % 2)) | ||
869 | { | ||
870 | dClipPolyToPlane( avTempArray1 , iTmpCounter1 , avTempArray2, iTmpCounter2, plPlane); | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | dClipPolyToPlane( avTempArray2, iTmpCounter2, avTempArray1 , iTmpCounter1 , plPlane ); | ||
875 | } | ||
876 | |||
877 | dIASSERT( iTmpCounter1 >= 0 && iTmpCounter1 <= MAX_CYLBOX_CLIP_POINTS ); | ||
878 | dIASSERT( iTmpCounter2 >= 0 && iTmpCounter2 <= MAX_CYLBOX_CLIP_POINTS ); | ||
879 | } | ||
880 | |||
881 | // back transform clipped points to absolute space | ||
882 | dReal ftmpdot; | ||
883 | dReal fTempDepth; | ||
884 | dVector3 vPoint; | ||
885 | |||
886 | if (nCircleSegment % 2) | ||
887 | { | ||
888 | for( i=0; i<iTmpCounter2; i++) | ||
889 | { | ||
890 | dMULTIPLY0_331(vPoint,cData.mCylinderRot,avTempArray2[i]); | ||
891 | vPoint[0] += vCylinderCirclePos[0]; | ||
892 | vPoint[1] += vCylinderCirclePos[1]; | ||
893 | vPoint[2] += vCylinderCirclePos[2]; | ||
894 | |||
895 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
896 | ftmpdot = dVector3Dot(vTemp, cData.vNormal); | ||
897 | fTempDepth = cData.fBestrc - ftmpdot; | ||
898 | // Depth must be positive | ||
899 | if (fTempDepth > REAL(0.0)) | ||
900 | { | ||
901 | // generate contacts | ||
902 | dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); | ||
903 | Contact0->depth = fTempDepth; | ||
904 | dVector3Copy(cData.vNormal,Contact0->normal); | ||
905 | dVector3Copy(vPoint,Contact0->pos); | ||
906 | Contact0->g1 = cData.gCylinder; | ||
907 | Contact0->g2 = cData.gBox; | ||
908 | dVector3Inv(Contact0->normal); | ||
909 | cData.nContacts++; | ||
910 | |||
911 | if (cData.nContacts == (cData.iFlags & NUMC_MASK)) | ||
912 | { | ||
913 | break; | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | } | ||
918 | else | ||
919 | { | ||
920 | for( i=0; i<iTmpCounter1; i++) | ||
921 | { | ||
922 | dMULTIPLY0_331(vPoint,cData.mCylinderRot,avTempArray1[i]); | ||
923 | vPoint[0] += vCylinderCirclePos[0]; | ||
924 | vPoint[1] += vCylinderCirclePos[1]; | ||
925 | vPoint[2] += vCylinderCirclePos[2]; | ||
926 | |||
927 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
928 | ftmpdot = dVector3Dot(vTemp, cData.vNormal); | ||
929 | fTempDepth = cData.fBestrc - ftmpdot; | ||
930 | // Depth must be positive | ||
931 | if (fTempDepth > REAL(0.0)) | ||
932 | { | ||
933 | // generate contacts | ||
934 | dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); | ||
935 | Contact0->depth = fTempDepth; | ||
936 | dVector3Copy(cData.vNormal,Contact0->normal); | ||
937 | dVector3Copy(vPoint,Contact0->pos); | ||
938 | Contact0->g1 = cData.gCylinder; | ||
939 | Contact0->g2 = cData.gBox; | ||
940 | dVector3Inv(Contact0->normal); | ||
941 | cData.nContacts++; | ||
942 | |||
943 | if (cData.nContacts == (cData.iFlags & NUMC_MASK)) | ||
944 | { | ||
945 | break; | ||
946 | } | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | |||
952 | |||
953 | // Cylinder - Box by CroTeam | ||
954 | // Ported by Nguyen Binh | ||
955 | int dCollideCylinderBox(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
956 | { | ||
957 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
958 | dIASSERT (o1->type == dCylinderClass); | ||
959 | dIASSERT (o2->type == dBoxClass); | ||
960 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
961 | |||
962 | sCylinderBoxData cData; | ||
963 | |||
964 | // Assign ODE stuff | ||
965 | cData.gCylinder = o1; | ||
966 | cData.gBox = o2; | ||
967 | cData.iFlags = flags; | ||
968 | cData.iSkip = skip; | ||
969 | cData.gContact = contact; | ||
970 | |||
971 | // initialize collider | ||
972 | _cldInitCylinderBox( cData ); | ||
973 | |||
974 | // do intersection test and find best separating axis | ||
975 | if(!_cldTestSeparatingAxes( cData ) ) | ||
976 | { | ||
977 | // if not found do nothing | ||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | // if best separation axis is not found | ||
982 | if ( cData.iBestAxis == 0 ) | ||
983 | { | ||
984 | // this should not happen (we should already exit in that case) | ||
985 | dIASSERT(0); | ||
986 | // do nothing | ||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | dReal fdot = dVector3Dot(cData.vNormal,cData.vCylinderAxis); | ||
991 | // choose which clipping method are we going to apply | ||
992 | if (dFabs(fdot) < REAL(0.9) ) | ||
993 | { | ||
994 | // clip cylinder over box | ||
995 | if(!_cldClipCylinderToBox(cData)) | ||
996 | { | ||
997 | return 0; | ||
998 | } | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | _cldClipBoxToCylinder(cData); | ||
1003 | } | ||
1004 | |||
1005 | return cData.nContacts; | ||
1006 | } | ||
1007 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_cylinder_plane.cpp b/libraries/ode-0.9\/ode/src/collision_cylinder_plane.cpp new file mode 100755 index 0000000..f85701d --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_cylinder_plane.cpp | |||
@@ -0,0 +1,254 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | |||
24 | /* | ||
25 | * Cylinder-Plane collider by Christoph Beyer ( boernerb@web.de ) | ||
26 | * | ||
27 | * This testing basically comes down to testing the intersection | ||
28 | * of the cylinder caps (discs) with the plane. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <ode/collision.h> | ||
33 | #include <ode/matrix.h> | ||
34 | #include <ode/rotation.h> | ||
35 | #include <ode/odemath.h> | ||
36 | #include <ode/objects.h> | ||
37 | |||
38 | #include "collision_kernel.h" // for dxGeom | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | |||
42 | int dCollideCylinderPlane(dxGeom *Cylinder, dxGeom *Plane, int flags, dContactGeom *contact, int skip) | ||
43 | { | ||
44 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
45 | dIASSERT (Cylinder->type == dCylinderClass); | ||
46 | dIASSERT (Plane->type == dPlaneClass); | ||
47 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
48 | |||
49 | int GeomCount = 0; // count of used contactgeoms | ||
50 | |||
51 | #ifdef dSINGLE | ||
52 | const dReal toleranz = REAL(0.0001); | ||
53 | #endif | ||
54 | #ifdef dDOUBLE | ||
55 | const dReal toleranz = REAL(0.0000001); | ||
56 | #endif | ||
57 | |||
58 | // Get the properties of the cylinder (length+radius) | ||
59 | dReal radius, length; | ||
60 | dGeomCylinderGetParams(Cylinder, &radius, &length); | ||
61 | dVector3 &cylpos = Cylinder->final_posr->pos; | ||
62 | // and the plane | ||
63 | dVector4 planevec; | ||
64 | dGeomPlaneGetParams(Plane, planevec); | ||
65 | dVector3 PlaneNormal = {planevec[0],planevec[1],planevec[2]}; | ||
66 | dVector3 PlanePos = {planevec[0] * planevec[3],planevec[1] * planevec[3],planevec[2] * planevec[3]}; | ||
67 | |||
68 | dVector3 G1Pos1, G1Pos2, vDir1; | ||
69 | vDir1[0] = Cylinder->final_posr->R[2]; | ||
70 | vDir1[1] = Cylinder->final_posr->R[6]; | ||
71 | vDir1[2] = Cylinder->final_posr->R[10]; | ||
72 | |||
73 | dReal s; | ||
74 | s = length * REAL(0.5); | ||
75 | G1Pos2[0] = vDir1[0] * s + cylpos[0]; | ||
76 | G1Pos2[1] = vDir1[1] * s + cylpos[1]; | ||
77 | G1Pos2[2] = vDir1[2] * s + cylpos[2]; | ||
78 | |||
79 | G1Pos1[0] = vDir1[0] * -s + cylpos[0]; | ||
80 | G1Pos1[1] = vDir1[1] * -s + cylpos[1]; | ||
81 | G1Pos1[2] = vDir1[2] * -s + cylpos[2]; | ||
82 | |||
83 | dVector3 C; | ||
84 | |||
85 | // parallel-check | ||
86 | s = vDir1[0] * PlaneNormal[0] + vDir1[1] * PlaneNormal[1] + vDir1[2] * PlaneNormal[2]; | ||
87 | if(s < 0) | ||
88 | s += REAL(1.0); // is ca. 0, if vDir1 and PlaneNormal are parallel | ||
89 | else | ||
90 | s -= REAL(1.0); // is ca. 0, if vDir1 and PlaneNormal are parallel | ||
91 | if(s < toleranz && s > (-toleranz)) | ||
92 | { | ||
93 | // discs are parallel to the plane | ||
94 | |||
95 | // 1.compute if, and where contacts are | ||
96 | dVector3 P; | ||
97 | s = planevec[3] - dVector3Dot(planevec, G1Pos1); | ||
98 | dReal t; | ||
99 | t = planevec[3] - dVector3Dot(planevec, G1Pos2); | ||
100 | if(s >= t) // s == t does never happen, | ||
101 | { | ||
102 | if(s >= 0) | ||
103 | { | ||
104 | // 1. Disc | ||
105 | dVector3Copy(G1Pos1, P); | ||
106 | } | ||
107 | else | ||
108 | return GeomCount; // no contacts | ||
109 | } | ||
110 | else | ||
111 | { | ||
112 | if(t >= 0) | ||
113 | { | ||
114 | // 2. Disc | ||
115 | dVector3Copy(G1Pos2, P); | ||
116 | } | ||
117 | else | ||
118 | return GeomCount; // no contacts | ||
119 | } | ||
120 | |||
121 | // 2. generate a coordinate-system on the disc | ||
122 | dVector3 V1, V2; | ||
123 | if(vDir1[0] < toleranz && vDir1[0] > (-toleranz)) | ||
124 | { | ||
125 | // not x-axis | ||
126 | V1[0] = vDir1[0] + REAL(1.0); // random value | ||
127 | V1[1] = vDir1[1]; | ||
128 | V1[2] = vDir1[2]; | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | // maybe x-axis | ||
133 | V1[0] = vDir1[0]; | ||
134 | V1[1] = vDir1[1] + REAL(1.0); // random value | ||
135 | V1[2] = vDir1[2]; | ||
136 | } | ||
137 | // V1 is now another direction than vDir1 | ||
138 | // Cross-product | ||
139 | dVector3Cross(V1, vDir1, V2); | ||
140 | // make unit V2 | ||
141 | t = dVector3Length(V2); | ||
142 | t = radius / t; | ||
143 | dVector3Scale(V2, t); | ||
144 | // cross again | ||
145 | dVector3Cross(V2, vDir1, V1); | ||
146 | // |V2| is 'radius' and vDir1 unit, so |V1| is 'radius' | ||
147 | // V1 = first axis | ||
148 | // V2 = second axis | ||
149 | |||
150 | // 3. generate contactpoints | ||
151 | |||
152 | // Potential contact 1 | ||
153 | dVector3Add(P, V1, contact->pos); | ||
154 | contact->depth = planevec[3] - dVector3Dot(planevec, contact->pos); | ||
155 | if(contact->depth > 0) | ||
156 | { | ||
157 | dVector3Copy(PlaneNormal, contact->normal); | ||
158 | contact->g1 = Cylinder; | ||
159 | contact->g2 = Plane; | ||
160 | GeomCount++; | ||
161 | if( GeomCount >= (flags & NUMC_MASK)) | ||
162 | return GeomCount; // enough contactgeoms | ||
163 | contact = (dContactGeom *)((char *)contact + skip); | ||
164 | } | ||
165 | |||
166 | // Potential contact 2 | ||
167 | dVector3Subtract(P, V1, contact->pos); | ||
168 | contact->depth = planevec[3] - dVector3Dot(planevec, contact->pos); | ||
169 | if(contact->depth > 0) | ||
170 | { | ||
171 | dVector3Copy(PlaneNormal, contact->normal); | ||
172 | contact->g1 = Cylinder; | ||
173 | contact->g2 = Plane; | ||
174 | GeomCount++; | ||
175 | if( GeomCount >= (flags & NUMC_MASK)) | ||
176 | return GeomCount; // enough contactgeoms | ||
177 | contact = (dContactGeom *)((char *)contact + skip); | ||
178 | } | ||
179 | |||
180 | // Potential contact 3 | ||
181 | dVector3Add(P, V2, contact->pos); | ||
182 | contact->depth = planevec[3] - dVector3Dot(planevec, contact->pos); | ||
183 | if(contact->depth > 0) | ||
184 | { | ||
185 | dVector3Copy(PlaneNormal, contact->normal); | ||
186 | contact->g1 = Cylinder; | ||
187 | contact->g2 = Plane; | ||
188 | GeomCount++; | ||
189 | if( GeomCount >= (flags & NUMC_MASK)) | ||
190 | return GeomCount; // enough contactgeoms | ||
191 | contact = (dContactGeom *)((char *)contact + skip); | ||
192 | } | ||
193 | |||
194 | // Potential contact 4 | ||
195 | dVector3Subtract(P, V2, contact->pos); | ||
196 | contact->depth = planevec[3] - dVector3Dot(planevec, contact->pos); | ||
197 | if(contact->depth > 0) | ||
198 | { | ||
199 | dVector3Copy(PlaneNormal, contact->normal); | ||
200 | contact->g1 = Cylinder; | ||
201 | contact->g2 = Plane; | ||
202 | GeomCount++; | ||
203 | if( GeomCount >= (flags & NUMC_MASK)) | ||
204 | return GeomCount; // enough contactgeoms | ||
205 | contact = (dContactGeom *)((char *)contact + skip); | ||
206 | } | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | dReal t = dVector3Dot(PlaneNormal, vDir1); | ||
211 | C[0] = vDir1[0] * t - PlaneNormal[0]; | ||
212 | C[1] = vDir1[1] * t - PlaneNormal[1]; | ||
213 | C[2] = vDir1[2] * t - PlaneNormal[2]; | ||
214 | s = dVector3Length(C); | ||
215 | // move C onto the circle | ||
216 | s = radius / s; | ||
217 | dVector3Scale(C, s); | ||
218 | |||
219 | // deepest point of disc 1 | ||
220 | dVector3Add(C, G1Pos1, contact->pos); | ||
221 | |||
222 | // depth of the deepest point | ||
223 | contact->depth = planevec[3] - dVector3Dot(planevec, contact->pos); | ||
224 | if(contact->depth >= 0) | ||
225 | { | ||
226 | dVector3Copy(PlaneNormal, contact->normal); | ||
227 | contact->g1 = Cylinder; | ||
228 | contact->g2 = Plane; | ||
229 | GeomCount++; | ||
230 | if( GeomCount >= (flags & NUMC_MASK)) | ||
231 | return GeomCount; // enough contactgeoms | ||
232 | contact = (dContactGeom *)((char *)contact + skip); | ||
233 | } | ||
234 | |||
235 | // C is still computed | ||
236 | |||
237 | // deepest point of disc 2 | ||
238 | dVector3Add(C, G1Pos2, contact->pos); | ||
239 | |||
240 | // depth of the deepest point | ||
241 | contact->depth = planevec[3] - planevec[0] * contact->pos[0] - planevec[1] * contact->pos[1] - planevec[2] * contact->pos[2]; | ||
242 | if(contact->depth >= 0) | ||
243 | { | ||
244 | dVector3Copy(PlaneNormal, contact->normal); | ||
245 | contact->g1 = Cylinder; | ||
246 | contact->g2 = Plane; | ||
247 | GeomCount++; | ||
248 | if( GeomCount >= (flags & NUMC_MASK)) | ||
249 | return GeomCount; // enough contactgeoms | ||
250 | contact = (dContactGeom *)((char *)contact + skip); | ||
251 | } | ||
252 | } | ||
253 | return GeomCount; | ||
254 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_cylinder_sphere.cpp b/libraries/ode-0.9\/ode/src/collision_cylinder_sphere.cpp new file mode 100755 index 0000000..964c531 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_cylinder_sphere.cpp | |||
@@ -0,0 +1,264 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | |||
24 | /******************************************************************* | ||
25 | * * | ||
26 | * cylinder-sphere collider by Christoph Beyer (boernerb@web.de) * | ||
27 | * * | ||
28 | * In Cylinder/Sphere-collisions, there are three possibilies: * | ||
29 | * 1. collision with the cylinder's nappe * | ||
30 | * 2. collision with one of the cylinder's disc * | ||
31 | * 3. collision with one of the disc's border * | ||
32 | * * | ||
33 | * This collider computes two distances (s, t) and based on them, * | ||
34 | * it decides, which collision we have. * | ||
35 | * This collider always generates 1 (or 0, if we have no collison) * | ||
36 | * contacts. * | ||
37 | * It is able to "separate" cylinder and sphere in all * | ||
38 | * configurations, but it never pays attention to velocity. * | ||
39 | * So, in extrem situations, "tunneling-effect" is possible. * | ||
40 | * * | ||
41 | *******************************************************************/ | ||
42 | |||
43 | #include <ode/collision.h> | ||
44 | #include <ode/matrix.h> | ||
45 | #include <ode/rotation.h> | ||
46 | #include <ode/odemath.h> | ||
47 | #include <ode/objects.h> | ||
48 | #include "collision_kernel.h" // for dxGeom | ||
49 | #include "collision_util.h" | ||
50 | |||
51 | int dCollideCylinderSphere(dxGeom* Cylinder, dxGeom* Sphere, | ||
52 | int flags, dContactGeom *contact, int skip) | ||
53 | { | ||
54 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
55 | dIASSERT (Cylinder->type == dCylinderClass); | ||
56 | dIASSERT (Sphere->type == dSphereClass); | ||
57 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
58 | |||
59 | unsigned char* pContactData = (unsigned char*)contact; | ||
60 | int GeomCount = 0; // count of used contacts | ||
61 | |||
62 | #ifdef dSINGLE | ||
63 | const dReal toleranz = REAL(0.0001); | ||
64 | #endif | ||
65 | #ifdef dDOUBLE | ||
66 | const dReal toleranz = REAL(0.0000001); | ||
67 | #endif | ||
68 | |||
69 | // get the data from the geoms | ||
70 | dReal radius, length; | ||
71 | dGeomCylinderGetParams(Cylinder, &radius, &length); | ||
72 | dVector3 &cylpos = Cylinder->final_posr->pos; | ||
73 | const dReal* pfRot1 = dGeomGetRotation(Cylinder); | ||
74 | |||
75 | dReal radius2; | ||
76 | radius2 = dGeomSphereGetRadius(Sphere); | ||
77 | const dReal* SpherePos = dGeomGetPosition(Sphere); | ||
78 | |||
79 | // G1Pos1 is the middle of the first disc | ||
80 | // G1Pos2 is the middle of the second disc | ||
81 | // vDir1 is the unit direction of the cylinderaxis | ||
82 | dVector3 G1Pos1, G1Pos2, vDir1; | ||
83 | vDir1[0] = Cylinder->final_posr->R[2]; | ||
84 | vDir1[1] = Cylinder->final_posr->R[6]; | ||
85 | vDir1[2] = Cylinder->final_posr->R[10]; | ||
86 | |||
87 | dReal s; | ||
88 | s = length * REAL(0.5); // just a precomputed factor | ||
89 | G1Pos2[0] = vDir1[0] * s + cylpos[0]; | ||
90 | G1Pos2[1] = vDir1[1] * s + cylpos[1]; | ||
91 | G1Pos2[2] = vDir1[2] * s + cylpos[2]; | ||
92 | |||
93 | G1Pos1[0] = vDir1[0] * -s + cylpos[0]; | ||
94 | G1Pos1[1] = vDir1[1] * -s + cylpos[1]; | ||
95 | G1Pos1[2] = vDir1[2] * -s + cylpos[2]; | ||
96 | |||
97 | dVector3 C; | ||
98 | dReal t; | ||
99 | // Step 1: compute the two distances 's' and 't' | ||
100 | // 's' is the distance from the first disc (in vDir1-/Zylinderaxis-direction), the disc with G1Pos1 in the middle | ||
101 | s = (SpherePos[0] - G1Pos1[0]) * vDir1[0] - (G1Pos1[1] - SpherePos[1]) * vDir1[1] - (G1Pos1[2] - SpherePos[2]) * vDir1[2]; | ||
102 | if(s < (-radius2) || s > (length + radius2) ) | ||
103 | { | ||
104 | // Sphere is too far away from the discs | ||
105 | // no collision | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | // C is the direction from Sphere-middle to the cylinder-axis (vDir1); C is orthogonal to the cylinder-axis | ||
110 | C[0] = s * vDir1[0] + G1Pos1[0] - SpherePos[0]; | ||
111 | C[1] = s * vDir1[1] + G1Pos1[1] - SpherePos[1]; | ||
112 | C[2] = s * vDir1[2] + G1Pos1[2] - SpherePos[2]; | ||
113 | // t is the distance from the Sphere-middle to the cylinder-axis! | ||
114 | t = dVector3Length(C); | ||
115 | if(t > (radius + radius2) ) | ||
116 | { | ||
117 | // Sphere is too far away from the cylinder axis! | ||
118 | // no collision | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | // decide which kind of collision we have: | ||
123 | if(t > radius && (s < 0 || s > length) ) | ||
124 | { | ||
125 | // 3. collision | ||
126 | if(s <= 0) | ||
127 | { | ||
128 | contact->depth = radius2 - dSqrt( (s) * (s) + (t - radius) * (t - radius) ); | ||
129 | if(contact->depth < 0) | ||
130 | { | ||
131 | // no collision! | ||
132 | return 0; | ||
133 | } | ||
134 | contact->pos[0] = C[0] / t * -radius + G1Pos1[0]; | ||
135 | contact->pos[1] = C[1] / t * -radius + G1Pos1[1]; | ||
136 | contact->pos[2] = C[2] / t * -radius + G1Pos1[2]; | ||
137 | contact->normal[0] = (contact->pos[0] - SpherePos[0]) / (radius2 - contact->depth); | ||
138 | contact->normal[1] = (contact->pos[1] - SpherePos[1]) / (radius2 - contact->depth); | ||
139 | contact->normal[2] = (contact->pos[2] - SpherePos[2]) / (radius2 - contact->depth); | ||
140 | contact->g1 = Cylinder; | ||
141 | contact->g2 = Sphere; | ||
142 | GeomCount++; | ||
143 | return GeomCount; | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | // now s is bigger than length here! | ||
148 | contact->depth = radius2 - dSqrt( (s - length) * (s - length) + (t - radius) * (t - radius) ); | ||
149 | if(contact->depth < 0) | ||
150 | { | ||
151 | // no collision! | ||
152 | return 0; | ||
153 | } | ||
154 | contact->pos[0] = C[0] / t * -radius + G1Pos2[0]; | ||
155 | contact->pos[1] = C[1] / t * -radius + G1Pos2[1]; | ||
156 | contact->pos[2] = C[2] / t * -radius + G1Pos2[2]; | ||
157 | contact->normal[0] = (contact->pos[0] - SpherePos[0]) / (radius2 - contact->depth); | ||
158 | contact->normal[1] = (contact->pos[1] - SpherePos[1]) / (radius2 - contact->depth); | ||
159 | contact->normal[2] = (contact->pos[2] - SpherePos[2]) / (radius2 - contact->depth); | ||
160 | contact->g1 = Cylinder; | ||
161 | contact->g2 = Sphere; | ||
162 | GeomCount++; | ||
163 | return GeomCount; | ||
164 | } | ||
165 | } | ||
166 | else if( (radius - t) <= s && (radius - t) <= (length - s) ) | ||
167 | { | ||
168 | // 1. collsision | ||
169 | if(t > (radius2 + toleranz)) | ||
170 | { | ||
171 | // cylinder-axis is outside the sphere | ||
172 | contact->depth = (radius2 + radius) - t; | ||
173 | if(contact->depth < 0) | ||
174 | { | ||
175 | // should never happen, but just for safeness | ||
176 | return 0; | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | C[0] /= t; | ||
181 | C[1] /= t; | ||
182 | C[2] /= t; | ||
183 | contact->pos[0] = C[0] * radius2 + SpherePos[0]; | ||
184 | contact->pos[1] = C[1] * radius2 + SpherePos[1]; | ||
185 | contact->pos[2] = C[2] * radius2 + SpherePos[2]; | ||
186 | contact->normal[0] = C[0]; | ||
187 | contact->normal[1] = C[1]; | ||
188 | contact->normal[2] = C[2]; | ||
189 | contact->g1 = Cylinder; | ||
190 | contact->g2 = Sphere; | ||
191 | GeomCount++; | ||
192 | return GeomCount; | ||
193 | } | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | // cylinder-axis is outside of the sphere | ||
198 | contact->depth = (radius2 + radius) - t; | ||
199 | if(contact->depth < 0) | ||
200 | { | ||
201 | // should never happen, but just for safeness | ||
202 | return 0; | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | contact->pos[0] = C[0] + SpherePos[0]; | ||
207 | contact->pos[1] = C[1] + SpherePos[1]; | ||
208 | contact->pos[2] = C[2] + SpherePos[2]; | ||
209 | contact->normal[0] = C[0] / t; | ||
210 | contact->normal[1] = C[1] / t; | ||
211 | contact->normal[2] = C[2] / t; | ||
212 | contact->g1 = Cylinder; | ||
213 | contact->g2 = Sphere; | ||
214 | GeomCount++; | ||
215 | return GeomCount; | ||
216 | } | ||
217 | } | ||
218 | } | ||
219 | else | ||
220 | { | ||
221 | // 2. collision | ||
222 | if(s <= (length * REAL(0.5)) ) | ||
223 | { | ||
224 | // collsision with the first disc | ||
225 | contact->depth = s + radius2; | ||
226 | if(contact->depth < 0) | ||
227 | { | ||
228 | // should never happen, but just for safeness | ||
229 | return 0; | ||
230 | } | ||
231 | contact->pos[0] = radius2 * vDir1[0] + SpherePos[0]; | ||
232 | contact->pos[1] = radius2 * vDir1[1] + SpherePos[1]; | ||
233 | contact->pos[2] = radius2 * vDir1[2] + SpherePos[2]; | ||
234 | contact->normal[0] = vDir1[0]; | ||
235 | contact->normal[1] = vDir1[1]; | ||
236 | contact->normal[2] = vDir1[2]; | ||
237 | contact->g1 = Cylinder; | ||
238 | contact->g2 = Sphere; | ||
239 | GeomCount++; | ||
240 | return GeomCount; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | // collsision with the second disc | ||
245 | contact->depth = (radius2 + length - s); | ||
246 | if(contact->depth < 0) | ||
247 | { | ||
248 | // should never happen, but just for safeness | ||
249 | return 0; | ||
250 | } | ||
251 | contact->pos[0] = radius2 * -vDir1[0] + SpherePos[0]; | ||
252 | contact->pos[1] = radius2 * -vDir1[1] + SpherePos[1]; | ||
253 | contact->pos[2] = radius2 * -vDir1[2] + SpherePos[2]; | ||
254 | contact->normal[0] = -vDir1[0]; | ||
255 | contact->normal[1] = -vDir1[1]; | ||
256 | contact->normal[2] = -vDir1[2]; | ||
257 | contact->g1 = Cylinder; | ||
258 | contact->g2 = Sphere; | ||
259 | GeomCount++; | ||
260 | return GeomCount; | ||
261 | } | ||
262 | } | ||
263 | return GeomCount; | ||
264 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_cylinder_trimesh.cpp b/libraries/ode-0.9\/ode/src/collision_cylinder_trimesh.cpp new file mode 100755 index 0000000..342be04 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_cylinder_trimesh.cpp | |||
@@ -0,0 +1,1145 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | * Cylinder-trimesh collider by Alen Ladavac | ||
25 | * Ported to ODE by Nguyen Binh | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | #include "collision_util.h" | ||
34 | |||
35 | #define TRIMESH_INTERNAL | ||
36 | #include "collision_trimesh_internal.h" | ||
37 | |||
38 | #define MAX_REAL dInfinity | ||
39 | static const int nCYLINDER_AXIS = 2; | ||
40 | static const int nCYLINDER_CIRCLE_SEGMENTS = 8; | ||
41 | static const int nMAX_CYLINDER_TRIANGLE_CLIP_POINTS = 12; | ||
42 | |||
43 | #define OPTIMIZE_CONTACTS 1 | ||
44 | |||
45 | // Local contacts data | ||
46 | typedef struct _sLocalContactData | ||
47 | { | ||
48 | dVector3 vPos; | ||
49 | dVector3 vNormal; | ||
50 | dReal fDepth; | ||
51 | int triIndex; | ||
52 | int nFlags; // 0 = filtered out, 1 = OK | ||
53 | }sLocalContactData; | ||
54 | |||
55 | typedef struct _sCylinderTrimeshColliderData | ||
56 | { | ||
57 | // cylinder data | ||
58 | dMatrix3 mCylinderRot; | ||
59 | dQuaternion qCylinderRot; | ||
60 | dQuaternion qInvCylinderRot; | ||
61 | dVector3 vCylinderPos; | ||
62 | dVector3 vCylinderAxis; | ||
63 | dReal fCylinderRadius; | ||
64 | dReal fCylinderSize; | ||
65 | dVector3 avCylinderNormals[nCYLINDER_CIRCLE_SEGMENTS]; | ||
66 | |||
67 | // mesh data | ||
68 | dQuaternion qTrimeshRot; | ||
69 | dQuaternion qInvTrimeshRot; | ||
70 | dMatrix3 mTrimeshRot; | ||
71 | dVector3 vTrimeshPos; | ||
72 | |||
73 | // global collider data | ||
74 | dVector3 vBestPoint; | ||
75 | dReal fBestDepth; | ||
76 | dReal fBestCenter; | ||
77 | dReal fBestrt; | ||
78 | int iBestAxis; | ||
79 | dVector3 vContactNormal; | ||
80 | dVector3 vNormal; | ||
81 | dVector3 vE0; | ||
82 | dVector3 vE1; | ||
83 | dVector3 vE2; | ||
84 | |||
85 | // ODE stuff | ||
86 | dGeomID gCylinder; | ||
87 | dxTriMesh* gTrimesh; | ||
88 | dContactGeom* gContact; | ||
89 | int iFlags; | ||
90 | int iSkip; | ||
91 | int nContacts;// = 0; | ||
92 | sLocalContactData* gLocalContacts; | ||
93 | } sCylinderTrimeshColliderData; | ||
94 | |||
95 | // Short type name | ||
96 | typedef sCylinderTrimeshColliderData sData; | ||
97 | |||
98 | // Use to classify contacts to be "near" in position | ||
99 | static const dReal fSameContactPositionEpsilon = REAL(0.0001); // 1e-4 | ||
100 | // Use to classify contacts to be "near" in normal direction | ||
101 | static const dReal fSameContactNormalEpsilon = REAL(0.0001); // 1e-4 | ||
102 | |||
103 | // If this two contact can be classified as "near" | ||
104 | inline int _IsNearContacts(sLocalContactData& c1,sLocalContactData& c2) | ||
105 | { | ||
106 | int bPosNear = 0; | ||
107 | int bSameDir = 0; | ||
108 | dVector3 vDiff; | ||
109 | |||
110 | // First check if they are "near" in position | ||
111 | dVector3Subtract(c1.vPos,c2.vPos,vDiff); | ||
112 | if ( (dFabs(vDiff[0]) < fSameContactPositionEpsilon) | ||
113 | &&(dFabs(vDiff[1]) < fSameContactPositionEpsilon) | ||
114 | &&(dFabs(vDiff[2]) < fSameContactPositionEpsilon)) | ||
115 | { | ||
116 | bPosNear = 1; | ||
117 | } | ||
118 | |||
119 | // Second check if they are "near" in normal direction | ||
120 | dVector3Subtract(c1.vNormal,c2.vNormal,vDiff); | ||
121 | if ( (dFabs(vDiff[0]) < fSameContactNormalEpsilon) | ||
122 | &&(dFabs(vDiff[1]) < fSameContactNormalEpsilon) | ||
123 | &&(dFabs(vDiff[2]) < fSameContactNormalEpsilon) ) | ||
124 | { | ||
125 | bSameDir = 1; | ||
126 | } | ||
127 | |||
128 | // Will be "near" if position and normal direction are "near" | ||
129 | return (bPosNear && bSameDir); | ||
130 | } | ||
131 | |||
132 | inline int _IsBetter(sLocalContactData& c1,sLocalContactData& c2) | ||
133 | { | ||
134 | // The not better will be throw away | ||
135 | // You can change the selection criteria here | ||
136 | return (c1.fDepth > c2.fDepth); | ||
137 | } | ||
138 | |||
139 | // iterate through gLocalContacts and filtered out "near contact" | ||
140 | inline void _OptimizeLocalContacts(sData& cData) | ||
141 | { | ||
142 | int nContacts = cData.nContacts; | ||
143 | |||
144 | for (int i = 0; i < nContacts-1; i++) | ||
145 | { | ||
146 | for (int j = i+1; j < nContacts; j++) | ||
147 | { | ||
148 | if (_IsNearContacts(cData.gLocalContacts[i],cData.gLocalContacts[j])) | ||
149 | { | ||
150 | // If they are seem to be the same then filtered | ||
151 | // out the least penetrate one | ||
152 | if (_IsBetter(cData.gLocalContacts[j],cData.gLocalContacts[i])) | ||
153 | { | ||
154 | cData.gLocalContacts[i].nFlags = 0; // filtered 1st contact | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | cData.gLocalContacts[j].nFlags = 0; // filtered 2nd contact | ||
159 | } | ||
160 | |||
161 | // NOTE | ||
162 | // There is other way is to add two depth together but | ||
163 | // it not work so well. Why??? | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | inline int _ProcessLocalContacts(sData& cData) | ||
170 | { | ||
171 | if (cData.nContacts == 0) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | #ifdef OPTIMIZE_CONTACTS | ||
177 | if (cData.nContacts > 1 && !(cData.iFlags & CONTACTS_UNIMPORTANT)) | ||
178 | { | ||
179 | // Can be optimized... | ||
180 | _OptimizeLocalContacts(cData); | ||
181 | } | ||
182 | #endif | ||
183 | |||
184 | int iContact = 0; | ||
185 | dContactGeom* Contact = 0; | ||
186 | |||
187 | int nFinalContact = 0; | ||
188 | |||
189 | for (iContact = 0; iContact < cData.nContacts; iContact ++) | ||
190 | { | ||
191 | if (1 == cData.gLocalContacts[iContact].nFlags) | ||
192 | { | ||
193 | Contact = SAFECONTACT(cData.iFlags, cData.gContact, nFinalContact, cData.iSkip); | ||
194 | Contact->depth = cData.gLocalContacts[iContact].fDepth; | ||
195 | dVector3Copy(cData.gLocalContacts[iContact].vNormal,Contact->normal); | ||
196 | dVector3Copy(cData.gLocalContacts[iContact].vPos,Contact->pos); | ||
197 | Contact->g1 = cData.gCylinder; | ||
198 | Contact->g2 = cData.gTrimesh; | ||
199 | Contact->side2 = cData.gLocalContacts[iContact].triIndex; | ||
200 | dVector3Inv(Contact->normal); | ||
201 | |||
202 | nFinalContact++; | ||
203 | } | ||
204 | } | ||
205 | // debug | ||
206 | //if (nFinalContact != cData.nContacts) | ||
207 | //{ | ||
208 | // printf("[Info] %d contacts generated,%d filtered.\n",cData.nContacts,cData.nContacts-nFinalContact); | ||
209 | //} | ||
210 | |||
211 | return nFinalContact; | ||
212 | } | ||
213 | |||
214 | |||
215 | bool _cldTestAxis(sData& cData, | ||
216 | const dVector3 &v0, | ||
217 | const dVector3 &v1, | ||
218 | const dVector3 &v2, | ||
219 | dVector3& vAxis, | ||
220 | int iAxis, | ||
221 | bool bNoFlip = false) | ||
222 | { | ||
223 | |||
224 | // calculate length of separating axis vector | ||
225 | dReal fL = dVector3Length(vAxis); | ||
226 | // if not long enough | ||
227 | if ( fL < REAL(1e-5) ) | ||
228 | { | ||
229 | // do nothing | ||
230 | return true; | ||
231 | } | ||
232 | |||
233 | // otherwise normalize it | ||
234 | vAxis[0] /= fL; | ||
235 | vAxis[1] /= fL; | ||
236 | vAxis[2] /= fL; | ||
237 | |||
238 | dReal fdot1 = dVector3Dot(cData.vCylinderAxis,vAxis); | ||
239 | // project capsule on vAxis | ||
240 | dReal frc; | ||
241 | |||
242 | if (dFabs(fdot1) > REAL(1.0) ) | ||
243 | { | ||
244 | // fdot1 = REAL(1.0); | ||
245 | frc = dFabs(cData.fCylinderSize* REAL(0.5)); | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | frc = dFabs((cData.fCylinderSize* REAL(0.5)) * fdot1) | ||
250 | + cData.fCylinderRadius * dSqrt(REAL(1.0)-(fdot1*fdot1)); | ||
251 | } | ||
252 | |||
253 | dVector3 vV0; | ||
254 | dVector3Subtract(v0,cData.vCylinderPos,vV0); | ||
255 | dVector3 vV1; | ||
256 | dVector3Subtract(v1,cData.vCylinderPos,vV1); | ||
257 | dVector3 vV2; | ||
258 | dVector3Subtract(v2,cData.vCylinderPos,vV2); | ||
259 | |||
260 | // project triangle on vAxis | ||
261 | dReal afv[3]; | ||
262 | afv[0] = dVector3Dot( vV0 , vAxis ); | ||
263 | afv[1] = dVector3Dot( vV1 , vAxis ); | ||
264 | afv[2] = dVector3Dot( vV2 , vAxis ); | ||
265 | |||
266 | dReal fMin = MAX_REAL; | ||
267 | dReal fMax = -MAX_REAL; | ||
268 | |||
269 | // for each vertex | ||
270 | for(int i = 0; i < 3; i++) | ||
271 | { | ||
272 | // find minimum | ||
273 | if (afv[i]<fMin) | ||
274 | { | ||
275 | fMin = afv[i]; | ||
276 | } | ||
277 | // find maximum | ||
278 | if (afv[i]>fMax) | ||
279 | { | ||
280 | fMax = afv[i]; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | // find capsule's center of interval on axis | ||
285 | dReal fCenter = (fMin+fMax)* REAL(0.5); | ||
286 | // calculate triangles halfinterval | ||
287 | dReal fTriangleRadius = (fMax-fMin)*REAL(0.5); | ||
288 | |||
289 | // if they do not overlap, | ||
290 | if( dFabs(fCenter) > (frc+fTriangleRadius) ) | ||
291 | { | ||
292 | // exit, we have no intersection | ||
293 | return false; | ||
294 | } | ||
295 | |||
296 | // calculate depth | ||
297 | dReal fDepth = -(dFabs(fCenter) - (frc + fTriangleRadius ) ); | ||
298 | |||
299 | // if greater then best found so far | ||
300 | if ( fDepth < cData.fBestDepth ) | ||
301 | { | ||
302 | // remember depth | ||
303 | cData.fBestDepth = fDepth; | ||
304 | cData.fBestCenter = fCenter; | ||
305 | cData.fBestrt = frc; | ||
306 | dVector3Copy(vAxis,cData.vContactNormal); | ||
307 | cData.iBestAxis = iAxis; | ||
308 | |||
309 | // flip normal if interval is wrong faced | ||
310 | if ( fCenter< REAL(0.0) && !bNoFlip) | ||
311 | { | ||
312 | dVector3Inv(cData.vContactNormal); | ||
313 | cData.fBestCenter = -fCenter; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | return true; | ||
318 | } | ||
319 | |||
320 | // intersection test between edge and circle | ||
321 | bool _cldTestCircleToEdgeAxis(sData& cData, | ||
322 | const dVector3 &v0, const dVector3 &v1, const dVector3 &v2, | ||
323 | const dVector3 &vCenterPoint, const dVector3 &vCylinderAxis1, | ||
324 | const dVector3 &vVx0, const dVector3 &vVx1, int iAxis) | ||
325 | { | ||
326 | // calculate direction of edge | ||
327 | dVector3 vkl; | ||
328 | dVector3Subtract( vVx1 , vVx0 , vkl); | ||
329 | dNormalize3(vkl); | ||
330 | // starting point of edge | ||
331 | dVector3 vol; | ||
332 | dVector3Copy(vVx0,vol); | ||
333 | |||
334 | // calculate angle cosine between cylinder axis and edge | ||
335 | dReal fdot2 = dVector3Dot(vkl , vCylinderAxis1); | ||
336 | |||
337 | // if edge is perpendicular to cylinder axis | ||
338 | if(dFabs(fdot2)<REAL(1e-5)) | ||
339 | { | ||
340 | // this can't be separating axis, because edge is parallel to circle plane | ||
341 | return true; | ||
342 | } | ||
343 | |||
344 | // find point of intersection between edge line and circle plane | ||
345 | dVector3 vTemp; | ||
346 | dVector3Subtract(vCenterPoint,vol,vTemp); | ||
347 | dReal fdot1 = dVector3Dot(vTemp,vCylinderAxis1); | ||
348 | dVector3 vpnt;// = vol + vkl * (fdot1/fdot2); | ||
349 | vpnt[0] = vol[0] + vkl[0] * fdot1/fdot2; | ||
350 | vpnt[1] = vol[1] + vkl[1] * fdot1/fdot2; | ||
351 | vpnt[2] = vol[2] + vkl[2] * fdot1/fdot2; | ||
352 | |||
353 | // find tangent vector on circle with same center (vCenterPoint) that touches point of intersection (vpnt) | ||
354 | dVector3 vTangent; | ||
355 | dVector3Subtract(vCenterPoint,vpnt,vTemp); | ||
356 | dVector3Cross(vTemp,vCylinderAxis1,vTangent); | ||
357 | |||
358 | // find vector orthogonal both to tangent and edge direction | ||
359 | dVector3 vAxis; | ||
360 | dVector3Cross(vTangent,vkl,vAxis); | ||
361 | |||
362 | // use that vector as separating axis | ||
363 | return _cldTestAxis( cData ,v0, v1, v2, vAxis, iAxis ); | ||
364 | } | ||
365 | |||
366 | // helper for less key strokes | ||
367 | // r = ( (v1 - v2) cross v3 ) cross v3 | ||
368 | inline void _CalculateAxis(const dVector3& v1, | ||
369 | const dVector3& v2, | ||
370 | const dVector3& v3, | ||
371 | dVector3& r) | ||
372 | { | ||
373 | dVector3 t1; | ||
374 | dVector3 t2; | ||
375 | |||
376 | dVector3Subtract(v1,v2,t1); | ||
377 | dVector3Cross(t1,v3,t2); | ||
378 | dVector3Cross(t2,v3,r); | ||
379 | } | ||
380 | |||
381 | bool _cldTestSeparatingAxes(sData& cData, | ||
382 | const dVector3 &v0, | ||
383 | const dVector3 &v1, | ||
384 | const dVector3 &v2) | ||
385 | { | ||
386 | |||
387 | // calculate edge vectors | ||
388 | dVector3Subtract(v1 ,v0 , cData.vE0); | ||
389 | // cData.vE1 has been calculated before -> so save some cycles here | ||
390 | dVector3Subtract(v0 ,v2 , cData.vE2); | ||
391 | |||
392 | // calculate caps centers in absolute space | ||
393 | dVector3 vCp0; | ||
394 | vCp0[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); | ||
395 | vCp0[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); | ||
396 | vCp0[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); | ||
397 | |||
398 | dVector3 vCp1; | ||
399 | vCp1[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); | ||
400 | vCp1[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); | ||
401 | vCp1[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); | ||
402 | |||
403 | // reset best axis | ||
404 | cData.iBestAxis = 0; | ||
405 | dVector3 vAxis; | ||
406 | |||
407 | // axis cData.vNormal | ||
408 | //vAxis = -cData.vNormal; | ||
409 | vAxis[0] = -cData.vNormal[0]; | ||
410 | vAxis[1] = -cData.vNormal[1]; | ||
411 | vAxis[2] = -cData.vNormal[2]; | ||
412 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 1, true)) | ||
413 | { | ||
414 | return false; | ||
415 | } | ||
416 | |||
417 | // axis CxE0 | ||
418 | // vAxis = ( cData.vCylinderAxis cross cData.vE0 ); | ||
419 | dVector3Cross(cData.vCylinderAxis, cData.vE0,vAxis); | ||
420 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 2)) | ||
421 | { | ||
422 | return false; | ||
423 | } | ||
424 | |||
425 | // axis CxE1 | ||
426 | // vAxis = ( cData.vCylinderAxis cross cData.vE1 ); | ||
427 | dVector3Cross(cData.vCylinderAxis, cData.vE1,vAxis); | ||
428 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 3)) | ||
429 | { | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | // axis CxE2 | ||
434 | // vAxis = ( cData.vCylinderAxis cross cData.vE2 ); | ||
435 | dVector3Cross(cData.vCylinderAxis, cData.vE2,vAxis); | ||
436 | if (!_cldTestAxis( cData ,v0, v1, v2, vAxis, 4)) | ||
437 | { | ||
438 | return false; | ||
439 | } | ||
440 | |||
441 | // first vertex on triangle | ||
442 | // axis ((V0-Cp0) x C) x C | ||
443 | //vAxis = ( ( v0-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
444 | _CalculateAxis(v0 , vCp0 , cData.vCylinderAxis , vAxis); | ||
445 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 11)) | ||
446 | { | ||
447 | return false; | ||
448 | } | ||
449 | |||
450 | // second vertex on triangle | ||
451 | // axis ((V1-Cp0) x C) x C | ||
452 | // vAxis = ( ( v1-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
453 | _CalculateAxis(v1 , vCp0 , cData.vCylinderAxis , vAxis); | ||
454 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 12)) | ||
455 | { | ||
456 | return false; | ||
457 | } | ||
458 | |||
459 | // third vertex on triangle | ||
460 | // axis ((V2-Cp0) x C) x C | ||
461 | //vAxis = ( ( v2-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
462 | _CalculateAxis(v2 , vCp0 , cData.vCylinderAxis , vAxis); | ||
463 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 13)) | ||
464 | { | ||
465 | return false; | ||
466 | } | ||
467 | |||
468 | // test cylinder axis | ||
469 | // vAxis = cData.vCylinderAxis; | ||
470 | dVector3Copy(cData.vCylinderAxis , vAxis); | ||
471 | if (!_cldTestAxis(cData , v0, v1, v2, vAxis, 14)) | ||
472 | { | ||
473 | return false; | ||
474 | } | ||
475 | |||
476 | // Test top and bottom circle ring of cylinder for separation | ||
477 | dVector3 vccATop; | ||
478 | vccATop[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); | ||
479 | vccATop[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); | ||
480 | vccATop[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); | ||
481 | |||
482 | dVector3 vccABottom; | ||
483 | vccABottom[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); | ||
484 | vccABottom[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); | ||
485 | vccABottom[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); | ||
486 | |||
487 | |||
488 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v1, 15)) | ||
489 | { | ||
490 | return false; | ||
491 | } | ||
492 | |||
493 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v1, v2, 16)) | ||
494 | { | ||
495 | return false; | ||
496 | } | ||
497 | |||
498 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v2, 17)) | ||
499 | { | ||
500 | return false; | ||
501 | } | ||
502 | |||
503 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v1, 18)) | ||
504 | { | ||
505 | return false; | ||
506 | } | ||
507 | |||
508 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v1, v2, 19)) | ||
509 | { | ||
510 | return false; | ||
511 | } | ||
512 | |||
513 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v2, 20)) | ||
514 | { | ||
515 | return false; | ||
516 | } | ||
517 | |||
518 | return true; | ||
519 | } | ||
520 | |||
521 | bool _cldClipCylinderEdgeToTriangle(sData& cData, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) | ||
522 | { | ||
523 | // translate cylinder | ||
524 | dReal fTemp = dVector3Dot(cData.vCylinderAxis , cData.vContactNormal); | ||
525 | dVector3 vN2; | ||
526 | vN2[0] = cData.vContactNormal[0] - cData.vCylinderAxis[0]*fTemp; | ||
527 | vN2[1] = cData.vContactNormal[1] - cData.vCylinderAxis[1]*fTemp; | ||
528 | vN2[2] = cData.vContactNormal[2] - cData.vCylinderAxis[2]*fTemp; | ||
529 | |||
530 | fTemp = dVector3Length(vN2); | ||
531 | if (fTemp < REAL(1e-5)) | ||
532 | { | ||
533 | return false; | ||
534 | } | ||
535 | |||
536 | // Normalize it | ||
537 | vN2[0] /= fTemp; | ||
538 | vN2[1] /= fTemp; | ||
539 | vN2[2] /= fTemp; | ||
540 | |||
541 | // calculate caps centers in absolute space | ||
542 | dVector3 vCposTrans; | ||
543 | vCposTrans[0] = cData.vCylinderPos[0] + vN2[0]*cData.fCylinderRadius; | ||
544 | vCposTrans[1] = cData.vCylinderPos[1] + vN2[1]*cData.fCylinderRadius; | ||
545 | vCposTrans[2] = cData.vCylinderPos[2] + vN2[2]*cData.fCylinderRadius; | ||
546 | |||
547 | dVector3 vCEdgePoint0; | ||
548 | vCEdgePoint0[0] = vCposTrans[0] + cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); | ||
549 | vCEdgePoint0[1] = vCposTrans[1] + cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); | ||
550 | vCEdgePoint0[2] = vCposTrans[2] + cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); | ||
551 | |||
552 | dVector3 vCEdgePoint1; | ||
553 | vCEdgePoint1[0] = vCposTrans[0] - cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); | ||
554 | vCEdgePoint1[1] = vCposTrans[1] - cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); | ||
555 | vCEdgePoint1[2] = vCposTrans[2] - cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); | ||
556 | |||
557 | // transform cylinder edge points into triangle space | ||
558 | vCEdgePoint0[0] -= v0[0]; | ||
559 | vCEdgePoint0[1] -= v0[1]; | ||
560 | vCEdgePoint0[2] -= v0[2]; | ||
561 | |||
562 | vCEdgePoint1[0] -= v0[0]; | ||
563 | vCEdgePoint1[1] -= v0[1]; | ||
564 | vCEdgePoint1[2] -= v0[2]; | ||
565 | |||
566 | dVector4 plPlane; | ||
567 | dVector3 vPlaneNormal; | ||
568 | |||
569 | // triangle plane | ||
570 | //plPlane = Plane4f( -cData.vNormal, 0); | ||
571 | vPlaneNormal[0] = -cData.vNormal[0]; | ||
572 | vPlaneNormal[1] = -cData.vNormal[1]; | ||
573 | vPlaneNormal[2] = -cData.vNormal[2]; | ||
574 | dConstructPlane(vPlaneNormal,REAL(0.0),plPlane); | ||
575 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
576 | { | ||
577 | return false; | ||
578 | } | ||
579 | |||
580 | // plane with edge 0 | ||
581 | //plPlane = Plane4f( ( cData.vNormal cross cData.vE0 ), REAL(1e-5)); | ||
582 | dVector3Cross(cData.vNormal,cData.vE0,vPlaneNormal); | ||
583 | dConstructPlane(vPlaneNormal,REAL(1e-5),plPlane); | ||
584 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
585 | { | ||
586 | return false; | ||
587 | } | ||
588 | |||
589 | // plane with edge 1 | ||
590 | //dVector3 vTemp = ( cData.vNormal cross cData.vE1 ); | ||
591 | dVector3Cross(cData.vNormal,cData.vE1,vPlaneNormal); | ||
592 | fTemp = dVector3Dot(cData.vE0 , vPlaneNormal) - REAL(1e-5); | ||
593 | //plPlane = Plane4f( vTemp, -(( cData.vE0 dot vTemp )-REAL(1e-5))); | ||
594 | dConstructPlane(vPlaneNormal,-fTemp,plPlane); | ||
595 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
596 | { | ||
597 | return false; | ||
598 | } | ||
599 | |||
600 | // plane with edge 2 | ||
601 | // plPlane = Plane4f( ( cData.vNormal cross cData.vE2 ), REAL(1e-5)); | ||
602 | dVector3Cross(cData.vNormal,cData.vE2,vPlaneNormal); | ||
603 | dConstructPlane(vPlaneNormal,REAL(1e-5),plPlane); | ||
604 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
605 | { | ||
606 | return false; | ||
607 | } | ||
608 | |||
609 | // return capsule edge points into absolute space | ||
610 | vCEdgePoint0[0] += v0[0]; | ||
611 | vCEdgePoint0[1] += v0[1]; | ||
612 | vCEdgePoint0[2] += v0[2]; | ||
613 | |||
614 | vCEdgePoint1[0] += v0[0]; | ||
615 | vCEdgePoint1[1] += v0[1]; | ||
616 | vCEdgePoint1[2] += v0[2]; | ||
617 | |||
618 | // calculate depths for both contact points | ||
619 | dVector3 vTemp; | ||
620 | dVector3Subtract(vCEdgePoint0,cData.vCylinderPos, vTemp); | ||
621 | dReal fRestDepth0 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; | ||
622 | dVector3Subtract(vCEdgePoint1,cData.vCylinderPos, vTemp); | ||
623 | dReal fRestDepth1 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; | ||
624 | |||
625 | dReal fDepth0 = cData.fBestDepth - (fRestDepth0); | ||
626 | dReal fDepth1 = cData.fBestDepth - (fRestDepth1); | ||
627 | |||
628 | // clamp depths to zero | ||
629 | if(fDepth0 < REAL(0.0) ) | ||
630 | { | ||
631 | fDepth0 = REAL(0.0); | ||
632 | } | ||
633 | |||
634 | if(fDepth1<REAL(0.0)) | ||
635 | { | ||
636 | fDepth1 = REAL(0.0); | ||
637 | } | ||
638 | |||
639 | // Generate contact 0 | ||
640 | { | ||
641 | cData.gLocalContacts[cData.nContacts].fDepth = fDepth0; | ||
642 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
643 | dVector3Copy(vCEdgePoint0,cData.gLocalContacts[cData.nContacts].vPos); | ||
644 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
645 | cData.nContacts++; | ||
646 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
647 | return true; | ||
648 | } | ||
649 | |||
650 | // Generate contact 1 | ||
651 | { | ||
652 | // generate contacts | ||
653 | cData.gLocalContacts[cData.nContacts].fDepth = fDepth1; | ||
654 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
655 | dVector3Copy(vCEdgePoint1,cData.gLocalContacts[cData.nContacts].vPos); | ||
656 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
657 | cData.nContacts++; | ||
658 | } | ||
659 | |||
660 | return true; | ||
661 | } | ||
662 | |||
663 | void _cldClipCylinderToTriangle(sData& cData,const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) | ||
664 | { | ||
665 | int i = 0; | ||
666 | dVector3 avPoints[3]; | ||
667 | dVector3 avTempArray1[nMAX_CYLINDER_TRIANGLE_CLIP_POINTS]; | ||
668 | dVector3 avTempArray2[nMAX_CYLINDER_TRIANGLE_CLIP_POINTS]; | ||
669 | |||
670 | dSetZero(&avTempArray1[0][0],nMAX_CYLINDER_TRIANGLE_CLIP_POINTS * 4); | ||
671 | dSetZero(&avTempArray2[0][0],nMAX_CYLINDER_TRIANGLE_CLIP_POINTS * 4); | ||
672 | |||
673 | // setup array of triangle vertices | ||
674 | dVector3Copy(v0,avPoints[0]); | ||
675 | dVector3Copy(v1,avPoints[1]); | ||
676 | dVector3Copy(v2,avPoints[2]); | ||
677 | |||
678 | dVector3 vCylinderCirclePos, vCylinderCircleNormal_Rel; | ||
679 | dSetZero(vCylinderCircleNormal_Rel,4); | ||
680 | // check which circle from cylinder we take for clipping | ||
681 | if ( dVector3Dot(cData.vCylinderAxis , cData.vContactNormal) > REAL(0.0)) | ||
682 | { | ||
683 | // get top circle | ||
684 | vCylinderCirclePos[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
685 | vCylinderCirclePos[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
686 | vCylinderCirclePos[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
687 | |||
688 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(-1.0); | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | // get bottom circle | ||
693 | vCylinderCirclePos[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
694 | vCylinderCirclePos[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
695 | vCylinderCirclePos[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
696 | |||
697 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(1.0); | ||
698 | } | ||
699 | |||
700 | dVector3 vTemp; | ||
701 | dQuatInv(cData.qCylinderRot , cData.qInvCylinderRot); | ||
702 | // transform triangle points to space of cylinder circle | ||
703 | for(i=0; i<3; i++) | ||
704 | { | ||
705 | dVector3Subtract(avPoints[i] , vCylinderCirclePos , vTemp); | ||
706 | dQuatTransform(cData.qInvCylinderRot,vTemp,avPoints[i]); | ||
707 | } | ||
708 | |||
709 | int iTmpCounter1 = 0; | ||
710 | int iTmpCounter2 = 0; | ||
711 | dVector4 plPlane; | ||
712 | |||
713 | // plane of cylinder that contains circle for intersection | ||
714 | //plPlane = Plane4f( vCylinderCircleNormal_Rel, 0.0f ); | ||
715 | dConstructPlane(vCylinderCircleNormal_Rel,REAL(0.0),plPlane); | ||
716 | dClipPolyToPlane(avPoints, 3, avTempArray1, iTmpCounter1, plPlane); | ||
717 | |||
718 | // Body of base circle of Cylinder | ||
719 | int nCircleSegment = 0; | ||
720 | for (nCircleSegment = 0; nCircleSegment < nCYLINDER_CIRCLE_SEGMENTS; nCircleSegment++) | ||
721 | { | ||
722 | dConstructPlane(cData.avCylinderNormals[nCircleSegment],cData.fCylinderRadius,plPlane); | ||
723 | |||
724 | if (0 == (nCircleSegment % 2)) | ||
725 | { | ||
726 | dClipPolyToPlane( avTempArray1 , iTmpCounter1 , avTempArray2, iTmpCounter2, plPlane); | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | dClipPolyToPlane( avTempArray2, iTmpCounter2, avTempArray1 , iTmpCounter1 , plPlane ); | ||
731 | } | ||
732 | |||
733 | dIASSERT( iTmpCounter1 >= 0 && iTmpCounter1 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); | ||
734 | dIASSERT( iTmpCounter2 >= 0 && iTmpCounter2 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); | ||
735 | } | ||
736 | |||
737 | // back transform clipped points to absolute space | ||
738 | dReal ftmpdot; | ||
739 | dReal fTempDepth; | ||
740 | dVector3 vPoint; | ||
741 | |||
742 | if (nCircleSegment %2) | ||
743 | { | ||
744 | for( i=0; i<iTmpCounter2; i++) | ||
745 | { | ||
746 | dQuatTransform(cData.qCylinderRot,avTempArray2[i], vPoint); | ||
747 | vPoint[0] += vCylinderCirclePos[0]; | ||
748 | vPoint[1] += vCylinderCirclePos[1]; | ||
749 | vPoint[2] += vCylinderCirclePos[2]; | ||
750 | |||
751 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
752 | ftmpdot = dFabs(dVector3Dot(vTemp, cData.vContactNormal)); | ||
753 | fTempDepth = cData.fBestrt - ftmpdot; | ||
754 | // Depth must be positive | ||
755 | if (fTempDepth > REAL(0.0)) | ||
756 | { | ||
757 | cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; | ||
758 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
759 | dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); | ||
760 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
761 | cData.nContacts++; | ||
762 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
763 | return;; | ||
764 | } | ||
765 | } | ||
766 | } | ||
767 | else | ||
768 | { | ||
769 | for( i=0; i<iTmpCounter1; i++) | ||
770 | { | ||
771 | dQuatTransform(cData.qCylinderRot,avTempArray1[i], vPoint); | ||
772 | vPoint[0] += vCylinderCirclePos[0]; | ||
773 | vPoint[1] += vCylinderCirclePos[1]; | ||
774 | vPoint[2] += vCylinderCirclePos[2]; | ||
775 | |||
776 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
777 | ftmpdot = dFabs(dVector3Dot(vTemp, cData.vContactNormal)); | ||
778 | fTempDepth = cData.fBestrt - ftmpdot; | ||
779 | // Depth must be positive | ||
780 | if (fTempDepth > REAL(0.0)) | ||
781 | { | ||
782 | cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; | ||
783 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
784 | dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); | ||
785 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
786 | cData.nContacts++; | ||
787 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
788 | return;; | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | } | ||
793 | |||
794 | void TestOneTriangleVsCylinder( sData& cData, | ||
795 | const dVector3 &v0, | ||
796 | const dVector3 &v1, | ||
797 | const dVector3 &v2, | ||
798 | const bool bDoubleSided) | ||
799 | { | ||
800 | |||
801 | // calculate triangle normal | ||
802 | dVector3Subtract( v2 , v1 ,cData.vE1); | ||
803 | dVector3 vTemp; | ||
804 | dVector3Subtract( v0 , v1 ,vTemp); | ||
805 | dVector3Cross(cData.vE1 , vTemp , cData.vNormal ); | ||
806 | |||
807 | dNormalize3( cData.vNormal); | ||
808 | |||
809 | // create plane from triangle | ||
810 | //Plane4f plTrianglePlane = Plane4f( vPolyNormal, v0 ); | ||
811 | dReal plDistance = -dVector3Dot(v0, cData.vNormal); | ||
812 | dVector4 plTrianglePlane; | ||
813 | dConstructPlane( cData.vNormal,plDistance,plTrianglePlane); | ||
814 | |||
815 | // calculate sphere distance to plane | ||
816 | dReal fDistanceCylinderCenterToPlane = dPointPlaneDistance(cData.vCylinderPos , plTrianglePlane); | ||
817 | |||
818 | // Sphere must be over positive side of triangle | ||
819 | if(fDistanceCylinderCenterToPlane < 0 && !bDoubleSided) | ||
820 | { | ||
821 | // if not don't generate contacts | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | dVector3 vPnt0; | ||
826 | dVector3 vPnt1; | ||
827 | dVector3 vPnt2; | ||
828 | |||
829 | if (fDistanceCylinderCenterToPlane < REAL(0.0) ) | ||
830 | { | ||
831 | // flip it | ||
832 | dVector3Copy(v0 , vPnt0); | ||
833 | dVector3Copy(v1 , vPnt2); | ||
834 | dVector3Copy(v2 , vPnt1); | ||
835 | } | ||
836 | else | ||
837 | { | ||
838 | dVector3Copy(v0 , vPnt0); | ||
839 | dVector3Copy(v1 , vPnt1); | ||
840 | dVector3Copy(v2 , vPnt2); | ||
841 | } | ||
842 | |||
843 | cData.fBestDepth = MAX_REAL; | ||
844 | |||
845 | // do intersection test and find best separating axis | ||
846 | if(!_cldTestSeparatingAxes(cData , vPnt0, vPnt1, vPnt2) ) | ||
847 | { | ||
848 | // if not found do nothing | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | // if best separation axis is not found | ||
853 | if ( cData.iBestAxis == 0 ) | ||
854 | { | ||
855 | // this should not happen (we should already exit in that case) | ||
856 | dIASSERT(false); | ||
857 | // do nothing | ||
858 | return; | ||
859 | } | ||
860 | |||
861 | dReal fdot = dVector3Dot( cData.vContactNormal , cData.vCylinderAxis ); | ||
862 | |||
863 | // choose which clipping method are we going to apply | ||
864 | if (dFabs(fdot) < REAL(0.9) ) | ||
865 | { | ||
866 | if (!_cldClipCylinderEdgeToTriangle(cData ,vPnt0, vPnt1, vPnt2)) | ||
867 | { | ||
868 | return; | ||
869 | } | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | _cldClipCylinderToTriangle(cData ,vPnt0, vPnt1, vPnt2); | ||
874 | } | ||
875 | |||
876 | } | ||
877 | |||
878 | void _InitCylinderTrimeshData(sData& cData) | ||
879 | { | ||
880 | // get cylinder information | ||
881 | // Rotation | ||
882 | const dReal* pRotCyc = dGeomGetRotation(cData.gCylinder); | ||
883 | dMatrix3Copy(pRotCyc,cData.mCylinderRot); | ||
884 | dGeomGetQuaternion(cData.gCylinder,cData.qCylinderRot); | ||
885 | |||
886 | // Position | ||
887 | const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(cData.gCylinder); | ||
888 | dVector3Copy(*pPosCyc,cData.vCylinderPos); | ||
889 | // Cylinder axis | ||
890 | dMat3GetCol(cData.mCylinderRot,nCYLINDER_AXIS,cData.vCylinderAxis); | ||
891 | // get cylinder radius and size | ||
892 | dGeomCylinderGetParams(cData.gCylinder,&cData.fCylinderRadius,&cData.fCylinderSize); | ||
893 | |||
894 | // get trimesh position and orientation | ||
895 | const dReal* pRotTris = dGeomGetRotation(cData.gTrimesh); | ||
896 | dMatrix3Copy(pRotTris,cData.mTrimeshRot); | ||
897 | dGeomGetQuaternion(cData.gTrimesh,cData.qTrimeshRot); | ||
898 | |||
899 | // Position | ||
900 | const dVector3* pPosTris = (const dVector3*)dGeomGetPosition(cData.gTrimesh); | ||
901 | dVector3Copy(*pPosTris,cData.vTrimeshPos); | ||
902 | |||
903 | |||
904 | // calculate basic angle for 8-gon | ||
905 | dReal fAngle = M_PI / nCYLINDER_CIRCLE_SEGMENTS; | ||
906 | // calculate angle increment | ||
907 | dReal fAngleIncrement = fAngle*REAL(2.0); | ||
908 | |||
909 | // calculate plane normals | ||
910 | // axis dependant code | ||
911 | for(int i=0; i<nCYLINDER_CIRCLE_SEGMENTS; i++) | ||
912 | { | ||
913 | cData.avCylinderNormals[i][0] = -dCos(fAngle); | ||
914 | cData.avCylinderNormals[i][1] = -dSin(fAngle); | ||
915 | cData.avCylinderNormals[i][2] = REAL(0.0); | ||
916 | |||
917 | fAngle += fAngleIncrement; | ||
918 | } | ||
919 | |||
920 | dSetZero(cData.vBestPoint,4); | ||
921 | // reset best depth | ||
922 | cData.fBestCenter = REAL(0.0); | ||
923 | } | ||
924 | |||
925 | #if dTRIMESH_ENABLED | ||
926 | |||
927 | // OPCODE version of cylinder to mesh collider | ||
928 | #if dTRIMESH_OPCODE | ||
929 | int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
930 | { | ||
931 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
932 | dIASSERT( o1->type == dCylinderClass ); | ||
933 | dIASSERT( o2->type == dTriMeshClass ); | ||
934 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
935 | |||
936 | // Main data holder | ||
937 | sData cData; | ||
938 | |||
939 | // Assign ODE stuff | ||
940 | cData.gCylinder = o1; | ||
941 | cData.gTrimesh = (dxTriMesh*)o2; | ||
942 | cData.iFlags = flags; | ||
943 | cData.iSkip = skip; | ||
944 | cData.gContact = contact; | ||
945 | cData.nContacts = 0; | ||
946 | |||
947 | _InitCylinderTrimeshData(cData); | ||
948 | |||
949 | OBBCollider& Collider = cData.gTrimesh->_OBBCollider; | ||
950 | |||
951 | Point cCenter(cData.vCylinderPos[0],cData.vCylinderPos[1],cData.vCylinderPos[2]); | ||
952 | |||
953 | Point cExtents(cData.fCylinderRadius,cData.fCylinderRadius,cData.fCylinderRadius); | ||
954 | cExtents[nCYLINDER_AXIS] = cData.fCylinderSize * REAL(0.5); | ||
955 | |||
956 | Matrix3x3 obbRot; | ||
957 | |||
958 | // It is a potential issue to explicitly cast to float | ||
959 | // if custom width floating point type is introduced in OPCODE. | ||
960 | // It is necessary to make a typedef and cast to it | ||
961 | // (e.g. typedef float opc_float;) | ||
962 | // However I'm not sure in what header it should be added. | ||
963 | |||
964 | obbRot[0][0] = /*(float)*/cData.mCylinderRot[0]; | ||
965 | obbRot[1][0] = /*(float)*/cData.mCylinderRot[1]; | ||
966 | obbRot[2][0] = /*(float)*/cData.mCylinderRot[2]; | ||
967 | |||
968 | obbRot[0][1] = /*(float)*/cData.mCylinderRot[4]; | ||
969 | obbRot[1][1] = /*(float)*/cData.mCylinderRot[5]; | ||
970 | obbRot[2][1] = /*(float)*/cData.mCylinderRot[6]; | ||
971 | |||
972 | obbRot[0][2] = /*(float)*/cData.mCylinderRot[8]; | ||
973 | obbRot[1][2] = /*(float)*/cData.mCylinderRot[9]; | ||
974 | obbRot[2][2] = /*(float)*/cData.mCylinderRot[10]; | ||
975 | |||
976 | OBB obbCapsule(cCenter,cExtents,obbRot); | ||
977 | |||
978 | Matrix4x4 CapsuleMatrix; | ||
979 | MakeMatrix(cData.vCylinderPos, cData.mCylinderRot, CapsuleMatrix); | ||
980 | |||
981 | Matrix4x4 MeshMatrix; | ||
982 | MakeMatrix(cData.vTrimeshPos, cData.mTrimeshRot, MeshMatrix); | ||
983 | |||
984 | // TC results | ||
985 | if (cData.gTrimesh->doBoxTC) | ||
986 | { | ||
987 | dxTriMesh::BoxTC* BoxTC = 0; | ||
988 | for (int i = 0; i < cData.gTrimesh->BoxTCCache.size(); i++) | ||
989 | { | ||
990 | if (cData.gTrimesh->BoxTCCache[i].Geom == cData.gCylinder) | ||
991 | { | ||
992 | BoxTC = &cData.gTrimesh->BoxTCCache[i]; | ||
993 | break; | ||
994 | } | ||
995 | } | ||
996 | if (!BoxTC) | ||
997 | { | ||
998 | cData.gTrimesh->BoxTCCache.push(dxTriMesh::BoxTC()); | ||
999 | |||
1000 | BoxTC = &cData.gTrimesh->BoxTCCache[cData.gTrimesh->BoxTCCache.size() - 1]; | ||
1001 | BoxTC->Geom = cData.gCylinder; | ||
1002 | BoxTC->FatCoeff = REAL(1.0); | ||
1003 | } | ||
1004 | |||
1005 | // Intersect | ||
1006 | Collider.SetTemporalCoherence(true); | ||
1007 | Collider.Collide(*BoxTC, obbCapsule, cData.gTrimesh->Data->BVTree, null, &MeshMatrix); | ||
1008 | } | ||
1009 | else | ||
1010 | { | ||
1011 | Collider.SetTemporalCoherence(false); | ||
1012 | Collider.Collide(dxTriMesh::defaultBoxCache, obbCapsule, cData.gTrimesh->Data->BVTree, null,&MeshMatrix); | ||
1013 | } | ||
1014 | |||
1015 | // Retrieve data | ||
1016 | int TriCount = Collider.GetNbTouchedPrimitives(); | ||
1017 | const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); | ||
1018 | |||
1019 | |||
1020 | if (TriCount != 0) | ||
1021 | { | ||
1022 | if (cData.gTrimesh->ArrayCallback != null) | ||
1023 | { | ||
1024 | cData.gTrimesh->ArrayCallback(cData.gTrimesh, cData.gCylinder, Triangles, TriCount); | ||
1025 | } | ||
1026 | |||
1027 | // allocate buffer for local contacts on stack | ||
1028 | cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK)); | ||
1029 | |||
1030 | int ctContacts0 = 0; | ||
1031 | |||
1032 | // loop through all intersecting triangles | ||
1033 | for (int i = 0; i < TriCount; i++) | ||
1034 | { | ||
1035 | const int Triint = Triangles[i]; | ||
1036 | if (!Callback(cData.gTrimesh, cData.gCylinder, Triint)) continue; | ||
1037 | |||
1038 | |||
1039 | dVector3 dv[3]; | ||
1040 | FetchTriangle(cData.gTrimesh, Triint, cData.vTrimeshPos, cData.mTrimeshRot, dv); | ||
1041 | |||
1042 | // test this triangle | ||
1043 | TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false); | ||
1044 | |||
1045 | // fill-in tri index for generated contacts | ||
1046 | for (; ctContacts0<cData.nContacts; ctContacts0++) | ||
1047 | cData.gLocalContacts[ctContacts0].triIndex = Triint; | ||
1048 | |||
1049 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1050 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
1051 | { | ||
1052 | break; | ||
1053 | } | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | return _ProcessLocalContacts(cData); | ||
1058 | } | ||
1059 | #endif | ||
1060 | |||
1061 | // GIMPACT version of cylinder to mesh collider | ||
1062 | #if dTRIMESH_GIMPACT | ||
1063 | int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
1064 | { | ||
1065 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
1066 | dIASSERT( o1->type == dCylinderClass ); | ||
1067 | dIASSERT( o2->type == dTriMeshClass ); | ||
1068 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1069 | |||
1070 | // Main data holder | ||
1071 | sData cData; | ||
1072 | |||
1073 | // Assign ODE stuff | ||
1074 | cData.gCylinder = o1; | ||
1075 | cData.gTrimesh = (dxTriMesh*)o2; | ||
1076 | cData.iFlags = flags; | ||
1077 | cData.iSkip = skip; | ||
1078 | cData.gContact = contact; | ||
1079 | cData.nContacts = 0; | ||
1080 | |||
1081 | _InitCylinderTrimeshData(cData); | ||
1082 | |||
1083 | //*****at first , collide box aabb******// | ||
1084 | |||
1085 | aabb3f test_aabb; | ||
1086 | |||
1087 | test_aabb.minX = o1->aabb[0]; | ||
1088 | test_aabb.maxX = o1->aabb[1]; | ||
1089 | test_aabb.minY = o1->aabb[2]; | ||
1090 | test_aabb.maxY = o1->aabb[3]; | ||
1091 | test_aabb.minZ = o1->aabb[4]; | ||
1092 | test_aabb.maxZ = o1->aabb[5]; | ||
1093 | |||
1094 | |||
1095 | GDYNAMIC_ARRAY collision_result; | ||
1096 | GIM_CREATE_BOXQUERY_LIST(collision_result); | ||
1097 | |||
1098 | gim_aabbset_box_collision(&test_aabb, &cData.gTrimesh->m_collision_trimesh.m_aabbset , &collision_result); | ||
1099 | |||
1100 | if(collision_result.m_size==0) | ||
1101 | { | ||
1102 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1103 | return 0; | ||
1104 | } | ||
1105 | //*****Set globals for box collision******// | ||
1106 | |||
1107 | int ctContacts0 = 0; | ||
1108 | cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK)); | ||
1109 | |||
1110 | GUINT * boxesresult = GIM_DYNARRAY_POINTER(GUINT,collision_result); | ||
1111 | GIM_TRIMESH * ptrimesh = &cData.gTrimesh->m_collision_trimesh; | ||
1112 | |||
1113 | gim_trimesh_locks_work_data(ptrimesh); | ||
1114 | |||
1115 | |||
1116 | for(unsigned int i=0;i<collision_result.m_size;i++) | ||
1117 | { | ||
1118 | const int Triint = boxesresult[i]; | ||
1119 | |||
1120 | dVector3 dv[3]; | ||
1121 | gim_trimesh_get_triangle_vertices(ptrimesh, Triint,dv[0],dv[1],dv[2]); | ||
1122 | // test this triangle | ||
1123 | TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false); | ||
1124 | |||
1125 | // fill-in triangle index for generated contacts | ||
1126 | for (; ctContacts0<cData.nContacts; ctContacts0++) | ||
1127 | cData.gLocalContacts[ctContacts0].triIndex = Triint; | ||
1128 | |||
1129 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1130 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
1131 | { | ||
1132 | break; | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | gim_trimesh_unlocks_work_data(ptrimesh); | ||
1137 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1138 | |||
1139 | return _ProcessLocalContacts(cData); | ||
1140 | } | ||
1141 | #endif | ||
1142 | |||
1143 | #endif // dTRIMESH_ENABLED | ||
1144 | |||
1145 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_kernel.cpp b/libraries/ode-0.9\/ode/src/collision_kernel.cpp new file mode 100755 index 0000000..b885603 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_kernel.cpp | |||
@@ -0,0 +1,1103 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | core collision functions and data structures, plus part of the public API | ||
26 | for geometry objects | ||
27 | |||
28 | */ | ||
29 | |||
30 | #include <ode/common.h> | ||
31 | #include <ode/matrix.h> | ||
32 | #include <ode/rotation.h> | ||
33 | #include <ode/objects.h> | ||
34 | #include <ode/odemath.h> | ||
35 | #include "collision_kernel.h" | ||
36 | #include "collision_util.h" | ||
37 | #include "collision_std.h" | ||
38 | #include "collision_transform.h" | ||
39 | #include "collision_trimesh_internal.h" | ||
40 | |||
41 | #if dTRIMESH_GIMPACT | ||
42 | #include <GIMPACT/gimpact.h> | ||
43 | #endif | ||
44 | |||
45 | #ifdef _MSC_VER | ||
46 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
47 | #endif | ||
48 | |||
49 | //**************************************************************************** | ||
50 | // helper functions for dCollide()ing a space with another geom | ||
51 | |||
52 | // this struct records the parameters passed to dCollideSpaceGeom() | ||
53 | |||
54 | // Allocate and free posr - we cache a single posr to avoid thrashing | ||
55 | static dxPosR* s_cachedPosR = 0; | ||
56 | |||
57 | dxPosR* dAllocPosr() | ||
58 | { | ||
59 | dxPosR* retPosR; | ||
60 | if (s_cachedPosR) | ||
61 | { | ||
62 | retPosR = s_cachedPosR; | ||
63 | s_cachedPosR = 0; | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | retPosR = (dxPosR*) dAlloc (sizeof(dxPosR)); | ||
68 | } | ||
69 | return retPosR; | ||
70 | } | ||
71 | |||
72 | void dFreePosr(dxPosR* oldPosR) | ||
73 | { | ||
74 | if (oldPosR) | ||
75 | { | ||
76 | if (s_cachedPosR) | ||
77 | { | ||
78 | dFree(s_cachedPosR, sizeof(dxPosR)); | ||
79 | } | ||
80 | s_cachedPosR = oldPosR; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | void dClearPosrCache(void) | ||
85 | { | ||
86 | if (s_cachedPosR) | ||
87 | { | ||
88 | dFree(s_cachedPosR, sizeof(dxPosR)); | ||
89 | s_cachedPosR = 0; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | struct SpaceGeomColliderData { | ||
94 | int flags; // space left in contacts array | ||
95 | dContactGeom *contact; | ||
96 | int skip; | ||
97 | }; | ||
98 | |||
99 | |||
100 | static void space_geom_collider (void *data, dxGeom *o1, dxGeom *o2) | ||
101 | { | ||
102 | SpaceGeomColliderData *d = (SpaceGeomColliderData*) data; | ||
103 | if (d->flags & NUMC_MASK) { | ||
104 | int n = dCollide (o1,o2,d->flags,d->contact,d->skip); | ||
105 | d->contact = CONTACT (d->contact,d->skip*n); | ||
106 | d->flags -= n; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | |||
111 | static int dCollideSpaceGeom (dxGeom *o1, dxGeom *o2, int flags, | ||
112 | dContactGeom *contact, int skip) | ||
113 | { | ||
114 | SpaceGeomColliderData data; | ||
115 | data.flags = flags; | ||
116 | data.contact = contact; | ||
117 | data.skip = skip; | ||
118 | dSpaceCollide2 (o1,o2,&data,&space_geom_collider); | ||
119 | return (flags & NUMC_MASK) - (data.flags & NUMC_MASK); | ||
120 | } | ||
121 | |||
122 | //**************************************************************************** | ||
123 | // dispatcher for the N^2 collider functions | ||
124 | |||
125 | // function pointers and modes for n^2 class collider functions | ||
126 | |||
127 | struct dColliderEntry { | ||
128 | dColliderFn *fn; // collider function, 0 = no function available | ||
129 | int reverse; // 1 = reverse o1 and o2 | ||
130 | }; | ||
131 | static dColliderEntry colliders[dGeomNumClasses][dGeomNumClasses]; | ||
132 | static int colliders_initialized = 0; | ||
133 | |||
134 | |||
135 | // setCollider() will refuse to write over a collider entry once it has | ||
136 | // been written. | ||
137 | |||
138 | static void setCollider (int i, int j, dColliderFn *fn) | ||
139 | { | ||
140 | if (colliders[i][j].fn == 0) { | ||
141 | colliders[i][j].fn = fn; | ||
142 | colliders[i][j].reverse = 0; | ||
143 | } | ||
144 | if (colliders[j][i].fn == 0) { | ||
145 | colliders[j][i].fn = fn; | ||
146 | colliders[j][i].reverse = 1; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | static void setAllColliders (int i, dColliderFn *fn) | ||
152 | { | ||
153 | for (int j=0; j<dGeomNumClasses; j++) setCollider (i,j,fn); | ||
154 | } | ||
155 | |||
156 | |||
157 | static void initColliders() | ||
158 | { | ||
159 | int i,j; | ||
160 | |||
161 | if (colliders_initialized) return; | ||
162 | colliders_initialized = 1; | ||
163 | |||
164 | memset (colliders,0,sizeof(colliders)); | ||
165 | |||
166 | // setup space colliders | ||
167 | for (i=dFirstSpaceClass; i <= dLastSpaceClass; i++) { | ||
168 | for (j=0; j < dGeomNumClasses; j++) { | ||
169 | setCollider (i,j,&dCollideSpaceGeom); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | setCollider (dSphereClass,dSphereClass,&dCollideSphereSphere); | ||
174 | setCollider (dSphereClass,dBoxClass,&dCollideSphereBox); | ||
175 | setCollider (dSphereClass,dPlaneClass,&dCollideSpherePlane); | ||
176 | setCollider (dBoxClass,dBoxClass,&dCollideBoxBox); | ||
177 | setCollider (dBoxClass,dPlaneClass,&dCollideBoxPlane); | ||
178 | setCollider (dCapsuleClass,dSphereClass,&dCollideCapsuleSphere); | ||
179 | setCollider (dCapsuleClass,dBoxClass,&dCollideCapsuleBox); | ||
180 | setCollider (dCapsuleClass,dCapsuleClass,&dCollideCapsuleCapsule); | ||
181 | setCollider (dCapsuleClass,dPlaneClass,&dCollideCapsulePlane); | ||
182 | setCollider (dRayClass,dSphereClass,&dCollideRaySphere); | ||
183 | setCollider (dRayClass,dBoxClass,&dCollideRayBox); | ||
184 | setCollider (dRayClass,dCapsuleClass,&dCollideRayCapsule); | ||
185 | setCollider (dRayClass,dPlaneClass,&dCollideRayPlane); | ||
186 | setCollider (dRayClass,dCylinderClass,&dCollideRayCylinder); | ||
187 | #if dTRIMESH_ENABLED | ||
188 | setCollider (dTriMeshClass,dSphereClass,&dCollideSTL); | ||
189 | setCollider (dTriMeshClass,dBoxClass,&dCollideBTL); | ||
190 | setCollider (dTriMeshClass,dRayClass,&dCollideRTL); | ||
191 | setCollider (dTriMeshClass,dTriMeshClass,&dCollideTTL); | ||
192 | setCollider (dTriMeshClass,dCapsuleClass,&dCollideCCTL); | ||
193 | setCollider (dTriMeshClass,dPlaneClass,&dCollideTrimeshPlane); | ||
194 | setCollider (dCylinderClass,dTriMeshClass,&dCollideCylinderTrimesh); | ||
195 | #endif | ||
196 | setCollider (dCylinderClass,dBoxClass,&dCollideCylinderBox); | ||
197 | setCollider (dCylinderClass,dSphereClass,&dCollideCylinderSphere); | ||
198 | setCollider (dCylinderClass,dPlaneClass,&dCollideCylinderPlane); | ||
199 | //setCollider (dCylinderClass,dCylinderClass,&dCollideCylinderCylinder); | ||
200 | |||
201 | //--> Convex Collision | ||
202 | setCollider (dConvexClass,dPlaneClass,&dCollideConvexPlane); | ||
203 | setCollider (dSphereClass,dConvexClass,&dCollideSphereConvex); | ||
204 | setCollider (dConvexClass,dBoxClass,&dCollideConvexBox); | ||
205 | setCollider (dConvexClass,dCapsuleClass,&dCollideConvexCapsule); | ||
206 | setCollider (dConvexClass,dConvexClass,&dCollideConvexConvex); | ||
207 | setCollider (dRayClass,dConvexClass,&dCollideRayConvex); | ||
208 | //<-- Convex Collision | ||
209 | |||
210 | //--> dHeightfield Collision | ||
211 | setCollider (dHeightfieldClass,dRayClass,&dCollideHeightfield); | ||
212 | setCollider (dHeightfieldClass,dSphereClass,&dCollideHeightfield); | ||
213 | setCollider (dHeightfieldClass,dBoxClass,&dCollideHeightfield); | ||
214 | setCollider (dHeightfieldClass,dCapsuleClass,&dCollideHeightfield); | ||
215 | setCollider (dHeightfieldClass,dCylinderClass,&dCollideHeightfield); | ||
216 | setCollider (dHeightfieldClass,dConvexClass,&dCollideHeightfield); | ||
217 | #if dTRIMESH_ENABLED | ||
218 | setCollider (dHeightfieldClass,dTriMeshClass,&dCollideHeightfield); | ||
219 | #endif | ||
220 | //<-- dHeightfield Collision | ||
221 | |||
222 | setAllColliders (dGeomTransformClass,&dCollideTransform); | ||
223 | } | ||
224 | |||
225 | |||
226 | /* | ||
227 | * NOTE! | ||
228 | * If it is necessary to add special processing mode without contact generation | ||
229 | * use NULL contact parameter value as indicator, not zero in flags. | ||
230 | */ | ||
231 | int dCollide (dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, | ||
232 | int skip) | ||
233 | { | ||
234 | dAASSERT(o1 && o2 && contact); | ||
235 | dUASSERT(colliders_initialized,"colliders array not initialized"); | ||
236 | dUASSERT(o1->type >= 0 && o1->type < dGeomNumClasses,"bad o1 class number"); | ||
237 | dUASSERT(o2->type >= 0 && o2->type < dGeomNumClasses,"bad o2 class number"); | ||
238 | // Even though comparison for greater or equal to one is used in all the | ||
239 | // other places, here it is more logical to check for greater than zero | ||
240 | // because function does not require any specific number of contact slots - | ||
241 | // it must be just a positive. | ||
242 | dUASSERT((flags & NUMC_MASK) > 0, "no contacts requested"); | ||
243 | |||
244 | // Extra precaution for zero contact count in parameters | ||
245 | if ((flags & NUMC_MASK) == 0) return 0; | ||
246 | // no contacts if both geoms are the same | ||
247 | if (o1 == o2) return 0; | ||
248 | |||
249 | // no contacts if both geoms on the same body, and the body is not 0 | ||
250 | if (o1->body == o2->body && o1->body) return 0; | ||
251 | |||
252 | o1->recomputePosr(); | ||
253 | o2->recomputePosr(); | ||
254 | |||
255 | dColliderEntry *ce = &colliders[o1->type][o2->type]; | ||
256 | int count = 0; | ||
257 | if (ce->fn) { | ||
258 | if (ce->reverse) { | ||
259 | count = (*ce->fn) (o2,o1,flags,contact,skip); | ||
260 | for (int i=0; i<count; i++) { | ||
261 | dContactGeom *c = CONTACT(contact,skip*i); | ||
262 | c->normal[0] = -c->normal[0]; | ||
263 | c->normal[1] = -c->normal[1]; | ||
264 | c->normal[2] = -c->normal[2]; | ||
265 | dxGeom *tmp = c->g1; | ||
266 | c->g1 = c->g2; | ||
267 | c->g2 = tmp; | ||
268 | int tmpint = c->side1; | ||
269 | c->side1 = c->side2; | ||
270 | c->side2 = tmpint; | ||
271 | } | ||
272 | } | ||
273 | else { | ||
274 | count = (*ce->fn) (o1,o2,flags,contact,skip); | ||
275 | } | ||
276 | } | ||
277 | return count; | ||
278 | } | ||
279 | |||
280 | //**************************************************************************** | ||
281 | // dxGeom | ||
282 | |||
283 | dxGeom::dxGeom (dSpaceID _space, int is_placeable) | ||
284 | { | ||
285 | initColliders(); | ||
286 | |||
287 | // setup body vars. invalid type of -1 must be changed by the constructor. | ||
288 | type = -1; | ||
289 | gflags = GEOM_DIRTY | GEOM_AABB_BAD | GEOM_ENABLED; | ||
290 | if (is_placeable) gflags |= GEOM_PLACEABLE; | ||
291 | data = 0; | ||
292 | body = 0; | ||
293 | body_next = 0; | ||
294 | if (is_placeable) { | ||
295 | final_posr = dAllocPosr(); | ||
296 | dSetZero (final_posr->pos,4); | ||
297 | dRSetIdentity (final_posr->R); | ||
298 | } | ||
299 | else { | ||
300 | final_posr = 0; | ||
301 | } | ||
302 | offset_posr = 0; | ||
303 | |||
304 | // setup space vars | ||
305 | next = 0; | ||
306 | tome = 0; | ||
307 | parent_space = 0; | ||
308 | dSetZero (aabb,6); | ||
309 | category_bits = ~0; | ||
310 | collide_bits = ~0; | ||
311 | |||
312 | // put this geom in a space if required | ||
313 | if (_space) dSpaceAdd (_space,this); | ||
314 | } | ||
315 | |||
316 | |||
317 | dxGeom::~dxGeom() | ||
318 | { | ||
319 | if (parent_space) dSpaceRemove (parent_space,this); | ||
320 | if ((gflags & GEOM_PLACEABLE) && (!body || (body && offset_posr))) | ||
321 | dFreePosr(final_posr); | ||
322 | if (offset_posr) dFreePosr(offset_posr); | ||
323 | bodyRemove(); | ||
324 | } | ||
325 | |||
326 | |||
327 | int dxGeom::AABBTest (dxGeom *o, dReal aabb[6]) | ||
328 | { | ||
329 | return 1; | ||
330 | } | ||
331 | |||
332 | |||
333 | void dxGeom::bodyRemove() | ||
334 | { | ||
335 | if (body) { | ||
336 | // delete this geom from body list | ||
337 | dxGeom **last = &body->geom, *g = body->geom; | ||
338 | while (g) { | ||
339 | if (g == this) { | ||
340 | *last = g->body_next; | ||
341 | break; | ||
342 | } | ||
343 | last = &g->body_next; | ||
344 | g = g->body_next; | ||
345 | } | ||
346 | body = 0; | ||
347 | body_next = 0; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | inline void myswap(dReal& a, dReal& b) { dReal t=b; b=a; a=t; } | ||
352 | |||
353 | |||
354 | inline void matrixInvert(const dMatrix3& inMat, dMatrix3& outMat) | ||
355 | { | ||
356 | memcpy(outMat, inMat, sizeof(dMatrix3)); | ||
357 | // swap _12 and _21 | ||
358 | myswap(outMat[0 + 4*1], outMat[1 + 4*0]); | ||
359 | // swap _31 and _13 | ||
360 | myswap(outMat[2 + 4*0], outMat[0 + 4*2]); | ||
361 | // swap _23 and _32 | ||
362 | myswap(outMat[1 + 4*2], outMat[2 + 4*1]); | ||
363 | } | ||
364 | |||
365 | void getBodyPosr(const dxPosR& offset_posr, const dxPosR& final_posr, dxPosR& body_posr) | ||
366 | { | ||
367 | dMatrix3 inv_offset; | ||
368 | matrixInvert(offset_posr.R, inv_offset); | ||
369 | |||
370 | dMULTIPLY0_333(body_posr.R, final_posr.R, inv_offset); | ||
371 | dVector3 world_offset; | ||
372 | dMULTIPLY0_331(world_offset, body_posr.R, offset_posr.pos); | ||
373 | body_posr.pos[0] = final_posr.pos[0] - world_offset[0]; | ||
374 | body_posr.pos[1] = final_posr.pos[1] - world_offset[1]; | ||
375 | body_posr.pos[2] = final_posr.pos[2] - world_offset[2]; | ||
376 | } | ||
377 | |||
378 | void getWorldOffsetPosr(const dxPosR& body_posr, const dxPosR& world_posr, dxPosR& offset_posr) | ||
379 | { | ||
380 | dMatrix3 inv_body; | ||
381 | matrixInvert(body_posr.R, inv_body); | ||
382 | |||
383 | dMULTIPLY0_333(offset_posr.R, inv_body, world_posr.R); | ||
384 | dVector3 world_offset; | ||
385 | world_offset[0] = world_posr.pos[0] - body_posr.pos[0]; | ||
386 | world_offset[1] = world_posr.pos[1] - body_posr.pos[1]; | ||
387 | world_offset[2] = world_posr.pos[2] - body_posr.pos[2]; | ||
388 | dMULTIPLY0_331(offset_posr.pos, inv_body, world_offset); | ||
389 | } | ||
390 | |||
391 | void dxGeom::computePosr() | ||
392 | { | ||
393 | // should only be recalced if we need to - ie offset from a body | ||
394 | dIASSERT(offset_posr); | ||
395 | dIASSERT(body); | ||
396 | |||
397 | dMULTIPLY0_331 (final_posr->pos,body->posr.R,offset_posr->pos); | ||
398 | final_posr->pos[0] += body->posr.pos[0]; | ||
399 | final_posr->pos[1] += body->posr.pos[1]; | ||
400 | final_posr->pos[2] += body->posr.pos[2]; | ||
401 | dMULTIPLY0_333 (final_posr->R,body->posr.R,offset_posr->R); | ||
402 | } | ||
403 | |||
404 | //**************************************************************************** | ||
405 | // misc | ||
406 | |||
407 | dxGeom *dGeomGetBodyNext (dxGeom *geom) | ||
408 | { | ||
409 | return geom->body_next; | ||
410 | } | ||
411 | |||
412 | //**************************************************************************** | ||
413 | // public API for geometry objects | ||
414 | |||
415 | #define CHECK_NOT_LOCKED(space) \ | ||
416 | dUASSERT (!(space && space->lock_count), \ | ||
417 | "invalid operation for geom in locked space"); | ||
418 | |||
419 | |||
420 | void dGeomDestroy (dxGeom *g) | ||
421 | { | ||
422 | dAASSERT (g); | ||
423 | delete g; | ||
424 | } | ||
425 | |||
426 | |||
427 | void dGeomSetData (dxGeom *g, void *data) | ||
428 | { | ||
429 | dAASSERT (g); | ||
430 | g->data = data; | ||
431 | } | ||
432 | |||
433 | |||
434 | void *dGeomGetData (dxGeom *g) | ||
435 | { | ||
436 | dAASSERT (g); | ||
437 | return g->data; | ||
438 | } | ||
439 | |||
440 | |||
441 | void dGeomSetBody (dxGeom *g, dxBody *b) | ||
442 | { | ||
443 | dAASSERT (g); | ||
444 | dUASSERT (b == NULL || (g->gflags & GEOM_PLACEABLE),"geom must be placeable"); | ||
445 | CHECK_NOT_LOCKED (g->parent_space); | ||
446 | |||
447 | if (b) { | ||
448 | if (!g->body) dFreePosr(g->final_posr); | ||
449 | if (g->body != b) { | ||
450 | if (g->offset_posr) { | ||
451 | dFreePosr(g->offset_posr); | ||
452 | g->offset_posr = 0; | ||
453 | } | ||
454 | g->final_posr = &b->posr; | ||
455 | g->bodyRemove(); | ||
456 | g->bodyAdd (b); | ||
457 | } | ||
458 | dGeomMoved (g); | ||
459 | } | ||
460 | else { | ||
461 | if (g->body) { | ||
462 | if (g->offset_posr) | ||
463 | { | ||
464 | // if we're offset, we already have our own final position, make sure its updated | ||
465 | g->recomputePosr(); | ||
466 | dFreePosr(g->offset_posr); | ||
467 | g->offset_posr = 0; | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | g->final_posr = dAllocPosr(); | ||
472 | memcpy (g->final_posr->pos,g->body->posr.pos,sizeof(dVector3)); | ||
473 | memcpy (g->final_posr->R,g->body->posr.R,sizeof(dMatrix3)); | ||
474 | } | ||
475 | g->bodyRemove(); | ||
476 | } | ||
477 | // dGeomMoved() should not be called if the body is being set to 0, as the | ||
478 | // new position of the geom is set to the old position of the body, so the | ||
479 | // effective position of the geom remains unchanged. | ||
480 | } | ||
481 | } | ||
482 | |||
483 | |||
484 | dBodyID dGeomGetBody (dxGeom *g) | ||
485 | { | ||
486 | dAASSERT (g); | ||
487 | return g->body; | ||
488 | } | ||
489 | |||
490 | |||
491 | void dGeomSetPosition (dxGeom *g, dReal x, dReal y, dReal z) | ||
492 | { | ||
493 | dAASSERT (g); | ||
494 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
495 | CHECK_NOT_LOCKED (g->parent_space); | ||
496 | if (g->offset_posr) { | ||
497 | // move body such that body+offset = position | ||
498 | dVector3 world_offset; | ||
499 | dMULTIPLY0_331(world_offset, g->body->posr.R, g->offset_posr->pos); | ||
500 | dBodySetPosition(g->body, | ||
501 | x - world_offset[0], | ||
502 | y - world_offset[1], | ||
503 | z - world_offset[2]); | ||
504 | } | ||
505 | else if (g->body) { | ||
506 | // this will call dGeomMoved (g), so we don't have to | ||
507 | dBodySetPosition (g->body,x,y,z); | ||
508 | } | ||
509 | else { | ||
510 | g->final_posr->pos[0] = x; | ||
511 | g->final_posr->pos[1] = y; | ||
512 | g->final_posr->pos[2] = z; | ||
513 | dGeomMoved (g); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | |||
518 | void dGeomSetRotation (dxGeom *g, const dMatrix3 R) | ||
519 | { | ||
520 | dAASSERT (g && R); | ||
521 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
522 | CHECK_NOT_LOCKED (g->parent_space); | ||
523 | if (g->offset_posr) { | ||
524 | g->recomputePosr(); | ||
525 | // move body such that body+offset = rotation | ||
526 | dxPosR new_final_posr; | ||
527 | dxPosR new_body_posr; | ||
528 | memcpy(new_final_posr.pos, g->final_posr->pos, sizeof(dVector3)); | ||
529 | memcpy(new_final_posr.R, R, sizeof(dMatrix3)); | ||
530 | getBodyPosr(*g->offset_posr, new_final_posr, new_body_posr); | ||
531 | dBodySetRotation(g->body, new_body_posr.R); | ||
532 | dBodySetPosition(g->body, new_body_posr.pos[0], new_body_posr.pos[1], new_body_posr.pos[2]); | ||
533 | } | ||
534 | else if (g->body) { | ||
535 | // this will call dGeomMoved (g), so we don't have to | ||
536 | dBodySetRotation (g->body,R); | ||
537 | } | ||
538 | else { | ||
539 | memcpy (g->final_posr->R,R,sizeof(dMatrix3)); | ||
540 | dGeomMoved (g); | ||
541 | } | ||
542 | } | ||
543 | |||
544 | |||
545 | void dGeomSetQuaternion (dxGeom *g, const dQuaternion quat) | ||
546 | { | ||
547 | dAASSERT (g && quat); | ||
548 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
549 | CHECK_NOT_LOCKED (g->parent_space); | ||
550 | if (g->offset_posr) { | ||
551 | g->recomputePosr(); | ||
552 | // move body such that body+offset = rotation | ||
553 | dxPosR new_final_posr; | ||
554 | dxPosR new_body_posr; | ||
555 | dQtoR (quat, new_final_posr.R); | ||
556 | memcpy(new_final_posr.pos, g->final_posr->pos, sizeof(dVector3)); | ||
557 | |||
558 | getBodyPosr(*g->offset_posr, new_final_posr, new_body_posr); | ||
559 | dBodySetRotation(g->body, new_body_posr.R); | ||
560 | dBodySetPosition(g->body, new_body_posr.pos[0], new_body_posr.pos[1], new_body_posr.pos[2]); | ||
561 | } | ||
562 | if (g->body) { | ||
563 | // this will call dGeomMoved (g), so we don't have to | ||
564 | dBodySetQuaternion (g->body,quat); | ||
565 | } | ||
566 | else { | ||
567 | dQtoR (quat, g->final_posr->R); | ||
568 | dGeomMoved (g); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | |||
573 | const dReal * dGeomGetPosition (dxGeom *g) | ||
574 | { | ||
575 | dAASSERT (g); | ||
576 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
577 | g->recomputePosr(); | ||
578 | return g->final_posr->pos; | ||
579 | } | ||
580 | |||
581 | |||
582 | void dGeomCopyPosition(dxGeom *g, dVector3 pos) | ||
583 | { | ||
584 | dAASSERT (g); | ||
585 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
586 | g->recomputePosr(); | ||
587 | const dReal* src = g->final_posr->pos; | ||
588 | pos[0] = src[0]; | ||
589 | pos[1] = src[1]; | ||
590 | pos[2] = src[2]; | ||
591 | } | ||
592 | |||
593 | |||
594 | const dReal * dGeomGetRotation (dxGeom *g) | ||
595 | { | ||
596 | dAASSERT (g); | ||
597 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
598 | g->recomputePosr(); | ||
599 | return g->final_posr->R; | ||
600 | } | ||
601 | |||
602 | |||
603 | void dGeomCopyRotation(dxGeom *g, dMatrix3 R) | ||
604 | { | ||
605 | dAASSERT (g); | ||
606 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
607 | g->recomputePosr(); | ||
608 | const dReal* src = g->final_posr->R; | ||
609 | R[0] = src[0]; | ||
610 | R[1] = src[1]; | ||
611 | R[2] = src[2]; | ||
612 | R[4] = src[4]; | ||
613 | R[5] = src[5]; | ||
614 | R[6] = src[6]; | ||
615 | R[8] = src[8]; | ||
616 | R[9] = src[9]; | ||
617 | R[10] = src[10]; | ||
618 | } | ||
619 | |||
620 | |||
621 | void dGeomGetQuaternion (dxGeom *g, dQuaternion quat) | ||
622 | { | ||
623 | dAASSERT (g); | ||
624 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
625 | if (g->body && !g->offset_posr) { | ||
626 | const dReal * body_quat = dBodyGetQuaternion (g->body); | ||
627 | quat[0] = body_quat[0]; | ||
628 | quat[1] = body_quat[1]; | ||
629 | quat[2] = body_quat[2]; | ||
630 | quat[3] = body_quat[3]; | ||
631 | } | ||
632 | else { | ||
633 | g->recomputePosr(); | ||
634 | dRtoQ (g->final_posr->R, quat); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | |||
639 | void dGeomGetAABB (dxGeom *g, dReal aabb[6]) | ||
640 | { | ||
641 | dAASSERT (g); | ||
642 | dAASSERT (aabb); | ||
643 | g->recomputeAABB(); | ||
644 | memcpy (aabb,g->aabb,6 * sizeof(dReal)); | ||
645 | } | ||
646 | |||
647 | |||
648 | int dGeomIsSpace (dxGeom *g) | ||
649 | { | ||
650 | dAASSERT (g); | ||
651 | return IS_SPACE(g); | ||
652 | } | ||
653 | |||
654 | |||
655 | dSpaceID dGeomGetSpace (dxGeom *g) | ||
656 | { | ||
657 | dAASSERT (g); | ||
658 | return g->parent_space; | ||
659 | } | ||
660 | |||
661 | |||
662 | int dGeomGetClass (dxGeom *g) | ||
663 | { | ||
664 | dAASSERT (g); | ||
665 | return g->type; | ||
666 | } | ||
667 | |||
668 | |||
669 | void dGeomSetCategoryBits (dxGeom *g, unsigned long bits) | ||
670 | { | ||
671 | dAASSERT (g); | ||
672 | CHECK_NOT_LOCKED (g->parent_space); | ||
673 | g->category_bits = bits; | ||
674 | } | ||
675 | |||
676 | |||
677 | void dGeomSetCollideBits (dxGeom *g, unsigned long bits) | ||
678 | { | ||
679 | dAASSERT (g); | ||
680 | CHECK_NOT_LOCKED (g->parent_space); | ||
681 | g->collide_bits = bits; | ||
682 | } | ||
683 | |||
684 | |||
685 | unsigned long dGeomGetCategoryBits (dxGeom *g) | ||
686 | { | ||
687 | dAASSERT (g); | ||
688 | return g->category_bits; | ||
689 | } | ||
690 | |||
691 | |||
692 | unsigned long dGeomGetCollideBits (dxGeom *g) | ||
693 | { | ||
694 | dAASSERT (g); | ||
695 | return g->collide_bits; | ||
696 | } | ||
697 | |||
698 | |||
699 | void dGeomEnable (dxGeom *g) | ||
700 | { | ||
701 | dAASSERT (g); | ||
702 | g->gflags |= GEOM_ENABLED; | ||
703 | } | ||
704 | |||
705 | void dGeomDisable (dxGeom *g) | ||
706 | { | ||
707 | dAASSERT (g); | ||
708 | g->gflags &= ~GEOM_ENABLED; | ||
709 | } | ||
710 | |||
711 | int dGeomIsEnabled (dxGeom *g) | ||
712 | { | ||
713 | dAASSERT (g); | ||
714 | return (g->gflags & GEOM_ENABLED) != 0; | ||
715 | } | ||
716 | |||
717 | |||
718 | //**************************************************************************** | ||
719 | // C interface that lets the user make new classes. this interface is a lot | ||
720 | // more cumbersome than C++ subclassing, which is what is used internally | ||
721 | // in ODE. this API is mainly to support legacy code. | ||
722 | |||
723 | static int num_user_classes = 0; | ||
724 | static dGeomClass user_classes [dMaxUserClasses]; | ||
725 | |||
726 | |||
727 | struct dxUserGeom : public dxGeom { | ||
728 | void *user_data; | ||
729 | |||
730 | dxUserGeom (int class_num); | ||
731 | ~dxUserGeom(); | ||
732 | void computeAABB(); | ||
733 | int AABBTest (dxGeom *o, dReal aabb[6]); | ||
734 | }; | ||
735 | |||
736 | |||
737 | dxUserGeom::dxUserGeom (int class_num) : dxGeom (0,1) | ||
738 | { | ||
739 | type = class_num; | ||
740 | int size = user_classes[type-dFirstUserClass].bytes; | ||
741 | user_data = dAlloc (size); | ||
742 | memset (user_data,0,size); | ||
743 | } | ||
744 | |||
745 | |||
746 | dxUserGeom::~dxUserGeom() | ||
747 | { | ||
748 | dGeomClass *c = &user_classes[type-dFirstUserClass]; | ||
749 | if (c->dtor) c->dtor (this); | ||
750 | dFree (user_data,c->bytes); | ||
751 | } | ||
752 | |||
753 | |||
754 | void dxUserGeom::computeAABB() | ||
755 | { | ||
756 | user_classes[type-dFirstUserClass].aabb (this,aabb); | ||
757 | } | ||
758 | |||
759 | |||
760 | int dxUserGeom::AABBTest (dxGeom *o, dReal aabb[6]) | ||
761 | { | ||
762 | dGeomClass *c = &user_classes[type-dFirstUserClass]; | ||
763 | if (c->aabb_test) return c->aabb_test (this,o,aabb); | ||
764 | else return 1; | ||
765 | } | ||
766 | |||
767 | |||
768 | static int dCollideUserGeomWithGeom (dxGeom *o1, dxGeom *o2, int flags, | ||
769 | dContactGeom *contact, int skip) | ||
770 | { | ||
771 | // this generic collider function is called the first time that a user class | ||
772 | // tries to collide against something. it will find out the correct collider | ||
773 | // function and then set the colliders array so that the correct function is | ||
774 | // called directly the next time around. | ||
775 | |||
776 | int t1 = o1->type; // note that o1 is a user geom | ||
777 | int t2 = o2->type; // o2 *may* be a user geom | ||
778 | |||
779 | // find the collider function to use. if o1 does not know how to collide with | ||
780 | // o2, then o2 might know how to collide with o1 (provided that it is a user | ||
781 | // geom). | ||
782 | dColliderFn *fn = user_classes[t1-dFirstUserClass].collider (t2); | ||
783 | int reverse = 0; | ||
784 | if (!fn && t2 >= dFirstUserClass && t2 <= dLastUserClass) { | ||
785 | fn = user_classes[t2-dFirstUserClass].collider (t1); | ||
786 | reverse = 1; | ||
787 | } | ||
788 | |||
789 | // set the colliders array so that the correct function is called directly | ||
790 | // the next time around. note that fn can be 0 here if no collider was found, | ||
791 | // which means that dCollide() will always return 0 for this case. | ||
792 | colliders[t1][t2].fn = fn; | ||
793 | colliders[t1][t2].reverse = reverse; | ||
794 | colliders[t2][t1].fn = fn; | ||
795 | colliders[t2][t1].reverse = !reverse; | ||
796 | |||
797 | // now call the collider function indirectly through dCollide(), so that | ||
798 | // contact reversing is properly handled. | ||
799 | return dCollide (o1,o2,flags,contact,skip); | ||
800 | } | ||
801 | |||
802 | |||
803 | int dCreateGeomClass (const dGeomClass *c) | ||
804 | { | ||
805 | dUASSERT(c && c->bytes >= 0 && c->collider && c->aabb,"bad geom class"); | ||
806 | |||
807 | if (num_user_classes >= dMaxUserClasses) { | ||
808 | dDebug (0,"too many user classes, you must increase the limit and " | ||
809 | "recompile ODE"); | ||
810 | } | ||
811 | user_classes[num_user_classes] = *c; | ||
812 | int class_number = num_user_classes + dFirstUserClass; | ||
813 | initColliders(); | ||
814 | setAllColliders (class_number,&dCollideUserGeomWithGeom); | ||
815 | |||
816 | num_user_classes++; | ||
817 | return class_number; | ||
818 | } | ||
819 | |||
820 | |||
821 | void * dGeomGetClassData (dxGeom *g) | ||
822 | { | ||
823 | dUASSERT (g && g->type >= dFirstUserClass && | ||
824 | g->type <= dLastUserClass,"not a custom class"); | ||
825 | dxUserGeom *user = (dxUserGeom*) g; | ||
826 | return user->user_data; | ||
827 | } | ||
828 | |||
829 | |||
830 | dGeomID dCreateGeom (int classnum) | ||
831 | { | ||
832 | dUASSERT (classnum >= dFirstUserClass && | ||
833 | classnum <= dLastUserClass,"not a custom class"); | ||
834 | return new dxUserGeom (classnum); | ||
835 | } | ||
836 | |||
837 | |||
838 | |||
839 | /* ************************************************************************ */ | ||
840 | /* geom offset from body */ | ||
841 | |||
842 | void dGeomCreateOffset (dxGeom *g) | ||
843 | { | ||
844 | dAASSERT (g); | ||
845 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
846 | dUASSERT (g->body, "geom must be on a body"); | ||
847 | if (g->offset_posr) | ||
848 | { | ||
849 | return; // already created | ||
850 | } | ||
851 | dIASSERT (g->final_posr == &g->body->posr); | ||
852 | |||
853 | g->final_posr = dAllocPosr(); | ||
854 | g->offset_posr = dAllocPosr(); | ||
855 | dSetZero (g->offset_posr->pos,4); | ||
856 | dRSetIdentity (g->offset_posr->R); | ||
857 | |||
858 | g->gflags |= GEOM_POSR_BAD; | ||
859 | } | ||
860 | |||
861 | void dGeomSetOffsetPosition (dxGeom *g, dReal x, dReal y, dReal z) | ||
862 | { | ||
863 | dAASSERT (g); | ||
864 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
865 | dUASSERT (g->body, "geom must be on a body"); | ||
866 | CHECK_NOT_LOCKED (g->parent_space); | ||
867 | if (!g->offset_posr) | ||
868 | { | ||
869 | dGeomCreateOffset(g); | ||
870 | } | ||
871 | g->offset_posr->pos[0] = x; | ||
872 | g->offset_posr->pos[1] = y; | ||
873 | g->offset_posr->pos[2] = z; | ||
874 | dGeomMoved (g); | ||
875 | } | ||
876 | |||
877 | void dGeomSetOffsetRotation (dxGeom *g, const dMatrix3 R) | ||
878 | { | ||
879 | dAASSERT (g && R); | ||
880 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
881 | dUASSERT (g->body, "geom must be on a body"); | ||
882 | CHECK_NOT_LOCKED (g->parent_space); | ||
883 | if (!g->offset_posr) | ||
884 | { | ||
885 | dGeomCreateOffset (g); | ||
886 | } | ||
887 | memcpy (g->offset_posr->R,R,sizeof(dMatrix3)); | ||
888 | dGeomMoved (g); | ||
889 | } | ||
890 | |||
891 | void dGeomSetOffsetQuaternion (dxGeom *g, const dQuaternion quat) | ||
892 | { | ||
893 | dAASSERT (g && quat); | ||
894 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
895 | dUASSERT (g->body, "geom must be on a body"); | ||
896 | CHECK_NOT_LOCKED (g->parent_space); | ||
897 | if (!g->offset_posr) | ||
898 | { | ||
899 | dGeomCreateOffset (g); | ||
900 | } | ||
901 | dQtoR (quat, g->offset_posr->R); | ||
902 | dGeomMoved (g); | ||
903 | } | ||
904 | |||
905 | void dGeomSetOffsetWorldPosition (dxGeom *g, dReal x, dReal y, dReal z) | ||
906 | { | ||
907 | dAASSERT (g); | ||
908 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
909 | dUASSERT (g->body, "geom must be on a body"); | ||
910 | CHECK_NOT_LOCKED (g->parent_space); | ||
911 | if (!g->offset_posr) | ||
912 | { | ||
913 | dGeomCreateOffset(g); | ||
914 | } | ||
915 | dBodyGetPosRelPoint(g->body, x, y, z, g->offset_posr->pos); | ||
916 | dGeomMoved (g); | ||
917 | } | ||
918 | |||
919 | void dGeomSetOffsetWorldRotation (dxGeom *g, const dMatrix3 R) | ||
920 | { | ||
921 | dAASSERT (g && R); | ||
922 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
923 | dUASSERT (g->body, "geom must be on a body"); | ||
924 | CHECK_NOT_LOCKED (g->parent_space); | ||
925 | if (!g->offset_posr) | ||
926 | { | ||
927 | dGeomCreateOffset (g); | ||
928 | } | ||
929 | g->recomputePosr(); | ||
930 | |||
931 | dxPosR new_final_posr; | ||
932 | memcpy(new_final_posr.pos, g->final_posr->pos, sizeof(dVector3)); | ||
933 | memcpy(new_final_posr.R, R, sizeof(dMatrix3)); | ||
934 | |||
935 | getWorldOffsetPosr(g->body->posr, new_final_posr, *g->offset_posr); | ||
936 | dGeomMoved (g); | ||
937 | } | ||
938 | |||
939 | void dGeomSetOffsetWorldQuaternion (dxGeom *g, const dQuaternion quat) | ||
940 | { | ||
941 | dAASSERT (g && quat); | ||
942 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
943 | dUASSERT (g->body, "geom must be on a body"); | ||
944 | CHECK_NOT_LOCKED (g->parent_space); | ||
945 | if (!g->offset_posr) | ||
946 | { | ||
947 | dGeomCreateOffset (g); | ||
948 | } | ||
949 | |||
950 | g->recomputePosr(); | ||
951 | |||
952 | dxPosR new_final_posr; | ||
953 | memcpy(new_final_posr.pos, g->final_posr->pos, sizeof(dVector3)); | ||
954 | dQtoR (quat, new_final_posr.R); | ||
955 | |||
956 | getWorldOffsetPosr(g->body->posr, new_final_posr, *g->offset_posr); | ||
957 | dGeomMoved (g); | ||
958 | } | ||
959 | |||
960 | void dGeomClearOffset(dxGeom *g) | ||
961 | { | ||
962 | dAASSERT (g); | ||
963 | dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); | ||
964 | if (g->offset_posr) | ||
965 | { | ||
966 | dIASSERT(g->body); | ||
967 | // no longer need an offset posr | ||
968 | dFreePosr(g->offset_posr); | ||
969 | g->offset_posr = 0; | ||
970 | // the geom will now share the position of the body | ||
971 | dFreePosr(g->final_posr); | ||
972 | g->final_posr = &g->body->posr; | ||
973 | // geom has moved | ||
974 | g->gflags &= ~GEOM_POSR_BAD; | ||
975 | dGeomMoved (g); | ||
976 | } | ||
977 | } | ||
978 | |||
979 | int dGeomIsOffset(dxGeom *g) | ||
980 | { | ||
981 | dAASSERT (g); | ||
982 | return ((0 != g->offset_posr) ? 1 : 0); | ||
983 | } | ||
984 | |||
985 | static const dVector3 OFFSET_POSITION_ZERO = { 0.0f, 0.0f, 0.0f, 0.0f }; | ||
986 | |||
987 | const dReal * dGeomGetOffsetPosition (dxGeom *g) | ||
988 | { | ||
989 | dAASSERT (g); | ||
990 | if (g->offset_posr) | ||
991 | { | ||
992 | return g->offset_posr->pos; | ||
993 | } | ||
994 | return OFFSET_POSITION_ZERO; | ||
995 | } | ||
996 | |||
997 | void dGeomCopyOffsetPosition (dxGeom *g, dVector3 pos) | ||
998 | { | ||
999 | dAASSERT (g); | ||
1000 | if (g->offset_posr) | ||
1001 | { | ||
1002 | const dReal* src = g->offset_posr->pos; | ||
1003 | pos[0] = src[0]; | ||
1004 | pos[1] = src[1]; | ||
1005 | pos[2] = src[2]; | ||
1006 | } | ||
1007 | else | ||
1008 | { | ||
1009 | pos[0] = 0; | ||
1010 | pos[1] = 0; | ||
1011 | pos[2] = 0; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | static const dMatrix3 OFFSET_ROTATION_ZERO = | ||
1016 | { | ||
1017 | 1.0f, 0.0f, 0.0f, 0.0f, | ||
1018 | 0.0f, 1.0f, 0.0f, 0.0f, | ||
1019 | 0.0f, 0.0f, 1.0f, 0.0f, | ||
1020 | }; | ||
1021 | |||
1022 | const dReal * dGeomGetOffsetRotation (dxGeom *g) | ||
1023 | { | ||
1024 | dAASSERT (g); | ||
1025 | if (g->offset_posr) | ||
1026 | { | ||
1027 | return g->offset_posr->R; | ||
1028 | } | ||
1029 | return OFFSET_ROTATION_ZERO; | ||
1030 | } | ||
1031 | |||
1032 | void dGeomCopyOffsetRotation (dxGeom *g, dMatrix3 R) | ||
1033 | { | ||
1034 | dAASSERT (g); | ||
1035 | if (g->offset_posr) | ||
1036 | { | ||
1037 | const dReal* src = g->final_posr->R; | ||
1038 | R[0] = src[0]; | ||
1039 | R[1] = src[1]; | ||
1040 | R[2] = src[2]; | ||
1041 | R[4] = src[4]; | ||
1042 | R[5] = src[5]; | ||
1043 | R[6] = src[6]; | ||
1044 | R[8] = src[8]; | ||
1045 | R[9] = src[9]; | ||
1046 | R[10] = src[10]; | ||
1047 | } | ||
1048 | else | ||
1049 | { | ||
1050 | R[0] = OFFSET_ROTATION_ZERO[0]; | ||
1051 | R[1] = OFFSET_ROTATION_ZERO[1]; | ||
1052 | R[2] = OFFSET_ROTATION_ZERO[2]; | ||
1053 | R[4] = OFFSET_ROTATION_ZERO[4]; | ||
1054 | R[5] = OFFSET_ROTATION_ZERO[5]; | ||
1055 | R[6] = OFFSET_ROTATION_ZERO[6]; | ||
1056 | R[8] = OFFSET_ROTATION_ZERO[8]; | ||
1057 | R[9] = OFFSET_ROTATION_ZERO[9]; | ||
1058 | R[10] = OFFSET_ROTATION_ZERO[10]; | ||
1059 | } | ||
1060 | } | ||
1061 | |||
1062 | void dGeomGetOffsetQuaternion (dxGeom *g, dQuaternion result) | ||
1063 | { | ||
1064 | dAASSERT (g); | ||
1065 | if (g->offset_posr) | ||
1066 | { | ||
1067 | dRtoQ (g->offset_posr->R, result); | ||
1068 | } | ||
1069 | else | ||
1070 | { | ||
1071 | dSetZero (result,4); | ||
1072 | result[0] = 1; | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | //**************************************************************************** | ||
1077 | // initialization and shutdown routines - allocate and initialize data, | ||
1078 | // cleanup before exiting | ||
1079 | |||
1080 | extern void opcode_collider_cleanup(); | ||
1081 | |||
1082 | void dInitODE() | ||
1083 | { | ||
1084 | #if dTRIMESH_ENABLED && dTRIMESH_GIMPACT | ||
1085 | gimpact_init(); | ||
1086 | #endif | ||
1087 | } | ||
1088 | |||
1089 | void dCloseODE() | ||
1090 | { | ||
1091 | colliders_initialized = 0; | ||
1092 | num_user_classes = 0; | ||
1093 | dClearPosrCache(); | ||
1094 | |||
1095 | #if dTRIMESH_ENABLED && dTRIMESH_GIMPACT | ||
1096 | gimpact_terminate(); | ||
1097 | #endif | ||
1098 | |||
1099 | #if dTRIMESH_ENABLED && dTRIMESH_OPCODE | ||
1100 | // Free up static allocations in opcode | ||
1101 | opcode_collider_cleanup(); | ||
1102 | #endif | ||
1103 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_kernel.h b/libraries/ode-0.9\/ode/src/collision_kernel.h new file mode 100755 index 0000000..d5a2bc4 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_kernel.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | internal data structures and functions for collision detection. | ||
26 | |||
27 | */ | ||
28 | |||
29 | #ifndef _ODE_COLLISION_KERNEL_H_ | ||
30 | #define _ODE_COLLISION_KERNEL_H_ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/contact.h> | ||
34 | #include <ode/collision.h> | ||
35 | #include "objects.h" | ||
36 | |||
37 | //**************************************************************************** | ||
38 | // constants and macros | ||
39 | |||
40 | // mask for the number-of-contacts field in the dCollide() flags parameter | ||
41 | #define NUMC_MASK (0xffff) | ||
42 | |||
43 | #define IS_SPACE(geom) \ | ||
44 | ((geom)->type >= dFirstSpaceClass && (geom)->type <= dLastSpaceClass) | ||
45 | |||
46 | //**************************************************************************** | ||
47 | // geometry object base class | ||
48 | |||
49 | |||
50 | // geom flags. | ||
51 | // | ||
52 | // GEOM_DIRTY means that the space data structures for this geom are | ||
53 | // potentially not up to date. NOTE THAT all space parents of a dirty geom | ||
54 | // are themselves dirty. this is an invariant that must be enforced. | ||
55 | // | ||
56 | // GEOM_AABB_BAD means that the cached AABB for this geom is not up to date. | ||
57 | // note that GEOM_DIRTY does not imply GEOM_AABB_BAD, as the geom might | ||
58 | // recalculate its own AABB but does not know how to update the space data | ||
59 | // structures for the space it is in. but GEOM_AABB_BAD implies GEOM_DIRTY. | ||
60 | // the valid combinations are: | ||
61 | // 0 | ||
62 | // GEOM_DIRTY | ||
63 | // GEOM_DIRTY|GEOM_AABB_BAD | ||
64 | // GEOM_DIRTY|GEOM_AABB_BAD|GEOM_POSR_BAD | ||
65 | |||
66 | enum { | ||
67 | GEOM_DIRTY = 1, // geom is 'dirty', i.e. position unknown | ||
68 | GEOM_POSR_BAD = 2, // geom's final posr is not valid | ||
69 | GEOM_AABB_BAD = 4, // geom's AABB is not valid | ||
70 | GEOM_PLACEABLE = 8, // geom is placeable | ||
71 | GEOM_ENABLED = 16, // geom is enabled | ||
72 | |||
73 | // Ray specific | ||
74 | RAY_FIRSTCONTACT = 0x10000, | ||
75 | RAY_BACKFACECULL = 0x20000, | ||
76 | RAY_CLOSEST_HIT = 0x40000 | ||
77 | }; | ||
78 | |||
79 | |||
80 | // geometry object base class. pos and R will either point to a separately | ||
81 | // allocated buffer (if body is 0 - pos points to the dxPosR object) or to | ||
82 | // the pos and R of the body (if body nonzero). | ||
83 | // a dGeomID is a pointer to this object. | ||
84 | |||
85 | struct dxGeom : public dBase { | ||
86 | int type; // geom type number, set by subclass constructor | ||
87 | int gflags; // flags used by geom and space | ||
88 | void *data; // user-defined data pointer | ||
89 | dBodyID body; // dynamics body associated with this object (if any) | ||
90 | dxGeom *body_next; // next geom in body's linked list of associated geoms | ||
91 | dxPosR *final_posr; // final position of the geom in world coordinates | ||
92 | dxPosR *offset_posr; // offset from body in local coordinates | ||
93 | |||
94 | // information used by spaces | ||
95 | dxGeom *next; // next geom in linked list of geoms | ||
96 | dxGeom **tome; // linked list backpointer | ||
97 | dxSpace *parent_space;// the space this geom is contained in, 0 if none | ||
98 | dReal aabb[6]; // cached AABB for this space | ||
99 | unsigned long category_bits,collide_bits; | ||
100 | |||
101 | dxGeom (dSpaceID _space, int is_placeable); | ||
102 | virtual ~dxGeom(); | ||
103 | |||
104 | |||
105 | // calculate our new final position from our offset and body | ||
106 | void computePosr(); | ||
107 | |||
108 | // recalculate our new final position if needed | ||
109 | void recomputePosr() | ||
110 | { | ||
111 | if (gflags & GEOM_POSR_BAD) { | ||
112 | computePosr(); | ||
113 | gflags &= ~GEOM_POSR_BAD; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | virtual void computeAABB()=0; | ||
118 | // compute the AABB for this object and put it in aabb. this function | ||
119 | // always performs a fresh computation, it does not inspect the | ||
120 | // GEOM_AABB_BAD flag. | ||
121 | |||
122 | virtual int AABBTest (dxGeom *o, dReal aabb[6]); | ||
123 | // test whether the given AABB object intersects with this object, return | ||
124 | // 1=yes, 0=no. this is used as an early-exit test in the space collision | ||
125 | // functions. the default implementation returns 1, which is the correct | ||
126 | // behavior if no more detailed implementation can be provided. | ||
127 | |||
128 | // utility functions | ||
129 | |||
130 | // compute the AABB only if it is not current. this function manipulates | ||
131 | // the GEOM_AABB_BAD flag. | ||
132 | |||
133 | void recomputeAABB() { | ||
134 | if (gflags & GEOM_AABB_BAD) { | ||
135 | // our aabb functions assume final_posr is up to date | ||
136 | recomputePosr(); | ||
137 | computeAABB(); | ||
138 | gflags &= ~GEOM_AABB_BAD; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // add and remove this geom from a linked list maintained by a space. | ||
143 | |||
144 | void spaceAdd (dxGeom **first_ptr) { | ||
145 | next = *first_ptr; | ||
146 | tome = first_ptr; | ||
147 | if (*first_ptr) (*first_ptr)->tome = &next; | ||
148 | *first_ptr = this; | ||
149 | } | ||
150 | void spaceRemove() { | ||
151 | if (next) next->tome = tome; | ||
152 | *tome = next; | ||
153 | } | ||
154 | |||
155 | // add and remove this geom from a linked list maintained by a body. | ||
156 | |||
157 | void bodyAdd (dxBody *b) { | ||
158 | body = b; | ||
159 | body_next = b->geom; | ||
160 | b->geom = this; | ||
161 | } | ||
162 | void bodyRemove(); | ||
163 | }; | ||
164 | |||
165 | //**************************************************************************** | ||
166 | // the base space class | ||
167 | // | ||
168 | // the contained geoms are divided into two kinds: clean and dirty. | ||
169 | // the clean geoms have not moved since they were put in the list, | ||
170 | // and their AABBs are valid. the dirty geoms have changed position, and | ||
171 | // their AABBs are may not be valid. the two types are distinguished by the | ||
172 | // GEOM_DIRTY flag. all dirty geoms come *before* all clean geoms in the list. | ||
173 | |||
174 | struct dxSpace : public dxGeom { | ||
175 | int count; // number of geoms in this space | ||
176 | dxGeom *first; // first geom in list | ||
177 | int cleanup; // cleanup mode, 1=destroy geoms on exit | ||
178 | |||
179 | // cached state for getGeom() | ||
180 | int current_index; // only valid if current_geom != 0 | ||
181 | dxGeom *current_geom; // if 0 then there is no information | ||
182 | |||
183 | // locking stuff. the space is locked when it is currently traversing its | ||
184 | // internal data structures, e.g. in collide() and collide2(). operations | ||
185 | // that modify the contents of the space are not permitted when the space | ||
186 | // is locked. | ||
187 | int lock_count; | ||
188 | |||
189 | dxSpace (dSpaceID _space); | ||
190 | ~dxSpace(); | ||
191 | |||
192 | void computeAABB(); | ||
193 | |||
194 | void setCleanup (int mode); | ||
195 | int getCleanup(); | ||
196 | int query (dxGeom *geom); | ||
197 | int getNumGeoms(); | ||
198 | virtual dxGeom *getGeom (int i); | ||
199 | |||
200 | virtual void add (dxGeom *); | ||
201 | virtual void remove (dxGeom *); | ||
202 | virtual void dirty (dxGeom *); | ||
203 | |||
204 | virtual void cleanGeoms()=0; | ||
205 | // turn all dirty geoms into clean geoms by computing their AABBs and any | ||
206 | // other space data structures that are required. this should clear the | ||
207 | // GEOM_DIRTY and GEOM_AABB_BAD flags of all geoms. | ||
208 | |||
209 | virtual void collide (void *data, dNearCallback *callback)=0; | ||
210 | virtual void collide2 (void *data, dxGeom *geom, dNearCallback *callback)=0; | ||
211 | }; | ||
212 | |||
213 | |||
214 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_quadtreespace.cpp b/libraries/ode-0.9\/ode/src/collision_quadtreespace.cpp new file mode 100755 index 0000000..86a1833 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_quadtreespace.cpp | |||
@@ -0,0 +1,584 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // QuadTreeSpace by Erwin de Vries. | ||
24 | |||
25 | #include <ode/common.h> | ||
26 | #include <ode/matrix.h> | ||
27 | #include <ode/collision_space.h> | ||
28 | #include <ode/collision.h> | ||
29 | #include "collision_kernel.h" | ||
30 | |||
31 | #include "collision_space_internal.h" | ||
32 | |||
33 | |||
34 | #define AXIS0 0 | ||
35 | #define AXIS1 1 | ||
36 | #define UP 2 | ||
37 | |||
38 | //#define DRAWBLOCKS | ||
39 | |||
40 | const int SPLITAXIS = 2; | ||
41 | const int SPLITS = SPLITAXIS * SPLITAXIS; | ||
42 | |||
43 | #define GEOM_ENABLED(g) (g)->gflags & GEOM_ENABLED | ||
44 | |||
45 | class Block{ | ||
46 | public: | ||
47 | dReal MinX, MaxX; | ||
48 | dReal MinZ, MaxZ; | ||
49 | |||
50 | dGeomID First; | ||
51 | int GeomCount; | ||
52 | |||
53 | Block* Parent; | ||
54 | Block* Children; | ||
55 | |||
56 | void Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks); | ||
57 | |||
58 | void Collide(void* UserData, dNearCallback* Callback); | ||
59 | void Collide(dGeomID Object, dGeomID g, void* UserData, dNearCallback* Callback); | ||
60 | |||
61 | void CollideLocal(dGeomID Object, void* UserData, dNearCallback* Callback); | ||
62 | |||
63 | void AddObject(dGeomID Object); | ||
64 | void DelObject(dGeomID Object); | ||
65 | void Traverse(dGeomID Object); | ||
66 | |||
67 | bool Inside(const dReal* AABB); | ||
68 | |||
69 | Block* GetBlock(const dReal* AABB); | ||
70 | Block* GetBlockChild(const dReal* AABB); | ||
71 | }; | ||
72 | |||
73 | |||
74 | #ifdef DRAWBLOCKS | ||
75 | #include "..\..\Include\drawstuff\\drawstuff.h" | ||
76 | |||
77 | static void DrawBlock(Block* Block){ | ||
78 | dVector3 v[8]; | ||
79 | v[0][AXIS0] = Block->MinX; | ||
80 | v[0][UP] = REAL(-1.0); | ||
81 | v[0][AXIS1] = Block->MinZ; | ||
82 | |||
83 | v[1][AXIS0] = Block->MinX; | ||
84 | v[1][UP] = REAL(-1.0); | ||
85 | v[1][AXIS1] = Block->MaxZ; | ||
86 | |||
87 | v[2][AXIS0] = Block->MaxX; | ||
88 | v[2][UP] = REAL(-1.0); | ||
89 | v[2][AXIS1] = Block->MinZ; | ||
90 | |||
91 | v[3][AXIS0] = Block->MaxX; | ||
92 | v[3][UP] = REAL(-1.0); | ||
93 | v[3][AXIS1] = Block->MaxZ; | ||
94 | |||
95 | v[4][AXIS0] = Block->MinX; | ||
96 | v[4][UP] = REAL(1.0); | ||
97 | v[4][AXIS1] = Block->MinZ; | ||
98 | |||
99 | v[5][AXIS0] = Block->MinX; | ||
100 | v[5][UP] = REAL(1.0); | ||
101 | v[5][AXIS1] = Block->MaxZ; | ||
102 | |||
103 | v[6][AXIS0] = Block->MaxX; | ||
104 | v[6][UP] = REAL(1.0); | ||
105 | v[6][AXIS1] = Block->MinZ; | ||
106 | |||
107 | v[7][AXIS0] = Block->MaxX; | ||
108 | v[7][UP] = REAL(1.0); | ||
109 | v[7][AXIS1] = Block->MaxZ; | ||
110 | |||
111 | // Bottom | ||
112 | dsDrawLine(v[0], v[1]); | ||
113 | dsDrawLine(v[1], v[3]); | ||
114 | dsDrawLine(v[3], v[2]); | ||
115 | dsDrawLine(v[2], v[0]); | ||
116 | |||
117 | // Top | ||
118 | dsDrawLine(v[4], v[5]); | ||
119 | dsDrawLine(v[5], v[7]); | ||
120 | dsDrawLine(v[7], v[6]); | ||
121 | dsDrawLine(v[6], v[4]); | ||
122 | |||
123 | // Sides | ||
124 | dsDrawLine(v[0], v[4]); | ||
125 | dsDrawLine(v[1], v[5]); | ||
126 | dsDrawLine(v[2], v[6]); | ||
127 | dsDrawLine(v[3], v[7]); | ||
128 | } | ||
129 | #endif //DRAWBLOCKS | ||
130 | |||
131 | |||
132 | void Block::Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks){ | ||
133 | GeomCount = 0; | ||
134 | First = 0; | ||
135 | |||
136 | MinX = Center[AXIS0] - Extents[AXIS0]; | ||
137 | MaxX = Center[AXIS0] + Extents[AXIS0]; | ||
138 | |||
139 | MinZ = Center[AXIS1] - Extents[AXIS1]; | ||
140 | MaxZ = Center[AXIS1] + Extents[AXIS1]; | ||
141 | |||
142 | this->Parent = Parent; | ||
143 | if (Depth > 0){ | ||
144 | Children = Blocks; | ||
145 | Blocks += SPLITS; | ||
146 | |||
147 | dVector3 ChildExtents; | ||
148 | ChildExtents[AXIS0] = Extents[AXIS0] / SPLITAXIS; | ||
149 | ChildExtents[AXIS1] = Extents[AXIS1] / SPLITAXIS; | ||
150 | ChildExtents[UP] = Extents[UP]; | ||
151 | |||
152 | for (int i = 0; i < SPLITAXIS; i++){ | ||
153 | for (int j = 0; j < SPLITAXIS; j++){ | ||
154 | int Index = i * SPLITAXIS + j; | ||
155 | |||
156 | dVector3 ChildCenter; | ||
157 | ChildCenter[AXIS0] = Center[AXIS0] - Extents[AXIS0] + ChildExtents[AXIS0] + i * (ChildExtents[AXIS0] * 2); | ||
158 | ChildCenter[AXIS1] = Center[AXIS1] - Extents[AXIS1] + ChildExtents[AXIS1] + j * (ChildExtents[AXIS1] * 2); | ||
159 | ChildCenter[UP] = Center[UP]; | ||
160 | |||
161 | Children[Index].Create(ChildCenter, ChildExtents, this, Depth - 1, Blocks); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | else Children = 0; | ||
166 | } | ||
167 | |||
168 | void Block::Collide(void* UserData, dNearCallback* Callback){ | ||
169 | #ifdef DRAWBLOCKS | ||
170 | DrawBlock(this); | ||
171 | #endif | ||
172 | // Collide the local list | ||
173 | dxGeom* g = First; | ||
174 | while (g){ | ||
175 | if (GEOM_ENABLED(g)){ | ||
176 | Collide(g, g->next, UserData, Callback); | ||
177 | } | ||
178 | g = g->next; | ||
179 | } | ||
180 | |||
181 | // Recurse for children | ||
182 | if (Children){ | ||
183 | for (int i = 0; i < SPLITS; i++){ | ||
184 | if (Children[i].GeomCount <= 1){ // Early out | ||
185 | continue; | ||
186 | } | ||
187 | Children[i].Collide(UserData, Callback); | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | |||
192 | void Block::Collide(dxGeom* g1, dxGeom* g2, void* UserData, dNearCallback* Callback){ | ||
193 | #ifdef DRAWBLOCKS | ||
194 | DrawBlock(this); | ||
195 | #endif | ||
196 | // Collide against local list | ||
197 | while (g2){ | ||
198 | if (GEOM_ENABLED(g2)){ | ||
199 | collideAABBs (g1, g2, UserData, Callback); | ||
200 | } | ||
201 | g2 = g2->next; | ||
202 | } | ||
203 | |||
204 | // Collide against children | ||
205 | if (Children){ | ||
206 | for (int i = 0; i < SPLITS; i++){ | ||
207 | // Early out for empty blocks | ||
208 | if (Children[i].GeomCount == 0){ | ||
209 | continue; | ||
210 | } | ||
211 | |||
212 | // Does the geom's AABB collide with the block? | ||
213 | // Dont do AABB tests for single geom blocks. | ||
214 | if (Children[i].GeomCount == 1 && Children[i].First){ | ||
215 | // | ||
216 | } | ||
217 | else if (true){ | ||
218 | if (g1->aabb[AXIS0 * 2 + 0] > Children[i].MaxX || | ||
219 | g1->aabb[AXIS0 * 2 + 1] < Children[i].MinX || | ||
220 | g1->aabb[AXIS1 * 2 + 0] > Children[i].MaxZ || | ||
221 | g1->aabb[AXIS1 * 2 + 1] < Children[i].MinZ) continue; | ||
222 | } | ||
223 | Children[i].Collide(g1, Children[i].First, UserData, Callback); | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | void Block::CollideLocal(dxGeom* g1, void* UserData, dNearCallback* Callback){ | ||
229 | // Collide against local list | ||
230 | dxGeom* g2 = First; | ||
231 | while (g2){ | ||
232 | if (GEOM_ENABLED(g2)){ | ||
233 | collideAABBs (g1, g2, UserData, Callback); | ||
234 | } | ||
235 | g2 = g2->next; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | void Block::AddObject(dGeomID Object){ | ||
240 | // Add the geom | ||
241 | Object->next = First; | ||
242 | First = Object; | ||
243 | Object->tome = (dxGeom**)this; | ||
244 | |||
245 | // Now traverse upwards to tell that we have a geom | ||
246 | Block* Block = this; | ||
247 | do{ | ||
248 | Block->GeomCount++; | ||
249 | Block = Block->Parent; | ||
250 | } | ||
251 | while (Block); | ||
252 | } | ||
253 | |||
254 | void Block::DelObject(dGeomID Object){ | ||
255 | // Del the geom | ||
256 | dxGeom* g = First; | ||
257 | dxGeom* Last = 0; | ||
258 | while (g){ | ||
259 | if (g == Object){ | ||
260 | if (Last){ | ||
261 | Last->next = g->next; | ||
262 | } | ||
263 | else First = g->next; | ||
264 | |||
265 | break; | ||
266 | } | ||
267 | Last = g; | ||
268 | g = g->next; | ||
269 | } | ||
270 | |||
271 | Object->tome = 0; | ||
272 | |||
273 | // Now traverse upwards to tell that we have lost a geom | ||
274 | Block* Block = this; | ||
275 | do{ | ||
276 | Block->GeomCount--; | ||
277 | Block = Block->Parent; | ||
278 | } | ||
279 | while (Block); | ||
280 | } | ||
281 | |||
282 | void Block::Traverse(dGeomID Object){ | ||
283 | Block* NewBlock = GetBlock(Object->aabb); | ||
284 | |||
285 | if (NewBlock != this){ | ||
286 | // Remove the geom from the old block and add it to the new block. | ||
287 | // This could be more optimal, but the loss should be very small. | ||
288 | DelObject(Object); | ||
289 | NewBlock->AddObject(Object); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | bool Block::Inside(const dReal* AABB){ | ||
294 | return AABB[AXIS0 * 2 + 0] >= MinX && AABB[AXIS0 * 2 + 1] <= MaxX && AABB[AXIS1 * 2 + 0] >= MinZ && AABB[AXIS1 * 2 + 1] <= MaxZ; | ||
295 | } | ||
296 | |||
297 | Block* Block::GetBlock(const dReal* AABB){ | ||
298 | if (Inside(AABB)){ | ||
299 | return GetBlockChild(AABB); // Child or this will have a good block | ||
300 | } | ||
301 | else if (Parent){ | ||
302 | return Parent->GetBlock(AABB); // Parent has a good block | ||
303 | } | ||
304 | else return this; // We are at the root, so we have little choice | ||
305 | } | ||
306 | |||
307 | Block* Block::GetBlockChild(const dReal* AABB){ | ||
308 | if (Children){ | ||
309 | for (int i = 0; i < SPLITS; i++){ | ||
310 | if (Children[i].Inside(AABB)){ | ||
311 | return Children[i].GetBlockChild(AABB); // Child will have good block | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | return this; // This is the best block | ||
316 | } | ||
317 | |||
318 | //**************************************************************************** | ||
319 | // quadtree space | ||
320 | |||
321 | struct dxQuadTreeSpace : public dxSpace{ | ||
322 | Block* Blocks; // Blocks[0] is the root | ||
323 | |||
324 | dArray<dxGeom*> DirtyList; | ||
325 | |||
326 | dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth); | ||
327 | ~dxQuadTreeSpace(); | ||
328 | |||
329 | dxGeom* getGeom(int i); | ||
330 | |||
331 | void add(dxGeom* g); | ||
332 | void remove(dxGeom* g); | ||
333 | void dirty(dxGeom* g); | ||
334 | |||
335 | void computeAABB(); | ||
336 | |||
337 | void cleanGeoms(); | ||
338 | void collide(void* UserData, dNearCallback* Callback); | ||
339 | void collide2(void* UserData, dxGeom* g1, dNearCallback* Callback); | ||
340 | |||
341 | // Temp data | ||
342 | Block* CurrentBlock; // Only used while enumerating | ||
343 | int* CurrentChild; // Only used while enumerating | ||
344 | int CurrentLevel; // Only used while enumerating | ||
345 | dxGeom* CurrentObject; // Only used while enumerating | ||
346 | int CurrentIndex; | ||
347 | }; | ||
348 | |||
349 | dxQuadTreeSpace::dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth) : dxSpace(_space){ | ||
350 | type = dQuadTreeSpaceClass; | ||
351 | |||
352 | int BlockCount = 0; | ||
353 | for (int i = 0; i <= Depth; i++){ | ||
354 | BlockCount += (int)pow((dReal)SPLITS, i); | ||
355 | } | ||
356 | |||
357 | Blocks = (Block*)dAlloc(BlockCount * sizeof(Block)); | ||
358 | Block* Blocks = this->Blocks + 1; // This pointer gets modified! | ||
359 | |||
360 | this->Blocks[0].Create(Center, Extents, 0, Depth, Blocks); | ||
361 | |||
362 | CurrentBlock = 0; | ||
363 | CurrentChild = (int*)dAlloc((Depth + 1) * sizeof(int)); | ||
364 | CurrentLevel = 0; | ||
365 | CurrentObject = 0; | ||
366 | CurrentIndex = -1; | ||
367 | |||
368 | // Init AABB. We initialize to infinity because it is not illegal for an object to be outside of the tree. Its simply inserted in the root block | ||
369 | aabb[0] = -dInfinity; | ||
370 | aabb[1] = dInfinity; | ||
371 | aabb[2] = -dInfinity; | ||
372 | aabb[3] = dInfinity; | ||
373 | aabb[4] = -dInfinity; | ||
374 | aabb[5] = dInfinity; | ||
375 | } | ||
376 | |||
377 | dxQuadTreeSpace::~dxQuadTreeSpace(){ | ||
378 | int Depth = 0; | ||
379 | Block* Current = &Blocks[0]; | ||
380 | while (Current){ | ||
381 | Depth++; | ||
382 | Current = Current->Children; | ||
383 | } | ||
384 | |||
385 | int BlockCount = 0; | ||
386 | for (int i = 0; i < Depth; i++){ | ||
387 | BlockCount += (int)pow((dReal)SPLITS, i); | ||
388 | } | ||
389 | |||
390 | dFree(Blocks, BlockCount * sizeof(Block)); | ||
391 | dFree(CurrentChild, (Depth + 1) * sizeof(int)); | ||
392 | } | ||
393 | |||
394 | dxGeom* dxQuadTreeSpace::getGeom(int Index){ | ||
395 | dUASSERT(Index >= 0 && Index < count, "index out of range"); | ||
396 | |||
397 | //@@@ | ||
398 | dDebug (0,"dxQuadTreeSpace::getGeom() not yet implemented"); | ||
399 | |||
400 | return 0; | ||
401 | |||
402 | // This doesnt work | ||
403 | |||
404 | /*if (CurrentIndex == Index){ | ||
405 | // Loop through all objects in the local list | ||
406 | CHILDRECURSE: | ||
407 | if (CurrentObject){ | ||
408 | dGeomID g = CurrentObject; | ||
409 | CurrentObject = CurrentObject->next; | ||
410 | CurrentIndex++; | ||
411 | |||
412 | #ifdef DRAWBLOCKS | ||
413 | DrawBlock(CurrentBlock); | ||
414 | #endif //DRAWBLOCKS | ||
415 | return g; | ||
416 | } | ||
417 | else{ | ||
418 | // Now lets loop through our children. Starting at index 0. | ||
419 | if (CurrentBlock->Children){ | ||
420 | CurrentChild[CurrentLevel] = 0; | ||
421 | PARENTRECURSE: | ||
422 | for (int& i = CurrentChild[CurrentLevel]; i < SPLITS; i++){ | ||
423 | if (CurrentBlock->Children[i].GeomCount == 0){ | ||
424 | continue; | ||
425 | } | ||
426 | CurrentBlock = &CurrentBlock->Children[i]; | ||
427 | CurrentObject = CurrentBlock->First; | ||
428 | |||
429 | i++; | ||
430 | |||
431 | CurrentLevel++; | ||
432 | goto CHILDRECURSE; | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | |||
437 | // Now lets go back to the parent so it can continue processing its other children. | ||
438 | if (CurrentBlock->Parent){ | ||
439 | CurrentBlock = CurrentBlock->Parent; | ||
440 | CurrentLevel--; | ||
441 | goto PARENTRECURSE; | ||
442 | } | ||
443 | } | ||
444 | else{ | ||
445 | CurrentBlock = &Blocks[0]; | ||
446 | CurrentLevel = 0; | ||
447 | CurrentObject = CurrentObject; | ||
448 | CurrentIndex = 0; | ||
449 | |||
450 | // Other states are already set | ||
451 | CurrentObject = CurrentBlock->First; | ||
452 | } | ||
453 | |||
454 | |||
455 | if (current_geom && current_index == Index - 1){ | ||
456 | //current_geom = current_geom->next; // next | ||
457 | current_index = Index; | ||
458 | return current_geom; | ||
459 | } | ||
460 | else for (int i = 0; i < Index; i++){ // this will be verrrrrrry slow | ||
461 | getGeom(i); | ||
462 | }*/ | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | void dxQuadTreeSpace::add(dxGeom* g){ | ||
468 | CHECK_NOT_LOCKED (this); | ||
469 | dAASSERT(g); | ||
470 | dUASSERT(g->parent_space == 0 && g->next == 0, "geom is already in a space"); | ||
471 | |||
472 | g->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
473 | DirtyList.push(g); | ||
474 | |||
475 | // add | ||
476 | g->parent_space = this; | ||
477 | Blocks[0].GetBlock(g->aabb)->AddObject(g); // Add to best block | ||
478 | count++; | ||
479 | |||
480 | // enumerator has been invalidated | ||
481 | current_geom = 0; | ||
482 | |||
483 | dGeomMoved(this); | ||
484 | } | ||
485 | |||
486 | void dxQuadTreeSpace::remove(dxGeom* g){ | ||
487 | CHECK_NOT_LOCKED(this); | ||
488 | dAASSERT(g); | ||
489 | dUASSERT(g->parent_space == this,"object is not in this space"); | ||
490 | |||
491 | // remove | ||
492 | ((Block*)g->tome)->DelObject(g); | ||
493 | count--; | ||
494 | |||
495 | for (int i = 0; i < DirtyList.size(); i++){ | ||
496 | if (DirtyList[i] == g){ | ||
497 | DirtyList.remove(i); | ||
498 | // (mg) there can be multiple instances of a dirty object on stack be sure to remove ALL and not just first, for this we decrement i | ||
499 | --i; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | // safeguard | ||
504 | g->next = 0; | ||
505 | g->tome = 0; | ||
506 | g->parent_space = 0; | ||
507 | |||
508 | // enumerator has been invalidated | ||
509 | current_geom = 0; | ||
510 | |||
511 | // the bounding box of this space (and that of all the parents) may have | ||
512 | // changed as a consequence of the removal. | ||
513 | dGeomMoved(this); | ||
514 | } | ||
515 | |||
516 | void dxQuadTreeSpace::dirty(dxGeom* g){ | ||
517 | DirtyList.push(g); | ||
518 | } | ||
519 | |||
520 | void dxQuadTreeSpace::computeAABB(){ | ||
521 | // | ||
522 | } | ||
523 | |||
524 | void dxQuadTreeSpace::cleanGeoms(){ | ||
525 | // compute the AABBs of all dirty geoms, and clear the dirty flags | ||
526 | lock_count++; | ||
527 | |||
528 | for (int i = 0; i < DirtyList.size(); i++){ | ||
529 | dxGeom* g = DirtyList[i]; | ||
530 | if (IS_SPACE(g)){ | ||
531 | ((dxSpace*)g)->cleanGeoms(); | ||
532 | } | ||
533 | g->recomputeAABB(); | ||
534 | g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); | ||
535 | |||
536 | ((Block*)g->tome)->Traverse(g); | ||
537 | } | ||
538 | DirtyList.setSize(0); | ||
539 | |||
540 | lock_count--; | ||
541 | } | ||
542 | |||
543 | void dxQuadTreeSpace::collide(void* UserData, dNearCallback* Callback){ | ||
544 | dAASSERT(Callback); | ||
545 | |||
546 | lock_count++; | ||
547 | cleanGeoms(); | ||
548 | |||
549 | Blocks[0].Collide(UserData, Callback); | ||
550 | |||
551 | lock_count--; | ||
552 | } | ||
553 | |||
554 | void dxQuadTreeSpace::collide2(void* UserData, dxGeom* g1, dNearCallback* Callback){ | ||
555 | dAASSERT(g1 && Callback); | ||
556 | |||
557 | lock_count++; | ||
558 | cleanGeoms(); | ||
559 | g1->recomputeAABB(); | ||
560 | |||
561 | if (g1->parent_space == this){ | ||
562 | // The block the geom is in | ||
563 | Block* CurrentBlock = (Block*)g1->tome; | ||
564 | |||
565 | // Collide against block and its children | ||
566 | CurrentBlock->Collide(g1, CurrentBlock->First, UserData, Callback); | ||
567 | |||
568 | // Collide against parents | ||
569 | while (true){ | ||
570 | CurrentBlock = CurrentBlock->Parent; | ||
571 | if (!CurrentBlock){ | ||
572 | break; | ||
573 | } | ||
574 | CurrentBlock->CollideLocal(g1, UserData, Callback); | ||
575 | } | ||
576 | } | ||
577 | else Blocks[0].Collide(g1, Blocks[0].First, UserData, Callback); | ||
578 | |||
579 | lock_count--; | ||
580 | } | ||
581 | |||
582 | dSpaceID dQuadTreeSpaceCreate(dxSpace* space, dVector3 Center, dVector3 Extents, int Depth){ | ||
583 | return new dxQuadTreeSpace(space, Center, Extents, Depth); | ||
584 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_space.cpp b/libraries/ode-0.9\/ode/src/collision_space.cpp new file mode 100755 index 0000000..1a8fc81 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_space.cpp | |||
@@ -0,0 +1,790 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | spaces | ||
26 | |||
27 | */ | ||
28 | |||
29 | #include <ode/common.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/collision_space.h> | ||
32 | #include <ode/collision.h> | ||
33 | #include "collision_kernel.h" | ||
34 | |||
35 | #include "collision_space_internal.h" | ||
36 | |||
37 | #ifdef _MSC_VER | ||
38 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
39 | #endif | ||
40 | |||
41 | //**************************************************************************** | ||
42 | // make the geom dirty by setting the GEOM_DIRTY and GEOM_BAD_AABB flags | ||
43 | // and moving it to the front of the space's list. all the parents of a | ||
44 | // dirty geom also become dirty. | ||
45 | |||
46 | void dGeomMoved (dxGeom *geom) | ||
47 | { | ||
48 | dAASSERT (geom); | ||
49 | |||
50 | // if geom is offset, mark it as needing a calculate | ||
51 | if (geom->offset_posr) { | ||
52 | geom->gflags |= GEOM_POSR_BAD; | ||
53 | } | ||
54 | |||
55 | // from the bottom of the space heirarchy up, process all clean geoms | ||
56 | // turning them into dirty geoms. | ||
57 | dxSpace *parent = geom->parent_space; | ||
58 | |||
59 | while (parent && (geom->gflags & GEOM_DIRTY)==0) { | ||
60 | CHECK_NOT_LOCKED (parent); | ||
61 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
62 | parent->dirty (geom); | ||
63 | geom = parent; | ||
64 | parent = parent->parent_space; | ||
65 | } | ||
66 | |||
67 | // all the remaining dirty geoms must have their AABB_BAD flags set, to | ||
68 | // ensure that their AABBs get recomputed | ||
69 | while (geom) { | ||
70 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
71 | CHECK_NOT_LOCKED (geom->parent_space); | ||
72 | geom = geom->parent_space; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | #define GEOM_ENABLED(g) ((g)->gflags & GEOM_ENABLED) | ||
77 | |||
78 | //**************************************************************************** | ||
79 | // dxSpace | ||
80 | |||
81 | dxSpace::dxSpace (dSpaceID _space) : dxGeom (_space,0) | ||
82 | { | ||
83 | count = 0; | ||
84 | first = 0; | ||
85 | cleanup = 1; | ||
86 | current_index = 0; | ||
87 | current_geom = 0; | ||
88 | lock_count = 0; | ||
89 | } | ||
90 | |||
91 | |||
92 | dxSpace::~dxSpace() | ||
93 | { | ||
94 | CHECK_NOT_LOCKED (this); | ||
95 | if (cleanup) { | ||
96 | // note that destroying each geom will call remove() | ||
97 | dxGeom *g,*n; | ||
98 | for (g = first; g; g=n) { | ||
99 | n = g->next; | ||
100 | dGeomDestroy (g); | ||
101 | } | ||
102 | } | ||
103 | else { | ||
104 | dxGeom *g,*n; | ||
105 | for (g = first; g; g=n) { | ||
106 | n = g->next; | ||
107 | remove (g); | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | |||
113 | void dxSpace::computeAABB() | ||
114 | { | ||
115 | if (first) { | ||
116 | int i; | ||
117 | dReal a[6]; | ||
118 | a[0] = dInfinity; | ||
119 | a[1] = -dInfinity; | ||
120 | a[2] = dInfinity; | ||
121 | a[3] = -dInfinity; | ||
122 | a[4] = dInfinity; | ||
123 | a[5] = -dInfinity; | ||
124 | for (dxGeom *g=first; g; g=g->next) { | ||
125 | g->recomputeAABB(); | ||
126 | for (i=0; i<6; i += 2) if (g->aabb[i] < a[i]) a[i] = g->aabb[i]; | ||
127 | for (i=1; i<6; i += 2) if (g->aabb[i] > a[i]) a[i] = g->aabb[i]; | ||
128 | } | ||
129 | memcpy(aabb,a,6*sizeof(dReal)); | ||
130 | } | ||
131 | else { | ||
132 | dSetZero (aabb,6); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | |||
137 | void dxSpace::setCleanup (int mode) | ||
138 | { | ||
139 | cleanup = (mode != 0); | ||
140 | } | ||
141 | |||
142 | |||
143 | int dxSpace::getCleanup() | ||
144 | { | ||
145 | return cleanup; | ||
146 | } | ||
147 | |||
148 | |||
149 | int dxSpace::query (dxGeom *geom) | ||
150 | { | ||
151 | dAASSERT (geom); | ||
152 | return (geom->parent_space == this); | ||
153 | } | ||
154 | |||
155 | |||
156 | int dxSpace::getNumGeoms() | ||
157 | { | ||
158 | return count; | ||
159 | } | ||
160 | |||
161 | |||
162 | // the dirty geoms are numbered 0..k, the clean geoms are numbered k+1..count-1 | ||
163 | |||
164 | dxGeom *dxSpace::getGeom (int i) | ||
165 | { | ||
166 | dUASSERT (i >= 0 && i < count,"index out of range"); | ||
167 | if (current_geom && current_index == i-1) { | ||
168 | current_geom = current_geom->next; | ||
169 | current_index = i; | ||
170 | return current_geom; | ||
171 | } | ||
172 | else { | ||
173 | dxGeom *g=first; | ||
174 | for (int j=0; j<i; j++) { | ||
175 | if (g) g = g->next; else return 0; | ||
176 | } | ||
177 | current_geom = g; | ||
178 | current_index = i; | ||
179 | return g; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | void dxSpace::add (dxGeom *geom) | ||
185 | { | ||
186 | CHECK_NOT_LOCKED (this); | ||
187 | dAASSERT (geom); | ||
188 | dUASSERT (geom->parent_space == 0 && geom->next == 0, | ||
189 | "geom is already in a space"); | ||
190 | |||
191 | // add | ||
192 | geom->parent_space = this; | ||
193 | geom->spaceAdd (&first); | ||
194 | count++; | ||
195 | |||
196 | // enumerator has been invalidated | ||
197 | current_geom = 0; | ||
198 | |||
199 | // new geoms are added to the front of the list and are always | ||
200 | // considered to be dirty. as a consequence, this space and all its | ||
201 | // parents are dirty too. | ||
202 | geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; | ||
203 | dGeomMoved (this); | ||
204 | } | ||
205 | |||
206 | |||
207 | void dxSpace::remove (dxGeom *geom) | ||
208 | { | ||
209 | CHECK_NOT_LOCKED (this); | ||
210 | dAASSERT (geom); | ||
211 | dUASSERT (geom->parent_space == this,"object is not in this space"); | ||
212 | |||
213 | // remove | ||
214 | geom->spaceRemove(); | ||
215 | count--; | ||
216 | |||
217 | // safeguard | ||
218 | geom->next = 0; | ||
219 | geom->tome = 0; | ||
220 | geom->parent_space = 0; | ||
221 | |||
222 | // enumerator has been invalidated | ||
223 | current_geom = 0; | ||
224 | |||
225 | // the bounding box of this space (and that of all the parents) may have | ||
226 | // changed as a consequence of the removal. | ||
227 | dGeomMoved (this); | ||
228 | } | ||
229 | |||
230 | |||
231 | void dxSpace::dirty (dxGeom *geom) | ||
232 | { | ||
233 | geom->spaceRemove(); | ||
234 | geom->spaceAdd (&first); | ||
235 | } | ||
236 | |||
237 | //**************************************************************************** | ||
238 | // simple space - reports all n^2 object intersections | ||
239 | |||
240 | struct dxSimpleSpace : public dxSpace { | ||
241 | dxSimpleSpace (dSpaceID _space); | ||
242 | void cleanGeoms(); | ||
243 | void collide (void *data, dNearCallback *callback); | ||
244 | void collide2 (void *data, dxGeom *geom, dNearCallback *callback); | ||
245 | }; | ||
246 | |||
247 | |||
248 | dxSimpleSpace::dxSimpleSpace (dSpaceID _space) : dxSpace (_space) | ||
249 | { | ||
250 | type = dSimpleSpaceClass; | ||
251 | } | ||
252 | |||
253 | |||
254 | void dxSimpleSpace::cleanGeoms() | ||
255 | { | ||
256 | // compute the AABBs of all dirty geoms, and clear the dirty flags | ||
257 | lock_count++; | ||
258 | for (dxGeom *g=first; g && (g->gflags & GEOM_DIRTY); g=g->next) { | ||
259 | if (IS_SPACE(g)) { | ||
260 | ((dxSpace*)g)->cleanGeoms(); | ||
261 | } | ||
262 | g->recomputeAABB(); | ||
263 | g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); | ||
264 | } | ||
265 | lock_count--; | ||
266 | } | ||
267 | |||
268 | |||
269 | void dxSimpleSpace::collide (void *data, dNearCallback *callback) | ||
270 | { | ||
271 | dAASSERT (callback); | ||
272 | |||
273 | lock_count++; | ||
274 | cleanGeoms(); | ||
275 | |||
276 | // intersect all bounding boxes | ||
277 | for (dxGeom *g1=first; g1; g1=g1->next) { | ||
278 | if (GEOM_ENABLED(g1)){ | ||
279 | for (dxGeom *g2=g1->next; g2; g2=g2->next) { | ||
280 | if (GEOM_ENABLED(g2)){ | ||
281 | collideAABBs (g1,g2,data,callback); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | lock_count--; | ||
288 | } | ||
289 | |||
290 | |||
291 | void dxSimpleSpace::collide2 (void *data, dxGeom *geom, | ||
292 | dNearCallback *callback) | ||
293 | { | ||
294 | dAASSERT (geom && callback); | ||
295 | |||
296 | lock_count++; | ||
297 | cleanGeoms(); | ||
298 | geom->recomputeAABB(); | ||
299 | |||
300 | // intersect bounding boxes | ||
301 | for (dxGeom *g=first; g; g=g->next) { | ||
302 | if (GEOM_ENABLED(g)){ | ||
303 | collideAABBs (g,geom,data,callback); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | lock_count--; | ||
308 | } | ||
309 | |||
310 | //**************************************************************************** | ||
311 | // utility stuff for hash table space | ||
312 | |||
313 | // kind of silly, but oh well... | ||
314 | #ifndef MAXINT | ||
315 | #define MAXINT ((int)((((unsigned int)(-1)) << 1) >> 1)) | ||
316 | #endif | ||
317 | |||
318 | |||
319 | // prime[i] is the largest prime smaller than 2^i | ||
320 | #define NUM_PRIMES 31 | ||
321 | static long int prime[NUM_PRIMES] = {1L,2L,3L,7L,13L,31L,61L,127L,251L,509L, | ||
322 | 1021L,2039L,4093L,8191L,16381L,32749L,65521L,131071L,262139L, | ||
323 | 524287L,1048573L,2097143L,4194301L,8388593L,16777213L,33554393L, | ||
324 | 67108859L,134217689L,268435399L,536870909L,1073741789L}; | ||
325 | |||
326 | |||
327 | // an axis aligned bounding box in the hash table | ||
328 | struct dxAABB { | ||
329 | dxAABB *next; // next in the list of all AABBs | ||
330 | int level; // the level this is stored in (cell size = 2^level) | ||
331 | int dbounds[6]; // AABB bounds, discretized to cell size | ||
332 | dxGeom *geom; // corresponding geometry object (AABB stored here) | ||
333 | int index; // index of this AABB, starting from 0 | ||
334 | }; | ||
335 | |||
336 | |||
337 | // a hash table node that represents an AABB that intersects a particular cell | ||
338 | // at a particular level | ||
339 | struct Node { | ||
340 | Node *next; // next node in hash table collision list, 0 if none | ||
341 | int x,y,z; // cell position in space, discretized to cell size | ||
342 | dxAABB *aabb; // axis aligned bounding box that intersects this cell | ||
343 | }; | ||
344 | |||
345 | |||
346 | // return the `level' of an AABB. the AABB will be put into cells at this | ||
347 | // level - the cell size will be 2^level. the level is chosen to be the | ||
348 | // smallest value such that the AABB occupies no more than 8 cells, regardless | ||
349 | // of its placement. this means that: | ||
350 | // size/2 < q <= size | ||
351 | // where q is the maximum AABB dimension. | ||
352 | |||
353 | static int findLevel (dReal bounds[6]) | ||
354 | { | ||
355 | if (bounds[0] <= -dInfinity || bounds[1] >= dInfinity || | ||
356 | bounds[2] <= -dInfinity || bounds[3] >= dInfinity || | ||
357 | bounds[4] <= -dInfinity || bounds[5] >= dInfinity) { | ||
358 | return MAXINT; | ||
359 | } | ||
360 | |||
361 | // compute q | ||
362 | dReal q,q2; | ||
363 | q = bounds[1] - bounds[0]; // x bounds | ||
364 | q2 = bounds[3] - bounds[2]; // y bounds | ||
365 | if (q2 > q) q = q2; | ||
366 | q2 = bounds[5] - bounds[4]; // z bounds | ||
367 | if (q2 > q) q = q2; | ||
368 | |||
369 | // find level such that 0.5 * 2^level < q <= 2^level | ||
370 | int level; | ||
371 | frexp (q,&level); // q = (0.5 .. 1.0) * 2^level (definition of frexp) | ||
372 | return level; | ||
373 | } | ||
374 | |||
375 | |||
376 | // find a virtual memory address for a cell at the given level and x,y,z | ||
377 | // position. | ||
378 | // @@@ currently this is not very sophisticated, e.g. the scaling | ||
379 | // factors could be better designed to avoid collisions, and they should | ||
380 | // probably depend on the hash table physical size. | ||
381 | |||
382 | static unsigned long getVirtualAddress (int level, int x, int y, int z) | ||
383 | { | ||
384 | return level*1000 + x*100 + y*10 + z; | ||
385 | } | ||
386 | |||
387 | //**************************************************************************** | ||
388 | // hash space | ||
389 | |||
390 | struct dxHashSpace : public dxSpace { | ||
391 | int global_minlevel; // smallest hash table level to put AABBs in | ||
392 | int global_maxlevel; // objects that need a level larger than this will be | ||
393 | // put in a "big objects" list instead of a hash table | ||
394 | |||
395 | dxHashSpace (dSpaceID _space); | ||
396 | void setLevels (int minlevel, int maxlevel); | ||
397 | void getLevels (int *minlevel, int *maxlevel); | ||
398 | void cleanGeoms(); | ||
399 | void collide (void *data, dNearCallback *callback); | ||
400 | void collide2 (void *data, dxGeom *geom, dNearCallback *callback); | ||
401 | }; | ||
402 | |||
403 | |||
404 | dxHashSpace::dxHashSpace (dSpaceID _space) : dxSpace (_space) | ||
405 | { | ||
406 | type = dHashSpaceClass; | ||
407 | global_minlevel = -3; | ||
408 | global_maxlevel = 10; | ||
409 | } | ||
410 | |||
411 | |||
412 | void dxHashSpace::setLevels (int minlevel, int maxlevel) | ||
413 | { | ||
414 | dAASSERT (minlevel <= maxlevel); | ||
415 | global_minlevel = minlevel; | ||
416 | global_maxlevel = maxlevel; | ||
417 | } | ||
418 | |||
419 | |||
420 | void dxHashSpace::getLevels (int *minlevel, int *maxlevel) | ||
421 | { | ||
422 | if (minlevel) *minlevel = global_minlevel; | ||
423 | if (maxlevel) *maxlevel = global_maxlevel; | ||
424 | } | ||
425 | |||
426 | |||
427 | void dxHashSpace::cleanGeoms() | ||
428 | { | ||
429 | // compute the AABBs of all dirty geoms, and clear the dirty flags | ||
430 | lock_count++; | ||
431 | for (dxGeom *g=first; g && (g->gflags & GEOM_DIRTY); g=g->next) { | ||
432 | if (IS_SPACE(g)) { | ||
433 | ((dxSpace*)g)->cleanGeoms(); | ||
434 | } | ||
435 | g->recomputeAABB(); | ||
436 | g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); | ||
437 | } | ||
438 | lock_count--; | ||
439 | } | ||
440 | |||
441 | |||
442 | void dxHashSpace::collide (void *data, dNearCallback *callback) | ||
443 | { | ||
444 | dAASSERT(this && callback); | ||
445 | dxGeom *geom; | ||
446 | dxAABB *aabb; | ||
447 | int i,maxlevel; | ||
448 | |||
449 | // 0 or 1 geoms can't collide with anything | ||
450 | if (count < 2) return; | ||
451 | |||
452 | lock_count++; | ||
453 | cleanGeoms(); | ||
454 | |||
455 | // create a list of auxiliary information for all geom axis aligned bounding | ||
456 | // boxes. set the level for all AABBs. put AABBs larger than the space's | ||
457 | // global_maxlevel in the big_boxes list, check everything else against | ||
458 | // that list at the end. for AABBs that are not too big, record the maximum | ||
459 | // level that we need. | ||
460 | |||
461 | int n = 0; // number of AABBs in main list | ||
462 | dxAABB *first_aabb = 0; // list of AABBs in hash table | ||
463 | dxAABB *big_boxes = 0; // list of AABBs too big for hash table | ||
464 | maxlevel = global_minlevel - 1; | ||
465 | for (geom = first; geom; geom=geom->next) { | ||
466 | if (!GEOM_ENABLED(geom)){ | ||
467 | continue; | ||
468 | } | ||
469 | dxAABB *aabb = (dxAABB*) ALLOCA (sizeof(dxAABB)); | ||
470 | aabb->geom = geom; | ||
471 | // compute level, but prevent cells from getting too small | ||
472 | int level = findLevel (geom->aabb); | ||
473 | if (level < global_minlevel) level = global_minlevel; | ||
474 | if (level <= global_maxlevel) { | ||
475 | // aabb goes in main list | ||
476 | aabb->next = first_aabb; | ||
477 | first_aabb = aabb; | ||
478 | aabb->level = level; | ||
479 | if (level > maxlevel) maxlevel = level; | ||
480 | // cellsize = 2^level | ||
481 | dReal cellsize = (dReal) ldexp (1.0,level); | ||
482 | // discretize AABB position to cell size | ||
483 | for (i=0; i < 6; i++) aabb->dbounds[i] = (int) | ||
484 | floor (geom->aabb[i]/cellsize); | ||
485 | // set AABB index | ||
486 | aabb->index = n; | ||
487 | n++; | ||
488 | } | ||
489 | else { | ||
490 | // aabb is too big, put it in the big_boxes list. we don't care about | ||
491 | // setting level, dbounds, index, or the maxlevel | ||
492 | aabb->next = big_boxes; | ||
493 | big_boxes = aabb; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | // for `n' objects, an n*n array of bits is used to record if those objects | ||
498 | // have been intersection-tested against each other yet. this array can | ||
499 | // grow large with high n, but oh well... | ||
500 | int tested_rowsize = (n+7) >> 3; // number of bytes needed for n bits | ||
501 | unsigned char *tested = (unsigned char *) ALLOCA (n * tested_rowsize); | ||
502 | memset (tested,0,n * tested_rowsize); | ||
503 | |||
504 | // create a hash table to store all AABBs. each AABB may take up to 8 cells. | ||
505 | // we use chaining to resolve collisions, but we use a relatively large table | ||
506 | // to reduce the chance of collisions. | ||
507 | |||
508 | // compute hash table size sz to be a prime > 8*n | ||
509 | for (i=0; i<NUM_PRIMES; i++) { | ||
510 | if (prime[i] >= (8*n)) break; | ||
511 | } | ||
512 | if (i >= NUM_PRIMES) i = NUM_PRIMES-1; // probably pointless | ||
513 | int sz = prime[i]; | ||
514 | |||
515 | // allocate and initialize hash table node pointers | ||
516 | Node **table = (Node **) ALLOCA (sizeof(Node*) * sz); | ||
517 | for (i=0; i<sz; i++) table[i] = 0; | ||
518 | |||
519 | // add each AABB to the hash table (may need to add it to up to 8 cells) | ||
520 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
521 | int *dbounds = aabb->dbounds; | ||
522 | for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { | ||
523 | for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { | ||
524 | for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { | ||
525 | // get the hash index | ||
526 | unsigned long hi = getVirtualAddress (aabb->level,xi,yi,zi) % sz; | ||
527 | // add a new node to the hash table | ||
528 | Node *node = (Node*) ALLOCA (sizeof (Node)); | ||
529 | node->x = xi; | ||
530 | node->y = yi; | ||
531 | node->z = zi; | ||
532 | node->aabb = aabb; | ||
533 | node->next = table[hi]; | ||
534 | table[hi] = node; | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | // now that all AABBs are loaded into the hash table, we do the actual | ||
541 | // collision detection. for all AABBs, check for other AABBs in the | ||
542 | // same cells for collisions, and then check for other AABBs in all | ||
543 | // intersecting higher level cells. | ||
544 | |||
545 | int db[6]; // discrete bounds at current level | ||
546 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
547 | // we are searching for collisions with aabb | ||
548 | for (i=0; i<6; i++) db[i] = aabb->dbounds[i]; | ||
549 | for (int level = aabb->level; level <= maxlevel; level++) { | ||
550 | for (int xi = db[0]; xi <= db[1]; xi++) { | ||
551 | for (int yi = db[2]; yi <= db[3]; yi++) { | ||
552 | for (int zi = db[4]; zi <= db[5]; zi++) { | ||
553 | // get the hash index | ||
554 | unsigned long hi = getVirtualAddress (level,xi,yi,zi) % sz; | ||
555 | // search all nodes at this index | ||
556 | Node *node; | ||
557 | for (node = table[hi]; node; node=node->next) { | ||
558 | // node points to an AABB that may intersect aabb | ||
559 | if (node->aabb == aabb) continue; | ||
560 | if (node->aabb->level == level && | ||
561 | node->x == xi && node->y == yi && node->z == zi) { | ||
562 | // see if aabb and node->aabb have already been tested | ||
563 | // against each other | ||
564 | unsigned char mask; | ||
565 | if (aabb->index <= node->aabb->index) { | ||
566 | i = (aabb->index * tested_rowsize)+(node->aabb->index >> 3); | ||
567 | mask = 1 << (node->aabb->index & 7); | ||
568 | } | ||
569 | else { | ||
570 | i = (node->aabb->index * tested_rowsize)+(aabb->index >> 3); | ||
571 | mask = 1 << (aabb->index & 7); | ||
572 | } | ||
573 | dIASSERT (i >= 0 && i < (tested_rowsize*n)); | ||
574 | if ((tested[i] & mask)==0) { | ||
575 | collideAABBs (aabb->geom,node->aabb->geom,data,callback); | ||
576 | } | ||
577 | tested[i] |= mask; | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | } | ||
582 | } | ||
583 | // get the discrete bounds for the next level up | ||
584 | for (i=0; i<6; i++) db[i] >>= 1; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | // every AABB in the normal list must now be intersected against every | ||
589 | // AABB in the big_boxes list. so let's hope there are not too many objects | ||
590 | // in the big_boxes list. | ||
591 | for (aabb=first_aabb; aabb; aabb=aabb->next) { | ||
592 | for (dxAABB *aabb2=big_boxes; aabb2; aabb2=aabb2->next) { | ||
593 | collideAABBs (aabb->geom,aabb2->geom,data,callback); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | // intersected all AABBs in the big_boxes list together | ||
598 | for (aabb=big_boxes; aabb; aabb=aabb->next) { | ||
599 | for (dxAABB *aabb2=aabb->next; aabb2; aabb2=aabb2->next) { | ||
600 | collideAABBs (aabb->geom,aabb2->geom,data,callback); | ||
601 | } | ||
602 | } | ||
603 | |||
604 | lock_count--; | ||
605 | } | ||
606 | |||
607 | |||
608 | void dxHashSpace::collide2 (void *data, dxGeom *geom, | ||
609 | dNearCallback *callback) | ||
610 | { | ||
611 | dAASSERT (geom && callback); | ||
612 | |||
613 | // this could take advantage of the hash structure to avoid | ||
614 | // O(n2) complexity, but it does not yet. | ||
615 | |||
616 | lock_count++; | ||
617 | cleanGeoms(); | ||
618 | geom->recomputeAABB(); | ||
619 | |||
620 | // intersect bounding boxes | ||
621 | for (dxGeom *g=first; g; g=g->next) { | ||
622 | if (GEOM_ENABLED(g)) collideAABBs (g,geom,data,callback); | ||
623 | } | ||
624 | |||
625 | lock_count--; | ||
626 | } | ||
627 | |||
628 | //**************************************************************************** | ||
629 | // space functions | ||
630 | |||
631 | dxSpace *dSimpleSpaceCreate (dxSpace *space) | ||
632 | { | ||
633 | return new dxSimpleSpace (space); | ||
634 | } | ||
635 | |||
636 | |||
637 | dxSpace *dHashSpaceCreate (dxSpace *space) | ||
638 | { | ||
639 | return new dxHashSpace (space); | ||
640 | } | ||
641 | |||
642 | |||
643 | void dHashSpaceSetLevels (dxSpace *space, int minlevel, int maxlevel) | ||
644 | { | ||
645 | dAASSERT (space); | ||
646 | dUASSERT (minlevel <= maxlevel,"must have minlevel <= maxlevel"); | ||
647 | dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); | ||
648 | dxHashSpace *hspace = (dxHashSpace*) space; | ||
649 | hspace->setLevels (minlevel,maxlevel); | ||
650 | } | ||
651 | |||
652 | |||
653 | void dHashSpaceGetLevels (dxSpace *space, int *minlevel, int *maxlevel) | ||
654 | { | ||
655 | dAASSERT (space); | ||
656 | dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); | ||
657 | dxHashSpace *hspace = (dxHashSpace*) space; | ||
658 | hspace->getLevels (minlevel,maxlevel); | ||
659 | } | ||
660 | |||
661 | |||
662 | void dSpaceDestroy (dxSpace *space) | ||
663 | { | ||
664 | dAASSERT (space); | ||
665 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
666 | dGeomDestroy (space); | ||
667 | } | ||
668 | |||
669 | |||
670 | void dSpaceSetCleanup (dxSpace *space, int mode) | ||
671 | { | ||
672 | dAASSERT (space); | ||
673 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
674 | space->setCleanup (mode); | ||
675 | } | ||
676 | |||
677 | |||
678 | int dSpaceGetCleanup (dxSpace *space) | ||
679 | { | ||
680 | dAASSERT (space); | ||
681 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
682 | return space->getCleanup(); | ||
683 | } | ||
684 | |||
685 | |||
686 | void dSpaceAdd (dxSpace *space, dxGeom *g) | ||
687 | { | ||
688 | dAASSERT (space); | ||
689 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
690 | CHECK_NOT_LOCKED (space); | ||
691 | space->add (g); | ||
692 | } | ||
693 | |||
694 | |||
695 | void dSpaceRemove (dxSpace *space, dxGeom *g) | ||
696 | { | ||
697 | dAASSERT (space); | ||
698 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
699 | CHECK_NOT_LOCKED (space); | ||
700 | space->remove (g); | ||
701 | } | ||
702 | |||
703 | |||
704 | int dSpaceQuery (dxSpace *space, dxGeom *g) | ||
705 | { | ||
706 | dAASSERT (space); | ||
707 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
708 | return space->query (g); | ||
709 | } | ||
710 | |||
711 | void dSpaceClean (dxSpace *space){ | ||
712 | dAASSERT (space); | ||
713 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
714 | |||
715 | space->cleanGeoms(); | ||
716 | } | ||
717 | |||
718 | int dSpaceGetNumGeoms (dxSpace *space) | ||
719 | { | ||
720 | dAASSERT (space); | ||
721 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
722 | return space->getNumGeoms(); | ||
723 | } | ||
724 | |||
725 | |||
726 | dGeomID dSpaceGetGeom (dxSpace *space, int i) | ||
727 | { | ||
728 | dAASSERT (space); | ||
729 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
730 | return space->getGeom (i); | ||
731 | } | ||
732 | |||
733 | |||
734 | void dSpaceCollide (dxSpace *space, void *data, dNearCallback *callback) | ||
735 | { | ||
736 | dAASSERT (space && callback); | ||
737 | dUASSERT (dGeomIsSpace(space),"argument not a space"); | ||
738 | space->collide (data,callback); | ||
739 | } | ||
740 | |||
741 | |||
742 | void dSpaceCollide2 (dxGeom *g1, dxGeom *g2, void *data, | ||
743 | dNearCallback *callback) | ||
744 | { | ||
745 | dAASSERT (g1 && g2 && callback); | ||
746 | dxSpace *s1,*s2; | ||
747 | |||
748 | // see if either geom is a space | ||
749 | if (IS_SPACE(g1)) s1 = (dxSpace*) g1; else s1 = 0; | ||
750 | if (IS_SPACE(g2)) s2 = (dxSpace*) g2; else s2 = 0; | ||
751 | |||
752 | // handle the four space/geom cases | ||
753 | if (s1) { | ||
754 | if (s2) { | ||
755 | // g1 and g2 are spaces. | ||
756 | if (s1==s2) { | ||
757 | // collide a space with itself --> interior collision | ||
758 | s1->collide (data,callback); | ||
759 | } | ||
760 | else { | ||
761 | // iterate through the space that has the fewest geoms, calling | ||
762 | // collide2 in the other space for each one. | ||
763 | if (s1->count < s2->count) { | ||
764 | for (dxGeom *g = s1->first; g; g=g->next) { | ||
765 | s2->collide2 (data,g,callback); | ||
766 | } | ||
767 | } | ||
768 | else { | ||
769 | for (dxGeom *g = s2->first; g; g=g->next) { | ||
770 | s1->collide2 (data,g,callback); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | } | ||
775 | else { | ||
776 | // g1 is a space, g2 is a geom | ||
777 | s1->collide2 (data,g2,callback); | ||
778 | } | ||
779 | } | ||
780 | else { | ||
781 | if (s2) { | ||
782 | // g1 is a geom, g2 is a space | ||
783 | s2->collide2 (data,g1,callback); | ||
784 | } | ||
785 | else { | ||
786 | // g1 and g2 are geoms, call the callback directly | ||
787 | callback (data,g1,g2); | ||
788 | } | ||
789 | } | ||
790 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_space_internal.h b/libraries/ode-0.9\/ode/src/collision_space_internal.h new file mode 100755 index 0000000..004276a --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_space_internal.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | stuff common to all spaces | ||
26 | |||
27 | */ | ||
28 | |||
29 | #ifndef _ODE_COLLISION_SPACE_INTERNAL_H_ | ||
30 | #define _ODE_COLLISION_SPACE_INTERNAL_H_ | ||
31 | |||
32 | #define ALLOCA(x) dALLOCA16(x) | ||
33 | |||
34 | #define CHECK_NOT_LOCKED(space) \ | ||
35 | dUASSERT ((space)==0 || (space)->lock_count==0, \ | ||
36 | "invalid operation for locked space"); | ||
37 | |||
38 | |||
39 | // collide two geoms together. for the hash table space, this is | ||
40 | // called if the two AABBs inhabit the same hash table cells. | ||
41 | // this only calls the callback function if the AABBs actually | ||
42 | // intersect. if a geom has an AABB test function, that is called to | ||
43 | // provide a further refinement of the intersection. | ||
44 | // | ||
45 | // NOTE: this assumes that the geom AABBs are valid on entry | ||
46 | // and that both geoms are enabled. | ||
47 | |||
48 | static void collideAABBs (dxGeom *g1, dxGeom *g2, | ||
49 | void *data, dNearCallback *callback) | ||
50 | { | ||
51 | dIASSERT((g1->gflags & GEOM_AABB_BAD)==0); | ||
52 | dIASSERT((g2->gflags & GEOM_AABB_BAD)==0); | ||
53 | |||
54 | // no contacts if both geoms on the same body, and the body is not 0 | ||
55 | if (g1->body == g2->body && g1->body) return; | ||
56 | |||
57 | // test if the category and collide bitfields match | ||
58 | if ( ((g1->category_bits & g2->collide_bits) || | ||
59 | (g2->category_bits & g1->collide_bits)) == 0) { | ||
60 | return; | ||
61 | } | ||
62 | |||
63 | // if the bounding boxes are disjoint then don't do anything | ||
64 | dReal *bounds1 = g1->aabb; | ||
65 | dReal *bounds2 = g2->aabb; | ||
66 | if (bounds1[0] > bounds2[1] || | ||
67 | bounds1[1] < bounds2[0] || | ||
68 | bounds1[2] > bounds2[3] || | ||
69 | bounds1[3] < bounds2[2] || | ||
70 | bounds1[4] > bounds2[5] || | ||
71 | bounds1[5] < bounds2[4]) { | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | // check if either object is able to prove that it doesn't intersect the | ||
76 | // AABB of the other | ||
77 | if (g1->AABBTest (g2,bounds2) == 0) return; | ||
78 | if (g2->AABBTest (g1,bounds1) == 0) return; | ||
79 | |||
80 | // the objects might actually intersect - call the space callback function | ||
81 | callback (data,g1,g2); | ||
82 | } | ||
83 | |||
84 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_std.h b/libraries/ode-0.9\/ode/src/collision_std.h new file mode 100755 index 0000000..d203ad0 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_std.h | |||
@@ -0,0 +1,172 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | the standard ODE geometry primitives. | ||
26 | |||
27 | */ | ||
28 | |||
29 | #ifndef _ODE_COLLISION_STD_H_ | ||
30 | #define _ODE_COLLISION_STD_H_ | ||
31 | |||
32 | #include <set> | ||
33 | #include <ode/common.h> | ||
34 | #include "collision_kernel.h" | ||
35 | |||
36 | |||
37 | // primitive collision functions - these have the dColliderFn interface, i.e. | ||
38 | // the same interface as dCollide(). the first and second geom arguments must | ||
39 | // have the specified types. | ||
40 | |||
41 | int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags, | ||
42 | dContactGeom *contact, int skip); | ||
43 | int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags, | ||
44 | dContactGeom *contact, int skip); | ||
45 | int dCollideSpherePlane (dxGeom *o1, dxGeom *o2, int flags, | ||
46 | dContactGeom *contact, int skip); | ||
47 | int dCollideBoxBox (dxGeom *o1, dxGeom *o2, int flags, | ||
48 | dContactGeom *contact, int skip); | ||
49 | int dCollideBoxPlane (dxGeom *o1, dxGeom *o2, | ||
50 | int flags, dContactGeom *contact, int skip); | ||
51 | int dCollideCapsuleSphere (dxGeom *o1, dxGeom *o2, int flags, | ||
52 | dContactGeom *contact, int skip); | ||
53 | int dCollideCapsuleBox (dxGeom *o1, dxGeom *o2, int flags, | ||
54 | dContactGeom *contact, int skip); | ||
55 | int dCollideCapsuleCapsule (dxGeom *o1, dxGeom *o2, | ||
56 | int flags, dContactGeom *contact, int skip); | ||
57 | int dCollideCapsulePlane (dxGeom *o1, dxGeom *o2, int flags, | ||
58 | dContactGeom *contact, int skip); | ||
59 | int dCollideRaySphere (dxGeom *o1, dxGeom *o2, int flags, | ||
60 | dContactGeom *contact, int skip); | ||
61 | int dCollideRayBox (dxGeom *o1, dxGeom *o2, int flags, | ||
62 | dContactGeom *contact, int skip); | ||
63 | int dCollideRayCapsule (dxGeom *o1, dxGeom *o2, | ||
64 | int flags, dContactGeom *contact, int skip); | ||
65 | int dCollideRayPlane (dxGeom *o1, dxGeom *o2, int flags, | ||
66 | dContactGeom *contact, int skip); | ||
67 | int dCollideRayCylinder (dxGeom *o1, dxGeom *o2, int flags, | ||
68 | dContactGeom *contact, int skip); | ||
69 | |||
70 | // Cylinder - Box/Sphere by (C) CroTeam | ||
71 | // Ported by Nguyen Binh | ||
72 | int dCollideCylinderBox(dxGeom *o1, dxGeom *o2, | ||
73 | int flags, dContactGeom *contact, int skip); | ||
74 | int dCollideCylinderSphere(dxGeom *gCylinder, dxGeom *gSphere, | ||
75 | int flags, dContactGeom *contact, int skip); | ||
76 | int dCollideCylinderPlane(dxGeom *gCylinder, dxGeom *gPlane, | ||
77 | int flags, dContactGeom *contact, int skip); | ||
78 | |||
79 | //--> Convex Collision | ||
80 | int dCollideConvexPlane (dxGeom *o1, dxGeom *o2, int flags, | ||
81 | dContactGeom *contact, int skip); | ||
82 | int dCollideSphereConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
83 | dContactGeom *contact, int skip); | ||
84 | int dCollideConvexBox (dxGeom *o1, dxGeom *o2, int flags, | ||
85 | dContactGeom *contact, int skip); | ||
86 | int dCollideConvexCapsule (dxGeom *o1, dxGeom *o2, | ||
87 | int flags, dContactGeom *contact, int skip); | ||
88 | int dCollideConvexConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
89 | dContactGeom *contact, int skip); | ||
90 | int dCollideRayConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
91 | dContactGeom *contact, int skip); | ||
92 | //<-- Convex Collision | ||
93 | |||
94 | // dHeightfield | ||
95 | int dCollideHeightfield( dxGeom *o1, dxGeom *o2, | ||
96 | int flags, dContactGeom *contact, int skip ); | ||
97 | |||
98 | //**************************************************************************** | ||
99 | // the basic geometry objects | ||
100 | |||
101 | struct dxSphere : public dxGeom { | ||
102 | dReal radius; // sphere radius | ||
103 | dxSphere (dSpaceID space, dReal _radius); | ||
104 | void computeAABB(); | ||
105 | }; | ||
106 | |||
107 | |||
108 | struct dxBox : public dxGeom { | ||
109 | dVector3 side; // side lengths (x,y,z) | ||
110 | dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz); | ||
111 | void computeAABB(); | ||
112 | }; | ||
113 | |||
114 | |||
115 | struct dxCapsule : public dxGeom { | ||
116 | dReal radius,lz; // radius, length along z axis | ||
117 | dxCapsule (dSpaceID space, dReal _radius, dReal _length); | ||
118 | void computeAABB(); | ||
119 | }; | ||
120 | |||
121 | |||
122 | struct dxCylinder : public dxGeom { | ||
123 | dReal radius,lz; // radius, length along z axis | ||
124 | dxCylinder (dSpaceID space, dReal _radius, dReal _length); | ||
125 | void computeAABB(); | ||
126 | }; | ||
127 | |||
128 | |||
129 | struct dxPlane : public dxGeom { | ||
130 | dReal p[4]; | ||
131 | dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); | ||
132 | void computeAABB(); | ||
133 | }; | ||
134 | |||
135 | |||
136 | struct dxRay : public dxGeom { | ||
137 | dReal length; | ||
138 | dxRay (dSpaceID space, dReal _length); | ||
139 | void computeAABB(); | ||
140 | }; | ||
141 | |||
142 | typedef std::pair<unsigned int,unsigned int> edge; /*!< Used to descrive a convex hull edge, an edge is a pair or indices into the hull's points */ | ||
143 | struct dxConvex : public dxGeom | ||
144 | { | ||
145 | |||
146 | dReal *planes; /*!< An array of planes in the form: | ||
147 | normal X, normal Y, normal Z,Distance | ||
148 | */ | ||
149 | dReal *points; /*!< An array of points X,Y,Z */ | ||
150 | unsigned int *polygons; /*! An array of indices to the points of each polygon, it should be the number of vertices followed by that amount of indices to "points" in counter clockwise order*/ | ||
151 | unsigned int planecount; /*!< Amount of planes in planes */ | ||
152 | unsigned int pointcount;/*!< Amount of points in points */ | ||
153 | dReal saabb[6];/*!< Static AABB */ | ||
154 | std::set<edge> edges; | ||
155 | dxConvex(dSpaceID space, | ||
156 | dReal *planes, | ||
157 | unsigned int planecount, | ||
158 | dReal *points, | ||
159 | unsigned int pointcount, | ||
160 | unsigned int *polygons); | ||
161 | ~dxConvex() | ||
162 | { | ||
163 | //fprintf(stdout,"dxConvex Destroy\n"); | ||
164 | } | ||
165 | void computeAABB(); | ||
166 | private: | ||
167 | // For Internal Use Only | ||
168 | void FillEdges(); | ||
169 | }; | ||
170 | |||
171 | |||
172 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_transform.cpp b/libraries/ode-0.9\/ode/src/collision_transform.cpp new file mode 100755 index 0000000..85fd623 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_transform.cpp | |||
@@ -0,0 +1,232 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | geom transform | ||
26 | |||
27 | */ | ||
28 | |||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | #include "collision_transform.h" | ||
34 | #include "collision_util.h" | ||
35 | |||
36 | #ifdef _MSC_VER | ||
37 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
38 | #endif | ||
39 | |||
40 | //**************************************************************************** | ||
41 | // dxGeomTransform class | ||
42 | |||
43 | struct dxGeomTransform : public dxGeom { | ||
44 | dxGeom *obj; // object that is being transformed | ||
45 | int cleanup; // 1 to destroy obj when destroyed | ||
46 | int infomode; // 1 to put Tx geom in dContactGeom g1 | ||
47 | |||
48 | // cached final object transform (body tx + relative tx). this is set by | ||
49 | // computeAABB(), and it is valid while the AABB is valid. | ||
50 | dxPosR transform_posr; | ||
51 | |||
52 | dxGeomTransform (dSpaceID space); | ||
53 | ~dxGeomTransform(); | ||
54 | void computeAABB(); | ||
55 | void computeFinalTx(); | ||
56 | }; | ||
57 | /* | ||
58 | void RunMe() | ||
59 | { | ||
60 | printf("sizeof body = %i\n", sizeof(dxBody)); | ||
61 | printf("sizeof geom = %i\n", sizeof(dxGeom)); | ||
62 | printf("sizeof geomtransform = %i\n", sizeof(dxGeomTransform)); | ||
63 | printf("sizeof posr = %i\n", sizeof(dxPosR)); | ||
64 | } | ||
65 | */ | ||
66 | |||
67 | dxGeomTransform::dxGeomTransform (dSpaceID space) : dxGeom (space,1) | ||
68 | { | ||
69 | type = dGeomTransformClass; | ||
70 | obj = 0; | ||
71 | cleanup = 0; | ||
72 | infomode = 0; | ||
73 | dSetZero (transform_posr.pos,4); | ||
74 | dRSetIdentity (transform_posr.R); | ||
75 | } | ||
76 | |||
77 | |||
78 | dxGeomTransform::~dxGeomTransform() | ||
79 | { | ||
80 | if (obj && cleanup) delete obj; | ||
81 | } | ||
82 | |||
83 | |||
84 | void dxGeomTransform::computeAABB() | ||
85 | { | ||
86 | if (!obj) { | ||
87 | dSetZero (aabb,6); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | // backup the relative pos and R pointers of the encapsulated geom object | ||
92 | dxPosR* posr_bak = obj->final_posr; | ||
93 | |||
94 | // compute temporary pos and R for the encapsulated geom object | ||
95 | computeFinalTx(); | ||
96 | obj->final_posr = &transform_posr; | ||
97 | |||
98 | // compute the AABB | ||
99 | obj->computeAABB(); | ||
100 | memcpy (aabb,obj->aabb,6*sizeof(dReal)); | ||
101 | |||
102 | // restore the pos and R | ||
103 | obj->final_posr = posr_bak; | ||
104 | } | ||
105 | |||
106 | |||
107 | // utility function for dCollideTransform() : compute final pos and R | ||
108 | // for the encapsulated geom object | ||
109 | |||
110 | void dxGeomTransform::computeFinalTx() | ||
111 | { | ||
112 | dMULTIPLY0_331 (transform_posr.pos,final_posr->R,obj->final_posr->pos); | ||
113 | transform_posr.pos[0] += final_posr->pos[0]; | ||
114 | transform_posr.pos[1] += final_posr->pos[1]; | ||
115 | transform_posr.pos[2] += final_posr->pos[2]; | ||
116 | dMULTIPLY0_333 (transform_posr.R,final_posr->R,obj->final_posr->R); | ||
117 | } | ||
118 | |||
119 | //**************************************************************************** | ||
120 | // collider function: | ||
121 | // this collides a transformed geom with another geom. the other geom can | ||
122 | // also be a transformed geom, but this case is not handled specially. | ||
123 | |||
124 | int dCollideTransform (dxGeom *o1, dxGeom *o2, int flags, | ||
125 | dContactGeom *contact, int skip) | ||
126 | { | ||
127 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
128 | dIASSERT (o1->type == dGeomTransformClass); | ||
129 | |||
130 | dxGeomTransform *tr = (dxGeomTransform*) o1; | ||
131 | if (!tr->obj) return 0; | ||
132 | dUASSERT (tr->obj->parent_space==0, | ||
133 | "GeomTransform encapsulated object must not be in a space"); | ||
134 | dUASSERT (tr->obj->body==0, | ||
135 | "GeomTransform encapsulated object must not be attached " | ||
136 | "to a body"); | ||
137 | |||
138 | // backup the relative pos and R pointers of the encapsulated geom object, | ||
139 | // and the body pointer | ||
140 | dxPosR *posr_bak = tr->obj->final_posr; | ||
141 | dxBody *bodybak = tr->obj->body; | ||
142 | |||
143 | // compute temporary pos and R for the encapsulated geom object. | ||
144 | // note that final_pos and final_R are valid if no GEOM_AABB_BAD flag, | ||
145 | // because computeFinalTx() will have already been called in | ||
146 | // dxGeomTransform::computeAABB() | ||
147 | |||
148 | if (tr->gflags & GEOM_AABB_BAD) tr->computeFinalTx(); | ||
149 | tr->obj->final_posr = &tr->transform_posr; | ||
150 | tr->obj->body = o1->body; | ||
151 | |||
152 | // do the collision | ||
153 | int n = dCollide (tr->obj,o2,flags,contact,skip); | ||
154 | |||
155 | // if required, adjust the 'g1' values in the generated contacts so that | ||
156 | // thay indicated the GeomTransform object instead of the encapsulated | ||
157 | // object. | ||
158 | if (tr->infomode) { | ||
159 | for (int i=0; i<n; i++) { | ||
160 | dContactGeom *c = CONTACT(contact,skip*i); | ||
161 | c->g1 = o1; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // restore the pos, R and body | ||
166 | tr->obj->final_posr = posr_bak; | ||
167 | tr->obj->body = bodybak; | ||
168 | return n; | ||
169 | } | ||
170 | |||
171 | //**************************************************************************** | ||
172 | // public API | ||
173 | |||
174 | dGeomID dCreateGeomTransform (dSpaceID space) | ||
175 | { | ||
176 | return new dxGeomTransform (space); | ||
177 | } | ||
178 | |||
179 | |||
180 | void dGeomTransformSetGeom (dGeomID g, dGeomID obj) | ||
181 | { | ||
182 | dUASSERT (g && g->type == dGeomTransformClass, | ||
183 | "argument not a geom transform"); | ||
184 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
185 | if (tr->obj && tr->cleanup) delete tr->obj; | ||
186 | tr->obj = obj; | ||
187 | } | ||
188 | |||
189 | |||
190 | dGeomID dGeomTransformGetGeom (dGeomID g) | ||
191 | { | ||
192 | dUASSERT (g && g->type == dGeomTransformClass, | ||
193 | "argument not a geom transform"); | ||
194 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
195 | return tr->obj; | ||
196 | } | ||
197 | |||
198 | |||
199 | void dGeomTransformSetCleanup (dGeomID g, int mode) | ||
200 | { | ||
201 | dUASSERT (g && g->type == dGeomTransformClass, | ||
202 | "argument not a geom transform"); | ||
203 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
204 | tr->cleanup = mode; | ||
205 | } | ||
206 | |||
207 | |||
208 | int dGeomTransformGetCleanup (dGeomID g) | ||
209 | { | ||
210 | dUASSERT (g && g->type == dGeomTransformClass, | ||
211 | "argument not a geom transform"); | ||
212 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
213 | return tr->cleanup; | ||
214 | } | ||
215 | |||
216 | |||
217 | void dGeomTransformSetInfo (dGeomID g, int mode) | ||
218 | { | ||
219 | dUASSERT (g && g->type == dGeomTransformClass, | ||
220 | "argument not a geom transform"); | ||
221 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
222 | tr->infomode = mode; | ||
223 | } | ||
224 | |||
225 | |||
226 | int dGeomTransformGetInfo (dGeomID g) | ||
227 | { | ||
228 | dUASSERT (g && g->type == dGeomTransformClass, | ||
229 | "argument not a geom transform"); | ||
230 | dxGeomTransform *tr = (dxGeomTransform*) g; | ||
231 | return tr->infomode; | ||
232 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_transform.h b/libraries/ode-0.9\/ode/src/collision_transform.h new file mode 100755 index 0000000..406a687 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_transform.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | geom transform | ||
26 | |||
27 | */ | ||
28 | |||
29 | #ifndef _ODE_COLLISION_TRANSFORM_H_ | ||
30 | #define _ODE_COLLISION_TRANSFORM_H_ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include "collision_kernel.h" | ||
34 | |||
35 | |||
36 | int dCollideTransform (dxGeom *o1, dxGeom *o2, int flags, | ||
37 | dContactGeom *contact, int skip); | ||
38 | |||
39 | |||
40 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_box.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_box.cpp new file mode 100755 index 0000000..0194d02 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_box.cpp | |||
@@ -0,0 +1,1497 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | |||
24 | /************************************************************************* | ||
25 | * * | ||
26 | * Triangle-box collider by Alen Ladavac and Vedran Klanac. * | ||
27 | * Ported to ODE by Oskari Nyman. * | ||
28 | * * | ||
29 | *************************************************************************/ | ||
30 | |||
31 | |||
32 | #include <ode/collision.h> | ||
33 | #include <ode/matrix.h> | ||
34 | #include <ode/rotation.h> | ||
35 | #include <ode/odemath.h> | ||
36 | #include "collision_util.h" | ||
37 | |||
38 | #define TRIMESH_INTERNAL | ||
39 | #include "collision_trimesh_internal.h" | ||
40 | |||
41 | #if dTRIMESH_ENABLED | ||
42 | |||
43 | |||
44 | static void | ||
45 | GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, | ||
46 | dxGeom* in_g1, dxGeom* in_g2, | ||
47 | const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, | ||
48 | int& OutTriCount); | ||
49 | |||
50 | |||
51 | // largest number, double or float | ||
52 | #if defined(dSINGLE) | ||
53 | #define MAXVALUE FLT_MAX | ||
54 | #else | ||
55 | #define MAXVALUE DBL_MAX | ||
56 | #endif | ||
57 | |||
58 | |||
59 | // dVector3 | ||
60 | // r=a-b | ||
61 | #define SUBTRACT(a,b,r) do{ \ | ||
62 | (r)[0]=(a)[0] - (b)[0]; \ | ||
63 | (r)[1]=(a)[1] - (b)[1]; \ | ||
64 | (r)[2]=(a)[2] - (b)[2]; }while(0) | ||
65 | |||
66 | |||
67 | // dVector3 | ||
68 | // a=b | ||
69 | #define SET(a,b) do{ \ | ||
70 | (a)[0]=(b)[0]; \ | ||
71 | (a)[1]=(b)[1]; \ | ||
72 | (a)[2]=(b)[2]; }while(0) | ||
73 | |||
74 | |||
75 | // dMatrix3 | ||
76 | // a=b | ||
77 | #define SETM(a,b) do{ \ | ||
78 | (a)[0]=(b)[0]; \ | ||
79 | (a)[1]=(b)[1]; \ | ||
80 | (a)[2]=(b)[2]; \ | ||
81 | (a)[3]=(b)[3]; \ | ||
82 | (a)[4]=(b)[4]; \ | ||
83 | (a)[5]=(b)[5]; \ | ||
84 | (a)[6]=(b)[6]; \ | ||
85 | (a)[7]=(b)[7]; \ | ||
86 | (a)[8]=(b)[8]; \ | ||
87 | (a)[9]=(b)[9]; \ | ||
88 | (a)[10]=(b)[10]; \ | ||
89 | (a)[11]=(b)[11]; }while(0) | ||
90 | |||
91 | |||
92 | // dVector3 | ||
93 | // r=a+b | ||
94 | #define ADD(a,b,r) do{ \ | ||
95 | (r)[0]=(a)[0] + (b)[0]; \ | ||
96 | (r)[1]=(a)[1] + (b)[1]; \ | ||
97 | (r)[2]=(a)[2] + (b)[2]; }while(0) | ||
98 | |||
99 | |||
100 | // dMatrix3, int, dVector3 | ||
101 | // v=column a from m | ||
102 | #define GETCOL(m,a,v) do{ \ | ||
103 | (v)[0]=(m)[(a)+0]; \ | ||
104 | (v)[1]=(m)[(a)+4]; \ | ||
105 | (v)[2]=(m)[(a)+8]; }while(0) | ||
106 | |||
107 | |||
108 | // dVector4, dVector3 | ||
109 | // distance between plane p and point v | ||
110 | #define POINTDISTANCE(p,v) \ | ||
111 | ( p[0]*v[0] + p[1]*v[1] + p[2]*v[2] + p[3] ) | ||
112 | |||
113 | |||
114 | // dVector4, dVector3, dReal | ||
115 | // construct plane from normal and d | ||
116 | #define CONSTRUCTPLANE(plane,normal,d) do{ \ | ||
117 | plane[0]=normal[0];\ | ||
118 | plane[1]=normal[1];\ | ||
119 | plane[2]=normal[2];\ | ||
120 | plane[3]=d; }while(0) | ||
121 | |||
122 | |||
123 | // dVector3 | ||
124 | // length of vector a | ||
125 | #define LENGTHOF(a) \ | ||
126 | dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]) | ||
127 | |||
128 | |||
129 | // box data | ||
130 | static dMatrix3 mHullBoxRot; | ||
131 | static dVector3 vHullBoxPos; | ||
132 | static dVector3 vBoxHalfSize; | ||
133 | |||
134 | // mesh data | ||
135 | static dVector3 vHullDstPos; | ||
136 | |||
137 | // global collider data | ||
138 | static dVector3 vBestNormal; | ||
139 | static dReal fBestDepth; | ||
140 | static int iBestAxis = 0; | ||
141 | static int iExitAxis = 0; | ||
142 | static dVector3 vE0, vE1, vE2, vN; | ||
143 | |||
144 | // global info for contact creation | ||
145 | static int iFlags; | ||
146 | static dContactGeom *ContactGeoms; | ||
147 | static int iStride; | ||
148 | static dxGeom *Geom1; | ||
149 | static dxGeom *Geom2; | ||
150 | static int ctContacts = 0; | ||
151 | |||
152 | |||
153 | |||
154 | // Test normal of mesh face as separating axis for intersection | ||
155 | static bool _cldTestNormal( dReal fp0, dReal fR, dVector3 vNormal, int iAxis ) | ||
156 | { | ||
157 | // calculate overlapping interval of box and triangle | ||
158 | dReal fDepth = fR+fp0; | ||
159 | |||
160 | // if we do not overlap | ||
161 | if ( fDepth<0 ) { | ||
162 | // do nothing | ||
163 | return false; | ||
164 | } | ||
165 | |||
166 | // calculate normal's length | ||
167 | dReal fLength = LENGTHOF(vNormal); | ||
168 | // if long enough | ||
169 | if ( fLength > 0.0f ) { | ||
170 | |||
171 | dReal fOneOverLength = 1.0f/fLength; | ||
172 | // normalize depth | ||
173 | fDepth = fDepth*fOneOverLength; | ||
174 | |||
175 | // get minimum depth | ||
176 | if (fDepth<fBestDepth) { | ||
177 | vBestNormal[0] = -vNormal[0]*fOneOverLength; | ||
178 | vBestNormal[1] = -vNormal[1]*fOneOverLength; | ||
179 | vBestNormal[2] = -vNormal[2]*fOneOverLength; | ||
180 | iBestAxis = iAxis; | ||
181 | //dAASSERT(fDepth>=0); | ||
182 | fBestDepth = fDepth; | ||
183 | } | ||
184 | |||
185 | } | ||
186 | |||
187 | return true; | ||
188 | } | ||
189 | |||
190 | |||
191 | |||
192 | |||
193 | // Test box axis as separating axis | ||
194 | static bool _cldTestFace( dReal fp0, dReal fp1, dReal fp2, dReal fR, dReal fD, | ||
195 | dVector3 vNormal, int iAxis ) | ||
196 | { | ||
197 | dReal fMin, fMax; | ||
198 | |||
199 | // find min of triangle interval | ||
200 | if ( fp0 < fp1 ) { | ||
201 | if ( fp0 < fp2 ) { | ||
202 | fMin = fp0; | ||
203 | } else { | ||
204 | fMin = fp2; | ||
205 | } | ||
206 | } else { | ||
207 | if( fp1 < fp2 ) { | ||
208 | fMin = fp1; | ||
209 | } else { | ||
210 | fMin = fp2; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | // find max of triangle interval | ||
215 | if ( fp0 > fp1 ) { | ||
216 | if ( fp0 > fp2 ) { | ||
217 | fMax = fp0; | ||
218 | } else { | ||
219 | fMax = fp2; | ||
220 | } | ||
221 | } else { | ||
222 | if( fp1 > fp2 ) { | ||
223 | fMax = fp1; | ||
224 | } else { | ||
225 | fMax = fp2; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | // calculate minimum and maximum depth | ||
230 | dReal fDepthMin = fR - fMin; | ||
231 | dReal fDepthMax = fMax + fR; | ||
232 | |||
233 | // if we dont't have overlapping interval | ||
234 | if ( fDepthMin < 0 || fDepthMax < 0 ) { | ||
235 | // do nothing | ||
236 | return false; | ||
237 | } | ||
238 | |||
239 | dReal fDepth = 0; | ||
240 | |||
241 | // if greater depth is on negative side | ||
242 | if ( fDepthMin > fDepthMax ) { | ||
243 | // use smaller depth (one from positive side) | ||
244 | fDepth = fDepthMax; | ||
245 | // flip normal direction | ||
246 | vNormal[0] = -vNormal[0]; | ||
247 | vNormal[1] = -vNormal[1]; | ||
248 | vNormal[2] = -vNormal[2]; | ||
249 | fD = -fD; | ||
250 | // if greater depth is on positive side | ||
251 | } else { | ||
252 | // use smaller depth (one from negative side) | ||
253 | fDepth = fDepthMin; | ||
254 | } | ||
255 | |||
256 | |||
257 | // if lower depth than best found so far | ||
258 | if (fDepth<fBestDepth) { | ||
259 | // remember current axis as best axis | ||
260 | vBestNormal[0] = vNormal[0]; | ||
261 | vBestNormal[1] = vNormal[1]; | ||
262 | vBestNormal[2] = vNormal[2]; | ||
263 | iBestAxis = iAxis; | ||
264 | //dAASSERT(fDepth>=0); | ||
265 | fBestDepth = fDepth; | ||
266 | } | ||
267 | |||
268 | return true; | ||
269 | } | ||
270 | |||
271 | |||
272 | |||
273 | |||
274 | |||
275 | // Test cross products of box axis and triangle edges as separating axis | ||
276 | static bool _cldTestEdge( dReal fp0, dReal fp1, dReal fR, dReal fD, | ||
277 | dVector3 vNormal, int iAxis ) | ||
278 | { | ||
279 | dReal fMin, fMax; | ||
280 | |||
281 | |||
282 | // ===== Begin Patch by Francisco Leon, 2006/10/28 ===== | ||
283 | |||
284 | // Fixed Null Normal. This prevents boxes passing | ||
285 | // through trimeshes at certain contact angles | ||
286 | |||
287 | fMin = vNormal[0] * vNormal[0] + | ||
288 | vNormal[1] * vNormal[1] + | ||
289 | vNormal[2] * vNormal[2]; | ||
290 | |||
291 | if ( fMin <= dEpsilon ) /// THIS NORMAL WOULD BE DANGEROUS | ||
292 | return true; | ||
293 | |||
294 | // ===== Ending Patch by Francisco Leon ===== | ||
295 | |||
296 | |||
297 | // calculate min and max interval values | ||
298 | if ( fp0 < fp1 ) { | ||
299 | fMin = fp0; | ||
300 | fMax = fp1; | ||
301 | } else { | ||
302 | fMin = fp1; | ||
303 | fMax = fp0; | ||
304 | } | ||
305 | |||
306 | // check if we overlapp | ||
307 | dReal fDepthMin = fR - fMin; | ||
308 | dReal fDepthMax = fMax + fR; | ||
309 | |||
310 | // if we don't overlapp | ||
311 | if ( fDepthMin < 0 || fDepthMax < 0 ) { | ||
312 | // do nothing | ||
313 | return false; | ||
314 | } | ||
315 | |||
316 | dReal fDepth; | ||
317 | |||
318 | |||
319 | // if greater depth is on negative side | ||
320 | if ( fDepthMin > fDepthMax ) { | ||
321 | // use smaller depth (one from positive side) | ||
322 | fDepth = fDepthMax; | ||
323 | // flip normal direction | ||
324 | vNormal[0] = -vNormal[0]; | ||
325 | vNormal[1] = -vNormal[1]; | ||
326 | vNormal[2] = -vNormal[2]; | ||
327 | fD = -fD; | ||
328 | // if greater depth is on positive side | ||
329 | } else { | ||
330 | // use smaller depth (one from negative side) | ||
331 | fDepth = fDepthMin; | ||
332 | } | ||
333 | |||
334 | // calculate normal's length | ||
335 | dReal fLength = LENGTHOF(vNormal); | ||
336 | |||
337 | // if long enough | ||
338 | if ( fLength > 0.0f ) { | ||
339 | |||
340 | // normalize depth | ||
341 | dReal fOneOverLength = 1.0f/fLength; | ||
342 | fDepth = fDepth*fOneOverLength; | ||
343 | fD*=fOneOverLength; | ||
344 | |||
345 | |||
346 | // if lower depth than best found so far (favor face over edges) | ||
347 | if (fDepth*1.5f<fBestDepth) { | ||
348 | // remember current axis as best axis | ||
349 | vBestNormal[0] = vNormal[0]*fOneOverLength; | ||
350 | vBestNormal[1] = vNormal[1]*fOneOverLength; | ||
351 | vBestNormal[2] = vNormal[2]*fOneOverLength; | ||
352 | iBestAxis = iAxis; | ||
353 | //dAASSERT(fDepth>=0); | ||
354 | fBestDepth = fDepth; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | return true; | ||
359 | } | ||
360 | |||
361 | |||
362 | |||
363 | |||
364 | |||
365 | // clip polygon with plane and generate new polygon points | ||
366 | static void _cldClipPolyToPlane( dVector3 avArrayIn[], int ctIn, | ||
367 | dVector3 avArrayOut[], int &ctOut, | ||
368 | const dVector4 &plPlane ) | ||
369 | { | ||
370 | // start with no output points | ||
371 | ctOut = 0; | ||
372 | |||
373 | int i0 = ctIn-1; | ||
374 | |||
375 | // for each edge in input polygon | ||
376 | for (int i1=0; i1<ctIn; i0=i1, i1++) { | ||
377 | |||
378 | |||
379 | // calculate distance of edge points to plane | ||
380 | dReal fDistance0 = POINTDISTANCE( plPlane ,avArrayIn[i0] ); | ||
381 | dReal fDistance1 = POINTDISTANCE( plPlane ,avArrayIn[i1] ); | ||
382 | |||
383 | |||
384 | // if first point is in front of plane | ||
385 | if( fDistance0 >= 0 ) { | ||
386 | // emit point | ||
387 | avArrayOut[ctOut][0] = avArrayIn[i0][0]; | ||
388 | avArrayOut[ctOut][1] = avArrayIn[i0][1]; | ||
389 | avArrayOut[ctOut][2] = avArrayIn[i0][2]; | ||
390 | ctOut++; | ||
391 | } | ||
392 | |||
393 | // if points are on different sides | ||
394 | if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) { | ||
395 | |||
396 | // find intersection point of edge and plane | ||
397 | dVector3 vIntersectionPoint; | ||
398 | vIntersectionPoint[0]= avArrayIn[i0][0] - (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); | ||
399 | vIntersectionPoint[1]= avArrayIn[i0][1] - (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); | ||
400 | vIntersectionPoint[2]= avArrayIn[i0][2] - (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); | ||
401 | |||
402 | // emit intersection point | ||
403 | avArrayOut[ctOut][0] = vIntersectionPoint[0]; | ||
404 | avArrayOut[ctOut][1] = vIntersectionPoint[1]; | ||
405 | avArrayOut[ctOut][2] = vIntersectionPoint[2]; | ||
406 | ctOut++; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | } | ||
411 | |||
412 | |||
413 | |||
414 | |||
415 | static bool _cldTestSeparatingAxes(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) { | ||
416 | // reset best axis | ||
417 | iBestAxis = 0; | ||
418 | iExitAxis = -1; | ||
419 | fBestDepth = MAXVALUE; | ||
420 | |||
421 | // calculate edges | ||
422 | SUBTRACT(v1,v0,vE0); | ||
423 | SUBTRACT(v2,v0,vE1); | ||
424 | SUBTRACT(vE1,vE0,vE2); | ||
425 | |||
426 | // calculate poly normal | ||
427 | dCROSS(vN,=,vE0,vE1); | ||
428 | |||
429 | // extract box axes as vectors | ||
430 | dVector3 vA0,vA1,vA2; | ||
431 | GETCOL(mHullBoxRot,0,vA0); | ||
432 | GETCOL(mHullBoxRot,1,vA1); | ||
433 | GETCOL(mHullBoxRot,2,vA2); | ||
434 | |||
435 | // box halfsizes | ||
436 | dReal fa0 = vBoxHalfSize[0]; | ||
437 | dReal fa1 = vBoxHalfSize[1]; | ||
438 | dReal fa2 = vBoxHalfSize[2]; | ||
439 | |||
440 | // calculate relative position between box and triangle | ||
441 | dVector3 vD; | ||
442 | SUBTRACT(v0,vHullBoxPos,vD); | ||
443 | |||
444 | // calculate length of face normal | ||
445 | dReal fNLen = LENGTHOF( vN ); | ||
446 | |||
447 | dVector3 vL; | ||
448 | dReal fp0, fp1, fp2, fR, fD; | ||
449 | |||
450 | // Test separating axes for intersection | ||
451 | // ************************************************ | ||
452 | // Axis 1 - Triangle Normal | ||
453 | SET(vL,vN); | ||
454 | fp0 = dDOT(vL,vD); | ||
455 | fp1 = fp0; | ||
456 | fp2 = fp0; | ||
457 | fR=fa0*dFabs( dDOT(vN,vA0) ) + fa1 * dFabs( dDOT(vN,vA1) ) + fa2 * dFabs( dDOT(vN,vA2) ); | ||
458 | |||
459 | |||
460 | if( !_cldTestNormal( fp0, fR, vL, 1) ) { | ||
461 | iExitAxis=1; | ||
462 | return false; | ||
463 | } | ||
464 | |||
465 | // ************************************************ | ||
466 | |||
467 | // Test Faces | ||
468 | // ************************************************ | ||
469 | // Axis 2 - Box X-Axis | ||
470 | SET(vL,vA0); | ||
471 | fD = dDOT(vL,vN)/fNLen; | ||
472 | fp0 = dDOT(vL,vD); | ||
473 | fp1 = fp0 + dDOT(vA0,vE0); | ||
474 | fp2 = fp0 + dDOT(vA0,vE1); | ||
475 | fR = fa0; | ||
476 | |||
477 | |||
478 | if( !_cldTestFace( fp0, fp1, fp2, fR, fD, vL, 2) ) { | ||
479 | iExitAxis=2; | ||
480 | return false; | ||
481 | } | ||
482 | // ************************************************ | ||
483 | |||
484 | // ************************************************ | ||
485 | // Axis 3 - Box Y-Axis | ||
486 | SET(vL,vA1); | ||
487 | fD = dDOT(vL,vN)/fNLen; | ||
488 | fp0 = dDOT(vL,vD); | ||
489 | fp1 = fp0 + dDOT(vA1,vE0); | ||
490 | fp2 = fp0 + dDOT(vA1,vE1); | ||
491 | fR = fa1; | ||
492 | |||
493 | |||
494 | if( !_cldTestFace( fp0, fp1, fp2, fR, fD, vL, 3) ) { | ||
495 | iExitAxis=3; | ||
496 | return false; | ||
497 | } | ||
498 | |||
499 | // ************************************************ | ||
500 | |||
501 | // ************************************************ | ||
502 | // Axis 4 - Box Z-Axis | ||
503 | SET(vL,vA2); | ||
504 | fD = dDOT(vL,vN)/fNLen; | ||
505 | fp0 = dDOT(vL,vD); | ||
506 | fp1 = fp0 + dDOT(vA2,vE0); | ||
507 | fp2 = fp0 + dDOT(vA2,vE1); | ||
508 | fR = fa2; | ||
509 | |||
510 | |||
511 | if( !_cldTestFace( fp0, fp1, fp2, fR, fD, vL, 4) ) { | ||
512 | iExitAxis=4; | ||
513 | return false; | ||
514 | } | ||
515 | |||
516 | // ************************************************ | ||
517 | |||
518 | // Test Edges | ||
519 | // ************************************************ | ||
520 | // Axis 5 - Box X-Axis cross Edge0 | ||
521 | dCROSS(vL,=,vA0,vE0); | ||
522 | fD = dDOT(vL,vN)/fNLen; | ||
523 | fp0 = dDOT(vL,vD); | ||
524 | fp1 = fp0; | ||
525 | fp2 = fp0 + dDOT(vA0,vN); | ||
526 | fR = fa1 * dFabs(dDOT(vA2,vE0)) + fa2 * dFabs(dDOT(vA1,vE0)); | ||
527 | |||
528 | |||
529 | if( !_cldTestEdge( fp1, fp2, fR, fD, vL, 5) ) { | ||
530 | iExitAxis=5; | ||
531 | return false; | ||
532 | } | ||
533 | // ************************************************ | ||
534 | |||
535 | // ************************************************ | ||
536 | // Axis 6 - Box X-Axis cross Edge1 | ||
537 | dCROSS(vL,=,vA0,vE1); | ||
538 | fD = dDOT(vL,vN)/fNLen; | ||
539 | fp0 = dDOT(vL,vD); | ||
540 | fp1 = fp0 - dDOT(vA0,vN); | ||
541 | fp2 = fp0; | ||
542 | fR = fa1 * dFabs(dDOT(vA2,vE1)) + fa2 * dFabs(dDOT(vA1,vE1)); | ||
543 | |||
544 | |||
545 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 6) ) { | ||
546 | iExitAxis=6; | ||
547 | return false; | ||
548 | } | ||
549 | // ************************************************ | ||
550 | |||
551 | // ************************************************ | ||
552 | // Axis 7 - Box X-Axis cross Edge2 | ||
553 | dCROSS(vL,=,vA0,vE2); | ||
554 | fD = dDOT(vL,vN)/fNLen; | ||
555 | fp0 = dDOT(vL,vD); | ||
556 | fp1 = fp0 - dDOT(vA0,vN); | ||
557 | fp2 = fp0 - dDOT(vA0,vN); | ||
558 | fR = fa1 * dFabs(dDOT(vA2,vE2)) + fa2 * dFabs(dDOT(vA1,vE2)); | ||
559 | |||
560 | |||
561 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 7) ) { | ||
562 | iExitAxis=7; | ||
563 | return false; | ||
564 | } | ||
565 | |||
566 | // ************************************************ | ||
567 | |||
568 | // ************************************************ | ||
569 | // Axis 8 - Box Y-Axis cross Edge0 | ||
570 | dCROSS(vL,=,vA1,vE0); | ||
571 | fD = dDOT(vL,vN)/fNLen; | ||
572 | fp0 = dDOT(vL,vD); | ||
573 | fp1 = fp0; | ||
574 | fp2 = fp0 + dDOT(vA1,vN); | ||
575 | fR = fa0 * dFabs(dDOT(vA2,vE0)) + fa2 * dFabs(dDOT(vA0,vE0)); | ||
576 | |||
577 | |||
578 | if( !_cldTestEdge( fp0, fp2, fR, fD, vL, 8) ) { | ||
579 | iExitAxis=8; | ||
580 | return false; | ||
581 | } | ||
582 | |||
583 | // ************************************************ | ||
584 | |||
585 | // ************************************************ | ||
586 | // Axis 9 - Box Y-Axis cross Edge1 | ||
587 | dCROSS(vL,=,vA1,vE1); | ||
588 | fD = dDOT(vL,vN)/fNLen; | ||
589 | fp0 = dDOT(vL,vD); | ||
590 | fp1 = fp0 - dDOT(vA1,vN); | ||
591 | fp2 = fp0; | ||
592 | fR = fa0 * dFabs(dDOT(vA2,vE1)) + fa2 * dFabs(dDOT(vA0,vE1)); | ||
593 | |||
594 | |||
595 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 9) ) { | ||
596 | iExitAxis=9; | ||
597 | return false; | ||
598 | } | ||
599 | |||
600 | // ************************************************ | ||
601 | |||
602 | // ************************************************ | ||
603 | // Axis 10 - Box Y-Axis cross Edge2 | ||
604 | dCROSS(vL,=,vA1,vE2); | ||
605 | fD = dDOT(vL,vN)/fNLen; | ||
606 | fp0 = dDOT(vL,vD); | ||
607 | fp1 = fp0 - dDOT(vA1,vN); | ||
608 | fp2 = fp0 - dDOT(vA1,vN); | ||
609 | fR = fa0 * dFabs(dDOT(vA2,vE2)) + fa2 * dFabs(dDOT(vA0,vE2)); | ||
610 | |||
611 | |||
612 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 10) ) { | ||
613 | iExitAxis=10; | ||
614 | return false; | ||
615 | } | ||
616 | |||
617 | // ************************************************ | ||
618 | |||
619 | // ************************************************ | ||
620 | // Axis 11 - Box Z-Axis cross Edge0 | ||
621 | dCROSS(vL,=,vA2,vE0); | ||
622 | fD = dDOT(vL,vN)/fNLen; | ||
623 | fp0 = dDOT(vL,vD); | ||
624 | fp1 = fp0; | ||
625 | fp2 = fp0 + dDOT(vA2,vN); | ||
626 | fR = fa0 * dFabs(dDOT(vA1,vE0)) + fa1 * dFabs(dDOT(vA0,vE0)); | ||
627 | |||
628 | |||
629 | if( !_cldTestEdge( fp0, fp2, fR, fD, vL, 11) ) { | ||
630 | iExitAxis=11; | ||
631 | return false; | ||
632 | } | ||
633 | // ************************************************ | ||
634 | |||
635 | // ************************************************ | ||
636 | // Axis 12 - Box Z-Axis cross Edge1 | ||
637 | dCROSS(vL,=,vA2,vE1); | ||
638 | fD = dDOT(vL,vN)/fNLen; | ||
639 | fp0 = dDOT(vL,vD); | ||
640 | fp1 = fp0 - dDOT(vA2,vN); | ||
641 | fp2 = fp0; | ||
642 | fR = fa0 * dFabs(dDOT(vA1,vE1)) + fa1 * dFabs(dDOT(vA0,vE1)); | ||
643 | |||
644 | |||
645 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 12) ) { | ||
646 | iExitAxis=12; | ||
647 | return false; | ||
648 | } | ||
649 | // ************************************************ | ||
650 | |||
651 | // ************************************************ | ||
652 | // Axis 13 - Box Z-Axis cross Edge2 | ||
653 | dCROSS(vL,=,vA2,vE2); | ||
654 | fD = dDOT(vL,vN)/fNLen; | ||
655 | fp0 = dDOT(vL,vD); | ||
656 | fp1 = fp0 - dDOT(vA2,vN); | ||
657 | fp2 = fp0 - dDOT(vA2,vN); | ||
658 | fR = fa0 * dFabs(dDOT(vA1,vE2)) + fa1 * dFabs(dDOT(vA0,vE2)); | ||
659 | |||
660 | |||
661 | if( !_cldTestEdge( fp0, fp1, fR, fD, vL, 13) ) { | ||
662 | iExitAxis=13; | ||
663 | return false; | ||
664 | } | ||
665 | |||
666 | // ************************************************ | ||
667 | return true; | ||
668 | } | ||
669 | |||
670 | |||
671 | |||
672 | |||
673 | |||
674 | // find two closest points on two lines | ||
675 | static bool _cldClosestPointOnTwoLines( dVector3 vPoint1, dVector3 vLenVec1, | ||
676 | dVector3 vPoint2, dVector3 vLenVec2, | ||
677 | dReal &fvalue1, dReal &fvalue2) | ||
678 | { | ||
679 | // calulate denominator | ||
680 | dVector3 vp; | ||
681 | SUBTRACT(vPoint2,vPoint1,vp); | ||
682 | dReal fuaub = dDOT(vLenVec1,vLenVec2); | ||
683 | dReal fq1 = dDOT(vLenVec1,vp); | ||
684 | dReal fq2 = -dDOT(vLenVec2,vp); | ||
685 | dReal fd = 1.0f - fuaub * fuaub; | ||
686 | |||
687 | // if denominator is positive | ||
688 | if (fd > 0.0f) { | ||
689 | // calculate points of closest approach | ||
690 | fd = 1.0f/fd; | ||
691 | fvalue1 = (fq1 + fuaub*fq2)*fd; | ||
692 | fvalue2 = (fuaub*fq1 + fq2)*fd; | ||
693 | return true; | ||
694 | // otherwise | ||
695 | } else { | ||
696 | // lines are parallel | ||
697 | fvalue1 = 0.0f; | ||
698 | fvalue2 = 0.0f; | ||
699 | return false; | ||
700 | } | ||
701 | |||
702 | } | ||
703 | |||
704 | |||
705 | |||
706 | |||
707 | |||
708 | // clip and generate contacts | ||
709 | static void _cldClipping(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) { | ||
710 | dIASSERT( !(iFlags & CONTACTS_UNIMPORTANT) || ctContacts < (iFlags & NUMC_MASK) ); // Do not call the function if there is no room to store results | ||
711 | |||
712 | // if we have edge/edge intersection | ||
713 | if ( iBestAxis > 4 ) { | ||
714 | |||
715 | dVector3 vub,vPb,vPa; | ||
716 | |||
717 | SET(vPa,vHullBoxPos); | ||
718 | |||
719 | // calculate point on box edge | ||
720 | for( int i=0; i<3; i++) { | ||
721 | dVector3 vRotCol; | ||
722 | GETCOL(mHullBoxRot,i,vRotCol); | ||
723 | dReal fSign = dDOT(vBestNormal,vRotCol) > 0 ? 1.0f : -1.0f; | ||
724 | |||
725 | vPa[0] += fSign * vBoxHalfSize[i] * vRotCol[0]; | ||
726 | vPa[1] += fSign * vBoxHalfSize[i] * vRotCol[1]; | ||
727 | vPa[2] += fSign * vBoxHalfSize[i] * vRotCol[2]; | ||
728 | } | ||
729 | |||
730 | int iEdge = (iBestAxis-5)%3; | ||
731 | |||
732 | // decide which edge is on triangle | ||
733 | if ( iEdge == 0 ) { | ||
734 | SET(vPb,v0); | ||
735 | SET(vub,vE0); | ||
736 | } else if ( iEdge == 1) { | ||
737 | SET(vPb,v2); | ||
738 | SET(vub,vE1); | ||
739 | } else { | ||
740 | SET(vPb,v1); | ||
741 | SET(vub,vE2); | ||
742 | } | ||
743 | |||
744 | |||
745 | // setup direction parameter for face edge | ||
746 | dNormalize3(vub); | ||
747 | |||
748 | dReal fParam1, fParam2; | ||
749 | |||
750 | // setup direction parameter for box edge | ||
751 | dVector3 vua; | ||
752 | int col=(iBestAxis-5)/3; | ||
753 | GETCOL(mHullBoxRot,col,vua); | ||
754 | |||
755 | // find two closest points on both edges | ||
756 | _cldClosestPointOnTwoLines( vPa, vua, vPb, vub, fParam1, fParam2 ); | ||
757 | vPa[0] += vua[0]*fParam1; | ||
758 | vPa[1] += vua[1]*fParam1; | ||
759 | vPa[2] += vua[2]*fParam1; | ||
760 | |||
761 | vPb[0] += vub[0]*fParam2; | ||
762 | vPb[1] += vub[1]*fParam2; | ||
763 | vPb[2] += vub[2]*fParam2; | ||
764 | |||
765 | // calculate collision point | ||
766 | dVector3 vPntTmp; | ||
767 | ADD(vPa,vPb,vPntTmp); | ||
768 | |||
769 | vPntTmp[0]*=0.5f; | ||
770 | vPntTmp[1]*=0.5f; | ||
771 | vPntTmp[2]*=0.5f; | ||
772 | |||
773 | // generate contact point between two closest points | ||
774 | #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else | ||
775 | dContactGeom* Contact = SAFECONTACT(iFlags, ContactGeoms, ctContacts, iStride); | ||
776 | Contact->depth = fBestDepth; | ||
777 | SET(Contact->normal,vBestNormal); | ||
778 | SET(Contact->pos,vPntTmp); | ||
779 | Contact->g1 = Geom1; | ||
780 | Contact->g2 = Geom2; | ||
781 | ctContacts++; | ||
782 | #endif | ||
783 | GenerateContact(iFlags, ContactGeoms, iStride, Geom1, Geom2, | ||
784 | vPntTmp, vBestNormal, fBestDepth, ctContacts); | ||
785 | |||
786 | |||
787 | // if triangle is the referent face then clip box to triangle face | ||
788 | } else if ( iBestAxis == 1 ) { | ||
789 | |||
790 | |||
791 | dVector3 vNormal2; | ||
792 | vNormal2[0]=-vBestNormal[0]; | ||
793 | vNormal2[1]=-vBestNormal[1]; | ||
794 | vNormal2[2]=-vBestNormal[2]; | ||
795 | |||
796 | |||
797 | // vNr is normal in box frame, pointing from triangle to box | ||
798 | dMatrix3 mTransposed; | ||
799 | mTransposed[0*4+0]=mHullBoxRot[0*4+0]; | ||
800 | mTransposed[0*4+1]=mHullBoxRot[1*4+0]; | ||
801 | mTransposed[0*4+2]=mHullBoxRot[2*4+0]; | ||
802 | |||
803 | mTransposed[1*4+0]=mHullBoxRot[0*4+1]; | ||
804 | mTransposed[1*4+1]=mHullBoxRot[1*4+1]; | ||
805 | mTransposed[1*4+2]=mHullBoxRot[2*4+1]; | ||
806 | |||
807 | mTransposed[2*4+0]=mHullBoxRot[0*4+2]; | ||
808 | mTransposed[2*4+1]=mHullBoxRot[1*4+2]; | ||
809 | mTransposed[2*4+2]=mHullBoxRot[2*4+2]; | ||
810 | |||
811 | dVector3 vNr; | ||
812 | vNr[0]=mTransposed[0*4+0]*vNormal2[0]+ mTransposed[0*4+1]*vNormal2[1]+ mTransposed[0*4+2]*vNormal2[2]; | ||
813 | vNr[1]=mTransposed[1*4+0]*vNormal2[0]+ mTransposed[1*4+1]*vNormal2[1]+ mTransposed[1*4+2]*vNormal2[2]; | ||
814 | vNr[2]=mTransposed[2*4+0]*vNormal2[0]+ mTransposed[2*4+1]*vNormal2[1]+ mTransposed[2*4+2]*vNormal2[2]; | ||
815 | |||
816 | |||
817 | dVector3 vAbsNormal; | ||
818 | vAbsNormal[0] = dFabs( vNr[0] ); | ||
819 | vAbsNormal[1] = dFabs( vNr[1] ); | ||
820 | vAbsNormal[2] = dFabs( vNr[2] ); | ||
821 | |||
822 | // get closest face from box | ||
823 | int iB0, iB1, iB2; | ||
824 | if (vAbsNormal[1] > vAbsNormal[0]) { | ||
825 | if (vAbsNormal[1] > vAbsNormal[2]) { | ||
826 | iB1 = 0; iB0 = 1; iB2 = 2; | ||
827 | } else { | ||
828 | iB1 = 0; iB2 = 1; iB0 = 2; | ||
829 | } | ||
830 | } else { | ||
831 | |||
832 | if (vAbsNormal[0] > vAbsNormal[2]) { | ||
833 | iB0 = 0; iB1 = 1; iB2 = 2; | ||
834 | } else { | ||
835 | iB1 = 0; iB2 = 1; iB0 = 2; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | // Here find center of box face we are going to project | ||
840 | dVector3 vCenter; | ||
841 | dVector3 vRotCol; | ||
842 | GETCOL(mHullBoxRot,iB0,vRotCol); | ||
843 | |||
844 | if (vNr[iB0] > 0) { | ||
845 | vCenter[0] = vHullBoxPos[0] - v0[0] - vBoxHalfSize[iB0] * vRotCol[0]; | ||
846 | vCenter[1] = vHullBoxPos[1] - v0[1] - vBoxHalfSize[iB0] * vRotCol[1]; | ||
847 | vCenter[2] = vHullBoxPos[2] - v0[2] - vBoxHalfSize[iB0] * vRotCol[2]; | ||
848 | } else { | ||
849 | vCenter[0] = vHullBoxPos[0] - v0[0] + vBoxHalfSize[iB0] * vRotCol[0]; | ||
850 | vCenter[1] = vHullBoxPos[1] - v0[1] + vBoxHalfSize[iB0] * vRotCol[1]; | ||
851 | vCenter[2] = vHullBoxPos[2] - v0[2] + vBoxHalfSize[iB0] * vRotCol[2]; | ||
852 | } | ||
853 | |||
854 | // Here find 4 corner points of box | ||
855 | dVector3 avPoints[4]; | ||
856 | |||
857 | dVector3 vRotCol2; | ||
858 | GETCOL(mHullBoxRot,iB1,vRotCol); | ||
859 | GETCOL(mHullBoxRot,iB2,vRotCol2); | ||
860 | |||
861 | for(int x=0;x<3;x++) { | ||
862 | avPoints[0][x] = vCenter[x] + (vBoxHalfSize[iB1] * vRotCol[x]) - (vBoxHalfSize[iB2] * vRotCol2[x]); | ||
863 | avPoints[1][x] = vCenter[x] - (vBoxHalfSize[iB1] * vRotCol[x]) - (vBoxHalfSize[iB2] * vRotCol2[x]); | ||
864 | avPoints[2][x] = vCenter[x] - (vBoxHalfSize[iB1] * vRotCol[x]) + (vBoxHalfSize[iB2] * vRotCol2[x]); | ||
865 | avPoints[3][x] = vCenter[x] + (vBoxHalfSize[iB1] * vRotCol[x]) + (vBoxHalfSize[iB2] * vRotCol2[x]); | ||
866 | } | ||
867 | |||
868 | |||
869 | // clip Box face with 4 planes of triangle (1 face plane, 3 egde planes) | ||
870 | dVector3 avTempArray1[9]; | ||
871 | dVector3 avTempArray2[9]; | ||
872 | dVector4 plPlane; | ||
873 | |||
874 | int iTempCnt1=0; | ||
875 | int iTempCnt2=0; | ||
876 | |||
877 | // zeroify vectors - necessary? | ||
878 | for(int i=0; i<9; i++) { | ||
879 | avTempArray1[i][0]=0; | ||
880 | avTempArray1[i][1]=0; | ||
881 | avTempArray1[i][2]=0; | ||
882 | |||
883 | avTempArray2[i][0]=0; | ||
884 | avTempArray2[i][1]=0; | ||
885 | avTempArray2[i][2]=0; | ||
886 | } | ||
887 | |||
888 | |||
889 | // Normal plane | ||
890 | dVector3 vTemp; | ||
891 | vTemp[0]=-vN[0]; | ||
892 | vTemp[1]=-vN[1]; | ||
893 | vTemp[2]=-vN[2]; | ||
894 | dNormalize3(vTemp); | ||
895 | CONSTRUCTPLANE(plPlane,vTemp,0); | ||
896 | |||
897 | _cldClipPolyToPlane( avPoints, 4, avTempArray1, iTempCnt1, plPlane ); | ||
898 | |||
899 | |||
900 | // Plane p0 | ||
901 | dVector3 vTemp2; | ||
902 | SUBTRACT(v1,v0,vTemp2); | ||
903 | dCROSS(vTemp,=,vN,vTemp2); | ||
904 | dNormalize3(vTemp); | ||
905 | CONSTRUCTPLANE(plPlane,vTemp,0); | ||
906 | |||
907 | _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); | ||
908 | |||
909 | |||
910 | // Plane p1 | ||
911 | SUBTRACT(v2,v1,vTemp2); | ||
912 | dCROSS(vTemp,=,vN,vTemp2); | ||
913 | dNormalize3(vTemp); | ||
914 | SUBTRACT(v0,v2,vTemp2); | ||
915 | CONSTRUCTPLANE(plPlane,vTemp,dDOT(vTemp2,vTemp)); | ||
916 | |||
917 | _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); | ||
918 | |||
919 | |||
920 | // Plane p2 | ||
921 | SUBTRACT(v0,v2,vTemp2); | ||
922 | dCROSS(vTemp,=,vN,vTemp2); | ||
923 | dNormalize3(vTemp); | ||
924 | CONSTRUCTPLANE(plPlane,vTemp,0); | ||
925 | |||
926 | _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); | ||
927 | |||
928 | |||
929 | // END of clipping polygons | ||
930 | |||
931 | |||
932 | |||
933 | // for each generated contact point | ||
934 | for ( int i=0; i<iTempCnt2; i++ ) { | ||
935 | // calculate depth | ||
936 | dReal fTempDepth = dDOT(vNormal2,avTempArray2[i]); | ||
937 | |||
938 | // clamp depth to zero | ||
939 | if (fTempDepth > 0) { | ||
940 | fTempDepth = 0; | ||
941 | } | ||
942 | |||
943 | dVector3 vPntTmp; | ||
944 | ADD(avTempArray2[i],v0,vPntTmp); | ||
945 | |||
946 | #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else | ||
947 | dContactGeom* Contact = SAFECONTACT(iFlags, ContactGeoms, ctContacts, iStride); | ||
948 | |||
949 | Contact->depth = -fTempDepth; | ||
950 | SET(Contact->normal,vBestNormal); | ||
951 | SET(Contact->pos,vPntTmp); | ||
952 | Contact->g1 = Geom1; | ||
953 | Contact->g2 = Geom2; | ||
954 | ctContacts++; | ||
955 | #endif | ||
956 | GenerateContact(iFlags, ContactGeoms, iStride, Geom1, Geom2, | ||
957 | vPntTmp, vBestNormal, -fTempDepth, ctContacts); | ||
958 | |||
959 | if ((ctContacts | CONTACTS_UNIMPORTANT) == (iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
960 | break; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | //dAASSERT(ctContacts>0); | ||
965 | |||
966 | // if box face is the referent face, then clip triangle on box face | ||
967 | } else { // 2 <= if iBestAxis <= 4 | ||
968 | |||
969 | // get normal of box face | ||
970 | dVector3 vNormal2; | ||
971 | SET(vNormal2,vBestNormal); | ||
972 | |||
973 | // get indices of box axes in correct order | ||
974 | int iA0,iA1,iA2; | ||
975 | iA0 = iBestAxis-2; | ||
976 | if ( iA0 == 0 ) { | ||
977 | iA1 = 1; iA2 = 2; | ||
978 | } else if ( iA0 == 1 ) { | ||
979 | iA1 = 0; iA2 = 2; | ||
980 | } else { | ||
981 | iA1 = 0; iA2 = 1; | ||
982 | } | ||
983 | |||
984 | dVector3 avPoints[3]; | ||
985 | // calculate triangle vertices in box frame | ||
986 | SUBTRACT(v0,vHullBoxPos,avPoints[0]); | ||
987 | SUBTRACT(v1,vHullBoxPos,avPoints[1]); | ||
988 | SUBTRACT(v2,vHullBoxPos,avPoints[2]); | ||
989 | |||
990 | // CLIP Polygons | ||
991 | // define temp data for clipping | ||
992 | dVector3 avTempArray1[9]; | ||
993 | dVector3 avTempArray2[9]; | ||
994 | |||
995 | int iTempCnt1, iTempCnt2; | ||
996 | |||
997 | // zeroify vectors - necessary? | ||
998 | for(int i=0; i<9; i++) { | ||
999 | avTempArray1[i][0]=0; | ||
1000 | avTempArray1[i][1]=0; | ||
1001 | avTempArray1[i][2]=0; | ||
1002 | |||
1003 | avTempArray2[i][0]=0; | ||
1004 | avTempArray2[i][1]=0; | ||
1005 | avTempArray2[i][2]=0; | ||
1006 | } | ||
1007 | |||
1008 | // clip triangle with 5 box planes (1 face plane, 4 edge planes) | ||
1009 | |||
1010 | dVector4 plPlane; | ||
1011 | |||
1012 | // Normal plane | ||
1013 | dVector3 vTemp; | ||
1014 | vTemp[0]=-vNormal2[0]; | ||
1015 | vTemp[1]=-vNormal2[1]; | ||
1016 | vTemp[2]=-vNormal2[2]; | ||
1017 | CONSTRUCTPLANE(plPlane,vTemp,vBoxHalfSize[iA0]); | ||
1018 | |||
1019 | _cldClipPolyToPlane( avPoints, 3, avTempArray1, iTempCnt1, plPlane ); | ||
1020 | |||
1021 | |||
1022 | // Plane p0 | ||
1023 | GETCOL(mHullBoxRot,iA1,vTemp); | ||
1024 | CONSTRUCTPLANE(plPlane,vTemp,vBoxHalfSize[iA1]); | ||
1025 | |||
1026 | _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); | ||
1027 | |||
1028 | |||
1029 | // Plane p1 | ||
1030 | GETCOL(mHullBoxRot,iA1,vTemp); | ||
1031 | vTemp[0]=-vTemp[0]; | ||
1032 | vTemp[1]=-vTemp[1]; | ||
1033 | vTemp[2]=-vTemp[2]; | ||
1034 | CONSTRUCTPLANE(plPlane,vTemp,vBoxHalfSize[iA1]); | ||
1035 | |||
1036 | _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); | ||
1037 | |||
1038 | |||
1039 | // Plane p2 | ||
1040 | GETCOL(mHullBoxRot,iA2,vTemp); | ||
1041 | CONSTRUCTPLANE(plPlane,vTemp,vBoxHalfSize[iA2]); | ||
1042 | |||
1043 | _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); | ||
1044 | |||
1045 | |||
1046 | // Plane p3 | ||
1047 | GETCOL(mHullBoxRot,iA2,vTemp); | ||
1048 | vTemp[0]=-vTemp[0]; | ||
1049 | vTemp[1]=-vTemp[1]; | ||
1050 | vTemp[2]=-vTemp[2]; | ||
1051 | CONSTRUCTPLANE(plPlane,vTemp,vBoxHalfSize[iA2]); | ||
1052 | |||
1053 | _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); | ||
1054 | |||
1055 | |||
1056 | // for each generated contact point | ||
1057 | for ( int i=0; i<iTempCnt1; i++ ) { | ||
1058 | // calculate depth | ||
1059 | dReal fTempDepth = dDOT(vNormal2,avTempArray1[i])-vBoxHalfSize[iA0]; | ||
1060 | |||
1061 | // clamp depth to zero | ||
1062 | if (fTempDepth > 0) { | ||
1063 | fTempDepth = 0; | ||
1064 | } | ||
1065 | |||
1066 | // generate contact data | ||
1067 | dVector3 vPntTmp; | ||
1068 | ADD(avTempArray1[i],vHullBoxPos,vPntTmp); | ||
1069 | |||
1070 | #if 0 //#ifdef ORIG -- if to use conditional define, GenerateContact must be moved into #else | ||
1071 | dContactGeom* Contact = SAFECONTACT(iFlags, ContactGeoms, ctContacts, iStride); | ||
1072 | |||
1073 | Contact->depth = -fTempDepth; | ||
1074 | SET(Contact->normal,vBestNormal); | ||
1075 | SET(Contact->pos,vPntTmp); | ||
1076 | Contact->g1 = Geom1; | ||
1077 | Contact->g2 = Geom2; | ||
1078 | ctContacts++; | ||
1079 | #endif | ||
1080 | GenerateContact(iFlags, ContactGeoms, iStride, Geom1, Geom2, | ||
1081 | vPntTmp, vBestNormal, -fTempDepth, ctContacts); | ||
1082 | |||
1083 | if ((ctContacts | CONTACTS_UNIMPORTANT) == (iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
1084 | break; | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | //dAASSERT(ctContacts>0); | ||
1089 | } | ||
1090 | |||
1091 | } | ||
1092 | |||
1093 | |||
1094 | |||
1095 | |||
1096 | |||
1097 | // test one mesh triangle on intersection with given box | ||
1098 | static void _cldTestOneTriangle(const dVector3 &v0, const dVector3 &v1, const dVector3 &v2)//, void *pvUser) | ||
1099 | { | ||
1100 | // do intersection test and find best separating axis | ||
1101 | if(!_cldTestSeparatingAxes(v0, v1, v2) ) { | ||
1102 | // if not found do nothing | ||
1103 | return; | ||
1104 | } | ||
1105 | |||
1106 | // if best separation axis is not found | ||
1107 | if ( iBestAxis == 0 ) { | ||
1108 | // this should not happen (we should already exit in that case) | ||
1109 | //dMessage (0, "best separation axis not found"); | ||
1110 | // do nothing | ||
1111 | return; | ||
1112 | } | ||
1113 | |||
1114 | _cldClipping(v0, v1, v2); | ||
1115 | } | ||
1116 | |||
1117 | |||
1118 | |||
1119 | |||
1120 | |||
1121 | // OPCODE version of box to mesh collider | ||
1122 | #if dTRIMESH_OPCODE | ||
1123 | int dCollideBTL(dxGeom* g1, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride){ | ||
1124 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
1125 | dIASSERT (g1->type == dTriMeshClass); | ||
1126 | dIASSERT (BoxGeom->type == dBoxClass); | ||
1127 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
1128 | |||
1129 | |||
1130 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
1131 | |||
1132 | |||
1133 | // get source hull position, orientation and half size | ||
1134 | const dMatrix3& mRotBox=*(const dMatrix3*)dGeomGetRotation(BoxGeom); | ||
1135 | const dVector3& vPosBox=*(const dVector3*)dGeomGetPosition(BoxGeom); | ||
1136 | |||
1137 | // to global | ||
1138 | SETM(mHullBoxRot,mRotBox); | ||
1139 | SET(vHullBoxPos,vPosBox); | ||
1140 | |||
1141 | dGeomBoxGetLengths(BoxGeom, vBoxHalfSize); | ||
1142 | vBoxHalfSize[0] *= 0.5f; | ||
1143 | vBoxHalfSize[1] *= 0.5f; | ||
1144 | vBoxHalfSize[2] *= 0.5f; | ||
1145 | |||
1146 | |||
1147 | |||
1148 | // get destination hull position and orientation | ||
1149 | const dMatrix3& mRotMesh=*(const dMatrix3*)dGeomGetRotation(TriMesh); | ||
1150 | const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh); | ||
1151 | |||
1152 | // to global | ||
1153 | SET(vHullDstPos,vPosMesh); | ||
1154 | |||
1155 | |||
1156 | |||
1157 | // global info for contact creation | ||
1158 | ctContacts = 0; | ||
1159 | iStride=Stride; | ||
1160 | iFlags=Flags; | ||
1161 | ContactGeoms=Contacts; | ||
1162 | Geom1=TriMesh; | ||
1163 | Geom2=BoxGeom; | ||
1164 | |||
1165 | |||
1166 | |||
1167 | // reset stuff | ||
1168 | fBestDepth = MAXVALUE; | ||
1169 | vBestNormal[0]=0; | ||
1170 | vBestNormal[1]=0; | ||
1171 | vBestNormal[2]=0; | ||
1172 | |||
1173 | OBBCollider& Collider = TriMesh->_OBBCollider; | ||
1174 | |||
1175 | |||
1176 | |||
1177 | |||
1178 | // Make OBB | ||
1179 | OBB Box; | ||
1180 | Box.mCenter.x = vPosBox[0]; | ||
1181 | Box.mCenter.y = vPosBox[1]; | ||
1182 | Box.mCenter.z = vPosBox[2]; | ||
1183 | |||
1184 | // It is a potential issue to explicitly cast to float | ||
1185 | // if custom width floating point type is introduced in OPCODE. | ||
1186 | // It is necessary to make a typedef and cast to it | ||
1187 | // (e.g. typedef float opc_float;) | ||
1188 | // However I'm not sure in what header it should be added. | ||
1189 | |||
1190 | Box.mExtents.x = /*(float)*/vBoxHalfSize[0]; | ||
1191 | Box.mExtents.y = /*(float)*/vBoxHalfSize[1]; | ||
1192 | Box.mExtents.z = /*(float)*/vBoxHalfSize[2]; | ||
1193 | |||
1194 | Box.mRot.m[0][0] = /*(float)*/mRotBox[0]; | ||
1195 | Box.mRot.m[1][0] = /*(float)*/mRotBox[1]; | ||
1196 | Box.mRot.m[2][0] = /*(float)*/mRotBox[2]; | ||
1197 | |||
1198 | Box.mRot.m[0][1] = /*(float)*/mRotBox[4]; | ||
1199 | Box.mRot.m[1][1] = /*(float)*/mRotBox[5]; | ||
1200 | Box.mRot.m[2][1] = /*(float)*/mRotBox[6]; | ||
1201 | |||
1202 | Box.mRot.m[0][2] = /*(float)*/mRotBox[8]; | ||
1203 | Box.mRot.m[1][2] = /*(float)*/mRotBox[9]; | ||
1204 | Box.mRot.m[2][2] = /*(float)*/mRotBox[10]; | ||
1205 | |||
1206 | Matrix4x4 amatrix; | ||
1207 | Matrix4x4 BoxMatrix = MakeMatrix(vPosBox, mRotBox, amatrix); | ||
1208 | |||
1209 | Matrix4x4 InvBoxMatrix; | ||
1210 | InvertPRMatrix(InvBoxMatrix, BoxMatrix); | ||
1211 | |||
1212 | // TC results | ||
1213 | if (TriMesh->doBoxTC) { | ||
1214 | dxTriMesh::BoxTC* BoxTC = 0; | ||
1215 | for (int i = 0; i < TriMesh->BoxTCCache.size(); i++){ | ||
1216 | if (TriMesh->BoxTCCache[i].Geom == BoxGeom){ | ||
1217 | BoxTC = &TriMesh->BoxTCCache[i]; | ||
1218 | break; | ||
1219 | } | ||
1220 | } | ||
1221 | if (!BoxTC){ | ||
1222 | TriMesh->BoxTCCache.push(dxTriMesh::BoxTC()); | ||
1223 | |||
1224 | BoxTC = &TriMesh->BoxTCCache[TriMesh->BoxTCCache.size() - 1]; | ||
1225 | BoxTC->Geom = BoxGeom; | ||
1226 | BoxTC->FatCoeff = 1.1f; // Pierre recommends this, instead of 1.0 | ||
1227 | } | ||
1228 | |||
1229 | // Intersect | ||
1230 | Collider.SetTemporalCoherence(true); | ||
1231 | Collider.Collide(*BoxTC, Box, TriMesh->Data->BVTree, null, &MakeMatrix(vPosMesh, mRotMesh, amatrix)); | ||
1232 | } | ||
1233 | else { | ||
1234 | Collider.SetTemporalCoherence(false); | ||
1235 | Collider.Collide(dxTriMesh::defaultBoxCache, Box, TriMesh->Data->BVTree, null, | ||
1236 | &MakeMatrix(vPosMesh, mRotMesh, amatrix)); | ||
1237 | } | ||
1238 | |||
1239 | if (! Collider.GetContactStatus()) { | ||
1240 | // no collision occurred | ||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | // Retrieve data | ||
1245 | int TriCount = Collider.GetNbTouchedPrimitives(); | ||
1246 | const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); | ||
1247 | |||
1248 | if (TriCount != 0){ | ||
1249 | if (TriMesh->ArrayCallback != null){ | ||
1250 | TriMesh->ArrayCallback(TriMesh, BoxGeom, Triangles, TriCount); | ||
1251 | } | ||
1252 | |||
1253 | int ctContacts0 = 0; | ||
1254 | |||
1255 | // loop through all intersecting triangles | ||
1256 | for (int i = 0; i < TriCount; i++){ | ||
1257 | |||
1258 | |||
1259 | const int Triint = Triangles[i]; | ||
1260 | if (!Callback(TriMesh, BoxGeom, Triint)) continue; | ||
1261 | |||
1262 | |||
1263 | dVector3 dv[3]; | ||
1264 | FetchTriangle(TriMesh, Triint, vPosMesh, mRotMesh, dv); | ||
1265 | |||
1266 | |||
1267 | // test this triangle | ||
1268 | _cldTestOneTriangle(dv[0],dv[1],dv[2]); | ||
1269 | |||
1270 | // fill-in tri index for generated contacts | ||
1271 | for (; ctContacts0<ctContacts; ctContacts0++) | ||
1272 | SAFECONTACT(iFlags, ContactGeoms, ctContacts0, iStride)->side1 = Triint; | ||
1273 | |||
1274 | /* | ||
1275 | NOTE by Oleh_Derevenko: | ||
1276 | The function continues checking triangles after maximal number | ||
1277 | of contacts is reached because it selects maximal penetration depths. | ||
1278 | See also comments in GenerateContact() | ||
1279 | */ | ||
1280 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1281 | if ((ctContacts | CONTACTS_UNIMPORTANT) == (iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) | ||
1282 | break; | ||
1283 | } | ||
1284 | } | ||
1285 | |||
1286 | |||
1287 | return ctContacts; | ||
1288 | } | ||
1289 | #endif | ||
1290 | |||
1291 | // GIMPACT version of box to mesh collider | ||
1292 | #if dTRIMESH_GIMPACT | ||
1293 | int dCollideBTL(dxGeom* g1, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride) | ||
1294 | { | ||
1295 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
1296 | dIASSERT (g1->type == dTriMeshClass); | ||
1297 | dIASSERT (BoxGeom->type == dBoxClass); | ||
1298 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
1299 | |||
1300 | |||
1301 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
1302 | |||
1303 | |||
1304 | // get source hull position, orientation and half size | ||
1305 | const dMatrix3& mRotBox=*(const dMatrix3*)dGeomGetRotation(BoxGeom); | ||
1306 | const dVector3& vPosBox=*(const dVector3*)dGeomGetPosition(BoxGeom); | ||
1307 | |||
1308 | // to global | ||
1309 | SETM(mHullBoxRot,mRotBox); | ||
1310 | SET(vHullBoxPos,vPosBox); | ||
1311 | |||
1312 | dGeomBoxGetLengths(BoxGeom, vBoxHalfSize); | ||
1313 | vBoxHalfSize[0] *= 0.5f; | ||
1314 | vBoxHalfSize[1] *= 0.5f; | ||
1315 | vBoxHalfSize[2] *= 0.5f; | ||
1316 | |||
1317 | // get destination hull position and orientation | ||
1318 | /*const dMatrix3& mRotMesh=*(const dMatrix3*)dGeomGetRotation(TriMesh); | ||
1319 | const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh); | ||
1320 | |||
1321 | // to global | ||
1322 | SET(vHullDstPos,vPosMesh);*/ | ||
1323 | |||
1324 | // global info for contact creation | ||
1325 | ctContacts = 0; | ||
1326 | iStride=Stride; | ||
1327 | iFlags=Flags; | ||
1328 | ContactGeoms=Contacts; | ||
1329 | Geom1=TriMesh; | ||
1330 | Geom2=BoxGeom; | ||
1331 | |||
1332 | |||
1333 | // reset stuff | ||
1334 | fBestDepth = MAXVALUE; | ||
1335 | vBestNormal[0]=0; | ||
1336 | vBestNormal[1]=0; | ||
1337 | vBestNormal[2]=0; | ||
1338 | |||
1339 | |||
1340 | //*****at first , collide box aabb******// | ||
1341 | |||
1342 | GIM_TRIMESH * ptrimesh = &TriMesh->m_collision_trimesh; | ||
1343 | aabb3f test_aabb; | ||
1344 | |||
1345 | test_aabb.minX = BoxGeom->aabb[0]; | ||
1346 | test_aabb.maxX = BoxGeom->aabb[1]; | ||
1347 | test_aabb.minY = BoxGeom->aabb[2]; | ||
1348 | test_aabb.maxY = BoxGeom->aabb[3]; | ||
1349 | test_aabb.minZ = BoxGeom->aabb[4]; | ||
1350 | test_aabb.maxZ = BoxGeom->aabb[5]; | ||
1351 | |||
1352 | GDYNAMIC_ARRAY collision_result; | ||
1353 | GIM_CREATE_BOXQUERY_LIST(collision_result); | ||
1354 | |||
1355 | gim_aabbset_box_collision(&test_aabb, &ptrimesh->m_aabbset , &collision_result); | ||
1356 | |||
1357 | if(collision_result.m_size==0) | ||
1358 | { | ||
1359 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1360 | return 0; | ||
1361 | } | ||
1362 | //*****Set globals for box collision******// | ||
1363 | |||
1364 | //collide triangles | ||
1365 | |||
1366 | GUINT * boxesresult = GIM_DYNARRAY_POINTER(GUINT,collision_result); | ||
1367 | gim_trimesh_locks_work_data(ptrimesh); | ||
1368 | |||
1369 | int ctContacts0 = 0; | ||
1370 | |||
1371 | for(unsigned int i=0;i<collision_result.m_size;i++) | ||
1372 | { | ||
1373 | dVector3 dv[3]; | ||
1374 | |||
1375 | int Triint = boxesresult[i]; | ||
1376 | gim_trimesh_get_triangle_vertices(ptrimesh, Triint,dv[0],dv[1],dv[2]); | ||
1377 | // test this triangle | ||
1378 | _cldTestOneTriangle(dv[0],dv[1],dv[2]); | ||
1379 | |||
1380 | // fill-in tri index for generated contacts | ||
1381 | for (; ctContacts0<ctContacts; ctContacts0++) | ||
1382 | SAFECONTACT(iFlags, ContactGeoms, ctContacts0, iStride)->side1 = Triint; | ||
1383 | |||
1384 | /* | ||
1385 | NOTE by Oleh_Derevenko: | ||
1386 | The function continues checking triangles after maximal number | ||
1387 | of contacts is reached because it selects maximal penetration depths. | ||
1388 | See also comments in GenerateContact() | ||
1389 | */ | ||
1390 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1391 | if ((ctContacts | CONTACTS_UNIMPORTANT) == (iFlags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) | ||
1392 | break; | ||
1393 | } | ||
1394 | |||
1395 | gim_trimesh_unlocks_work_data(ptrimesh); | ||
1396 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1397 | |||
1398 | return ctContacts; | ||
1399 | } | ||
1400 | #endif | ||
1401 | |||
1402 | |||
1403 | // GenerateContact - Written by Jeff Smith (jeff@burri.to) | ||
1404 | // Generate a "unique" contact. A unique contact has a unique | ||
1405 | // position or normal. If the potential contact has the same | ||
1406 | // position and normal as an existing contact, but a larger | ||
1407 | // penetration depth, this new depth is used instead | ||
1408 | // | ||
1409 | static void | ||
1410 | GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, | ||
1411 | dxGeom* in_g1, dxGeom* in_g2, | ||
1412 | const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, | ||
1413 | int& OutTriCount) | ||
1414 | { | ||
1415 | /* | ||
1416 | NOTE by Oleh_Derevenko: | ||
1417 | This function is called after maximal number of contacts has already been | ||
1418 | collected because it has a side effect of replacing penetration depth of | ||
1419 | existing contact with larger penetration depth of another matching normal contact. | ||
1420 | If this logic is not necessary any more, you can bail out on reach of contact | ||
1421 | number maximum immediately in dCollideBTL(). You will also need to correct | ||
1422 | conditional statements after invocations of GenerateContact() in _cldClipping(). | ||
1423 | */ | ||
1424 | do | ||
1425 | { | ||
1426 | dContactGeom* Contact; | ||
1427 | dVector3 diff; | ||
1428 | |||
1429 | if (!(in_Flags & CONTACTS_UNIMPORTANT)) | ||
1430 | { | ||
1431 | bool duplicate = false; | ||
1432 | for (int i=0; i<OutTriCount; i++) | ||
1433 | { | ||
1434 | Contact = SAFECONTACT(in_Flags, in_Contacts, i, in_Stride); | ||
1435 | |||
1436 | // same position? | ||
1437 | for (int j=0; j<3; j++) | ||
1438 | diff[j] = in_ContactPos[j] - Contact->pos[j]; | ||
1439 | if (dDOT(diff, diff) < dEpsilon) | ||
1440 | { | ||
1441 | // same normal? | ||
1442 | if (dFabs(dDOT(in_Normal, Contact->normal)) > (REAL(1.0)-dEpsilon)) | ||
1443 | { | ||
1444 | if (in_Depth > Contact->depth) | ||
1445 | Contact->depth = in_Depth; | ||
1446 | duplicate = true; | ||
1447 | /* | ||
1448 | NOTE by Oleh_Derevenko: | ||
1449 | There may be a case when two normals are close to each other but not duplicate | ||
1450 | while third normal is detected to be duplicate for both of them. | ||
1451 | This is the only reason I can think of, there is no "break" statement. | ||
1452 | Perhaps author considered it to be logical that the third normal would | ||
1453 | replace the depth in both of initial contacts. | ||
1454 | However, I consider it a questionable practice which should not | ||
1455 | be applied without deep understanding of underlaying physics. | ||
1456 | Even more, is this situation with close normal triplet acceptable at all? | ||
1457 | Should not be two initial contacts reduced to one (replaced with the latter)? | ||
1458 | If you know the answers for these questions, you may want to change this code. | ||
1459 | See the same statement in GenerateContact() of collision_trimesh_trimesh.cpp | ||
1460 | */ | ||
1461 | } | ||
1462 | } | ||
1463 | } | ||
1464 | if (duplicate || OutTriCount == (in_Flags & NUMC_MASK)) | ||
1465 | { | ||
1466 | break; | ||
1467 | } | ||
1468 | } | ||
1469 | else | ||
1470 | { | ||
1471 | dIASSERT(OutTriCount < (in_Flags & NUMC_MASK)); | ||
1472 | } | ||
1473 | |||
1474 | // Add a new contact | ||
1475 | Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride); | ||
1476 | |||
1477 | Contact->pos[0] = in_ContactPos[0]; | ||
1478 | Contact->pos[1] = in_ContactPos[1]; | ||
1479 | Contact->pos[2] = in_ContactPos[2]; | ||
1480 | Contact->pos[3] = 0.0; | ||
1481 | |||
1482 | Contact->normal[0] = in_Normal[0]; | ||
1483 | Contact->normal[1] = in_Normal[1]; | ||
1484 | Contact->normal[2] = in_Normal[2]; | ||
1485 | Contact->normal[3] = 0.0; | ||
1486 | |||
1487 | Contact->depth = in_Depth; | ||
1488 | |||
1489 | Contact->g1 = in_g1; | ||
1490 | Contact->g2 = in_g2; | ||
1491 | |||
1492 | OutTriCount++; | ||
1493 | } | ||
1494 | while (false); | ||
1495 | } | ||
1496 | |||
1497 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_ccylinder.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_ccylinder.cpp new file mode 100755 index 0000000..da235e0 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_ccylinder.cpp | |||
@@ -0,0 +1,1181 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | * Triangle-Capsule(Capsule) collider by Alen Ladavac | ||
25 | * Ported to ODE by Nguyen Binh | ||
26 | */ | ||
27 | |||
28 | // NOTES from Nguyen Binh | ||
29 | // 14 Apr : Seem to be robust | ||
30 | // There is a problem when you use original Step and set contact friction | ||
31 | // surface.mu = dInfinity; | ||
32 | // More description : | ||
33 | // When I dropped Capsule over the bunny ears, it seems to stuck | ||
34 | // there for a while. I think the cause is when you set surface.mu = dInfinity; | ||
35 | // the friction force is too high so it just hang the capsule there. | ||
36 | // So the good cure for this is to set mu = around 1.5 (in my case) | ||
37 | // For StepFast1, this become as solid as rock : StepFast1 just approximate | ||
38 | // friction force. | ||
39 | |||
40 | // NOTES from Croteam's Alen | ||
41 | //As a side note... there are some extra contacts that can be generated | ||
42 | //on the edge between two triangles, and if the capsule penetrates deeply into | ||
43 | //the triangle (usually happens with large mass or low FPS), some such | ||
44 | //contacts can in some cases push the capsule away from the edge instead of | ||
45 | //away from the two triangles. This shows up as capsule slowing down a bit | ||
46 | //when hitting an edge while sliding along a flat tesselated grid of | ||
47 | //triangles. This is only if capsule is standing upwards. | ||
48 | |||
49 | //Same thing can appear whenever a smooth object (e.g sphere) hits such an | ||
50 | //edge, and it needs to be solved as a special case probably. This is a | ||
51 | //problem we are looking forward to address soon. | ||
52 | |||
53 | #include <ode/collision.h> | ||
54 | #include <ode/matrix.h> | ||
55 | #include <ode/rotation.h> | ||
56 | #include <ode/odemath.h> | ||
57 | #include "collision_util.h" | ||
58 | |||
59 | #define TRIMESH_INTERNAL | ||
60 | #include "collision_trimesh_internal.h" | ||
61 | |||
62 | #if dTRIMESH_ENABLED | ||
63 | |||
64 | // OPCODE version | ||
65 | #if dTRIMESH_OPCODE | ||
66 | // largest number, double or float | ||
67 | #if defined(dSINGLE) | ||
68 | #define MAX_REAL FLT_MAX | ||
69 | #define MIN_REAL (-FLT_MAX) | ||
70 | #else | ||
71 | #define MAX_REAL DBL_MAX | ||
72 | #define MIN_REAL (-DBL_MAX) | ||
73 | #endif | ||
74 | |||
75 | // To optimize before send contacts to dynamic part | ||
76 | #define OPTIMIZE_CONTACTS | ||
77 | |||
78 | // dVector3 | ||
79 | // r=a-b | ||
80 | #define SUBTRACT(a,b,r) \ | ||
81 | (r)[0]=(a)[0] - (b)[0]; \ | ||
82 | (r)[1]=(a)[1] - (b)[1]; \ | ||
83 | (r)[2]=(a)[2] - (b)[2]; | ||
84 | |||
85 | |||
86 | // dVector3 | ||
87 | // a=b | ||
88 | #define SET(a,b) \ | ||
89 | (a)[0]=(b)[0]; \ | ||
90 | (a)[1]=(b)[1]; \ | ||
91 | (a)[2]=(b)[2]; | ||
92 | |||
93 | |||
94 | // dMatrix3 | ||
95 | // a=b | ||
96 | #define SETM(a,b) \ | ||
97 | (a)[0]=(b)[0]; \ | ||
98 | (a)[1]=(b)[1]; \ | ||
99 | (a)[2]=(b)[2]; \ | ||
100 | (a)[3]=(b)[3]; \ | ||
101 | (a)[4]=(b)[4]; \ | ||
102 | (a)[5]=(b)[5]; \ | ||
103 | (a)[6]=(b)[6]; \ | ||
104 | (a)[7]=(b)[7]; \ | ||
105 | (a)[8]=(b)[8]; \ | ||
106 | (a)[9]=(b)[9]; \ | ||
107 | (a)[10]=(b)[10]; \ | ||
108 | (a)[11]=(b)[11]; | ||
109 | |||
110 | |||
111 | // dVector3 | ||
112 | // r=a+b | ||
113 | #define ADD(a,b,r) \ | ||
114 | (r)[0]=(a)[0] + (b)[0]; \ | ||
115 | (r)[1]=(a)[1] + (b)[1]; \ | ||
116 | (r)[2]=(a)[2] + (b)[2]; | ||
117 | |||
118 | |||
119 | // dMatrix3, int, dVector3 | ||
120 | // v=column a from m | ||
121 | #define GETCOL(m,a,v) \ | ||
122 | (v)[0]=(m)[(a)+0]; \ | ||
123 | (v)[1]=(m)[(a)+4]; \ | ||
124 | (v)[2]=(m)[(a)+8]; | ||
125 | |||
126 | |||
127 | // dVector4, dVector3 | ||
128 | // distance between plane p and point v | ||
129 | #define POINTDISTANCE(p,v) \ | ||
130 | ( p[0]*v[0] + p[1]*v[1] + p[2]*v[2] + p[3] ); \ | ||
131 | |||
132 | |||
133 | // dVector4, dVector3, dReal | ||
134 | // construct plane from normal and d | ||
135 | #define CONSTRUCTPLANE(plane,normal,d) \ | ||
136 | plane[0]=normal[0];\ | ||
137 | plane[1]=normal[1];\ | ||
138 | plane[2]=normal[2];\ | ||
139 | plane[3]=d; | ||
140 | |||
141 | |||
142 | // dVector3 | ||
143 | // length of vector a | ||
144 | #define LENGTHOF(a) \ | ||
145 | dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);\ | ||
146 | |||
147 | inline dReal _length2OfVector3(dVector3 v) | ||
148 | { | ||
149 | return (v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); | ||
150 | } | ||
151 | |||
152 | |||
153 | // Local contacts data | ||
154 | typedef struct _sLocalContactData | ||
155 | { | ||
156 | dVector3 vPos; | ||
157 | dVector3 vNormal; | ||
158 | dReal fDepth; | ||
159 | int triIndex; | ||
160 | int nFlags; // 0 = filtered out, 1 = OK | ||
161 | }sLocalContactData; | ||
162 | |||
163 | static sLocalContactData *gLocalContacts; | ||
164 | static unsigned int ctContacts = 0; | ||
165 | |||
166 | // capsule data | ||
167 | // real time data | ||
168 | static dMatrix3 mCapsuleRotation; | ||
169 | static dVector3 vCapsulePosition; | ||
170 | static dVector3 vCapsuleAxis; | ||
171 | // static data | ||
172 | static dReal vCapsuleRadius; | ||
173 | static dReal fCapsuleSize; | ||
174 | |||
175 | // mesh data | ||
176 | static dMatrix4 mHullDstPl; | ||
177 | static dMatrix3 mTriMeshRot; | ||
178 | static dVector3 mTriMeshPos; | ||
179 | static dVector3 vE0, vE1, vE2; | ||
180 | |||
181 | // Two geom | ||
182 | dxGeom* gCylinder; | ||
183 | dxGeom* gTriMesh; | ||
184 | |||
185 | // global collider data | ||
186 | static dVector3 vNormal; | ||
187 | static dReal fBestDepth; | ||
188 | static dReal fBestCenter; | ||
189 | static dReal fBestrt; | ||
190 | static int iBestAxis; | ||
191 | static dVector3 vN = {0,0,0,0}; | ||
192 | |||
193 | static dVector3 vV0; | ||
194 | static dVector3 vV1; | ||
195 | static dVector3 vV2; | ||
196 | |||
197 | // ODE contact's specific | ||
198 | static unsigned int iFlags; | ||
199 | static dContactGeom *ContactGeoms; | ||
200 | static int iStride; | ||
201 | |||
202 | // Capsule lie on axis number 3 = (Z axis) | ||
203 | static const int nCAPSULE_AXIS = 2; | ||
204 | |||
205 | // Use to classify contacts to be "near" in position | ||
206 | static const dReal fSameContactPositionEpsilon = REAL(0.0001); // 1e-4 | ||
207 | // Use to classify contacts to be "near" in normal direction | ||
208 | static const dReal fSameContactNormalEpsilon = REAL(0.0001); // 1e-4 | ||
209 | |||
210 | |||
211 | // If this two contact can be classified as "near" | ||
212 | inline int _IsNearContacts(sLocalContactData& c1,sLocalContactData& c2) | ||
213 | { | ||
214 | int bPosNear = 0; | ||
215 | int bSameDir = 0; | ||
216 | dVector3 vDiff; | ||
217 | |||
218 | // First check if they are "near" in position | ||
219 | SUBTRACT(c1.vPos,c2.vPos,vDiff); | ||
220 | if ( (dFabs(vDiff[0]) < fSameContactPositionEpsilon) | ||
221 | &&(dFabs(vDiff[1]) < fSameContactPositionEpsilon) | ||
222 | &&(dFabs(vDiff[2]) < fSameContactPositionEpsilon)) | ||
223 | { | ||
224 | bPosNear = 1; | ||
225 | } | ||
226 | |||
227 | // Second check if they are "near" in normal direction | ||
228 | SUBTRACT(c1.vNormal,c2.vNormal,vDiff); | ||
229 | if ( (dFabs(vDiff[0]) < fSameContactNormalEpsilon) | ||
230 | &&(dFabs(vDiff[1]) < fSameContactNormalEpsilon) | ||
231 | &&(dFabs(vDiff[2]) < fSameContactNormalEpsilon) ) | ||
232 | { | ||
233 | bSameDir = 1; | ||
234 | } | ||
235 | |||
236 | // Will be "near" if position and normal direction are "near" | ||
237 | return (bPosNear && bSameDir); | ||
238 | } | ||
239 | |||
240 | inline int _IsBetter(sLocalContactData& c1,sLocalContactData& c2) | ||
241 | { | ||
242 | // The not better will be throw away | ||
243 | // You can change the selection criteria here | ||
244 | return (c1.fDepth > c2.fDepth); | ||
245 | } | ||
246 | |||
247 | // iterate through gLocalContacts and filtered out "near contact" | ||
248 | inline void _OptimizeLocalContacts() | ||
249 | { | ||
250 | int nContacts = ctContacts; | ||
251 | |||
252 | for (int i = 0; i < nContacts-1; i++) | ||
253 | { | ||
254 | for (int j = i+1; j < nContacts; j++) | ||
255 | { | ||
256 | if (_IsNearContacts(gLocalContacts[i],gLocalContacts[j])) | ||
257 | { | ||
258 | // If they are seem to be the samed then filtered | ||
259 | // out the least penetrate one | ||
260 | if (_IsBetter(gLocalContacts[j],gLocalContacts[i])) | ||
261 | { | ||
262 | gLocalContacts[i].nFlags = 0; // filtered 1st contact | ||
263 | } | ||
264 | else | ||
265 | { | ||
266 | gLocalContacts[j].nFlags = 0; // filtered 2nd contact | ||
267 | } | ||
268 | |||
269 | // NOTE | ||
270 | // There is other way is to add two depth together but | ||
271 | // it not work so well. Why??? | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | inline int _ProcessLocalContacts() | ||
278 | { | ||
279 | if (ctContacts == 0) | ||
280 | { | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | #ifdef OPTIMIZE_CONTACTS | ||
285 | if (ctContacts > 1 && !(iFlags & CONTACTS_UNIMPORTANT)) | ||
286 | { | ||
287 | // Can be optimized... | ||
288 | _OptimizeLocalContacts(); | ||
289 | } | ||
290 | #endif | ||
291 | |||
292 | unsigned int iContact = 0; | ||
293 | dContactGeom* Contact = 0; | ||
294 | |||
295 | unsigned int nFinalContact = 0; | ||
296 | |||
297 | for (iContact = 0; iContact < ctContacts; iContact ++) | ||
298 | { | ||
299 | // Ensure that we haven't created too many contacts | ||
300 | if( nFinalContact >= (iFlags & NUMC_MASK)) | ||
301 | { | ||
302 | break; | ||
303 | } | ||
304 | |||
305 | if (1 == gLocalContacts[iContact].nFlags) | ||
306 | { | ||
307 | Contact = SAFECONTACT(iFlags, ContactGeoms, nFinalContact, iStride); | ||
308 | Contact->depth = gLocalContacts[iContact].fDepth; | ||
309 | SET(Contact->normal,gLocalContacts[iContact].vNormal); | ||
310 | SET(Contact->pos,gLocalContacts[iContact].vPos); | ||
311 | Contact->g1 = gTriMesh; | ||
312 | Contact->g2 = gCylinder; | ||
313 | Contact->side2 = gLocalContacts[iContact].triIndex; | ||
314 | |||
315 | nFinalContact++; | ||
316 | } | ||
317 | } | ||
318 | // debug | ||
319 | //if (nFinalContact != ctContacts) | ||
320 | //{ | ||
321 | // printf("[Info] %d contacts generated,%d filtered.\n",ctContacts,ctContacts-nFinalContact); | ||
322 | //} | ||
323 | |||
324 | return nFinalContact; | ||
325 | } | ||
326 | |||
327 | BOOL _cldClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane) | ||
328 | { | ||
329 | // calculate distance of edge points to plane | ||
330 | dReal fDistance0 = POINTDISTANCE( plPlane, vEpnt0 ); | ||
331 | dReal fDistance1 = POINTDISTANCE( plPlane, vEpnt1 ); | ||
332 | |||
333 | // if both points are behind the plane | ||
334 | if ( fDistance0 < 0 && fDistance1 < 0 ) | ||
335 | { | ||
336 | // do nothing | ||
337 | return FALSE; | ||
338 | // if both points in front of the plane | ||
339 | } else if ( fDistance0 > 0 && fDistance1 > 0 ) | ||
340 | { | ||
341 | // accept them | ||
342 | return TRUE; | ||
343 | // if we have edge/plane intersection | ||
344 | } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0)) | ||
345 | { | ||
346 | |||
347 | // find intersection point of edge and plane | ||
348 | dVector3 vIntersectionPoint; | ||
349 | vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1); | ||
350 | vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1); | ||
351 | vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1); | ||
352 | |||
353 | // clamp correct edge to intersection point | ||
354 | if ( fDistance0 < 0 ) | ||
355 | { | ||
356 | SET(vEpnt0,vIntersectionPoint); | ||
357 | } else | ||
358 | { | ||
359 | SET(vEpnt1,vIntersectionPoint); | ||
360 | } | ||
361 | return TRUE; | ||
362 | } | ||
363 | return TRUE; | ||
364 | } | ||
365 | |||
366 | static BOOL _cldTestAxis(const dVector3 &v0, | ||
367 | const dVector3 &v1, | ||
368 | const dVector3 &v2, | ||
369 | dVector3 vAxis, | ||
370 | int iAxis, | ||
371 | BOOL bNoFlip = FALSE) | ||
372 | { | ||
373 | |||
374 | // calculate length of separating axis vector | ||
375 | dReal fL = LENGTHOF(vAxis); | ||
376 | // if not long enough | ||
377 | // TODO : dReal epsilon please | ||
378 | if ( fL < REAL(1e-5) ) | ||
379 | { | ||
380 | // do nothing | ||
381 | //iLastOutAxis = 0; | ||
382 | return TRUE; | ||
383 | } | ||
384 | |||
385 | // otherwise normalize it | ||
386 | dNormalize3(vAxis); | ||
387 | |||
388 | // project capsule on vAxis | ||
389 | dReal frc = dFabs(dDOT(vCapsuleAxis,vAxis))*(fCapsuleSize*REAL(0.5)-vCapsuleRadius) + vCapsuleRadius; | ||
390 | |||
391 | // project triangle on vAxis | ||
392 | dReal afv[3]; | ||
393 | afv[0] = dDOT( vV0 , vAxis ); | ||
394 | afv[1] = dDOT( vV1 , vAxis ); | ||
395 | afv[2] = dDOT( vV2 , vAxis ); | ||
396 | |||
397 | dReal fMin = MAX_REAL; | ||
398 | dReal fMax = MIN_REAL; | ||
399 | |||
400 | // for each vertex | ||
401 | for(int i=0; i<3; i++) | ||
402 | { | ||
403 | // find minimum | ||
404 | if (afv[i]<fMin) | ||
405 | { | ||
406 | fMin = afv[i]; | ||
407 | } | ||
408 | // find maximum | ||
409 | if (afv[i]>fMax) | ||
410 | { | ||
411 | fMax = afv[i]; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | // find triangle's center of interval on axis | ||
416 | dReal fCenter = (fMin+fMax)*REAL(0.5); | ||
417 | // calculate triangles half interval | ||
418 | dReal fTriangleRadius = (fMax-fMin)*REAL(0.5); | ||
419 | |||
420 | // if they do not overlap, | ||
421 | if( dFabs(fCenter) > ( frc + fTriangleRadius ) ) | ||
422 | { | ||
423 | // exit, we have no intersection | ||
424 | return FALSE; | ||
425 | } | ||
426 | |||
427 | // calculate depth | ||
428 | dReal fDepth = dFabs(fCenter) - (frc+fTriangleRadius); | ||
429 | |||
430 | // if greater then best found so far | ||
431 | if ( fDepth > fBestDepth ) | ||
432 | { | ||
433 | // remember depth | ||
434 | fBestDepth = fDepth; | ||
435 | fBestCenter = fCenter; | ||
436 | fBestrt = fTriangleRadius; | ||
437 | |||
438 | vNormal[0] = vAxis[0]; | ||
439 | vNormal[1] = vAxis[1]; | ||
440 | vNormal[2] = vAxis[2]; | ||
441 | |||
442 | iBestAxis = iAxis; | ||
443 | |||
444 | // flip normal if interval is wrong faced | ||
445 | if (fCenter<0 && !bNoFlip) | ||
446 | { | ||
447 | vNormal[0] = -vNormal[0]; | ||
448 | vNormal[1] = -vNormal[1]; | ||
449 | vNormal[2] = -vNormal[2]; | ||
450 | |||
451 | fBestCenter = -fCenter; | ||
452 | } | ||
453 | } | ||
454 | |||
455 | return TRUE; | ||
456 | } | ||
457 | |||
458 | // helper for less key strokes | ||
459 | inline void _CalculateAxis(const dVector3& v1, | ||
460 | const dVector3& v2, | ||
461 | const dVector3& v3, | ||
462 | const dVector3& v4, | ||
463 | dVector3& r) | ||
464 | { | ||
465 | dVector3 t1; | ||
466 | dVector3 t2; | ||
467 | |||
468 | SUBTRACT(v1,v2,t1); | ||
469 | dCROSS(t2,=,t1,v3); | ||
470 | dCROSS(r,=,t2,v4); | ||
471 | } | ||
472 | |||
473 | static BOOL _cldTestSeparatingAxesOfCapsule(const dVector3 &v0, | ||
474 | const dVector3 &v1, | ||
475 | const dVector3 &v2, | ||
476 | uint8 flags) | ||
477 | { | ||
478 | // calculate caps centers in absolute space | ||
479 | dVector3 vCp0; | ||
480 | vCp0[0] = vCapsulePosition[0] + vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
481 | vCp0[1] = vCapsulePosition[1] + vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
482 | vCp0[2] = vCapsulePosition[2] + vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
483 | |||
484 | dVector3 vCp1; | ||
485 | vCp1[0] = vCapsulePosition[0] - vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
486 | vCp1[1] = vCapsulePosition[1] - vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
487 | vCp1[2] = vCapsulePosition[2] - vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
488 | |||
489 | // reset best axis | ||
490 | iBestAxis = 0; | ||
491 | // reset best depth | ||
492 | fBestDepth = -MAX_REAL; | ||
493 | // reset separating axis vector | ||
494 | dVector3 vAxis = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; | ||
495 | |||
496 | // Epsilon value for checking axis vector length | ||
497 | const dReal fEpsilon = 1e-6f; | ||
498 | |||
499 | // Translate triangle to Cc cord. | ||
500 | SUBTRACT(v0 , vCapsulePosition, vV0); | ||
501 | SUBTRACT(v1 , vCapsulePosition, vV1); | ||
502 | SUBTRACT(v2 , vCapsulePosition, vV2); | ||
503 | |||
504 | // We begin to test for 19 separating axis now | ||
505 | // I wonder does it help if we employ the method like ISA-GJK??? | ||
506 | // Or at least we should do experiment and find what axis will | ||
507 | // be most likely to be separating axis to check it first. | ||
508 | |||
509 | // Original | ||
510 | // axis vN | ||
511 | //vAxis = -vN; | ||
512 | vAxis[0] = - vN[0]; | ||
513 | vAxis[1] = - vN[1]; | ||
514 | vAxis[2] = - vN[2]; | ||
515 | if (!_cldTestAxis( v0, v1, v2, vAxis, 1, TRUE)) | ||
516 | { | ||
517 | return FALSE; | ||
518 | } | ||
519 | |||
520 | if (flags & dxTriMeshData::kEdge0) | ||
521 | { | ||
522 | // axis CxE0 - Edge 0 | ||
523 | dCROSS(vAxis,=,vCapsuleAxis,vE0); | ||
524 | //vAxis = dCROSS( vCapsuleAxis cross vE0 ); | ||
525 | if( _length2OfVector3( vAxis ) > fEpsilon ) { | ||
526 | if (!_cldTestAxis( v0, v1, v2, vAxis, 2)) { | ||
527 | return FALSE; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
532 | if (flags & dxTriMeshData::kEdge1) | ||
533 | { | ||
534 | // axis CxE1 - Edge 1 | ||
535 | dCROSS(vAxis,=,vCapsuleAxis,vE1); | ||
536 | //vAxis = ( vCapsuleAxis cross vE1 ); | ||
537 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
538 | if (!_cldTestAxis( v0, v1, v2, vAxis, 3)) { | ||
539 | return FALSE; | ||
540 | } | ||
541 | } | ||
542 | } | ||
543 | |||
544 | if (flags & dxTriMeshData::kEdge2) | ||
545 | { | ||
546 | // axis CxE2 - Edge 2 | ||
547 | //vAxis = ( vCapsuleAxis cross vE2 ); | ||
548 | dCROSS(vAxis,=,vCapsuleAxis,vE2); | ||
549 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
550 | if (!_cldTestAxis( v0, v1, v2, vAxis, 4)) { | ||
551 | return FALSE; | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if (flags & dxTriMeshData::kEdge0) | ||
557 | { | ||
558 | // first capsule point | ||
559 | // axis ((Cp0-V0) x E0) x E0 | ||
560 | _CalculateAxis(vCp0,v0,vE0,vE0,vAxis); | ||
561 | // vAxis = ( ( vCp0-v0) cross vE0 ) cross vE0; | ||
562 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
563 | if (!_cldTestAxis( v0, v1, v2, vAxis, 5)) { | ||
564 | return FALSE; | ||
565 | } | ||
566 | } | ||
567 | } | ||
568 | |||
569 | if (flags & dxTriMeshData::kEdge1) | ||
570 | { | ||
571 | // axis ((Cp0-V1) x E1) x E1 | ||
572 | _CalculateAxis(vCp0,v1,vE1,vE1,vAxis); | ||
573 | //vAxis = ( ( vCp0-v1) cross vE1 ) cross vE1; | ||
574 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
575 | if (!_cldTestAxis( v0, v1, v2, vAxis, 6)) { | ||
576 | return FALSE; | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | |||
581 | if (flags & dxTriMeshData::kEdge2) | ||
582 | { | ||
583 | // axis ((Cp0-V2) x E2) x E2 | ||
584 | _CalculateAxis(vCp0,v2,vE2,vE2,vAxis); | ||
585 | //vAxis = ( ( vCp0-v2) cross vE2 ) cross vE2; | ||
586 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
587 | if (!_cldTestAxis( v0, v1, v2, vAxis, 7)) { | ||
588 | return FALSE; | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | |||
593 | if (flags & dxTriMeshData::kEdge0) | ||
594 | { | ||
595 | // second capsule point | ||
596 | // axis ((Cp1-V0) x E0) x E0 | ||
597 | _CalculateAxis(vCp1,v0,vE0,vE0,vAxis); | ||
598 | //vAxis = ( ( vCp1-v0 ) cross vE0 ) cross vE0; | ||
599 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
600 | if (!_cldTestAxis( v0, v1, v2, vAxis, 8)) { | ||
601 | return FALSE; | ||
602 | } | ||
603 | } | ||
604 | } | ||
605 | |||
606 | if (flags & dxTriMeshData::kEdge1) | ||
607 | { | ||
608 | // axis ((Cp1-V1) x E1) x E1 | ||
609 | _CalculateAxis(vCp1,v1,vE1,vE1,vAxis); | ||
610 | //vAxis = ( ( vCp1-v1 ) cross vE1 ) cross vE1; | ||
611 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
612 | if (!_cldTestAxis( v0, v1, v2, vAxis, 9)) { | ||
613 | return FALSE; | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | if (flags & dxTriMeshData::kEdge2) | ||
619 | { | ||
620 | // axis ((Cp1-V2) x E2) x E2 | ||
621 | _CalculateAxis(vCp1,v2,vE2,vE2,vAxis); | ||
622 | //vAxis = ( ( vCp1-v2 ) cross vE2 ) cross vE2; | ||
623 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
624 | if (!_cldTestAxis( v0, v1, v2, vAxis, 10)) { | ||
625 | return FALSE; | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | |||
630 | if (flags & dxTriMeshData::kVert0) | ||
631 | { | ||
632 | // first vertex on triangle | ||
633 | // axis ((V0-Cp0) x C) x C | ||
634 | _CalculateAxis(v0,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); | ||
635 | //vAxis = ( ( v0-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; | ||
636 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
637 | if (!_cldTestAxis( v0, v1, v2, vAxis, 11)) { | ||
638 | return FALSE; | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | |||
643 | if (flags & dxTriMeshData::kVert1) | ||
644 | { | ||
645 | // second vertex on triangle | ||
646 | // axis ((V1-Cp0) x C) x C | ||
647 | _CalculateAxis(v1,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); | ||
648 | //vAxis = ( ( v1-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; | ||
649 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
650 | if (!_cldTestAxis( v0, v1, v2, vAxis, 12)) { | ||
651 | return FALSE; | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | |||
656 | if (flags & dxTriMeshData::kVert2) | ||
657 | { | ||
658 | // third vertex on triangle | ||
659 | // axis ((V2-Cp0) x C) x C | ||
660 | _CalculateAxis(v2,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); | ||
661 | //vAxis = ( ( v2-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; | ||
662 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
663 | if (!_cldTestAxis( v0, v1, v2, vAxis, 13)) { | ||
664 | return FALSE; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
669 | // Test as separating axes direction vectors between each triangle | ||
670 | // edge and each capsule's cap center | ||
671 | |||
672 | if (flags & dxTriMeshData::kVert0) | ||
673 | { | ||
674 | // first triangle vertex and first capsule point | ||
675 | //vAxis = v0 - vCp0; | ||
676 | SUBTRACT(v0,vCp0,vAxis); | ||
677 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
678 | if (!_cldTestAxis( v0, v1, v2, vAxis, 14)) { | ||
679 | return FALSE; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (flags & dxTriMeshData::kVert1) | ||
685 | { | ||
686 | // second triangle vertex and first capsule point | ||
687 | //vAxis = v1 - vCp0; | ||
688 | SUBTRACT(v1,vCp0,vAxis); | ||
689 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
690 | if (!_cldTestAxis( v0, v1, v2, vAxis, 15)) { | ||
691 | return FALSE; | ||
692 | } | ||
693 | } | ||
694 | } | ||
695 | |||
696 | if (flags & dxTriMeshData::kVert2) | ||
697 | { | ||
698 | // third triangle vertex and first capsule point | ||
699 | //vAxis = v2 - vCp0; | ||
700 | SUBTRACT(v2,vCp0,vAxis); | ||
701 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
702 | if (!_cldTestAxis( v0, v1, v2, vAxis, 16)) { | ||
703 | return FALSE; | ||
704 | } | ||
705 | } | ||
706 | } | ||
707 | |||
708 | if (flags & dxTriMeshData::kVert0) | ||
709 | { | ||
710 | // first triangle vertex and second capsule point | ||
711 | //vAxis = v0 - vCp1; | ||
712 | SUBTRACT(v0,vCp1,vAxis); | ||
713 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
714 | if (!_cldTestAxis( v0, v1, v2, vAxis, 17)) { | ||
715 | return FALSE; | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | |||
720 | if (flags & dxTriMeshData::kVert1) | ||
721 | { | ||
722 | // second triangle vertex and second capsule point | ||
723 | //vAxis = v1 - vCp1; | ||
724 | SUBTRACT(v1,vCp1,vAxis); | ||
725 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
726 | if (!_cldTestAxis( v0, v1, v2, vAxis, 18)) { | ||
727 | return FALSE; | ||
728 | } | ||
729 | } | ||
730 | } | ||
731 | |||
732 | if (flags & dxTriMeshData::kVert2) | ||
733 | { | ||
734 | // third triangle vertex and second capsule point | ||
735 | //vAxis = v2 - vCp1; | ||
736 | SUBTRACT(v2,vCp1,vAxis); | ||
737 | if(_length2OfVector3( vAxis ) > fEpsilon ) { | ||
738 | if (!_cldTestAxis( v0, v1, v2, vAxis, 19)) { | ||
739 | return FALSE; | ||
740 | } | ||
741 | } | ||
742 | } | ||
743 | |||
744 | return TRUE; | ||
745 | } | ||
746 | |||
747 | // test one mesh triangle on intersection with capsule | ||
748 | static void _cldTestOneTriangleVSCapsule( const dVector3 &v0, | ||
749 | const dVector3 &v1, | ||
750 | const dVector3 &v2, | ||
751 | uint8 flags) | ||
752 | { | ||
753 | |||
754 | // calculate edges | ||
755 | SUBTRACT(v1,v0,vE0); | ||
756 | SUBTRACT(v2,v1,vE1); | ||
757 | SUBTRACT(v0,v2,vE2); | ||
758 | |||
759 | dVector3 _minus_vE0; | ||
760 | SUBTRACT(v0,v1,_minus_vE0); | ||
761 | |||
762 | // calculate poly normal | ||
763 | dCROSS(vN,=,vE1,_minus_vE0); | ||
764 | dNormalize3(vN); | ||
765 | |||
766 | // create plane from triangle | ||
767 | dReal plDistance = -dDOT(v0,vN); | ||
768 | dVector4 plTrianglePlane; | ||
769 | CONSTRUCTPLANE(plTrianglePlane,vN,plDistance); | ||
770 | |||
771 | // calculate capsule distance to plane | ||
772 | dReal fDistanceCapsuleCenterToPlane = POINTDISTANCE(plTrianglePlane,vCapsulePosition); | ||
773 | |||
774 | // Capsule must be over positive side of triangle | ||
775 | if(fDistanceCapsuleCenterToPlane < 0 /* && !bDoubleSided*/) | ||
776 | { | ||
777 | // if not don't generate contacts | ||
778 | return; | ||
779 | } | ||
780 | |||
781 | dVector3 vPnt0; | ||
782 | SET (vPnt0,v0); | ||
783 | dVector3 vPnt1; | ||
784 | SET (vPnt1,v1); | ||
785 | dVector3 vPnt2; | ||
786 | SET (vPnt2,v2); | ||
787 | |||
788 | if (fDistanceCapsuleCenterToPlane < 0 ) | ||
789 | { | ||
790 | SET (vPnt0,v0); | ||
791 | SET (vPnt1,v2); | ||
792 | SET (vPnt2,v1); | ||
793 | } | ||
794 | |||
795 | // do intersection test and find best separating axis | ||
796 | if(!_cldTestSeparatingAxesOfCapsule(vPnt0, vPnt1, vPnt2, flags) ) | ||
797 | { | ||
798 | // if not found do nothing | ||
799 | return; | ||
800 | } | ||
801 | |||
802 | // if best separation axis is not found | ||
803 | if ( iBestAxis == 0 ) | ||
804 | { | ||
805 | // this should not happen (we should already exit in that case) | ||
806 | dIASSERT(FALSE); | ||
807 | // do nothing | ||
808 | return; | ||
809 | } | ||
810 | |||
811 | // calculate caps centers in absolute space | ||
812 | dVector3 vCposTrans; | ||
813 | vCposTrans[0] = vCapsulePosition[0] + vNormal[0]*vCapsuleRadius; | ||
814 | vCposTrans[1] = vCapsulePosition[1] + vNormal[1]*vCapsuleRadius; | ||
815 | vCposTrans[2] = vCapsulePosition[2] + vNormal[2]*vCapsuleRadius; | ||
816 | |||
817 | dVector3 vCEdgePoint0; | ||
818 | vCEdgePoint0[0] = vCposTrans[0] + vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
819 | vCEdgePoint0[1] = vCposTrans[1] + vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
820 | vCEdgePoint0[2] = vCposTrans[2] + vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
821 | |||
822 | dVector3 vCEdgePoint1; | ||
823 | vCEdgePoint1[0] = vCposTrans[0] - vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
824 | vCEdgePoint1[1] = vCposTrans[1] - vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
825 | vCEdgePoint1[2] = vCposTrans[2] - vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); | ||
826 | |||
827 | // transform capsule edge points into triangle space | ||
828 | vCEdgePoint0[0] -= vPnt0[0]; | ||
829 | vCEdgePoint0[1] -= vPnt0[1]; | ||
830 | vCEdgePoint0[2] -= vPnt0[2]; | ||
831 | |||
832 | vCEdgePoint1[0] -= vPnt0[0]; | ||
833 | vCEdgePoint1[1] -= vPnt0[1]; | ||
834 | vCEdgePoint1[2] -= vPnt0[2]; | ||
835 | |||
836 | dVector4 plPlane; | ||
837 | dVector3 _minus_vN; | ||
838 | _minus_vN[0] = -vN[0]; | ||
839 | _minus_vN[1] = -vN[1]; | ||
840 | _minus_vN[2] = -vN[2]; | ||
841 | // triangle plane | ||
842 | CONSTRUCTPLANE(plPlane,_minus_vN,0); | ||
843 | //plPlane = Plane4f( -vN, 0); | ||
844 | |||
845 | if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
846 | { | ||
847 | return; | ||
848 | } | ||
849 | |||
850 | // plane with edge 0 | ||
851 | dVector3 vTemp; | ||
852 | dCROSS(vTemp,=,vN,vE0); | ||
853 | CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5)); | ||
854 | if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
855 | { | ||
856 | return; | ||
857 | } | ||
858 | |||
859 | dCROSS(vTemp,=,vN,vE1); | ||
860 | CONSTRUCTPLANE(plPlane, vTemp, -(dDOT(vE0,vTemp)-REAL(1e-5))); | ||
861 | if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
862 | { | ||
863 | return; | ||
864 | } | ||
865 | |||
866 | dCROSS(vTemp,=,vN,vE2); | ||
867 | CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5)); | ||
868 | if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) { | ||
869 | return; | ||
870 | } | ||
871 | |||
872 | // return capsule edge points into absolute space | ||
873 | vCEdgePoint0[0] += vPnt0[0]; | ||
874 | vCEdgePoint0[1] += vPnt0[1]; | ||
875 | vCEdgePoint0[2] += vPnt0[2]; | ||
876 | |||
877 | vCEdgePoint1[0] += vPnt0[0]; | ||
878 | vCEdgePoint1[1] += vPnt0[1]; | ||
879 | vCEdgePoint1[2] += vPnt0[2]; | ||
880 | |||
881 | // calculate depths for both contact points | ||
882 | SUBTRACT(vCEdgePoint0,vCapsulePosition,vTemp); | ||
883 | dReal fDepth0 = dDOT(vTemp,vNormal) - (fBestCenter-fBestrt); | ||
884 | SUBTRACT(vCEdgePoint1,vCapsulePosition,vTemp); | ||
885 | dReal fDepth1 = dDOT(vTemp,vNormal) - (fBestCenter-fBestrt); | ||
886 | |||
887 | // clamp depths to zero | ||
888 | if(fDepth0 < 0) | ||
889 | { | ||
890 | fDepth0 = 0.0f; | ||
891 | } | ||
892 | |||
893 | if(fDepth1 < 0 ) | ||
894 | { | ||
895 | fDepth1 = 0.0f; | ||
896 | } | ||
897 | |||
898 | // Cached contacts's data | ||
899 | // contact 0 | ||
900 | dIASSERT(ctContacts < (iFlags & NUMC_MASK)); // Do not call function if there is no room to store result | ||
901 | gLocalContacts[ctContacts].fDepth = fDepth0; | ||
902 | SET(gLocalContacts[ctContacts].vNormal,vNormal); | ||
903 | SET(gLocalContacts[ctContacts].vPos,vCEdgePoint0); | ||
904 | gLocalContacts[ctContacts].nFlags = 1; | ||
905 | ctContacts++; | ||
906 | |||
907 | if (ctContacts < (iFlags & NUMC_MASK)) { | ||
908 | // contact 1 | ||
909 | gLocalContacts[ctContacts].fDepth = fDepth1; | ||
910 | SET(gLocalContacts[ctContacts].vNormal,vNormal); | ||
911 | SET(gLocalContacts[ctContacts].vPos,vCEdgePoint1); | ||
912 | gLocalContacts[ctContacts].nFlags = 1; | ||
913 | ctContacts++; | ||
914 | } | ||
915 | |||
916 | } | ||
917 | |||
918 | // capsule - trimesh by CroTeam | ||
919 | // Ported by Nguyem Binh | ||
920 | int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
921 | { | ||
922 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
923 | dIASSERT (o1->type == dTriMeshClass); | ||
924 | dIASSERT (o2->type == dCapsuleClass); | ||
925 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
926 | |||
927 | dxTriMesh* TriMesh = (dxTriMesh*)o1; | ||
928 | gCylinder = o2; | ||
929 | gTriMesh = o1; | ||
930 | |||
931 | const dMatrix3* pRot = (const dMatrix3*) dGeomGetRotation(gCylinder); | ||
932 | memcpy(mCapsuleRotation,pRot,sizeof(dMatrix3)); | ||
933 | |||
934 | const dVector3* pDst = (const dVector3*)dGeomGetPosition(gCylinder); | ||
935 | memcpy(vCapsulePosition,pDst,sizeof(dVector3)); | ||
936 | |||
937 | vCapsuleAxis[0] = mCapsuleRotation[0*4 + nCAPSULE_AXIS]; | ||
938 | vCapsuleAxis[1] = mCapsuleRotation[1*4 + nCAPSULE_AXIS]; | ||
939 | vCapsuleAxis[2] = mCapsuleRotation[2*4 + nCAPSULE_AXIS]; | ||
940 | |||
941 | // Get size of Capsule | ||
942 | dGeomCapsuleGetParams(gCylinder,&vCapsuleRadius,&fCapsuleSize); | ||
943 | fCapsuleSize += 2*vCapsuleRadius; | ||
944 | |||
945 | const dMatrix3* pTriRot = (const dMatrix3*)dGeomGetRotation(TriMesh); | ||
946 | memcpy(mTriMeshRot,pTriRot,sizeof(dMatrix3)); | ||
947 | |||
948 | const dVector3* pTriPos = (const dVector3*)dGeomGetPosition(TriMesh); | ||
949 | memcpy(mTriMeshPos,pTriPos,sizeof(dVector3)); | ||
950 | |||
951 | // global info for contact creation | ||
952 | iStride =skip; | ||
953 | iFlags =flags; | ||
954 | ContactGeoms =contact; | ||
955 | |||
956 | // reset contact counter | ||
957 | ctContacts = 0; | ||
958 | |||
959 | // reset best depth | ||
960 | fBestDepth = - MAX_REAL; | ||
961 | fBestCenter = 0; | ||
962 | fBestrt = 0; | ||
963 | |||
964 | |||
965 | |||
966 | |||
967 | // reset collision normal | ||
968 | vNormal[0] = REAL(0.0); | ||
969 | vNormal[1] = REAL(0.0); | ||
970 | vNormal[2] = REAL(0.0); | ||
971 | |||
972 | // Will it better to use LSS here? -> confirm Pierre. | ||
973 | OBBCollider& Collider = TriMesh->_OBBCollider; | ||
974 | |||
975 | // It is a potential issue to explicitly cast to float | ||
976 | // if custom width floating point type is introduced in OPCODE. | ||
977 | // It is necessary to make a typedef and cast to it | ||
978 | // (e.g. typedef float opc_float;) | ||
979 | // However I'm not sure in what header it should be added. | ||
980 | |||
981 | Point cCenter(/*(float)*/ vCapsulePosition[0], /*(float)*/ vCapsulePosition[1], /*(float)*/ vCapsulePosition[2]); | ||
982 | Point cExtents(/*(float)*/ vCapsuleRadius, /*(float)*/ vCapsuleRadius,/*(float)*/ fCapsuleSize/2); | ||
983 | |||
984 | Matrix3x3 obbRot; | ||
985 | |||
986 | obbRot[0][0] = /*(float)*/ mCapsuleRotation[0]; | ||
987 | obbRot[1][0] = /*(float)*/ mCapsuleRotation[1]; | ||
988 | obbRot[2][0] = /*(float)*/ mCapsuleRotation[2]; | ||
989 | |||
990 | obbRot[0][1] = /*(float)*/ mCapsuleRotation[4]; | ||
991 | obbRot[1][1] = /*(float)*/ mCapsuleRotation[5]; | ||
992 | obbRot[2][1] = /*(float)*/ mCapsuleRotation[6]; | ||
993 | |||
994 | obbRot[0][2] = /*(float)*/ mCapsuleRotation[8]; | ||
995 | obbRot[1][2] = /*(float)*/ mCapsuleRotation[9]; | ||
996 | obbRot[2][2] = /*(float)*/ mCapsuleRotation[10]; | ||
997 | |||
998 | OBB obbCapsule(cCenter,cExtents,obbRot); | ||
999 | |||
1000 | Matrix4x4 CapsuleMatrix; | ||
1001 | MakeMatrix(vCapsulePosition, mCapsuleRotation, CapsuleMatrix); | ||
1002 | |||
1003 | Matrix4x4 MeshMatrix; | ||
1004 | MakeMatrix(mTriMeshPos, mTriMeshRot, MeshMatrix); | ||
1005 | |||
1006 | // TC results | ||
1007 | if (TriMesh->doBoxTC) { | ||
1008 | dxTriMesh::BoxTC* BoxTC = 0; | ||
1009 | for (int i = 0; i < TriMesh->BoxTCCache.size(); i++){ | ||
1010 | if (TriMesh->BoxTCCache[i].Geom == gCylinder){ | ||
1011 | BoxTC = &TriMesh->BoxTCCache[i]; | ||
1012 | break; | ||
1013 | } | ||
1014 | } | ||
1015 | if (!BoxTC){ | ||
1016 | TriMesh->BoxTCCache.push(dxTriMesh::BoxTC()); | ||
1017 | |||
1018 | BoxTC = &TriMesh->BoxTCCache[TriMesh->BoxTCCache.size() - 1]; | ||
1019 | BoxTC->Geom = gCylinder; | ||
1020 | BoxTC->FatCoeff = 1.0f; | ||
1021 | } | ||
1022 | |||
1023 | // Intersect | ||
1024 | Collider.SetTemporalCoherence(true); | ||
1025 | Collider.Collide(*BoxTC, obbCapsule, TriMesh->Data->BVTree, null, &MeshMatrix); | ||
1026 | } | ||
1027 | else { | ||
1028 | Collider.SetTemporalCoherence(false); | ||
1029 | Collider.Collide(dxTriMesh::defaultBoxCache, obbCapsule, TriMesh->Data->BVTree, null,&MeshMatrix); | ||
1030 | } | ||
1031 | |||
1032 | if (! Collider.GetContactStatus()) { | ||
1033 | // no collision occurred | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | // Retrieve data | ||
1038 | int TriCount = Collider.GetNbTouchedPrimitives(); | ||
1039 | const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); | ||
1040 | |||
1041 | if (TriCount != 0) | ||
1042 | { | ||
1043 | if (TriMesh->ArrayCallback != null) | ||
1044 | { | ||
1045 | TriMesh->ArrayCallback(TriMesh, gCylinder, Triangles, TriCount); | ||
1046 | } | ||
1047 | |||
1048 | // allocate buffer for local contacts on stack | ||
1049 | gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(iFlags & NUMC_MASK)); | ||
1050 | |||
1051 | unsigned int ctContacts0 = ctContacts; | ||
1052 | |||
1053 | uint8* UseFlags = TriMesh->Data->UseFlags; | ||
1054 | |||
1055 | // loop through all intersecting triangles | ||
1056 | for (int i = 0; i < TriCount; i++) | ||
1057 | { | ||
1058 | const int Triint = Triangles[i]; | ||
1059 | if (!Callback(TriMesh, gCylinder, Triint)) continue; | ||
1060 | |||
1061 | |||
1062 | dVector3 dv[3]; | ||
1063 | FetchTriangle(TriMesh, Triint, mTriMeshPos, mTriMeshRot, dv); | ||
1064 | |||
1065 | uint8 flags = UseFlags ? UseFlags[Triint] : dxTriMeshData::kUseAll; | ||
1066 | |||
1067 | // test this triangle | ||
1068 | _cldTestOneTriangleVSCapsule(dv[0],dv[1],dv[2], flags); | ||
1069 | |||
1070 | // fill-in tri index for generated contacts | ||
1071 | for (; ctContacts0<ctContacts; ctContacts0++) | ||
1072 | gLocalContacts[ctContacts0].triIndex = Triint; | ||
1073 | |||
1074 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1075 | if(ctContacts>=(iFlags & NUMC_MASK)) | ||
1076 | { | ||
1077 | break; | ||
1078 | } | ||
1079 | |||
1080 | } | ||
1081 | } | ||
1082 | |||
1083 | return _ProcessLocalContacts(); | ||
1084 | } | ||
1085 | #endif | ||
1086 | |||
1087 | // GIMPACT version | ||
1088 | #if dTRIMESH_GIMPACT | ||
1089 | #define nCAPSULE_AXIS 2 | ||
1090 | // capsule - trimesh By francisco leon | ||
1091 | int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
1092 | { | ||
1093 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
1094 | dIASSERT (o1->type == dTriMeshClass); | ||
1095 | dIASSERT (o2->type == dCapsuleClass); | ||
1096 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1097 | |||
1098 | dxTriMesh* TriMesh = (dxTriMesh*)o1; | ||
1099 | dxGeom* gCylinder = o2; | ||
1100 | |||
1101 | //Get capsule params | ||
1102 | dMatrix3 mCapsuleRotation; | ||
1103 | dVector3 vCapsulePosition; | ||
1104 | dVector3 vCapsuleAxis; | ||
1105 | dReal vCapsuleRadius; | ||
1106 | dReal fCapsuleSize; | ||
1107 | dMatrix3* pRot = (dMatrix3*) dGeomGetRotation(gCylinder); | ||
1108 | memcpy(mCapsuleRotation,pRot,sizeof(dMatrix3)); | ||
1109 | dVector3* pDst = (dVector3*)dGeomGetPosition(gCylinder); | ||
1110 | memcpy(vCapsulePosition,pDst,sizeof(dVector3)); | ||
1111 | //Axis | ||
1112 | vCapsuleAxis[0] = mCapsuleRotation[0*4 + nCAPSULE_AXIS]; | ||
1113 | vCapsuleAxis[1] = mCapsuleRotation[1*4 + nCAPSULE_AXIS]; | ||
1114 | vCapsuleAxis[2] = mCapsuleRotation[2*4 + nCAPSULE_AXIS]; | ||
1115 | // Get size of CCylinder | ||
1116 | dGeomCCylinderGetParams(gCylinder,&vCapsuleRadius,&fCapsuleSize); | ||
1117 | fCapsuleSize*=0.5f; | ||
1118 | //Set Capsule params | ||
1119 | GIM_CAPSULE_DATA capsule; | ||
1120 | |||
1121 | capsule.m_radius = vCapsuleRadius; | ||
1122 | VEC_SCALE(capsule.m_point1,fCapsuleSize,vCapsuleAxis); | ||
1123 | VEC_SUM(capsule.m_point1,vCapsulePosition,capsule.m_point1); | ||
1124 | VEC_SCALE(capsule.m_point2,-fCapsuleSize,vCapsuleAxis); | ||
1125 | VEC_SUM(capsule.m_point2,vCapsulePosition,capsule.m_point2); | ||
1126 | |||
1127 | |||
1128 | //Create contact list | ||
1129 | GDYNAMIC_ARRAY trimeshcontacts; | ||
1130 | GIM_CREATE_CONTACT_LIST(trimeshcontacts); | ||
1131 | |||
1132 | //Collide trimeshe vs capsule | ||
1133 | gim_trimesh_capsule_collision(&TriMesh->m_collision_trimesh,&capsule,&trimeshcontacts); | ||
1134 | |||
1135 | |||
1136 | if(trimeshcontacts.m_size == 0) | ||
1137 | { | ||
1138 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); | ||
1143 | |||
1144 | unsigned contactcount = trimeshcontacts.m_size; | ||
1145 | unsigned contactmax = (unsigned)(flags & NUMC_MASK); | ||
1146 | if (contactcount > contactmax) | ||
1147 | { | ||
1148 | contactcount = contactmax; | ||
1149 | } | ||
1150 | |||
1151 | dContactGeom* pcontact; | ||
1152 | unsigned i; | ||
1153 | |||
1154 | for (i=0;i<contactcount;i++) | ||
1155 | { | ||
1156 | pcontact = SAFECONTACT(flags, contact, i, skip); | ||
1157 | |||
1158 | pcontact->pos[0] = ptrimeshcontacts->m_point[0]; | ||
1159 | pcontact->pos[1] = ptrimeshcontacts->m_point[1]; | ||
1160 | pcontact->pos[2] = ptrimeshcontacts->m_point[2]; | ||
1161 | pcontact->pos[3] = 1.0f; | ||
1162 | |||
1163 | pcontact->normal[0] = ptrimeshcontacts->m_normal[0]; | ||
1164 | pcontact->normal[1] = ptrimeshcontacts->m_normal[1]; | ||
1165 | pcontact->normal[2] = ptrimeshcontacts->m_normal[2]; | ||
1166 | pcontact->normal[3] = 0; | ||
1167 | |||
1168 | pcontact->depth = ptrimeshcontacts->m_depth; | ||
1169 | pcontact->g1 = TriMesh; | ||
1170 | pcontact->g2 = gCylinder; | ||
1171 | |||
1172 | ptrimeshcontacts++; | ||
1173 | } | ||
1174 | |||
1175 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
1176 | |||
1177 | return (int)contactcount; | ||
1178 | } | ||
1179 | #endif | ||
1180 | |||
1181 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_distance.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_distance.cpp new file mode 100755 index 0000000..717c763 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_distance.cpp | |||
@@ -0,0 +1,1255 @@ | |||
1 | // This file contains some code based on the code from Magic Software. | ||
2 | // That code is available under a Free Source License Agreement | ||
3 | // that can be found at http://www.magic-software.com/License/free.pdf | ||
4 | |||
5 | #include <ode/common.h> | ||
6 | #include <ode/odemath.h> | ||
7 | #include <ode/collision.h> | ||
8 | #define TRIMESH_INTERNAL | ||
9 | #include "collision_trimesh_internal.h" | ||
10 | |||
11 | //------------------------------------------------------------------------------ | ||
12 | /** | ||
13 | @brief Finds the shortest distance squared between a point and a triangle. | ||
14 | |||
15 | @param pfSParam Barycentric coordinate of triangle at point closest to p (u) | ||
16 | @param pfTParam Barycentric coordinate of triangle at point closest to p (v) | ||
17 | @return Shortest distance squared. | ||
18 | |||
19 | The third Barycentric coordinate is implicit, ie. w = 1.0 - u - v | ||
20 | |||
21 | Taken from: | ||
22 | Magic Software, Inc. | ||
23 | http://www.magic-software.com | ||
24 | */ | ||
25 | dReal SqrDistancePointTri( const dVector3 p, const dVector3 triOrigin, | ||
26 | const dVector3 triEdge0, const dVector3 triEdge1, | ||
27 | dReal* pfSParam, dReal* pfTParam ) | ||
28 | { | ||
29 | dVector3 kDiff; | ||
30 | Vector3Subtract( triOrigin, p, kDiff ); | ||
31 | dReal fA00 = dDOT( triEdge0, triEdge0 ); | ||
32 | dReal fA01 = dDOT( triEdge0, triEdge1 ); | ||
33 | dReal fA11 = dDOT( triEdge1, triEdge1 ); | ||
34 | dReal fB0 = dDOT( kDiff, triEdge0 ); | ||
35 | dReal fB1 = dDOT( kDiff, triEdge1 ); | ||
36 | dReal fC = dDOT( kDiff, kDiff ); | ||
37 | dReal fDet = dReal(fabs(fA00*fA11-fA01*fA01)); | ||
38 | dReal fS = fA01*fB1-fA11*fB0; | ||
39 | dReal fT = fA01*fB0-fA00*fB1; | ||
40 | dReal fSqrDist; | ||
41 | |||
42 | if ( fS + fT <= fDet ) | ||
43 | { | ||
44 | if ( fS < REAL(0.0) ) | ||
45 | { | ||
46 | if ( fT < REAL(0.0) ) // region 4 | ||
47 | { | ||
48 | if ( fB0 < REAL(0.0) ) | ||
49 | { | ||
50 | fT = REAL(0.0); | ||
51 | if ( -fB0 >= fA00 ) | ||
52 | { | ||
53 | fS = REAL(1.0); | ||
54 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
55 | } | ||
56 | else | ||
57 | { | ||
58 | fS = -fB0/fA00; | ||
59 | fSqrDist = fB0*fS+fC; | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | fS = REAL(0.0); | ||
65 | if ( fB1 >= REAL(0.0) ) | ||
66 | { | ||
67 | fT = REAL(0.0); | ||
68 | fSqrDist = fC; | ||
69 | } | ||
70 | else if ( -fB1 >= fA11 ) | ||
71 | { | ||
72 | fT = REAL(1.0); | ||
73 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
74 | } | ||
75 | else | ||
76 | { | ||
77 | fT = -fB1/fA11; | ||
78 | fSqrDist = fB1*fT+fC; | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | else // region 3 | ||
83 | { | ||
84 | fS = REAL(0.0); | ||
85 | if ( fB1 >= REAL(0.0) ) | ||
86 | { | ||
87 | fT = REAL(0.0); | ||
88 | fSqrDist = fC; | ||
89 | } | ||
90 | else if ( -fB1 >= fA11 ) | ||
91 | { | ||
92 | fT = REAL(1.0); | ||
93 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
94 | } | ||
95 | else | ||
96 | { | ||
97 | fT = -fB1/fA11; | ||
98 | fSqrDist = fB1*fT+fC; | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | else if ( fT < REAL(0.0) ) // region 5 | ||
103 | { | ||
104 | fT = REAL(0.0); | ||
105 | if ( fB0 >= REAL(0.0) ) | ||
106 | { | ||
107 | fS = REAL(0.0); | ||
108 | fSqrDist = fC; | ||
109 | } | ||
110 | else if ( -fB0 >= fA00 ) | ||
111 | { | ||
112 | fS = REAL(1.0); | ||
113 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
114 | } | ||
115 | else | ||
116 | { | ||
117 | fS = -fB0/fA00; | ||
118 | fSqrDist = fB0*fS+fC; | ||
119 | } | ||
120 | } | ||
121 | else // region 0 | ||
122 | { | ||
123 | // minimum at interior point | ||
124 | if ( fDet == REAL(0.0) ) | ||
125 | { | ||
126 | fS = REAL(0.0); | ||
127 | fT = REAL(0.0); | ||
128 | fSqrDist = dInfinity; | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | dReal fInvDet = REAL(1.0)/fDet; | ||
133 | fS *= fInvDet; | ||
134 | fT *= fInvDet; | ||
135 | fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + | ||
136 | fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | dReal fTmp0, fTmp1, fNumer, fDenom; | ||
143 | |||
144 | if ( fS < REAL(0.0) ) // region 2 | ||
145 | { | ||
146 | fTmp0 = fA01 + fB0; | ||
147 | fTmp1 = fA11 + fB1; | ||
148 | if ( fTmp1 > fTmp0 ) | ||
149 | { | ||
150 | fNumer = fTmp1 - fTmp0; | ||
151 | fDenom = fA00-REAL(2.0)*fA01+fA11; | ||
152 | if ( fNumer >= fDenom ) | ||
153 | { | ||
154 | fS = REAL(1.0); | ||
155 | fT = REAL(0.0); | ||
156 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
157 | } | ||
158 | else | ||
159 | { | ||
160 | fS = fNumer/fDenom; | ||
161 | fT = REAL(1.0) - fS; | ||
162 | fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + | ||
163 | fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; | ||
164 | } | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | fS = REAL(0.0); | ||
169 | if ( fTmp1 <= REAL(0.0) ) | ||
170 | { | ||
171 | fT = REAL(1.0); | ||
172 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
173 | } | ||
174 | else if ( fB1 >= REAL(0.0) ) | ||
175 | { | ||
176 | fT = REAL(0.0); | ||
177 | fSqrDist = fC; | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | fT = -fB1/fA11; | ||
182 | fSqrDist = fB1*fT+fC; | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | else if ( fT < REAL(0.0) ) // region 6 | ||
187 | { | ||
188 | fTmp0 = fA01 + fB1; | ||
189 | fTmp1 = fA00 + fB0; | ||
190 | if ( fTmp1 > fTmp0 ) | ||
191 | { | ||
192 | fNumer = fTmp1 - fTmp0; | ||
193 | fDenom = fA00-REAL(2.0)*fA01+fA11; | ||
194 | if ( fNumer >= fDenom ) | ||
195 | { | ||
196 | fT = REAL(1.0); | ||
197 | fS = REAL(0.0); | ||
198 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | fT = fNumer/fDenom; | ||
203 | fS = REAL(1.0) - fT; | ||
204 | fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + | ||
205 | fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; | ||
206 | } | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | fT = REAL(0.0); | ||
211 | if ( fTmp1 <= REAL(0.0) ) | ||
212 | { | ||
213 | fS = REAL(1.0); | ||
214 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
215 | } | ||
216 | else if ( fB0 >= REAL(0.0) ) | ||
217 | { | ||
218 | fS = REAL(0.0); | ||
219 | fSqrDist = fC; | ||
220 | } | ||
221 | else | ||
222 | { | ||
223 | fS = -fB0/fA00; | ||
224 | fSqrDist = fB0*fS+fC; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | else // region 1 | ||
229 | { | ||
230 | fNumer = fA11 + fB1 - fA01 - fB0; | ||
231 | if ( fNumer <= REAL(0.0) ) | ||
232 | { | ||
233 | fS = REAL(0.0); | ||
234 | fT = REAL(1.0); | ||
235 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | fDenom = fA00-REAL(2.0)*fA01+fA11; | ||
240 | if ( fNumer >= fDenom ) | ||
241 | { | ||
242 | fS = REAL(1.0); | ||
243 | fT = REAL(0.0); | ||
244 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | fS = fNumer/fDenom; | ||
249 | fT = REAL(1.0) - fS; | ||
250 | fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + | ||
251 | fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if ( pfSParam ) | ||
258 | *pfSParam = (float)fS; | ||
259 | |||
260 | if ( pfTParam ) | ||
261 | *pfTParam = (float)fT; | ||
262 | |||
263 | return dReal(fabs(fSqrDist)); | ||
264 | } | ||
265 | |||
266 | //------------------------------------------------------------------------------ | ||
267 | /** | ||
268 | @brief Finds the shortest distance squared between two line segments. | ||
269 | @param pfSegP0 t value for seg1 where the shortest distance between | ||
270 | the segments exists. | ||
271 | @param pfSegP0 t value for seg2 where the shortest distance between | ||
272 | the segments exists. | ||
273 | @return Shortest distance squared. | ||
274 | |||
275 | Taken from: | ||
276 | Magic Software, Inc. | ||
277 | http://www.magic-software.com | ||
278 | */ | ||
279 | dReal SqrDistanceSegments( const dVector3 seg1Origin, const dVector3 seg1Direction, | ||
280 | const dVector3 seg2Origin, const dVector3 seg2Direction, | ||
281 | dReal* pfSegP0, dReal* pfSegP1 ) | ||
282 | { | ||
283 | const dReal gs_fTolerance = 1e-05f; | ||
284 | dVector3 kDiff, kNegDiff, seg1NegDirection; | ||
285 | Vector3Subtract( seg1Origin, seg2Origin, kDiff ); | ||
286 | Vector3Negate( kDiff, kNegDiff ); | ||
287 | dReal fA00 = dDOT( seg1Direction, seg1Direction ); | ||
288 | Vector3Negate( seg1Direction, seg1NegDirection ); | ||
289 | dReal fA01 = dDOT( seg1NegDirection, seg2Direction ); | ||
290 | dReal fA11 = dDOT( seg2Direction, seg2Direction ); | ||
291 | dReal fB0 = dDOT( kDiff, seg1Direction ); | ||
292 | dReal fC = dDOT( kDiff, kDiff ); | ||
293 | dReal fDet = dReal(fabs(fA00*fA11-fA01*fA01)); | ||
294 | dReal fB1, fS, fT, fSqrDist, fTmp; | ||
295 | |||
296 | if ( fDet >= gs_fTolerance ) | ||
297 | { | ||
298 | // line segments are not parallel | ||
299 | fB1 = dDOT( kNegDiff, seg2Direction ); | ||
300 | fS = fA01*fB1-fA11*fB0; | ||
301 | fT = fA01*fB0-fA00*fB1; | ||
302 | |||
303 | if ( fS >= REAL(0.0) ) | ||
304 | { | ||
305 | if ( fS <= fDet ) | ||
306 | { | ||
307 | if ( fT >= REAL(0.0) ) | ||
308 | { | ||
309 | if ( fT <= fDet ) // region 0 (interior) | ||
310 | { | ||
311 | // minimum at two interior points of 3D lines | ||
312 | dReal fInvDet = REAL(1.0)/fDet; | ||
313 | fS *= fInvDet; | ||
314 | fT *= fInvDet; | ||
315 | fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + | ||
316 | fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; | ||
317 | } | ||
318 | else // region 3 (side) | ||
319 | { | ||
320 | fT = REAL(1.0); | ||
321 | fTmp = fA01+fB0; | ||
322 | if ( fTmp >= REAL(0.0) ) | ||
323 | { | ||
324 | fS = REAL(0.0); | ||
325 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
326 | } | ||
327 | else if ( -fTmp >= fA00 ) | ||
328 | { | ||
329 | fS = REAL(1.0); | ||
330 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB1+fTmp); | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | fS = -fTmp/fA00; | ||
335 | fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | else // region 7 (side) | ||
340 | { | ||
341 | fT = REAL(0.0); | ||
342 | if ( fB0 >= REAL(0.0) ) | ||
343 | { | ||
344 | fS = REAL(0.0); | ||
345 | fSqrDist = fC; | ||
346 | } | ||
347 | else if ( -fB0 >= fA00 ) | ||
348 | { | ||
349 | fS = REAL(1.0); | ||
350 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | fS = -fB0/fA00; | ||
355 | fSqrDist = fB0*fS+fC; | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | if ( fT >= REAL(0.0) ) | ||
362 | { | ||
363 | if ( fT <= fDet ) // region 1 (side) | ||
364 | { | ||
365 | fS = REAL(1.0); | ||
366 | fTmp = fA01+fB1; | ||
367 | if ( fTmp >= REAL(0.0) ) | ||
368 | { | ||
369 | fT = REAL(0.0); | ||
370 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
371 | } | ||
372 | else if ( -fTmp >= fA11 ) | ||
373 | { | ||
374 | fT = REAL(1.0); | ||
375 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | fT = -fTmp/fA11; | ||
380 | fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; | ||
381 | } | ||
382 | } | ||
383 | else // region 2 (corner) | ||
384 | { | ||
385 | fTmp = fA01+fB0; | ||
386 | if ( -fTmp <= fA00 ) | ||
387 | { | ||
388 | fT = REAL(1.0); | ||
389 | if ( fTmp >= REAL(0.0) ) | ||
390 | { | ||
391 | fS = REAL(0.0); | ||
392 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | fS = -fTmp/fA00; | ||
397 | fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; | ||
398 | } | ||
399 | } | ||
400 | else | ||
401 | { | ||
402 | fS = REAL(1.0); | ||
403 | fTmp = fA01+fB1; | ||
404 | if ( fTmp >= REAL(0.0) ) | ||
405 | { | ||
406 | fT = REAL(0.0); | ||
407 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
408 | } | ||
409 | else if ( -fTmp >= fA11 ) | ||
410 | { | ||
411 | fT = REAL(1.0); | ||
412 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); | ||
413 | } | ||
414 | else | ||
415 | { | ||
416 | fT = -fTmp/fA11; | ||
417 | fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | else // region 8 (corner) | ||
423 | { | ||
424 | if ( -fB0 < fA00 ) | ||
425 | { | ||
426 | fT = REAL(0.0); | ||
427 | if ( fB0 >= REAL(0.0) ) | ||
428 | { | ||
429 | fS = REAL(0.0); | ||
430 | fSqrDist = fC; | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | fS = -fB0/fA00; | ||
435 | fSqrDist = fB0*fS+fC; | ||
436 | } | ||
437 | } | ||
438 | else | ||
439 | { | ||
440 | fS = REAL(1.0); | ||
441 | fTmp = fA01+fB1; | ||
442 | if ( fTmp >= REAL(0.0) ) | ||
443 | { | ||
444 | fT = REAL(0.0); | ||
445 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
446 | } | ||
447 | else if ( -fTmp >= fA11 ) | ||
448 | { | ||
449 | fT = REAL(1.0); | ||
450 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | fT = -fTmp/fA11; | ||
455 | fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; | ||
456 | } | ||
457 | } | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | else | ||
462 | { | ||
463 | if ( fT >= REAL(0.0) ) | ||
464 | { | ||
465 | if ( fT <= fDet ) // region 5 (side) | ||
466 | { | ||
467 | fS = REAL(0.0); | ||
468 | if ( fB1 >= REAL(0.0) ) | ||
469 | { | ||
470 | fT = REAL(0.0); | ||
471 | fSqrDist = fC; | ||
472 | } | ||
473 | else if ( -fB1 >= fA11 ) | ||
474 | { | ||
475 | fT = REAL(1.0); | ||
476 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | fT = -fB1/fA11; | ||
481 | fSqrDist = fB1*fT+fC; | ||
482 | } | ||
483 | } | ||
484 | else // region 4 (corner) | ||
485 | { | ||
486 | fTmp = fA01+fB0; | ||
487 | if ( fTmp < REAL(0.0) ) | ||
488 | { | ||
489 | fT = REAL(1.0); | ||
490 | if ( -fTmp >= fA00 ) | ||
491 | { | ||
492 | fS = REAL(1.0); | ||
493 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB1+fTmp); | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | fS = -fTmp/fA00; | ||
498 | fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; | ||
499 | } | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | fS = REAL(0.0); | ||
504 | if ( fB1 >= REAL(0.0) ) | ||
505 | { | ||
506 | fT = REAL(0.0); | ||
507 | fSqrDist = fC; | ||
508 | } | ||
509 | else if ( -fB1 >= fA11 ) | ||
510 | { | ||
511 | fT = REAL(1.0); | ||
512 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | fT = -fB1/fA11; | ||
517 | fSqrDist = fB1*fT+fC; | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | else // region 6 (corner) | ||
523 | { | ||
524 | if ( fB0 < REAL(0.0) ) | ||
525 | { | ||
526 | fT = REAL(0.0); | ||
527 | if ( -fB0 >= fA00 ) | ||
528 | { | ||
529 | fS = REAL(1.0); | ||
530 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | fS = -fB0/fA00; | ||
535 | fSqrDist = fB0*fS+fC; | ||
536 | } | ||
537 | } | ||
538 | else | ||
539 | { | ||
540 | fS = REAL(0.0); | ||
541 | if ( fB1 >= REAL(0.0) ) | ||
542 | { | ||
543 | fT = REAL(0.0); | ||
544 | fSqrDist = fC; | ||
545 | } | ||
546 | else if ( -fB1 >= fA11 ) | ||
547 | { | ||
548 | fT = REAL(1.0); | ||
549 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | fT = -fB1/fA11; | ||
554 | fSqrDist = fB1*fT+fC; | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | } | ||
560 | else | ||
561 | { | ||
562 | // line segments are parallel | ||
563 | if ( fA01 > REAL(0.0) ) | ||
564 | { | ||
565 | // direction vectors form an obtuse angle | ||
566 | if ( fB0 >= REAL(0.0) ) | ||
567 | { | ||
568 | fS = REAL(0.0); | ||
569 | fT = REAL(0.0); | ||
570 | fSqrDist = fC; | ||
571 | } | ||
572 | else if ( -fB0 <= fA00 ) | ||
573 | { | ||
574 | fS = -fB0/fA00; | ||
575 | fT = REAL(0.0); | ||
576 | fSqrDist = fB0*fS+fC; | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | //fB1 = -kDiff % seg2.m; | ||
581 | fB1 = dDOT( kNegDiff, seg2Direction ); | ||
582 | fS = REAL(1.0); | ||
583 | fTmp = fA00+fB0; | ||
584 | if ( -fTmp >= fA01 ) | ||
585 | { | ||
586 | fT = REAL(1.0); | ||
587 | fSqrDist = fA00+fA11+fC+REAL(2.0)*(fA01+fB0+fB1); | ||
588 | } | ||
589 | else | ||
590 | { | ||
591 | fT = -fTmp/fA01; | ||
592 | fSqrDist = fA00+REAL(2.0)*fB0+fC+fT*(fA11*fT+REAL(2.0)*(fA01+fB1)); | ||
593 | } | ||
594 | } | ||
595 | } | ||
596 | else | ||
597 | { | ||
598 | // direction vectors form an acute angle | ||
599 | if ( -fB0 >= fA00 ) | ||
600 | { | ||
601 | fS = REAL(1.0); | ||
602 | fT = REAL(0.0); | ||
603 | fSqrDist = fA00+REAL(2.0)*fB0+fC; | ||
604 | } | ||
605 | else if ( fB0 <= REAL(0.0) ) | ||
606 | { | ||
607 | fS = -fB0/fA00; | ||
608 | fT = REAL(0.0); | ||
609 | fSqrDist = fB0*fS+fC; | ||
610 | } | ||
611 | else | ||
612 | { | ||
613 | fB1 = dDOT( kNegDiff, seg2Direction ); | ||
614 | fS = REAL(0.0); | ||
615 | if ( fB0 >= -fA01 ) | ||
616 | { | ||
617 | fT = REAL(1.0); | ||
618 | fSqrDist = fA11+REAL(2.0)*fB1+fC; | ||
619 | } | ||
620 | else | ||
621 | { | ||
622 | fT = -fB0/fA01; | ||
623 | fSqrDist = fC+fT*(REAL(2.0)*fB1+fA11*fT); | ||
624 | } | ||
625 | } | ||
626 | } | ||
627 | } | ||
628 | |||
629 | if ( pfSegP0 ) | ||
630 | *pfSegP0 = fS; | ||
631 | |||
632 | if ( pfSegP1 ) | ||
633 | *pfSegP1 = fT; | ||
634 | |||
635 | return dReal(fabs(fSqrDist)); | ||
636 | } | ||
637 | |||
638 | //------------------------------------------------------------------------------ | ||
639 | /** | ||
640 | @brief Finds the shortest distance squared between a line segment and | ||
641 | a triangle. | ||
642 | |||
643 | @param pfSegP t value for the line segment where the shortest distance between | ||
644 | the segment and the triangle occurs. | ||
645 | So the point along the segment that is the shortest distance | ||
646 | away from the triangle can be obtained by (seg.end - seg.start) * t. | ||
647 | @param pfTriP0 Barycentric coordinate of triangle at point closest to seg (u) | ||
648 | @param pfTriP1 Barycentric coordinate of triangle at point closest to seg (v) | ||
649 | @return Shortest distance squared. | ||
650 | |||
651 | The third Barycentric coordinate is implicit, ie. w = 1.0 - u - v | ||
652 | |||
653 | Taken from: | ||
654 | Magic Software, Inc. | ||
655 | http://www.magic-software.com | ||
656 | */ | ||
657 | dReal SqrDistanceSegTri( const dVector3 segOrigin, const dVector3 segEnd, | ||
658 | const dVector3 triOrigin, | ||
659 | const dVector3 triEdge0, const dVector3 triEdge1, | ||
660 | dReal* pfSegP, dReal* pfTriP0, dReal* pfTriP1 ) | ||
661 | { | ||
662 | const dReal gs_fTolerance = 1e-06f; | ||
663 | dVector3 segDirection, segNegDirection, kDiff, kNegDiff; | ||
664 | Vector3Subtract( segEnd, segOrigin, segDirection ); | ||
665 | Vector3Negate( segDirection, segNegDirection ); | ||
666 | Vector3Subtract( triOrigin, segOrigin, kDiff ); | ||
667 | Vector3Negate( kDiff, kNegDiff ); | ||
668 | dReal fA00 = dDOT( segDirection, segDirection ); | ||
669 | dReal fA01 = dDOT( segNegDirection, triEdge0 ); | ||
670 | dReal fA02 = dDOT( segNegDirection, triEdge1 ); | ||
671 | dReal fA11 = dDOT( triEdge0, triEdge0 ); | ||
672 | dReal fA12 = dDOT( triEdge0, triEdge1 ); | ||
673 | dReal fA22 = dDOT( triEdge1, triEdge1 ); | ||
674 | dReal fB0 = dDOT( kNegDiff, segDirection ); | ||
675 | dReal fB1 = dDOT( kDiff, triEdge0 ); | ||
676 | dReal fB2 = dDOT( kDiff, triEdge1 ); | ||
677 | |||
678 | dVector3 kTriSegOrigin, kTriSegDirection, kPt; | ||
679 | dReal fSqrDist, fSqrDist0, fR, fS, fT, fR0, fS0, fT0; | ||
680 | |||
681 | // Set up for a relative error test on the angle between ray direction | ||
682 | // and triangle normal to determine parallel/nonparallel status. | ||
683 | dVector3 kN; | ||
684 | dCROSS( kN, =, triEdge0, triEdge1 ); | ||
685 | dReal fNSqrLen = dDOT( kN, kN ); | ||
686 | dReal fDot = dDOT( segDirection, kN ); | ||
687 | bool bNotParallel = (fDot*fDot >= gs_fTolerance*fA00*fNSqrLen); | ||
688 | |||
689 | if ( bNotParallel ) | ||
690 | { | ||
691 | dReal fCof00 = fA11*fA22-fA12*fA12; | ||
692 | dReal fCof01 = fA02*fA12-fA01*fA22; | ||
693 | dReal fCof02 = fA01*fA12-fA02*fA11; | ||
694 | dReal fCof11 = fA00*fA22-fA02*fA02; | ||
695 | dReal fCof12 = fA02*fA01-fA00*fA12; | ||
696 | dReal fCof22 = fA00*fA11-fA01*fA01; | ||
697 | dReal fInvDet = REAL(1.0)/(fA00*fCof00+fA01*fCof01+fA02*fCof02); | ||
698 | dReal fRhs0 = -fB0*fInvDet; | ||
699 | dReal fRhs1 = -fB1*fInvDet; | ||
700 | dReal fRhs2 = -fB2*fInvDet; | ||
701 | |||
702 | fR = fCof00*fRhs0+fCof01*fRhs1+fCof02*fRhs2; | ||
703 | fS = fCof01*fRhs0+fCof11*fRhs1+fCof12*fRhs2; | ||
704 | fT = fCof02*fRhs0+fCof12*fRhs1+fCof22*fRhs2; | ||
705 | |||
706 | if ( fR < REAL(0.0) ) | ||
707 | { | ||
708 | if ( fS+fT <= REAL(1.0) ) | ||
709 | { | ||
710 | if ( fS < REAL(0.0) ) | ||
711 | { | ||
712 | if ( fT < REAL(0.0) ) // region 4m | ||
713 | { | ||
714 | // min on face s=0 or t=0 or r=0 | ||
715 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
716 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
717 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
718 | kTriSegOrigin, kTriSegDirection, | ||
719 | &fR, &fT ); | ||
720 | fS = REAL(0.0); | ||
721 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
722 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
723 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
724 | kTriSegOrigin, kTriSegDirection, | ||
725 | &fR0, &fS0 ); | ||
726 | fT0 = REAL(0.0); | ||
727 | if ( fSqrDist0 < fSqrDist ) | ||
728 | { | ||
729 | fSqrDist = fSqrDist0; | ||
730 | fR = fR0; | ||
731 | fS = fS0; | ||
732 | fT = fT0; | ||
733 | } | ||
734 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
735 | &fS0, &fT0 ); | ||
736 | fR0 = REAL(0.0); | ||
737 | if ( fSqrDist0 < fSqrDist ) | ||
738 | { | ||
739 | fSqrDist = fSqrDist0; | ||
740 | fR = fR0; | ||
741 | fS = fS0; | ||
742 | fT = fT0; | ||
743 | } | ||
744 | } | ||
745 | else // region 3m | ||
746 | { | ||
747 | // min on face s=0 or r=0 | ||
748 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
749 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
750 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
751 | kTriSegOrigin, kTriSegDirection, | ||
752 | &fR,&fT ); | ||
753 | fS = REAL(0.0); | ||
754 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
755 | &fS0, &fT0 ); | ||
756 | fR0 = REAL(0.0); | ||
757 | if ( fSqrDist0 < fSqrDist ) | ||
758 | { | ||
759 | fSqrDist = fSqrDist0; | ||
760 | fR = fR0; | ||
761 | fS = fS0; | ||
762 | fT = fT0; | ||
763 | } | ||
764 | } | ||
765 | } | ||
766 | else if ( fT < REAL(0.0) ) // region 5m | ||
767 | { | ||
768 | // min on face t=0 or r=0 | ||
769 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
770 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
771 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
772 | kTriSegOrigin, kTriSegDirection, | ||
773 | &fR, &fS ); | ||
774 | fT = REAL(0.0); | ||
775 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
776 | &fS0, &fT0 ); | ||
777 | fR0 = REAL(0.0); | ||
778 | if ( fSqrDist0 < fSqrDist ) | ||
779 | { | ||
780 | fSqrDist = fSqrDist0; | ||
781 | fR = fR0; | ||
782 | fS = fS0; | ||
783 | fT = fT0; | ||
784 | } | ||
785 | } | ||
786 | else // region 0m | ||
787 | { | ||
788 | // min on face r=0 | ||
789 | fSqrDist = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
790 | &fS, &fT ); | ||
791 | fR = REAL(0.0); | ||
792 | } | ||
793 | } | ||
794 | else | ||
795 | { | ||
796 | if ( fS < REAL(0.0) ) // region 2m | ||
797 | { | ||
798 | // min on face s=0 or s+t=1 or r=0 | ||
799 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
800 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
801 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
802 | kTriSegOrigin, kTriSegDirection, | ||
803 | &fR, &fT ); | ||
804 | fS = REAL(0.0); | ||
805 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
806 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
807 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
808 | kTriSegOrigin, kTriSegDirection, | ||
809 | &fR0, &fT0 ); | ||
810 | fS0 = REAL(1.0) - fT0; | ||
811 | if ( fSqrDist0 < fSqrDist ) | ||
812 | { | ||
813 | fSqrDist = fSqrDist0; | ||
814 | fR = fR0; | ||
815 | fS = fS0; | ||
816 | fT = fT0; | ||
817 | } | ||
818 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
819 | &fS0, &fT0 ); | ||
820 | fR0 = REAL(0.0); | ||
821 | if ( fSqrDist0 < fSqrDist ) | ||
822 | { | ||
823 | fSqrDist = fSqrDist0; | ||
824 | fR = fR0; | ||
825 | fS = fS0; | ||
826 | fT = fT0; | ||
827 | } | ||
828 | } | ||
829 | else if ( fT < REAL(0.0) ) // region 6m | ||
830 | { | ||
831 | // min on face t=0 or s+t=1 or r=0 | ||
832 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
833 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
834 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
835 | kTriSegOrigin, kTriSegDirection, | ||
836 | &fR, &fS ); | ||
837 | fT = REAL(0.0); | ||
838 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
839 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
840 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
841 | kTriSegOrigin, kTriSegDirection, | ||
842 | &fR0, &fT0 ); | ||
843 | fS0 = REAL(1.0) - fT0; | ||
844 | if ( fSqrDist0 < fSqrDist ) | ||
845 | { | ||
846 | fSqrDist = fSqrDist0; | ||
847 | fR = fR0; | ||
848 | fS = fS0; | ||
849 | fT = fT0; | ||
850 | } | ||
851 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
852 | &fS0, &fT0 ); | ||
853 | fR0 = REAL(0.0); | ||
854 | if ( fSqrDist0 < fSqrDist ) | ||
855 | { | ||
856 | fSqrDist = fSqrDist0; | ||
857 | fR = fR0; | ||
858 | fS = fS0; | ||
859 | fT = fT0; | ||
860 | } | ||
861 | } | ||
862 | else // region 1m | ||
863 | { | ||
864 | // min on face s+t=1 or r=0 | ||
865 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
866 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
867 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
868 | kTriSegOrigin, kTriSegDirection, | ||
869 | &fR, &fT ); | ||
870 | fS = REAL(1.0) - fT; | ||
871 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
872 | &fS0, &fT0 ); | ||
873 | fR0 = REAL(0.0); | ||
874 | if ( fSqrDist0 < fSqrDist ) | ||
875 | { | ||
876 | fSqrDist = fSqrDist0; | ||
877 | fR = fR0; | ||
878 | fS = fS0; | ||
879 | fT = fT0; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | } | ||
884 | else if ( fR <= REAL(1.0) ) | ||
885 | { | ||
886 | if ( fS+fT <= REAL(1.0) ) | ||
887 | { | ||
888 | if ( fS < REAL(0.0) ) | ||
889 | { | ||
890 | if ( fT < REAL(0.0) ) // region 4 | ||
891 | { | ||
892 | // min on face s=0 or t=0 | ||
893 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
894 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
895 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
896 | kTriSegOrigin, kTriSegDirection, | ||
897 | &fR, &fT ); | ||
898 | fS = REAL(0.0); | ||
899 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
900 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
901 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
902 | kTriSegOrigin, kTriSegDirection, | ||
903 | &fR0, &fS0 ); | ||
904 | fT0 = REAL(0.0); | ||
905 | if ( fSqrDist0 < fSqrDist ) | ||
906 | { | ||
907 | fSqrDist = fSqrDist0; | ||
908 | fR = fR0; | ||
909 | fS = fS0; | ||
910 | fT = fT0; | ||
911 | } | ||
912 | } | ||
913 | else // region 3 | ||
914 | { | ||
915 | // min on face s=0 | ||
916 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
917 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
918 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
919 | kTriSegOrigin, kTriSegDirection, | ||
920 | &fR, &fT ); | ||
921 | fS = REAL(0.0); | ||
922 | } | ||
923 | } | ||
924 | else if ( fT < REAL(0.0) ) // region 5 | ||
925 | { | ||
926 | // min on face t=0 | ||
927 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
928 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
929 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
930 | kTriSegOrigin, kTriSegDirection, | ||
931 | &fR, &fS ); | ||
932 | fT = REAL(0.0); | ||
933 | } | ||
934 | else // region 0 | ||
935 | { | ||
936 | // global minimum is interior, done | ||
937 | fSqrDist = REAL(0.0); | ||
938 | } | ||
939 | } | ||
940 | else | ||
941 | { | ||
942 | if ( fS < REAL(0.0) ) // region 2 | ||
943 | { | ||
944 | // min on face s=0 or s+t=1 | ||
945 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
946 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
947 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
948 | kTriSegOrigin, kTriSegDirection, | ||
949 | &fR, &fT ); | ||
950 | fS = REAL(0.0); | ||
951 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
952 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
953 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
954 | kTriSegOrigin, kTriSegDirection, | ||
955 | &fR0, &fT0 ); | ||
956 | fS0 = REAL(1.0) - fT0; | ||
957 | if ( fSqrDist0 < fSqrDist ) | ||
958 | { | ||
959 | fSqrDist = fSqrDist0; | ||
960 | fR = fR0; | ||
961 | fS = fS0; | ||
962 | fT = fT0; | ||
963 | } | ||
964 | } | ||
965 | else if ( fT < REAL(0.0) ) // region 6 | ||
966 | { | ||
967 | // min on face t=0 or s+t=1 | ||
968 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
969 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
970 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
971 | kTriSegOrigin, kTriSegDirection, | ||
972 | &fR, &fS ); | ||
973 | fT = REAL(0.0); | ||
974 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
975 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
976 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
977 | kTriSegOrigin, kTriSegDirection, | ||
978 | &fR0, &fT0 ); | ||
979 | fS0 = REAL(1.0) - fT0; | ||
980 | if ( fSqrDist0 < fSqrDist ) | ||
981 | { | ||
982 | fSqrDist = fSqrDist0; | ||
983 | fR = fR0; | ||
984 | fS = fS0; | ||
985 | fT = fT0; | ||
986 | } | ||
987 | } | ||
988 | else // region 1 | ||
989 | { | ||
990 | // min on face s+t=1 | ||
991 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
992 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
993 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
994 | kTriSegOrigin, kTriSegDirection, | ||
995 | &fR, &fT ); | ||
996 | fS = REAL(1.0) - fT; | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | else // fR > 1 | ||
1001 | { | ||
1002 | if ( fS+fT <= REAL(1.0) ) | ||
1003 | { | ||
1004 | if ( fS < REAL(0.0) ) | ||
1005 | { | ||
1006 | if ( fT < REAL(0.0) ) // region 4p | ||
1007 | { | ||
1008 | // min on face s=0 or t=0 or r=1 | ||
1009 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1010 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
1011 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1012 | kTriSegOrigin, kTriSegDirection, | ||
1013 | &fR, &fT ); | ||
1014 | fS = REAL(0.0); | ||
1015 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1016 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
1017 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
1018 | kTriSegOrigin, kTriSegDirection, | ||
1019 | &fR0, &fS0 ); | ||
1020 | fT0 = REAL(0.0); | ||
1021 | if ( fSqrDist0 < fSqrDist ) | ||
1022 | { | ||
1023 | fSqrDist = fSqrDist0; | ||
1024 | fR = fR0; | ||
1025 | fS = fS0; | ||
1026 | fT = fT0; | ||
1027 | } | ||
1028 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1029 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1030 | &fS0, &fT0 ); | ||
1031 | fR0 = REAL(1.0); | ||
1032 | if ( fSqrDist0 < fSqrDist ) | ||
1033 | { | ||
1034 | fSqrDist = fSqrDist0; | ||
1035 | fR = fR0; | ||
1036 | fS = fS0; | ||
1037 | fT = fT0; | ||
1038 | } | ||
1039 | } | ||
1040 | else // region 3p | ||
1041 | { | ||
1042 | // min on face s=0 or r=1 | ||
1043 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1044 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
1045 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1046 | kTriSegOrigin, kTriSegDirection, | ||
1047 | &fR, &fT ); | ||
1048 | fS = REAL(0.0); | ||
1049 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1050 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1051 | &fS0, &fT0 ); | ||
1052 | fR0 = REAL(1.0); | ||
1053 | if ( fSqrDist0 < fSqrDist ) | ||
1054 | { | ||
1055 | fSqrDist = fSqrDist0; | ||
1056 | fR = fR0; | ||
1057 | fS = fS0; | ||
1058 | fT = fT0; | ||
1059 | } | ||
1060 | } | ||
1061 | } | ||
1062 | else if ( fT < REAL(0.0) ) // region 5p | ||
1063 | { | ||
1064 | // min on face t=0 or r=1 | ||
1065 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1066 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
1067 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1068 | kTriSegOrigin, kTriSegDirection, | ||
1069 | &fR, &fS ); | ||
1070 | fT = REAL(0.0); | ||
1071 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1072 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1073 | &fS0, &fT0 ); | ||
1074 | fR0 = REAL(1.0); | ||
1075 | if ( fSqrDist0 < fSqrDist ) | ||
1076 | { | ||
1077 | fSqrDist = fSqrDist0; | ||
1078 | fR = fR0; | ||
1079 | fS = fS0; | ||
1080 | fT = fT0; | ||
1081 | } | ||
1082 | } | ||
1083 | else // region 0p | ||
1084 | { | ||
1085 | // min face on r=1 | ||
1086 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1087 | fSqrDist = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1088 | &fS, &fT ); | ||
1089 | fR = REAL(1.0); | ||
1090 | } | ||
1091 | } | ||
1092 | else | ||
1093 | { | ||
1094 | if ( fS < REAL(0.0) ) // region 2p | ||
1095 | { | ||
1096 | // min on face s=0 or s+t=1 or r=1 | ||
1097 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1098 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
1099 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1100 | kTriSegOrigin, kTriSegDirection, | ||
1101 | &fR, &fT ); | ||
1102 | fS = REAL(0.0); | ||
1103 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
1104 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
1105 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
1106 | kTriSegOrigin, kTriSegDirection, | ||
1107 | &fR0, &fT0 ); | ||
1108 | fS0 = REAL(1.0) - fT0; | ||
1109 | if ( fSqrDist0 < fSqrDist ) | ||
1110 | { | ||
1111 | fSqrDist = fSqrDist0; | ||
1112 | fR = fR0; | ||
1113 | fS = fS0; | ||
1114 | fT = fT0; | ||
1115 | } | ||
1116 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1117 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1118 | &fS0, &fT0 ); | ||
1119 | fR0 = REAL(1.0); | ||
1120 | if ( fSqrDist0 < fSqrDist ) | ||
1121 | { | ||
1122 | fSqrDist = fSqrDist0; | ||
1123 | fR = fR0; | ||
1124 | fS = fS0; | ||
1125 | fT = fT0; | ||
1126 | } | ||
1127 | } | ||
1128 | else if ( fT < REAL(0.0) ) // region 6p | ||
1129 | { | ||
1130 | // min on face t=0 or s+t=1 or r=1 | ||
1131 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1132 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
1133 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1134 | kTriSegOrigin, kTriSegDirection, | ||
1135 | &fR, &fS ); | ||
1136 | fT = REAL(0.0); | ||
1137 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
1138 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
1139 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
1140 | kTriSegOrigin, kTriSegDirection, | ||
1141 | &fR0, &fT0 ); | ||
1142 | fS0 = REAL(1.0) - fT0; | ||
1143 | if ( fSqrDist0 < fSqrDist ) | ||
1144 | { | ||
1145 | fSqrDist = fSqrDist0; | ||
1146 | fR = fR0; | ||
1147 | fS = fS0; | ||
1148 | fT = fT0; | ||
1149 | } | ||
1150 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1151 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1152 | &fS0, &fT0 ); | ||
1153 | fR0 = REAL(1.0); | ||
1154 | if ( fSqrDist0 < fSqrDist ) | ||
1155 | { | ||
1156 | fSqrDist = fSqrDist0; | ||
1157 | fR = fR0; | ||
1158 | fS = fS0; | ||
1159 | fT = fT0; | ||
1160 | } | ||
1161 | } | ||
1162 | else // region 1p | ||
1163 | { | ||
1164 | // min on face s+t=1 or r=1 | ||
1165 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
1166 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
1167 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1168 | kTriSegOrigin, kTriSegDirection, | ||
1169 | &fR, &fT ); | ||
1170 | fS = REAL(1.0) - fT; | ||
1171 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1172 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1173 | &fS0, &fT0 ); | ||
1174 | fR0 = REAL(1.0); | ||
1175 | if ( fSqrDist0 < fSqrDist ) | ||
1176 | { | ||
1177 | fSqrDist = fSqrDist0; | ||
1178 | fR = fR0; | ||
1179 | fS = fS0; | ||
1180 | fT = fT0; | ||
1181 | } | ||
1182 | } | ||
1183 | } | ||
1184 | } | ||
1185 | } | ||
1186 | else | ||
1187 | { | ||
1188 | // segment and triangle are parallel | ||
1189 | Vector3Copy( triOrigin, kTriSegOrigin ); | ||
1190 | Vector3Copy( triEdge0, kTriSegDirection ); | ||
1191 | fSqrDist = SqrDistanceSegments( segOrigin, segDirection, | ||
1192 | kTriSegOrigin, kTriSegDirection, &fR, &fS ); | ||
1193 | fT = REAL(0.0); | ||
1194 | |||
1195 | Vector3Copy( triEdge1, kTriSegDirection ); | ||
1196 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
1197 | kTriSegOrigin, kTriSegDirection, | ||
1198 | &fR0, &fT0 ); | ||
1199 | fS0 = REAL(0.0); | ||
1200 | if ( fSqrDist0 < fSqrDist ) | ||
1201 | { | ||
1202 | fSqrDist = fSqrDist0; | ||
1203 | fR = fR0; | ||
1204 | fS = fS0; | ||
1205 | fT = fT0; | ||
1206 | } | ||
1207 | |||
1208 | Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); | ||
1209 | Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); | ||
1210 | fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, | ||
1211 | kTriSegOrigin, kTriSegDirection, &fR0, &fT0 ); | ||
1212 | fS0 = REAL(1.0) - fT0; | ||
1213 | if ( fSqrDist0 < fSqrDist ) | ||
1214 | { | ||
1215 | fSqrDist = fSqrDist0; | ||
1216 | fR = fR0; | ||
1217 | fS = fS0; | ||
1218 | fT = fT0; | ||
1219 | } | ||
1220 | |||
1221 | fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, | ||
1222 | &fS0, &fT0 ); | ||
1223 | fR0 = REAL(0.0); | ||
1224 | if ( fSqrDist0 < fSqrDist ) | ||
1225 | { | ||
1226 | fSqrDist = fSqrDist0; | ||
1227 | fR = fR0; | ||
1228 | fS = fS0; | ||
1229 | fT = fT0; | ||
1230 | } | ||
1231 | |||
1232 | Vector3Add( segOrigin, segDirection, kPt ); | ||
1233 | fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, | ||
1234 | &fS0, &fT0 ); | ||
1235 | fR0 = REAL(1.0); | ||
1236 | if ( fSqrDist0 < fSqrDist ) | ||
1237 | { | ||
1238 | fSqrDist = fSqrDist0; | ||
1239 | fR = fR0; | ||
1240 | fS = fS0; | ||
1241 | fT = fT0; | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | if ( pfSegP ) | ||
1246 | *pfSegP = fR; | ||
1247 | |||
1248 | if ( pfTriP0 ) | ||
1249 | *pfTriP0 = fS; | ||
1250 | |||
1251 | if ( pfTriP1 ) | ||
1252 | *pfTriP1 = fT; | ||
1253 | |||
1254 | return fSqrDist; | ||
1255 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_gimpact.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_gimpact.cpp new file mode 100755 index 0000000..229966b --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_gimpact.cpp | |||
@@ -0,0 +1,456 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/collision.h> | ||
24 | #include <ode/matrix.h> | ||
25 | #include <ode/rotation.h> | ||
26 | #include <ode/odemath.h> | ||
27 | |||
28 | #if dTRIMESH_ENABLED | ||
29 | |||
30 | #include "collision_util.h" | ||
31 | #define TRIMESH_INTERNAL | ||
32 | #include "collision_trimesh_internal.h" | ||
33 | |||
34 | #if dTRIMESH_GIMPACT | ||
35 | |||
36 | void dxTriMeshData::Preprocess(){ // stub | ||
37 | } | ||
38 | |||
39 | dTriMeshDataID dGeomTriMeshDataCreate(){ | ||
40 | return new dxTriMeshData(); | ||
41 | } | ||
42 | |||
43 | void dGeomTriMeshDataDestroy(dTriMeshDataID g){ | ||
44 | delete g; | ||
45 | } | ||
46 | |||
47 | void dGeomTriMeshSetLastTransform( dxGeom* g, dMatrix4 last_trans ) { //stub | ||
48 | } | ||
49 | |||
50 | dReal* dGeomTriMeshGetLastTransform( dxGeom* g ) { | ||
51 | return NULL; // stub | ||
52 | } | ||
53 | |||
54 | void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data) { //stub | ||
55 | } | ||
56 | |||
57 | void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id) { | ||
58 | dUASSERT(g, "argument not trimesh data"); | ||
59 | return NULL; // stub | ||
60 | } | ||
61 | |||
62 | void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g, | ||
63 | const void* Vertices, int VertexStride, int VertexCount, | ||
64 | const void* Indices, int IndexCount, int TriStride, | ||
65 | const void* Normals) | ||
66 | { | ||
67 | dUASSERT(g, "argument not trimesh data"); | ||
68 | dIASSERT(Vertices); | ||
69 | dIASSERT(Indices); | ||
70 | |||
71 | g->Build(Vertices, VertexStride, VertexCount, | ||
72 | Indices, IndexCount, TriStride, | ||
73 | Normals, | ||
74 | true); | ||
75 | } | ||
76 | |||
77 | |||
78 | void dGeomTriMeshDataBuildSingle(dTriMeshDataID g, | ||
79 | const void* Vertices, int VertexStride, int VertexCount, | ||
80 | const void* Indices, int IndexCount, int TriStride) | ||
81 | { | ||
82 | dGeomTriMeshDataBuildSingle1(g, Vertices, VertexStride, VertexCount, | ||
83 | Indices, IndexCount, TriStride, (void*)NULL); | ||
84 | } | ||
85 | |||
86 | |||
87 | void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g, | ||
88 | const void* Vertices, int VertexStride, int VertexCount, | ||
89 | const void* Indices, int IndexCount, int TriStride, | ||
90 | const void* Normals) | ||
91 | { | ||
92 | dUASSERT(g, "argument not trimesh data"); | ||
93 | |||
94 | g->Build(Vertices, VertexStride, VertexCount, | ||
95 | Indices, IndexCount, TriStride, | ||
96 | Normals, | ||
97 | false); | ||
98 | } | ||
99 | |||
100 | |||
101 | void dGeomTriMeshDataBuildDouble(dTriMeshDataID g, | ||
102 | const void* Vertices, int VertexStride, int VertexCount, | ||
103 | const void* Indices, int IndexCount, int TriStride) { | ||
104 | dGeomTriMeshDataBuildDouble1(g, Vertices, VertexStride, VertexCount, | ||
105 | Indices, IndexCount, TriStride, NULL); | ||
106 | } | ||
107 | |||
108 | |||
109 | void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g, | ||
110 | const dReal* Vertices, int VertexCount, | ||
111 | const int* Indices, int IndexCount, | ||
112 | const int* Normals){ | ||
113 | #ifdef dSINGLE | ||
114 | dGeomTriMeshDataBuildSingle1(g, | ||
115 | Vertices, 4 * sizeof(dReal), VertexCount, | ||
116 | Indices, IndexCount, 3 * sizeof(unsigned int), | ||
117 | Normals); | ||
118 | #else | ||
119 | dGeomTriMeshDataBuildDouble1(g, Vertices, 4 * sizeof(dReal), VertexCount, | ||
120 | Indices, IndexCount, 3 * sizeof(unsigned int), | ||
121 | Normals); | ||
122 | #endif | ||
123 | } | ||
124 | |||
125 | |||
126 | void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, | ||
127 | const dReal* Vertices, int VertexCount, | ||
128 | const int* Indices, int IndexCount) { | ||
129 | dGeomTriMeshDataBuildSimple1(g, | ||
130 | Vertices, VertexCount, Indices, IndexCount, | ||
131 | (const int*)NULL); | ||
132 | } | ||
133 | |||
134 | void dGeomTriMeshDataPreprocess(dTriMeshDataID g) | ||
135 | { | ||
136 | dUASSERT(g, "argument not trimesh data"); | ||
137 | g->Preprocess(); | ||
138 | } | ||
139 | |||
140 | void dGeomTriMeshDataGetBuffer(dTriMeshDataID g, unsigned char** buf, int* bufLen) | ||
141 | { | ||
142 | dUASSERT(g, "argument not trimesh data"); | ||
143 | *buf = NULL; | ||
144 | *bufLen = 0; | ||
145 | } | ||
146 | |||
147 | void dGeomTriMeshDataSetBuffer(dTriMeshDataID g, unsigned char* buf) | ||
148 | { | ||
149 | dUASSERT(g, "argument not trimesh data"); | ||
150 | // g->UseFlags = buf; | ||
151 | } | ||
152 | |||
153 | |||
154 | // Trimesh | ||
155 | |||
156 | dxTriMesh::dxTriMesh(dSpaceID Space, dTriMeshDataID Data) : dxGeom(Space, 1){ | ||
157 | type = dTriMeshClass; | ||
158 | |||
159 | dGeomTriMeshSetData(this,Data); | ||
160 | |||
161 | /* TC has speed/space 'issues' that don't make it a clear | ||
162 | win by default on spheres/boxes. */ | ||
163 | this->doSphereTC = true; | ||
164 | this->doBoxTC = true; | ||
165 | this->doCapsuleTC = true; | ||
166 | |||
167 | } | ||
168 | |||
169 | dxTriMesh::~dxTriMesh(){ | ||
170 | |||
171 | //Terminate Trimesh | ||
172 | gim_trimesh_destroy(&m_collision_trimesh); | ||
173 | } | ||
174 | |||
175 | |||
176 | void dxTriMesh::ClearTCCache(){ | ||
177 | |||
178 | } | ||
179 | |||
180 | |||
181 | int dxTriMesh::AABBTest(dxGeom* g, dReal aabb[6]){ | ||
182 | return 1; | ||
183 | } | ||
184 | |||
185 | |||
186 | void dxTriMesh::computeAABB() | ||
187 | { | ||
188 | //update trimesh transform | ||
189 | mat4f transform; | ||
190 | IDENTIFY_MATRIX_4X4(transform); | ||
191 | MakeMatrix(this, transform); | ||
192 | gim_trimesh_set_tranform(&m_collision_trimesh,transform); | ||
193 | |||
194 | //Update trimesh boxes | ||
195 | gim_trimesh_update(&m_collision_trimesh); | ||
196 | |||
197 | memcpy(aabb,&m_collision_trimesh.m_aabbset.m_global_bound,6*sizeof(GREAL)); | ||
198 | } | ||
199 | |||
200 | |||
201 | void dxTriMeshData::UpdateData() | ||
202 | { | ||
203 | // BVTree.Refit(); | ||
204 | } | ||
205 | |||
206 | |||
207 | dGeomID dCreateTriMesh(dSpaceID space, | ||
208 | dTriMeshDataID Data, | ||
209 | dTriCallback* Callback, | ||
210 | dTriArrayCallback* ArrayCallback, | ||
211 | dTriRayCallback* RayCallback) | ||
212 | { | ||
213 | dxTriMesh* Geom = new dxTriMesh(space, Data); | ||
214 | Geom->Callback = Callback; | ||
215 | Geom->ArrayCallback = ArrayCallback; | ||
216 | Geom->RayCallback = RayCallback; | ||
217 | |||
218 | return Geom; | ||
219 | } | ||
220 | |||
221 | void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback) | ||
222 | { | ||
223 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
224 | ((dxTriMesh*)g)->Callback = Callback; | ||
225 | } | ||
226 | |||
227 | dTriCallback* dGeomTriMeshGetCallback(dGeomID g) | ||
228 | { | ||
229 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
230 | return ((dxTriMesh*)g)->Callback; | ||
231 | } | ||
232 | |||
233 | void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback) | ||
234 | { | ||
235 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
236 | ((dxTriMesh*)g)->ArrayCallback = ArrayCallback; | ||
237 | } | ||
238 | |||
239 | dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g) | ||
240 | { | ||
241 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
242 | return ((dxTriMesh*)g)->ArrayCallback; | ||
243 | } | ||
244 | |||
245 | void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback) | ||
246 | { | ||
247 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
248 | ((dxTriMesh*)g)->RayCallback = Callback; | ||
249 | } | ||
250 | |||
251 | dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g) | ||
252 | { | ||
253 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
254 | return ((dxTriMesh*)g)->RayCallback; | ||
255 | } | ||
256 | |||
257 | void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data) | ||
258 | { | ||
259 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
260 | dxTriMesh* mesh = (dxTriMesh*) g; | ||
261 | mesh->Data = Data; | ||
262 | // I changed my data -- I know nothing about my own AABB anymore. | ||
263 | ((dxTriMesh*)g)->gflags |= (GEOM_DIRTY|GEOM_AABB_BAD); | ||
264 | |||
265 | // GIMPACT only supports stride 12, so we need to catch the error early. | ||
266 | dUASSERT | ||
267 | ( | ||
268 | Data->m_VertexStride == 3*sizeof(dReal) && Data->m_TriStride == 3*sizeof(int), | ||
269 | "Gimpact trimesh only supports a stride of 3 dReal/int\n" | ||
270 | "This means that you cannot use dGeomTriMeshDataBuildSimple() with Gimpact.\n" | ||
271 | "Change the stride, or use Opcode trimeshes instead.\n" | ||
272 | ); | ||
273 | |||
274 | //Create trimesh | ||
275 | if ( Data->m_Vertices ) | ||
276 | gim_trimesh_create_from_data | ||
277 | ( | ||
278 | &mesh->m_collision_trimesh, // gimpact mesh | ||
279 | ( vec3f *)(&Data->m_Vertices[0]), // vertices | ||
280 | Data->m_VertexCount, // nr of verts | ||
281 | 0, // copy verts? | ||
282 | ( GUINT *)(&Data->m_Indices[0]), // indices | ||
283 | Data->m_TriangleCount*3, // nr of indices | ||
284 | 0, // copy indices? | ||
285 | 1 // transformed reply | ||
286 | ); | ||
287 | } | ||
288 | |||
289 | dTriMeshDataID dGeomTriMeshGetData(dGeomID g) | ||
290 | { | ||
291 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
292 | return ((dxTriMesh*)g)->Data; | ||
293 | } | ||
294 | |||
295 | |||
296 | |||
297 | void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable) | ||
298 | { | ||
299 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
300 | |||
301 | switch (geomClass) | ||
302 | { | ||
303 | case dSphereClass: | ||
304 | ((dxTriMesh*)g)->doSphereTC = (1 == enable); | ||
305 | break; | ||
306 | case dBoxClass: | ||
307 | ((dxTriMesh*)g)->doBoxTC = (1 == enable); | ||
308 | break; | ||
309 | case dCapsuleClass: | ||
310 | // case dCCylinderClass: | ||
311 | ((dxTriMesh*)g)->doCapsuleTC = (1 == enable); | ||
312 | break; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass) | ||
317 | { | ||
318 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
319 | |||
320 | switch (geomClass) | ||
321 | { | ||
322 | case dSphereClass: | ||
323 | if (((dxTriMesh*)g)->doSphereTC) | ||
324 | return 1; | ||
325 | break; | ||
326 | case dBoxClass: | ||
327 | if (((dxTriMesh*)g)->doBoxTC) | ||
328 | return 1; | ||
329 | break; | ||
330 | case dCapsuleClass: | ||
331 | if (((dxTriMesh*)g)->doCapsuleTC) | ||
332 | return 1; | ||
333 | break; | ||
334 | } | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | void dGeomTriMeshClearTCCache(dGeomID g){ | ||
339 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
340 | |||
341 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
342 | Geom->ClearTCCache(); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * returns the TriMeshDataID | ||
347 | */ | ||
348 | dTriMeshDataID | ||
349 | dGeomTriMeshGetTriMeshDataID(dGeomID g) | ||
350 | { | ||
351 | dxTriMesh* Geom = (dxTriMesh*) g; | ||
352 | return Geom->Data; | ||
353 | } | ||
354 | |||
355 | // Getting data | ||
356 | void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2) | ||
357 | { | ||
358 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
359 | |||
360 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
361 | gim_trimesh_locks_work_data(&Geom->m_collision_trimesh); | ||
362 | gim_trimesh_get_triangle_vertices(&Geom->m_collision_trimesh, Index, (*v0),(*v1),(*v2)); | ||
363 | gim_trimesh_unlocks_work_data(&Geom->m_collision_trimesh); | ||
364 | |||
365 | } | ||
366 | |||
367 | void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out){ | ||
368 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
369 | |||
370 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
371 | dVector3 dv[3]; | ||
372 | gim_trimesh_locks_work_data(&Geom->m_collision_trimesh); | ||
373 | gim_trimesh_get_triangle_vertices(&Geom->m_collision_trimesh, Index, dv[0],dv[1],dv[2]); | ||
374 | GetPointFromBarycentric(dv, u, v, Out); | ||
375 | gim_trimesh_unlocks_work_data(&Geom->m_collision_trimesh); | ||
376 | } | ||
377 | |||
378 | int dGeomTriMeshGetTriangleCount (dGeomID g) | ||
379 | { | ||
380 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
381 | return gim_trimesh_get_triangle_count(&Geom->m_collision_trimesh); | ||
382 | } | ||
383 | |||
384 | void dGeomTriMeshDataUpdate(dTriMeshDataID g) { | ||
385 | dUASSERT(g, "argument not trimesh data"); | ||
386 | g->UpdateData(); | ||
387 | } | ||
388 | |||
389 | |||
390 | // | ||
391 | // GIMPACT TRIMESH-TRIMESH COLLIDER | ||
392 | // | ||
393 | |||
394 | int dCollideTTL(dxGeom* g1, dxGeom* g2, int Flags, dContactGeom* Contacts, int Stride) | ||
395 | { | ||
396 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
397 | dIASSERT (g1->type == dTriMeshClass); | ||
398 | dIASSERT (g2->type == dTriMeshClass); | ||
399 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
400 | |||
401 | dxTriMesh* TriMesh1 = (dxTriMesh*) g1; | ||
402 | dxTriMesh* TriMesh2 = (dxTriMesh*) g2; | ||
403 | //Create contact list | ||
404 | GDYNAMIC_ARRAY trimeshcontacts; | ||
405 | GIM_CREATE_CONTACT_LIST(trimeshcontacts); | ||
406 | |||
407 | //Collide trimeshes | ||
408 | gim_trimesh_trimesh_collision(&TriMesh1->m_collision_trimesh,&TriMesh2->m_collision_trimesh,&trimeshcontacts); | ||
409 | |||
410 | if(trimeshcontacts.m_size == 0) | ||
411 | { | ||
412 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); | ||
417 | |||
418 | |||
419 | unsigned contactcount = trimeshcontacts.m_size; | ||
420 | unsigned maxcontacts = (unsigned)(Flags & NUMC_MASK); | ||
421 | if (contactcount > maxcontacts) | ||
422 | { | ||
423 | contactcount = maxcontacts; | ||
424 | } | ||
425 | |||
426 | dContactGeom* pcontact; | ||
427 | unsigned i; | ||
428 | |||
429 | for (i=0;i<contactcount;i++) | ||
430 | { | ||
431 | pcontact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
432 | |||
433 | pcontact->pos[0] = ptrimeshcontacts->m_point[0]; | ||
434 | pcontact->pos[1] = ptrimeshcontacts->m_point[1]; | ||
435 | pcontact->pos[2] = ptrimeshcontacts->m_point[2]; | ||
436 | pcontact->pos[3] = 1.0f; | ||
437 | |||
438 | pcontact->normal[0] = ptrimeshcontacts->m_normal[0]; | ||
439 | pcontact->normal[1] = ptrimeshcontacts->m_normal[1]; | ||
440 | pcontact->normal[2] = ptrimeshcontacts->m_normal[2]; | ||
441 | pcontact->normal[3] = 0; | ||
442 | |||
443 | pcontact->depth = ptrimeshcontacts->m_depth; | ||
444 | pcontact->g1 = g1; | ||
445 | pcontact->g2 = g2; | ||
446 | |||
447 | ptrimeshcontacts++; | ||
448 | } | ||
449 | |||
450 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
451 | |||
452 | return (int)contactcount; | ||
453 | } | ||
454 | |||
455 | #endif // dTRIMESH_GIMPACT | ||
456 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_internal.h b/libraries/ode-0.9\/ode/src/collision_trimesh_internal.h new file mode 100755 index 0000000..bf474a2 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_internal.h | |||
@@ -0,0 +1,495 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // TriMesh code by Erwin de Vries. | ||
24 | // Modified for FreeSOLID Compatibility by Rodrigo Hernandez | ||
25 | |||
26 | #ifndef _ODE_COLLISION_TRIMESH_INTERNAL_H_ | ||
27 | #define _ODE_COLLISION_TRIMESH_INTERNAL_H_ | ||
28 | |||
29 | int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
30 | int dCollideTrimeshPlane(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
31 | |||
32 | int dCollideSTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
33 | int dCollideBTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
34 | int dCollideRTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
35 | int dCollideTTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
36 | int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); | ||
37 | |||
38 | PURE_INLINE int dCollideRayTrimesh( dxGeom *ray, dxGeom *trimesh, int flags, | ||
39 | dContactGeom *contact, int skip ) | ||
40 | { | ||
41 | // Swapped case, for code that needs it (heightfield initially) | ||
42 | // The other ray-geom colliders take geoms in a swapped order to the | ||
43 | // dCollideRTL function which is annoying when using function pointers. | ||
44 | return dCollideRTL( trimesh, ray, flags, contact, skip ); | ||
45 | } | ||
46 | |||
47 | //**************************************************************************** | ||
48 | // dxTriMesh class | ||
49 | |||
50 | #ifdef TRIMESH_INTERNAL | ||
51 | |||
52 | #include "collision_kernel.h" | ||
53 | #include <ode/collision_trimesh.h> | ||
54 | |||
55 | #if dTRIMESH_OPCODE | ||
56 | #define BAN_OPCODE_AUTOLINK | ||
57 | #include "Opcode.h" | ||
58 | using namespace Opcode; | ||
59 | #endif // dTRIMESH_OPCODE | ||
60 | |||
61 | #if dTRIMESH_GIMPACT | ||
62 | #include <GIMPACT/gimpact.h> | ||
63 | #endif | ||
64 | |||
65 | struct dxTriMeshData : public dBase | ||
66 | { | ||
67 | /* Array of flags for which edges and verts should be used on each triangle */ | ||
68 | enum UseFlags | ||
69 | { | ||
70 | kEdge0 = 0x1, | ||
71 | kEdge1 = 0x2, | ||
72 | kEdge2 = 0x4, | ||
73 | kVert0 = 0x8, | ||
74 | kVert1 = 0x10, | ||
75 | kVert2 = 0x20, | ||
76 | |||
77 | kUseAll = 0xFF, | ||
78 | }; | ||
79 | |||
80 | /* Setup the UseFlags array */ | ||
81 | void Preprocess(); | ||
82 | /* For when app changes the vertices */ | ||
83 | void UpdateData(); | ||
84 | |||
85 | #if dTRIMESH_OPCODE | ||
86 | Model BVTree; | ||
87 | MeshInterface Mesh; | ||
88 | |||
89 | dxTriMeshData(); | ||
90 | ~dxTriMeshData(); | ||
91 | |||
92 | void Build(const void* Vertices, int VertexStide, int VertexCount, | ||
93 | const void* Indices, int IndexCount, int TriStride, | ||
94 | const void* Normals, | ||
95 | bool Single); | ||
96 | |||
97 | /* aabb in model space */ | ||
98 | dVector3 AABBCenter; | ||
99 | dVector3 AABBExtents; | ||
100 | |||
101 | // data for use in collision resolution | ||
102 | const void* Normals; | ||
103 | uint8* UseFlags; | ||
104 | #endif // dTRIMESH_OPCODE | ||
105 | |||
106 | #if dTRIMESH_GIMPACT | ||
107 | const char* m_Vertices; | ||
108 | int m_VertexStride; | ||
109 | int m_VertexCount; | ||
110 | const char* m_Indices; | ||
111 | int m_TriangleCount; | ||
112 | int m_TriStride; | ||
113 | bool m_single; | ||
114 | |||
115 | dxTriMeshData() | ||
116 | { | ||
117 | m_Vertices=NULL; | ||
118 | m_VertexStride = 12; | ||
119 | m_VertexCount = 0; | ||
120 | m_Indices = 0; | ||
121 | m_TriangleCount = 0; | ||
122 | m_TriStride = 12; | ||
123 | m_single = true; | ||
124 | } | ||
125 | |||
126 | void Build(const void* Vertices, int VertexStride, int VertexCount, | ||
127 | const void* Indices, int IndexCount, int TriStride, | ||
128 | const void* Normals, | ||
129 | bool Single) | ||
130 | { | ||
131 | dIASSERT(Vertices); | ||
132 | dIASSERT(Indices); | ||
133 | dIASSERT(VertexStride); | ||
134 | dIASSERT(TriStride); | ||
135 | dIASSERT(IndexCount); | ||
136 | m_Vertices=(const char *)Vertices; | ||
137 | m_VertexStride = VertexStride; | ||
138 | m_VertexCount = VertexCount; | ||
139 | m_Indices = (const char *)Indices; | ||
140 | m_TriangleCount = IndexCount/3; | ||
141 | m_TriStride = TriStride; | ||
142 | m_single = Single; | ||
143 | } | ||
144 | |||
145 | inline void GetVertex(unsigned int i, dVector3 Out) | ||
146 | { | ||
147 | if(m_single) | ||
148 | { | ||
149 | const float * fverts = (const float * )(m_Vertices + m_VertexStride*i); | ||
150 | Out[0] = fverts[0]; | ||
151 | Out[1] = fverts[1]; | ||
152 | Out[2] = fverts[2]; | ||
153 | Out[3] = 1.0f; | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | const double * dverts = (const double * )(m_Vertices + m_VertexStride*i); | ||
158 | Out[0] = (float)dverts[0]; | ||
159 | Out[1] = (float)dverts[1]; | ||
160 | Out[2] = (float)dverts[2]; | ||
161 | Out[3] = 1.0f; | ||
162 | |||
163 | } | ||
164 | } | ||
165 | |||
166 | inline void GetTriIndices(unsigned int itriangle, unsigned int triindices[3]) | ||
167 | { | ||
168 | const unsigned int * ind = (const unsigned int * )(m_Indices + m_TriStride*itriangle); | ||
169 | triindices[0] = ind[0]; | ||
170 | triindices[1] = ind[1]; | ||
171 | triindices[2] = ind[2]; | ||
172 | } | ||
173 | #endif // dTRIMESH_GIMPACT | ||
174 | }; | ||
175 | |||
176 | |||
177 | struct dxTriMesh : public dxGeom{ | ||
178 | // Callbacks | ||
179 | dTriCallback* Callback; | ||
180 | dTriArrayCallback* ArrayCallback; | ||
181 | dTriRayCallback* RayCallback; | ||
182 | |||
183 | // Data types | ||
184 | dxTriMeshData* Data; | ||
185 | |||
186 | bool doSphereTC; | ||
187 | bool doBoxTC; | ||
188 | bool doCapsuleTC; | ||
189 | |||
190 | // Functions | ||
191 | dxTriMesh(dSpaceID Space, dTriMeshDataID Data); | ||
192 | ~dxTriMesh(); | ||
193 | |||
194 | void ClearTCCache(); | ||
195 | |||
196 | int AABBTest(dxGeom* g, dReal aabb[6]); | ||
197 | void computeAABB(); | ||
198 | |||
199 | #if dTRIMESH_OPCODE | ||
200 | // Instance data for last transform. | ||
201 | dMatrix4 last_trans; | ||
202 | |||
203 | // Colliders | ||
204 | static PlanesCollider _PlanesCollider; | ||
205 | static SphereCollider _SphereCollider; | ||
206 | static OBBCollider _OBBCollider; | ||
207 | static RayCollider _RayCollider; | ||
208 | static AABBTreeCollider _AABBTreeCollider; | ||
209 | static LSSCollider _LSSCollider; | ||
210 | |||
211 | // Some constants | ||
212 | static CollisionFaces Faces; | ||
213 | // Temporal coherence | ||
214 | struct SphereTC : public SphereCache{ | ||
215 | dxGeom* Geom; | ||
216 | }; | ||
217 | dArray<SphereTC> SphereTCCache; | ||
218 | static SphereCache defaultSphereCache; | ||
219 | |||
220 | struct BoxTC : public OBBCache{ | ||
221 | dxGeom* Geom; | ||
222 | }; | ||
223 | dArray<BoxTC> BoxTCCache; | ||
224 | static OBBCache defaultBoxCache; | ||
225 | |||
226 | struct CapsuleTC : public LSSCache{ | ||
227 | dxGeom* Geom; | ||
228 | }; | ||
229 | dArray<CapsuleTC> CapsuleTCCache; | ||
230 | static LSSCache defaultCapsuleCache; | ||
231 | #endif // dTRIMESH_OPCODE | ||
232 | |||
233 | #if dTRIMESH_GIMPACT | ||
234 | GIM_TRIMESH m_collision_trimesh; | ||
235 | #endif // dTRIMESH_GIMPACT | ||
236 | }; | ||
237 | |||
238 | #if 0 | ||
239 | #include "collision_kernel.h" | ||
240 | // Fetches a contact | ||
241 | inline dContactGeom* SAFECONTACT(int Flags, dContactGeom* Contacts, int Index, int Stride){ | ||
242 | dIASSERT(Index >= 0 && Index < (Flags & NUMC_MASK)); | ||
243 | return ((dContactGeom*)(((char*)Contacts) + (Index * Stride))); | ||
244 | } | ||
245 | #endif | ||
246 | |||
247 | #if dTRIMESH_OPCODE | ||
248 | inline void FetchTriangle(dxTriMesh* TriMesh, int Index, dVector3 Out[3]){ | ||
249 | VertexPointers VP; | ||
250 | TriMesh->Data->Mesh.GetTriangle(VP, Index); | ||
251 | for (int i = 0; i < 3; i++){ | ||
252 | Out[i][0] = VP.Vertex[i]->x; | ||
253 | Out[i][1] = VP.Vertex[i]->y; | ||
254 | Out[i][2] = VP.Vertex[i]->z; | ||
255 | Out[i][3] = 0; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | inline void FetchTriangle(dxTriMesh* TriMesh, int Index, const dVector3 Position, const dMatrix3 Rotation, dVector3 Out[3]){ | ||
260 | VertexPointers VP; | ||
261 | TriMesh->Data->Mesh.GetTriangle(VP, Index); | ||
262 | for (int i = 0; i < 3; i++){ | ||
263 | dVector3 v; | ||
264 | v[0] = VP.Vertex[i]->x; | ||
265 | v[1] = VP.Vertex[i]->y; | ||
266 | v[2] = VP.Vertex[i]->z; | ||
267 | v[3] = 0; | ||
268 | |||
269 | dMULTIPLY0_331(Out[i], Rotation, v); | ||
270 | Out[i][0] += Position[0]; | ||
271 | Out[i][1] += Position[1]; | ||
272 | Out[i][2] += Position[2]; | ||
273 | Out[i][3] = 0; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | inline Matrix4x4& MakeMatrix(const dVector3 Position, const dMatrix3 Rotation, Matrix4x4& Out){ | ||
278 | Out.m[0][0] = (float) Rotation[0]; | ||
279 | Out.m[1][0] = (float) Rotation[1]; | ||
280 | Out.m[2][0] = (float) Rotation[2]; | ||
281 | |||
282 | Out.m[0][1] = (float) Rotation[4]; | ||
283 | Out.m[1][1] = (float) Rotation[5]; | ||
284 | Out.m[2][1] = (float) Rotation[6]; | ||
285 | |||
286 | Out.m[0][2] = (float) Rotation[8]; | ||
287 | Out.m[1][2] = (float) Rotation[9]; | ||
288 | Out.m[2][2] = (float) Rotation[10]; | ||
289 | |||
290 | Out.m[3][0] = (float) Position[0]; | ||
291 | Out.m[3][1] = (float) Position[1]; | ||
292 | Out.m[3][2] = (float) Position[2]; | ||
293 | |||
294 | Out.m[0][3] = 0.0f; | ||
295 | Out.m[1][3] = 0.0f; | ||
296 | Out.m[2][3] = 0.0f; | ||
297 | Out.m[3][3] = 1.0f; | ||
298 | |||
299 | return Out; | ||
300 | } | ||
301 | |||
302 | inline Matrix4x4& MakeMatrix(dxGeom* g, Matrix4x4& Out){ | ||
303 | const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); | ||
304 | const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); | ||
305 | return MakeMatrix(Position, Rotation, Out); | ||
306 | } | ||
307 | #endif // dTRIMESH_OPCODE | ||
308 | |||
309 | #if dTRIMESH_GIMPACT | ||
310 | inline void FetchTriangle(dxTriMesh* TriMesh, int Index, const dVector3 Position, const dMatrix3 Rotation, dVector3 Out[3]){ | ||
311 | // why is this not implemented? | ||
312 | dAASSERT(false); | ||
313 | } | ||
314 | |||
315 | inline void MakeMatrix(const dVector3 Position, const dMatrix3 Rotation, mat4f m) | ||
316 | { | ||
317 | m[0][0] = (float) Rotation[0]; | ||
318 | m[0][1] = (float) Rotation[1]; | ||
319 | m[0][2] = (float) Rotation[2]; | ||
320 | |||
321 | m[1][0] = (float) Rotation[4]; | ||
322 | m[1][1] = (float) Rotation[5]; | ||
323 | m[1][2] = (float) Rotation[6]; | ||
324 | |||
325 | m[2][0] = (float) Rotation[8]; | ||
326 | m[2][1] = (float) Rotation[9]; | ||
327 | m[2][2] = (float) Rotation[10]; | ||
328 | |||
329 | m[0][3] = (float) Position[0]; | ||
330 | m[1][3] = (float) Position[1]; | ||
331 | m[2][3] = (float) Position[2]; | ||
332 | |||
333 | } | ||
334 | |||
335 | inline void MakeMatrix(dxGeom* g, mat4f Out){ | ||
336 | const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); | ||
337 | const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); | ||
338 | MakeMatrix(Position, Rotation, Out); | ||
339 | } | ||
340 | #endif // dTRIMESH_GIMPACT | ||
341 | |||
342 | // Outputs a matrix to 3 vectors | ||
343 | inline void Decompose(const dMatrix3 Matrix, dVector3 Right, dVector3 Up, dVector3 Direction){ | ||
344 | Right[0] = Matrix[0 * 4 + 0]; | ||
345 | Right[1] = Matrix[1 * 4 + 0]; | ||
346 | Right[2] = Matrix[2 * 4 + 0]; | ||
347 | Right[3] = REAL(0.0); | ||
348 | Up[0] = Matrix[0 * 4 + 1]; | ||
349 | Up[1] = Matrix[1 * 4 + 1]; | ||
350 | Up[2] = Matrix[2 * 4 + 1]; | ||
351 | Up[3] = REAL(0.0); | ||
352 | Direction[0] = Matrix[0 * 4 + 2]; | ||
353 | Direction[1] = Matrix[1 * 4 + 2]; | ||
354 | Direction[2] = Matrix[2 * 4 + 2]; | ||
355 | Direction[3] = REAL(0.0); | ||
356 | } | ||
357 | |||
358 | // Outputs a matrix to 3 vectors | ||
359 | inline void Decompose(const dMatrix3 Matrix, dVector3 Vectors[3]){ | ||
360 | Decompose(Matrix, Vectors[0], Vectors[1], Vectors[2]); | ||
361 | } | ||
362 | |||
363 | // Finds barycentric | ||
364 | inline void GetPointFromBarycentric(const dVector3 dv[3], dReal u, dReal v, dVector3 Out){ | ||
365 | dReal w = REAL(1.0) - u - v; | ||
366 | |||
367 | Out[0] = (dv[0][0] * w) + (dv[1][0] * u) + (dv[2][0] * v); | ||
368 | Out[1] = (dv[0][1] * w) + (dv[1][1] * u) + (dv[2][1] * v); | ||
369 | Out[2] = (dv[0][2] * w) + (dv[1][2] * u) + (dv[2][2] * v); | ||
370 | Out[3] = (dv[0][3] * w) + (dv[1][3] * u) + (dv[2][3] * v); | ||
371 | } | ||
372 | |||
373 | // Performs a callback | ||
374 | inline bool Callback(dxTriMesh* TriMesh, dxGeom* Object, int TriIndex){ | ||
375 | if (TriMesh->Callback != NULL){ | ||
376 | return (TriMesh->Callback(TriMesh, Object, TriIndex)!=0); | ||
377 | } | ||
378 | else return true; | ||
379 | } | ||
380 | |||
381 | // Some utilities | ||
382 | template<class T> const T& dcMAX(const T& x, const T& y){ | ||
383 | return x > y ? x : y; | ||
384 | } | ||
385 | |||
386 | template<class T> const T& dcMIN(const T& x, const T& y){ | ||
387 | return x < y ? x : y; | ||
388 | } | ||
389 | |||
390 | dReal SqrDistancePointTri( const dVector3 p, const dVector3 triOrigin, | ||
391 | const dVector3 triEdge1, const dVector3 triEdge2, | ||
392 | dReal* pfSParam = 0, dReal* pfTParam = 0 ); | ||
393 | |||
394 | dReal SqrDistanceSegments( const dVector3 seg1Origin, const dVector3 seg1Direction, | ||
395 | const dVector3 seg2Origin, const dVector3 seg2Direction, | ||
396 | dReal* pfSegP0 = 0, dReal* pfSegP1 = 0 ); | ||
397 | |||
398 | dReal SqrDistanceSegTri( const dVector3 segOrigin, const dVector3 segEnd, | ||
399 | const dVector3 triOrigin, | ||
400 | const dVector3 triEdge1, const dVector3 triEdge2, | ||
401 | dReal* t = 0, dReal* u = 0, dReal* v = 0 ); | ||
402 | |||
403 | inline | ||
404 | void Vector3Subtract( const dVector3 left, const dVector3 right, dVector3 result ) | ||
405 | { | ||
406 | result[0] = left[0] - right[0]; | ||
407 | result[1] = left[1] - right[1]; | ||
408 | result[2] = left[2] - right[2]; | ||
409 | result[3] = REAL(0.0); | ||
410 | } | ||
411 | |||
412 | inline | ||
413 | void Vector3Add( const dVector3 left, const dVector3 right, dVector3 result ) | ||
414 | { | ||
415 | result[0] = left[0] + right[0]; | ||
416 | result[1] = left[1] + right[1]; | ||
417 | result[2] = left[2] + right[2]; | ||
418 | result[3] = REAL(0.0); | ||
419 | } | ||
420 | |||
421 | inline | ||
422 | void Vector3Negate( const dVector3 in, dVector3 out ) | ||
423 | { | ||
424 | out[0] = -in[0]; | ||
425 | out[1] = -in[1]; | ||
426 | out[2] = -in[2]; | ||
427 | out[3] = REAL(0.0); | ||
428 | } | ||
429 | |||
430 | inline | ||
431 | void Vector3Copy( const dVector3 in, dVector3 out ) | ||
432 | { | ||
433 | out[0] = in[0]; | ||
434 | out[1] = in[1]; | ||
435 | out[2] = in[2]; | ||
436 | out[3] = REAL(0.0); | ||
437 | } | ||
438 | |||
439 | inline | ||
440 | void Vector3Multiply( const dVector3 in, dReal scalar, dVector3 out ) | ||
441 | { | ||
442 | out[0] = in[0] * scalar; | ||
443 | out[1] = in[1] * scalar; | ||
444 | out[2] = in[2] * scalar; | ||
445 | out[3] = REAL(0.0); | ||
446 | } | ||
447 | |||
448 | inline | ||
449 | void TransformVector3( const dVector3 in, | ||
450 | const dMatrix3 orientation, const dVector3 position, | ||
451 | dVector3 out ) | ||
452 | { | ||
453 | dMULTIPLY0_331( out, orientation, in ); | ||
454 | out[0] += position[0]; | ||
455 | out[1] += position[1]; | ||
456 | out[2] += position[2]; | ||
457 | } | ||
458 | |||
459 | //------------------------------------------------------------------------------ | ||
460 | /** | ||
461 | @brief Check for intersection between triangle and capsule. | ||
462 | |||
463 | @param dist [out] Shortest distance squared between the triangle and | ||
464 | the capsule segment (central axis). | ||
465 | @param t [out] t value of point on segment that's the shortest distance | ||
466 | away from the triangle, the coordinates of this point | ||
467 | can be found by (cap.seg.end - cap.seg.start) * t, | ||
468 | or cap.seg.ipol(t). | ||
469 | @param u [out] Barycentric coord on triangle. | ||
470 | @param v [out] Barycentric coord on triangle. | ||
471 | @return True if intersection exists. | ||
472 | |||
473 | The third Barycentric coord is implicit, ie. w = 1.0 - u - v | ||
474 | The Barycentric coords give the location of the point on the triangle | ||
475 | closest to the capsule (where the distance between the two shapes | ||
476 | is the shortest). | ||
477 | */ | ||
478 | inline | ||
479 | bool IntersectCapsuleTri( const dVector3 segOrigin, const dVector3 segEnd, | ||
480 | const dReal radius, const dVector3 triOrigin, | ||
481 | const dVector3 triEdge0, const dVector3 triEdge1, | ||
482 | dReal* dist, dReal* t, dReal* u, dReal* v ) | ||
483 | { | ||
484 | dReal sqrDist = SqrDistanceSegTri( segOrigin, segEnd, triOrigin, triEdge0, triEdge1, | ||
485 | t, u, v ); | ||
486 | |||
487 | if ( dist ) | ||
488 | *dist = sqrDist; | ||
489 | |||
490 | return ( sqrDist <= (radius * radius) ); | ||
491 | } | ||
492 | |||
493 | #endif //TRIMESH_INTERNAL | ||
494 | |||
495 | #endif //_ODE_COLLISION_TRIMESH_INTERNAL_H_ | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_opcode.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_opcode.cpp new file mode 100755 index 0000000..07f3f8a --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_opcode.cpp | |||
@@ -0,0 +1,833 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // TriMesh code by Erwin de Vries. | ||
24 | |||
25 | #include <ode/collision.h> | ||
26 | #include <ode/matrix.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/odemath.h> | ||
29 | #include "collision_util.h" | ||
30 | #define TRIMESH_INTERNAL | ||
31 | #include "collision_trimesh_internal.h" | ||
32 | |||
33 | #if dTRIMESH_ENABLED | ||
34 | #if dTRIMESH_OPCODE | ||
35 | |||
36 | // Trimesh data | ||
37 | dxTriMeshData::dxTriMeshData() : UseFlags( NULL ) | ||
38 | { | ||
39 | #if !dTRIMESH_ENABLED | ||
40 | dUASSERT(false, "dTRIMESH_ENABLED is not defined. Trimesh geoms will not work"); | ||
41 | #endif | ||
42 | } | ||
43 | |||
44 | dxTriMeshData::~dxTriMeshData() | ||
45 | { | ||
46 | if ( UseFlags ) | ||
47 | delete [] UseFlags; | ||
48 | } | ||
49 | |||
50 | void | ||
51 | dxTriMeshData::Build(const void* Vertices, int VertexStide, int VertexCount, | ||
52 | const void* Indices, int IndexCount, int TriStride, | ||
53 | const void* in_Normals, | ||
54 | bool Single) | ||
55 | { | ||
56 | #if dTRIMESH_ENABLED | ||
57 | |||
58 | Mesh.SetNbTriangles(IndexCount / 3); | ||
59 | Mesh.SetNbVertices(VertexCount); | ||
60 | Mesh.SetPointers((IndexedTriangle*)Indices, (Point*)Vertices); | ||
61 | Mesh.SetStrides(TriStride, VertexStide); | ||
62 | Mesh.Single = Single; | ||
63 | |||
64 | // Build tree | ||
65 | BuildSettings Settings; | ||
66 | // recommended in Opcode User Manual | ||
67 | //Settings.mRules = SPLIT_COMPLETE | SPLIT_SPLATTERPOINTS | SPLIT_GEOMCENTER; | ||
68 | // used in ODE, why? | ||
69 | //Settings.mRules = SPLIT_BEST_AXIS; | ||
70 | |||
71 | // best compromise? | ||
72 | Settings.mRules = SPLIT_BEST_AXIS | SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER; | ||
73 | |||
74 | |||
75 | OPCODECREATE TreeBuilder; | ||
76 | TreeBuilder.mIMesh = &Mesh; | ||
77 | |||
78 | TreeBuilder.mSettings = Settings; | ||
79 | TreeBuilder.mNoLeaf = true; | ||
80 | TreeBuilder.mQuantized = false; | ||
81 | |||
82 | TreeBuilder.mKeepOriginal = false; | ||
83 | TreeBuilder.mCanRemap = false; | ||
84 | |||
85 | |||
86 | |||
87 | BVTree.Build(TreeBuilder); | ||
88 | |||
89 | // compute model space AABB | ||
90 | dVector3 AABBMax, AABBMin; | ||
91 | AABBMax[0] = AABBMax[1] = AABBMax[2] = (dReal) -dInfinity; | ||
92 | AABBMin[0] = AABBMin[1] = AABBMin[2] = (dReal) dInfinity; | ||
93 | if( Single ) { | ||
94 | const char* verts = (const char*)Vertices; | ||
95 | for( int i = 0; i < VertexCount; ++i ) { | ||
96 | const float* v = (const float*)verts; | ||
97 | if( v[0] > AABBMax[0] ) AABBMax[0] = v[0]; | ||
98 | if( v[1] > AABBMax[1] ) AABBMax[1] = v[1]; | ||
99 | if( v[2] > AABBMax[2] ) AABBMax[2] = v[2]; | ||
100 | if( v[0] < AABBMin[0] ) AABBMin[0] = v[0]; | ||
101 | if( v[1] < AABBMin[1] ) AABBMin[1] = v[1]; | ||
102 | if( v[2] < AABBMin[2] ) AABBMin[2] = v[2]; | ||
103 | verts += VertexStide; | ||
104 | } | ||
105 | } else { | ||
106 | const char* verts = (const char*)Vertices; | ||
107 | for( int i = 0; i < VertexCount; ++i ) { | ||
108 | const double* v = (const double*)verts; | ||
109 | if( v[0] > AABBMax[0] ) AABBMax[0] = (dReal) v[0]; | ||
110 | if( v[1] > AABBMax[1] ) AABBMax[1] = (dReal) v[1]; | ||
111 | if( v[2] > AABBMax[2] ) AABBMax[2] = (dReal) v[2]; | ||
112 | if( v[0] < AABBMin[0] ) AABBMin[0] = (dReal) v[0]; | ||
113 | if( v[1] < AABBMin[1] ) AABBMin[1] = (dReal) v[1]; | ||
114 | if( v[2] < AABBMin[2] ) AABBMin[2] = (dReal) v[2]; | ||
115 | verts += VertexStide; | ||
116 | } | ||
117 | } | ||
118 | AABBCenter[0] = (AABBMin[0] + AABBMax[0]) * REAL(0.5); | ||
119 | AABBCenter[1] = (AABBMin[1] + AABBMax[1]) * REAL(0.5); | ||
120 | AABBCenter[2] = (AABBMin[2] + AABBMax[2]) * REAL(0.5); | ||
121 | AABBExtents[0] = AABBMax[0] - AABBCenter[0]; | ||
122 | AABBExtents[1] = AABBMax[1] - AABBCenter[1]; | ||
123 | AABBExtents[2] = AABBMax[2] - AABBCenter[2]; | ||
124 | |||
125 | // user data (not used by OPCODE) | ||
126 | Normals = (dReal *) in_Normals; | ||
127 | |||
128 | UseFlags = 0; | ||
129 | |||
130 | #endif // dTRIMESH_ENABLED | ||
131 | } | ||
132 | |||
133 | struct EdgeRecord | ||
134 | { | ||
135 | int VertIdx1; // Index into vertex array for this edges vertices | ||
136 | int VertIdx2; | ||
137 | int TriIdx; // Index into triangle array for triangle this edge belongs to | ||
138 | |||
139 | uint8 EdgeFlags; | ||
140 | uint8 Vert1Flags; | ||
141 | uint8 Vert2Flags; | ||
142 | bool Concave; | ||
143 | }; | ||
144 | |||
145 | // Edge comparison function for qsort | ||
146 | static int EdgeCompare(const void* edge1, const void* edge2) | ||
147 | { | ||
148 | EdgeRecord* e1 = (EdgeRecord*)edge1; | ||
149 | EdgeRecord* e2 = (EdgeRecord*)edge2; | ||
150 | |||
151 | if (e1->VertIdx1 == e2->VertIdx1) | ||
152 | return e1->VertIdx2 - e2->VertIdx2; | ||
153 | else | ||
154 | return e1->VertIdx1 - e2->VertIdx1; | ||
155 | } | ||
156 | |||
157 | void SetupEdge(EdgeRecord* edge, int edgeIdx, int triIdx, const unsigned int* vertIdxs) | ||
158 | { | ||
159 | if (edgeIdx == 0) | ||
160 | { | ||
161 | edge->EdgeFlags = dxTriMeshData::kEdge0; | ||
162 | edge->Vert1Flags = dxTriMeshData::kVert0; | ||
163 | edge->Vert2Flags = dxTriMeshData::kVert1; | ||
164 | edge->VertIdx1 = vertIdxs[0]; | ||
165 | edge->VertIdx2 = vertIdxs[1]; | ||
166 | } | ||
167 | else if (edgeIdx == 1) | ||
168 | { | ||
169 | edge->EdgeFlags = dxTriMeshData::kEdge1; | ||
170 | edge->Vert1Flags = dxTriMeshData::kVert1; | ||
171 | edge->Vert2Flags = dxTriMeshData::kVert2; | ||
172 | edge->VertIdx1 = vertIdxs[1]; | ||
173 | edge->VertIdx2 = vertIdxs[2]; | ||
174 | } | ||
175 | else if (edgeIdx == 2) | ||
176 | { | ||
177 | edge->EdgeFlags = dxTriMeshData::kEdge2; | ||
178 | edge->Vert1Flags = dxTriMeshData::kVert2; | ||
179 | edge->Vert2Flags = dxTriMeshData::kVert0; | ||
180 | edge->VertIdx1 = vertIdxs[2]; | ||
181 | edge->VertIdx2 = vertIdxs[0]; | ||
182 | } | ||
183 | |||
184 | // Make sure vert index 1 is less than index 2 (for easier sorting) | ||
185 | if (edge->VertIdx1 > edge->VertIdx2) | ||
186 | { | ||
187 | unsigned int tempIdx = edge->VertIdx1; | ||
188 | edge->VertIdx1 = edge->VertIdx2; | ||
189 | edge->VertIdx2 = tempIdx; | ||
190 | |||
191 | uint8 tempFlags = edge->Vert1Flags; | ||
192 | edge->Vert1Flags = edge->Vert2Flags; | ||
193 | edge->Vert2Flags = tempFlags; | ||
194 | } | ||
195 | |||
196 | edge->TriIdx = triIdx; | ||
197 | edge->Concave = false; | ||
198 | } | ||
199 | |||
200 | #if dTRIMESH_ENABLED | ||
201 | |||
202 | // Get the vertex opposite this edge in the triangle | ||
203 | inline Point GetOppositeVert(EdgeRecord* edge, const Point* vertices[]) | ||
204 | { | ||
205 | if ((edge->Vert1Flags == dxTriMeshData::kVert0 && edge->Vert2Flags == dxTriMeshData::kVert1) || | ||
206 | (edge->Vert1Flags == dxTriMeshData::kVert1 && edge->Vert2Flags == dxTriMeshData::kVert0)) | ||
207 | { | ||
208 | return *vertices[2]; | ||
209 | } | ||
210 | else if ((edge->Vert1Flags == dxTriMeshData::kVert1 && edge->Vert2Flags == dxTriMeshData::kVert2) || | ||
211 | (edge->Vert1Flags == dxTriMeshData::kVert2 && edge->Vert2Flags == dxTriMeshData::kVert1)) | ||
212 | { | ||
213 | return *vertices[0]; | ||
214 | } | ||
215 | else | ||
216 | return *vertices[1]; | ||
217 | } | ||
218 | |||
219 | #endif // dTRIMESH_ENABLED | ||
220 | |||
221 | void dxTriMeshData::Preprocess() | ||
222 | { | ||
223 | |||
224 | #if dTRIMESH_ENABLED | ||
225 | |||
226 | // If this mesh has already been preprocessed, exit | ||
227 | if (UseFlags) | ||
228 | return; | ||
229 | |||
230 | udword numTris = Mesh.GetNbTriangles(); | ||
231 | udword numEdges = numTris * 3; | ||
232 | |||
233 | UseFlags = new uint8[numTris]; | ||
234 | memset(UseFlags, 0, sizeof(uint8) * numTris); | ||
235 | |||
236 | EdgeRecord* records = new EdgeRecord[numEdges]; | ||
237 | |||
238 | // Make a list of every edge in the mesh | ||
239 | const IndexedTriangle* tris = Mesh.GetTris(); | ||
240 | for (unsigned int i = 0; i < numTris; i++) | ||
241 | { | ||
242 | SetupEdge(&records[i*3], 0, i, tris->mVRef); | ||
243 | SetupEdge(&records[i*3+1], 1, i, tris->mVRef); | ||
244 | SetupEdge(&records[i*3+2], 2, i, tris->mVRef); | ||
245 | |||
246 | tris = (const IndexedTriangle*)(((uint8*)tris) + Mesh.GetTriStride()); | ||
247 | } | ||
248 | |||
249 | // Sort the edges, so the ones sharing the same verts are beside each other | ||
250 | qsort(records, numEdges, sizeof(EdgeRecord), EdgeCompare); | ||
251 | |||
252 | // Go through the sorted list of edges and flag all the edges and vertices that we need to use | ||
253 | for (unsigned int i = 0; i < numEdges; i++) | ||
254 | { | ||
255 | EdgeRecord* rec1 = &records[i]; | ||
256 | EdgeRecord* rec2 = 0; | ||
257 | if (i < numEdges - 1) | ||
258 | rec2 = &records[i+1]; | ||
259 | |||
260 | if (rec2 && | ||
261 | rec1->VertIdx1 == rec2->VertIdx1 && | ||
262 | rec1->VertIdx2 == rec2->VertIdx2) | ||
263 | { | ||
264 | VertexPointers vp; | ||
265 | Mesh.GetTriangle(vp, rec1->TriIdx); | ||
266 | |||
267 | // Get the normal of the first triangle | ||
268 | Point triNorm = (*vp.Vertex[2] - *vp.Vertex[1]) ^ (*vp.Vertex[0] - *vp.Vertex[1]); | ||
269 | triNorm.Normalize(); | ||
270 | |||
271 | // Get the vert opposite this edge in the first triangle | ||
272 | Point oppositeVert1 = GetOppositeVert(rec1, vp.Vertex); | ||
273 | |||
274 | // Get the vert opposite this edge in the second triangle | ||
275 | Mesh.GetTriangle(vp, rec2->TriIdx); | ||
276 | Point oppositeVert2 = GetOppositeVert(rec2, vp.Vertex); | ||
277 | |||
278 | float dot = triNorm.Dot((oppositeVert2 - oppositeVert1).Normalize()); | ||
279 | |||
280 | // We let the dot threshold for concavity get slightly negative to allow for rounding errors | ||
281 | static const float kConcaveThresh = -0.000001f; | ||
282 | |||
283 | // This is a concave edge, leave it for the next pass | ||
284 | if (dot >= kConcaveThresh) | ||
285 | rec1->Concave = true; | ||
286 | // If this is a convex edge, mark its vertices and edge as used | ||
287 | else | ||
288 | UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags; | ||
289 | |||
290 | // Skip the second edge | ||
291 | i++; | ||
292 | } | ||
293 | // This is a boundary edge | ||
294 | else | ||
295 | { | ||
296 | UseFlags[rec1->TriIdx] |= rec1->Vert1Flags | rec1->Vert2Flags | rec1->EdgeFlags; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | // Go through the list once more, and take any edge we marked as concave and | ||
301 | // clear it's vertices flags in any triangles they're used in | ||
302 | for (unsigned int i = 0; i < numEdges; i++) | ||
303 | { | ||
304 | EdgeRecord& er = records[i]; | ||
305 | |||
306 | if (er.Concave) | ||
307 | { | ||
308 | for (unsigned int j = 0; j < numEdges; j++) | ||
309 | { | ||
310 | EdgeRecord& curER = records[j]; | ||
311 | |||
312 | if (curER.VertIdx1 == er.VertIdx1 || | ||
313 | curER.VertIdx1 == er.VertIdx2) | ||
314 | UseFlags[curER.TriIdx] &= ~curER.Vert1Flags; | ||
315 | |||
316 | if (curER.VertIdx2 == er.VertIdx1 || | ||
317 | curER.VertIdx2 == er.VertIdx2) | ||
318 | UseFlags[curER.TriIdx] &= ~curER.Vert2Flags; | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | delete [] records; | ||
324 | |||
325 | #endif // dTRIMESH_ENABLED | ||
326 | |||
327 | } | ||
328 | |||
329 | dTriMeshDataID dGeomTriMeshDataCreate(){ | ||
330 | return new dxTriMeshData(); | ||
331 | } | ||
332 | |||
333 | void dGeomTriMeshDataDestroy(dTriMeshDataID g){ | ||
334 | delete g; | ||
335 | } | ||
336 | |||
337 | |||
338 | |||
339 | |||
340 | void dGeomTriMeshSetLastTransform( dxGeom* g, dMatrix4 last_trans ) | ||
341 | { | ||
342 | dAASSERT(g) | ||
343 | dUASSERT(g->type == dTriMeshClass, "geom not trimesh"); | ||
344 | |||
345 | for (int i=0; i<16; i++) | ||
346 | (((dxTriMesh*)g)->last_trans)[ i ] = last_trans[ i ]; | ||
347 | |||
348 | return; | ||
349 | } | ||
350 | |||
351 | |||
352 | dReal* dGeomTriMeshGetLastTransform( dxGeom* g ) | ||
353 | { | ||
354 | dAASSERT(g) | ||
355 | dUASSERT(g->type == dTriMeshClass, "geom not trimesh"); | ||
356 | |||
357 | return (dReal*)(((dxTriMesh*)g)->last_trans); | ||
358 | } | ||
359 | |||
360 | |||
361 | |||
362 | |||
363 | void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data) | ||
364 | { | ||
365 | dUASSERT(g, "argument not trimesh data"); | ||
366 | |||
367 | switch (data_id) | ||
368 | { | ||
369 | case TRIMESH_FACE_NORMALS: | ||
370 | g->Normals = (dReal *) in_data; | ||
371 | break; | ||
372 | |||
373 | default: | ||
374 | dUASSERT(data_id, "invalid data type"); | ||
375 | break; | ||
376 | } | ||
377 | |||
378 | return; | ||
379 | } | ||
380 | |||
381 | |||
382 | |||
383 | void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id) | ||
384 | { | ||
385 | dUASSERT(g, "argument not trimesh data"); | ||
386 | |||
387 | switch (data_id) | ||
388 | { | ||
389 | case TRIMESH_FACE_NORMALS: | ||
390 | return (void *) g->Normals; | ||
391 | break; | ||
392 | |||
393 | default: | ||
394 | dUASSERT(data_id, "invalid data type"); | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | return NULL; | ||
399 | } | ||
400 | |||
401 | |||
402 | void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g, | ||
403 | const void* Vertices, int VertexStride, int VertexCount, | ||
404 | const void* Indices, int IndexCount, int TriStride, | ||
405 | const void* Normals) | ||
406 | { | ||
407 | dUASSERT(g, "argument not trimesh data"); | ||
408 | |||
409 | g->Build(Vertices, VertexStride, VertexCount, | ||
410 | Indices, IndexCount, TriStride, | ||
411 | Normals, | ||
412 | true); | ||
413 | } | ||
414 | |||
415 | |||
416 | void dGeomTriMeshDataBuildSingle(dTriMeshDataID g, | ||
417 | const void* Vertices, int VertexStride, int VertexCount, | ||
418 | const void* Indices, int IndexCount, int TriStride) | ||
419 | { | ||
420 | dGeomTriMeshDataBuildSingle1(g, Vertices, VertexStride, VertexCount, | ||
421 | Indices, IndexCount, TriStride, (void*)NULL); | ||
422 | } | ||
423 | |||
424 | |||
425 | void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g, | ||
426 | const void* Vertices, int VertexStride, int VertexCount, | ||
427 | const void* Indices, int IndexCount, int TriStride, | ||
428 | const void* Normals) | ||
429 | { | ||
430 | dUASSERT(g, "argument not trimesh data"); | ||
431 | |||
432 | g->Build(Vertices, VertexStride, VertexCount, | ||
433 | Indices, IndexCount, TriStride, | ||
434 | Normals, | ||
435 | false); | ||
436 | } | ||
437 | |||
438 | |||
439 | void dGeomTriMeshDataBuildDouble(dTriMeshDataID g, | ||
440 | const void* Vertices, int VertexStride, int VertexCount, | ||
441 | const void* Indices, int IndexCount, int TriStride) { | ||
442 | dGeomTriMeshDataBuildDouble1(g, Vertices, VertexStride, VertexCount, | ||
443 | Indices, IndexCount, TriStride, NULL); | ||
444 | } | ||
445 | |||
446 | |||
447 | void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g, | ||
448 | const dReal* Vertices, int VertexCount, | ||
449 | const int* Indices, int IndexCount, | ||
450 | const int* Normals){ | ||
451 | #ifdef dSINGLE | ||
452 | dGeomTriMeshDataBuildSingle1(g, | ||
453 | Vertices, 4 * sizeof(dReal), VertexCount, | ||
454 | Indices, IndexCount, 3 * sizeof(unsigned int), | ||
455 | Normals); | ||
456 | #else | ||
457 | dGeomTriMeshDataBuildDouble1(g, Vertices, 4 * sizeof(dReal), VertexCount, | ||
458 | Indices, IndexCount, 3 * sizeof(unsigned int), | ||
459 | Normals); | ||
460 | #endif | ||
461 | } | ||
462 | |||
463 | |||
464 | void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, | ||
465 | const dReal* Vertices, int VertexCount, | ||
466 | const int* Indices, int IndexCount) { | ||
467 | dGeomTriMeshDataBuildSimple1(g, | ||
468 | Vertices, VertexCount, Indices, IndexCount, | ||
469 | (const int*)NULL); | ||
470 | } | ||
471 | |||
472 | void dGeomTriMeshDataPreprocess(dTriMeshDataID g) | ||
473 | { | ||
474 | dUASSERT(g, "argument not trimesh data"); | ||
475 | g->Preprocess(); | ||
476 | } | ||
477 | |||
478 | void dGeomTriMeshDataGetBuffer(dTriMeshDataID g, unsigned char** buf, int* bufLen) | ||
479 | { | ||
480 | dUASSERT(g, "argument not trimesh data"); | ||
481 | #if dTRIMESH_ENABLED | ||
482 | *buf = g->UseFlags; | ||
483 | *bufLen = g->Mesh.GetNbTriangles(); | ||
484 | #endif // dTRIMESH_ENABLED | ||
485 | } | ||
486 | |||
487 | void dGeomTriMeshDataSetBuffer(dTriMeshDataID g, unsigned char* buf) | ||
488 | { | ||
489 | dUASSERT(g, "argument not trimesh data"); | ||
490 | g->UseFlags = buf; | ||
491 | } | ||
492 | |||
493 | |||
494 | #if dTRIMESH_ENABLED | ||
495 | |||
496 | // Trimesh Class Statics | ||
497 | PlanesCollider dxTriMesh::_PlanesCollider; | ||
498 | SphereCollider dxTriMesh::_SphereCollider; | ||
499 | OBBCollider dxTriMesh::_OBBCollider; | ||
500 | RayCollider dxTriMesh::_RayCollider; | ||
501 | AABBTreeCollider dxTriMesh::_AABBTreeCollider; | ||
502 | LSSCollider dxTriMesh::_LSSCollider; | ||
503 | |||
504 | SphereCache dxTriMesh::defaultSphereCache; | ||
505 | OBBCache dxTriMesh::defaultBoxCache; | ||
506 | LSSCache dxTriMesh::defaultCapsuleCache; | ||
507 | |||
508 | CollisionFaces dxTriMesh::Faces; | ||
509 | |||
510 | #endif // dTRIMESH_ENABLED | ||
511 | |||
512 | |||
513 | dxTriMesh::dxTriMesh(dSpaceID Space, dTriMeshDataID Data) : dxGeom(Space, 1) | ||
514 | { | ||
515 | type = dTriMeshClass; | ||
516 | |||
517 | this->Data = Data; | ||
518 | |||
519 | #if dTRIMESH_ENABLED | ||
520 | |||
521 | _RayCollider.SetDestination(&Faces); | ||
522 | |||
523 | _PlanesCollider.SetTemporalCoherence(true); | ||
524 | |||
525 | _SphereCollider.SetTemporalCoherence(true); | ||
526 | _SphereCollider.SetPrimitiveTests(false); | ||
527 | |||
528 | _OBBCollider.SetTemporalCoherence(true); | ||
529 | |||
530 | // no first-contact test (i.e. return full contact info) | ||
531 | _AABBTreeCollider.SetFirstContact( false ); | ||
532 | // temporal coherence only works with "first conact" tests | ||
533 | _AABBTreeCollider.SetTemporalCoherence(false); | ||
534 | // Perform full BV-BV tests (true) or SAT-lite tests (false) | ||
535 | _AABBTreeCollider.SetFullBoxBoxTest( true ); | ||
536 | // Perform full Primitive-BV tests (true) or SAT-lite tests (false) | ||
537 | _AABBTreeCollider.SetFullPrimBoxTest( true ); | ||
538 | _LSSCollider.SetTemporalCoherence(false); | ||
539 | |||
540 | #endif // dTRIMESH_ENABLED | ||
541 | |||
542 | /* TC has speed/space 'issues' that don't make it a clear | ||
543 | win by default on spheres/boxes. */ | ||
544 | this->doSphereTC = false; | ||
545 | this->doBoxTC = false; | ||
546 | this->doCapsuleTC = false; | ||
547 | |||
548 | #if dTRIMESH_ENABLED | ||
549 | |||
550 | const char* msg; | ||
551 | if ((msg =_AABBTreeCollider.ValidateSettings())) | ||
552 | dDebug (d_ERR_UASSERT, msg, " (%s:%d)", __FILE__,__LINE__); | ||
553 | _LSSCollider.SetPrimitiveTests(false); | ||
554 | _LSSCollider.SetFirstContact(false); | ||
555 | |||
556 | #endif // dTRIMESH_ENABLED | ||
557 | |||
558 | for (int i=0; i<16; i++) | ||
559 | last_trans[i] = REAL( 0.0 ); | ||
560 | } | ||
561 | |||
562 | dxTriMesh::~dxTriMesh(){ | ||
563 | // | ||
564 | } | ||
565 | |||
566 | // Cleanup for allocations when shutting down ODE | ||
567 | void opcode_collider_cleanup() | ||
568 | { | ||
569 | #if dTRIMESH_ENABLED | ||
570 | |||
571 | // Clear TC caches | ||
572 | dxTriMesh::Faces.Empty(); | ||
573 | dxTriMesh::defaultSphereCache.TouchedPrimitives.Empty(); | ||
574 | dxTriMesh::defaultBoxCache.TouchedPrimitives.Empty(); | ||
575 | dxTriMesh::defaultCapsuleCache.TouchedPrimitives.Empty(); | ||
576 | |||
577 | #endif // dTRIMESH_ENABLED | ||
578 | } | ||
579 | |||
580 | |||
581 | |||
582 | void dxTriMesh::ClearTCCache() | ||
583 | { | ||
584 | #if dTRIMESH_ENABLED | ||
585 | /* dxTriMesh::ClearTCCache uses dArray's setSize(0) to clear the caches - | ||
586 | but the destructor isn't called when doing this, so we would leak. | ||
587 | So, call the previous caches' containers' destructors by hand first. */ | ||
588 | int i, n; | ||
589 | n = SphereTCCache.size(); | ||
590 | for( i = 0; i < n; ++i ) { | ||
591 | SphereTCCache[i].~SphereTC(); | ||
592 | } | ||
593 | SphereTCCache.setSize(0); | ||
594 | n = BoxTCCache.size(); | ||
595 | for( i = 0; i < n; ++i ) { | ||
596 | BoxTCCache[i].~BoxTC(); | ||
597 | } | ||
598 | BoxTCCache.setSize(0); | ||
599 | n = CapsuleTCCache.size(); | ||
600 | for( i = 0; i < n; ++i ) { | ||
601 | CapsuleTCCache[i].~CapsuleTC(); | ||
602 | } | ||
603 | CapsuleTCCache.setSize(0); | ||
604 | #endif // dTRIMESH_ENABLED | ||
605 | } | ||
606 | |||
607 | |||
608 | int dxTriMesh::AABBTest(dxGeom* g, dReal aabb[6]){ | ||
609 | return 1; | ||
610 | } | ||
611 | |||
612 | |||
613 | void dxTriMesh::computeAABB() { | ||
614 | const dxTriMeshData* d = Data; | ||
615 | dVector3 c; | ||
616 | const dMatrix3& R = final_posr->R; | ||
617 | const dVector3& pos = final_posr->pos; | ||
618 | |||
619 | dMULTIPLY0_331( c, R, d->AABBCenter ); | ||
620 | |||
621 | dReal xrange = dFabs(R[0] * Data->AABBExtents[0]) + | ||
622 | dFabs(R[1] * Data->AABBExtents[1]) + | ||
623 | dFabs(R[2] * Data->AABBExtents[2]); | ||
624 | dReal yrange = dFabs(R[4] * Data->AABBExtents[0]) + | ||
625 | dFabs(R[5] * Data->AABBExtents[1]) + | ||
626 | dFabs(R[6] * Data->AABBExtents[2]); | ||
627 | dReal zrange = dFabs(R[8] * Data->AABBExtents[0]) + | ||
628 | dFabs(R[9] * Data->AABBExtents[1]) + | ||
629 | dFabs(R[10] * Data->AABBExtents[2]); | ||
630 | |||
631 | aabb[0] = c[0] + pos[0] - xrange; | ||
632 | aabb[1] = c[0] + pos[0] + xrange; | ||
633 | aabb[2] = c[1] + pos[1] - yrange; | ||
634 | aabb[3] = c[1] + pos[1] + yrange; | ||
635 | aabb[4] = c[2] + pos[2] - zrange; | ||
636 | aabb[5] = c[2] + pos[2] + zrange; | ||
637 | } | ||
638 | |||
639 | |||
640 | void dxTriMeshData::UpdateData() | ||
641 | { | ||
642 | #if dTRIMESH_ENABLED | ||
643 | BVTree.Refit(); | ||
644 | #endif // dTRIMESH_ENABLED | ||
645 | } | ||
646 | |||
647 | |||
648 | dGeomID dCreateTriMesh(dSpaceID space, | ||
649 | dTriMeshDataID Data, | ||
650 | dTriCallback* Callback, | ||
651 | dTriArrayCallback* ArrayCallback, | ||
652 | dTriRayCallback* RayCallback) | ||
653 | { | ||
654 | dxTriMesh* Geom = new dxTriMesh(space, Data); | ||
655 | Geom->Callback = Callback; | ||
656 | Geom->ArrayCallback = ArrayCallback; | ||
657 | Geom->RayCallback = RayCallback; | ||
658 | |||
659 | return Geom; | ||
660 | } | ||
661 | |||
662 | void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback) | ||
663 | { | ||
664 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
665 | ((dxTriMesh*)g)->Callback = Callback; | ||
666 | } | ||
667 | |||
668 | dTriCallback* dGeomTriMeshGetCallback(dGeomID g) | ||
669 | { | ||
670 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
671 | return ((dxTriMesh*)g)->Callback; | ||
672 | } | ||
673 | |||
674 | void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback) | ||
675 | { | ||
676 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
677 | ((dxTriMesh*)g)->ArrayCallback = ArrayCallback; | ||
678 | } | ||
679 | |||
680 | dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g) | ||
681 | { | ||
682 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
683 | return ((dxTriMesh*)g)->ArrayCallback; | ||
684 | } | ||
685 | |||
686 | void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback) | ||
687 | { | ||
688 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
689 | ((dxTriMesh*)g)->RayCallback = Callback; | ||
690 | } | ||
691 | |||
692 | dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g) | ||
693 | { | ||
694 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
695 | return ((dxTriMesh*)g)->RayCallback; | ||
696 | } | ||
697 | |||
698 | void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data) | ||
699 | { | ||
700 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
701 | ((dxTriMesh*)g)->Data = Data; | ||
702 | // I changed my data -- I know nothing about my own AABB anymore. | ||
703 | ((dxTriMesh*)g)->gflags |= (GEOM_DIRTY|GEOM_AABB_BAD); | ||
704 | } | ||
705 | |||
706 | dTriMeshDataID dGeomTriMeshGetData(dGeomID g) | ||
707 | { | ||
708 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
709 | return ((dxTriMesh*)g)->Data; | ||
710 | } | ||
711 | |||
712 | |||
713 | |||
714 | void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable) | ||
715 | { | ||
716 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
717 | |||
718 | switch (geomClass) | ||
719 | { | ||
720 | case dSphereClass: | ||
721 | ((dxTriMesh*)g)->doSphereTC = (1 == enable); | ||
722 | break; | ||
723 | case dBoxClass: | ||
724 | ((dxTriMesh*)g)->doBoxTC = (1 == enable); | ||
725 | break; | ||
726 | case dCapsuleClass: | ||
727 | ((dxTriMesh*)g)->doCapsuleTC = (1 == enable); | ||
728 | break; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass) | ||
733 | { | ||
734 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
735 | |||
736 | switch (geomClass) | ||
737 | { | ||
738 | case dSphereClass: | ||
739 | if (((dxTriMesh*)g)->doSphereTC) | ||
740 | return 1; | ||
741 | break; | ||
742 | case dBoxClass: | ||
743 | if (((dxTriMesh*)g)->doBoxTC) | ||
744 | return 1; | ||
745 | break; | ||
746 | case dCapsuleClass: | ||
747 | if (((dxTriMesh*)g)->doCapsuleTC) | ||
748 | return 1; | ||
749 | break; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | void dGeomTriMeshClearTCCache(dGeomID g){ | ||
755 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
756 | |||
757 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
758 | Geom->ClearTCCache(); | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * returns the TriMeshDataID | ||
763 | */ | ||
764 | dTriMeshDataID | ||
765 | dGeomTriMeshGetTriMeshDataID(dGeomID g) | ||
766 | { | ||
767 | dxTriMesh* Geom = (dxTriMesh*) g; | ||
768 | return Geom->Data; | ||
769 | } | ||
770 | |||
771 | // Getting data | ||
772 | void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2){ | ||
773 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
774 | |||
775 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
776 | |||
777 | const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); | ||
778 | const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); | ||
779 | |||
780 | dVector3 v[3]; | ||
781 | FetchTriangle(Geom, Index, Position, Rotation, v); | ||
782 | |||
783 | if (v0){ | ||
784 | (*v0)[0] = v[0][0]; | ||
785 | (*v0)[1] = v[0][1]; | ||
786 | (*v0)[2] = v[0][2]; | ||
787 | (*v0)[3] = v[0][3]; | ||
788 | } | ||
789 | if (v1){ | ||
790 | (*v1)[0] = v[1][0]; | ||
791 | (*v1)[1] = v[1][1]; | ||
792 | (*v1)[2] = v[1][2]; | ||
793 | (*v1)[3] = v[1][3]; | ||
794 | } | ||
795 | if (v2){ | ||
796 | (*v2)[0] = v[2][0]; | ||
797 | (*v2)[1] = v[2][1]; | ||
798 | (*v2)[2] = v[2][2]; | ||
799 | (*v2)[3] = v[2][3]; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out){ | ||
804 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
805 | |||
806 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
807 | |||
808 | const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); | ||
809 | const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); | ||
810 | |||
811 | dVector3 dv[3]; | ||
812 | FetchTriangle(Geom, Index, Position, Rotation, dv); | ||
813 | |||
814 | GetPointFromBarycentric(dv, u, v, Out); | ||
815 | } | ||
816 | |||
817 | int dGeomTriMeshGetTriangleCount (dGeomID g) | ||
818 | { | ||
819 | #if dTRIMESH_ENABLED | ||
820 | dxTriMesh* Geom = (dxTriMesh*)g; | ||
821 | return Geom->Data->Mesh.GetNbTriangles(); | ||
822 | #else | ||
823 | return 0; | ||
824 | #endif // dTRIMESH_ENABLED | ||
825 | } | ||
826 | |||
827 | void dGeomTriMeshDataUpdate(dTriMeshDataID g) { | ||
828 | dUASSERT(g, "argument not trimesh data"); | ||
829 | g->UpdateData(); | ||
830 | } | ||
831 | |||
832 | #endif // dTRIMESH_OPCODE | ||
833 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_plane.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_plane.cpp new file mode 100755 index 0000000..54034aa --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_plane.cpp | |||
@@ -0,0 +1,213 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // TriMesh - Plane collider by David Walters, July 2006 | ||
24 | |||
25 | #include <ode/collision.h> | ||
26 | #include <ode/matrix.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/odemath.h> | ||
29 | |||
30 | #if dTRIMESH_ENABLED | ||
31 | |||
32 | #include "collision_util.h" | ||
33 | #include "collision_std.h" | ||
34 | |||
35 | #define TRIMESH_INTERNAL | ||
36 | #include "collision_trimesh_internal.h" | ||
37 | |||
38 | #if dTRIMESH_OPCODE | ||
39 | int dCollideTrimeshPlane( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* contacts, int skip ) | ||
40 | { | ||
41 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
42 | dIASSERT( o1->type == dTriMeshClass ); | ||
43 | dIASSERT( o2->type == dPlaneClass ); | ||
44 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
45 | |||
46 | // Alias pointers to the plane and trimesh | ||
47 | dxTriMesh* trimesh = (dxTriMesh*)( o1 ); | ||
48 | dxPlane* plane = (dxPlane*)( o2 ); | ||
49 | |||
50 | int contact_count = 0; | ||
51 | |||
52 | // Cache the maximum contact count. | ||
53 | const int contact_max = ( flags & NUMC_MASK ); | ||
54 | |||
55 | // Cache trimesh position and rotation. | ||
56 | const dVector3& trimesh_pos = *(const dVector3*)dGeomGetPosition( trimesh ); | ||
57 | const dMatrix3& trimesh_R = *(const dMatrix3*)dGeomGetRotation( trimesh ); | ||
58 | |||
59 | // | ||
60 | // For all triangles. | ||
61 | // | ||
62 | |||
63 | // Cache the triangle count. | ||
64 | const int tri_count = trimesh->Data->Mesh.GetNbTriangles(); | ||
65 | |||
66 | VertexPointers VP; | ||
67 | dReal alpha; | ||
68 | dVector3 vertex; | ||
69 | |||
70 | #if !defined(dSINGLE) || 1 | ||
71 | dVector3 int_vertex; // Intermediate vertex for double precision mode. | ||
72 | #endif // dSINGLE | ||
73 | |||
74 | // For each triangle | ||
75 | for ( int t = 0; t < tri_count; ++t ) | ||
76 | { | ||
77 | // Get triangle, which should also use callback. | ||
78 | trimesh->Data->Mesh.GetTriangle( VP, t ); | ||
79 | |||
80 | // For each vertex. | ||
81 | for ( int v = 0; v < 3; ++v ) | ||
82 | { | ||
83 | // | ||
84 | // Get Vertex | ||
85 | // | ||
86 | |||
87 | #if defined(dSINGLE) && 0 // Always assign via intermediate array as otherwise it is an incapsulation violation | ||
88 | |||
89 | dMULTIPLY0_331( vertex, trimesh_R, (float*)( VP.Vertex[ v ] ) ); | ||
90 | |||
91 | #else // dDOUBLE || 1 | ||
92 | |||
93 | // OPCODE data is in single precision format. | ||
94 | int_vertex[ 0 ] = VP.Vertex[ v ]->x; | ||
95 | int_vertex[ 1 ] = VP.Vertex[ v ]->y; | ||
96 | int_vertex[ 2 ] = VP.Vertex[ v ]->z; | ||
97 | |||
98 | dMULTIPLY0_331( vertex, trimesh_R, int_vertex ); | ||
99 | |||
100 | #endif // dSINGLE/dDOUBLE | ||
101 | |||
102 | vertex[ 0 ] += trimesh_pos[ 0 ]; | ||
103 | vertex[ 1 ] += trimesh_pos[ 1 ]; | ||
104 | vertex[ 2 ] += trimesh_pos[ 2 ]; | ||
105 | |||
106 | |||
107 | // | ||
108 | // Collision? | ||
109 | // | ||
110 | |||
111 | // If alpha < 0 then point is if front of plane. i.e. no contact | ||
112 | // If alpha = 0 then the point is on the plane | ||
113 | alpha = plane->p[ 3 ] - dDOT( plane->p, vertex ); | ||
114 | |||
115 | // If alpha > 0 the point is behind the plane. CONTACT! | ||
116 | if ( alpha > 0 ) | ||
117 | { | ||
118 | // Alias the contact | ||
119 | dContactGeom* contact = SAFECONTACT( flags, contacts, contact_count, skip ); | ||
120 | |||
121 | contact->pos[ 0 ] = vertex[ 0 ]; | ||
122 | contact->pos[ 1 ] = vertex[ 1 ]; | ||
123 | contact->pos[ 2 ] = vertex[ 2 ]; | ||
124 | |||
125 | contact->normal[ 0 ] = plane->p[ 0 ]; | ||
126 | contact->normal[ 1 ] = plane->p[ 1 ]; | ||
127 | contact->normal[ 2 ] = plane->p[ 2 ]; | ||
128 | |||
129 | contact->depth = alpha; | ||
130 | contact->g1 = plane; | ||
131 | contact->g2 = trimesh; | ||
132 | |||
133 | ++contact_count; | ||
134 | |||
135 | // All contact slots are full? | ||
136 | if ( contact_count >= contact_max ) | ||
137 | return contact_count; // <=== STOP HERE | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | |||
142 | // Return contact count. | ||
143 | return contact_count; | ||
144 | } | ||
145 | #endif // dTRIMESH_OPCODE | ||
146 | |||
147 | #if dTRIMESH_GIMPACT | ||
148 | int dCollideTrimeshPlane( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* contacts, int skip ) | ||
149 | { | ||
150 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
151 | dIASSERT( o1->type == dTriMeshClass ); | ||
152 | dIASSERT( o2->type == dPlaneClass ); | ||
153 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
154 | |||
155 | // Alias pointers to the plane and trimesh | ||
156 | dxTriMesh* trimesh = (dxTriMesh*)( o1 ); | ||
157 | vec4f plane; | ||
158 | dGeomPlaneGetParams(o2, plane); | ||
159 | |||
160 | //Find collision | ||
161 | |||
162 | GDYNAMIC_ARRAY collision_result; | ||
163 | GIM_CREATE_TRIMESHPLANE_CONTACTS(collision_result); | ||
164 | |||
165 | gim_trimesh_plane_collision(&trimesh->m_collision_trimesh,plane,&collision_result); | ||
166 | |||
167 | if(collision_result.m_size == 0 ) | ||
168 | { | ||
169 | GIM_DYNARRAY_DESTROY(collision_result); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | |||
174 | unsigned int contactcount = collision_result.m_size; | ||
175 | unsigned int contactmax = (unsigned int)(flags & NUMC_MASK); | ||
176 | if (contactcount > contactmax) | ||
177 | { | ||
178 | contactcount = contactmax; | ||
179 | } | ||
180 | |||
181 | dContactGeom* pcontact; | ||
182 | vec4f * planecontact_results = GIM_DYNARRAY_POINTER(vec4f,collision_result); | ||
183 | |||
184 | for(unsigned int i = 0; i < contactcount; i++ ) | ||
185 | { | ||
186 | pcontact = SAFECONTACT(flags, contacts, i, skip); | ||
187 | |||
188 | pcontact->pos[0] = (*planecontact_results)[0]; | ||
189 | pcontact->pos[1] = (*planecontact_results)[1]; | ||
190 | pcontact->pos[2] = (*planecontact_results)[2]; | ||
191 | pcontact->pos[3] = REAL(1.0); | ||
192 | |||
193 | pcontact->normal[0] = plane[0]; | ||
194 | pcontact->normal[1] = plane[1]; | ||
195 | pcontact->normal[2] = plane[2]; | ||
196 | pcontact->normal[3] = 0; | ||
197 | |||
198 | pcontact->depth = (*planecontact_results)[3]; | ||
199 | pcontact->g1 = o1; | ||
200 | pcontact->g2 = o2; | ||
201 | |||
202 | planecontact_results++; | ||
203 | } | ||
204 | |||
205 | GIM_DYNARRAY_DESTROY(collision_result); | ||
206 | |||
207 | return (int)contactcount; | ||
208 | } | ||
209 | #endif // dTRIMESH_GIMPACT | ||
210 | |||
211 | |||
212 | #endif // dTRIMESH_ENABLED | ||
213 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_ray.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_ray.cpp new file mode 100755 index 0000000..c0b97ca --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_ray.cpp | |||
@@ -0,0 +1,198 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // TriMesh code by Erwin de Vries. | ||
24 | |||
25 | #include <ode/collision.h> | ||
26 | #include <ode/matrix.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/odemath.h> | ||
29 | |||
30 | #if dTRIMESH_ENABLED | ||
31 | |||
32 | #include "collision_util.h" | ||
33 | |||
34 | #define TRIMESH_INTERNAL | ||
35 | #include "collision_trimesh_internal.h" | ||
36 | |||
37 | #if dTRIMESH_OPCODE | ||
38 | int dCollideRTL(dxGeom* g1, dxGeom* RayGeom, int Flags, dContactGeom* Contacts, int Stride){ | ||
39 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
40 | dIASSERT (g1->type == dTriMeshClass); | ||
41 | dIASSERT (RayGeom->type == dRayClass); | ||
42 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
43 | |||
44 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
45 | |||
46 | const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh); | ||
47 | const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh); | ||
48 | |||
49 | RayCollider& Collider = TriMesh->_RayCollider; | ||
50 | |||
51 | dReal Length = dGeomRayGetLength(RayGeom); | ||
52 | |||
53 | int FirstContact, BackfaceCull; | ||
54 | dGeomRayGetParams(RayGeom, &FirstContact, &BackfaceCull); | ||
55 | int ClosestHit = dGeomRayGetClosestHit(RayGeom); | ||
56 | |||
57 | Collider.SetFirstContact(FirstContact != 0); | ||
58 | Collider.SetClosestHit(ClosestHit != 0); | ||
59 | Collider.SetCulling(BackfaceCull != 0); | ||
60 | Collider.SetMaxDist(Length); | ||
61 | |||
62 | dVector3 Origin, Direction; | ||
63 | dGeomRayGet(RayGeom, Origin, Direction); | ||
64 | |||
65 | /* Make Ray */ | ||
66 | Ray WorldRay; | ||
67 | WorldRay.mOrig.x = Origin[0]; | ||
68 | WorldRay.mOrig.y = Origin[1]; | ||
69 | WorldRay.mOrig.z = Origin[2]; | ||
70 | WorldRay.mDir.x = Direction[0]; | ||
71 | WorldRay.mDir.y = Direction[1]; | ||
72 | WorldRay.mDir.z = Direction[2]; | ||
73 | |||
74 | /* Intersect */ | ||
75 | Matrix4x4 amatrix; | ||
76 | int TriCount = 0; | ||
77 | if (Collider.Collide(WorldRay, TriMesh->Data->BVTree, &MakeMatrix(TLPosition, TLRotation, amatrix))) { | ||
78 | TriCount = TriMesh->Faces.GetNbFaces(); | ||
79 | } | ||
80 | |||
81 | if (TriCount == 0) { | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | const CollisionFace* Faces = TriMesh->Faces.GetFaces(); | ||
86 | |||
87 | int OutTriCount = 0; | ||
88 | for (int i = 0; i < TriCount; i++) { | ||
89 | if (TriMesh->RayCallback == null || | ||
90 | TriMesh->RayCallback(TriMesh, RayGeom, Faces[i].mFaceID, | ||
91 | Faces[i].mU, Faces[i].mV)) { | ||
92 | const int& TriIndex = Faces[i].mFaceID; | ||
93 | if (!Callback(TriMesh, RayGeom, TriIndex)) { | ||
94 | continue; | ||
95 | } | ||
96 | |||
97 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride); | ||
98 | |||
99 | dVector3 dv[3]; | ||
100 | FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv); | ||
101 | |||
102 | // No sense to save on single type conversion in algorithm of this size. | ||
103 | // If there would be a custom typedef for distance type it could be used | ||
104 | // instead of dReal. However using float directly is the loss of abstraction | ||
105 | // and possible loss of precision in future. | ||
106 | /*float*/ dReal T = Faces[i].mDistance; | ||
107 | Contact->pos[0] = Origin[0] + (Direction[0] * T); | ||
108 | Contact->pos[1] = Origin[1] + (Direction[1] * T); | ||
109 | Contact->pos[2] = Origin[2] + (Direction[2] * T); | ||
110 | Contact->pos[3] = REAL(0.0); | ||
111 | |||
112 | dVector3 vu; | ||
113 | vu[0] = dv[1][0] - dv[0][0]; | ||
114 | vu[1] = dv[1][1] - dv[0][1]; | ||
115 | vu[2] = dv[1][2] - dv[0][2]; | ||
116 | vu[3] = REAL(0.0); | ||
117 | |||
118 | dVector3 vv; | ||
119 | vv[0] = dv[2][0] - dv[0][0]; | ||
120 | vv[1] = dv[2][1] - dv[0][1]; | ||
121 | vv[2] = dv[2][2] - dv[0][2]; | ||
122 | vv[3] = REAL(0.0); | ||
123 | |||
124 | dCROSS(Contact->normal, =, vv, vu); // Reversed | ||
125 | |||
126 | dNormalize3(Contact->normal); | ||
127 | |||
128 | Contact->depth = T; | ||
129 | Contact->g1 = TriMesh; | ||
130 | Contact->g2 = RayGeom; | ||
131 | |||
132 | OutTriCount++; | ||
133 | |||
134 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
135 | if (OutTriCount >= (Flags & NUMC_MASK)) { | ||
136 | break; | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | return OutTriCount; | ||
141 | } | ||
142 | #endif // dTRIMESH_OPCODE | ||
143 | |||
144 | #if dTRIMESH_GIMPACT | ||
145 | int dCollideRTL(dxGeom* g1, dxGeom* RayGeom, int Flags, dContactGeom* Contacts, int Stride) | ||
146 | { | ||
147 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
148 | dIASSERT (g1->type == dTriMeshClass); | ||
149 | dIASSERT (RayGeom->type == dRayClass); | ||
150 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
151 | |||
152 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
153 | |||
154 | dReal Length = dGeomRayGetLength(RayGeom); | ||
155 | int FirstContact, BackfaceCull; | ||
156 | dGeomRayGetParams(RayGeom, &FirstContact, &BackfaceCull); | ||
157 | int ClosestHit = dGeomRayGetClosestHit(RayGeom); | ||
158 | dVector3 Origin, Direction; | ||
159 | dGeomRayGet(RayGeom, Origin, Direction); | ||
160 | |||
161 | char intersect=0; | ||
162 | GIM_TRIANGLE_RAY_CONTACT_DATA contact_data; | ||
163 | |||
164 | if(ClosestHit) | ||
165 | { | ||
166 | intersect = gim_trimesh_ray_closest_collision(&TriMesh->m_collision_trimesh,Origin,Direction,Length,&contact_data); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | intersect = gim_trimesh_ray_collision(&TriMesh->m_collision_trimesh,Origin,Direction,Length,&contact_data); | ||
171 | } | ||
172 | |||
173 | if(intersect == 0) | ||
174 | { | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | int OutTriCount = 0; | ||
179 | |||
180 | if(!TriMesh->RayCallback || | ||
181 | TriMesh->RayCallback(TriMesh, RayGeom, contact_data.m_face_id, contact_data.u , contact_data.v)) | ||
182 | { | ||
183 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, (OutTriCount-1), Stride); | ||
184 | VEC_COPY(Contact->pos,contact_data.m_point); | ||
185 | VEC_COPY(Contact->normal,contact_data.m_normal); | ||
186 | Contact->depth = contact_data.tparam; | ||
187 | Contact->g1 = TriMesh; | ||
188 | Contact->g2 = RayGeom; | ||
189 | |||
190 | OutTriCount = 1; | ||
191 | } | ||
192 | |||
193 | return OutTriCount; | ||
194 | } | ||
195 | #endif // dTRIMESH_GIMPACT | ||
196 | |||
197 | #endif // dTRIMESH_ENABLED | ||
198 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_sphere.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_sphere.cpp new file mode 100755 index 0000000..7ee9b4b --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_sphere.cpp | |||
@@ -0,0 +1,573 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // TriMesh code by Erwin de Vries. | ||
24 | |||
25 | #include <ode/collision.h> | ||
26 | #include <ode/matrix.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/odemath.h> | ||
29 | #include "collision_util.h" | ||
30 | |||
31 | #if dTRIMESH_ENABLED | ||
32 | |||
33 | #define TRIMESH_INTERNAL | ||
34 | #include "collision_trimesh_internal.h" | ||
35 | |||
36 | #if dTRIMESH_OPCODE | ||
37 | #define MERGECONTACTS | ||
38 | |||
39 | // Ripped from Opcode 1.1. | ||
40 | static bool GetContactData(const dVector3& Center, dReal Radius, const dVector3 Origin, const dVector3 Edge0, const dVector3 Edge1, dReal& Dist, dReal& u, dReal& v){ | ||
41 | |||
42 | // now onto the bulk of the collision... | ||
43 | |||
44 | dVector3 Diff; | ||
45 | Diff[0] = Origin[0] - Center[0]; | ||
46 | Diff[1] = Origin[1] - Center[1]; | ||
47 | Diff[2] = Origin[2] - Center[2]; | ||
48 | Diff[3] = Origin[3] - Center[3]; | ||
49 | |||
50 | dReal A00 = dDOT(Edge0, Edge0); | ||
51 | dReal A01 = dDOT(Edge0, Edge1); | ||
52 | dReal A11 = dDOT(Edge1, Edge1); | ||
53 | |||
54 | dReal B0 = dDOT(Diff, Edge0); | ||
55 | dReal B1 = dDOT(Diff, Edge1); | ||
56 | |||
57 | dReal C = dDOT(Diff, Diff); | ||
58 | |||
59 | dReal Det = dFabs(A00 * A11 - A01 * A01); | ||
60 | u = A01 * B1 - A11 * B0; | ||
61 | v = A01 * B0 - A00 * B1; | ||
62 | |||
63 | dReal DistSq; | ||
64 | |||
65 | if (u + v <= Det){ | ||
66 | if(u < REAL(0.0)){ | ||
67 | if(v < REAL(0.0)){ // region 4 | ||
68 | if(B0 < REAL(0.0)){ | ||
69 | v = REAL(0.0); | ||
70 | if (-B0 >= A00){ | ||
71 | u = REAL(1.0); | ||
72 | DistSq = A00 + REAL(2.0) * B0 + C; | ||
73 | } | ||
74 | else{ | ||
75 | u = -B0 / A00; | ||
76 | DistSq = B0 * u + C; | ||
77 | } | ||
78 | } | ||
79 | else{ | ||
80 | u = REAL(0.0); | ||
81 | if(B1 >= REAL(0.0)){ | ||
82 | v = REAL(0.0); | ||
83 | DistSq = C; | ||
84 | } | ||
85 | else if(-B1 >= A11){ | ||
86 | v = REAL(1.0); | ||
87 | DistSq = A11 + REAL(2.0) * B1 + C; | ||
88 | } | ||
89 | else{ | ||
90 | v = -B1 / A11; | ||
91 | DistSq = B1 * v + C; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | else{ // region 3 | ||
96 | u = REAL(0.0); | ||
97 | if(B1 >= REAL(0.0)){ | ||
98 | v = REAL(0.0); | ||
99 | DistSq = C; | ||
100 | } | ||
101 | else if(-B1 >= A11){ | ||
102 | v = REAL(1.0); | ||
103 | DistSq = A11 + REAL(2.0) * B1 + C; | ||
104 | } | ||
105 | else{ | ||
106 | v = -B1 / A11; | ||
107 | DistSq = B1 * v + C; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | else if(v < REAL(0.0)){ // region 5 | ||
112 | v = REAL(0.0); | ||
113 | if (B0 >= REAL(0.0)){ | ||
114 | u = REAL(0.0); | ||
115 | DistSq = C; | ||
116 | } | ||
117 | else if (-B0 >= A00){ | ||
118 | u = REAL(1.0); | ||
119 | DistSq = A00 + REAL(2.0) * B0 + C; | ||
120 | } | ||
121 | else{ | ||
122 | u = -B0 / A00; | ||
123 | DistSq = B0 * u + C; | ||
124 | } | ||
125 | } | ||
126 | else{ // region 0 | ||
127 | // minimum at interior point | ||
128 | if (Det == REAL(0.0)){ | ||
129 | u = REAL(0.0); | ||
130 | v = REAL(0.0); | ||
131 | DistSq = FLT_MAX; | ||
132 | } | ||
133 | else{ | ||
134 | dReal InvDet = REAL(1.0) / Det; | ||
135 | u *= InvDet; | ||
136 | v *= InvDet; | ||
137 | DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | else{ | ||
142 | dReal Tmp0, Tmp1, Numer, Denom; | ||
143 | |||
144 | if(u < REAL(0.0)){ // region 2 | ||
145 | Tmp0 = A01 + B0; | ||
146 | Tmp1 = A11 + B1; | ||
147 | if (Tmp1 > Tmp0){ | ||
148 | Numer = Tmp1 - Tmp0; | ||
149 | Denom = A00 - REAL(2.0) * A01 + A11; | ||
150 | if (Numer >= Denom){ | ||
151 | u = REAL(1.0); | ||
152 | v = REAL(0.0); | ||
153 | DistSq = A00 + REAL(2.0) * B0 + C; | ||
154 | } | ||
155 | else{ | ||
156 | u = Numer / Denom; | ||
157 | v = REAL(1.0) - u; | ||
158 | DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; | ||
159 | } | ||
160 | } | ||
161 | else{ | ||
162 | u = REAL(0.0); | ||
163 | if(Tmp1 <= REAL(0.0)){ | ||
164 | v = REAL(1.0); | ||
165 | DistSq = A11 + REAL(2.0) * B1 + C; | ||
166 | } | ||
167 | else if(B1 >= REAL(0.0)){ | ||
168 | v = REAL(0.0); | ||
169 | DistSq = C; | ||
170 | } | ||
171 | else{ | ||
172 | v = -B1 / A11; | ||
173 | DistSq = B1 * v + C; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | else if(v < REAL(0.0)){ // region 6 | ||
178 | Tmp0 = A01 + B1; | ||
179 | Tmp1 = A00 + B0; | ||
180 | if (Tmp1 > Tmp0){ | ||
181 | Numer = Tmp1 - Tmp0; | ||
182 | Denom = A00 - REAL(2.0) * A01 + A11; | ||
183 | if (Numer >= Denom){ | ||
184 | v = REAL(1.0); | ||
185 | u = REAL(0.0); | ||
186 | DistSq = A11 + REAL(2.0) * B1 + C; | ||
187 | } | ||
188 | else{ | ||
189 | v = Numer / Denom; | ||
190 | u = REAL(1.0) - v; | ||
191 | DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; | ||
192 | } | ||
193 | } | ||
194 | else{ | ||
195 | v = REAL(0.0); | ||
196 | if (Tmp1 <= REAL(0.0)){ | ||
197 | u = REAL(1.0); | ||
198 | DistSq = A00 + REAL(2.0) * B0 + C; | ||
199 | } | ||
200 | else if(B0 >= REAL(0.0)){ | ||
201 | u = REAL(0.0); | ||
202 | DistSq = C; | ||
203 | } | ||
204 | else{ | ||
205 | u = -B0 / A00; | ||
206 | DistSq = B0 * u + C; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | else{ // region 1 | ||
211 | Numer = A11 + B1 - A01 - B0; | ||
212 | if (Numer <= REAL(0.0)){ | ||
213 | u = REAL(0.0); | ||
214 | v = REAL(1.0); | ||
215 | DistSq = A11 + REAL(2.0) * B1 + C; | ||
216 | } | ||
217 | else{ | ||
218 | Denom = A00 - REAL(2.0) * A01 + A11; | ||
219 | if (Numer >= Denom){ | ||
220 | u = REAL(1.0); | ||
221 | v = REAL(0.0); | ||
222 | DistSq = A00 + REAL(2.0) * B0 + C; | ||
223 | } | ||
224 | else{ | ||
225 | u = Numer / Denom; | ||
226 | v = REAL(1.0) - u; | ||
227 | DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | |||
233 | Dist = dSqrt(dFabs(DistSq)); | ||
234 | |||
235 | if (Dist <= Radius){ | ||
236 | Dist = Radius - Dist; | ||
237 | return true; | ||
238 | } | ||
239 | else return false; | ||
240 | } | ||
241 | |||
242 | int dCollideSTL(dxGeom* g1, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride){ | ||
243 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
244 | dIASSERT (g1->type == dTriMeshClass); | ||
245 | dIASSERT (SphereGeom->type == dSphereClass); | ||
246 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
247 | |||
248 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
249 | |||
250 | // Init | ||
251 | const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh); | ||
252 | const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh); | ||
253 | |||
254 | SphereCollider& Collider = TriMesh->_SphereCollider; | ||
255 | |||
256 | const dVector3& Position = *(const dVector3*)dGeomGetPosition(SphereGeom); | ||
257 | dReal Radius = dGeomSphereGetRadius(SphereGeom); | ||
258 | |||
259 | // Sphere | ||
260 | Sphere Sphere; | ||
261 | Sphere.mCenter.x = Position[0]; | ||
262 | Sphere.mCenter.y = Position[1]; | ||
263 | Sphere.mCenter.z = Position[2]; | ||
264 | Sphere.mRadius = Radius; | ||
265 | |||
266 | Matrix4x4 amatrix; | ||
267 | |||
268 | // TC results | ||
269 | if (TriMesh->doSphereTC) { | ||
270 | dxTriMesh::SphereTC* sphereTC = 0; | ||
271 | for (int i = 0; i < TriMesh->SphereTCCache.size(); i++){ | ||
272 | if (TriMesh->SphereTCCache[i].Geom == SphereGeom){ | ||
273 | sphereTC = &TriMesh->SphereTCCache[i]; | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | if (!sphereTC){ | ||
279 | TriMesh->SphereTCCache.push(dxTriMesh::SphereTC()); | ||
280 | |||
281 | sphereTC = &TriMesh->SphereTCCache[TriMesh->SphereTCCache.size() - 1]; | ||
282 | sphereTC->Geom = SphereGeom; | ||
283 | } | ||
284 | |||
285 | // Intersect | ||
286 | Collider.SetTemporalCoherence(true); | ||
287 | Collider.Collide(*sphereTC, Sphere, TriMesh->Data->BVTree, null, | ||
288 | &MakeMatrix(TLPosition, TLRotation, amatrix)); | ||
289 | } | ||
290 | else { | ||
291 | Collider.SetTemporalCoherence(false); | ||
292 | Collider.Collide(dxTriMesh::defaultSphereCache, Sphere, TriMesh->Data->BVTree, null, | ||
293 | &MakeMatrix(TLPosition, TLRotation, amatrix)); | ||
294 | } | ||
295 | |||
296 | if (! Collider.GetContactStatus()) { | ||
297 | // no collision occurred | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | // get results | ||
302 | int TriCount = Collider.GetNbTouchedPrimitives(); | ||
303 | const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); | ||
304 | |||
305 | if (TriCount != 0){ | ||
306 | if (TriMesh->ArrayCallback != null){ | ||
307 | TriMesh->ArrayCallback(TriMesh, SphereGeom, Triangles, TriCount); | ||
308 | } | ||
309 | |||
310 | int OutTriCount = 0; | ||
311 | for (int i = 0; i < TriCount; i++){ | ||
312 | if (OutTriCount == (Flags & NUMC_MASK)){ | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | const int TriIndex = Triangles[i]; | ||
317 | |||
318 | dVector3 dv[3]; | ||
319 | if (!Callback(TriMesh, SphereGeom, TriIndex)) | ||
320 | continue; | ||
321 | FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv); | ||
322 | |||
323 | dVector3& v0 = dv[0]; | ||
324 | dVector3& v1 = dv[1]; | ||
325 | dVector3& v2 = dv[2]; | ||
326 | |||
327 | dVector3 vu; | ||
328 | vu[0] = v1[0] - v0[0]; | ||
329 | vu[1] = v1[1] - v0[1]; | ||
330 | vu[2] = v1[2] - v0[2]; | ||
331 | vu[3] = REAL(0.0); | ||
332 | |||
333 | dVector3 vv; | ||
334 | vv[0] = v2[0] - v0[0]; | ||
335 | vv[1] = v2[1] - v0[1]; | ||
336 | vv[2] = v2[2] - v0[2]; | ||
337 | vv[3] = REAL(0.0); | ||
338 | |||
339 | // Get plane coefficients | ||
340 | dVector4 Plane; | ||
341 | dCROSS(Plane, =, vu, vv); | ||
342 | |||
343 | dReal Area = dSqrt(dDOT(Plane, Plane)); // We can use this later | ||
344 | Plane[0] /= Area; | ||
345 | Plane[1] /= Area; | ||
346 | Plane[2] /= Area; | ||
347 | |||
348 | Plane[3] = dDOT(Plane, v0); | ||
349 | |||
350 | /* If the center of the sphere is within the positive halfspace of the | ||
351 | * triangle's plane, allow a contact to be generated. | ||
352 | * If the center of the sphere made it into the positive halfspace of a | ||
353 | * back-facing triangle, then the physics update and/or velocity needs | ||
354 | * to be adjusted (penetration has occured anyway). | ||
355 | */ | ||
356 | |||
357 | dReal side = dDOT(Plane,Position) - Plane[3]; | ||
358 | |||
359 | if(side < REAL(0.0)) { | ||
360 | continue; | ||
361 | } | ||
362 | |||
363 | dReal Depth; | ||
364 | dReal u, v; | ||
365 | if (!GetContactData(Position, Radius, v0, vu, vv, Depth, u, v)){ | ||
366 | continue; // Sphere doesn't hit triangle | ||
367 | } | ||
368 | |||
369 | if (Depth < REAL(0.0)){ | ||
370 | Depth = REAL(0.0); | ||
371 | } | ||
372 | |||
373 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride); | ||
374 | |||
375 | dReal w = REAL(1.0) - u - v; | ||
376 | Contact->pos[0] = (v0[0] * w) + (v1[0] * u) + (v2[0] * v); | ||
377 | Contact->pos[1] = (v0[1] * w) + (v1[1] * u) + (v2[1] * v); | ||
378 | Contact->pos[2] = (v0[2] * w) + (v1[2] * u) + (v2[2] * v); | ||
379 | Contact->pos[3] = REAL(0.0); | ||
380 | |||
381 | // Using normal as plane (reversed) | ||
382 | Contact->normal[0] = -Plane[0]; | ||
383 | Contact->normal[1] = -Plane[1]; | ||
384 | Contact->normal[2] = -Plane[2]; | ||
385 | Contact->normal[3] = REAL(0.0); | ||
386 | |||
387 | // Depth returned from GetContactData is depth along | ||
388 | // contact point - sphere center direction | ||
389 | // we'll project it to contact normal | ||
390 | dVector3 dir; | ||
391 | dir[0] = Position[0]-Contact->pos[0]; | ||
392 | dir[1] = Position[1]-Contact->pos[1]; | ||
393 | dir[2] = Position[2]-Contact->pos[2]; | ||
394 | dReal dirProj = dDOT(dir, Plane) / dSqrt(dDOT(dir, dir)); | ||
395 | Contact->depth = Depth * dirProj; | ||
396 | //Contact->depth = Radius - side; // (mg) penetration depth is distance along normal not shortest distance | ||
397 | Contact->side1 = TriIndex; | ||
398 | |||
399 | //Contact->g1 = TriMesh; | ||
400 | //Contact->g2 = SphereGeom; | ||
401 | |||
402 | OutTriCount++; | ||
403 | } | ||
404 | #ifdef MERGECONTACTS // Merge all contacts into 1 | ||
405 | if (OutTriCount != 0){ | ||
406 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, 0, Stride); | ||
407 | |||
408 | if (OutTriCount != 1 && !(Flags & CONTACTS_UNIMPORTANT)){ | ||
409 | Contact->normal[0] *= Contact->depth; | ||
410 | Contact->normal[1] *= Contact->depth; | ||
411 | Contact->normal[2] *= Contact->depth; | ||
412 | Contact->normal[3] *= Contact->depth; | ||
413 | |||
414 | for (int i = 1; i < OutTriCount; i++){ | ||
415 | dContactGeom* TempContact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
416 | |||
417 | Contact->pos[0] += TempContact->pos[0]; | ||
418 | Contact->pos[1] += TempContact->pos[1]; | ||
419 | Contact->pos[2] += TempContact->pos[2]; | ||
420 | Contact->pos[3] += TempContact->pos[3]; | ||
421 | |||
422 | Contact->normal[0] += TempContact->normal[0] * TempContact->depth; | ||
423 | Contact->normal[1] += TempContact->normal[1] * TempContact->depth; | ||
424 | Contact->normal[2] += TempContact->normal[2] * TempContact->depth; | ||
425 | Contact->normal[3] += TempContact->normal[3] * TempContact->depth; | ||
426 | } | ||
427 | |||
428 | Contact->pos[0] /= OutTriCount; | ||
429 | Contact->pos[1] /= OutTriCount; | ||
430 | Contact->pos[2] /= OutTriCount; | ||
431 | Contact->pos[3] /= OutTriCount; | ||
432 | |||
433 | // Remember to divide in square space. | ||
434 | Contact->depth = dSqrt(dDOT(Contact->normal, Contact->normal) / OutTriCount); | ||
435 | |||
436 | dNormalize3(Contact->normal); | ||
437 | } | ||
438 | |||
439 | Contact->g1 = TriMesh; | ||
440 | Contact->g2 = SphereGeom; | ||
441 | |||
442 | // TODO: | ||
443 | // Side1 now contains index of triangle that gave first hit | ||
444 | // Probably we should find index of triangle with deepest penetration | ||
445 | |||
446 | return 1; | ||
447 | } | ||
448 | else return 0; | ||
449 | #elif defined MERGECONTACTNORMALS // Merge all normals, and distribute between all contacts | ||
450 | if (OutTriCount != 0){ | ||
451 | if (OutTriCount != 1 && !(Flags & CONTACTS_UNIMPORTANT)){ | ||
452 | dVector3& Normal = SAFECONTACT(Flags, Contacts, 0, Stride)->normal; | ||
453 | Normal[0] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; | ||
454 | Normal[1] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; | ||
455 | Normal[2] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; | ||
456 | Normal[3] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; | ||
457 | |||
458 | for (int i = 1; i < OutTriCount; i++){ | ||
459 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
460 | |||
461 | Normal[0] += Contact->normal[0] * Contact->depth; | ||
462 | Normal[1] += Contact->normal[1] * Contact->depth; | ||
463 | Normal[2] += Contact->normal[2] * Contact->depth; | ||
464 | Normal[3] += Contact->normal[3] * Contact->depth; | ||
465 | } | ||
466 | dNormalize3(Normal); | ||
467 | |||
468 | for (int i = 1; i < OutTriCount; i++){ | ||
469 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
470 | |||
471 | Contact->normal[0] = Normal[0]; | ||
472 | Contact->normal[1] = Normal[1]; | ||
473 | Contact->normal[2] = Normal[2]; | ||
474 | Contact->normal[3] = Normal[3]; | ||
475 | |||
476 | Contact->g1 = TriMesh; | ||
477 | Contact->g2 = SphereGeom; | ||
478 | } | ||
479 | } | ||
480 | else{ | ||
481 | SAFECONTACT(Flags, Contacts, 0, Stride)->g1 = TriMesh; | ||
482 | SAFECONTACT(Flags, Contacts, 0, Stride)->g2 = SphereGeom; | ||
483 | } | ||
484 | |||
485 | return OutTriCount; | ||
486 | } | ||
487 | else return 0; | ||
488 | #else //MERGECONTACTNORMALS // Just gather penetration depths and return | ||
489 | for (int i = 0; i < OutTriCount; i++){ | ||
490 | dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
491 | |||
492 | //Contact->depth = dSqrt(dDOT(Contact->normal, Contact->normal)); | ||
493 | |||
494 | /*Contact->normal[0] /= Contact->depth; | ||
495 | Contact->normal[1] /= Contact->depth; | ||
496 | Contact->normal[2] /= Contact->depth; | ||
497 | Contact->normal[3] /= Contact->depth;*/ | ||
498 | |||
499 | Contact->g1 = TriMesh; | ||
500 | Contact->g2 = SphereGeom; | ||
501 | } | ||
502 | |||
503 | return OutTriCount; | ||
504 | #endif // MERGECONTACTS | ||
505 | } | ||
506 | else return 0; | ||
507 | } | ||
508 | #endif // dTRIMESH_OPCODE | ||
509 | |||
510 | #if dTRIMESH_GIMPACT | ||
511 | int dCollideSTL(dxGeom* g1, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride) | ||
512 | { | ||
513 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
514 | dIASSERT (g1->type == dTriMeshClass); | ||
515 | dIASSERT (SphereGeom->type == dSphereClass); | ||
516 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
517 | |||
518 | dxTriMesh* TriMesh = (dxTriMesh*)g1; | ||
519 | dVector3& Position = *(dVector3*)dGeomGetPosition(SphereGeom); | ||
520 | dReal Radius = dGeomSphereGetRadius(SphereGeom); | ||
521 | //Create contact list | ||
522 | GDYNAMIC_ARRAY trimeshcontacts; | ||
523 | GIM_CREATE_CONTACT_LIST(trimeshcontacts); | ||
524 | |||
525 | //Collide trimeshes | ||
526 | gim_trimesh_sphere_collision(&TriMesh->m_collision_trimesh,Position,Radius,&trimeshcontacts); | ||
527 | |||
528 | if(trimeshcontacts.m_size == 0) | ||
529 | { | ||
530 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | GIM_CONTACT * ptrimeshcontacts = GIM_DYNARRAY_POINTER(GIM_CONTACT,trimeshcontacts); | ||
535 | |||
536 | unsigned contactcount = trimeshcontacts.m_size; | ||
537 | unsigned maxcontacts = (unsigned)(Flags & NUMC_MASK); | ||
538 | if (contactcount > maxcontacts) | ||
539 | { | ||
540 | contactcount = maxcontacts; | ||
541 | } | ||
542 | |||
543 | dContactGeom* pcontact; | ||
544 | unsigned i; | ||
545 | |||
546 | for (i=0;i<contactcount;i++) | ||
547 | { | ||
548 | pcontact = SAFECONTACT(Flags, Contacts, i, Stride); | ||
549 | |||
550 | pcontact->pos[0] = ptrimeshcontacts->m_point[0]; | ||
551 | pcontact->pos[1] = ptrimeshcontacts->m_point[1]; | ||
552 | pcontact->pos[2] = ptrimeshcontacts->m_point[2]; | ||
553 | pcontact->pos[3] = REAL(1.0); | ||
554 | |||
555 | pcontact->normal[0] = ptrimeshcontacts->m_normal[0]; | ||
556 | pcontact->normal[1] = ptrimeshcontacts->m_normal[1]; | ||
557 | pcontact->normal[2] = ptrimeshcontacts->m_normal[2]; | ||
558 | pcontact->normal[3] = 0; | ||
559 | |||
560 | pcontact->depth = ptrimeshcontacts->m_depth; | ||
561 | pcontact->g1 = g1; | ||
562 | pcontact->g2 = SphereGeom; | ||
563 | |||
564 | ptrimeshcontacts++; | ||
565 | } | ||
566 | |||
567 | GIM_DYNARRAY_DESTROY(trimeshcontacts); | ||
568 | |||
569 | return (int)contactcount; | ||
570 | } | ||
571 | #endif // dTRIMESH_GIMPACT | ||
572 | |||
573 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh.cpp new file mode 100755 index 0000000..c9f209e --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh.cpp | |||
@@ -0,0 +1,2033 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // OPCODE TriMesh/TriMesh collision code by Jeff Smith (c) 2004 | ||
24 | |||
25 | #ifdef _MSC_VER | ||
26 | #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints | ||
27 | #endif | ||
28 | |||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | |||
34 | // Classic Implementation | ||
35 | #if !dTRIMESH_OPCODE_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
36 | |||
37 | #if dTRIMESH_ENABLED | ||
38 | |||
39 | #include "collision_util.h" | ||
40 | #define TRIMESH_INTERNAL | ||
41 | #include "collision_trimesh_internal.h" | ||
42 | |||
43 | #if dTRIMESH_OPCODE | ||
44 | |||
45 | #define SMALL_ELT REAL(2.5e-4) | ||
46 | #define EXPANDED_ELT_THRESH REAL(1.0e-3) | ||
47 | #define DISTANCE_EPSILON REAL(1.0e-8) | ||
48 | #define VELOCITY_EPSILON REAL(1.0e-5) | ||
49 | #define TINY_PENETRATION REAL(5.0e-6) | ||
50 | |||
51 | struct LineContactSet | ||
52 | { | ||
53 | enum | ||
54 | { | ||
55 | MAX_POINTS = 8 | ||
56 | }; | ||
57 | |||
58 | dVector3 Points[MAX_POINTS]; | ||
59 | int Count; | ||
60 | }; | ||
61 | |||
62 | |||
63 | static void GetTriangleGeometryCallback(udword, VertexPointers&, udword); | ||
64 | static void GenerateContact(int, dContactGeom*, int, dxTriMesh*, dxTriMesh*, | ||
65 | const dVector3, const dVector3, dReal, int&); | ||
66 | static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
67 | dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, | ||
68 | dReal isectpt1[3],dReal isectpt2[3]); | ||
69 | inline void dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B); | ||
70 | static void dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ); | ||
71 | static int IntersectLineSegmentRay(dVector3, dVector3, dVector3, dVector3, dVector3); | ||
72 | static bool FindTriSolidIntrsection(const dVector3 Tri[3], | ||
73 | const dVector4 Planes[6], int numSides, | ||
74 | LineContactSet& ClippedPolygon ); | ||
75 | static void ClipConvexPolygonAgainstPlane( const dVector3, dReal, LineContactSet& ); | ||
76 | static bool SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, | ||
77 | dVector3 in_n, dVector3* in_col_v, dReal &out_depth); | ||
78 | static int ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point); | ||
79 | static int RayTriangleIntersect(const dVector3 orig, const dVector3 dir, | ||
80 | const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, | ||
81 | dReal *t,dReal *u,dReal *v); | ||
82 | |||
83 | |||
84 | |||
85 | |||
86 | /* some math macros */ | ||
87 | #define CROSS(dest,v1,v2) { dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ | ||
88 | dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ | ||
89 | dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; } | ||
90 | |||
91 | #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) | ||
92 | |||
93 | #define SUB(dest,v1,v2) { dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; } | ||
94 | |||
95 | #define ADD(dest,v1,v2) { dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; } | ||
96 | |||
97 | #define MULT(dest,v,factor) { dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2]; } | ||
98 | |||
99 | #define SET(dest,src) { dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; } | ||
100 | |||
101 | #define SMULT(p,q,s) { p[0]=q[0]*s; p[1]=q[1]*s; p[2]=q[2]*s; } | ||
102 | |||
103 | #define COMBO(combo,p,t,q) { combo[0]=p[0]+t*q[0]; combo[1]=p[1]+t*q[1]; combo[2]=p[2]+t*q[2]; } | ||
104 | |||
105 | #define LENGTH(x) ((dReal) dSqrt(dDOT(x, x))) | ||
106 | |||
107 | #define DEPTH(d, p, q, n) d = (p[0] - q[0])*n[0] + (p[1] - q[1])*n[1] + (p[2] - q[2])*n[2]; | ||
108 | |||
109 | inline const dReal dMin(const dReal x, const dReal y) | ||
110 | { | ||
111 | return x < y ? x : y; | ||
112 | } | ||
113 | |||
114 | |||
115 | inline void | ||
116 | SwapNormals(dVector3 *&pen_v, dVector3 *&col_v, dVector3* v1, dVector3* v2, | ||
117 | dVector3 *&pen_elt, dVector3 *elt_f1, dVector3 *elt_f2, | ||
118 | dVector3 n, dVector3 n1, dVector3 n2) | ||
119 | { | ||
120 | if (pen_v == v1) { | ||
121 | pen_v = v2; | ||
122 | pen_elt = elt_f2; | ||
123 | col_v = v1; | ||
124 | SET(n, n1); | ||
125 | } | ||
126 | else { | ||
127 | pen_v = v1; | ||
128 | pen_elt = elt_f1; | ||
129 | col_v = v2; | ||
130 | SET(n, n2); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | |||
137 | int | ||
138 | dCollideTTL(dxGeom* g1, dxGeom* g2, int Flags, dContactGeom* Contacts, int Stride) | ||
139 | { | ||
140 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
141 | dIASSERT (g1->type == dTriMeshClass); | ||
142 | dIASSERT (g2->type == dTriMeshClass); | ||
143 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
144 | |||
145 | dxTriMesh* TriMesh1 = (dxTriMesh*) g1; | ||
146 | dxTriMesh* TriMesh2 = (dxTriMesh*) g2; | ||
147 | |||
148 | dReal * TriNormals1 = (dReal *) TriMesh1->Data->Normals; | ||
149 | dReal * TriNormals2 = (dReal *) TriMesh2->Data->Normals; | ||
150 | |||
151 | const dVector3& TLPosition1 = *(const dVector3*) dGeomGetPosition(TriMesh1); | ||
152 | // TLRotation1 = column-major order | ||
153 | const dMatrix3& TLRotation1 = *(const dMatrix3*) dGeomGetRotation(TriMesh1); | ||
154 | |||
155 | const dVector3& TLPosition2 = *(const dVector3*) dGeomGetPosition(TriMesh2); | ||
156 | // TLRotation2 = column-major order | ||
157 | const dMatrix3& TLRotation2 = *(const dMatrix3*) dGeomGetRotation(TriMesh2); | ||
158 | |||
159 | AABBTreeCollider& Collider = TriMesh1->_AABBTreeCollider; | ||
160 | |||
161 | static BVTCache ColCache; | ||
162 | ColCache.Model0 = &TriMesh1->Data->BVTree; | ||
163 | ColCache.Model1 = &TriMesh2->Data->BVTree; | ||
164 | |||
165 | // Collision query | ||
166 | Matrix4x4 amatrix, bmatrix; | ||
167 | BOOL IsOk = Collider.Collide(ColCache, | ||
168 | &MakeMatrix(TLPosition1, TLRotation1, amatrix), | ||
169 | &MakeMatrix(TLPosition2, TLRotation2, bmatrix) ); | ||
170 | |||
171 | |||
172 | // Make "double" versions of these matrices, if appropriate | ||
173 | dMatrix4 A, B; | ||
174 | dMakeMatrix4(TLPosition1, TLRotation1, A); | ||
175 | dMakeMatrix4(TLPosition2, TLRotation2, B); | ||
176 | |||
177 | |||
178 | if (IsOk) { | ||
179 | // Get collision status => if true, objects overlap | ||
180 | if ( Collider.GetContactStatus() ) { | ||
181 | // Number of colliding pairs and list of pairs | ||
182 | int TriCount = Collider.GetNbPairs(); | ||
183 | const Pair* CollidingPairs = Collider.GetPairs(); | ||
184 | |||
185 | if (TriCount > 0) { | ||
186 | // step through the pairs, adding contacts | ||
187 | int id1, id2; | ||
188 | int OutTriCount = 0; | ||
189 | dVector3 v1[3], v2[3], CoplanarPt; | ||
190 | dVector3 e1, e2, e3, n1, n2, n, ContactNormal; | ||
191 | dReal depth; | ||
192 | dVector3 orig_pos, old_pos1, old_pos2, elt1, elt2, elt_sum; | ||
193 | dVector3 elt_f1[3], elt_f2[3]; | ||
194 | dReal contact_elt_length = SMALL_ELT; | ||
195 | LineContactSet firstClippedTri, secondClippedTri; | ||
196 | dVector3 *firstClippedElt = new dVector3[LineContactSet::MAX_POINTS]; | ||
197 | dVector3 *secondClippedElt = new dVector3[LineContactSet::MAX_POINTS]; | ||
198 | |||
199 | |||
200 | // only do these expensive inversions once | ||
201 | dMatrix4 InvMatrix1, InvMatrix2; | ||
202 | dInvertMatrix4(A, InvMatrix1); | ||
203 | dInvertMatrix4(B, InvMatrix2); | ||
204 | |||
205 | |||
206 | for (int i = 0; i < TriCount; i++) { | ||
207 | |||
208 | id1 = CollidingPairs[i].id0; | ||
209 | id2 = CollidingPairs[i].id1; | ||
210 | |||
211 | // grab the colliding triangles | ||
212 | FetchTriangle((dxTriMesh*) g1, id1, TLPosition1, TLRotation1, v1); | ||
213 | FetchTriangle((dxTriMesh*) g2, id2, TLPosition2, TLRotation2, v2); | ||
214 | // Since we'll be doing matrix transfomrations, we need to | ||
215 | // make sure that all vertices have four elements | ||
216 | for (int j=0; j<3; j++) { | ||
217 | v1[j][3] = 1.0; | ||
218 | v2[j][3] = 1.0; | ||
219 | } | ||
220 | |||
221 | |||
222 | int IsCoplanar = 0; | ||
223 | dReal IsectPt1[3], IsectPt2[3]; | ||
224 | |||
225 | // Sometimes OPCODE makes mistakes, so we look at the return | ||
226 | // value for TriTriIntersectWithIsectLine. A retcode of "0" | ||
227 | // means no intersection took place | ||
228 | if ( TriTriIntersectWithIsectLine( v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], | ||
229 | &IsCoplanar, | ||
230 | IsectPt1, IsectPt2) ) { | ||
231 | |||
232 | // Compute the normals of the colliding faces | ||
233 | // | ||
234 | if (TriNormals1 == NULL) { | ||
235 | SUB( e1, v1[1], v1[0] ); | ||
236 | SUB( e2, v1[2], v1[0] ); | ||
237 | CROSS( n1, e1, e2 ); | ||
238 | dNormalize3(n1); | ||
239 | } | ||
240 | else { | ||
241 | // If we were passed normals, we need to adjust them to take into | ||
242 | // account the objects' current rotations | ||
243 | e1[0] = TriNormals1[id1*3]; | ||
244 | e1[1] = TriNormals1[id1*3 + 1]; | ||
245 | e1[2] = TriNormals1[id1*3 + 2]; | ||
246 | e1[3] = 0.0; | ||
247 | |||
248 | //dMultiply1(n1, TLRotation1, e1, 3, 3, 1); | ||
249 | dMultiply0(n1, TLRotation1, e1, 3, 3, 1); | ||
250 | n1[3] = 1.0; | ||
251 | } | ||
252 | |||
253 | if (TriNormals2 == NULL) { | ||
254 | SUB( e1, v2[1], v2[0] ); | ||
255 | SUB( e2, v2[2], v2[0] ); | ||
256 | CROSS( n2, e1, e2); | ||
257 | dNormalize3(n2); | ||
258 | } | ||
259 | else { | ||
260 | // If we were passed normals, we need to adjust them to take into | ||
261 | // account the objects' current rotations | ||
262 | e2[0] = TriNormals2[id2*3]; | ||
263 | e2[1] = TriNormals2[id2*3 + 1]; | ||
264 | e2[2] = TriNormals2[id2*3 + 2]; | ||
265 | e2[3] = 0.0; | ||
266 | |||
267 | //dMultiply1(n2, TLRotation2, e2, 3, 3, 1); | ||
268 | dMultiply0(n2, TLRotation2, e2, 3, 3, 1); | ||
269 | n2[3] = 1.0; | ||
270 | } | ||
271 | |||
272 | |||
273 | if (IsCoplanar) { | ||
274 | // We can reach this case if the faces are coplanar, OR | ||
275 | // if they don't actually intersect. (OPCODE can make | ||
276 | // mistakes) | ||
277 | if (dFabs(dDOT(n1, n2)) > REAL(0.999)) { | ||
278 | // If the faces are coplanar, we declare that the point of | ||
279 | // contact is at the average location of the vertices of | ||
280 | // both faces | ||
281 | dVector3 ContactPt; | ||
282 | for (int j=0; j<3; j++) { | ||
283 | ContactPt[j] = 0.0; | ||
284 | for (int k=0; k<3; k++) | ||
285 | ContactPt[j] += v1[k][j] + v2[k][j]; | ||
286 | ContactPt[j] /= 6.0; | ||
287 | } | ||
288 | ContactPt[3] = 1.0; | ||
289 | |||
290 | // and the contact normal is the normal of face 2 | ||
291 | // (could be face 1, because they are the same) | ||
292 | SET(n, n2); | ||
293 | |||
294 | // and the penetration depth is the co-normal | ||
295 | // distance between any two vertices A and B, | ||
296 | // i.e. d = DOT(n, (A-B)) | ||
297 | DEPTH(depth, v1[1], v2[1], n); | ||
298 | if (depth < 0) | ||
299 | depth *= -1.0; | ||
300 | |||
301 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
302 | ContactPt, n, depth, OutTriCount); | ||
303 | } | ||
304 | } | ||
305 | else { | ||
306 | // Otherwise (in non-co-planar cases), we create a coplanar | ||
307 | // point -- the middle of the line of intersection -- that | ||
308 | // will be used for various computations down the road | ||
309 | for (int j=0; j<3; j++) | ||
310 | CoplanarPt[j] = ( (IsectPt1[j] + IsectPt2[j]) / REAL(2.0) ); | ||
311 | CoplanarPt[3] = 1.0; | ||
312 | |||
313 | // Find the ELT of the coplanar point | ||
314 | // | ||
315 | dMultiply1(orig_pos, InvMatrix1, CoplanarPt, 4, 4, 1); | ||
316 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
317 | SUB(elt1, CoplanarPt, old_pos1); | ||
318 | |||
319 | dMultiply1(orig_pos, InvMatrix2, CoplanarPt, 4, 4, 1); | ||
320 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
321 | SUB(elt2, CoplanarPt, old_pos2); | ||
322 | |||
323 | SUB(elt_sum, elt1, elt2); // net motion of the coplanar point | ||
324 | |||
325 | |||
326 | // Calculate how much the vertices of each face moved in the | ||
327 | // direction of the opposite face's normal | ||
328 | // | ||
329 | dReal total_dp1, total_dp2; | ||
330 | total_dp1 = 0.0; | ||
331 | total_dp2 = 0.0; | ||
332 | |||
333 | for (int ii=0; ii<3; ii++) { | ||
334 | // find the estimated linear translation (ELT) of the vertices | ||
335 | // on face 1, wrt to the center of face 2. | ||
336 | |||
337 | // un-transform this vertex by the current transform | ||
338 | dMultiply1(orig_pos, InvMatrix1, v1[ii], 4, 4, 1 ); | ||
339 | |||
340 | // re-transform this vertex by last_trans (to get its old | ||
341 | // position) | ||
342 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
343 | |||
344 | // Then subtract this position from our current one to find | ||
345 | // the elapsed linear translation (ELT) | ||
346 | for (int k=0; k<3; k++) { | ||
347 | elt_f1[ii][k] = (v1[ii][k] - old_pos1[k]) - elt2[k]; | ||
348 | } | ||
349 | |||
350 | // Take the dot product of the ELT for each vertex (wrt the | ||
351 | // center of face2) | ||
352 | total_dp1 += dFabs( dDOT(elt_f1[ii], n2) ); | ||
353 | } | ||
354 | |||
355 | for (int ii=0; ii<3; ii++) { | ||
356 | // find the estimated linear translation (ELT) of the vertices | ||
357 | // on face 2, wrt to the center of face 1. | ||
358 | dMultiply1(orig_pos, InvMatrix2, v2[ii], 4, 4, 1); | ||
359 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
360 | for (int k=0; k<3; k++) { | ||
361 | elt_f2[ii][k] = (v2[ii][k] - old_pos2[k]) - elt1[k]; | ||
362 | } | ||
363 | |||
364 | // Take the dot product of the ELT for each vertex (wrt the | ||
365 | // center of face2) and add them | ||
366 | total_dp2 += dFabs( dDOT(elt_f2[ii], n1) ); | ||
367 | } | ||
368 | |||
369 | |||
370 | //////// | ||
371 | // Estimate the penetration depth. | ||
372 | // | ||
373 | dReal dp; | ||
374 | BOOL badPen = true; | ||
375 | dVector3 *pen_v; // the "penetrating vertices" | ||
376 | dVector3 *pen_elt; // the elt_f of the penetrating face | ||
377 | dVector3 *col_v; // the "collision vertices" (the penetrated face) | ||
378 | |||
379 | SMULT(n2, n2, -1.0); // SF PATCH #1335183 | ||
380 | depth = 0.0; | ||
381 | if ((total_dp1 > DISTANCE_EPSILON) || (total_dp2 > DISTANCE_EPSILON)) { | ||
382 | //////// | ||
383 | // Find the collision normal, by finding the face | ||
384 | // that is pointed "most" in the direction of travel | ||
385 | // of the two triangles | ||
386 | // | ||
387 | if (total_dp2 > total_dp1) { | ||
388 | pen_v = v2; | ||
389 | pen_elt = elt_f2; | ||
390 | col_v = v1; | ||
391 | SET(n, n1); | ||
392 | } | ||
393 | else { | ||
394 | pen_v = v1; | ||
395 | pen_elt = elt_f1; | ||
396 | col_v = v2; | ||
397 | SET(n, n2); | ||
398 | } | ||
399 | } | ||
400 | else { | ||
401 | // the total_dp is very small, so let's fall back | ||
402 | // to a different test | ||
403 | if (LENGTH(elt2) > LENGTH(elt1)) { | ||
404 | pen_v = v2; | ||
405 | pen_elt = elt_f2; | ||
406 | col_v = v1; | ||
407 | SET(n, n1); | ||
408 | } | ||
409 | else { | ||
410 | pen_v = v1; | ||
411 | pen_elt = elt_f1; | ||
412 | col_v = v2; | ||
413 | SET(n, n2); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | |||
418 | for (int j=0; j<3; j++) | ||
419 | if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { | ||
420 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
421 | pen_v[j], n, depth, OutTriCount); | ||
422 | badPen = false; | ||
423 | |||
424 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | |||
430 | if (badPen) { | ||
431 | // try the other normal | ||
432 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
433 | |||
434 | for (int j=0; j<3; j++) | ||
435 | if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { | ||
436 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
437 | pen_v[j], n, depth, OutTriCount); | ||
438 | badPen = false; | ||
439 | |||
440 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | |||
448 | //////////////////////////////////////// | ||
449 | // | ||
450 | // If we haven't found a good penetration, then we're probably straddling | ||
451 | // the edge of one of the objects, or the penetraing face is big | ||
452 | // enough that all of its vertices are outside the bounds of the | ||
453 | // penetrated face. | ||
454 | // In these cases, we do a more expensive test. We clip the penetrating | ||
455 | // triangle with a solid defined by the penetrated triangle, and repeat | ||
456 | // the tests above on this new polygon | ||
457 | if (badPen) { | ||
458 | |||
459 | // Switch pen_v and n back again | ||
460 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
461 | |||
462 | |||
463 | // Find the three sides (no top or bottom) of the solid defined by | ||
464 | // the edges of the penetrated triangle. | ||
465 | |||
466 | // The dVector4 "plane" structures contain the following information: | ||
467 | // [0]-[2]: The normal of the face, pointing INWARDS (i.e. | ||
468 | // the inverse normal | ||
469 | // [3]: The distance between the face and the center of the | ||
470 | // solid, along the normal | ||
471 | dVector4 SolidPlanes[3]; | ||
472 | dVector3 tmp1; | ||
473 | dVector3 sn; | ||
474 | |||
475 | for (int j=0; j<3; j++) { | ||
476 | e1[j] = col_v[1][j] - col_v[0][j]; | ||
477 | e2[j] = col_v[0][j] - col_v[2][j]; | ||
478 | e3[j] = col_v[2][j] - col_v[1][j]; | ||
479 | } | ||
480 | |||
481 | // side 1 | ||
482 | CROSS(sn, e1, n); | ||
483 | dNormalize3(sn); | ||
484 | SMULT( SolidPlanes[0], sn, -1.0 ); | ||
485 | |||
486 | ADD(tmp1, col_v[0], col_v[1]); | ||
487 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
488 | // distance from center to edge along normal | ||
489 | SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); | ||
490 | |||
491 | |||
492 | // side 2 | ||
493 | CROSS(sn, e2, n); | ||
494 | dNormalize3(sn); | ||
495 | SMULT( SolidPlanes[1], sn, -1.0 ); | ||
496 | |||
497 | ADD(tmp1, col_v[0], col_v[2]); | ||
498 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
499 | // distance from center to edge along normal | ||
500 | SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); | ||
501 | |||
502 | |||
503 | // side 3 | ||
504 | CROSS(sn, e3, n); | ||
505 | dNormalize3(sn); | ||
506 | SMULT( SolidPlanes[2], sn, -1.0 ); | ||
507 | |||
508 | ADD(tmp1, col_v[2], col_v[1]); | ||
509 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
510 | // distance from center to edge along normal | ||
511 | SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); | ||
512 | |||
513 | |||
514 | FindTriSolidIntrsection(pen_v, SolidPlanes, 3, firstClippedTri); | ||
515 | |||
516 | for (int j=0; j<firstClippedTri.Count; j++) { | ||
517 | firstClippedTri.Points[j][3] = 1.0; // because we will be doing matrix mults | ||
518 | |||
519 | DEPTH(dp, CoplanarPt, firstClippedTri.Points[j], n); | ||
520 | |||
521 | // if the penetration depth (calculated above) is more than the contact | ||
522 | // point's ELT, then we've chosen the wrong face and should switch faces | ||
523 | if (pen_v == v1) { | ||
524 | dMultiply1(orig_pos, InvMatrix1, firstClippedTri.Points[j], 4, 4, 1); | ||
525 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
526 | for (int k=0; k<3; k++) { | ||
527 | firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; | ||
528 | } | ||
529 | } | ||
530 | else { | ||
531 | dMultiply1(orig_pos, InvMatrix2, firstClippedTri.Points[j], 4, 4, 1); | ||
532 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
533 | for (int k=0; k<3; k++) { | ||
534 | firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | if (dp >= 0.0) { | ||
539 | contact_elt_length = dFabs(dDOT(firstClippedElt[j], n)); | ||
540 | |||
541 | depth = dp; | ||
542 | if (depth == 0.0) | ||
543 | depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
544 | |||
545 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
546 | depth = contact_elt_length; | ||
547 | |||
548 | if (depth <= contact_elt_length) { | ||
549 | // Add a contact | ||
550 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
551 | firstClippedTri.Points[j], n, depth, OutTriCount); | ||
552 | badPen = false; | ||
553 | |||
554 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | } | ||
561 | } | ||
562 | |||
563 | if (badPen) { | ||
564 | // Switch pen_v and n (again!) | ||
565 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
566 | |||
567 | |||
568 | // Find the three sides (no top or bottom) of the solid created by | ||
569 | // the penetrated triangle. | ||
570 | // The dVector4 "plane" structures contain the following information: | ||
571 | // [0]-[2]: The normal of the face, pointing INWARDS (i.e. | ||
572 | // the inverse normal | ||
573 | // [3]: The distance between the face and the center of the | ||
574 | // solid, along the normal | ||
575 | dVector4 SolidPlanes[3]; | ||
576 | dVector3 tmp1; | ||
577 | |||
578 | dVector3 sn; | ||
579 | for (int j=0; j<3; j++) { | ||
580 | e1[j] = col_v[1][j] - col_v[0][j]; | ||
581 | e2[j] = col_v[0][j] - col_v[2][j]; | ||
582 | e3[j] = col_v[2][j] - col_v[1][j]; | ||
583 | } | ||
584 | |||
585 | // side 1 | ||
586 | CROSS(sn, e1, n); | ||
587 | dNormalize3(sn); | ||
588 | SMULT( SolidPlanes[0], sn, -1.0 ); | ||
589 | |||
590 | ADD(tmp1, col_v[0], col_v[1]); | ||
591 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
592 | // distance from center to edge along normal | ||
593 | SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); | ||
594 | |||
595 | |||
596 | // side 2 | ||
597 | CROSS(sn, e2, n); | ||
598 | dNormalize3(sn); | ||
599 | SMULT( SolidPlanes[1], sn, -1.0 ); | ||
600 | |||
601 | ADD(tmp1, col_v[0], col_v[2]); | ||
602 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
603 | // distance from center to edge along normal | ||
604 | SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); | ||
605 | |||
606 | |||
607 | // side 3 | ||
608 | CROSS(sn, e3, n); | ||
609 | dNormalize3(sn); | ||
610 | SMULT( SolidPlanes[2], sn, -1.0 ); | ||
611 | |||
612 | ADD(tmp1, col_v[2], col_v[1]); | ||
613 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
614 | // distance from center to edge along normal | ||
615 | SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); | ||
616 | |||
617 | FindTriSolidIntrsection(pen_v, SolidPlanes, 3, secondClippedTri); | ||
618 | |||
619 | for (int j=0; j<secondClippedTri.Count; j++) { | ||
620 | secondClippedTri.Points[j][3] = 1.0; // because we will be doing matrix mults | ||
621 | |||
622 | DEPTH(dp, CoplanarPt, secondClippedTri.Points[j], n); | ||
623 | |||
624 | if (pen_v == v1) { | ||
625 | dMultiply1(orig_pos, InvMatrix1, secondClippedTri.Points[j], 4, 4, 1); | ||
626 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
627 | for (int k=0; k<3; k++) { | ||
628 | secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; | ||
629 | } | ||
630 | } | ||
631 | else { | ||
632 | dMultiply1(orig_pos, InvMatrix2, secondClippedTri.Points[j], 4, 4, 1); | ||
633 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
634 | for (int k=0; k<3; k++) { | ||
635 | secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | |||
640 | if (dp >= 0.0) { | ||
641 | contact_elt_length = dFabs(dDOT(secondClippedElt[j],n)); | ||
642 | |||
643 | depth = dp; | ||
644 | if (depth == 0.0) | ||
645 | depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
646 | |||
647 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
648 | depth = contact_elt_length; | ||
649 | |||
650 | if (depth <= contact_elt_length) { | ||
651 | // Add a contact | ||
652 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
653 | secondClippedTri.Points[j], n, depth, OutTriCount); | ||
654 | badPen = false; | ||
655 | |||
656 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
657 | break; | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | |||
662 | |||
663 | } | ||
664 | } | ||
665 | |||
666 | |||
667 | |||
668 | ///////////////// | ||
669 | // All conventional tests have failed at this point, so now we deal with | ||
670 | // cases on a more "heuristic" basis | ||
671 | // | ||
672 | |||
673 | if (badPen) { | ||
674 | // Switch pen_v and n (for the fourth time, so they're | ||
675 | // what my original guess said they were) | ||
676 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
677 | |||
678 | if (dFabs(dDOT(n1, n2)) < REAL(0.01)) { | ||
679 | // If we reach this point, we have (close to) perpindicular | ||
680 | // faces, either resting on each other or sliding in a | ||
681 | // direction orthogonal to both surface normals. | ||
682 | if (LENGTH(elt_sum) < DISTANCE_EPSILON) { | ||
683 | depth = dFabs(dDOT(n, elt_sum)); | ||
684 | |||
685 | if (depth > REAL(1e-12)) { | ||
686 | dNormalize3(n); | ||
687 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
688 | CoplanarPt, n, depth, OutTriCount); | ||
689 | badPen = false; | ||
690 | } | ||
691 | else { | ||
692 | // If the two faces are (nearly) perfectly at rest with | ||
693 | // respect to each other, then we ignore the contact, | ||
694 | // allowing the objects to slip a little in the hopes | ||
695 | // that next frame, they'll give us something to work | ||
696 | // with. | ||
697 | badPen = false; | ||
698 | } | ||
699 | } | ||
700 | else { | ||
701 | // The faces are perpindicular, but moving significantly | ||
702 | // This can be sliding, or an unusual edge-straddling | ||
703 | // penetration. | ||
704 | dVector3 cn; | ||
705 | |||
706 | CROSS(cn, n1, n2); | ||
707 | dNormalize3(cn); | ||
708 | SET(n, cn); | ||
709 | |||
710 | // The shallowest ineterpenetration of the faces | ||
711 | // is the depth | ||
712 | dVector3 ContactPt; | ||
713 | dVector3 dvTmp; | ||
714 | dReal rTmp; | ||
715 | depth = dInfinity; | ||
716 | for (int j=0; j<3; j++) { | ||
717 | for (int k=0; k<3; k++) { | ||
718 | SUB(dvTmp, col_v[k], pen_v[j]); | ||
719 | |||
720 | rTmp = dDOT(dvTmp, n); | ||
721 | if ( dFabs(rTmp) < dFabs(depth) ) { | ||
722 | depth = rTmp; | ||
723 | SET( ContactPt, pen_v[j] ); | ||
724 | contact_elt_length = dFabs(dDOT(pen_elt[j], n)); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | if (depth < 0.0) { | ||
729 | SMULT(n, n, -1.0); | ||
730 | depth *= -1.0; | ||
731 | } | ||
732 | |||
733 | if ((depth > 0.0) && (depth <= contact_elt_length)) { | ||
734 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
735 | ContactPt, n, depth, OutTriCount); | ||
736 | badPen = false; | ||
737 | } | ||
738 | |||
739 | } | ||
740 | } | ||
741 | } | ||
742 | |||
743 | |||
744 | if (badPen) { | ||
745 | // Use as the normal the direction of travel, rather than any particular | ||
746 | // face normal | ||
747 | // | ||
748 | dVector3 esn; | ||
749 | |||
750 | if (pen_v == v1) { | ||
751 | SMULT(esn, elt_sum, -1.0); | ||
752 | } | ||
753 | else { | ||
754 | SET(esn, elt_sum); | ||
755 | } | ||
756 | dNormalize3(esn); | ||
757 | |||
758 | |||
759 | // The shallowest ineterpenetration of the faces | ||
760 | // is the depth | ||
761 | dVector3 ContactPt; | ||
762 | depth = dInfinity; | ||
763 | for (int j=0; j<3; j++) { | ||
764 | for (int k=0; k<3; k++) { | ||
765 | DEPTH(dp, col_v[k], pen_v[j], esn); | ||
766 | if ( (ExamineContactPoint(col_v, esn, pen_v[j])) && | ||
767 | ( dFabs(dp) < dFabs(depth)) ) { | ||
768 | depth = dp; | ||
769 | SET( ContactPt, pen_v[j] ); | ||
770 | contact_elt_length = dFabs(dDOT(pen_elt[j], esn)); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if ((depth > 0.0) && (depth <= contact_elt_length)) { | ||
776 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
777 | ContactPt, esn, depth, OutTriCount); | ||
778 | badPen = false; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | |||
783 | if (badPen) { | ||
784 | // If the direction of motion is perpindicular to both normals | ||
785 | if ( (dFabs(dDOT(n1, elt_sum)) < REAL(0.01)) && (dFabs(dDOT(n2, elt_sum)) < REAL(0.01)) ) { | ||
786 | dVector3 esn; | ||
787 | if (pen_v == v1) { | ||
788 | SMULT(esn, elt_sum, -1.0); | ||
789 | } | ||
790 | else { | ||
791 | SET(esn, elt_sum); | ||
792 | } | ||
793 | |||
794 | dNormalize3(esn); | ||
795 | |||
796 | |||
797 | // Look at the clipped points again, checking them against this | ||
798 | // new normal | ||
799 | for (int j=0; j<firstClippedTri.Count; j++) { | ||
800 | DEPTH(dp, CoplanarPt, firstClippedTri.Points[j], esn); | ||
801 | |||
802 | if (dp >= 0.0) { | ||
803 | contact_elt_length = dFabs(dDOT(firstClippedElt[j], esn)); | ||
804 | |||
805 | depth = dp; | ||
806 | //if (depth == 0.0) | ||
807 | //depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
808 | |||
809 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
810 | depth = contact_elt_length; | ||
811 | |||
812 | if (depth <= contact_elt_length) { | ||
813 | // Add a contact | ||
814 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
815 | firstClippedTri.Points[j], esn, depth, OutTriCount); | ||
816 | badPen = false; | ||
817 | |||
818 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
819 | break; | ||
820 | } | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
825 | if (badPen) { | ||
826 | // If this test failed, try it with the second set of clipped faces | ||
827 | for (int j=0; j<secondClippedTri.Count; j++) { | ||
828 | DEPTH(dp, CoplanarPt, secondClippedTri.Points[j], esn); | ||
829 | |||
830 | if (dp >= 0.0) { | ||
831 | contact_elt_length = dFabs(dDOT(secondClippedElt[j], esn)); | ||
832 | |||
833 | depth = dp; | ||
834 | //if (depth == 0.0) | ||
835 | //depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
836 | |||
837 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
838 | depth = contact_elt_length; | ||
839 | |||
840 | if (depth <= contact_elt_length) { | ||
841 | // Add a contact | ||
842 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
843 | secondClippedTri.Points[j], esn, depth, OutTriCount); | ||
844 | badPen = false; | ||
845 | |||
846 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | |||
856 | |||
857 | |||
858 | if (badPen) { | ||
859 | // if we have very little motion, we're dealing with resting contact | ||
860 | // and shouldn't reference the ELTs at all | ||
861 | // | ||
862 | if (LENGTH(elt_sum) < VELOCITY_EPSILON) { | ||
863 | |||
864 | // instead of a "contact_elt_length" threshhold, we'll use an | ||
865 | // arbitrary, small one | ||
866 | for (int j=0; j<3; j++) { | ||
867 | DEPTH(dp, CoplanarPt, pen_v[j], n); | ||
868 | |||
869 | if (dp == 0.0) | ||
870 | dp = TINY_PENETRATION; | ||
871 | |||
872 | if ( (dp > 0.0) && (dp <= SMALL_ELT)) { | ||
873 | // Add a contact | ||
874 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
875 | pen_v[j], n, dp, OutTriCount); | ||
876 | badPen = false; | ||
877 | |||
878 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
879 | break; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | |||
884 | |||
885 | if (badPen) { | ||
886 | // try the other normal | ||
887 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
888 | |||
889 | for (int j=0; j<3; j++) { | ||
890 | DEPTH(dp, CoplanarPt, pen_v[j], n); | ||
891 | |||
892 | if (dp == 0.0) | ||
893 | dp = TINY_PENETRATION; | ||
894 | |||
895 | if ( (dp > 0.0) && (dp <= SMALL_ELT)) { | ||
896 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
897 | pen_v[j], n, dp, OutTriCount); | ||
898 | badPen = false; | ||
899 | |||
900 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | |||
907 | |||
908 | |||
909 | } | ||
910 | } | ||
911 | |||
912 | if (badPen) { | ||
913 | // find the nearest existing contact, and replicate it's | ||
914 | // normal and depth | ||
915 | // | ||
916 | dContactGeom* Contact; | ||
917 | dVector3 pos_diff; | ||
918 | dReal min_dist, dist; | ||
919 | |||
920 | min_dist = dInfinity; | ||
921 | depth = 0.0; | ||
922 | for (int j=0; j<OutTriCount; j++) { | ||
923 | Contact = SAFECONTACT(Flags, Contacts, j, Stride); | ||
924 | |||
925 | SUB(pos_diff, Contact->pos, CoplanarPt); | ||
926 | |||
927 | dist = dDOT(pos_diff, pos_diff); | ||
928 | if (dist < min_dist) { | ||
929 | min_dist = dist; | ||
930 | depth = Contact->depth; | ||
931 | SMULT(ContactNormal, Contact->normal, -1.0); | ||
932 | } | ||
933 | } | ||
934 | |||
935 | if (depth > 0.0) { | ||
936 | // Add a tiny contact at the coplanar point | ||
937 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
938 | CoplanarPt, ContactNormal, depth, OutTriCount); | ||
939 | badPen = false; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | |||
944 | if (badPen) { | ||
945 | // Add a tiny contact at the coplanar point | ||
946 | if (-dDOT(elt_sum, n1) > -dDOT(elt_sum, n2)) { | ||
947 | SET(ContactNormal, n1); | ||
948 | } | ||
949 | else { | ||
950 | SET(ContactNormal, n2); | ||
951 | } | ||
952 | |||
953 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
954 | CoplanarPt, ContactNormal, TINY_PENETRATION, OutTriCount); | ||
955 | badPen = false; | ||
956 | } | ||
957 | |||
958 | |||
959 | } // not coplanar (main loop) | ||
960 | } // TriTriIntersectWithIsectLine | ||
961 | |||
962 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
963 | break; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | // Free memory | ||
968 | delete[] firstClippedElt; | ||
969 | delete[] secondClippedElt; | ||
970 | |||
971 | // Return the number of contacts | ||
972 | return OutTriCount; | ||
973 | } | ||
974 | } | ||
975 | } | ||
976 | |||
977 | |||
978 | // There was some kind of failure during the Collide call or | ||
979 | // there are no faces overlapping | ||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | |||
984 | |||
985 | static void | ||
986 | GetTriangleGeometryCallback(udword triangleindex, VertexPointers& triangle, udword user_data) | ||
987 | { | ||
988 | dVector3 Out[3]; | ||
989 | |||
990 | FetchTriangle((dxTriMesh*) user_data, (int) triangleindex, Out); | ||
991 | |||
992 | for (int i = 0; i < 3; i++) | ||
993 | triangle.Vertex[i] = (const Point*) ((dReal*) Out[i]); | ||
994 | } | ||
995 | |||
996 | |||
997 | // | ||
998 | // | ||
999 | // | ||
1000 | #define B11 B[0] | ||
1001 | #define B12 B[1] | ||
1002 | #define B13 B[2] | ||
1003 | #define B14 B[3] | ||
1004 | #define B21 B[4] | ||
1005 | #define B22 B[5] | ||
1006 | #define B23 B[6] | ||
1007 | #define B24 B[7] | ||
1008 | #define B31 B[8] | ||
1009 | #define B32 B[9] | ||
1010 | #define B33 B[10] | ||
1011 | #define B34 B[11] | ||
1012 | #define B41 B[12] | ||
1013 | #define B42 B[13] | ||
1014 | #define B43 B[14] | ||
1015 | #define B44 B[15] | ||
1016 | |||
1017 | #define Binv11 Binv[0] | ||
1018 | #define Binv12 Binv[1] | ||
1019 | #define Binv13 Binv[2] | ||
1020 | #define Binv14 Binv[3] | ||
1021 | #define Binv21 Binv[4] | ||
1022 | #define Binv22 Binv[5] | ||
1023 | #define Binv23 Binv[6] | ||
1024 | #define Binv24 Binv[7] | ||
1025 | #define Binv31 Binv[8] | ||
1026 | #define Binv32 Binv[9] | ||
1027 | #define Binv33 Binv[10] | ||
1028 | #define Binv34 Binv[11] | ||
1029 | #define Binv41 Binv[12] | ||
1030 | #define Binv42 Binv[13] | ||
1031 | #define Binv43 Binv[14] | ||
1032 | #define Binv44 Binv[15] | ||
1033 | |||
1034 | inline void | ||
1035 | dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B) | ||
1036 | { | ||
1037 | B11 = Rotation[0]; B21 = Rotation[1]; B31 = Rotation[2]; B41 = Position[0]; | ||
1038 | B12 = Rotation[4]; B22 = Rotation[5]; B32 = Rotation[6]; B42 = Position[1]; | ||
1039 | B13 = Rotation[8]; B23 = Rotation[9]; B33 = Rotation[10]; B43 = Position[2]; | ||
1040 | |||
1041 | B14 = 0.0; B24 = 0.0; B34 = 0.0; B44 = 1.0; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | static void | ||
1046 | dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ) | ||
1047 | { | ||
1048 | dReal det = (B11 * B22 - B12 * B21) * (B33 * B44 - B34 * B43) | ||
1049 | -(B11 * B23 - B13 * B21) * (B32 * B44 - B34 * B42) | ||
1050 | +(B11 * B24 - B14 * B21) * (B32 * B43 - B33 * B42) | ||
1051 | +(B12 * B23 - B13 * B22) * (B31 * B44 - B34 * B41) | ||
1052 | -(B12 * B24 - B14 * B22) * (B31 * B43 - B33 * B41) | ||
1053 | +(B13 * B24 - B14 * B23) * (B31 * B42 - B32 * B41); | ||
1054 | |||
1055 | dAASSERT (det != 0.0); | ||
1056 | |||
1057 | det = 1.0 / det; | ||
1058 | |||
1059 | Binv11 = (dReal) (det * ((B22 * B33) - (B23 * B32))); | ||
1060 | Binv12 = (dReal) (det * ((B32 * B13) - (B33 * B12))); | ||
1061 | Binv13 = (dReal) (det * ((B12 * B23) - (B13 * B22))); | ||
1062 | Binv14 = 0.0f; | ||
1063 | Binv21 = (dReal) (det * ((B23 * B31) - (B21 * B33))); | ||
1064 | Binv22 = (dReal) (det * ((B33 * B11) - (B31 * B13))); | ||
1065 | Binv23 = (dReal) (det * ((B13 * B21) - (B11 * B23))); | ||
1066 | Binv24 = 0.0f; | ||
1067 | Binv31 = (dReal) (det * ((B21 * B32) - (B22 * B31))); | ||
1068 | Binv32 = (dReal) (det * ((B31 * B12) - (B32 * B11))); | ||
1069 | Binv33 = (dReal) (det * ((B11 * B22) - (B12 * B21))); | ||
1070 | Binv34 = 0.0f; | ||
1071 | Binv41 = (dReal) (det * (B21*(B33*B42 - B32*B43) + B22*(B31*B43 - B33*B41) + B23*(B32*B41 - B31*B42))); | ||
1072 | Binv42 = (dReal) (det * (B31*(B13*B42 - B12*B43) + B32*(B11*B43 - B13*B41) + B33*(B12*B41 - B11*B42))); | ||
1073 | Binv43 = (dReal) (det * (B41*(B13*B22 - B12*B23) + B42*(B11*B23 - B13*B21) + B43*(B12*B21 - B11*B22))); | ||
1074 | Binv44 = 1.0f; | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | |||
1079 | ///////////////////////////////////////////////// | ||
1080 | // | ||
1081 | // Triangle/Triangle intersection utilities | ||
1082 | // | ||
1083 | // From the article "A Fast Triangle-Triangle Intersection Test", | ||
1084 | // Journal of Graphics Tools, 2(2), 1997 | ||
1085 | // | ||
1086 | // Some of this functionality is duplicated in OPCODE (see | ||
1087 | // OPC_TriTriOverlap.h) but we have replicated it here so we don't | ||
1088 | // have to mess with the internals of OPCODE, as well as so we can | ||
1089 | // further optimize some of the functions. | ||
1090 | // | ||
1091 | // This version computes the line of intersection as well (if they | ||
1092 | // are not coplanar): | ||
1093 | // int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
1094 | // dReal U0[3],dReal U1[3],dReal U2[3], | ||
1095 | // int *coplanar, | ||
1096 | // dReal isectpt1[3],dReal isectpt2[3]); | ||
1097 | // | ||
1098 | // parameters: vertices of triangle 1: V0,V1,V2 | ||
1099 | // vertices of triangle 2: U0,U1,U2 | ||
1100 | // | ||
1101 | // result : returns 1 if the triangles intersect, otherwise 0 | ||
1102 | // "coplanar" returns whether the tris are coplanar | ||
1103 | // isectpt1, isectpt2 are the endpoints of the line of | ||
1104 | // intersection | ||
1105 | // | ||
1106 | |||
1107 | |||
1108 | |||
1109 | /* if USE_EPSILON_TEST is true then we do a check: | ||
1110 | if |dv|<EPSILON then dv=0.0; | ||
1111 | else no check is done (which is less robust) | ||
1112 | */ | ||
1113 | #define USE_EPSILON_TEST TRUE | ||
1114 | #define EPSILON REAL(0.000001) | ||
1115 | |||
1116 | |||
1117 | /* sort so that a<=b */ | ||
1118 | #define SORT(a,b) \ | ||
1119 | if(a>b) \ | ||
1120 | { \ | ||
1121 | dReal c; \ | ||
1122 | c=a; \ | ||
1123 | a=b; \ | ||
1124 | b=c; \ | ||
1125 | } | ||
1126 | |||
1127 | #define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \ | ||
1128 | isect0=VV0+(VV1-VV0)*D0/(D0-D1); \ | ||
1129 | isect1=VV0+(VV2-VV0)*D0/(D0-D2); | ||
1130 | |||
1131 | |||
1132 | #define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \ | ||
1133 | if(D0D1>0.0f) \ | ||
1134 | { \ | ||
1135 | /* here we know that D0D2<=0.0 */ \ | ||
1136 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1137 | ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ | ||
1138 | } \ | ||
1139 | else if(D0D2>0.0f) \ | ||
1140 | { \ | ||
1141 | /* here we know that d0d1<=0.0 */ \ | ||
1142 | ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ | ||
1143 | } \ | ||
1144 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1145 | { \ | ||
1146 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1147 | ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1); \ | ||
1148 | } \ | ||
1149 | else if(D1!=0.0f) \ | ||
1150 | { \ | ||
1151 | ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ | ||
1152 | } \ | ||
1153 | else if(D2!=0.0f) \ | ||
1154 | { \ | ||
1155 | ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ | ||
1156 | } \ | ||
1157 | else \ | ||
1158 | { \ | ||
1159 | /* triangles are coplanar */ \ | ||
1160 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | |||
1165 | /* this edge to edge test is based on Franlin Antonio's gem: | ||
1166 | "Faster Line Segment Intersection", in Graphics Gems III, | ||
1167 | pp. 199-202 */ | ||
1168 | #define EDGE_EDGE_TEST(V0,U0,U1) \ | ||
1169 | Bx=U0[i0]-U1[i0]; \ | ||
1170 | By=U0[i1]-U1[i1]; \ | ||
1171 | Cx=V0[i0]-U0[i0]; \ | ||
1172 | Cy=V0[i1]-U0[i1]; \ | ||
1173 | f=Ay*Bx-Ax*By; \ | ||
1174 | d=By*Cx-Bx*Cy; \ | ||
1175 | if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \ | ||
1176 | { \ | ||
1177 | e=Ax*Cy-Ay*Cx; \ | ||
1178 | if(f>0) \ | ||
1179 | { \ | ||
1180 | if(e>=0 && e<=f) return 1; \ | ||
1181 | } \ | ||
1182 | else \ | ||
1183 | { \ | ||
1184 | if(e<=0 && e>=f) return 1; \ | ||
1185 | } \ | ||
1186 | } | ||
1187 | |||
1188 | #define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \ | ||
1189 | { \ | ||
1190 | dReal Ax,Ay,Bx,By,Cx,Cy,e,d,f; \ | ||
1191 | Ax=V1[i0]-V0[i0]; \ | ||
1192 | Ay=V1[i1]-V0[i1]; \ | ||
1193 | /* test edge U0,U1 against V0,V1 */ \ | ||
1194 | EDGE_EDGE_TEST(V0,U0,U1); \ | ||
1195 | /* test edge U1,U2 against V0,V1 */ \ | ||
1196 | EDGE_EDGE_TEST(V0,U1,U2); \ | ||
1197 | /* test edge U2,U1 against V0,V1 */ \ | ||
1198 | EDGE_EDGE_TEST(V0,U2,U0); \ | ||
1199 | } | ||
1200 | |||
1201 | #define POINT_IN_TRI(V0,U0,U1,U2) \ | ||
1202 | { \ | ||
1203 | dReal a,b,c,d0,d1,d2; \ | ||
1204 | /* is T1 completly inside T2? */ \ | ||
1205 | /* check if V0 is inside tri(U0,U1,U2) */ \ | ||
1206 | a=U1[i1]-U0[i1]; \ | ||
1207 | b=-(U1[i0]-U0[i0]); \ | ||
1208 | c=-a*U0[i0]-b*U0[i1]; \ | ||
1209 | d0=a*V0[i0]+b*V0[i1]+c; \ | ||
1210 | \ | ||
1211 | a=U2[i1]-U1[i1]; \ | ||
1212 | b=-(U2[i0]-U1[i0]); \ | ||
1213 | c=-a*U1[i0]-b*U1[i1]; \ | ||
1214 | d1=a*V0[i0]+b*V0[i1]+c; \ | ||
1215 | \ | ||
1216 | a=U0[i1]-U2[i1]; \ | ||
1217 | b=-(U0[i0]-U2[i0]); \ | ||
1218 | c=-a*U2[i0]-b*U2[i1]; \ | ||
1219 | d2=a*V0[i0]+b*V0[i1]+c; \ | ||
1220 | if(d0*d1>0.0) \ | ||
1221 | { \ | ||
1222 | if(d0*d2>0.0) return 1; \ | ||
1223 | } \ | ||
1224 | } | ||
1225 | |||
1226 | int coplanar_tri_tri(dReal N[3],dReal V0[3],dReal V1[3],dReal V2[3], | ||
1227 | dReal U0[3],dReal U1[3],dReal U2[3]) | ||
1228 | { | ||
1229 | dReal A[3]; | ||
1230 | short i0,i1; | ||
1231 | /* first project onto an axis-aligned plane, that maximizes the area */ | ||
1232 | /* of the triangles, compute indices: i0,i1. */ | ||
1233 | A[0]= dFabs(N[0]); | ||
1234 | A[1]= dFabs(N[1]); | ||
1235 | A[2]= dFabs(N[2]); | ||
1236 | if(A[0]>A[1]) | ||
1237 | { | ||
1238 | if(A[0]>A[2]) | ||
1239 | { | ||
1240 | i0=1; /* A[0] is greatest */ | ||
1241 | i1=2; | ||
1242 | } | ||
1243 | else | ||
1244 | { | ||
1245 | i0=0; /* A[2] is greatest */ | ||
1246 | i1=1; | ||
1247 | } | ||
1248 | } | ||
1249 | else /* A[0]<=A[1] */ | ||
1250 | { | ||
1251 | if(A[2]>A[1]) | ||
1252 | { | ||
1253 | i0=0; /* A[2] is greatest */ | ||
1254 | i1=1; | ||
1255 | } | ||
1256 | else | ||
1257 | { | ||
1258 | i0=0; /* A[1] is greatest */ | ||
1259 | i1=2; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | /* test all edges of triangle 1 against the edges of triangle 2 */ | ||
1264 | EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2); | ||
1265 | EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2); | ||
1266 | EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2); | ||
1267 | |||
1268 | /* finally, test if tri1 is totally contained in tri2 or vice versa */ | ||
1269 | POINT_IN_TRI(V0,U0,U1,U2); | ||
1270 | POINT_IN_TRI(U0,V0,V1,V2); | ||
1271 | |||
1272 | return 0; | ||
1273 | } | ||
1274 | |||
1275 | |||
1276 | |||
1277 | #define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \ | ||
1278 | { \ | ||
1279 | if(D0D1>0.0f) \ | ||
1280 | { \ | ||
1281 | /* here we know that D0D2<=0.0 */ \ | ||
1282 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1283 | A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ | ||
1284 | } \ | ||
1285 | else if(D0D2>0.0f)\ | ||
1286 | { \ | ||
1287 | /* here we know that d0d1<=0.0 */ \ | ||
1288 | A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ | ||
1289 | } \ | ||
1290 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1291 | { \ | ||
1292 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1293 | A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \ | ||
1294 | } \ | ||
1295 | else if(D1!=0.0f) \ | ||
1296 | { \ | ||
1297 | A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ | ||
1298 | } \ | ||
1299 | else if(D2!=0.0f) \ | ||
1300 | { \ | ||
1301 | A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ | ||
1302 | } \ | ||
1303 | else \ | ||
1304 | { \ | ||
1305 | /* triangles are coplanar */ \ | ||
1306 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1307 | } \ | ||
1308 | } | ||
1309 | |||
1310 | |||
1311 | |||
1312 | |||
1313 | /* sort so that a<=b */ | ||
1314 | #define SORT2(a,b,smallest) \ | ||
1315 | if(a>b) \ | ||
1316 | { \ | ||
1317 | dReal c; \ | ||
1318 | c=a; \ | ||
1319 | a=b; \ | ||
1320 | b=c; \ | ||
1321 | smallest=1; \ | ||
1322 | } \ | ||
1323 | else smallest=0; | ||
1324 | |||
1325 | |||
1326 | inline void isect2(dReal VTX0[3],dReal VTX1[3],dReal VTX2[3],dReal VV0,dReal VV1,dReal VV2, | ||
1327 | dReal D0,dReal D1,dReal D2,dReal *isect0,dReal *isect1,dReal isectpoint0[3],dReal isectpoint1[3]) | ||
1328 | { | ||
1329 | dReal tmp=D0/(D0-D1); | ||
1330 | dReal diff[3]; | ||
1331 | *isect0=VV0+(VV1-VV0)*tmp; | ||
1332 | SUB(diff,VTX1,VTX0); | ||
1333 | MULT(diff,diff,tmp); | ||
1334 | ADD(isectpoint0,diff,VTX0); | ||
1335 | tmp=D0/(D0-D2); | ||
1336 | *isect1=VV0+(VV2-VV0)*tmp; | ||
1337 | SUB(diff,VTX2,VTX0); | ||
1338 | MULT(diff,diff,tmp); | ||
1339 | ADD(isectpoint1,VTX0,diff); | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | #if 0 | ||
1344 | #define ISECT2(VTX0,VTX1,VTX2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1) \ | ||
1345 | tmp=D0/(D0-D1); \ | ||
1346 | isect0=VV0+(VV1-VV0)*tmp; \ | ||
1347 | SUB(diff,VTX1,VTX0); \ | ||
1348 | MULT(diff,diff,tmp); \ | ||
1349 | ADD(isectpoint0,diff,VTX0); \ | ||
1350 | tmp=D0/(D0-D2); | ||
1351 | /* isect1=VV0+(VV2-VV0)*tmp; \ */ | ||
1352 | /* SUB(diff,VTX2,VTX0); \ */ | ||
1353 | /* MULT(diff,diff,tmp); \ */ | ||
1354 | /* ADD(isectpoint1,VTX0,diff); */ | ||
1355 | #endif | ||
1356 | |||
1357 | inline int compute_intervals_isectline(dReal VERT0[3],dReal VERT1[3],dReal VERT2[3], | ||
1358 | dReal VV0,dReal VV1,dReal VV2,dReal D0,dReal D1,dReal D2, | ||
1359 | dReal D0D1,dReal D0D2,dReal *isect0,dReal *isect1, | ||
1360 | dReal isectpoint0[3],dReal isectpoint1[3]) | ||
1361 | { | ||
1362 | if(D0D1>0.0f) | ||
1363 | { | ||
1364 | /* here we know that D0D2<=0.0 */ | ||
1365 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ | ||
1366 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); | ||
1367 | } | ||
1368 | else if(D0D2>0.0f) | ||
1369 | { | ||
1370 | /* here we know that d0d1<=0.0 */ | ||
1371 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1372 | } | ||
1373 | else if(D1*D2>0.0f || D0!=0.0f) | ||
1374 | { | ||
1375 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ | ||
1376 | isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1377 | } | ||
1378 | else if(D1!=0.0f) | ||
1379 | { | ||
1380 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1381 | } | ||
1382 | else if(D2!=0.0f) | ||
1383 | { | ||
1384 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); | ||
1385 | } | ||
1386 | else | ||
1387 | { | ||
1388 | /* triangles are coplanar */ | ||
1389 | return 1; | ||
1390 | } | ||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | #define COMPUTE_INTERVALS_ISECTLINE(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1,isectpoint0,isectpoint1) \ | ||
1395 | if(D0D1>0.0f) \ | ||
1396 | { \ | ||
1397 | /* here we know that D0D2<=0.0 */ \ | ||
1398 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1399 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1400 | } | ||
1401 | #if 0 | ||
1402 | else if(D0D2>0.0f) \ | ||
1403 | { \ | ||
1404 | /* here we know that d0d1<=0.0 */ \ | ||
1405 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1406 | } \ | ||
1407 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1408 | { \ | ||
1409 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1410 | isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1411 | } \ | ||
1412 | else if(D1!=0.0f) \ | ||
1413 | { \ | ||
1414 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1415 | } \ | ||
1416 | else if(D2!=0.0f) \ | ||
1417 | { \ | ||
1418 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1419 | } \ | ||
1420 | else \ | ||
1421 | { \ | ||
1422 | /* triangles are coplanar */ \ | ||
1423 | coplanar=1; \ | ||
1424 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1425 | } | ||
1426 | #endif | ||
1427 | |||
1428 | |||
1429 | |||
1430 | static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
1431 | dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, | ||
1432 | dReal isectpt1[3],dReal isectpt2[3]) | ||
1433 | { | ||
1434 | dReal E1[3],E2[3]; | ||
1435 | dReal N1[3],N2[3],d1,d2; | ||
1436 | dReal du0,du1,du2,dv0,dv1,dv2; | ||
1437 | dReal D[3]; | ||
1438 | dReal isect1[2], isect2[2]; | ||
1439 | dReal isectpointA1[3],isectpointA2[3]; | ||
1440 | dReal isectpointB1[3],isectpointB2[3]; | ||
1441 | dReal du0du1,du0du2,dv0dv1,dv0dv2; | ||
1442 | short index; | ||
1443 | dReal vp0,vp1,vp2; | ||
1444 | dReal up0,up1,up2; | ||
1445 | dReal b,c,max; | ||
1446 | int smallest1,smallest2; | ||
1447 | |||
1448 | /* compute plane equation of triangle(V0,V1,V2) */ | ||
1449 | SUB(E1,V1,V0); | ||
1450 | SUB(E2,V2,V0); | ||
1451 | CROSS(N1,E1,E2); | ||
1452 | d1=-DOT(N1,V0); | ||
1453 | /* plane equation 1: N1.X+d1=0 */ | ||
1454 | |||
1455 | /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/ | ||
1456 | du0=DOT(N1,U0)+d1; | ||
1457 | du1=DOT(N1,U1)+d1; | ||
1458 | du2=DOT(N1,U2)+d1; | ||
1459 | |||
1460 | /* coplanarity robustness check */ | ||
1461 | #if USE_EPSILON_TEST==TRUE | ||
1462 | if(dFabs(du0)<EPSILON) du0=0.0; | ||
1463 | if(dFabs(du1)<EPSILON) du1=0.0; | ||
1464 | if(dFabs(du2)<EPSILON) du2=0.0; | ||
1465 | #endif | ||
1466 | du0du1=du0*du1; | ||
1467 | du0du2=du0*du2; | ||
1468 | |||
1469 | if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */ | ||
1470 | return 0; /* no intersection occurs */ | ||
1471 | |||
1472 | /* compute plane of triangle (U0,U1,U2) */ | ||
1473 | SUB(E1,U1,U0); | ||
1474 | SUB(E2,U2,U0); | ||
1475 | CROSS(N2,E1,E2); | ||
1476 | d2=-DOT(N2,U0); | ||
1477 | /* plane equation 2: N2.X+d2=0 */ | ||
1478 | |||
1479 | /* put V0,V1,V2 into plane equation 2 */ | ||
1480 | dv0=DOT(N2,V0)+d2; | ||
1481 | dv1=DOT(N2,V1)+d2; | ||
1482 | dv2=DOT(N2,V2)+d2; | ||
1483 | |||
1484 | #if USE_EPSILON_TEST==TRUE | ||
1485 | if(dFabs(dv0)<EPSILON) dv0=0.0; | ||
1486 | if(dFabs(dv1)<EPSILON) dv1=0.0; | ||
1487 | if(dFabs(dv2)<EPSILON) dv2=0.0; | ||
1488 | #endif | ||
1489 | |||
1490 | dv0dv1=dv0*dv1; | ||
1491 | dv0dv2=dv0*dv2; | ||
1492 | |||
1493 | if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */ | ||
1494 | return 0; /* no intersection occurs */ | ||
1495 | |||
1496 | /* compute direction of intersection line */ | ||
1497 | CROSS(D,N1,N2); | ||
1498 | |||
1499 | /* compute and index to the largest component of D */ | ||
1500 | max= dFabs(D[0]); | ||
1501 | index=0; | ||
1502 | b= dFabs(D[1]); | ||
1503 | c= dFabs(D[2]); | ||
1504 | if(b>max) max=b,index=1; | ||
1505 | if(c>max) max=c,index=2; | ||
1506 | |||
1507 | /* this is the simplified projection onto L*/ | ||
1508 | vp0=V0[index]; | ||
1509 | vp1=V1[index]; | ||
1510 | vp2=V2[index]; | ||
1511 | |||
1512 | up0=U0[index]; | ||
1513 | up1=U1[index]; | ||
1514 | up2=U2[index]; | ||
1515 | |||
1516 | /* compute interval for triangle 1 */ | ||
1517 | *coplanar=compute_intervals_isectline(V0,V1,V2,vp0,vp1,vp2,dv0,dv1,dv2, | ||
1518 | dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA1,isectpointA2); | ||
1519 | if(*coplanar) return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); | ||
1520 | |||
1521 | |||
1522 | /* compute interval for triangle 2 */ | ||
1523 | compute_intervals_isectline(U0,U1,U2,up0,up1,up2,du0,du1,du2, | ||
1524 | du0du1,du0du2,&isect2[0],&isect2[1],isectpointB1,isectpointB2); | ||
1525 | |||
1526 | SORT2(isect1[0],isect1[1],smallest1); | ||
1527 | SORT2(isect2[0],isect2[1],smallest2); | ||
1528 | |||
1529 | if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0; | ||
1530 | |||
1531 | /* at this point, we know that the triangles intersect */ | ||
1532 | |||
1533 | if(isect2[0]<isect1[0]) | ||
1534 | { | ||
1535 | if(smallest1==0) { SET(isectpt1,isectpointA1); } | ||
1536 | else { SET(isectpt1,isectpointA2); } | ||
1537 | |||
1538 | if(isect2[1]<isect1[1]) | ||
1539 | { | ||
1540 | if(smallest2==0) { SET(isectpt2,isectpointB2); } | ||
1541 | else { SET(isectpt2,isectpointB1); } | ||
1542 | } | ||
1543 | else | ||
1544 | { | ||
1545 | if(smallest1==0) { SET(isectpt2,isectpointA2); } | ||
1546 | else { SET(isectpt2,isectpointA1); } | ||
1547 | } | ||
1548 | } | ||
1549 | else | ||
1550 | { | ||
1551 | if(smallest2==0) { SET(isectpt1,isectpointB1); } | ||
1552 | else { SET(isectpt1,isectpointB2); } | ||
1553 | |||
1554 | if(isect2[1]>isect1[1]) | ||
1555 | { | ||
1556 | if(smallest1==0) { SET(isectpt2,isectpointA2); } | ||
1557 | else { SET(isectpt2,isectpointA1); } | ||
1558 | } | ||
1559 | else | ||
1560 | { | ||
1561 | if(smallest2==0) { SET(isectpt2,isectpointB2); } | ||
1562 | else { SET(isectpt2,isectpointB1); } | ||
1563 | } | ||
1564 | } | ||
1565 | return 1; | ||
1566 | } | ||
1567 | |||
1568 | |||
1569 | |||
1570 | |||
1571 | |||
1572 | // Find the intersectiojn point between a coplanar line segement, | ||
1573 | // defined by X1 and X2, and a ray defined by X3 and direction N. | ||
1574 | // | ||
1575 | // This forumla for this calculation is: | ||
1576 | // (c x b) . (a x b) | ||
1577 | // Q = x1 + a ------------------- | ||
1578 | // | a x b | ^2 | ||
1579 | // | ||
1580 | // where a = x2 - x1 | ||
1581 | // b = x4 - x3 | ||
1582 | // c = x3 - x1 | ||
1583 | // x1 and x2 are the edges of the triangle, and x3 is CoplanarPt | ||
1584 | // and x4 is (CoplanarPt - n) | ||
1585 | static int | ||
1586 | IntersectLineSegmentRay(dVector3 x1, dVector3 x2, dVector3 x3, dVector3 n, | ||
1587 | dVector3 out_pt) | ||
1588 | { | ||
1589 | dVector3 a, b, c, x4; | ||
1590 | |||
1591 | ADD(x4, x3, n); // x4 = x3 + n | ||
1592 | |||
1593 | SUB(a, x2, x1); // a = x2 - x1 | ||
1594 | SUB(b, x4, x3); | ||
1595 | SUB(c, x3, x1); | ||
1596 | |||
1597 | dVector3 tmp1, tmp2; | ||
1598 | CROSS(tmp1, c, b); | ||
1599 | CROSS(tmp2, a, b); | ||
1600 | |||
1601 | dReal num, denom; | ||
1602 | num = dDOT(tmp1, tmp2); | ||
1603 | denom = LENGTH( tmp2 ); | ||
1604 | |||
1605 | dReal s; | ||
1606 | s = num /(denom*denom); | ||
1607 | |||
1608 | for (int i=0; i<3; i++) | ||
1609 | out_pt[i] = x1[i] + a[i]*s; | ||
1610 | |||
1611 | // Test if this intersection is "behind" x3, w.r.t. n | ||
1612 | SUB(a, x3, out_pt); | ||
1613 | if (dDOT(a, n) > 0.0) | ||
1614 | return 0; | ||
1615 | |||
1616 | // Test if this intersection point is outside the edge limits, | ||
1617 | // if (dot( (out_pt-x1), (out_pt-x2) ) < 0) it's inside | ||
1618 | // else outside | ||
1619 | SUB(a, out_pt, x1); | ||
1620 | SUB(b, out_pt, x2); | ||
1621 | if (dDOT(a,b) < 0.0) | ||
1622 | return 1; | ||
1623 | else | ||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | |||
1628 | // FindTriSolidIntersection - Clips the input trinagle TRI with the | ||
1629 | // sides of a convex bounding solid, described by PLANES, returning | ||
1630 | // the (convex) clipped polygon in CLIPPEDPOLYGON | ||
1631 | // | ||
1632 | static bool | ||
1633 | FindTriSolidIntrsection(const dVector3 Tri[3], | ||
1634 | const dVector4 Planes[6], int numSides, | ||
1635 | LineContactSet& ClippedPolygon ) | ||
1636 | { | ||
1637 | // Set up the LineContactSet structure | ||
1638 | for (int k=0; k<3; k++) { | ||
1639 | SET(ClippedPolygon.Points[k], Tri[k]); | ||
1640 | } | ||
1641 | ClippedPolygon.Count = 3; | ||
1642 | |||
1643 | // Clip wrt the sides | ||
1644 | for ( int i = 0; i < numSides; i++ ) | ||
1645 | ClipConvexPolygonAgainstPlane( Planes[i], Planes[i][3], ClippedPolygon ); | ||
1646 | |||
1647 | return (ClippedPolygon.Count > 0); | ||
1648 | } | ||
1649 | |||
1650 | |||
1651 | |||
1652 | |||
1653 | // ClipConvexPolygonAgainstPlane - Clip a a convex polygon, described by | ||
1654 | // CONTACTS, with a plane (described by N and C). Note: the input | ||
1655 | // vertices are assumed to be in counterclockwise order. | ||
1656 | // | ||
1657 | // This code is taken from The Nebula Device: | ||
1658 | // http://nebuladevice.sourceforge.net/cgi-bin/twiki/view/Nebula/WebHome | ||
1659 | // and is licensed under the following license: | ||
1660 | // http://nebuladevice.sourceforge.net/doc/source/license.txt | ||
1661 | // | ||
1662 | static void | ||
1663 | ClipConvexPolygonAgainstPlane( const dVector3 N, dReal C, | ||
1664 | LineContactSet& Contacts ) | ||
1665 | { | ||
1666 | // test on which side of line are the vertices | ||
1667 | int Positive = 0, Negative = 0, PIndex = -1; | ||
1668 | int Quantity = Contacts.Count; | ||
1669 | |||
1670 | dReal Test[8]; | ||
1671 | for ( int i = 0; i < Contacts.Count; i++ ) { | ||
1672 | // An epsilon is used here because it is possible for the dot product | ||
1673 | // and C to be exactly equal to each other (in theory), but differ | ||
1674 | // slightly because of floating point problems. Thus, add a little | ||
1675 | // to the test number to push actually equal numbers over the edge | ||
1676 | // towards the positive. This should probably be somehow a relative | ||
1677 | // tolerance, and I don't think multiplying by the constant is the best | ||
1678 | // way to do this. | ||
1679 | Test[i] = dDOT(N, Contacts.Points[i]) - C + dFabs(C)*REAL(1e-08); | ||
1680 | |||
1681 | if (Test[i] >= REAL(0.0)) { | ||
1682 | Positive++; | ||
1683 | if (PIndex < 0) { | ||
1684 | PIndex = i; | ||
1685 | } | ||
1686 | } | ||
1687 | else Negative++; | ||
1688 | } | ||
1689 | |||
1690 | if (Positive > 0) { | ||
1691 | if (Negative > 0) { | ||
1692 | // plane transversely intersects polygon | ||
1693 | dVector3 CV[8]; | ||
1694 | int CQuantity = 0, Cur, Prv; | ||
1695 | dReal T; | ||
1696 | |||
1697 | if (PIndex > 0) { | ||
1698 | // first clip vertex on line | ||
1699 | Cur = PIndex; | ||
1700 | Prv = Cur - 1; | ||
1701 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1702 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1703 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1704 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1705 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1706 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1707 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1708 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1709 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1710 | CQuantity++; | ||
1711 | |||
1712 | // vertices on positive side of line | ||
1713 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1714 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1715 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1716 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1717 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1718 | CQuantity++; | ||
1719 | Cur++; | ||
1720 | } | ||
1721 | |||
1722 | // last clip vertex on line | ||
1723 | if (Cur < Quantity) { | ||
1724 | Prv = Cur - 1; | ||
1725 | } | ||
1726 | else { | ||
1727 | Cur = 0; | ||
1728 | Prv = Quantity - 1; | ||
1729 | } | ||
1730 | |||
1731 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1732 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1733 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1734 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1735 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1736 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1737 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1738 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1739 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1740 | CQuantity++; | ||
1741 | } | ||
1742 | else { | ||
1743 | // iPIndex is 0 | ||
1744 | // vertices on positive side of line | ||
1745 | Cur = 0; | ||
1746 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1747 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1748 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1749 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1750 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1751 | CQuantity++; | ||
1752 | Cur++; | ||
1753 | } | ||
1754 | |||
1755 | // last clip vertex on line | ||
1756 | Prv = Cur - 1; | ||
1757 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1758 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1759 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1760 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1761 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1762 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1763 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1764 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1765 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1766 | CQuantity++; | ||
1767 | |||
1768 | // skip vertices on negative side | ||
1769 | while (Cur < Quantity && Test[Cur] < REAL(0.0)) { | ||
1770 | Cur++; | ||
1771 | } | ||
1772 | |||
1773 | // first clip vertex on line | ||
1774 | if (Cur < Quantity) { | ||
1775 | Prv = Cur - 1; | ||
1776 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1777 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1778 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1779 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1780 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1781 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1782 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1783 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1784 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1785 | CQuantity++; | ||
1786 | |||
1787 | // vertices on positive side of line | ||
1788 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1789 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1790 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1791 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1792 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1793 | CQuantity++; | ||
1794 | Cur++; | ||
1795 | } | ||
1796 | } | ||
1797 | else { | ||
1798 | // iCur = 0 | ||
1799 | Prv = Quantity - 1; | ||
1800 | T = Test[0] / (Test[0] - Test[Prv]); | ||
1801 | CV[CQuantity][0] = Contacts.Points[0][0] | ||
1802 | + T * (Contacts.Points[Prv][0] - Contacts.Points[0][0]); | ||
1803 | CV[CQuantity][1] = Contacts.Points[0][1] | ||
1804 | + T * (Contacts.Points[Prv][1] - Contacts.Points[0][1]); | ||
1805 | CV[CQuantity][2] = Contacts.Points[0][2] | ||
1806 | + T * (Contacts.Points[Prv][2] - Contacts.Points[0][2]); | ||
1807 | CV[CQuantity][3] = Contacts.Points[0][3] | ||
1808 | + T * (Contacts.Points[Prv][3] - Contacts.Points[0][3]); | ||
1809 | CQuantity++; | ||
1810 | } | ||
1811 | } | ||
1812 | Quantity = CQuantity; | ||
1813 | memcpy( Contacts.Points, CV, CQuantity * sizeof(dVector3) ); | ||
1814 | } | ||
1815 | // else polygon fully on positive side of plane, nothing to do | ||
1816 | Contacts.Count = Quantity; | ||
1817 | } | ||
1818 | else { | ||
1819 | Contacts.Count = 0; // This should not happen, but for safety | ||
1820 | } | ||
1821 | |||
1822 | } | ||
1823 | |||
1824 | |||
1825 | |||
1826 | // Determine if a potential collision point is | ||
1827 | // | ||
1828 | // | ||
1829 | static int | ||
1830 | ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point) | ||
1831 | { | ||
1832 | // Cast a ray from in_point, along the collison normal. Does it intersect the | ||
1833 | // collision face. | ||
1834 | dReal t, u, v; | ||
1835 | |||
1836 | if (!RayTriangleIntersect(in_point, in_n, v_col[0], v_col[1], v_col[2], | ||
1837 | &t, &u, &v)) | ||
1838 | return 0; | ||
1839 | else | ||
1840 | return 1; | ||
1841 | } | ||
1842 | |||
1843 | |||
1844 | |||
1845 | // RayTriangleIntersect - If an intersection is found, t contains the | ||
1846 | // distance along the ray (dir) and u/v contain u/v coordinates into | ||
1847 | // the triangle. Returns 0 if no hit is found | ||
1848 | // From "Real-Time Rendering," page 305 | ||
1849 | // | ||
1850 | static int | ||
1851 | RayTriangleIntersect(const dVector3 orig, const dVector3 dir, | ||
1852 | const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, | ||
1853 | dReal *t,dReal *u,dReal *v) | ||
1854 | |||
1855 | { | ||
1856 | dReal edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; | ||
1857 | dReal det,inv_det; | ||
1858 | |||
1859 | // find vectors for two edges sharing vert0 | ||
1860 | SUB(edge1, vert1, vert0); | ||
1861 | SUB(edge2, vert2, vert0); | ||
1862 | |||
1863 | // begin calculating determinant - also used to calculate U parameter | ||
1864 | CROSS(pvec, dir, edge2); | ||
1865 | |||
1866 | // if determinant is near zero, ray lies in plane of triangle | ||
1867 | det = DOT(edge1, pvec); | ||
1868 | |||
1869 | if ((det > REAL(-0.001)) && (det < REAL(0.001))) | ||
1870 | return 0; | ||
1871 | inv_det = 1.0 / det; | ||
1872 | |||
1873 | // calculate distance from vert0 to ray origin | ||
1874 | SUB(tvec, orig, vert0); | ||
1875 | |||
1876 | // calculate U parameter and test bounds | ||
1877 | *u = DOT(tvec, pvec) * inv_det; | ||
1878 | if ((*u < 0.0) || (*u > 1.0)) | ||
1879 | return 0; | ||
1880 | |||
1881 | // prepare to test V parameter | ||
1882 | CROSS(qvec, tvec, edge1); | ||
1883 | |||
1884 | // calculate V parameter and test bounds | ||
1885 | *v = DOT(dir, qvec) * inv_det; | ||
1886 | if ((*v < 0.0) || ((*u + *v) > 1.0)) | ||
1887 | return 0; | ||
1888 | |||
1889 | // calculate t, ray intersects triangle | ||
1890 | *t = DOT(edge2, qvec) * inv_det; | ||
1891 | |||
1892 | return 1; | ||
1893 | } | ||
1894 | |||
1895 | |||
1896 | |||
1897 | static bool | ||
1898 | SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, | ||
1899 | dVector3 in_n, dVector3* in_col_v, dReal &out_depth) | ||
1900 | { | ||
1901 | dReal dp = 0.0; | ||
1902 | dReal contact_elt_length; | ||
1903 | |||
1904 | DEPTH(dp, in_CoplanarPt, in_v, in_n); | ||
1905 | |||
1906 | if (dp >= 0.0) { | ||
1907 | // if the penetration depth (calculated above) is more than | ||
1908 | // the contact point's ELT, then we've chosen the wrong face | ||
1909 | // and should switch faces | ||
1910 | contact_elt_length = dFabs(dDOT(in_elt, in_n)); | ||
1911 | |||
1912 | if (dp == 0.0) | ||
1913 | dp = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
1914 | |||
1915 | if ((contact_elt_length < SMALL_ELT) && (dp < EXPANDED_ELT_THRESH)) | ||
1916 | dp = contact_elt_length; | ||
1917 | |||
1918 | if ( (dp > 0.0) && (dp <= contact_elt_length)) { | ||
1919 | // Add a contact | ||
1920 | |||
1921 | if ( ExamineContactPoint(in_col_v, in_n, in_v) ) { | ||
1922 | out_depth = dp; | ||
1923 | return true; | ||
1924 | } | ||
1925 | } | ||
1926 | } | ||
1927 | |||
1928 | return false; | ||
1929 | } | ||
1930 | |||
1931 | |||
1932 | |||
1933 | |||
1934 | // Generate a "unique" contact. A unique contact has a unique | ||
1935 | // position or normal. If the potential contact has the same | ||
1936 | // position and normal as an existing contact, but a larger | ||
1937 | // penetration depth, this new depth is used instead | ||
1938 | // | ||
1939 | static void | ||
1940 | GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, | ||
1941 | dxTriMesh* in_TriMesh1, dxTriMesh* in_TriMesh2, | ||
1942 | const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, | ||
1943 | int& OutTriCount) | ||
1944 | { | ||
1945 | /* | ||
1946 | NOTE by Oleh_Derevenko: | ||
1947 | This function is called after maximal number of contacts has already been | ||
1948 | collected because it has a side effect of replacing penetration depth of | ||
1949 | existing contact with larger penetration depth of another matching normal contact. | ||
1950 | If this logic is not necessary any more, you can bail out on reach of contact | ||
1951 | number maximum immediately in dCollideTTL(). You will also need to correct | ||
1952 | conditional statements after invocations of GenerateContact() in dCollideTTL(). | ||
1953 | */ | ||
1954 | dIASSERT(in_Depth >= 0.0); | ||
1955 | //if (in_Depth < 0.0) -- the function is always called with depth >= 0 | ||
1956 | // return; | ||
1957 | |||
1958 | do | ||
1959 | { | ||
1960 | dContactGeom* Contact; | ||
1961 | dVector3 diff; | ||
1962 | |||
1963 | if (!(in_Flags & CONTACTS_UNIMPORTANT)) | ||
1964 | { | ||
1965 | bool duplicate = false; | ||
1966 | |||
1967 | for (int i=0; i<OutTriCount; i++) | ||
1968 | { | ||
1969 | Contact = SAFECONTACT(in_Flags, in_Contacts, i, in_Stride); | ||
1970 | |||
1971 | // same position? | ||
1972 | SUB(diff, in_ContactPos, Contact->pos); | ||
1973 | if (dDOT(diff, diff) < dEpsilon) | ||
1974 | { | ||
1975 | // same normal? | ||
1976 | if (dFabs(dDOT(in_Normal, Contact->normal)) > (REAL(1.0)-dEpsilon)) | ||
1977 | { | ||
1978 | if (in_Depth > Contact->depth) { | ||
1979 | Contact->depth = in_Depth; | ||
1980 | SMULT( Contact->normal, in_Normal, -1.0); | ||
1981 | Contact->normal[3] = 0.0; | ||
1982 | } | ||
1983 | duplicate = true; | ||
1984 | /* | ||
1985 | NOTE by Oleh_Derevenko: | ||
1986 | There may be a case when two normals are close to each other but no duplicate | ||
1987 | while third normal is detected to be duplicate for both of them. | ||
1988 | This is the only reason I can think of, there is no "break" statement. | ||
1989 | Perhaps author considered it to be logical that the third normal would | ||
1990 | replace the depth in both of initial contacts. | ||
1991 | However, I consider it a questionable practice which should not | ||
1992 | be applied without deep understanding of underlaying physics. | ||
1993 | Even more, is this situation with close normal triplet acceptable at all? | ||
1994 | Should not be two initial contacts reduced to one (replaced with the latter)? | ||
1995 | If you know the answers for these questions, you may want to change this code. | ||
1996 | See the same statement in GenerateContact() of collision_trimesh_box.cpp | ||
1997 | */ | ||
1998 | } | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | if (duplicate || OutTriCount == (in_Flags & NUMC_MASK)) | ||
2003 | { | ||
2004 | break; | ||
2005 | } | ||
2006 | } | ||
2007 | else | ||
2008 | { | ||
2009 | dIASSERT(OutTriCount < (in_Flags & NUMC_MASK)); | ||
2010 | } | ||
2011 | |||
2012 | // Add a new contact | ||
2013 | Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride); | ||
2014 | |||
2015 | SET( Contact->pos, in_ContactPos ); | ||
2016 | Contact->pos[3] = 0.0; | ||
2017 | |||
2018 | SMULT( Contact->normal, in_Normal, -1.0); | ||
2019 | Contact->normal[3] = 0.0; | ||
2020 | |||
2021 | Contact->depth = in_Depth; | ||
2022 | |||
2023 | Contact->g1 = in_TriMesh1; | ||
2024 | Contact->g2 = in_TriMesh2; | ||
2025 | |||
2026 | OutTriCount++; | ||
2027 | } | ||
2028 | while (false); | ||
2029 | } | ||
2030 | |||
2031 | #endif // dTRIMESH_OPCODE | ||
2032 | #endif // !dTRIMESH_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
2033 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh_new.cpp b/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh_new.cpp new file mode 100755 index 0000000..c4af41c --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_trimesh_trimesh_new.cpp | |||
@@ -0,0 +1,1304 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // OPCODE TriMesh/TriMesh collision code | ||
24 | // Written at 2006-10-28 by Francisco León (http://gimpact.sourceforge.net) | ||
25 | |||
26 | #ifdef _MSC_VER | ||
27 | #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints | ||
28 | #endif | ||
29 | |||
30 | #include <ode/collision.h> | ||
31 | #include <ode/matrix.h> | ||
32 | #include <ode/rotation.h> | ||
33 | #include <ode/odemath.h> | ||
34 | |||
35 | // New Implementation | ||
36 | #if dTRIMESH_OPCODE_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
37 | |||
38 | #if dTRIMESH_ENABLED | ||
39 | |||
40 | #include "collision_util.h" | ||
41 | #define TRIMESH_INTERNAL | ||
42 | #include "collision_trimesh_internal.h" | ||
43 | |||
44 | #if dTRIMESH_OPCODE | ||
45 | |||
46 | #define SMALL_ELT REAL(2.5e-4) | ||
47 | #define EXPANDED_ELT_THRESH REAL(1.0e-3) | ||
48 | #define DISTANCE_EPSILON REAL(1.0e-8) | ||
49 | #define VELOCITY_EPSILON REAL(1.0e-5) | ||
50 | #define TINY_PENETRATION REAL(5.0e-6) | ||
51 | |||
52 | struct LineContactSet | ||
53 | { | ||
54 | enum | ||
55 | { | ||
56 | MAX_POINTS = 8 | ||
57 | }; | ||
58 | |||
59 | dVector3 Points[MAX_POINTS]; | ||
60 | int Count; | ||
61 | }; | ||
62 | |||
63 | |||
64 | static void GetTriangleGeometryCallback(udword, VertexPointers&, udword); | ||
65 | inline void dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B); | ||
66 | static void dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ); | ||
67 | static int IntersectLineSegmentRay(dVector3, dVector3, dVector3, dVector3, dVector3); | ||
68 | static void ClipConvexPolygonAgainstPlane( const dVector3, dReal, LineContactSet& ); | ||
69 | static int RayTriangleIntersect(const dVector3 orig, const dVector3 dir, | ||
70 | const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, | ||
71 | dReal *t,dReal *u,dReal *v); | ||
72 | |||
73 | |||
74 | ///returns the penetration depth | ||
75 | static dReal MostDeepPoints( | ||
76 | LineContactSet & points, | ||
77 | const dVector3 plane_normal, | ||
78 | dReal plane_dist, | ||
79 | LineContactSet & deep_points); | ||
80 | ///returns the penetration depth | ||
81 | static dReal FindMostDeepPointsInTetra( | ||
82 | LineContactSet contact_points, | ||
83 | const dVector3 sourcetri[3],///triangle which contains contact_points | ||
84 | const dVector3 tetra[4], | ||
85 | const dVector4 tetraplanes[4], | ||
86 | dVector3 separating_normal, | ||
87 | LineContactSet deep_points); | ||
88 | |||
89 | static bool ClipTriByTetra(const dVector3 tri[3], | ||
90 | const dVector3 tetra[4], | ||
91 | LineContactSet& Contacts); | ||
92 | static bool TriTriContacts(const dVector3 tr1[3], | ||
93 | const dVector3 tr2[3], | ||
94 | dxGeom* g1, dxGeom* g2, int Flags, | ||
95 | dContactGeom* Contacts, int Stride, | ||
96 | int &contactcount); | ||
97 | |||
98 | |||
99 | /* some math macros */ | ||
100 | #define CROSS(dest,v1,v2) { dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ | ||
101 | dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ | ||
102 | dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; } | ||
103 | |||
104 | #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) | ||
105 | |||
106 | #define SUB(dest,v1,v2) { dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; } | ||
107 | |||
108 | #define ADD(dest,v1,v2) { dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; } | ||
109 | |||
110 | #define MULT(dest,v,factor) { dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2]; } | ||
111 | |||
112 | #define SET(dest,src) { dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; } | ||
113 | |||
114 | #define SMULT(p,q,s) { p[0]=q[0]*s; p[1]=q[1]*s; p[2]=q[2]*s; } | ||
115 | |||
116 | #define COMBO(combo,p,t,q) { combo[0]=p[0]+t*q[0]; combo[1]=p[1]+t*q[1]; combo[2]=p[2]+t*q[2]; } | ||
117 | |||
118 | #define LENGTH(x) ((dReal) 1.0f/InvSqrt(dDOT(x, x))) | ||
119 | |||
120 | #define DEPTH(d, p, q, n) d = (p[0] - q[0])*n[0] + (p[1] - q[1])*n[1] + (p[2] - q[2])*n[2]; | ||
121 | |||
122 | inline const dReal dMin(const dReal x, const dReal y) | ||
123 | { | ||
124 | return x < y ? x : y; | ||
125 | } | ||
126 | |||
127 | |||
128 | inline void | ||
129 | SwapNormals(dVector3 *&pen_v, dVector3 *&col_v, dVector3* v1, dVector3* v2, | ||
130 | dVector3 *&pen_elt, dVector3 *elt_f1, dVector3 *elt_f2, | ||
131 | dVector3 n, dVector3 n1, dVector3 n2) | ||
132 | { | ||
133 | if (pen_v == v1) { | ||
134 | pen_v = v2; | ||
135 | pen_elt = elt_f2; | ||
136 | col_v = v1; | ||
137 | SET(n, n1); | ||
138 | } | ||
139 | else { | ||
140 | pen_v = v1; | ||
141 | pen_elt = elt_f1; | ||
142 | col_v = v2; | ||
143 | SET(n, n2); | ||
144 | } | ||
145 | } | ||
146 | |||
147 | ///////////////////////MECHANISM FOR AVOID CONTACT REDUNDANCE/////////////////////////////// | ||
148 | ////* Written by Francisco León (http://gimpact.sourceforge.net) */// | ||
149 | #define CONTACT_DIFF_EPSILON REAL(0.00001) | ||
150 | #if defined(dDOUBLE) | ||
151 | #define CONTACT_NORMAL_ZERO REAL(0.0000001) | ||
152 | #else // if defined(dSINGLE) | ||
153 | #define CONTACT_NORMAL_ZERO REAL(0.00001) | ||
154 | #endif | ||
155 | #define CONTACT_POS_HASH_QUOTIENT REAL(10000.0) | ||
156 | #define dSQRT3 REAL(1.7320508075688773) | ||
157 | |||
158 | struct CONTACT_KEY | ||
159 | { | ||
160 | dContactGeom * m_contact; | ||
161 | unsigned int m_key; | ||
162 | }; | ||
163 | |||
164 | #define MAXCONTACT_X_NODE 4 | ||
165 | struct CONTACT_KEY_HASH_NODE | ||
166 | { | ||
167 | CONTACT_KEY m_keyarray[MAXCONTACT_X_NODE]; | ||
168 | int m_keycount; | ||
169 | }; | ||
170 | |||
171 | #define CONTACTS_HASHSIZE 256 | ||
172 | CONTACT_KEY_HASH_NODE g_hashcontactset[CONTACTS_HASHSIZE]; | ||
173 | |||
174 | |||
175 | |||
176 | void UpdateContactKey(CONTACT_KEY & key, dContactGeom * contact) | ||
177 | { | ||
178 | key.m_contact = contact; | ||
179 | |||
180 | unsigned int hash=0; | ||
181 | |||
182 | int i = 0; | ||
183 | |||
184 | while (true) | ||
185 | { | ||
186 | dReal coord = contact->pos[i]; | ||
187 | coord = dFloor(coord * CONTACT_POS_HASH_QUOTIENT); | ||
188 | |||
189 | unsigned int hash_input = ((unsigned int *)&coord)[0]; | ||
190 | if (sizeof(dReal) / sizeof(unsigned int) != 1) | ||
191 | { | ||
192 | dIASSERT(sizeof(dReal) / sizeof(unsigned int) == 2); | ||
193 | hash_input ^= ((unsigned int *)&coord)[1]; | ||
194 | } | ||
195 | |||
196 | hash = (( hash << 4 ) + (hash_input >> 24)) ^ ( hash >> 28 ); | ||
197 | hash = (( hash << 4 ) + ((hash_input >> 16) & 0xFF)) ^ ( hash >> 28 ); | ||
198 | hash = (( hash << 4 ) + ((hash_input >> 8) & 0xFF)) ^ ( hash >> 28 ); | ||
199 | hash = (( hash << 4 ) + (hash_input & 0xFF)) ^ ( hash >> 28 ); | ||
200 | |||
201 | if (++i == 3) | ||
202 | { | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | hash = (hash << 11) | (hash >> 21); | ||
207 | } | ||
208 | |||
209 | key.m_key = hash; | ||
210 | } | ||
211 | |||
212 | |||
213 | static inline unsigned int MakeContactIndex(unsigned int key) | ||
214 | { | ||
215 | dIASSERT(CONTACTS_HASHSIZE == 256); | ||
216 | |||
217 | unsigned int index = key ^ (key >> 16); | ||
218 | index = (index ^ (index >> 8)) & 0xFF; | ||
219 | return index; | ||
220 | } | ||
221 | |||
222 | dContactGeom *AddContactToNode(const CONTACT_KEY * contactkey,CONTACT_KEY_HASH_NODE * node) | ||
223 | { | ||
224 | for(int i=0;i<node->m_keycount;i++) | ||
225 | { | ||
226 | if(node->m_keyarray[i].m_key == contactkey->m_key) | ||
227 | { | ||
228 | dContactGeom *contactfound = node->m_keyarray[i].m_contact; | ||
229 | if (dDISTANCE(contactfound->pos, contactkey->m_contact->pos) < REAL(1.00001) /*for comp. errors*/ * dSQRT3 / CONTACT_POS_HASH_QUOTIENT /*cube diagonal*/) | ||
230 | { | ||
231 | return contactfound; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | if (node->m_keycount < MAXCONTACT_X_NODE) | ||
237 | { | ||
238 | node->m_keyarray[node->m_keycount].m_contact = contactkey->m_contact; | ||
239 | node->m_keyarray[node->m_keycount].m_key = contactkey->m_key; | ||
240 | node->m_keycount++; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | dDEBUGMSG("Trimesh-trimesh contach hash table bucket overflow - close contacts might not be culled"); | ||
245 | } | ||
246 | |||
247 | return contactkey->m_contact; | ||
248 | } | ||
249 | |||
250 | void RemoveNewContactFromNode(const CONTACT_KEY * contactkey, CONTACT_KEY_HASH_NODE * node) | ||
251 | { | ||
252 | dIASSERT(node->m_keycount > 0); | ||
253 | |||
254 | if (node->m_keyarray[node->m_keycount - 1].m_contact == contactkey->m_contact) | ||
255 | { | ||
256 | node->m_keycount -= 1; | ||
257 | } | ||
258 | else | ||
259 | { | ||
260 | dIASSERT(node->m_keycount == MAXCONTACT_X_NODE); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | void RemoveArbitraryContactFromNode(const CONTACT_KEY *contactkey, CONTACT_KEY_HASH_NODE *node) | ||
265 | { | ||
266 | dIASSERT(node->m_keycount > 0); | ||
267 | |||
268 | int keyindex, lastkeyindex = node->m_keycount - 1; | ||
269 | |||
270 | // Do not check the last contact | ||
271 | for (keyindex = 0; keyindex < lastkeyindex; keyindex++) | ||
272 | { | ||
273 | if (node->m_keyarray[keyindex].m_contact == contactkey->m_contact) | ||
274 | { | ||
275 | node->m_keyarray[keyindex] = node->m_keyarray[lastkeyindex]; | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | dIASSERT(keyindex < lastkeyindex || | ||
281 | node->m_keyarray[keyindex].m_contact == contactkey->m_contact); // It has been either the break from loop or last element should match | ||
282 | |||
283 | node->m_keycount = lastkeyindex; | ||
284 | } | ||
285 | |||
286 | void UpdateArbitraryContactInNode(const CONTACT_KEY *contactkey, CONTACT_KEY_HASH_NODE *node, | ||
287 | dContactGeom *pwithcontact) | ||
288 | { | ||
289 | dIASSERT(node->m_keycount > 0); | ||
290 | |||
291 | int keyindex, lastkeyindex = node->m_keycount - 1; | ||
292 | |||
293 | // Do not check the last contact | ||
294 | for (keyindex = 0; keyindex < lastkeyindex; keyindex++) | ||
295 | { | ||
296 | if (node->m_keyarray[keyindex].m_contact == contactkey->m_contact) | ||
297 | { | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | dIASSERT(keyindex < lastkeyindex || | ||
303 | node->m_keyarray[keyindex].m_contact == contactkey->m_contact); // It has been either the break from loop or last element should match | ||
304 | |||
305 | node->m_keyarray[keyindex].m_contact = pwithcontact; | ||
306 | } | ||
307 | |||
308 | void ClearContactSet() | ||
309 | { | ||
310 | memset(g_hashcontactset,0,sizeof(CONTACT_KEY_HASH_NODE)*CONTACTS_HASHSIZE); | ||
311 | } | ||
312 | |||
313 | //return true if found | ||
314 | dContactGeom *InsertContactInSet(const CONTACT_KEY &newkey) | ||
315 | { | ||
316 | unsigned int index = MakeContactIndex(newkey.m_key); | ||
317 | |||
318 | return AddContactToNode(&newkey, &g_hashcontactset[index]); | ||
319 | } | ||
320 | |||
321 | void RemoveNewContactFromSet(const CONTACT_KEY &contactkey) | ||
322 | { | ||
323 | unsigned int index = MakeContactIndex(contactkey.m_key); | ||
324 | |||
325 | RemoveNewContactFromNode(&contactkey, &g_hashcontactset[index]); | ||
326 | } | ||
327 | |||
328 | void RemoveArbitraryContactFromSet(const CONTACT_KEY &contactkey) | ||
329 | { | ||
330 | unsigned int index = MakeContactIndex(contactkey.m_key); | ||
331 | |||
332 | RemoveArbitraryContactFromNode(&contactkey, &g_hashcontactset[index]); | ||
333 | } | ||
334 | |||
335 | void UpdateArbitraryContactInSet(const CONTACT_KEY &contactkey, | ||
336 | dContactGeom *pwithcontact) | ||
337 | { | ||
338 | unsigned int index = MakeContactIndex(contactkey.m_key); | ||
339 | |||
340 | UpdateArbitraryContactInNode(&contactkey, &g_hashcontactset[index], pwithcontact); | ||
341 | } | ||
342 | |||
343 | bool AllocNewContact( | ||
344 | const dVector3 newpoint, dContactGeom *& out_pcontact, | ||
345 | int Flags, dContactGeom* Contacts, | ||
346 | int Stride, int &contactcount) | ||
347 | { | ||
348 | bool allocated_new = false; | ||
349 | |||
350 | dContactGeom dLocalContact; | ||
351 | |||
352 | dContactGeom * pcontact = contactcount != (Flags & NUMC_MASK) ? | ||
353 | SAFECONTACT(Flags, Contacts, contactcount, Stride) : &dLocalContact; | ||
354 | |||
355 | pcontact->pos[0] = newpoint[0]; | ||
356 | pcontact->pos[1] = newpoint[1]; | ||
357 | pcontact->pos[2] = newpoint[2]; | ||
358 | pcontact->pos[3] = 1.0f; | ||
359 | |||
360 | CONTACT_KEY newkey; | ||
361 | UpdateContactKey(newkey, pcontact); | ||
362 | |||
363 | dContactGeom *pcontactfound = InsertContactInSet(newkey); | ||
364 | if (pcontactfound == pcontact) | ||
365 | { | ||
366 | if (pcontactfound != &dLocalContact) | ||
367 | { | ||
368 | contactcount++; | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | RemoveNewContactFromSet(newkey); | ||
373 | pcontactfound = NULL; | ||
374 | } | ||
375 | |||
376 | allocated_new = true; | ||
377 | } | ||
378 | |||
379 | out_pcontact = pcontactfound; | ||
380 | return allocated_new; | ||
381 | } | ||
382 | |||
383 | void FreeExistingContact(dContactGeom *pcontact, | ||
384 | int Flags, dContactGeom *Contacts, | ||
385 | int Stride, int &contactcount) | ||
386 | { | ||
387 | CONTACT_KEY contactKey; | ||
388 | UpdateContactKey(contactKey, pcontact); | ||
389 | |||
390 | RemoveArbitraryContactFromSet(contactKey); | ||
391 | |||
392 | int lastContactIndex = contactcount - 1; | ||
393 | dContactGeom *plastContact = SAFECONTACT(Flags, Contacts, lastContactIndex, Stride); | ||
394 | |||
395 | if (pcontact != plastContact) | ||
396 | { | ||
397 | *pcontact = *plastContact; | ||
398 | |||
399 | CONTACT_KEY lastContactKey; | ||
400 | UpdateContactKey(lastContactKey, plastContact); | ||
401 | |||
402 | UpdateArbitraryContactInSet(lastContactKey, pcontact); | ||
403 | } | ||
404 | |||
405 | contactcount = lastContactIndex; | ||
406 | } | ||
407 | |||
408 | |||
409 | dContactGeom * PushNewContact( dxGeom* g1, dxGeom* g2, | ||
410 | const dVector3 point, | ||
411 | dVector3 normal, | ||
412 | dReal depth, | ||
413 | int Flags, | ||
414 | dContactGeom* Contacts, int Stride, | ||
415 | int &contactcount) | ||
416 | { | ||
417 | dIASSERT(dFabs(dVector3Length((const dVector3 &)(*normal)) - REAL(1.0)) < REAL(1e-6)); // This assumption is used in the code | ||
418 | |||
419 | dContactGeom * pcontact; | ||
420 | |||
421 | if (!AllocNewContact(point, pcontact, Flags, Contacts, Stride, contactcount)) | ||
422 | { | ||
423 | const dReal depthDifference = depth - pcontact->depth; | ||
424 | |||
425 | if (depthDifference > CONTACT_DIFF_EPSILON) | ||
426 | { | ||
427 | pcontact->normal[0] = normal[0]; | ||
428 | pcontact->normal[1] = normal[1]; | ||
429 | pcontact->normal[2] = normal[2]; | ||
430 | pcontact->normal[3] = REAL(1.0); // used to store length of vector sum for averaging | ||
431 | pcontact->depth = depth; | ||
432 | |||
433 | pcontact->g1 = g1; | ||
434 | pcontact->g2 = g2; | ||
435 | } | ||
436 | else if (depthDifference >= -CONTACT_DIFF_EPSILON) ///average | ||
437 | { | ||
438 | if(pcontact->g1 == g2) | ||
439 | { | ||
440 | MULT(normal,normal, REAL(-1.0)); | ||
441 | } | ||
442 | |||
443 | const dReal oldLen = pcontact->normal[3]; | ||
444 | COMBO(pcontact->normal, normal, oldLen, pcontact->normal); | ||
445 | |||
446 | const dReal len = LENGTH(pcontact->normal); | ||
447 | if (len > CONTACT_NORMAL_ZERO) | ||
448 | { | ||
449 | MULT(pcontact->normal, pcontact->normal, REAL(1.0) / len); | ||
450 | pcontact->normal[3] = len; | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | FreeExistingContact(pcontact, Flags, Contacts, Stride, contactcount); | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | // Contact can be not available if buffer is full | ||
459 | else if (pcontact) | ||
460 | { | ||
461 | pcontact->normal[0] = normal[0]; | ||
462 | pcontact->normal[1] = normal[1]; | ||
463 | pcontact->normal[2] = normal[2]; | ||
464 | pcontact->normal[3] = REAL(1.0); // used to store length of vector sum for averaging | ||
465 | pcontact->depth = depth; | ||
466 | pcontact->g1 = g1; | ||
467 | pcontact->g2 = g2; | ||
468 | } | ||
469 | |||
470 | return pcontact; | ||
471 | } | ||
472 | |||
473 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
474 | |||
475 | |||
476 | |||
477 | |||
478 | |||
479 | int | ||
480 | dCollideTTL(dxGeom* g1, dxGeom* g2, int Flags, dContactGeom* Contacts, int Stride) | ||
481 | { | ||
482 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
483 | dIASSERT (g1->type == dTriMeshClass); | ||
484 | dIASSERT (g2->type == dTriMeshClass); | ||
485 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
486 | |||
487 | dxTriMesh* TriMesh1 = (dxTriMesh*) g1; | ||
488 | dxTriMesh* TriMesh2 = (dxTriMesh*) g2; | ||
489 | |||
490 | dReal * TriNormals1 = (dReal *) TriMesh1->Data->Normals; | ||
491 | dReal * TriNormals2 = (dReal *) TriMesh2->Data->Normals; | ||
492 | |||
493 | const dVector3& TLPosition1 = *(const dVector3*) dGeomGetPosition(TriMesh1); | ||
494 | // TLRotation1 = column-major order | ||
495 | const dMatrix3& TLRotation1 = *(const dMatrix3*) dGeomGetRotation(TriMesh1); | ||
496 | |||
497 | const dVector3& TLPosition2 = *(const dVector3*) dGeomGetPosition(TriMesh2); | ||
498 | // TLRotation2 = column-major order | ||
499 | const dMatrix3& TLRotation2 = *(const dMatrix3*) dGeomGetRotation(TriMesh2); | ||
500 | |||
501 | AABBTreeCollider& Collider = TriMesh1->_AABBTreeCollider; | ||
502 | |||
503 | |||
504 | static BVTCache ColCache; | ||
505 | ColCache.Model0 = &TriMesh1->Data->BVTree; | ||
506 | ColCache.Model1 = &TriMesh2->Data->BVTree; | ||
507 | |||
508 | ////Prepare contact list | ||
509 | ClearContactSet(); | ||
510 | |||
511 | // Collision query | ||
512 | Matrix4x4 amatrix, bmatrix; | ||
513 | BOOL IsOk = Collider.Collide(ColCache, | ||
514 | &MakeMatrix(TLPosition1, TLRotation1, amatrix), | ||
515 | &MakeMatrix(TLPosition2, TLRotation2, bmatrix) ); | ||
516 | |||
517 | |||
518 | // Make "double" versions of these matrices, if appropriate | ||
519 | dMatrix4 A, B; | ||
520 | dMakeMatrix4(TLPosition1, TLRotation1, A); | ||
521 | dMakeMatrix4(TLPosition2, TLRotation2, B); | ||
522 | |||
523 | |||
524 | |||
525 | |||
526 | if (IsOk) { | ||
527 | // Get collision status => if true, objects overlap | ||
528 | if ( Collider.GetContactStatus() ) { | ||
529 | // Number of colliding pairs and list of pairs | ||
530 | int TriCount = Collider.GetNbPairs(); | ||
531 | const Pair* CollidingPairs = Collider.GetPairs(); | ||
532 | |||
533 | if (TriCount > 0) { | ||
534 | // step through the pairs, adding contacts | ||
535 | int id1, id2; | ||
536 | int OutTriCount = 0; | ||
537 | dVector3 v1[3], v2[3]; | ||
538 | |||
539 | // only do these expensive inversions once | ||
540 | /*dMatrix4 InvMatrix1, InvMatrix2; | ||
541 | dInvertMatrix4(A, InvMatrix1); | ||
542 | dInvertMatrix4(B, InvMatrix2);*/ | ||
543 | |||
544 | |||
545 | for (int i = 0; i < TriCount; i++) | ||
546 | { | ||
547 | id1 = CollidingPairs[i].id0; | ||
548 | id2 = CollidingPairs[i].id1; | ||
549 | |||
550 | // grab the colliding triangles | ||
551 | FetchTriangle((dxTriMesh*) g1, id1, TLPosition1, TLRotation1, v1); | ||
552 | FetchTriangle((dxTriMesh*) g2, id2, TLPosition2, TLRotation2, v2); | ||
553 | // Since we'll be doing matrix transformations, we need to | ||
554 | // make sure that all vertices have four elements | ||
555 | for (int j=0; j<3; j++) { | ||
556 | v1[j][3] = 1.0; | ||
557 | v2[j][3] = 1.0; | ||
558 | } | ||
559 | |||
560 | TriTriContacts(v1,v2, | ||
561 | g1, g2, Flags, | ||
562 | Contacts,Stride,OutTriCount); | ||
563 | |||
564 | // Continue loop even after contacts are full | ||
565 | // as existing contacts' normals/depths might be updated | ||
566 | // Break only if contacts are not important | ||
567 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) | ||
568 | { | ||
569 | break; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | // Return the number of contacts | ||
574 | return OutTriCount; | ||
575 | |||
576 | } | ||
577 | } | ||
578 | } | ||
579 | |||
580 | |||
581 | // There was some kind of failure during the Collide call or | ||
582 | // there are no faces overlapping | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | |||
587 | |||
588 | static void | ||
589 | GetTriangleGeometryCallback(udword triangleindex, VertexPointers& triangle, udword user_data) | ||
590 | { | ||
591 | dVector3 Out[3]; | ||
592 | |||
593 | FetchTriangle((dxTriMesh*) user_data, (int) triangleindex, Out); | ||
594 | |||
595 | for (int i = 0; i < 3; i++) | ||
596 | triangle.Vertex[i] = (const Point*) ((dReal*) Out[i]); | ||
597 | } | ||
598 | |||
599 | |||
600 | // | ||
601 | // | ||
602 | // | ||
603 | #define B11 B[0] | ||
604 | #define B12 B[1] | ||
605 | #define B13 B[2] | ||
606 | #define B14 B[3] | ||
607 | #define B21 B[4] | ||
608 | #define B22 B[5] | ||
609 | #define B23 B[6] | ||
610 | #define B24 B[7] | ||
611 | #define B31 B[8] | ||
612 | #define B32 B[9] | ||
613 | #define B33 B[10] | ||
614 | #define B34 B[11] | ||
615 | #define B41 B[12] | ||
616 | #define B42 B[13] | ||
617 | #define B43 B[14] | ||
618 | #define B44 B[15] | ||
619 | |||
620 | #define Binv11 Binv[0] | ||
621 | #define Binv12 Binv[1] | ||
622 | #define Binv13 Binv[2] | ||
623 | #define Binv14 Binv[3] | ||
624 | #define Binv21 Binv[4] | ||
625 | #define Binv22 Binv[5] | ||
626 | #define Binv23 Binv[6] | ||
627 | #define Binv24 Binv[7] | ||
628 | #define Binv31 Binv[8] | ||
629 | #define Binv32 Binv[9] | ||
630 | #define Binv33 Binv[10] | ||
631 | #define Binv34 Binv[11] | ||
632 | #define Binv41 Binv[12] | ||
633 | #define Binv42 Binv[13] | ||
634 | #define Binv43 Binv[14] | ||
635 | #define Binv44 Binv[15] | ||
636 | |||
637 | inline void | ||
638 | dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B) | ||
639 | { | ||
640 | B11 = Rotation[0]; B21 = Rotation[1]; B31 = Rotation[2]; B41 = Position[0]; | ||
641 | B12 = Rotation[4]; B22 = Rotation[5]; B32 = Rotation[6]; B42 = Position[1]; | ||
642 | B13 = Rotation[8]; B23 = Rotation[9]; B33 = Rotation[10]; B43 = Position[2]; | ||
643 | |||
644 | B14 = 0.0; B24 = 0.0; B34 = 0.0; B44 = 1.0; | ||
645 | } | ||
646 | |||
647 | |||
648 | static void | ||
649 | dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ) | ||
650 | { | ||
651 | dReal det = (B11 * B22 - B12 * B21) * (B33 * B44 - B34 * B43) | ||
652 | -(B11 * B23 - B13 * B21) * (B32 * B44 - B34 * B42) | ||
653 | +(B11 * B24 - B14 * B21) * (B32 * B43 - B33 * B42) | ||
654 | +(B12 * B23 - B13 * B22) * (B31 * B44 - B34 * B41) | ||
655 | -(B12 * B24 - B14 * B22) * (B31 * B43 - B33 * B41) | ||
656 | +(B13 * B24 - B14 * B23) * (B31 * B42 - B32 * B41); | ||
657 | |||
658 | dAASSERT (det != 0.0); | ||
659 | |||
660 | det = 1.0 / det; | ||
661 | |||
662 | Binv11 = (dReal) (det * ((B22 * B33) - (B23 * B32))); | ||
663 | Binv12 = (dReal) (det * ((B32 * B13) - (B33 * B12))); | ||
664 | Binv13 = (dReal) (det * ((B12 * B23) - (B13 * B22))); | ||
665 | Binv14 = 0.0f; | ||
666 | Binv21 = (dReal) (det * ((B23 * B31) - (B21 * B33))); | ||
667 | Binv22 = (dReal) (det * ((B33 * B11) - (B31 * B13))); | ||
668 | Binv23 = (dReal) (det * ((B13 * B21) - (B11 * B23))); | ||
669 | Binv24 = 0.0f; | ||
670 | Binv31 = (dReal) (det * ((B21 * B32) - (B22 * B31))); | ||
671 | Binv32 = (dReal) (det * ((B31 * B12) - (B32 * B11))); | ||
672 | Binv33 = (dReal) (det * ((B11 * B22) - (B12 * B21))); | ||
673 | Binv34 = 0.0f; | ||
674 | Binv41 = (dReal) (det * (B21*(B33*B42 - B32*B43) + B22*(B31*B43 - B33*B41) + B23*(B32*B41 - B31*B42))); | ||
675 | Binv42 = (dReal) (det * (B31*(B13*B42 - B12*B43) + B32*(B11*B43 - B13*B41) + B33*(B12*B41 - B11*B42))); | ||
676 | Binv43 = (dReal) (det * (B41*(B13*B22 - B12*B23) + B42*(B11*B23 - B13*B21) + B43*(B12*B21 - B11*B22))); | ||
677 | Binv44 = 1.0f; | ||
678 | } | ||
679 | |||
680 | |||
681 | |||
682 | // Find the intersectiojn point between a coplanar line segement, | ||
683 | // defined by X1 and X2, and a ray defined by X3 and direction N. | ||
684 | // | ||
685 | // This forumla for this calculation is: | ||
686 | // (c x b) . (a x b) | ||
687 | // Q = x1 + a ------------------- | ||
688 | // | a x b | ^2 | ||
689 | // | ||
690 | // where a = x2 - x1 | ||
691 | // b = x4 - x3 | ||
692 | // c = x3 - x1 | ||
693 | // x1 and x2 are the edges of the triangle, and x3 is CoplanarPt | ||
694 | // and x4 is (CoplanarPt - n) | ||
695 | static int | ||
696 | IntersectLineSegmentRay(dVector3 x1, dVector3 x2, dVector3 x3, dVector3 n, | ||
697 | dVector3 out_pt) | ||
698 | { | ||
699 | dVector3 a, b, c, x4; | ||
700 | |||
701 | ADD(x4, x3, n); // x4 = x3 + n | ||
702 | |||
703 | SUB(a, x2, x1); // a = x2 - x1 | ||
704 | SUB(b, x4, x3); | ||
705 | SUB(c, x3, x1); | ||
706 | |||
707 | dVector3 tmp1, tmp2; | ||
708 | CROSS(tmp1, c, b); | ||
709 | CROSS(tmp2, a, b); | ||
710 | |||
711 | dReal num, denom; | ||
712 | num = dDOT(tmp1, tmp2); | ||
713 | denom = LENGTH( tmp2 ); | ||
714 | |||
715 | dReal s; | ||
716 | s = num /(denom*denom); | ||
717 | |||
718 | for (int i=0; i<3; i++) | ||
719 | out_pt[i] = x1[i] + a[i]*s; | ||
720 | |||
721 | // Test if this intersection is "behind" x3, w.r.t. n | ||
722 | SUB(a, x3, out_pt); | ||
723 | if (dDOT(a, n) > 0.0) | ||
724 | return 0; | ||
725 | |||
726 | // Test if this intersection point is outside the edge limits, | ||
727 | // if (dot( (out_pt-x1), (out_pt-x2) ) < 0) it's inside | ||
728 | // else outside | ||
729 | SUB(a, out_pt, x1); | ||
730 | SUB(b, out_pt, x2); | ||
731 | if (dDOT(a,b) < 0.0) | ||
732 | return 1; | ||
733 | else | ||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | |||
738 | |||
739 | void PlaneClipSegment( const dVector3 s1, const dVector3 s2, | ||
740 | const dVector3 N, dReal C, dVector3 clipped) | ||
741 | { | ||
742 | dReal dis1,dis2; | ||
743 | dis1 = DOT(s1,N)-C; | ||
744 | SUB(clipped,s2,s1); | ||
745 | dis2 = DOT(clipped,N); | ||
746 | MULT(clipped,clipped,-dis1/dis2); | ||
747 | ADD(clipped,clipped,s1); | ||
748 | clipped[3] = 1.0f; | ||
749 | } | ||
750 | |||
751 | /* ClipConvexPolygonAgainstPlane - Clip a a convex polygon, described by | ||
752 | CONTACTS, with a plane (described by N and C distance from origin). | ||
753 | Note: the input vertices are assumed to be in invcounterclockwise order. | ||
754 | changed by Francisco Leon (http://gimpact.sourceforge.net) */ | ||
755 | static void | ||
756 | ClipConvexPolygonAgainstPlane( const dVector3 N, dReal C, | ||
757 | LineContactSet& Contacts ) | ||
758 | { | ||
759 | int i, vi, prevclassif=32000, classif; | ||
760 | /* | ||
761 | classif 0 : back, 1 : front | ||
762 | */ | ||
763 | |||
764 | dReal d; | ||
765 | dVector3 clipped[8]; | ||
766 | int clippedcount =0; | ||
767 | |||
768 | if(Contacts.Count==0) | ||
769 | { | ||
770 | return; | ||
771 | } | ||
772 | for(i=0;i<=Contacts.Count;i++) | ||
773 | { | ||
774 | vi = i%Contacts.Count; | ||
775 | |||
776 | d = DOT(N,Contacts.Points[vi]) - C; | ||
777 | ////classify point | ||
778 | if(d>REAL(1.0e-8)) classif = 1; | ||
779 | else classif = 0; | ||
780 | |||
781 | if(classif == 0)//back | ||
782 | { | ||
783 | if(i>0) | ||
784 | { | ||
785 | if(prevclassif==1)///in front | ||
786 | { | ||
787 | |||
788 | ///add clipped point | ||
789 | if(clippedcount<8) | ||
790 | { | ||
791 | PlaneClipSegment(Contacts.Points[i-1],Contacts.Points[vi], | ||
792 | N,C,clipped[clippedcount]); | ||
793 | clippedcount++; | ||
794 | } | ||
795 | } | ||
796 | } | ||
797 | ///add point | ||
798 | if(clippedcount<8&&i<Contacts.Count) | ||
799 | { | ||
800 | clipped[clippedcount][0] = Contacts.Points[vi][0]; | ||
801 | clipped[clippedcount][1] = Contacts.Points[vi][1]; | ||
802 | clipped[clippedcount][2] = Contacts.Points[vi][2]; | ||
803 | clipped[clippedcount][3] = 1.0f; | ||
804 | clippedcount++; | ||
805 | } | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | |||
810 | if(i>0) | ||
811 | { | ||
812 | if(prevclassif==0) | ||
813 | { | ||
814 | ///add point | ||
815 | if(clippedcount<8) | ||
816 | { | ||
817 | PlaneClipSegment(Contacts.Points[i-1],Contacts.Points[vi], | ||
818 | N,C,clipped[clippedcount]); | ||
819 | clippedcount++; | ||
820 | } | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
825 | prevclassif = classif; | ||
826 | } | ||
827 | |||
828 | if(clippedcount==0) | ||
829 | { | ||
830 | Contacts.Count = 0; | ||
831 | return; | ||
832 | } | ||
833 | Contacts.Count = clippedcount; | ||
834 | memcpy( Contacts.Points, clipped, clippedcount * sizeof(dVector3) ); | ||
835 | return; | ||
836 | } | ||
837 | |||
838 | |||
839 | bool BuildPlane(const dVector3 s0, const dVector3 s1,const dVector3 s2, | ||
840 | dVector3 Normal, dReal & Dist) | ||
841 | { | ||
842 | dVector3 e0,e1; | ||
843 | SUB(e0,s1,s0); | ||
844 | SUB(e1,s2,s0); | ||
845 | |||
846 | CROSS(Normal,e0,e1); | ||
847 | |||
848 | if (!dSafeNormalize3(Normal)) | ||
849 | { | ||
850 | return false; | ||
851 | } | ||
852 | |||
853 | Dist = DOT(Normal,s0); | ||
854 | return true; | ||
855 | |||
856 | } | ||
857 | |||
858 | bool BuildEdgesDir(const dVector3 s0, const dVector3 s1, | ||
859 | const dVector3 t0, const dVector3 t1, | ||
860 | dVector3 crossdir) | ||
861 | { | ||
862 | dVector3 e0,e1; | ||
863 | |||
864 | SUB(e0,s1,s0); | ||
865 | SUB(e1,t1,t0); | ||
866 | CROSS(crossdir,e0,e1); | ||
867 | |||
868 | if (!dSafeNormalize3(crossdir)) | ||
869 | { | ||
870 | return false; | ||
871 | } | ||
872 | return true; | ||
873 | } | ||
874 | |||
875 | |||
876 | |||
877 | bool BuildEdgePlane( | ||
878 | const dVector3 s0, const dVector3 s1, | ||
879 | const dVector3 normal, | ||
880 | dVector3 plane_normal, | ||
881 | dReal & plane_dist) | ||
882 | { | ||
883 | dVector3 e0; | ||
884 | |||
885 | SUB(e0,s1,s0); | ||
886 | CROSS(plane_normal,e0,normal); | ||
887 | if (!dSafeNormalize3(plane_normal)) | ||
888 | { | ||
889 | return false; | ||
890 | } | ||
891 | plane_dist = DOT(plane_normal,s0); | ||
892 | return true; | ||
893 | } | ||
894 | |||
895 | |||
896 | |||
897 | |||
898 | /* | ||
899 | Positive penetration | ||
900 | Negative number: they are separated | ||
901 | */ | ||
902 | dReal IntervalPenetration(dReal &vmin1,dReal &vmax1, | ||
903 | dReal &vmin2,dReal &vmax2) | ||
904 | { | ||
905 | if(vmax1<=vmin2) | ||
906 | { | ||
907 | return -(vmin2-vmax1); | ||
908 | } | ||
909 | else | ||
910 | { | ||
911 | if(vmax2<=vmin1) | ||
912 | { | ||
913 | return -(vmin1-vmax2); | ||
914 | } | ||
915 | else | ||
916 | { | ||
917 | if(vmax1<=vmax2) | ||
918 | { | ||
919 | return vmax1-vmin2; | ||
920 | } | ||
921 | |||
922 | return vmax2-vmin1; | ||
923 | } | ||
924 | |||
925 | } | ||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | void FindInterval( | ||
930 | const dVector3 * vertices, int verticecount, | ||
931 | dVector3 dir,dReal &vmin,dReal &vmax) | ||
932 | { | ||
933 | |||
934 | dReal dist; | ||
935 | int i; | ||
936 | vmin = DOT(vertices[0],dir); | ||
937 | vmax = vmin; | ||
938 | for(i=1;i<verticecount;i++) | ||
939 | { | ||
940 | dist = DOT(vertices[i],dir); | ||
941 | if(vmin>dist) vmin=dist; | ||
942 | else if(vmax<dist) vmax=dist; | ||
943 | } | ||
944 | } | ||
945 | |||
946 | ///returns the penetration depth | ||
947 | dReal MostDeepPoints( | ||
948 | LineContactSet & points, | ||
949 | const dVector3 plane_normal, | ||
950 | dReal plane_dist, | ||
951 | LineContactSet & deep_points) | ||
952 | { | ||
953 | int i; | ||
954 | int max_candidates[8]; | ||
955 | dReal maxdeep=-dInfinity; | ||
956 | dReal dist; | ||
957 | |||
958 | deep_points.Count = 0; | ||
959 | for(i=0;i<points.Count;i++) | ||
960 | { | ||
961 | dist = DOT(plane_normal,points.Points[i]) - plane_dist; | ||
962 | dist *= -1.0f; | ||
963 | if(dist>maxdeep) | ||
964 | { | ||
965 | maxdeep = dist; | ||
966 | deep_points.Count=1; | ||
967 | max_candidates[deep_points.Count-1] = i; | ||
968 | } | ||
969 | else if(dist+REAL(0.000001)>=maxdeep) | ||
970 | { | ||
971 | deep_points.Count++; | ||
972 | max_candidates[deep_points.Count-1] = i; | ||
973 | } | ||
974 | } | ||
975 | |||
976 | for(i=0;i<deep_points.Count;i++) | ||
977 | { | ||
978 | SET(deep_points.Points[i],points.Points[max_candidates[i]]); | ||
979 | } | ||
980 | return maxdeep; | ||
981 | |||
982 | } | ||
983 | |||
984 | void ClipPointsByTri( | ||
985 | const dVector3 * points, int pointcount, | ||
986 | const dVector3 tri[3], | ||
987 | const dVector3 triplanenormal, | ||
988 | dReal triplanedist, | ||
989 | LineContactSet & clipped_points, | ||
990 | bool triplane_clips) | ||
991 | { | ||
992 | ///build edges planes | ||
993 | int i; | ||
994 | dVector4 plane; | ||
995 | |||
996 | clipped_points.Count = pointcount; | ||
997 | memcpy(&clipped_points.Points[0],&points[0],pointcount*sizeof(dVector3)); | ||
998 | for(i=0;i<3;i++) | ||
999 | { | ||
1000 | if (BuildEdgePlane( | ||
1001 | tri[i],tri[(i+1)%3],triplanenormal, | ||
1002 | plane,plane[3])) | ||
1003 | { | ||
1004 | ClipConvexPolygonAgainstPlane( | ||
1005 | plane, | ||
1006 | plane[3], | ||
1007 | clipped_points); | ||
1008 | } | ||
1009 | } | ||
1010 | |||
1011 | if(triplane_clips) | ||
1012 | { | ||
1013 | ClipConvexPolygonAgainstPlane( | ||
1014 | triplanenormal, | ||
1015 | triplanedist, | ||
1016 | clipped_points); | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | |||
1021 | ///returns the penetration depth | ||
1022 | dReal FindTriangleTriangleCollision( | ||
1023 | const dVector3 tri1[3], | ||
1024 | const dVector3 tri2[3], | ||
1025 | dVector3 separating_normal, | ||
1026 | LineContactSet & deep_points) | ||
1027 | { | ||
1028 | dReal maxdeep=dInfinity; | ||
1029 | dReal dist; | ||
1030 | int mostdir=0,mostface = 0, currdir=0; | ||
1031 | // dReal vmin1,vmax1,vmin2,vmax2; | ||
1032 | // dVector3 crossdir, pt1,pt2; | ||
1033 | dVector4 tri1plane,tri2plane; | ||
1034 | separating_normal[3] = 0.0f; | ||
1035 | bool bl; | ||
1036 | LineContactSet clipped_points1,clipped_points2; | ||
1037 | LineContactSet deep_points1,deep_points2; | ||
1038 | ////find interval face1 | ||
1039 | |||
1040 | bl = BuildPlane(tri1[0],tri1[1],tri1[2], | ||
1041 | tri1plane,tri1plane[3]); | ||
1042 | clipped_points1.Count = 0; | ||
1043 | |||
1044 | if(bl) | ||
1045 | { | ||
1046 | ClipPointsByTri( | ||
1047 | tri2, 3, | ||
1048 | tri1, | ||
1049 | tri1plane, | ||
1050 | tri1plane[3], | ||
1051 | clipped_points1,false); | ||
1052 | |||
1053 | |||
1054 | |||
1055 | maxdeep = MostDeepPoints( | ||
1056 | clipped_points1, | ||
1057 | tri1plane, | ||
1058 | tri1plane[3], | ||
1059 | deep_points1); | ||
1060 | SET(separating_normal,tri1plane); | ||
1061 | |||
1062 | } | ||
1063 | currdir++; | ||
1064 | |||
1065 | ////find interval face2 | ||
1066 | |||
1067 | bl = BuildPlane(tri2[0],tri2[1],tri2[2], | ||
1068 | tri2plane,tri2plane[3]); | ||
1069 | |||
1070 | |||
1071 | clipped_points2.Count = 0; | ||
1072 | if(bl) | ||
1073 | { | ||
1074 | ClipPointsByTri( | ||
1075 | tri1, 3, | ||
1076 | tri2, | ||
1077 | tri2plane, | ||
1078 | tri2plane[3], | ||
1079 | clipped_points2,false); | ||
1080 | |||
1081 | |||
1082 | |||
1083 | dist = MostDeepPoints( | ||
1084 | clipped_points2, | ||
1085 | tri2plane, | ||
1086 | tri2plane[3], | ||
1087 | deep_points2); | ||
1088 | |||
1089 | |||
1090 | |||
1091 | if(dist<maxdeep) | ||
1092 | { | ||
1093 | maxdeep = dist; | ||
1094 | mostdir = currdir; | ||
1095 | mostface = 1; | ||
1096 | SET(separating_normal,tri2plane); | ||
1097 | } | ||
1098 | } | ||
1099 | currdir++; | ||
1100 | |||
1101 | |||
1102 | ///find edge edge distances | ||
1103 | ///test each edge plane | ||
1104 | |||
1105 | /*for(i=0;i<3;i++) | ||
1106 | { | ||
1107 | |||
1108 | |||
1109 | for(j=0;j<3;j++) | ||
1110 | { | ||
1111 | |||
1112 | |||
1113 | bl = BuildEdgesDir( | ||
1114 | tri1[i],tri1[(i+1)%3], | ||
1115 | tri2[j],tri2[(j+1)%3], | ||
1116 | crossdir); | ||
1117 | |||
1118 | ////find plane distance | ||
1119 | |||
1120 | if(bl) | ||
1121 | { | ||
1122 | FindInterval(tri1,3,crossdir,vmin1,vmax1); | ||
1123 | FindInterval(tri2,3,crossdir,vmin2,vmax2); | ||
1124 | |||
1125 | dist = IntervalPenetration( | ||
1126 | vmin1, | ||
1127 | vmax1, | ||
1128 | vmin2, | ||
1129 | vmax2); | ||
1130 | if(dist<maxdeep) | ||
1131 | { | ||
1132 | maxdeep = dist; | ||
1133 | mostdir = currdir; | ||
1134 | SET(separating_normal,crossdir); | ||
1135 | } | ||
1136 | } | ||
1137 | currdir++; | ||
1138 | } | ||
1139 | }*/ | ||
1140 | |||
1141 | |||
1142 | ////check most dir for contacts | ||
1143 | if(mostdir==0) | ||
1144 | { | ||
1145 | ///find most deep points | ||
1146 | deep_points.Count = deep_points1.Count; | ||
1147 | memcpy( | ||
1148 | &deep_points.Points[0], | ||
1149 | &deep_points1.Points[0], | ||
1150 | deep_points1.Count*sizeof(dVector3)); | ||
1151 | |||
1152 | ///invert normal for point to tri1 | ||
1153 | MULT(separating_normal,separating_normal,-1.0f); | ||
1154 | } | ||
1155 | else if(mostdir==1) | ||
1156 | { | ||
1157 | deep_points.Count = deep_points2.Count; | ||
1158 | memcpy( | ||
1159 | &deep_points.Points[0], | ||
1160 | &deep_points2.Points[0], | ||
1161 | deep_points2.Count*sizeof(dVector3)); | ||
1162 | |||
1163 | } | ||
1164 | /*else | ||
1165 | {///edge separation | ||
1166 | mostdir -= 2; | ||
1167 | |||
1168 | //edge 2 | ||
1169 | j = mostdir%3; | ||
1170 | //edge 1 | ||
1171 | i = mostdir/3; | ||
1172 | |||
1173 | ///find edge closest points | ||
1174 | dClosestLineSegmentPoints( | ||
1175 | tri1[i],tri1[(i+1)%3], | ||
1176 | tri2[j],tri2[(j+1)%3], | ||
1177 | pt1,pt2); | ||
1178 | ///find correct direction | ||
1179 | |||
1180 | SUB(crossdir,pt2,pt1); | ||
1181 | |||
1182 | vmin1 = LENGTH(crossdir); | ||
1183 | if(vmin1<REAL(0.000001)) | ||
1184 | { | ||
1185 | |||
1186 | if(mostface==0) | ||
1187 | { | ||
1188 | vmin1 = DOT(separating_normal,tri1plane); | ||
1189 | if(vmin1>0.0) | ||
1190 | { | ||
1191 | MULT(separating_normal,separating_normal,-1.0f); | ||
1192 | deep_points.Count = 1; | ||
1193 | SET(deep_points.Points[0],pt2); | ||
1194 | } | ||
1195 | else | ||
1196 | { | ||
1197 | deep_points.Count = 1; | ||
1198 | SET(deep_points.Points[0],pt2); | ||
1199 | } | ||
1200 | |||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | vmin1 = DOT(separating_normal,tri2plane); | ||
1205 | if(vmin1<0.0) | ||
1206 | { | ||
1207 | MULT(separating_normal,separating_normal,-1.0f); | ||
1208 | deep_points.Count = 1; | ||
1209 | SET(deep_points.Points[0],pt2); | ||
1210 | } | ||
1211 | else | ||
1212 | { | ||
1213 | deep_points.Count = 1; | ||
1214 | SET(deep_points.Points[0],pt2); | ||
1215 | } | ||
1216 | |||
1217 | } | ||
1218 | |||
1219 | |||
1220 | |||
1221 | |||
1222 | } | ||
1223 | else | ||
1224 | { | ||
1225 | MULT(separating_normal,crossdir,1.0f/vmin1); | ||
1226 | |||
1227 | vmin1 = DOT(separating_normal,tri1plane); | ||
1228 | if(vmin1>0.0) | ||
1229 | { | ||
1230 | MULT(separating_normal,separating_normal,-1.0f); | ||
1231 | deep_points.Count = 1; | ||
1232 | SET(deep_points.Points[0],pt2); | ||
1233 | } | ||
1234 | else | ||
1235 | { | ||
1236 | deep_points.Count = 1; | ||
1237 | SET(deep_points.Points[0],pt2); | ||
1238 | } | ||
1239 | |||
1240 | |||
1241 | } | ||
1242 | |||
1243 | |||
1244 | }*/ | ||
1245 | return maxdeep; | ||
1246 | } | ||
1247 | |||
1248 | |||
1249 | |||
1250 | ///SUPPORT UP TO 8 CONTACTS | ||
1251 | bool TriTriContacts(const dVector3 tr1[3], | ||
1252 | const dVector3 tr2[3], | ||
1253 | dxGeom* g1, dxGeom* g2, int Flags, | ||
1254 | dContactGeom* Contacts, int Stride, | ||
1255 | int &contactcount) | ||
1256 | { | ||
1257 | |||
1258 | |||
1259 | dVector4 normal; | ||
1260 | dReal depth; | ||
1261 | ///Test Tri Vs Tri | ||
1262 | // dContactGeom* pcontact; | ||
1263 | int ccount = 0; | ||
1264 | LineContactSet contactpoints; | ||
1265 | contactpoints.Count = 0; | ||
1266 | |||
1267 | |||
1268 | |||
1269 | ///find best direction | ||
1270 | |||
1271 | depth = FindTriangleTriangleCollision( | ||
1272 | tr1, | ||
1273 | tr2, | ||
1274 | normal, | ||
1275 | contactpoints); | ||
1276 | |||
1277 | |||
1278 | |||
1279 | if(depth<0.0f) return false; | ||
1280 | |||
1281 | ccount = 0; | ||
1282 | while (ccount<contactpoints.Count) | ||
1283 | { | ||
1284 | PushNewContact( g1, g2, | ||
1285 | contactpoints.Points[ccount], | ||
1286 | normal, depth, Flags, | ||
1287 | Contacts,Stride,contactcount); | ||
1288 | |||
1289 | // Continue loop even after contacts are full | ||
1290 | // as existing contacts' normals/depths might be updated | ||
1291 | // Break only if contacts are not important | ||
1292 | if ((contactcount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) | ||
1293 | { | ||
1294 | break; | ||
1295 | } | ||
1296 | |||
1297 | ccount++; | ||
1298 | } | ||
1299 | return true; | ||
1300 | } | ||
1301 | |||
1302 | #endif // dTRIMESH_OPCODE | ||
1303 | #endif // dTRIMESH_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
1304 | #endif // dTRIMESH_ENABLED | ||
diff --git a/libraries/ode-0.9\/ode/src/collision_util.cpp b/libraries/ode-0.9\/ode/src/collision_util.cpp new file mode 100755 index 0000000..460cc20 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_util.cpp | |||
@@ -0,0 +1,612 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | some useful collision utility stuff. this includes some API utility | ||
26 | functions that are defined in the public header files. | ||
27 | |||
28 | */ | ||
29 | |||
30 | #include <ode/common.h> | ||
31 | #include <ode/collision.h> | ||
32 | #include <ode/odemath.h> | ||
33 | #include "collision_util.h" | ||
34 | |||
35 | //**************************************************************************** | ||
36 | |||
37 | int dCollideSpheres (dVector3 p1, dReal r1, | ||
38 | dVector3 p2, dReal r2, dContactGeom *c) | ||
39 | { | ||
40 | // printf ("d=%.2f (%.2f %.2f %.2f) (%.2f %.2f %.2f) r1=%.2f r2=%.2f\n", | ||
41 | // d,p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],r1,r2); | ||
42 | |||
43 | dReal d = dDISTANCE (p1,p2); | ||
44 | if (d > (r1 + r2)) return 0; | ||
45 | if (d <= 0) { | ||
46 | c->pos[0] = p1[0]; | ||
47 | c->pos[1] = p1[1]; | ||
48 | c->pos[2] = p1[2]; | ||
49 | c->normal[0] = 1; | ||
50 | c->normal[1] = 0; | ||
51 | c->normal[2] = 0; | ||
52 | c->depth = r1 + r2; | ||
53 | } | ||
54 | else { | ||
55 | dReal d1 = dRecip (d); | ||
56 | c->normal[0] = (p1[0]-p2[0])*d1; | ||
57 | c->normal[1] = (p1[1]-p2[1])*d1; | ||
58 | c->normal[2] = (p1[2]-p2[2])*d1; | ||
59 | dReal k = REAL(0.5) * (r2 - r1 - d); | ||
60 | c->pos[0] = p1[0] + c->normal[0]*k; | ||
61 | c->pos[1] = p1[1] + c->normal[1]*k; | ||
62 | c->pos[2] = p1[2] + c->normal[2]*k; | ||
63 | c->depth = r1 + r2 - d; | ||
64 | } | ||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | |||
69 | void dLineClosestApproach (const dVector3 pa, const dVector3 ua, | ||
70 | const dVector3 pb, const dVector3 ub, | ||
71 | dReal *alpha, dReal *beta) | ||
72 | { | ||
73 | dVector3 p; | ||
74 | p[0] = pb[0] - pa[0]; | ||
75 | p[1] = pb[1] - pa[1]; | ||
76 | p[2] = pb[2] - pa[2]; | ||
77 | dReal uaub = dDOT(ua,ub); | ||
78 | dReal q1 = dDOT(ua,p); | ||
79 | dReal q2 = -dDOT(ub,p); | ||
80 | dReal d = 1-uaub*uaub; | ||
81 | if (d <= REAL(0.0001)) { | ||
82 | // @@@ this needs to be made more robust | ||
83 | *alpha = 0; | ||
84 | *beta = 0; | ||
85 | } | ||
86 | else { | ||
87 | d = dRecip(d); | ||
88 | *alpha = (q1 + uaub*q2)*d; | ||
89 | *beta = (uaub*q1 + q2)*d; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | |||
94 | // given two line segments A and B with endpoints a1-a2 and b1-b2, return the | ||
95 | // points on A and B that are closest to each other (in cp1 and cp2). | ||
96 | // in the case of parallel lines where there are multiple solutions, a | ||
97 | // solution involving the endpoint of at least one line will be returned. | ||
98 | // this will work correctly for zero length lines, e.g. if a1==a2 and/or | ||
99 | // b1==b2. | ||
100 | // | ||
101 | // the algorithm works by applying the voronoi clipping rule to the features | ||
102 | // of the line segments. the three features of each line segment are the two | ||
103 | // endpoints and the line between them. the voronoi clipping rule states that, | ||
104 | // for feature X on line A and feature Y on line B, the closest points PA and | ||
105 | // PB between X and Y are globally the closest points if PA is in V(Y) and | ||
106 | // PB is in V(X), where V(X) is the voronoi region of X. | ||
107 | |||
108 | void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2, | ||
109 | const dVector3 b1, const dVector3 b2, | ||
110 | dVector3 cp1, dVector3 cp2) | ||
111 | { | ||
112 | dVector3 a1a2,b1b2,a1b1,a1b2,a2b1,a2b2,n; | ||
113 | dReal la,lb,k,da1,da2,da3,da4,db1,db2,db3,db4,det; | ||
114 | |||
115 | #define SET2(a,b) a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; | ||
116 | #define SET3(a,b,op,c) a[0]=b[0] op c[0]; a[1]=b[1] op c[1]; a[2]=b[2] op c[2]; | ||
117 | |||
118 | // check vertex-vertex features | ||
119 | |||
120 | SET3 (a1a2,a2,-,a1); | ||
121 | SET3 (b1b2,b2,-,b1); | ||
122 | SET3 (a1b1,b1,-,a1); | ||
123 | da1 = dDOT(a1a2,a1b1); | ||
124 | db1 = dDOT(b1b2,a1b1); | ||
125 | if (da1 <= 0 && db1 >= 0) { | ||
126 | SET2 (cp1,a1); | ||
127 | SET2 (cp2,b1); | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | SET3 (a1b2,b2,-,a1); | ||
132 | da2 = dDOT(a1a2,a1b2); | ||
133 | db2 = dDOT(b1b2,a1b2); | ||
134 | if (da2 <= 0 && db2 <= 0) { | ||
135 | SET2 (cp1,a1); | ||
136 | SET2 (cp2,b2); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | SET3 (a2b1,b1,-,a2); | ||
141 | da3 = dDOT(a1a2,a2b1); | ||
142 | db3 = dDOT(b1b2,a2b1); | ||
143 | if (da3 >= 0 && db3 >= 0) { | ||
144 | SET2 (cp1,a2); | ||
145 | SET2 (cp2,b1); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | SET3 (a2b2,b2,-,a2); | ||
150 | da4 = dDOT(a1a2,a2b2); | ||
151 | db4 = dDOT(b1b2,a2b2); | ||
152 | if (da4 >= 0 && db4 <= 0) { | ||
153 | SET2 (cp1,a2); | ||
154 | SET2 (cp2,b2); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | // check edge-vertex features. | ||
159 | // if one or both of the lines has zero length, we will never get to here, | ||
160 | // so we do not have to worry about the following divisions by zero. | ||
161 | |||
162 | la = dDOT(a1a2,a1a2); | ||
163 | if (da1 >= 0 && da3 <= 0) { | ||
164 | k = da1 / la; | ||
165 | SET3 (n,a1b1,-,k*a1a2); | ||
166 | if (dDOT(b1b2,n) >= 0) { | ||
167 | SET3 (cp1,a1,+,k*a1a2); | ||
168 | SET2 (cp2,b1); | ||
169 | return; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | if (da2 >= 0 && da4 <= 0) { | ||
174 | k = da2 / la; | ||
175 | SET3 (n,a1b2,-,k*a1a2); | ||
176 | if (dDOT(b1b2,n) <= 0) { | ||
177 | SET3 (cp1,a1,+,k*a1a2); | ||
178 | SET2 (cp2,b2); | ||
179 | return; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | lb = dDOT(b1b2,b1b2); | ||
184 | if (db1 <= 0 && db2 >= 0) { | ||
185 | k = -db1 / lb; | ||
186 | SET3 (n,-a1b1,-,k*b1b2); | ||
187 | if (dDOT(a1a2,n) >= 0) { | ||
188 | SET2 (cp1,a1); | ||
189 | SET3 (cp2,b1,+,k*b1b2); | ||
190 | return; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | if (db3 <= 0 && db4 >= 0) { | ||
195 | k = -db3 / lb; | ||
196 | SET3 (n,-a2b1,-,k*b1b2); | ||
197 | if (dDOT(a1a2,n) <= 0) { | ||
198 | SET2 (cp1,a2); | ||
199 | SET3 (cp2,b1,+,k*b1b2); | ||
200 | return; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | // it must be edge-edge | ||
205 | |||
206 | k = dDOT(a1a2,b1b2); | ||
207 | det = la*lb - k*k; | ||
208 | if (det <= 0) { | ||
209 | // this should never happen, but just in case... | ||
210 | SET2(cp1,a1); | ||
211 | SET2(cp2,b1); | ||
212 | return; | ||
213 | } | ||
214 | det = dRecip (det); | ||
215 | dReal alpha = (lb*da1 - k*db1) * det; | ||
216 | dReal beta = ( k*da1 - la*db1) * det; | ||
217 | SET3 (cp1,a1,+,alpha*a1a2); | ||
218 | SET3 (cp2,b1,+,beta*b1b2); | ||
219 | |||
220 | # undef SET2 | ||
221 | # undef SET3 | ||
222 | } | ||
223 | |||
224 | |||
225 | // a simple root finding algorithm is used to find the value of 't' that | ||
226 | // satisfies: | ||
227 | // d|D(t)|^2/dt = 0 | ||
228 | // where: | ||
229 | // |D(t)| = |p(t)-b(t)| | ||
230 | // where p(t) is a point on the line parameterized by t: | ||
231 | // p(t) = p1 + t*(p2-p1) | ||
232 | // and b(t) is that same point clipped to the boundary of the box. in box- | ||
233 | // relative coordinates d|D(t)|^2/dt is the sum of three x,y,z components | ||
234 | // each of which looks like this: | ||
235 | // | ||
236 | // t_lo / | ||
237 | // ______/ -->t | ||
238 | // / t_hi | ||
239 | // / | ||
240 | // | ||
241 | // t_lo and t_hi are the t values where the line passes through the planes | ||
242 | // corresponding to the sides of the box. the algorithm computes d|D(t)|^2/dt | ||
243 | // in a piecewise fashion from t=0 to t=1, stopping at the point where | ||
244 | // d|D(t)|^2/dt crosses from negative to positive. | ||
245 | |||
246 | void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2, | ||
247 | const dVector3 c, const dMatrix3 R, | ||
248 | const dVector3 side, | ||
249 | dVector3 lret, dVector3 bret) | ||
250 | { | ||
251 | int i; | ||
252 | |||
253 | // compute the start and delta of the line p1-p2 relative to the box. | ||
254 | // we will do all subsequent computations in this box-relative coordinate | ||
255 | // system. we have to do a translation and rotation for each point. | ||
256 | dVector3 tmp,s,v; | ||
257 | tmp[0] = p1[0] - c[0]; | ||
258 | tmp[1] = p1[1] - c[1]; | ||
259 | tmp[2] = p1[2] - c[2]; | ||
260 | dMULTIPLY1_331 (s,R,tmp); | ||
261 | tmp[0] = p2[0] - p1[0]; | ||
262 | tmp[1] = p2[1] - p1[1]; | ||
263 | tmp[2] = p2[2] - p1[2]; | ||
264 | dMULTIPLY1_331 (v,R,tmp); | ||
265 | |||
266 | // mirror the line so that v has all components >= 0 | ||
267 | dVector3 sign; | ||
268 | for (i=0; i<3; i++) { | ||
269 | if (v[i] < 0) { | ||
270 | s[i] = -s[i]; | ||
271 | v[i] = -v[i]; | ||
272 | sign[i] = -1; | ||
273 | } | ||
274 | else sign[i] = 1; | ||
275 | } | ||
276 | |||
277 | // compute v^2 | ||
278 | dVector3 v2; | ||
279 | v2[0] = v[0]*v[0]; | ||
280 | v2[1] = v[1]*v[1]; | ||
281 | v2[2] = v[2]*v[2]; | ||
282 | |||
283 | // compute the half-sides of the box | ||
284 | dReal h[3]; | ||
285 | h[0] = REAL(0.5) * side[0]; | ||
286 | h[1] = REAL(0.5) * side[1]; | ||
287 | h[2] = REAL(0.5) * side[2]; | ||
288 | |||
289 | // region is -1,0,+1 depending on which side of the box planes each | ||
290 | // coordinate is on. tanchor is the next t value at which there is a | ||
291 | // transition, or the last one if there are no more. | ||
292 | int region[3]; | ||
293 | dReal tanchor[3]; | ||
294 | |||
295 | // Denormals are a problem, because we divide by v[i], and then | ||
296 | // multiply that by 0. Alas, infinity times 0 is infinity (!) | ||
297 | // We also use v2[i], which is v[i] squared. Here's how the epsilons | ||
298 | // are chosen: | ||
299 | // float epsilon = 1.175494e-038 (smallest non-denormal number) | ||
300 | // double epsilon = 2.225074e-308 (smallest non-denormal number) | ||
301 | // For single precision, choose an epsilon such that v[i] squared is | ||
302 | // not a denormal; this is for performance. | ||
303 | // For double precision, choose an epsilon such that v[i] is not a | ||
304 | // denormal; this is for correctness. (Jon Watte on mailinglist) | ||
305 | |||
306 | #if defined( dSINGLE ) | ||
307 | const dReal tanchor_eps = REAL(1e-19); | ||
308 | #else | ||
309 | const dReal tanchor_eps = REAL(1e-307); | ||
310 | #endif | ||
311 | |||
312 | // find the region and tanchor values for p1 | ||
313 | for (i=0; i<3; i++) { | ||
314 | if (v[i] > tanchor_eps) { | ||
315 | if (s[i] < -h[i]) { | ||
316 | region[i] = -1; | ||
317 | tanchor[i] = (-h[i]-s[i])/v[i]; | ||
318 | } | ||
319 | else { | ||
320 | region[i] = (s[i] > h[i]); | ||
321 | tanchor[i] = (h[i]-s[i])/v[i]; | ||
322 | } | ||
323 | } | ||
324 | else { | ||
325 | region[i] = 0; | ||
326 | tanchor[i] = 2; // this will never be a valid tanchor | ||
327 | } | ||
328 | } | ||
329 | |||
330 | // compute d|d|^2/dt for t=0. if it's >= 0 then p1 is the closest point | ||
331 | dReal t=0; | ||
332 | dReal dd2dt = 0; | ||
333 | for (i=0; i<3; i++) dd2dt -= (region[i] ? v2[i] : 0) * tanchor[i]; | ||
334 | if (dd2dt >= 0) goto got_answer; | ||
335 | |||
336 | do { | ||
337 | // find the point on the line that is at the next clip plane boundary | ||
338 | dReal next_t = 1; | ||
339 | for (i=0; i<3; i++) { | ||
340 | if (tanchor[i] > t && tanchor[i] < 1 && tanchor[i] < next_t) | ||
341 | next_t = tanchor[i]; | ||
342 | } | ||
343 | |||
344 | // compute d|d|^2/dt for the next t | ||
345 | dReal next_dd2dt = 0; | ||
346 | for (i=0; i<3; i++) { | ||
347 | next_dd2dt += (region[i] ? v2[i] : 0) * (next_t - tanchor[i]); | ||
348 | } | ||
349 | |||
350 | // if the sign of d|d|^2/dt has changed, solution = the crossover point | ||
351 | if (next_dd2dt >= 0) { | ||
352 | dReal m = (next_dd2dt-dd2dt)/(next_t - t); | ||
353 | t -= dd2dt/m; | ||
354 | goto got_answer; | ||
355 | } | ||
356 | |||
357 | // advance to the next anchor point / region | ||
358 | for (i=0; i<3; i++) { | ||
359 | if (tanchor[i] == next_t) { | ||
360 | tanchor[i] = (h[i]-s[i])/v[i]; | ||
361 | region[i]++; | ||
362 | } | ||
363 | } | ||
364 | t = next_t; | ||
365 | dd2dt = next_dd2dt; | ||
366 | } | ||
367 | while (t < 1); | ||
368 | t = 1; | ||
369 | |||
370 | got_answer: | ||
371 | |||
372 | // compute closest point on the line | ||
373 | for (i=0; i<3; i++) lret[i] = p1[i] + t*tmp[i]; // note: tmp=p2-p1 | ||
374 | |||
375 | // compute closest point on the box | ||
376 | for (i=0; i<3; i++) { | ||
377 | tmp[i] = sign[i] * (s[i] + t*v[i]); | ||
378 | if (tmp[i] < -h[i]) tmp[i] = -h[i]; | ||
379 | else if (tmp[i] > h[i]) tmp[i] = h[i]; | ||
380 | } | ||
381 | dMULTIPLY0_331 (s,R,tmp); | ||
382 | for (i=0; i<3; i++) bret[i] = s[i] + c[i]; | ||
383 | } | ||
384 | |||
385 | |||
386 | // given boxes (p1,R1,side1) and (p1,R1,side1), return 1 if they intersect | ||
387 | // or 0 if not. | ||
388 | |||
389 | int dBoxTouchesBox (const dVector3 p1, const dMatrix3 R1, | ||
390 | const dVector3 side1, const dVector3 p2, | ||
391 | const dMatrix3 R2, const dVector3 side2) | ||
392 | { | ||
393 | // two boxes are disjoint if (and only if) there is a separating axis | ||
394 | // perpendicular to a face from one box or perpendicular to an edge from | ||
395 | // either box. the following tests are derived from: | ||
396 | // "OBB Tree: A Hierarchical Structure for Rapid Interference Detection", | ||
397 | // S.Gottschalk, M.C.Lin, D.Manocha., Proc of ACM Siggraph 1996. | ||
398 | |||
399 | // Rij is R1'*R2, i.e. the relative rotation between R1 and R2. | ||
400 | // Qij is abs(Rij) | ||
401 | dVector3 p,pp; | ||
402 | dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33, | ||
403 | Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33; | ||
404 | |||
405 | // get vector from centers of box 1 to box 2, relative to box 1 | ||
406 | p[0] = p2[0] - p1[0]; | ||
407 | p[1] = p2[1] - p1[1]; | ||
408 | p[2] = p2[2] - p1[2]; | ||
409 | dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 | ||
410 | |||
411 | // get side lengths / 2 | ||
412 | A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5); | ||
413 | B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5); | ||
414 | |||
415 | // for the following tests, excluding computation of Rij, in the worst case, | ||
416 | // 15 compares, 60 adds, 81 multiplies, and 24 absolutes. | ||
417 | // notation: R1=[u1 u2 u3], R2=[v1 v2 v3] | ||
418 | |||
419 | // separating axis = u1,u2,u3 | ||
420 | R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); | ||
421 | Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); | ||
422 | if (dFabs(pp[0]) > (A1 + B1*Q11 + B2*Q12 + B3*Q13)) return 0; | ||
423 | R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); | ||
424 | Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); | ||
425 | if (dFabs(pp[1]) > (A2 + B1*Q21 + B2*Q22 + B3*Q23)) return 0; | ||
426 | R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); | ||
427 | Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); | ||
428 | if (dFabs(pp[2]) > (A3 + B1*Q31 + B2*Q32 + B3*Q33)) return 0; | ||
429 | |||
430 | // separating axis = v1,v2,v3 | ||
431 | if (dFabs(dDOT41(R2+0,p)) > (A1*Q11 + A2*Q21 + A3*Q31 + B1)) return 0; | ||
432 | if (dFabs(dDOT41(R2+1,p)) > (A1*Q12 + A2*Q22 + A3*Q32 + B2)) return 0; | ||
433 | if (dFabs(dDOT41(R2+2,p)) > (A1*Q13 + A2*Q23 + A3*Q33 + B3)) return 0; | ||
434 | |||
435 | // separating axis = u1 x (v1,v2,v3) | ||
436 | if (dFabs(pp[2]*R21-pp[1]*R31) > A2*Q31 + A3*Q21 + B2*Q13 + B3*Q12) return 0; | ||
437 | if (dFabs(pp[2]*R22-pp[1]*R32) > A2*Q32 + A3*Q22 + B1*Q13 + B3*Q11) return 0; | ||
438 | if (dFabs(pp[2]*R23-pp[1]*R33) > A2*Q33 + A3*Q23 + B1*Q12 + B2*Q11) return 0; | ||
439 | |||
440 | // separating axis = u2 x (v1,v2,v3) | ||
441 | if (dFabs(pp[0]*R31-pp[2]*R11) > A1*Q31 + A3*Q11 + B2*Q23 + B3*Q22) return 0; | ||
442 | if (dFabs(pp[0]*R32-pp[2]*R12) > A1*Q32 + A3*Q12 + B1*Q23 + B3*Q21) return 0; | ||
443 | if (dFabs(pp[0]*R33-pp[2]*R13) > A1*Q33 + A3*Q13 + B1*Q22 + B2*Q21) return 0; | ||
444 | |||
445 | // separating axis = u3 x (v1,v2,v3) | ||
446 | if (dFabs(pp[1]*R11-pp[0]*R21) > A1*Q21 + A2*Q11 + B2*Q33 + B3*Q32) return 0; | ||
447 | if (dFabs(pp[1]*R12-pp[0]*R22) > A1*Q22 + A2*Q12 + B1*Q33 + B3*Q31) return 0; | ||
448 | if (dFabs(pp[1]*R13-pp[0]*R23) > A1*Q23 + A2*Q13 + B1*Q32 + B2*Q31) return 0; | ||
449 | |||
450 | return 1; | ||
451 | } | ||
452 | |||
453 | //**************************************************************************** | ||
454 | // other utility functions | ||
455 | |||
456 | void dInfiniteAABB (dxGeom *geom, dReal aabb[6]) | ||
457 | { | ||
458 | aabb[0] = -dInfinity; | ||
459 | aabb[1] = dInfinity; | ||
460 | aabb[2] = -dInfinity; | ||
461 | aabb[3] = dInfinity; | ||
462 | aabb[4] = -dInfinity; | ||
463 | aabb[5] = dInfinity; | ||
464 | } | ||
465 | |||
466 | |||
467 | //**************************************************************************** | ||
468 | // Helpers for Croteam's collider - by Nguyen Binh | ||
469 | |||
470 | int dClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane) | ||
471 | { | ||
472 | // calculate distance of edge points to plane | ||
473 | dReal fDistance0 = dPointPlaneDistance( vEpnt0 ,plPlane ); | ||
474 | dReal fDistance1 = dPointPlaneDistance( vEpnt1 ,plPlane ); | ||
475 | |||
476 | // if both points are behind the plane | ||
477 | if ( fDistance0 < 0 && fDistance1 < 0 ) | ||
478 | { | ||
479 | // do nothing | ||
480 | return 0; | ||
481 | // if both points in front of the plane | ||
482 | } | ||
483 | else if ( fDistance0 > 0 && fDistance1 > 0 ) | ||
484 | { | ||
485 | // accept them | ||
486 | return 1; | ||
487 | // if we have edge/plane intersection | ||
488 | } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0)) | ||
489 | { | ||
490 | |||
491 | // find intersection point of edge and plane | ||
492 | dVector3 vIntersectionPoint; | ||
493 | vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1); | ||
494 | vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1); | ||
495 | vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1); | ||
496 | |||
497 | // clamp correct edge to intersection point | ||
498 | if ( fDistance0 < 0 ) | ||
499 | { | ||
500 | dVector3Copy(vIntersectionPoint,vEpnt0); | ||
501 | } else | ||
502 | { | ||
503 | dVector3Copy(vIntersectionPoint,vEpnt1); | ||
504 | } | ||
505 | return 1; | ||
506 | } | ||
507 | return 1; | ||
508 | } | ||
509 | |||
510 | // clip polygon with plane and generate new polygon points | ||
511 | void dClipPolyToPlane( const dVector3 avArrayIn[], const int ctIn, | ||
512 | dVector3 avArrayOut[], int &ctOut, | ||
513 | const dVector4 &plPlane ) | ||
514 | { | ||
515 | // start with no output points | ||
516 | ctOut = 0; | ||
517 | |||
518 | int i0 = ctIn-1; | ||
519 | |||
520 | // for each edge in input polygon | ||
521 | for (int i1=0; i1<ctIn; i0=i1, i1++) { | ||
522 | |||
523 | |||
524 | // calculate distance of edge points to plane | ||
525 | dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane ); | ||
526 | dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane ); | ||
527 | |||
528 | // if first point is in front of plane | ||
529 | if( fDistance0 >= 0 ) { | ||
530 | // emit point | ||
531 | avArrayOut[ctOut][0] = avArrayIn[i0][0]; | ||
532 | avArrayOut[ctOut][1] = avArrayIn[i0][1]; | ||
533 | avArrayOut[ctOut][2] = avArrayIn[i0][2]; | ||
534 | ctOut++; | ||
535 | } | ||
536 | |||
537 | // if points are on different sides | ||
538 | if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) { | ||
539 | |||
540 | // find intersection point of edge and plane | ||
541 | dVector3 vIntersectionPoint; | ||
542 | vIntersectionPoint[0]= avArrayIn[i0][0] - | ||
543 | (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); | ||
544 | vIntersectionPoint[1]= avArrayIn[i0][1] - | ||
545 | (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); | ||
546 | vIntersectionPoint[2]= avArrayIn[i0][2] - | ||
547 | (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); | ||
548 | |||
549 | // emit intersection point | ||
550 | avArrayOut[ctOut][0] = vIntersectionPoint[0]; | ||
551 | avArrayOut[ctOut][1] = vIntersectionPoint[1]; | ||
552 | avArrayOut[ctOut][2] = vIntersectionPoint[2]; | ||
553 | ctOut++; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | } | ||
558 | |||
559 | void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn, | ||
560 | dVector3 avArrayOut[], int &ctOut, | ||
561 | const dVector4 &plPlane ,dReal fRadius) | ||
562 | { | ||
563 | // start with no output points | ||
564 | ctOut = 0; | ||
565 | |||
566 | int i0 = ctIn-1; | ||
567 | |||
568 | // for each edge in input polygon | ||
569 | for (int i1=0; i1<ctIn; i0=i1, i1++) | ||
570 | { | ||
571 | // calculate distance of edge points to plane | ||
572 | dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane ); | ||
573 | dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane ); | ||
574 | |||
575 | // if first point is in front of plane | ||
576 | if( fDistance0 >= 0 ) | ||
577 | { | ||
578 | // emit point | ||
579 | if (dVector3Length2(avArrayIn[i0]) <= fRadius*fRadius) | ||
580 | { | ||
581 | avArrayOut[ctOut][0] = avArrayIn[i0][0]; | ||
582 | avArrayOut[ctOut][1] = avArrayIn[i0][1]; | ||
583 | avArrayOut[ctOut][2] = avArrayIn[i0][2]; | ||
584 | ctOut++; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | // if points are on different sides | ||
589 | if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) | ||
590 | { | ||
591 | |||
592 | // find intersection point of edge and plane | ||
593 | dVector3 vIntersectionPoint; | ||
594 | vIntersectionPoint[0]= avArrayIn[i0][0] - | ||
595 | (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); | ||
596 | vIntersectionPoint[1]= avArrayIn[i0][1] - | ||
597 | (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); | ||
598 | vIntersectionPoint[2]= avArrayIn[i0][2] - | ||
599 | (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); | ||
600 | |||
601 | // emit intersection point | ||
602 | if (dVector3Length2(avArrayIn[i0]) <= fRadius*fRadius) | ||
603 | { | ||
604 | avArrayOut[ctOut][0] = vIntersectionPoint[0]; | ||
605 | avArrayOut[ctOut][1] = vIntersectionPoint[1]; | ||
606 | avArrayOut[ctOut][2] = vIntersectionPoint[2]; | ||
607 | ctOut++; | ||
608 | } | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | |||
diff --git a/libraries/ode-0.9\/ode/src/collision_util.h b/libraries/ode-0.9\/ode/src/collision_util.h new file mode 100755 index 0000000..4c479e3 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/collision_util.h | |||
@@ -0,0 +1,340 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | some useful collision utility stuff. | ||
26 | |||
27 | */ | ||
28 | |||
29 | #ifndef _ODE_COLLISION_UTIL_H_ | ||
30 | #define _ODE_COLLISION_UTIL_H_ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/contact.h> | ||
34 | #include <ode/odemath.h> | ||
35 | #include <ode/rotation.h> | ||
36 | |||
37 | |||
38 | // given a pointer `p' to a dContactGeom, return the dContactGeom at | ||
39 | // p + skip bytes. | ||
40 | #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) | ||
41 | |||
42 | #if 1 | ||
43 | #include "collision_kernel.h" | ||
44 | // Fetches a contact | ||
45 | inline dContactGeom* SAFECONTACT(int Flags, dContactGeom* Contacts, int Index, int Stride){ | ||
46 | dIASSERT(Index >= 0 && Index < (Flags & NUMC_MASK)); | ||
47 | return ((dContactGeom*)(((char*)Contacts) + (Index * Stride))); | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | |||
52 | // if the spheres (p1,r1) and (p2,r2) collide, set the contact `c' and | ||
53 | // return 1, else return 0. | ||
54 | |||
55 | int dCollideSpheres (dVector3 p1, dReal r1, | ||
56 | dVector3 p2, dReal r2, dContactGeom *c); | ||
57 | |||
58 | |||
59 | // given two lines | ||
60 | // qa = pa + alpha* ua | ||
61 | // qb = pb + beta * ub | ||
62 | // where pa,pb are two points, ua,ub are two unit length vectors, and alpha, | ||
63 | // beta go from [-inf,inf], return alpha and beta such that qa and qb are | ||
64 | // as close as possible | ||
65 | |||
66 | void dLineClosestApproach (const dVector3 pa, const dVector3 ua, | ||
67 | const dVector3 pb, const dVector3 ub, | ||
68 | dReal *alpha, dReal *beta); | ||
69 | |||
70 | |||
71 | // given a line segment p1-p2 and a box (center 'c', rotation 'R', side length | ||
72 | // vector 'side'), compute the points of closest approach between the box | ||
73 | // and the line. return these points in 'lret' (the point on the line) and | ||
74 | // 'bret' (the point on the box). if the line actually penetrates the box | ||
75 | // then the solution is not unique, but only one solution will be returned. | ||
76 | // in this case the solution points will coincide. | ||
77 | |||
78 | void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2, | ||
79 | const dVector3 c, const dMatrix3 R, | ||
80 | const dVector3 side, | ||
81 | dVector3 lret, dVector3 bret); | ||
82 | |||
83 | // 20 Apr 2004 | ||
84 | // Start code by Nguyen Binh | ||
85 | int dClipEdgeToPlane(dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane); | ||
86 | // clip polygon with plane and generate new polygon points | ||
87 | void dClipPolyToPlane(const dVector3 avArrayIn[], const int ctIn, dVector3 avArrayOut[], int &ctOut, const dVector4 &plPlane ); | ||
88 | |||
89 | void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn, dVector3 avArrayOut[], int &ctOut, const dVector4 &plPlane ,dReal fRadius); | ||
90 | |||
91 | // Some vector math | ||
92 | inline void dVector3Subtract(const dVector3& a,const dVector3& b,dVector3& c) | ||
93 | { | ||
94 | c[0] = a[0] - b[0]; | ||
95 | c[1] = a[1] - b[1]; | ||
96 | c[2] = a[2] - b[2]; | ||
97 | } | ||
98 | |||
99 | // Some vector math | ||
100 | inline void dVector3Scale(dVector3& a,dReal nScale) | ||
101 | { | ||
102 | a[0] *= nScale ; | ||
103 | a[1] *= nScale ; | ||
104 | a[2] *= nScale ; | ||
105 | } | ||
106 | |||
107 | inline void dVector3Add(const dVector3& a,const dVector3& b,dVector3& c) | ||
108 | { | ||
109 | c[0] = a[0] + b[0]; | ||
110 | c[1] = a[1] + b[1]; | ||
111 | c[2] = a[2] + b[2]; | ||
112 | } | ||
113 | |||
114 | inline void dVector3Copy(const dVector3& a,dVector3& c) | ||
115 | { | ||
116 | c[0] = a[0]; | ||
117 | c[1] = a[1]; | ||
118 | c[2] = a[2]; | ||
119 | } | ||
120 | |||
121 | inline void dVector3Cross(const dVector3& a,const dVector3& b,dVector3& c) | ||
122 | { | ||
123 | dCROSS(c,=,a,b); | ||
124 | } | ||
125 | |||
126 | inline dReal dVector3Length(const dVector3& a) | ||
127 | { | ||
128 | return dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); | ||
129 | } | ||
130 | |||
131 | inline dReal dVector3Dot(const dVector3& a,const dVector3& b) | ||
132 | { | ||
133 | return dDOT(a,b); | ||
134 | } | ||
135 | |||
136 | inline void dVector3Inv(dVector3& a) | ||
137 | { | ||
138 | a[0] = -a[0]; | ||
139 | a[1] = -a[1]; | ||
140 | a[2] = -a[2]; | ||
141 | } | ||
142 | |||
143 | inline dReal dVector3Length2(const dVector3& a) | ||
144 | { | ||
145 | return (a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); | ||
146 | } | ||
147 | |||
148 | inline void dMat3GetCol(const dMatrix3& m,const int col, dVector3& v) | ||
149 | { | ||
150 | v[0] = m[col + 0]; | ||
151 | v[1] = m[col + 4]; | ||
152 | v[2] = m[col + 8]; | ||
153 | } | ||
154 | |||
155 | inline void dVector3CrossMat3Col(const dMatrix3& m,const int col,const dVector3& v,dVector3& r) | ||
156 | { | ||
157 | r[0] = v[1] * m[2*4 + col] - v[2] * m[1*4 + col]; | ||
158 | r[1] = v[2] * m[0*4 + col] - v[0] * m[2*4 + col]; | ||
159 | r[2] = v[0] * m[1*4 + col] - v[1] * m[0*4 + col]; | ||
160 | } | ||
161 | |||
162 | inline void dMat3ColCrossVector3(const dMatrix3& m,const int col,const dVector3& v,dVector3& r) | ||
163 | { | ||
164 | r[0] = v[2] * m[1*4 + col] - v[1] * m[2*4 + col]; | ||
165 | r[1] = v[0] * m[2*4 + col] - v[2] * m[0*4 + col]; | ||
166 | r[2] = v[1] * m[0*4 + col] - v[0] * m[1*4 + col]; | ||
167 | } | ||
168 | |||
169 | inline void dMultiplyMat3Vec3(const dMatrix3& m,const dVector3& v, dVector3& r) | ||
170 | { | ||
171 | dMULTIPLY0_331(r,m,v); | ||
172 | } | ||
173 | |||
174 | inline dReal dPointPlaneDistance(const dVector3& point,const dVector4& plane) | ||
175 | { | ||
176 | return (plane[0]*point[0] + plane[1]*point[1] + plane[2]*point[2] + plane[3]); | ||
177 | } | ||
178 | |||
179 | inline void dConstructPlane(const dVector3& normal,const dReal& distance, dVector4& plane) | ||
180 | { | ||
181 | plane[0] = normal[0]; | ||
182 | plane[1] = normal[1]; | ||
183 | plane[2] = normal[2]; | ||
184 | plane[3] = distance; | ||
185 | } | ||
186 | |||
187 | inline void dMatrix3Copy(const dReal* source,dMatrix3& dest) | ||
188 | { | ||
189 | dest[0] = source[0]; | ||
190 | dest[1] = source[1]; | ||
191 | dest[2] = source[2]; | ||
192 | |||
193 | dest[4] = source[4]; | ||
194 | dest[5] = source[5]; | ||
195 | dest[6] = source[6]; | ||
196 | |||
197 | dest[8] = source[8]; | ||
198 | dest[9] = source[9]; | ||
199 | dest[10]= source[10]; | ||
200 | } | ||
201 | |||
202 | inline dReal dMatrix3Det( const dMatrix3& mat ) | ||
203 | { | ||
204 | dReal det; | ||
205 | |||
206 | det = mat[0] * ( mat[5]*mat[10] - mat[9]*mat[6] ) | ||
207 | - mat[1] * ( mat[4]*mat[10] - mat[8]*mat[6] ) | ||
208 | + mat[2] * ( mat[4]*mat[9] - mat[8]*mat[5] ); | ||
209 | |||
210 | return( det ); | ||
211 | } | ||
212 | |||
213 | |||
214 | inline void dMatrix3Inv( const dMatrix3& ma, dMatrix3& dst ) | ||
215 | { | ||
216 | dReal det = dMatrix3Det( ma ); | ||
217 | |||
218 | if ( dFabs( det ) < REAL(0.0005) ) | ||
219 | { | ||
220 | dRSetIdentity( dst ); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | dst[0] = ma[5]*ma[10] - ma[6]*ma[9] / det; | ||
225 | dst[1] = -( ma[1]*ma[10] - ma[9]*ma[2] ) / det; | ||
226 | dst[2] = ma[1]*ma[6] - ma[5]*ma[2] / det; | ||
227 | |||
228 | dst[4] = -( ma[4]*ma[10] - ma[6]*ma[8] ) / det; | ||
229 | dst[5] = ma[0]*ma[10] - ma[8]*ma[2] / det; | ||
230 | dst[6] = -( ma[0]*ma[6] - ma[4]*ma[2] ) / det; | ||
231 | |||
232 | dst[8] = ma[4]*ma[9] - ma[8]*ma[5] / det; | ||
233 | dst[9] = -( ma[0]*ma[9] - ma[8]*ma[1] ) / det; | ||
234 | dst[10] = ma[0]*ma[5] - ma[1]*ma[4] / det; | ||
235 | } | ||
236 | |||
237 | inline void dQuatTransform(const dQuaternion& quat,const dVector3& source,dVector3& dest) | ||
238 | { | ||
239 | |||
240 | // Nguyen Binh : this code seem to be the fastest. | ||
241 | dReal x0 = source[0] * quat[0] + source[2] * quat[2] - source[1] * quat[3]; | ||
242 | dReal x1 = source[1] * quat[0] + source[0] * quat[3] - source[2] * quat[1]; | ||
243 | dReal x2 = source[2] * quat[0] + source[1] * quat[1] - source[0] * quat[2]; | ||
244 | dReal x3 = source[0] * quat[1] + source[1] * quat[2] + source[2] * quat[3]; | ||
245 | |||
246 | dest[0] = quat[0] * x0 + quat[1] * x3 + quat[2] * x2 - quat[3] * x1; | ||
247 | dest[1] = quat[0] * x1 + quat[2] * x3 + quat[3] * x0 - quat[1] * x2; | ||
248 | dest[2] = quat[0] * x2 + quat[3] * x3 + quat[1] * x1 - quat[2] * x0; | ||
249 | |||
250 | /* | ||
251 | // nVidia SDK implementation | ||
252 | dVector3 uv, uuv; | ||
253 | dVector3 qvec; | ||
254 | qvec[0] = quat[1]; | ||
255 | qvec[1] = quat[2]; | ||
256 | qvec[2] = quat[3]; | ||
257 | |||
258 | dVector3Cross(qvec,source,uv); | ||
259 | dVector3Cross(qvec,uv,uuv); | ||
260 | |||
261 | dVector3Scale(uv,REAL(2.0)*quat[0]); | ||
262 | dVector3Scale(uuv,REAL(2.0)); | ||
263 | |||
264 | dest[0] = source[0] + uv[0] + uuv[0]; | ||
265 | dest[1] = source[1] + uv[1] + uuv[1]; | ||
266 | dest[2] = source[2] + uv[2] + uuv[2]; | ||
267 | */ | ||
268 | } | ||
269 | |||
270 | inline void dQuatInvTransform(const dQuaternion& quat,const dVector3& source,dVector3& dest) | ||
271 | { | ||
272 | |||
273 | dReal norm = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2] + quat[3]*quat[3]; | ||
274 | |||
275 | if (norm > REAL(0.0)) | ||
276 | { | ||
277 | dQuaternion invQuat; | ||
278 | invQuat[0] = quat[0] / norm; | ||
279 | invQuat[1] = -quat[1] / norm; | ||
280 | invQuat[2] = -quat[2] / norm; | ||
281 | invQuat[3] = -quat[3] / norm; | ||
282 | |||
283 | dQuatTransform(invQuat,source,dest); | ||
284 | |||
285 | } | ||
286 | else | ||
287 | { | ||
288 | // Singular -> return identity | ||
289 | dVector3Copy(source,dest); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | inline void dGetEulerAngleFromRot(const dMatrix3& mRot,dReal& rX,dReal& rY,dReal& rZ) | ||
294 | { | ||
295 | rY = asin(mRot[0 * 4 + 2]); | ||
296 | if (rY < M_PI /2) | ||
297 | { | ||
298 | if (rY > -M_PI /2) | ||
299 | { | ||
300 | rX = atan2(-mRot[1*4 + 2], mRot[2*4 + 2]); | ||
301 | rZ = atan2(-mRot[0*4 + 1], mRot[0*4 + 0]); | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | // not unique | ||
306 | rX = -atan2(mRot[1*4 + 0], mRot[1*4 + 1]); | ||
307 | rZ = REAL(0.0); | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | // not unique | ||
313 | rX = atan2(mRot[1*4 + 0], mRot[1*4 + 1]); | ||
314 | rZ = REAL(0.0); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | inline void dQuatInv(const dQuaternion& source, dQuaternion& dest) | ||
319 | { | ||
320 | dReal norm = source[0]*source[0] + source[1]*source[1] + source[2]*source[2] + source[3]*source[3]; | ||
321 | |||
322 | if (norm > 0.0f) | ||
323 | { | ||
324 | dest[0] = source[0] / norm; | ||
325 | dest[1] = -source[1] / norm; | ||
326 | dest[2] = -source[2] / norm; | ||
327 | dest[3] = -source[3] / norm; | ||
328 | } | ||
329 | else | ||
330 | { | ||
331 | // Singular -> return identity | ||
332 | dest[0] = REAL(1.0); | ||
333 | dest[1] = REAL(0.0); | ||
334 | dest[2] = REAL(0.0); | ||
335 | dest[3] = REAL(0.0); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | |||
340 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/convex.cpp b/libraries/ode-0.9\/ode/src/convex.cpp new file mode 100755 index 0000000..db93beb --- /dev/null +++ b/libraries/ode-0.9\/ode/src/convex.cpp | |||
@@ -0,0 +1,1294 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | Code for Convex Collision Detection | ||
25 | By Rodrigo Hernandez | ||
26 | */ | ||
27 | //#include <algorithm> | ||
28 | #include <ode/common.h> | ||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | #include "collision_kernel.h" | ||
34 | #include "collision_std.h" | ||
35 | #include "collision_util.h" | ||
36 | |||
37 | #ifdef _MSC_VER | ||
38 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
39 | #endif | ||
40 | |||
41 | #if _MSC_VER <= 1200 | ||
42 | #define dMIN(A,B) ((A)>(B) ? B : A) | ||
43 | #define dMAX(A,B) ((A)>(B) ? A : B) | ||
44 | #else | ||
45 | #define dMIN(A,B) std::min(A,B) | ||
46 | #define dMAX(A,B) std::max(A,B) | ||
47 | #endif | ||
48 | |||
49 | //**************************************************************************** | ||
50 | // Convex public API | ||
51 | dxConvex::dxConvex (dSpaceID space, | ||
52 | dReal *_planes, | ||
53 | unsigned int _planecount, | ||
54 | dReal *_points, | ||
55 | unsigned int _pointcount, | ||
56 | unsigned int *_polygons) : | ||
57 | dxGeom (space,1) | ||
58 | { | ||
59 | dAASSERT (_planes != NULL); | ||
60 | dAASSERT (_points != NULL); | ||
61 | dAASSERT (_polygons != NULL); | ||
62 | //fprintf(stdout,"dxConvex Constructor planes %X\n",_planes); | ||
63 | type = dConvexClass; | ||
64 | planes = _planes; | ||
65 | planecount = _planecount; | ||
66 | // we need points as well | ||
67 | points = _points; | ||
68 | pointcount = _pointcount; | ||
69 | polygons=_polygons; | ||
70 | FillEdges(); | ||
71 | } | ||
72 | |||
73 | |||
74 | void dxConvex::computeAABB() | ||
75 | { | ||
76 | // this can, and should be optimized | ||
77 | dVector3 point; | ||
78 | dMULTIPLY0_331 (point,final_posr->R,points); | ||
79 | aabb[0] = point[0]+final_posr->pos[0]; | ||
80 | aabb[1] = point[0]+final_posr->pos[0]; | ||
81 | aabb[2] = point[1]+final_posr->pos[1]; | ||
82 | aabb[3] = point[1]+final_posr->pos[1]; | ||
83 | aabb[4] = point[2]+final_posr->pos[2]; | ||
84 | aabb[5] = point[2]+final_posr->pos[2]; | ||
85 | for(unsigned int i=3;i<(pointcount*3);i+=3) | ||
86 | { | ||
87 | dMULTIPLY0_331 (point,final_posr->R,&points[i]); | ||
88 | aabb[0] = dMIN(aabb[0],point[0]+final_posr->pos[0]); | ||
89 | aabb[1] = dMAX(aabb[1],point[0]+final_posr->pos[0]); | ||
90 | aabb[2] = dMIN(aabb[2],point[1]+final_posr->pos[1]); | ||
91 | aabb[3] = dMAX(aabb[3],point[1]+final_posr->pos[1]); | ||
92 | aabb[4] = dMIN(aabb[4],point[2]+final_posr->pos[2]); | ||
93 | aabb[5] = dMAX(aabb[5],point[2]+final_posr->pos[2]); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /*! \brief Populates the edges set, should be called only once whenever | ||
98 | the polygon array gets updated */ | ||
99 | void dxConvex::FillEdges() | ||
100 | { | ||
101 | unsigned int *points_in_poly=polygons; | ||
102 | unsigned int *index=polygons+1; | ||
103 | for(unsigned int i=0;i<planecount;++i) | ||
104 | { | ||
105 | //fprintf(stdout,"Points in Poly: %d\n",*points_in_poly); | ||
106 | for(unsigned int j=0;j<*points_in_poly;++j) | ||
107 | { | ||
108 | edges.insert(edge(dMIN(index[j],index[(j+1)%*points_in_poly]), | ||
109 | dMAX(index[j],index[(j+1)%*points_in_poly]))); | ||
110 | //fprintf(stdout,"Insert %d-%d\n",index[j],index[(j+1)%*points_in_poly]); | ||
111 | } | ||
112 | points_in_poly+=(*points_in_poly+1); | ||
113 | index=points_in_poly+1; | ||
114 | } | ||
115 | /* | ||
116 | fprintf(stdout,"Edge Count: %d\n",edges.size()); | ||
117 | for(std::set<edge>::iterator it=edges.begin(); | ||
118 | it!=edges.end(); | ||
119 | ++it) | ||
120 | { | ||
121 | fprintf(stdout,"Edge: %d-%d\n",it->first,it->second); | ||
122 | } | ||
123 | */ | ||
124 | } | ||
125 | |||
126 | dGeomID dCreateConvex (dSpaceID space,dReal *_planes,unsigned int _planecount, | ||
127 | dReal *_points, | ||
128 | unsigned int _pointcount, | ||
129 | unsigned int *_polygons) | ||
130 | { | ||
131 | //fprintf(stdout,"dxConvex dCreateConvex\n"); | ||
132 | return new dxConvex(space,_planes, _planecount, | ||
133 | _points, | ||
134 | _pointcount, | ||
135 | _polygons); | ||
136 | } | ||
137 | |||
138 | void dGeomSetConvex (dGeomID g,dReal *_planes,unsigned int _planecount, | ||
139 | dReal *_points, | ||
140 | unsigned int _pointcount, | ||
141 | unsigned int *_polygons) | ||
142 | { | ||
143 | //fprintf(stdout,"dxConvex dGeomSetConvex\n"); | ||
144 | dUASSERT (g && g->type == dConvexClass,"argument not a convex shape"); | ||
145 | dxConvex *s = (dxConvex*) g; | ||
146 | s->planes = _planes; | ||
147 | s->planecount = _planecount; | ||
148 | s->points = _points; | ||
149 | s->pointcount = _pointcount; | ||
150 | s->polygons=_polygons; | ||
151 | } | ||
152 | |||
153 | //**************************************************************************** | ||
154 | // Helper Inlines | ||
155 | // | ||
156 | |||
157 | /*! \brief Returns Whether or not the segment ab intersects plane p | ||
158 | \param a origin of the segment | ||
159 | \param b segment destination | ||
160 | \param p plane to test for intersection | ||
161 | \param t returns the time "t" in the segment ray that gives us the intersecting | ||
162 | point | ||
163 | \param q returns the intersection point | ||
164 | \return true if there is an intersection, otherwise false. | ||
165 | */ | ||
166 | bool IntersectSegmentPlane(dVector3 a, | ||
167 | dVector3 b, | ||
168 | dVector4 p, | ||
169 | dReal &t, | ||
170 | dVector3 q) | ||
171 | { | ||
172 | // Compute the t value for the directed line ab intersecting the plane | ||
173 | dVector3 ab; | ||
174 | ab[0]= b[0] - a[0]; | ||
175 | ab[1]= b[1] - a[1]; | ||
176 | ab[2]= b[2] - a[2]; | ||
177 | |||
178 | t = (p[3] - dDOT(p,a)) / dDOT(p,ab); | ||
179 | |||
180 | // If t in [0..1] compute and return intersection point | ||
181 | if (t >= 0.0 && t <= 1.0) | ||
182 | { | ||
183 | q[0] = a[0] + t * ab[0]; | ||
184 | q[1] = a[1] + t * ab[1]; | ||
185 | q[2] = a[2] + t * ab[2]; | ||
186 | return true; | ||
187 | } | ||
188 | // Else no intersection | ||
189 | return false; | ||
190 | } | ||
191 | |||
192 | /*! \brief Returns the Closest Point in Ray 1 to Ray 2 | ||
193 | \param Origin1 The origin of Ray 1 | ||
194 | \param Direction1 The direction of Ray 1 | ||
195 | \param Origin1 The origin of Ray 2 | ||
196 | \param Direction1 The direction of Ray 3 | ||
197 | \param t the time "t" in Ray 1 that gives us the closest point | ||
198 | (closest_point=Origin1+(Direction*t). | ||
199 | \return true if there is a closest point, false if the rays are paralell. | ||
200 | */ | ||
201 | inline bool ClosestPointInRay(const dVector3 Origin1, | ||
202 | const dVector3 Direction1, | ||
203 | const dVector3 Origin2, | ||
204 | const dVector3 Direction2, | ||
205 | dReal& t) | ||
206 | { | ||
207 | dVector3 w = {Origin1[0]-Origin2[0], | ||
208 | Origin1[1]-Origin2[1], | ||
209 | Origin1[2]-Origin2[2]}; | ||
210 | dReal a = dDOT(Direction1 , Direction1); | ||
211 | dReal b = dDOT(Direction1 , Direction2); | ||
212 | dReal c = dDOT(Direction2 , Direction2); | ||
213 | dReal d = dDOT(Direction1 , w); | ||
214 | dReal e = dDOT(Direction2 , w); | ||
215 | dReal denominator = (a*c)-(b*b); | ||
216 | if(denominator==0.0f) | ||
217 | { | ||
218 | return false; | ||
219 | } | ||
220 | t = ((a*e)-(b*d))/denominator; | ||
221 | return true; | ||
222 | } | ||
223 | |||
224 | /*! \brief Returns the Ray on which 2 planes intersect if they do. | ||
225 | \param p1 Plane 1 | ||
226 | \param p2 Plane 2 | ||
227 | \param p Contains the origin of the ray upon returning if planes intersect | ||
228 | \param d Contains the direction of the ray upon returning if planes intersect | ||
229 | \return true if the planes intersect, false if paralell. | ||
230 | */ | ||
231 | inline bool IntersectPlanes(const dVector4 p1, const dVector4 p2, dVector3 p, dVector3 d) | ||
232 | { | ||
233 | // Compute direction of intersection line | ||
234 | //Cross(p1, p2,d); | ||
235 | dCROSS(d,=,p1,p2); | ||
236 | |||
237 | // If d is (near) zero, the planes are parallel (and separated) | ||
238 | // or coincident, so they're not considered intersecting | ||
239 | dReal denom = dDOT(d, d); | ||
240 | if (denom < dEpsilon) return false; | ||
241 | |||
242 | dVector3 n; | ||
243 | n[0]=p1[3]*p2[0] - p2[3]*p1[0]; | ||
244 | n[1]=p1[3]*p2[1] - p2[3]*p1[1]; | ||
245 | n[2]=p1[3]*p2[2] - p2[3]*p1[2]; | ||
246 | // Compute point on intersection line | ||
247 | //Cross(n, d,p); | ||
248 | dCROSS(p,=,n,d); | ||
249 | p[0]/=denom; | ||
250 | p[1]/=denom; | ||
251 | p[2]/=denom; | ||
252 | return true; | ||
253 | } | ||
254 | |||
255 | /*! \brief Finds out if a point lies inside a 2D polygon | ||
256 | \param p Point to test | ||
257 | \param polygon a pointer to the start of the convex polygon index buffer | ||
258 | \param out the closest point in the polygon if the point is not inside | ||
259 | \return true if the point lies inside of the polygon, false if not. | ||
260 | */ | ||
261 | inline bool IsPointInPolygon(dVector3 p, | ||
262 | unsigned int *polygon, | ||
263 | dxConvex *convex, | ||
264 | dVector3 out) | ||
265 | { | ||
266 | // p is the point we want to check, | ||
267 | // polygon is a pointer to the polygon we | ||
268 | // are checking against, remember it goes | ||
269 | // number of vertices then that many indexes | ||
270 | // out returns the closest point on the border of the | ||
271 | // polygon if the point is not inside it. | ||
272 | size_t pointcount=polygon[0]; | ||
273 | dVector3 a; | ||
274 | dVector3 b; | ||
275 | dVector3 c; | ||
276 | dVector3 ab; | ||
277 | dVector3 ac; | ||
278 | dVector3 ap; | ||
279 | dVector3 bp; | ||
280 | dReal d1; | ||
281 | dReal d2; | ||
282 | dReal d3; | ||
283 | dReal d4; | ||
284 | dReal vc; | ||
285 | polygon++; // skip past pointcount | ||
286 | for(size_t i=0;i<pointcount;++i) | ||
287 | { | ||
288 | dMULTIPLY0_331 (a,convex->final_posr->R,&convex->points[(polygon[i]*3)]); | ||
289 | a[0]=convex->final_posr->pos[0]+a[0]; | ||
290 | a[1]=convex->final_posr->pos[1]+a[1]; | ||
291 | a[2]=convex->final_posr->pos[2]+a[2]; | ||
292 | |||
293 | dMULTIPLY0_331 (b,convex->final_posr->R, | ||
294 | &convex->points[(polygon[(i+1)%pointcount]*3)]); | ||
295 | b[0]=convex->final_posr->pos[0]+b[0]; | ||
296 | b[1]=convex->final_posr->pos[1]+b[1]; | ||
297 | b[2]=convex->final_posr->pos[2]+b[2]; | ||
298 | |||
299 | dMULTIPLY0_331 (c,convex->final_posr->R, | ||
300 | &convex->points[(polygon[(i+2)%pointcount]*3)]); | ||
301 | c[0]=convex->final_posr->pos[0]+c[0]; | ||
302 | c[1]=convex->final_posr->pos[1]+c[1]; | ||
303 | c[2]=convex->final_posr->pos[2]+c[2]; | ||
304 | |||
305 | ab[0] = b[0] - a[0]; | ||
306 | ab[1] = b[1] - a[1]; | ||
307 | ab[2] = b[2] - a[2]; | ||
308 | ac[0] = c[0] - a[0]; | ||
309 | ac[1] = c[1] - a[1]; | ||
310 | ac[2] = c[2] - a[2]; | ||
311 | ap[0] = p[0] - a[0]; | ||
312 | ap[1] = p[1] - a[1]; | ||
313 | ap[2] = p[2] - a[2]; | ||
314 | d1 = dDOT(ab,ap); | ||
315 | d2 = dDOT(ac,ap); | ||
316 | if (d1 <= 0.0f && d2 <= 0.0f) | ||
317 | { | ||
318 | out[0]=a[0]; | ||
319 | out[1]=a[1]; | ||
320 | out[2]=a[2]; | ||
321 | return false; | ||
322 | } | ||
323 | bp[0] = p[0] - b[0]; | ||
324 | bp[1] = p[1] - b[1]; | ||
325 | bp[2] = p[2] - b[2]; | ||
326 | d3 = dDOT(ab,bp); | ||
327 | d4 = dDOT(ac,bp); | ||
328 | if (d3 >= 0.0f && d4 <= d3) | ||
329 | { | ||
330 | out[0]=b[0]; | ||
331 | out[1]=b[1]; | ||
332 | out[2]=b[2]; | ||
333 | return false; | ||
334 | } | ||
335 | vc = d1*d4 - d3*d2; | ||
336 | if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) | ||
337 | { | ||
338 | dReal v = d1 / (d1 - d3); | ||
339 | out[0] = a[0] + (ab[0]*v); | ||
340 | out[1] = a[1] + (ab[1]*v); | ||
341 | out[2] = a[2] + (ab[2]*v); | ||
342 | return false; | ||
343 | } | ||
344 | } | ||
345 | return true; | ||
346 | } | ||
347 | |||
348 | int dCollideConvexPlane (dxGeom *o1, dxGeom *o2, int flags, | ||
349 | dContactGeom *contact, int skip) | ||
350 | { | ||
351 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
352 | dIASSERT (o1->type == dConvexClass); | ||
353 | dIASSERT (o2->type == dPlaneClass); | ||
354 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
355 | |||
356 | dxConvex *Convex = (dxConvex*) o1; | ||
357 | dxPlane *Plane = (dxPlane*) o2; | ||
358 | unsigned int contacts=0; | ||
359 | unsigned int maxc = flags & NUMC_MASK; | ||
360 | dVector3 v2; | ||
361 | |||
362 | #define LTEQ_ZERO 0x10000000 | ||
363 | #define GTEQ_ZERO 0x20000000 | ||
364 | #define BOTH_SIGNS (LTEQ_ZERO | GTEQ_ZERO) | ||
365 | dIASSERT((BOTH_SIGNS & NUMC_MASK) == 0); // used in conditional operator later | ||
366 | |||
367 | unsigned int totalsign = 0; | ||
368 | for(unsigned int i=0;i<Convex->pointcount;++i) | ||
369 | { | ||
370 | dMULTIPLY0_331 (v2,Convex->final_posr->R,&Convex->points[(i*3)]); | ||
371 | dVector3Add(Convex->final_posr->pos, v2, v2); | ||
372 | |||
373 | unsigned int distance2sign = GTEQ_ZERO; | ||
374 | dReal distance2 = dVector3Dot(Plane->p, v2) - Plane->p[3]; // Ax + By + Cz - D | ||
375 | if((distance2 <= REAL(0.0))) | ||
376 | { | ||
377 | distance2sign = distance2 != REAL(0.0) ? LTEQ_ZERO : BOTH_SIGNS; | ||
378 | |||
379 | if (contacts != maxc) | ||
380 | { | ||
381 | dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip); | ||
382 | dVector3Copy(Plane->p, target->normal); | ||
383 | dVector3Copy(v2, target->pos); | ||
384 | target->depth = -distance2; | ||
385 | target->g1 = Convex; | ||
386 | target->g2 = Plane; | ||
387 | contacts++; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | // Take new sign into account | ||
392 | totalsign |= distance2sign; | ||
393 | // Check if contacts are full and both signs have been already found | ||
394 | if ((contacts ^ maxc | totalsign) == BOTH_SIGNS) // harder to comprehend but requires one register less | ||
395 | { | ||
396 | break; // Nothing can be changed any more | ||
397 | } | ||
398 | } | ||
399 | if (totalsign == BOTH_SIGNS) return contacts; | ||
400 | return 0; | ||
401 | #undef BOTH_SIGNS | ||
402 | #undef GTEQ_ZERO | ||
403 | #undef LTEQ_ZERO | ||
404 | } | ||
405 | |||
406 | int dCollideSphereConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
407 | dContactGeom *contact, int skip) | ||
408 | { | ||
409 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
410 | dIASSERT (o1->type == dSphereClass); | ||
411 | dIASSERT (o2->type == dConvexClass); | ||
412 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
413 | |||
414 | dxSphere *Sphere = (dxSphere*) o1; | ||
415 | dxConvex *Convex = (dxConvex*) o2; | ||
416 | dReal dist,closestdist=dInfinity; | ||
417 | dVector4 plane; | ||
418 | // dVector3 contactpoint; | ||
419 | dVector3 offsetpos,out,temp; | ||
420 | unsigned int *pPoly=Convex->polygons; | ||
421 | int closestplane; | ||
422 | bool sphereinside=true; | ||
423 | /* | ||
424 | Do a good old sphere vs plane check first, | ||
425 | if a collision is found then check if the contact point | ||
426 | is within the polygon | ||
427 | */ | ||
428 | // offset the sphere final_posr->position into the convex space | ||
429 | offsetpos[0]=Sphere->final_posr->pos[0]-Convex->final_posr->pos[0]; | ||
430 | offsetpos[1]=Sphere->final_posr->pos[1]-Convex->final_posr->pos[1]; | ||
431 | offsetpos[2]=Sphere->final_posr->pos[2]-Convex->final_posr->pos[2]; | ||
432 | //fprintf(stdout,"Begin Check\n"); | ||
433 | for(unsigned int i=0;i<Convex->planecount;++i) | ||
434 | { | ||
435 | // apply rotation to the plane | ||
436 | dMULTIPLY0_331(plane,Convex->final_posr->R,&Convex->planes[(i*4)]); | ||
437 | plane[3]=(&Convex->planes[(i*4)])[3]; | ||
438 | // Get the distance from the sphere origin to the plane | ||
439 | dist = dVector3Dot(plane, offsetpos) - plane[3]; // Ax + By + Cz - D | ||
440 | if(dist>0) | ||
441 | { | ||
442 | // if we get here, we know the center of the sphere is | ||
443 | // outside of the convex hull. | ||
444 | if(dist<Sphere->radius) | ||
445 | { | ||
446 | // if we get here we know the sphere surface penetrates | ||
447 | // the plane | ||
448 | if(IsPointInPolygon(Sphere->final_posr->pos,pPoly,Convex,out)) | ||
449 | { | ||
450 | // finally if we get here we know that the | ||
451 | // sphere is directly touching the inside of the polyhedron | ||
452 | //fprintf(stdout,"Contact! distance=%f\n",dist); | ||
453 | contact->normal[0] = plane[0]; | ||
454 | contact->normal[1] = plane[1]; | ||
455 | contact->normal[2] = plane[2]; | ||
456 | contact->pos[0] = Sphere->final_posr->pos[0]+ | ||
457 | (-contact->normal[0]*Sphere->radius); | ||
458 | contact->pos[1] = Sphere->final_posr->pos[1]+ | ||
459 | (-contact->normal[1]*Sphere->radius); | ||
460 | contact->pos[2] = Sphere->final_posr->pos[2]+ | ||
461 | (-contact->normal[2]*Sphere->radius); | ||
462 | contact->depth = Sphere->radius-dist; | ||
463 | contact->g1 = Sphere; | ||
464 | contact->g2 = Convex; | ||
465 | return 1; | ||
466 | } | ||
467 | else | ||
468 | { | ||
469 | // the sphere may not be directly touching | ||
470 | // the polyhedron, but it may be touching | ||
471 | // a point or an edge, if the distance between | ||
472 | // the closest point on the poly (out) and the | ||
473 | // center of the sphere is less than the sphere | ||
474 | // radius we have a hit. | ||
475 | temp[0] = (Sphere->final_posr->pos[0]-out[0]); | ||
476 | temp[1] = (Sphere->final_posr->pos[1]-out[1]); | ||
477 | temp[2] = (Sphere->final_posr->pos[2]-out[2]); | ||
478 | dist=(temp[0]*temp[0])+(temp[1]*temp[1])+(temp[2]*temp[2]); | ||
479 | // avoid the sqrt unless really necesary | ||
480 | if(dist<(Sphere->radius*Sphere->radius)) | ||
481 | { | ||
482 | // We got an indirect hit | ||
483 | dist=dSqrt(dist); | ||
484 | contact->normal[0] = temp[0]/dist; | ||
485 | contact->normal[1] = temp[1]/dist; | ||
486 | contact->normal[2] = temp[2]/dist; | ||
487 | contact->pos[0] = Sphere->final_posr->pos[0]+ | ||
488 | (-contact->normal[0]*Sphere->radius); | ||
489 | contact->pos[1] = Sphere->final_posr->pos[1]+ | ||
490 | (-contact->normal[1]*Sphere->radius); | ||
491 | contact->pos[2] = Sphere->final_posr->pos[2]+ | ||
492 | (-contact->normal[2]*Sphere->radius); | ||
493 | contact->depth = Sphere->radius-dist; | ||
494 | contact->g1 = Sphere; | ||
495 | contact->g2 = Convex; | ||
496 | return 1; | ||
497 | } | ||
498 | } | ||
499 | } | ||
500 | sphereinside=false; | ||
501 | } | ||
502 | if(sphereinside) | ||
503 | { | ||
504 | if(closestdist>dFabs(dist)) | ||
505 | { | ||
506 | closestdist=dFabs(dist); | ||
507 | closestplane=i; | ||
508 | } | ||
509 | } | ||
510 | pPoly+=pPoly[0]+1; | ||
511 | } | ||
512 | if(sphereinside) | ||
513 | { | ||
514 | // if the center of the sphere is inside | ||
515 | // the Convex, we need to pop it out | ||
516 | dMULTIPLY0_331(contact->normal, | ||
517 | Convex->final_posr->R, | ||
518 | &Convex->planes[(closestplane*4)]); | ||
519 | contact->pos[0] = Sphere->final_posr->pos[0]; | ||
520 | contact->pos[1] = Sphere->final_posr->pos[1]; | ||
521 | contact->pos[2] = Sphere->final_posr->pos[2]; | ||
522 | contact->depth = closestdist+Sphere->radius; | ||
523 | contact->g1 = Sphere; | ||
524 | contact->g2 = Convex; | ||
525 | return 1; | ||
526 | } | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | int dCollideConvexBox (dxGeom *o1, dxGeom *o2, int flags, | ||
531 | dContactGeom *contact, int skip) | ||
532 | { | ||
533 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
534 | dIASSERT (o1->type == dConvexClass); | ||
535 | dIASSERT (o2->type == dBoxClass); | ||
536 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
537 | |||
538 | dxConvex *Convex = (dxConvex*) o1; | ||
539 | dxBox *Box = (dxBox*) o2; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | int dCollideConvexCapsule (dxGeom *o1, dxGeom *o2, | ||
545 | int flags, dContactGeom *contact, int skip) | ||
546 | { | ||
547 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
548 | dIASSERT (o1->type == dConvexClass); | ||
549 | dIASSERT (o2->type == dCapsuleClass); | ||
550 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
551 | |||
552 | dxConvex *Convex = (dxConvex*) o1; | ||
553 | dxCapsule *Capsule = (dxCapsule*) o2; | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | /*! | ||
559 | \brief Retrieves the proper convex and plane index between 2 convex objects. | ||
560 | |||
561 | Seidel's Algorithm does not discriminate between 2 different Convex Hulls, | ||
562 | it only cares about planes, so we feed it the planes of Convex 1 followed | ||
563 | by the planes of Convex 2 as a single collection of planes, | ||
564 | given an index into the single collection, | ||
565 | this function determines the correct convex object and index to retrieve | ||
566 | the current plane. | ||
567 | |||
568 | \param c1 Convex 1 | ||
569 | \param c2 Convex 2 | ||
570 | \param i Plane Index to retrieve | ||
571 | \param index contains the translated index uppon return | ||
572 | \return a pointer to the convex object containing plane index "i" | ||
573 | */ | ||
574 | inline dxConvex* GetPlaneIndex(dxConvex& c1, | ||
575 | dxConvex& c2, | ||
576 | unsigned int i,unsigned int& index) | ||
577 | { | ||
578 | if(i>=c1.planecount) | ||
579 | { | ||
580 | index = i-c1.planecount; | ||
581 | return &c2; | ||
582 | } | ||
583 | index=i; | ||
584 | return &c1; | ||
585 | } | ||
586 | |||
587 | inline void dumpplanes(dxConvex& cvx) | ||
588 | { | ||
589 | // This is just a dummy debug function | ||
590 | dVector4 plane; | ||
591 | fprintf(stdout,"DUMP PLANES\n"); | ||
592 | for (unsigned int i=0;i<cvx.planecount;++i) | ||
593 | { | ||
594 | dMULTIPLY0_331(plane,cvx.final_posr->R,&cvx.planes[(i*4)]); | ||
595 | // Translate | ||
596 | plane[3]= | ||
597 | (cvx.planes[(i*4)+3])+ | ||
598 | ((plane[0] * cvx.final_posr->pos[0]) + | ||
599 | (plane[1] * cvx.final_posr->pos[1]) + | ||
600 | (plane[2] * cvx.final_posr->pos[2])); | ||
601 | fprintf(stdout,"%f %f %f %f\n",plane[0],plane[1],plane[2],plane[3]); | ||
602 | } | ||
603 | } | ||
604 | |||
605 | // this variable is for debuggin purpuses only, should go once everything works | ||
606 | static bool hit=false; | ||
607 | |||
608 | /* | ||
609 | \brief Tests whether 2 convex objects collide | ||
610 | |||
611 | Seidel's algorithm is a method to solve linear programs, | ||
612 | it finds the optimum vertex "v" of a set of functions, | ||
613 | in our case, the set of functions are the plane functions | ||
614 | for the 2 convex objects being tested. | ||
615 | We don't really care about the value optimum vertex though, | ||
616 | but the 2 convex objects only collide if this vertex exists, | ||
617 | otherwise, the set of functions is said to be "empty" or "void". | ||
618 | |||
619 | Seidel's Original algorithm is recursive and not bound to any number | ||
620 | of dimensions, the one I present here is Iterative rather than recursive | ||
621 | and bound to 3 dimensions, which is what we care about. | ||
622 | |||
623 | If you're interested (and you should be!) on the algorithm, the paper | ||
624 | by Raimund Seidel himself should explain a lot better than I did, you can | ||
625 | find it here: http://www.cs.berkeley.edu/~jrs/meshpapers/SeidelLP.pdf | ||
626 | |||
627 | If posible, read the section about Linear Programming in | ||
628 | Christer Ericson's RealTime Collision Detection book. | ||
629 | |||
630 | \note currently there seem to be some issues with this function since | ||
631 | it doesn't detect collisions except for the most simple tests :(. | ||
632 | */ | ||
633 | bool SeidelLP(dxConvex& cvx1,dxConvex& cvx2) | ||
634 | { | ||
635 | dVector3 c={1,0,0}; // The Objective vector can be anything | ||
636 | dVector3 solution; // We dont really need the solution so its local | ||
637 | dxConvex *cvx; | ||
638 | unsigned int index; | ||
639 | unsigned int planecount=cvx1.planecount+cvx2.planecount; | ||
640 | dReal sum,min,max,med; | ||
641 | dVector3 c1; // ,c2; | ||
642 | dVector4 aoveral,aoveram; // these will contain cached computations | ||
643 | unsigned int l,m,n; // l and m are the axes to the zerod dimensions, n is the axe for the last dimension | ||
644 | unsigned int i,j,k; | ||
645 | dVector4 eq1,eq2,eq3; // cached equations for 3d,2d and 1d respectivelly | ||
646 | // Get the support mapping for a HUGE bounding box in direction c | ||
647 | solution[0]= (c[0]>0) ? dInfinity : -dInfinity; | ||
648 | solution[1]= (c[1]>0) ? dInfinity : -dInfinity; | ||
649 | solution[2]= (c[2]>0) ? dInfinity : -dInfinity; | ||
650 | for( i=0;i<planecount;++i) | ||
651 | { | ||
652 | // Isolate plane equation | ||
653 | cvx=GetPlaneIndex(cvx1,cvx2,i,index); | ||
654 | // Rotate | ||
655 | dMULTIPLY0_331(eq1,cvx->final_posr->R,&cvx->planes[(index*4)]); | ||
656 | |||
657 | // Translate | ||
658 | eq1[3]=(cvx->planes[(index*4)+3])+ | ||
659 | ((eq1[0] * cvx->final_posr->pos[0]) + | ||
660 | (eq1[1] * cvx->final_posr->pos[1]) + | ||
661 | (eq1[2] * cvx->final_posr->pos[2])); | ||
662 | // if(!hit) | ||
663 | // { | ||
664 | // fprintf(stdout,"Plane I %d: %f %f %f %f\n",i, | ||
665 | // cvx->planes[(index*4)+0], | ||
666 | // cvx->planes[(index*4)+1], | ||
667 | // cvx->planes[(index*4)+2], | ||
668 | // cvx->planes[(index*4)+3]); | ||
669 | // fprintf(stdout,"Transformed Plane %d: %f %f %f %f\n",i, | ||
670 | // eq1[0], | ||
671 | // eq1[1],eq1[2],eq1[3]); | ||
672 | // fprintf(stdout,"POS %f,%f,%f\n", | ||
673 | // cvx->final_posr->pos[0], | ||
674 | // cvx->final_posr->pos[1], | ||
675 | // cvx->final_posr->pos[2]); | ||
676 | // } | ||
677 | // find if the solution is behind the current plane | ||
678 | sum= | ||
679 | ((eq1[0]*solution[0])+ | ||
680 | (eq1[1]*solution[1])+ | ||
681 | (eq1[2]*solution[2]))-eq1[3]; | ||
682 | // if not we need to discard the current solution | ||
683 | if(sum>0) | ||
684 | { | ||
685 | // go down a dimension by eliminating a variable | ||
686 | // first find l | ||
687 | l=0; | ||
688 | for( j=0;j<3;++j) | ||
689 | { | ||
690 | if(fabs(eq1[j])>fabs(eq1[l])) | ||
691 | { | ||
692 | l=j; | ||
693 | } | ||
694 | } | ||
695 | if(eq1[l]==0) | ||
696 | { | ||
697 | if(!hit) | ||
698 | { | ||
699 | fprintf(stdout,"Plane %d: %f %f %f %f is invalid\n",i, | ||
700 | eq1[0],eq1[1],eq1[2],eq1[3]); | ||
701 | } | ||
702 | return false; | ||
703 | } | ||
704 | // then compute a/a[l] c1 and solution | ||
705 | aoveral[0]=eq1[0]/eq1[l]; | ||
706 | aoveral[1]=eq1[1]/eq1[l]; | ||
707 | aoveral[2]=eq1[2]/eq1[l]; | ||
708 | aoveral[3]=eq1[3]/eq1[l]; | ||
709 | c1[0]=c[0]-((c[l]/eq1[l])*eq1[0]); | ||
710 | c1[1]=c[1]-((c[l]/eq1[l])*eq1[1]); | ||
711 | c1[2]=c[2]-((c[l]/eq1[l])*eq1[2]); | ||
712 | solution[0]=solution[0]-((solution[l]/eq1[l])*eq1[0]); | ||
713 | solution[1]=solution[1]-((solution[l]/eq1[l])*eq1[1]); | ||
714 | solution[2]=solution[2]-((solution[l]/eq1[l])*eq1[2]); | ||
715 | // iterate a to get the new equations with the help of a/a[l] | ||
716 | for( j=0;j<planecount;++j) | ||
717 | { | ||
718 | if(i!=j) | ||
719 | { | ||
720 | cvx=GetPlaneIndex(cvx1,cvx2,j,index); | ||
721 | // Rotate | ||
722 | dMULTIPLY0_331(eq2,cvx->final_posr->R,&cvx->planes[(index*4)]); | ||
723 | // Translate | ||
724 | eq2[3]=(cvx->planes[(index*4)+3])+ | ||
725 | ((eq2[0] * cvx->final_posr->pos[0]) + | ||
726 | (eq2[1] * cvx->final_posr->pos[1]) + | ||
727 | (eq2[2] * cvx->final_posr->pos[2])); | ||
728 | |||
729 | // if(!hit) | ||
730 | // { | ||
731 | // fprintf(stdout,"Plane J %d: %f %f %f %f\n",j, | ||
732 | // cvx->planes[(index*4)+0], | ||
733 | // cvx->planes[(index*4)+1], | ||
734 | // cvx->planes[(index*4)+2], | ||
735 | // cvx->planes[(index*4)+3]); | ||
736 | // fprintf(stdout,"Transformed Plane %d: %f %f %f %f\n",j, | ||
737 | // eq2[0], | ||
738 | // eq2[1], | ||
739 | // eq2[2], | ||
740 | // eq2[3]); | ||
741 | // fprintf(stdout,"POS %f,%f,%f\n", | ||
742 | // cvx->final_posr->pos[0], | ||
743 | // cvx->final_posr->pos[1], | ||
744 | // cvx->final_posr->pos[2]); | ||
745 | // } | ||
746 | |||
747 | // Take The equation down a dimension | ||
748 | eq2[0]-=(cvx->planes[(index*4)+l]*aoveral[0]); | ||
749 | eq2[1]-=(cvx->planes[(index*4)+l]*aoveral[1]); | ||
750 | eq2[2]-=(cvx->planes[(index*4)+l]*aoveral[2]); | ||
751 | eq2[3]-=(cvx->planes[(index*4)+l]*aoveral[3]); | ||
752 | sum= | ||
753 | ((eq2[0]*solution[0])+ | ||
754 | (eq2[1]*solution[1])+ | ||
755 | (eq2[2]*solution[2]))-eq2[3]; | ||
756 | if(sum>0) | ||
757 | { | ||
758 | m=0; | ||
759 | for( k=0;k<3;++k) | ||
760 | { | ||
761 | if(fabs(eq2[k])>fabs(eq2[m])) | ||
762 | { | ||
763 | m=k; | ||
764 | } | ||
765 | } | ||
766 | if(eq2[m]==0) | ||
767 | { | ||
768 | /* | ||
769 | if(!hit) fprintf(stdout, | ||
770 | "Plane %d: %f %f %f %f is invalid\n",j, | ||
771 | eq2[0],eq2[1],eq2[2],eq2[3]); | ||
772 | */ | ||
773 | return false; | ||
774 | } | ||
775 | // then compute a/a[m] c1 and solution | ||
776 | aoveram[0]=eq2[0]/eq2[m]; | ||
777 | aoveram[1]=eq2[1]/eq2[m]; | ||
778 | aoveram[2]=eq2[2]/eq2[m]; | ||
779 | aoveram[3]=eq2[3]/eq2[m]; | ||
780 | c1[0]=c[0]-((c[m]/eq2[m])*eq2[0]); | ||
781 | c1[1]=c[1]-((c[m]/eq2[m])*eq2[1]); | ||
782 | c1[2]=c[2]-((c[m]/eq2[m])*eq2[2]); | ||
783 | solution[0]=solution[0]-((solution[m]/eq2[m])*eq2[0]); | ||
784 | solution[1]=solution[1]-((solution[m]/eq2[m])*eq2[1]); | ||
785 | solution[2]=solution[2]-((solution[m]/eq2[m])*eq2[2]); | ||
786 | // figure out the value for n by elimination | ||
787 | n = (l==0) ? ((m==1)? 2:1):((m==0)?((l==1)?2:1):0); | ||
788 | // iterate a to get the new equations with the help of a/a[l] | ||
789 | min=-dInfinity; | ||
790 | max=med=dInfinity; | ||
791 | for(k=0;k<planecount;++k) | ||
792 | { | ||
793 | if((i!=k)&&(j!=k)) | ||
794 | { | ||
795 | cvx=GetPlaneIndex(cvx1,cvx2,k,index); | ||
796 | // Rotate | ||
797 | dMULTIPLY0_331(eq3,cvx->final_posr->R,&cvx->planes[(index*4)]); | ||
798 | // Translate | ||
799 | eq3[3]=(cvx->planes[(index*4)+3])+ | ||
800 | ((eq3[0] * cvx->final_posr->pos[0]) + | ||
801 | (eq3[1] * cvx->final_posr->pos[1]) + | ||
802 | (eq3[2] * cvx->final_posr->pos[2])); | ||
803 | // if(!hit) | ||
804 | // { | ||
805 | // fprintf(stdout,"Plane K %d: %f %f %f %f\n",k, | ||
806 | // cvx->planes[(index*4)+0], | ||
807 | // cvx->planes[(index*4)+1], | ||
808 | // cvx->planes[(index*4)+2], | ||
809 | // cvx->planes[(index*4)+3]); | ||
810 | // fprintf(stdout,"Transformed Plane %d: %f %f %f %f\n",k, | ||
811 | // eq3[0], | ||
812 | // eq3[1], | ||
813 | // eq3[2], | ||
814 | // eq3[3]); | ||
815 | // fprintf(stdout,"POS %f,%f,%f\n", | ||
816 | // cvx->final_posr->pos[0], | ||
817 | // cvx->final_posr->pos[1], | ||
818 | // cvx->final_posr->pos[2]); | ||
819 | // } | ||
820 | |||
821 | // Take the equation Down to 1D | ||
822 | eq3[0]-=(cvx->planes[(index*4)+m]*aoveram[0]); | ||
823 | eq3[1]-=(cvx->planes[(index*4)+m]*aoveram[1]); | ||
824 | eq3[2]-=(cvx->planes[(index*4)+m]*aoveram[2]); | ||
825 | eq3[3]-=(cvx->planes[(index*4)+m]*aoveram[3]); | ||
826 | if(eq3[n]>0) | ||
827 | { | ||
828 | max=dMIN(max,eq3[3]/eq3[n]); | ||
829 | } | ||
830 | else if(eq3[n]<0) | ||
831 | { | ||
832 | min=dMAX(min,eq3[3]/eq3[n]); | ||
833 | } | ||
834 | else | ||
835 | { | ||
836 | med=dMIN(med,eq3[3]); | ||
837 | } | ||
838 | } | ||
839 | } | ||
840 | if ((max<min)||(med<0)) | ||
841 | { | ||
842 | // if(!hit) fprintf(stdout,"((max<min)||(med<0)) ((%f<%f)||(%f<0))",max,min,med); | ||
843 | if(!hit) | ||
844 | { | ||
845 | dumpplanes(cvx1); | ||
846 | dumpplanes(cvx2); | ||
847 | } | ||
848 | //fprintf(stdout,"Planes %d %d\n",i,j); | ||
849 | return false; | ||
850 | |||
851 | } | ||
852 | // find the value for the solution in one dimension | ||
853 | solution[n] = (c1[n]>=0) ? max:min; | ||
854 | // lift to 2D | ||
855 | solution[m] = (eq2[3]-(eq2[n]*solution[n]))/eq2[m]; | ||
856 | // lift to 3D | ||
857 | solution[l] = (eq1[3]-(eq1[m]*solution[m]+ | ||
858 | eq1[n]*solution[n]))/eq1[l]; | ||
859 | } | ||
860 | } | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | return true; | ||
865 | } | ||
866 | |||
867 | /*! \brief A Support mapping function for convex shapes | ||
868 | \param dir direction to find the Support Point for | ||
869 | \param cvx convex object to find the support point for | ||
870 | \param out the support mapping in dir. | ||
871 | */ | ||
872 | inline void Support(dVector3 dir,dxConvex& cvx,dVector3 out) | ||
873 | { | ||
874 | unsigned int index = 0; | ||
875 | dVector3 point; | ||
876 | dMULTIPLY0_331 (point,cvx.final_posr->R,cvx.points); | ||
877 | point[0]+=cvx.final_posr->pos[0]; | ||
878 | point[1]+=cvx.final_posr->pos[1]; | ||
879 | point[2]+=cvx.final_posr->pos[2]; | ||
880 | |||
881 | dReal max = dDOT(point,dir); | ||
882 | dReal tmp; | ||
883 | for (unsigned int i = 1; i < cvx.pointcount; ++i) | ||
884 | { | ||
885 | dMULTIPLY0_331 (point,cvx.final_posr->R,cvx.points+(i*3)); | ||
886 | point[0]+=cvx.final_posr->pos[0]; | ||
887 | point[1]+=cvx.final_posr->pos[1]; | ||
888 | point[2]+=cvx.final_posr->pos[2]; | ||
889 | tmp = dDOT(point, dir); | ||
890 | if (tmp > max) | ||
891 | { | ||
892 | out[0]=point[0]; | ||
893 | out[1]=point[1]; | ||
894 | out[2]=point[2]; | ||
895 | max = tmp; | ||
896 | } | ||
897 | } | ||
898 | } | ||
899 | |||
900 | inline void ComputeInterval(dxConvex& cvx,dVector4 axis,dReal& min,dReal& max) | ||
901 | { | ||
902 | dVector3 point; | ||
903 | dReal value; | ||
904 | //fprintf(stdout,"Compute Interval Axis %f,%f,%f\n",axis[0],axis[1],axis[2]); | ||
905 | dMULTIPLY0_331 (point,cvx.final_posr->R,cvx.points); | ||
906 | //fprintf(stdout,"initial point %f,%f,%f\n",point[0],point[1],point[2]); | ||
907 | point[0]+=cvx.final_posr->pos[0]; | ||
908 | point[1]+=cvx.final_posr->pos[1]; | ||
909 | point[2]+=cvx.final_posr->pos[2]; | ||
910 | max = min = dDOT(axis,cvx.points); | ||
911 | for (unsigned int i = 1; i < cvx.pointcount; ++i) | ||
912 | { | ||
913 | dMULTIPLY0_331 (point,cvx.final_posr->R,cvx.points+(i*3)); | ||
914 | point[0]+=cvx.final_posr->pos[0]; | ||
915 | point[1]+=cvx.final_posr->pos[1]; | ||
916 | point[2]+=cvx.final_posr->pos[2]; | ||
917 | value=dDOT(axis,point); | ||
918 | if(value<min) | ||
919 | { | ||
920 | min=value; | ||
921 | } | ||
922 | else if(value>max) | ||
923 | { | ||
924 | max=value; | ||
925 | } | ||
926 | } | ||
927 | //fprintf(stdout,"Compute Interval Min Max %f,%f\n",min,max); | ||
928 | } | ||
929 | |||
930 | /*! \brief Does an axis separation test between the 2 convex shapes | ||
931 | using faces and edges */ | ||
932 | int TestConvexIntersection(dxConvex& cvx1,dxConvex& cvx2, int flags, | ||
933 | dContactGeom *contact, int skip) | ||
934 | { | ||
935 | dVector4 plane,savedplane; | ||
936 | dReal min1,max1,min2,max2,min_depth=-dInfinity; | ||
937 | dVector3 e1,e2,t; | ||
938 | int maxc = flags & NUMC_MASK; // this is causing a segfault | ||
939 | dIASSERT(maxc != 0); | ||
940 | dxConvex *g1,*g2; | ||
941 | unsigned int *pPoly; | ||
942 | dVector3 v; | ||
943 | // Test faces of cvx1 for separation | ||
944 | pPoly=cvx1.polygons; | ||
945 | for(unsigned int i=0;i<cvx1.planecount;++i) | ||
946 | { | ||
947 | // -- Apply Transforms -- | ||
948 | // Rotate | ||
949 | dMULTIPLY0_331(plane,cvx1.final_posr->R,cvx1.planes+(i*4)); | ||
950 | dNormalize3(plane); | ||
951 | // Translate | ||
952 | plane[3]= | ||
953 | (cvx1.planes[(i*4)+3])+ | ||
954 | ((plane[0] * cvx1.final_posr->pos[0]) + | ||
955 | (plane[1] * cvx1.final_posr->pos[1]) + | ||
956 | (plane[2] * cvx1.final_posr->pos[2])); | ||
957 | ComputeInterval(cvx1,plane,min1,max1); | ||
958 | ComputeInterval(cvx2,plane,min2,max2); | ||
959 | //fprintf(stdout,"width %f\n",max1-min1); | ||
960 | if(max2<min1 || max1<min2) return 0; | ||
961 | #if 1 | ||
962 | // this one ON works | ||
963 | else if ((max1>min2)&&(max1<max2)) | ||
964 | { | ||
965 | min_depth=max1-min2; | ||
966 | savedplane[0]=plane[0]; | ||
967 | savedplane[1]=plane[1]; | ||
968 | savedplane[2]=plane[2]; | ||
969 | savedplane[3]=plane[3]; | ||
970 | g1=&cvx2; // cvx2 moves | ||
971 | g2=&cvx1; | ||
972 | } | ||
973 | #endif | ||
974 | pPoly+=pPoly[0]+1; | ||
975 | } | ||
976 | // Test faces of cvx2 for separation | ||
977 | pPoly=cvx2.polygons; | ||
978 | for(unsigned int i=0;i<cvx2.planecount;++i) | ||
979 | { | ||
980 | // fprintf(stdout,"Poly verts %d\n",pPoly[0]); | ||
981 | // -- Apply Transforms -- | ||
982 | // Rotate | ||
983 | dMULTIPLY0_331(plane, | ||
984 | cvx2.final_posr->R, | ||
985 | cvx2.planes+(i*4)); | ||
986 | dNormalize3(plane); | ||
987 | // Translate | ||
988 | plane[3]= | ||
989 | (cvx2.planes[(i*4)+3])+ | ||
990 | ((plane[0] * cvx2.final_posr->pos[0]) + | ||
991 | (plane[1] * cvx2.final_posr->pos[1]) + | ||
992 | (plane[2] * cvx2.final_posr->pos[2])); | ||
993 | ComputeInterval(cvx2,plane,min1,max1); | ||
994 | ComputeInterval(cvx1,plane,min2,max2); | ||
995 | //fprintf(stdout,"width %f\n",max1-min1); | ||
996 | if(max2<min1 || max1<min2) return 0; | ||
997 | #if 1 | ||
998 | // this one ON does not work | ||
999 | else if ((max1>min2)&&(max1<max2)) | ||
1000 | { | ||
1001 | min_depth=max1-min2; | ||
1002 | savedplane[0]=plane[0]; | ||
1003 | savedplane[1]=plane[1]; | ||
1004 | savedplane[2]=plane[2]; | ||
1005 | savedplane[3]=plane[3]; | ||
1006 | g1=&cvx1; // cvx1 moves | ||
1007 | g2=&cvx2; | ||
1008 | } | ||
1009 | #endif | ||
1010 | pPoly+=pPoly[0]+1; | ||
1011 | } | ||
1012 | // Test cross products of pairs of edges | ||
1013 | for(std::set<edge>::iterator i = cvx1.edges.begin(); | ||
1014 | i!= cvx1.edges.end(); | ||
1015 | ++i) | ||
1016 | { | ||
1017 | // we only need to apply rotation here | ||
1018 | dMULTIPLY0_331 (t,cvx1.final_posr->R,cvx1.points+(i->first*3)); | ||
1019 | dMULTIPLY0_331 (e1,cvx1.final_posr->R,cvx1.points+(i->second*3)); | ||
1020 | e1[0]-=t[0]; | ||
1021 | e1[1]-=t[1]; | ||
1022 | e1[2]-=t[2]; | ||
1023 | for(std::set<edge>::iterator j = cvx2.edges.begin(); | ||
1024 | j!= cvx2.edges.end(); | ||
1025 | ++j) | ||
1026 | { | ||
1027 | // we only need to apply rotation here | ||
1028 | dMULTIPLY0_331 (t,cvx2.final_posr->R,cvx2.points+(j->first*3)); | ||
1029 | dMULTIPLY0_331 (e2,cvx2.final_posr->R,cvx2.points+(j->second*3)); | ||
1030 | e2[0]-=t[0]; | ||
1031 | e2[1]-=t[1]; | ||
1032 | e2[2]-=t[2]; | ||
1033 | dCROSS(plane,=,e1,e2); | ||
1034 | plane[3]=0; | ||
1035 | ComputeInterval(cvx1,plane,min1,max1); | ||
1036 | ComputeInterval(cvx2,plane,min2,max2); | ||
1037 | if(max2<min1 || max1 < min2) return 0; | ||
1038 | } | ||
1039 | } | ||
1040 | /* -- uncomment if you are debugging | ||
1041 | static int cvxhit=0; | ||
1042 | if(cvxhit<2) | ||
1043 | fprintf(stdout,"Plane: %f,%f,%f,%f\n", | ||
1044 | (double)savedplane[0], | ||
1045 | (double)savedplane[1], | ||
1046 | (double)savedplane[2], | ||
1047 | (double)savedplane[3]); | ||
1048 | */ | ||
1049 | // If we get here, there was a collision | ||
1050 | int contacts=0; | ||
1051 | for(unsigned int i=0;i<g1->pointcount;++i) | ||
1052 | { | ||
1053 | dMULTIPLY0_331 (v,g1->final_posr->R,&g1->points[(i*3)]); | ||
1054 | dVector3Add(g1->final_posr->pos, v, v); | ||
1055 | |||
1056 | dReal distance = dVector3Dot(savedplane, v) - savedplane[3]; // Ax + By + Cz - D | ||
1057 | if(distance<0) | ||
1058 | { | ||
1059 | dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip); | ||
1060 | dVector3Copy(savedplane, target->normal); | ||
1061 | dVector3Copy(v, target->pos); | ||
1062 | target->depth = -distance; | ||
1063 | target->g1 = g1; | ||
1064 | target->g2 = g2; | ||
1065 | /* -- uncomment if you are debugging | ||
1066 | if(cvxhit<2) | ||
1067 | fprintf(stdout,"Contact: %f,%f,%f depth %f\n", | ||
1068 | (double)target->pos[0], | ||
1069 | (double)target->pos[1], | ||
1070 | (double)target->pos[2], | ||
1071 | (double)target->depth); | ||
1072 | */ | ||
1073 | contacts++; | ||
1074 | if (contacts==maxc) break; | ||
1075 | } | ||
1076 | } | ||
1077 | /* -- uncomment if you are debugging | ||
1078 | cvxhit++; | ||
1079 | */ | ||
1080 | |||
1081 | return contacts; | ||
1082 | } | ||
1083 | |||
1084 | int dCollideConvexConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
1085 | dContactGeom *contact, int skip) | ||
1086 | { | ||
1087 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
1088 | dIASSERT (o1->type == dConvexClass); | ||
1089 | dIASSERT (o2->type == dConvexClass); | ||
1090 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1091 | |||
1092 | // if(!hit) fprintf(stdout,"dCollideConvexConvex\n"); | ||
1093 | dxConvex *Convex1 = (dxConvex*) o1; | ||
1094 | dxConvex *Convex2 = (dxConvex*) o2; | ||
1095 | int contacts; | ||
1096 | if(contacts=TestConvexIntersection(*Convex1,*Convex2,flags, | ||
1097 | contact,skip)) | ||
1098 | { | ||
1099 | //fprintf(stdout,"We have a Hit!\n"); | ||
1100 | } | ||
1101 | return contacts; | ||
1102 | } | ||
1103 | |||
1104 | #if 0 | ||
1105 | |||
1106 | int dCollideRayConvex (dxGeom *o1, dxGeom *o2, int flags, | ||
1107 | dContactGeom *contact, int skip) | ||
1108 | { | ||
1109 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
1110 | dIASSERT( o1->type == dRayClass ); | ||
1111 | dIASSERT( o2->type == dConvexClass ); | ||
1112 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1113 | |||
1114 | dxRay* ray = (dxRay*) o1; | ||
1115 | dxConvex* convex = (dxConvex*) o2; | ||
1116 | dVector3 origin,destination,contactpoint,out; | ||
1117 | dReal depth; | ||
1118 | dVector4 plane; | ||
1119 | unsigned int *pPoly=convex->polygons; | ||
1120 | // Calculate ray origin and destination | ||
1121 | destination[0]=0; | ||
1122 | destination[1]=0; | ||
1123 | destination[2]= ray->length; | ||
1124 | // -- Rotate -- | ||
1125 | dMULTIPLY0_331(destination,ray->final_posr->R,destination); | ||
1126 | origin[0]=ray->final_posr->pos[0]; | ||
1127 | origin[1]=ray->final_posr->pos[1]; | ||
1128 | origin[2]=ray->final_posr->pos[2]; | ||
1129 | destination[0]+=origin[0]; | ||
1130 | destination[1]+=origin[1]; | ||
1131 | destination[2]+=origin[2]; | ||
1132 | for(int i=0;i<convex->planecount;++i) | ||
1133 | { | ||
1134 | // Rotate | ||
1135 | dMULTIPLY0_331(plane,convex->final_posr->R,convex->planes+(i*4)); | ||
1136 | // Translate | ||
1137 | plane[3]= | ||
1138 | (convex->planes[(i*4)+3])+ | ||
1139 | ((plane[0] * convex->final_posr->pos[0]) + | ||
1140 | (plane[1] * convex->final_posr->pos[1]) + | ||
1141 | (plane[2] * convex->final_posr->pos[2])); | ||
1142 | if(IntersectSegmentPlane(origin, | ||
1143 | destination, | ||
1144 | plane, | ||
1145 | depth, | ||
1146 | contactpoint)) | ||
1147 | { | ||
1148 | if(IsPointInPolygon(contactpoint,pPoly,convex,out)) | ||
1149 | { | ||
1150 | contact->pos[0]=contactpoint[0]; | ||
1151 | contact->pos[1]=contactpoint[1]; | ||
1152 | contact->pos[2]=contactpoint[2]; | ||
1153 | contact->normal[0]=plane[0]; | ||
1154 | contact->normal[1]=plane[1]; | ||
1155 | contact->normal[2]=plane[2]; | ||
1156 | contact->depth=depth; | ||
1157 | contact->g1 = ray; | ||
1158 | contact->g2 = convex; | ||
1159 | return 1; | ||
1160 | } | ||
1161 | } | ||
1162 | pPoly+=pPoly[0]+1; | ||
1163 | } | ||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | #else | ||
1168 | |||
1169 | // Ray - Convex collider by David Walters, June 2006 | ||
1170 | int dCollideRayConvex( dxGeom *o1, dxGeom *o2, | ||
1171 | int flags, dContactGeom *contact, int skip ) | ||
1172 | { | ||
1173 | dIASSERT( skip >= (int)sizeof(dContactGeom) ); | ||
1174 | dIASSERT( o1->type == dRayClass ); | ||
1175 | dIASSERT( o2->type == dConvexClass ); | ||
1176 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1177 | |||
1178 | dxRay* ray = (dxRay*) o1; | ||
1179 | dxConvex* convex = (dxConvex*) o2; | ||
1180 | |||
1181 | contact->g1 = ray; | ||
1182 | contact->g2 = convex; | ||
1183 | |||
1184 | dReal alpha, beta, nsign; | ||
1185 | int flag; | ||
1186 | |||
1187 | // | ||
1188 | // Compute some useful info | ||
1189 | // | ||
1190 | |||
1191 | flag = 0; // Assume start point is behind all planes. | ||
1192 | |||
1193 | for ( unsigned int i = 0; i < convex->planecount; ++i ) | ||
1194 | { | ||
1195 | // Alias this plane. | ||
1196 | dReal* plane = convex->planes + ( i * 4 ); | ||
1197 | |||
1198 | // If alpha >= 0 then start point is outside of plane. | ||
1199 | alpha = dDOT( plane, ray->final_posr->pos ) - plane[3]; | ||
1200 | |||
1201 | // If any alpha is positive, then | ||
1202 | // the ray start is _outside_ of the hull | ||
1203 | if ( alpha >= 0 ) | ||
1204 | { | ||
1205 | flag = 1; | ||
1206 | break; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | // If the ray starts inside the convex hull, then everything is flipped. | ||
1211 | nsign = ( flag ) ? REAL( 1.0 ) : REAL( -1.0 ); | ||
1212 | |||
1213 | |||
1214 | // | ||
1215 | // Find closest contact point | ||
1216 | // | ||
1217 | |||
1218 | // Assume no contacts. | ||
1219 | contact->depth = dInfinity; | ||
1220 | |||
1221 | for ( unsigned int i = 0; i < convex->planecount; ++i ) | ||
1222 | { | ||
1223 | // Alias this plane. | ||
1224 | dReal* plane = convex->planes + ( i * 4 ); | ||
1225 | |||
1226 | // If alpha >= 0 then point is outside of plane. | ||
1227 | alpha = nsign * ( dDOT( plane, ray->final_posr->pos ) - plane[3] ); | ||
1228 | |||
1229 | // Compute [ plane-normal DOT ray-normal ], (/flip) | ||
1230 | beta = dDOT13( plane, ray->final_posr->R+2 ) * nsign; | ||
1231 | |||
1232 | // Ray is pointing at the plane? ( beta < 0 ) | ||
1233 | // Ray start to plane is within maximum ray length? | ||
1234 | // Ray start to plane is closer than the current best distance? | ||
1235 | if ( beta < -dEpsilon && | ||
1236 | alpha >= 0 && alpha <= ray->length && | ||
1237 | alpha < contact->depth ) | ||
1238 | { | ||
1239 | // Compute contact point on convex hull surface. | ||
1240 | contact->pos[0] = ray->final_posr->pos[0] + alpha * ray->final_posr->R[0*4+2]; | ||
1241 | contact->pos[1] = ray->final_posr->pos[1] + alpha * ray->final_posr->R[1*4+2]; | ||
1242 | contact->pos[2] = ray->final_posr->pos[2] + alpha * ray->final_posr->R[2*4+2]; | ||
1243 | |||
1244 | flag = 0; | ||
1245 | |||
1246 | // For all _other_ planes. | ||
1247 | for ( unsigned int j = 0; j < convex->planecount; ++j ) | ||
1248 | { | ||
1249 | if ( i == j ) | ||
1250 | continue; // Skip self. | ||
1251 | |||
1252 | // Alias this plane. | ||
1253 | dReal* planej = convex->planes + ( j * 4 ); | ||
1254 | |||
1255 | // If beta >= 0 then start is outside of plane. | ||
1256 | beta = dDOT( planej, contact->pos ) - plane[3]; | ||
1257 | |||
1258 | // If any beta is positive, then the contact point | ||
1259 | // is not on the surface of the convex hull - it's just | ||
1260 | // intersecting some part of its infinite extent. | ||
1261 | if ( beta > dEpsilon ) | ||
1262 | { | ||
1263 | flag = 1; | ||
1264 | break; | ||
1265 | } | ||
1266 | } | ||
1267 | |||
1268 | // Contact point isn't outside hull's surface? then it's a good contact! | ||
1269 | if ( flag == 0 ) | ||
1270 | { | ||
1271 | // Store the contact normal, possibly flipped. | ||
1272 | contact->normal[0] = nsign * plane[0]; | ||
1273 | contact->normal[1] = nsign * plane[1]; | ||
1274 | contact->normal[2] = nsign * plane[2]; | ||
1275 | |||
1276 | // Store depth | ||
1277 | contact->depth = alpha; | ||
1278 | |||
1279 | if ((flags & CONTACTS_UNIMPORTANT) && contact->depth <= ray->length ) | ||
1280 | { | ||
1281 | // Break on any contact if contacts are not important | ||
1282 | break; | ||
1283 | } | ||
1284 | } | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | // Contact? | ||
1289 | return ( contact->depth <= ray->length ); | ||
1290 | } | ||
1291 | |||
1292 | #endif | ||
1293 | |||
1294 | //<-- Convex Collision | ||
diff --git a/libraries/ode-0.9\/ode/src/cylinder.cpp b/libraries/ode-0.9\/ode/src/cylinder.cpp new file mode 100755 index 0000000..39a6cf3 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/cylinder.cpp | |||
@@ -0,0 +1,100 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | // flat cylinder public API | ||
46 | |||
47 | dxCylinder::dxCylinder (dSpaceID space, dReal _radius, dReal _length) : | ||
48 | dxGeom (space,1) | ||
49 | { | ||
50 | dAASSERT (_radius > 0 && _length > 0); | ||
51 | type = dCylinderClass; | ||
52 | radius = _radius; | ||
53 | lz = _length; | ||
54 | } | ||
55 | |||
56 | |||
57 | void dxCylinder::computeAABB() | ||
58 | { | ||
59 | const dMatrix3& R = final_posr->R; | ||
60 | const dVector3& pos = final_posr->pos; | ||
61 | |||
62 | dReal xrange = dFabs (R[0] * radius) + dFabs (R[1] * radius) + REAL(0.5)* dFabs (R[2] * | ||
63 | lz); | ||
64 | dReal yrange = dFabs (R[4] * radius) + dFabs (R[5] * radius) + REAL(0.5)* dFabs (R[6] * | ||
65 | lz); | ||
66 | dReal zrange = dFabs (R[8] * radius) + dFabs (R[9] * radius) + REAL(0.5)* dFabs (R[10] * | ||
67 | lz); | ||
68 | aabb[0] = pos[0] - xrange; | ||
69 | aabb[1] = pos[0] + xrange; | ||
70 | aabb[2] = pos[1] - yrange; | ||
71 | aabb[3] = pos[1] + yrange; | ||
72 | aabb[4] = pos[2] - zrange; | ||
73 | aabb[5] = pos[2] + zrange; | ||
74 | } | ||
75 | |||
76 | |||
77 | dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length) | ||
78 | { | ||
79 | return new dxCylinder (space,radius,length); | ||
80 | } | ||
81 | |||
82 | void dGeomCylinderSetParams (dGeomID cylinder, dReal radius, dReal length) | ||
83 | { | ||
84 | dUASSERT (cylinder && cylinder->type == dCylinderClass,"argument not a ccylinder"); | ||
85 | dAASSERT (radius > 0 && length > 0); | ||
86 | dxCylinder *c = (dxCylinder*) cylinder; | ||
87 | c->radius = radius; | ||
88 | c->lz = length; | ||
89 | dGeomMoved (cylinder); | ||
90 | } | ||
91 | |||
92 | void dGeomCylinderGetParams (dGeomID cylinder, dReal *radius, dReal *length) | ||
93 | { | ||
94 | dUASSERT (cylinder && cylinder->type == dCylinderClass,"argument not a ccylinder"); | ||
95 | dxCylinder *c = (dxCylinder*) cylinder; | ||
96 | *radius = c->radius; | ||
97 | *length = c->lz; | ||
98 | } | ||
99 | |||
100 | |||
diff --git a/libraries/ode-0.9\/ode/src/error.cpp b/libraries/ode-0.9\/ode/src/error.cpp new file mode 100755 index 0000000..9b33db5 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/error.cpp | |||
@@ -0,0 +1,172 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/error.h> | ||
25 | |||
26 | |||
27 | static dMessageFunction *error_function = 0; | ||
28 | static dMessageFunction *debug_function = 0; | ||
29 | static dMessageFunction *message_function = 0; | ||
30 | |||
31 | |||
32 | extern "C" void dSetErrorHandler (dMessageFunction *fn) | ||
33 | { | ||
34 | error_function = fn; | ||
35 | } | ||
36 | |||
37 | |||
38 | extern "C" void dSetDebugHandler (dMessageFunction *fn) | ||
39 | { | ||
40 | debug_function = fn; | ||
41 | } | ||
42 | |||
43 | |||
44 | extern "C" void dSetMessageHandler (dMessageFunction *fn) | ||
45 | { | ||
46 | message_function = fn; | ||
47 | } | ||
48 | |||
49 | |||
50 | extern "C" dMessageFunction *dGetErrorHandler() | ||
51 | { | ||
52 | return error_function; | ||
53 | } | ||
54 | |||
55 | |||
56 | extern "C" dMessageFunction *dGetDebugHandler() | ||
57 | { | ||
58 | return debug_function; | ||
59 | } | ||
60 | |||
61 | |||
62 | extern "C" dMessageFunction *dGetMessageHandler() | ||
63 | { | ||
64 | return message_function; | ||
65 | } | ||
66 | |||
67 | |||
68 | static void printMessage (int num, const char *msg1, const char *msg2, | ||
69 | va_list ap) | ||
70 | { | ||
71 | fflush (stderr); | ||
72 | fflush (stdout); | ||
73 | if (num) fprintf (stderr,"\n%s %d: ",msg1,num); | ||
74 | else fprintf (stderr,"\n%s: ",msg1); | ||
75 | vfprintf (stderr,msg2,ap); | ||
76 | fprintf (stderr,"\n"); | ||
77 | fflush (stderr); | ||
78 | } | ||
79 | |||
80 | //**************************************************************************** | ||
81 | // unix | ||
82 | |||
83 | #ifndef WIN32 | ||
84 | |||
85 | extern "C" void dError (int num, const char *msg, ...) | ||
86 | { | ||
87 | va_list ap; | ||
88 | va_start (ap,msg); | ||
89 | if (error_function) error_function (num,msg,ap); | ||
90 | else printMessage (num,"ODE Error",msg,ap); | ||
91 | exit (1); | ||
92 | } | ||
93 | |||
94 | |||
95 | extern "C" void dDebug (int num, const char *msg, ...) | ||
96 | { | ||
97 | va_list ap; | ||
98 | va_start (ap,msg); | ||
99 | if (debug_function) debug_function (num,msg,ap); | ||
100 | else printMessage (num,"ODE INTERNAL ERROR",msg,ap); | ||
101 | // *((char *)0) = 0; ... commit SEGVicide | ||
102 | abort(); | ||
103 | } | ||
104 | |||
105 | |||
106 | extern "C" void dMessage (int num, const char *msg, ...) | ||
107 | { | ||
108 | va_list ap; | ||
109 | va_start (ap,msg); | ||
110 | if (message_function) message_function (num,msg,ap); | ||
111 | else printMessage (num,"ODE Message",msg,ap); | ||
112 | } | ||
113 | |||
114 | #endif | ||
115 | |||
116 | //**************************************************************************** | ||
117 | // windows | ||
118 | |||
119 | #ifdef WIN32 | ||
120 | |||
121 | // isn't cygwin annoying! | ||
122 | #ifdef CYGWIN | ||
123 | #define _snprintf snprintf | ||
124 | #define _vsnprintf vsnprintf | ||
125 | #endif | ||
126 | |||
127 | |||
128 | #include "windows.h" | ||
129 | |||
130 | |||
131 | extern "C" void dError (int num, const char *msg, ...) | ||
132 | { | ||
133 | va_list ap; | ||
134 | va_start (ap,msg); | ||
135 | if (error_function) error_function (num,msg,ap); | ||
136 | else { | ||
137 | char s[1000],title[100]; | ||
138 | _snprintf (title,sizeof(title),"ODE Error %d",num); | ||
139 | _vsnprintf (s,sizeof(s),msg,ap); | ||
140 | s[sizeof(s)-1] = 0; | ||
141 | MessageBox(0,s,title,MB_OK | MB_ICONWARNING); | ||
142 | } | ||
143 | exit (1); | ||
144 | } | ||
145 | |||
146 | |||
147 | extern "C" void dDebug (int num, const char *msg, ...) | ||
148 | { | ||
149 | va_list ap; | ||
150 | va_start (ap,msg); | ||
151 | if (debug_function) debug_function (num,msg,ap); | ||
152 | else { | ||
153 | char s[1000],title[100]; | ||
154 | _snprintf (title,sizeof(title),"ODE INTERNAL ERROR %d",num); | ||
155 | _vsnprintf (s,sizeof(s),msg,ap); | ||
156 | s[sizeof(s)-1] = 0; | ||
157 | MessageBox(0,s,title,MB_OK | MB_ICONSTOP); | ||
158 | } | ||
159 | abort(); | ||
160 | } | ||
161 | |||
162 | |||
163 | extern "C" void dMessage (int num, const char *msg, ...) | ||
164 | { | ||
165 | va_list ap; | ||
166 | va_start (ap,msg); | ||
167 | if (message_function) message_function (num,msg,ap); | ||
168 | else printMessage (num,"ODE Message",msg,ap); | ||
169 | } | ||
170 | |||
171 | |||
172 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/export-dif.cpp b/libraries/ode-0.9\/ode/src/export-dif.cpp new file mode 100755 index 0000000..577d3e1 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/export-dif.cpp | |||
@@ -0,0 +1,568 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | * Export a DIF (Dynamics Interchange Format) file. | ||
25 | */ | ||
26 | |||
27 | |||
28 | // @@@ TODO: | ||
29 | // * export all spaces, and geoms in spaces, not just ones attached to bodies | ||
30 | // (separate export function?) | ||
31 | // * say the space each geom is in, so reader can construct space heirarchy | ||
32 | // * limot --> separate out into limits and motors? | ||
33 | // * make sure ODE-specific parameters divided out | ||
34 | |||
35 | |||
36 | #include "ode/ode.h" | ||
37 | #include "objects.h" | ||
38 | #include "joint.h" | ||
39 | #include "collision_kernel.h" | ||
40 | |||
41 | //*************************************************************************** | ||
42 | // utility | ||
43 | |||
44 | struct PrintingContext { | ||
45 | FILE *file; // file to write to | ||
46 | int precision; // digits of precision to print | ||
47 | int indent; // number of levels of indent | ||
48 | |||
49 | void printIndent(); | ||
50 | void printReal (dReal x); | ||
51 | void print (const char *name, int x); | ||
52 | void print (const char *name, dReal x); | ||
53 | void print (const char *name, const dReal *x, int n=3); | ||
54 | void print (const char *name, const char *x=0); | ||
55 | void printNonzero (const char *name, dReal x); | ||
56 | void printNonzero (const char *name, const dReal x[3]); | ||
57 | }; | ||
58 | |||
59 | |||
60 | void PrintingContext::printIndent() | ||
61 | { | ||
62 | for (int i=0; i<indent; i++) fputc ('\t',file); | ||
63 | } | ||
64 | |||
65 | |||
66 | void PrintingContext::print (const char *name, int x) | ||
67 | { | ||
68 | printIndent(); | ||
69 | fprintf (file,"%s = %d,\n",name,x); | ||
70 | } | ||
71 | |||
72 | |||
73 | void PrintingContext::printReal (dReal x) | ||
74 | { | ||
75 | if (x==dInfinity) { | ||
76 | fprintf (file,"inf"); | ||
77 | } | ||
78 | else if (x==-dInfinity) { | ||
79 | fprintf (file,"-inf"); | ||
80 | } | ||
81 | else { | ||
82 | fprintf (file,"%.*g",precision,x); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | |||
87 | void PrintingContext::print (const char *name, dReal x) | ||
88 | { | ||
89 | printIndent(); | ||
90 | fprintf (file,"%s = ",name); | ||
91 | printReal (x); | ||
92 | fprintf (file,",\n"); | ||
93 | } | ||
94 | |||
95 | |||
96 | void PrintingContext::print (const char *name, const dReal *x, int n) | ||
97 | { | ||
98 | printIndent(); | ||
99 | fprintf (file,"%s = {",name); | ||
100 | for (int i=0; i<n; i++) { | ||
101 | printReal (x[i]); | ||
102 | if (i < n-1) fputc (',',file); | ||
103 | } | ||
104 | fprintf (file,"},\n"); | ||
105 | } | ||
106 | |||
107 | |||
108 | void PrintingContext::print (const char *name, const char *x) | ||
109 | { | ||
110 | printIndent(); | ||
111 | if (x) { | ||
112 | fprintf (file,"%s = \"%s\",\n",name,x); | ||
113 | } | ||
114 | else { | ||
115 | fprintf (file,"%s\n",name); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | |||
120 | void PrintingContext::printNonzero (const char *name, dReal x) | ||
121 | { | ||
122 | if (x != 0) print (name,x); | ||
123 | } | ||
124 | |||
125 | |||
126 | void PrintingContext::printNonzero (const char *name, const dReal x[3]) | ||
127 | { | ||
128 | if (x[0] != 0 && x[1] != 0 && x[2] != 0) print (name,x); | ||
129 | } | ||
130 | |||
131 | //*************************************************************************** | ||
132 | // joints | ||
133 | |||
134 | |||
135 | static void printLimot (PrintingContext &c, dxJointLimitMotor &limot, int num) | ||
136 | { | ||
137 | if (num >= 0) { | ||
138 | c.printIndent(); | ||
139 | fprintf (c.file,"limit%d = {\n",num); | ||
140 | } | ||
141 | else { | ||
142 | c.print ("limit = {"); | ||
143 | } | ||
144 | c.indent++; | ||
145 | c.print ("low_stop",limot.lostop); | ||
146 | c.print ("high_stop",limot.histop); | ||
147 | c.printNonzero ("bounce",limot.bounce); | ||
148 | c.print ("ODE = {"); | ||
149 | c.indent++; | ||
150 | c.printNonzero ("stop_erp",limot.stop_erp); | ||
151 | c.printNonzero ("stop_cfm",limot.stop_cfm); | ||
152 | c.indent--; | ||
153 | c.print ("},"); | ||
154 | c.indent--; | ||
155 | c.print ("},"); | ||
156 | |||
157 | if (num >= 0) { | ||
158 | c.printIndent(); | ||
159 | fprintf (c.file,"motor%d = {\n",num); | ||
160 | } | ||
161 | else { | ||
162 | c.print ("motor = {"); | ||
163 | } | ||
164 | c.indent++; | ||
165 | c.printNonzero ("vel",limot.vel); | ||
166 | c.printNonzero ("fmax",limot.fmax); | ||
167 | c.print ("ODE = {"); | ||
168 | c.indent++; | ||
169 | c.printNonzero ("fudge_factor",limot.fudge_factor); | ||
170 | c.printNonzero ("normal_cfm",limot.normal_cfm); | ||
171 | c.indent--; | ||
172 | c.print ("},"); | ||
173 | c.indent--; | ||
174 | c.print ("},"); | ||
175 | } | ||
176 | |||
177 | |||
178 | static const char *getJointName (dxJoint *j) | ||
179 | { | ||
180 | switch (j->vtable->typenum) { | ||
181 | case dJointTypeBall: return "ball"; | ||
182 | case dJointTypeHinge: return "hinge"; | ||
183 | case dJointTypeSlider: return "slider"; | ||
184 | case dJointTypeContact: return "contact"; | ||
185 | case dJointTypeUniversal: return "universal"; | ||
186 | case dJointTypeHinge2: return "ODE_hinge2"; | ||
187 | case dJointTypeFixed: return "fixed"; | ||
188 | case dJointTypeNull: return "null"; | ||
189 | case dJointTypeAMotor: return "ODE_angular_motor"; | ||
190 | case dJointTypeLMotor: return "ODE_linear_motor"; | ||
191 | case dJointTypePR: return "PR"; | ||
192 | } | ||
193 | return "unknown"; | ||
194 | } | ||
195 | |||
196 | |||
197 | static void printBall (PrintingContext &c, dxJoint *j) | ||
198 | { | ||
199 | dxJointBall *b = (dxJointBall*) j; | ||
200 | c.print ("anchor1",b->anchor1); | ||
201 | c.print ("anchor2",b->anchor2); | ||
202 | } | ||
203 | |||
204 | |||
205 | static void printHinge (PrintingContext &c, dxJoint *j) | ||
206 | { | ||
207 | dxJointHinge *h = (dxJointHinge*) j; | ||
208 | c.print ("anchor1",h->anchor1); | ||
209 | c.print ("anchor2",h->anchor2); | ||
210 | c.print ("axis1",h->axis1); | ||
211 | c.print ("axis2",h->axis2); | ||
212 | c.print ("qrel",h->qrel,4); | ||
213 | printLimot (c,h->limot,-1); | ||
214 | } | ||
215 | |||
216 | |||
217 | static void printSlider (PrintingContext &c, dxJoint *j) | ||
218 | { | ||
219 | dxJointSlider *s = (dxJointSlider*) j; | ||
220 | c.print ("axis1",s->axis1); | ||
221 | c.print ("qrel",s->qrel,4); | ||
222 | c.print ("offset",s->offset); | ||
223 | printLimot (c,s->limot,-1); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void printContact (PrintingContext &c, dxJoint *j) | ||
228 | { | ||
229 | dxJointContact *ct = (dxJointContact*) j; | ||
230 | int mode = ct->contact.surface.mode; | ||
231 | c.print ("pos",ct->contact.geom.pos); | ||
232 | c.print ("normal",ct->contact.geom.normal); | ||
233 | c.print ("depth",ct->contact.geom.depth); | ||
234 | //@@@ may want to write the geoms g1 and g2 that are involved, for debugging. | ||
235 | // to do this we must have written out all geoms in all spaces, not just | ||
236 | // geoms that are attached to bodies. | ||
237 | c.print ("mu",ct->contact.surface.mu); | ||
238 | if (mode & dContactMu2) c.print ("mu2",ct->contact.surface.mu2); | ||
239 | if (mode & dContactBounce) c.print ("bounce",ct->contact.surface.bounce); | ||
240 | if (mode & dContactBounce) c.print ("bounce_vel",ct->contact.surface.bounce_vel); | ||
241 | if (mode & dContactSoftERP) c.print ("soft_ERP",ct->contact.surface.soft_erp); | ||
242 | if (mode & dContactSoftCFM) c.print ("soft_CFM",ct->contact.surface.soft_cfm); | ||
243 | if (mode & dContactMotion1) c.print ("motion1",ct->contact.surface.motion1); | ||
244 | if (mode & dContactMotion2) c.print ("motion2",ct->contact.surface.motion2); | ||
245 | if (mode & dContactSlip1) c.print ("slip1",ct->contact.surface.slip1); | ||
246 | if (mode & dContactSlip2) c.print ("slip2",ct->contact.surface.slip2); | ||
247 | int fa = 0; // friction approximation code | ||
248 | if (mode & dContactApprox1_1) fa |= 1; | ||
249 | if (mode & dContactApprox1_2) fa |= 2; | ||
250 | if (fa) c.print ("friction_approximation",fa); | ||
251 | if (mode & dContactFDir1) c.print ("fdir1",ct->contact.fdir1); | ||
252 | } | ||
253 | |||
254 | |||
255 | static void printUniversal (PrintingContext &c, dxJoint *j) | ||
256 | { | ||
257 | dxJointUniversal *u = (dxJointUniversal*) j; | ||
258 | c.print ("anchor1",u->anchor1); | ||
259 | c.print ("anchor2",u->anchor2); | ||
260 | c.print ("axis1",u->axis1); | ||
261 | c.print ("axis2",u->axis2); | ||
262 | c.print ("qrel1",u->qrel1,4); | ||
263 | c.print ("qrel2",u->qrel2,4); | ||
264 | printLimot (c,u->limot1,1); | ||
265 | printLimot (c,u->limot2,2); | ||
266 | } | ||
267 | |||
268 | |||
269 | static void printHinge2 (PrintingContext &c, dxJoint *j) | ||
270 | { | ||
271 | dxJointHinge2 *h = (dxJointHinge2*) j; | ||
272 | c.print ("anchor1",h->anchor1); | ||
273 | c.print ("anchor2",h->anchor2); | ||
274 | c.print ("axis1",h->axis1); | ||
275 | c.print ("axis2",h->axis2); | ||
276 | c.print ("v1",h->v1); //@@@ much better to write out 'qrel' here, if it's available | ||
277 | c.print ("v2",h->v2); | ||
278 | c.print ("susp_erp",h->susp_erp); | ||
279 | c.print ("susp_cfm",h->susp_cfm); | ||
280 | printLimot (c,h->limot1,1); | ||
281 | printLimot (c,h->limot2,2); | ||
282 | } | ||
283 | |||
284 | static void printPR (PrintingContext &c, dxJoint *j) | ||
285 | { | ||
286 | dxJointPR *pr = (dxJointPR*) j; | ||
287 | c.print ("anchor2",pr->anchor2); | ||
288 | c.print ("axisR1",pr->axisR1); | ||
289 | c.print ("axisR2",pr->axisR2); | ||
290 | c.print ("axisP1",pr->axisP1); | ||
291 | c.print ("qrel",pr->qrel,4); | ||
292 | c.print ("offset",pr->offset); | ||
293 | printLimot (c,pr->limotP,1); | ||
294 | printLimot (c,pr->limotR,2); | ||
295 | } | ||
296 | |||
297 | |||
298 | static void printFixed (PrintingContext &c, dxJoint *j) | ||
299 | { | ||
300 | dxJointFixed *f = (dxJointFixed*) j; | ||
301 | c.print ("qrel",f->qrel); | ||
302 | c.print ("offset",f->offset); | ||
303 | } | ||
304 | |||
305 | static void printLMotor (PrintingContext &c, dxJoint *j) | ||
306 | { | ||
307 | dxJointLMotor *a = (dxJointLMotor*) j; | ||
308 | c.print("num", a->num); | ||
309 | c.printIndent(); | ||
310 | fprintf (c.file,"rel = {%d,%d,%d},\n",a->rel[0],a->rel[1],a->rel[2]); | ||
311 | c.print ("axis1",a->axis[0]); | ||
312 | c.print ("axis2",a->axis[1]); | ||
313 | c.print ("axis3",a->axis[2]); | ||
314 | for (int i=0; i<3; i++) printLimot (c,a->limot[i],i+1); | ||
315 | } | ||
316 | |||
317 | |||
318 | static void printAMotor (PrintingContext &c, dxJoint *j) | ||
319 | { | ||
320 | dxJointAMotor *a = (dxJointAMotor*) j; | ||
321 | c.print ("num",a->num); | ||
322 | c.print ("mode",a->mode); | ||
323 | c.printIndent(); | ||
324 | fprintf (c.file,"rel = {%d,%d,%d},\n",a->rel[0],a->rel[1],a->rel[2]); | ||
325 | c.print ("axis1",a->axis[0]); | ||
326 | c.print ("axis2",a->axis[1]); | ||
327 | c.print ("axis3",a->axis[2]); | ||
328 | for (int i=0; i<3; i++) printLimot (c,a->limot[i],i+1); | ||
329 | c.print ("angle1",a->angle[0]); | ||
330 | c.print ("angle2",a->angle[1]); | ||
331 | c.print ("angle3",a->angle[2]); | ||
332 | } | ||
333 | |||
334 | //*************************************************************************** | ||
335 | // geometry | ||
336 | |||
337 | static void printGeom (PrintingContext &c, dxGeom *g); | ||
338 | |||
339 | static void printSphere (PrintingContext &c, dxGeom *g) | ||
340 | { | ||
341 | c.print ("type","sphere"); | ||
342 | c.print ("radius",dGeomSphereGetRadius (g)); | ||
343 | } | ||
344 | |||
345 | |||
346 | static void printBox (PrintingContext &c, dxGeom *g) | ||
347 | { | ||
348 | dVector3 sides; | ||
349 | dGeomBoxGetLengths (g,sides); | ||
350 | c.print ("type","box"); | ||
351 | c.print ("sides",sides); | ||
352 | } | ||
353 | |||
354 | |||
355 | |||
356 | static void printCapsule (PrintingContext &c, dxGeom *g) | ||
357 | { | ||
358 | dReal radius,length; | ||
359 | dGeomCapsuleGetParams (g,&radius,&length); | ||
360 | c.print ("type","capsule"); | ||
361 | c.print ("radius",radius); | ||
362 | c.print ("length",length); | ||
363 | } | ||
364 | |||
365 | |||
366 | static void printPlane (PrintingContext &c, dxGeom *g) | ||
367 | { | ||
368 | dVector4 e; | ||
369 | dGeomPlaneGetParams (g,e); | ||
370 | c.print ("type","plane"); | ||
371 | c.print ("normal",e); | ||
372 | c.print ("d",e[3]); | ||
373 | } | ||
374 | |||
375 | |||
376 | |||
377 | static void printRay (PrintingContext &c, dxGeom *g) | ||
378 | { | ||
379 | dReal length = dGeomRayGetLength (g); | ||
380 | c.print ("type","ray"); | ||
381 | c.print ("length",length); | ||
382 | } | ||
383 | |||
384 | |||
385 | |||
386 | static void printGeomTransform (PrintingContext &c, dxGeom *g) | ||
387 | { | ||
388 | dxGeom *g2 = dGeomTransformGetGeom (g); | ||
389 | const dReal *pos = dGeomGetPosition (g2); | ||
390 | dQuaternion q; | ||
391 | dGeomGetQuaternion (g2,q); | ||
392 | c.print ("type","transform"); | ||
393 | c.print ("pos",pos); | ||
394 | c.print ("q",q,4); | ||
395 | c.print ("geometry = {"); | ||
396 | c.indent++; | ||
397 | printGeom (c,g2); | ||
398 | c.indent--; | ||
399 | c.print ("}"); | ||
400 | } | ||
401 | |||
402 | |||
403 | |||
404 | static void printTriMesh (PrintingContext &c, dxGeom *g) | ||
405 | { | ||
406 | c.print ("type","trimesh"); | ||
407 | //@@@ i don't think that the trimesh accessor functions are really | ||
408 | // sufficient to read out all the triangle data, and anyway we | ||
409 | // should have a method of not duplicating trimesh data that is | ||
410 | // shared. | ||
411 | } | ||
412 | |||
413 | |||
414 | static void printGeom (PrintingContext &c, dxGeom *g) | ||
415 | { | ||
416 | unsigned long category = dGeomGetCategoryBits (g); | ||
417 | if (category != (unsigned long)(~0)) { | ||
418 | c.printIndent(); | ||
419 | fprintf (c.file,"category_bits = %lu\n",category); | ||
420 | } | ||
421 | unsigned long collide = dGeomGetCollideBits (g); | ||
422 | if (collide != (unsigned long)(~0)) { | ||
423 | c.printIndent(); | ||
424 | fprintf (c.file,"collide_bits = %lu\n",collide); | ||
425 | } | ||
426 | if (!dGeomIsEnabled (g)) { | ||
427 | c.print ("disabled",1); | ||
428 | } | ||
429 | switch (g->type) { | ||
430 | case dSphereClass: printSphere (c,g); break; | ||
431 | case dBoxClass: printBox (c,g); break; | ||
432 | case dCapsuleClass: printCapsule (c,g); break; | ||
433 | case dPlaneClass: printPlane (c,g); break; | ||
434 | case dRayClass: printRay (c,g); break; | ||
435 | case dGeomTransformClass: printGeomTransform (c,g); break; | ||
436 | case dTriMeshClass: printTriMesh (c,g); break; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | //*************************************************************************** | ||
441 | // world | ||
442 | |||
443 | void dWorldExportDIF (dWorldID w, FILE *file, const char *prefix) | ||
444 | { | ||
445 | PrintingContext c; | ||
446 | c.file = file; | ||
447 | #if defined(dSINGLE) | ||
448 | c.precision = 7; | ||
449 | #else | ||
450 | c.precision = 15; | ||
451 | #endif | ||
452 | c.indent = 1; | ||
453 | |||
454 | fprintf (file,"-- Dynamics Interchange Format v0.1\n\n%sworld = dynamics.world {\n",prefix); | ||
455 | c.print ("gravity",w->gravity); | ||
456 | c.print ("ODE = {"); | ||
457 | c.indent++; | ||
458 | c.print ("ERP",w->global_erp); | ||
459 | c.print ("CFM",w->global_cfm); | ||
460 | c.print ("auto_disable = {"); | ||
461 | c.indent++; | ||
462 | c.print ("linear_threshold",w->adis.linear_average_threshold); | ||
463 | c.print ("angular_threshold",w->adis.angular_average_threshold); | ||
464 | c.print ("average_samples",(int)w->adis.average_samples); | ||
465 | c.print ("idle_time",w->adis.idle_time); | ||
466 | c.print ("idle_steps",w->adis.idle_steps); | ||
467 | fprintf (file,"\t\t},\n\t},\n}\n"); | ||
468 | c.indent -= 3; | ||
469 | |||
470 | // bodies | ||
471 | int num = 0; | ||
472 | fprintf (file,"%sbody = {}\n",prefix); | ||
473 | for (dxBody *b=w->firstbody; b; b=(dxBody*)b->next) { | ||
474 | b->tag = num; | ||
475 | fprintf (file,"%sbody[%d] = dynamics.body {\n\tworld = %sworld,\n",prefix,num,prefix); | ||
476 | c.indent++; | ||
477 | c.print ("pos",b->posr.pos); | ||
478 | c.print ("q",b->q,4); | ||
479 | c.print ("lvel",b->lvel); | ||
480 | c.print ("avel",b->avel); | ||
481 | c.print ("mass",b->mass.mass); | ||
482 | fprintf (file,"\tI = {{"); | ||
483 | for (int i=0; i<3; i++) { | ||
484 | for (int j=0; j<3; j++) { | ||
485 | c.printReal (b->mass.I[i*4+j]); | ||
486 | if (j < 2) fputc (',',file); | ||
487 | } | ||
488 | if (i < 2) fprintf (file,"},{"); | ||
489 | } | ||
490 | fprintf (file,"}},\n"); | ||
491 | c.printNonzero ("com",b->mass.c); | ||
492 | c.print ("ODE = {"); | ||
493 | c.indent++; | ||
494 | if (b->flags & dxBodyFlagFiniteRotation) c.print ("finite_rotation",1); | ||
495 | if (b->flags & dxBodyDisabled) c.print ("disabled",1); | ||
496 | if (b->flags & dxBodyNoGravity) c.print ("no_gravity",1); | ||
497 | if (b->flags & dxBodyAutoDisable) { | ||
498 | c.print ("auto_disable = {"); | ||
499 | c.indent++; | ||
500 | c.print ("linear_threshold",b->adis.linear_average_threshold); | ||
501 | c.print ("angular_threshold",b->adis.angular_average_threshold); | ||
502 | c.print ("average_samples",(int)b->adis.average_samples); | ||
503 | c.print ("idle_time",b->adis.idle_time); | ||
504 | c.print ("idle_steps",b->adis.idle_steps); | ||
505 | c.print ("time_left",b->adis_timeleft); | ||
506 | c.print ("steps_left",b->adis_stepsleft); | ||
507 | c.indent--; | ||
508 | c.print ("},"); | ||
509 | } | ||
510 | c.printNonzero ("facc",b->facc); | ||
511 | c.printNonzero ("tacc",b->tacc); | ||
512 | if (b->flags & dxBodyFlagFiniteRotationAxis) { | ||
513 | c.print ("finite_rotation_axis",b->finite_rot_axis); | ||
514 | } | ||
515 | c.indent--; | ||
516 | c.print ("},"); | ||
517 | if (b->geom) { | ||
518 | c.print ("geometry = {"); | ||
519 | c.indent++; | ||
520 | for (dxGeom *g=b->geom; g; g=g->body_next) { | ||
521 | c.print ("{"); | ||
522 | c.indent++; | ||
523 | printGeom (c,g); | ||
524 | c.indent--; | ||
525 | c.print ("},"); | ||
526 | } | ||
527 | c.indent--; | ||
528 | c.print ("},"); | ||
529 | } | ||
530 | c.indent--; | ||
531 | c.print ("}"); | ||
532 | num++; | ||
533 | } | ||
534 | |||
535 | // joints | ||
536 | num = 0; | ||
537 | fprintf (file,"%sjoint = {}\n",prefix); | ||
538 | for (dxJoint *j=w->firstjoint; j; j=(dxJoint*)j->next) { | ||
539 | c.indent++; | ||
540 | const char *name = getJointName (j); | ||
541 | fprintf (file, | ||
542 | "%sjoint[%d] = dynamics.%s_joint {\n" | ||
543 | "\tworld = %sworld,\n" | ||
544 | "\tbody = {" | ||
545 | ,prefix,num,name,prefix); | ||
546 | |||
547 | if ( j->node[0].body ) | ||
548 | fprintf (file,"%sbody[%d]",prefix,j->node[0].body->tag); | ||
549 | if ( j->node[1].body ) | ||
550 | fprintf (file,",%sbody[%d]",prefix,j->node[1].body->tag); | ||
551 | |||
552 | switch (j->vtable->typenum) { | ||
553 | case dJointTypeBall: printBall (c,j); break; | ||
554 | case dJointTypeHinge: printHinge (c,j); break; | ||
555 | case dJointTypeSlider: printSlider (c,j); break; | ||
556 | case dJointTypeContact: printContact (c,j); break; | ||
557 | case dJointTypeUniversal: printUniversal (c,j); break; | ||
558 | case dJointTypeHinge2: printHinge2 (c,j); break; | ||
559 | case dJointTypeFixed: printFixed (c,j); break; | ||
560 | case dJointTypeAMotor: printAMotor (c,j); break; | ||
561 | case dJointTypeLMotor: printLMotor (c,j); break; | ||
562 | case dJointTypePR: printPR (c,j); break; | ||
563 | } | ||
564 | c.indent--; | ||
565 | c.print ("}"); | ||
566 | num++; | ||
567 | } | ||
568 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/fastdot.c b/libraries/ode-0.9\/ode/src/fastdot.c new file mode 100755 index 0000000..148d2dd --- /dev/null +++ b/libraries/ode-0.9\/ode/src/fastdot.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* generated code, do not edit. */ | ||
2 | |||
3 | #include "ode/matrix.h" | ||
4 | |||
5 | |||
6 | dReal dDot (const dReal *a, const dReal *b, int n) | ||
7 | { | ||
8 | dReal p0,q0,m0,p1,q1,m1,sum; | ||
9 | sum = 0; | ||
10 | n -= 2; | ||
11 | while (n >= 0) { | ||
12 | p0 = a[0]; q0 = b[0]; | ||
13 | m0 = p0 * q0; | ||
14 | p1 = a[1]; q1 = b[1]; | ||
15 | m1 = p1 * q1; | ||
16 | sum += m0; | ||
17 | sum += m1; | ||
18 | a += 2; | ||
19 | b += 2; | ||
20 | n -= 2; | ||
21 | } | ||
22 | n += 2; | ||
23 | while (n > 0) { | ||
24 | sum += (*a) * (*b); | ||
25 | a++; | ||
26 | b++; | ||
27 | n--; | ||
28 | } | ||
29 | return sum; | ||
30 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/fastldlt.c b/libraries/ode-0.9\/ode/src/fastldlt.c new file mode 100755 index 0000000..df2ea6e --- /dev/null +++ b/libraries/ode-0.9\/ode/src/fastldlt.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /* generated code, do not edit. */ | ||
2 | |||
3 | #include "ode/matrix.h" | ||
4 | |||
5 | /* solve L*X=B, with B containing 1 right hand sides. | ||
6 | * L is an n*n lower triangular matrix with ones on the diagonal. | ||
7 | * L is stored by rows and its leading dimension is lskip. | ||
8 | * B is an n*1 matrix that contains the right hand sides. | ||
9 | * B is stored by columns and its leading dimension is also lskip. | ||
10 | * B is overwritten with X. | ||
11 | * this processes blocks of 2*2. | ||
12 | * if this is in the factorizer source file, n must be a multiple of 2. | ||
13 | */ | ||
14 | |||
15 | static void dSolveL1_1 (const dReal *L, dReal *B, int n, int lskip1) | ||
16 | { | ||
17 | /* declare variables - Z matrix, p and q vectors, etc */ | ||
18 | dReal Z11,m11,Z21,m21,p1,q1,p2,*ex; | ||
19 | const dReal *ell; | ||
20 | int i,j; | ||
21 | /* compute all 2 x 1 blocks of X */ | ||
22 | for (i=0; i < n; i+=2) { | ||
23 | /* compute all 2 x 1 block of X, from rows i..i+2-1 */ | ||
24 | /* set the Z matrix to 0 */ | ||
25 | Z11=0; | ||
26 | Z21=0; | ||
27 | ell = L + i*lskip1; | ||
28 | ex = B; | ||
29 | /* the inner loop that computes outer products and adds them to Z */ | ||
30 | for (j=i-2; j >= 0; j -= 2) { | ||
31 | /* compute outer product and add it to the Z matrix */ | ||
32 | p1=ell[0]; | ||
33 | q1=ex[0]; | ||
34 | m11 = p1 * q1; | ||
35 | p2=ell[lskip1]; | ||
36 | m21 = p2 * q1; | ||
37 | Z11 += m11; | ||
38 | Z21 += m21; | ||
39 | /* compute outer product and add it to the Z matrix */ | ||
40 | p1=ell[1]; | ||
41 | q1=ex[1]; | ||
42 | m11 = p1 * q1; | ||
43 | p2=ell[1+lskip1]; | ||
44 | m21 = p2 * q1; | ||
45 | /* advance pointers */ | ||
46 | ell += 2; | ||
47 | ex += 2; | ||
48 | Z11 += m11; | ||
49 | Z21 += m21; | ||
50 | /* end of inner loop */ | ||
51 | } | ||
52 | /* compute left-over iterations */ | ||
53 | j += 2; | ||
54 | for (; j > 0; j--) { | ||
55 | /* compute outer product and add it to the Z matrix */ | ||
56 | p1=ell[0]; | ||
57 | q1=ex[0]; | ||
58 | m11 = p1 * q1; | ||
59 | p2=ell[lskip1]; | ||
60 | m21 = p2 * q1; | ||
61 | /* advance pointers */ | ||
62 | ell += 1; | ||
63 | ex += 1; | ||
64 | Z11 += m11; | ||
65 | Z21 += m21; | ||
66 | } | ||
67 | /* finish computing the X(i) block */ | ||
68 | Z11 = ex[0] - Z11; | ||
69 | ex[0] = Z11; | ||
70 | p1 = ell[lskip1]; | ||
71 | Z21 = ex[1] - Z21 - p1*Z11; | ||
72 | ex[1] = Z21; | ||
73 | /* end of outer loop */ | ||
74 | } | ||
75 | } | ||
76 | |||
77 | /* solve L*X=B, with B containing 2 right hand sides. | ||
78 | * L is an n*n lower triangular matrix with ones on the diagonal. | ||
79 | * L is stored by rows and its leading dimension is lskip. | ||
80 | * B is an n*2 matrix that contains the right hand sides. | ||
81 | * B is stored by columns and its leading dimension is also lskip. | ||
82 | * B is overwritten with X. | ||
83 | * this processes blocks of 2*2. | ||
84 | * if this is in the factorizer source file, n must be a multiple of 2. | ||
85 | */ | ||
86 | |||
87 | static void dSolveL1_2 (const dReal *L, dReal *B, int n, int lskip1) | ||
88 | { | ||
89 | /* declare variables - Z matrix, p and q vectors, etc */ | ||
90 | dReal Z11,m11,Z12,m12,Z21,m21,Z22,m22,p1,q1,p2,q2,*ex; | ||
91 | const dReal *ell; | ||
92 | int i,j; | ||
93 | /* compute all 2 x 2 blocks of X */ | ||
94 | for (i=0; i < n; i+=2) { | ||
95 | /* compute all 2 x 2 block of X, from rows i..i+2-1 */ | ||
96 | /* set the Z matrix to 0 */ | ||
97 | Z11=0; | ||
98 | Z12=0; | ||
99 | Z21=0; | ||
100 | Z22=0; | ||
101 | ell = L + i*lskip1; | ||
102 | ex = B; | ||
103 | /* the inner loop that computes outer products and adds them to Z */ | ||
104 | for (j=i-2; j >= 0; j -= 2) { | ||
105 | /* compute outer product and add it to the Z matrix */ | ||
106 | p1=ell[0]; | ||
107 | q1=ex[0]; | ||
108 | m11 = p1 * q1; | ||
109 | q2=ex[lskip1]; | ||
110 | m12 = p1 * q2; | ||
111 | p2=ell[lskip1]; | ||
112 | m21 = p2 * q1; | ||
113 | m22 = p2 * q2; | ||
114 | Z11 += m11; | ||
115 | Z12 += m12; | ||
116 | Z21 += m21; | ||
117 | Z22 += m22; | ||
118 | /* compute outer product and add it to the Z matrix */ | ||
119 | p1=ell[1]; | ||
120 | q1=ex[1]; | ||
121 | m11 = p1 * q1; | ||
122 | q2=ex[1+lskip1]; | ||
123 | m12 = p1 * q2; | ||
124 | p2=ell[1+lskip1]; | ||
125 | m21 = p2 * q1; | ||
126 | m22 = p2 * q2; | ||
127 | /* advance pointers */ | ||
128 | ell += 2; | ||
129 | ex += 2; | ||
130 | Z11 += m11; | ||
131 | Z12 += m12; | ||
132 | Z21 += m21; | ||
133 | Z22 += m22; | ||
134 | /* end of inner loop */ | ||
135 | } | ||
136 | /* compute left-over iterations */ | ||
137 | j += 2; | ||
138 | for (; j > 0; j--) { | ||
139 | /* compute outer product and add it to the Z matrix */ | ||
140 | p1=ell[0]; | ||
141 | q1=ex[0]; | ||
142 | m11 = p1 * q1; | ||
143 | q2=ex[lskip1]; | ||
144 | m12 = p1 * q2; | ||
145 | p2=ell[lskip1]; | ||
146 | m21 = p2 * q1; | ||
147 | m22 = p2 * q2; | ||
148 | /* advance pointers */ | ||
149 | ell += 1; | ||
150 | ex += 1; | ||
151 | Z11 += m11; | ||
152 | Z12 += m12; | ||
153 | Z21 += m21; | ||
154 | Z22 += m22; | ||
155 | } | ||
156 | /* finish computing the X(i) block */ | ||
157 | Z11 = ex[0] - Z11; | ||
158 | ex[0] = Z11; | ||
159 | Z12 = ex[lskip1] - Z12; | ||
160 | ex[lskip1] = Z12; | ||
161 | p1 = ell[lskip1]; | ||
162 | Z21 = ex[1] - Z21 - p1*Z11; | ||
163 | ex[1] = Z21; | ||
164 | Z22 = ex[1+lskip1] - Z22 - p1*Z12; | ||
165 | ex[1+lskip1] = Z22; | ||
166 | /* end of outer loop */ | ||
167 | } | ||
168 | } | ||
169 | |||
170 | |||
171 | void dFactorLDLT (dReal *A, dReal *d, int n, int nskip1) | ||
172 | { | ||
173 | int i,j; | ||
174 | dReal sum,*ell,*dee,dd,p1,p2,q1,q2,Z11,m11,Z21,m21,Z22,m22; | ||
175 | if (n < 1) return; | ||
176 | |||
177 | for (i=0; i<=n-2; i += 2) { | ||
178 | /* solve L*(D*l)=a, l is scaled elements in 2 x i block at A(i,0) */ | ||
179 | dSolveL1_2 (A,A+i*nskip1,i,nskip1); | ||
180 | /* scale the elements in a 2 x i block at A(i,0), and also */ | ||
181 | /* compute Z = the outer product matrix that we'll need. */ | ||
182 | Z11 = 0; | ||
183 | Z21 = 0; | ||
184 | Z22 = 0; | ||
185 | ell = A+i*nskip1; | ||
186 | dee = d; | ||
187 | for (j=i-6; j >= 0; j -= 6) { | ||
188 | p1 = ell[0]; | ||
189 | p2 = ell[nskip1]; | ||
190 | dd = dee[0]; | ||
191 | q1 = p1*dd; | ||
192 | q2 = p2*dd; | ||
193 | ell[0] = q1; | ||
194 | ell[nskip1] = q2; | ||
195 | m11 = p1*q1; | ||
196 | m21 = p2*q1; | ||
197 | m22 = p2*q2; | ||
198 | Z11 += m11; | ||
199 | Z21 += m21; | ||
200 | Z22 += m22; | ||
201 | p1 = ell[1]; | ||
202 | p2 = ell[1+nskip1]; | ||
203 | dd = dee[1]; | ||
204 | q1 = p1*dd; | ||
205 | q2 = p2*dd; | ||
206 | ell[1] = q1; | ||
207 | ell[1+nskip1] = q2; | ||
208 | m11 = p1*q1; | ||
209 | m21 = p2*q1; | ||
210 | m22 = p2*q2; | ||
211 | Z11 += m11; | ||
212 | Z21 += m21; | ||
213 | Z22 += m22; | ||
214 | p1 = ell[2]; | ||
215 | p2 = ell[2+nskip1]; | ||
216 | dd = dee[2]; | ||
217 | q1 = p1*dd; | ||
218 | q2 = p2*dd; | ||
219 | ell[2] = q1; | ||
220 | ell[2+nskip1] = q2; | ||
221 | m11 = p1*q1; | ||
222 | m21 = p2*q1; | ||
223 | m22 = p2*q2; | ||
224 | Z11 += m11; | ||
225 | Z21 += m21; | ||
226 | Z22 += m22; | ||
227 | p1 = ell[3]; | ||
228 | p2 = ell[3+nskip1]; | ||
229 | dd = dee[3]; | ||
230 | q1 = p1*dd; | ||
231 | q2 = p2*dd; | ||
232 | ell[3] = q1; | ||
233 | ell[3+nskip1] = q2; | ||
234 | m11 = p1*q1; | ||
235 | m21 = p2*q1; | ||
236 | m22 = p2*q2; | ||
237 | Z11 += m11; | ||
238 | Z21 += m21; | ||
239 | Z22 += m22; | ||
240 | p1 = ell[4]; | ||
241 | p2 = ell[4+nskip1]; | ||
242 | dd = dee[4]; | ||
243 | q1 = p1*dd; | ||
244 | q2 = p2*dd; | ||
245 | ell[4] = q1; | ||
246 | ell[4+nskip1] = q2; | ||
247 | m11 = p1*q1; | ||
248 | m21 = p2*q1; | ||
249 | m22 = p2*q2; | ||
250 | Z11 += m11; | ||
251 | Z21 += m21; | ||
252 | Z22 += m22; | ||
253 | p1 = ell[5]; | ||
254 | p2 = ell[5+nskip1]; | ||
255 | dd = dee[5]; | ||
256 | q1 = p1*dd; | ||
257 | q2 = p2*dd; | ||
258 | ell[5] = q1; | ||
259 | ell[5+nskip1] = q2; | ||
260 | m11 = p1*q1; | ||
261 | m21 = p2*q1; | ||
262 | m22 = p2*q2; | ||
263 | Z11 += m11; | ||
264 | Z21 += m21; | ||
265 | Z22 += m22; | ||
266 | ell += 6; | ||
267 | dee += 6; | ||
268 | } | ||
269 | /* compute left-over iterations */ | ||
270 | j += 6; | ||
271 | for (; j > 0; j--) { | ||
272 | p1 = ell[0]; | ||
273 | p2 = ell[nskip1]; | ||
274 | dd = dee[0]; | ||
275 | q1 = p1*dd; | ||
276 | q2 = p2*dd; | ||
277 | ell[0] = q1; | ||
278 | ell[nskip1] = q2; | ||
279 | m11 = p1*q1; | ||
280 | m21 = p2*q1; | ||
281 | m22 = p2*q2; | ||
282 | Z11 += m11; | ||
283 | Z21 += m21; | ||
284 | Z22 += m22; | ||
285 | ell++; | ||
286 | dee++; | ||
287 | } | ||
288 | /* solve for diagonal 2 x 2 block at A(i,i) */ | ||
289 | Z11 = ell[0] - Z11; | ||
290 | Z21 = ell[nskip1] - Z21; | ||
291 | Z22 = ell[1+nskip1] - Z22; | ||
292 | dee = d + i; | ||
293 | /* factorize 2 x 2 block Z,dee */ | ||
294 | /* factorize row 1 */ | ||
295 | dee[0] = dRecip(Z11); | ||
296 | /* factorize row 2 */ | ||
297 | sum = 0; | ||
298 | q1 = Z21; | ||
299 | q2 = q1 * dee[0]; | ||
300 | Z21 = q2; | ||
301 | sum += q1*q2; | ||
302 | dee[1] = dRecip(Z22 - sum); | ||
303 | /* done factorizing 2 x 2 block */ | ||
304 | ell[nskip1] = Z21; | ||
305 | } | ||
306 | /* compute the (less than 2) rows at the bottom */ | ||
307 | switch (n-i) { | ||
308 | case 0: | ||
309 | break; | ||
310 | |||
311 | case 1: | ||
312 | dSolveL1_1 (A,A+i*nskip1,i,nskip1); | ||
313 | /* scale the elements in a 1 x i block at A(i,0), and also */ | ||
314 | /* compute Z = the outer product matrix that we'll need. */ | ||
315 | Z11 = 0; | ||
316 | ell = A+i*nskip1; | ||
317 | dee = d; | ||
318 | for (j=i-6; j >= 0; j -= 6) { | ||
319 | p1 = ell[0]; | ||
320 | dd = dee[0]; | ||
321 | q1 = p1*dd; | ||
322 | ell[0] = q1; | ||
323 | m11 = p1*q1; | ||
324 | Z11 += m11; | ||
325 | p1 = ell[1]; | ||
326 | dd = dee[1]; | ||
327 | q1 = p1*dd; | ||
328 | ell[1] = q1; | ||
329 | m11 = p1*q1; | ||
330 | Z11 += m11; | ||
331 | p1 = ell[2]; | ||
332 | dd = dee[2]; | ||
333 | q1 = p1*dd; | ||
334 | ell[2] = q1; | ||
335 | m11 = p1*q1; | ||
336 | Z11 += m11; | ||
337 | p1 = ell[3]; | ||
338 | dd = dee[3]; | ||
339 | q1 = p1*dd; | ||
340 | ell[3] = q1; | ||
341 | m11 = p1*q1; | ||
342 | Z11 += m11; | ||
343 | p1 = ell[4]; | ||
344 | dd = dee[4]; | ||
345 | q1 = p1*dd; | ||
346 | ell[4] = q1; | ||
347 | m11 = p1*q1; | ||
348 | Z11 += m11; | ||
349 | p1 = ell[5]; | ||
350 | dd = dee[5]; | ||
351 | q1 = p1*dd; | ||
352 | ell[5] = q1; | ||
353 | m11 = p1*q1; | ||
354 | Z11 += m11; | ||
355 | ell += 6; | ||
356 | dee += 6; | ||
357 | } | ||
358 | /* compute left-over iterations */ | ||
359 | j += 6; | ||
360 | for (; j > 0; j--) { | ||
361 | p1 = ell[0]; | ||
362 | dd = dee[0]; | ||
363 | q1 = p1*dd; | ||
364 | ell[0] = q1; | ||
365 | m11 = p1*q1; | ||
366 | Z11 += m11; | ||
367 | ell++; | ||
368 | dee++; | ||
369 | } | ||
370 | /* solve for diagonal 1 x 1 block at A(i,i) */ | ||
371 | Z11 = ell[0] - Z11; | ||
372 | dee = d + i; | ||
373 | /* factorize 1 x 1 block Z,dee */ | ||
374 | /* factorize row 1 */ | ||
375 | dee[0] = dRecip(Z11); | ||
376 | /* done factorizing 1 x 1 block */ | ||
377 | break; | ||
378 | |||
379 | default: *((char*)0)=0; /* this should never happen! */ | ||
380 | } | ||
381 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/fastlsolve.c b/libraries/ode-0.9\/ode/src/fastlsolve.c new file mode 100755 index 0000000..0ae99d6 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/fastlsolve.c | |||
@@ -0,0 +1,298 @@ | |||
1 | /* generated code, do not edit. */ | ||
2 | |||
3 | #include "ode/matrix.h" | ||
4 | |||
5 | /* solve L*X=B, with B containing 1 right hand sides. | ||
6 | * L is an n*n lower triangular matrix with ones on the diagonal. | ||
7 | * L is stored by rows and its leading dimension is lskip. | ||
8 | * B is an n*1 matrix that contains the right hand sides. | ||
9 | * B is stored by columns and its leading dimension is also lskip. | ||
10 | * B is overwritten with X. | ||
11 | * this processes blocks of 4*4. | ||
12 | * if this is in the factorizer source file, n must be a multiple of 4. | ||
13 | */ | ||
14 | |||
15 | void dSolveL1 (const dReal *L, dReal *B, int n, int lskip1) | ||
16 | { | ||
17 | /* declare variables - Z matrix, p and q vectors, etc */ | ||
18 | dReal Z11,Z21,Z31,Z41,p1,q1,p2,p3,p4,*ex; | ||
19 | const dReal *ell; | ||
20 | int lskip2,lskip3,i,j; | ||
21 | /* compute lskip values */ | ||
22 | lskip2 = 2*lskip1; | ||
23 | lskip3 = 3*lskip1; | ||
24 | /* compute all 4 x 1 blocks of X */ | ||
25 | for (i=0; i <= n-4; i+=4) { | ||
26 | /* compute all 4 x 1 block of X, from rows i..i+4-1 */ | ||
27 | /* set the Z matrix to 0 */ | ||
28 | Z11=0; | ||
29 | Z21=0; | ||
30 | Z31=0; | ||
31 | Z41=0; | ||
32 | ell = L + i*lskip1; | ||
33 | ex = B; | ||
34 | /* the inner loop that computes outer products and adds them to Z */ | ||
35 | for (j=i-12; j >= 0; j -= 12) { | ||
36 | /* load p and q values */ | ||
37 | p1=ell[0]; | ||
38 | q1=ex[0]; | ||
39 | p2=ell[lskip1]; | ||
40 | p3=ell[lskip2]; | ||
41 | p4=ell[lskip3]; | ||
42 | /* compute outer product and add it to the Z matrix */ | ||
43 | Z11 += p1 * q1; | ||
44 | Z21 += p2 * q1; | ||
45 | Z31 += p3 * q1; | ||
46 | Z41 += p4 * q1; | ||
47 | /* load p and q values */ | ||
48 | p1=ell[1]; | ||
49 | q1=ex[1]; | ||
50 | p2=ell[1+lskip1]; | ||
51 | p3=ell[1+lskip2]; | ||
52 | p4=ell[1+lskip3]; | ||
53 | /* compute outer product and add it to the Z matrix */ | ||
54 | Z11 += p1 * q1; | ||
55 | Z21 += p2 * q1; | ||
56 | Z31 += p3 * q1; | ||
57 | Z41 += p4 * q1; | ||
58 | /* load p and q values */ | ||
59 | p1=ell[2]; | ||
60 | q1=ex[2]; | ||
61 | p2=ell[2+lskip1]; | ||
62 | p3=ell[2+lskip2]; | ||
63 | p4=ell[2+lskip3]; | ||
64 | /* compute outer product and add it to the Z matrix */ | ||
65 | Z11 += p1 * q1; | ||
66 | Z21 += p2 * q1; | ||
67 | Z31 += p3 * q1; | ||
68 | Z41 += p4 * q1; | ||
69 | /* load p and q values */ | ||
70 | p1=ell[3]; | ||
71 | q1=ex[3]; | ||
72 | p2=ell[3+lskip1]; | ||
73 | p3=ell[3+lskip2]; | ||
74 | p4=ell[3+lskip3]; | ||
75 | /* compute outer product and add it to the Z matrix */ | ||
76 | Z11 += p1 * q1; | ||
77 | Z21 += p2 * q1; | ||
78 | Z31 += p3 * q1; | ||
79 | Z41 += p4 * q1; | ||
80 | /* load p and q values */ | ||
81 | p1=ell[4]; | ||
82 | q1=ex[4]; | ||
83 | p2=ell[4+lskip1]; | ||
84 | p3=ell[4+lskip2]; | ||
85 | p4=ell[4+lskip3]; | ||
86 | /* compute outer product and add it to the Z matrix */ | ||
87 | Z11 += p1 * q1; | ||
88 | Z21 += p2 * q1; | ||
89 | Z31 += p3 * q1; | ||
90 | Z41 += p4 * q1; | ||
91 | /* load p and q values */ | ||
92 | p1=ell[5]; | ||
93 | q1=ex[5]; | ||
94 | p2=ell[5+lskip1]; | ||
95 | p3=ell[5+lskip2]; | ||
96 | p4=ell[5+lskip3]; | ||
97 | /* compute outer product and add it to the Z matrix */ | ||
98 | Z11 += p1 * q1; | ||
99 | Z21 += p2 * q1; | ||
100 | Z31 += p3 * q1; | ||
101 | Z41 += p4 * q1; | ||
102 | /* load p and q values */ | ||
103 | p1=ell[6]; | ||
104 | q1=ex[6]; | ||
105 | p2=ell[6+lskip1]; | ||
106 | p3=ell[6+lskip2]; | ||
107 | p4=ell[6+lskip3]; | ||
108 | /* compute outer product and add it to the Z matrix */ | ||
109 | Z11 += p1 * q1; | ||
110 | Z21 += p2 * q1; | ||
111 | Z31 += p3 * q1; | ||
112 | Z41 += p4 * q1; | ||
113 | /* load p and q values */ | ||
114 | p1=ell[7]; | ||
115 | q1=ex[7]; | ||
116 | p2=ell[7+lskip1]; | ||
117 | p3=ell[7+lskip2]; | ||
118 | p4=ell[7+lskip3]; | ||
119 | /* compute outer product and add it to the Z matrix */ | ||
120 | Z11 += p1 * q1; | ||
121 | Z21 += p2 * q1; | ||
122 | Z31 += p3 * q1; | ||
123 | Z41 += p4 * q1; | ||
124 | /* load p and q values */ | ||
125 | p1=ell[8]; | ||
126 | q1=ex[8]; | ||
127 | p2=ell[8+lskip1]; | ||
128 | p3=ell[8+lskip2]; | ||
129 | p4=ell[8+lskip3]; | ||
130 | /* compute outer product and add it to the Z matrix */ | ||
131 | Z11 += p1 * q1; | ||
132 | Z21 += p2 * q1; | ||
133 | Z31 += p3 * q1; | ||
134 | Z41 += p4 * q1; | ||
135 | /* load p and q values */ | ||
136 | p1=ell[9]; | ||
137 | q1=ex[9]; | ||
138 | p2=ell[9+lskip1]; | ||
139 | p3=ell[9+lskip2]; | ||
140 | p4=ell[9+lskip3]; | ||
141 | /* compute outer product and add it to the Z matrix */ | ||
142 | Z11 += p1 * q1; | ||
143 | Z21 += p2 * q1; | ||
144 | Z31 += p3 * q1; | ||
145 | Z41 += p4 * q1; | ||
146 | /* load p and q values */ | ||
147 | p1=ell[10]; | ||
148 | q1=ex[10]; | ||
149 | p2=ell[10+lskip1]; | ||
150 | p3=ell[10+lskip2]; | ||
151 | p4=ell[10+lskip3]; | ||
152 | /* compute outer product and add it to the Z matrix */ | ||
153 | Z11 += p1 * q1; | ||
154 | Z21 += p2 * q1; | ||
155 | Z31 += p3 * q1; | ||
156 | Z41 += p4 * q1; | ||
157 | /* load p and q values */ | ||
158 | p1=ell[11]; | ||
159 | q1=ex[11]; | ||
160 | p2=ell[11+lskip1]; | ||
161 | p3=ell[11+lskip2]; | ||
162 | p4=ell[11+lskip3]; | ||
163 | /* compute outer product and add it to the Z matrix */ | ||
164 | Z11 += p1 * q1; | ||
165 | Z21 += p2 * q1; | ||
166 | Z31 += p3 * q1; | ||
167 | Z41 += p4 * q1; | ||
168 | /* advance pointers */ | ||
169 | ell += 12; | ||
170 | ex += 12; | ||
171 | /* end of inner loop */ | ||
172 | } | ||
173 | /* compute left-over iterations */ | ||
174 | j += 12; | ||
175 | for (; j > 0; j--) { | ||
176 | /* load p and q values */ | ||
177 | p1=ell[0]; | ||
178 | q1=ex[0]; | ||
179 | p2=ell[lskip1]; | ||
180 | p3=ell[lskip2]; | ||
181 | p4=ell[lskip3]; | ||
182 | /* compute outer product and add it to the Z matrix */ | ||
183 | Z11 += p1 * q1; | ||
184 | Z21 += p2 * q1; | ||
185 | Z31 += p3 * q1; | ||
186 | Z41 += p4 * q1; | ||
187 | /* advance pointers */ | ||
188 | ell += 1; | ||
189 | ex += 1; | ||
190 | } | ||
191 | /* finish computing the X(i) block */ | ||
192 | Z11 = ex[0] - Z11; | ||
193 | ex[0] = Z11; | ||
194 | p1 = ell[lskip1]; | ||
195 | Z21 = ex[1] - Z21 - p1*Z11; | ||
196 | ex[1] = Z21; | ||
197 | p1 = ell[lskip2]; | ||
198 | p2 = ell[1+lskip2]; | ||
199 | Z31 = ex[2] - Z31 - p1*Z11 - p2*Z21; | ||
200 | ex[2] = Z31; | ||
201 | p1 = ell[lskip3]; | ||
202 | p2 = ell[1+lskip3]; | ||
203 | p3 = ell[2+lskip3]; | ||
204 | Z41 = ex[3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; | ||
205 | ex[3] = Z41; | ||
206 | /* end of outer loop */ | ||
207 | } | ||
208 | /* compute rows at end that are not a multiple of block size */ | ||
209 | for (; i < n; i++) { | ||
210 | /* compute all 1 x 1 block of X, from rows i..i+1-1 */ | ||
211 | /* set the Z matrix to 0 */ | ||
212 | Z11=0; | ||
213 | ell = L + i*lskip1; | ||
214 | ex = B; | ||
215 | /* the inner loop that computes outer products and adds them to Z */ | ||
216 | for (j=i-12; j >= 0; j -= 12) { | ||
217 | /* load p and q values */ | ||
218 | p1=ell[0]; | ||
219 | q1=ex[0]; | ||
220 | /* compute outer product and add it to the Z matrix */ | ||
221 | Z11 += p1 * q1; | ||
222 | /* load p and q values */ | ||
223 | p1=ell[1]; | ||
224 | q1=ex[1]; | ||
225 | /* compute outer product and add it to the Z matrix */ | ||
226 | Z11 += p1 * q1; | ||
227 | /* load p and q values */ | ||
228 | p1=ell[2]; | ||
229 | q1=ex[2]; | ||
230 | /* compute outer product and add it to the Z matrix */ | ||
231 | Z11 += p1 * q1; | ||
232 | /* load p and q values */ | ||
233 | p1=ell[3]; | ||
234 | q1=ex[3]; | ||
235 | /* compute outer product and add it to the Z matrix */ | ||
236 | Z11 += p1 * q1; | ||
237 | /* load p and q values */ | ||
238 | p1=ell[4]; | ||
239 | q1=ex[4]; | ||
240 | /* compute outer product and add it to the Z matrix */ | ||
241 | Z11 += p1 * q1; | ||
242 | /* load p and q values */ | ||
243 | p1=ell[5]; | ||
244 | q1=ex[5]; | ||
245 | /* compute outer product and add it to the Z matrix */ | ||
246 | Z11 += p1 * q1; | ||
247 | /* load p and q values */ | ||
248 | p1=ell[6]; | ||
249 | q1=ex[6]; | ||
250 | /* compute outer product and add it to the Z matrix */ | ||
251 | Z11 += p1 * q1; | ||
252 | /* load p and q values */ | ||
253 | p1=ell[7]; | ||
254 | q1=ex[7]; | ||
255 | /* compute outer product and add it to the Z matrix */ | ||
256 | Z11 += p1 * q1; | ||
257 | /* load p and q values */ | ||
258 | p1=ell[8]; | ||
259 | q1=ex[8]; | ||
260 | /* compute outer product and add it to the Z matrix */ | ||
261 | Z11 += p1 * q1; | ||
262 | /* load p and q values */ | ||
263 | p1=ell[9]; | ||
264 | q1=ex[9]; | ||
265 | /* compute outer product and add it to the Z matrix */ | ||
266 | Z11 += p1 * q1; | ||
267 | /* load p and q values */ | ||
268 | p1=ell[10]; | ||
269 | q1=ex[10]; | ||
270 | /* compute outer product and add it to the Z matrix */ | ||
271 | Z11 += p1 * q1; | ||
272 | /* load p and q values */ | ||
273 | p1=ell[11]; | ||
274 | q1=ex[11]; | ||
275 | /* compute outer product and add it to the Z matrix */ | ||
276 | Z11 += p1 * q1; | ||
277 | /* advance pointers */ | ||
278 | ell += 12; | ||
279 | ex += 12; | ||
280 | /* end of inner loop */ | ||
281 | } | ||
282 | /* compute left-over iterations */ | ||
283 | j += 12; | ||
284 | for (; j > 0; j--) { | ||
285 | /* load p and q values */ | ||
286 | p1=ell[0]; | ||
287 | q1=ex[0]; | ||
288 | /* compute outer product and add it to the Z matrix */ | ||
289 | Z11 += p1 * q1; | ||
290 | /* advance pointers */ | ||
291 | ell += 1; | ||
292 | ex += 1; | ||
293 | } | ||
294 | /* finish computing the X(i) block */ | ||
295 | Z11 = ex[0] - Z11; | ||
296 | ex[0] = Z11; | ||
297 | } | ||
298 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/fastltsolve.c b/libraries/ode-0.9\/ode/src/fastltsolve.c new file mode 100755 index 0000000..eb950f6 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/fastltsolve.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* generated code, do not edit. */ | ||
2 | |||
3 | #include "ode/matrix.h" | ||
4 | |||
5 | /* solve L^T * x=b, with b containing 1 right hand side. | ||
6 | * L is an n*n lower triangular matrix with ones on the diagonal. | ||
7 | * L is stored by rows and its leading dimension is lskip. | ||
8 | * b is an n*1 matrix that contains the right hand side. | ||
9 | * b is overwritten with x. | ||
10 | * this processes blocks of 4. | ||
11 | */ | ||
12 | |||
13 | void dSolveL1T (const dReal *L, dReal *B, int n, int lskip1) | ||
14 | { | ||
15 | /* declare variables - Z matrix, p and q vectors, etc */ | ||
16 | dReal Z11,m11,Z21,m21,Z31,m31,Z41,m41,p1,q1,p2,p3,p4,*ex; | ||
17 | const dReal *ell; | ||
18 | int lskip2,lskip3,i,j; | ||
19 | /* special handling for L and B because we're solving L1 *transpose* */ | ||
20 | L = L + (n-1)*(lskip1+1); | ||
21 | B = B + n-1; | ||
22 | lskip1 = -lskip1; | ||
23 | /* compute lskip values */ | ||
24 | lskip2 = 2*lskip1; | ||
25 | lskip3 = 3*lskip1; | ||
26 | /* compute all 4 x 1 blocks of X */ | ||
27 | for (i=0; i <= n-4; i+=4) { | ||
28 | /* compute all 4 x 1 block of X, from rows i..i+4-1 */ | ||
29 | /* set the Z matrix to 0 */ | ||
30 | Z11=0; | ||
31 | Z21=0; | ||
32 | Z31=0; | ||
33 | Z41=0; | ||
34 | ell = L - i; | ||
35 | ex = B; | ||
36 | /* the inner loop that computes outer products and adds them to Z */ | ||
37 | for (j=i-4; j >= 0; j -= 4) { | ||
38 | /* load p and q values */ | ||
39 | p1=ell[0]; | ||
40 | q1=ex[0]; | ||
41 | p2=ell[-1]; | ||
42 | p3=ell[-2]; | ||
43 | p4=ell[-3]; | ||
44 | /* compute outer product and add it to the Z matrix */ | ||
45 | m11 = p1 * q1; | ||
46 | m21 = p2 * q1; | ||
47 | m31 = p3 * q1; | ||
48 | m41 = p4 * q1; | ||
49 | ell += lskip1; | ||
50 | Z11 += m11; | ||
51 | Z21 += m21; | ||
52 | Z31 += m31; | ||
53 | Z41 += m41; | ||
54 | /* load p and q values */ | ||
55 | p1=ell[0]; | ||
56 | q1=ex[-1]; | ||
57 | p2=ell[-1]; | ||
58 | p3=ell[-2]; | ||
59 | p4=ell[-3]; | ||
60 | /* compute outer product and add it to the Z matrix */ | ||
61 | m11 = p1 * q1; | ||
62 | m21 = p2 * q1; | ||
63 | m31 = p3 * q1; | ||
64 | m41 = p4 * q1; | ||
65 | ell += lskip1; | ||
66 | Z11 += m11; | ||
67 | Z21 += m21; | ||
68 | Z31 += m31; | ||
69 | Z41 += m41; | ||
70 | /* load p and q values */ | ||
71 | p1=ell[0]; | ||
72 | q1=ex[-2]; | ||
73 | p2=ell[-1]; | ||
74 | p3=ell[-2]; | ||
75 | p4=ell[-3]; | ||
76 | /* compute outer product and add it to the Z matrix */ | ||
77 | m11 = p1 * q1; | ||
78 | m21 = p2 * q1; | ||
79 | m31 = p3 * q1; | ||
80 | m41 = p4 * q1; | ||
81 | ell += lskip1; | ||
82 | Z11 += m11; | ||
83 | Z21 += m21; | ||
84 | Z31 += m31; | ||
85 | Z41 += m41; | ||
86 | /* load p and q values */ | ||
87 | p1=ell[0]; | ||
88 | q1=ex[-3]; | ||
89 | p2=ell[-1]; | ||
90 | p3=ell[-2]; | ||
91 | p4=ell[-3]; | ||
92 | /* compute outer product and add it to the Z matrix */ | ||
93 | m11 = p1 * q1; | ||
94 | m21 = p2 * q1; | ||
95 | m31 = p3 * q1; | ||
96 | m41 = p4 * q1; | ||
97 | ell += lskip1; | ||
98 | ex -= 4; | ||
99 | Z11 += m11; | ||
100 | Z21 += m21; | ||
101 | Z31 += m31; | ||
102 | Z41 += m41; | ||
103 | /* end of inner loop */ | ||
104 | } | ||
105 | /* compute left-over iterations */ | ||
106 | j += 4; | ||
107 | for (; j > 0; j--) { | ||
108 | /* load p and q values */ | ||
109 | p1=ell[0]; | ||
110 | q1=ex[0]; | ||
111 | p2=ell[-1]; | ||
112 | p3=ell[-2]; | ||
113 | p4=ell[-3]; | ||
114 | /* compute outer product and add it to the Z matrix */ | ||
115 | m11 = p1 * q1; | ||
116 | m21 = p2 * q1; | ||
117 | m31 = p3 * q1; | ||
118 | m41 = p4 * q1; | ||
119 | ell += lskip1; | ||
120 | ex -= 1; | ||
121 | Z11 += m11; | ||
122 | Z21 += m21; | ||
123 | Z31 += m31; | ||
124 | Z41 += m41; | ||
125 | } | ||
126 | /* finish computing the X(i) block */ | ||
127 | Z11 = ex[0] - Z11; | ||
128 | ex[0] = Z11; | ||
129 | p1 = ell[-1]; | ||
130 | Z21 = ex[-1] - Z21 - p1*Z11; | ||
131 | ex[-1] = Z21; | ||
132 | p1 = ell[-2]; | ||
133 | p2 = ell[-2+lskip1]; | ||
134 | Z31 = ex[-2] - Z31 - p1*Z11 - p2*Z21; | ||
135 | ex[-2] = Z31; | ||
136 | p1 = ell[-3]; | ||
137 | p2 = ell[-3+lskip1]; | ||
138 | p3 = ell[-3+lskip2]; | ||
139 | Z41 = ex[-3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; | ||
140 | ex[-3] = Z41; | ||
141 | /* end of outer loop */ | ||
142 | } | ||
143 | /* compute rows at end that are not a multiple of block size */ | ||
144 | for (; i < n; i++) { | ||
145 | /* compute all 1 x 1 block of X, from rows i..i+1-1 */ | ||
146 | /* set the Z matrix to 0 */ | ||
147 | Z11=0; | ||
148 | ell = L - i; | ||
149 | ex = B; | ||
150 | /* the inner loop that computes outer products and adds them to Z */ | ||
151 | for (j=i-4; j >= 0; j -= 4) { | ||
152 | /* load p and q values */ | ||
153 | p1=ell[0]; | ||
154 | q1=ex[0]; | ||
155 | /* compute outer product and add it to the Z matrix */ | ||
156 | m11 = p1 * q1; | ||
157 | ell += lskip1; | ||
158 | Z11 += m11; | ||
159 | /* load p and q values */ | ||
160 | p1=ell[0]; | ||
161 | q1=ex[-1]; | ||
162 | /* compute outer product and add it to the Z matrix */ | ||
163 | m11 = p1 * q1; | ||
164 | ell += lskip1; | ||
165 | Z11 += m11; | ||
166 | /* load p and q values */ | ||
167 | p1=ell[0]; | ||
168 | q1=ex[-2]; | ||
169 | /* compute outer product and add it to the Z matrix */ | ||
170 | m11 = p1 * q1; | ||
171 | ell += lskip1; | ||
172 | Z11 += m11; | ||
173 | /* load p and q values */ | ||
174 | p1=ell[0]; | ||
175 | q1=ex[-3]; | ||
176 | /* compute outer product and add it to the Z matrix */ | ||
177 | m11 = p1 * q1; | ||
178 | ell += lskip1; | ||
179 | ex -= 4; | ||
180 | Z11 += m11; | ||
181 | /* end of inner loop */ | ||
182 | } | ||
183 | /* compute left-over iterations */ | ||
184 | j += 4; | ||
185 | for (; j > 0; j--) { | ||
186 | /* load p and q values */ | ||
187 | p1=ell[0]; | ||
188 | q1=ex[0]; | ||
189 | /* compute outer product and add it to the Z matrix */ | ||
190 | m11 = p1 * q1; | ||
191 | ell += lskip1; | ||
192 | ex -= 1; | ||
193 | Z11 += m11; | ||
194 | } | ||
195 | /* finish computing the X(i) block */ | ||
196 | Z11 = ex[0] - Z11; | ||
197 | ex[0] = Z11; | ||
198 | } | ||
199 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/heightfield.cpp b/libraries/ode-0.9\/ode/src/heightfield.cpp new file mode 100755 index 0000000..36755fc --- /dev/null +++ b/libraries/ode-0.9\/ode/src/heightfield.cpp | |||
@@ -0,0 +1,1812 @@ | |||
1 | // dHeightfield Collider | ||
2 | // Paul Cheyrou-Lagreze aka Tuan Kuranes 2006 Speed enhancements http://www.pop-3d.com | ||
3 | // Martijn Buijs 2006 http://home.planet.nl/~buijs512/ | ||
4 | // Based on Terrain & Cone contrib by: | ||
5 | // Benoit CHAPEROT 2003-2004 http://www.jstarlab.com | ||
6 | // Some code inspired by Magic Software | ||
7 | |||
8 | |||
9 | #include <ode/common.h> | ||
10 | #include <ode/collision.h> | ||
11 | #include <ode/matrix.h> | ||
12 | #include <ode/rotation.h> | ||
13 | #include <ode/odemath.h> | ||
14 | #include "collision_kernel.h" | ||
15 | #include "collision_std.h" | ||
16 | #include "collision_util.h" | ||
17 | #include "heightfield.h" | ||
18 | |||
19 | |||
20 | |||
21 | #if dTRIMESH_ENABLED | ||
22 | #include "collision_trimesh_internal.h" | ||
23 | #endif // dTRIMESH_ENABLED | ||
24 | |||
25 | #define TERRAINTOL REAL(0.0) | ||
26 | |||
27 | #define dMIN(A,B) ((A)>(B) ? B : A) | ||
28 | #define dMAX(A,B) ((A)>(B) ? A : B) | ||
29 | |||
30 | |||
31 | // Three-way MIN and MAX | ||
32 | #define dMIN3(A,B,C) ( (A)<(B) ? dMIN((A),(C)) : dMIN((B),(C)) ) | ||
33 | #define dMAX3(A,B,C) ( (A)>(B) ? dMAX((A),(C)) : dMAX((B),(C)) ) | ||
34 | |||
35 | #define dOPESIGN(a, op1, op2,b) \ | ||
36 | (a)[0] op1 op2 ((b)[0]); \ | ||
37 | (a)[1] op1 op2 ((b)[1]); \ | ||
38 | (a)[2] op1 op2 ((b)[2]); | ||
39 | |||
40 | #define dGeomRaySetNoNormalize(myRay, MyPoint, MyVector) { \ | ||
41 | \ | ||
42 | dVector3Copy (MyPoint, myRay.final_posr->pos); \ | ||
43 | myRay.final_posr->R[2] = MyVector[0]; \ | ||
44 | myRay.final_posr->R[6] = MyVector[1]; \ | ||
45 | myRay.final_posr->R[10] = MyVector[2]; \ | ||
46 | dGeomMoved (&myRay); \ | ||
47 | } | ||
48 | |||
49 | #define dGeomPlaneSetNoNormalize(MyPlane, MyPlaneDef) { \ | ||
50 | \ | ||
51 | MyPlane->p[0] = MyPlaneDef[0]; \ | ||
52 | MyPlane->p[1] = MyPlaneDef[1]; \ | ||
53 | MyPlane->p[2] = MyPlaneDef[2]; \ | ||
54 | MyPlane->p[3] = MyPlaneDef[3]; \ | ||
55 | dGeomMoved (MyPlane); \ | ||
56 | } | ||
57 | //////// Local Build Option //////////////////////////////////////////////////// | ||
58 | |||
59 | // Uncomment this #define to use the (0,0) corner of the geom as the origin, | ||
60 | // rather than the center. This was the way the original heightfield worked, | ||
61 | // but as it does not match the way all other geometries work, so for constancy it | ||
62 | // was changed to work like this. | ||
63 | |||
64 | // #define DHEIGHTFIELD_CORNER_ORIGIN | ||
65 | |||
66 | |||
67 | // Uncomment this #define to add heightfield triangles edge colliding | ||
68 | // Code is not guaranteed and I didn't find the need to add that as | ||
69 | // colliding planes triangles and edge triangles seems enough. | ||
70 | // #define _HEIGHTFIELDEDGECOLLIDING | ||
71 | |||
72 | |||
73 | //////// dxHeightfieldData ///////////////////////////////////////////////////////////// | ||
74 | |||
75 | // dxHeightfieldData constructor | ||
76 | dxHeightfieldData::dxHeightfieldData() | ||
77 | { | ||
78 | // | ||
79 | } | ||
80 | |||
81 | |||
82 | // build Heightfield data | ||
83 | void dxHeightfieldData::SetData( int nWidthSamples, int nDepthSamples, | ||
84 | dReal fWidth, dReal fDepth, | ||
85 | dReal fScale, dReal fOffset, dReal fThickness, | ||
86 | int bWrapMode ) | ||
87 | { | ||
88 | dIASSERT( fWidth > REAL( 0.0 ) ); | ||
89 | dIASSERT( fDepth > REAL( 0.0 ) ); | ||
90 | dIASSERT( nWidthSamples > 0 ); | ||
91 | dIASSERT( nDepthSamples > 0 ); | ||
92 | |||
93 | // x,z bounds | ||
94 | m_fWidth = fWidth; | ||
95 | m_fDepth = fDepth; | ||
96 | |||
97 | // cache half x,z bounds | ||
98 | m_fHalfWidth = fWidth / REAL( 2.0 ); | ||
99 | m_fHalfDepth = fDepth / REAL( 2.0 ); | ||
100 | |||
101 | // scale and offset | ||
102 | m_fScale = fScale; | ||
103 | m_fOffset = fOffset; | ||
104 | |||
105 | // infinite min height bounds | ||
106 | m_fThickness = fThickness; | ||
107 | |||
108 | // number of vertices per side | ||
109 | m_nWidthSamples = nWidthSamples; | ||
110 | m_nDepthSamples = nDepthSamples; | ||
111 | |||
112 | m_fSampleWidth = m_fWidth / ( m_nWidthSamples - 1 ); | ||
113 | m_fSampleDepth = m_fDepth / ( m_nDepthSamples - 1 ); | ||
114 | |||
115 | m_fInvSampleWidth = 1 / m_fSampleWidth; | ||
116 | m_fInvSampleDepth = 1 / m_fSampleDepth; | ||
117 | |||
118 | // finite or repeated terrain? | ||
119 | m_bWrapMode = bWrapMode; | ||
120 | } | ||
121 | |||
122 | |||
123 | // recomputes heights bounds | ||
124 | void dxHeightfieldData::ComputeHeightBounds() | ||
125 | { | ||
126 | static int i; | ||
127 | static dReal h; | ||
128 | static unsigned char *data_byte; | ||
129 | static short *data_short; | ||
130 | static float *data_float; | ||
131 | static double *data_double; | ||
132 | |||
133 | switch ( m_nGetHeightMode ) | ||
134 | { | ||
135 | |||
136 | // callback | ||
137 | case 0: | ||
138 | // change nothing, keep using default or user specified bounds | ||
139 | return; | ||
140 | |||
141 | // byte | ||
142 | case 1: | ||
143 | data_byte = (unsigned char*)m_pHeightData; | ||
144 | m_fMinHeight = dInfinity; | ||
145 | m_fMaxHeight = -dInfinity; | ||
146 | |||
147 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
148 | { | ||
149 | h = data_byte[i]; | ||
150 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
151 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
152 | } | ||
153 | |||
154 | break; | ||
155 | |||
156 | // short | ||
157 | case 2: | ||
158 | data_short = (short*)m_pHeightData; | ||
159 | m_fMinHeight = dInfinity; | ||
160 | m_fMaxHeight = -dInfinity; | ||
161 | |||
162 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
163 | { | ||
164 | h = data_short[i]; | ||
165 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
166 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
167 | } | ||
168 | |||
169 | break; | ||
170 | |||
171 | // float | ||
172 | case 3: | ||
173 | data_float = (float*)m_pHeightData; | ||
174 | m_fMinHeight = dInfinity; | ||
175 | m_fMaxHeight = -dInfinity; | ||
176 | |||
177 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
178 | { | ||
179 | h = data_float[i]; | ||
180 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
181 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
182 | } | ||
183 | |||
184 | break; | ||
185 | |||
186 | // double | ||
187 | case 4: | ||
188 | data_double = (double*)m_pHeightData; | ||
189 | m_fMinHeight = dInfinity; | ||
190 | m_fMaxHeight = -dInfinity; | ||
191 | |||
192 | for (i=0; i<m_nWidthSamples*m_nDepthSamples; i++) | ||
193 | { | ||
194 | h = static_cast< dReal >( data_double[i] ); | ||
195 | if (h < m_fMinHeight) m_fMinHeight = h; | ||
196 | if (h > m_fMaxHeight) m_fMaxHeight = h; | ||
197 | } | ||
198 | |||
199 | break; | ||
200 | |||
201 | } | ||
202 | |||
203 | // scale and offset | ||
204 | m_fMinHeight *= m_fScale; | ||
205 | m_fMaxHeight *= m_fScale; | ||
206 | m_fMinHeight += m_fOffset; | ||
207 | m_fMaxHeight += m_fOffset; | ||
208 | |||
209 | // add thickness | ||
210 | m_fMinHeight -= m_fThickness; | ||
211 | } | ||
212 | |||
213 | |||
214 | // returns whether point is over terrain Cell triangle? | ||
215 | bool dxHeightfieldData::IsOnHeightfield ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const | ||
216 | { | ||
217 | { | ||
218 | const dReal MaxX = CellOrigin[0] + m_fSampleWidth; | ||
219 | const dReal TolX = m_fSampleWidth * TERRAINTOL; | ||
220 | if ((pos[0]<CellOrigin[0]-TolX) || (pos[0]>MaxX+TolX)) | ||
221 | return false; | ||
222 | } | ||
223 | |||
224 | { | ||
225 | const dReal MaxZ = CellOrigin[2] + m_fSampleDepth; | ||
226 | const dReal TolZ = m_fSampleDepth * TERRAINTOL; | ||
227 | if ((pos[2]<CellOrigin[2]-TolZ) || (pos[2]>MaxZ+TolZ)) | ||
228 | return false; | ||
229 | } | ||
230 | |||
231 | // add X percentage position on cell and Z percentage position on cell | ||
232 | const dReal pctTotal = (pos[0] - CellOrigin[0]) * m_fInvSampleWidth | ||
233 | + (pos[2] - CellOrigin[2]) * m_fInvSampleDepth; | ||
234 | |||
235 | if (isABC) | ||
236 | { | ||
237 | if (pctTotal >= REAL(1.0) + TERRAINTOL) | ||
238 | return false; | ||
239 | else | ||
240 | return true; | ||
241 | } | ||
242 | else if (pctTotal <= REAL(1.0) - TERRAINTOL) | ||
243 | { | ||
244 | return false; | ||
245 | } | ||
246 | return true; | ||
247 | } | ||
248 | // returns whether point is over terrain Cell triangle? | ||
249 | bool dxHeightfieldData::IsOnHeightfield2 ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const | ||
250 | { | ||
251 | dReal MaxX, MinX; | ||
252 | dReal MaxZ, MinZ; | ||
253 | if (isABC) | ||
254 | { | ||
255 | // point A | ||
256 | MinX = CellOrigin[0]; | ||
257 | MaxX = CellOrigin[0] + m_fSampleWidth; | ||
258 | |||
259 | MinZ = CellOrigin[2]; | ||
260 | MaxZ = CellOrigin[2] + m_fSampleDepth; | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | // point D | ||
265 | MinX = CellOrigin[0] - m_fSampleWidth; | ||
266 | MaxX = CellOrigin[0]; | ||
267 | |||
268 | MinZ = CellOrigin[2] - m_fSampleDepth; | ||
269 | MaxZ = CellOrigin[2]; | ||
270 | } | ||
271 | |||
272 | // check if inside CELL | ||
273 | { | ||
274 | const dReal TolX = m_fSampleWidth * TERRAINTOL; | ||
275 | if ((pos[0]<MinX-TolX) || (pos[0]>MaxX+TolX)) | ||
276 | return false; | ||
277 | } | ||
278 | |||
279 | { | ||
280 | const dReal TolZ = m_fSampleDepth * TERRAINTOL; | ||
281 | if ((pos[2]<MinZ-TolZ) || (pos[2]>MaxZ+TolZ)) | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | // Sum up X percentage position on cell and Z percentage position on cell | ||
286 | const dReal pctTotal = (pos[0] - MinX) * m_fInvSampleWidth | ||
287 | + (pos[2] - MinZ) * m_fInvSampleDepth; | ||
288 | |||
289 | // check if inside respective Triangle of Cell | ||
290 | if (isABC) | ||
291 | { | ||
292 | if (pctTotal >= REAL(1.0) + TERRAINTOL) | ||
293 | return false; | ||
294 | else | ||
295 | return true; | ||
296 | } | ||
297 | else if (pctTotal <= REAL(1.0) - TERRAINTOL) | ||
298 | { | ||
299 | return false; | ||
300 | } | ||
301 | return true; | ||
302 | } | ||
303 | |||
304 | |||
305 | // returns height at given sample coordinates | ||
306 | dReal dxHeightfieldData::GetHeight( int x, int z ) | ||
307 | { | ||
308 | static dReal h; | ||
309 | static unsigned char *data_byte; | ||
310 | static short *data_short; | ||
311 | static float *data_float; | ||
312 | static double *data_double; | ||
313 | |||
314 | if ( m_bWrapMode == 0 ) | ||
315 | { | ||
316 | // Finite | ||
317 | if ( x < 0 ) x = 0; | ||
318 | if ( z < 0 ) z = 0; | ||
319 | if ( x > m_nWidthSamples - 1 ) x = m_nWidthSamples - 1; | ||
320 | if ( z > m_nDepthSamples - 1 ) z = m_nDepthSamples - 1; | ||
321 | } | ||
322 | else | ||
323 | { | ||
324 | // Infinite | ||
325 | x %= m_nWidthSamples - 1; | ||
326 | z %= m_nDepthSamples - 1; | ||
327 | if ( x < 0 ) x += m_nWidthSamples - 1; | ||
328 | if ( z < 0 ) z += m_nDepthSamples - 1; | ||
329 | } | ||
330 | |||
331 | switch ( m_nGetHeightMode ) | ||
332 | { | ||
333 | |||
334 | // callback (dReal) | ||
335 | case 0: | ||
336 | h = (*m_pGetHeightCallback)(m_pUserData, x, z); | ||
337 | break; | ||
338 | |||
339 | // byte | ||
340 | case 1: | ||
341 | data_byte = (unsigned char*)m_pHeightData; | ||
342 | h = data_byte[x+(z * m_nWidthSamples)]; | ||
343 | break; | ||
344 | |||
345 | // short | ||
346 | case 2: | ||
347 | data_short = (short*)m_pHeightData; | ||
348 | h = data_short[x+(z * m_nWidthSamples)]; | ||
349 | break; | ||
350 | |||
351 | // float | ||
352 | case 3: | ||
353 | data_float = (float*)m_pHeightData; | ||
354 | h = data_float[x+(z * m_nWidthSamples)]; | ||
355 | break; | ||
356 | |||
357 | // double | ||
358 | case 4: | ||
359 | data_double = (double*)m_pHeightData; | ||
360 | h = static_cast< dReal >( data_double[x+(z * m_nWidthSamples)] ); | ||
361 | break; | ||
362 | } | ||
363 | |||
364 | return (h * m_fScale) + m_fOffset; | ||
365 | } | ||
366 | |||
367 | |||
368 | // returns height at given coordinates | ||
369 | dReal dxHeightfieldData::GetHeight( dReal x, dReal z ) | ||
370 | { | ||
371 | dReal dnX = dFloor( x * m_fInvSampleWidth ); | ||
372 | dReal dnZ = dFloor( z * m_fInvSampleDepth ); | ||
373 | |||
374 | dReal dx = ( x - ( dnX * m_fSampleWidth ) ) * m_fInvSampleWidth; | ||
375 | dReal dz = ( z - ( dnZ * m_fSampleDepth ) ) * m_fInvSampleDepth; | ||
376 | |||
377 | int nX = int( dnX ); | ||
378 | int nZ = int( dnZ ); | ||
379 | |||
380 | //dIASSERT( ( dx + dEpsilon >= 0.0f ) && ( dx - dEpsilon <= 1.0f ) ); | ||
381 | //dIASSERT( ( dz + dEpsilon >= 0.0f ) && ( dz - dEpsilon <= 1.0f ) ); | ||
382 | |||
383 | dReal y, y0; | ||
384 | |||
385 | if ( dx + dz < REAL( 1.0 ) ) | ||
386 | { | ||
387 | y0 = GetHeight( nX, nZ ); | ||
388 | |||
389 | y = y0 + ( GetHeight( nX + 1, nZ ) - y0 ) * dx | ||
390 | + ( GetHeight( nX, nZ + 1 ) - y0 ) * dz; | ||
391 | } | ||
392 | else | ||
393 | { | ||
394 | y0 = GetHeight( nX + 1, nZ + 1 ); | ||
395 | |||
396 | y = y0 + ( GetHeight( nX + 1, nZ ) - y0 ) * ( REAL(1.0) - dz ) + | ||
397 | ( GetHeight( nX, nZ + 1 ) - y0 ) * ( REAL(1.0) - dx ); | ||
398 | } | ||
399 | |||
400 | return y; | ||
401 | } | ||
402 | |||
403 | |||
404 | // dxHeightfieldData destructor | ||
405 | dxHeightfieldData::~dxHeightfieldData() | ||
406 | { | ||
407 | static unsigned char *data_byte; | ||
408 | static short *data_short; | ||
409 | static float *data_float; | ||
410 | static double *data_double; | ||
411 | |||
412 | dIASSERT( m_pHeightData ); | ||
413 | |||
414 | if ( m_bCopyHeightData ) | ||
415 | { | ||
416 | switch ( m_nGetHeightMode ) | ||
417 | { | ||
418 | |||
419 | // callback | ||
420 | case 0: | ||
421 | // do nothing | ||
422 | break; | ||
423 | |||
424 | // byte | ||
425 | case 1: | ||
426 | data_byte = (unsigned char*)m_pHeightData; | ||
427 | delete [] data_byte; | ||
428 | break; | ||
429 | |||
430 | // short | ||
431 | case 2: | ||
432 | data_short = (short*)m_pHeightData; | ||
433 | delete [] data_short; | ||
434 | break; | ||
435 | |||
436 | // float | ||
437 | case 3: | ||
438 | data_float = (float*)m_pHeightData; | ||
439 | delete [] data_float; | ||
440 | break; | ||
441 | |||
442 | // double | ||
443 | case 4: | ||
444 | data_double = (double*)m_pHeightData; | ||
445 | delete [] data_double; | ||
446 | break; | ||
447 | |||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | |||
453 | //////// dxHeightfield ///////////////////////////////////////////////////////////////// | ||
454 | |||
455 | |||
456 | // dxHeightfield constructor | ||
457 | dxHeightfield::dxHeightfield( dSpaceID space, | ||
458 | dHeightfieldDataID data, | ||
459 | int bPlaceable ) : | ||
460 | dxGeom( space, bPlaceable ), | ||
461 | tempPlaneBuffer(0), | ||
462 | tempPlaneInstances(0), | ||
463 | tempPlaneBufferSize(0), | ||
464 | tempTriangleBuffer(0), | ||
465 | tempTriangleBufferSize(0), | ||
466 | tempHeightBuffer(0), | ||
467 | tempHeightInstances(0), | ||
468 | tempHeightBufferSizeX(0), | ||
469 | tempHeightBufferSizeZ(0) | ||
470 | { | ||
471 | type = dHeightfieldClass; | ||
472 | this->m_p_data = data; | ||
473 | } | ||
474 | |||
475 | |||
476 | // compute axis aligned bounding box | ||
477 | void dxHeightfield::computeAABB() | ||
478 | { | ||
479 | const dxHeightfieldData *d = m_p_data; | ||
480 | |||
481 | if ( d->m_bWrapMode == 0 ) | ||
482 | { | ||
483 | // Finite | ||
484 | if ( gflags & GEOM_PLACEABLE ) | ||
485 | { | ||
486 | dReal dx[6], dy[6], dz[6]; | ||
487 | |||
488 | // Y-axis | ||
489 | dy[0] = ( final_posr->R[ 1] * d->m_fMinHeight ); | ||
490 | dy[1] = ( final_posr->R[ 5] * d->m_fMinHeight ); | ||
491 | dy[2] = ( final_posr->R[ 9] * d->m_fMinHeight ); | ||
492 | dy[3] = ( final_posr->R[ 1] * d->m_fMaxHeight ); | ||
493 | dy[4] = ( final_posr->R[ 5] * d->m_fMaxHeight ); | ||
494 | dy[5] = ( final_posr->R[ 9] * d->m_fMaxHeight ); | ||
495 | |||
496 | #ifdef DHEIGHTFIELD_CORNER_ORIGIN | ||
497 | |||
498 | // X-axis | ||
499 | dx[0] = 0; dx[3] = ( final_posr->R[ 0] * d->m_fWidth ); | ||
500 | dx[1] = 0; dx[4] = ( final_posr->R[ 4] * d->m_fWidth ); | ||
501 | dx[2] = 0; dx[5] = ( final_posr->R[ 8] * d->m_fWidth ); | ||
502 | |||
503 | // Z-axis | ||
504 | dz[0] = 0; dz[3] = ( final_posr->R[ 2] * d->m_fDepth ); | ||
505 | dz[1] = 0; dz[4] = ( final_posr->R[ 6] * d->m_fDepth ); | ||
506 | dz[2] = 0; dz[5] = ( final_posr->R[10] * d->m_fDepth ); | ||
507 | |||
508 | #else // DHEIGHTFIELD_CORNER_ORIGIN | ||
509 | |||
510 | // X-axis | ||
511 | dx[0] = ( final_posr->R[ 0] * -d->m_fHalfWidth ); | ||
512 | dx[1] = ( final_posr->R[ 4] * -d->m_fHalfWidth ); | ||
513 | dx[2] = ( final_posr->R[ 8] * -d->m_fHalfWidth ); | ||
514 | dx[3] = ( final_posr->R[ 0] * d->m_fHalfWidth ); | ||
515 | dx[4] = ( final_posr->R[ 4] * d->m_fHalfWidth ); | ||
516 | dx[5] = ( final_posr->R[ 8] * d->m_fHalfWidth ); | ||
517 | |||
518 | // Z-axis | ||
519 | dz[0] = ( final_posr->R[ 2] * -d->m_fHalfDepth ); | ||
520 | dz[1] = ( final_posr->R[ 6] * -d->m_fHalfDepth ); | ||
521 | dz[2] = ( final_posr->R[10] * -d->m_fHalfDepth ); | ||
522 | dz[3] = ( final_posr->R[ 2] * d->m_fHalfDepth ); | ||
523 | dz[4] = ( final_posr->R[ 6] * d->m_fHalfDepth ); | ||
524 | dz[5] = ( final_posr->R[10] * d->m_fHalfDepth ); | ||
525 | |||
526 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
527 | |||
528 | // X extents | ||
529 | aabb[0] = final_posr->pos[0] + | ||
530 | dMIN3( dMIN( dx[0], dx[3] ), dMIN( dy[0], dy[3] ), dMIN( dz[0], dz[3] ) ); | ||
531 | aabb[1] = final_posr->pos[0] + | ||
532 | dMAX3( dMAX( dx[0], dx[3] ), dMAX( dy[0], dy[3] ), dMAX( dz[0], dz[3] ) ); | ||
533 | |||
534 | // Y extents | ||
535 | aabb[2] = final_posr->pos[1] + | ||
536 | dMIN3( dMIN( dx[1], dx[4] ), dMIN( dy[1], dy[4] ), dMIN( dz[1], dz[4] ) ); | ||
537 | aabb[3] = final_posr->pos[1] + | ||
538 | dMAX3( dMAX( dx[1], dx[4] ), dMAX( dy[1], dy[4] ), dMAX( dz[1], dz[4] ) ); | ||
539 | |||
540 | // Z extents | ||
541 | aabb[4] = final_posr->pos[2] + | ||
542 | dMIN3( dMIN( dx[2], dx[5] ), dMIN( dy[2], dy[5] ), dMIN( dz[2], dz[5] ) ); | ||
543 | aabb[5] = final_posr->pos[2] + | ||
544 | dMAX3( dMAX( dx[2], dx[5] ), dMAX( dy[2], dy[5] ), dMAX( dz[2], dz[5] ) ); | ||
545 | } | ||
546 | else | ||
547 | { | ||
548 | |||
549 | #ifdef DHEIGHTFIELD_CORNER_ORIGIN | ||
550 | |||
551 | aabb[0] = 0; aabb[1] = d->m_fWidth; | ||
552 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
553 | aabb[4] = 0; aabb[5] = d->m_fDepth; | ||
554 | |||
555 | #else // DHEIGHTFIELD_CORNER_ORIGIN | ||
556 | |||
557 | aabb[0] = -d->m_fHalfWidth; aabb[1] = +d->m_fHalfWidth; | ||
558 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
559 | aabb[4] = -d->m_fHalfDepth; aabb[5] = +d->m_fHalfDepth; | ||
560 | |||
561 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
562 | |||
563 | } | ||
564 | } | ||
565 | else | ||
566 | { | ||
567 | // Infinite | ||
568 | if ( gflags & GEOM_PLACEABLE ) | ||
569 | { | ||
570 | aabb[0] = -dInfinity; aabb[1] = +dInfinity; | ||
571 | aabb[2] = -dInfinity; aabb[3] = +dInfinity; | ||
572 | aabb[4] = -dInfinity; aabb[5] = +dInfinity; | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | aabb[0] = -dInfinity; aabb[1] = +dInfinity; | ||
577 | aabb[2] = d->m_fMinHeight; aabb[3] = d->m_fMaxHeight; | ||
578 | aabb[4] = -dInfinity; aabb[5] = +dInfinity; | ||
579 | } | ||
580 | } | ||
581 | |||
582 | } | ||
583 | |||
584 | |||
585 | // dxHeightfield destructor | ||
586 | dxHeightfield::~dxHeightfield() | ||
587 | { | ||
588 | resetTriangleBuffer(); | ||
589 | resetPlaneBuffer(); | ||
590 | resetHeightBuffer(); | ||
591 | } | ||
592 | |||
593 | void dxHeightfield::allocateTriangleBuffer(size_t numTri) | ||
594 | { | ||
595 | size_t alignedNumTri = AlignBufferSize(numTri, TEMP_TRIANGLE_BUFFER_ELEMENT_COUNT_ALIGNMENT); | ||
596 | tempTriangleBufferSize = alignedNumTri; | ||
597 | tempTriangleBuffer = new HeightFieldTriangle[alignedNumTri]; | ||
598 | } | ||
599 | |||
600 | void dxHeightfield::resetTriangleBuffer() | ||
601 | { | ||
602 | delete[] tempTriangleBuffer; | ||
603 | } | ||
604 | |||
605 | void dxHeightfield::allocatePlaneBuffer(size_t numTri) | ||
606 | { | ||
607 | size_t alignedNumTri = AlignBufferSize(numTri, TEMP_PLANE_BUFFER_ELEMENT_COUNT_ALIGNMENT); | ||
608 | tempPlaneBufferSize = alignedNumTri; | ||
609 | tempPlaneBuffer = new HeightFieldPlane *[alignedNumTri]; | ||
610 | tempPlaneInstances = new HeightFieldPlane[alignedNumTri]; | ||
611 | |||
612 | HeightFieldPlane *ptrPlaneMatrix = tempPlaneInstances; | ||
613 | for (size_t indexTri = 0; indexTri != alignedNumTri; indexTri++) | ||
614 | { | ||
615 | tempPlaneBuffer[indexTri] = ptrPlaneMatrix; | ||
616 | ptrPlaneMatrix += 1; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | void dxHeightfield::resetPlaneBuffer() | ||
621 | { | ||
622 | delete[] tempPlaneInstances; | ||
623 | delete[] tempPlaneBuffer; | ||
624 | } | ||
625 | |||
626 | void dxHeightfield::allocateHeightBuffer(size_t numX, size_t numZ) | ||
627 | { | ||
628 | size_t alignedNumX = AlignBufferSize(numX, TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_X); | ||
629 | size_t alignedNumZ = AlignBufferSize(numZ, TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_Z); | ||
630 | tempHeightBufferSizeX = alignedNumX; | ||
631 | tempHeightBufferSizeZ = alignedNumZ; | ||
632 | tempHeightBuffer = new HeightFieldVertex *[alignedNumX]; | ||
633 | size_t numCells = alignedNumX * alignedNumZ; | ||
634 | tempHeightInstances = new HeightFieldVertex [numCells]; | ||
635 | |||
636 | HeightFieldVertex *ptrHeightMatrix = tempHeightInstances; | ||
637 | for (size_t indexX = 0; indexX != alignedNumX; indexX++) | ||
638 | { | ||
639 | tempHeightBuffer[indexX] = ptrHeightMatrix; | ||
640 | ptrHeightMatrix += alignedNumZ; | ||
641 | } | ||
642 | } | ||
643 | |||
644 | void dxHeightfield::resetHeightBuffer() | ||
645 | { | ||
646 | delete[] tempHeightInstances; | ||
647 | delete[] tempHeightBuffer; | ||
648 | } | ||
649 | //////// Heightfield data interface //////////////////////////////////////////////////// | ||
650 | |||
651 | |||
652 | dHeightfieldDataID dGeomHeightfieldDataCreate() | ||
653 | { | ||
654 | return new dxHeightfieldData(); | ||
655 | } | ||
656 | |||
657 | |||
658 | void dGeomHeightfieldDataBuildCallback( dHeightfieldDataID d, | ||
659 | void* pUserData, dHeightfieldGetHeight* pCallback, | ||
660 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
661 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
662 | { | ||
663 | dUASSERT( d, "argument not Heightfield data" ); | ||
664 | dIASSERT( pCallback ); | ||
665 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
666 | dIASSERT( depthSamples >= 2 ); | ||
667 | |||
668 | // callback | ||
669 | d->m_nGetHeightMode = 0; | ||
670 | d->m_pUserData = pUserData; | ||
671 | d->m_pGetHeightCallback = pCallback; | ||
672 | |||
673 | // set info | ||
674 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
675 | |||
676 | // default bounds | ||
677 | d->m_fMinHeight = -dInfinity; | ||
678 | d->m_fMaxHeight = dInfinity; | ||
679 | } | ||
680 | |||
681 | |||
682 | void dGeomHeightfieldDataBuildByte( dHeightfieldDataID d, | ||
683 | const unsigned char *pHeightData, int bCopyHeightData, | ||
684 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
685 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
686 | { | ||
687 | dUASSERT( d, "Argument not Heightfield data" ); | ||
688 | dIASSERT( pHeightData ); | ||
689 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
690 | dIASSERT( depthSamples >= 2 ); | ||
691 | |||
692 | // set info | ||
693 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
694 | d->m_nGetHeightMode = 1; | ||
695 | d->m_bCopyHeightData = bCopyHeightData; | ||
696 | |||
697 | if ( d->m_bCopyHeightData == 0 ) | ||
698 | { | ||
699 | // Data is referenced only. | ||
700 | d->m_pHeightData = pHeightData; | ||
701 | } | ||
702 | else | ||
703 | { | ||
704 | // We own the height data, allocate storage | ||
705 | d->m_pHeightData = new unsigned char[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
706 | dIASSERT( d->m_pHeightData ); | ||
707 | |||
708 | // Copy data. | ||
709 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
710 | sizeof( unsigned char ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
711 | } | ||
712 | |||
713 | // Find height bounds | ||
714 | d->ComputeHeightBounds(); | ||
715 | } | ||
716 | |||
717 | |||
718 | void dGeomHeightfieldDataBuildShort( dHeightfieldDataID d, | ||
719 | const short* pHeightData, int bCopyHeightData, | ||
720 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
721 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
722 | { | ||
723 | dUASSERT( d, "Argument not Heightfield data" ); | ||
724 | dIASSERT( pHeightData ); | ||
725 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
726 | dIASSERT( depthSamples >= 2 ); | ||
727 | |||
728 | // set info | ||
729 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
730 | d->m_nGetHeightMode = 2; | ||
731 | d->m_bCopyHeightData = bCopyHeightData; | ||
732 | |||
733 | if ( d->m_bCopyHeightData == 0 ) | ||
734 | { | ||
735 | // Data is referenced only. | ||
736 | d->m_pHeightData = pHeightData; | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | // We own the height data, allocate storage | ||
741 | d->m_pHeightData = new short[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
742 | dIASSERT( d->m_pHeightData ); | ||
743 | |||
744 | // Copy data. | ||
745 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
746 | sizeof( short ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
747 | } | ||
748 | |||
749 | // Find height bounds | ||
750 | d->ComputeHeightBounds(); | ||
751 | } | ||
752 | |||
753 | |||
754 | void dGeomHeightfieldDataBuildSingle( dHeightfieldDataID d, | ||
755 | const float *pHeightData, int bCopyHeightData, | ||
756 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
757 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
758 | { | ||
759 | dUASSERT( d, "Argument not Heightfield data" ); | ||
760 | dIASSERT( pHeightData ); | ||
761 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
762 | dIASSERT( depthSamples >= 2 ); | ||
763 | |||
764 | // set info | ||
765 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
766 | d->m_nGetHeightMode = 3; | ||
767 | d->m_bCopyHeightData = bCopyHeightData; | ||
768 | |||
769 | if ( d->m_bCopyHeightData == 0 ) | ||
770 | { | ||
771 | // Data is referenced only. | ||
772 | d->m_pHeightData = pHeightData; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | // We own the height data, allocate storage | ||
777 | d->m_pHeightData = new float[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
778 | dIASSERT( d->m_pHeightData ); | ||
779 | |||
780 | // Copy data. | ||
781 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
782 | sizeof( float ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
783 | } | ||
784 | |||
785 | // Find height bounds | ||
786 | d->ComputeHeightBounds(); | ||
787 | } | ||
788 | |||
789 | void dGeomHeightfieldDataBuildDouble( dHeightfieldDataID d, | ||
790 | const double *pHeightData, int bCopyHeightData, | ||
791 | dReal width, dReal depth, int widthSamples, int depthSamples, | ||
792 | dReal scale, dReal offset, dReal thickness, int bWrap ) | ||
793 | { | ||
794 | dUASSERT( d, "Argument not Heightfield data" ); | ||
795 | dIASSERT( pHeightData ); | ||
796 | dIASSERT( widthSamples >= 2 ); // Ensure we're making something with at least one cell. | ||
797 | dIASSERT( depthSamples >= 2 ); | ||
798 | |||
799 | // set info | ||
800 | d->SetData( widthSamples, depthSamples, width, depth, scale, offset, thickness, bWrap ); | ||
801 | d->m_nGetHeightMode = 4; | ||
802 | d->m_bCopyHeightData = bCopyHeightData; | ||
803 | |||
804 | if ( d->m_bCopyHeightData == 0 ) | ||
805 | { | ||
806 | // Data is referenced only. | ||
807 | d->m_pHeightData = pHeightData; | ||
808 | } | ||
809 | else | ||
810 | { | ||
811 | // We own the height data, allocate storage | ||
812 | d->m_pHeightData = new double[ d->m_nWidthSamples * d->m_nDepthSamples ]; | ||
813 | dIASSERT( d->m_pHeightData ); | ||
814 | |||
815 | // Copy data. | ||
816 | memcpy( (void*)d->m_pHeightData, pHeightData, | ||
817 | sizeof( double ) * d->m_nWidthSamples * d->m_nDepthSamples ); | ||
818 | } | ||
819 | |||
820 | // Find height bounds | ||
821 | d->ComputeHeightBounds(); | ||
822 | } | ||
823 | |||
824 | |||
825 | |||
826 | |||
827 | void dGeomHeightfieldDataSetBounds( dHeightfieldDataID d, dReal minHeight, dReal maxHeight ) | ||
828 | { | ||
829 | dUASSERT(d, "Argument not Heightfield data"); | ||
830 | d->m_fMinHeight = ( minHeight * d->m_fScale ) + d->m_fOffset - d->m_fThickness; | ||
831 | d->m_fMaxHeight = ( maxHeight * d->m_fScale ) + d->m_fOffset; | ||
832 | } | ||
833 | |||
834 | |||
835 | void dGeomHeightfieldDataDestroy( dHeightfieldDataID d ) | ||
836 | { | ||
837 | dUASSERT(d, "argument not Heightfield data"); | ||
838 | delete d; | ||
839 | } | ||
840 | |||
841 | |||
842 | //////// Heightfield geom interface //////////////////////////////////////////////////// | ||
843 | |||
844 | |||
845 | dGeomID dCreateHeightfield( dSpaceID space, dHeightfieldDataID data, int bPlaceable ) | ||
846 | { | ||
847 | return new dxHeightfield( space, data, bPlaceable ); | ||
848 | } | ||
849 | |||
850 | |||
851 | void dGeomHeightfieldSetHeightfieldData( dGeomID g, dHeightfieldDataID d ) | ||
852 | { | ||
853 | dxHeightfield* geom = (dxHeightfield*) g; | ||
854 | geom->data = d; | ||
855 | } | ||
856 | |||
857 | |||
858 | dHeightfieldDataID dGeomHeightfieldGetHeightfieldData( dGeomID g ) | ||
859 | { | ||
860 | dxHeightfield* geom = (dxHeightfield*) g; | ||
861 | return geom->m_p_data; | ||
862 | } | ||
863 | |||
864 | //////// dxHeightfield ///////////////////////////////////////////////////////////////// | ||
865 | |||
866 | |||
867 | // Typedef for generic 'get point depth' function | ||
868 | typedef dReal dGetDepthFn( dGeomID g, dReal x, dReal y, dReal z ); | ||
869 | |||
870 | |||
871 | #define DMESS(A) \ | ||
872 | dMessage(0,"Contact Plane (%d %d %d) %.5e %.5e (%.5e %.5e %.5e)(%.5e %.5e %.5e)).", \ | ||
873 | x,z,A, \ | ||
874 | pContact->depth, \ | ||
875 | dGeomSphereGetRadius(o2), \ | ||
876 | pContact->pos[0], \ | ||
877 | pContact->pos[1], \ | ||
878 | pContact->pos[2], \ | ||
879 | pContact->normal[0], \ | ||
880 | pContact->normal[1], \ | ||
881 | pContact->normal[2]); | ||
882 | |||
883 | static inline bool DescendingTriangleSort(const HeightFieldTriangle * const A, const HeightFieldTriangle * const B) | ||
884 | { | ||
885 | return ((A->maxAAAB - B->maxAAAB) > dEpsilon); | ||
886 | } | ||
887 | static inline bool DescendingPlaneSort(const HeightFieldPlane * const A, const HeightFieldPlane * const B) | ||
888 | { | ||
889 | return ((A->maxAAAB - B->maxAAAB) > dEpsilon); | ||
890 | } | ||
891 | |||
892 | void dxHeightfield::sortPlanes(const size_t numPlanes) | ||
893 | { | ||
894 | bool has_swapped = true; | ||
895 | do | ||
896 | { | ||
897 | has_swapped = false;//reset flag | ||
898 | for (size_t i = 0; i < numPlanes - 1; i++) | ||
899 | { | ||
900 | //if they are in the wrong order | ||
901 | if (DescendingPlaneSort(tempPlaneBuffer[i], tempPlaneBuffer[i + 1])) | ||
902 | { | ||
903 | //exchange them | ||
904 | HeightFieldPlane * tempPlane = tempPlaneBuffer[i]; | ||
905 | tempPlaneBuffer[i] = tempPlaneBuffer[i + 1]; | ||
906 | tempPlaneBuffer[i + 1] = tempPlane; | ||
907 | |||
908 | //we have swapped at least once, list may not be sorted yet | ||
909 | has_swapped = true; | ||
910 | } | ||
911 | } | ||
912 | } //if no swaps were made during this pass, the list has been sorted | ||
913 | while (has_swapped); | ||
914 | } | ||
915 | |||
916 | static inline dReal DistancePointToLine(const dVector3 &_point, | ||
917 | const dVector3 &_pt0, | ||
918 | const dVector3 &_Edge, | ||
919 | const dReal _Edgelength) | ||
920 | { | ||
921 | dVector3 v; | ||
922 | dVector3Subtract(_point, _pt0, v); | ||
923 | dVector3 s; | ||
924 | dVector3Copy (_Edge, s); | ||
925 | const dReal dot = dVector3Dot(v, _Edge) / _Edgelength; | ||
926 | dVector3Scale(s, dot); | ||
927 | dVector3Subtract(v, s, v); | ||
928 | return dVector3Length(v); | ||
929 | } | ||
930 | |||
931 | |||
932 | |||
933 | |||
934 | int dxHeightfield::dCollideHeightfieldZone( const int minX, const int maxX, const int minZ, const int maxZ, | ||
935 | dxGeom* o2, const int numMaxContactsPossible, | ||
936 | int flags, dContactGeom* contact, | ||
937 | int skip ) | ||
938 | { | ||
939 | dContactGeom *pContact = 0; | ||
940 | int x, z; | ||
941 | // check if not above or inside terrain first | ||
942 | // while filling a heightmap partial temporary buffer | ||
943 | const unsigned int numX = (maxX - minX) + 1; | ||
944 | const unsigned int numZ = (maxZ - minZ) + 1; | ||
945 | const dReal minO2Height = o2->aabb[2]; | ||
946 | const dReal maxO2Height = o2->aabb[3]; | ||
947 | unsigned int x_local, z_local; | ||
948 | dReal maxY = - dInfinity; | ||
949 | dReal minY = dInfinity; | ||
950 | // localize and const for faster access | ||
951 | const dReal cfSampleWidth = m_p_data->m_fSampleWidth; | ||
952 | const dReal cfSampleDepth = m_p_data->m_fSampleDepth; | ||
953 | { | ||
954 | if (tempHeightBufferSizeX < numX || tempHeightBufferSizeZ < numZ) | ||
955 | { | ||
956 | resetHeightBuffer(); | ||
957 | allocateHeightBuffer(numX, numZ); | ||
958 | } | ||
959 | |||
960 | dReal Xpos, Ypos; | ||
961 | Xpos = minX * cfSampleWidth; | ||
962 | |||
963 | |||
964 | for ( x = minX, x_local = 0; x_local < numX; x++, x_local++) | ||
965 | { | ||
966 | const dReal c_Xpos = Xpos; | ||
967 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
968 | Ypos = minZ * cfSampleDepth; | ||
969 | for ( z = minZ, z_local = 0; z_local < numZ; z++, z_local++) | ||
970 | { | ||
971 | const dReal h = m_p_data->GetHeight(x, z); | ||
972 | HeightFieldRow[z_local].vertex[0] = c_Xpos; | ||
973 | HeightFieldRow[z_local].vertex[1] = h; | ||
974 | HeightFieldRow[z_local].vertex[2] = Ypos; | ||
975 | |||
976 | |||
977 | maxY = dMAX(maxY, h); | ||
978 | minY = dMIN(minY, h); | ||
979 | |||
980 | |||
981 | Ypos += cfSampleDepth; | ||
982 | } | ||
983 | Xpos += cfSampleWidth; | ||
984 | } | ||
985 | if (minO2Height - maxY > -dEpsilon ) | ||
986 | { | ||
987 | //totally above heightfield | ||
988 | return 0; | ||
989 | } | ||
990 | if (minY - maxO2Height > -dEpsilon ) | ||
991 | { | ||
992 | // totally under heightfield | ||
993 | pContact = CONTACT(contact, 0); | ||
994 | |||
995 | pContact->pos[0] = o2->final_posr->pos[0]; | ||
996 | pContact->pos[1] = minY; | ||
997 | pContact->pos[2] = o2->final_posr->pos[2]; | ||
998 | |||
999 | pContact->normal[0] = 0; | ||
1000 | pContact->normal[1] = - 1; | ||
1001 | pContact->normal[2] = 0; | ||
1002 | |||
1003 | pContact->depth = minY - maxO2Height; | ||
1004 | |||
1005 | return 1; | ||
1006 | } | ||
1007 | } | ||
1008 | // get All Planes that could collide against. | ||
1009 | dColliderFn *geomRayNCollider; | ||
1010 | dColliderFn *geomNPlaneCollider; | ||
1011 | dGetDepthFn *geomNDepthGetter; | ||
1012 | |||
1013 | // int max_collisionContact = numMaxContactsPossible; -- not used | ||
1014 | switch (o2->type) | ||
1015 | { | ||
1016 | case dRayClass: | ||
1017 | geomRayNCollider = NULL; | ||
1018 | geomNPlaneCollider = dCollideRayPlane; | ||
1019 | geomNDepthGetter = NULL; | ||
1020 | //max_collisionContact = 1; | ||
1021 | break; | ||
1022 | |||
1023 | case dSphereClass: | ||
1024 | geomRayNCollider = dCollideRaySphere; | ||
1025 | geomNPlaneCollider = dCollideSpherePlane; | ||
1026 | geomNDepthGetter = dGeomSpherePointDepth; | ||
1027 | //max_collisionContact = 3; | ||
1028 | break; | ||
1029 | |||
1030 | case dBoxClass: | ||
1031 | geomRayNCollider = dCollideRayBox; | ||
1032 | geomNPlaneCollider = dCollideBoxPlane; | ||
1033 | geomNDepthGetter = dGeomBoxPointDepth; | ||
1034 | //max_collisionContact = 8; | ||
1035 | break; | ||
1036 | |||
1037 | case dCapsuleClass: | ||
1038 | geomRayNCollider = dCollideRayCapsule; | ||
1039 | geomNPlaneCollider = dCollideCapsulePlane; | ||
1040 | geomNDepthGetter = dGeomCapsulePointDepth; | ||
1041 | // max_collisionContact = 3; | ||
1042 | break; | ||
1043 | |||
1044 | case dCylinderClass: | ||
1045 | geomRayNCollider = dCollideRayCylinder; | ||
1046 | geomNPlaneCollider = dCollideCylinderPlane; | ||
1047 | geomNDepthGetter = NULL;// TODO: dGeomCCylinderPointDepth | ||
1048 | //max_collisionContact = 3; | ||
1049 | break; | ||
1050 | |||
1051 | case dConvexClass: | ||
1052 | geomRayNCollider = dCollideRayConvex; | ||
1053 | geomNPlaneCollider = dCollideConvexPlane; | ||
1054 | geomNDepthGetter = NULL;// TODO: dGeomConvexPointDepth; | ||
1055 | //max_collisionContact = 3; | ||
1056 | break; | ||
1057 | |||
1058 | #if dTRIMESH_ENABLED | ||
1059 | |||
1060 | case dTriMeshClass: | ||
1061 | geomRayNCollider = dCollideRayTrimesh; | ||
1062 | geomNPlaneCollider = dCollideTrimeshPlane; | ||
1063 | geomNDepthGetter = NULL;// TODO: dGeomTrimeshPointDepth; | ||
1064 | //max_collisionContact = 3; | ||
1065 | break; | ||
1066 | |||
1067 | #endif // dTRIMESH_ENABLED | ||
1068 | |||
1069 | default: | ||
1070 | dIASSERT(0); // Shouldn't ever get here. | ||
1071 | break; | ||
1072 | |||
1073 | } | ||
1074 | |||
1075 | dxPlane myplane(0,0,0,0,0); | ||
1076 | dxPlane* sliding_plane = &myplane; | ||
1077 | dReal triplane[4]; | ||
1078 | int i; | ||
1079 | |||
1080 | // check some trivial case. | ||
1081 | // Vector Up plane | ||
1082 | if (maxY - minY < dEpsilon) | ||
1083 | { | ||
1084 | // it's a single plane. | ||
1085 | triplane[0] = 0; | ||
1086 | triplane[1] = 1; | ||
1087 | triplane[2] = 0; | ||
1088 | triplane[3] = minY; | ||
1089 | dGeomPlaneSetNoNormalize (sliding_plane, triplane); | ||
1090 | // find collision and compute contact points | ||
1091 | const int numTerrainContacts = geomNPlaneCollider (o2, sliding_plane, flags, contact, skip); | ||
1092 | dIASSERT(numTerrainContacts <= numMaxContactsPossible); | ||
1093 | for (i = 0; i < numTerrainContacts; i++) | ||
1094 | { | ||
1095 | pContact = CONTACT(contact, i*skip); | ||
1096 | dOPESIGN(pContact->normal, =, -, triplane); | ||
1097 | } | ||
1098 | return numTerrainContacts; | ||
1099 | } | ||
1100 | // unique plane | ||
1101 | { | ||
1102 | // check for very simple plane heightfield | ||
1103 | dReal minXHeightDelta = dInfinity, maxXHeightDelta = - dInfinity; | ||
1104 | dReal minZHeightDelta = dInfinity, maxZHeightDelta = - dInfinity; | ||
1105 | |||
1106 | |||
1107 | dReal lastXHeight = tempHeightBuffer[0][0].vertex[1]; | ||
1108 | for ( x_local = 1; x_local < numX; x_local++) | ||
1109 | { | ||
1110 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
1111 | |||
1112 | const dReal deltaX = HeightFieldRow[0].vertex[1] - lastXHeight; | ||
1113 | |||
1114 | maxXHeightDelta = dMAX (maxXHeightDelta, deltaX); | ||
1115 | minXHeightDelta = dMIN (minXHeightDelta, deltaX); | ||
1116 | |||
1117 | dReal lastZHeight = HeightFieldRow[0].vertex[1]; | ||
1118 | for ( z_local = 1; z_local < numZ; z_local++) | ||
1119 | { | ||
1120 | const dReal deltaZ = (HeightFieldRow[z_local].vertex[1] - lastZHeight); | ||
1121 | |||
1122 | maxZHeightDelta = dMAX (maxZHeightDelta, deltaZ); | ||
1123 | minZHeightDelta = dMIN (minZHeightDelta, deltaZ); | ||
1124 | |||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | if (maxZHeightDelta - minZHeightDelta < dEpsilon && | ||
1129 | maxXHeightDelta - minXHeightDelta < dEpsilon ) | ||
1130 | { | ||
1131 | // it's a single plane. | ||
1132 | const dVector3 &A = tempHeightBuffer[0][0].vertex; | ||
1133 | const dVector3 &B = tempHeightBuffer[1][0].vertex; | ||
1134 | const dVector3 &C = tempHeightBuffer[0][1].vertex; | ||
1135 | |||
1136 | // define 2 edges and a point that will define collision plane | ||
1137 | { | ||
1138 | dVector3 Edge1, Edge2; | ||
1139 | dVector3Subtract(C, A, Edge1); | ||
1140 | dVector3Subtract(B, A, Edge2); | ||
1141 | dVector3Cross(Edge1, Edge2, triplane); | ||
1142 | } | ||
1143 | |||
1144 | // Define Plane | ||
1145 | // Normalize plane normal | ||
1146 | const dReal dinvlength = REAL(1.0) / dVector3Length(triplane); | ||
1147 | triplane[0] *= dinvlength; | ||
1148 | triplane[1] *= dinvlength; | ||
1149 | triplane[2] *= dinvlength; | ||
1150 | // get distance to origin from plane | ||
1151 | triplane[3] = dVector3Dot(triplane, A); | ||
1152 | |||
1153 | dGeomPlaneSetNoNormalize (sliding_plane, triplane); | ||
1154 | // find collision and compute contact points | ||
1155 | const int numTerrainContacts = geomNPlaneCollider (o2, sliding_plane, flags, contact, skip); | ||
1156 | dIASSERT(numTerrainContacts <= numMaxContactsPossible); | ||
1157 | for (i = 0; i < numTerrainContacts; i++) | ||
1158 | { | ||
1159 | pContact = CONTACT(contact, i*skip); | ||
1160 | dOPESIGN(pContact->normal, =, -, triplane); | ||
1161 | } | ||
1162 | return numTerrainContacts; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | |||
1167 | int numTerrainContacts = 0; | ||
1168 | dContactGeom *PlaneContact = m_p_data->m_contacts; | ||
1169 | |||
1170 | const unsigned int numTriMax = (maxX - minX) * (maxZ - minZ) * 2; | ||
1171 | if (tempTriangleBufferSize < numTriMax) | ||
1172 | { | ||
1173 | resetTriangleBuffer(); | ||
1174 | allocateTriangleBuffer(numTriMax); | ||
1175 | } | ||
1176 | |||
1177 | // Sorting triangle/plane resulting from heightfield zone | ||
1178 | // Perhaps that would be necessary in case of too much limited | ||
1179 | // maximum contact point... | ||
1180 | // or in complex mesh case (trimesh and convex) | ||
1181 | // need some test or insights on this before enabling this. | ||
1182 | const bool isContactNumPointsLimited = | ||
1183 | true; | ||
1184 | // (numMaxContacts < 8) | ||
1185 | // || o2->type == dConvexClass | ||
1186 | // || o2->type == dTriMeshClass | ||
1187 | // || (numMaxContacts < (int)numTriMax) | ||
1188 | |||
1189 | |||
1190 | |||
1191 | // if small heightfield triangle related to O2 colliding | ||
1192 | // or no Triangle colliding at all. | ||
1193 | bool needFurtherPasses = (o2->type == dTriMeshClass); | ||
1194 | //compute Ratio between Triangle size and O2 aabb size | ||
1195 | // no FurtherPasses are needed in ray class | ||
1196 | if (o2->type != dRayClass && needFurtherPasses == false) | ||
1197 | { | ||
1198 | const dReal xratio = (o2->aabb[1] - o2->aabb[0]) * m_p_data->m_fInvSampleWidth; | ||
1199 | if (xratio > REAL(1.5)) | ||
1200 | needFurtherPasses = true; | ||
1201 | else | ||
1202 | { | ||
1203 | const dReal zratio = (o2->aabb[5] - o2->aabb[4]) * m_p_data->m_fInvSampleDepth; | ||
1204 | if (zratio > REAL(1.5)) | ||
1205 | needFurtherPasses = true; | ||
1206 | } | ||
1207 | |||
1208 | } | ||
1209 | |||
1210 | unsigned int numTri = 0; | ||
1211 | HeightFieldVertex *A, *B, *C, *D; | ||
1212 | /* (y is up) | ||
1213 | A--------B-...x | ||
1214 | | /| | ||
1215 | | / | | ||
1216 | | / | | ||
1217 | | / | | ||
1218 | | / | | ||
1219 | | / | | ||
1220 | | / | | ||
1221 | |/ | | ||
1222 | C--------D | ||
1223 | . | ||
1224 | . | ||
1225 | . | ||
1226 | z | ||
1227 | */ | ||
1228 | // keep only triangle that does intersect geom | ||
1229 | for ( x = minX, x_local = 0; x < maxX; x++, x_local++) | ||
1230 | { | ||
1231 | HeightFieldVertex *HeightFieldRow = tempHeightBuffer[x_local]; | ||
1232 | HeightFieldVertex *HeightFieldNextRow = tempHeightBuffer[x_local + 1]; | ||
1233 | |||
1234 | // First A | ||
1235 | C = &HeightFieldRow [0]; | ||
1236 | // First B | ||
1237 | D = &HeightFieldNextRow[0]; | ||
1238 | for ( z = minZ, z_local = 0; z < maxZ; z++, z_local++) | ||
1239 | { | ||
1240 | A = C; | ||
1241 | B = D; | ||
1242 | |||
1243 | C = &HeightFieldRow [z_local + 1]; | ||
1244 | D = &HeightFieldNextRow[z_local + 1]; | ||
1245 | |||
1246 | const dReal AHeight = A->vertex[1]; | ||
1247 | const dReal BHeight = B->vertex[1]; | ||
1248 | const dReal CHeight = C->vertex[1]; | ||
1249 | const dReal DHeight = D->vertex[1]; | ||
1250 | |||
1251 | const bool isACollide = 0 < AHeight - minO2Height; | ||
1252 | const bool isBCollide = 0 < BHeight - minO2Height; | ||
1253 | const bool isCCollide = 0 < CHeight - minO2Height; | ||
1254 | const bool isDCollide = 0 < DHeight - minO2Height; | ||
1255 | |||
1256 | A->state = !(isACollide); | ||
1257 | B->state = !(isBCollide); | ||
1258 | C->state = !(isCCollide); | ||
1259 | D->state = !(isCCollide); | ||
1260 | |||
1261 | if (isACollide || isBCollide || isCCollide) | ||
1262 | { | ||
1263 | HeightFieldTriangle * const CurrTriUp = &tempTriangleBuffer[numTri++]; | ||
1264 | |||
1265 | CurrTriUp->state = false; | ||
1266 | |||
1267 | // changing point order here implies to change it in isOnHeightField | ||
1268 | CurrTriUp->vertices[0] = A; | ||
1269 | CurrTriUp->vertices[1] = B; | ||
1270 | CurrTriUp->vertices[2] = C; | ||
1271 | |||
1272 | if (isContactNumPointsLimited) | ||
1273 | CurrTriUp->setMinMax(); | ||
1274 | CurrTriUp->isUp = true; | ||
1275 | } | ||
1276 | |||
1277 | if (isBCollide || isCCollide || isDCollide) | ||
1278 | { | ||
1279 | HeightFieldTriangle * const CurrTriDown = &tempTriangleBuffer[numTri++]; | ||
1280 | |||
1281 | CurrTriDown->state = false; | ||
1282 | // changing point order here implies to change it in isOnHeightField | ||
1283 | |||
1284 | CurrTriDown->vertices[0] = D; | ||
1285 | CurrTriDown->vertices[1] = B; | ||
1286 | CurrTriDown->vertices[2] = C; | ||
1287 | |||
1288 | |||
1289 | if (isContactNumPointsLimited) | ||
1290 | CurrTriDown->setMinMax(); | ||
1291 | CurrTriDown->isUp = false; | ||
1292 | } | ||
1293 | |||
1294 | |||
1295 | if (needFurtherPasses && | ||
1296 | (isBCollide || isCCollide) | ||
1297 | && | ||
1298 | (AHeight - CHeight > 0 && | ||
1299 | AHeight - BHeight > 0 && | ||
1300 | DHeight - CHeight > 0 && | ||
1301 | DHeight - BHeight > 0)) | ||
1302 | { | ||
1303 | // That means Edge BC is concave, therefore | ||
1304 | // BC Edge and B and C vertices cannot collide | ||
1305 | |||
1306 | B->state = true; | ||
1307 | C->state = true; | ||
1308 | } | ||
1309 | // should find a way to check other edges (AB, BD, CD) too for concavity | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | // at least on triangle should intersect geom | ||
1314 | dIASSERT (numTri != 0); | ||
1315 | // pass1: VS triangle as Planes | ||
1316 | // Group Triangle by same plane definition | ||
1317 | // as Terrain often has many triangles using same plane definition | ||
1318 | // then collide against that list of triangles. | ||
1319 | { | ||
1320 | |||
1321 | dVector3 Edge1, Edge2; | ||
1322 | //compute all triangles normals. | ||
1323 | for (unsigned int k = 0; k < numTri; k++) | ||
1324 | { | ||
1325 | HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1326 | |||
1327 | // define 2 edges and a point that will define collision plane | ||
1328 | dVector3Subtract(itTriangle->vertices[2]->vertex, itTriangle->vertices[0]->vertex, Edge1); | ||
1329 | dVector3Subtract(itTriangle->vertices[1]->vertex, itTriangle->vertices[0]->vertex, Edge2); | ||
1330 | |||
1331 | // find a perpendicular vector to the triangle | ||
1332 | if (itTriangle->isUp) | ||
1333 | dVector3Cross(Edge1, Edge2, triplane); | ||
1334 | else | ||
1335 | dVector3Cross(Edge2, Edge1, triplane); | ||
1336 | |||
1337 | // Define Plane | ||
1338 | // Normalize plane normal | ||
1339 | const dReal dinvlength = REAL(1.0) / dVector3Length(triplane); | ||
1340 | triplane[0] *= dinvlength; | ||
1341 | triplane[1] *= dinvlength; | ||
1342 | triplane[2] *= dinvlength; | ||
1343 | // get distance to origin from plane | ||
1344 | triplane[3] = dVector3Dot(triplane, itTriangle->vertices[0]->vertex); | ||
1345 | |||
1346 | // saves normal for collision check (planes, triangles, vertices and edges.) | ||
1347 | dVector3Copy(triplane, itTriangle->planeDef); | ||
1348 | // saves distance for collision check (planes, triangles, vertices and edges.) | ||
1349 | itTriangle->planeDef[3] = triplane[3]; | ||
1350 | } | ||
1351 | |||
1352 | // group by Triangles by Planes sharing shame plane definition | ||
1353 | if (tempPlaneBufferSize < numTri) | ||
1354 | { | ||
1355 | resetPlaneBuffer(); | ||
1356 | allocatePlaneBuffer(numTri); | ||
1357 | } | ||
1358 | unsigned int numPlanes = 0; | ||
1359 | for (unsigned int k = 0; k < numTri; k++) | ||
1360 | { | ||
1361 | HeightFieldTriangle * const tri_base = &tempTriangleBuffer[k]; | ||
1362 | |||
1363 | if (tri_base->state == true) | ||
1364 | continue;// already tested or added to plane list. | ||
1365 | |||
1366 | HeightFieldPlane * const currPlane = tempPlaneBuffer[numPlanes]; | ||
1367 | currPlane->resetTriangleListSize(numTri - k); | ||
1368 | currPlane->addTriangle(tri_base); | ||
1369 | // saves normal for collision check (planes, triangles, vertices and edges.) | ||
1370 | dVector3Copy(tri_base->planeDef, currPlane->planeDef); | ||
1371 | // saves distance for collision check (planes, triangles, vertices and edges.) | ||
1372 | currPlane->planeDef[3]= tri_base->planeDef[3]; | ||
1373 | |||
1374 | const dReal normx = tri_base->planeDef[0]; | ||
1375 | const dReal normy = tri_base->planeDef[1]; | ||
1376 | const dReal normz = tri_base->planeDef[2]; | ||
1377 | const dReal dist = tri_base->planeDef[3]; | ||
1378 | |||
1379 | for (unsigned int m = k + 1; m < numTri; m++) | ||
1380 | { | ||
1381 | |||
1382 | HeightFieldTriangle * const tri_test = &tempTriangleBuffer[m]; | ||
1383 | if (tri_test->state == true) | ||
1384 | continue;// already tested or added to plane list. | ||
1385 | |||
1386 | // normals and distance are the same. | ||
1387 | if ( | ||
1388 | dFabs(normy - tri_test->planeDef[1]) < dEpsilon && | ||
1389 | dFabs(dist - tri_test->planeDef[3]) < dEpsilon && | ||
1390 | dFabs(normx - tri_test->planeDef[0]) < dEpsilon && | ||
1391 | dFabs(normz - tri_test->planeDef[2]) < dEpsilon | ||
1392 | ) | ||
1393 | { | ||
1394 | currPlane->addTriangle (tri_test); | ||
1395 | tri_test->state = true; | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | tri_base->state = true; | ||
1400 | if (isContactNumPointsLimited) | ||
1401 | currPlane->setMinMax(); | ||
1402 | |||
1403 | numPlanes++; | ||
1404 | } | ||
1405 | |||
1406 | // sort planes | ||
1407 | if (isContactNumPointsLimited) | ||
1408 | sortPlanes(numPlanes); | ||
1409 | |||
1410 | #if !defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1411 | /* | ||
1412 | Note by Oleh_Derevenko: | ||
1413 | It seems to be incorrect to limit contact count by some particular value | ||
1414 | since some of them (and even all of them) may be culled in following condition. | ||
1415 | However I do not see an easy way to fix this. | ||
1416 | If not that culling the flags modification should be changed here and | ||
1417 | additionally repeated after some contacts have been generated (in "if (didCollide)"). | ||
1418 | The maximum of contacts in flags would then be set to minimum of contacts | ||
1419 | remaining and HEIGHTFIELDMAXCONTACTPERCELL. | ||
1420 | */ | ||
1421 | int planeTestFlags = (flags & ~NUMC_MASK) | HEIGHTFIELDMAXCONTACTPERCELL; | ||
1422 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1423 | #else // if defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1424 | int numMaxContactsPerPlane = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1425 | int planeTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerPlane; | ||
1426 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1427 | #endif | ||
1428 | |||
1429 | for (unsigned int k = 0; k < numPlanes; k++) | ||
1430 | { | ||
1431 | HeightFieldPlane * const itPlane = tempPlaneBuffer[k]; | ||
1432 | |||
1433 | //set Geom | ||
1434 | dGeomPlaneSetNoNormalize (sliding_plane, itPlane->planeDef); | ||
1435 | //dGeomPlaneSetParams (sliding_plane, triangle_Plane[0], triangle_Plane[1], triangle_Plane[2], triangle_Plane[3]); | ||
1436 | // find collision and compute contact points | ||
1437 | bool didCollide = false; | ||
1438 | const int numPlaneContacts = geomNPlaneCollider (o2, sliding_plane, planeTestFlags, PlaneContact, sizeof(dContactGeom)); | ||
1439 | const size_t planeTriListSize = itPlane->trianglelistCurrentSize; | ||
1440 | for (i = 0; i < numPlaneContacts; i++) | ||
1441 | { | ||
1442 | // Check if contact point found in plane is inside Triangle. | ||
1443 | const dVector3 &pCPos = PlaneContact[i].pos; | ||
1444 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1445 | { | ||
1446 | if (m_p_data->IsOnHeightfield2 (itPlane->trianglelist[b]->vertices[0]->vertex, | ||
1447 | pCPos, | ||
1448 | itPlane->trianglelist[b]->isUp)) | ||
1449 | { | ||
1450 | pContact = CONTACT(contact, numTerrainContacts*skip); | ||
1451 | dVector3Copy(pCPos, pContact->pos); | ||
1452 | dOPESIGN(pContact->normal, =, -, itPlane->planeDef); | ||
1453 | pContact->depth = PlaneContact[i].depth; | ||
1454 | numTerrainContacts++; | ||
1455 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1456 | return numTerrainContacts; | ||
1457 | |||
1458 | didCollide = true; | ||
1459 | break; | ||
1460 | } | ||
1461 | } | ||
1462 | } | ||
1463 | if (didCollide) | ||
1464 | { | ||
1465 | #if defined(NO_CONTACT_CULLING_BY_ISONHEIGHTFIELD2) | ||
1466 | /* Note by Oleh_Derevenko: | ||
1467 | This code is not used - see another note above | ||
1468 | */ | ||
1469 | numMaxContactsPerPlane = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1470 | planeTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerPlane; | ||
1471 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1472 | #endif | ||
1473 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1474 | { | ||
1475 | // flag Triangles Vertices as collided | ||
1476 | // to prevent any collision test of those | ||
1477 | for (i = 0; i < 3; i++) | ||
1478 | itPlane->trianglelist[b]->vertices[i]->state = true; | ||
1479 | } | ||
1480 | } | ||
1481 | else | ||
1482 | { | ||
1483 | // flag triangle as not collided so that Vertices or Edge | ||
1484 | // of that triangles will be checked. | ||
1485 | for (size_t b = 0; planeTriListSize > b; b++) | ||
1486 | { | ||
1487 | itPlane->trianglelist[b]->state = false; | ||
1488 | } | ||
1489 | } | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | |||
1494 | |||
1495 | // pass2: VS triangle vertices | ||
1496 | if (needFurtherPasses) | ||
1497 | { | ||
1498 | dxRay tempRay(0, 1); | ||
1499 | dReal depth; | ||
1500 | bool vertexCollided; | ||
1501 | |||
1502 | // Only one contact is necessary for ray test | ||
1503 | int rayTestFlags = (flags & ~NUMC_MASK) | 1; | ||
1504 | dIASSERT((1 & ~NUMC_MASK) == 0); | ||
1505 | // | ||
1506 | // Find Contact Penetration Depth of each vertices | ||
1507 | // | ||
1508 | for (unsigned int k = 0; k < numTri; k++) | ||
1509 | { | ||
1510 | const HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1511 | if (itTriangle->state == true) | ||
1512 | continue;// plane triangle did already collide. | ||
1513 | |||
1514 | for (size_t i = 0; i < 3; i++) | ||
1515 | { | ||
1516 | HeightFieldVertex *vertex = itTriangle->vertices[i]; | ||
1517 | if (vertex->state == true) | ||
1518 | continue;// vertice did already collide. | ||
1519 | |||
1520 | vertexCollided = false; | ||
1521 | const dVector3 &triVertex = vertex->vertex; | ||
1522 | if ( geomNDepthGetter ) | ||
1523 | { | ||
1524 | depth = geomNDepthGetter( o2, | ||
1525 | triVertex[0], triVertex[1], triVertex[2] ); | ||
1526 | if (depth + dEpsilon < 0) | ||
1527 | vertexCollided = true; | ||
1528 | } | ||
1529 | else | ||
1530 | { | ||
1531 | // We don't have a GetDepth function, so do a ray cast instead. | ||
1532 | // NOTE: This isn't ideal, and a GetDepth function should be | ||
1533 | // written for all geom classes. | ||
1534 | tempRay.length = (minO2Height - triVertex[1]) * REAL(1000.0); | ||
1535 | |||
1536 | //dGeomRaySet( &tempRay, pContact->pos[0], pContact->pos[1], pContact->pos[2], | ||
1537 | // - itTriangle->Normal[0], - itTriangle->Normal[1], - itTriangle->Normal[2] ); | ||
1538 | dGeomRaySetNoNormalize(tempRay, triVertex, itTriangle->planeDef); | ||
1539 | |||
1540 | if ( geomRayNCollider( &tempRay, o2, rayTestFlags, PlaneContact, sizeof( dContactGeom ) ) ) | ||
1541 | { | ||
1542 | depth = PlaneContact[0].depth; | ||
1543 | vertexCollided = true; | ||
1544 | } | ||
1545 | } | ||
1546 | if (vertexCollided) | ||
1547 | { | ||
1548 | pContact = CONTACT(contact, numTerrainContacts*skip); | ||
1549 | //create contact using vertices | ||
1550 | dVector3Copy (triVertex, pContact->pos); | ||
1551 | //create contact using Plane Normal | ||
1552 | dOPESIGN(pContact->normal, =, -, itTriangle->planeDef); | ||
1553 | |||
1554 | pContact->depth = depth; | ||
1555 | |||
1556 | numTerrainContacts++; | ||
1557 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1558 | return numTerrainContacts; | ||
1559 | |||
1560 | vertex->state = true; | ||
1561 | } | ||
1562 | } | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | #ifdef _HEIGHTFIELDEDGECOLLIDING | ||
1567 | // pass3: VS triangle Edges | ||
1568 | if (needFurtherPasses) | ||
1569 | { | ||
1570 | dVector3 Edge; | ||
1571 | dxRay edgeRay(0, 1); | ||
1572 | |||
1573 | int numMaxContactsPerTri = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1574 | int triTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerTri; | ||
1575 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1576 | |||
1577 | for (unsigned int k = 0; k < numTri; k++) | ||
1578 | { | ||
1579 | const HeightFieldTriangle * const itTriangle = &tempTriangleBuffer[k]; | ||
1580 | |||
1581 | if (itTriangle->state == true) | ||
1582 | continue;// plane did already collide. | ||
1583 | |||
1584 | for (size_t m = 0; m < 3; m++) | ||
1585 | { | ||
1586 | const size_t next = (m + 1) % 3; | ||
1587 | HeightFieldVertex *vertex0 = itTriangle->vertices[m]; | ||
1588 | HeightFieldVertex *vertex1 = itTriangle->vertices[next]; | ||
1589 | |||
1590 | // not concave or under the AABB | ||
1591 | // nor triangle already collided against vertices | ||
1592 | if (vertex0->state == true && vertex1->state == true) | ||
1593 | continue;// plane did already collide. | ||
1594 | |||
1595 | dVector3Subtract(vertex1->vertex, vertex0->vertex, Edge); | ||
1596 | edgeRay.length = dVector3Length (Edge); | ||
1597 | dGeomRaySetNoNormalize(edgeRay, vertex1->vertex, Edge); | ||
1598 | int prevTerrainContacts = numTerrainContacts; | ||
1599 | pContact = CONTACT(contact, prevTerrainContacts*skip); | ||
1600 | const int numCollision = geomRayNCollider(&edgeRay,o2,triTestFlags,pContact,skip); | ||
1601 | dIASSERT(numCollision <= numMaxContactsPerTri); | ||
1602 | |||
1603 | if (numCollision) | ||
1604 | { | ||
1605 | numTerrainContacts += numCollision; | ||
1606 | |||
1607 | do | ||
1608 | { | ||
1609 | pContact = CONTACT(contact, prevTerrainContacts*skip); | ||
1610 | |||
1611 | //create contact using Plane Normal | ||
1612 | dOPESIGN(pContact->normal, =, -, itTriangle->planeDef); | ||
1613 | |||
1614 | pContact->depth = DistancePointToLine(pContact->pos, vertex1->vertex, Edge, edgeRay.length); | ||
1615 | } | ||
1616 | while (++prevTerrainContacts != numTerrainContacts); | ||
1617 | |||
1618 | if ( numTerrainContacts == numMaxContactsPossible ) | ||
1619 | return numTerrainContacts; | ||
1620 | |||
1621 | numMaxContactsPerTri = dMIN(numMaxContactsPossible - numTerrainContacts, HEIGHTFIELDMAXCONTACTPERCELL); | ||
1622 | triTestFlags = (flags & ~NUMC_MASK) | numMaxContactsPerTri; | ||
1623 | dIASSERT((HEIGHTFIELDMAXCONTACTPERCELL & ~NUMC_MASK) == 0); | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | itTriangle->vertices[0]->state = true; | ||
1628 | itTriangle->vertices[1]->state = true; | ||
1629 | itTriangle->vertices[2]->state = true; | ||
1630 | } | ||
1631 | } | ||
1632 | #endif // _HEIGHTFIELDEDGECOLLIDING | ||
1633 | return numTerrainContacts; | ||
1634 | } | ||
1635 | |||
1636 | int dCollideHeightfield( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* contact, int skip ) | ||
1637 | { | ||
1638 | dIASSERT( skip >= (int)sizeof(dContactGeom) ); | ||
1639 | dIASSERT( o1->type == dHeightfieldClass ); | ||
1640 | dIASSERT((flags & NUMC_MASK) >= 1); | ||
1641 | |||
1642 | int i; | ||
1643 | |||
1644 | // if ((flags & NUMC_MASK) == 0) -- An assertion check is made on entry | ||
1645 | // { flags = (flags & ~NUMC_MASK) | 1; dIASSERT((1 & ~NUMC_MASK) == 0); } | ||
1646 | |||
1647 | int numMaxTerrainContacts = (flags & NUMC_MASK); | ||
1648 | |||
1649 | dxHeightfield *terrain = (dxHeightfield*) o1; | ||
1650 | |||
1651 | dVector3 posbak; | ||
1652 | dMatrix3 Rbak; | ||
1653 | dReal aabbbak[6]; | ||
1654 | int gflagsbak; | ||
1655 | dVector3 pos0,pos1; | ||
1656 | dMatrix3 R1; | ||
1657 | |||
1658 | int numTerrainContacts = 0; | ||
1659 | |||
1660 | //@@ Should find a way to set reComputeAABB to false in default case | ||
1661 | // aka DHEIGHTFIELD_CORNER_ORIGIN not defined and terrain not PLACEABLE | ||
1662 | // so that we can free some memory and speed up things a bit | ||
1663 | // while saving some precision loss | ||
1664 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1665 | const bool reComputeAABB = true; | ||
1666 | #else | ||
1667 | const bool reComputeAABB = ( terrain->gflags & GEOM_PLACEABLE ) ? true : false; | ||
1668 | #endif //DHEIGHTFIELD_CORNER_ORIGIN | ||
1669 | |||
1670 | // | ||
1671 | // Transform O2 into Heightfield Space | ||
1672 | // | ||
1673 | if (reComputeAABB) | ||
1674 | { | ||
1675 | // Backup original o2 position, rotation and AABB. | ||
1676 | dVector3Copy( o2->final_posr->pos, posbak ); | ||
1677 | dMatrix3Copy( o2->final_posr->R, Rbak ); | ||
1678 | memcpy( aabbbak, o2->aabb, sizeof( dReal ) * 6 ); | ||
1679 | gflagsbak = o2->gflags; | ||
1680 | } | ||
1681 | |||
1682 | if ( terrain->gflags & GEOM_PLACEABLE ) | ||
1683 | { | ||
1684 | // Transform o2 into heightfield space. | ||
1685 | dOP( pos0, -, o2->final_posr->pos, terrain->final_posr->pos ); | ||
1686 | dMULTIPLY1_331( pos1, terrain->final_posr->R, pos0 ); | ||
1687 | dMULTIPLY1_333( R1, terrain->final_posr->R, o2->final_posr->R ); | ||
1688 | |||
1689 | // Update o2 with transformed position and rotation. | ||
1690 | dVector3Copy( pos1, o2->final_posr->pos ); | ||
1691 | dMatrix3Copy( R1, o2->final_posr->R ); | ||
1692 | } | ||
1693 | |||
1694 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1695 | o2->final_posr->pos[ 0 ] += terrain->m_p_data->m_fHalfWidth; | ||
1696 | o2->final_posr->pos[ 2 ] += terrain->m_p_data->m_fHalfDepth; | ||
1697 | #endif // DHEIGHTFIELD_CORNER_ORIGIN | ||
1698 | |||
1699 | // Rebuild AABB for O2 | ||
1700 | if (reComputeAABB) | ||
1701 | o2->computeAABB(); | ||
1702 | |||
1703 | // | ||
1704 | // Collide | ||
1705 | // | ||
1706 | |||
1707 | //check if inside boundaries | ||
1708 | // using O2 aabb | ||
1709 | // aabb[6] is (minx, maxx, miny, maxy, minz, maxz) | ||
1710 | const bool wrapped = terrain->m_p_data->m_bWrapMode != 0; | ||
1711 | |||
1712 | int nMinX; | ||
1713 | int nMaxX; | ||
1714 | int nMinZ; | ||
1715 | int nMaxZ; | ||
1716 | |||
1717 | if ( !wrapped ) | ||
1718 | { | ||
1719 | if ( o2->aabb[0] > terrain->m_p_data->m_fWidth //MinX | ||
1720 | && o2->aabb[4] > terrain->m_p_data->m_fDepth)//MinZ | ||
1721 | goto dCollideHeightfieldExit; | ||
1722 | |||
1723 | if ( o2->aabb[1] < 0 //MaxX | ||
1724 | && o2->aabb[5] < 0) //MaxZ | ||
1725 | goto dCollideHeightfieldExit; | ||
1726 | |||
1727 | } | ||
1728 | |||
1729 | nMinX = int(dFloor(o2->aabb[0] * terrain->m_p_data->m_fInvSampleWidth)); | ||
1730 | nMaxX = int(dFloor(o2->aabb[1] * terrain->m_p_data->m_fInvSampleWidth)) + 1; | ||
1731 | nMinZ = int(dFloor(o2->aabb[4] * terrain->m_p_data->m_fInvSampleDepth)); | ||
1732 | nMaxZ = int(dFloor(o2->aabb[5] * terrain->m_p_data->m_fInvSampleDepth)) + 1; | ||
1733 | |||
1734 | if ( !wrapped ) | ||
1735 | { | ||
1736 | nMinX = dMAX( nMinX, 0 ); | ||
1737 | nMaxX = dMIN( nMaxX, terrain->m_p_data->m_nWidthSamples - 1 ); | ||
1738 | nMinZ = dMAX( nMinZ, 0 ); | ||
1739 | nMaxZ = dMIN( nMaxZ, terrain->m_p_data->m_nDepthSamples - 1 ); | ||
1740 | |||
1741 | dIASSERT ((nMinX < nMaxX) || (nMinZ < nMaxZ)) | ||
1742 | } | ||
1743 | |||
1744 | |||
1745 | |||
1746 | numTerrainContacts += terrain->dCollideHeightfieldZone( | ||
1747 | nMinX,nMaxX,nMinZ,nMaxZ,o2,numMaxTerrainContacts - numTerrainContacts, | ||
1748 | flags,CONTACT(contact,numTerrainContacts*skip),skip ); | ||
1749 | |||
1750 | dIASSERT( numTerrainContacts <= numMaxTerrainContacts ); | ||
1751 | |||
1752 | dContactGeom *pContact; | ||
1753 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1754 | { | ||
1755 | pContact = CONTACT(contact,i*skip); | ||
1756 | pContact->g1 = o1; | ||
1757 | pContact->g2 = o2; | ||
1758 | } | ||
1759 | |||
1760 | |||
1761 | //------------------------------------------------------------------------------ | ||
1762 | |||
1763 | dCollideHeightfieldExit: | ||
1764 | |||
1765 | if (reComputeAABB) | ||
1766 | { | ||
1767 | // Restore o2 position, rotation and AABB | ||
1768 | dVector3Copy( posbak, o2->final_posr->pos ); | ||
1769 | dMatrix3Copy( Rbak, o2->final_posr->R ); | ||
1770 | memcpy( o2->aabb, aabbbak, sizeof(dReal)*6 ); | ||
1771 | o2->gflags = gflagsbak; | ||
1772 | |||
1773 | // | ||
1774 | // Transform Contacts to World Space | ||
1775 | // | ||
1776 | if ( terrain->gflags & GEOM_PLACEABLE ) | ||
1777 | { | ||
1778 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1779 | { | ||
1780 | pContact = CONTACT(contact,i*skip); | ||
1781 | dOPE( pos0, =, pContact->pos ); | ||
1782 | |||
1783 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1784 | pos0[ 0 ] -= terrain->m_p_data->m_fHalfWidth; | ||
1785 | pos0[ 2 ] -= terrain->m_p_data->m_fHalfDepth; | ||
1786 | #endif // !DHEIGHTFIELD_CORNER_ORIGIN | ||
1787 | |||
1788 | dMULTIPLY0_331( pContact->pos, terrain->final_posr->R, pos0 ); | ||
1789 | |||
1790 | dOP( pContact->pos, +, pContact->pos, terrain->final_posr->pos ); | ||
1791 | dOPE( pos0, =, pContact->normal ); | ||
1792 | |||
1793 | dMULTIPLY0_331( pContact->normal, terrain->final_posr->R, pos0 ); | ||
1794 | } | ||
1795 | } | ||
1796 | #ifndef DHEIGHTFIELD_CORNER_ORIGIN | ||
1797 | else | ||
1798 | { | ||
1799 | for ( i = 0; i < numTerrainContacts; ++i ) | ||
1800 | { | ||
1801 | pContact = CONTACT(contact,i*skip); | ||
1802 | pContact->pos[ 0 ] -= terrain->m_p_data->m_fHalfWidth; | ||
1803 | pContact->pos[ 2 ] -= terrain->m_p_data->m_fHalfDepth; | ||
1804 | } | ||
1805 | } | ||
1806 | #endif // !DHEIGHTFIELD_CORNER_ORIGIN | ||
1807 | } | ||
1808 | // Return contact count. | ||
1809 | return numTerrainContacts; | ||
1810 | } | ||
1811 | |||
1812 | |||
diff --git a/libraries/ode-0.9\/ode/src/heightfield.h b/libraries/ode-0.9\/ode/src/heightfield.h new file mode 100755 index 0000000..f4c5952 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/heightfield.h | |||
@@ -0,0 +1,225 @@ | |||
1 | // dHeightfield Collider | ||
2 | // Martijn Buijs 2006 http://home.planet.nl/~buijs512/ | ||
3 | // Based on Terrain & Cone contrib by: | ||
4 | // Benoit CHAPEROT 2003-2004 http://www.jstarlab.com | ||
5 | |||
6 | #ifndef _DHEIGHTFIELD_H_ | ||
7 | #define _DHEIGHTFIELD_H_ | ||
8 | //------------------------------------------------------------------------------ | ||
9 | |||
10 | #include <ode/common.h> | ||
11 | #include "collision_kernel.h" | ||
12 | |||
13 | |||
14 | #define HEIGHTFIELDMAXCONTACTPERCELL 10 | ||
15 | |||
16 | // | ||
17 | // dxHeightfieldData | ||
18 | // | ||
19 | // Heightfield Data structure | ||
20 | // | ||
21 | struct dxHeightfieldData | ||
22 | { | ||
23 | dReal m_fWidth; // World space heightfield dimension on X axis | ||
24 | dReal m_fDepth; // World space heightfield dimension on Z axis | ||
25 | dReal m_fSampleWidth; // Vertex count on X axis edge (== m_vWidth / (m_nWidthSamples-1)) | ||
26 | dReal m_fSampleDepth; // Vertex count on Z axis edge (== m_vDepth / (m_nDepthSamples-1)) | ||
27 | dReal m_fInvSampleWidth; // Cache of inverse Vertex count on X axis edge (== m_vWidth / (m_nWidthSamples-1)) | ||
28 | dReal m_fInvSampleDepth; // Cache of inverse Vertex count on Z axis edge (== m_vDepth / (m_nDepthSamples-1)) | ||
29 | |||
30 | dReal m_fHalfWidth; // Cache of half of m_fWidth | ||
31 | dReal m_fHalfDepth; // Cache of half of m_fDepth | ||
32 | |||
33 | dReal m_fMinHeight; // Min sample height value (scaled and offset) | ||
34 | dReal m_fMaxHeight; // Max sample height value (scaled and offset) | ||
35 | dReal m_fThickness; // Surface thickness (added to bottom AABB) | ||
36 | dReal m_fScale; // Sample value multiplier | ||
37 | dReal m_fOffset; // Vertical sample offset | ||
38 | |||
39 | int m_nWidthSamples; // Vertex count on X axis edge (number of samples) | ||
40 | int m_nDepthSamples; // Vertex count on Z axis edge (number of samples) | ||
41 | int m_bCopyHeightData; // Do we own the sample data? | ||
42 | int m_bWrapMode; // Heightfield wrapping mode (0=finite, 1=infinite) | ||
43 | int m_nGetHeightMode; // GetHeight mode ( 0=callback, 1=byte, 2=short, 3=float ) | ||
44 | |||
45 | const void* m_pHeightData; // Sample data array | ||
46 | void* m_pUserData; // Callback user data | ||
47 | |||
48 | dContactGeom m_contacts[HEIGHTFIELDMAXCONTACTPERCELL]; | ||
49 | |||
50 | dHeightfieldGetHeight* m_pGetHeightCallback; // Callback pointer. | ||
51 | |||
52 | dxHeightfieldData(); | ||
53 | ~dxHeightfieldData(); | ||
54 | |||
55 | void SetData( int nWidthSamples, int nDepthSamples, | ||
56 | dReal fWidth, dReal fDepth, | ||
57 | dReal fScale, dReal fOffset, | ||
58 | dReal fThickness, int bWrapMode ); | ||
59 | |||
60 | void ComputeHeightBounds(); | ||
61 | |||
62 | bool IsOnHeightfield ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const; | ||
63 | bool IsOnHeightfield2 ( const dReal * const CellOrigin, const dReal * const pos, const bool isABC) const; | ||
64 | |||
65 | dReal GetHeight(int x, int z); | ||
66 | dReal GetHeight(dReal x, dReal z); | ||
67 | |||
68 | }; | ||
69 | |||
70 | class HeightFieldVertex; | ||
71 | class HeightFieldEdge; | ||
72 | class HeightFieldTriangle; | ||
73 | |||
74 | class HeightFieldVertex | ||
75 | { | ||
76 | public: | ||
77 | HeightFieldVertex(){}; | ||
78 | |||
79 | dVector3 vertex; | ||
80 | bool state; | ||
81 | }; | ||
82 | |||
83 | class HeightFieldEdge | ||
84 | { | ||
85 | public: | ||
86 | HeightFieldEdge(){}; | ||
87 | |||
88 | HeightFieldVertex *vertices[2]; | ||
89 | }; | ||
90 | // | ||
91 | // HeightFieldTriangle | ||
92 | // | ||
93 | // HeightFieldTriangle composing heightfield mesh | ||
94 | // | ||
95 | class HeightFieldTriangle | ||
96 | { | ||
97 | public: | ||
98 | HeightFieldTriangle(){}; | ||
99 | |||
100 | inline void setMinMax() | ||
101 | { | ||
102 | maxAAAB = vertices[0]->vertex[1] > vertices[1]->vertex[1] ? vertices[0]->vertex[1] : vertices[1]->vertex[1]; | ||
103 | maxAAAB = vertices[2]->vertex[1] > maxAAAB ? vertices[2]->vertex[1] : maxAAAB; | ||
104 | }; | ||
105 | |||
106 | HeightFieldVertex *vertices[3]; | ||
107 | dReal planeDef[4]; | ||
108 | dReal maxAAAB; | ||
109 | |||
110 | bool isUp; | ||
111 | bool state; | ||
112 | }; | ||
113 | // | ||
114 | // HeightFieldTriangle | ||
115 | // | ||
116 | // HeightFieldPlane composing heightfield mesh | ||
117 | // | ||
118 | class HeightFieldPlane | ||
119 | { | ||
120 | public: | ||
121 | HeightFieldPlane(): | ||
122 | trianglelist(0), | ||
123 | trianglelistReservedSize(0), | ||
124 | trianglelistCurrentSize(0) | ||
125 | { | ||
126 | |||
127 | }; | ||
128 | ~HeightFieldPlane() | ||
129 | { | ||
130 | delete [] trianglelist; | ||
131 | }; | ||
132 | |||
133 | inline void setMinMax() | ||
134 | { | ||
135 | const size_t asize = trianglelistCurrentSize; | ||
136 | if (asize > 0) | ||
137 | { | ||
138 | maxAAAB = trianglelist[0]->maxAAAB; | ||
139 | for (size_t k = 1; asize > k; k++) | ||
140 | { | ||
141 | if (trianglelist[k]->maxAAAB > maxAAAB) | ||
142 | maxAAAB = trianglelist[k]->maxAAAB; | ||
143 | } | ||
144 | } | ||
145 | }; | ||
146 | |||
147 | void resetTriangleListSize(const size_t newSize) | ||
148 | { | ||
149 | if (trianglelistReservedSize < newSize) | ||
150 | { | ||
151 | delete [] trianglelist; | ||
152 | trianglelistReservedSize = newSize; | ||
153 | trianglelist = new HeightFieldTriangle *[newSize]; | ||
154 | } | ||
155 | trianglelistCurrentSize = 0; | ||
156 | } | ||
157 | |||
158 | void addTriangle(HeightFieldTriangle *tri) | ||
159 | { | ||
160 | dIASSERT(trianglelistCurrentSize < trianglelistReservedSize); | ||
161 | |||
162 | trianglelist[trianglelistCurrentSize++] = tri; | ||
163 | } | ||
164 | |||
165 | HeightFieldTriangle **trianglelist; | ||
166 | size_t trianglelistReservedSize; | ||
167 | size_t trianglelistCurrentSize; | ||
168 | |||
169 | dReal maxAAAB; | ||
170 | dReal planeDef[4]; | ||
171 | }; | ||
172 | // | ||
173 | // dxHeightfield | ||
174 | // | ||
175 | // Heightfield geom structure | ||
176 | // | ||
177 | struct dxHeightfield : public dxGeom | ||
178 | { | ||
179 | dxHeightfieldData* m_p_data; | ||
180 | |||
181 | dxHeightfield( dSpaceID space, dHeightfieldDataID data, int bPlaceable ); | ||
182 | ~dxHeightfield(); | ||
183 | |||
184 | void computeAABB(); | ||
185 | |||
186 | int dCollideHeightfieldZone( const int minX, const int maxX, const int minZ, const int maxZ, | ||
187 | dxGeom *o2, const int numMaxContacts, | ||
188 | int flags, dContactGeom *contact, int skip ); | ||
189 | |||
190 | enum | ||
191 | { | ||
192 | TEMP_PLANE_BUFFER_ELEMENT_COUNT_ALIGNMENT = 4, | ||
193 | TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_X = 4, | ||
194 | TEMP_HEIGHT_BUFFER_ELEMENT_COUNT_ALIGNMENT_Z = 4, | ||
195 | TEMP_TRIANGLE_BUFFER_ELEMENT_COUNT_ALIGNMENT = 1, // Triangles are easy to reallocate and hard to predict | ||
196 | }; | ||
197 | |||
198 | static inline size_t AlignBufferSize(size_t value, size_t alignment) { dIASSERT((alignment & (alignment - 1)) == 0); return (value + (alignment - 1)) & ~(alignment - 1); } | ||
199 | |||
200 | void allocateTriangleBuffer(size_t numTri); | ||
201 | void resetTriangleBuffer(); | ||
202 | void allocatePlaneBuffer(size_t numTri); | ||
203 | void resetPlaneBuffer(); | ||
204 | void allocateHeightBuffer(size_t numX, size_t numZ); | ||
205 | void resetHeightBuffer(); | ||
206 | |||
207 | void sortPlanes(const size_t numPlanes); | ||
208 | |||
209 | HeightFieldPlane **tempPlaneBuffer; | ||
210 | HeightFieldPlane *tempPlaneInstances; | ||
211 | size_t tempPlaneBufferSize; | ||
212 | |||
213 | HeightFieldTriangle *tempTriangleBuffer; | ||
214 | size_t tempTriangleBufferSize; | ||
215 | |||
216 | HeightFieldVertex **tempHeightBuffer; | ||
217 | HeightFieldVertex *tempHeightInstances; | ||
218 | size_t tempHeightBufferSizeX; | ||
219 | size_t tempHeightBufferSizeZ; | ||
220 | |||
221 | }; | ||
222 | |||
223 | |||
224 | //------------------------------------------------------------------------------ | ||
225 | #endif //_DHEIGHTFIELD_H_ | ||
diff --git a/libraries/ode-0.9\/ode/src/joint.cpp b/libraries/ode-0.9\/ode/src/joint.cpp new file mode 100755 index 0000000..d83294b --- /dev/null +++ b/libraries/ode-0.9\/ode/src/joint.cpp | |||
@@ -0,0 +1,4065 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | design note: the general principle for giving a joint the option of connecting | ||
26 | to the static environment (i.e. the absolute frame) is to check the second | ||
27 | body (joint->node[1].body), and if it is zero then behave as if its body | ||
28 | transform is the identity. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/ode.h> | ||
33 | #include <ode/odemath.h> | ||
34 | #include <ode/rotation.h> | ||
35 | #include <ode/matrix.h> | ||
36 | #include "joint.h" | ||
37 | |||
38 | //**************************************************************************** | ||
39 | // externs | ||
40 | |||
41 | // extern "C" void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); | ||
42 | // extern "C" void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); | ||
43 | |||
44 | //**************************************************************************** | ||
45 | // utility | ||
46 | |||
47 | // set three "ball-and-socket" rows in the constraint equation, and the | ||
48 | // corresponding right hand side. | ||
49 | |||
50 | static inline void setBall (dxJoint *joint, dxJoint::Info2 *info, | ||
51 | dVector3 anchor1, dVector3 anchor2) | ||
52 | { | ||
53 | // anchor points in global coordinates with respect to body PORs. | ||
54 | dVector3 a1,a2; | ||
55 | |||
56 | int s = info->rowskip; | ||
57 | |||
58 | // set jacobian | ||
59 | info->J1l[0] = 1; | ||
60 | info->J1l[s+1] = 1; | ||
61 | info->J1l[2*s+2] = 1; | ||
62 | dMULTIPLY0_331 (a1,joint->node[0].body->posr.R,anchor1); | ||
63 | dCROSSMAT (info->J1a,a1,s,-,+); | ||
64 | if (joint->node[1].body) { | ||
65 | info->J2l[0] = -1; | ||
66 | info->J2l[s+1] = -1; | ||
67 | info->J2l[2*s+2] = -1; | ||
68 | dMULTIPLY0_331 (a2,joint->node[1].body->posr.R,anchor2); | ||
69 | dCROSSMAT (info->J2a,a2,s,+,-); | ||
70 | } | ||
71 | |||
72 | // set right hand side | ||
73 | dReal k = info->fps * info->erp; | ||
74 | if (joint->node[1].body) { | ||
75 | for (int j=0; j<3; j++) { | ||
76 | info->c[j] = k * (a2[j] + joint->node[1].body->posr.pos[j] - | ||
77 | a1[j] - joint->node[0].body->posr.pos[j]); | ||
78 | } | ||
79 | } | ||
80 | else { | ||
81 | for (int j=0; j<3; j++) { | ||
82 | info->c[j] = k * (anchor2[j] - a1[j] - | ||
83 | joint->node[0].body->posr.pos[j]); | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | |||
88 | |||
89 | // this is like setBall(), except that `axis' is a unit length vector | ||
90 | // (in global coordinates) that should be used for the first jacobian | ||
91 | // position row (the other two row vectors will be derived from this). | ||
92 | // `erp1' is the erp value to use along the axis. | ||
93 | |||
94 | static inline void setBall2 (dxJoint *joint, dxJoint::Info2 *info, | ||
95 | dVector3 anchor1, dVector3 anchor2, | ||
96 | dVector3 axis, dReal erp1) | ||
97 | { | ||
98 | // anchor points in global coordinates with respect to body PORs. | ||
99 | dVector3 a1,a2; | ||
100 | |||
101 | int i,s = info->rowskip; | ||
102 | |||
103 | // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0], | ||
104 | // [0 1 0] and [0 0 1], which makes everything much easier. | ||
105 | dVector3 q1,q2; | ||
106 | dPlaneSpace (axis,q1,q2); | ||
107 | |||
108 | // set jacobian | ||
109 | for (i=0; i<3; i++) info->J1l[i] = axis[i]; | ||
110 | for (i=0; i<3; i++) info->J1l[s+i] = q1[i]; | ||
111 | for (i=0; i<3; i++) info->J1l[2*s+i] = q2[i]; | ||
112 | dMULTIPLY0_331 (a1,joint->node[0].body->posr.R,anchor1); | ||
113 | dCROSS (info->J1a,=,a1,axis); | ||
114 | dCROSS (info->J1a+s,=,a1,q1); | ||
115 | dCROSS (info->J1a+2*s,=,a1,q2); | ||
116 | if (joint->node[1].body) { | ||
117 | for (i=0; i<3; i++) info->J2l[i] = -axis[i]; | ||
118 | for (i=0; i<3; i++) info->J2l[s+i] = -q1[i]; | ||
119 | for (i=0; i<3; i++) info->J2l[2*s+i] = -q2[i]; | ||
120 | dMULTIPLY0_331 (a2,joint->node[1].body->posr.R,anchor2); | ||
121 | dCROSS (info->J2a,= -,a2,axis); | ||
122 | dCROSS (info->J2a+s,= -,a2,q1); | ||
123 | dCROSS (info->J2a+2*s,= -,a2,q2); | ||
124 | } | ||
125 | |||
126 | // set right hand side - measure error along (axis,q1,q2) | ||
127 | dReal k1 = info->fps * erp1; | ||
128 | dReal k = info->fps * info->erp; | ||
129 | |||
130 | for (i=0; i<3; i++) a1[i] += joint->node[0].body->posr.pos[i]; | ||
131 | if (joint->node[1].body) { | ||
132 | for (i=0; i<3; i++) a2[i] += joint->node[1].body->posr.pos[i]; | ||
133 | info->c[0] = k1 * (dDOT(axis,a2) - dDOT(axis,a1)); | ||
134 | info->c[1] = k * (dDOT(q1,a2) - dDOT(q1,a1)); | ||
135 | info->c[2] = k * (dDOT(q2,a2) - dDOT(q2,a1)); | ||
136 | } | ||
137 | else { | ||
138 | info->c[0] = k1 * (dDOT(axis,anchor2) - dDOT(axis,a1)); | ||
139 | info->c[1] = k * (dDOT(q1,anchor2) - dDOT(q1,a1)); | ||
140 | info->c[2] = k * (dDOT(q2,anchor2) - dDOT(q2,a1)); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | // set three orientation rows in the constraint equation, and the | ||
146 | // corresponding right hand side. | ||
147 | |||
148 | static void setFixedOrientation(dxJoint *joint, dxJoint::Info2 *info, dQuaternion qrel, int start_row) | ||
149 | { | ||
150 | int s = info->rowskip; | ||
151 | int start_index = start_row * s; | ||
152 | |||
153 | // 3 rows to make body rotations equal | ||
154 | info->J1a[start_index] = 1; | ||
155 | info->J1a[start_index + s + 1] = 1; | ||
156 | info->J1a[start_index + s*2+2] = 1; | ||
157 | if (joint->node[1].body) { | ||
158 | info->J2a[start_index] = -1; | ||
159 | info->J2a[start_index + s+1] = -1; | ||
160 | info->J2a[start_index + s*2+2] = -1; | ||
161 | } | ||
162 | |||
163 | // compute the right hand side. the first three elements will result in | ||
164 | // relative angular velocity of the two bodies - this is set to bring them | ||
165 | // back into alignment. the correcting angular velocity is | ||
166 | // |angular_velocity| = angle/time = erp*theta / stepsize | ||
167 | // = (erp*fps) * theta | ||
168 | // angular_velocity = |angular_velocity| * u | ||
169 | // = (erp*fps) * theta * u | ||
170 | // where rotation along unit length axis u by theta brings body 2's frame | ||
171 | // to qrel with respect to body 1's frame. using a small angle approximation | ||
172 | // for sin(), this gives | ||
173 | // angular_velocity = (erp*fps) * 2 * v | ||
174 | // where the quaternion of the relative rotation between the two bodies is | ||
175 | // q = [cos(theta/2) sin(theta/2)*u] = [s v] | ||
176 | |||
177 | // get qerr = relative rotation (rotation error) between two bodies | ||
178 | dQuaternion qerr,e; | ||
179 | if (joint->node[1].body) { | ||
180 | dQuaternion qq; | ||
181 | dQMultiply1 (qq,joint->node[0].body->q,joint->node[1].body->q); | ||
182 | dQMultiply2 (qerr,qq,qrel); | ||
183 | } | ||
184 | else { | ||
185 | dQMultiply3 (qerr,joint->node[0].body->q,qrel); | ||
186 | } | ||
187 | if (qerr[0] < 0) { | ||
188 | qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small | ||
189 | qerr[2] = -qerr[2]; | ||
190 | qerr[3] = -qerr[3]; | ||
191 | } | ||
192 | dMULTIPLY0_331 (e,joint->node[0].body->posr.R,qerr+1); // @@@ bad SIMD padding! | ||
193 | dReal k = info->fps * info->erp; | ||
194 | info->c[start_row] = 2*k * e[0]; | ||
195 | info->c[start_row+1] = 2*k * e[1]; | ||
196 | info->c[start_row+2] = 2*k * e[2]; | ||
197 | } | ||
198 | |||
199 | |||
200 | // compute anchor points relative to bodies | ||
201 | |||
202 | static void setAnchors (dxJoint *j, dReal x, dReal y, dReal z, | ||
203 | dVector3 anchor1, dVector3 anchor2) | ||
204 | { | ||
205 | if (j->node[0].body) { | ||
206 | dReal q[4]; | ||
207 | q[0] = x - j->node[0].body->posr.pos[0]; | ||
208 | q[1] = y - j->node[0].body->posr.pos[1]; | ||
209 | q[2] = z - j->node[0].body->posr.pos[2]; | ||
210 | q[3] = 0; | ||
211 | dMULTIPLY1_331 (anchor1,j->node[0].body->posr.R,q); | ||
212 | if (j->node[1].body) { | ||
213 | q[0] = x - j->node[1].body->posr.pos[0]; | ||
214 | q[1] = y - j->node[1].body->posr.pos[1]; | ||
215 | q[2] = z - j->node[1].body->posr.pos[2]; | ||
216 | q[3] = 0; | ||
217 | dMULTIPLY1_331 (anchor2,j->node[1].body->posr.R,q); | ||
218 | } | ||
219 | else { | ||
220 | anchor2[0] = x; | ||
221 | anchor2[1] = y; | ||
222 | anchor2[2] = z; | ||
223 | } | ||
224 | } | ||
225 | anchor1[3] = 0; | ||
226 | anchor2[3] = 0; | ||
227 | } | ||
228 | |||
229 | |||
230 | // compute axes relative to bodies. either axis1 or axis2 can be 0. | ||
231 | |||
232 | static void setAxes (dxJoint *j, dReal x, dReal y, dReal z, | ||
233 | dVector3 axis1, dVector3 axis2) | ||
234 | { | ||
235 | if (j->node[0].body) { | ||
236 | dReal q[4]; | ||
237 | q[0] = x; | ||
238 | q[1] = y; | ||
239 | q[2] = z; | ||
240 | q[3] = 0; | ||
241 | dNormalize3 (q); | ||
242 | if (axis1) { | ||
243 | dMULTIPLY1_331 (axis1,j->node[0].body->posr.R,q); | ||
244 | axis1[3] = 0; | ||
245 | } | ||
246 | if (axis2) { | ||
247 | if (j->node[1].body) { | ||
248 | dMULTIPLY1_331 (axis2,j->node[1].body->posr.R,q); | ||
249 | } | ||
250 | else { | ||
251 | axis2[0] = x; | ||
252 | axis2[1] = y; | ||
253 | axis2[2] = z; | ||
254 | } | ||
255 | axis2[3] = 0; | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | |||
260 | |||
261 | static void getAnchor (dxJoint *j, dVector3 result, dVector3 anchor1) | ||
262 | { | ||
263 | if (j->node[0].body) { | ||
264 | dMULTIPLY0_331 (result,j->node[0].body->posr.R,anchor1); | ||
265 | result[0] += j->node[0].body->posr.pos[0]; | ||
266 | result[1] += j->node[0].body->posr.pos[1]; | ||
267 | result[2] += j->node[0].body->posr.pos[2]; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | |||
272 | static void getAnchor2 (dxJoint *j, dVector3 result, dVector3 anchor2) | ||
273 | { | ||
274 | if (j->node[1].body) { | ||
275 | dMULTIPLY0_331 (result,j->node[1].body->posr.R,anchor2); | ||
276 | result[0] += j->node[1].body->posr.pos[0]; | ||
277 | result[1] += j->node[1].body->posr.pos[1]; | ||
278 | result[2] += j->node[1].body->posr.pos[2]; | ||
279 | } | ||
280 | else { | ||
281 | result[0] = anchor2[0]; | ||
282 | result[1] = anchor2[1]; | ||
283 | result[2] = anchor2[2]; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | |||
288 | static void getAxis (dxJoint *j, dVector3 result, dVector3 axis1) | ||
289 | { | ||
290 | if (j->node[0].body) { | ||
291 | dMULTIPLY0_331 (result,j->node[0].body->posr.R,axis1); | ||
292 | } | ||
293 | } | ||
294 | |||
295 | |||
296 | static void getAxis2 (dxJoint *j, dVector3 result, dVector3 axis2) | ||
297 | { | ||
298 | if (j->node[1].body) { | ||
299 | dMULTIPLY0_331 (result,j->node[1].body->posr.R,axis2); | ||
300 | } | ||
301 | else { | ||
302 | result[0] = axis2[0]; | ||
303 | result[1] = axis2[1]; | ||
304 | result[2] = axis2[2]; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | |||
309 | static dReal getHingeAngleFromRelativeQuat (dQuaternion qrel, dVector3 axis) | ||
310 | { | ||
311 | // the angle between the two bodies is extracted from the quaternion that | ||
312 | // represents the relative rotation between them. recall that a quaternion | ||
313 | // q is: | ||
314 | // [s,v] = [ cos(theta/2) , sin(theta/2) * u ] | ||
315 | // where s is a scalar and v is a 3-vector. u is a unit length axis and | ||
316 | // theta is a rotation along that axis. we can get theta/2 by: | ||
317 | // theta/2 = atan2 ( sin(theta/2) , cos(theta/2) ) | ||
318 | // but we can't get sin(theta/2) directly, only its absolute value, i.e.: | ||
319 | // |v| = |sin(theta/2)| * |u| | ||
320 | // = |sin(theta/2)| | ||
321 | // using this value will have a strange effect. recall that there are two | ||
322 | // quaternion representations of a given rotation, q and -q. typically as | ||
323 | // a body rotates along the axis it will go through a complete cycle using | ||
324 | // one representation and then the next cycle will use the other | ||
325 | // representation. this corresponds to u pointing in the direction of the | ||
326 | // hinge axis and then in the opposite direction. the result is that theta | ||
327 | // will appear to go "backwards" every other cycle. here is a fix: if u | ||
328 | // points "away" from the direction of the hinge (motor) axis (i.e. more | ||
329 | // than 90 degrees) then use -q instead of q. this represents the same | ||
330 | // rotation, but results in the cos(theta/2) value being sign inverted. | ||
331 | |||
332 | // extract the angle from the quaternion. cost2 = cos(theta/2), | ||
333 | // sint2 = |sin(theta/2)| | ||
334 | dReal cost2 = qrel[0]; | ||
335 | dReal sint2 = dSqrt (qrel[1]*qrel[1]+qrel[2]*qrel[2]+qrel[3]*qrel[3]); | ||
336 | dReal theta = (dDOT(qrel+1,axis) >= 0) ? // @@@ padding assumptions | ||
337 | (2 * dAtan2(sint2,cost2)) : // if u points in direction of axis | ||
338 | (2 * dAtan2(sint2,-cost2)); // if u points in opposite direction | ||
339 | |||
340 | // the angle we get will be between 0..2*pi, but we want to return angles | ||
341 | // between -pi..pi | ||
342 | if (theta > M_PI) theta -= 2*M_PI; | ||
343 | |||
344 | // the angle we've just extracted has the wrong sign | ||
345 | theta = -theta; | ||
346 | |||
347 | return theta; | ||
348 | } | ||
349 | |||
350 | |||
351 | // given two bodies (body1,body2), the hinge axis that they are connected by | ||
352 | // w.r.t. body1 (axis), and the initial relative orientation between them | ||
353 | // (q_initial), return the relative rotation angle. the initial relative | ||
354 | // orientation corresponds to an angle of zero. if body2 is 0 then measure the | ||
355 | // angle between body1 and the static frame. | ||
356 | // | ||
357 | // this will not return the correct angle if the bodies rotate along any axis | ||
358 | // other than the given hinge axis. | ||
359 | |||
360 | static dReal getHingeAngle (dxBody *body1, dxBody *body2, dVector3 axis, | ||
361 | dQuaternion q_initial) | ||
362 | { | ||
363 | // get qrel = relative rotation between the two bodies | ||
364 | dQuaternion qrel; | ||
365 | if (body2) { | ||
366 | dQuaternion qq; | ||
367 | dQMultiply1 (qq,body1->q,body2->q); | ||
368 | dQMultiply2 (qrel,qq,q_initial); | ||
369 | } | ||
370 | else { | ||
371 | // pretend body2->q is the identity | ||
372 | dQMultiply3 (qrel,body1->q,q_initial); | ||
373 | } | ||
374 | |||
375 | return getHingeAngleFromRelativeQuat (qrel,axis); | ||
376 | } | ||
377 | |||
378 | //**************************************************************************** | ||
379 | // dxJointLimitMotor | ||
380 | |||
381 | void dxJointLimitMotor::init (dxWorld *world) | ||
382 | { | ||
383 | vel = 0; | ||
384 | fmax = 0; | ||
385 | lostop = -dInfinity; | ||
386 | histop = dInfinity; | ||
387 | fudge_factor = 1; | ||
388 | normal_cfm = world->global_cfm; | ||
389 | stop_erp = world->global_erp; | ||
390 | stop_cfm = world->global_cfm; | ||
391 | bounce = 0; | ||
392 | limit = 0; | ||
393 | limit_err = 0; | ||
394 | } | ||
395 | |||
396 | |||
397 | void dxJointLimitMotor::set (int num, dReal value) | ||
398 | { | ||
399 | switch (num) { | ||
400 | case dParamLoStop: | ||
401 | lostop = value; | ||
402 | break; | ||
403 | case dParamHiStop: | ||
404 | histop = value; | ||
405 | break; | ||
406 | case dParamVel: | ||
407 | vel = value; | ||
408 | break; | ||
409 | case dParamFMax: | ||
410 | if (value >= 0) fmax = value; | ||
411 | break; | ||
412 | case dParamFudgeFactor: | ||
413 | if (value >= 0 && value <= 1) fudge_factor = value; | ||
414 | break; | ||
415 | case dParamBounce: | ||
416 | bounce = value; | ||
417 | break; | ||
418 | case dParamCFM: | ||
419 | normal_cfm = value; | ||
420 | break; | ||
421 | case dParamStopERP: | ||
422 | stop_erp = value; | ||
423 | break; | ||
424 | case dParamStopCFM: | ||
425 | stop_cfm = value; | ||
426 | break; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | |||
431 | dReal dxJointLimitMotor::get (int num) | ||
432 | { | ||
433 | switch (num) { | ||
434 | case dParamLoStop: return lostop; | ||
435 | case dParamHiStop: return histop; | ||
436 | case dParamVel: return vel; | ||
437 | case dParamFMax: return fmax; | ||
438 | case dParamFudgeFactor: return fudge_factor; | ||
439 | case dParamBounce: return bounce; | ||
440 | case dParamCFM: return normal_cfm; | ||
441 | case dParamStopERP: return stop_erp; | ||
442 | case dParamStopCFM: return stop_cfm; | ||
443 | default: return 0; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | |||
448 | int dxJointLimitMotor::testRotationalLimit (dReal angle) | ||
449 | { | ||
450 | if (angle <= lostop) { | ||
451 | limit = 1; | ||
452 | limit_err = angle - lostop; | ||
453 | return 1; | ||
454 | } | ||
455 | else if (angle >= histop) { | ||
456 | limit = 2; | ||
457 | limit_err = angle - histop; | ||
458 | return 1; | ||
459 | } | ||
460 | else { | ||
461 | limit = 0; | ||
462 | return 0; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | |||
467 | int dxJointLimitMotor::addLimot (dxJoint *joint, | ||
468 | dxJoint::Info2 *info, int row, | ||
469 | dVector3 ax1, int rotational) | ||
470 | { | ||
471 | int srow = row * info->rowskip; | ||
472 | |||
473 | // if the joint is powered, or has joint limits, add in the extra row | ||
474 | int powered = fmax > 0; | ||
475 | if (powered || limit) { | ||
476 | dReal *J1 = rotational ? info->J1a : info->J1l; | ||
477 | dReal *J2 = rotational ? info->J2a : info->J2l; | ||
478 | |||
479 | J1[srow+0] = ax1[0]; | ||
480 | J1[srow+1] = ax1[1]; | ||
481 | J1[srow+2] = ax1[2]; | ||
482 | if (joint->node[1].body) { | ||
483 | J2[srow+0] = -ax1[0]; | ||
484 | J2[srow+1] = -ax1[1]; | ||
485 | J2[srow+2] = -ax1[2]; | ||
486 | } | ||
487 | |||
488 | // linear limot torque decoupling step: | ||
489 | // | ||
490 | // if this is a linear limot (e.g. from a slider), we have to be careful | ||
491 | // that the linear constraint forces (+/- ax1) applied to the two bodies | ||
492 | // do not create a torque couple. in other words, the points that the | ||
493 | // constraint force is applied at must lie along the same ax1 axis. | ||
494 | // a torque couple will result in powered or limited slider-jointed free | ||
495 | // bodies from gaining angular momentum. | ||
496 | // the solution used here is to apply the constraint forces at the point | ||
497 | // halfway between the body centers. there is no penalty (other than an | ||
498 | // extra tiny bit of computation) in doing this adjustment. note that we | ||
499 | // only need to do this if the constraint connects two bodies. | ||
500 | |||
501 | dVector3 ltd; // Linear Torque Decoupling vector (a torque) | ||
502 | if (!rotational && joint->node[1].body) { | ||
503 | dVector3 c; | ||
504 | c[0]=REAL(0.5)*(joint->node[1].body->posr.pos[0]-joint->node[0].body->posr.pos[0]); | ||
505 | c[1]=REAL(0.5)*(joint->node[1].body->posr.pos[1]-joint->node[0].body->posr.pos[1]); | ||
506 | c[2]=REAL(0.5)*(joint->node[1].body->posr.pos[2]-joint->node[0].body->posr.pos[2]); | ||
507 | dCROSS (ltd,=,c,ax1); | ||
508 | info->J1a[srow+0] = ltd[0]; | ||
509 | info->J1a[srow+1] = ltd[1]; | ||
510 | info->J1a[srow+2] = ltd[2]; | ||
511 | info->J2a[srow+0] = ltd[0]; | ||
512 | info->J2a[srow+1] = ltd[1]; | ||
513 | info->J2a[srow+2] = ltd[2]; | ||
514 | } | ||
515 | |||
516 | // if we're limited low and high simultaneously, the joint motor is | ||
517 | // ineffective | ||
518 | if (limit && (lostop == histop)) powered = 0; | ||
519 | |||
520 | if (powered) { | ||
521 | info->cfm[row] = normal_cfm; | ||
522 | if (! limit) { | ||
523 | info->c[row] = vel; | ||
524 | info->lo[row] = -fmax; | ||
525 | info->hi[row] = fmax; | ||
526 | } | ||
527 | else { | ||
528 | // the joint is at a limit, AND is being powered. if the joint is | ||
529 | // being powered into the limit then we apply the maximum motor force | ||
530 | // in that direction, because the motor is working against the | ||
531 | // immovable limit. if the joint is being powered away from the limit | ||
532 | // then we have problems because actually we need *two* lcp | ||
533 | // constraints to handle this case. so we fake it and apply some | ||
534 | // fraction of the maximum force. the fraction to use can be set as | ||
535 | // a fudge factor. | ||
536 | |||
537 | dReal fm = fmax; | ||
538 | if ((vel > 0) || (vel==0 && limit==2)) fm = -fm; | ||
539 | |||
540 | // if we're powering away from the limit, apply the fudge factor | ||
541 | if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) fm *= fudge_factor; | ||
542 | |||
543 | if (rotational) { | ||
544 | dBodyAddTorque (joint->node[0].body,-fm*ax1[0],-fm*ax1[1], | ||
545 | -fm*ax1[2]); | ||
546 | if (joint->node[1].body) | ||
547 | dBodyAddTorque (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); | ||
548 | } | ||
549 | else { | ||
550 | dBodyAddForce (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],-fm*ax1[2]); | ||
551 | if (joint->node[1].body) { | ||
552 | dBodyAddForce (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); | ||
553 | |||
554 | // linear limot torque decoupling step: refer to above discussion | ||
555 | dBodyAddTorque (joint->node[0].body,-fm*ltd[0],-fm*ltd[1], | ||
556 | -fm*ltd[2]); | ||
557 | dBodyAddTorque (joint->node[1].body,-fm*ltd[0],-fm*ltd[1], | ||
558 | -fm*ltd[2]); | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
564 | if (limit) { | ||
565 | dReal k = info->fps * stop_erp; | ||
566 | info->c[row] = -k * limit_err; | ||
567 | info->cfm[row] = stop_cfm; | ||
568 | |||
569 | if (lostop == histop) { | ||
570 | // limited low and high simultaneously | ||
571 | info->lo[row] = -dInfinity; | ||
572 | info->hi[row] = dInfinity; | ||
573 | } | ||
574 | else { | ||
575 | if (limit == 1) { | ||
576 | // low limit | ||
577 | info->lo[row] = 0; | ||
578 | info->hi[row] = dInfinity; | ||
579 | } | ||
580 | else { | ||
581 | // high limit | ||
582 | info->lo[row] = -dInfinity; | ||
583 | info->hi[row] = 0; | ||
584 | } | ||
585 | |||
586 | // deal with bounce | ||
587 | if (bounce > 0) { | ||
588 | // calculate joint velocity | ||
589 | dReal vel; | ||
590 | if (rotational) { | ||
591 | vel = dDOT(joint->node[0].body->avel,ax1); | ||
592 | if (joint->node[1].body) | ||
593 | vel -= dDOT(joint->node[1].body->avel,ax1); | ||
594 | } | ||
595 | else { | ||
596 | vel = dDOT(joint->node[0].body->lvel,ax1); | ||
597 | if (joint->node[1].body) | ||
598 | vel -= dDOT(joint->node[1].body->lvel,ax1); | ||
599 | } | ||
600 | |||
601 | // only apply bounce if the velocity is incoming, and if the | ||
602 | // resulting c[] exceeds what we already have. | ||
603 | if (limit == 1) { | ||
604 | // low limit | ||
605 | if (vel < 0) { | ||
606 | dReal newc = -bounce * vel; | ||
607 | if (newc > info->c[row]) info->c[row] = newc; | ||
608 | } | ||
609 | } | ||
610 | else { | ||
611 | // high limit - all those computations are reversed | ||
612 | if (vel > 0) { | ||
613 | dReal newc = -bounce * vel; | ||
614 | if (newc < info->c[row]) info->c[row] = newc; | ||
615 | } | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | } | ||
620 | return 1; | ||
621 | } | ||
622 | else return 0; | ||
623 | } | ||
624 | |||
625 | //**************************************************************************** | ||
626 | // ball and socket | ||
627 | |||
628 | static void ballInit (dxJointBall *j) | ||
629 | { | ||
630 | dSetZero (j->anchor1,4); | ||
631 | dSetZero (j->anchor2,4); | ||
632 | j->erp = j->world->global_erp; | ||
633 | j->cfm = j->world->global_cfm; | ||
634 | } | ||
635 | |||
636 | |||
637 | static void ballGetInfo1 (dxJointBall *j, dxJoint::Info1 *info) | ||
638 | { | ||
639 | info->m = 3; | ||
640 | info->nub = 3; | ||
641 | } | ||
642 | |||
643 | |||
644 | static void ballGetInfo2 (dxJointBall *joint, dxJoint::Info2 *info) | ||
645 | { | ||
646 | info->erp = joint->erp; | ||
647 | info->cfm[0] = joint->cfm; | ||
648 | info->cfm[1] = joint->cfm; | ||
649 | info->cfm[2] = joint->cfm; | ||
650 | setBall (joint,info,joint->anchor1,joint->anchor2); | ||
651 | } | ||
652 | |||
653 | |||
654 | void dJointSetBallAnchor (dJointID j, dReal x, dReal y, dReal z) | ||
655 | { | ||
656 | dxJointBall* joint = (dxJointBall*)j; | ||
657 | dUASSERT(joint,"bad joint argument"); | ||
658 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); | ||
659 | setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); | ||
660 | } | ||
661 | |||
662 | |||
663 | void dJointSetBallAnchor2 (dJointID j, dReal x, dReal y, dReal z) | ||
664 | { | ||
665 | dxJointBall* joint = (dxJointBall*)j; | ||
666 | dUASSERT(joint,"bad joint argument"); | ||
667 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); | ||
668 | joint->anchor2[0] = x; | ||
669 | joint->anchor2[1] = y; | ||
670 | joint->anchor2[2] = z; | ||
671 | joint->anchor2[3] = 0; | ||
672 | |||
673 | } | ||
674 | |||
675 | void dJointGetBallAnchor (dJointID j, dVector3 result) | ||
676 | { | ||
677 | dxJointBall* joint = (dxJointBall*)j; | ||
678 | dUASSERT(joint,"bad joint argument"); | ||
679 | dUASSERT(result,"bad result argument"); | ||
680 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); | ||
681 | if (joint->flags & dJOINT_REVERSE) | ||
682 | getAnchor2 (joint,result,joint->anchor2); | ||
683 | else | ||
684 | getAnchor (joint,result,joint->anchor1); | ||
685 | } | ||
686 | |||
687 | |||
688 | void dJointGetBallAnchor2 (dJointID j, dVector3 result) | ||
689 | { | ||
690 | dxJointBall* joint = (dxJointBall*)j; | ||
691 | dUASSERT(joint,"bad joint argument"); | ||
692 | dUASSERT(result,"bad result argument"); | ||
693 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); | ||
694 | if (joint->flags & dJOINT_REVERSE) | ||
695 | getAnchor (joint,result,joint->anchor1); | ||
696 | else | ||
697 | getAnchor2 (joint,result,joint->anchor2); | ||
698 | } | ||
699 | |||
700 | |||
701 | void dxJointBall::set (int num, dReal value) | ||
702 | { | ||
703 | switch (num) { | ||
704 | case dParamCFM: | ||
705 | cfm = value; | ||
706 | break; | ||
707 | case dParamERP: | ||
708 | erp = value; | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | |||
714 | dReal dxJointBall::get (int num) | ||
715 | { | ||
716 | switch (num) { | ||
717 | case dParamCFM: | ||
718 | return cfm; | ||
719 | case dParamERP: | ||
720 | return erp; | ||
721 | default: | ||
722 | return 0; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | |||
727 | void dJointSetBallParam (dJointID j, int parameter, dReal value) | ||
728 | { | ||
729 | dxJointBall* joint = (dxJointBall*)j; | ||
730 | dUASSERT(joint,"bad joint argument"); | ||
731 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball joint"); | ||
732 | joint->set (parameter,value); | ||
733 | } | ||
734 | |||
735 | |||
736 | dReal dJointGetBallParam (dJointID j, int parameter) | ||
737 | { | ||
738 | dxJointBall* joint = (dxJointBall*)j; | ||
739 | dUASSERT(joint,"bad joint argument"); | ||
740 | dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball joint"); | ||
741 | return joint->get (parameter); | ||
742 | } | ||
743 | |||
744 | |||
745 | dxJoint::Vtable __dball_vtable = { | ||
746 | sizeof(dxJointBall), | ||
747 | (dxJoint::init_fn*) ballInit, | ||
748 | (dxJoint::getInfo1_fn*) ballGetInfo1, | ||
749 | (dxJoint::getInfo2_fn*) ballGetInfo2, | ||
750 | dJointTypeBall}; | ||
751 | |||
752 | //**************************************************************************** | ||
753 | // hinge | ||
754 | |||
755 | static void hingeInit (dxJointHinge *j) | ||
756 | { | ||
757 | dSetZero (j->anchor1,4); | ||
758 | dSetZero (j->anchor2,4); | ||
759 | dSetZero (j->axis1,4); | ||
760 | j->axis1[0] = 1; | ||
761 | dSetZero (j->axis2,4); | ||
762 | j->axis2[0] = 1; | ||
763 | dSetZero (j->qrel,4); | ||
764 | j->limot.init (j->world); | ||
765 | } | ||
766 | |||
767 | |||
768 | static void hingeGetInfo1 (dxJointHinge *j, dxJoint::Info1 *info) | ||
769 | { | ||
770 | info->nub = 5; | ||
771 | |||
772 | // see if joint is powered | ||
773 | if (j->limot.fmax > 0) | ||
774 | info->m = 6; // powered hinge needs an extra constraint row | ||
775 | else info->m = 5; | ||
776 | |||
777 | // see if we're at a joint limit. | ||
778 | if ((j->limot.lostop >= -M_PI || j->limot.histop <= M_PI) && | ||
779 | j->limot.lostop <= j->limot.histop) { | ||
780 | dReal angle = getHingeAngle (j->node[0].body,j->node[1].body,j->axis1, | ||
781 | j->qrel); | ||
782 | if (j->limot.testRotationalLimit (angle)) info->m = 6; | ||
783 | } | ||
784 | } | ||
785 | |||
786 | |||
787 | static void hingeGetInfo2 (dxJointHinge *joint, dxJoint::Info2 *info) | ||
788 | { | ||
789 | // set the three ball-and-socket rows | ||
790 | setBall (joint,info,joint->anchor1,joint->anchor2); | ||
791 | |||
792 | // set the two hinge rows. the hinge axis should be the only unconstrained | ||
793 | // rotational axis, the angular velocity of the two bodies perpendicular to | ||
794 | // the hinge axis should be equal. thus the constraint equations are | ||
795 | // p*w1 - p*w2 = 0 | ||
796 | // q*w1 - q*w2 = 0 | ||
797 | // where p and q are unit vectors normal to the hinge axis, and w1 and w2 | ||
798 | // are the angular velocity vectors of the two bodies. | ||
799 | |||
800 | dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body | ||
801 | dVector3 p,q; // plane space vectors for ax1 | ||
802 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); | ||
803 | dPlaneSpace (ax1,p,q); | ||
804 | |||
805 | int s3=3*info->rowskip; | ||
806 | int s4=4*info->rowskip; | ||
807 | |||
808 | info->J1a[s3+0] = p[0]; | ||
809 | info->J1a[s3+1] = p[1]; | ||
810 | info->J1a[s3+2] = p[2]; | ||
811 | info->J1a[s4+0] = q[0]; | ||
812 | info->J1a[s4+1] = q[1]; | ||
813 | info->J1a[s4+2] = q[2]; | ||
814 | |||
815 | if (joint->node[1].body) { | ||
816 | info->J2a[s3+0] = -p[0]; | ||
817 | info->J2a[s3+1] = -p[1]; | ||
818 | info->J2a[s3+2] = -p[2]; | ||
819 | info->J2a[s4+0] = -q[0]; | ||
820 | info->J2a[s4+1] = -q[1]; | ||
821 | info->J2a[s4+2] = -q[2]; | ||
822 | } | ||
823 | |||
824 | // compute the right hand side of the constraint equation. set relative | ||
825 | // body velocities along p and q to bring the hinge back into alignment. | ||
826 | // if ax1,ax2 are the unit length hinge axes as computed from body1 and | ||
827 | // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). | ||
828 | // if `theta' is the angle between ax1 and ax2, we need an angular velocity | ||
829 | // along u to cover angle erp*theta in one step : | ||
830 | // |angular_velocity| = angle/time = erp*theta / stepsize | ||
831 | // = (erp*fps) * theta | ||
832 | // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| | ||
833 | // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) | ||
834 | // ...as ax1 and ax2 are unit length. if theta is smallish, | ||
835 | // theta ~= sin(theta), so | ||
836 | // angular_velocity = (erp*fps) * (ax1 x ax2) | ||
837 | // ax1 x ax2 is in the plane space of ax1, so we project the angular | ||
838 | // velocity to p and q to find the right hand side. | ||
839 | |||
840 | dVector3 ax2,b; | ||
841 | if (joint->node[1].body) { | ||
842 | dMULTIPLY0_331 (ax2,joint->node[1].body->posr.R,joint->axis2); | ||
843 | } | ||
844 | else { | ||
845 | ax2[0] = joint->axis2[0]; | ||
846 | ax2[1] = joint->axis2[1]; | ||
847 | ax2[2] = joint->axis2[2]; | ||
848 | } | ||
849 | dCROSS (b,=,ax1,ax2); | ||
850 | dReal k = info->fps * info->erp; | ||
851 | info->c[3] = k * dDOT(b,p); | ||
852 | info->c[4] = k * dDOT(b,q); | ||
853 | |||
854 | // if the hinge is powered, or has joint limits, add in the stuff | ||
855 | joint->limot.addLimot (joint,info,5,ax1,1); | ||
856 | } | ||
857 | |||
858 | |||
859 | // compute initial relative rotation body1 -> body2, or env -> body1 | ||
860 | |||
861 | static void hingeComputeInitialRelativeRotation (dxJointHinge *joint) | ||
862 | { | ||
863 | if (joint->node[0].body) { | ||
864 | if (joint->node[1].body) { | ||
865 | dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); | ||
866 | } | ||
867 | else { | ||
868 | // set joint->qrel to the transpose of the first body q | ||
869 | joint->qrel[0] = joint->node[0].body->q[0]; | ||
870 | for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; | ||
871 | } | ||
872 | } | ||
873 | } | ||
874 | |||
875 | |||
876 | void dJointSetHingeAnchor (dJointID j, dReal x, dReal y, dReal z) | ||
877 | { | ||
878 | dxJointHinge* joint = (dxJointHinge*)j; | ||
879 | dUASSERT(joint,"bad joint argument"); | ||
880 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
881 | setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); | ||
882 | hingeComputeInitialRelativeRotation (joint); | ||
883 | } | ||
884 | |||
885 | |||
886 | void dJointSetHingeAnchorDelta (dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz) | ||
887 | { | ||
888 | dxJointHinge* joint = (dxJointHinge*)j; | ||
889 | dUASSERT(joint,"bad joint argument"); | ||
890 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
891 | |||
892 | if (joint->node[0].body) { | ||
893 | dReal q[4]; | ||
894 | q[0] = x - joint->node[0].body->posr.pos[0]; | ||
895 | q[1] = y - joint->node[0].body->posr.pos[1]; | ||
896 | q[2] = z - joint->node[0].body->posr.pos[2]; | ||
897 | q[3] = 0; | ||
898 | dMULTIPLY1_331 (joint->anchor1,joint->node[0].body->posr.R,q); | ||
899 | |||
900 | if (joint->node[1].body) { | ||
901 | q[0] = x - joint->node[1].body->posr.pos[0]; | ||
902 | q[1] = y - joint->node[1].body->posr.pos[1]; | ||
903 | q[2] = z - joint->node[1].body->posr.pos[2]; | ||
904 | q[3] = 0; | ||
905 | dMULTIPLY1_331 (joint->anchor2,joint->node[1].body->posr.R,q); | ||
906 | } | ||
907 | else { | ||
908 | // Move the relative displacement between the passive body and the | ||
909 | // anchor in the same direction as the passive body has just moved | ||
910 | joint->anchor2[0] = x + dx; | ||
911 | joint->anchor2[1] = y + dy; | ||
912 | joint->anchor2[2] = z + dz; | ||
913 | } | ||
914 | } | ||
915 | joint->anchor1[3] = 0; | ||
916 | joint->anchor2[3] = 0; | ||
917 | |||
918 | hingeComputeInitialRelativeRotation (joint); | ||
919 | } | ||
920 | |||
921 | |||
922 | |||
923 | void dJointSetHingeAxis (dJointID j, dReal x, dReal y, dReal z) | ||
924 | { | ||
925 | dxJointHinge* joint = (dxJointHinge*)j; | ||
926 | dUASSERT(joint,"bad joint argument"); | ||
927 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
928 | setAxes (joint,x,y,z,joint->axis1,joint->axis2); | ||
929 | hingeComputeInitialRelativeRotation (joint); | ||
930 | } | ||
931 | |||
932 | |||
933 | void dJointGetHingeAnchor (dJointID j, dVector3 result) | ||
934 | { | ||
935 | dxJointHinge* joint = (dxJointHinge*)j; | ||
936 | dUASSERT(joint,"bad joint argument"); | ||
937 | dUASSERT(result,"bad result argument"); | ||
938 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
939 | if (joint->flags & dJOINT_REVERSE) | ||
940 | getAnchor2 (joint,result,joint->anchor2); | ||
941 | else | ||
942 | getAnchor (joint,result,joint->anchor1); | ||
943 | } | ||
944 | |||
945 | |||
946 | void dJointGetHingeAnchor2 (dJointID j, dVector3 result) | ||
947 | { | ||
948 | dxJointHinge* joint = (dxJointHinge*)j; | ||
949 | dUASSERT(joint,"bad joint argument"); | ||
950 | dUASSERT(result,"bad result argument"); | ||
951 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
952 | if (joint->flags & dJOINT_REVERSE) | ||
953 | getAnchor (joint,result,joint->anchor1); | ||
954 | else | ||
955 | getAnchor2 (joint,result,joint->anchor2); | ||
956 | } | ||
957 | |||
958 | |||
959 | void dJointGetHingeAxis (dJointID j, dVector3 result) | ||
960 | { | ||
961 | dxJointHinge* joint = (dxJointHinge*)j; | ||
962 | dUASSERT(joint,"bad joint argument"); | ||
963 | dUASSERT(result,"bad result argument"); | ||
964 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
965 | getAxis (joint,result,joint->axis1); | ||
966 | } | ||
967 | |||
968 | |||
969 | void dJointSetHingeParam (dJointID j, int parameter, dReal value) | ||
970 | { | ||
971 | dxJointHinge* joint = (dxJointHinge*)j; | ||
972 | dUASSERT(joint,"bad joint argument"); | ||
973 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
974 | joint->limot.set (parameter,value); | ||
975 | } | ||
976 | |||
977 | |||
978 | dReal dJointGetHingeParam (dJointID j, int parameter) | ||
979 | { | ||
980 | dxJointHinge* joint = (dxJointHinge*)j; | ||
981 | dUASSERT(joint,"bad joint argument"); | ||
982 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
983 | return joint->limot.get (parameter); | ||
984 | } | ||
985 | |||
986 | |||
987 | dReal dJointGetHingeAngle (dJointID j) | ||
988 | { | ||
989 | dxJointHinge* joint = (dxJointHinge*)j; | ||
990 | dAASSERT(joint); | ||
991 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); | ||
992 | if (joint->node[0].body) { | ||
993 | dReal ang = getHingeAngle (joint->node[0].body,joint->node[1].body,joint->axis1, | ||
994 | joint->qrel); | ||
995 | if (joint->flags & dJOINT_REVERSE) | ||
996 | return -ang; | ||
997 | else | ||
998 | return ang; | ||
999 | } | ||
1000 | else return 0; | ||
1001 | } | ||
1002 | |||
1003 | |||
1004 | dReal dJointGetHingeAngleRate (dJointID j) | ||
1005 | { | ||
1006 | dxJointHinge* joint = (dxJointHinge*)j; | ||
1007 | dAASSERT(joint); | ||
1008 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); | ||
1009 | if (joint->node[0].body) { | ||
1010 | dVector3 axis; | ||
1011 | dMULTIPLY0_331 (axis,joint->node[0].body->posr.R,joint->axis1); | ||
1012 | dReal rate = dDOT(axis,joint->node[0].body->avel); | ||
1013 | if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); | ||
1014 | if (joint->flags & dJOINT_REVERSE) rate = - rate; | ||
1015 | return rate; | ||
1016 | } | ||
1017 | else return 0; | ||
1018 | } | ||
1019 | |||
1020 | |||
1021 | void dJointAddHingeTorque (dJointID j, dReal torque) | ||
1022 | { | ||
1023 | dxJointHinge* joint = (dxJointHinge*)j; | ||
1024 | dVector3 axis; | ||
1025 | dAASSERT(joint); | ||
1026 | dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); | ||
1027 | |||
1028 | if (joint->flags & dJOINT_REVERSE) | ||
1029 | torque = -torque; | ||
1030 | |||
1031 | getAxis (joint,axis,joint->axis1); | ||
1032 | axis[0] *= torque; | ||
1033 | axis[1] *= torque; | ||
1034 | axis[2] *= torque; | ||
1035 | |||
1036 | if (joint->node[0].body != 0) | ||
1037 | dBodyAddTorque (joint->node[0].body, axis[0], axis[1], axis[2]); | ||
1038 | if (joint->node[1].body != 0) | ||
1039 | dBodyAddTorque(joint->node[1].body, -axis[0], -axis[1], -axis[2]); | ||
1040 | } | ||
1041 | |||
1042 | |||
1043 | dxJoint::Vtable __dhinge_vtable = { | ||
1044 | sizeof(dxJointHinge), | ||
1045 | (dxJoint::init_fn*) hingeInit, | ||
1046 | (dxJoint::getInfo1_fn*) hingeGetInfo1, | ||
1047 | (dxJoint::getInfo2_fn*) hingeGetInfo2, | ||
1048 | dJointTypeHinge}; | ||
1049 | |||
1050 | //**************************************************************************** | ||
1051 | // slider | ||
1052 | |||
1053 | static void sliderInit (dxJointSlider *j) | ||
1054 | { | ||
1055 | dSetZero (j->axis1,4); | ||
1056 | j->axis1[0] = 1; | ||
1057 | dSetZero (j->qrel,4); | ||
1058 | dSetZero (j->offset,4); | ||
1059 | j->limot.init (j->world); | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | dReal dJointGetSliderPosition (dJointID j) | ||
1064 | { | ||
1065 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1066 | dUASSERT(joint,"bad joint argument"); | ||
1067 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1068 | |||
1069 | // get axis1 in global coordinates | ||
1070 | dVector3 ax1,q; | ||
1071 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); | ||
1072 | |||
1073 | if (joint->node[1].body) { | ||
1074 | // get body2 + offset point in global coordinates | ||
1075 | dMULTIPLY0_331 (q,joint->node[1].body->posr.R,joint->offset); | ||
1076 | for (int i=0; i<3; i++) q[i] = joint->node[0].body->posr.pos[i] - q[i] - | ||
1077 | joint->node[1].body->posr.pos[i]; | ||
1078 | } | ||
1079 | else { | ||
1080 | for (int i=0; i<3; i++) q[i] = joint->node[0].body->posr.pos[i] - | ||
1081 | joint->offset[i]; | ||
1082 | |||
1083 | } | ||
1084 | return dDOT(ax1,q); | ||
1085 | } | ||
1086 | |||
1087 | |||
1088 | dReal dJointGetSliderPositionRate (dJointID j) | ||
1089 | { | ||
1090 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1091 | dUASSERT(joint,"bad joint argument"); | ||
1092 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1093 | |||
1094 | // get axis1 in global coordinates | ||
1095 | dVector3 ax1; | ||
1096 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); | ||
1097 | |||
1098 | if (joint->node[1].body) { | ||
1099 | return dDOT(ax1,joint->node[0].body->lvel) - | ||
1100 | dDOT(ax1,joint->node[1].body->lvel); | ||
1101 | } | ||
1102 | else { | ||
1103 | return dDOT(ax1,joint->node[0].body->lvel); | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | static void sliderGetInfo1 (dxJointSlider *j, dxJoint::Info1 *info) | ||
1109 | { | ||
1110 | info->nub = 5; | ||
1111 | |||
1112 | // see if joint is powered | ||
1113 | if (j->limot.fmax > 0) | ||
1114 | info->m = 6; // powered slider needs an extra constraint row | ||
1115 | else info->m = 5; | ||
1116 | |||
1117 | // see if we're at a joint limit. | ||
1118 | j->limot.limit = 0; | ||
1119 | if ((j->limot.lostop > -dInfinity || j->limot.histop < dInfinity) && | ||
1120 | j->limot.lostop <= j->limot.histop) { | ||
1121 | // measure joint position | ||
1122 | dReal pos = dJointGetSliderPosition (j); | ||
1123 | if (pos <= j->limot.lostop) { | ||
1124 | j->limot.limit = 1; | ||
1125 | j->limot.limit_err = pos - j->limot.lostop; | ||
1126 | info->m = 6; | ||
1127 | } | ||
1128 | else if (pos >= j->limot.histop) { | ||
1129 | j->limot.limit = 2; | ||
1130 | j->limot.limit_err = pos - j->limot.histop; | ||
1131 | info->m = 6; | ||
1132 | } | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | static void sliderGetInfo2 (dxJointSlider *joint, dxJoint::Info2 *info) | ||
1138 | { | ||
1139 | int i,s = info->rowskip; | ||
1140 | int s3=3*s,s4=4*s; | ||
1141 | |||
1142 | // pull out pos and R for both bodies. also get the `connection' | ||
1143 | // vector pos2-pos1. | ||
1144 | |||
1145 | dReal *pos1,*pos2,*R1,*R2; | ||
1146 | dVector3 c; | ||
1147 | pos1 = joint->node[0].body->posr.pos; | ||
1148 | R1 = joint->node[0].body->posr.R; | ||
1149 | if (joint->node[1].body) { | ||
1150 | pos2 = joint->node[1].body->posr.pos; | ||
1151 | R2 = joint->node[1].body->posr.R; | ||
1152 | for (i=0; i<3; i++) c[i] = pos2[i] - pos1[i]; | ||
1153 | } | ||
1154 | else { | ||
1155 | pos2 = 0; | ||
1156 | R2 = 0; | ||
1157 | } | ||
1158 | |||
1159 | // 3 rows to make body rotations equal | ||
1160 | setFixedOrientation(joint, info, joint->qrel, 0); | ||
1161 | |||
1162 | // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would | ||
1163 | // result in three equations, so we project along the planespace vectors | ||
1164 | // so that sliding along the slider axis is disregarded. for symmetry we | ||
1165 | // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2. | ||
1166 | |||
1167 | dVector3 ax1; // joint axis in global coordinates (unit length) | ||
1168 | dVector3 p,q; // plane space of ax1 | ||
1169 | dMULTIPLY0_331 (ax1,R1,joint->axis1); | ||
1170 | dPlaneSpace (ax1,p,q); | ||
1171 | if (joint->node[1].body) { | ||
1172 | dVector3 tmp; | ||
1173 | dCROSS (tmp, = REAL(0.5) * ,c,p); | ||
1174 | for (i=0; i<3; i++) info->J1a[s3+i] = tmp[i]; | ||
1175 | for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; | ||
1176 | dCROSS (tmp, = REAL(0.5) * ,c,q); | ||
1177 | for (i=0; i<3; i++) info->J1a[s4+i] = tmp[i]; | ||
1178 | for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; | ||
1179 | for (i=0; i<3; i++) info->J2l[s3+i] = -p[i]; | ||
1180 | for (i=0; i<3; i++) info->J2l[s4+i] = -q[i]; | ||
1181 | } | ||
1182 | for (i=0; i<3; i++) info->J1l[s3+i] = p[i]; | ||
1183 | for (i=0; i<3; i++) info->J1l[s4+i] = q[i]; | ||
1184 | |||
1185 | // compute last two elements of right hand side. we want to align the offset | ||
1186 | // point (in body 2's frame) with the center of body 1. | ||
1187 | dReal k = info->fps * info->erp; | ||
1188 | if (joint->node[1].body) { | ||
1189 | dVector3 ofs; // offset point in global coordinates | ||
1190 | dMULTIPLY0_331 (ofs,R2,joint->offset); | ||
1191 | for (i=0; i<3; i++) c[i] += ofs[i]; | ||
1192 | info->c[3] = k * dDOT(p,c); | ||
1193 | info->c[4] = k * dDOT(q,c); | ||
1194 | } | ||
1195 | else { | ||
1196 | dVector3 ofs; // offset point in global coordinates | ||
1197 | for (i=0; i<3; i++) ofs[i] = joint->offset[i] - pos1[i]; | ||
1198 | info->c[3] = k * dDOT(p,ofs); | ||
1199 | info->c[4] = k * dDOT(q,ofs); | ||
1200 | } | ||
1201 | |||
1202 | // if the slider is powered, or has joint limits, add in the extra row | ||
1203 | joint->limot.addLimot (joint,info,5,ax1,0); | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | void dJointSetSliderAxis (dJointID j, dReal x, dReal y, dReal z) | ||
1208 | { | ||
1209 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1210 | int i; | ||
1211 | dUASSERT(joint,"bad joint argument"); | ||
1212 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1213 | setAxes (joint,x,y,z,joint->axis1,0); | ||
1214 | |||
1215 | // compute initial relative rotation body1 -> body2, or env -> body1 | ||
1216 | // also compute center of body1 w.r.t body 2 | ||
1217 | if (joint->node[1].body) { | ||
1218 | dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); | ||
1219 | dVector3 c; | ||
1220 | for (i=0; i<3; i++) | ||
1221 | c[i] = joint->node[0].body->posr.pos[i] - joint->node[1].body->posr.pos[i]; | ||
1222 | dMULTIPLY1_331 (joint->offset,joint->node[1].body->posr.R,c); | ||
1223 | } | ||
1224 | else { | ||
1225 | // set joint->qrel to the transpose of the first body's q | ||
1226 | joint->qrel[0] = joint->node[0].body->q[0]; | ||
1227 | for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; | ||
1228 | for (i=0; i<3; i++) joint->offset[i] = joint->node[0].body->posr.pos[i]; | ||
1229 | } | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | void dJointSetSliderAxisDelta (dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz) | ||
1234 | { | ||
1235 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1236 | int i; | ||
1237 | dUASSERT(joint,"bad joint argument"); | ||
1238 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1239 | setAxes (joint,x,y,z,joint->axis1,0); | ||
1240 | |||
1241 | // compute initial relative rotation body1 -> body2, or env -> body1 | ||
1242 | // also compute center of body1 w.r.t body 2 | ||
1243 | if (joint->node[1].body) { | ||
1244 | dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); | ||
1245 | dVector3 c; | ||
1246 | for (i=0; i<3; i++) | ||
1247 | c[i] = joint->node[0].body->posr.pos[i] - joint->node[1].body->posr.pos[i]; | ||
1248 | dMULTIPLY1_331 (joint->offset,joint->node[1].body->posr.R,c); | ||
1249 | } | ||
1250 | else { | ||
1251 | // set joint->qrel to the transpose of the first body's q | ||
1252 | joint->qrel[0] = joint->node[0].body->q[0]; | ||
1253 | |||
1254 | for (i=1; i<4; i++) | ||
1255 | joint->qrel[i] = -joint->node[0].body->q[i]; | ||
1256 | |||
1257 | joint->offset[0] = joint->node[0].body->posr.pos[0] + dx; | ||
1258 | joint->offset[1] = joint->node[0].body->posr.pos[1] + dy; | ||
1259 | joint->offset[2] = joint->node[0].body->posr.pos[2] + dz; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | |||
1264 | |||
1265 | void dJointGetSliderAxis (dJointID j, dVector3 result) | ||
1266 | { | ||
1267 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1268 | dUASSERT(joint,"bad joint argument"); | ||
1269 | dUASSERT(result,"bad result argument"); | ||
1270 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1271 | getAxis (joint,result,joint->axis1); | ||
1272 | } | ||
1273 | |||
1274 | |||
1275 | void dJointSetSliderParam (dJointID j, int parameter, dReal value) | ||
1276 | { | ||
1277 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1278 | dUASSERT(joint,"bad joint argument"); | ||
1279 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1280 | joint->limot.set (parameter,value); | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | dReal dJointGetSliderParam (dJointID j, int parameter) | ||
1285 | { | ||
1286 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1287 | dUASSERT(joint,"bad joint argument"); | ||
1288 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1289 | return joint->limot.get (parameter); | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | void dJointAddSliderForce (dJointID j, dReal force) | ||
1294 | { | ||
1295 | dxJointSlider* joint = (dxJointSlider*)j; | ||
1296 | dVector3 axis; | ||
1297 | dUASSERT(joint,"bad joint argument"); | ||
1298 | dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); | ||
1299 | |||
1300 | if (joint->flags & dJOINT_REVERSE) | ||
1301 | force -= force; | ||
1302 | |||
1303 | getAxis (joint,axis,joint->axis1); | ||
1304 | axis[0] *= force; | ||
1305 | axis[1] *= force; | ||
1306 | axis[2] *= force; | ||
1307 | |||
1308 | if (joint->node[0].body != 0) | ||
1309 | dBodyAddForce (joint->node[0].body,axis[0],axis[1],axis[2]); | ||
1310 | if (joint->node[1].body != 0) | ||
1311 | dBodyAddForce(joint->node[1].body, -axis[0], -axis[1], -axis[2]); | ||
1312 | |||
1313 | if (joint->node[0].body != 0 && joint->node[1].body != 0) { | ||
1314 | // linear torque decoupling: | ||
1315 | // we have to compensate the torque, that this slider force may generate | ||
1316 | // if body centers are not aligned along the slider axis | ||
1317 | |||
1318 | dVector3 ltd; // Linear Torque Decoupling vector (a torque) | ||
1319 | |||
1320 | dVector3 c; | ||
1321 | c[0]=REAL(0.5)*(joint->node[1].body->posr.pos[0]-joint->node[0].body->posr.pos[0]); | ||
1322 | c[1]=REAL(0.5)*(joint->node[1].body->posr.pos[1]-joint->node[0].body->posr.pos[1]); | ||
1323 | c[2]=REAL(0.5)*(joint->node[1].body->posr.pos[2]-joint->node[0].body->posr.pos[2]); | ||
1324 | dCROSS (ltd,=,c,axis); | ||
1325 | |||
1326 | dBodyAddTorque (joint->node[0].body,ltd[0],ltd[1], ltd[2]); | ||
1327 | dBodyAddTorque (joint->node[1].body,ltd[0],ltd[1], ltd[2]); | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | dxJoint::Vtable __dslider_vtable = { | ||
1333 | sizeof(dxJointSlider), | ||
1334 | (dxJoint::init_fn*) sliderInit, | ||
1335 | (dxJoint::getInfo1_fn*) sliderGetInfo1, | ||
1336 | (dxJoint::getInfo2_fn*) sliderGetInfo2, | ||
1337 | dJointTypeSlider}; | ||
1338 | |||
1339 | //**************************************************************************** | ||
1340 | // contact | ||
1341 | |||
1342 | static void contactInit (dxJointContact *j) | ||
1343 | { | ||
1344 | // default frictionless contact. hmmm, this info gets overwritten straight | ||
1345 | // away anyway, so why bother? | ||
1346 | #if 0 /* so don't bother ;) */ | ||
1347 | j->contact.surface.mode = 0; | ||
1348 | j->contact.surface.mu = 0; | ||
1349 | dSetZero (j->contact.geom.pos,4); | ||
1350 | dSetZero (j->contact.geom.normal,4); | ||
1351 | j->contact.geom.depth = 0; | ||
1352 | #endif | ||
1353 | } | ||
1354 | |||
1355 | |||
1356 | static void contactGetInfo1 (dxJointContact *j, dxJoint::Info1 *info) | ||
1357 | { | ||
1358 | // make sure mu's >= 0, then calculate number of constraint rows and number | ||
1359 | // of unbounded rows. | ||
1360 | int m = 1, nub=0; | ||
1361 | if (j->contact.surface.mu < 0) j->contact.surface.mu = 0; | ||
1362 | if (j->contact.surface.mode & dContactMu2) { | ||
1363 | if (j->contact.surface.mu > 0) m++; | ||
1364 | if (j->contact.surface.mu2 < 0) j->contact.surface.mu2 = 0; | ||
1365 | if (j->contact.surface.mu2 > 0) m++; | ||
1366 | if (j->contact.surface.mu == dInfinity) nub ++; | ||
1367 | if (j->contact.surface.mu2 == dInfinity) nub ++; | ||
1368 | } | ||
1369 | else { | ||
1370 | if (j->contact.surface.mu > 0) m += 2; | ||
1371 | if (j->contact.surface.mu == dInfinity) nub += 2; | ||
1372 | } | ||
1373 | |||
1374 | j->the_m = m; | ||
1375 | info->m = m; | ||
1376 | info->nub = nub; | ||
1377 | } | ||
1378 | |||
1379 | |||
1380 | static void contactGetInfo2 (dxJointContact *j, dxJoint::Info2 *info) | ||
1381 | { | ||
1382 | int s = info->rowskip; | ||
1383 | int s2 = 2*s; | ||
1384 | |||
1385 | // get normal, with sign adjusted for body1/body2 polarity | ||
1386 | dVector3 normal; | ||
1387 | if (j->flags & dJOINT_REVERSE) { | ||
1388 | normal[0] = - j->contact.geom.normal[0]; | ||
1389 | normal[1] = - j->contact.geom.normal[1]; | ||
1390 | normal[2] = - j->contact.geom.normal[2]; | ||
1391 | } | ||
1392 | else { | ||
1393 | normal[0] = j->contact.geom.normal[0]; | ||
1394 | normal[1] = j->contact.geom.normal[1]; | ||
1395 | normal[2] = j->contact.geom.normal[2]; | ||
1396 | } | ||
1397 | normal[3] = 0; // @@@ hmmm | ||
1398 | |||
1399 | // c1,c2 = contact points with respect to body PORs | ||
1400 | dVector3 c1,c2; | ||
1401 | c1[0] = j->contact.geom.pos[0] - j->node[0].body->posr.pos[0]; | ||
1402 | c1[1] = j->contact.geom.pos[1] - j->node[0].body->posr.pos[1]; | ||
1403 | c1[2] = j->contact.geom.pos[2] - j->node[0].body->posr.pos[2]; | ||
1404 | |||
1405 | // set jacobian for normal | ||
1406 | info->J1l[0] = normal[0]; | ||
1407 | info->J1l[1] = normal[1]; | ||
1408 | info->J1l[2] = normal[2]; | ||
1409 | dCROSS (info->J1a,=,c1,normal); | ||
1410 | if (j->node[1].body) { | ||
1411 | c2[0] = j->contact.geom.pos[0] - j->node[1].body->posr.pos[0]; | ||
1412 | c2[1] = j->contact.geom.pos[1] - j->node[1].body->posr.pos[1]; | ||
1413 | c2[2] = j->contact.geom.pos[2] - j->node[1].body->posr.pos[2]; | ||
1414 | info->J2l[0] = -normal[0]; | ||
1415 | info->J2l[1] = -normal[1]; | ||
1416 | info->J2l[2] = -normal[2]; | ||
1417 | dCROSS (info->J2a,= -,c2,normal); | ||
1418 | } | ||
1419 | |||
1420 | // set right hand side and cfm value for normal | ||
1421 | dReal erp = info->erp; | ||
1422 | if (j->contact.surface.mode & dContactSoftERP) | ||
1423 | erp = j->contact.surface.soft_erp; | ||
1424 | dReal k = info->fps * erp; | ||
1425 | dReal depth = j->contact.geom.depth - j->world->contactp.min_depth; | ||
1426 | if (depth < 0) depth = 0; | ||
1427 | |||
1428 | const dReal maxvel = j->world->contactp.max_vel; | ||
1429 | info->c[0] = k*depth; | ||
1430 | if (info->c[0] > maxvel) | ||
1431 | info->c[0] = maxvel; | ||
1432 | |||
1433 | if (j->contact.surface.mode & dContactSoftCFM) | ||
1434 | info->cfm[0] = j->contact.surface.soft_cfm; | ||
1435 | |||
1436 | // deal with bounce | ||
1437 | if (j->contact.surface.mode & dContactBounce) { | ||
1438 | // calculate outgoing velocity (-ve for incoming contact) | ||
1439 | dReal outgoing = dDOT(info->J1l,j->node[0].body->lvel) + | ||
1440 | dDOT(info->J1a,j->node[0].body->avel); | ||
1441 | if (j->node[1].body) { | ||
1442 | outgoing += dDOT(info->J2l,j->node[1].body->lvel) + | ||
1443 | dDOT(info->J2a,j->node[1].body->avel); | ||
1444 | } | ||
1445 | // only apply bounce if the outgoing velocity is greater than the | ||
1446 | // threshold, and if the resulting c[0] exceeds what we already have. | ||
1447 | if (j->contact.surface.bounce_vel >= 0 && | ||
1448 | (-outgoing) > j->contact.surface.bounce_vel) { | ||
1449 | dReal newc = - j->contact.surface.bounce * outgoing; | ||
1450 | if (newc > info->c[0]) info->c[0] = newc; | ||
1451 | } | ||
1452 | } | ||
1453 | |||
1454 | // set LCP limits for normal | ||
1455 | info->lo[0] = 0; | ||
1456 | info->hi[0] = dInfinity; | ||
1457 | |||
1458 | // now do jacobian for tangential forces | ||
1459 | dVector3 t1,t2; // two vectors tangential to normal | ||
1460 | |||
1461 | // first friction direction | ||
1462 | if (j->the_m >= 2) { | ||
1463 | if (j->contact.surface.mode & dContactFDir1) { // use fdir1 ? | ||
1464 | t1[0] = j->contact.fdir1[0]; | ||
1465 | t1[1] = j->contact.fdir1[1]; | ||
1466 | t1[2] = j->contact.fdir1[2]; | ||
1467 | dCROSS (t2,=,normal,t1); | ||
1468 | } | ||
1469 | else { | ||
1470 | dPlaneSpace (normal,t1,t2); | ||
1471 | } | ||
1472 | info->J1l[s+0] = t1[0]; | ||
1473 | info->J1l[s+1] = t1[1]; | ||
1474 | info->J1l[s+2] = t1[2]; | ||
1475 | dCROSS (info->J1a+s,=,c1,t1); | ||
1476 | if (j->node[1].body) { | ||
1477 | info->J2l[s+0] = -t1[0]; | ||
1478 | info->J2l[s+1] = -t1[1]; | ||
1479 | info->J2l[s+2] = -t1[2]; | ||
1480 | dCROSS (info->J2a+s,= -,c2,t1); | ||
1481 | } | ||
1482 | // set right hand side | ||
1483 | if (j->contact.surface.mode & dContactMotion1) { | ||
1484 | info->c[1] = j->contact.surface.motion1; | ||
1485 | } | ||
1486 | // set LCP bounds and friction index. this depends on the approximation | ||
1487 | // mode | ||
1488 | info->lo[1] = -j->contact.surface.mu; | ||
1489 | info->hi[1] = j->contact.surface.mu; | ||
1490 | if (j->contact.surface.mode & dContactApprox1_1) info->findex[1] = 0; | ||
1491 | |||
1492 | // set slip (constraint force mixing) | ||
1493 | if (j->contact.surface.mode & dContactSlip1) | ||
1494 | info->cfm[1] = j->contact.surface.slip1; | ||
1495 | } | ||
1496 | |||
1497 | // second friction direction | ||
1498 | if (j->the_m >= 3) { | ||
1499 | info->J1l[s2+0] = t2[0]; | ||
1500 | info->J1l[s2+1] = t2[1]; | ||
1501 | info->J1l[s2+2] = t2[2]; | ||
1502 | dCROSS (info->J1a+s2,=,c1,t2); | ||
1503 | if (j->node[1].body) { | ||
1504 | info->J2l[s2+0] = -t2[0]; | ||
1505 | info->J2l[s2+1] = -t2[1]; | ||
1506 | info->J2l[s2+2] = -t2[2]; | ||
1507 | dCROSS (info->J2a+s2,= -,c2,t2); | ||
1508 | } | ||
1509 | // set right hand side | ||
1510 | if (j->contact.surface.mode & dContactMotion2) { | ||
1511 | info->c[2] = j->contact.surface.motion2; | ||
1512 | } | ||
1513 | // set LCP bounds and friction index. this depends on the approximation | ||
1514 | // mode | ||
1515 | if (j->contact.surface.mode & dContactMu2) { | ||
1516 | info->lo[2] = -j->contact.surface.mu2; | ||
1517 | info->hi[2] = j->contact.surface.mu2; | ||
1518 | } | ||
1519 | else { | ||
1520 | info->lo[2] = -j->contact.surface.mu; | ||
1521 | info->hi[2] = j->contact.surface.mu; | ||
1522 | } | ||
1523 | if (j->contact.surface.mode & dContactApprox1_2) info->findex[2] = 0; | ||
1524 | |||
1525 | // set slip (constraint force mixing) | ||
1526 | if (j->contact.surface.mode & dContactSlip2) | ||
1527 | info->cfm[2] = j->contact.surface.slip2; | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | |||
1532 | dxJoint::Vtable __dcontact_vtable = { | ||
1533 | sizeof(dxJointContact), | ||
1534 | (dxJoint::init_fn*) contactInit, | ||
1535 | (dxJoint::getInfo1_fn*) contactGetInfo1, | ||
1536 | (dxJoint::getInfo2_fn*) contactGetInfo2, | ||
1537 | dJointTypeContact}; | ||
1538 | |||
1539 | //**************************************************************************** | ||
1540 | // hinge 2. note that this joint must be attached to two bodies for it to work | ||
1541 | |||
1542 | static dReal measureHinge2Angle (dxJointHinge2 *joint) | ||
1543 | { | ||
1544 | dVector3 a1,a2; | ||
1545 | dMULTIPLY0_331 (a1,joint->node[1].body->posr.R,joint->axis2); | ||
1546 | dMULTIPLY1_331 (a2,joint->node[0].body->posr.R,a1); | ||
1547 | dReal x = dDOT(joint->v1,a2); | ||
1548 | dReal y = dDOT(joint->v2,a2); | ||
1549 | return -dAtan2 (y,x); | ||
1550 | } | ||
1551 | |||
1552 | |||
1553 | static void hinge2Init (dxJointHinge2 *j) | ||
1554 | { | ||
1555 | dSetZero (j->anchor1,4); | ||
1556 | dSetZero (j->anchor2,4); | ||
1557 | dSetZero (j->axis1,4); | ||
1558 | j->axis1[0] = 1; | ||
1559 | dSetZero (j->axis2,4); | ||
1560 | j->axis2[1] = 1; | ||
1561 | j->c0 = 0; | ||
1562 | j->s0 = 0; | ||
1563 | |||
1564 | dSetZero (j->v1,4); | ||
1565 | j->v1[0] = 1; | ||
1566 | dSetZero (j->v2,4); | ||
1567 | j->v2[1] = 1; | ||
1568 | |||
1569 | j->limot1.init (j->world); | ||
1570 | j->limot2.init (j->world); | ||
1571 | |||
1572 | j->susp_erp = j->world->global_erp; | ||
1573 | j->susp_cfm = j->world->global_cfm; | ||
1574 | |||
1575 | j->flags |= dJOINT_TWOBODIES; | ||
1576 | } | ||
1577 | |||
1578 | |||
1579 | static void hinge2GetInfo1 (dxJointHinge2 *j, dxJoint::Info1 *info) | ||
1580 | { | ||
1581 | info->m = 4; | ||
1582 | info->nub = 4; | ||
1583 | |||
1584 | // see if we're powered or at a joint limit for axis 1 | ||
1585 | int atlimit=0; | ||
1586 | if ((j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && | ||
1587 | j->limot1.lostop <= j->limot1.histop) { | ||
1588 | dReal angle = measureHinge2Angle (j); | ||
1589 | if (j->limot1.testRotationalLimit (angle)) atlimit = 1; | ||
1590 | } | ||
1591 | if (atlimit || j->limot1.fmax > 0) info->m++; | ||
1592 | |||
1593 | // see if we're powering axis 2 (we currently never limit this axis) | ||
1594 | j->limot2.limit = 0; | ||
1595 | if (j->limot2.fmax > 0) info->m++; | ||
1596 | } | ||
1597 | |||
1598 | |||
1599 | // macro that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are | ||
1600 | // relative to body 1 and 2 initially) and then computes the constrained | ||
1601 | // rotational axis as the cross product of ax1 and ax2. | ||
1602 | // the sin and cos of the angle between axis 1 and 2 is computed, this comes | ||
1603 | // from dot and cross product rules. | ||
1604 | |||
1605 | #define HINGE2_GET_AXIS_INFO(axis,sin_angle,cos_angle) \ | ||
1606 | dVector3 ax1,ax2; \ | ||
1607 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); \ | ||
1608 | dMULTIPLY0_331 (ax2,joint->node[1].body->posr.R,joint->axis2); \ | ||
1609 | dCROSS (axis,=,ax1,ax2); \ | ||
1610 | sin_angle = dSqrt (axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); \ | ||
1611 | cos_angle = dDOT (ax1,ax2); | ||
1612 | |||
1613 | |||
1614 | static void hinge2GetInfo2 (dxJointHinge2 *joint, dxJoint::Info2 *info) | ||
1615 | { | ||
1616 | // get information we need to set the hinge row | ||
1617 | dReal s,c; | ||
1618 | dVector3 q; | ||
1619 | HINGE2_GET_AXIS_INFO (q,s,c); | ||
1620 | dNormalize3 (q); // @@@ quicker: divide q by s ? | ||
1621 | |||
1622 | // set the three ball-and-socket rows (aligned to the suspension axis ax1) | ||
1623 | setBall2 (joint,info,joint->anchor1,joint->anchor2,ax1,joint->susp_erp); | ||
1624 | |||
1625 | // set the hinge row | ||
1626 | int s3=3*info->rowskip; | ||
1627 | info->J1a[s3+0] = q[0]; | ||
1628 | info->J1a[s3+1] = q[1]; | ||
1629 | info->J1a[s3+2] = q[2]; | ||
1630 | if (joint->node[1].body) { | ||
1631 | info->J2a[s3+0] = -q[0]; | ||
1632 | info->J2a[s3+1] = -q[1]; | ||
1633 | info->J2a[s3+2] = -q[2]; | ||
1634 | } | ||
1635 | |||
1636 | // compute the right hand side for the constrained rotational DOF. | ||
1637 | // axis 1 and axis 2 are separated by an angle `theta'. the desired | ||
1638 | // separation angle is theta0. sin(theta0) and cos(theta0) are recorded | ||
1639 | // in the joint structure. the correcting angular velocity is: | ||
1640 | // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize | ||
1641 | // = (erp*fps) * (theta0-theta) | ||
1642 | // (theta0-theta) can be computed using the following small-angle-difference | ||
1643 | // approximation: | ||
1644 | // theta0-theta ~= tan(theta0-theta) | ||
1645 | // = sin(theta0-theta)/cos(theta0-theta) | ||
1646 | // = (c*s0 - s*c0) / (c*c0 + s*s0) | ||
1647 | // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1 | ||
1648 | // where c = cos(theta), s = sin(theta) | ||
1649 | // c0 = cos(theta0), s0 = sin(theta0) | ||
1650 | |||
1651 | dReal k = info->fps * info->erp; | ||
1652 | info->c[3] = k * (joint->c0 * s - joint->s0 * c); | ||
1653 | |||
1654 | // if the axis1 hinge is powered, or has joint limits, add in more stuff | ||
1655 | int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); | ||
1656 | |||
1657 | // if the axis2 hinge is powered, add in more stuff | ||
1658 | joint->limot2.addLimot (joint,info,row,ax2,1); | ||
1659 | |||
1660 | // set parameter for the suspension | ||
1661 | info->cfm[0] = joint->susp_cfm; | ||
1662 | } | ||
1663 | |||
1664 | |||
1665 | // compute vectors v1 and v2 (embedded in body1), used to measure angle | ||
1666 | // between body 1 and body 2 | ||
1667 | |||
1668 | static void makeHinge2V1andV2 (dxJointHinge2 *joint) | ||
1669 | { | ||
1670 | if (joint->node[0].body) { | ||
1671 | // get axis 1 and 2 in global coords | ||
1672 | dVector3 ax1,ax2,v; | ||
1673 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); | ||
1674 | dMULTIPLY0_331 (ax2,joint->node[1].body->posr.R,joint->axis2); | ||
1675 | |||
1676 | // don't do anything if the axis1 or axis2 vectors are zero or the same | ||
1677 | if ((ax1[0]==0 && ax1[1]==0 && ax1[2]==0) || | ||
1678 | (ax2[0]==0 && ax2[1]==0 && ax2[2]==0) || | ||
1679 | (ax1[0]==ax2[0] && ax1[1]==ax2[1] && ax1[2]==ax2[2])) return; | ||
1680 | |||
1681 | // modify axis 2 so it's perpendicular to axis 1 | ||
1682 | dReal k = dDOT(ax1,ax2); | ||
1683 | for (int i=0; i<3; i++) ax2[i] -= k*ax1[i]; | ||
1684 | dNormalize3 (ax2); | ||
1685 | |||
1686 | // make v1 = modified axis2, v2 = axis1 x (modified axis2) | ||
1687 | dCROSS (v,=,ax1,ax2); | ||
1688 | dMULTIPLY1_331 (joint->v1,joint->node[0].body->posr.R,ax2); | ||
1689 | dMULTIPLY1_331 (joint->v2,joint->node[0].body->posr.R,v); | ||
1690 | } | ||
1691 | } | ||
1692 | |||
1693 | |||
1694 | void dJointSetHinge2Anchor (dJointID j, dReal x, dReal y, dReal z) | ||
1695 | { | ||
1696 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1697 | dUASSERT(joint,"bad joint argument"); | ||
1698 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1699 | setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); | ||
1700 | makeHinge2V1andV2 (joint); | ||
1701 | } | ||
1702 | |||
1703 | |||
1704 | void dJointSetHinge2Axis1 (dJointID j, dReal x, dReal y, dReal z) | ||
1705 | { | ||
1706 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1707 | dUASSERT(joint,"bad joint argument"); | ||
1708 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1709 | if (joint->node[0].body) { | ||
1710 | dReal q[4]; | ||
1711 | q[0] = x; | ||
1712 | q[1] = y; | ||
1713 | q[2] = z; | ||
1714 | q[3] = 0; | ||
1715 | dNormalize3 (q); | ||
1716 | dMULTIPLY1_331 (joint->axis1,joint->node[0].body->posr.R,q); | ||
1717 | joint->axis1[3] = 0; | ||
1718 | |||
1719 | // compute the sin and cos of the angle between axis 1 and axis 2 | ||
1720 | dVector3 ax; | ||
1721 | HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); | ||
1722 | } | ||
1723 | makeHinge2V1andV2 (joint); | ||
1724 | } | ||
1725 | |||
1726 | |||
1727 | void dJointSetHinge2Axis2 (dJointID j, dReal x, dReal y, dReal z) | ||
1728 | { | ||
1729 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1730 | dUASSERT(joint,"bad joint argument"); | ||
1731 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1732 | if (joint->node[1].body) { | ||
1733 | dReal q[4]; | ||
1734 | q[0] = x; | ||
1735 | q[1] = y; | ||
1736 | q[2] = z; | ||
1737 | q[3] = 0; | ||
1738 | dNormalize3 (q); | ||
1739 | dMULTIPLY1_331 (joint->axis2,joint->node[1].body->posr.R,q); | ||
1740 | joint->axis1[3] = 0; | ||
1741 | |||
1742 | // compute the sin and cos of the angle between axis 1 and axis 2 | ||
1743 | dVector3 ax; | ||
1744 | HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); | ||
1745 | } | ||
1746 | makeHinge2V1andV2 (joint); | ||
1747 | } | ||
1748 | |||
1749 | |||
1750 | void dJointSetHinge2Param (dJointID j, int parameter, dReal value) | ||
1751 | { | ||
1752 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1753 | dUASSERT(joint,"bad joint argument"); | ||
1754 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1755 | if ((parameter & 0xff00) == 0x100) { | ||
1756 | joint->limot2.set (parameter & 0xff,value); | ||
1757 | } | ||
1758 | else { | ||
1759 | if (parameter == dParamSuspensionERP) joint->susp_erp = value; | ||
1760 | else if (parameter == dParamSuspensionCFM) joint->susp_cfm = value; | ||
1761 | else joint->limot1.set (parameter,value); | ||
1762 | } | ||
1763 | } | ||
1764 | |||
1765 | |||
1766 | void dJointGetHinge2Anchor (dJointID j, dVector3 result) | ||
1767 | { | ||
1768 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1769 | dUASSERT(joint,"bad joint argument"); | ||
1770 | dUASSERT(result,"bad result argument"); | ||
1771 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1772 | if (joint->flags & dJOINT_REVERSE) | ||
1773 | getAnchor2 (joint,result,joint->anchor2); | ||
1774 | else | ||
1775 | getAnchor (joint,result,joint->anchor1); | ||
1776 | } | ||
1777 | |||
1778 | |||
1779 | void dJointGetHinge2Anchor2 (dJointID j, dVector3 result) | ||
1780 | { | ||
1781 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1782 | dUASSERT(joint,"bad joint argument"); | ||
1783 | dUASSERT(result,"bad result argument"); | ||
1784 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1785 | if (joint->flags & dJOINT_REVERSE) | ||
1786 | getAnchor (joint,result,joint->anchor1); | ||
1787 | else | ||
1788 | getAnchor2 (joint,result,joint->anchor2); | ||
1789 | } | ||
1790 | |||
1791 | |||
1792 | void dJointGetHinge2Axis1 (dJointID j, dVector3 result) | ||
1793 | { | ||
1794 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1795 | dUASSERT(joint,"bad joint argument"); | ||
1796 | dUASSERT(result,"bad result argument"); | ||
1797 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1798 | if (joint->node[0].body) { | ||
1799 | dMULTIPLY0_331 (result,joint->node[0].body->posr.R,joint->axis1); | ||
1800 | } | ||
1801 | } | ||
1802 | |||
1803 | |||
1804 | void dJointGetHinge2Axis2 (dJointID j, dVector3 result) | ||
1805 | { | ||
1806 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1807 | dUASSERT(joint,"bad joint argument"); | ||
1808 | dUASSERT(result,"bad result argument"); | ||
1809 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1810 | if (joint->node[1].body) { | ||
1811 | dMULTIPLY0_331 (result,joint->node[1].body->posr.R,joint->axis2); | ||
1812 | } | ||
1813 | } | ||
1814 | |||
1815 | |||
1816 | dReal dJointGetHinge2Param (dJointID j, int parameter) | ||
1817 | { | ||
1818 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1819 | dUASSERT(joint,"bad joint argument"); | ||
1820 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1821 | if ((parameter & 0xff00) == 0x100) { | ||
1822 | return joint->limot2.get (parameter & 0xff); | ||
1823 | } | ||
1824 | else { | ||
1825 | if (parameter == dParamSuspensionERP) return joint->susp_erp; | ||
1826 | else if (parameter == dParamSuspensionCFM) return joint->susp_cfm; | ||
1827 | else return joint->limot1.get (parameter); | ||
1828 | } | ||
1829 | } | ||
1830 | |||
1831 | |||
1832 | dReal dJointGetHinge2Angle1 (dJointID j) | ||
1833 | { | ||
1834 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1835 | dUASSERT(joint,"bad joint argument"); | ||
1836 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1837 | if (joint->node[0].body) return measureHinge2Angle (joint); | ||
1838 | else return 0; | ||
1839 | } | ||
1840 | |||
1841 | |||
1842 | dReal dJointGetHinge2Angle1Rate (dJointID j) | ||
1843 | { | ||
1844 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1845 | dUASSERT(joint,"bad joint argument"); | ||
1846 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1847 | if (joint->node[0].body) { | ||
1848 | dVector3 axis; | ||
1849 | dMULTIPLY0_331 (axis,joint->node[0].body->posr.R,joint->axis1); | ||
1850 | dReal rate = dDOT(axis,joint->node[0].body->avel); | ||
1851 | if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); | ||
1852 | return rate; | ||
1853 | } | ||
1854 | else return 0; | ||
1855 | } | ||
1856 | |||
1857 | |||
1858 | dReal dJointGetHinge2Angle2Rate (dJointID j) | ||
1859 | { | ||
1860 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1861 | dUASSERT(joint,"bad joint argument"); | ||
1862 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1863 | if (joint->node[0].body && joint->node[1].body) { | ||
1864 | dVector3 axis; | ||
1865 | dMULTIPLY0_331 (axis,joint->node[1].body->posr.R,joint->axis2); | ||
1866 | dReal rate = dDOT(axis,joint->node[0].body->avel); | ||
1867 | if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); | ||
1868 | return rate; | ||
1869 | } | ||
1870 | else return 0; | ||
1871 | } | ||
1872 | |||
1873 | |||
1874 | void dJointAddHinge2Torques (dJointID j, dReal torque1, dReal torque2) | ||
1875 | { | ||
1876 | dxJointHinge2* joint = (dxJointHinge2*)j; | ||
1877 | dVector3 axis1, axis2; | ||
1878 | dUASSERT(joint,"bad joint argument"); | ||
1879 | dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); | ||
1880 | |||
1881 | if (joint->node[0].body && joint->node[1].body) { | ||
1882 | dMULTIPLY0_331 (axis1,joint->node[0].body->posr.R,joint->axis1); | ||
1883 | dMULTIPLY0_331 (axis2,joint->node[1].body->posr.R,joint->axis2); | ||
1884 | axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; | ||
1885 | axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; | ||
1886 | axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; | ||
1887 | dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); | ||
1888 | dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); | ||
1889 | } | ||
1890 | } | ||
1891 | |||
1892 | |||
1893 | dxJoint::Vtable __dhinge2_vtable = { | ||
1894 | sizeof(dxJointHinge2), | ||
1895 | (dxJoint::init_fn*) hinge2Init, | ||
1896 | (dxJoint::getInfo1_fn*) hinge2GetInfo1, | ||
1897 | (dxJoint::getInfo2_fn*) hinge2GetInfo2, | ||
1898 | dJointTypeHinge2}; | ||
1899 | |||
1900 | //**************************************************************************** | ||
1901 | // universal | ||
1902 | |||
1903 | // I just realized that the universal joint is equivalent to a hinge 2 joint with | ||
1904 | // perfectly stiff suspension. By comparing the hinge 2 implementation to | ||
1905 | // the universal implementation, you may be able to improve this | ||
1906 | // implementation (or, less likely, the hinge2 implementation). | ||
1907 | |||
1908 | static void universalInit (dxJointUniversal *j) | ||
1909 | { | ||
1910 | dSetZero (j->anchor1,4); | ||
1911 | dSetZero (j->anchor2,4); | ||
1912 | dSetZero (j->axis1,4); | ||
1913 | j->axis1[0] = 1; | ||
1914 | dSetZero (j->axis2,4); | ||
1915 | j->axis2[1] = 1; | ||
1916 | dSetZero(j->qrel1,4); | ||
1917 | dSetZero(j->qrel2,4); | ||
1918 | j->limot1.init (j->world); | ||
1919 | j->limot2.init (j->world); | ||
1920 | } | ||
1921 | |||
1922 | |||
1923 | static void getUniversalAxes(dxJointUniversal *joint, dVector3 ax1, dVector3 ax2) | ||
1924 | { | ||
1925 | // This says "ax1 = joint->node[0].body->posr.R * joint->axis1" | ||
1926 | dMULTIPLY0_331 (ax1,joint->node[0].body->posr.R,joint->axis1); | ||
1927 | |||
1928 | if (joint->node[1].body) { | ||
1929 | dMULTIPLY0_331 (ax2,joint->node[1].body->posr.R,joint->axis2); | ||
1930 | } | ||
1931 | else { | ||
1932 | ax2[0] = joint->axis2[0]; | ||
1933 | ax2[1] = joint->axis2[1]; | ||
1934 | ax2[2] = joint->axis2[2]; | ||
1935 | } | ||
1936 | } | ||
1937 | |||
1938 | static void getUniversalAngles(dxJointUniversal *joint, dReal *angle1, dReal *angle2) | ||
1939 | { | ||
1940 | if (joint->node[0].body) | ||
1941 | { | ||
1942 | // length 1 joint axis in global coordinates, from each body | ||
1943 | dVector3 ax1, ax2; | ||
1944 | dMatrix3 R; | ||
1945 | dQuaternion qcross, qq, qrel; | ||
1946 | |||
1947 | getUniversalAxes (joint,ax1,ax2); | ||
1948 | |||
1949 | // It should be possible to get both angles without explicitly | ||
1950 | // constructing the rotation matrix of the cross. Basically, | ||
1951 | // orientation of the cross about axis1 comes from body 2, | ||
1952 | // about axis 2 comes from body 1, and the perpendicular | ||
1953 | // axis can come from the two bodies somehow. (We don't really | ||
1954 | // want to assume it's 90 degrees, because in general the | ||
1955 | // constraints won't be perfectly satisfied, or even very well | ||
1956 | // satisfied.) | ||
1957 | // | ||
1958 | // However, we'd need a version of getHingeAngleFromRElativeQuat() | ||
1959 | // that CAN handle when its relative quat is rotated along a direction | ||
1960 | // other than the given axis. What I have here works, | ||
1961 | // although it's probably much slower than need be. | ||
1962 | |||
1963 | dRFrom2Axes (R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); | ||
1964 | |||
1965 | dRtoQ (R, qcross); | ||
1966 | |||
1967 | |||
1968 | // This code is essentialy the same as getHingeAngle(), see the comments | ||
1969 | // there for details. | ||
1970 | |||
1971 | // get qrel = relative rotation between node[0] and the cross | ||
1972 | dQMultiply1 (qq, joint->node[0].body->q, qcross); | ||
1973 | dQMultiply2 (qrel, qq, joint->qrel1); | ||
1974 | |||
1975 | *angle1 = getHingeAngleFromRelativeQuat(qrel, joint->axis1); | ||
1976 | |||
1977 | // This is equivalent to | ||
1978 | // dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); | ||
1979 | // You see that the R is constructed from the same 2 axis as for angle1 | ||
1980 | // but the first and second axis are swapped. | ||
1981 | // So we can take the first R and rapply a rotation to it. | ||
1982 | // The rotation is around the axis between the 2 axes (ax1 and ax2). | ||
1983 | // We do a rotation of 180deg. | ||
1984 | |||
1985 | dQuaternion qcross2; | ||
1986 | // Find the vector between ax1 and ax2 (i.e. in the middle) | ||
1987 | // We need to turn around this vector by 180deg | ||
1988 | |||
1989 | // The 2 axes should be normalize so to find the vector between the 2. | ||
1990 | // Add and devide by 2 then normalize or simply normalize | ||
1991 | // ax2 | ||
1992 | // ^ | ||
1993 | // | | ||
1994 | // | | ||
1995 | /// *------------> ax1 | ||
1996 | // We want the vector a 45deg | ||
1997 | // | ||
1998 | // N.B. We don't need to normalize the ax1 and ax2 since there are | ||
1999 | // normalized when we set them. | ||
2000 | |||
2001 | // We set the quaternion q = [cos(theta), dir*sin(theta)] = [w, x, y, Z] | ||
2002 | qrel[0] = 0; // equivalent to cos(Pi/2) | ||
2003 | qrel[1] = ax1[0] + ax2[0]; // equivalent to x*sin(Pi/2); since sin(Pi/2) = 1 | ||
2004 | qrel[2] = ax1[1] + ax2[1]; | ||
2005 | qrel[3] = ax1[2] + ax2[2]; | ||
2006 | |||
2007 | dReal l = dRecip(sqrt(qrel[1]*qrel[1] + qrel[2]*qrel[2] + qrel[3]*qrel[3])); | ||
2008 | qrel[1] *= l; | ||
2009 | qrel[2] *= l; | ||
2010 | qrel[3] *= l; | ||
2011 | |||
2012 | dQMultiply0 (qcross2, qrel, qcross); | ||
2013 | |||
2014 | if (joint->node[1].body) { | ||
2015 | dQMultiply1 (qq, joint->node[1].body->q, qcross2); | ||
2016 | dQMultiply2 (qrel, qq, joint->qrel2); | ||
2017 | } | ||
2018 | else { | ||
2019 | // pretend joint->node[1].body->q is the identity | ||
2020 | dQMultiply2 (qrel, qcross2, joint->qrel2); | ||
2021 | } | ||
2022 | |||
2023 | *angle2 = - getHingeAngleFromRelativeQuat(qrel, joint->axis2); | ||
2024 | |||
2025 | } | ||
2026 | else | ||
2027 | { | ||
2028 | *angle1 = 0; | ||
2029 | *angle2 = 0; | ||
2030 | } | ||
2031 | } | ||
2032 | |||
2033 | static dReal getUniversalAngle1(dxJointUniversal *joint) | ||
2034 | { | ||
2035 | if (joint->node[0].body) { | ||
2036 | // length 1 joint axis in global coordinates, from each body | ||
2037 | dVector3 ax1, ax2; | ||
2038 | dMatrix3 R; | ||
2039 | dQuaternion qcross, qq, qrel; | ||
2040 | |||
2041 | getUniversalAxes (joint,ax1,ax2); | ||
2042 | |||
2043 | // It should be possible to get both angles without explicitly | ||
2044 | // constructing the rotation matrix of the cross. Basically, | ||
2045 | // orientation of the cross about axis1 comes from body 2, | ||
2046 | // about axis 2 comes from body 1, and the perpendicular | ||
2047 | // axis can come from the two bodies somehow. (We don't really | ||
2048 | // want to assume it's 90 degrees, because in general the | ||
2049 | // constraints won't be perfectly satisfied, or even very well | ||
2050 | // satisfied.) | ||
2051 | // | ||
2052 | // However, we'd need a version of getHingeAngleFromRElativeQuat() | ||
2053 | // that CAN handle when its relative quat is rotated along a direction | ||
2054 | // other than the given axis. What I have here works, | ||
2055 | // although it's probably much slower than need be. | ||
2056 | |||
2057 | dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); | ||
2058 | dRtoQ (R,qcross); | ||
2059 | |||
2060 | // This code is essential the same as getHingeAngle(), see the comments | ||
2061 | // there for details. | ||
2062 | |||
2063 | // get qrel = relative rotation between node[0] and the cross | ||
2064 | dQMultiply1 (qq,joint->node[0].body->q,qcross); | ||
2065 | dQMultiply2 (qrel,qq,joint->qrel1); | ||
2066 | |||
2067 | return getHingeAngleFromRelativeQuat(qrel, joint->axis1); | ||
2068 | } | ||
2069 | return 0; | ||
2070 | } | ||
2071 | |||
2072 | |||
2073 | static dReal getUniversalAngle2(dxJointUniversal *joint) | ||
2074 | { | ||
2075 | if (joint->node[0].body) { | ||
2076 | // length 1 joint axis in global coordinates, from each body | ||
2077 | dVector3 ax1, ax2; | ||
2078 | dMatrix3 R; | ||
2079 | dQuaternion qcross, qq, qrel; | ||
2080 | |||
2081 | getUniversalAxes (joint,ax1,ax2); | ||
2082 | |||
2083 | // It should be possible to get both angles without explicitly | ||
2084 | // constructing the rotation matrix of the cross. Basically, | ||
2085 | // orientation of the cross about axis1 comes from body 2, | ||
2086 | // about axis 2 comes from body 1, and the perpendicular | ||
2087 | // axis can come from the two bodies somehow. (We don't really | ||
2088 | // want to assume it's 90 degrees, because in general the | ||
2089 | // constraints won't be perfectly satisfied, or even very well | ||
2090 | // satisfied.) | ||
2091 | // | ||
2092 | // However, we'd need a version of getHingeAngleFromRElativeQuat() | ||
2093 | // that CAN handle when its relative quat is rotated along a direction | ||
2094 | // other than the given axis. What I have here works, | ||
2095 | // although it's probably much slower than need be. | ||
2096 | |||
2097 | dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); | ||
2098 | dRtoQ(R, qcross); | ||
2099 | |||
2100 | if (joint->node[1].body) { | ||
2101 | dQMultiply1 (qq, joint->node[1].body->q, qcross); | ||
2102 | dQMultiply2 (qrel,qq,joint->qrel2); | ||
2103 | } | ||
2104 | else { | ||
2105 | // pretend joint->node[1].body->q is the identity | ||
2106 | dQMultiply2 (qrel,qcross, joint->qrel2); | ||
2107 | } | ||
2108 | |||
2109 | return - getHingeAngleFromRelativeQuat(qrel, joint->axis2); | ||
2110 | } | ||
2111 | return 0; | ||
2112 | } | ||
2113 | |||
2114 | |||
2115 | static void universalGetInfo1 (dxJointUniversal *j, dxJoint::Info1 *info) | ||
2116 | { | ||
2117 | info->nub = 4; | ||
2118 | info->m = 4; | ||
2119 | |||
2120 | // see if we're powered or at a joint limit. | ||
2121 | bool constraint1 = j->limot1.fmax > 0; | ||
2122 | bool constraint2 = j->limot2.fmax > 0; | ||
2123 | |||
2124 | bool limiting1 = (j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && | ||
2125 | j->limot1.lostop <= j->limot1.histop; | ||
2126 | bool limiting2 = (j->limot2.lostop >= -M_PI || j->limot2.histop <= M_PI) && | ||
2127 | j->limot2.lostop <= j->limot2.histop; | ||
2128 | |||
2129 | // We need to call testRotationLimit() even if we're motored, since it | ||
2130 | // records the result. | ||
2131 | if (limiting1 || limiting2) { | ||
2132 | dReal angle1, angle2; | ||
2133 | getUniversalAngles (j, &angle1, &angle2); | ||
2134 | if (limiting1 && j->limot1.testRotationalLimit (angle1)) constraint1 = true; | ||
2135 | if (limiting2 && j->limot2.testRotationalLimit (angle2)) constraint2 = true; | ||
2136 | } | ||
2137 | if (constraint1) | ||
2138 | info->m++; | ||
2139 | if (constraint2) | ||
2140 | info->m++; | ||
2141 | } | ||
2142 | |||
2143 | |||
2144 | static void universalGetInfo2 (dxJointUniversal *joint, dxJoint::Info2 *info) | ||
2145 | { | ||
2146 | // set the three ball-and-socket rows | ||
2147 | setBall (joint,info,joint->anchor1,joint->anchor2); | ||
2148 | |||
2149 | // set the universal joint row. the angular velocity about an axis | ||
2150 | // perpendicular to both joint axes should be equal. thus the constraint | ||
2151 | // equation is | ||
2152 | // p*w1 - p*w2 = 0 | ||
2153 | // where p is a vector normal to both joint axes, and w1 and w2 | ||
2154 | // are the angular velocity vectors of the two bodies. | ||
2155 | |||
2156 | // length 1 joint axis in global coordinates, from each body | ||
2157 | dVector3 ax1, ax2; | ||
2158 | dVector3 ax2_temp; | ||
2159 | // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate | ||
2160 | // about this. | ||
2161 | dVector3 p; | ||
2162 | dReal k; | ||
2163 | |||
2164 | getUniversalAxes(joint, ax1, ax2); | ||
2165 | k = dDOT(ax1, ax2); | ||
2166 | ax2_temp[0] = ax2[0] - k*ax1[0]; | ||
2167 | ax2_temp[1] = ax2[1] - k*ax1[1]; | ||
2168 | ax2_temp[2] = ax2[2] - k*ax1[2]; | ||
2169 | dCROSS(p, =, ax1, ax2_temp); | ||
2170 | dNormalize3(p); | ||
2171 | |||
2172 | int s3=3*info->rowskip; | ||
2173 | |||
2174 | info->J1a[s3+0] = p[0]; | ||
2175 | info->J1a[s3+1] = p[1]; | ||
2176 | info->J1a[s3+2] = p[2]; | ||
2177 | |||
2178 | if (joint->node[1].body) { | ||
2179 | info->J2a[s3+0] = -p[0]; | ||
2180 | info->J2a[s3+1] = -p[1]; | ||
2181 | info->J2a[s3+2] = -p[2]; | ||
2182 | } | ||
2183 | |||
2184 | // compute the right hand side of the constraint equation. set relative | ||
2185 | // body velocities along p to bring the axes back to perpendicular. | ||
2186 | // If ax1, ax2 are unit length joint axes as computed from body1 and | ||
2187 | // body2, we need to rotate both bodies along the axis p. If theta | ||
2188 | // is the angle between ax1 and ax2, we need an angular velocity | ||
2189 | // along p to cover the angle erp * (theta - Pi/2) in one step: | ||
2190 | // | ||
2191 | // |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize | ||
2192 | // = (erp*fps) * (theta - Pi/2) | ||
2193 | // | ||
2194 | // if theta is close to Pi/2, | ||
2195 | // theta - Pi/2 ~= cos(theta), so | ||
2196 | // |angular_velocity| ~= (erp*fps) * (ax1 dot ax2) | ||
2197 | |||
2198 | info->c[3] = info->fps * info->erp * - dDOT(ax1, ax2); | ||
2199 | |||
2200 | // if the first angle is powered, or has joint limits, add in the stuff | ||
2201 | int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); | ||
2202 | |||
2203 | // if the second angle is powered, or has joint limits, add in more stuff | ||
2204 | joint->limot2.addLimot (joint,info,row,ax2,1); | ||
2205 | } | ||
2206 | |||
2207 | |||
2208 | static void universalComputeInitialRelativeRotations (dxJointUniversal *joint) | ||
2209 | { | ||
2210 | if (joint->node[0].body) { | ||
2211 | dVector3 ax1, ax2; | ||
2212 | dMatrix3 R; | ||
2213 | dQuaternion qcross; | ||
2214 | |||
2215 | getUniversalAxes(joint, ax1, ax2); | ||
2216 | |||
2217 | // Axis 1. | ||
2218 | dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); | ||
2219 | dRtoQ(R, qcross); | ||
2220 | dQMultiply1 (joint->qrel1, joint->node[0].body->q, qcross); | ||
2221 | |||
2222 | // Axis 2. | ||
2223 | dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); | ||
2224 | dRtoQ(R, qcross); | ||
2225 | if (joint->node[1].body) { | ||
2226 | dQMultiply1 (joint->qrel2, joint->node[1].body->q, qcross); | ||
2227 | } | ||
2228 | else { | ||
2229 | // set joint->qrel to qcross | ||
2230 | for (int i=0; i<4; i++) joint->qrel2[i] = qcross[i]; | ||
2231 | } | ||
2232 | } | ||
2233 | } | ||
2234 | |||
2235 | |||
2236 | void dJointSetUniversalAnchor (dJointID j, dReal x, dReal y, dReal z) | ||
2237 | { | ||
2238 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2239 | dUASSERT(joint,"bad joint argument"); | ||
2240 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2241 | setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); | ||
2242 | universalComputeInitialRelativeRotations(joint); | ||
2243 | } | ||
2244 | |||
2245 | |||
2246 | void dJointSetUniversalAxis1 (dJointID j, dReal x, dReal y, dReal z) | ||
2247 | { | ||
2248 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2249 | dUASSERT(joint,"bad joint argument"); | ||
2250 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2251 | if (joint->flags & dJOINT_REVERSE) | ||
2252 | setAxes (joint,x,y,z,NULL,joint->axis2); | ||
2253 | else | ||
2254 | setAxes (joint,x,y,z,joint->axis1,NULL); | ||
2255 | universalComputeInitialRelativeRotations(joint); | ||
2256 | } | ||
2257 | |||
2258 | |||
2259 | void dJointSetUniversalAxis2 (dJointID j, dReal x, dReal y, dReal z) | ||
2260 | { | ||
2261 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2262 | dUASSERT(joint,"bad joint argument"); | ||
2263 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2264 | if (joint->flags & dJOINT_REVERSE) | ||
2265 | setAxes (joint,x,y,z,joint->axis1,NULL); | ||
2266 | else | ||
2267 | setAxes (joint,x,y,z,NULL,joint->axis2); | ||
2268 | universalComputeInitialRelativeRotations(joint); | ||
2269 | } | ||
2270 | |||
2271 | |||
2272 | void dJointGetUniversalAnchor (dJointID j, dVector3 result) | ||
2273 | { | ||
2274 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2275 | dUASSERT(joint,"bad joint argument"); | ||
2276 | dUASSERT(result,"bad result argument"); | ||
2277 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2278 | if (joint->flags & dJOINT_REVERSE) | ||
2279 | getAnchor2 (joint,result,joint->anchor2); | ||
2280 | else | ||
2281 | getAnchor (joint,result,joint->anchor1); | ||
2282 | } | ||
2283 | |||
2284 | |||
2285 | void dJointGetUniversalAnchor2 (dJointID j, dVector3 result) | ||
2286 | { | ||
2287 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2288 | dUASSERT(joint,"bad joint argument"); | ||
2289 | dUASSERT(result,"bad result argument"); | ||
2290 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2291 | if (joint->flags & dJOINT_REVERSE) | ||
2292 | getAnchor (joint,result,joint->anchor1); | ||
2293 | else | ||
2294 | getAnchor2 (joint,result,joint->anchor2); | ||
2295 | } | ||
2296 | |||
2297 | |||
2298 | void dJointGetUniversalAxis1 (dJointID j, dVector3 result) | ||
2299 | { | ||
2300 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2301 | dUASSERT(joint,"bad joint argument"); | ||
2302 | dUASSERT(result,"bad result argument"); | ||
2303 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2304 | if (joint->flags & dJOINT_REVERSE) | ||
2305 | getAxis2 (joint,result,joint->axis2); | ||
2306 | else | ||
2307 | getAxis (joint,result,joint->axis1); | ||
2308 | } | ||
2309 | |||
2310 | |||
2311 | void dJointGetUniversalAxis2 (dJointID j, dVector3 result) | ||
2312 | { | ||
2313 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2314 | dUASSERT(joint,"bad joint argument"); | ||
2315 | dUASSERT(result,"bad result argument"); | ||
2316 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2317 | if (joint->flags & dJOINT_REVERSE) | ||
2318 | getAxis (joint,result,joint->axis1); | ||
2319 | else | ||
2320 | getAxis2 (joint,result,joint->axis2); | ||
2321 | } | ||
2322 | |||
2323 | |||
2324 | void dJointSetUniversalParam (dJointID j, int parameter, dReal value) | ||
2325 | { | ||
2326 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2327 | dUASSERT(joint,"bad joint argument"); | ||
2328 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2329 | if ((parameter & 0xff00) == 0x100) { | ||
2330 | joint->limot2.set (parameter & 0xff,value); | ||
2331 | } | ||
2332 | else { | ||
2333 | joint->limot1.set (parameter,value); | ||
2334 | } | ||
2335 | } | ||
2336 | |||
2337 | |||
2338 | dReal dJointGetUniversalParam (dJointID j, int parameter) | ||
2339 | { | ||
2340 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2341 | dUASSERT(joint,"bad joint argument"); | ||
2342 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2343 | if ((parameter & 0xff00) == 0x100) { | ||
2344 | return joint->limot2.get (parameter & 0xff); | ||
2345 | } | ||
2346 | else { | ||
2347 | return joint->limot1.get (parameter); | ||
2348 | } | ||
2349 | } | ||
2350 | |||
2351 | void dJointGetUniversalAngles (dJointID j, dReal *angle1, dReal *angle2) | ||
2352 | { | ||
2353 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2354 | dUASSERT(joint,"bad joint argument"); | ||
2355 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2356 | if (joint->flags & dJOINT_REVERSE) | ||
2357 | return getUniversalAngles (joint, angle2, angle1); | ||
2358 | else | ||
2359 | return getUniversalAngles (joint, angle1, angle2); | ||
2360 | } | ||
2361 | |||
2362 | |||
2363 | dReal dJointGetUniversalAngle1 (dJointID j) | ||
2364 | { | ||
2365 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2366 | dUASSERT(joint,"bad joint argument"); | ||
2367 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2368 | if (joint->flags & dJOINT_REVERSE) | ||
2369 | return getUniversalAngle2 (joint); | ||
2370 | else | ||
2371 | return getUniversalAngle1 (joint); | ||
2372 | } | ||
2373 | |||
2374 | |||
2375 | dReal dJointGetUniversalAngle2 (dJointID j) | ||
2376 | { | ||
2377 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2378 | dUASSERT(joint,"bad joint argument"); | ||
2379 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2380 | if (joint->flags & dJOINT_REVERSE) | ||
2381 | return getUniversalAngle1 (joint); | ||
2382 | else | ||
2383 | return getUniversalAngle2 (joint); | ||
2384 | } | ||
2385 | |||
2386 | |||
2387 | dReal dJointGetUniversalAngle1Rate (dJointID j) | ||
2388 | { | ||
2389 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2390 | dUASSERT(joint,"bad joint argument"); | ||
2391 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2392 | |||
2393 | if (joint->node[0].body) { | ||
2394 | dVector3 axis; | ||
2395 | |||
2396 | if (joint->flags & dJOINT_REVERSE) | ||
2397 | getAxis2 (joint,axis,joint->axis2); | ||
2398 | else | ||
2399 | getAxis (joint,axis,joint->axis1); | ||
2400 | |||
2401 | dReal rate = dDOT(axis, joint->node[0].body->avel); | ||
2402 | if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); | ||
2403 | return rate; | ||
2404 | } | ||
2405 | return 0; | ||
2406 | } | ||
2407 | |||
2408 | |||
2409 | dReal dJointGetUniversalAngle2Rate (dJointID j) | ||
2410 | { | ||
2411 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2412 | dUASSERT(joint,"bad joint argument"); | ||
2413 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2414 | |||
2415 | if (joint->node[0].body) { | ||
2416 | dVector3 axis; | ||
2417 | |||
2418 | if (joint->flags & dJOINT_REVERSE) | ||
2419 | getAxis (joint,axis,joint->axis1); | ||
2420 | else | ||
2421 | getAxis2 (joint,axis,joint->axis2); | ||
2422 | |||
2423 | dReal rate = dDOT(axis, joint->node[0].body->avel); | ||
2424 | if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); | ||
2425 | return rate; | ||
2426 | } | ||
2427 | return 0; | ||
2428 | } | ||
2429 | |||
2430 | |||
2431 | void dJointAddUniversalTorques (dJointID j, dReal torque1, dReal torque2) | ||
2432 | { | ||
2433 | dxJointUniversal* joint = (dxJointUniversal*)j; | ||
2434 | dVector3 axis1, axis2; | ||
2435 | dAASSERT(joint); | ||
2436 | dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); | ||
2437 | |||
2438 | if (joint->flags & dJOINT_REVERSE) { | ||
2439 | dReal temp = torque1; | ||
2440 | torque1 = - torque2; | ||
2441 | torque2 = - temp; | ||
2442 | } | ||
2443 | |||
2444 | getAxis (joint,axis1,joint->axis1); | ||
2445 | getAxis2 (joint,axis2,joint->axis2); | ||
2446 | axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; | ||
2447 | axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; | ||
2448 | axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; | ||
2449 | |||
2450 | if (joint->node[0].body != 0) | ||
2451 | dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); | ||
2452 | if (joint->node[1].body != 0) | ||
2453 | dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); | ||
2454 | } | ||
2455 | |||
2456 | |||
2457 | |||
2458 | |||
2459 | |||
2460 | dxJoint::Vtable __duniversal_vtable = { | ||
2461 | sizeof(dxJointUniversal), | ||
2462 | (dxJoint::init_fn*) universalInit, | ||
2463 | (dxJoint::getInfo1_fn*) universalGetInfo1, | ||
2464 | (dxJoint::getInfo2_fn*) universalGetInfo2, | ||
2465 | dJointTypeUniversal}; | ||
2466 | |||
2467 | |||
2468 | |||
2469 | //**************************************************************************** | ||
2470 | // Prismatic and Rotoide | ||
2471 | |||
2472 | static void PRInit (dxJointPR *j) | ||
2473 | { | ||
2474 | // Default Position | ||
2475 | // Z^ | ||
2476 | // | Body 1 P R Body2 | ||
2477 | // |+---------+ _ _ +-----------+ | ||
2478 | // || |----|----(_)--------+ | | ||
2479 | // |+---------+ - +-----------+ | ||
2480 | // | | ||
2481 | // X.-----------------------------------------> Y | ||
2482 | // N.B. X is comming out of the page | ||
2483 | dSetZero (j->anchor2,4); | ||
2484 | |||
2485 | dSetZero (j->axisR1,4); | ||
2486 | j->axisR1[0] = 1; | ||
2487 | dSetZero (j->axisR2,4); | ||
2488 | j->axisR2[0] = 1; | ||
2489 | |||
2490 | dSetZero (j->axisP1,4); | ||
2491 | j->axisP1[1] = 1; | ||
2492 | dSetZero (j->qrel,4); | ||
2493 | dSetZero (j->offset,4); | ||
2494 | |||
2495 | j->limotR.init (j->world); | ||
2496 | j->limotP.init (j->world); | ||
2497 | } | ||
2498 | |||
2499 | |||
2500 | dReal dJointGetPRPosition (dJointID j) | ||
2501 | { | ||
2502 | dxJointPR* joint = (dxJointPR*)j; | ||
2503 | dUASSERT(joint,"bad joint argument"); | ||
2504 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
2505 | |||
2506 | dVector3 q; | ||
2507 | // get the offset in global coordinates | ||
2508 | dMULTIPLY0_331 (q,joint->node[0].body->posr.R,joint->offset); | ||
2509 | |||
2510 | if (joint->node[1].body) { | ||
2511 | dVector3 anchor2; | ||
2512 | |||
2513 | // get the anchor2 in global coordinates | ||
2514 | dMULTIPLY0_331 (anchor2,joint->node[1].body->posr.R,joint->anchor2); | ||
2515 | |||
2516 | q[0] = ( (joint->node[0].body->posr.pos[0] + q[0]) - | ||
2517 | (joint->node[1].body->posr.pos[0] + anchor2[0]) ); | ||
2518 | q[1] = ( (joint->node[0].body->posr.pos[1] + q[1]) - | ||
2519 | (joint->node[1].body->posr.pos[1] + anchor2[1]) ); | ||
2520 | q[2] = ( (joint->node[0].body->posr.pos[2] + q[2]) - | ||
2521 | (joint->node[1].body->posr.pos[2] + anchor2[2]) ); | ||
2522 | |||
2523 | } | ||
2524 | else { | ||
2525 | //N.B. When there is no body 2 the joint->anchor2 is already in | ||
2526 | // global coordinates | ||
2527 | |||
2528 | q[0] = ( (joint->node[0].body->posr.pos[0] + q[0]) - | ||
2529 | (joint->anchor2[0]) ); | ||
2530 | q[1] = ( (joint->node[0].body->posr.pos[1] + q[1]) - | ||
2531 | (joint->anchor2[1]) ); | ||
2532 | q[2] = ( (joint->node[0].body->posr.pos[2] + q[2]) - | ||
2533 | (joint->anchor2[2]) ); | ||
2534 | |||
2535 | } | ||
2536 | |||
2537 | dVector3 axP; | ||
2538 | // get prismatic axis in global coordinates | ||
2539 | dMULTIPLY0_331 (axP,joint->node[0].body->posr.R,joint->axisP1); | ||
2540 | |||
2541 | return dDOT(axP, q); | ||
2542 | } | ||
2543 | |||
2544 | |||
2545 | dReal dJointGetPRPositionRate (dJointID j) | ||
2546 | { | ||
2547 | dxJointPR* joint = (dxJointPR*)j; | ||
2548 | dUASSERT(joint,"bad joint argument"); | ||
2549 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
2550 | |||
2551 | if (joint->node[0].body) { | ||
2552 | // We want to find the rate of change of the prismatic part of the joint | ||
2553 | // We can find it by looking at the speed difference between body1 and the | ||
2554 | // anchor point. | ||
2555 | |||
2556 | // r will be used to find the distance between body1 and the anchor point | ||
2557 | dVector3 r; | ||
2558 | if (joint->node[1].body) { | ||
2559 | // Find joint->anchor2 in global coordinates | ||
2560 | dVector3 anchor2; | ||
2561 | dMULTIPLY0_331 (anchor2,joint->node[1].body->posr.R,joint->anchor2); | ||
2562 | |||
2563 | r[0] = joint->node[0].body->posr.pos[0] - anchor2[0]; | ||
2564 | r[1] = joint->node[0].body->posr.pos[1] - anchor2[1]; | ||
2565 | r[2] = joint->node[0].body->posr.pos[2] - anchor2[2]; | ||
2566 | } | ||
2567 | else { | ||
2568 | //N.B. When there is no body 2 the joint->anchor2 is already in | ||
2569 | // global coordinates | ||
2570 | r[0] = joint->node[0].body->posr.pos[0] - joint->anchor2[0]; | ||
2571 | r[1] = joint->node[0].body->posr.pos[1] - joint->anchor2[1]; | ||
2572 | r[2] = joint->node[0].body->posr.pos[2] - joint->anchor2[2]; | ||
2573 | } | ||
2574 | |||
2575 | // The body1 can have velocity coming from the rotation of | ||
2576 | // the rotoide axis. We need to remove this. | ||
2577 | |||
2578 | // Take only the angular rotation coming from the rotation | ||
2579 | // of the rotoide articulation | ||
2580 | // N.B. Body1 and Body2 should have the same rotation along axis | ||
2581 | // other than the rotoide axis. | ||
2582 | dVector3 angular; | ||
2583 | dMULTIPLY0_331 (angular,joint->node[0].body->posr.R,joint->axisR1); | ||
2584 | dReal omega = dDOT(angular, joint->node[0].body->avel); | ||
2585 | angular[0] *= omega; | ||
2586 | angular[1] *= omega; | ||
2587 | angular[2] *= omega; | ||
2588 | |||
2589 | // Find the contribution of the angular rotation to the linear speed | ||
2590 | // N.B. We do vel = r X w instead of vel = w x r to have vel negative | ||
2591 | // since we want to remove it from the linear velocity of the body | ||
2592 | dVector3 lvel1; | ||
2593 | dCROSS(lvel1, =, r, angular); | ||
2594 | |||
2595 | lvel1[0] += joint->node[0].body->lvel[0]; | ||
2596 | lvel1[1] += joint->node[0].body->lvel[1]; | ||
2597 | lvel1[2] += joint->node[0].body->lvel[2]; | ||
2598 | |||
2599 | // Since we want rate of change along the prismatic axis | ||
2600 | // get axisP1 in global coordinates and get the component | ||
2601 | // along this axis only | ||
2602 | dVector3 axP1; | ||
2603 | dMULTIPLY0_331 (axP1,joint->node[0].body->posr.R,joint->axisP1); | ||
2604 | return dDOT(axP1, lvel1); | ||
2605 | } | ||
2606 | |||
2607 | return 0.0; | ||
2608 | } | ||
2609 | |||
2610 | |||
2611 | |||
2612 | static void PRGetInfo1 (dxJointPR *j, dxJoint::Info1 *info) | ||
2613 | { | ||
2614 | info->m = 4; | ||
2615 | info->nub = 4; | ||
2616 | |||
2617 | bool added = false; | ||
2618 | |||
2619 | added = false; | ||
2620 | // see if the prismatic articulation is powered | ||
2621 | if (j->limotP.fmax > 0) | ||
2622 | { | ||
2623 | added = true; | ||
2624 | (info->m)++; // powered needs an extra constraint row | ||
2625 | } | ||
2626 | |||
2627 | // see if we're at a joint limit. | ||
2628 | j->limotP.limit = 0; | ||
2629 | if ((j->limotP.lostop > -dInfinity || j->limotP.histop < dInfinity) && | ||
2630 | j->limotP.lostop <= j->limotP.histop) { | ||
2631 | // measure joint position | ||
2632 | dReal pos = dJointGetPRPosition (j); | ||
2633 | if (pos <= j->limotP.lostop) { | ||
2634 | j->limotP.limit = 1; | ||
2635 | j->limotP.limit_err = pos - j->limotP.lostop; | ||
2636 | if (!added) | ||
2637 | (info->m)++; | ||
2638 | } | ||
2639 | |||
2640 | if (pos >= j->limotP.histop) { | ||
2641 | j->limotP.limit = 2; | ||
2642 | j->limotP.limit_err = pos - j->limotP.histop; | ||
2643 | if (!added) | ||
2644 | (info->m)++; | ||
2645 | } | ||
2646 | } | ||
2647 | |||
2648 | } | ||
2649 | |||
2650 | |||
2651 | |||
2652 | static void PRGetInfo2 (dxJointPR *joint, dxJoint::Info2 *info) | ||
2653 | { | ||
2654 | int s = info->rowskip; | ||
2655 | int s2= 2*s; | ||
2656 | int s3= 3*s; | ||
2657 | int s4= 4*s; | ||
2658 | |||
2659 | dReal k = info->fps * info->erp; | ||
2660 | |||
2661 | |||
2662 | dVector3 q; // plane space of axP and after that axR | ||
2663 | |||
2664 | // pull out pos and R for both bodies. also get the `connection' | ||
2665 | // vector pos2-pos1. | ||
2666 | |||
2667 | dReal *pos1,*pos2,*R1,*R2; | ||
2668 | pos1 = joint->node[0].body->posr.pos; | ||
2669 | R1 = joint->node[0].body->posr.R; | ||
2670 | if (joint->node[1].body) { | ||
2671 | pos2 = joint->node[1].body->posr.pos; | ||
2672 | R2 = joint->node[1].body->posr.R; | ||
2673 | } | ||
2674 | else { | ||
2675 | // pos2 = 0; // N.B. We can do that to be safe but it is no necessary | ||
2676 | // R2 = 0; // N.B. We can do that to be safe but it is no necessary | ||
2677 | } | ||
2678 | |||
2679 | |||
2680 | dVector3 axP; // Axis of the prismatic joint in global frame | ||
2681 | dMULTIPLY0_331 (axP, R1, joint->axisP1); | ||
2682 | |||
2683 | // distance between the body1 and the anchor2 in global frame | ||
2684 | // Calculated in the same way as the offset | ||
2685 | dVector3 dist; | ||
2686 | |||
2687 | if (joint->node[1].body) | ||
2688 | { | ||
2689 | dMULTIPLY0_331 (dist, R2, joint->anchor2); | ||
2690 | dist[0] += pos2[0] - pos1[0]; | ||
2691 | dist[1] += pos2[1] - pos1[1]; | ||
2692 | dist[2] += pos2[2] - pos1[2]; | ||
2693 | } | ||
2694 | else { | ||
2695 | dist[0] = joint->anchor2[0] - pos1[0]; | ||
2696 | dist[1] = joint->anchor2[1] - pos1[1]; | ||
2697 | dist[2] = joint->anchor2[2] - pos1[2]; | ||
2698 | } | ||
2699 | |||
2700 | |||
2701 | // ====================================================================== | ||
2702 | // Work on the Rotoide part (i.e. row 0, 1 and maybe 4 if rotoide powered | ||
2703 | |||
2704 | // Set the two rotoide rows. The rotoide axis should be the only unconstrained | ||
2705 | // rotational axis, the angular velocity of the two bodies perpendicular to | ||
2706 | // the rotoide axis should be equal. Thus the constraint equations are | ||
2707 | // p*w1 - p*w2 = 0 | ||
2708 | // q*w1 - q*w2 = 0 | ||
2709 | // where p and q are unit vectors normal to the rotoide axis, and w1 and w2 | ||
2710 | // are the angular velocity vectors of the two bodies. | ||
2711 | dVector3 ax1; | ||
2712 | dMULTIPLY0_331 (ax1, joint->node[0].body->posr.R, joint->axisR1); | ||
2713 | dCROSS(q , =, ax1, axP); | ||
2714 | |||
2715 | info->J1a[0] = axP[0]; | ||
2716 | info->J1a[1] = axP[1]; | ||
2717 | info->J1a[2] = axP[2]; | ||
2718 | info->J1a[s+0] = q[0]; | ||
2719 | info->J1a[s+1] = q[1]; | ||
2720 | info->J1a[s+2] = q[2]; | ||
2721 | |||
2722 | if (joint->node[1].body) { | ||
2723 | info->J2a[0] = -axP[0]; | ||
2724 | info->J2a[1] = -axP[1]; | ||
2725 | info->J2a[2] = -axP[2]; | ||
2726 | info->J2a[s+0] = -q[0]; | ||
2727 | info->J2a[s+1] = -q[1]; | ||
2728 | info->J2a[s+2] = -q[2]; | ||
2729 | } | ||
2730 | |||
2731 | |||
2732 | // Compute the right hand side of the constraint equation set. Relative | ||
2733 | // body velocities along p and q to bring the rotoide back into alignment. | ||
2734 | // ax1,ax2 are the unit length rotoide axes of body1 and body2 in world frame. | ||
2735 | // We need to rotate both bodies along the axis u = (ax1 x ax2). | ||
2736 | // if `theta' is the angle between ax1 and ax2, we need an angular velocity | ||
2737 | // along u to cover angle erp*theta in one step : | ||
2738 | // |angular_velocity| = angle/time = erp*theta / stepsize | ||
2739 | // = (erp*fps) * theta | ||
2740 | // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| | ||
2741 | // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) | ||
2742 | // ...as ax1 and ax2 are unit length. if theta is smallish, | ||
2743 | // theta ~= sin(theta), so | ||
2744 | // angular_velocity = (erp*fps) * (ax1 x ax2) | ||
2745 | // ax1 x ax2 is in the plane space of ax1, so we project the angular | ||
2746 | // velocity to p and q to find the right hand side. | ||
2747 | |||
2748 | dVector3 ax2; | ||
2749 | if (joint->node[1].body) { | ||
2750 | dMULTIPLY0_331 (ax2, R2, joint->axisR2); | ||
2751 | } | ||
2752 | else { | ||
2753 | ax2[0] = joint->axisR2[0]; | ||
2754 | ax2[1] = joint->axisR2[1]; | ||
2755 | ax2[2] = joint->axisR2[2]; | ||
2756 | } | ||
2757 | |||
2758 | dVector3 b; | ||
2759 | dCROSS (b,=,ax1, ax2); | ||
2760 | info->c[0] = k * dDOT(b, axP); | ||
2761 | info->c[1] = k * dDOT(b, q); | ||
2762 | |||
2763 | |||
2764 | |||
2765 | // ========================== | ||
2766 | // Work on the Prismatic part (i.e row 2,3 and 4 if only the prismatic is powered | ||
2767 | // or 5 if rotoide and prismatic powered | ||
2768 | |||
2769 | // two rows. we want: vel2 = vel1 + w1 x c ... but this would | ||
2770 | // result in three equations, so we project along the planespace vectors | ||
2771 | // so that sliding along the prismatic axis is disregarded. for symmetry we | ||
2772 | // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2. | ||
2773 | |||
2774 | // p1 + R1 dist' = p2 + R2 anchor2' ## OLD ## p1 + R1 anchor1' = p2 + R2 dist' | ||
2775 | // v1 + w1 x R1 dist' + v_p = v2 + w2 x R2 anchor2'## OLD v1 + w1 x R1 anchor1' = v2 + w2 x R2 dist' + v_p | ||
2776 | // v_p is speed of prismatic joint (i.e. elongation rate) | ||
2777 | // Since the constraints are perpendicular to v_p we have: | ||
2778 | // p dot v_p = 0 and q dot v_p = 0 | ||
2779 | // ax1 dot ( v1 + w1 x dist = v2 + w2 x anchor2 ) | ||
2780 | // q dot ( v1 + w1 x dist = v2 + w2 x anchor2 ) | ||
2781 | // == | ||
2782 | // ax1 . v1 + ax1 . w1 x dist = ax1 . v2 + ax1 . w2 x anchor2 ## OLD ## ax1 . v1 + ax1 . w1 x anchor1 = ax1 . v2 + ax1 . w2 x dist | ||
2783 | // since a . (b x c) = - b . (a x c) = - (a x c) . b | ||
2784 | // and a x b = - b x a | ||
2785 | // ax1 . v1 - ax1 x dist . w1 - ax1 . v2 - (- ax1 x anchor2 . w2) = 0 | ||
2786 | // ax1 . v1 + dist x ax1 . w1 - ax1 . v2 - anchor2 x ax1 . w2 = 0 | ||
2787 | // Coeff for 1er line of: J1l => ax1, J2l => -ax1 | ||
2788 | // Coeff for 2er line of: J1l => q, J2l => -q | ||
2789 | // Coeff for 1er line of: J1a => dist x ax1, J2a => - anchor2 x ax1 | ||
2790 | // Coeff for 2er line of: J1a => dist x q, J2a => - anchor2 x q | ||
2791 | |||
2792 | |||
2793 | dCROSS ((info->J1a)+s2, = , dist, ax1); | ||
2794 | |||
2795 | dCROSS ((info->J1a)+s3, = , dist, q); | ||
2796 | |||
2797 | |||
2798 | info->J1l[s2+0] = ax1[0]; | ||
2799 | info->J1l[s2+1] = ax1[1]; | ||
2800 | info->J1l[s2+2] = ax1[2]; | ||
2801 | |||
2802 | info->J1l[s3+0] = q[0]; | ||
2803 | info->J1l[s3+1] = q[1]; | ||
2804 | info->J1l[s3+2] = q[2]; | ||
2805 | |||
2806 | if (joint->node[1].body) { | ||
2807 | dVector3 anchor2; | ||
2808 | |||
2809 | // Calculate anchor2 in world coordinate | ||
2810 | dMULTIPLY0_331 (anchor2, R2, joint->anchor2); | ||
2811 | |||
2812 | // ax2 x anchor2 instead of anchor2 x ax2 since we want the negative value | ||
2813 | dCROSS ((info->J2a)+s2, = , ax2, anchor2); // since ax1 == ax2 | ||
2814 | |||
2815 | // The cross product is in reverse order since we want the negative value | ||
2816 | dCROSS ((info->J2a)+s3, = , q, anchor2); | ||
2817 | |||
2818 | info->J2l[s2+0] = -ax1[0]; | ||
2819 | info->J2l[s2+1] = -ax1[1]; | ||
2820 | info->J2l[s2+2] = -ax1[2]; | ||
2821 | |||
2822 | info->J2l[s3+0] = -q[0]; | ||
2823 | info->J2l[s3+1] = -q[1]; | ||
2824 | info->J2l[s3+2] = -q[2]; | ||
2825 | } | ||
2826 | |||
2827 | |||
2828 | // We want to make correction for motion not in the line of the axisP | ||
2829 | // We calculate the displacement w.r.t. the anchor pt. | ||
2830 | // | ||
2831 | // compute the elements 2 and 3 of right hand side. | ||
2832 | // we want to align the offset point (in body 2's frame) with the center of body 1. | ||
2833 | // The position should be the same when we are not along the prismatic axis | ||
2834 | dVector3 err; | ||
2835 | dMULTIPLY0_331 (err, R1, joint->offset); | ||
2836 | err[0] += dist[0]; | ||
2837 | err[1] += dist[1]; | ||
2838 | err[2] += dist[2]; | ||
2839 | info->c[2] = k * dDOT(ax1, err); | ||
2840 | info->c[3] = k * dDOT(q, err); | ||
2841 | |||
2842 | // Here we can't use addLimot because of some assumption in the function | ||
2843 | int powered = joint->limotP.fmax > 0; | ||
2844 | if (powered || joint->limotP.limit) { | ||
2845 | info->J1l[s4+0] = axP[0]; | ||
2846 | info->J1l[s4+1] = axP[1]; | ||
2847 | info->J1l[s4+2] = axP[2]; | ||
2848 | if (joint->node[1].body) { | ||
2849 | info->J2l[s4+0] = -axP[0]; | ||
2850 | info->J2l[s4+1] = -axP[1]; | ||
2851 | info->J2l[s4+2] = -axP[2]; | ||
2852 | } | ||
2853 | // linear limot torque decoupling step: | ||
2854 | // | ||
2855 | // if this is a linear limot (e.g. from a slider), we have to be careful | ||
2856 | // that the linear constraint forces (+/- ax1) applied to the two bodies | ||
2857 | // do not create a torque couple. in other words, the points that the | ||
2858 | // constraint force is applied at must lie along the same ax1 axis. | ||
2859 | // a torque couple will result in powered or limited slider-jointed free | ||
2860 | // bodies from gaining angular momentum. | ||
2861 | // the solution used here is to apply the constraint forces at the point | ||
2862 | // halfway between the body centers. there is no penalty (other than an | ||
2863 | // extra tiny bit of computation) in doing this adjustment. note that we | ||
2864 | // only need to do this if the constraint connects two bodies. | ||
2865 | |||
2866 | dVector3 ltd; // Linear Torque Decoupling vector (a torque) | ||
2867 | if (joint->node[1].body) { | ||
2868 | dVector3 c; | ||
2869 | c[0]=REAL(0.5)*(joint->node[1].body->posr.pos[0]-joint->node[0].body->posr.pos[0]); | ||
2870 | c[1]=REAL(0.5)*(joint->node[1].body->posr.pos[1]-joint->node[0].body->posr.pos[1]); | ||
2871 | c[2]=REAL(0.5)*(joint->node[1].body->posr.pos[2]-joint->node[0].body->posr.pos[2]); | ||
2872 | dReal val = dDOT(q, c); | ||
2873 | c[0] -= val * c[0]; | ||
2874 | c[1] -= val * c[1]; | ||
2875 | c[2] -= val * c[2]; | ||
2876 | |||
2877 | dCROSS (ltd,=,c,axP); | ||
2878 | info->J1a[s4+0] = ltd[0]; | ||
2879 | info->J1a[s4+1] = ltd[1]; | ||
2880 | info->J1a[s4+2] = ltd[2]; | ||
2881 | info->J2a[s4+0] = ltd[0]; | ||
2882 | info->J2a[s4+1] = ltd[1]; | ||
2883 | info->J2a[s4+2] = ltd[2]; | ||
2884 | } | ||
2885 | |||
2886 | // if we're limited low and high simultaneously, the joint motor is | ||
2887 | // ineffective | ||
2888 | if (joint->limotP.limit && (joint->limotP.lostop == joint->limotP.histop)) | ||
2889 | powered = 0; | ||
2890 | |||
2891 | int row = 4; | ||
2892 | if (powered) { | ||
2893 | info->cfm[row] = joint->limotP.normal_cfm; | ||
2894 | if (!joint->limotP.limit) { | ||
2895 | info->c[row] = joint->limotP.vel; | ||
2896 | info->lo[row] = -joint->limotP.fmax; | ||
2897 | info->hi[row] = joint->limotP.fmax; | ||
2898 | } | ||
2899 | else { | ||
2900 | // the joint is at a limit, AND is being powered. if the joint is | ||
2901 | // being powered into the limit then we apply the maximum motor force | ||
2902 | // in that direction, because the motor is working against the | ||
2903 | // immovable limit. if the joint is being powered away from the limit | ||
2904 | // then we have problems because actually we need *two* lcp | ||
2905 | // constraints to handle this case. so we fake it and apply some | ||
2906 | // fraction of the maximum force. the fraction to use can be set as | ||
2907 | // a fudge factor. | ||
2908 | |||
2909 | dReal fm = joint->limotP.fmax; | ||
2910 | dReal vel = joint->limotP.vel; | ||
2911 | int limit = joint->limotP.limit; | ||
2912 | if ((vel > 0) || (vel==0 && limit==2)) fm = -fm; | ||
2913 | |||
2914 | // if we're powering away from the limit, apply the fudge factor | ||
2915 | if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) | ||
2916 | fm *= joint->limotP.fudge_factor; | ||
2917 | |||
2918 | |||
2919 | dBodyAddForce (joint->node[0].body,-fm*axP[0],-fm*axP[1],-fm*axP[2]); | ||
2920 | |||
2921 | if (joint->node[1].body) { | ||
2922 | dBodyAddForce (joint->node[1].body,fm*axP[0],fm*axP[1],fm*axP[2]); | ||
2923 | |||
2924 | // linear limot torque decoupling step: refer to above discussion | ||
2925 | dBodyAddTorque (joint->node[0].body,-fm*ltd[0],-fm*ltd[1], | ||
2926 | -fm*ltd[2]); | ||
2927 | dBodyAddTorque (joint->node[1].body,-fm*ltd[0],-fm*ltd[1], | ||
2928 | -fm*ltd[2]); | ||
2929 | } | ||
2930 | } | ||
2931 | } | ||
2932 | |||
2933 | if (joint->limotP.limit) { | ||
2934 | dReal k = info->fps * joint->limotP.stop_erp; | ||
2935 | info->c[row] = -k * joint->limotP.limit_err; | ||
2936 | info->cfm[row] = joint->limotP.stop_cfm; | ||
2937 | |||
2938 | if (joint->limotP.lostop == joint->limotP.histop) { | ||
2939 | // limited low and high simultaneously | ||
2940 | info->lo[row] = -dInfinity; | ||
2941 | info->hi[row] = dInfinity; | ||
2942 | } | ||
2943 | else { | ||
2944 | if (joint->limotP.limit == 1) { | ||
2945 | // low limit | ||
2946 | info->lo[row] = 0; | ||
2947 | info->hi[row] = dInfinity; | ||
2948 | } | ||
2949 | else { | ||
2950 | // high limit | ||
2951 | info->lo[row] = -dInfinity; | ||
2952 | info->hi[row] = 0; | ||
2953 | } | ||
2954 | |||
2955 | // deal with bounce | ||
2956 | if (joint->limotP.bounce > 0) { | ||
2957 | // calculate joint velocity | ||
2958 | dReal vel; | ||
2959 | vel = dDOT(joint->node[0].body->lvel, axP); | ||
2960 | if (joint->node[1].body) | ||
2961 | vel -= dDOT(joint->node[1].body->lvel, axP); | ||
2962 | |||
2963 | // only apply bounce if the velocity is incoming, and if the | ||
2964 | // resulting c[] exceeds what we already have. | ||
2965 | if (joint->limotP.limit == 1) { | ||
2966 | // low limit | ||
2967 | if (vel < 0) { | ||
2968 | dReal newc = -joint->limotP.bounce * vel; | ||
2969 | if (newc > info->c[row]) info->c[row] = newc; | ||
2970 | } | ||
2971 | } | ||
2972 | else { | ||
2973 | // high limit - all those computations are reversed | ||
2974 | if (vel > 0) { | ||
2975 | dReal newc = -joint->limotP.bounce * vel; | ||
2976 | if (newc < info->c[row]) info->c[row] = newc; | ||
2977 | } | ||
2978 | } | ||
2979 | } | ||
2980 | } | ||
2981 | } | ||
2982 | } | ||
2983 | } | ||
2984 | |||
2985 | |||
2986 | // compute initial relative rotation body1 -> body2, or env -> body1 | ||
2987 | static void PRComputeInitialRelativeRotation (dxJointPR *joint) | ||
2988 | { | ||
2989 | if (joint->node[0].body) { | ||
2990 | if (joint->node[1].body) { | ||
2991 | dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); | ||
2992 | } | ||
2993 | else { | ||
2994 | // set joint->qrel to the transpose of the first body q | ||
2995 | joint->qrel[0] = joint->node[0].body->q[0]; | ||
2996 | for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; | ||
2997 | // WARNING do we need the - in -joint->node[0].body->q[i]; or not | ||
2998 | } | ||
2999 | } | ||
3000 | } | ||
3001 | |||
3002 | void dJointSetPRAnchor (dJointID j, dReal x, dReal y, dReal z) | ||
3003 | { | ||
3004 | dxJointPR* joint = (dxJointPR*)j; | ||
3005 | dUASSERT(joint,"bad joint argument"); | ||
3006 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3007 | |||
3008 | dVector3 dummy; | ||
3009 | setAnchors (joint,x,y,z,dummy,joint->anchor2); | ||
3010 | } | ||
3011 | |||
3012 | |||
3013 | void dJointSetPRAxis1 (dJointID j, dReal x, dReal y, dReal z) | ||
3014 | { | ||
3015 | dxJointPR* joint = (dxJointPR*)j; | ||
3016 | dUASSERT(joint,"bad joint argument"); | ||
3017 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3018 | |||
3019 | setAxes (joint,x,y,z,joint->axisP1, 0); | ||
3020 | |||
3021 | PRComputeInitialRelativeRotation (joint); | ||
3022 | |||
3023 | // compute initial relative rotation body1 -> body2, or env -> body1 | ||
3024 | // also compute distance between anchor of body1 w.r.t center of body 2 | ||
3025 | dVector3 c; | ||
3026 | if (joint->node[1].body) { | ||
3027 | dVector3 anchor2; | ||
3028 | dMULTIPLY0_331 (anchor2,joint->node[1].body->posr.R, joint->anchor2); | ||
3029 | |||
3030 | c[0] = ( joint->node[1].body->posr.pos[0] + anchor2[0] - | ||
3031 | joint->node[0].body->posr.pos[0] ); | ||
3032 | c[1] = ( joint->node[1].body->posr.pos[1] + anchor2[1] - | ||
3033 | joint->node[0].body->posr.pos[1] ); | ||
3034 | c[2] = ( joint->node[1].body->posr.pos[2] + anchor2[2] - | ||
3035 | joint->node[0].body->posr.pos[2] ); | ||
3036 | } | ||
3037 | else if (joint->node[0].body) { | ||
3038 | c[0] = joint->anchor2[0] - joint->node[0].body->posr.pos[0]; | ||
3039 | c[1] = joint->anchor2[1] - joint->node[0].body->posr.pos[1]; | ||
3040 | c[2] = joint->anchor2[2] - joint->node[0].body->posr.pos[2]; | ||
3041 | } | ||
3042 | else | ||
3043 | { | ||
3044 | joint->offset[0] = joint->anchor2[0]; | ||
3045 | joint->offset[1] = joint->anchor2[1]; | ||
3046 | joint->offset[2] = joint->anchor2[2]; | ||
3047 | |||
3048 | return; | ||
3049 | } | ||
3050 | |||
3051 | |||
3052 | dMULTIPLY1_331 (joint->offset,joint->node[0].body->posr.R,c); | ||
3053 | } | ||
3054 | |||
3055 | |||
3056 | void dJointSetPRAxis2 (dJointID j, dReal x, dReal y, dReal z) | ||
3057 | { | ||
3058 | dxJointPR* joint = (dxJointPR*)j; | ||
3059 | dUASSERT(joint,"bad joint argument"); | ||
3060 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3061 | setAxes (joint,x,y,z,joint->axisR1,joint->axisR2); | ||
3062 | PRComputeInitialRelativeRotation (joint); | ||
3063 | } | ||
3064 | |||
3065 | |||
3066 | void dJointSetPRParam (dJointID j, int parameter, dReal value) | ||
3067 | { | ||
3068 | dxJointPR* joint = (dxJointPR*)j; | ||
3069 | dUASSERT(joint,"bad joint argument"); | ||
3070 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3071 | if ((parameter & 0xff00) == 0x100) { | ||
3072 | joint->limotR.set (parameter,value); | ||
3073 | } | ||
3074 | else { | ||
3075 | joint->limotP.set (parameter & 0xff,value); | ||
3076 | } | ||
3077 | } | ||
3078 | |||
3079 | void dJointGetPRAnchor (dJointID j, dVector3 result) | ||
3080 | { | ||
3081 | dxJointPR* joint = (dxJointPR*)j; | ||
3082 | dUASSERT(joint,"bad joint argument"); | ||
3083 | dUASSERT(result,"bad result argument"); | ||
3084 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3085 | |||
3086 | if (joint->node[1].body) | ||
3087 | getAnchor2 (joint,result,joint->anchor2); | ||
3088 | else | ||
3089 | { | ||
3090 | result[0] = joint->anchor2[0]; | ||
3091 | result[1] = joint->anchor2[1]; | ||
3092 | result[2] = joint->anchor2[2]; | ||
3093 | } | ||
3094 | |||
3095 | } | ||
3096 | |||
3097 | void dJointGetPRAxis1 (dJointID j, dVector3 result) | ||
3098 | { | ||
3099 | dxJointPR* joint = (dxJointPR*)j; | ||
3100 | dUASSERT(joint,"bad joint argument"); | ||
3101 | dUASSERT(result,"bad result argument"); | ||
3102 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3103 | getAxis(joint, result, joint->axisP1); | ||
3104 | } | ||
3105 | |||
3106 | void dJointGetPRAxis2 (dJointID j, dVector3 result) | ||
3107 | { | ||
3108 | dxJointPR* joint = (dxJointPR*)j; | ||
3109 | dUASSERT(joint,"bad joint argument"); | ||
3110 | dUASSERT(result,"bad result argument"); | ||
3111 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3112 | getAxis(joint, result, joint->axisR1); | ||
3113 | } | ||
3114 | |||
3115 | dReal dJointGetPRParam (dJointID j, int parameter) | ||
3116 | { | ||
3117 | dxJointPR* joint = (dxJointPR*)j; | ||
3118 | dUASSERT(joint,"bad joint argument"); | ||
3119 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not Prismatic and Rotoide"); | ||
3120 | if ((parameter & 0xff00) == 0x100) { | ||
3121 | return joint->limotR.get (parameter & 0xff); | ||
3122 | } | ||
3123 | else { | ||
3124 | return joint->limotP.get (parameter); | ||
3125 | } | ||
3126 | } | ||
3127 | |||
3128 | void dJointAddPRTorque (dJointID j, dReal torque) | ||
3129 | { | ||
3130 | dxJointPR* joint = (dxJointPR*)j; | ||
3131 | dVector3 axis; | ||
3132 | dAASSERT(joint); | ||
3133 | dUASSERT(joint->vtable == &__dPR_vtable,"joint is not a Prismatic and Rotoide"); | ||
3134 | |||
3135 | if (joint->flags & dJOINT_REVERSE) | ||
3136 | torque = -torque; | ||
3137 | |||
3138 | getAxis (joint,axis,joint->axisR1); | ||
3139 | axis[0] *= torque; | ||
3140 | axis[1] *= torque; | ||
3141 | axis[2] *= torque; | ||
3142 | |||
3143 | if (joint->node[0].body != 0) | ||
3144 | dBodyAddTorque (joint->node[0].body, axis[0], axis[1], axis[2]); | ||
3145 | if (joint->node[1].body != 0) | ||
3146 | dBodyAddTorque(joint->node[1].body, -axis[0], -axis[1], -axis[2]); | ||
3147 | } | ||
3148 | |||
3149 | |||
3150 | dxJoint::Vtable __dPR_vtable = { | ||
3151 | sizeof(dxJointPR), | ||
3152 | (dxJoint::init_fn*) PRInit, | ||
3153 | (dxJoint::getInfo1_fn*) PRGetInfo1, | ||
3154 | (dxJoint::getInfo2_fn*) PRGetInfo2, | ||
3155 | dJointTypePR | ||
3156 | }; | ||
3157 | |||
3158 | |||
3159 | //**************************************************************************** | ||
3160 | // angular motor | ||
3161 | |||
3162 | static void amotorInit (dxJointAMotor *j) | ||
3163 | { | ||
3164 | int i; | ||
3165 | j->num = 0; | ||
3166 | j->mode = dAMotorUser; | ||
3167 | for (i=0; i<3; i++) { | ||
3168 | j->rel[i] = 0; | ||
3169 | dSetZero (j->axis[i],4); | ||
3170 | j->limot[i].init (j->world); | ||
3171 | j->angle[i] = 0; | ||
3172 | } | ||
3173 | dSetZero (j->reference1,4); | ||
3174 | dSetZero (j->reference2,4); | ||
3175 | } | ||
3176 | |||
3177 | |||
3178 | // compute the 3 axes in global coordinates | ||
3179 | |||
3180 | static void amotorComputeGlobalAxes (dxJointAMotor *joint, dVector3 ax[3]) | ||
3181 | { | ||
3182 | if (joint->mode == dAMotorEuler) { | ||
3183 | // special handling for euler mode | ||
3184 | dMULTIPLY0_331 (ax[0],joint->node[0].body->posr.R,joint->axis[0]); | ||
3185 | if (joint->node[1].body) { | ||
3186 | dMULTIPLY0_331 (ax[2],joint->node[1].body->posr.R,joint->axis[2]); | ||
3187 | } | ||
3188 | else { | ||
3189 | ax[2][0] = joint->axis[2][0]; | ||
3190 | ax[2][1] = joint->axis[2][1]; | ||
3191 | ax[2][2] = joint->axis[2][2]; | ||
3192 | } | ||
3193 | dCROSS (ax[1],=,ax[2],ax[0]); | ||
3194 | dNormalize3 (ax[1]); | ||
3195 | } | ||
3196 | else { | ||
3197 | for (int i=0; i < joint->num; i++) { | ||
3198 | if (joint->rel[i] == 1) { | ||
3199 | // relative to b1 | ||
3200 | dMULTIPLY0_331 (ax[i],joint->node[0].body->posr.R,joint->axis[i]); | ||
3201 | } | ||
3202 | else if (joint->rel[i] == 2) { | ||
3203 | // relative to b2 | ||
3204 | if (joint->node[1].body) { // jds: don't assert, just ignore | ||
3205 | dMULTIPLY0_331 (ax[i],joint->node[1].body->posr.R,joint->axis[i]); | ||
3206 | } | ||
3207 | } | ||
3208 | else { | ||
3209 | // global - just copy it | ||
3210 | ax[i][0] = joint->axis[i][0]; | ||
3211 | ax[i][1] = joint->axis[i][1]; | ||
3212 | ax[i][2] = joint->axis[i][2]; | ||
3213 | } | ||
3214 | } | ||
3215 | } | ||
3216 | } | ||
3217 | |||
3218 | |||
3219 | static void amotorComputeEulerAngles (dxJointAMotor *joint, dVector3 ax[3]) | ||
3220 | { | ||
3221 | // assumptions: | ||
3222 | // global axes already calculated --> ax | ||
3223 | // axis[0] is relative to body 1 --> global ax[0] | ||
3224 | // axis[2] is relative to body 2 --> global ax[2] | ||
3225 | // ax[1] = ax[2] x ax[0] | ||
3226 | // original ax[0] and ax[2] are perpendicular | ||
3227 | // reference1 is perpendicular to ax[0] (in body 1 frame) | ||
3228 | // reference2 is perpendicular to ax[2] (in body 2 frame) | ||
3229 | // all ax[] and reference vectors are unit length | ||
3230 | |||
3231 | // calculate references in global frame | ||
3232 | dVector3 ref1,ref2; | ||
3233 | dMULTIPLY0_331 (ref1,joint->node[0].body->posr.R,joint->reference1); | ||
3234 | if (joint->node[1].body) { | ||
3235 | dMULTIPLY0_331 (ref2,joint->node[1].body->posr.R,joint->reference2); | ||
3236 | } | ||
3237 | else { | ||
3238 | ref2[0] = joint->reference2[0]; | ||
3239 | ref2[1] = joint->reference2[1]; | ||
3240 | ref2[2] = joint->reference2[2]; | ||
3241 | } | ||
3242 | |||
3243 | // get q perpendicular to both ax[0] and ref1, get first euler angle | ||
3244 | dVector3 q; | ||
3245 | dCROSS (q,=,ax[0],ref1); | ||
3246 | joint->angle[0] = -dAtan2 (dDOT(ax[2],q),dDOT(ax[2],ref1)); | ||
3247 | |||
3248 | // get q perpendicular to both ax[0] and ax[1], get second euler angle | ||
3249 | dCROSS (q,=,ax[0],ax[1]); | ||
3250 | joint->angle[1] = -dAtan2 (dDOT(ax[2],ax[0]),dDOT(ax[2],q)); | ||
3251 | |||
3252 | // get q perpendicular to both ax[1] and ax[2], get third euler angle | ||
3253 | dCROSS (q,=,ax[1],ax[2]); | ||
3254 | joint->angle[2] = -dAtan2 (dDOT(ref2,ax[1]), dDOT(ref2,q)); | ||
3255 | } | ||
3256 | |||
3257 | |||
3258 | // set the reference vectors as follows: | ||
3259 | // * reference1 = current axis[2] relative to body 1 | ||
3260 | // * reference2 = current axis[0] relative to body 2 | ||
3261 | // this assumes that: | ||
3262 | // * axis[0] is relative to body 1 | ||
3263 | // * axis[2] is relative to body 2 | ||
3264 | |||
3265 | static void amotorSetEulerReferenceVectors (dxJointAMotor *j) | ||
3266 | { | ||
3267 | if (j->node[0].body && j->node[1].body) { | ||
3268 | dVector3 r; // axis[2] and axis[0] in global coordinates | ||
3269 | dMULTIPLY0_331 (r,j->node[1].body->posr.R,j->axis[2]); | ||
3270 | dMULTIPLY1_331 (j->reference1,j->node[0].body->posr.R,r); | ||
3271 | dMULTIPLY0_331 (r,j->node[0].body->posr.R,j->axis[0]); | ||
3272 | dMULTIPLY1_331 (j->reference2,j->node[1].body->posr.R,r); | ||
3273 | } | ||
3274 | |||
3275 | else { // jds | ||
3276 | // else if (j->node[0].body) { | ||
3277 | // dMULTIPLY1_331 (j->reference1,j->node[0].body->posr.R,j->axis[2]); | ||
3278 | // dMULTIPLY0_331 (j->reference2,j->node[0].body->posr.R,j->axis[0]); | ||
3279 | |||
3280 | // We want to handle angular motors attached to passive geoms | ||
3281 | dVector3 r; // axis[2] and axis[0] in global coordinates | ||
3282 | r[0] = j->axis[2][0]; r[1] = j->axis[2][1]; r[2] = j->axis[2][2]; r[3] = j->axis[2][3]; | ||
3283 | dMULTIPLY1_331 (j->reference1,j->node[0].body->posr.R,r); | ||
3284 | dMULTIPLY0_331 (r,j->node[0].body->posr.R,j->axis[0]); | ||
3285 | j->reference2[0] += r[0]; j->reference2[1] += r[1]; | ||
3286 | j->reference2[2] += r[2]; j->reference2[3] += r[3]; | ||
3287 | } | ||
3288 | } | ||
3289 | |||
3290 | |||
3291 | static void amotorGetInfo1 (dxJointAMotor *j, dxJoint::Info1 *info) | ||
3292 | { | ||
3293 | info->m = 0; | ||
3294 | info->nub = 0; | ||
3295 | |||
3296 | // compute the axes and angles, if in euler mode | ||
3297 | if (j->mode == dAMotorEuler) { | ||
3298 | dVector3 ax[3]; | ||
3299 | amotorComputeGlobalAxes (j,ax); | ||
3300 | amotorComputeEulerAngles (j,ax); | ||
3301 | } | ||
3302 | |||
3303 | // see if we're powered or at a joint limit for each axis | ||
3304 | for (int i=0; i < j->num; i++) { | ||
3305 | if (j->limot[i].testRotationalLimit (j->angle[i]) || | ||
3306 | j->limot[i].fmax > 0) { | ||
3307 | info->m++; | ||
3308 | } | ||
3309 | } | ||
3310 | } | ||
3311 | |||
3312 | |||
3313 | static void amotorGetInfo2 (dxJointAMotor *joint, dxJoint::Info2 *info) | ||
3314 | { | ||
3315 | int i; | ||
3316 | |||
3317 | // compute the axes (if not global) | ||
3318 | dVector3 ax[3]; | ||
3319 | amotorComputeGlobalAxes (joint,ax); | ||
3320 | |||
3321 | // in euler angle mode we do not actually constrain the angular velocity | ||
3322 | // along the axes axis[0] and axis[2] (although we do use axis[1]) : | ||
3323 | // | ||
3324 | // to get constrain w2-w1 along ...not | ||
3325 | // ------ --------------------- ------ | ||
3326 | // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] | ||
3327 | // d(angle[1])/dt = 0 ax[1] | ||
3328 | // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] | ||
3329 | // | ||
3330 | // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. | ||
3331 | // to prove the result for angle[0], write the expression for angle[0] from | ||
3332 | // GetInfo1 then take the derivative. to prove this for angle[2] it is | ||
3333 | // easier to take the euler rate expression for d(angle[2])/dt with respect | ||
3334 | // to the components of w and set that to 0. | ||
3335 | |||
3336 | dVector3 *axptr[3]; | ||
3337 | axptr[0] = &ax[0]; | ||
3338 | axptr[1] = &ax[1]; | ||
3339 | axptr[2] = &ax[2]; | ||
3340 | |||
3341 | dVector3 ax0_cross_ax1; | ||
3342 | dVector3 ax1_cross_ax2; | ||
3343 | if (joint->mode == dAMotorEuler) { | ||
3344 | dCROSS (ax0_cross_ax1,=,ax[0],ax[1]); | ||
3345 | axptr[2] = &ax0_cross_ax1; | ||
3346 | dCROSS (ax1_cross_ax2,=,ax[1],ax[2]); | ||
3347 | axptr[0] = &ax1_cross_ax2; | ||
3348 | } | ||
3349 | |||
3350 | int row=0; | ||
3351 | for (i=0; i < joint->num; i++) { | ||
3352 | row += joint->limot[i].addLimot (joint,info,row,*(axptr[i]),1); | ||
3353 | } | ||
3354 | } | ||
3355 | |||
3356 | |||
3357 | void dJointSetAMotorNumAxes (dJointID j, int num) | ||
3358 | { | ||
3359 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3360 | dAASSERT(joint && num >= 0 && num <= 3); | ||
3361 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3362 | if (joint->mode == dAMotorEuler) { | ||
3363 | joint->num = 3; | ||
3364 | } | ||
3365 | else { | ||
3366 | if (num < 0) num = 0; | ||
3367 | if (num > 3) num = 3; | ||
3368 | joint->num = num; | ||
3369 | } | ||
3370 | } | ||
3371 | |||
3372 | |||
3373 | void dJointSetAMotorAxis (dJointID j, int anum, int rel, dReal x, dReal y, dReal z) | ||
3374 | { | ||
3375 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3376 | dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2); | ||
3377 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3378 | dUASSERT(!(!joint->node[1].body && (joint->flags & dJOINT_REVERSE) && rel == 1),"no first body, can't set axis rel=1"); | ||
3379 | dUASSERT(!(!joint->node[1].body && !(joint->flags & dJOINT_REVERSE) && rel == 2),"no second body, can't set axis rel=2"); | ||
3380 | if (anum < 0) anum = 0; | ||
3381 | if (anum > 2) anum = 2; | ||
3382 | |||
3383 | // adjust rel to match the internal body order | ||
3384 | if (!joint->node[1].body && rel==2) rel = 1; | ||
3385 | |||
3386 | joint->rel[anum] = rel; | ||
3387 | |||
3388 | // x,y,z is always in global coordinates regardless of rel, so we may have | ||
3389 | // to convert it to be relative to a body | ||
3390 | dVector3 r; | ||
3391 | r[0] = x; | ||
3392 | r[1] = y; | ||
3393 | r[2] = z; | ||
3394 | r[3] = 0; | ||
3395 | if (rel > 0) { | ||
3396 | if (rel==1) { | ||
3397 | dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->posr.R,r); | ||
3398 | } | ||
3399 | else { | ||
3400 | // don't assert; handle the case of attachment to a bodiless geom | ||
3401 | if (joint->node[1].body) { // jds | ||
3402 | dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->posr.R,r); | ||
3403 | } | ||
3404 | else { | ||
3405 | joint->axis[anum][0] = r[0]; joint->axis[anum][1] = r[1]; | ||
3406 | joint->axis[anum][2] = r[2]; joint->axis[anum][3] = r[3]; | ||
3407 | } | ||
3408 | } | ||
3409 | } | ||
3410 | else { | ||
3411 | joint->axis[anum][0] = r[0]; | ||
3412 | joint->axis[anum][1] = r[1]; | ||
3413 | joint->axis[anum][2] = r[2]; | ||
3414 | } | ||
3415 | dNormalize3 (joint->axis[anum]); | ||
3416 | if (joint->mode == dAMotorEuler) amotorSetEulerReferenceVectors (joint); | ||
3417 | } | ||
3418 | |||
3419 | |||
3420 | void dJointSetAMotorAngle (dJointID j, int anum, dReal angle) | ||
3421 | { | ||
3422 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3423 | dAASSERT(joint && anum >= 0 && anum < 3); | ||
3424 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3425 | if (joint->mode == dAMotorUser) { | ||
3426 | if (anum < 0) anum = 0; | ||
3427 | if (anum > 3) anum = 3; | ||
3428 | joint->angle[anum] = angle; | ||
3429 | } | ||
3430 | } | ||
3431 | |||
3432 | |||
3433 | void dJointSetAMotorParam (dJointID j, int parameter, dReal value) | ||
3434 | { | ||
3435 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3436 | dAASSERT(joint); | ||
3437 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3438 | int anum = parameter >> 8; | ||
3439 | if (anum < 0) anum = 0; | ||
3440 | if (anum > 2) anum = 2; | ||
3441 | parameter &= 0xff; | ||
3442 | joint->limot[anum].set (parameter, value); | ||
3443 | } | ||
3444 | |||
3445 | |||
3446 | void dJointSetAMotorMode (dJointID j, int mode) | ||
3447 | { | ||
3448 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3449 | dAASSERT(joint); | ||
3450 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3451 | joint->mode = mode; | ||
3452 | if (joint->mode == dAMotorEuler) { | ||
3453 | joint->num = 3; | ||
3454 | amotorSetEulerReferenceVectors (joint); | ||
3455 | } | ||
3456 | } | ||
3457 | |||
3458 | |||
3459 | int dJointGetAMotorNumAxes (dJointID j) | ||
3460 | { | ||
3461 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3462 | dAASSERT(joint); | ||
3463 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3464 | return joint->num; | ||
3465 | } | ||
3466 | |||
3467 | |||
3468 | void dJointGetAMotorAxis (dJointID j, int anum, dVector3 result) | ||
3469 | { | ||
3470 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3471 | dAASSERT(joint && anum >= 0 && anum < 3); | ||
3472 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3473 | if (anum < 0) anum = 0; | ||
3474 | if (anum > 2) anum = 2; | ||
3475 | if (joint->rel[anum] > 0) { | ||
3476 | if (joint->rel[anum]==1) { | ||
3477 | dMULTIPLY0_331 (result,joint->node[0].body->posr.R,joint->axis[anum]); | ||
3478 | } | ||
3479 | else { | ||
3480 | if (joint->node[1].body) { // jds | ||
3481 | dMULTIPLY0_331 (result,joint->node[1].body->posr.R,joint->axis[anum]); | ||
3482 | } | ||
3483 | else { | ||
3484 | result[0] = joint->axis[anum][0]; result[1] = joint->axis[anum][1]; | ||
3485 | result[2] = joint->axis[anum][2]; result[3] = joint->axis[anum][3]; | ||
3486 | } | ||
3487 | } | ||
3488 | } | ||
3489 | else { | ||
3490 | result[0] = joint->axis[anum][0]; | ||
3491 | result[1] = joint->axis[anum][1]; | ||
3492 | result[2] = joint->axis[anum][2]; | ||
3493 | } | ||
3494 | } | ||
3495 | |||
3496 | |||
3497 | int dJointGetAMotorAxisRel (dJointID j, int anum) | ||
3498 | { | ||
3499 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3500 | dAASSERT(joint && anum >= 0 && anum < 3); | ||
3501 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3502 | if (anum < 0) anum = 0; | ||
3503 | if (anum > 2) anum = 2; | ||
3504 | return joint->rel[anum]; | ||
3505 | } | ||
3506 | |||
3507 | |||
3508 | dReal dJointGetAMotorAngle (dJointID j, int anum) | ||
3509 | { | ||
3510 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3511 | dAASSERT(joint && anum >= 0 && anum < 3); | ||
3512 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3513 | if (anum < 0) anum = 0; | ||
3514 | if (anum > 3) anum = 3; | ||
3515 | return joint->angle[anum]; | ||
3516 | } | ||
3517 | |||
3518 | |||
3519 | dReal dJointGetAMotorAngleRate (dJointID j, int anum) | ||
3520 | { | ||
3521 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3522 | // @@@ | ||
3523 | dDebug (0,"not yet implemented"); | ||
3524 | return 0; | ||
3525 | } | ||
3526 | |||
3527 | |||
3528 | dReal dJointGetAMotorParam (dJointID j, int parameter) | ||
3529 | { | ||
3530 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3531 | dAASSERT(joint); | ||
3532 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3533 | int anum = parameter >> 8; | ||
3534 | if (anum < 0) anum = 0; | ||
3535 | if (anum > 2) anum = 2; | ||
3536 | parameter &= 0xff; | ||
3537 | return joint->limot[anum].get (parameter); | ||
3538 | } | ||
3539 | |||
3540 | |||
3541 | int dJointGetAMotorMode (dJointID j) | ||
3542 | { | ||
3543 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3544 | dAASSERT(joint); | ||
3545 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3546 | return joint->mode; | ||
3547 | } | ||
3548 | |||
3549 | |||
3550 | void dJointAddAMotorTorques (dJointID j, dReal torque1, dReal torque2, dReal torque3) | ||
3551 | { | ||
3552 | dxJointAMotor* joint = (dxJointAMotor*)j; | ||
3553 | dVector3 axes[3]; | ||
3554 | dAASSERT(joint); | ||
3555 | dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); | ||
3556 | |||
3557 | if (joint->num == 0) | ||
3558 | return; | ||
3559 | dUASSERT((joint->flags & dJOINT_REVERSE) == 0, "dJointAddAMotorTorques not yet implemented for reverse AMotor joints"); | ||
3560 | |||
3561 | amotorComputeGlobalAxes (joint,axes); | ||
3562 | axes[0][0] *= torque1; | ||
3563 | axes[0][1] *= torque1; | ||
3564 | axes[0][2] *= torque1; | ||
3565 | if (joint->num >= 2) { | ||
3566 | axes[0][0] += axes[1][0] * torque2; | ||
3567 | axes[0][1] += axes[1][1] * torque2; | ||
3568 | axes[0][2] += axes[1][2] * torque2; | ||
3569 | if (joint->num >= 3) { | ||
3570 | axes[0][0] += axes[2][0] * torque3; | ||
3571 | axes[0][1] += axes[2][1] * torque3; | ||
3572 | axes[0][2] += axes[2][2] * torque3; | ||
3573 | } | ||
3574 | } | ||
3575 | |||
3576 | if (joint->node[0].body != 0) | ||
3577 | dBodyAddTorque (joint->node[0].body,axes[0][0],axes[0][1],axes[0][2]); | ||
3578 | if (joint->node[1].body != 0) | ||
3579 | dBodyAddTorque(joint->node[1].body, -axes[0][0], -axes[0][1], -axes[0][2]); | ||
3580 | } | ||
3581 | |||
3582 | |||
3583 | dxJoint::Vtable __damotor_vtable = { | ||
3584 | sizeof(dxJointAMotor), | ||
3585 | (dxJoint::init_fn*) amotorInit, | ||
3586 | (dxJoint::getInfo1_fn*) amotorGetInfo1, | ||
3587 | (dxJoint::getInfo2_fn*) amotorGetInfo2, | ||
3588 | dJointTypeAMotor}; | ||
3589 | |||
3590 | |||
3591 | |||
3592 | //**************************************************************************** | ||
3593 | // lmotor joint | ||
3594 | static void lmotorInit (dxJointLMotor *j) | ||
3595 | { | ||
3596 | int i; | ||
3597 | j->num = 0; | ||
3598 | for (i=0;i<3;i++) { | ||
3599 | dSetZero(j->axis[i],4); | ||
3600 | j->limot[i].init(j->world); | ||
3601 | } | ||
3602 | } | ||
3603 | |||
3604 | static void lmotorComputeGlobalAxes (dxJointLMotor *joint, dVector3 ax[3]) | ||
3605 | { | ||
3606 | for (int i=0; i< joint->num; i++) { | ||
3607 | if (joint->rel[i] == 1) { | ||
3608 | dMULTIPLY0_331 (ax[i],joint->node[0].body->posr.R,joint->axis[i]); | ||
3609 | } | ||
3610 | else if (joint->rel[i] == 2) { | ||
3611 | if (joint->node[1].body) { // jds: don't assert, just ignore | ||
3612 | dMULTIPLY0_331 (ax[i],joint->node[1].body->posr.R,joint->axis[i]); | ||
3613 | } | ||
3614 | } else { | ||
3615 | ax[i][0] = joint->axis[i][0]; | ||
3616 | ax[i][1] = joint->axis[i][1]; | ||
3617 | ax[i][2] = joint->axis[i][2]; | ||
3618 | } | ||
3619 | } | ||
3620 | } | ||
3621 | |||
3622 | static void lmotorGetInfo1 (dxJointLMotor *j, dxJoint::Info1 *info) | ||
3623 | { | ||
3624 | info->m = 0; | ||
3625 | info->nub = 0; | ||
3626 | for (int i=0; i < j->num; i++) { | ||
3627 | if (j->limot[i].fmax > 0) { | ||
3628 | info->m++; | ||
3629 | } | ||
3630 | } | ||
3631 | } | ||
3632 | |||
3633 | static void lmotorGetInfo2 (dxJointLMotor *joint, dxJoint::Info2 *info) | ||
3634 | { | ||
3635 | int row=0; | ||
3636 | dVector3 ax[3]; | ||
3637 | lmotorComputeGlobalAxes(joint, ax); | ||
3638 | |||
3639 | for (int i=0;i<joint->num;i++) { | ||
3640 | row += joint->limot[i].addLimot(joint,info,row,ax[i], 0); | ||
3641 | } | ||
3642 | } | ||
3643 | |||
3644 | void dJointSetLMotorAxis (dJointID j, int anum, int rel, dReal x, dReal y, dReal z) | ||
3645 | { | ||
3646 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3647 | //for now we are ignoring rel! | ||
3648 | dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2); | ||
3649 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3650 | if (anum < 0) anum = 0; | ||
3651 | if (anum > 2) anum = 2; | ||
3652 | |||
3653 | if (!joint->node[1].body && rel==2) rel = 1; //ref 1 | ||
3654 | |||
3655 | joint->rel[anum] = rel; | ||
3656 | |||
3657 | dVector3 r; | ||
3658 | r[0] = x; | ||
3659 | r[1] = y; | ||
3660 | r[2] = z; | ||
3661 | r[3] = 0; | ||
3662 | if (rel > 0) { | ||
3663 | if (rel==1) { | ||
3664 | dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->posr.R,r); | ||
3665 | } else { | ||
3666 | //second body has to exists thanks to ref 1 line | ||
3667 | dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->posr.R,r); | ||
3668 | } | ||
3669 | } else { | ||
3670 | joint->axis[anum][0] = r[0]; | ||
3671 | joint->axis[anum][1] = r[1]; | ||
3672 | joint->axis[anum][2] = r[2]; | ||
3673 | } | ||
3674 | |||
3675 | dNormalize3 (joint->axis[anum]); | ||
3676 | } | ||
3677 | |||
3678 | void dJointSetLMotorNumAxes (dJointID j, int num) | ||
3679 | { | ||
3680 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3681 | dAASSERT(joint && num >= 0 && num <= 3); | ||
3682 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3683 | if (num < 0) num = 0; | ||
3684 | if (num > 3) num = 3; | ||
3685 | joint->num = num; | ||
3686 | } | ||
3687 | |||
3688 | void dJointSetLMotorParam (dJointID j, int parameter, dReal value) | ||
3689 | { | ||
3690 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3691 | dAASSERT(joint); | ||
3692 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3693 | int anum = parameter >> 8; | ||
3694 | if (anum < 0) anum = 0; | ||
3695 | if (anum > 2) anum = 2; | ||
3696 | parameter &= 0xff; | ||
3697 | joint->limot[anum].set (parameter, value); | ||
3698 | } | ||
3699 | |||
3700 | int dJointGetLMotorNumAxes (dJointID j) | ||
3701 | { | ||
3702 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3703 | dAASSERT(joint); | ||
3704 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3705 | return joint->num; | ||
3706 | } | ||
3707 | |||
3708 | |||
3709 | void dJointGetLMotorAxis (dJointID j, int anum, dVector3 result) | ||
3710 | { | ||
3711 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3712 | dAASSERT(joint && anum >= 0 && anum < 3); | ||
3713 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3714 | if (anum < 0) anum = 0; | ||
3715 | if (anum > 2) anum = 2; | ||
3716 | result[0] = joint->axis[anum][0]; | ||
3717 | result[1] = joint->axis[anum][1]; | ||
3718 | result[2] = joint->axis[anum][2]; | ||
3719 | } | ||
3720 | |||
3721 | dReal dJointGetLMotorParam (dJointID j, int parameter) | ||
3722 | { | ||
3723 | dxJointLMotor* joint = (dxJointLMotor*)j; | ||
3724 | dAASSERT(joint); | ||
3725 | dUASSERT(joint->vtable == &__dlmotor_vtable,"joint is not an lmotor"); | ||
3726 | int anum = parameter >> 8; | ||
3727 | if (anum < 0) anum = 0; | ||
3728 | if (anum > 2) anum = 2; | ||
3729 | parameter &= 0xff; | ||
3730 | return joint->limot[anum].get (parameter); | ||
3731 | } | ||
3732 | |||
3733 | dxJoint::Vtable __dlmotor_vtable = { | ||
3734 | sizeof(dxJointLMotor), | ||
3735 | (dxJoint::init_fn*) lmotorInit, | ||
3736 | (dxJoint::getInfo1_fn*) lmotorGetInfo1, | ||
3737 | (dxJoint::getInfo2_fn*) lmotorGetInfo2, | ||
3738 | dJointTypeLMotor | ||
3739 | }; | ||
3740 | |||
3741 | |||
3742 | //**************************************************************************** | ||
3743 | // fixed joint | ||
3744 | |||
3745 | static void fixedInit (dxJointFixed *j) | ||
3746 | { | ||
3747 | dSetZero (j->offset,4); | ||
3748 | dSetZero (j->qrel,4); | ||
3749 | j->erp = j->world->global_erp; | ||
3750 | j->cfm = j->world->global_cfm; | ||
3751 | } | ||
3752 | |||
3753 | |||
3754 | static void fixedGetInfo1 (dxJointFixed *j, dxJoint::Info1 *info) | ||
3755 | { | ||
3756 | info->m = 6; | ||
3757 | info->nub = 6; | ||
3758 | } | ||
3759 | |||
3760 | |||
3761 | static void fixedGetInfo2 (dxJointFixed *joint, dxJoint::Info2 *info) | ||
3762 | { | ||
3763 | int s = info->rowskip; | ||
3764 | |||
3765 | // Three rows for orientation | ||
3766 | setFixedOrientation(joint, info, joint->qrel, 3); | ||
3767 | |||
3768 | // Three rows for position. | ||
3769 | // set jacobian | ||
3770 | info->J1l[0] = 1; | ||
3771 | info->J1l[s+1] = 1; | ||
3772 | info->J1l[2*s+2] = 1; | ||
3773 | |||
3774 | info->erp = joint->erp; | ||
3775 | info->cfm[0] = joint->cfm; | ||
3776 | info->cfm[1] = joint->cfm; | ||
3777 | info->cfm[2] = joint->cfm; | ||
3778 | |||
3779 | dVector3 ofs; | ||
3780 | dMULTIPLY0_331 (ofs,joint->node[0].body->posr.R,joint->offset); | ||
3781 | if (joint->node[1].body) { | ||
3782 | dCROSSMAT (info->J1a,ofs,s,+,-); | ||
3783 | info->J2l[0] = -1; | ||
3784 | info->J2l[s+1] = -1; | ||
3785 | info->J2l[2*s+2] = -1; | ||
3786 | } | ||
3787 | |||
3788 | // set right hand side for the first three rows (linear) | ||
3789 | dReal k = info->fps * info->erp; | ||
3790 | if (joint->node[1].body) { | ||
3791 | for (int j=0; j<3; j++) | ||
3792 | info->c[j] = k * (joint->node[1].body->posr.pos[j] - | ||
3793 | joint->node[0].body->posr.pos[j] + ofs[j]); | ||
3794 | } | ||
3795 | else { | ||
3796 | for (int j=0; j<3; j++) | ||
3797 | info->c[j] = k * (joint->offset[j] - joint->node[0].body->posr.pos[j]); | ||
3798 | } | ||
3799 | } | ||
3800 | |||
3801 | |||
3802 | void dJointSetFixed (dJointID j) | ||
3803 | { | ||
3804 | dxJointFixed* joint = (dxJointFixed*)j; | ||
3805 | dUASSERT(joint,"bad joint argument"); | ||
3806 | dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed"); | ||
3807 | int i; | ||
3808 | |||
3809 | // This code is taken from sJointSetSliderAxis(), we should really put the | ||
3810 | // common code in its own function. | ||
3811 | // compute the offset between the bodies | ||
3812 | if (joint->node[0].body) { | ||
3813 | if (joint->node[1].body) { | ||
3814 | dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); | ||
3815 | dReal ofs[4]; | ||
3816 | for (i=0; i<4; i++) ofs[i] = joint->node[0].body->posr.pos[i]; | ||
3817 | for (i=0; i<4; i++) ofs[i] -= joint->node[1].body->posr.pos[i]; | ||
3818 | dMULTIPLY1_331 (joint->offset,joint->node[0].body->posr.R,ofs); | ||
3819 | } | ||
3820 | else { | ||
3821 | // set joint->qrel to the transpose of the first body's q | ||
3822 | joint->qrel[0] = joint->node[0].body->q[0]; | ||
3823 | for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; | ||
3824 | for (i=0; i<4; i++) joint->offset[i] = joint->node[0].body->posr.pos[i]; | ||
3825 | } | ||
3826 | } | ||
3827 | } | ||
3828 | |||
3829 | void dxJointFixed::set (int num, dReal value) | ||
3830 | { | ||
3831 | switch (num) { | ||
3832 | case dParamCFM: | ||
3833 | cfm = value; | ||
3834 | break; | ||
3835 | case dParamERP: | ||
3836 | erp = value; | ||
3837 | break; | ||
3838 | } | ||
3839 | } | ||
3840 | |||
3841 | |||
3842 | dReal dxJointFixed::get (int num) | ||
3843 | { | ||
3844 | switch (num) { | ||
3845 | case dParamCFM: | ||
3846 | return cfm; | ||
3847 | case dParamERP: | ||
3848 | return erp; | ||
3849 | default: | ||
3850 | return 0; | ||
3851 | } | ||
3852 | } | ||
3853 | |||
3854 | |||
3855 | void dJointSetFixedParam (dJointID j, int parameter, dReal value) | ||
3856 | { | ||
3857 | dxJointFixed* joint = (dxJointFixed*)j; | ||
3858 | dUASSERT(joint,"bad joint argument"); | ||
3859 | dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not a fixed joint"); | ||
3860 | joint->set (parameter,value); | ||
3861 | } | ||
3862 | |||
3863 | |||
3864 | dReal dJointGetFixedParam (dJointID j, int parameter) | ||
3865 | { | ||
3866 | dxJointFixed* joint = (dxJointFixed*)j; | ||
3867 | dUASSERT(joint,"bad joint argument"); | ||
3868 | dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not a fixed joint"); | ||
3869 | return joint->get (parameter); | ||
3870 | } | ||
3871 | |||
3872 | |||
3873 | dxJoint::Vtable __dfixed_vtable = { | ||
3874 | sizeof(dxJointFixed), | ||
3875 | (dxJoint::init_fn*) fixedInit, | ||
3876 | (dxJoint::getInfo1_fn*) fixedGetInfo1, | ||
3877 | (dxJoint::getInfo2_fn*) fixedGetInfo2, | ||
3878 | dJointTypeFixed}; | ||
3879 | |||
3880 | //**************************************************************************** | ||
3881 | // null joint | ||
3882 | |||
3883 | static void nullGetInfo1 (dxJointNull *j, dxJoint::Info1 *info) | ||
3884 | { | ||
3885 | info->m = 0; | ||
3886 | info->nub = 0; | ||
3887 | } | ||
3888 | |||
3889 | |||
3890 | static void nullGetInfo2 (dxJointNull *joint, dxJoint::Info2 *info) | ||
3891 | { | ||
3892 | dDebug (0,"this should never get called"); | ||
3893 | } | ||
3894 | |||
3895 | |||
3896 | dxJoint::Vtable __dnull_vtable = { | ||
3897 | sizeof(dxJointNull), | ||
3898 | (dxJoint::init_fn*) 0, | ||
3899 | (dxJoint::getInfo1_fn*) nullGetInfo1, | ||
3900 | (dxJoint::getInfo2_fn*) nullGetInfo2, | ||
3901 | dJointTypeNull}; | ||
3902 | |||
3903 | |||
3904 | |||
3905 | |||
3906 | /* | ||
3907 | This code is part of the Plane2D ODE joint | ||
3908 | by psero@gmx.de | ||
3909 | Wed Apr 23 18:53:43 CEST 2003 | ||
3910 | |||
3911 | Add this code to the file: ode/src/joint.cpp | ||
3912 | */ | ||
3913 | |||
3914 | |||
3915 | # define VoXYZ(v1, o1, x, y, z) \ | ||
3916 | ( \ | ||
3917 | (v1)[0] o1 (x), \ | ||
3918 | (v1)[1] o1 (y), \ | ||
3919 | (v1)[2] o1 (z) \ | ||
3920 | ) | ||
3921 | |||
3922 | static dReal Midentity[3][3] = | ||
3923 | { | ||
3924 | { 1, 0, 0 }, | ||
3925 | { 0, 1, 0 }, | ||
3926 | { 0, 0, 1, } | ||
3927 | }; | ||
3928 | |||
3929 | |||
3930 | |||
3931 | static void plane2dInit (dxJointPlane2D *j) | ||
3932 | /*********************************************/ | ||
3933 | { | ||
3934 | /* MINFO ("plane2dInit ()"); */ | ||
3935 | j->motor_x.init (j->world); | ||
3936 | j->motor_y.init (j->world); | ||
3937 | j->motor_angle.init (j->world); | ||
3938 | } | ||
3939 | |||
3940 | |||
3941 | |||
3942 | static void plane2dGetInfo1 (dxJointPlane2D *j, dxJoint::Info1 *info) | ||
3943 | /***********************************************************************/ | ||
3944 | { | ||
3945 | /* MINFO ("plane2dGetInfo1 ()"); */ | ||
3946 | |||
3947 | info->nub = 3; | ||
3948 | info->m = 3; | ||
3949 | |||
3950 | if (j->motor_x.fmax > 0) | ||
3951 | j->row_motor_x = info->m ++; | ||
3952 | if (j->motor_y.fmax > 0) | ||
3953 | j->row_motor_y = info->m ++; | ||
3954 | if (j->motor_angle.fmax > 0) | ||
3955 | j->row_motor_angle = info->m ++; | ||
3956 | } | ||
3957 | |||
3958 | |||
3959 | |||
3960 | static void plane2dGetInfo2 (dxJointPlane2D *joint, dxJoint::Info2 *info) | ||
3961 | /***************************************************************************/ | ||
3962 | { | ||
3963 | int r0 = 0, | ||
3964 | r1 = info->rowskip, | ||
3965 | r2 = 2 * r1; | ||
3966 | dReal eps = info->fps * info->erp; | ||
3967 | |||
3968 | /* MINFO ("plane2dGetInfo2 ()"); */ | ||
3969 | |||
3970 | /* | ||
3971 | v = v1, w = omega1 | ||
3972 | (v2, omega2 not important (== static environment)) | ||
3973 | |||
3974 | constraint equations: | ||
3975 | xz = 0 | ||
3976 | wx = 0 | ||
3977 | wy = 0 | ||
3978 | |||
3979 | <=> ( 0 0 1 ) (vx) ( 0 0 0 ) (wx) ( 0 ) | ||
3980 | ( 0 0 0 ) (vy) + ( 1 0 0 ) (wy) = ( 0 ) | ||
3981 | ( 0 0 0 ) (vz) ( 0 1 0 ) (wz) ( 0 ) | ||
3982 | J1/J1l Omega1/J1a | ||
3983 | */ | ||
3984 | |||
3985 | // fill in linear and angular coeff. for left hand side: | ||
3986 | |||
3987 | VoXYZ (&info->J1l[r0], =, 0, 0, 1); | ||
3988 | VoXYZ (&info->J1l[r1], =, 0, 0, 0); | ||
3989 | VoXYZ (&info->J1l[r2], =, 0, 0, 0); | ||
3990 | |||
3991 | VoXYZ (&info->J1a[r0], =, 0, 0, 0); | ||
3992 | VoXYZ (&info->J1a[r1], =, 1, 0, 0); | ||
3993 | VoXYZ (&info->J1a[r2], =, 0, 1, 0); | ||
3994 | |||
3995 | // error correction (against drift): | ||
3996 | |||
3997 | // a) linear vz, so that z (== pos[2]) == 0 | ||
3998 | info->c[0] = eps * -joint->node[0].body->posr.pos[2]; | ||
3999 | |||
4000 | # if 0 | ||
4001 | // b) angular correction? -> left to application !!! | ||
4002 | dReal *body_z_axis = &joint->node[0].body->R[8]; | ||
4003 | info->c[1] = eps * +atan2 (body_z_axis[1], body_z_axis[2]); // wx error | ||
4004 | info->c[2] = eps * -atan2 (body_z_axis[0], body_z_axis[2]); // wy error | ||
4005 | # endif | ||
4006 | |||
4007 | // if the slider is powered, or has joint limits, add in the extra row: | ||
4008 | |||
4009 | if (joint->row_motor_x > 0) | ||
4010 | joint->motor_x.addLimot ( | ||
4011 | joint, info, joint->row_motor_x, Midentity[0], 0); | ||
4012 | |||
4013 | if (joint->row_motor_y > 0) | ||
4014 | joint->motor_y.addLimot ( | ||
4015 | joint, info, joint->row_motor_y, Midentity[1], 0); | ||
4016 | |||
4017 | if (joint->row_motor_angle > 0) | ||
4018 | joint->motor_angle.addLimot ( | ||
4019 | joint, info, joint->row_motor_angle, Midentity[2], 1); | ||
4020 | } | ||
4021 | |||
4022 | |||
4023 | |||
4024 | dxJoint::Vtable __dplane2d_vtable = | ||
4025 | { | ||
4026 | sizeof (dxJointPlane2D), | ||
4027 | (dxJoint::init_fn*) plane2dInit, | ||
4028 | (dxJoint::getInfo1_fn*) plane2dGetInfo1, | ||
4029 | (dxJoint::getInfo2_fn*) plane2dGetInfo2, | ||
4030 | dJointTypePlane2D | ||
4031 | }; | ||
4032 | |||
4033 | |||
4034 | void dJointSetPlane2DXParam (dxJoint *joint, | ||
4035 | int parameter, dReal value) | ||
4036 | { | ||
4037 | dUASSERT (joint, "bad joint argument"); | ||
4038 | dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d"); | ||
4039 | dxJointPlane2D* joint2d = (dxJointPlane2D*)( joint ); | ||
4040 | joint2d->motor_x.set (parameter, value); | ||
4041 | } | ||
4042 | |||
4043 | |||
4044 | void dJointSetPlane2DYParam (dxJoint *joint, | ||
4045 | int parameter, dReal value) | ||
4046 | { | ||
4047 | dUASSERT (joint, "bad joint argument"); | ||
4048 | dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d"); | ||
4049 | dxJointPlane2D* joint2d = (dxJointPlane2D*)( joint ); | ||
4050 | joint2d->motor_y.set (parameter, value); | ||
4051 | } | ||
4052 | |||
4053 | |||
4054 | |||
4055 | void dJointSetPlane2DAngleParam (dxJoint *joint, | ||
4056 | int parameter, dReal value) | ||
4057 | { | ||
4058 | dUASSERT (joint, "bad joint argument"); | ||
4059 | dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d"); | ||
4060 | dxJointPlane2D* joint2d = (dxJointPlane2D*)( joint ); | ||
4061 | joint2d->motor_angle.set (parameter, value); | ||
4062 | } | ||
4063 | |||
4064 | |||
4065 | |||
diff --git a/libraries/ode-0.9\/ode/src/joint.h b/libraries/ode-0.9\/ode/src/joint.h new file mode 100755 index 0000000..27c013e --- /dev/null +++ b/libraries/ode-0.9\/ode/src/joint.h | |||
@@ -0,0 +1,346 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifndef _ODE_JOINT_H_ | ||
24 | #define _ODE_JOINT_H_ | ||
25 | |||
26 | |||
27 | #include "objects.h" | ||
28 | #include <ode/contact.h> | ||
29 | #include "obstack.h" | ||
30 | |||
31 | |||
32 | // joint flags | ||
33 | enum { | ||
34 | // if this flag is set, the joint was allocated in a joint group | ||
35 | dJOINT_INGROUP = 1, | ||
36 | |||
37 | // if this flag is set, the joint was attached with arguments (0,body). | ||
38 | // our convention is to treat all attaches as (body,0), i.e. so node[0].body | ||
39 | // is always nonzero, so this flag records the fact that the arguments were | ||
40 | // swapped. | ||
41 | dJOINT_REVERSE = 2, | ||
42 | |||
43 | // if this flag is set, the joint can not have just one body attached to it, | ||
44 | // it must have either zero or two bodies attached. | ||
45 | dJOINT_TWOBODIES = 4 | ||
46 | }; | ||
47 | |||
48 | |||
49 | // there are two of these nodes in the joint, one for each connection to a | ||
50 | // body. these are node of a linked list kept by each body of it's connecting | ||
51 | // joints. but note that the body pointer in each node points to the body that | ||
52 | // makes use of the *other* node, not this node. this trick makes it a bit | ||
53 | // easier to traverse the body/joint graph. | ||
54 | |||
55 | struct dxJointNode { | ||
56 | dxJoint *joint; // pointer to enclosing dxJoint object | ||
57 | dxBody *body; // *other* body this joint is connected to | ||
58 | dxJointNode *next; // next node in body's list of connected joints | ||
59 | }; | ||
60 | |||
61 | |||
62 | struct dxJoint : public dObject { | ||
63 | // naming convention: the "first" body this is connected to is node[0].body, | ||
64 | // and the "second" body is node[1].body. if this joint is only connected | ||
65 | // to one body then the second body is 0. | ||
66 | |||
67 | // info returned by getInfo1 function. the constraint dimension is m (<=6). | ||
68 | // i.e. that is the total number of rows in the jacobian. `nub' is the | ||
69 | // number of unbounded variables (which have lo,hi = -/+ infinity). | ||
70 | |||
71 | struct Info1 { | ||
72 | int m,nub; | ||
73 | }; | ||
74 | |||
75 | // info returned by getInfo2 function | ||
76 | |||
77 | struct Info2 { | ||
78 | // integrator parameters: frames per second (1/stepsize), default error | ||
79 | // reduction parameter (0..1). | ||
80 | dReal fps,erp; | ||
81 | |||
82 | // for the first and second body, pointers to two (linear and angular) | ||
83 | // n*3 jacobian sub matrices, stored by rows. these matrices will have | ||
84 | // been initialized to 0 on entry. if the second body is zero then the | ||
85 | // J2xx pointers may be 0. | ||
86 | dReal *J1l,*J1a,*J2l,*J2a; | ||
87 | |||
88 | // elements to jump from one row to the next in J's | ||
89 | int rowskip; | ||
90 | |||
91 | // right hand sides of the equation J*v = c + cfm * lambda. cfm is the | ||
92 | // "constraint force mixing" vector. c is set to zero on entry, cfm is | ||
93 | // set to a constant value (typically very small or zero) value on entry. | ||
94 | dReal *c,*cfm; | ||
95 | |||
96 | // lo and hi limits for variables (set to -/+ infinity on entry). | ||
97 | dReal *lo,*hi; | ||
98 | |||
99 | // findex vector for variables. see the LCP solver interface for a | ||
100 | // description of what this does. this is set to -1 on entry. | ||
101 | // note that the returned indexes are relative to the first index of | ||
102 | // the constraint. | ||
103 | int *findex; | ||
104 | }; | ||
105 | |||
106 | // virtual function table: size of the joint structure, function pointers. | ||
107 | // we do it this way instead of using C++ virtual functions because | ||
108 | // sometimes we need to allocate joints ourself within a memory pool. | ||
109 | |||
110 | typedef void init_fn (dxJoint *joint); | ||
111 | typedef void getInfo1_fn (dxJoint *joint, Info1 *info); | ||
112 | typedef void getInfo2_fn (dxJoint *joint, Info2 *info); | ||
113 | struct Vtable { | ||
114 | int size; | ||
115 | init_fn *init; | ||
116 | getInfo1_fn *getInfo1; | ||
117 | getInfo2_fn *getInfo2; | ||
118 | int typenum; // a dJointTypeXXX type number | ||
119 | }; | ||
120 | |||
121 | Vtable *vtable; // virtual function table | ||
122 | int flags; // dJOINT_xxx flags | ||
123 | dxJointNode node[2]; // connections to bodies. node[1].body can be 0 | ||
124 | dJointFeedback *feedback; // optional feedback structure | ||
125 | dReal lambda[6]; // lambda generated by last step | ||
126 | }; | ||
127 | |||
128 | |||
129 | // joint group. NOTE: any joints in the group that have their world destroyed | ||
130 | // will have their world pointer set to 0. | ||
131 | |||
132 | struct dxJointGroup : public dBase { | ||
133 | int num; // number of joints on the stack | ||
134 | dObStack stack; // a stack of (possibly differently sized) dxJoint | ||
135 | }; // objects. | ||
136 | |||
137 | |||
138 | // common limit and motor information for a single joint axis of movement | ||
139 | struct dxJointLimitMotor { | ||
140 | dReal vel,fmax; // powered joint: velocity, max force | ||
141 | dReal lostop,histop; // joint limits, relative to initial position | ||
142 | dReal fudge_factor; // when powering away from joint limits | ||
143 | dReal normal_cfm; // cfm to use when not at a stop | ||
144 | dReal stop_erp,stop_cfm; // erp and cfm for when at joint limit | ||
145 | dReal bounce; // restitution factor | ||
146 | // variables used between getInfo1() and getInfo2() | ||
147 | int limit; // 0=free, 1=at lo limit, 2=at hi limit | ||
148 | dReal limit_err; // if at limit, amount over limit | ||
149 | |||
150 | void init (dxWorld *); | ||
151 | void set (int num, dReal value); | ||
152 | dReal get (int num); | ||
153 | int testRotationalLimit (dReal angle); | ||
154 | int addLimot (dxJoint *joint, dxJoint::Info2 *info, int row, | ||
155 | dVector3 ax1, int rotational); | ||
156 | }; | ||
157 | |||
158 | |||
159 | // ball and socket | ||
160 | |||
161 | struct dxJointBall : public dxJoint { | ||
162 | dVector3 anchor1; // anchor w.r.t first body | ||
163 | dVector3 anchor2; // anchor w.r.t second body | ||
164 | dReal erp; // error reduction | ||
165 | dReal cfm; // constraint force mix in | ||
166 | void set (int num, dReal value); | ||
167 | dReal get (int num); | ||
168 | }; | ||
169 | extern struct dxJoint::Vtable __dball_vtable; | ||
170 | |||
171 | |||
172 | // hinge | ||
173 | |||
174 | struct dxJointHinge : public dxJoint { | ||
175 | dVector3 anchor1; // anchor w.r.t first body | ||
176 | dVector3 anchor2; // anchor w.r.t second body | ||
177 | dVector3 axis1; // axis w.r.t first body | ||
178 | dVector3 axis2; // axis w.r.t second body | ||
179 | dQuaternion qrel; // initial relative rotation body1 -> body2 | ||
180 | dxJointLimitMotor limot; // limit and motor information | ||
181 | }; | ||
182 | extern struct dxJoint::Vtable __dhinge_vtable; | ||
183 | |||
184 | |||
185 | // universal | ||
186 | |||
187 | struct dxJointUniversal : public dxJoint { | ||
188 | dVector3 anchor1; // anchor w.r.t first body | ||
189 | dVector3 anchor2; // anchor w.r.t second body | ||
190 | dVector3 axis1; // axis w.r.t first body | ||
191 | dVector3 axis2; // axis w.r.t second body | ||
192 | dQuaternion qrel1; // initial relative rotation body1 -> virtual cross piece | ||
193 | dQuaternion qrel2; // initial relative rotation virtual cross piece -> body2 | ||
194 | dxJointLimitMotor limot1; // limit and motor information for axis1 | ||
195 | dxJointLimitMotor limot2; // limit and motor information for axis2 | ||
196 | }; | ||
197 | extern struct dxJoint::Vtable __duniversal_vtable; | ||
198 | |||
199 | |||
200 | /** | ||
201 | * The axisP must be perpendicular to axis2 | ||
202 | * <PRE> | ||
203 | * +-------------+ | ||
204 | * | x | | ||
205 | * +------------\+ | ||
206 | * Prismatic articulation .. .. | ||
207 | * | .. .. | ||
208 | * \/ .. .. | ||
209 | * +--------------+ --| __.. .. anchor2 | ||
210 | * | x | .....|.......(__) .. | ||
211 | * +--------------+ --| ^ < | ||
212 | * |----------------------->| | ||
213 | * Offset |--- Rotoide articulation | ||
214 | * </PRE> | ||
215 | */ | ||
216 | struct dxJointPR : public dxJoint { | ||
217 | |||
218 | dVector3 anchor2; ///< @brief Position of the rotoide articulation | ||
219 | ///< w.r.t second body. | ||
220 | ///< @note Position of body 2 in world frame + | ||
221 | ///< anchor2 in world frame give the position | ||
222 | ///< of the rotoide articulation | ||
223 | dVector3 axisR1; ///< axis of the rotoide articulation w.r.t first body. | ||
224 | ///< @note This is considered as axis1 from the parameter | ||
225 | ///< view. | ||
226 | dVector3 axisR2; ///< axis of the rotoide articulation w.r.t second body. | ||
227 | ///< @note This is considered also as axis1 from the | ||
228 | ///< parameter view | ||
229 | dVector3 axisP1; ///< axis for the prismatic articulation w.r.t first body. | ||
230 | ///< @note This is considered as axis2 in from the parameter | ||
231 | ///< view | ||
232 | dQuaternion qrel; ///< initial relative rotation body1 -> body2. | ||
233 | dVector3 offset; ///< @brief vector between the body1 and the rotoide | ||
234 | ///< articulation. | ||
235 | ///< | ||
236 | ///< Going from the first to the second in the frame | ||
237 | ///< of body1. | ||
238 | ///< That should be aligned with body1 center along axisP | ||
239 | ///< This is calculated whe the axis are set. | ||
240 | dxJointLimitMotor limotR; ///< limit and motor information for the rotoide articulation. | ||
241 | dxJointLimitMotor limotP; ///< limit and motor information for the prismatic articulation. | ||
242 | }; | ||
243 | extern struct dxJoint::Vtable __dPR_vtable; | ||
244 | |||
245 | |||
246 | |||
247 | // slider. if body2 is 0 then qrel is the absolute rotation of body1 and | ||
248 | // offset is the position of body1 center along axis1. | ||
249 | |||
250 | struct dxJointSlider : public dxJoint { | ||
251 | dVector3 axis1; // axis w.r.t first body | ||
252 | dQuaternion qrel; // initial relative rotation body1 -> body2 | ||
253 | dVector3 offset; // point relative to body2 that should be | ||
254 | // aligned with body1 center along axis1 | ||
255 | dxJointLimitMotor limot; // limit and motor information | ||
256 | }; | ||
257 | extern struct dxJoint::Vtable __dslider_vtable; | ||
258 | |||
259 | |||
260 | // contact | ||
261 | |||
262 | struct dxJointContact : public dxJoint { | ||
263 | int the_m; // number of rows computed by getInfo1 | ||
264 | dContact contact; | ||
265 | }; | ||
266 | extern struct dxJoint::Vtable __dcontact_vtable; | ||
267 | |||
268 | |||
269 | // hinge 2 | ||
270 | |||
271 | struct dxJointHinge2 : public dxJoint { | ||
272 | dVector3 anchor1; // anchor w.r.t first body | ||
273 | dVector3 anchor2; // anchor w.r.t second body | ||
274 | dVector3 axis1; // axis 1 w.r.t first body | ||
275 | dVector3 axis2; // axis 2 w.r.t second body | ||
276 | dReal c0,s0; // cos,sin of desired angle between axis 1,2 | ||
277 | dVector3 v1,v2; // angle ref vectors embedded in first body | ||
278 | dxJointLimitMotor limot1; // limit+motor info for axis 1 | ||
279 | dxJointLimitMotor limot2; // limit+motor info for axis 2 | ||
280 | dReal susp_erp,susp_cfm; // suspension parameters (erp,cfm) | ||
281 | }; | ||
282 | extern struct dxJoint::Vtable __dhinge2_vtable; | ||
283 | |||
284 | |||
285 | // angular motor | ||
286 | |||
287 | struct dxJointAMotor : public dxJoint { | ||
288 | int num; // number of axes (0..3) | ||
289 | int mode; // a dAMotorXXX constant | ||
290 | int rel[3]; // what the axes are relative to (global,b1,b2) | ||
291 | dVector3 axis[3]; // three axes | ||
292 | dxJointLimitMotor limot[3]; // limit+motor info for axes | ||
293 | dReal angle[3]; // user-supplied angles for axes | ||
294 | // these vectors are used for calculating euler angles | ||
295 | dVector3 reference1; // original axis[2], relative to body 1 | ||
296 | dVector3 reference2; // original axis[0], relative to body 2 | ||
297 | }; | ||
298 | extern struct dxJoint::Vtable __damotor_vtable; | ||
299 | |||
300 | |||
301 | struct dxJointLMotor : public dxJoint { | ||
302 | int num; | ||
303 | int rel[3]; | ||
304 | dVector3 axis[3]; | ||
305 | dxJointLimitMotor limot[3]; | ||
306 | }; | ||
307 | |||
308 | extern struct dxJoint::Vtable __dlmotor_vtable; | ||
309 | |||
310 | |||
311 | // 2d joint, constrains to z == 0 | ||
312 | |||
313 | struct dxJointPlane2D : public dxJoint | ||
314 | { | ||
315 | int row_motor_x; | ||
316 | int row_motor_y; | ||
317 | int row_motor_angle; | ||
318 | dxJointLimitMotor motor_x; | ||
319 | dxJointLimitMotor motor_y; | ||
320 | dxJointLimitMotor motor_angle; | ||
321 | }; | ||
322 | |||
323 | extern struct dxJoint::Vtable __dplane2d_vtable; | ||
324 | |||
325 | |||
326 | // fixed | ||
327 | |||
328 | struct dxJointFixed : public dxJoint { | ||
329 | dQuaternion qrel; // initial relative rotation body1 -> body2 | ||
330 | dVector3 offset; // relative offset between the bodies | ||
331 | dReal erp; // error reduction parameter | ||
332 | dReal cfm; // constraint force mix-in | ||
333 | void set (int num, dReal value); | ||
334 | dReal get (int num); | ||
335 | }; | ||
336 | extern struct dxJoint::Vtable __dfixed_vtable; | ||
337 | |||
338 | |||
339 | // null joint, for testing only | ||
340 | |||
341 | struct dxJointNull : public dxJoint { | ||
342 | }; | ||
343 | extern struct dxJoint::Vtable __dnull_vtable; | ||
344 | |||
345 | |||
346 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/lcp.cpp b/libraries/ode-0.9\/ode/src/lcp.cpp new file mode 100755 index 0000000..d03d3e8 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/lcp.cpp | |||
@@ -0,0 +1,2007 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | |||
26 | THE ALGORITHM | ||
27 | ------------- | ||
28 | |||
29 | solve A*x = b+w, with x and w subject to certain LCP conditions. | ||
30 | each x(i),w(i) must lie on one of the three line segments in the following | ||
31 | diagram. each line segment corresponds to one index set : | ||
32 | |||
33 | w(i) | ||
34 | /|\ | : | ||
35 | | | : | ||
36 | | |i in N : | ||
37 | w>0 | |state[i]=0 : | ||
38 | | | : | ||
39 | | | : i in C | ||
40 | w=0 + +-----------------------+ | ||
41 | | : | | ||
42 | | : | | ||
43 | w<0 | : |i in N | ||
44 | | : |state[i]=1 | ||
45 | | : | | ||
46 | | : | | ||
47 | +-------|-----------|-----------|----------> x(i) | ||
48 | lo 0 hi | ||
49 | |||
50 | the Dantzig algorithm proceeds as follows: | ||
51 | for i=1:n | ||
52 | * if (x(i),w(i)) is not on the line, push x(i) and w(i) positive or | ||
53 | negative towards the line. as this is done, the other (x(j),w(j)) | ||
54 | for j<i are constrained to be on the line. if any (x,w) reaches the | ||
55 | end of a line segment then it is switched between index sets. | ||
56 | * i is added to the appropriate index set depending on what line segment | ||
57 | it hits. | ||
58 | |||
59 | we restrict lo(i) <= 0 and hi(i) >= 0. this makes the algorithm a bit | ||
60 | simpler, because the starting point for x(i),w(i) is always on the dotted | ||
61 | line x=0 and x will only ever increase in one direction, so it can only hit | ||
62 | two out of the three line segments. | ||
63 | |||
64 | |||
65 | NOTES | ||
66 | ----- | ||
67 | |||
68 | this is an implementation of "lcp_dantzig2_ldlt.m" and "lcp_dantzig_lohi.m". | ||
69 | the implementation is split into an LCP problem object (dLCP) and an LCP | ||
70 | driver function. most optimization occurs in the dLCP object. | ||
71 | |||
72 | a naive implementation of the algorithm requires either a lot of data motion | ||
73 | or a lot of permutation-array lookup, because we are constantly re-ordering | ||
74 | rows and columns. to avoid this and make a more optimized algorithm, a | ||
75 | non-trivial data structure is used to represent the matrix A (this is | ||
76 | implemented in the fast version of the dLCP object). | ||
77 | |||
78 | during execution of this algorithm, some indexes in A are clamped (set C), | ||
79 | some are non-clamped (set N), and some are "don't care" (where x=0). | ||
80 | A,x,b,w (and other problem vectors) are permuted such that the clamped | ||
81 | indexes are first, the unclamped indexes are next, and the don't-care | ||
82 | indexes are last. this permutation is recorded in the array `p'. | ||
83 | initially p = 0..n-1, and as the rows and columns of A,x,b,w are swapped, | ||
84 | the corresponding elements of p are swapped. | ||
85 | |||
86 | because the C and N elements are grouped together in the rows of A, we can do | ||
87 | lots of work with a fast dot product function. if A,x,etc were not permuted | ||
88 | and we only had a permutation array, then those dot products would be much | ||
89 | slower as we would have a permutation array lookup in some inner loops. | ||
90 | |||
91 | A is accessed through an array of row pointers, so that element (i,j) of the | ||
92 | permuted matrix is A[i][j]. this makes row swapping fast. for column swapping | ||
93 | we still have to actually move the data. | ||
94 | |||
95 | during execution of this algorithm we maintain an L*D*L' factorization of | ||
96 | the clamped submatrix of A (call it `AC') which is the top left nC*nC | ||
97 | submatrix of A. there are two ways we could arrange the rows/columns in AC. | ||
98 | |||
99 | (1) AC is always permuted such that L*D*L' = AC. this causes a problem | ||
100 | when a row/column is removed from C, because then all the rows/columns of A | ||
101 | between the deleted index and the end of C need to be rotated downward. | ||
102 | this results in a lot of data motion and slows things down. | ||
103 | (2) L*D*L' is actually a factorization of a *permutation* of AC (which is | ||
104 | itself a permutation of the underlying A). this is what we do - the | ||
105 | permutation is recorded in the vector C. call this permutation A[C,C]. | ||
106 | when a row/column is removed from C, all we have to do is swap two | ||
107 | rows/columns and manipulate C. | ||
108 | |||
109 | */ | ||
110 | |||
111 | #include <ode/common.h> | ||
112 | #include "lcp.h" | ||
113 | #include <ode/matrix.h> | ||
114 | #include <ode/misc.h> | ||
115 | #include "mat.h" // for testing | ||
116 | #include <ode/timer.h> // for testing | ||
117 | |||
118 | //*************************************************************************** | ||
119 | // code generation parameters | ||
120 | |||
121 | // LCP debugging (mosty for fast dLCP) - this slows things down a lot | ||
122 | //#define DEBUG_LCP | ||
123 | |||
124 | //#define dLCP_SLOW // use slow dLCP object | ||
125 | #define dLCP_FAST // use fast dLCP object | ||
126 | |||
127 | // option 1 : matrix row pointers (less data copying) | ||
128 | #define ROWPTRS | ||
129 | #define ATYPE dReal ** | ||
130 | #define AROW(i) (A[i]) | ||
131 | |||
132 | // option 2 : no matrix row pointers (slightly faster inner loops) | ||
133 | //#define NOROWPTRS | ||
134 | //#define ATYPE dReal * | ||
135 | //#define AROW(i) (A+(i)*nskip) | ||
136 | |||
137 | // use protected, non-stack memory allocation system | ||
138 | |||
139 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
140 | extern unsigned int dMemoryFlag; | ||
141 | |||
142 | #define ALLOCA(t,v,s) t* v = (t*) malloc(s) | ||
143 | #define UNALLOCA(t) free(t) | ||
144 | |||
145 | #else | ||
146 | |||
147 | #define ALLOCA(t,v,s) t* v =(t*)dALLOCA16(s) | ||
148 | #define UNALLOCA(t) /* nothing */ | ||
149 | |||
150 | #endif | ||
151 | |||
152 | #define NUB_OPTIMIZATIONS | ||
153 | |||
154 | //*************************************************************************** | ||
155 | |||
156 | // swap row/column i1 with i2 in the n*n matrix A. the leading dimension of | ||
157 | // A is nskip. this only references and swaps the lower triangle. | ||
158 | // if `do_fast_row_swaps' is nonzero and row pointers are being used, then | ||
159 | // rows will be swapped by exchanging row pointers. otherwise the data will | ||
160 | // be copied. | ||
161 | |||
162 | static void swapRowsAndCols (ATYPE A, int n, int i1, int i2, int nskip, | ||
163 | int do_fast_row_swaps) | ||
164 | { | ||
165 | int i; | ||
166 | dAASSERT (A && n > 0 && i1 >= 0 && i2 >= 0 && i1 < n && i2 < n && | ||
167 | nskip >= n && i1 < i2); | ||
168 | |||
169 | # ifdef ROWPTRS | ||
170 | for (i=i1+1; i<i2; i++) A[i1][i] = A[i][i1]; | ||
171 | for (i=i1+1; i<i2; i++) A[i][i1] = A[i2][i]; | ||
172 | A[i1][i2] = A[i1][i1]; | ||
173 | A[i1][i1] = A[i2][i1]; | ||
174 | A[i2][i1] = A[i2][i2]; | ||
175 | // swap rows, by swapping row pointers | ||
176 | if (do_fast_row_swaps) { | ||
177 | dReal *tmpp; | ||
178 | tmpp = A[i1]; | ||
179 | A[i1] = A[i2]; | ||
180 | A[i2] = tmpp; | ||
181 | } | ||
182 | else { | ||
183 | ALLOCA (dReal,tmprow,n * sizeof(dReal)); | ||
184 | |||
185 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
186 | if (tmprow == NULL) { | ||
187 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
188 | return; | ||
189 | } | ||
190 | #endif | ||
191 | |||
192 | memcpy (tmprow,A[i1],n * sizeof(dReal)); | ||
193 | memcpy (A[i1],A[i2],n * sizeof(dReal)); | ||
194 | memcpy (A[i2],tmprow,n * sizeof(dReal)); | ||
195 | UNALLOCA(tmprow); | ||
196 | } | ||
197 | // swap columns the hard way | ||
198 | for (i=i2+1; i<n; i++) { | ||
199 | dReal tmp = A[i][i1]; | ||
200 | A[i][i1] = A[i][i2]; | ||
201 | A[i][i2] = tmp; | ||
202 | } | ||
203 | # else | ||
204 | dReal tmp; | ||
205 | ALLOCA (dReal,tmprow,n * sizeof(dReal)); | ||
206 | |||
207 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
208 | if (tmprow == NULL) { | ||
209 | return; | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | if (i1 > 0) { | ||
214 | memcpy (tmprow,A+i1*nskip,i1*sizeof(dReal)); | ||
215 | memcpy (A+i1*nskip,A+i2*nskip,i1*sizeof(dReal)); | ||
216 | memcpy (A+i2*nskip,tmprow,i1*sizeof(dReal)); | ||
217 | } | ||
218 | for (i=i1+1; i<i2; i++) { | ||
219 | tmp = A[i2*nskip+i]; | ||
220 | A[i2*nskip+i] = A[i*nskip+i1]; | ||
221 | A[i*nskip+i1] = tmp; | ||
222 | } | ||
223 | tmp = A[i1*nskip+i1]; | ||
224 | A[i1*nskip+i1] = A[i2*nskip+i2]; | ||
225 | A[i2*nskip+i2] = tmp; | ||
226 | for (i=i2+1; i<n; i++) { | ||
227 | tmp = A[i*nskip+i1]; | ||
228 | A[i*nskip+i1] = A[i*nskip+i2]; | ||
229 | A[i*nskip+i2] = tmp; | ||
230 | } | ||
231 | UNALLOCA(tmprow); | ||
232 | # endif | ||
233 | |||
234 | } | ||
235 | |||
236 | |||
237 | // swap two indexes in the n*n LCP problem. i1 must be <= i2. | ||
238 | |||
239 | static void swapProblem (ATYPE A, dReal *x, dReal *b, dReal *w, dReal *lo, | ||
240 | dReal *hi, int *p, int *state, int *findex, | ||
241 | int n, int i1, int i2, int nskip, | ||
242 | int do_fast_row_swaps) | ||
243 | { | ||
244 | dReal tmp; | ||
245 | int tmpi; | ||
246 | dIASSERT (n>0 && i1 >=0 && i2 >= 0 && i1 < n && i2 < n && nskip >= n && | ||
247 | i1 <= i2); | ||
248 | if (i1==i2) return; | ||
249 | swapRowsAndCols (A,n,i1,i2,nskip,do_fast_row_swaps); | ||
250 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
251 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) | ||
252 | return; | ||
253 | #endif | ||
254 | tmp = x[i1]; | ||
255 | x[i1] = x[i2]; | ||
256 | x[i2] = tmp; | ||
257 | tmp = b[i1]; | ||
258 | b[i1] = b[i2]; | ||
259 | b[i2] = tmp; | ||
260 | tmp = w[i1]; | ||
261 | w[i1] = w[i2]; | ||
262 | w[i2] = tmp; | ||
263 | tmp = lo[i1]; | ||
264 | lo[i1] = lo[i2]; | ||
265 | lo[i2] = tmp; | ||
266 | tmp = hi[i1]; | ||
267 | hi[i1] = hi[i2]; | ||
268 | hi[i2] = tmp; | ||
269 | tmpi = p[i1]; | ||
270 | p[i1] = p[i2]; | ||
271 | p[i2] = tmpi; | ||
272 | tmpi = state[i1]; | ||
273 | state[i1] = state[i2]; | ||
274 | state[i2] = tmpi; | ||
275 | if (findex) { | ||
276 | tmpi = findex[i1]; | ||
277 | findex[i1] = findex[i2]; | ||
278 | findex[i2] = tmpi; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | |||
283 | // for debugging - check that L,d is the factorization of A[C,C]. | ||
284 | // A[C,C] has size nC*nC and leading dimension nskip. | ||
285 | // L has size nC*nC and leading dimension nskip. | ||
286 | // d has size nC. | ||
287 | |||
288 | #ifdef DEBUG_LCP | ||
289 | |||
290 | static void checkFactorization (ATYPE A, dReal *_L, dReal *_d, | ||
291 | int nC, int *C, int nskip) | ||
292 | { | ||
293 | int i,j; | ||
294 | if (nC==0) return; | ||
295 | |||
296 | // get A1=A, copy the lower triangle to the upper triangle, get A2=A[C,C] | ||
297 | dMatrix A1 (nC,nC); | ||
298 | for (i=0; i<nC; i++) { | ||
299 | for (j=0; j<=i; j++) A1(i,j) = A1(j,i) = AROW(i)[j]; | ||
300 | } | ||
301 | dMatrix A2 = A1.select (nC,C,nC,C); | ||
302 | |||
303 | // printf ("A1=\n"); A1.print(); printf ("\n"); | ||
304 | // printf ("A2=\n"); A2.print(); printf ("\n"); | ||
305 | |||
306 | // compute A3 = L*D*L' | ||
307 | dMatrix L (nC,nC,_L,nskip,1); | ||
308 | dMatrix D (nC,nC); | ||
309 | for (i=0; i<nC; i++) D(i,i) = 1/_d[i]; | ||
310 | L.clearUpperTriangle(); | ||
311 | for (i=0; i<nC; i++) L(i,i) = 1; | ||
312 | dMatrix A3 = L * D * L.transpose(); | ||
313 | |||
314 | // printf ("L=\n"); L.print(); printf ("\n"); | ||
315 | // printf ("D=\n"); D.print(); printf ("\n"); | ||
316 | // printf ("A3=\n"); A2.print(); printf ("\n"); | ||
317 | |||
318 | // compare A2 and A3 | ||
319 | dReal diff = A2.maxDifference (A3); | ||
320 | if (diff > 1e-8) | ||
321 | dDebug (0,"L*D*L' check, maximum difference = %.6e\n",diff); | ||
322 | } | ||
323 | |||
324 | #endif | ||
325 | |||
326 | |||
327 | // for debugging | ||
328 | |||
329 | #ifdef DEBUG_LCP | ||
330 | |||
331 | static void checkPermutations (int i, int n, int nC, int nN, int *p, int *C) | ||
332 | { | ||
333 | int j,k; | ||
334 | dIASSERT (nC>=0 && nN>=0 && (nC+nN)==i && i < n); | ||
335 | for (k=0; k<i; k++) dIASSERT (p[k] >= 0 && p[k] < i); | ||
336 | for (k=i; k<n; k++) dIASSERT (p[k] == k); | ||
337 | for (j=0; j<nC; j++) { | ||
338 | int C_is_bad = 1; | ||
339 | for (k=0; k<nC; k++) if (C[k]==j) C_is_bad = 0; | ||
340 | dIASSERT (C_is_bad==0); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | #endif | ||
345 | |||
346 | //*************************************************************************** | ||
347 | // dLCP manipulator object. this represents an n*n LCP problem. | ||
348 | // | ||
349 | // two index sets C and N are kept. each set holds a subset of | ||
350 | // the variable indexes 0..n-1. an index can only be in one set. | ||
351 | // initially both sets are empty. | ||
352 | // | ||
353 | // the index set C is special: solutions to A(C,C)\A(C,i) can be generated. | ||
354 | |||
355 | #ifdef dLCP_SLOW | ||
356 | |||
357 | // simple but slow implementation of dLCP, for testing the LCP drivers. | ||
358 | |||
359 | #include "array.h" | ||
360 | |||
361 | struct dLCP { | ||
362 | int n,nub,nskip; | ||
363 | dReal *Adata,*x,*b,*w,*lo,*hi; // LCP problem data | ||
364 | ATYPE A; // A rows | ||
365 | dArray<int> C,N; // index sets | ||
366 | int last_i_for_solve1; // last i value given to solve1 | ||
367 | |||
368 | dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, | ||
369 | dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, | ||
370 | dReal *_Dell, dReal *_ell, dReal *_tmp, | ||
371 | int *_state, int *_findex, int *_p, int *_C, dReal **Arows); | ||
372 | // the constructor is given an initial problem description (A,x,b,w) and | ||
373 | // space for other working data (which the caller may allocate on the stack). | ||
374 | // some of this data is specific to the fast dLCP implementation. | ||
375 | // the matrices A and L have size n*n, vectors have size n*1. | ||
376 | // A represents a symmetric matrix but only the lower triangle is valid. | ||
377 | // `nub' is the number of unbounded indexes at the start. all the indexes | ||
378 | // 0..nub-1 will be put into C. | ||
379 | |||
380 | ~dLCP(); | ||
381 | |||
382 | int getNub() { return nub; } | ||
383 | // return the value of `nub'. the constructor may want to change it, | ||
384 | // so the caller should find out its new value. | ||
385 | |||
386 | // transfer functions: transfer index i to the given set (C or N). indexes | ||
387 | // less than `nub' can never be given. A,x,b,w,etc may be permuted by these | ||
388 | // functions, the caller must be robust to this. | ||
389 | |||
390 | void transfer_i_to_C (int i); | ||
391 | // this assumes C and N span 1:i-1. this also assumes that solve1() has | ||
392 | // been recently called for the same i without any other transfer | ||
393 | // functions in between (thereby allowing some data reuse for the fast | ||
394 | // implementation). | ||
395 | void transfer_i_to_N (int i); | ||
396 | // this assumes C and N span 1:i-1. | ||
397 | void transfer_i_from_N_to_C (int i); | ||
398 | void transfer_i_from_C_to_N (int i); | ||
399 | |||
400 | int numC(); | ||
401 | int numN(); | ||
402 | // return the number of indexes in set C/N | ||
403 | |||
404 | int indexC (int i); | ||
405 | int indexN (int i); | ||
406 | // return index i in set C/N. | ||
407 | |||
408 | // accessor and arithmetic functions. Aij translates as A(i,j), etc. | ||
409 | // make sure that only the lower triangle of A is ever referenced. | ||
410 | |||
411 | dReal Aii (int i); | ||
412 | dReal AiC_times_qC (int i, dReal *q); | ||
413 | dReal AiN_times_qN (int i, dReal *q); // for all Nj | ||
414 | void pN_equals_ANC_times_qC (dReal *p, dReal *q); // for all Nj | ||
415 | void pN_plusequals_ANi (dReal *p, int i, int sign=1); | ||
416 | // for all Nj. sign = +1,-1. assumes i > maximum index in N. | ||
417 | void pC_plusequals_s_times_qC (dReal *p, dReal s, dReal *q); | ||
418 | void pN_plusequals_s_times_qN (dReal *p, dReal s, dReal *q); // for all Nj | ||
419 | void solve1 (dReal *a, int i, int dir=1, int only_transfer=0); | ||
420 | // get a(C) = - dir * A(C,C) \ A(C,i). dir must be +/- 1. | ||
421 | // the fast version of this function computes some data that is needed by | ||
422 | // transfer_i_to_C(). if only_transfer is nonzero then this function | ||
423 | // *only* computes that data, it does not set a(C). | ||
424 | |||
425 | void unpermute(); | ||
426 | // call this at the end of the LCP function. if the x/w values have been | ||
427 | // permuted then this will unscramble them. | ||
428 | }; | ||
429 | |||
430 | |||
431 | dLCP::dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, | ||
432 | dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, | ||
433 | dReal *_Dell, dReal *_ell, dReal *_tmp, | ||
434 | int *_state, int *_findex, int *_p, int *_C, dReal **Arows) | ||
435 | { | ||
436 | dUASSERT (_findex==0,"slow dLCP object does not support findex array"); | ||
437 | |||
438 | n = _n; | ||
439 | nub = _nub; | ||
440 | Adata = _Adata; | ||
441 | A = 0; | ||
442 | x = _x; | ||
443 | b = _b; | ||
444 | w = _w; | ||
445 | lo = _lo; | ||
446 | hi = _hi; | ||
447 | nskip = dPAD(n); | ||
448 | dSetZero (x,n); | ||
449 | last_i_for_solve1 = -1; | ||
450 | |||
451 | int i,j; | ||
452 | C.setSize (n); | ||
453 | N.setSize (n); | ||
454 | for (i=0; i<n; i++) { | ||
455 | C[i] = 0; | ||
456 | N[i] = 0; | ||
457 | } | ||
458 | |||
459 | # ifdef ROWPTRS | ||
460 | // make matrix row pointers | ||
461 | A = Arows; | ||
462 | for (i=0; i<n; i++) A[i] = Adata + i*nskip; | ||
463 | # else | ||
464 | A = Adata; | ||
465 | # endif | ||
466 | |||
467 | // lets make A symmetric | ||
468 | for (i=0; i<n; i++) { | ||
469 | for (j=i+1; j<n; j++) AROW(i)[j] = AROW(j)[i]; | ||
470 | } | ||
471 | |||
472 | // if nub>0, put all indexes 0..nub-1 into C and solve for x | ||
473 | if (nub > 0) { | ||
474 | for (i=0; i<nub; i++) memcpy (_L+i*nskip,AROW(i),(i+1)*sizeof(dReal)); | ||
475 | dFactorLDLT (_L,_d,nub,nskip); | ||
476 | memcpy (x,b,nub*sizeof(dReal)); | ||
477 | dSolveLDLT (_L,_d,x,nub,nskip); | ||
478 | dSetZero (_w,nub); | ||
479 | for (i=0; i<nub; i++) C[i] = 1; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | |||
484 | dLCP::~dLCP() | ||
485 | { | ||
486 | } | ||
487 | |||
488 | |||
489 | void dLCP::transfer_i_to_C (int i) | ||
490 | { | ||
491 | if (i < nub) dDebug (0,"bad i"); | ||
492 | if (C[i]) dDebug (0,"i already in C"); | ||
493 | if (N[i]) dDebug (0,"i already in N"); | ||
494 | for (int k=0; k<i; k++) { | ||
495 | if (!(C[k] ^ N[k])) dDebug (0,"assumptions for C and N violated"); | ||
496 | } | ||
497 | for (int k=i; k<n; k++) | ||
498 | if (C[k] || N[k]) dDebug (0,"assumptions for C and N violated"); | ||
499 | if (i != last_i_for_solve1) dDebug (0,"assumptions for i violated"); | ||
500 | last_i_for_solve1 = -1; | ||
501 | C[i] = 1; | ||
502 | } | ||
503 | |||
504 | |||
505 | void dLCP::transfer_i_to_N (int i) | ||
506 | { | ||
507 | if (i < nub) dDebug (0,"bad i"); | ||
508 | if (C[i]) dDebug (0,"i already in C"); | ||
509 | if (N[i]) dDebug (0,"i already in N"); | ||
510 | for (int k=0; k<i; k++) | ||
511 | if (!C[k] && !N[k]) dDebug (0,"assumptions for C and N violated"); | ||
512 | for (int k=i; k<n; k++) | ||
513 | if (C[k] || N[k]) dDebug (0,"assumptions for C and N violated"); | ||
514 | last_i_for_solve1 = -1; | ||
515 | N[i] = 1; | ||
516 | } | ||
517 | |||
518 | |||
519 | void dLCP::transfer_i_from_N_to_C (int i) | ||
520 | { | ||
521 | if (i < nub) dDebug (0,"bad i"); | ||
522 | if (C[i]) dDebug (0,"i already in C"); | ||
523 | if (!N[i]) dDebug (0,"i not in N"); | ||
524 | last_i_for_solve1 = -1; | ||
525 | N[i] = 0; | ||
526 | C[i] = 1; | ||
527 | } | ||
528 | |||
529 | |||
530 | void dLCP::transfer_i_from_C_to_N (int i) | ||
531 | { | ||
532 | if (i < nub) dDebug (0,"bad i"); | ||
533 | if (N[i]) dDebug (0,"i already in N"); | ||
534 | if (!C[i]) dDebug (0,"i not in C"); | ||
535 | last_i_for_solve1 = -1; | ||
536 | C[i] = 0; | ||
537 | N[i] = 1; | ||
538 | } | ||
539 | |||
540 | |||
541 | int dLCP::numC() | ||
542 | { | ||
543 | int i,count=0; | ||
544 | for (i=0; i<n; i++) if (C[i]) count++; | ||
545 | return count; | ||
546 | } | ||
547 | |||
548 | |||
549 | int dLCP::numN() | ||
550 | { | ||
551 | int i,count=0; | ||
552 | for (i=0; i<n; i++) if (N[i]) count++; | ||
553 | return count; | ||
554 | } | ||
555 | |||
556 | |||
557 | int dLCP::indexC (int i) | ||
558 | { | ||
559 | int k,count=0; | ||
560 | for (k=0; k<n; k++) { | ||
561 | if (C[k]) { | ||
562 | if (count==i) return k; | ||
563 | count++; | ||
564 | } | ||
565 | } | ||
566 | dDebug (0,"bad index C (%d)",i); | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | |||
571 | int dLCP::indexN (int i) | ||
572 | { | ||
573 | int k,count=0; | ||
574 | for (k=0; k<n; k++) { | ||
575 | if (N[k]) { | ||
576 | if (count==i) return k; | ||
577 | count++; | ||
578 | } | ||
579 | } | ||
580 | dDebug (0,"bad index into N"); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | |||
585 | dReal dLCP::Aii (int i) | ||
586 | { | ||
587 | return AROW(i)[i]; | ||
588 | } | ||
589 | |||
590 | |||
591 | dReal dLCP::AiC_times_qC (int i, dReal *q) | ||
592 | { | ||
593 | dReal sum = 0; | ||
594 | for (int k=0; k<n; k++) if (C[k]) sum += AROW(i)[k] * q[k]; | ||
595 | return sum; | ||
596 | } | ||
597 | |||
598 | |||
599 | dReal dLCP::AiN_times_qN (int i, dReal *q) | ||
600 | { | ||
601 | dReal sum = 0; | ||
602 | for (int k=0; k<n; k++) if (N[k]) sum += AROW(i)[k] * q[k]; | ||
603 | return sum; | ||
604 | } | ||
605 | |||
606 | |||
607 | void dLCP::pN_equals_ANC_times_qC (dReal *p, dReal *q) | ||
608 | { | ||
609 | dReal sum; | ||
610 | for (int ii=0; ii<n; ii++) if (N[ii]) { | ||
611 | sum = 0; | ||
612 | for (int jj=0; jj<n; jj++) if (C[jj]) sum += AROW(ii)[jj] * q[jj]; | ||
613 | p[ii] = sum; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | |||
618 | void dLCP::pN_plusequals_ANi (dReal *p, int i, int sign) | ||
619 | { | ||
620 | int k; | ||
621 | for (k=0; k<n; k++) if (N[k] && k >= i) dDebug (0,"N assumption violated"); | ||
622 | if (sign > 0) { | ||
623 | for (k=0; k<n; k++) if (N[k]) p[k] += AROW(i)[k]; | ||
624 | } | ||
625 | else { | ||
626 | for (k=0; k<n; k++) if (N[k]) p[k] -= AROW(i)[k]; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | |||
631 | void dLCP::pC_plusequals_s_times_qC (dReal *p, dReal s, dReal *q) | ||
632 | { | ||
633 | for (int k=0; k<n; k++) if (C[k]) p[k] += s*q[k]; | ||
634 | } | ||
635 | |||
636 | |||
637 | void dLCP::pN_plusequals_s_times_qN (dReal *p, dReal s, dReal *q) | ||
638 | { | ||
639 | for (int k=0; k<n; k++) if (N[k]) p[k] += s*q[k]; | ||
640 | } | ||
641 | |||
642 | |||
643 | void dLCP::solve1 (dReal *a, int i, int dir, int only_transfer) | ||
644 | { | ||
645 | |||
646 | ALLOCA (dReal,AA,n*nskip*sizeof(dReal)); | ||
647 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
648 | if (AA == NULL) { | ||
649 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
650 | return; | ||
651 | } | ||
652 | #endif | ||
653 | ALLOCA (dReal,dd,n*sizeof(dReal)); | ||
654 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
655 | if (dd == NULL) { | ||
656 | UNALLOCA(AA); | ||
657 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
658 | return; | ||
659 | } | ||
660 | #endif | ||
661 | ALLOCA (dReal,bb,n*sizeof(dReal)); | ||
662 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
663 | if (bb == NULL) { | ||
664 | UNALLOCA(AA); | ||
665 | UNALLOCA(dd); | ||
666 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
667 | return; | ||
668 | } | ||
669 | #endif | ||
670 | |||
671 | int ii,jj,AAi,AAj; | ||
672 | |||
673 | last_i_for_solve1 = i; | ||
674 | AAi = 0; | ||
675 | for (ii=0; ii<n; ii++) if (C[ii]) { | ||
676 | AAj = 0; | ||
677 | for (jj=0; jj<n; jj++) if (C[jj]) { | ||
678 | AA[AAi*nskip+AAj] = AROW(ii)[jj]; | ||
679 | AAj++; | ||
680 | } | ||
681 | bb[AAi] = AROW(i)[ii]; | ||
682 | AAi++; | ||
683 | } | ||
684 | if (AAi==0) { | ||
685 | UNALLOCA (AA); | ||
686 | UNALLOCA (dd); | ||
687 | UNALLOCA (bb); | ||
688 | return; | ||
689 | } | ||
690 | |||
691 | dFactorLDLT (AA,dd,AAi,nskip); | ||
692 | dSolveLDLT (AA,dd,bb,AAi,nskip); | ||
693 | |||
694 | AAi=0; | ||
695 | if (dir > 0) { | ||
696 | for (ii=0; ii<n; ii++) if (C[ii]) a[ii] = -bb[AAi++]; | ||
697 | } | ||
698 | else { | ||
699 | for (ii=0; ii<n; ii++) if (C[ii]) a[ii] = bb[AAi++]; | ||
700 | } | ||
701 | |||
702 | UNALLOCA (AA); | ||
703 | UNALLOCA (dd); | ||
704 | UNALLOCA (bb); | ||
705 | } | ||
706 | |||
707 | |||
708 | void dLCP::unpermute() | ||
709 | { | ||
710 | } | ||
711 | |||
712 | #endif // dLCP_SLOW | ||
713 | |||
714 | //*************************************************************************** | ||
715 | // fast implementation of dLCP. see the above definition of dLCP for | ||
716 | // interface comments. | ||
717 | // | ||
718 | // `p' records the permutation of A,x,b,w,etc. p is initially 1:n and is | ||
719 | // permuted as the other vectors/matrices are permuted. | ||
720 | // | ||
721 | // A,x,b,w,lo,hi,state,findex,p,c are permuted such that sets C,N have | ||
722 | // contiguous indexes. the don't-care indexes follow N. | ||
723 | // | ||
724 | // an L*D*L' factorization is maintained of A(C,C), and whenever indexes are | ||
725 | // added or removed from the set C the factorization is updated. | ||
726 | // thus L*D*L'=A[C,C], i.e. a permuted top left nC*nC submatrix of A. | ||
727 | // the leading dimension of the matrix L is always `nskip'. | ||
728 | // | ||
729 | // at the start there may be other indexes that are unbounded but are not | ||
730 | // included in `nub'. dLCP will permute the matrix so that absolutely all | ||
731 | // unbounded vectors are at the start. thus there may be some initial | ||
732 | // permutation. | ||
733 | // | ||
734 | // the algorithms here assume certain patterns, particularly with respect to | ||
735 | // index transfer. | ||
736 | |||
737 | #ifdef dLCP_FAST | ||
738 | |||
739 | struct dLCP { | ||
740 | int n,nskip,nub; | ||
741 | ATYPE A; // A rows | ||
742 | dReal *Adata,*x,*b,*w,*lo,*hi; // permuted LCP problem data | ||
743 | dReal *L,*d; // L*D*L' factorization of set C | ||
744 | dReal *Dell,*ell,*tmp; | ||
745 | int *state,*findex,*p,*C; | ||
746 | int nC,nN; // size of each index set | ||
747 | |||
748 | dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, | ||
749 | dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, | ||
750 | dReal *_Dell, dReal *_ell, dReal *_tmp, | ||
751 | int *_state, int *_findex, int *_p, int *_C, dReal **Arows); | ||
752 | int getNub() { return nub; } | ||
753 | void transfer_i_to_C (int i); | ||
754 | void transfer_i_to_N (int i) | ||
755 | { nN++; } // because we can assume C and N span 1:i-1 | ||
756 | void transfer_i_from_N_to_C (int i); | ||
757 | void transfer_i_from_C_to_N (int i); | ||
758 | int numC() { return nC; } | ||
759 | int numN() { return nN; } | ||
760 | int indexC (int i) { return i; } | ||
761 | int indexN (int i) { return i+nC; } | ||
762 | dReal Aii (int i) { return AROW(i)[i]; } | ||
763 | dReal AiC_times_qC (int i, dReal *q) { return dDot (AROW(i),q,nC); } | ||
764 | dReal AiN_times_qN (int i, dReal *q) { return dDot (AROW(i)+nC,q+nC,nN); } | ||
765 | void pN_equals_ANC_times_qC (dReal *p, dReal *q); | ||
766 | void pN_plusequals_ANi (dReal *p, int i, int sign=1); | ||
767 | void pC_plusequals_s_times_qC (dReal *p, dReal s, dReal *q) | ||
768 | { for (int i=0; i<nC; i++) p[i] += s*q[i]; } | ||
769 | void pN_plusequals_s_times_qN (dReal *p, dReal s, dReal *q) | ||
770 | { for (int i=0; i<nN; i++) p[i+nC] += s*q[i+nC]; } | ||
771 | void solve1 (dReal *a, int i, int dir=1, int only_transfer=0); | ||
772 | void unpermute(); | ||
773 | }; | ||
774 | |||
775 | |||
776 | dLCP::dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, | ||
777 | dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, | ||
778 | dReal *_Dell, dReal *_ell, dReal *_tmp, | ||
779 | int *_state, int *_findex, int *_p, int *_C, dReal **Arows) | ||
780 | { | ||
781 | n = _n; | ||
782 | nub = _nub; | ||
783 | Adata = _Adata; | ||
784 | A = 0; | ||
785 | x = _x; | ||
786 | b = _b; | ||
787 | w = _w; | ||
788 | lo = _lo; | ||
789 | hi = _hi; | ||
790 | L = _L; | ||
791 | d = _d; | ||
792 | Dell = _Dell; | ||
793 | ell = _ell; | ||
794 | tmp = _tmp; | ||
795 | state = _state; | ||
796 | findex = _findex; | ||
797 | p = _p; | ||
798 | C = _C; | ||
799 | nskip = dPAD(n); | ||
800 | dSetZero (x,n); | ||
801 | |||
802 | int k; | ||
803 | |||
804 | # ifdef ROWPTRS | ||
805 | // make matrix row pointers | ||
806 | A = Arows; | ||
807 | for (k=0; k<n; k++) A[k] = Adata + k*nskip; | ||
808 | # else | ||
809 | A = Adata; | ||
810 | # endif | ||
811 | |||
812 | nC = 0; | ||
813 | nN = 0; | ||
814 | for (k=0; k<n; k++) p[k]=k; // initially unpermuted | ||
815 | |||
816 | /* | ||
817 | // for testing, we can do some random swaps in the area i > nub | ||
818 | if (nub < n) { | ||
819 | for (k=0; k<100; k++) { | ||
820 | int i1,i2; | ||
821 | do { | ||
822 | i1 = dRandInt(n-nub)+nub; | ||
823 | i2 = dRandInt(n-nub)+nub; | ||
824 | } | ||
825 | while (i1 > i2); | ||
826 | //printf ("--> %d %d\n",i1,i2); | ||
827 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,i1,i2,nskip,0); | ||
828 | } | ||
829 | } | ||
830 | */ | ||
831 | |||
832 | // permute the problem so that *all* the unbounded variables are at the | ||
833 | // start, i.e. look for unbounded variables not included in `nub'. we can | ||
834 | // potentially push up `nub' this way and get a bigger initial factorization. | ||
835 | // note that when we swap rows/cols here we must not just swap row pointers, | ||
836 | // as the initial factorization relies on the data being all in one chunk. | ||
837 | // variables that have findex >= 0 are *not* considered to be unbounded even | ||
838 | // if lo=-inf and hi=inf - this is because these limits may change during the | ||
839 | // solution process. | ||
840 | |||
841 | for (k=nub; k<n; k++) { | ||
842 | if (findex && findex[k] >= 0) continue; | ||
843 | if (lo[k]==-dInfinity && hi[k]==dInfinity) { | ||
844 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,nub,k,nskip,0); | ||
845 | nub++; | ||
846 | } | ||
847 | } | ||
848 | |||
849 | // if there are unbounded variables at the start, factorize A up to that | ||
850 | // point and solve for x. this puts all indexes 0..nub-1 into C. | ||
851 | if (nub > 0) { | ||
852 | for (k=0; k<nub; k++) memcpy (L+k*nskip,AROW(k),(k+1)*sizeof(dReal)); | ||
853 | dFactorLDLT (L,d,nub,nskip); | ||
854 | memcpy (x,b,nub*sizeof(dReal)); | ||
855 | dSolveLDLT (L,d,x,nub,nskip); | ||
856 | dSetZero (w,nub); | ||
857 | for (k=0; k<nub; k++) C[k] = k; | ||
858 | nC = nub; | ||
859 | } | ||
860 | |||
861 | // permute the indexes > nub such that all findex variables are at the end | ||
862 | if (findex) { | ||
863 | int num_at_end = 0; | ||
864 | for (k=n-1; k >= nub; k--) { | ||
865 | if (findex[k] >= 0) { | ||
866 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,k,n-1-num_at_end,nskip,1); | ||
867 | num_at_end++; | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | |||
872 | // print info about indexes | ||
873 | /* | ||
874 | for (k=0; k<n; k++) { | ||
875 | if (k<nub) printf ("C"); | ||
876 | else if (lo[k]==-dInfinity && hi[k]==dInfinity) printf ("c"); | ||
877 | else printf ("."); | ||
878 | } | ||
879 | printf ("\n"); | ||
880 | */ | ||
881 | } | ||
882 | |||
883 | |||
884 | void dLCP::transfer_i_to_C (int i) | ||
885 | { | ||
886 | int j; | ||
887 | if (nC > 0) { | ||
888 | // ell,Dell were computed by solve1(). note, ell = D \ L1solve (L,A(i,C)) | ||
889 | for (j=0; j<nC; j++) L[nC*nskip+j] = ell[j]; | ||
890 | d[nC] = dRecip (AROW(i)[i] - dDot(ell,Dell,nC)); | ||
891 | } | ||
892 | else { | ||
893 | d[0] = dRecip (AROW(i)[i]); | ||
894 | } | ||
895 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,nC,i,nskip,1); | ||
896 | C[nC] = nC; | ||
897 | nC++; | ||
898 | |||
899 | # ifdef DEBUG_LCP | ||
900 | checkFactorization (A,L,d,nC,C,nskip); | ||
901 | if (i < (n-1)) checkPermutations (i+1,n,nC,nN,p,C); | ||
902 | # endif | ||
903 | } | ||
904 | |||
905 | |||
906 | void dLCP::transfer_i_from_N_to_C (int i) | ||
907 | { | ||
908 | int j; | ||
909 | if (nC > 0) { | ||
910 | dReal *aptr = AROW(i); | ||
911 | # ifdef NUB_OPTIMIZATIONS | ||
912 | // if nub>0, initial part of aptr unpermuted | ||
913 | for (j=0; j<nub; j++) Dell[j] = aptr[j]; | ||
914 | for (j=nub; j<nC; j++) Dell[j] = aptr[C[j]]; | ||
915 | # else | ||
916 | for (j=0; j<nC; j++) Dell[j] = aptr[C[j]]; | ||
917 | # endif | ||
918 | dSolveL1 (L,Dell,nC,nskip); | ||
919 | for (j=0; j<nC; j++) ell[j] = Dell[j] * d[j]; | ||
920 | for (j=0; j<nC; j++) L[nC*nskip+j] = ell[j]; | ||
921 | d[nC] = dRecip (AROW(i)[i] - dDot(ell,Dell,nC)); | ||
922 | } | ||
923 | else { | ||
924 | d[0] = dRecip (AROW(i)[i]); | ||
925 | } | ||
926 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,nC,i,nskip,1); | ||
927 | C[nC] = nC; | ||
928 | nN--; | ||
929 | nC++; | ||
930 | |||
931 | // @@@ TO DO LATER | ||
932 | // if we just finish here then we'll go back and re-solve for | ||
933 | // delta_x. but actually we can be more efficient and incrementally | ||
934 | // update delta_x here. but if we do this, we wont have ell and Dell | ||
935 | // to use in updating the factorization later. | ||
936 | |||
937 | # ifdef DEBUG_LCP | ||
938 | checkFactorization (A,L,d,nC,C,nskip); | ||
939 | # endif | ||
940 | } | ||
941 | |||
942 | |||
943 | void dLCP::transfer_i_from_C_to_N (int i) | ||
944 | { | ||
945 | // remove a row/column from the factorization, and adjust the | ||
946 | // indexes (black magic!) | ||
947 | int j,k; | ||
948 | for (j=0; j<nC; j++) if (C[j]==i) { | ||
949 | dLDLTRemove (A,C,L,d,n,nC,j,nskip); | ||
950 | for (k=0; k<nC; k++) if (C[k]==nC-1) { | ||
951 | C[k] = C[j]; | ||
952 | if (j < (nC-1)) memmove (C+j,C+j+1,(nC-j-1)*sizeof(int)); | ||
953 | break; | ||
954 | } | ||
955 | dIASSERT (k < nC); | ||
956 | break; | ||
957 | } | ||
958 | dIASSERT (j < nC); | ||
959 | swapProblem (A,x,b,w,lo,hi,p,state,findex,n,i,nC-1,nskip,1); | ||
960 | nC--; | ||
961 | nN++; | ||
962 | |||
963 | # ifdef DEBUG_LCP | ||
964 | checkFactorization (A,L,d,nC,C,nskip); | ||
965 | # endif | ||
966 | } | ||
967 | |||
968 | |||
969 | void dLCP::pN_equals_ANC_times_qC (dReal *p, dReal *q) | ||
970 | { | ||
971 | // we could try to make this matrix-vector multiplication faster using | ||
972 | // outer product matrix tricks, e.g. with the dMultidotX() functions. | ||
973 | // but i tried it and it actually made things slower on random 100x100 | ||
974 | // problems because of the overhead involved. so we'll stick with the | ||
975 | // simple method for now. | ||
976 | for (int i=0; i<nN; i++) p[i+nC] = dDot (AROW(i+nC),q,nC); | ||
977 | } | ||
978 | |||
979 | |||
980 | void dLCP::pN_plusequals_ANi (dReal *p, int i, int sign) | ||
981 | { | ||
982 | dReal *aptr = AROW(i)+nC; | ||
983 | if (sign > 0) { | ||
984 | for (int i=0; i<nN; i++) p[i+nC] += aptr[i]; | ||
985 | } | ||
986 | else { | ||
987 | for (int i=0; i<nN; i++) p[i+nC] -= aptr[i]; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | |||
992 | void dLCP::solve1 (dReal *a, int i, int dir, int only_transfer) | ||
993 | { | ||
994 | // the `Dell' and `ell' that are computed here are saved. if index i is | ||
995 | // later added to the factorization then they can be reused. | ||
996 | // | ||
997 | // @@@ question: do we need to solve for entire delta_x??? yes, but | ||
998 | // only if an x goes below 0 during the step. | ||
999 | |||
1000 | int j; | ||
1001 | if (nC > 0) { | ||
1002 | dReal *aptr = AROW(i); | ||
1003 | # ifdef NUB_OPTIMIZATIONS | ||
1004 | // if nub>0, initial part of aptr[] is guaranteed unpermuted | ||
1005 | for (j=0; j<nub; j++) Dell[j] = aptr[j]; | ||
1006 | for (j=nub; j<nC; j++) Dell[j] = aptr[C[j]]; | ||
1007 | # else | ||
1008 | for (j=0; j<nC; j++) Dell[j] = aptr[C[j]]; | ||
1009 | # endif | ||
1010 | dSolveL1 (L,Dell,nC,nskip); | ||
1011 | for (j=0; j<nC; j++) ell[j] = Dell[j] * d[j]; | ||
1012 | |||
1013 | if (!only_transfer) { | ||
1014 | for (j=0; j<nC; j++) tmp[j] = ell[j]; | ||
1015 | dSolveL1T (L,tmp,nC,nskip); | ||
1016 | if (dir > 0) { | ||
1017 | for (j=0; j<nC; j++) a[C[j]] = -tmp[j]; | ||
1018 | } | ||
1019 | else { | ||
1020 | for (j=0; j<nC; j++) a[C[j]] = tmp[j]; | ||
1021 | } | ||
1022 | } | ||
1023 | } | ||
1024 | } | ||
1025 | |||
1026 | |||
1027 | void dLCP::unpermute() | ||
1028 | { | ||
1029 | // now we have to un-permute x and w | ||
1030 | int j; | ||
1031 | ALLOCA (dReal,tmp,n*sizeof(dReal)); | ||
1032 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1033 | if (tmp == NULL) { | ||
1034 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1035 | return; | ||
1036 | } | ||
1037 | #endif | ||
1038 | memcpy (tmp,x,n*sizeof(dReal)); | ||
1039 | for (j=0; j<n; j++) x[p[j]] = tmp[j]; | ||
1040 | memcpy (tmp,w,n*sizeof(dReal)); | ||
1041 | for (j=0; j<n; j++) w[p[j]] = tmp[j]; | ||
1042 | |||
1043 | UNALLOCA (tmp); | ||
1044 | } | ||
1045 | |||
1046 | #endif // dLCP_FAST | ||
1047 | |||
1048 | //*************************************************************************** | ||
1049 | // an unoptimized Dantzig LCP driver routine for the basic LCP problem. | ||
1050 | // must have lo=0, hi=dInfinity, and nub=0. | ||
1051 | |||
1052 | void dSolveLCPBasic (int n, dReal *A, dReal *x, dReal *b, | ||
1053 | dReal *w, int nub, dReal *lo, dReal *hi) | ||
1054 | { | ||
1055 | dAASSERT (n>0 && A && x && b && w && nub == 0); | ||
1056 | |||
1057 | int i,k; | ||
1058 | int nskip = dPAD(n); | ||
1059 | ALLOCA (dReal,L,n*nskip*sizeof(dReal)); | ||
1060 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1061 | if (L == NULL) { | ||
1062 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1063 | return; | ||
1064 | } | ||
1065 | #endif | ||
1066 | ALLOCA (dReal,d,n*sizeof(dReal)); | ||
1067 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1068 | if (d == NULL) { | ||
1069 | UNALLOCA(L); | ||
1070 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1071 | return; | ||
1072 | } | ||
1073 | #endif | ||
1074 | ALLOCA (dReal,delta_x,n*sizeof(dReal)); | ||
1075 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1076 | if (delta_x == NULL) { | ||
1077 | UNALLOCA(d); | ||
1078 | UNALLOCA(L); | ||
1079 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1080 | return; | ||
1081 | } | ||
1082 | #endif | ||
1083 | ALLOCA (dReal,delta_w,n*sizeof(dReal)); | ||
1084 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1085 | if (delta_w == NULL) { | ||
1086 | UNALLOCA(delta_x); | ||
1087 | UNALLOCA(d); | ||
1088 | UNALLOCA(L); | ||
1089 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1090 | return; | ||
1091 | } | ||
1092 | #endif | ||
1093 | ALLOCA (dReal,Dell,n*sizeof(dReal)); | ||
1094 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1095 | if (Dell == NULL) { | ||
1096 | UNALLOCA(delta_w); | ||
1097 | UNALLOCA(delta_x); | ||
1098 | UNALLOCA(d); | ||
1099 | UNALLOCA(L); | ||
1100 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1101 | return; | ||
1102 | } | ||
1103 | #endif | ||
1104 | ALLOCA (dReal,ell,n*sizeof(dReal)); | ||
1105 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1106 | if (ell == NULL) { | ||
1107 | UNALLOCA(Dell); | ||
1108 | UNALLOCA(delta_w); | ||
1109 | UNALLOCA(delta_x); | ||
1110 | UNALLOCA(d); | ||
1111 | UNALLOCA(L); | ||
1112 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1113 | return; | ||
1114 | } | ||
1115 | #endif | ||
1116 | ALLOCA (dReal,tmp,n*sizeof(dReal)); | ||
1117 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1118 | if (tmp == NULL) { | ||
1119 | UNALLOCA(ell); | ||
1120 | UNALLOCA(Dell); | ||
1121 | UNALLOCA(delta_w); | ||
1122 | UNALLOCA(delta_x); | ||
1123 | UNALLOCA(d); | ||
1124 | UNALLOCA(L); | ||
1125 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1126 | return; | ||
1127 | } | ||
1128 | #endif | ||
1129 | ALLOCA (dReal*,Arows,n*sizeof(dReal*)); | ||
1130 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1131 | if (Arows == NULL) { | ||
1132 | UNALLOCA(tmp); | ||
1133 | UNALLOCA(ell); | ||
1134 | UNALLOCA(Dell); | ||
1135 | UNALLOCA(delta_w); | ||
1136 | UNALLOCA(delta_x); | ||
1137 | UNALLOCA(d); | ||
1138 | UNALLOCA(L); | ||
1139 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1140 | return; | ||
1141 | } | ||
1142 | #endif | ||
1143 | ALLOCA (int,p,n*sizeof(int)); | ||
1144 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1145 | if (p == NULL) { | ||
1146 | UNALLOCA(Arows); | ||
1147 | UNALLOCA(tmp); | ||
1148 | UNALLOCA(ell); | ||
1149 | UNALLOCA(Dell); | ||
1150 | UNALLOCA(delta_w); | ||
1151 | UNALLOCA(delta_x); | ||
1152 | UNALLOCA(d); | ||
1153 | UNALLOCA(L); | ||
1154 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1155 | return; | ||
1156 | } | ||
1157 | #endif | ||
1158 | ALLOCA (int,C,n*sizeof(int)); | ||
1159 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1160 | if (C == NULL) { | ||
1161 | UNALLOCA(p); | ||
1162 | UNALLOCA(Arows); | ||
1163 | UNALLOCA(tmp); | ||
1164 | UNALLOCA(ell); | ||
1165 | UNALLOCA(Dell); | ||
1166 | UNALLOCA(delta_w); | ||
1167 | UNALLOCA(delta_x); | ||
1168 | UNALLOCA(d); | ||
1169 | UNALLOCA(L); | ||
1170 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1171 | return; | ||
1172 | } | ||
1173 | #endif | ||
1174 | ALLOCA (int,dummy,n*sizeof(int)); | ||
1175 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1176 | if (dummy == NULL) { | ||
1177 | UNALLOCA(C); | ||
1178 | UNALLOCA(p); | ||
1179 | UNALLOCA(Arows); | ||
1180 | UNALLOCA(tmp); | ||
1181 | UNALLOCA(ell); | ||
1182 | UNALLOCA(Dell); | ||
1183 | UNALLOCA(delta_w); | ||
1184 | UNALLOCA(delta_x); | ||
1185 | UNALLOCA(d); | ||
1186 | UNALLOCA(L); | ||
1187 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1188 | return; | ||
1189 | } | ||
1190 | #endif | ||
1191 | |||
1192 | |||
1193 | dLCP lcp (n,0,A,x,b,w,tmp,tmp,L,d,Dell,ell,tmp,dummy,dummy,p,C,Arows); | ||
1194 | nub = lcp.getNub(); | ||
1195 | |||
1196 | for (i=0; i<n; i++) { | ||
1197 | w[i] = lcp.AiC_times_qC (i,x) - b[i]; | ||
1198 | if (w[i] >= 0) { | ||
1199 | lcp.transfer_i_to_N (i); | ||
1200 | } | ||
1201 | else { | ||
1202 | for (;;) { | ||
1203 | // compute: delta_x(C) = -A(C,C)\A(C,i) | ||
1204 | dSetZero (delta_x,n); | ||
1205 | lcp.solve1 (delta_x,i); | ||
1206 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1207 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1208 | UNALLOCA(dummy); | ||
1209 | UNALLOCA(C); | ||
1210 | UNALLOCA(p); | ||
1211 | UNALLOCA(Arows); | ||
1212 | UNALLOCA(tmp); | ||
1213 | UNALLOCA(ell); | ||
1214 | UNALLOCA(Dell); | ||
1215 | UNALLOCA(delta_w); | ||
1216 | UNALLOCA(delta_x); | ||
1217 | UNALLOCA(d); | ||
1218 | UNALLOCA(L); | ||
1219 | return; | ||
1220 | } | ||
1221 | #endif | ||
1222 | delta_x[i] = 1; | ||
1223 | |||
1224 | // compute: delta_w = A*delta_x | ||
1225 | dSetZero (delta_w,n); | ||
1226 | lcp.pN_equals_ANC_times_qC (delta_w,delta_x); | ||
1227 | lcp.pN_plusequals_ANi (delta_w,i); | ||
1228 | delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i); | ||
1229 | |||
1230 | // find index to switch | ||
1231 | int si = i; // si = switch index | ||
1232 | int si_in_N = 0; // set to 1 if si in N | ||
1233 | dReal s = -w[i]/delta_w[i]; | ||
1234 | |||
1235 | if (s <= 0) { | ||
1236 | dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); | ||
1237 | if (i < (n-1)) { | ||
1238 | dSetZero (x+i,n-i); | ||
1239 | dSetZero (w+i,n-i); | ||
1240 | } | ||
1241 | goto done; | ||
1242 | } | ||
1243 | |||
1244 | for (k=0; k < lcp.numN(); k++) { | ||
1245 | if (delta_w[lcp.indexN(k)] < 0) { | ||
1246 | dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)]; | ||
1247 | if (s2 < s) { | ||
1248 | s = s2; | ||
1249 | si = lcp.indexN(k); | ||
1250 | si_in_N = 1; | ||
1251 | } | ||
1252 | } | ||
1253 | } | ||
1254 | for (k=0; k < lcp.numC(); k++) { | ||
1255 | if (delta_x[lcp.indexC(k)] < 0) { | ||
1256 | dReal s2 = -x[lcp.indexC(k)] / delta_x[lcp.indexC(k)]; | ||
1257 | if (s2 < s) { | ||
1258 | s = s2; | ||
1259 | si = lcp.indexC(k); | ||
1260 | si_in_N = 0; | ||
1261 | } | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | // apply x = x + s * delta_x | ||
1266 | lcp.pC_plusequals_s_times_qC (x,s,delta_x); | ||
1267 | x[i] += s; | ||
1268 | lcp.pN_plusequals_s_times_qN (w,s,delta_w); | ||
1269 | w[i] += s * delta_w[i]; | ||
1270 | |||
1271 | // switch indexes between sets if necessary | ||
1272 | if (si==i) { | ||
1273 | w[i] = 0; | ||
1274 | lcp.transfer_i_to_C (i); | ||
1275 | break; | ||
1276 | } | ||
1277 | if (si_in_N) { | ||
1278 | w[si] = 0; | ||
1279 | lcp.transfer_i_from_N_to_C (si); | ||
1280 | } | ||
1281 | else { | ||
1282 | x[si] = 0; | ||
1283 | lcp.transfer_i_from_C_to_N (si); | ||
1284 | } | ||
1285 | } | ||
1286 | } | ||
1287 | } | ||
1288 | |||
1289 | done: | ||
1290 | lcp.unpermute(); | ||
1291 | |||
1292 | UNALLOCA (L); | ||
1293 | UNALLOCA (d); | ||
1294 | UNALLOCA (delta_x); | ||
1295 | UNALLOCA (delta_w); | ||
1296 | UNALLOCA (Dell); | ||
1297 | UNALLOCA (ell); | ||
1298 | UNALLOCA (tmp); | ||
1299 | UNALLOCA (Arows); | ||
1300 | UNALLOCA (p); | ||
1301 | UNALLOCA (C); | ||
1302 | UNALLOCA (dummy); | ||
1303 | } | ||
1304 | |||
1305 | //*************************************************************************** | ||
1306 | // an optimized Dantzig LCP driver routine for the lo-hi LCP problem. | ||
1307 | |||
1308 | void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, | ||
1309 | dReal *w, int nub, dReal *lo, dReal *hi, int *findex) | ||
1310 | { | ||
1311 | dAASSERT (n>0 && A && x && b && w && lo && hi && nub >= 0 && nub <= n); | ||
1312 | |||
1313 | int i,k,hit_first_friction_index = 0; | ||
1314 | int nskip = dPAD(n); | ||
1315 | |||
1316 | // if all the variables are unbounded then we can just factor, solve, | ||
1317 | // and return | ||
1318 | if (nub >= n) { | ||
1319 | dFactorLDLT (A,w,n,nskip); // use w for d | ||
1320 | dSolveLDLT (A,w,b,n,nskip); | ||
1321 | memcpy (x,b,n*sizeof(dReal)); | ||
1322 | dSetZero (w,n); | ||
1323 | |||
1324 | return; | ||
1325 | } | ||
1326 | # ifndef dNODEBUG | ||
1327 | // check restrictions on lo and hi | ||
1328 | for (k=0; k<n; k++) dIASSERT (lo[k] <= 0 && hi[k] >= 0); | ||
1329 | # endif | ||
1330 | ALLOCA (dReal,L,n*nskip*sizeof(dReal)); | ||
1331 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1332 | if (L == NULL) { | ||
1333 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1334 | return; | ||
1335 | } | ||
1336 | #endif | ||
1337 | ALLOCA (dReal,d,n*sizeof(dReal)); | ||
1338 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1339 | if (d == NULL) { | ||
1340 | UNALLOCA(L); | ||
1341 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1342 | return; | ||
1343 | } | ||
1344 | #endif | ||
1345 | ALLOCA (dReal,delta_x,n*sizeof(dReal)); | ||
1346 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1347 | if (delta_x == NULL) { | ||
1348 | UNALLOCA(d); | ||
1349 | UNALLOCA(L); | ||
1350 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1351 | return; | ||
1352 | } | ||
1353 | #endif | ||
1354 | ALLOCA (dReal,delta_w,n*sizeof(dReal)); | ||
1355 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1356 | if (delta_w == NULL) { | ||
1357 | UNALLOCA(delta_x); | ||
1358 | UNALLOCA(d); | ||
1359 | UNALLOCA(L); | ||
1360 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1361 | return; | ||
1362 | } | ||
1363 | #endif | ||
1364 | ALLOCA (dReal,Dell,n*sizeof(dReal)); | ||
1365 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1366 | if (Dell == NULL) { | ||
1367 | UNALLOCA(delta_w); | ||
1368 | UNALLOCA(delta_x); | ||
1369 | UNALLOCA(d); | ||
1370 | UNALLOCA(L); | ||
1371 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1372 | return; | ||
1373 | } | ||
1374 | #endif | ||
1375 | ALLOCA (dReal,ell,n*sizeof(dReal)); | ||
1376 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1377 | if (ell == NULL) { | ||
1378 | UNALLOCA(Dell); | ||
1379 | UNALLOCA(delta_w); | ||
1380 | UNALLOCA(delta_x); | ||
1381 | UNALLOCA(d); | ||
1382 | UNALLOCA(L); | ||
1383 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1384 | return; | ||
1385 | } | ||
1386 | #endif | ||
1387 | ALLOCA (dReal*,Arows,n*sizeof(dReal*)); | ||
1388 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1389 | if (Arows == NULL) { | ||
1390 | UNALLOCA(ell); | ||
1391 | UNALLOCA(Dell); | ||
1392 | UNALLOCA(delta_w); | ||
1393 | UNALLOCA(delta_x); | ||
1394 | UNALLOCA(d); | ||
1395 | UNALLOCA(L); | ||
1396 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1397 | return; | ||
1398 | } | ||
1399 | #endif | ||
1400 | ALLOCA (int,p,n*sizeof(int)); | ||
1401 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1402 | if (p == NULL) { | ||
1403 | UNALLOCA(Arows); | ||
1404 | UNALLOCA(ell); | ||
1405 | UNALLOCA(Dell); | ||
1406 | UNALLOCA(delta_w); | ||
1407 | UNALLOCA(delta_x); | ||
1408 | UNALLOCA(d); | ||
1409 | UNALLOCA(L); | ||
1410 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1411 | return; | ||
1412 | } | ||
1413 | #endif | ||
1414 | ALLOCA (int,C,n*sizeof(int)); | ||
1415 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1416 | if (C == NULL) { | ||
1417 | UNALLOCA(p); | ||
1418 | UNALLOCA(Arows); | ||
1419 | UNALLOCA(ell); | ||
1420 | UNALLOCA(Dell); | ||
1421 | UNALLOCA(delta_w); | ||
1422 | UNALLOCA(delta_x); | ||
1423 | UNALLOCA(d); | ||
1424 | UNALLOCA(L); | ||
1425 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1426 | return; | ||
1427 | } | ||
1428 | #endif | ||
1429 | |||
1430 | int dir; | ||
1431 | dReal dirf; | ||
1432 | |||
1433 | // for i in N, state[i] is 0 if x(i)==lo(i) or 1 if x(i)==hi(i) | ||
1434 | ALLOCA (int,state,n*sizeof(int)); | ||
1435 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1436 | if (state == NULL) { | ||
1437 | UNALLOCA(C); | ||
1438 | UNALLOCA(p); | ||
1439 | UNALLOCA(Arows); | ||
1440 | UNALLOCA(ell); | ||
1441 | UNALLOCA(Dell); | ||
1442 | UNALLOCA(delta_w); | ||
1443 | UNALLOCA(delta_x); | ||
1444 | UNALLOCA(d); | ||
1445 | UNALLOCA(L); | ||
1446 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1447 | return; | ||
1448 | } | ||
1449 | #endif | ||
1450 | |||
1451 | // create LCP object. note that tmp is set to delta_w to save space, this | ||
1452 | // optimization relies on knowledge of how tmp is used, so be careful! | ||
1453 | dLCP *lcp=new dLCP(n,nub,A,x,b,w,lo,hi,L,d,Dell,ell,delta_w,state,findex,p,C,Arows); | ||
1454 | nub = lcp->getNub(); | ||
1455 | |||
1456 | // loop over all indexes nub..n-1. for index i, if x(i),w(i) satisfy the | ||
1457 | // LCP conditions then i is added to the appropriate index set. otherwise | ||
1458 | // x(i),w(i) is driven either +ve or -ve to force it to the valid region. | ||
1459 | // as we drive x(i), x(C) is also adjusted to keep w(C) at zero. | ||
1460 | // while driving x(i) we maintain the LCP conditions on the other variables | ||
1461 | // 0..i-1. we do this by watching out for other x(i),w(i) values going | ||
1462 | // outside the valid region, and then switching them between index sets | ||
1463 | // when that happens. | ||
1464 | |||
1465 | for (i=nub; i<n; i++) { | ||
1466 | // the index i is the driving index and indexes i+1..n-1 are "dont care", | ||
1467 | // i.e. when we make changes to the system those x's will be zero and we | ||
1468 | // don't care what happens to those w's. in other words, we only consider | ||
1469 | // an (i+1)*(i+1) sub-problem of A*x=b+w. | ||
1470 | |||
1471 | // if we've hit the first friction index, we have to compute the lo and | ||
1472 | // hi values based on the values of x already computed. we have been | ||
1473 | // permuting the indexes, so the values stored in the findex vector are | ||
1474 | // no longer valid. thus we have to temporarily unpermute the x vector. | ||
1475 | // for the purposes of this computation, 0*infinity = 0 ... so if the | ||
1476 | // contact constraint's normal force is 0, there should be no tangential | ||
1477 | // force applied. | ||
1478 | |||
1479 | if (hit_first_friction_index == 0 && findex && findex[i] >= 0) { | ||
1480 | // un-permute x into delta_w, which is not being used at the moment | ||
1481 | for (k=0; k<n; k++) delta_w[p[k]] = x[k]; | ||
1482 | |||
1483 | // set lo and hi values | ||
1484 | for (k=i; k<n; k++) { | ||
1485 | dReal wfk = delta_w[findex[k]]; | ||
1486 | if (wfk == 0) { | ||
1487 | hi[k] = 0; | ||
1488 | lo[k] = 0; | ||
1489 | } | ||
1490 | else { | ||
1491 | hi[k] = dFabs (hi[k] * wfk); | ||
1492 | lo[k] = -hi[k]; | ||
1493 | } | ||
1494 | } | ||
1495 | hit_first_friction_index = 1; | ||
1496 | } | ||
1497 | |||
1498 | // thus far we have not even been computing the w values for indexes | ||
1499 | // greater than i, so compute w[i] now. | ||
1500 | w[i] = lcp->AiC_times_qC (i,x) + lcp->AiN_times_qN (i,x) - b[i]; | ||
1501 | |||
1502 | // if lo=hi=0 (which can happen for tangential friction when normals are | ||
1503 | // 0) then the index will be assigned to set N with some state. however, | ||
1504 | // set C's line has zero size, so the index will always remain in set N. | ||
1505 | // with the "normal" switching logic, if w changed sign then the index | ||
1506 | // would have to switch to set C and then back to set N with an inverted | ||
1507 | // state. this is pointless, and also computationally expensive. to | ||
1508 | // prevent this from happening, we use the rule that indexes with lo=hi=0 | ||
1509 | // will never be checked for set changes. this means that the state for | ||
1510 | // these indexes may be incorrect, but that doesn't matter. | ||
1511 | |||
1512 | // see if x(i),w(i) is in a valid region | ||
1513 | if (lo[i]==0 && w[i] >= 0) { | ||
1514 | lcp->transfer_i_to_N (i); | ||
1515 | state[i] = 0; | ||
1516 | } | ||
1517 | else if (hi[i]==0 && w[i] <= 0) { | ||
1518 | lcp->transfer_i_to_N (i); | ||
1519 | state[i] = 1; | ||
1520 | } | ||
1521 | else if (w[i]==0) { | ||
1522 | // this is a degenerate case. by the time we get to this test we know | ||
1523 | // that lo != 0, which means that lo < 0 as lo is not allowed to be +ve, | ||
1524 | // and similarly that hi > 0. this means that the line segment | ||
1525 | // corresponding to set C is at least finite in extent, and we are on it. | ||
1526 | // NOTE: we must call lcp->solve1() before lcp->transfer_i_to_C() | ||
1527 | lcp->solve1 (delta_x,i,0,1); | ||
1528 | |||
1529 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1530 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1531 | UNALLOCA(state); | ||
1532 | UNALLOCA(C); | ||
1533 | UNALLOCA(p); | ||
1534 | UNALLOCA(Arows); | ||
1535 | UNALLOCA(ell); | ||
1536 | UNALLOCA(Dell); | ||
1537 | UNALLOCA(delta_w); | ||
1538 | UNALLOCA(delta_x); | ||
1539 | UNALLOCA(d); | ||
1540 | UNALLOCA(L); | ||
1541 | return; | ||
1542 | } | ||
1543 | #endif | ||
1544 | |||
1545 | lcp->transfer_i_to_C (i); | ||
1546 | } | ||
1547 | else { | ||
1548 | // we must push x(i) and w(i) | ||
1549 | for (;;) { | ||
1550 | // find direction to push on x(i) | ||
1551 | if (w[i] <= 0) { | ||
1552 | dir = 1; | ||
1553 | dirf = REAL(1.0); | ||
1554 | } | ||
1555 | else { | ||
1556 | dir = -1; | ||
1557 | dirf = REAL(-1.0); | ||
1558 | } | ||
1559 | |||
1560 | // compute: delta_x(C) = -dir*A(C,C)\A(C,i) | ||
1561 | lcp->solve1 (delta_x,i,dir); | ||
1562 | |||
1563 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1564 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1565 | UNALLOCA(state); | ||
1566 | UNALLOCA(C); | ||
1567 | UNALLOCA(p); | ||
1568 | UNALLOCA(Arows); | ||
1569 | UNALLOCA(ell); | ||
1570 | UNALLOCA(Dell); | ||
1571 | UNALLOCA(delta_w); | ||
1572 | UNALLOCA(delta_x); | ||
1573 | UNALLOCA(d); | ||
1574 | UNALLOCA(L); | ||
1575 | return; | ||
1576 | } | ||
1577 | #endif | ||
1578 | |||
1579 | // note that delta_x[i] = dirf, but we wont bother to set it | ||
1580 | |||
1581 | // compute: delta_w = A*delta_x ... note we only care about | ||
1582 | // delta_w(N) and delta_w(i), the rest is ignored | ||
1583 | lcp->pN_equals_ANC_times_qC (delta_w,delta_x); | ||
1584 | lcp->pN_plusequals_ANi (delta_w,i,dir); | ||
1585 | delta_w[i] = lcp->AiC_times_qC (i,delta_x) + lcp->Aii(i)*dirf; | ||
1586 | |||
1587 | // find largest step we can take (size=s), either to drive x(i),w(i) | ||
1588 | // to the valid LCP region or to drive an already-valid variable | ||
1589 | // outside the valid region. | ||
1590 | |||
1591 | int cmd = 1; // index switching command | ||
1592 | int si = 0; // si = index to switch if cmd>3 | ||
1593 | dReal s = -w[i]/delta_w[i]; | ||
1594 | if (dir > 0) { | ||
1595 | if (hi[i] < dInfinity) { | ||
1596 | dReal s2 = (hi[i]-x[i])/dirf; // step to x(i)=hi(i) | ||
1597 | if (s2 < s) { | ||
1598 | s = s2; | ||
1599 | cmd = 3; | ||
1600 | } | ||
1601 | } | ||
1602 | } | ||
1603 | else { | ||
1604 | if (lo[i] > -dInfinity) { | ||
1605 | dReal s2 = (lo[i]-x[i])/dirf; // step to x(i)=lo(i) | ||
1606 | if (s2 < s) { | ||
1607 | s = s2; | ||
1608 | cmd = 2; | ||
1609 | } | ||
1610 | } | ||
1611 | } | ||
1612 | |||
1613 | for (k=0; k < lcp->numN(); k++) { | ||
1614 | if ((state[lcp->indexN(k)]==0 && delta_w[lcp->indexN(k)] < 0) || | ||
1615 | (state[lcp->indexN(k)]!=0 && delta_w[lcp->indexN(k)] > 0)) { | ||
1616 | // don't bother checking if lo=hi=0 | ||
1617 | if (lo[lcp->indexN(k)] == 0 && hi[lcp->indexN(k)] == 0) continue; | ||
1618 | dReal s2 = -w[lcp->indexN(k)] / delta_w[lcp->indexN(k)]; | ||
1619 | if (s2 < s) { | ||
1620 | s = s2; | ||
1621 | cmd = 4; | ||
1622 | si = lcp->indexN(k); | ||
1623 | } | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | for (k=nub; k < lcp->numC(); k++) { | ||
1628 | if (delta_x[lcp->indexC(k)] < 0 && lo[lcp->indexC(k)] > -dInfinity) { | ||
1629 | dReal s2 = (lo[lcp->indexC(k)]-x[lcp->indexC(k)]) / | ||
1630 | delta_x[lcp->indexC(k)]; | ||
1631 | if (s2 < s) { | ||
1632 | s = s2; | ||
1633 | cmd = 5; | ||
1634 | si = lcp->indexC(k); | ||
1635 | } | ||
1636 | } | ||
1637 | if (delta_x[lcp->indexC(k)] > 0 && hi[lcp->indexC(k)] < dInfinity) { | ||
1638 | dReal s2 = (hi[lcp->indexC(k)]-x[lcp->indexC(k)]) / | ||
1639 | delta_x[lcp->indexC(k)]; | ||
1640 | if (s2 < s) { | ||
1641 | s = s2; | ||
1642 | cmd = 6; | ||
1643 | si = lcp->indexC(k); | ||
1644 | } | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | //static char* cmdstring[8] = {0,"->C","->NL","->NH","N->C", | ||
1649 | // "C->NL","C->NH"}; | ||
1650 | //printf ("cmd=%d (%s), si=%d\n",cmd,cmdstring[cmd],(cmd>3) ? si : i); | ||
1651 | |||
1652 | // if s <= 0 then we've got a problem. if we just keep going then | ||
1653 | // we're going to get stuck in an infinite loop. instead, just cross | ||
1654 | // our fingers and exit with the current solution. | ||
1655 | if (s <= 0) { | ||
1656 | dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); | ||
1657 | if (i < (n-1)) { | ||
1658 | dSetZero (x+i,n-i); | ||
1659 | dSetZero (w+i,n-i); | ||
1660 | } | ||
1661 | goto done; | ||
1662 | } | ||
1663 | |||
1664 | // apply x = x + s * delta_x | ||
1665 | lcp->pC_plusequals_s_times_qC (x,s,delta_x); | ||
1666 | x[i] += s * dirf; | ||
1667 | |||
1668 | // apply w = w + s * delta_w | ||
1669 | lcp->pN_plusequals_s_times_qN (w,s,delta_w); | ||
1670 | w[i] += s * delta_w[i]; | ||
1671 | |||
1672 | // switch indexes between sets if necessary | ||
1673 | switch (cmd) { | ||
1674 | case 1: // done | ||
1675 | w[i] = 0; | ||
1676 | lcp->transfer_i_to_C (i); | ||
1677 | break; | ||
1678 | case 2: // done | ||
1679 | x[i] = lo[i]; | ||
1680 | state[i] = 0; | ||
1681 | lcp->transfer_i_to_N (i); | ||
1682 | break; | ||
1683 | case 3: // done | ||
1684 | x[i] = hi[i]; | ||
1685 | state[i] = 1; | ||
1686 | lcp->transfer_i_to_N (i); | ||
1687 | break; | ||
1688 | case 4: // keep going | ||
1689 | w[si] = 0; | ||
1690 | lcp->transfer_i_from_N_to_C (si); | ||
1691 | break; | ||
1692 | case 5: // keep going | ||
1693 | x[si] = lo[si]; | ||
1694 | state[si] = 0; | ||
1695 | lcp->transfer_i_from_C_to_N (si); | ||
1696 | break; | ||
1697 | case 6: // keep going | ||
1698 | x[si] = hi[si]; | ||
1699 | state[si] = 1; | ||
1700 | lcp->transfer_i_from_C_to_N (si); | ||
1701 | break; | ||
1702 | } | ||
1703 | |||
1704 | if (cmd <= 3) break; | ||
1705 | } | ||
1706 | } | ||
1707 | } | ||
1708 | |||
1709 | done: | ||
1710 | lcp->unpermute(); | ||
1711 | delete lcp; | ||
1712 | |||
1713 | UNALLOCA (L); | ||
1714 | UNALLOCA (d); | ||
1715 | UNALLOCA (delta_x); | ||
1716 | UNALLOCA (delta_w); | ||
1717 | UNALLOCA (Dell); | ||
1718 | UNALLOCA (ell); | ||
1719 | UNALLOCA (Arows); | ||
1720 | UNALLOCA (p); | ||
1721 | UNALLOCA (C); | ||
1722 | UNALLOCA (state); | ||
1723 | } | ||
1724 | |||
1725 | //*************************************************************************** | ||
1726 | // accuracy and timing test | ||
1727 | |||
1728 | extern "C" ODE_API void dTestSolveLCP() | ||
1729 | { | ||
1730 | int n = 100; | ||
1731 | int i,nskip = dPAD(n); | ||
1732 | #ifdef dDOUBLE | ||
1733 | const dReal tol = REAL(1e-9); | ||
1734 | #endif | ||
1735 | #ifdef dSINGLE | ||
1736 | const dReal tol = REAL(1e-4); | ||
1737 | #endif | ||
1738 | printf ("dTestSolveLCP()\n"); | ||
1739 | |||
1740 | ALLOCA (dReal,A,n*nskip*sizeof(dReal)); | ||
1741 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1742 | if (A == NULL) { | ||
1743 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1744 | return; | ||
1745 | } | ||
1746 | #endif | ||
1747 | ALLOCA (dReal,x,n*sizeof(dReal)); | ||
1748 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1749 | if (x == NULL) { | ||
1750 | UNALLOCA (A); | ||
1751 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1752 | return; | ||
1753 | } | ||
1754 | #endif | ||
1755 | ALLOCA (dReal,b,n*sizeof(dReal)); | ||
1756 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1757 | if (b == NULL) { | ||
1758 | UNALLOCA (x); | ||
1759 | UNALLOCA (A); | ||
1760 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1761 | return; | ||
1762 | } | ||
1763 | #endif | ||
1764 | ALLOCA (dReal,w,n*sizeof(dReal)); | ||
1765 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1766 | if (w == NULL) { | ||
1767 | UNALLOCA (b); | ||
1768 | UNALLOCA (x); | ||
1769 | UNALLOCA (A); | ||
1770 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1771 | return; | ||
1772 | } | ||
1773 | #endif | ||
1774 | ALLOCA (dReal,lo,n*sizeof(dReal)); | ||
1775 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1776 | if (lo == NULL) { | ||
1777 | UNALLOCA (w); | ||
1778 | UNALLOCA (b); | ||
1779 | UNALLOCA (x); | ||
1780 | UNALLOCA (A); | ||
1781 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1782 | return; | ||
1783 | } | ||
1784 | #endif | ||
1785 | ALLOCA (dReal,hi,n*sizeof(dReal)); | ||
1786 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1787 | if (hi == NULL) { | ||
1788 | UNALLOCA (lo); | ||
1789 | UNALLOCA (w); | ||
1790 | UNALLOCA (b); | ||
1791 | UNALLOCA (x); | ||
1792 | UNALLOCA (A); | ||
1793 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1794 | return; | ||
1795 | } | ||
1796 | #endif | ||
1797 | |||
1798 | ALLOCA (dReal,A2,n*nskip*sizeof(dReal)); | ||
1799 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1800 | if (A2 == NULL) { | ||
1801 | UNALLOCA (hi); | ||
1802 | UNALLOCA (lo); | ||
1803 | UNALLOCA (w); | ||
1804 | UNALLOCA (b); | ||
1805 | UNALLOCA (x); | ||
1806 | UNALLOCA (A); | ||
1807 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1808 | return; | ||
1809 | } | ||
1810 | #endif | ||
1811 | ALLOCA (dReal,b2,n*sizeof(dReal)); | ||
1812 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1813 | if (b2 == NULL) { | ||
1814 | UNALLOCA (A2); | ||
1815 | UNALLOCA (hi); | ||
1816 | UNALLOCA (lo); | ||
1817 | UNALLOCA (w); | ||
1818 | UNALLOCA (b); | ||
1819 | UNALLOCA (x); | ||
1820 | UNALLOCA (A); | ||
1821 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1822 | return; | ||
1823 | } | ||
1824 | #endif | ||
1825 | ALLOCA (dReal,lo2,n*sizeof(dReal)); | ||
1826 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1827 | if (lo2 == NULL) { | ||
1828 | UNALLOCA (b2); | ||
1829 | UNALLOCA (A2); | ||
1830 | UNALLOCA (hi); | ||
1831 | UNALLOCA (lo); | ||
1832 | UNALLOCA (w); | ||
1833 | UNALLOCA (b); | ||
1834 | UNALLOCA (x); | ||
1835 | UNALLOCA (A); | ||
1836 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1837 | return; | ||
1838 | } | ||
1839 | #endif | ||
1840 | ALLOCA (dReal,hi2,n*sizeof(dReal)); | ||
1841 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1842 | if (hi2 == NULL) { | ||
1843 | UNALLOCA (lo2); | ||
1844 | UNALLOCA (b2); | ||
1845 | UNALLOCA (A2); | ||
1846 | UNALLOCA (hi); | ||
1847 | UNALLOCA (lo); | ||
1848 | UNALLOCA (w); | ||
1849 | UNALLOCA (b); | ||
1850 | UNALLOCA (x); | ||
1851 | UNALLOCA (A); | ||
1852 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1853 | return; | ||
1854 | } | ||
1855 | #endif | ||
1856 | ALLOCA (dReal,tmp1,n*sizeof(dReal)); | ||
1857 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1858 | if (tmp1 == NULL) { | ||
1859 | UNALLOCA (hi2); | ||
1860 | UNALLOCA (lo2); | ||
1861 | UNALLOCA (b2); | ||
1862 | UNALLOCA (A2); | ||
1863 | UNALLOCA (hi); | ||
1864 | UNALLOCA (lo); | ||
1865 | UNALLOCA (w); | ||
1866 | UNALLOCA (b); | ||
1867 | UNALLOCA (x); | ||
1868 | UNALLOCA (A); | ||
1869 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1870 | return; | ||
1871 | } | ||
1872 | #endif | ||
1873 | ALLOCA (dReal,tmp2,n*sizeof(dReal)); | ||
1874 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1875 | if (tmp2 == NULL) { | ||
1876 | UNALLOCA (tmp1); | ||
1877 | UNALLOCA (hi2); | ||
1878 | UNALLOCA (lo2); | ||
1879 | UNALLOCA (b2); | ||
1880 | UNALLOCA (A2); | ||
1881 | UNALLOCA (hi); | ||
1882 | UNALLOCA (lo); | ||
1883 | UNALLOCA (w); | ||
1884 | UNALLOCA (b); | ||
1885 | UNALLOCA (x); | ||
1886 | UNALLOCA (A); | ||
1887 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1888 | return; | ||
1889 | } | ||
1890 | #endif | ||
1891 | |||
1892 | double total_time = 0; | ||
1893 | for (int count=0; count < 1000; count++) { | ||
1894 | |||
1895 | // form (A,b) = a random positive definite LCP problem | ||
1896 | dMakeRandomMatrix (A2,n,n,1.0); | ||
1897 | dMultiply2 (A,A2,A2,n,n,n); | ||
1898 | dMakeRandomMatrix (x,n,1,1.0); | ||
1899 | dMultiply0 (b,A,x,n,n,1); | ||
1900 | for (i=0; i<n; i++) b[i] += (dRandReal()*REAL(0.2))-REAL(0.1); | ||
1901 | |||
1902 | // choose `nub' in the range 0..n-1 | ||
1903 | int nub = 50; //dRandInt (n); | ||
1904 | |||
1905 | // make limits | ||
1906 | for (i=0; i<nub; i++) lo[i] = -dInfinity; | ||
1907 | for (i=0; i<nub; i++) hi[i] = dInfinity; | ||
1908 | //for (i=nub; i<n; i++) lo[i] = 0; | ||
1909 | //for (i=nub; i<n; i++) hi[i] = dInfinity; | ||
1910 | //for (i=nub; i<n; i++) lo[i] = -dInfinity; | ||
1911 | //for (i=nub; i<n; i++) hi[i] = 0; | ||
1912 | for (i=nub; i<n; i++) lo[i] = -(dRandReal()*REAL(1.0))-REAL(0.01); | ||
1913 | for (i=nub; i<n; i++) hi[i] = (dRandReal()*REAL(1.0))+REAL(0.01); | ||
1914 | |||
1915 | // set a few limits to lo=hi=0 | ||
1916 | /* | ||
1917 | for (i=0; i<10; i++) { | ||
1918 | int j = dRandInt (n-nub) + nub; | ||
1919 | lo[j] = 0; | ||
1920 | hi[j] = 0; | ||
1921 | } | ||
1922 | */ | ||
1923 | |||
1924 | // solve the LCP. we must make copy of A,b,lo,hi (A2,b2,lo2,hi2) for | ||
1925 | // SolveLCP() to permute. also, we'll clear the upper triangle of A2 to | ||
1926 | // ensure that it doesn't get referenced (if it does, the answer will be | ||
1927 | // wrong). | ||
1928 | |||
1929 | memcpy (A2,A,n*nskip*sizeof(dReal)); | ||
1930 | dClearUpperTriangle (A2,n); | ||
1931 | memcpy (b2,b,n*sizeof(dReal)); | ||
1932 | memcpy (lo2,lo,n*sizeof(dReal)); | ||
1933 | memcpy (hi2,hi,n*sizeof(dReal)); | ||
1934 | dSetZero (x,n); | ||
1935 | dSetZero (w,n); | ||
1936 | |||
1937 | dStopwatch sw; | ||
1938 | dStopwatchReset (&sw); | ||
1939 | dStopwatchStart (&sw); | ||
1940 | |||
1941 | dSolveLCP (n,A2,x,b2,w,nub,lo2,hi2,0); | ||
1942 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1943 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1944 | UNALLOCA (tmp2); | ||
1945 | UNALLOCA (tmp1); | ||
1946 | UNALLOCA (hi2); | ||
1947 | UNALLOCA (lo2); | ||
1948 | UNALLOCA (b2); | ||
1949 | UNALLOCA (A2); | ||
1950 | UNALLOCA (hi); | ||
1951 | UNALLOCA (lo); | ||
1952 | UNALLOCA (w); | ||
1953 | UNALLOCA (b); | ||
1954 | UNALLOCA (x); | ||
1955 | UNALLOCA (A); | ||
1956 | return; | ||
1957 | } | ||
1958 | #endif | ||
1959 | |||
1960 | dStopwatchStop (&sw); | ||
1961 | double time = dStopwatchTime(&sw); | ||
1962 | total_time += time; | ||
1963 | double average = total_time / double(count+1) * 1000.0; | ||
1964 | |||
1965 | // check the solution | ||
1966 | |||
1967 | dMultiply0 (tmp1,A,x,n,n,1); | ||
1968 | for (i=0; i<n; i++) tmp2[i] = b[i] + w[i]; | ||
1969 | dReal diff = dMaxDifference (tmp1,tmp2,n,1); | ||
1970 | // printf ("\tA*x = b+w, maximum difference = %.6e - %s (1)\n",diff, | ||
1971 | // diff > tol ? "FAILED" : "passed"); | ||
1972 | if (diff > tol) dDebug (0,"A*x = b+w, maximum difference = %.6e",diff); | ||
1973 | int n1=0,n2=0,n3=0; | ||
1974 | for (i=0; i<n; i++) { | ||
1975 | if (x[i]==lo[i] && w[i] >= 0) { | ||
1976 | n1++; // ok | ||
1977 | } | ||
1978 | else if (x[i]==hi[i] && w[i] <= 0) { | ||
1979 | n2++; // ok | ||
1980 | } | ||
1981 | else if (x[i] >= lo[i] && x[i] <= hi[i] && w[i] == 0) { | ||
1982 | n3++; // ok | ||
1983 | } | ||
1984 | else { | ||
1985 | dDebug (0,"FAILED: i=%d x=%.4e w=%.4e lo=%.4e hi=%.4e",i, | ||
1986 | x[i],w[i],lo[i],hi[i]); | ||
1987 | } | ||
1988 | } | ||
1989 | |||
1990 | // pacifier | ||
1991 | printf ("passed: NL=%3d NH=%3d C=%3d ",n1,n2,n3); | ||
1992 | printf ("time=%10.3f ms avg=%10.4f\n",time * 1000.0,average); | ||
1993 | } | ||
1994 | |||
1995 | UNALLOCA (A); | ||
1996 | UNALLOCA (x); | ||
1997 | UNALLOCA (b); | ||
1998 | UNALLOCA (w); | ||
1999 | UNALLOCA (lo); | ||
2000 | UNALLOCA (hi); | ||
2001 | UNALLOCA (A2); | ||
2002 | UNALLOCA (b2); | ||
2003 | UNALLOCA (lo2); | ||
2004 | UNALLOCA (hi2); | ||
2005 | UNALLOCA (tmp1); | ||
2006 | UNALLOCA (tmp2); | ||
2007 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/lcp.h b/libraries/ode-0.9\/ode/src/lcp.h new file mode 100755 index 0000000..484902c --- /dev/null +++ b/libraries/ode-0.9\/ode/src/lcp.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | given (A,b,lo,hi), solve the LCP problem: A*x = b+w, where each x(i),w(i) | ||
26 | satisfies one of | ||
27 | (1) x = lo, w >= 0 | ||
28 | (2) x = hi, w <= 0 | ||
29 | (3) lo < x < hi, w = 0 | ||
30 | A is a matrix of dimension n*n, everything else is a vector of size n*1. | ||
31 | lo and hi can be +/- dInfinity as needed. the first `nub' variables are | ||
32 | unbounded, i.e. hi and lo are assumed to be +/- dInfinity. | ||
33 | |||
34 | we restrict lo(i) <= 0 and hi(i) >= 0. | ||
35 | |||
36 | the original data (A,b) may be modified by this function. | ||
37 | |||
38 | if the `findex' (friction index) parameter is nonzero, it points to an array | ||
39 | of index values. in this case constraints that have findex[i] >= 0 are | ||
40 | special. all non-special constraints are solved for, then the lo and hi values | ||
41 | for the special constraints are set: | ||
42 | hi[i] = abs( hi[i] * x[findex[i]] ) | ||
43 | lo[i] = -hi[i] | ||
44 | and the solution continues. this mechanism allows a friction approximation | ||
45 | to be implemented. the first `nub' variables are assumed to have findex < 0. | ||
46 | |||
47 | */ | ||
48 | |||
49 | |||
50 | #ifndef _ODE_LCP_H_ | ||
51 | #define _ODE_LCP_H_ | ||
52 | |||
53 | |||
54 | void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, dReal *w, | ||
55 | int nub, dReal *lo, dReal *hi, int *findex); | ||
56 | |||
57 | |||
58 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/mass.cpp b/libraries/ode-0.9\/ode/src/mass.cpp new file mode 100755 index 0000000..7d0b1c2 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/mass.cpp | |||
@@ -0,0 +1,529 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/mass.h> | ||
25 | #include <ode/odemath.h> | ||
26 | #include <ode/matrix.h> | ||
27 | |||
28 | // Local dependencies | ||
29 | #include "collision_kernel.h" | ||
30 | |||
31 | #define SQR(x) ((x)*(x)) //!< Returns x square | ||
32 | #define CUBE(x) ((x)*(x)*(x)) //!< Returns x cube | ||
33 | |||
34 | #define _I(i,j) I[(i)*4+(j)] | ||
35 | |||
36 | |||
37 | // return 1 if ok, 0 if bad | ||
38 | |||
39 | int dMassCheck (const dMass *m) | ||
40 | { | ||
41 | int i; | ||
42 | |||
43 | if (m->mass <= 0) { | ||
44 | dDEBUGMSG ("mass must be > 0"); | ||
45 | return 0; | ||
46 | } | ||
47 | if (!dIsPositiveDefinite (m->I,3)) { | ||
48 | dDEBUGMSG ("inertia must be positive definite"); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | // verify that the center of mass position is consistent with the mass | ||
53 | // and inertia matrix. this is done by checking that the inertia around | ||
54 | // the center of mass is also positive definite. from the comment in | ||
55 | // dMassTranslate(), if the body is translated so that its center of mass | ||
56 | // is at the point of reference, then the new inertia is: | ||
57 | // I + mass*crossmat(c)^2 | ||
58 | // note that requiring this to be positive definite is exactly equivalent | ||
59 | // to requiring that the spatial inertia matrix | ||
60 | // [ mass*eye(3,3) M*crossmat(c)^T ] | ||
61 | // [ M*crossmat(c) I ] | ||
62 | // is positive definite, given that I is PD and mass>0. see the theorem | ||
63 | // about partitioned PD matrices for proof. | ||
64 | |||
65 | dMatrix3 I2,chat; | ||
66 | dSetZero (chat,12); | ||
67 | dCROSSMAT (chat,m->c,4,+,-); | ||
68 | dMULTIPLY0_333 (I2,chat,chat); | ||
69 | for (i=0; i<3; i++) I2[i] = m->I[i] + m->mass*I2[i]; | ||
70 | for (i=4; i<7; i++) I2[i] = m->I[i] + m->mass*I2[i]; | ||
71 | for (i=8; i<11; i++) I2[i] = m->I[i] + m->mass*I2[i]; | ||
72 | if (!dIsPositiveDefinite (I2,3)) { | ||
73 | dDEBUGMSG ("center of mass inconsistent with mass parameters"); | ||
74 | return 0; | ||
75 | } | ||
76 | return 1; | ||
77 | } | ||
78 | |||
79 | |||
80 | void dMassSetZero (dMass *m) | ||
81 | { | ||
82 | dAASSERT (m); | ||
83 | m->mass = REAL(0.0); | ||
84 | dSetZero (m->c,sizeof(m->c) / sizeof(dReal)); | ||
85 | dSetZero (m->I,sizeof(m->I) / sizeof(dReal)); | ||
86 | } | ||
87 | |||
88 | |||
89 | void dMassSetParameters (dMass *m, dReal themass, | ||
90 | dReal cgx, dReal cgy, dReal cgz, | ||
91 | dReal I11, dReal I22, dReal I33, | ||
92 | dReal I12, dReal I13, dReal I23) | ||
93 | { | ||
94 | dAASSERT (m); | ||
95 | dMassSetZero (m); | ||
96 | m->mass = themass; | ||
97 | m->c[0] = cgx; | ||
98 | m->c[1] = cgy; | ||
99 | m->c[2] = cgz; | ||
100 | m->_I(0,0) = I11; | ||
101 | m->_I(1,1) = I22; | ||
102 | m->_I(2,2) = I33; | ||
103 | m->_I(0,1) = I12; | ||
104 | m->_I(0,2) = I13; | ||
105 | m->_I(1,2) = I23; | ||
106 | m->_I(1,0) = I12; | ||
107 | m->_I(2,0) = I13; | ||
108 | m->_I(2,1) = I23; | ||
109 | dMassCheck (m); | ||
110 | } | ||
111 | |||
112 | |||
113 | void dMassSetSphere (dMass *m, dReal density, dReal radius) | ||
114 | { | ||
115 | dMassSetSphereTotal (m, (REAL(4.0)/REAL(3.0)) * M_PI * | ||
116 | radius*radius*radius * density, radius); | ||
117 | } | ||
118 | |||
119 | |||
120 | void dMassSetSphereTotal (dMass *m, dReal total_mass, dReal radius) | ||
121 | { | ||
122 | dAASSERT (m); | ||
123 | dMassSetZero (m); | ||
124 | m->mass = total_mass; | ||
125 | dReal II = REAL(0.4) * total_mass * radius*radius; | ||
126 | m->_I(0,0) = II; | ||
127 | m->_I(1,1) = II; | ||
128 | m->_I(2,2) = II; | ||
129 | |||
130 | # ifndef dNODEBUG | ||
131 | dMassCheck (m); | ||
132 | # endif | ||
133 | } | ||
134 | |||
135 | |||
136 | void dMassSetCapsule (dMass *m, dReal density, int direction, | ||
137 | dReal radius, dReal length) | ||
138 | { | ||
139 | dReal M1,M2,Ia,Ib; | ||
140 | dAASSERT (m); | ||
141 | dUASSERT (direction >= 1 && direction <= 3,"bad direction number"); | ||
142 | dMassSetZero (m); | ||
143 | M1 = M_PI*radius*radius*length*density; // cylinder mass | ||
144 | M2 = (REAL(4.0)/REAL(3.0))*M_PI*radius*radius*radius*density; // total cap mass | ||
145 | m->mass = M1+M2; | ||
146 | Ia = M1*(REAL(0.25)*radius*radius + (REAL(1.0)/REAL(12.0))*length*length) + | ||
147 | M2*(REAL(0.4)*radius*radius + REAL(0.375)*radius*length + REAL(0.25)*length*length); | ||
148 | Ib = (M1*REAL(0.5) + M2*REAL(0.4))*radius*radius; | ||
149 | m->_I(0,0) = Ia; | ||
150 | m->_I(1,1) = Ia; | ||
151 | m->_I(2,2) = Ia; | ||
152 | m->_I(direction-1,direction-1) = Ib; | ||
153 | |||
154 | # ifndef dNODEBUG | ||
155 | dMassCheck (m); | ||
156 | # endif | ||
157 | } | ||
158 | |||
159 | |||
160 | void dMassSetCapsuleTotal (dMass *m, dReal total_mass, int direction, | ||
161 | dReal a, dReal b) | ||
162 | { | ||
163 | dMassSetCapsule (m, 1.0, direction, a, b); | ||
164 | dMassAdjust (m, total_mass); | ||
165 | } | ||
166 | |||
167 | |||
168 | void dMassSetCylinder (dMass *m, dReal density, int direction, | ||
169 | dReal radius, dReal length) | ||
170 | { | ||
171 | dMassSetCylinderTotal (m, M_PI*radius*radius*length*density, | ||
172 | direction, radius, length); | ||
173 | } | ||
174 | |||
175 | void dMassSetCylinderTotal (dMass *m, dReal total_mass, int direction, | ||
176 | dReal radius, dReal length) | ||
177 | { | ||
178 | dReal r2,I; | ||
179 | dAASSERT (m); | ||
180 | dUASSERT (direction >= 1 && direction <= 3,"bad direction number"); | ||
181 | dMassSetZero (m); | ||
182 | r2 = radius*radius; | ||
183 | m->mass = total_mass; | ||
184 | I = total_mass*(REAL(0.25)*r2 + (REAL(1.0)/REAL(12.0))*length*length); | ||
185 | m->_I(0,0) = I; | ||
186 | m->_I(1,1) = I; | ||
187 | m->_I(2,2) = I; | ||
188 | m->_I(direction-1,direction-1) = total_mass*REAL(0.5)*r2; | ||
189 | |||
190 | # ifndef dNODEBUG | ||
191 | dMassCheck (m); | ||
192 | # endif | ||
193 | } | ||
194 | |||
195 | |||
196 | void dMassSetBox (dMass *m, dReal density, | ||
197 | dReal lx, dReal ly, dReal lz) | ||
198 | { | ||
199 | dMassSetBoxTotal (m, lx*ly*lz*density, lx, ly, lz); | ||
200 | } | ||
201 | |||
202 | |||
203 | void dMassSetBoxTotal (dMass *m, dReal total_mass, | ||
204 | dReal lx, dReal ly, dReal lz) | ||
205 | { | ||
206 | dAASSERT (m); | ||
207 | dMassSetZero (m); | ||
208 | m->mass = total_mass; | ||
209 | m->_I(0,0) = total_mass/REAL(12.0) * (ly*ly + lz*lz); | ||
210 | m->_I(1,1) = total_mass/REAL(12.0) * (lx*lx + lz*lz); | ||
211 | m->_I(2,2) = total_mass/REAL(12.0) * (lx*lx + ly*ly); | ||
212 | |||
213 | # ifndef dNODEBUG | ||
214 | dMassCheck (m); | ||
215 | # endif | ||
216 | } | ||
217 | |||
218 | |||
219 | |||
220 | |||
221 | |||
222 | |||
223 | #if dTRIMESH_ENABLED | ||
224 | |||
225 | /* | ||
226 | * dMassSetTrimesh, implementation by Gero Mueller. | ||
227 | * Based on Brian Mirtich, "Fast and Accurate Computation of | ||
228 | * Polyhedral Mass Properties," journal of graphics tools, volume 1, | ||
229 | * number 2, 1996. | ||
230 | */ | ||
231 | void dMassSetTrimesh( dMass *m, dReal density, dGeomID g ) | ||
232 | { | ||
233 | dAASSERT (m); | ||
234 | dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); | ||
235 | |||
236 | dMassSetZero (m); | ||
237 | |||
238 | unsigned int triangles = dGeomTriMeshGetTriangleCount( g ); | ||
239 | |||
240 | dReal nx, ny, nz; | ||
241 | unsigned int i, A, B, C; | ||
242 | // face integrals | ||
243 | dReal Fa, Fb, Fc, Faa, Fbb, Fcc, Faaa, Fbbb, Fccc, Faab, Fbbc, Fcca; | ||
244 | |||
245 | // projection integrals | ||
246 | dReal P1, Pa, Pb, Paa, Pab, Pbb, Paaa, Paab, Pabb, Pbbb; | ||
247 | |||
248 | dReal T0 = 0; | ||
249 | dReal T1[3] = {0., 0., 0.}; | ||
250 | dReal T2[3] = {0., 0., 0.}; | ||
251 | dReal TP[3] = {0., 0., 0.}; | ||
252 | |||
253 | for( i = 0; i < triangles; i++ ) | ||
254 | { | ||
255 | dVector3 v0, v1, v2; | ||
256 | dGeomTriMeshGetTriangle( g, i, &v0, &v1, &v2); | ||
257 | |||
258 | dVector3 n, a, b; | ||
259 | dOP( a, -, v1, v0 ); | ||
260 | dOP( b, -, v2, v0 ); | ||
261 | dCROSS( n, =, b, a ); | ||
262 | nx = fabs(n[0]); | ||
263 | ny = fabs(n[1]); | ||
264 | nz = fabs(n[2]); | ||
265 | |||
266 | if( nx > ny && nx > nz ) | ||
267 | C = 0; | ||
268 | else | ||
269 | C = (ny > nz) ? 1 : 2; | ||
270 | |||
271 | A = (C + 1) % 3; | ||
272 | B = (A + 1) % 3; | ||
273 | |||
274 | // calculate face integrals | ||
275 | { | ||
276 | dReal w; | ||
277 | dReal k1, k2, k3, k4; | ||
278 | |||
279 | //compProjectionIntegrals(f); | ||
280 | { | ||
281 | dReal a0, a1, da; | ||
282 | dReal b0, b1, db; | ||
283 | dReal a0_2, a0_3, a0_4, b0_2, b0_3, b0_4; | ||
284 | dReal a1_2, a1_3, b1_2, b1_3; | ||
285 | dReal C1, Ca, Caa, Caaa, Cb, Cbb, Cbbb; | ||
286 | dReal Cab, Kab, Caab, Kaab, Cabb, Kabb; | ||
287 | |||
288 | P1 = Pa = Pb = Paa = Pab = Pbb = Paaa = Paab = Pabb = Pbbb = 0.0; | ||
289 | |||
290 | for( int j = 0; j < 3; j++) | ||
291 | { | ||
292 | switch(j) | ||
293 | { | ||
294 | case 0: | ||
295 | a0 = v0[A]; | ||
296 | b0 = v0[B]; | ||
297 | a1 = v1[A]; | ||
298 | b1 = v1[B]; | ||
299 | break; | ||
300 | case 1: | ||
301 | a0 = v1[A]; | ||
302 | b0 = v1[B]; | ||
303 | a1 = v2[A]; | ||
304 | b1 = v2[B]; | ||
305 | break; | ||
306 | case 2: | ||
307 | a0 = v2[A]; | ||
308 | b0 = v2[B]; | ||
309 | a1 = v0[A]; | ||
310 | b1 = v0[B]; | ||
311 | break; | ||
312 | } | ||
313 | da = a1 - a0; | ||
314 | db = b1 - b0; | ||
315 | a0_2 = a0 * a0; a0_3 = a0_2 * a0; a0_4 = a0_3 * a0; | ||
316 | b0_2 = b0 * b0; b0_3 = b0_2 * b0; b0_4 = b0_3 * b0; | ||
317 | a1_2 = a1 * a1; a1_3 = a1_2 * a1; | ||
318 | b1_2 = b1 * b1; b1_3 = b1_2 * b1; | ||
319 | |||
320 | C1 = a1 + a0; | ||
321 | Ca = a1*C1 + a0_2; Caa = a1*Ca + a0_3; Caaa = a1*Caa + a0_4; | ||
322 | Cb = b1*(b1 + b0) + b0_2; Cbb = b1*Cb + b0_3; Cbbb = b1*Cbb + b0_4; | ||
323 | Cab = 3*a1_2 + 2*a1*a0 + a0_2; Kab = a1_2 + 2*a1*a0 + 3*a0_2; | ||
324 | Caab = a0*Cab + 4*a1_3; Kaab = a1*Kab + 4*a0_3; | ||
325 | Cabb = 4*b1_3 + 3*b1_2*b0 + 2*b1*b0_2 + b0_3; | ||
326 | Kabb = b1_3 + 2*b1_2*b0 + 3*b1*b0_2 + 4*b0_3; | ||
327 | |||
328 | P1 += db*C1; | ||
329 | Pa += db*Ca; | ||
330 | Paa += db*Caa; | ||
331 | Paaa += db*Caaa; | ||
332 | Pb += da*Cb; | ||
333 | Pbb += da*Cbb; | ||
334 | Pbbb += da*Cbbb; | ||
335 | Pab += db*(b1*Cab + b0*Kab); | ||
336 | Paab += db*(b1*Caab + b0*Kaab); | ||
337 | Pabb += da*(a1*Cabb + a0*Kabb); | ||
338 | } | ||
339 | |||
340 | P1 /= 2.0; | ||
341 | Pa /= 6.0; | ||
342 | Paa /= 12.0; | ||
343 | Paaa /= 20.0; | ||
344 | Pb /= -6.0; | ||
345 | Pbb /= -12.0; | ||
346 | Pbbb /= -20.0; | ||
347 | Pab /= 24.0; | ||
348 | Paab /= 60.0; | ||
349 | Pabb /= -60.0; | ||
350 | } | ||
351 | |||
352 | w = - dDOT(n, v0); | ||
353 | |||
354 | k1 = 1 / n[C]; k2 = k1 * k1; k3 = k2 * k1; k4 = k3 * k1; | ||
355 | |||
356 | Fa = k1 * Pa; | ||
357 | Fb = k1 * Pb; | ||
358 | Fc = -k2 * (n[A]*Pa + n[B]*Pb + w*P1); | ||
359 | |||
360 | Faa = k1 * Paa; | ||
361 | Fbb = k1 * Pbb; | ||
362 | Fcc = k3 * (SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb + | ||
363 | w*(2*(n[A]*Pa + n[B]*Pb) + w*P1)); | ||
364 | |||
365 | Faaa = k1 * Paaa; | ||
366 | Fbbb = k1 * Pbbb; | ||
367 | Fccc = -k4 * (CUBE(n[A])*Paaa + 3*SQR(n[A])*n[B]*Paab | ||
368 | + 3*n[A]*SQR(n[B])*Pabb + CUBE(n[B])*Pbbb | ||
369 | + 3*w*(SQR(n[A])*Paa + 2*n[A]*n[B]*Pab + SQR(n[B])*Pbb) | ||
370 | + w*w*(3*(n[A]*Pa + n[B]*Pb) + w*P1)); | ||
371 | |||
372 | Faab = k1 * Paab; | ||
373 | Fbbc = -k2 * (n[A]*Pabb + n[B]*Pbbb + w*Pbb); | ||
374 | Fcca = k3 * (SQR(n[A])*Paaa + 2*n[A]*n[B]*Paab + SQR(n[B])*Pabb | ||
375 | + w*(2*(n[A]*Paa + n[B]*Pab) + w*Pa)); | ||
376 | } | ||
377 | |||
378 | |||
379 | T0 += n[0] * ((A == 0) ? Fa : ((B == 0) ? Fb : Fc)); | ||
380 | |||
381 | T1[A] += n[A] * Faa; | ||
382 | T1[B] += n[B] * Fbb; | ||
383 | T1[C] += n[C] * Fcc; | ||
384 | T2[A] += n[A] * Faaa; | ||
385 | T2[B] += n[B] * Fbbb; | ||
386 | T2[C] += n[C] * Fccc; | ||
387 | TP[A] += n[A] * Faab; | ||
388 | TP[B] += n[B] * Fbbc; | ||
389 | TP[C] += n[C] * Fcca; | ||
390 | } | ||
391 | |||
392 | T1[0] /= 2; T1[1] /= 2; T1[2] /= 2; | ||
393 | T2[0] /= 3; T2[1] /= 3; T2[2] /= 3; | ||
394 | TP[0] /= 2; TP[1] /= 2; TP[2] /= 2; | ||
395 | |||
396 | m->mass = density * T0; | ||
397 | m->_I(0,0) = density * (T2[1] + T2[2]); | ||
398 | m->_I(1,1) = density * (T2[2] + T2[0]); | ||
399 | m->_I(2,2) = density * (T2[0] + T2[1]); | ||
400 | m->_I(0,1) = - density * TP[0]; | ||
401 | m->_I(1,0) = - density * TP[0]; | ||
402 | m->_I(2,1) = - density * TP[1]; | ||
403 | m->_I(1,2) = - density * TP[1]; | ||
404 | m->_I(2,0) = - density * TP[2]; | ||
405 | m->_I(0,2) = - density * TP[2]; | ||
406 | |||
407 | // Added to address SF bug 1729095 | ||
408 | dMassTranslate( m, T1[0] / T0, T1[1] / T0, T1[2] / T0 ); | ||
409 | |||
410 | # ifndef dNODEBUG | ||
411 | dMassCheck (m); | ||
412 | # endif | ||
413 | } | ||
414 | |||
415 | |||
416 | void dMassSetTrimeshTotal( dMass *m, dReal total_mass, dGeomID g) | ||
417 | { | ||
418 | dAASSERT( m ); | ||
419 | dUASSERT( g && g->type == dTriMeshClass, "argument not a trimesh" ); | ||
420 | dMassSetTrimesh( m, 1.0, g ); | ||
421 | dMassAdjust( m, total_mass ); | ||
422 | } | ||
423 | |||
424 | #endif // dTRIMESH_ENABLED | ||
425 | |||
426 | |||
427 | |||
428 | |||
429 | void dMassAdjust (dMass *m, dReal newmass) | ||
430 | { | ||
431 | dAASSERT (m); | ||
432 | dReal scale = newmass / m->mass; | ||
433 | m->mass = newmass; | ||
434 | for (int i=0; i<3; i++) for (int j=0; j<3; j++) m->_I(i,j) *= scale; | ||
435 | |||
436 | # ifndef dNODEBUG | ||
437 | dMassCheck (m); | ||
438 | # endif | ||
439 | } | ||
440 | |||
441 | |||
442 | void dMassTranslate (dMass *m, dReal x, dReal y, dReal z) | ||
443 | { | ||
444 | // if the body is translated by `a' relative to its point of reference, | ||
445 | // the new inertia about the point of reference is: | ||
446 | // | ||
447 | // I + mass*(crossmat(c)^2 - crossmat(c+a)^2) | ||
448 | // | ||
449 | // where c is the existing center of mass and I is the old inertia. | ||
450 | |||
451 | int i,j; | ||
452 | dMatrix3 ahat,chat,t1,t2; | ||
453 | dReal a[3]; | ||
454 | |||
455 | dAASSERT (m); | ||
456 | |||
457 | // adjust inertia matrix | ||
458 | dSetZero (chat,12); | ||
459 | dCROSSMAT (chat,m->c,4,+,-); | ||
460 | a[0] = x + m->c[0]; | ||
461 | a[1] = y + m->c[1]; | ||
462 | a[2] = z + m->c[2]; | ||
463 | dSetZero (ahat,12); | ||
464 | dCROSSMAT (ahat,a,4,+,-); | ||
465 | dMULTIPLY0_333 (t1,ahat,ahat); | ||
466 | dMULTIPLY0_333 (t2,chat,chat); | ||
467 | for (i=0; i<3; i++) for (j=0; j<3; j++) | ||
468 | m->_I(i,j) += m->mass * (t2[i*4+j]-t1[i*4+j]); | ||
469 | |||
470 | // ensure perfect symmetry | ||
471 | m->_I(1,0) = m->_I(0,1); | ||
472 | m->_I(2,0) = m->_I(0,2); | ||
473 | m->_I(2,1) = m->_I(1,2); | ||
474 | |||
475 | // adjust center of mass | ||
476 | m->c[0] += x; | ||
477 | m->c[1] += y; | ||
478 | m->c[2] += z; | ||
479 | |||
480 | # ifndef dNODEBUG | ||
481 | dMassCheck (m); | ||
482 | # endif | ||
483 | } | ||
484 | |||
485 | |||
486 | void dMassRotate (dMass *m, const dMatrix3 R) | ||
487 | { | ||
488 | // if the body is rotated by `R' relative to its point of reference, | ||
489 | // the new inertia about the point of reference is: | ||
490 | // | ||
491 | // R * I * R' | ||
492 | // | ||
493 | // where I is the old inertia. | ||
494 | |||
495 | dMatrix3 t1; | ||
496 | dReal t2[3]; | ||
497 | |||
498 | dAASSERT (m); | ||
499 | |||
500 | // rotate inertia matrix | ||
501 | dMULTIPLY2_333 (t1,m->I,R); | ||
502 | dMULTIPLY0_333 (m->I,R,t1); | ||
503 | |||
504 | // ensure perfect symmetry | ||
505 | m->_I(1,0) = m->_I(0,1); | ||
506 | m->_I(2,0) = m->_I(0,2); | ||
507 | m->_I(2,1) = m->_I(1,2); | ||
508 | |||
509 | // rotate center of mass | ||
510 | dMULTIPLY0_331 (t2,R,m->c); | ||
511 | m->c[0] = t2[0]; | ||
512 | m->c[1] = t2[1]; | ||
513 | m->c[2] = t2[2]; | ||
514 | |||
515 | # ifndef dNODEBUG | ||
516 | dMassCheck (m); | ||
517 | # endif | ||
518 | } | ||
519 | |||
520 | |||
521 | void dMassAdd (dMass *a, const dMass *b) | ||
522 | { | ||
523 | int i; | ||
524 | dAASSERT (a && b); | ||
525 | dReal denom = dRecip (a->mass + b->mass); | ||
526 | for (i=0; i<3; i++) a->c[i] = (a->c[i]*a->mass + b->c[i]*b->mass)*denom; | ||
527 | a->mass += b->mass; | ||
528 | for (i=0; i<12; i++) a->I[i] += b->I[i]; | ||
529 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/mat.cpp b/libraries/ode-0.9\/ode/src/mat.cpp new file mode 100755 index 0000000..6e635dc --- /dev/null +++ b/libraries/ode-0.9\/ode/src/mat.cpp | |||
@@ -0,0 +1,230 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/misc.h> | ||
25 | #include <ode/matrix.h> | ||
26 | #include <ode/error.h> | ||
27 | #include <ode/memory.h> | ||
28 | #include "mat.h" | ||
29 | |||
30 | |||
31 | dMatrix::dMatrix() | ||
32 | { | ||
33 | n = 0; | ||
34 | m = 0; | ||
35 | data = 0; | ||
36 | } | ||
37 | |||
38 | |||
39 | dMatrix::dMatrix (int rows, int cols) | ||
40 | { | ||
41 | if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); | ||
42 | n = rows; | ||
43 | m = cols; | ||
44 | data = (dReal*) dAlloc (n*m*sizeof(dReal)); | ||
45 | dSetZero (data,n*m); | ||
46 | } | ||
47 | |||
48 | |||
49 | dMatrix::dMatrix (const dMatrix &a) | ||
50 | { | ||
51 | n = a.n; | ||
52 | m = a.m; | ||
53 | data = (dReal*) dAlloc (n*m*sizeof(dReal)); | ||
54 | memcpy (data,a.data,n*m*sizeof(dReal)); | ||
55 | } | ||
56 | |||
57 | |||
58 | dMatrix::dMatrix (int rows, int cols, | ||
59 | dReal *_data, int rowskip, int colskip) | ||
60 | { | ||
61 | if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); | ||
62 | n = rows; | ||
63 | m = cols; | ||
64 | data = (dReal*) dAlloc (n*m*sizeof(dReal)); | ||
65 | for (int i=0; i<n; i++) { | ||
66 | for (int j=0; j<m; j++) data[i*m+j] = _data[i*rowskip + j*colskip]; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | |||
71 | dMatrix::~dMatrix() | ||
72 | { | ||
73 | if (data) dFree (data,n*m*sizeof(dReal)); | ||
74 | } | ||
75 | |||
76 | |||
77 | dReal & dMatrix::operator () (int i, int j) | ||
78 | { | ||
79 | if (i < 0 || i >= n || j < 0 || j >= m) dDebug (0,"bad matrix (i,j)"); | ||
80 | return data [i*m+j]; | ||
81 | } | ||
82 | |||
83 | |||
84 | void dMatrix::operator= (const dMatrix &a) | ||
85 | { | ||
86 | if (data) dFree (data,n*m*sizeof(dReal)); | ||
87 | n = a.n; | ||
88 | m = a.m; | ||
89 | if (n > 0 && m > 0) { | ||
90 | data = (dReal*) dAlloc (n*m*sizeof(dReal)); | ||
91 | memcpy (data,a.data,n*m*sizeof(dReal)); | ||
92 | } | ||
93 | else data = 0; | ||
94 | } | ||
95 | |||
96 | |||
97 | void dMatrix::operator= (dReal a) | ||
98 | { | ||
99 | for (int i=0; i<n*m; i++) data[i] = a; | ||
100 | } | ||
101 | |||
102 | |||
103 | dMatrix dMatrix::transpose() | ||
104 | { | ||
105 | dMatrix r (m,n); | ||
106 | for (int i=0; i<n; i++) { | ||
107 | for (int j=0; j<m; j++) r.data[j*n+i] = data[i*m+j]; | ||
108 | } | ||
109 | return r; | ||
110 | } | ||
111 | |||
112 | |||
113 | dMatrix dMatrix::select (int np, int *p, int nq, int *q) | ||
114 | { | ||
115 | if (np < 1 || nq < 1) dDebug (0,"Matrix select, bad index array sizes"); | ||
116 | dMatrix r (np,nq); | ||
117 | for (int i=0; i<np; i++) { | ||
118 | for (int j=0; j<nq; j++) { | ||
119 | if (p[i] < 0 || p[i] >= n || q[i] < 0 || q[i] >= m) | ||
120 | dDebug (0,"Matrix select, bad index arrays"); | ||
121 | r.data[i*nq+j] = data[p[i]*m+q[j]]; | ||
122 | } | ||
123 | } | ||
124 | return r; | ||
125 | } | ||
126 | |||
127 | |||
128 | dMatrix dMatrix::operator + (const dMatrix &a) | ||
129 | { | ||
130 | if (n != a.n || m != a.m) dDebug (0,"matrix +, mismatched sizes"); | ||
131 | dMatrix r (n,m); | ||
132 | for (int i=0; i<n*m; i++) r.data[i] = data[i] + a.data[i]; | ||
133 | return r; | ||
134 | } | ||
135 | |||
136 | |||
137 | dMatrix dMatrix::operator - (const dMatrix &a) | ||
138 | { | ||
139 | if (n != a.n || m != a.m) dDebug (0,"matrix -, mismatched sizes"); | ||
140 | dMatrix r (n,m); | ||
141 | for (int i=0; i<n*m; i++) r.data[i] = data[i] - a.data[i]; | ||
142 | return r; | ||
143 | } | ||
144 | |||
145 | |||
146 | dMatrix dMatrix::operator - () | ||
147 | { | ||
148 | dMatrix r (n,m); | ||
149 | for (int i=0; i<n*m; i++) r.data[i] = -data[i]; | ||
150 | return r; | ||
151 | } | ||
152 | |||
153 | |||
154 | dMatrix dMatrix::operator * (const dMatrix &a) | ||
155 | { | ||
156 | if (m != a.n) dDebug (0,"matrix *, mismatched sizes"); | ||
157 | dMatrix r (n,a.m); | ||
158 | for (int i=0; i<n; i++) { | ||
159 | for (int j=0; j<a.m; j++) { | ||
160 | dReal sum = 0; | ||
161 | for (int k=0; k<m; k++) sum += data[i*m+k] * a.data[k*a.m+j]; | ||
162 | r.data [i*a.m+j] = sum; | ||
163 | } | ||
164 | } | ||
165 | return r; | ||
166 | } | ||
167 | |||
168 | |||
169 | void dMatrix::operator += (const dMatrix &a) | ||
170 | { | ||
171 | if (n != a.n || m != a.m) dDebug (0,"matrix +=, mismatched sizes"); | ||
172 | for (int i=0; i<n*m; i++) data[i] += a.data[i]; | ||
173 | } | ||
174 | |||
175 | |||
176 | void dMatrix::operator -= (const dMatrix &a) | ||
177 | { | ||
178 | if (n != a.n || m != a.m) dDebug (0,"matrix -=, mismatched sizes"); | ||
179 | for (int i=0; i<n*m; i++) data[i] -= a.data[i]; | ||
180 | } | ||
181 | |||
182 | |||
183 | void dMatrix::clearUpperTriangle() | ||
184 | { | ||
185 | if (n != m) dDebug (0,"clearUpperTriangle() only works on square matrices"); | ||
186 | for (int i=0; i<n; i++) { | ||
187 | for (int j=i+1; j<m; j++) data[i*m+j] = 0; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | |||
192 | void dMatrix::clearLowerTriangle() | ||
193 | { | ||
194 | if (n != m) dDebug (0,"clearLowerTriangle() only works on square matrices"); | ||
195 | for (int i=0; i<n; i++) { | ||
196 | for (int j=0; j<i; j++) data[i*m+j] = 0; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | |||
201 | void dMatrix::makeRandom (dReal range) | ||
202 | { | ||
203 | for (int i=0; i<n; i++) { | ||
204 | for (int j=0; j<m; j++) | ||
205 | data[i*m+j] = (dRandReal()*REAL(2.0)-REAL(1.0))*range; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | void dMatrix::print (char *fmt, FILE *f) | ||
211 | { | ||
212 | for (int i=0; i<n; i++) { | ||
213 | for (int j=0; j<m; j++) fprintf (f,fmt,data[i*m+j]); | ||
214 | fprintf (f,"\n"); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | dReal dMatrix::maxDifference (const dMatrix &a) | ||
220 | { | ||
221 | if (n != a.n || m != a.m) dDebug (0,"maxDifference(), mismatched sizes"); | ||
222 | dReal max = 0; | ||
223 | for (int i=0; i<n; i++) { | ||
224 | for (int j=0; j<m; j++) { | ||
225 | dReal diff = dFabs(data[i*m+j] - a.data[i*m+j]); | ||
226 | if (diff > max) max = diff; | ||
227 | } | ||
228 | } | ||
229 | return max; | ||
230 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/mat.h b/libraries/ode-0.9\/ode/src/mat.h new file mode 100755 index 0000000..2814a01 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/mat.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // matrix class. this is mostly for convenience in the testing code, it is | ||
24 | // not optimized at all. correctness is much more importance here. | ||
25 | |||
26 | #ifndef _ODE_MAT_H_ | ||
27 | #define _ODE_MAT_H_ | ||
28 | |||
29 | #include <ode/common.h> | ||
30 | |||
31 | |||
32 | class dMatrix { | ||
33 | int n,m; // matrix dimension, n,m >= 0 | ||
34 | dReal *data; // if nonzero, n*m elements allocated on the heap | ||
35 | |||
36 | public: | ||
37 | // constructors, destructors | ||
38 | dMatrix(); // make default 0x0 matrix | ||
39 | dMatrix (int rows, int cols); // construct zero matrix of given size | ||
40 | dMatrix (const dMatrix &); // construct copy of given matrix | ||
41 | // create copy of given data - element (i,j) is data[i*rowskip+j*colskip] | ||
42 | dMatrix (int rows, int cols, dReal *_data, int rowskip, int colskip); | ||
43 | ~dMatrix(); // destructor | ||
44 | |||
45 | // data movement | ||
46 | dReal & operator () (int i, int j); // reference an element | ||
47 | void operator= (const dMatrix &); // matrix = matrix | ||
48 | void operator= (dReal); // matrix = scalar | ||
49 | dMatrix transpose(); // return transposed matrix | ||
50 | // return a permuted submatrix of this matrix, made up of the rows in p | ||
51 | // and the columns in q. p has np elements, q has nq elements. | ||
52 | dMatrix select (int np, int *p, int nq, int *q); | ||
53 | |||
54 | // operators | ||
55 | dMatrix operator + (const dMatrix &); | ||
56 | dMatrix operator - (const dMatrix &); | ||
57 | dMatrix operator - (); | ||
58 | dMatrix operator * (const dMatrix &); | ||
59 | void operator += (const dMatrix &); | ||
60 | void operator -= (const dMatrix &); | ||
61 | |||
62 | // utility | ||
63 | void clearUpperTriangle(); | ||
64 | void clearLowerTriangle(); | ||
65 | void makeRandom (dReal range); | ||
66 | void print (char *fmt = "%10.4f ", FILE *f=stdout); | ||
67 | dReal maxDifference (const dMatrix &); | ||
68 | }; | ||
69 | |||
70 | |||
71 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/matrix.cpp b/libraries/ode-0.9\/ode/src/matrix.cpp new file mode 100755 index 0000000..16afe91 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/matrix.cpp | |||
@@ -0,0 +1,358 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/common.h> | ||
24 | #include <ode/matrix.h> | ||
25 | |||
26 | // misc defines | ||
27 | #define ALLOCA dALLOCA16 | ||
28 | |||
29 | |||
30 | void dSetZero (dReal *a, int n) | ||
31 | { | ||
32 | dAASSERT (a && n >= 0); | ||
33 | while (n > 0) { | ||
34 | *(a++) = 0; | ||
35 | n--; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | |||
40 | void dSetValue (dReal *a, int n, dReal value) | ||
41 | { | ||
42 | dAASSERT (a && n >= 0); | ||
43 | while (n > 0) { | ||
44 | *(a++) = value; | ||
45 | n--; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | |||
50 | void dMultiply0 (dReal *A, const dReal *B, const dReal *C, int p, int q, int r) | ||
51 | { | ||
52 | int i,j,k,qskip,rskip,rpad; | ||
53 | dAASSERT (A && B && C && p>0 && q>0 && r>0); | ||
54 | qskip = dPAD(q); | ||
55 | rskip = dPAD(r); | ||
56 | rpad = rskip - r; | ||
57 | dReal sum; | ||
58 | const dReal *b,*c,*bb; | ||
59 | bb = B; | ||
60 | for (i=p; i; i--) { | ||
61 | for (j=0 ; j<r; j++) { | ||
62 | c = C + j; | ||
63 | b = bb; | ||
64 | sum = 0; | ||
65 | for (k=q; k; k--, c+=rskip) sum += (*(b++))*(*c); | ||
66 | *(A++) = sum; | ||
67 | } | ||
68 | A += rpad; | ||
69 | bb += qskip; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | |||
74 | void dMultiply1 (dReal *A, const dReal *B, const dReal *C, int p, int q, int r) | ||
75 | { | ||
76 | int i,j,k,pskip,rskip; | ||
77 | dReal sum; | ||
78 | dAASSERT (A && B && C && p>0 && q>0 && r>0); | ||
79 | pskip = dPAD(p); | ||
80 | rskip = dPAD(r); | ||
81 | for (i=0; i<p; i++) { | ||
82 | for (j=0; j<r; j++) { | ||
83 | sum = 0; | ||
84 | for (k=0; k<q; k++) sum += B[i+k*pskip] * C[j+k*rskip]; | ||
85 | A[i*rskip+j] = sum; | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | |||
90 | |||
91 | void dMultiply2 (dReal *A, const dReal *B, const dReal *C, int p, int q, int r) | ||
92 | { | ||
93 | int i,j,k,z,rpad,qskip; | ||
94 | dReal sum; | ||
95 | const dReal *bb,*cc; | ||
96 | dAASSERT (A && B && C && p>0 && q>0 && r>0); | ||
97 | rpad = dPAD(r) - r; | ||
98 | qskip = dPAD(q); | ||
99 | bb = B; | ||
100 | for (i=p; i; i--) { | ||
101 | cc = C; | ||
102 | for (j=r; j; j--) { | ||
103 | z = 0; | ||
104 | sum = 0; | ||
105 | for (k=q; k; k--,z++) sum += bb[z] * cc[z]; | ||
106 | *(A++) = sum; | ||
107 | cc += qskip; | ||
108 | } | ||
109 | A += rpad; | ||
110 | bb += qskip; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | |||
115 | int dFactorCholesky (dReal *A, int n) | ||
116 | { | ||
117 | int i,j,k,nskip; | ||
118 | dReal sum,*a,*b,*aa,*bb,*cc,*recip; | ||
119 | dAASSERT (n > 0 && A); | ||
120 | nskip = dPAD (n); | ||
121 | recip = (dReal*) ALLOCA (n * sizeof(dReal)); | ||
122 | aa = A; | ||
123 | for (i=0; i<n; i++) { | ||
124 | bb = A; | ||
125 | cc = A + i*nskip; | ||
126 | for (j=0; j<i; j++) { | ||
127 | sum = *cc; | ||
128 | a = aa; | ||
129 | b = bb; | ||
130 | for (k=j; k; k--) sum -= (*(a++))*(*(b++)); | ||
131 | *cc = sum * recip[j]; | ||
132 | bb += nskip; | ||
133 | cc++; | ||
134 | } | ||
135 | sum = *cc; | ||
136 | a = aa; | ||
137 | for (k=i; k; k--, a++) sum -= (*a)*(*a); | ||
138 | if (sum <= REAL(0.0)) return 0; | ||
139 | *cc = dSqrt(sum); | ||
140 | recip[i] = dRecip (*cc); | ||
141 | aa += nskip; | ||
142 | } | ||
143 | return 1; | ||
144 | } | ||
145 | |||
146 | |||
147 | void dSolveCholesky (const dReal *L, dReal *b, int n) | ||
148 | { | ||
149 | int i,k,nskip; | ||
150 | dReal sum,*y; | ||
151 | dAASSERT (n > 0 && L && b); | ||
152 | nskip = dPAD (n); | ||
153 | y = (dReal*) ALLOCA (n*sizeof(dReal)); | ||
154 | for (i=0; i<n; i++) { | ||
155 | sum = 0; | ||
156 | for (k=0; k < i; k++) sum += L[i*nskip+k]*y[k]; | ||
157 | y[i] = (b[i]-sum)/L[i*nskip+i]; | ||
158 | } | ||
159 | for (i=n-1; i >= 0; i--) { | ||
160 | sum = 0; | ||
161 | for (k=i+1; k < n; k++) sum += L[k*nskip+i]*b[k]; | ||
162 | b[i] = (y[i]-sum)/L[i*nskip+i]; | ||
163 | } | ||
164 | } | ||
165 | |||
166 | |||
167 | int dInvertPDMatrix (const dReal *A, dReal *Ainv, int n) | ||
168 | { | ||
169 | int i,j,nskip; | ||
170 | dReal *L,*x; | ||
171 | dAASSERT (n > 0 && A && Ainv); | ||
172 | nskip = dPAD (n); | ||
173 | L = (dReal*) ALLOCA (nskip*n*sizeof(dReal)); | ||
174 | memcpy (L,A,nskip*n*sizeof(dReal)); | ||
175 | x = (dReal*) ALLOCA (n*sizeof(dReal)); | ||
176 | if (dFactorCholesky (L,n)==0) return 0; | ||
177 | dSetZero (Ainv,n*nskip); // make sure all padding elements set to 0 | ||
178 | for (i=0; i<n; i++) { | ||
179 | for (j=0; j<n; j++) x[j] = 0; | ||
180 | x[i] = 1; | ||
181 | dSolveCholesky (L,x,n); | ||
182 | for (j=0; j<n; j++) Ainv[j*nskip+i] = x[j]; | ||
183 | } | ||
184 | return 1; | ||
185 | } | ||
186 | |||
187 | |||
188 | int dIsPositiveDefinite (const dReal *A, int n) | ||
189 | { | ||
190 | dReal *Acopy; | ||
191 | dAASSERT (n > 0 && A); | ||
192 | int nskip = dPAD (n); | ||
193 | Acopy = (dReal*) ALLOCA (nskip*n * sizeof(dReal)); | ||
194 | memcpy (Acopy,A,nskip*n * sizeof(dReal)); | ||
195 | return dFactorCholesky (Acopy,n); | ||
196 | } | ||
197 | |||
198 | |||
199 | /***** this has been replaced by a faster version | ||
200 | void dSolveL1T (const dReal *L, dReal *b, int n, int nskip) | ||
201 | { | ||
202 | int i,j; | ||
203 | dAASSERT (L && b && n >= 0 && nskip >= n); | ||
204 | dReal sum; | ||
205 | for (i=n-2; i>=0; i--) { | ||
206 | sum = 0; | ||
207 | for (j=i+1; j<n; j++) sum += L[j*nskip+i]*b[j]; | ||
208 | b[i] -= sum; | ||
209 | } | ||
210 | } | ||
211 | */ | ||
212 | |||
213 | |||
214 | void dVectorScale (dReal *a, const dReal *d, int n) | ||
215 | { | ||
216 | dAASSERT (a && d && n >= 0); | ||
217 | for (int i=0; i<n; i++) a[i] *= d[i]; | ||
218 | } | ||
219 | |||
220 | |||
221 | void dSolveLDLT (const dReal *L, const dReal *d, dReal *b, int n, int nskip) | ||
222 | { | ||
223 | dAASSERT (L && d && b && n > 0 && nskip >= n); | ||
224 | dSolveL1 (L,b,n,nskip); | ||
225 | dVectorScale (b,d,n); | ||
226 | dSolveL1T (L,b,n,nskip); | ||
227 | } | ||
228 | |||
229 | |||
230 | void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip) | ||
231 | { | ||
232 | int j,p; | ||
233 | dReal *W1,*W2,W11,W21,alpha1,alpha2,alphanew,gamma1,gamma2,k1,k2,Wp,ell,dee; | ||
234 | dAASSERT (L && d && a && n > 0 && nskip >= n); | ||
235 | |||
236 | if (n < 2) return; | ||
237 | W1 = (dReal*) ALLOCA (n*sizeof(dReal)); | ||
238 | W2 = (dReal*) ALLOCA (n*sizeof(dReal)); | ||
239 | |||
240 | W1[0] = 0; | ||
241 | W2[0] = 0; | ||
242 | for (j=1; j<n; j++) W1[j] = W2[j] = a[j] * M_SQRT1_2; | ||
243 | W11 = (REAL(0.5)*a[0]+1)*M_SQRT1_2; | ||
244 | W21 = (REAL(0.5)*a[0]-1)*M_SQRT1_2; | ||
245 | |||
246 | alpha1=1; | ||
247 | alpha2=1; | ||
248 | |||
249 | dee = d[0]; | ||
250 | alphanew = alpha1 + (W11*W11)*dee; | ||
251 | dee /= alphanew; | ||
252 | gamma1 = W11 * dee; | ||
253 | dee *= alpha1; | ||
254 | alpha1 = alphanew; | ||
255 | alphanew = alpha2 - (W21*W21)*dee; | ||
256 | dee /= alphanew; | ||
257 | gamma2 = W21 * dee; | ||
258 | alpha2 = alphanew; | ||
259 | k1 = REAL(1.0) - W21*gamma1; | ||
260 | k2 = W21*gamma1*W11 - W21; | ||
261 | for (p=1; p<n; p++) { | ||
262 | Wp = W1[p]; | ||
263 | ell = L[p*nskip]; | ||
264 | W1[p] = Wp - W11*ell; | ||
265 | W2[p] = k1*Wp + k2*ell; | ||
266 | } | ||
267 | |||
268 | for (j=1; j<n; j++) { | ||
269 | dee = d[j]; | ||
270 | alphanew = alpha1 + (W1[j]*W1[j])*dee; | ||
271 | dee /= alphanew; | ||
272 | gamma1 = W1[j] * dee; | ||
273 | dee *= alpha1; | ||
274 | alpha1 = alphanew; | ||
275 | alphanew = alpha2 - (W2[j]*W2[j])*dee; | ||
276 | dee /= alphanew; | ||
277 | gamma2 = W2[j] * dee; | ||
278 | dee *= alpha2; | ||
279 | d[j] = dee; | ||
280 | alpha2 = alphanew; | ||
281 | |||
282 | k1 = W1[j]; | ||
283 | k2 = W2[j]; | ||
284 | for (p=j+1; p<n; p++) { | ||
285 | ell = L[p*nskip+j]; | ||
286 | Wp = W1[p] - k1 * ell; | ||
287 | ell += gamma1 * Wp; | ||
288 | W1[p] = Wp; | ||
289 | Wp = W2[p] - k2 * ell; | ||
290 | ell -= gamma2 * Wp; | ||
291 | W2[p] = Wp; | ||
292 | L[p*nskip+j] = ell; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | |||
298 | // macros for dLDLTRemove() for accessing A - either access the matrix | ||
299 | // directly or access it via row pointers. we are only supposed to reference | ||
300 | // the lower triangle of A (it is symmetric), but indexes i and j come from | ||
301 | // permutation vectors so they are not predictable. so do a test on the | ||
302 | // indexes - this should not slow things down too much, as we don't do this | ||
303 | // in an inner loop. | ||
304 | |||
305 | #define _GETA(i,j) (A[i][j]) | ||
306 | //#define _GETA(i,j) (A[(i)*nskip+(j)]) | ||
307 | #define GETA(i,j) ((i > j) ? _GETA(i,j) : _GETA(j,i)) | ||
308 | |||
309 | |||
310 | void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, | ||
311 | int n1, int n2, int r, int nskip) | ||
312 | { | ||
313 | int i; | ||
314 | dAASSERT(A && p && L && d && n1 > 0 && n2 > 0 && r >= 0 && r < n2 && | ||
315 | n1 >= n2 && nskip >= n1); | ||
316 | #ifndef dNODEBUG | ||
317 | for (i=0; i<n2; i++) dIASSERT(p[i] >= 0 && p[i] < n1); | ||
318 | #endif | ||
319 | |||
320 | if (r==n2-1) { | ||
321 | return; // deleting last row/col is easy | ||
322 | } | ||
323 | else if (r==0) { | ||
324 | dReal *a = (dReal*) ALLOCA (n2 * sizeof(dReal)); | ||
325 | for (i=0; i<n2; i++) a[i] = -GETA(p[i],p[0]); | ||
326 | a[0] += REAL(1.0); | ||
327 | dLDLTAddTL (L,d,a,n2,nskip); | ||
328 | } | ||
329 | else { | ||
330 | dReal *t = (dReal*) ALLOCA (r * sizeof(dReal)); | ||
331 | dReal *a = (dReal*) ALLOCA ((n2-r) * sizeof(dReal)); | ||
332 | for (i=0; i<r; i++) t[i] = L[r*nskip+i] / d[i]; | ||
333 | for (i=0; i<(n2-r); i++) | ||
334 | a[i] = dDot(L+(r+i)*nskip,t,r) - GETA(p[r+i],p[r]); | ||
335 | a[0] += REAL(1.0); | ||
336 | dLDLTAddTL (L + r*nskip+r, d+r, a, n2-r, nskip); | ||
337 | } | ||
338 | |||
339 | // snip out row/column r from L and d | ||
340 | dRemoveRowCol (L,n2,nskip,r); | ||
341 | if (r < (n2-1)) memmove (d+r,d+r+1,(n2-r-1)*sizeof(dReal)); | ||
342 | } | ||
343 | |||
344 | |||
345 | void dRemoveRowCol (dReal *A, int n, int nskip, int r) | ||
346 | { | ||
347 | int i; | ||
348 | dAASSERT(A && n > 0 && nskip >= n && r >= 0 && r < n); | ||
349 | if (r >= n-1) return; | ||
350 | if (r > 0) { | ||
351 | for (i=0; i<r; i++) | ||
352 | memmove (A+i*nskip+r,A+i*nskip+r+1,(n-r-1)*sizeof(dReal)); | ||
353 | for (i=r; i<(n-1); i++) | ||
354 | memcpy (A+i*nskip,A+i*nskip+nskip,r*sizeof(dReal)); | ||
355 | } | ||
356 | for (i=r; i<(n-1); i++) | ||
357 | memcpy (A+i*nskip+r,A+i*nskip+nskip+r+1,(n-r-1)*sizeof(dReal)); | ||
358 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/memory.cpp b/libraries/ode-0.9\/ode/src/memory.cpp new file mode 100755 index 0000000..60bb5b6 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/memory.cpp | |||
@@ -0,0 +1,87 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/memory.h> | ||
25 | #include <ode/error.h> | ||
26 | |||
27 | |||
28 | static dAllocFunction *allocfn = 0; | ||
29 | static dReallocFunction *reallocfn = 0; | ||
30 | static dFreeFunction *freefn = 0; | ||
31 | |||
32 | |||
33 | |||
34 | void dSetAllocHandler (dAllocFunction *fn) | ||
35 | { | ||
36 | allocfn = fn; | ||
37 | } | ||
38 | |||
39 | |||
40 | void dSetReallocHandler (dReallocFunction *fn) | ||
41 | { | ||
42 | reallocfn = fn; | ||
43 | } | ||
44 | |||
45 | |||
46 | void dSetFreeHandler (dFreeFunction *fn) | ||
47 | { | ||
48 | freefn = fn; | ||
49 | } | ||
50 | |||
51 | |||
52 | dAllocFunction *dGetAllocHandler() | ||
53 | { | ||
54 | return allocfn; | ||
55 | } | ||
56 | |||
57 | |||
58 | dReallocFunction *dGetReallocHandler() | ||
59 | { | ||
60 | return reallocfn; | ||
61 | } | ||
62 | |||
63 | |||
64 | dFreeFunction *dGetFreeHandler() | ||
65 | { | ||
66 | return freefn; | ||
67 | } | ||
68 | |||
69 | |||
70 | void * dAlloc (size_t size) | ||
71 | { | ||
72 | if (allocfn) return allocfn (size); else return malloc (size); | ||
73 | } | ||
74 | |||
75 | |||
76 | void * dRealloc (void *ptr, size_t oldsize, size_t newsize) | ||
77 | { | ||
78 | if (reallocfn) return reallocfn (ptr,oldsize,newsize); | ||
79 | else return realloc (ptr,newsize); | ||
80 | } | ||
81 | |||
82 | |||
83 | void dFree (void *ptr, size_t size) | ||
84 | { | ||
85 | if (!ptr) return; | ||
86 | if (freefn) freefn (ptr,size); else free (ptr); | ||
87 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/misc.cpp b/libraries/ode-0.9\/ode/src/misc.cpp new file mode 100755 index 0000000..1a6f263 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/misc.cpp | |||
@@ -0,0 +1,169 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/misc.h> | ||
25 | #include <ode/matrix.h> | ||
26 | |||
27 | //**************************************************************************** | ||
28 | // random numbers | ||
29 | |||
30 | static unsigned long seed = 0; | ||
31 | |||
32 | unsigned long dRand() | ||
33 | { | ||
34 | seed = (1664525L*seed + 1013904223L) & 0xffffffff; | ||
35 | return seed; | ||
36 | } | ||
37 | |||
38 | |||
39 | unsigned long dRandGetSeed() | ||
40 | { | ||
41 | return seed; | ||
42 | } | ||
43 | |||
44 | |||
45 | void dRandSetSeed (unsigned long s) | ||
46 | { | ||
47 | seed = s; | ||
48 | } | ||
49 | |||
50 | |||
51 | int dTestRand() | ||
52 | { | ||
53 | unsigned long oldseed = seed; | ||
54 | int ret = 1; | ||
55 | seed = 0; | ||
56 | if (dRand() != 0x3c6ef35f || dRand() != 0x47502932 || | ||
57 | dRand() != 0xd1ccf6e9 || dRand() != 0xaaf95334 || | ||
58 | dRand() != 0x6252e503) ret = 0; | ||
59 | seed = oldseed; | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | |||
64 | // adam's all-int straightforward(?) dRandInt (0..n-1) | ||
65 | int dRandInt (int n) | ||
66 | { | ||
67 | // seems good; xor-fold and modulus | ||
68 | const unsigned long un = n; | ||
69 | unsigned long r = dRand(); | ||
70 | |||
71 | // note: probably more aggressive than it needs to be -- might be | ||
72 | // able to get away without one or two of the innermost branches. | ||
73 | if (un <= 0x00010000UL) { | ||
74 | r ^= (r >> 16); | ||
75 | if (un <= 0x00000100UL) { | ||
76 | r ^= (r >> 8); | ||
77 | if (un <= 0x00000010UL) { | ||
78 | r ^= (r >> 4); | ||
79 | if (un <= 0x00000004UL) { | ||
80 | r ^= (r >> 2); | ||
81 | if (un <= 0x00000002UL) { | ||
82 | r ^= (r >> 1); | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | return (int) (r % un); | ||
90 | } | ||
91 | |||
92 | |||
93 | dReal dRandReal() | ||
94 | { | ||
95 | return ((dReal) dRand()) / ((dReal) 0xffffffff); | ||
96 | } | ||
97 | |||
98 | //**************************************************************************** | ||
99 | // matrix utility stuff | ||
100 | |||
101 | void dPrintMatrix (const dReal *A, int n, int m, char *fmt, FILE *f) | ||
102 | { | ||
103 | int i,j; | ||
104 | int skip = dPAD(m); | ||
105 | for (i=0; i<n; i++) { | ||
106 | for (j=0; j<m; j++) fprintf (f,fmt,A[i*skip+j]); | ||
107 | fprintf (f,"\n"); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | |||
112 | void dMakeRandomVector (dReal *A, int n, dReal range) | ||
113 | { | ||
114 | int i; | ||
115 | for (i=0; i<n; i++) A[i] = (dRandReal()*REAL(2.0)-REAL(1.0))*range; | ||
116 | } | ||
117 | |||
118 | |||
119 | void dMakeRandomMatrix (dReal *A, int n, int m, dReal range) | ||
120 | { | ||
121 | int i,j; | ||
122 | int skip = dPAD(m); | ||
123 | dSetZero (A,n*skip); | ||
124 | for (i=0; i<n; i++) { | ||
125 | for (j=0; j<m; j++) A[i*skip+j] = (dRandReal()*REAL(2.0)-REAL(1.0))*range; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | |||
130 | void dClearUpperTriangle (dReal *A, int n) | ||
131 | { | ||
132 | int i,j; | ||
133 | int skip = dPAD(n); | ||
134 | for (i=0; i<n; i++) { | ||
135 | for (j=i+1; j<n; j++) A[i*skip+j] = 0; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | |||
140 | dReal dMaxDifference (const dReal *A, const dReal *B, int n, int m) | ||
141 | { | ||
142 | int i,j; | ||
143 | int skip = dPAD(m); | ||
144 | dReal diff,max; | ||
145 | max = 0; | ||
146 | for (i=0; i<n; i++) { | ||
147 | for (j=0; j<m; j++) { | ||
148 | diff = dFabs(A[i*skip+j] - B[i*skip+j]); | ||
149 | if (diff > max) max = diff; | ||
150 | } | ||
151 | } | ||
152 | return max; | ||
153 | } | ||
154 | |||
155 | |||
156 | dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n) | ||
157 | { | ||
158 | int i,j; | ||
159 | int skip = dPAD(n); | ||
160 | dReal diff,max; | ||
161 | max = 0; | ||
162 | for (i=0; i<n; i++) { | ||
163 | for (j=0; j<=i; j++) { | ||
164 | diff = dFabs(A[i*skip+j] - B[i*skip+j]); | ||
165 | if (diff > max) max = diff; | ||
166 | } | ||
167 | } | ||
168 | return max; | ||
169 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/objects.h b/libraries/ode-0.9\/ode/src/objects.h new file mode 100755 index 0000000..f286e2d --- /dev/null +++ b/libraries/ode-0.9\/ode/src/objects.h | |||
@@ -0,0 +1,138 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // object, body, and world structs. | ||
24 | |||
25 | |||
26 | #ifndef _ODE_OBJECT_H_ | ||
27 | #define _ODE_OBJECT_H_ | ||
28 | |||
29 | #include <ode/common.h> | ||
30 | #include <ode/memory.h> | ||
31 | #include <ode/mass.h> | ||
32 | #include "array.h" | ||
33 | |||
34 | |||
35 | // some body flags | ||
36 | |||
37 | enum { | ||
38 | dxBodyFlagFiniteRotation = 1, // use finite rotations | ||
39 | dxBodyFlagFiniteRotationAxis = 2, // use finite rotations only along axis | ||
40 | dxBodyDisabled = 4, // body is disabled | ||
41 | dxBodyNoGravity = 8, // body is not influenced by gravity | ||
42 | dxBodyAutoDisable = 16 // enable auto-disable on body | ||
43 | }; | ||
44 | |||
45 | |||
46 | // base class that does correct object allocation / deallocation | ||
47 | |||
48 | struct dBase { | ||
49 | void *operator new (size_t size) { return dAlloc (size); } | ||
50 | void operator delete (void *ptr, size_t size) { dFree (ptr,size); } | ||
51 | void *operator new[] (size_t size) { return dAlloc (size); } | ||
52 | void operator delete[] (void *ptr, size_t size) { dFree (ptr,size); } | ||
53 | }; | ||
54 | |||
55 | |||
56 | // base class for bodies and joints | ||
57 | |||
58 | struct dObject : public dBase { | ||
59 | dxWorld *world; // world this object is in | ||
60 | dObject *next; // next object of this type in list | ||
61 | dObject **tome; // pointer to previous object's next ptr | ||
62 | void *userdata; // user settable data | ||
63 | int tag; // used by dynamics algorithms | ||
64 | }; | ||
65 | |||
66 | |||
67 | // auto disable parameters | ||
68 | struct dxAutoDisable { | ||
69 | dReal idle_time; // time the body needs to be idle to auto-disable it | ||
70 | int idle_steps; // steps the body needs to be idle to auto-disable it | ||
71 | dReal linear_average_threshold; // linear (squared) average velocity threshold | ||
72 | dReal angular_average_threshold; // angular (squared) average velocity threshold | ||
73 | unsigned int average_samples; // size of the average_lvel and average_avel buffers | ||
74 | }; | ||
75 | |||
76 | |||
77 | // quick-step parameters | ||
78 | struct dxQuickStepParameters { | ||
79 | int num_iterations; // number of SOR iterations to perform | ||
80 | dReal w; // the SOR over-relaxation parameter | ||
81 | }; | ||
82 | |||
83 | |||
84 | // contact generation parameters | ||
85 | struct dxContactParameters { | ||
86 | dReal max_vel; // maximum correcting velocity | ||
87 | dReal min_depth; // thickness of 'surface layer' | ||
88 | }; | ||
89 | |||
90 | |||
91 | |||
92 | // position vector and rotation matrix for geometry objects that are not | ||
93 | // connected to bodies. | ||
94 | |||
95 | struct dxPosR { | ||
96 | dVector3 pos; | ||
97 | dMatrix3 R; | ||
98 | }; | ||
99 | |||
100 | struct dxBody : public dObject { | ||
101 | dxJointNode *firstjoint; // list of attached joints | ||
102 | int flags; // some dxBodyFlagXXX flags | ||
103 | dGeomID geom; // first collision geom associated with body | ||
104 | dMass mass; // mass parameters about POR | ||
105 | dMatrix3 invI; // inverse of mass.I | ||
106 | dReal invMass; // 1 / mass.mass | ||
107 | dxPosR posr; // position and orientation of point of reference | ||
108 | dQuaternion q; // orientation quaternion | ||
109 | dVector3 lvel,avel; // linear and angular velocity of POR | ||
110 | dVector3 facc,tacc; // force and torque accumulators | ||
111 | dVector3 finite_rot_axis; // finite rotation axis, unit length or 0=none | ||
112 | |||
113 | // auto-disable information | ||
114 | dxAutoDisable adis; // auto-disable parameters | ||
115 | dReal adis_timeleft; // time left to be idle | ||
116 | int adis_stepsleft; // steps left to be idle | ||
117 | dVector3* average_lvel_buffer; // buffer for the linear average velocity calculation | ||
118 | dVector3* average_avel_buffer; // buffer for the angular average velocity calculation | ||
119 | unsigned int average_counter; // counter/index to fill the average-buffers | ||
120 | int average_ready; // indicates ( with = 1 ), if the Body's buffers are ready for average-calculations | ||
121 | }; | ||
122 | |||
123 | |||
124 | struct dxWorld : public dBase { | ||
125 | dxBody *firstbody; // body linked list | ||
126 | dxJoint *firstjoint; // joint linked list | ||
127 | int nb,nj; // number of bodies and joints in lists | ||
128 | dVector3 gravity; // gravity vector (m/s/s) | ||
129 | dReal global_erp; // global error reduction parameter | ||
130 | dReal global_cfm; // global costraint force mixing parameter | ||
131 | dxAutoDisable adis; // auto-disable parameters | ||
132 | int adis_flag; // auto-disable flag for new bodies | ||
133 | dxQuickStepParameters qs; | ||
134 | dxContactParameters contactp; | ||
135 | }; | ||
136 | |||
137 | |||
138 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/obstack.cpp b/libraries/ode-0.9\/ode/src/obstack.cpp new file mode 100755 index 0000000..0840396 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/obstack.cpp | |||
@@ -0,0 +1,130 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/common.h> | ||
24 | #include <ode/error.h> | ||
25 | #include <ode/memory.h> | ||
26 | #include "obstack.h" | ||
27 | |||
28 | //**************************************************************************** | ||
29 | // macros and constants | ||
30 | |||
31 | #define ROUND_UP_OFFSET_TO_EFFICIENT_SIZE(arena,ofs) \ | ||
32 | ofs = (size_t) (dEFFICIENT_SIZE( ((intP)(arena)) + ofs ) - ((intP)(arena)) ); | ||
33 | |||
34 | #define MAX_ALLOC_SIZE \ | ||
35 | ((size_t)(dOBSTACK_ARENA_SIZE - sizeof (Arena) - EFFICIENT_ALIGNMENT + 1)) | ||
36 | |||
37 | //**************************************************************************** | ||
38 | // dObStack | ||
39 | |||
40 | dObStack::dObStack() | ||
41 | { | ||
42 | first = 0; | ||
43 | last = 0; | ||
44 | current_arena = 0; | ||
45 | current_ofs = 0; | ||
46 | } | ||
47 | |||
48 | |||
49 | dObStack::~dObStack() | ||
50 | { | ||
51 | // free all arenas | ||
52 | Arena *a,*nexta; | ||
53 | a = first; | ||
54 | while (a) { | ||
55 | nexta = a->next; | ||
56 | dFree (a,dOBSTACK_ARENA_SIZE); | ||
57 | a = nexta; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | void *dObStack::alloc (int num_bytes) | ||
63 | { | ||
64 | if ((size_t)num_bytes > MAX_ALLOC_SIZE) dDebug (0,"num_bytes too large"); | ||
65 | |||
66 | // allocate or move to a new arena if necessary | ||
67 | if (!first) { | ||
68 | // allocate the first arena if necessary | ||
69 | first = last = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); | ||
70 | first->next = 0; | ||
71 | first->used = sizeof (Arena); | ||
72 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); | ||
73 | } | ||
74 | else { | ||
75 | // we already have one or more arenas, see if a new arena must be used | ||
76 | if ((last->used + num_bytes) > dOBSTACK_ARENA_SIZE) { | ||
77 | if (!last->next) { | ||
78 | last->next = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); | ||
79 | last->next->next = 0; | ||
80 | } | ||
81 | last = last->next; | ||
82 | last->used = sizeof (Arena); | ||
83 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // allocate an area in the arena | ||
88 | char *c = ((char*) last) + last->used; | ||
89 | last->used += num_bytes; | ||
90 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); | ||
91 | return c; | ||
92 | } | ||
93 | |||
94 | |||
95 | void dObStack::freeAll() | ||
96 | { | ||
97 | last = first; | ||
98 | if (first) { | ||
99 | first->used = sizeof(Arena); | ||
100 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | |||
105 | void *dObStack::rewind() | ||
106 | { | ||
107 | current_arena = first; | ||
108 | current_ofs = sizeof (Arena); | ||
109 | if (current_arena) { | ||
110 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs) | ||
111 | return ((char*) current_arena) + current_ofs; | ||
112 | } | ||
113 | else return 0; | ||
114 | } | ||
115 | |||
116 | |||
117 | void *dObStack::next (int num_bytes) | ||
118 | { | ||
119 | // this functions like alloc, except that no new storage is ever allocated | ||
120 | if (!current_arena) return 0; | ||
121 | current_ofs += num_bytes; | ||
122 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); | ||
123 | if (current_ofs >= current_arena->used) { | ||
124 | current_arena = current_arena->next; | ||
125 | if (!current_arena) return 0; | ||
126 | current_ofs = sizeof (Arena); | ||
127 | ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); | ||
128 | } | ||
129 | return ((char*) current_arena) + current_ofs; | ||
130 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/obstack.h b/libraries/ode-0.9\/ode/src/obstack.h new file mode 100755 index 0000000..b5f715b --- /dev/null +++ b/libraries/ode-0.9\/ode/src/obstack.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifndef _ODE_OBSTACK_H_ | ||
24 | #define _ODE_OBSTACK_H_ | ||
25 | |||
26 | #include "objects.h" | ||
27 | |||
28 | // each obstack Arena pointer points to a block of this many bytes | ||
29 | #define dOBSTACK_ARENA_SIZE 16384 | ||
30 | |||
31 | |||
32 | struct dObStack : public dBase { | ||
33 | struct Arena { | ||
34 | Arena *next; // next arena in linked list | ||
35 | size_t used; // total number of bytes used in this arena, counting | ||
36 | }; // this header | ||
37 | |||
38 | Arena *first; // head of the arena linked list. 0 if no arenas yet | ||
39 | Arena *last; // arena where blocks are currently being allocated | ||
40 | |||
41 | // used for iterator | ||
42 | Arena *current_arena; | ||
43 | size_t current_ofs; | ||
44 | |||
45 | dObStack(); | ||
46 | ~dObStack(); | ||
47 | |||
48 | void *alloc (int num_bytes); | ||
49 | // allocate a block in the last arena, allocating a new arena if necessary. | ||
50 | // it is a runtime error if num_bytes is larger than the arena size. | ||
51 | |||
52 | void freeAll(); | ||
53 | // free all blocks in all arenas. this does not deallocate the arenas | ||
54 | // themselves, so future alloc()s will reuse them. | ||
55 | |||
56 | void *rewind(); | ||
57 | // rewind the obstack iterator, and return the address of the first | ||
58 | // allocated block. return 0 if there are no allocated blocks. | ||
59 | |||
60 | void *next (int num_bytes); | ||
61 | // return the address of the next allocated block. 'num_bytes' is the size | ||
62 | // of the previous block. this returns null if there are no more arenas. | ||
63 | // the sequence of 'num_bytes' parameters passed to next() during a | ||
64 | // traversal of the list must exactly match the parameters passed to alloc(). | ||
65 | }; | ||
66 | |||
67 | |||
68 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/ode.cpp b/libraries/ode-0.9\/ode/src/ode.cpp new file mode 100755 index 0000000..46f559a --- /dev/null +++ b/libraries/ode-0.9\/ode/src/ode.cpp | |||
@@ -0,0 +1,1732 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifdef _MSC_VER | ||
24 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
25 | #endif | ||
26 | |||
27 | // this source file is mostly concerned with the data structures, not the | ||
28 | // numerics. | ||
29 | |||
30 | #include "objects.h" | ||
31 | #include <ode/ode.h> | ||
32 | #include "joint.h" | ||
33 | #include <ode/odemath.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include "step.h" | ||
36 | #include "quickstep.h" | ||
37 | #include "util.h" | ||
38 | #include <ode/memory.h> | ||
39 | #include <ode/error.h> | ||
40 | |||
41 | // misc defines | ||
42 | #define ALLOCA dALLOCA16 | ||
43 | |||
44 | //**************************************************************************** | ||
45 | // utility | ||
46 | |||
47 | static inline void initObject (dObject *obj, dxWorld *w) | ||
48 | { | ||
49 | obj->world = w; | ||
50 | obj->next = 0; | ||
51 | obj->tome = 0; | ||
52 | obj->userdata = 0; | ||
53 | obj->tag = 0; | ||
54 | } | ||
55 | |||
56 | |||
57 | // add an object `obj' to the list who's head pointer is pointed to by `first'. | ||
58 | |||
59 | static inline void addObjectToList (dObject *obj, dObject **first) | ||
60 | { | ||
61 | obj->next = *first; | ||
62 | obj->tome = first; | ||
63 | if (*first) (*first)->tome = &obj->next; | ||
64 | (*first) = obj; | ||
65 | } | ||
66 | |||
67 | |||
68 | // remove the object from the linked list | ||
69 | |||
70 | static inline void removeObjectFromList (dObject *obj) | ||
71 | { | ||
72 | if (obj->next) obj->next->tome = obj->tome; | ||
73 | *(obj->tome) = obj->next; | ||
74 | // safeguard | ||
75 | obj->next = 0; | ||
76 | obj->tome = 0; | ||
77 | } | ||
78 | |||
79 | |||
80 | // remove the joint from neighbour lists of all connected bodies | ||
81 | |||
82 | static void removeJointReferencesFromAttachedBodies (dxJoint *j) | ||
83 | { | ||
84 | for (int i=0; i<2; i++) { | ||
85 | dxBody *body = j->node[i].body; | ||
86 | if (body) { | ||
87 | dxJointNode *n = body->firstjoint; | ||
88 | dxJointNode *last = 0; | ||
89 | while (n) { | ||
90 | if (n->joint == j) { | ||
91 | if (last) last->next = n->next; | ||
92 | else body->firstjoint = n->next; | ||
93 | break; | ||
94 | } | ||
95 | last = n; | ||
96 | n = n->next; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | j->node[0].body = 0; | ||
101 | j->node[0].next = 0; | ||
102 | j->node[1].body = 0; | ||
103 | j->node[1].next = 0; | ||
104 | } | ||
105 | |||
106 | //**************************************************************************** | ||
107 | // debugging | ||
108 | |||
109 | // see if an object list loops on itself (if so, it's bad). | ||
110 | |||
111 | static int listHasLoops (dObject *first) | ||
112 | { | ||
113 | if (first==0 || first->next==0) return 0; | ||
114 | dObject *a=first,*b=first->next; | ||
115 | int skip=0; | ||
116 | while (b) { | ||
117 | if (a==b) return 1; | ||
118 | b = b->next; | ||
119 | if (skip) a = a->next; | ||
120 | skip ^= 1; | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | |||
126 | // check the validity of the world data structures | ||
127 | |||
128 | static void checkWorld (dxWorld *w) | ||
129 | { | ||
130 | dxBody *b; | ||
131 | dxJoint *j; | ||
132 | |||
133 | // check there are no loops | ||
134 | if (listHasLoops (w->firstbody)) dDebug (0,"body list has loops"); | ||
135 | if (listHasLoops (w->firstjoint)) dDebug (0,"joint list has loops"); | ||
136 | |||
137 | // check lists are well formed (check `tome' pointers) | ||
138 | for (b=w->firstbody; b; b=(dxBody*)b->next) { | ||
139 | if (b->next && b->next->tome != &b->next) | ||
140 | dDebug (0,"bad tome pointer in body list"); | ||
141 | } | ||
142 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) { | ||
143 | if (j->next && j->next->tome != &j->next) | ||
144 | dDebug (0,"bad tome pointer in joint list"); | ||
145 | } | ||
146 | |||
147 | // check counts | ||
148 | int n = 0; | ||
149 | for (b=w->firstbody; b; b=(dxBody*)b->next) n++; | ||
150 | if (w->nb != n) dDebug (0,"body count incorrect"); | ||
151 | n = 0; | ||
152 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) n++; | ||
153 | if (w->nj != n) dDebug (0,"joint count incorrect"); | ||
154 | |||
155 | // set all tag values to a known value | ||
156 | static int count = 0; | ||
157 | count++; | ||
158 | for (b=w->firstbody; b; b=(dxBody*)b->next) b->tag = count; | ||
159 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) j->tag = count; | ||
160 | |||
161 | // check all body/joint world pointers are ok | ||
162 | for (b=w->firstbody; b; b=(dxBody*)b->next) if (b->world != w) | ||
163 | dDebug (0,"bad world pointer in body list"); | ||
164 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) if (j->world != w) | ||
165 | dDebug (0,"bad world pointer in joint list"); | ||
166 | |||
167 | /* | ||
168 | // check for half-connected joints - actually now these are valid | ||
169 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) { | ||
170 | if (j->node[0].body || j->node[1].body) { | ||
171 | if (!(j->node[0].body && j->node[1].body)) | ||
172 | dDebug (0,"half connected joint found"); | ||
173 | } | ||
174 | } | ||
175 | */ | ||
176 | |||
177 | // check that every joint node appears in the joint lists of both bodies it | ||
178 | // attaches | ||
179 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) { | ||
180 | for (int i=0; i<2; i++) { | ||
181 | if (j->node[i].body) { | ||
182 | int ok = 0; | ||
183 | for (dxJointNode *n=j->node[i].body->firstjoint; n; n=n->next) { | ||
184 | if (n->joint == j) ok = 1; | ||
185 | } | ||
186 | if (ok==0) dDebug (0,"joint not in joint list of attached body"); | ||
187 | } | ||
188 | } | ||
189 | } | ||
190 | |||
191 | // check all body joint lists (correct body ptrs) | ||
192 | for (b=w->firstbody; b; b=(dxBody*)b->next) { | ||
193 | for (dxJointNode *n=b->firstjoint; n; n=n->next) { | ||
194 | if (&n->joint->node[0] == n) { | ||
195 | if (n->joint->node[1].body != b) | ||
196 | dDebug (0,"bad body pointer in joint node of body list (1)"); | ||
197 | } | ||
198 | else { | ||
199 | if (n->joint->node[0].body != b) | ||
200 | dDebug (0,"bad body pointer in joint node of body list (2)"); | ||
201 | } | ||
202 | if (n->joint->tag != count) dDebug (0,"bad joint node pointer in body"); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // check all body pointers in joints, check they are distinct | ||
207 | for (j=w->firstjoint; j; j=(dxJoint*)j->next) { | ||
208 | if (j->node[0].body && (j->node[0].body == j->node[1].body)) | ||
209 | dDebug (0,"non-distinct body pointers in joint"); | ||
210 | if ((j->node[0].body && j->node[0].body->tag != count) || | ||
211 | (j->node[1].body && j->node[1].body->tag != count)) | ||
212 | dDebug (0,"bad body pointer in joint"); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | |||
217 | void dWorldCheck (dxWorld *w) | ||
218 | { | ||
219 | checkWorld (w); | ||
220 | } | ||
221 | |||
222 | //**************************************************************************** | ||
223 | // body | ||
224 | dxWorld* dBodyGetWorld (dxBody* b) | ||
225 | { | ||
226 | dAASSERT (b); | ||
227 | return b->world; | ||
228 | } | ||
229 | |||
230 | dxBody *dBodyCreate (dxWorld *w) | ||
231 | { | ||
232 | dAASSERT (w); | ||
233 | dxBody *b = new dxBody; | ||
234 | initObject (b,w); | ||
235 | b->firstjoint = 0; | ||
236 | b->flags = 0; | ||
237 | b->geom = 0; | ||
238 | b->average_lvel_buffer = 0; | ||
239 | b->average_avel_buffer = 0; | ||
240 | dMassSetParameters (&b->mass,1,0,0,0,1,1,1,0,0,0); | ||
241 | dSetZero (b->invI,4*3); | ||
242 | b->invI[0] = 1; | ||
243 | b->invI[5] = 1; | ||
244 | b->invI[10] = 1; | ||
245 | b->invMass = 1; | ||
246 | dSetZero (b->posr.pos,4); | ||
247 | dSetZero (b->q,4); | ||
248 | b->q[0] = 1; | ||
249 | dRSetIdentity (b->posr.R); | ||
250 | dSetZero (b->lvel,4); | ||
251 | dSetZero (b->avel,4); | ||
252 | dSetZero (b->facc,4); | ||
253 | dSetZero (b->tacc,4); | ||
254 | dSetZero (b->finite_rot_axis,4); | ||
255 | addObjectToList (b,(dObject **) &w->firstbody); | ||
256 | w->nb++; | ||
257 | |||
258 | // set auto-disable parameters | ||
259 | b->average_avel_buffer = b->average_lvel_buffer = 0; // no buffer at beginnin | ||
260 | dBodySetAutoDisableDefaults (b); // must do this after adding to world | ||
261 | b->adis_stepsleft = b->adis.idle_steps; | ||
262 | b->adis_timeleft = b->adis.idle_time; | ||
263 | b->average_counter = 0; | ||
264 | b->average_ready = 0; // average buffer not filled on the beginning | ||
265 | dBodySetAutoDisableAverageSamplesCount(b, b->adis.average_samples); | ||
266 | |||
267 | return b; | ||
268 | } | ||
269 | |||
270 | |||
271 | void dBodyDestroy (dxBody *b) | ||
272 | { | ||
273 | dAASSERT (b); | ||
274 | |||
275 | // all geoms that link to this body must be notified that the body is about | ||
276 | // to disappear. note that the call to dGeomSetBody(geom,0) will result in | ||
277 | // dGeomGetBodyNext() returning 0 for the body, so we must get the next body | ||
278 | // before setting the body to 0. | ||
279 | dxGeom *next_geom = 0; | ||
280 | for (dxGeom *geom = b->geom; geom; geom = next_geom) { | ||
281 | next_geom = dGeomGetBodyNext (geom); | ||
282 | dGeomSetBody (geom,0); | ||
283 | } | ||
284 | |||
285 | // detach all neighbouring joints, then delete this body. | ||
286 | dxJointNode *n = b->firstjoint; | ||
287 | while (n) { | ||
288 | // sneaky trick to speed up removal of joint references (black magic) | ||
289 | n->joint->node[(n == n->joint->node)].body = 0; | ||
290 | |||
291 | dxJointNode *next = n->next; | ||
292 | n->next = 0; | ||
293 | removeJointReferencesFromAttachedBodies (n->joint); | ||
294 | n = next; | ||
295 | } | ||
296 | removeObjectFromList (b); | ||
297 | b->world->nb--; | ||
298 | |||
299 | // delete the average buffers | ||
300 | if(b->average_lvel_buffer) | ||
301 | { | ||
302 | delete[] (b->average_lvel_buffer); | ||
303 | b->average_lvel_buffer = 0; | ||
304 | } | ||
305 | if(b->average_avel_buffer) | ||
306 | { | ||
307 | delete[] (b->average_avel_buffer); | ||
308 | b->average_avel_buffer = 0; | ||
309 | } | ||
310 | |||
311 | delete b; | ||
312 | } | ||
313 | |||
314 | |||
315 | void dBodySetData (dBodyID b, void *data) | ||
316 | { | ||
317 | dAASSERT (b); | ||
318 | b->userdata = data; | ||
319 | } | ||
320 | |||
321 | |||
322 | void *dBodyGetData (dBodyID b) | ||
323 | { | ||
324 | dAASSERT (b); | ||
325 | return b->userdata; | ||
326 | } | ||
327 | |||
328 | |||
329 | void dBodySetPosition (dBodyID b, dReal x, dReal y, dReal z) | ||
330 | { | ||
331 | dAASSERT (b); | ||
332 | b->posr.pos[0] = x; | ||
333 | b->posr.pos[1] = y; | ||
334 | b->posr.pos[2] = z; | ||
335 | |||
336 | // notify all attached geoms that this body has moved | ||
337 | for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) | ||
338 | dGeomMoved (geom); | ||
339 | } | ||
340 | |||
341 | |||
342 | void dBodySetRotation (dBodyID b, const dMatrix3 R) | ||
343 | { | ||
344 | dAASSERT (b && R); | ||
345 | dQuaternion q; | ||
346 | dRtoQ (R,q); | ||
347 | dNormalize4 (q); | ||
348 | b->q[0] = q[0]; | ||
349 | b->q[1] = q[1]; | ||
350 | b->q[2] = q[2]; | ||
351 | b->q[3] = q[3]; | ||
352 | dQtoR (b->q,b->posr.R); | ||
353 | |||
354 | // notify all attached geoms that this body has moved | ||
355 | for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) | ||
356 | dGeomMoved (geom); | ||
357 | } | ||
358 | |||
359 | |||
360 | void dBodySetQuaternion (dBodyID b, const dQuaternion q) | ||
361 | { | ||
362 | dAASSERT (b && q); | ||
363 | b->q[0] = q[0]; | ||
364 | b->q[1] = q[1]; | ||
365 | b->q[2] = q[2]; | ||
366 | b->q[3] = q[3]; | ||
367 | dNormalize4 (b->q); | ||
368 | dQtoR (b->q,b->posr.R); | ||
369 | |||
370 | // notify all attached geoms that this body has moved | ||
371 | for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) | ||
372 | dGeomMoved (geom); | ||
373 | } | ||
374 | |||
375 | |||
376 | void dBodySetLinearVel (dBodyID b, dReal x, dReal y, dReal z) | ||
377 | { | ||
378 | dAASSERT (b); | ||
379 | b->lvel[0] = x; | ||
380 | b->lvel[1] = y; | ||
381 | b->lvel[2] = z; | ||
382 | } | ||
383 | |||
384 | |||
385 | void dBodySetAngularVel (dBodyID b, dReal x, dReal y, dReal z) | ||
386 | { | ||
387 | dAASSERT (b); | ||
388 | b->avel[0] = x; | ||
389 | b->avel[1] = y; | ||
390 | b->avel[2] = z; | ||
391 | } | ||
392 | |||
393 | |||
394 | const dReal * dBodyGetPosition (dBodyID b) | ||
395 | { | ||
396 | dAASSERT (b); | ||
397 | return b->posr.pos; | ||
398 | } | ||
399 | |||
400 | |||
401 | void dBodyCopyPosition (dBodyID b, dVector3 pos) | ||
402 | { | ||
403 | dAASSERT (b); | ||
404 | dReal* src = b->posr.pos; | ||
405 | pos[0] = src[0]; | ||
406 | pos[1] = src[1]; | ||
407 | pos[2] = src[2]; | ||
408 | } | ||
409 | |||
410 | |||
411 | const dReal * dBodyGetRotation (dBodyID b) | ||
412 | { | ||
413 | dAASSERT (b); | ||
414 | return b->posr.R; | ||
415 | } | ||
416 | |||
417 | |||
418 | void dBodyCopyRotation (dBodyID b, dMatrix3 R) | ||
419 | { | ||
420 | dAASSERT (b); | ||
421 | const dReal* src = b->posr.R; | ||
422 | R[0] = src[0]; | ||
423 | R[1] = src[1]; | ||
424 | R[2] = src[2]; | ||
425 | R[3] = src[3]; | ||
426 | R[4] = src[4]; | ||
427 | R[5] = src[5]; | ||
428 | R[6] = src[6]; | ||
429 | R[7] = src[7]; | ||
430 | R[8] = src[8]; | ||
431 | R[9] = src[9]; | ||
432 | R[10] = src[10]; | ||
433 | R[11] = src[11]; | ||
434 | } | ||
435 | |||
436 | |||
437 | const dReal * dBodyGetQuaternion (dBodyID b) | ||
438 | { | ||
439 | dAASSERT (b); | ||
440 | return b->q; | ||
441 | } | ||
442 | |||
443 | |||
444 | void dBodyCopyQuaternion (dBodyID b, dQuaternion quat) | ||
445 | { | ||
446 | dAASSERT (b); | ||
447 | dReal* src = b->q; | ||
448 | quat[0] = src[0]; | ||
449 | quat[1] = src[1]; | ||
450 | quat[2] = src[2]; | ||
451 | quat[3] = src[3]; | ||
452 | } | ||
453 | |||
454 | |||
455 | const dReal * dBodyGetLinearVel (dBodyID b) | ||
456 | { | ||
457 | dAASSERT (b); | ||
458 | return b->lvel; | ||
459 | } | ||
460 | |||
461 | |||
462 | const dReal * dBodyGetAngularVel (dBodyID b) | ||
463 | { | ||
464 | dAASSERT (b); | ||
465 | return b->avel; | ||
466 | } | ||
467 | |||
468 | |||
469 | void dBodySetMass (dBodyID b, const dMass *mass) | ||
470 | { | ||
471 | dAASSERT (b && mass ); | ||
472 | dIASSERT(dMassCheck(mass)); | ||
473 | |||
474 | // The centre of mass must be at the origin. | ||
475 | // Use dMassTranslate( mass, -mass->c[0], -mass->c[1], -mass->c[2] ) to correct it. | ||
476 | dUASSERT( fabs( mass->c[0] ) <= dEpsilon && | ||
477 | fabs( mass->c[1] ) <= dEpsilon && | ||
478 | fabs( mass->c[2] ) <= dEpsilon, "The centre of mass must be at the origin." ) | ||
479 | |||
480 | memcpy (&b->mass,mass,sizeof(dMass)); | ||
481 | if (dInvertPDMatrix (b->mass.I,b->invI,3)==0) { | ||
482 | dDEBUGMSG ("inertia must be positive definite!"); | ||
483 | dRSetIdentity (b->invI); | ||
484 | } | ||
485 | b->invMass = dRecip(b->mass.mass); | ||
486 | } | ||
487 | |||
488 | |||
489 | void dBodyGetMass (dBodyID b, dMass *mass) | ||
490 | { | ||
491 | dAASSERT (b && mass); | ||
492 | memcpy (mass,&b->mass,sizeof(dMass)); | ||
493 | } | ||
494 | |||
495 | |||
496 | void dBodyAddForce (dBodyID b, dReal fx, dReal fy, dReal fz) | ||
497 | { | ||
498 | dAASSERT (b); | ||
499 | b->facc[0] += fx; | ||
500 | b->facc[1] += fy; | ||
501 | b->facc[2] += fz; | ||
502 | } | ||
503 | |||
504 | |||
505 | void dBodyAddTorque (dBodyID b, dReal fx, dReal fy, dReal fz) | ||
506 | { | ||
507 | dAASSERT (b); | ||
508 | b->tacc[0] += fx; | ||
509 | b->tacc[1] += fy; | ||
510 | b->tacc[2] += fz; | ||
511 | } | ||
512 | |||
513 | |||
514 | void dBodyAddRelForce (dBodyID b, dReal fx, dReal fy, dReal fz) | ||
515 | { | ||
516 | dAASSERT (b); | ||
517 | dVector3 t1,t2; | ||
518 | t1[0] = fx; | ||
519 | t1[1] = fy; | ||
520 | t1[2] = fz; | ||
521 | t1[3] = 0; | ||
522 | dMULTIPLY0_331 (t2,b->posr.R,t1); | ||
523 | b->facc[0] += t2[0]; | ||
524 | b->facc[1] += t2[1]; | ||
525 | b->facc[2] += t2[2]; | ||
526 | } | ||
527 | |||
528 | |||
529 | void dBodyAddRelTorque (dBodyID b, dReal fx, dReal fy, dReal fz) | ||
530 | { | ||
531 | dAASSERT (b); | ||
532 | dVector3 t1,t2; | ||
533 | t1[0] = fx; | ||
534 | t1[1] = fy; | ||
535 | t1[2] = fz; | ||
536 | t1[3] = 0; | ||
537 | dMULTIPLY0_331 (t2,b->posr.R,t1); | ||
538 | b->tacc[0] += t2[0]; | ||
539 | b->tacc[1] += t2[1]; | ||
540 | b->tacc[2] += t2[2]; | ||
541 | } | ||
542 | |||
543 | |||
544 | void dBodyAddForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, | ||
545 | dReal px, dReal py, dReal pz) | ||
546 | { | ||
547 | dAASSERT (b); | ||
548 | b->facc[0] += fx; | ||
549 | b->facc[1] += fy; | ||
550 | b->facc[2] += fz; | ||
551 | dVector3 f,q; | ||
552 | f[0] = fx; | ||
553 | f[1] = fy; | ||
554 | f[2] = fz; | ||
555 | q[0] = px - b->posr.pos[0]; | ||
556 | q[1] = py - b->posr.pos[1]; | ||
557 | q[2] = pz - b->posr.pos[2]; | ||
558 | dCROSS (b->tacc,+=,q,f); | ||
559 | } | ||
560 | |||
561 | |||
562 | void dBodyAddForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, | ||
563 | dReal px, dReal py, dReal pz) | ||
564 | { | ||
565 | dAASSERT (b); | ||
566 | dVector3 prel,f,p; | ||
567 | f[0] = fx; | ||
568 | f[1] = fy; | ||
569 | f[2] = fz; | ||
570 | f[3] = 0; | ||
571 | prel[0] = px; | ||
572 | prel[1] = py; | ||
573 | prel[2] = pz; | ||
574 | prel[3] = 0; | ||
575 | dMULTIPLY0_331 (p,b->posr.R,prel); | ||
576 | b->facc[0] += f[0]; | ||
577 | b->facc[1] += f[1]; | ||
578 | b->facc[2] += f[2]; | ||
579 | dCROSS (b->tacc,+=,p,f); | ||
580 | } | ||
581 | |||
582 | |||
583 | void dBodyAddRelForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, | ||
584 | dReal px, dReal py, dReal pz) | ||
585 | { | ||
586 | dAASSERT (b); | ||
587 | dVector3 frel,f; | ||
588 | frel[0] = fx; | ||
589 | frel[1] = fy; | ||
590 | frel[2] = fz; | ||
591 | frel[3] = 0; | ||
592 | dMULTIPLY0_331 (f,b->posr.R,frel); | ||
593 | b->facc[0] += f[0]; | ||
594 | b->facc[1] += f[1]; | ||
595 | b->facc[2] += f[2]; | ||
596 | dVector3 q; | ||
597 | q[0] = px - b->posr.pos[0]; | ||
598 | q[1] = py - b->posr.pos[1]; | ||
599 | q[2] = pz - b->posr.pos[2]; | ||
600 | dCROSS (b->tacc,+=,q,f); | ||
601 | } | ||
602 | |||
603 | |||
604 | void dBodyAddRelForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, | ||
605 | dReal px, dReal py, dReal pz) | ||
606 | { | ||
607 | dAASSERT (b); | ||
608 | dVector3 frel,prel,f,p; | ||
609 | frel[0] = fx; | ||
610 | frel[1] = fy; | ||
611 | frel[2] = fz; | ||
612 | frel[3] = 0; | ||
613 | prel[0] = px; | ||
614 | prel[1] = py; | ||
615 | prel[2] = pz; | ||
616 | prel[3] = 0; | ||
617 | dMULTIPLY0_331 (f,b->posr.R,frel); | ||
618 | dMULTIPLY0_331 (p,b->posr.R,prel); | ||
619 | b->facc[0] += f[0]; | ||
620 | b->facc[1] += f[1]; | ||
621 | b->facc[2] += f[2]; | ||
622 | dCROSS (b->tacc,+=,p,f); | ||
623 | } | ||
624 | |||
625 | |||
626 | const dReal * dBodyGetForce (dBodyID b) | ||
627 | { | ||
628 | dAASSERT (b); | ||
629 | return b->facc; | ||
630 | } | ||
631 | |||
632 | |||
633 | const dReal * dBodyGetTorque (dBodyID b) | ||
634 | { | ||
635 | dAASSERT (b); | ||
636 | return b->tacc; | ||
637 | } | ||
638 | |||
639 | |||
640 | void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z) | ||
641 | { | ||
642 | dAASSERT (b); | ||
643 | b->facc[0] = x; | ||
644 | b->facc[1] = y; | ||
645 | b->facc[2] = z; | ||
646 | } | ||
647 | |||
648 | |||
649 | void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z) | ||
650 | { | ||
651 | dAASSERT (b); | ||
652 | b->tacc[0] = x; | ||
653 | b->tacc[1] = y; | ||
654 | b->tacc[2] = z; | ||
655 | } | ||
656 | |||
657 | |||
658 | void dBodyGetRelPointPos (dBodyID b, dReal px, dReal py, dReal pz, | ||
659 | dVector3 result) | ||
660 | { | ||
661 | dAASSERT (b); | ||
662 | dVector3 prel,p; | ||
663 | prel[0] = px; | ||
664 | prel[1] = py; | ||
665 | prel[2] = pz; | ||
666 | prel[3] = 0; | ||
667 | dMULTIPLY0_331 (p,b->posr.R,prel); | ||
668 | result[0] = p[0] + b->posr.pos[0]; | ||
669 | result[1] = p[1] + b->posr.pos[1]; | ||
670 | result[2] = p[2] + b->posr.pos[2]; | ||
671 | } | ||
672 | |||
673 | |||
674 | void dBodyGetRelPointVel (dBodyID b, dReal px, dReal py, dReal pz, | ||
675 | dVector3 result) | ||
676 | { | ||
677 | dAASSERT (b); | ||
678 | dVector3 prel,p; | ||
679 | prel[0] = px; | ||
680 | prel[1] = py; | ||
681 | prel[2] = pz; | ||
682 | prel[3] = 0; | ||
683 | dMULTIPLY0_331 (p,b->posr.R,prel); | ||
684 | result[0] = b->lvel[0]; | ||
685 | result[1] = b->lvel[1]; | ||
686 | result[2] = b->lvel[2]; | ||
687 | dCROSS (result,+=,b->avel,p); | ||
688 | } | ||
689 | |||
690 | |||
691 | void dBodyGetPointVel (dBodyID b, dReal px, dReal py, dReal pz, | ||
692 | dVector3 result) | ||
693 | { | ||
694 | dAASSERT (b); | ||
695 | dVector3 p; | ||
696 | p[0] = px - b->posr.pos[0]; | ||
697 | p[1] = py - b->posr.pos[1]; | ||
698 | p[2] = pz - b->posr.pos[2]; | ||
699 | p[3] = 0; | ||
700 | result[0] = b->lvel[0]; | ||
701 | result[1] = b->lvel[1]; | ||
702 | result[2] = b->lvel[2]; | ||
703 | dCROSS (result,+=,b->avel,p); | ||
704 | } | ||
705 | |||
706 | |||
707 | void dBodyGetPosRelPoint (dBodyID b, dReal px, dReal py, dReal pz, | ||
708 | dVector3 result) | ||
709 | { | ||
710 | dAASSERT (b); | ||
711 | dVector3 prel; | ||
712 | prel[0] = px - b->posr.pos[0]; | ||
713 | prel[1] = py - b->posr.pos[1]; | ||
714 | prel[2] = pz - b->posr.pos[2]; | ||
715 | prel[3] = 0; | ||
716 | dMULTIPLY1_331 (result,b->posr.R,prel); | ||
717 | } | ||
718 | |||
719 | |||
720 | void dBodyVectorToWorld (dBodyID b, dReal px, dReal py, dReal pz, | ||
721 | dVector3 result) | ||
722 | { | ||
723 | dAASSERT (b); | ||
724 | dVector3 p; | ||
725 | p[0] = px; | ||
726 | p[1] = py; | ||
727 | p[2] = pz; | ||
728 | p[3] = 0; | ||
729 | dMULTIPLY0_331 (result,b->posr.R,p); | ||
730 | } | ||
731 | |||
732 | |||
733 | void dBodyVectorFromWorld (dBodyID b, dReal px, dReal py, dReal pz, | ||
734 | dVector3 result) | ||
735 | { | ||
736 | dAASSERT (b); | ||
737 | dVector3 p; | ||
738 | p[0] = px; | ||
739 | p[1] = py; | ||
740 | p[2] = pz; | ||
741 | p[3] = 0; | ||
742 | dMULTIPLY1_331 (result,b->posr.R,p); | ||
743 | } | ||
744 | |||
745 | |||
746 | void dBodySetFiniteRotationMode (dBodyID b, int mode) | ||
747 | { | ||
748 | dAASSERT (b); | ||
749 | b->flags &= ~(dxBodyFlagFiniteRotation | dxBodyFlagFiniteRotationAxis); | ||
750 | if (mode) { | ||
751 | b->flags |= dxBodyFlagFiniteRotation; | ||
752 | if (b->finite_rot_axis[0] != 0 || b->finite_rot_axis[1] != 0 || | ||
753 | b->finite_rot_axis[2] != 0) { | ||
754 | b->flags |= dxBodyFlagFiniteRotationAxis; | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | |||
759 | |||
760 | void dBodySetFiniteRotationAxis (dBodyID b, dReal x, dReal y, dReal z) | ||
761 | { | ||
762 | dAASSERT (b); | ||
763 | b->finite_rot_axis[0] = x; | ||
764 | b->finite_rot_axis[1] = y; | ||
765 | b->finite_rot_axis[2] = z; | ||
766 | if (x != 0 || y != 0 || z != 0) { | ||
767 | dNormalize3 (b->finite_rot_axis); | ||
768 | b->flags |= dxBodyFlagFiniteRotationAxis; | ||
769 | } | ||
770 | else { | ||
771 | b->flags &= ~dxBodyFlagFiniteRotationAxis; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | |||
776 | int dBodyGetFiniteRotationMode (dBodyID b) | ||
777 | { | ||
778 | dAASSERT (b); | ||
779 | return ((b->flags & dxBodyFlagFiniteRotation) != 0); | ||
780 | } | ||
781 | |||
782 | |||
783 | void dBodyGetFiniteRotationAxis (dBodyID b, dVector3 result) | ||
784 | { | ||
785 | dAASSERT (b); | ||
786 | result[0] = b->finite_rot_axis[0]; | ||
787 | result[1] = b->finite_rot_axis[1]; | ||
788 | result[2] = b->finite_rot_axis[2]; | ||
789 | } | ||
790 | |||
791 | |||
792 | int dBodyGetNumJoints (dBodyID b) | ||
793 | { | ||
794 | dAASSERT (b); | ||
795 | int count=0; | ||
796 | for (dxJointNode *n=b->firstjoint; n; n=n->next, count++); | ||
797 | return count; | ||
798 | } | ||
799 | |||
800 | |||
801 | dJointID dBodyGetJoint (dBodyID b, int index) | ||
802 | { | ||
803 | dAASSERT (b); | ||
804 | int i=0; | ||
805 | for (dxJointNode *n=b->firstjoint; n; n=n->next, i++) { | ||
806 | if (i == index) return n->joint; | ||
807 | } | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | |||
812 | void dBodyEnable (dBodyID b) | ||
813 | { | ||
814 | dAASSERT (b); | ||
815 | b->flags &= ~dxBodyDisabled; | ||
816 | b->adis_stepsleft = b->adis.idle_steps; | ||
817 | b->adis_timeleft = b->adis.idle_time; | ||
818 | // no code for average-processing needed here | ||
819 | } | ||
820 | |||
821 | |||
822 | void dBodyDisable (dBodyID b) | ||
823 | { | ||
824 | dAASSERT (b); | ||
825 | b->flags |= dxBodyDisabled; | ||
826 | } | ||
827 | |||
828 | |||
829 | int dBodyIsEnabled (dBodyID b) | ||
830 | { | ||
831 | dAASSERT (b); | ||
832 | return ((b->flags & dxBodyDisabled) == 0); | ||
833 | } | ||
834 | |||
835 | |||
836 | void dBodySetGravityMode (dBodyID b, int mode) | ||
837 | { | ||
838 | dAASSERT (b); | ||
839 | if (mode) b->flags &= ~dxBodyNoGravity; | ||
840 | else b->flags |= dxBodyNoGravity; | ||
841 | } | ||
842 | |||
843 | |||
844 | int dBodyGetGravityMode (dBodyID b) | ||
845 | { | ||
846 | dAASSERT (b); | ||
847 | return ((b->flags & dxBodyNoGravity) == 0); | ||
848 | } | ||
849 | |||
850 | |||
851 | // body auto-disable functions | ||
852 | |||
853 | dReal dBodyGetAutoDisableLinearThreshold (dBodyID b) | ||
854 | { | ||
855 | dAASSERT(b); | ||
856 | return dSqrt (b->adis.linear_average_threshold); | ||
857 | } | ||
858 | |||
859 | |||
860 | void dBodySetAutoDisableLinearThreshold (dBodyID b, dReal linear_average_threshold) | ||
861 | { | ||
862 | dAASSERT(b); | ||
863 | b->adis.linear_average_threshold = linear_average_threshold * linear_average_threshold; | ||
864 | } | ||
865 | |||
866 | |||
867 | dReal dBodyGetAutoDisableAngularThreshold (dBodyID b) | ||
868 | { | ||
869 | dAASSERT(b); | ||
870 | return dSqrt (b->adis.angular_average_threshold); | ||
871 | } | ||
872 | |||
873 | |||
874 | void dBodySetAutoDisableAngularThreshold (dBodyID b, dReal angular_average_threshold) | ||
875 | { | ||
876 | dAASSERT(b); | ||
877 | b->adis.angular_average_threshold = angular_average_threshold * angular_average_threshold; | ||
878 | } | ||
879 | |||
880 | |||
881 | int dBodyGetAutoDisableAverageSamplesCount (dBodyID b) | ||
882 | { | ||
883 | dAASSERT(b); | ||
884 | return b->adis.average_samples; | ||
885 | } | ||
886 | |||
887 | |||
888 | void dBodySetAutoDisableAverageSamplesCount (dBodyID b, unsigned int average_samples_count) | ||
889 | { | ||
890 | dAASSERT(b); | ||
891 | b->adis.average_samples = average_samples_count; | ||
892 | // update the average buffers | ||
893 | if(b->average_lvel_buffer) | ||
894 | { | ||
895 | delete[] b->average_lvel_buffer; | ||
896 | b->average_lvel_buffer = 0; | ||
897 | } | ||
898 | if(b->average_avel_buffer) | ||
899 | { | ||
900 | delete[] b->average_avel_buffer; | ||
901 | b->average_avel_buffer = 0; | ||
902 | } | ||
903 | if(b->adis.average_samples > 0) | ||
904 | { | ||
905 | b->average_lvel_buffer = new dVector3[b->adis.average_samples]; | ||
906 | b->average_avel_buffer = new dVector3[b->adis.average_samples]; | ||
907 | } | ||
908 | else | ||
909 | { | ||
910 | b->average_lvel_buffer = 0; | ||
911 | b->average_avel_buffer = 0; | ||
912 | } | ||
913 | // new buffer is empty | ||
914 | b->average_counter = 0; | ||
915 | b->average_ready = 0; | ||
916 | } | ||
917 | |||
918 | |||
919 | int dBodyGetAutoDisableSteps (dBodyID b) | ||
920 | { | ||
921 | dAASSERT(b); | ||
922 | return b->adis.idle_steps; | ||
923 | } | ||
924 | |||
925 | |||
926 | void dBodySetAutoDisableSteps (dBodyID b, int steps) | ||
927 | { | ||
928 | dAASSERT(b); | ||
929 | b->adis.idle_steps = steps; | ||
930 | } | ||
931 | |||
932 | |||
933 | dReal dBodyGetAutoDisableTime (dBodyID b) | ||
934 | { | ||
935 | dAASSERT(b); | ||
936 | return b->adis.idle_time; | ||
937 | } | ||
938 | |||
939 | |||
940 | void dBodySetAutoDisableTime (dBodyID b, dReal time) | ||
941 | { | ||
942 | dAASSERT(b); | ||
943 | b->adis.idle_time = time; | ||
944 | } | ||
945 | |||
946 | |||
947 | int dBodyGetAutoDisableFlag (dBodyID b) | ||
948 | { | ||
949 | dAASSERT(b); | ||
950 | return ((b->flags & dxBodyAutoDisable) != 0); | ||
951 | } | ||
952 | |||
953 | |||
954 | void dBodySetAutoDisableFlag (dBodyID b, int do_auto_disable) | ||
955 | { | ||
956 | dAASSERT(b); | ||
957 | if (!do_auto_disable) | ||
958 | { | ||
959 | b->flags &= ~dxBodyAutoDisable; | ||
960 | // (mg) we should also reset the IsDisabled state to correspond to the DoDisabling flag | ||
961 | b->flags &= ~dxBodyDisabled; | ||
962 | b->adis.idle_steps = dWorldGetAutoDisableSteps(b->world); | ||
963 | b->adis.idle_time = dWorldGetAutoDisableTime(b->world); | ||
964 | // resetting the average calculations too | ||
965 | dBodySetAutoDisableAverageSamplesCount(b, dWorldGetAutoDisableAverageSamplesCount(b->world) ); | ||
966 | } | ||
967 | else | ||
968 | { | ||
969 | b->flags |= dxBodyAutoDisable; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | |||
974 | void dBodySetAutoDisableDefaults (dBodyID b) | ||
975 | { | ||
976 | dAASSERT(b); | ||
977 | dWorldID w = b->world; | ||
978 | dAASSERT(w); | ||
979 | b->adis = w->adis; | ||
980 | dBodySetAutoDisableFlag (b, w->adis_flag); | ||
981 | } | ||
982 | |||
983 | //**************************************************************************** | ||
984 | // joints | ||
985 | |||
986 | static void dJointInit (dxWorld *w, dxJoint *j) | ||
987 | { | ||
988 | dIASSERT (w && j); | ||
989 | initObject (j,w); | ||
990 | j->vtable = 0; | ||
991 | j->flags = 0; | ||
992 | j->node[0].joint = j; | ||
993 | j->node[0].body = 0; | ||
994 | j->node[0].next = 0; | ||
995 | j->node[1].joint = j; | ||
996 | j->node[1].body = 0; | ||
997 | j->node[1].next = 0; | ||
998 | dSetZero (j->lambda,6); | ||
999 | addObjectToList (j,(dObject **) &w->firstjoint); | ||
1000 | w->nj++; | ||
1001 | } | ||
1002 | |||
1003 | |||
1004 | static dxJoint *createJoint (dWorldID w, dJointGroupID group, | ||
1005 | dxJoint::Vtable *vtable) | ||
1006 | { | ||
1007 | dIASSERT (w && vtable); | ||
1008 | dxJoint *j; | ||
1009 | if (group) { | ||
1010 | j = (dxJoint*) group->stack.alloc (vtable->size); | ||
1011 | group->num++; | ||
1012 | } | ||
1013 | else j = (dxJoint*) dAlloc (vtable->size); | ||
1014 | dJointInit (w,j); | ||
1015 | j->vtable = vtable; | ||
1016 | if (group) j->flags |= dJOINT_INGROUP; | ||
1017 | if (vtable->init) vtable->init (j); | ||
1018 | j->feedback = 0; | ||
1019 | return j; | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | dxJoint * dJointCreateBall (dWorldID w, dJointGroupID group) | ||
1024 | { | ||
1025 | dAASSERT (w); | ||
1026 | return createJoint (w,group,&__dball_vtable); | ||
1027 | } | ||
1028 | |||
1029 | |||
1030 | dxJoint * dJointCreateHinge (dWorldID w, dJointGroupID group) | ||
1031 | { | ||
1032 | dAASSERT (w); | ||
1033 | return createJoint (w,group,&__dhinge_vtable); | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | dxJoint * dJointCreateSlider (dWorldID w, dJointGroupID group) | ||
1038 | { | ||
1039 | dAASSERT (w); | ||
1040 | return createJoint (w,group,&__dslider_vtable); | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | dxJoint * dJointCreateContact (dWorldID w, dJointGroupID group, | ||
1045 | const dContact *c) | ||
1046 | { | ||
1047 | dAASSERT (w && c); | ||
1048 | dxJointContact *j = (dxJointContact *) | ||
1049 | createJoint (w,group,&__dcontact_vtable); | ||
1050 | j->contact = *c; | ||
1051 | return j; | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | dxJoint * dJointCreateHinge2 (dWorldID w, dJointGroupID group) | ||
1056 | { | ||
1057 | dAASSERT (w); | ||
1058 | return createJoint (w,group,&__dhinge2_vtable); | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | dxJoint * dJointCreateUniversal (dWorldID w, dJointGroupID group) | ||
1063 | { | ||
1064 | dAASSERT (w); | ||
1065 | return createJoint (w,group,&__duniversal_vtable); | ||
1066 | } | ||
1067 | |||
1068 | dxJoint * dJointCreatePR (dWorldID w, dJointGroupID group) | ||
1069 | { | ||
1070 | dAASSERT (w); | ||
1071 | return createJoint (w,group,&__dPR_vtable); | ||
1072 | } | ||
1073 | |||
1074 | dxJoint * dJointCreateFixed (dWorldID w, dJointGroupID group) | ||
1075 | { | ||
1076 | dAASSERT (w); | ||
1077 | return createJoint (w,group,&__dfixed_vtable); | ||
1078 | } | ||
1079 | |||
1080 | |||
1081 | dxJoint * dJointCreateNull (dWorldID w, dJointGroupID group) | ||
1082 | { | ||
1083 | dAASSERT (w); | ||
1084 | return createJoint (w,group,&__dnull_vtable); | ||
1085 | } | ||
1086 | |||
1087 | |||
1088 | dxJoint * dJointCreateAMotor (dWorldID w, dJointGroupID group) | ||
1089 | { | ||
1090 | dAASSERT (w); | ||
1091 | return createJoint (w,group,&__damotor_vtable); | ||
1092 | } | ||
1093 | |||
1094 | dxJoint * dJointCreateLMotor (dWorldID w, dJointGroupID group) | ||
1095 | { | ||
1096 | dAASSERT (w); | ||
1097 | return createJoint (w,group,&__dlmotor_vtable); | ||
1098 | } | ||
1099 | |||
1100 | dxJoint * dJointCreatePlane2D (dWorldID w, dJointGroupID group) | ||
1101 | { | ||
1102 | dAASSERT (w); | ||
1103 | return createJoint (w,group,&__dplane2d_vtable); | ||
1104 | } | ||
1105 | |||
1106 | void dJointDestroy (dxJoint *j) | ||
1107 | { | ||
1108 | dAASSERT (j); | ||
1109 | if (j->flags & dJOINT_INGROUP) return; | ||
1110 | removeJointReferencesFromAttachedBodies (j); | ||
1111 | removeObjectFromList (j); | ||
1112 | j->world->nj--; | ||
1113 | dFree (j,j->vtable->size); | ||
1114 | } | ||
1115 | |||
1116 | |||
1117 | dJointGroupID dJointGroupCreate (int max_size) | ||
1118 | { | ||
1119 | // not any more ... dUASSERT (max_size > 0,"max size must be > 0"); | ||
1120 | dxJointGroup *group = new dxJointGroup; | ||
1121 | group->num = 0; | ||
1122 | return group; | ||
1123 | } | ||
1124 | |||
1125 | |||
1126 | void dJointGroupDestroy (dJointGroupID group) | ||
1127 | { | ||
1128 | dAASSERT (group); | ||
1129 | dJointGroupEmpty (group); | ||
1130 | delete group; | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | void dJointGroupEmpty (dJointGroupID group) | ||
1135 | { | ||
1136 | // the joints in this group are detached starting from the most recently | ||
1137 | // added (at the top of the stack). this helps ensure that the various | ||
1138 | // linked lists are not traversed too much, as the joints will hopefully | ||
1139 | // be at the start of those lists. | ||
1140 | // if any group joints have their world pointer set to 0, their world was | ||
1141 | // previously destroyed. no special handling is required for these joints. | ||
1142 | |||
1143 | dAASSERT (group); | ||
1144 | int i; | ||
1145 | dxJoint **jlist = (dxJoint**) ALLOCA (group->num * sizeof(dxJoint*)); | ||
1146 | dxJoint *j = (dxJoint*) group->stack.rewind(); | ||
1147 | for (i=0; i < group->num; i++) { | ||
1148 | jlist[i] = j; | ||
1149 | j = (dxJoint*) (group->stack.next (j->vtable->size)); | ||
1150 | } | ||
1151 | for (i=group->num-1; i >= 0; i--) { | ||
1152 | if (jlist[i]->world) { | ||
1153 | removeJointReferencesFromAttachedBodies (jlist[i]); | ||
1154 | removeObjectFromList (jlist[i]); | ||
1155 | jlist[i]->world->nj--; | ||
1156 | } | ||
1157 | } | ||
1158 | group->num = 0; | ||
1159 | group->stack.freeAll(); | ||
1160 | } | ||
1161 | |||
1162 | |||
1163 | void dJointAttach (dxJoint *joint, dxBody *body1, dxBody *body2) | ||
1164 | { | ||
1165 | // check arguments | ||
1166 | dUASSERT (joint,"bad joint argument"); | ||
1167 | dUASSERT (body1 == 0 || body1 != body2,"can't have body1==body2"); | ||
1168 | dxWorld *world = joint->world; | ||
1169 | dUASSERT ( (!body1 || body1->world == world) && | ||
1170 | (!body2 || body2->world == world), | ||
1171 | "joint and bodies must be in same world"); | ||
1172 | |||
1173 | // check if the joint can not be attached to just one body | ||
1174 | dUASSERT (!((joint->flags & dJOINT_TWOBODIES) && | ||
1175 | ((body1 != 0) ^ (body2 != 0))), | ||
1176 | "joint can not be attached to just one body"); | ||
1177 | |||
1178 | // remove any existing body attachments | ||
1179 | if (joint->node[0].body || joint->node[1].body) { | ||
1180 | removeJointReferencesFromAttachedBodies (joint); | ||
1181 | } | ||
1182 | |||
1183 | // if a body is zero, make sure that it is body2, so 0 --> node[1].body | ||
1184 | if (body1==0) { | ||
1185 | body1 = body2; | ||
1186 | body2 = 0; | ||
1187 | joint->flags |= dJOINT_REVERSE; | ||
1188 | } | ||
1189 | else { | ||
1190 | joint->flags &= (~dJOINT_REVERSE); | ||
1191 | } | ||
1192 | |||
1193 | // attach to new bodies | ||
1194 | joint->node[0].body = body1; | ||
1195 | joint->node[1].body = body2; | ||
1196 | if (body1) { | ||
1197 | joint->node[1].next = body1->firstjoint; | ||
1198 | body1->firstjoint = &joint->node[1]; | ||
1199 | } | ||
1200 | else joint->node[1].next = 0; | ||
1201 | if (body2) { | ||
1202 | joint->node[0].next = body2->firstjoint; | ||
1203 | body2->firstjoint = &joint->node[0]; | ||
1204 | } | ||
1205 | else { | ||
1206 | joint->node[0].next = 0; | ||
1207 | } | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | void dJointSetData (dxJoint *joint, void *data) | ||
1212 | { | ||
1213 | dAASSERT (joint); | ||
1214 | joint->userdata = data; | ||
1215 | } | ||
1216 | |||
1217 | |||
1218 | void *dJointGetData (dxJoint *joint) | ||
1219 | { | ||
1220 | dAASSERT (joint); | ||
1221 | return joint->userdata; | ||
1222 | } | ||
1223 | |||
1224 | |||
1225 | int dJointGetType (dxJoint *joint) | ||
1226 | { | ||
1227 | dAASSERT (joint); | ||
1228 | return joint->vtable->typenum; | ||
1229 | } | ||
1230 | |||
1231 | |||
1232 | dBodyID dJointGetBody (dxJoint *joint, int index) | ||
1233 | { | ||
1234 | dAASSERT (joint); | ||
1235 | if (index == 0 || index == 1) { | ||
1236 | if (joint->flags & dJOINT_REVERSE) return joint->node[1-index].body; | ||
1237 | else return joint->node[index].body; | ||
1238 | } | ||
1239 | else return 0; | ||
1240 | } | ||
1241 | |||
1242 | |||
1243 | void dJointSetFeedback (dxJoint *joint, dJointFeedback *f) | ||
1244 | { | ||
1245 | dAASSERT (joint); | ||
1246 | joint->feedback = f; | ||
1247 | } | ||
1248 | |||
1249 | |||
1250 | dJointFeedback *dJointGetFeedback (dxJoint *joint) | ||
1251 | { | ||
1252 | dAASSERT (joint); | ||
1253 | return joint->feedback; | ||
1254 | } | ||
1255 | |||
1256 | |||
1257 | |||
1258 | dJointID dConnectingJoint (dBodyID in_b1, dBodyID in_b2) | ||
1259 | { | ||
1260 | dAASSERT (in_b1 || in_b2); | ||
1261 | |||
1262 | dBodyID b1, b2; | ||
1263 | |||
1264 | if (in_b1 == 0) { | ||
1265 | b1 = in_b2; | ||
1266 | b2 = in_b1; | ||
1267 | } | ||
1268 | else { | ||
1269 | b1 = in_b1; | ||
1270 | b2 = in_b2; | ||
1271 | } | ||
1272 | |||
1273 | // look through b1's neighbour list for b2 | ||
1274 | for (dxJointNode *n=b1->firstjoint; n; n=n->next) { | ||
1275 | if (n->body == b2) return n->joint; | ||
1276 | } | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | |||
1283 | int dConnectingJointList (dBodyID in_b1, dBodyID in_b2, dJointID* out_list) | ||
1284 | { | ||
1285 | dAASSERT (in_b1 || in_b2); | ||
1286 | |||
1287 | |||
1288 | dBodyID b1, b2; | ||
1289 | |||
1290 | if (in_b1 == 0) { | ||
1291 | b1 = in_b2; | ||
1292 | b2 = in_b1; | ||
1293 | } | ||
1294 | else { | ||
1295 | b1 = in_b1; | ||
1296 | b2 = in_b2; | ||
1297 | } | ||
1298 | |||
1299 | // look through b1's neighbour list for b2 | ||
1300 | int numConnectingJoints = 0; | ||
1301 | for (dxJointNode *n=b1->firstjoint; n; n=n->next) { | ||
1302 | if (n->body == b2) | ||
1303 | out_list[numConnectingJoints++] = n->joint; | ||
1304 | } | ||
1305 | |||
1306 | return numConnectingJoints; | ||
1307 | } | ||
1308 | |||
1309 | |||
1310 | int dAreConnected (dBodyID b1, dBodyID b2) | ||
1311 | { | ||
1312 | dAASSERT (b1 && b2); | ||
1313 | // look through b1's neighbour list for b2 | ||
1314 | for (dxJointNode *n=b1->firstjoint; n; n=n->next) { | ||
1315 | if (n->body == b2) return 1; | ||
1316 | } | ||
1317 | return 0; | ||
1318 | } | ||
1319 | |||
1320 | |||
1321 | int dAreConnectedExcluding (dBodyID b1, dBodyID b2, int joint_type) | ||
1322 | { | ||
1323 | dAASSERT (b1 && b2); | ||
1324 | // look through b1's neighbour list for b2 | ||
1325 | for (dxJointNode *n=b1->firstjoint; n; n=n->next) { | ||
1326 | if (dJointGetType (n->joint) != joint_type && n->body == b2) return 1; | ||
1327 | } | ||
1328 | return 0; | ||
1329 | } | ||
1330 | |||
1331 | //**************************************************************************** | ||
1332 | // world | ||
1333 | |||
1334 | dxWorld * dWorldCreate() | ||
1335 | { | ||
1336 | dxWorld *w = new dxWorld; | ||
1337 | w->firstbody = 0; | ||
1338 | w->firstjoint = 0; | ||
1339 | w->nb = 0; | ||
1340 | w->nj = 0; | ||
1341 | dSetZero (w->gravity,4); | ||
1342 | w->global_erp = REAL(0.2); | ||
1343 | #if defined(dSINGLE) | ||
1344 | w->global_cfm = 1e-5f; | ||
1345 | #elif defined(dDOUBLE) | ||
1346 | w->global_cfm = 1e-10; | ||
1347 | #else | ||
1348 | #error dSINGLE or dDOUBLE must be defined | ||
1349 | #endif | ||
1350 | |||
1351 | w->adis.idle_steps = 10; | ||
1352 | w->adis.idle_time = 0; | ||
1353 | w->adis_flag = 0; | ||
1354 | w->adis.average_samples = 1; // Default is 1 sample => Instantaneous velocity | ||
1355 | w->adis.angular_average_threshold = REAL(0.01)*REAL(0.01); // (magnitude squared) | ||
1356 | w->adis.linear_average_threshold = REAL(0.01)*REAL(0.01); // (magnitude squared) | ||
1357 | |||
1358 | w->qs.num_iterations = 20; | ||
1359 | w->qs.w = REAL(1.3); | ||
1360 | |||
1361 | w->contactp.max_vel = dInfinity; | ||
1362 | w->contactp.min_depth = 0; | ||
1363 | |||
1364 | return w; | ||
1365 | } | ||
1366 | |||
1367 | |||
1368 | void dWorldDestroy (dxWorld *w) | ||
1369 | { | ||
1370 | // delete all bodies and joints | ||
1371 | dAASSERT (w); | ||
1372 | dxBody *nextb, *b = w->firstbody; | ||
1373 | while (b) { | ||
1374 | nextb = (dxBody*) b->next; | ||
1375 | if(b->average_lvel_buffer) | ||
1376 | { | ||
1377 | delete[] (b->average_lvel_buffer); | ||
1378 | b->average_lvel_buffer = 0; | ||
1379 | } | ||
1380 | if(b->average_avel_buffer) | ||
1381 | { | ||
1382 | delete[] (b->average_avel_buffer); | ||
1383 | b->average_avel_buffer = 0; | ||
1384 | } | ||
1385 | dBodyDestroy(b); // calling here dBodyDestroy for correct destroying! (i.e. the average buffers) | ||
1386 | b = nextb; | ||
1387 | } | ||
1388 | dxJoint *nextj, *j = w->firstjoint; | ||
1389 | while (j) { | ||
1390 | nextj = (dxJoint*)j->next; | ||
1391 | if (j->flags & dJOINT_INGROUP) { | ||
1392 | // the joint is part of a group, so "deactivate" it instead | ||
1393 | j->world = 0; | ||
1394 | j->node[0].body = 0; | ||
1395 | j->node[0].next = 0; | ||
1396 | j->node[1].body = 0; | ||
1397 | j->node[1].next = 0; | ||
1398 | dMessage (0,"warning: destroying world containing grouped joints"); | ||
1399 | } | ||
1400 | else { | ||
1401 | dFree (j,j->vtable->size); | ||
1402 | } | ||
1403 | j = nextj; | ||
1404 | } | ||
1405 | delete w; | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | void dWorldSetGravity (dWorldID w, dReal x, dReal y, dReal z) | ||
1410 | { | ||
1411 | dAASSERT (w); | ||
1412 | w->gravity[0] = x; | ||
1413 | w->gravity[1] = y; | ||
1414 | w->gravity[2] = z; | ||
1415 | } | ||
1416 | |||
1417 | |||
1418 | void dWorldGetGravity (dWorldID w, dVector3 g) | ||
1419 | { | ||
1420 | dAASSERT (w); | ||
1421 | g[0] = w->gravity[0]; | ||
1422 | g[1] = w->gravity[1]; | ||
1423 | g[2] = w->gravity[2]; | ||
1424 | } | ||
1425 | |||
1426 | |||
1427 | void dWorldSetERP (dWorldID w, dReal erp) | ||
1428 | { | ||
1429 | dAASSERT (w); | ||
1430 | w->global_erp = erp; | ||
1431 | } | ||
1432 | |||
1433 | |||
1434 | dReal dWorldGetERP (dWorldID w) | ||
1435 | { | ||
1436 | dAASSERT (w); | ||
1437 | return w->global_erp; | ||
1438 | } | ||
1439 | |||
1440 | |||
1441 | void dWorldSetCFM (dWorldID w, dReal cfm) | ||
1442 | { | ||
1443 | dAASSERT (w); | ||
1444 | w->global_cfm = cfm; | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | dReal dWorldGetCFM (dWorldID w) | ||
1449 | { | ||
1450 | dAASSERT (w); | ||
1451 | return w->global_cfm; | ||
1452 | } | ||
1453 | |||
1454 | |||
1455 | void dWorldStep (dWorldID w, dReal stepsize) | ||
1456 | { | ||
1457 | dUASSERT (w,"bad world argument"); | ||
1458 | dUASSERT (stepsize > 0,"stepsize must be > 0"); | ||
1459 | dxProcessIslands (w,stepsize,&dInternalStepIsland); | ||
1460 | } | ||
1461 | |||
1462 | |||
1463 | void dWorldQuickStep (dWorldID w, dReal stepsize) | ||
1464 | { | ||
1465 | dUASSERT (w,"bad world argument"); | ||
1466 | dUASSERT (stepsize > 0,"stepsize must be > 0"); | ||
1467 | dxProcessIslands (w,stepsize,&dxQuickStepper); | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | void dWorldImpulseToForce (dWorldID w, dReal stepsize, | ||
1472 | dReal ix, dReal iy, dReal iz, | ||
1473 | dVector3 force) | ||
1474 | { | ||
1475 | dAASSERT (w); | ||
1476 | stepsize = dRecip(stepsize); | ||
1477 | force[0] = stepsize * ix; | ||
1478 | force[1] = stepsize * iy; | ||
1479 | force[2] = stepsize * iz; | ||
1480 | // @@@ force[3] = 0; | ||
1481 | } | ||
1482 | |||
1483 | |||
1484 | // world auto-disable functions | ||
1485 | |||
1486 | dReal dWorldGetAutoDisableLinearThreshold (dWorldID w) | ||
1487 | { | ||
1488 | dAASSERT(w); | ||
1489 | return dSqrt (w->adis.linear_average_threshold); | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | void dWorldSetAutoDisableLinearThreshold (dWorldID w, dReal linear_average_threshold) | ||
1494 | { | ||
1495 | dAASSERT(w); | ||
1496 | w->adis.linear_average_threshold = linear_average_threshold * linear_average_threshold; | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | dReal dWorldGetAutoDisableAngularThreshold (dWorldID w) | ||
1501 | { | ||
1502 | dAASSERT(w); | ||
1503 | return dSqrt (w->adis.angular_average_threshold); | ||
1504 | } | ||
1505 | |||
1506 | |||
1507 | void dWorldSetAutoDisableAngularThreshold (dWorldID w, dReal angular_average_threshold) | ||
1508 | { | ||
1509 | dAASSERT(w); | ||
1510 | w->adis.angular_average_threshold = angular_average_threshold * angular_average_threshold; | ||
1511 | } | ||
1512 | |||
1513 | |||
1514 | int dWorldGetAutoDisableAverageSamplesCount (dWorldID w) | ||
1515 | { | ||
1516 | dAASSERT(w); | ||
1517 | return w->adis.average_samples; | ||
1518 | } | ||
1519 | |||
1520 | |||
1521 | void dWorldSetAutoDisableAverageSamplesCount (dWorldID w, unsigned int average_samples_count) | ||
1522 | { | ||
1523 | dAASSERT(w); | ||
1524 | w->adis.average_samples = average_samples_count; | ||
1525 | } | ||
1526 | |||
1527 | |||
1528 | int dWorldGetAutoDisableSteps (dWorldID w) | ||
1529 | { | ||
1530 | dAASSERT(w); | ||
1531 | return w->adis.idle_steps; | ||
1532 | } | ||
1533 | |||
1534 | |||
1535 | void dWorldSetAutoDisableSteps (dWorldID w, int steps) | ||
1536 | { | ||
1537 | dAASSERT(w); | ||
1538 | w->adis.idle_steps = steps; | ||
1539 | } | ||
1540 | |||
1541 | |||
1542 | dReal dWorldGetAutoDisableTime (dWorldID w) | ||
1543 | { | ||
1544 | dAASSERT(w); | ||
1545 | return w->adis.idle_time; | ||
1546 | } | ||
1547 | |||
1548 | |||
1549 | void dWorldSetAutoDisableTime (dWorldID w, dReal time) | ||
1550 | { | ||
1551 | dAASSERT(w); | ||
1552 | w->adis.idle_time = time; | ||
1553 | } | ||
1554 | |||
1555 | |||
1556 | int dWorldGetAutoDisableFlag (dWorldID w) | ||
1557 | { | ||
1558 | dAASSERT(w); | ||
1559 | return w->adis_flag; | ||
1560 | } | ||
1561 | |||
1562 | |||
1563 | void dWorldSetAutoDisableFlag (dWorldID w, int do_auto_disable) | ||
1564 | { | ||
1565 | dAASSERT(w); | ||
1566 | w->adis_flag = (do_auto_disable != 0); | ||
1567 | } | ||
1568 | |||
1569 | |||
1570 | void dWorldSetQuickStepNumIterations (dWorldID w, int num) | ||
1571 | { | ||
1572 | dAASSERT(w); | ||
1573 | w->qs.num_iterations = num; | ||
1574 | } | ||
1575 | |||
1576 | |||
1577 | int dWorldGetQuickStepNumIterations (dWorldID w) | ||
1578 | { | ||
1579 | dAASSERT(w); | ||
1580 | return w->qs.num_iterations; | ||
1581 | } | ||
1582 | |||
1583 | |||
1584 | void dWorldSetQuickStepW (dWorldID w, dReal param) | ||
1585 | { | ||
1586 | dAASSERT(w); | ||
1587 | w->qs.w = param; | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | dReal dWorldGetQuickStepW (dWorldID w) | ||
1592 | { | ||
1593 | dAASSERT(w); | ||
1594 | return w->qs.w; | ||
1595 | } | ||
1596 | |||
1597 | |||
1598 | void dWorldSetContactMaxCorrectingVel (dWorldID w, dReal vel) | ||
1599 | { | ||
1600 | dAASSERT(w); | ||
1601 | w->contactp.max_vel = vel; | ||
1602 | } | ||
1603 | |||
1604 | |||
1605 | dReal dWorldGetContactMaxCorrectingVel (dWorldID w) | ||
1606 | { | ||
1607 | dAASSERT(w); | ||
1608 | return w->contactp.max_vel; | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | void dWorldSetContactSurfaceLayer (dWorldID w, dReal depth) | ||
1613 | { | ||
1614 | dAASSERT(w); | ||
1615 | w->contactp.min_depth = depth; | ||
1616 | } | ||
1617 | |||
1618 | |||
1619 | dReal dWorldGetContactSurfaceLayer (dWorldID w) | ||
1620 | { | ||
1621 | dAASSERT(w); | ||
1622 | return w->contactp.min_depth; | ||
1623 | } | ||
1624 | |||
1625 | //**************************************************************************** | ||
1626 | // testing | ||
1627 | |||
1628 | #define NUM 100 | ||
1629 | |||
1630 | #define DO(x) | ||
1631 | |||
1632 | |||
1633 | extern "C" void dTestDataStructures() | ||
1634 | { | ||
1635 | int i; | ||
1636 | DO(printf ("testDynamicsStuff()\n")); | ||
1637 | |||
1638 | dBodyID body [NUM]; | ||
1639 | int nb = 0; | ||
1640 | dJointID joint [NUM]; | ||
1641 | int nj = 0; | ||
1642 | |||
1643 | for (i=0; i<NUM; i++) body[i] = 0; | ||
1644 | for (i=0; i<NUM; i++) joint[i] = 0; | ||
1645 | |||
1646 | DO(printf ("creating world\n")); | ||
1647 | dWorldID w = dWorldCreate(); | ||
1648 | checkWorld (w); | ||
1649 | |||
1650 | for (;;) { | ||
1651 | if (nb < NUM && dRandReal() > 0.5) { | ||
1652 | DO(printf ("creating body\n")); | ||
1653 | body[nb] = dBodyCreate (w); | ||
1654 | DO(printf ("\t--> %p\n",body[nb])); | ||
1655 | nb++; | ||
1656 | checkWorld (w); | ||
1657 | DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); | ||
1658 | } | ||
1659 | if (nj < NUM && nb > 2 && dRandReal() > 0.5) { | ||
1660 | dBodyID b1 = body [dRand() % nb]; | ||
1661 | dBodyID b2 = body [dRand() % nb]; | ||
1662 | if (b1 != b2) { | ||
1663 | DO(printf ("creating joint, attaching to %p,%p\n",b1,b2)); | ||
1664 | joint[nj] = dJointCreateBall (w,0); | ||
1665 | DO(printf ("\t-->%p\n",joint[nj])); | ||
1666 | checkWorld (w); | ||
1667 | dJointAttach (joint[nj],b1,b2); | ||
1668 | nj++; | ||
1669 | checkWorld (w); | ||
1670 | DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); | ||
1671 | } | ||
1672 | } | ||
1673 | if (nj > 0 && nb > 2 && dRandReal() > 0.5) { | ||
1674 | dBodyID b1 = body [dRand() % nb]; | ||
1675 | dBodyID b2 = body [dRand() % nb]; | ||
1676 | if (b1 != b2) { | ||
1677 | int k = dRand() % nj; | ||
1678 | DO(printf ("reattaching joint %p\n",joint[k])); | ||
1679 | dJointAttach (joint[k],b1,b2); | ||
1680 | checkWorld (w); | ||
1681 | DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); | ||
1682 | } | ||
1683 | } | ||
1684 | if (nb > 0 && dRandReal() > 0.5) { | ||
1685 | int k = dRand() % nb; | ||
1686 | DO(printf ("destroying body %p\n",body[k])); | ||
1687 | dBodyDestroy (body[k]); | ||
1688 | checkWorld (w); | ||
1689 | for (; k < (NUM-1); k++) body[k] = body[k+1]; | ||
1690 | nb--; | ||
1691 | DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); | ||
1692 | } | ||
1693 | if (nj > 0 && dRandReal() > 0.5) { | ||
1694 | int k = dRand() % nj; | ||
1695 | DO(printf ("destroying joint %p\n",joint[k])); | ||
1696 | dJointDestroy (joint[k]); | ||
1697 | checkWorld (w); | ||
1698 | for (; k < (NUM-1); k++) joint[k] = joint[k+1]; | ||
1699 | nj--; | ||
1700 | DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); | ||
1701 | } | ||
1702 | } | ||
1703 | |||
1704 | /* | ||
1705 | printf ("creating world\n"); | ||
1706 | dWorldID w = dWorldCreate(); | ||
1707 | checkWorld (w); | ||
1708 | printf ("creating body\n"); | ||
1709 | dBodyID b1 = dBodyCreate (w); | ||
1710 | checkWorld (w); | ||
1711 | printf ("creating body\n"); | ||
1712 | dBodyID b2 = dBodyCreate (w); | ||
1713 | checkWorld (w); | ||
1714 | printf ("creating joint\n"); | ||
1715 | dJointID j = dJointCreateBall (w); | ||
1716 | checkWorld (w); | ||
1717 | printf ("attaching joint\n"); | ||
1718 | dJointAttach (j,b1,b2); | ||
1719 | checkWorld (w); | ||
1720 | printf ("destroying joint\n"); | ||
1721 | dJointDestroy (j); | ||
1722 | checkWorld (w); | ||
1723 | printf ("destroying body\n"); | ||
1724 | dBodyDestroy (b1); | ||
1725 | checkWorld (w); | ||
1726 | printf ("destroying body\n"); | ||
1727 | dBodyDestroy (b2); | ||
1728 | checkWorld (w); | ||
1729 | printf ("destroying world\n"); | ||
1730 | dWorldDestroy (w); | ||
1731 | */ | ||
1732 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/odemath.cpp b/libraries/ode-0.9\/ode/src/odemath.cpp new file mode 100755 index 0000000..11bc84e --- /dev/null +++ b/libraries/ode-0.9\/ode/src/odemath.cpp | |||
@@ -0,0 +1,178 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/common.h> | ||
24 | #include <ode/odemath.h> | ||
25 | |||
26 | // get some math functions under windows | ||
27 | #ifdef WIN32 | ||
28 | #include <float.h> | ||
29 | #ifndef CYGWIN // added by andy for cygwin | ||
30 | #undef copysign | ||
31 | #define copysign(a,b) ((dReal)_copysign(a,b)) | ||
32 | #endif // added by andy for cygwin | ||
33 | #endif | ||
34 | |||
35 | #undef dNormalize3 | ||
36 | #undef dNormalize4 | ||
37 | |||
38 | |||
39 | // this may be called for vectors `a' with extremely small magnitude, for | ||
40 | // example the result of a cross product on two nearly perpendicular vectors. | ||
41 | // we must be robust to these small vectors. to prevent numerical error, | ||
42 | // first find the component a[i] with the largest magnitude and then scale | ||
43 | // all the components by 1/a[i]. then we can compute the length of `a' and | ||
44 | // scale the components by 1/l. this has been verified to work with vectors | ||
45 | // containing the smallest representable numbers. | ||
46 | |||
47 | int dSafeNormalize3 (dVector3 a) | ||
48 | { | ||
49 | dReal a0,a1,a2,aa0,aa1,aa2,l; | ||
50 | dAASSERT (a); | ||
51 | a0 = a[0]; | ||
52 | a1 = a[1]; | ||
53 | a2 = a[2]; | ||
54 | aa0 = dFabs(a0); | ||
55 | aa1 = dFabs(a1); | ||
56 | aa2 = dFabs(a2); | ||
57 | if (aa1 > aa0) { | ||
58 | if (aa2 > aa1) { | ||
59 | goto aa2_largest; | ||
60 | } | ||
61 | else { // aa1 is largest | ||
62 | a0 /= aa1; | ||
63 | a2 /= aa1; | ||
64 | l = dRecipSqrt (a0*a0 + a2*a2 + 1); | ||
65 | a[0] = a0*l; | ||
66 | a[1] = dCopySign(l,a1); | ||
67 | a[2] = a2*l; | ||
68 | } | ||
69 | } | ||
70 | else { | ||
71 | if (aa2 > aa0) { | ||
72 | aa2_largest: // aa2 is largest | ||
73 | a0 /= aa2; | ||
74 | a1 /= aa2; | ||
75 | l = dRecipSqrt (a0*a0 + a1*a1 + 1); | ||
76 | a[0] = a0*l; | ||
77 | a[1] = a1*l; | ||
78 | a[2] = dCopySign(l,a2); | ||
79 | } | ||
80 | else { // aa0 is largest | ||
81 | if (aa0 <= 0) { | ||
82 | a[0] = 1; // if all a's are zero, this is where we'll end up. | ||
83 | a[1] = 0; // return a default unit length vector. | ||
84 | a[2] = 0; | ||
85 | return 0; | ||
86 | } | ||
87 | a1 /= aa0; | ||
88 | a2 /= aa0; | ||
89 | l = dRecipSqrt (a1*a1 + a2*a2 + 1); | ||
90 | a[0] = dCopySign(l,a0); | ||
91 | a[1] = a1*l; | ||
92 | a[2] = a2*l; | ||
93 | } | ||
94 | } | ||
95 | return 1; | ||
96 | } | ||
97 | |||
98 | /* OLD VERSION */ | ||
99 | /* | ||
100 | void dNormalize3 (dVector3 a) | ||
101 | { | ||
102 | dIASSERT (a); | ||
103 | dReal l = dDOT(a,a); | ||
104 | if (l > 0) { | ||
105 | l = dRecipSqrt(l); | ||
106 | a[0] *= l; | ||
107 | a[1] *= l; | ||
108 | a[2] *= l; | ||
109 | } | ||
110 | else { | ||
111 | a[0] = 1; | ||
112 | a[1] = 0; | ||
113 | a[2] = 0; | ||
114 | } | ||
115 | } | ||
116 | */ | ||
117 | |||
118 | void dNormalize3(dVector3 a) | ||
119 | { | ||
120 | _dNormalize3(a); | ||
121 | } | ||
122 | |||
123 | |||
124 | int dSafeNormalize4 (dVector4 a) | ||
125 | { | ||
126 | dAASSERT (a); | ||
127 | dReal l = dDOT(a,a)+a[3]*a[3]; | ||
128 | if (l > 0) { | ||
129 | l = dRecipSqrt(l); | ||
130 | a[0] *= l; | ||
131 | a[1] *= l; | ||
132 | a[2] *= l; | ||
133 | a[3] *= l; | ||
134 | return 1; | ||
135 | } | ||
136 | else { | ||
137 | a[0] = 1; | ||
138 | a[1] = 0; | ||
139 | a[2] = 0; | ||
140 | a[3] = 0; | ||
141 | return 0; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void dNormalize4(dVector4 a) | ||
146 | { | ||
147 | _dNormalize4(a); | ||
148 | } | ||
149 | |||
150 | |||
151 | void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q) | ||
152 | { | ||
153 | dAASSERT (n && p && q); | ||
154 | if (dFabs(n[2]) > M_SQRT1_2) { | ||
155 | // choose p in y-z plane | ||
156 | dReal a = n[1]*n[1] + n[2]*n[2]; | ||
157 | dReal k = dRecipSqrt (a); | ||
158 | p[0] = 0; | ||
159 | p[1] = -n[2]*k; | ||
160 | p[2] = n[1]*k; | ||
161 | // set q = n x p | ||
162 | q[0] = a*k; | ||
163 | q[1] = -n[0]*p[2]; | ||
164 | q[2] = n[0]*p[1]; | ||
165 | } | ||
166 | else { | ||
167 | // choose p in x-y plane | ||
168 | dReal a = n[0]*n[0] + n[1]*n[1]; | ||
169 | dReal k = dRecipSqrt (a); | ||
170 | p[0] = -n[1]*k; | ||
171 | p[1] = n[0]*k; | ||
172 | p[2] = 0; | ||
173 | // set q = n x p | ||
174 | q[0] = -n[2]*p[1]; | ||
175 | q[1] = n[2]*p[0]; | ||
176 | q[2] = a*k; | ||
177 | } | ||
178 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/plane.cpp b/libraries/ode-0.9\/ode/src/plane.cpp new file mode 100755 index 0000000..e3afb49 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/plane.cpp | |||
@@ -0,0 +1,145 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | //**************************************************************************** | ||
46 | // plane public API | ||
47 | |||
48 | static void make_sure_plane_normal_has_unit_length (dxPlane *g) | ||
49 | { | ||
50 | dReal l = g->p[0]*g->p[0] + g->p[1]*g->p[1] + g->p[2]*g->p[2]; | ||
51 | if (l > 0) { | ||
52 | l = dRecipSqrt(l); | ||
53 | g->p[0] *= l; | ||
54 | g->p[1] *= l; | ||
55 | g->p[2] *= l; | ||
56 | g->p[3] *= l; | ||
57 | } | ||
58 | else { | ||
59 | g->p[0] = 1; | ||
60 | g->p[1] = 0; | ||
61 | g->p[2] = 0; | ||
62 | g->p[3] = 0; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | |||
67 | dxPlane::dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) : | ||
68 | dxGeom (space,0) | ||
69 | { | ||
70 | type = dPlaneClass; | ||
71 | p[0] = a; | ||
72 | p[1] = b; | ||
73 | p[2] = c; | ||
74 | p[3] = d; | ||
75 | make_sure_plane_normal_has_unit_length (this); | ||
76 | } | ||
77 | |||
78 | |||
79 | void dxPlane::computeAABB() | ||
80 | { | ||
81 | aabb[0] = -dInfinity; | ||
82 | aabb[1] = dInfinity; | ||
83 | aabb[2] = -dInfinity; | ||
84 | aabb[3] = dInfinity; | ||
85 | aabb[4] = -dInfinity; | ||
86 | aabb[5] = dInfinity; | ||
87 | |||
88 | // Planes that have normal vectors aligned along an axis can use a | ||
89 | // less comprehensive (half space) bounding box. | ||
90 | |||
91 | if ( p[1] == 0.0f && p[2] == 0.0f ) { | ||
92 | // normal aligned with x-axis | ||
93 | aabb[0] = (p[0] > 0) ? -dInfinity : -p[3]; | ||
94 | aabb[1] = (p[0] > 0) ? p[3] : dInfinity; | ||
95 | } else | ||
96 | if ( p[0] == 0.0f && p[2] == 0.0f ) { | ||
97 | // normal aligned with y-axis | ||
98 | aabb[2] = (p[1] > 0) ? -dInfinity : -p[3]; | ||
99 | aabb[3] = (p[1] > 0) ? p[3] : dInfinity; | ||
100 | } else | ||
101 | if ( p[0] == 0.0f && p[1] == 0.0f ) { | ||
102 | // normal aligned with z-axis | ||
103 | aabb[4] = (p[2] > 0) ? -dInfinity : -p[3]; | ||
104 | aabb[5] = (p[2] > 0) ? p[3] : dInfinity; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | |||
109 | dGeomID dCreatePlane (dSpaceID space, | ||
110 | dReal a, dReal b, dReal c, dReal d) | ||
111 | { | ||
112 | return new dxPlane (space,a,b,c,d); | ||
113 | } | ||
114 | |||
115 | |||
116 | void dGeomPlaneSetParams (dGeomID g, dReal a, dReal b, dReal c, dReal d) | ||
117 | { | ||
118 | dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); | ||
119 | dxPlane *p = (dxPlane*) g; | ||
120 | p->p[0] = a; | ||
121 | p->p[1] = b; | ||
122 | p->p[2] = c; | ||
123 | p->p[3] = d; | ||
124 | make_sure_plane_normal_has_unit_length (p); | ||
125 | dGeomMoved (g); | ||
126 | } | ||
127 | |||
128 | |||
129 | void dGeomPlaneGetParams (dGeomID g, dVector4 result) | ||
130 | { | ||
131 | dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); | ||
132 | dxPlane *p = (dxPlane*) g; | ||
133 | result[0] = p->p[0]; | ||
134 | result[1] = p->p[1]; | ||
135 | result[2] = p->p[2]; | ||
136 | result[3] = p->p[3]; | ||
137 | } | ||
138 | |||
139 | |||
140 | dReal dGeomPlanePointDepth (dGeomID g, dReal x, dReal y, dReal z) | ||
141 | { | ||
142 | dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); | ||
143 | dxPlane *p = (dxPlane*) g; | ||
144 | return p->p[3] - p->p[0]*x - p->p[1]*y - p->p[2]*z; | ||
145 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/quickstep.cpp b/libraries/ode-0.9\/ode/src/quickstep.cpp new file mode 100755 index 0000000..07aa9f7 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/quickstep.cpp | |||
@@ -0,0 +1,880 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include "objects.h" | ||
24 | #include "joint.h" | ||
25 | #include <ode/config.h> | ||
26 | #include <ode/odemath.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/timer.h> | ||
29 | #include <ode/error.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/misc.h> | ||
32 | #include "lcp.h" | ||
33 | #include "util.h" | ||
34 | |||
35 | #define ALLOCA dALLOCA16 | ||
36 | |||
37 | typedef const dReal *dRealPtr; | ||
38 | typedef dReal *dRealMutablePtr; | ||
39 | #define dRealArray(name,n) dReal name[n]; | ||
40 | #define dRealAllocaArray(name,n) dReal *name = (dReal*) ALLOCA ((n)*sizeof(dReal)); | ||
41 | |||
42 | //*************************************************************************** | ||
43 | // configuration | ||
44 | |||
45 | // for the SOR and CG methods: | ||
46 | // uncomment the following line to use warm starting. this definitely | ||
47 | // help for motor-driven joints. unfortunately it appears to hurt | ||
48 | // with high-friction contacts using the SOR method. use with care | ||
49 | |||
50 | //#define WARM_STARTING 1 | ||
51 | |||
52 | |||
53 | // for the SOR method: | ||
54 | // uncomment the following line to determine a new constraint-solving | ||
55 | // order for each iteration. however, the qsort per iteration is expensive, | ||
56 | // and the optimal order is somewhat problem dependent. | ||
57 | // @@@ try the leaf->root ordering. | ||
58 | |||
59 | //#define REORDER_CONSTRAINTS 1 | ||
60 | |||
61 | |||
62 | // for the SOR method: | ||
63 | // uncomment the following line to randomly reorder constraint rows | ||
64 | // during the solution. depending on the situation, this can help a lot | ||
65 | // or hardly at all, but it doesn't seem to hurt. | ||
66 | |||
67 | #define RANDOMLY_REORDER_CONSTRAINTS 1 | ||
68 | |||
69 | //**************************************************************************** | ||
70 | // special matrix multipliers | ||
71 | |||
72 | // multiply block of B matrix (q x 6) with 12 dReal per row with C vektor (q) | ||
73 | static void Multiply1_12q1 (dReal *A, dReal *B, dReal *C, int q) | ||
74 | { | ||
75 | int k; | ||
76 | dReal sum; | ||
77 | dIASSERT (q>0 && A && B && C); | ||
78 | sum = 0; | ||
79 | for (k=0; k<q; k++) sum += B[k*12] * C[k]; | ||
80 | A[0] = sum; | ||
81 | sum = 0; | ||
82 | for (k=0; k<q; k++) sum += B[1+k*12] * C[k]; | ||
83 | A[1] = sum; | ||
84 | sum = 0; | ||
85 | for (k=0; k<q; k++) sum += B[2+k*12] * C[k]; | ||
86 | A[2] = sum; | ||
87 | sum = 0; | ||
88 | for (k=0; k<q; k++) sum += B[3+k*12] * C[k]; | ||
89 | A[3] = sum; | ||
90 | sum = 0; | ||
91 | for (k=0; k<q; k++) sum += B[4+k*12] * C[k]; | ||
92 | A[4] = sum; | ||
93 | sum = 0; | ||
94 | for (k=0; k<q; k++) sum += B[5+k*12] * C[k]; | ||
95 | A[5] = sum; | ||
96 | } | ||
97 | |||
98 | //*************************************************************************** | ||
99 | // testing stuff | ||
100 | |||
101 | #ifdef TIMING | ||
102 | #define IFTIMING(x) x | ||
103 | #else | ||
104 | #define IFTIMING(x) /* */ | ||
105 | #endif | ||
106 | |||
107 | //*************************************************************************** | ||
108 | // various common computations involving the matrix J | ||
109 | |||
110 | // compute iMJ = inv(M)*J' | ||
111 | |||
112 | static void compute_invM_JT (int m, dRealMutablePtr J, dRealMutablePtr iMJ, int *jb, | ||
113 | dxBody * const *body, dRealPtr invI) | ||
114 | { | ||
115 | int i,j; | ||
116 | dRealMutablePtr iMJ_ptr = iMJ; | ||
117 | dRealMutablePtr J_ptr = J; | ||
118 | for (i=0; i<m; i++) { | ||
119 | int b1 = jb[i*2]; | ||
120 | int b2 = jb[i*2+1]; | ||
121 | dReal k = body[b1]->invMass; | ||
122 | for (j=0; j<3; j++) iMJ_ptr[j] = k*J_ptr[j]; | ||
123 | dMULTIPLY0_331 (iMJ_ptr + 3, invI + 12*b1, J_ptr + 3); | ||
124 | if (b2 >= 0) { | ||
125 | k = body[b2]->invMass; | ||
126 | for (j=0; j<3; j++) iMJ_ptr[j+6] = k*J_ptr[j+6]; | ||
127 | dMULTIPLY0_331 (iMJ_ptr + 9, invI + 12*b2, J_ptr + 9); | ||
128 | } | ||
129 | J_ptr += 12; | ||
130 | iMJ_ptr += 12; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | |||
135 | // compute out = inv(M)*J'*in. | ||
136 | |||
137 | static void multiply_invM_JT (int m, int nb, dRealMutablePtr iMJ, int *jb, | ||
138 | dRealMutablePtr in, dRealMutablePtr out) | ||
139 | { | ||
140 | int i,j; | ||
141 | dSetZero (out,6*nb); | ||
142 | dRealPtr iMJ_ptr = iMJ; | ||
143 | for (i=0; i<m; i++) { | ||
144 | int b1 = jb[i*2]; | ||
145 | int b2 = jb[i*2+1]; | ||
146 | dRealMutablePtr out_ptr = out + b1*6; | ||
147 | for (j=0; j<6; j++) out_ptr[j] += iMJ_ptr[j] * in[i]; | ||
148 | iMJ_ptr += 6; | ||
149 | if (b2 >= 0) { | ||
150 | out_ptr = out + b2*6; | ||
151 | for (j=0; j<6; j++) out_ptr[j] += iMJ_ptr[j] * in[i]; | ||
152 | } | ||
153 | iMJ_ptr += 6; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
158 | // compute out = J*in. | ||
159 | |||
160 | static void multiply_J (int m, dRealMutablePtr J, int *jb, | ||
161 | dRealMutablePtr in, dRealMutablePtr out) | ||
162 | { | ||
163 | int i,j; | ||
164 | dRealPtr J_ptr = J; | ||
165 | for (i=0; i<m; i++) { | ||
166 | int b1 = jb[i*2]; | ||
167 | int b2 = jb[i*2+1]; | ||
168 | dReal sum = 0; | ||
169 | dRealMutablePtr in_ptr = in + b1*6; | ||
170 | for (j=0; j<6; j++) sum += J_ptr[j] * in_ptr[j]; | ||
171 | J_ptr += 6; | ||
172 | if (b2 >= 0) { | ||
173 | in_ptr = in + b2*6; | ||
174 | for (j=0; j<6; j++) sum += J_ptr[j] * in_ptr[j]; | ||
175 | } | ||
176 | J_ptr += 6; | ||
177 | out[i] = sum; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | |||
182 | // compute out = (J*inv(M)*J' + cfm)*in. | ||
183 | // use z as an nb*6 temporary. | ||
184 | |||
185 | static void multiply_J_invM_JT (int m, int nb, dRealMutablePtr J, dRealMutablePtr iMJ, int *jb, | ||
186 | dRealPtr cfm, dRealMutablePtr z, dRealMutablePtr in, dRealMutablePtr out) | ||
187 | { | ||
188 | multiply_invM_JT (m,nb,iMJ,jb,in,z); | ||
189 | multiply_J (m,J,jb,z,out); | ||
190 | |||
191 | // add cfm | ||
192 | for (int i=0; i<m; i++) out[i] += cfm[i] * in[i]; | ||
193 | } | ||
194 | |||
195 | //*************************************************************************** | ||
196 | // conjugate gradient method with jacobi preconditioner | ||
197 | // THIS IS EXPERIMENTAL CODE that doesn't work too well, so it is ifdefed out. | ||
198 | // | ||
199 | // adding CFM seems to be critically important to this method. | ||
200 | |||
201 | #if 0 | ||
202 | |||
203 | static inline dReal dot (int n, dRealPtr x, dRealPtr y) | ||
204 | { | ||
205 | dReal sum=0; | ||
206 | for (int i=0; i<n; i++) sum += x[i]*y[i]; | ||
207 | return sum; | ||
208 | } | ||
209 | |||
210 | |||
211 | // x = y + z*alpha | ||
212 | |||
213 | static inline void add (int n, dRealMutablePtr x, dRealPtr y, dRealPtr z, dReal alpha) | ||
214 | { | ||
215 | for (int i=0; i<n; i++) x[i] = y[i] + z[i]*alpha; | ||
216 | } | ||
217 | |||
218 | |||
219 | static void CG_LCP (int m, int nb, dRealMutablePtr J, int *jb, dxBody * const *body, | ||
220 | dRealPtr invI, dRealMutablePtr lambda, dRealMutablePtr fc, dRealMutablePtr b, | ||
221 | dRealMutablePtr lo, dRealMutablePtr hi, dRealPtr cfm, int *findex, | ||
222 | dxQuickStepParameters *qs) | ||
223 | { | ||
224 | int i,j; | ||
225 | const int num_iterations = qs->num_iterations; | ||
226 | |||
227 | // precompute iMJ = inv(M)*J' | ||
228 | dRealAllocaArray (iMJ,m*12); | ||
229 | compute_invM_JT (m,J,iMJ,jb,body,invI); | ||
230 | |||
231 | dReal last_rho = 0; | ||
232 | dRealAllocaArray (r,m); | ||
233 | dRealAllocaArray (z,m); | ||
234 | dRealAllocaArray (p,m); | ||
235 | dRealAllocaArray (q,m); | ||
236 | |||
237 | // precompute 1 / diagonals of A | ||
238 | dRealAllocaArray (Ad,m); | ||
239 | dRealPtr iMJ_ptr = iMJ; | ||
240 | dRealPtr J_ptr = J; | ||
241 | for (i=0; i<m; i++) { | ||
242 | dReal sum = 0; | ||
243 | for (j=0; j<6; j++) sum += iMJ_ptr[j] * J_ptr[j]; | ||
244 | if (jb[i*2+1] >= 0) { | ||
245 | for (j=6; j<12; j++) sum += iMJ_ptr[j] * J_ptr[j]; | ||
246 | } | ||
247 | iMJ_ptr += 12; | ||
248 | J_ptr += 12; | ||
249 | Ad[i] = REAL(1.0) / (sum + cfm[i]); | ||
250 | } | ||
251 | |||
252 | #ifdef WARM_STARTING | ||
253 | // compute residual r = b - A*lambda | ||
254 | multiply_J_invM_JT (m,nb,J,iMJ,jb,cfm,fc,lambda,r); | ||
255 | for (i=0; i<m; i++) r[i] = b[i] - r[i]; | ||
256 | #else | ||
257 | dSetZero (lambda,m); | ||
258 | memcpy (r,b,m*sizeof(dReal)); // residual r = b - A*lambda | ||
259 | #endif | ||
260 | |||
261 | for (int iteration=0; iteration < num_iterations; iteration++) { | ||
262 | for (i=0; i<m; i++) z[i] = r[i]*Ad[i]; // z = inv(M)*r | ||
263 | dReal rho = dot (m,r,z); // rho = r'*z | ||
264 | |||
265 | // @@@ | ||
266 | // we must check for convergence, otherwise rho will go to 0 if | ||
267 | // we get an exact solution, which will introduce NaNs into the equations. | ||
268 | if (rho < 1e-10) { | ||
269 | printf ("CG returned at iteration %d\n",iteration); | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | if (iteration==0) { | ||
274 | memcpy (p,z,m*sizeof(dReal)); // p = z | ||
275 | } | ||
276 | else { | ||
277 | add (m,p,z,p,rho/last_rho); // p = z + (rho/last_rho)*p | ||
278 | } | ||
279 | |||
280 | // compute q = (J*inv(M)*J')*p | ||
281 | multiply_J_invM_JT (m,nb,J,iMJ,jb,cfm,fc,p,q); | ||
282 | |||
283 | dReal alpha = rho/dot (m,p,q); // alpha = rho/(p'*q) | ||
284 | add (m,lambda,lambda,p,alpha); // lambda = lambda + alpha*p | ||
285 | add (m,r,r,q,-alpha); // r = r - alpha*q | ||
286 | last_rho = rho; | ||
287 | } | ||
288 | |||
289 | // compute fc = inv(M)*J'*lambda | ||
290 | multiply_invM_JT (m,nb,iMJ,jb,lambda,fc); | ||
291 | |||
292 | #if 0 | ||
293 | // measure solution error | ||
294 | multiply_J_invM_JT (m,nb,J,iMJ,jb,cfm,fc,lambda,r); | ||
295 | dReal error = 0; | ||
296 | for (i=0; i<m; i++) error += dFabs(r[i] - b[i]); | ||
297 | printf ("lambda error = %10.6e\n",error); | ||
298 | #endif | ||
299 | } | ||
300 | |||
301 | #endif | ||
302 | |||
303 | //*************************************************************************** | ||
304 | // SOR-LCP method | ||
305 | |||
306 | // nb is the number of bodies in the body array. | ||
307 | // J is an m*12 matrix of constraint rows | ||
308 | // jb is an array of first and second body numbers for each constraint row | ||
309 | // invI is the global frame inverse inertia for each body (stacked 3x3 matrices) | ||
310 | // | ||
311 | // this returns lambda and fc (the constraint force). | ||
312 | // note: fc is returned as inv(M)*J'*lambda, the constraint force is actually J'*lambda | ||
313 | // | ||
314 | // b, lo and hi are modified on exit | ||
315 | |||
316 | |||
317 | struct IndexError { | ||
318 | dReal error; // error to sort on | ||
319 | int findex; | ||
320 | int index; // row index | ||
321 | }; | ||
322 | |||
323 | |||
324 | #ifdef REORDER_CONSTRAINTS | ||
325 | |||
326 | static int compare_index_error (const void *a, const void *b) | ||
327 | { | ||
328 | const IndexError *i1 = (IndexError*) a; | ||
329 | const IndexError *i2 = (IndexError*) b; | ||
330 | if (i1->findex < 0 && i2->findex >= 0) return -1; | ||
331 | if (i1->findex >= 0 && i2->findex < 0) return 1; | ||
332 | if (i1->error < i2->error) return -1; | ||
333 | if (i1->error > i2->error) return 1; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | #endif | ||
338 | |||
339 | |||
340 | static void SOR_LCP (int m, int nb, dRealMutablePtr J, int *jb, dxBody * const *body, | ||
341 | dRealPtr invI, dRealMutablePtr lambda, dRealMutablePtr fc, dRealMutablePtr b, | ||
342 | dRealMutablePtr lo, dRealMutablePtr hi, dRealPtr cfm, int *findex, | ||
343 | dxQuickStepParameters *qs) | ||
344 | { | ||
345 | const int num_iterations = qs->num_iterations; | ||
346 | const dReal sor_w = qs->w; // SOR over-relaxation parameter | ||
347 | |||
348 | int i,j; | ||
349 | |||
350 | #ifdef WARM_STARTING | ||
351 | // for warm starting, this seems to be necessary to prevent | ||
352 | // jerkiness in motor-driven joints. i have no idea why this works. | ||
353 | for (i=0; i<m; i++) lambda[i] *= 0.9; | ||
354 | #else | ||
355 | dSetZero (lambda,m); | ||
356 | #endif | ||
357 | |||
358 | #ifdef REORDER_CONSTRAINTS | ||
359 | // the lambda computed at the previous iteration. | ||
360 | // this is used to measure error for when we are reordering the indexes. | ||
361 | dRealAllocaArray (last_lambda,m); | ||
362 | #endif | ||
363 | |||
364 | // a copy of the 'hi' vector in case findex[] is being used | ||
365 | dRealAllocaArray (hicopy,m); | ||
366 | memcpy (hicopy,hi,m*sizeof(dReal)); | ||
367 | |||
368 | // precompute iMJ = inv(M)*J' | ||
369 | dRealAllocaArray (iMJ,m*12); | ||
370 | compute_invM_JT (m,J,iMJ,jb,body,invI); | ||
371 | |||
372 | // compute fc=(inv(M)*J')*lambda. we will incrementally maintain fc | ||
373 | // as we change lambda. | ||
374 | #ifdef WARM_STARTING | ||
375 | multiply_invM_JT (m,nb,iMJ,jb,lambda,fc); | ||
376 | #else | ||
377 | dSetZero (fc,nb*6); | ||
378 | #endif | ||
379 | |||
380 | // precompute 1 / diagonals of A | ||
381 | dRealAllocaArray (Ad,m); | ||
382 | dRealPtr iMJ_ptr = iMJ; | ||
383 | dRealMutablePtr J_ptr = J; | ||
384 | for (i=0; i<m; i++) { | ||
385 | dReal sum = 0; | ||
386 | for (j=0; j<6; j++) sum += iMJ_ptr[j] * J_ptr[j]; | ||
387 | if (jb[i*2+1] >= 0) { | ||
388 | for (j=6; j<12; j++) sum += iMJ_ptr[j] * J_ptr[j]; | ||
389 | } | ||
390 | iMJ_ptr += 12; | ||
391 | J_ptr += 12; | ||
392 | Ad[i] = sor_w / (sum + cfm[i]); | ||
393 | } | ||
394 | |||
395 | // scale J and b by Ad | ||
396 | J_ptr = J; | ||
397 | for (i=0; i<m; i++) { | ||
398 | for (j=0; j<12; j++) { | ||
399 | J_ptr[0] *= Ad[i]; | ||
400 | J_ptr++; | ||
401 | } | ||
402 | b[i] *= Ad[i]; | ||
403 | |||
404 | // scale Ad by CFM. N.B. this should be done last since it is used above | ||
405 | Ad[i] *= cfm[i]; | ||
406 | } | ||
407 | |||
408 | // order to solve constraint rows in | ||
409 | IndexError *order = (IndexError*) ALLOCA (m*sizeof(IndexError)); | ||
410 | |||
411 | #ifndef REORDER_CONSTRAINTS | ||
412 | // make sure constraints with findex < 0 come first. | ||
413 | j=0; | ||
414 | int k=1; | ||
415 | |||
416 | // Fill the array from both ends | ||
417 | for (i=0; i<m; i++) | ||
418 | if (findex[i] < 0) | ||
419 | order[j++].index = i; // Place them at the front | ||
420 | else | ||
421 | order[m-k++].index = i; // Place them at the end | ||
422 | |||
423 | dIASSERT ((j+k-1)==m); // -1 since k was started at 1 and not 0 | ||
424 | #endif | ||
425 | |||
426 | for (int iteration=0; iteration < num_iterations; iteration++) { | ||
427 | |||
428 | #ifdef REORDER_CONSTRAINTS | ||
429 | // constraints with findex < 0 always come first. | ||
430 | if (iteration < 2) { | ||
431 | // for the first two iterations, solve the constraints in | ||
432 | // the given order | ||
433 | for (i=0; i<m; i++) { | ||
434 | order[i].error = i; | ||
435 | order[i].findex = findex[i]; | ||
436 | order[i].index = i; | ||
437 | } | ||
438 | } | ||
439 | else { | ||
440 | // sort the constraints so that the ones converging slowest | ||
441 | // get solved last. use the absolute (not relative) error. | ||
442 | for (i=0; i<m; i++) { | ||
443 | dReal v1 = dFabs (lambda[i]); | ||
444 | dReal v2 = dFabs (last_lambda[i]); | ||
445 | dReal max = (v1 > v2) ? v1 : v2; | ||
446 | if (max > 0) { | ||
447 | //@@@ relative error: order[i].error = dFabs(lambda[i]-last_lambda[i])/max; | ||
448 | order[i].error = dFabs(lambda[i]-last_lambda[i]); | ||
449 | } | ||
450 | else { | ||
451 | order[i].error = dInfinity; | ||
452 | } | ||
453 | order[i].findex = findex[i]; | ||
454 | order[i].index = i; | ||
455 | } | ||
456 | } | ||
457 | qsort (order,m,sizeof(IndexError),&compare_index_error); | ||
458 | |||
459 | //@@@ potential optimization: swap lambda and last_lambda pointers rather | ||
460 | // than copying the data. we must make sure lambda is properly | ||
461 | // returned to the caller | ||
462 | memcpy (last_lambda,lambda,m*sizeof(dReal)); | ||
463 | #endif | ||
464 | #ifdef RANDOMLY_REORDER_CONSTRAINTS | ||
465 | if ((iteration & 7) == 0) { | ||
466 | for (i=1; i<m; ++i) { | ||
467 | IndexError tmp = order[i]; | ||
468 | int swapi = dRandInt(i+1); | ||
469 | order[i] = order[swapi]; | ||
470 | order[swapi] = tmp; | ||
471 | } | ||
472 | } | ||
473 | #endif | ||
474 | |||
475 | for (int i=0; i<m; i++) { | ||
476 | // @@@ potential optimization: we could pre-sort J and iMJ, thereby | ||
477 | // linearizing access to those arrays. hmmm, this does not seem | ||
478 | // like a win, but we should think carefully about our memory | ||
479 | // access pattern. | ||
480 | |||
481 | int index = order[i].index; | ||
482 | J_ptr = J + index*12; | ||
483 | iMJ_ptr = iMJ + index*12; | ||
484 | |||
485 | // set the limits for this constraint. note that 'hicopy' is used. | ||
486 | // this is the place where the QuickStep method differs from the | ||
487 | // direct LCP solving method, since that method only performs this | ||
488 | // limit adjustment once per time step, whereas this method performs | ||
489 | // once per iteration per constraint row. | ||
490 | // the constraints are ordered so that all lambda[] values needed have | ||
491 | // already been computed. | ||
492 | if (findex[index] >= 0) { | ||
493 | hi[index] = dFabs (hicopy[index] * lambda[findex[index]]); | ||
494 | lo[index] = -hi[index]; | ||
495 | } | ||
496 | |||
497 | int b1 = jb[index*2]; | ||
498 | int b2 = jb[index*2+1]; | ||
499 | dReal delta = b[index] - lambda[index]*Ad[index]; | ||
500 | dRealMutablePtr fc_ptr = fc + 6*b1; | ||
501 | |||
502 | // @@@ potential optimization: SIMD-ize this and the b2 >= 0 case | ||
503 | delta -=fc_ptr[0] * J_ptr[0] + fc_ptr[1] * J_ptr[1] + | ||
504 | fc_ptr[2] * J_ptr[2] + fc_ptr[3] * J_ptr[3] + | ||
505 | fc_ptr[4] * J_ptr[4] + fc_ptr[5] * J_ptr[5]; | ||
506 | // @@@ potential optimization: handle 1-body constraints in a separate | ||
507 | // loop to avoid the cost of test & jump? | ||
508 | if (b2 >= 0) { | ||
509 | fc_ptr = fc + 6*b2; | ||
510 | delta -=fc_ptr[0] * J_ptr[6] + fc_ptr[1] * J_ptr[7] + | ||
511 | fc_ptr[2] * J_ptr[8] + fc_ptr[3] * J_ptr[9] + | ||
512 | fc_ptr[4] * J_ptr[10] + fc_ptr[5] * J_ptr[11]; | ||
513 | } | ||
514 | |||
515 | // compute lambda and clamp it to [lo,hi]. | ||
516 | // @@@ potential optimization: does SSE have clamping instructions | ||
517 | // to save test+jump penalties here? | ||
518 | dReal new_lambda = lambda[index] + delta; | ||
519 | if (new_lambda < lo[index]) { | ||
520 | delta = lo[index]-lambda[index]; | ||
521 | lambda[index] = lo[index]; | ||
522 | } | ||
523 | else if (new_lambda > hi[index]) { | ||
524 | delta = hi[index]-lambda[index]; | ||
525 | lambda[index] = hi[index]; | ||
526 | } | ||
527 | else { | ||
528 | lambda[index] = new_lambda; | ||
529 | } | ||
530 | |||
531 | //@@@ a trick that may or may not help | ||
532 | //dReal ramp = (1-((dReal)(iteration+1)/(dReal)num_iterations)); | ||
533 | //delta *= ramp; | ||
534 | |||
535 | // update fc. | ||
536 | // @@@ potential optimization: SIMD for this and the b2 >= 0 case | ||
537 | fc_ptr = fc + 6*b1; | ||
538 | fc_ptr[0] += delta * iMJ_ptr[0]; | ||
539 | fc_ptr[1] += delta * iMJ_ptr[1]; | ||
540 | fc_ptr[2] += delta * iMJ_ptr[2]; | ||
541 | fc_ptr[3] += delta * iMJ_ptr[3]; | ||
542 | fc_ptr[4] += delta * iMJ_ptr[4]; | ||
543 | fc_ptr[5] += delta * iMJ_ptr[5]; | ||
544 | // @@@ potential optimization: handle 1-body constraints in a separate | ||
545 | // loop to avoid the cost of test & jump? | ||
546 | if (b2 >= 0) { | ||
547 | fc_ptr = fc + 6*b2; | ||
548 | fc_ptr[0] += delta * iMJ_ptr[6]; | ||
549 | fc_ptr[1] += delta * iMJ_ptr[7]; | ||
550 | fc_ptr[2] += delta * iMJ_ptr[8]; | ||
551 | fc_ptr[3] += delta * iMJ_ptr[9]; | ||
552 | fc_ptr[4] += delta * iMJ_ptr[10]; | ||
553 | fc_ptr[5] += delta * iMJ_ptr[11]; | ||
554 | } | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | |||
559 | |||
560 | void dxQuickStepper (dxWorld *world, dxBody * const *body, int nb, | ||
561 | dxJoint * const *_joint, int nj, dReal stepsize) | ||
562 | { | ||
563 | int i,j; | ||
564 | IFTIMING(dTimerStart("preprocessing");) | ||
565 | |||
566 | dReal stepsize1 = dRecip(stepsize); | ||
567 | |||
568 | // number all bodies in the body list - set their tag values | ||
569 | for (i=0; i<nb; i++) body[i]->tag = i; | ||
570 | |||
571 | // make a local copy of the joint array, because we might want to modify it. | ||
572 | // (the "dxJoint *const*" declaration says we're allowed to modify the joints | ||
573 | // but not the joint array, because the caller might need it unchanged). | ||
574 | //@@@ do we really need to do this? we'll be sorting constraint rows individually, not joints | ||
575 | dxJoint **joint = (dxJoint**) ALLOCA (nj * sizeof(dxJoint*)); | ||
576 | memcpy (joint,_joint,nj * sizeof(dxJoint*)); | ||
577 | |||
578 | // for all bodies, compute the inertia tensor and its inverse in the global | ||
579 | // frame, and compute the rotational force and add it to the torque | ||
580 | // accumulator. I and invI are a vertical stack of 3x4 matrices, one per body. | ||
581 | //dRealAllocaArray (I,3*4*nb); // need to remember all I's for feedback purposes only | ||
582 | dRealAllocaArray (invI,3*4*nb); | ||
583 | for (i=0; i<nb; i++) { | ||
584 | dMatrix3 tmp; | ||
585 | |||
586 | // compute inverse inertia tensor in global frame | ||
587 | dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->posr.R); | ||
588 | dMULTIPLY0_333 (invI+i*12,body[i]->posr.R,tmp); | ||
589 | #ifdef dGYROSCOPIC | ||
590 | dMatrix3 I; | ||
591 | // compute inertia tensor in global frame | ||
592 | dMULTIPLY2_333 (tmp,body[i]->mass.I,body[i]->posr.R); | ||
593 | //dMULTIPLY0_333 (I+i*12,body[i]->posr.R,tmp); | ||
594 | dMULTIPLY0_333 (I,body[i]->posr.R,tmp); | ||
595 | // compute rotational force | ||
596 | //dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); | ||
597 | dMULTIPLY0_331 (tmp,I,body[i]->avel); | ||
598 | dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); | ||
599 | #endif | ||
600 | } | ||
601 | |||
602 | // add the gravity force to all bodies | ||
603 | for (i=0; i<nb; i++) { | ||
604 | if ((body[i]->flags & dxBodyNoGravity)==0) { | ||
605 | body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; | ||
606 | body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; | ||
607 | body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | // get joint information (m = total constraint dimension, nub = number of unbounded variables). | ||
612 | // joints with m=0 are inactive and are removed from the joints array | ||
613 | // entirely, so that the code that follows does not consider them. | ||
614 | //@@@ do we really need to save all the info1's | ||
615 | dxJoint::Info1 *info = (dxJoint::Info1*) ALLOCA (nj*sizeof(dxJoint::Info1)); | ||
616 | for (i=0, j=0; j<nj; j++) { // i=dest, j=src | ||
617 | joint[j]->vtable->getInfo1 (joint[j],info+i); | ||
618 | dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); | ||
619 | if (info[i].m > 0) { | ||
620 | joint[i] = joint[j]; | ||
621 | i++; | ||
622 | } | ||
623 | } | ||
624 | nj = i; | ||
625 | |||
626 | // create the row offset array | ||
627 | int m = 0; | ||
628 | int *ofs = (int*) ALLOCA (nj*sizeof(int)); | ||
629 | for (i=0; i<nj; i++) { | ||
630 | ofs[i] = m; | ||
631 | m += info[i].m; | ||
632 | } | ||
633 | |||
634 | // if there are constraints, compute the constraint force | ||
635 | dRealAllocaArray (J,m*12); | ||
636 | int *jb = (int*) ALLOCA (m*2*sizeof(int)); | ||
637 | if (m > 0) { | ||
638 | // create a constraint equation right hand side vector `c', a constraint | ||
639 | // force mixing vector `cfm', and LCP low and high bound vectors, and an | ||
640 | // 'findex' vector. | ||
641 | dRealAllocaArray (c,m); | ||
642 | dRealAllocaArray (cfm,m); | ||
643 | dRealAllocaArray (lo,m); | ||
644 | dRealAllocaArray (hi,m); | ||
645 | int *findex = (int*) ALLOCA (m*sizeof(int)); | ||
646 | dSetZero (c,m); | ||
647 | dSetValue (cfm,m,world->global_cfm); | ||
648 | dSetValue (lo,m,-dInfinity); | ||
649 | dSetValue (hi,m, dInfinity); | ||
650 | for (i=0; i<m; i++) findex[i] = -1; | ||
651 | |||
652 | // get jacobian data from constraints. an m*12 matrix will be created | ||
653 | // to store the two jacobian blocks from each constraint. it has this | ||
654 | // format: | ||
655 | // | ||
656 | // l1 l1 l1 a1 a1 a1 l2 l2 l2 a2 a2 a2 \ . | ||
657 | // l1 l1 l1 a1 a1 a1 l2 l2 l2 a2 a2 a2 }-- jacobian for joint 0, body 1 and body 2 (3 rows) | ||
658 | // l1 l1 l1 a1 a1 a1 l2 l2 l2 a2 a2 a2 / | ||
659 | // l1 l1 l1 a1 a1 a1 l2 l2 l2 a2 a2 a2 }--- jacobian for joint 1, body 1 and body 2 (3 rows) | ||
660 | // etc... | ||
661 | // | ||
662 | // (lll) = linear jacobian data | ||
663 | // (aaa) = angular jacobian data | ||
664 | // | ||
665 | IFTIMING (dTimerNow ("create J");) | ||
666 | dSetZero (J,m*12); | ||
667 | dxJoint::Info2 Jinfo; | ||
668 | Jinfo.rowskip = 12; | ||
669 | Jinfo.fps = stepsize1; | ||
670 | Jinfo.erp = world->global_erp; | ||
671 | int mfb = 0; // number of rows of Jacobian we will have to save for joint feedback | ||
672 | for (i=0; i<nj; i++) { | ||
673 | Jinfo.J1l = J + ofs[i]*12; | ||
674 | Jinfo.J1a = Jinfo.J1l + 3; | ||
675 | Jinfo.J2l = Jinfo.J1l + 6; | ||
676 | Jinfo.J2a = Jinfo.J1l + 9; | ||
677 | Jinfo.c = c + ofs[i]; | ||
678 | Jinfo.cfm = cfm + ofs[i]; | ||
679 | Jinfo.lo = lo + ofs[i]; | ||
680 | Jinfo.hi = hi + ofs[i]; | ||
681 | Jinfo.findex = findex + ofs[i]; | ||
682 | joint[i]->vtable->getInfo2 (joint[i],&Jinfo); | ||
683 | // adjust returned findex values for global index numbering | ||
684 | for (j=0; j<info[i].m; j++) { | ||
685 | if (findex[ofs[i] + j] >= 0) findex[ofs[i] + j] += ofs[i]; | ||
686 | } | ||
687 | if (joint[i]->feedback) | ||
688 | mfb += info[i].m; | ||
689 | } | ||
690 | |||
691 | // we need a copy of Jacobian for joint feedbacks | ||
692 | // because it gets destroyed by SOR solver | ||
693 | // instead of saving all Jacobian, we can save just rows | ||
694 | // for joints, that requested feedback (which is normaly much less) | ||
695 | dRealAllocaArray (Jcopy,mfb*12); | ||
696 | if (mfb > 0) { | ||
697 | mfb = 0; | ||
698 | for (i=0; i<nj; i++) | ||
699 | if (joint[i]->feedback) { | ||
700 | memcpy(Jcopy+mfb*12, J+ofs[i]*12, info[i].m*12*sizeof(dReal)); | ||
701 | mfb += info[i].m; | ||
702 | } | ||
703 | } | ||
704 | |||
705 | |||
706 | // create an array of body numbers for each joint row | ||
707 | int *jb_ptr = jb; | ||
708 | for (i=0; i<nj; i++) { | ||
709 | int b1 = (joint[i]->node[0].body) ? (joint[i]->node[0].body->tag) : -1; | ||
710 | int b2 = (joint[i]->node[1].body) ? (joint[i]->node[1].body->tag) : -1; | ||
711 | for (j=0; j<info[i].m; j++) { | ||
712 | jb_ptr[0] = b1; | ||
713 | jb_ptr[1] = b2; | ||
714 | jb_ptr += 2; | ||
715 | } | ||
716 | } | ||
717 | dIASSERT (jb_ptr == jb+2*m); | ||
718 | |||
719 | // compute the right hand side `rhs' | ||
720 | IFTIMING (dTimerNow ("compute rhs");) | ||
721 | dRealAllocaArray (tmp1,nb*6); | ||
722 | // put v/h + invM*fe into tmp1 | ||
723 | for (i=0; i<nb; i++) { | ||
724 | dReal body_invMass = body[i]->invMass; | ||
725 | for (j=0; j<3; j++) tmp1[i*6+j] = body[i]->facc[j] * body_invMass + body[i]->lvel[j] * stepsize1; | ||
726 | dMULTIPLY0_331 (tmp1 + i*6 + 3,invI + i*12,body[i]->tacc); | ||
727 | for (j=0; j<3; j++) tmp1[i*6+3+j] += body[i]->avel[j] * stepsize1; | ||
728 | } | ||
729 | |||
730 | // put J*tmp1 into rhs | ||
731 | dRealAllocaArray (rhs,m); | ||
732 | multiply_J (m,J,jb,tmp1,rhs); | ||
733 | |||
734 | // complete rhs | ||
735 | for (i=0; i<m; i++) rhs[i] = c[i]*stepsize1 - rhs[i]; | ||
736 | |||
737 | // scale CFM | ||
738 | for (i=0; i<m; i++) cfm[i] *= stepsize1; | ||
739 | |||
740 | // load lambda from the value saved on the previous iteration | ||
741 | dRealAllocaArray (lambda,m); | ||
742 | #ifdef WARM_STARTING | ||
743 | dSetZero (lambda,m); //@@@ shouldn't be necessary | ||
744 | for (i=0; i<nj; i++) { | ||
745 | memcpy (lambda+ofs[i],joint[i]->lambda,info[i].m * sizeof(dReal)); | ||
746 | } | ||
747 | #endif | ||
748 | |||
749 | // solve the LCP problem and get lambda and invM*constraint_force | ||
750 | IFTIMING (dTimerNow ("solving LCP problem");) | ||
751 | dRealAllocaArray (cforce,nb*6); | ||
752 | SOR_LCP (m,nb,J,jb,body,invI,lambda,cforce,rhs,lo,hi,cfm,findex,&world->qs); | ||
753 | |||
754 | #ifdef WARM_STARTING | ||
755 | // save lambda for the next iteration | ||
756 | //@@@ note that this doesn't work for contact joints yet, as they are | ||
757 | // recreated every iteration | ||
758 | for (i=0; i<nj; i++) { | ||
759 | memcpy (joint[i]->lambda,lambda+ofs[i],info[i].m * sizeof(dReal)); | ||
760 | } | ||
761 | #endif | ||
762 | |||
763 | // note that the SOR method overwrites rhs and J at this point, so | ||
764 | // they should not be used again. | ||
765 | |||
766 | // add stepsize * cforce to the body velocity | ||
767 | for (i=0; i<nb; i++) { | ||
768 | for (j=0; j<3; j++) body[i]->lvel[j] += stepsize * cforce[i*6+j]; | ||
769 | for (j=0; j<3; j++) body[i]->avel[j] += stepsize * cforce[i*6+3+j]; | ||
770 | } | ||
771 | |||
772 | // if joint feedback is requested, compute the constraint force. | ||
773 | // BUT: cforce is inv(M)*J'*lambda, whereas we want just J'*lambda, | ||
774 | // so we must compute M*cforce. | ||
775 | // @@@ if any joint has a feedback request we compute the entire | ||
776 | // adjusted cforce, which is not the most efficient way to do it. | ||
777 | /*for (j=0; j<nj; j++) { | ||
778 | if (joint[j]->feedback) { | ||
779 | // compute adjusted cforce | ||
780 | for (i=0; i<nb; i++) { | ||
781 | dReal k = body[i]->mass.mass; | ||
782 | cforce [i*6+0] *= k; | ||
783 | cforce [i*6+1] *= k; | ||
784 | cforce [i*6+2] *= k; | ||
785 | dVector3 tmp; | ||
786 | dMULTIPLY0_331 (tmp, I + 12*i, cforce + i*6 + 3); | ||
787 | cforce [i*6+3] = tmp[0]; | ||
788 | cforce [i*6+4] = tmp[1]; | ||
789 | cforce [i*6+5] = tmp[2]; | ||
790 | } | ||
791 | // compute feedback for this and all remaining joints | ||
792 | for (; j<nj; j++) { | ||
793 | dJointFeedback *fb = joint[j]->feedback; | ||
794 | if (fb) { | ||
795 | int b1 = joint[j]->node[0].body->tag; | ||
796 | memcpy (fb->f1,cforce+b1*6,3*sizeof(dReal)); | ||
797 | memcpy (fb->t1,cforce+b1*6+3,3*sizeof(dReal)); | ||
798 | if (joint[j]->node[1].body) { | ||
799 | int b2 = joint[j]->node[1].body->tag; | ||
800 | memcpy (fb->f2,cforce+b2*6,3*sizeof(dReal)); | ||
801 | memcpy (fb->t2,cforce+b2*6+3,3*sizeof(dReal)); | ||
802 | } | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | }*/ | ||
807 | |||
808 | if (mfb > 0) { | ||
809 | // straightforward computation of joint constraint forces: | ||
810 | // multiply related lambdas with respective J' block for joints | ||
811 | // where feedback was requested | ||
812 | mfb = 0; | ||
813 | for (i=0; i<nj; i++) { | ||
814 | if (joint[i]->feedback) { | ||
815 | dJointFeedback *fb = joint[i]->feedback; | ||
816 | dReal data[6]; | ||
817 | Multiply1_12q1 (data, Jcopy+mfb*12, lambda+ofs[i], info[i].m); | ||
818 | fb->f1[0] = data[0]; | ||
819 | fb->f1[1] = data[1]; | ||
820 | fb->f1[2] = data[2]; | ||
821 | fb->t1[0] = data[3]; | ||
822 | fb->t1[1] = data[4]; | ||
823 | fb->t1[2] = data[5]; | ||
824 | if (joint[i]->node[1].body) | ||
825 | { | ||
826 | Multiply1_12q1 (data, Jcopy+mfb*12+6, lambda+ofs[i], info[i].m); | ||
827 | fb->f2[0] = data[0]; | ||
828 | fb->f2[1] = data[1]; | ||
829 | fb->f2[2] = data[2]; | ||
830 | fb->t2[0] = data[3]; | ||
831 | fb->t2[1] = data[4]; | ||
832 | fb->t2[2] = data[5]; | ||
833 | } | ||
834 | mfb += info[i].m; | ||
835 | } | ||
836 | } | ||
837 | } | ||
838 | } | ||
839 | |||
840 | // compute the velocity update: | ||
841 | // add stepsize * invM * fe to the body velocity | ||
842 | |||
843 | IFTIMING (dTimerNow ("compute velocity update");) | ||
844 | for (i=0; i<nb; i++) { | ||
845 | dReal body_invMass = body[i]->invMass; | ||
846 | for (j=0; j<3; j++) body[i]->lvel[j] += stepsize * body_invMass * body[i]->facc[j]; | ||
847 | for (j=0; j<3; j++) body[i]->tacc[j] *= stepsize; | ||
848 | dMULTIPLYADD0_331 (body[i]->avel,invI + i*12,body[i]->tacc); | ||
849 | } | ||
850 | |||
851 | #if 0 | ||
852 | // check that the updated velocity obeys the constraint (this check needs unmodified J) | ||
853 | dRealAllocaArray (vel,nb*6); | ||
854 | for (i=0; i<nb; i++) { | ||
855 | for (j=0; j<3; j++) vel[i*6+j] = body[i]->lvel[j]; | ||
856 | for (j=0; j<3; j++) vel[i*6+3+j] = body[i]->avel[j]; | ||
857 | } | ||
858 | dRealAllocaArray (tmp,m); | ||
859 | multiply_J (m,J,jb,vel,tmp); | ||
860 | dReal error = 0; | ||
861 | for (i=0; i<m; i++) error += dFabs(tmp[i]); | ||
862 | printf ("velocity error = %10.6e\n",error); | ||
863 | #endif | ||
864 | |||
865 | // update the position and orientation from the new linear/angular velocity | ||
866 | // (over the given timestep) | ||
867 | IFTIMING (dTimerNow ("update position");) | ||
868 | for (i=0; i<nb; i++) dxStepBody (body[i],stepsize); | ||
869 | |||
870 | IFTIMING (dTimerNow ("tidy up");) | ||
871 | |||
872 | // zero all force accumulators | ||
873 | for (i=0; i<nb; i++) { | ||
874 | dSetZero (body[i]->facc,3); | ||
875 | dSetZero (body[i]->tacc,3); | ||
876 | } | ||
877 | |||
878 | IFTIMING (dTimerEnd();) | ||
879 | IFTIMING (if (m > 0) dTimerReport (stdout,1);) | ||
880 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/quickstep.h b/libraries/ode-0.9\/ode/src/quickstep.h new file mode 100755 index 0000000..43863e7 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/quickstep.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifndef _ODE_QUICK_STEP_H_ | ||
24 | #define _ODE_QUICK_STEP_H_ | ||
25 | |||
26 | #include <ode/common.h> | ||
27 | |||
28 | |||
29 | void dxQuickStepper (dxWorld *world, dxBody * const *body, int nb, | ||
30 | dxJoint * const *_joint, int nj, dReal stepsize); | ||
31 | |||
32 | |||
33 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/ray.cpp b/libraries/ode-0.9\/ode/src/ray.cpp new file mode 100755 index 0000000..adf61ac --- /dev/null +++ b/libraries/ode-0.9\/ode/src/ray.cpp | |||
@@ -0,0 +1,686 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | //**************************************************************************** | ||
46 | // ray public API | ||
47 | |||
48 | dxRay::dxRay (dSpaceID space, dReal _length) : dxGeom (space,1) | ||
49 | { | ||
50 | type = dRayClass; | ||
51 | length = _length; | ||
52 | } | ||
53 | |||
54 | |||
55 | void dxRay::computeAABB() | ||
56 | { | ||
57 | dVector3 e; | ||
58 | e[0] = final_posr->pos[0] + final_posr->R[0*4+2]*length; | ||
59 | e[1] = final_posr->pos[1] + final_posr->R[1*4+2]*length; | ||
60 | e[2] = final_posr->pos[2] + final_posr->R[2*4+2]*length; | ||
61 | |||
62 | if (final_posr->pos[0] < e[0]){ | ||
63 | aabb[0] = final_posr->pos[0]; | ||
64 | aabb[1] = e[0]; | ||
65 | } | ||
66 | else{ | ||
67 | aabb[0] = e[0]; | ||
68 | aabb[1] = final_posr->pos[0]; | ||
69 | } | ||
70 | |||
71 | if (final_posr->pos[1] < e[1]){ | ||
72 | aabb[2] = final_posr->pos[1]; | ||
73 | aabb[3] = e[1]; | ||
74 | } | ||
75 | else{ | ||
76 | aabb[2] = e[1]; | ||
77 | aabb[3] = final_posr->pos[1]; | ||
78 | } | ||
79 | |||
80 | if (final_posr->pos[2] < e[2]){ | ||
81 | aabb[4] = final_posr->pos[2]; | ||
82 | aabb[5] = e[2]; | ||
83 | } | ||
84 | else{ | ||
85 | aabb[4] = e[2]; | ||
86 | aabb[5] = final_posr->pos[2]; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | |||
91 | dGeomID dCreateRay (dSpaceID space, dReal length) | ||
92 | { | ||
93 | return new dxRay (space,length); | ||
94 | } | ||
95 | |||
96 | |||
97 | void dGeomRaySetLength (dGeomID g, dReal length) | ||
98 | { | ||
99 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
100 | dxRay *r = (dxRay*) g; | ||
101 | r->length = length; | ||
102 | dGeomMoved (g); | ||
103 | } | ||
104 | |||
105 | |||
106 | dReal dGeomRayGetLength (dGeomID g) | ||
107 | { | ||
108 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
109 | dxRay *r = (dxRay*) g; | ||
110 | return r->length; | ||
111 | } | ||
112 | |||
113 | |||
114 | void dGeomRaySet (dGeomID g, dReal px, dReal py, dReal pz, | ||
115 | dReal dx, dReal dy, dReal dz) | ||
116 | { | ||
117 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
118 | g->recomputePosr(); | ||
119 | dReal* rot = g->final_posr->R; | ||
120 | dReal* pos = g->final_posr->pos; | ||
121 | dVector3 n; | ||
122 | pos[0] = px; | ||
123 | pos[1] = py; | ||
124 | pos[2] = pz; | ||
125 | |||
126 | n[0] = dx; | ||
127 | n[1] = dy; | ||
128 | n[2] = dz; | ||
129 | dNormalize3(n); | ||
130 | rot[0*4+2] = n[0]; | ||
131 | rot[1*4+2] = n[1]; | ||
132 | rot[2*4+2] = n[2]; | ||
133 | dGeomMoved (g); | ||
134 | } | ||
135 | |||
136 | |||
137 | void dGeomRayGet (dGeomID g, dVector3 start, dVector3 dir) | ||
138 | { | ||
139 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
140 | g->recomputePosr(); | ||
141 | start[0] = g->final_posr->pos[0]; | ||
142 | start[1] = g->final_posr->pos[1]; | ||
143 | start[2] = g->final_posr->pos[2]; | ||
144 | dir[0] = g->final_posr->R[0*4+2]; | ||
145 | dir[1] = g->final_posr->R[1*4+2]; | ||
146 | dir[2] = g->final_posr->R[2*4+2]; | ||
147 | } | ||
148 | |||
149 | |||
150 | void dGeomRaySetParams (dxGeom *g, int FirstContact, int BackfaceCull) | ||
151 | { | ||
152 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
153 | |||
154 | if (FirstContact){ | ||
155 | g->gflags |= RAY_FIRSTCONTACT; | ||
156 | } | ||
157 | else g->gflags &= ~RAY_FIRSTCONTACT; | ||
158 | |||
159 | if (BackfaceCull){ | ||
160 | g->gflags |= RAY_BACKFACECULL; | ||
161 | } | ||
162 | else g->gflags &= ~RAY_BACKFACECULL; | ||
163 | } | ||
164 | |||
165 | |||
166 | void dGeomRayGetParams (dxGeom *g, int *FirstContact, int *BackfaceCull) | ||
167 | { | ||
168 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
169 | |||
170 | (*FirstContact) = ((g->gflags & RAY_FIRSTCONTACT) != 0); | ||
171 | (*BackfaceCull) = ((g->gflags & RAY_BACKFACECULL) != 0); | ||
172 | } | ||
173 | |||
174 | |||
175 | void dGeomRaySetClosestHit (dxGeom *g, int closestHit) | ||
176 | { | ||
177 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
178 | if (closestHit){ | ||
179 | g->gflags |= RAY_CLOSEST_HIT; | ||
180 | } | ||
181 | else g->gflags &= ~RAY_CLOSEST_HIT; | ||
182 | } | ||
183 | |||
184 | |||
185 | int dGeomRayGetClosestHit (dxGeom *g) | ||
186 | { | ||
187 | dUASSERT (g && g->type == dRayClass,"argument not a ray"); | ||
188 | return ((g->gflags & RAY_CLOSEST_HIT) != 0); | ||
189 | } | ||
190 | |||
191 | |||
192 | |||
193 | // if mode==1 then use the sphere exit contact, not the entry contact | ||
194 | |||
195 | static int ray_sphere_helper (dxRay *ray, dVector3 sphere_pos, dReal radius, | ||
196 | dContactGeom *contact, int mode) | ||
197 | { | ||
198 | dVector3 q; | ||
199 | q[0] = ray->final_posr->pos[0] - sphere_pos[0]; | ||
200 | q[1] = ray->final_posr->pos[1] - sphere_pos[1]; | ||
201 | q[2] = ray->final_posr->pos[2] - sphere_pos[2]; | ||
202 | dReal B = dDOT14(q,ray->final_posr->R+2); | ||
203 | dReal C = dDOT(q,q) - radius*radius; | ||
204 | // note: if C <= 0 then the start of the ray is inside the sphere | ||
205 | dReal k = B*B - C; | ||
206 | if (k < 0) return 0; | ||
207 | k = dSqrt(k); | ||
208 | dReal alpha; | ||
209 | if (mode && C >= 0) { | ||
210 | alpha = -B + k; | ||
211 | if (alpha < 0) return 0; | ||
212 | } | ||
213 | else { | ||
214 | alpha = -B - k; | ||
215 | if (alpha < 0) { | ||
216 | alpha = -B + k; | ||
217 | if (alpha < 0) return 0; | ||
218 | } | ||
219 | } | ||
220 | if (alpha > ray->length) return 0; | ||
221 | contact->pos[0] = ray->final_posr->pos[0] + alpha*ray->final_posr->R[0*4+2]; | ||
222 | contact->pos[1] = ray->final_posr->pos[1] + alpha*ray->final_posr->R[1*4+2]; | ||
223 | contact->pos[2] = ray->final_posr->pos[2] + alpha*ray->final_posr->R[2*4+2]; | ||
224 | dReal nsign = (C < 0 || mode) ? REAL(-1.0) : REAL(1.0); | ||
225 | contact->normal[0] = nsign*(contact->pos[0] - sphere_pos[0]); | ||
226 | contact->normal[1] = nsign*(contact->pos[1] - sphere_pos[1]); | ||
227 | contact->normal[2] = nsign*(contact->pos[2] - sphere_pos[2]); | ||
228 | dNormalize3 (contact->normal); | ||
229 | contact->depth = alpha; | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | |||
234 | int dCollideRaySphere (dxGeom *o1, dxGeom *o2, int flags, | ||
235 | dContactGeom *contact, int skip) | ||
236 | { | ||
237 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
238 | dIASSERT (o1->type == dRayClass); | ||
239 | dIASSERT (o2->type == dSphereClass); | ||
240 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
241 | |||
242 | dxRay *ray = (dxRay*) o1; | ||
243 | dxSphere *sphere = (dxSphere*) o2; | ||
244 | contact->g1 = ray; | ||
245 | contact->g2 = sphere; | ||
246 | return ray_sphere_helper (ray,sphere->final_posr->pos,sphere->radius,contact,0); | ||
247 | } | ||
248 | |||
249 | |||
250 | int dCollideRayBox (dxGeom *o1, dxGeom *o2, int flags, | ||
251 | dContactGeom *contact, int skip) | ||
252 | { | ||
253 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
254 | dIASSERT (o1->type == dRayClass); | ||
255 | dIASSERT (o2->type == dBoxClass); | ||
256 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
257 | |||
258 | dxRay *ray = (dxRay*) o1; | ||
259 | dxBox *box = (dxBox*) o2; | ||
260 | |||
261 | contact->g1 = ray; | ||
262 | contact->g2 = box; | ||
263 | |||
264 | int i; | ||
265 | |||
266 | // compute the start and delta of the ray relative to the box. | ||
267 | // we will do all subsequent computations in this box-relative coordinate | ||
268 | // system. we have to do a translation and rotation for each point. | ||
269 | dVector3 tmp,s,v; | ||
270 | tmp[0] = ray->final_posr->pos[0] - box->final_posr->pos[0]; | ||
271 | tmp[1] = ray->final_posr->pos[1] - box->final_posr->pos[1]; | ||
272 | tmp[2] = ray->final_posr->pos[2] - box->final_posr->pos[2]; | ||
273 | dMULTIPLY1_331 (s,box->final_posr->R,tmp); | ||
274 | tmp[0] = ray->final_posr->R[0*4+2]; | ||
275 | tmp[1] = ray->final_posr->R[1*4+2]; | ||
276 | tmp[2] = ray->final_posr->R[2*4+2]; | ||
277 | dMULTIPLY1_331 (v,box->final_posr->R,tmp); | ||
278 | |||
279 | // mirror the line so that v has all components >= 0 | ||
280 | dVector3 sign; | ||
281 | for (i=0; i<3; i++) { | ||
282 | if (v[i] < 0) { | ||
283 | s[i] = -s[i]; | ||
284 | v[i] = -v[i]; | ||
285 | sign[i] = 1; | ||
286 | } | ||
287 | else sign[i] = -1; | ||
288 | } | ||
289 | |||
290 | // compute the half-sides of the box | ||
291 | dReal h[3]; | ||
292 | h[0] = REAL(0.5) * box->side[0]; | ||
293 | h[1] = REAL(0.5) * box->side[1]; | ||
294 | h[2] = REAL(0.5) * box->side[2]; | ||
295 | |||
296 | // do a few early exit tests | ||
297 | if ((s[0] < -h[0] && v[0] <= 0) || s[0] > h[0] || | ||
298 | (s[1] < -h[1] && v[1] <= 0) || s[1] > h[1] || | ||
299 | (s[2] < -h[2] && v[2] <= 0) || s[2] > h[2] || | ||
300 | (v[0] == 0 && v[1] == 0 && v[2] == 0)) { | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | // compute the t=[lo..hi] range for where s+v*t intersects the box | ||
305 | dReal lo = -dInfinity; | ||
306 | dReal hi = dInfinity; | ||
307 | int nlo = 0, nhi = 0; | ||
308 | for (i=0; i<3; i++) { | ||
309 | if (v[i] != 0) { | ||
310 | dReal k = (-h[i] - s[i])/v[i]; | ||
311 | if (k > lo) { | ||
312 | lo = k; | ||
313 | nlo = i; | ||
314 | } | ||
315 | k = (h[i] - s[i])/v[i]; | ||
316 | if (k < hi) { | ||
317 | hi = k; | ||
318 | nhi = i; | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | // check if the ray intersects | ||
324 | if (lo > hi) return 0; | ||
325 | dReal alpha; | ||
326 | int n; | ||
327 | if (lo >= 0) { | ||
328 | alpha = lo; | ||
329 | n = nlo; | ||
330 | } | ||
331 | else { | ||
332 | alpha = hi; | ||
333 | n = nhi; | ||
334 | } | ||
335 | if (alpha < 0 || alpha > ray->length) return 0; | ||
336 | contact->pos[0] = ray->final_posr->pos[0] + alpha*ray->final_posr->R[0*4+2]; | ||
337 | contact->pos[1] = ray->final_posr->pos[1] + alpha*ray->final_posr->R[1*4+2]; | ||
338 | contact->pos[2] = ray->final_posr->pos[2] + alpha*ray->final_posr->R[2*4+2]; | ||
339 | contact->normal[0] = box->final_posr->R[0*4+n] * sign[n]; | ||
340 | contact->normal[1] = box->final_posr->R[1*4+n] * sign[n]; | ||
341 | contact->normal[2] = box->final_posr->R[2*4+n] * sign[n]; | ||
342 | contact->depth = alpha; | ||
343 | return 1; | ||
344 | } | ||
345 | |||
346 | |||
347 | int dCollideRayCapsule (dxGeom *o1, dxGeom *o2, | ||
348 | int flags, dContactGeom *contact, int skip) | ||
349 | { | ||
350 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
351 | dIASSERT (o1->type == dRayClass); | ||
352 | dIASSERT (o2->type == dCapsuleClass); | ||
353 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
354 | |||
355 | dxRay *ray = (dxRay*) o1; | ||
356 | dxCapsule *ccyl = (dxCapsule*) o2; | ||
357 | |||
358 | contact->g1 = ray; | ||
359 | contact->g2 = ccyl; | ||
360 | dReal lz2 = ccyl->lz * REAL(0.5); | ||
361 | |||
362 | // compute some useful info | ||
363 | dVector3 cs,q,r; | ||
364 | dReal C,k; | ||
365 | cs[0] = ray->final_posr->pos[0] - ccyl->final_posr->pos[0]; | ||
366 | cs[1] = ray->final_posr->pos[1] - ccyl->final_posr->pos[1]; | ||
367 | cs[2] = ray->final_posr->pos[2] - ccyl->final_posr->pos[2]; | ||
368 | k = dDOT41(ccyl->final_posr->R+2,cs); // position of ray start along ccyl axis | ||
369 | q[0] = k*ccyl->final_posr->R[0*4+2] - cs[0]; | ||
370 | q[1] = k*ccyl->final_posr->R[1*4+2] - cs[1]; | ||
371 | q[2] = k*ccyl->final_posr->R[2*4+2] - cs[2]; | ||
372 | C = dDOT(q,q) - ccyl->radius*ccyl->radius; | ||
373 | // if C < 0 then ray start position within infinite extension of cylinder | ||
374 | |||
375 | // see if ray start position is inside the capped cylinder | ||
376 | int inside_ccyl = 0; | ||
377 | if (C < 0) { | ||
378 | if (k < -lz2) k = -lz2; | ||
379 | else if (k > lz2) k = lz2; | ||
380 | r[0] = ccyl->final_posr->pos[0] + k*ccyl->final_posr->R[0*4+2]; | ||
381 | r[1] = ccyl->final_posr->pos[1] + k*ccyl->final_posr->R[1*4+2]; | ||
382 | r[2] = ccyl->final_posr->pos[2] + k*ccyl->final_posr->R[2*4+2]; | ||
383 | if ((ray->final_posr->pos[0]-r[0])*(ray->final_posr->pos[0]-r[0]) + | ||
384 | (ray->final_posr->pos[1]-r[1])*(ray->final_posr->pos[1]-r[1]) + | ||
385 | (ray->final_posr->pos[2]-r[2])*(ray->final_posr->pos[2]-r[2]) < ccyl->radius*ccyl->radius) { | ||
386 | inside_ccyl = 1; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | // compute ray collision with infinite cylinder, except for the case where | ||
391 | // the ray is outside the capped cylinder but within the infinite cylinder | ||
392 | // (it that case the ray can only hit endcaps) | ||
393 | if (!inside_ccyl && C < 0) { | ||
394 | // set k to cap position to check | ||
395 | if (k < 0) k = -lz2; else k = lz2; | ||
396 | } | ||
397 | else { | ||
398 | dReal uv = dDOT44(ccyl->final_posr->R+2,ray->final_posr->R+2); | ||
399 | r[0] = uv*ccyl->final_posr->R[0*4+2] - ray->final_posr->R[0*4+2]; | ||
400 | r[1] = uv*ccyl->final_posr->R[1*4+2] - ray->final_posr->R[1*4+2]; | ||
401 | r[2] = uv*ccyl->final_posr->R[2*4+2] - ray->final_posr->R[2*4+2]; | ||
402 | dReal A = dDOT(r,r); | ||
403 | dReal B = 2*dDOT(q,r); | ||
404 | k = B*B-4*A*C; | ||
405 | if (k < 0) { | ||
406 | // the ray does not intersect the infinite cylinder, but if the ray is | ||
407 | // inside and parallel to the cylinder axis it may intersect the end | ||
408 | // caps. set k to cap position to check. | ||
409 | if (!inside_ccyl) return 0; | ||
410 | if (uv < 0) k = -lz2; else k = lz2; | ||
411 | } | ||
412 | else { | ||
413 | k = dSqrt(k); | ||
414 | A = dRecip (2*A); | ||
415 | dReal alpha = (-B-k)*A; | ||
416 | if (alpha < 0) { | ||
417 | alpha = (-B+k)*A; | ||
418 | if (alpha < 0) return 0; | ||
419 | } | ||
420 | if (alpha > ray->length) return 0; | ||
421 | |||
422 | // the ray intersects the infinite cylinder. check to see if the | ||
423 | // intersection point is between the caps | ||
424 | contact->pos[0] = ray->final_posr->pos[0] + alpha*ray->final_posr->R[0*4+2]; | ||
425 | contact->pos[1] = ray->final_posr->pos[1] + alpha*ray->final_posr->R[1*4+2]; | ||
426 | contact->pos[2] = ray->final_posr->pos[2] + alpha*ray->final_posr->R[2*4+2]; | ||
427 | q[0] = contact->pos[0] - ccyl->final_posr->pos[0]; | ||
428 | q[1] = contact->pos[1] - ccyl->final_posr->pos[1]; | ||
429 | q[2] = contact->pos[2] - ccyl->final_posr->pos[2]; | ||
430 | k = dDOT14(q,ccyl->final_posr->R+2); | ||
431 | dReal nsign = inside_ccyl ? REAL(-1.0) : REAL(1.0); | ||
432 | if (k >= -lz2 && k <= lz2) { | ||
433 | contact->normal[0] = nsign * (contact->pos[0] - | ||
434 | (ccyl->final_posr->pos[0] + k*ccyl->final_posr->R[0*4+2])); | ||
435 | contact->normal[1] = nsign * (contact->pos[1] - | ||
436 | (ccyl->final_posr->pos[1] + k*ccyl->final_posr->R[1*4+2])); | ||
437 | contact->normal[2] = nsign * (contact->pos[2] - | ||
438 | (ccyl->final_posr->pos[2] + k*ccyl->final_posr->R[2*4+2])); | ||
439 | dNormalize3 (contact->normal); | ||
440 | contact->depth = alpha; | ||
441 | return 1; | ||
442 | } | ||
443 | |||
444 | // the infinite cylinder intersection point is not between the caps. | ||
445 | // set k to cap position to check. | ||
446 | if (k < 0) k = -lz2; else k = lz2; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | // check for ray intersection with the caps. k must indicate the cap | ||
451 | // position to check | ||
452 | q[0] = ccyl->final_posr->pos[0] + k*ccyl->final_posr->R[0*4+2]; | ||
453 | q[1] = ccyl->final_posr->pos[1] + k*ccyl->final_posr->R[1*4+2]; | ||
454 | q[2] = ccyl->final_posr->pos[2] + k*ccyl->final_posr->R[2*4+2]; | ||
455 | return ray_sphere_helper (ray,q,ccyl->radius,contact, inside_ccyl); | ||
456 | } | ||
457 | |||
458 | |||
459 | int dCollideRayPlane (dxGeom *o1, dxGeom *o2, int flags, | ||
460 | dContactGeom *contact, int skip) | ||
461 | { | ||
462 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
463 | dIASSERT (o1->type == dRayClass); | ||
464 | dIASSERT (o2->type == dPlaneClass); | ||
465 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
466 | |||
467 | dxRay *ray = (dxRay*) o1; | ||
468 | dxPlane *plane = (dxPlane*) o2; | ||
469 | |||
470 | dReal alpha = plane->p[3] - dDOT (plane->p,ray->final_posr->pos); | ||
471 | // note: if alpha > 0 the starting point is below the plane | ||
472 | dReal nsign = (alpha > 0) ? REAL(-1.0) : REAL(1.0); | ||
473 | dReal k = dDOT14(plane->p,ray->final_posr->R+2); | ||
474 | if (k==0) return 0; // ray parallel to plane | ||
475 | alpha /= k; | ||
476 | if (alpha < 0 || alpha > ray->length) return 0; | ||
477 | contact->pos[0] = ray->final_posr->pos[0] + alpha*ray->final_posr->R[0*4+2]; | ||
478 | contact->pos[1] = ray->final_posr->pos[1] + alpha*ray->final_posr->R[1*4+2]; | ||
479 | contact->pos[2] = ray->final_posr->pos[2] + alpha*ray->final_posr->R[2*4+2]; | ||
480 | contact->normal[0] = nsign*plane->p[0]; | ||
481 | contact->normal[1] = nsign*plane->p[1]; | ||
482 | contact->normal[2] = nsign*plane->p[2]; | ||
483 | contact->depth = alpha; | ||
484 | contact->g1 = ray; | ||
485 | contact->g2 = plane; | ||
486 | return 1; | ||
487 | } | ||
488 | |||
489 | // Ray - Cylinder collider by David Walters (June 2006) | ||
490 | int dCollideRayCylinder( dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip ) | ||
491 | { | ||
492 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
493 | dIASSERT( o1->type == dRayClass ); | ||
494 | dIASSERT( o2->type == dCylinderClass ); | ||
495 | dIASSERT( (flags & NUMC_MASK) >= 1 ); | ||
496 | |||
497 | dxRay* ray = (dxRay*)( o1 ); | ||
498 | dxCylinder* cyl = (dxCylinder*)( o2 ); | ||
499 | |||
500 | // Fill in contact information. | ||
501 | contact->g1 = ray; | ||
502 | contact->g2 = cyl; | ||
503 | |||
504 | const dReal half_length = cyl->lz * REAL( 0.5 ); | ||
505 | |||
506 | // | ||
507 | // Compute some useful info | ||
508 | // | ||
509 | |||
510 | dVector3 q, r; | ||
511 | dReal d, C, k; | ||
512 | |||
513 | // Vector 'r', line segment from C to R (ray start) ( r = R - C ) | ||
514 | r[ 0 ] = ray->final_posr->pos[0] - cyl->final_posr->pos[0]; | ||
515 | r[ 1 ] = ray->final_posr->pos[1] - cyl->final_posr->pos[1]; | ||
516 | r[ 2 ] = ray->final_posr->pos[2] - cyl->final_posr->pos[2]; | ||
517 | |||
518 | // Distance that ray start is along cyl axis ( Z-axis direction ) | ||
519 | d = dDOT41( cyl->final_posr->R + 2, r ); | ||
520 | |||
521 | // | ||
522 | // Compute vector 'q' representing the shortest line from R to the cylinder z-axis (Cz). | ||
523 | // | ||
524 | // Point on axis ( in world space ): cp = ( d * Cz ) + C | ||
525 | // | ||
526 | // Line 'q' from R to cp: q = cp - R | ||
527 | // q = ( d * Cz ) + C - R | ||
528 | // q = ( d * Cz ) - ( R - C ) | ||
529 | |||
530 | q[ 0 ] = ( d * cyl->final_posr->R[0*4+2] ) - r[ 0 ]; | ||
531 | q[ 1 ] = ( d * cyl->final_posr->R[1*4+2] ) - r[ 1 ]; | ||
532 | q[ 2 ] = ( d * cyl->final_posr->R[2*4+2] ) - r[ 2 ]; | ||
533 | |||
534 | |||
535 | // Compute square length of 'q'. Subtract from radius squared to | ||
536 | // get square distance 'C' between the line q and the radius. | ||
537 | |||
538 | // if C < 0 then ray start position is within infinite extension of cylinder | ||
539 | |||
540 | C = dDOT( q, q ) - ( cyl->radius * cyl->radius ); | ||
541 | |||
542 | // Compute the projection of ray direction normal onto cylinder direction normal. | ||
543 | dReal uv = dDOT44( cyl->final_posr->R+2, ray->final_posr->R+2 ); | ||
544 | |||
545 | |||
546 | |||
547 | // | ||
548 | // Find ray collision with infinite cylinder | ||
549 | // | ||
550 | |||
551 | // Compute vector from end of ray direction normal to projection on cylinder direction normal. | ||
552 | r[ 0 ] = ( uv * cyl->final_posr->R[0*4+2] ) - ray->final_posr->R[0*4+2]; | ||
553 | r[ 1 ] = ( uv * cyl->final_posr->R[1*4+2] ) - ray->final_posr->R[1*4+2]; | ||
554 | r[ 2 ] = ( uv * cyl->final_posr->R[2*4+2] ) - ray->final_posr->R[2*4+2]; | ||
555 | |||
556 | |||
557 | // Quadratic Formula Magic | ||
558 | // Compute discriminant 'k': | ||
559 | |||
560 | // k < 0 : No intersection | ||
561 | // k = 0 : Tangent | ||
562 | // k > 0 : Intersection | ||
563 | |||
564 | dReal A = dDOT( r, r ); | ||
565 | dReal B = 2 * dDOT( q, r ); | ||
566 | |||
567 | k = B*B - 4*A*C; | ||
568 | |||
569 | |||
570 | |||
571 | |||
572 | // | ||
573 | // Collision with Flat Caps ? | ||
574 | // | ||
575 | |||
576 | // No collision with cylinder edge. ( Use epsilon here or we miss some obvious cases ) | ||
577 | if ( k < dEpsilon && C <= 0 ) | ||
578 | { | ||
579 | // The ray does not intersect the edge of the infinite cylinder, | ||
580 | // but the ray start is inside and so must run parallel to the axis. | ||
581 | // It may yet intersect an end cap. The following cases are valid: | ||
582 | |||
583 | // -ve-cap , -half centre +half , +ve-cap | ||
584 | // <<================|-------------------|------------->>>---|================>> | ||
585 | // | | | ||
586 | // | d-------------------> 1. | ||
587 | // 2. d------------------> | | ||
588 | // 3. <------------------d | | ||
589 | // | <-------------------d 4. | ||
590 | // | | | ||
591 | // <<================|-------------------|------------->>>---|===============>> | ||
592 | |||
593 | // Negative if the ray and cylinder axes point in opposite directions. | ||
594 | const dReal uvsign = ( uv < 0 ) ? REAL( -1.0 ) : REAL( 1.0 ); | ||
595 | |||
596 | // Negative if the ray start is inside the cylinder | ||
597 | const dReal internal = ( d >= -half_length && d <= +half_length ) ? REAL( -1.0 ) : REAL( 1.0 ); | ||
598 | |||
599 | // Ray and Cylinder axes run in the same direction ( cases 1, 2 ) | ||
600 | // Ray and Cylinder axes run in opposite directions ( cases 3, 4 ) | ||
601 | if ( ( ( uv > 0 ) && ( d + ( uvsign * ray->length ) < half_length * internal ) ) || | ||
602 | ( ( uv < 0 ) && ( d + ( uvsign * ray->length ) > half_length * internal ) ) ) | ||
603 | { | ||
604 | return 0; // No intersection with caps or curved surface. | ||
605 | } | ||
606 | |||
607 | // Compute depth (distance from ray to cylinder) | ||
608 | contact->depth = ( ( -uvsign * d ) - ( internal * half_length ) ); | ||
609 | |||
610 | // Compute contact point. | ||
611 | contact->pos[0] = ray->final_posr->pos[0] + ( contact->depth * ray->final_posr->R[0*4+2] ); | ||
612 | contact->pos[1] = ray->final_posr->pos[1] + ( contact->depth * ray->final_posr->R[1*4+2] ); | ||
613 | contact->pos[2] = ray->final_posr->pos[2] + ( contact->depth * ray->final_posr->R[2*4+2] ); | ||
614 | |||
615 | // Compute reflected contact normal. | ||
616 | contact->normal[0] = uvsign * ( cyl->final_posr->R[0*4+2] ); | ||
617 | contact->normal[1] = uvsign * ( cyl->final_posr->R[1*4+2] ); | ||
618 | contact->normal[2] = uvsign * ( cyl->final_posr->R[2*4+2] ); | ||
619 | |||
620 | // Contact! | ||
621 | return 1; | ||
622 | } | ||
623 | |||
624 | |||
625 | |||
626 | // | ||
627 | // Collision with Curved Edge ? | ||
628 | // | ||
629 | |||
630 | if ( k > 0 ) | ||
631 | { | ||
632 | // Finish off quadratic formula to get intersection co-efficient | ||
633 | k = dSqrt( k ); | ||
634 | A = dRecip( 2 * A ); | ||
635 | |||
636 | // Compute distance along line to contact point. | ||
637 | dReal alpha = ( -B - k ) * A; | ||
638 | if ( alpha < 0 ) | ||
639 | { | ||
640 | // Flip in the other direction. | ||
641 | alpha = ( -B + k ) * A; | ||
642 | } | ||
643 | |||
644 | // Intersection point is within ray length? | ||
645 | if ( alpha >= 0 && alpha <= ray->length ) | ||
646 | { | ||
647 | // The ray intersects the infinite cylinder! | ||
648 | |||
649 | // Compute contact point. | ||
650 | contact->pos[0] = ray->final_posr->pos[0] + ( alpha * ray->final_posr->R[0*4+2] ); | ||
651 | contact->pos[1] = ray->final_posr->pos[1] + ( alpha * ray->final_posr->R[1*4+2] ); | ||
652 | contact->pos[2] = ray->final_posr->pos[2] + ( alpha * ray->final_posr->R[2*4+2] ); | ||
653 | |||
654 | // q is the vector from the cylinder centre to the contact point. | ||
655 | q[0] = contact->pos[0] - cyl->final_posr->pos[0]; | ||
656 | q[1] = contact->pos[1] - cyl->final_posr->pos[1]; | ||
657 | q[2] = contact->pos[2] - cyl->final_posr->pos[2]; | ||
658 | |||
659 | // Compute the distance along the cylinder axis of this contact point. | ||
660 | d = dDOT14( q, cyl->final_posr->R+2 ); | ||
661 | |||
662 | // Check to see if the intersection point is between the flat end caps | ||
663 | if ( d >= -half_length && d <= +half_length ) | ||
664 | { | ||
665 | // Flip the normal if the start point is inside the cylinder. | ||
666 | const dReal nsign = ( C < 0 ) ? REAL( -1.0 ) : REAL( 1.0 ); | ||
667 | |||
668 | // Compute contact normal. | ||
669 | contact->normal[0] = nsign * (contact->pos[0] - (cyl->final_posr->pos[0] + d*cyl->final_posr->R[0*4+2])); | ||
670 | contact->normal[1] = nsign * (contact->pos[1] - (cyl->final_posr->pos[1] + d*cyl->final_posr->R[1*4+2])); | ||
671 | contact->normal[2] = nsign * (contact->pos[2] - (cyl->final_posr->pos[2] + d*cyl->final_posr->R[2*4+2])); | ||
672 | dNormalize3( contact->normal ); | ||
673 | |||
674 | // Store depth. | ||
675 | contact->depth = alpha; | ||
676 | |||
677 | // Contact! | ||
678 | return 1; | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | |||
683 | // No contact with anything. | ||
684 | return 0; | ||
685 | } | ||
686 | |||
diff --git a/libraries/ode-0.9\/ode/src/rotation.cpp b/libraries/ode-0.9\/ode/src/rotation.cpp new file mode 100755 index 0000000..adb933b --- /dev/null +++ b/libraries/ode-0.9\/ode/src/rotation.cpp | |||
@@ -0,0 +1,316 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | quaternions have the format: (s,vx,vy,vz) where (vx,vy,vz) is the | ||
26 | "rotation axis" and s is the "rotation angle". | ||
27 | |||
28 | */ | ||
29 | |||
30 | #include <ode/rotation.h> | ||
31 | #include <ode/odemath.h> | ||
32 | |||
33 | |||
34 | #define _R(i,j) R[(i)*4+(j)] | ||
35 | |||
36 | #define SET_3x3_IDENTITY \ | ||
37 | _R(0,0) = REAL(1.0); \ | ||
38 | _R(0,1) = REAL(0.0); \ | ||
39 | _R(0,2) = REAL(0.0); \ | ||
40 | _R(0,3) = REAL(0.0); \ | ||
41 | _R(1,0) = REAL(0.0); \ | ||
42 | _R(1,1) = REAL(1.0); \ | ||
43 | _R(1,2) = REAL(0.0); \ | ||
44 | _R(1,3) = REAL(0.0); \ | ||
45 | _R(2,0) = REAL(0.0); \ | ||
46 | _R(2,1) = REAL(0.0); \ | ||
47 | _R(2,2) = REAL(1.0); \ | ||
48 | _R(2,3) = REAL(0.0); | ||
49 | |||
50 | |||
51 | void dRSetIdentity (dMatrix3 R) | ||
52 | { | ||
53 | dAASSERT (R); | ||
54 | SET_3x3_IDENTITY; | ||
55 | } | ||
56 | |||
57 | |||
58 | void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, | ||
59 | dReal angle) | ||
60 | { | ||
61 | dAASSERT (R); | ||
62 | dQuaternion q; | ||
63 | dQFromAxisAndAngle (q,ax,ay,az,angle); | ||
64 | dQtoR (q,R); | ||
65 | } | ||
66 | |||
67 | |||
68 | void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi) | ||
69 | { | ||
70 | dReal sphi,cphi,stheta,ctheta,spsi,cpsi; | ||
71 | dAASSERT (R); | ||
72 | sphi = dSin(phi); | ||
73 | cphi = dCos(phi); | ||
74 | stheta = dSin(theta); | ||
75 | ctheta = dCos(theta); | ||
76 | spsi = dSin(psi); | ||
77 | cpsi = dCos(psi); | ||
78 | _R(0,0) = cpsi*ctheta; | ||
79 | _R(0,1) = spsi*ctheta; | ||
80 | _R(0,2) =-stheta; | ||
81 | _R(0,3) = REAL(0.0); | ||
82 | _R(1,0) = cpsi*stheta*sphi - spsi*cphi; | ||
83 | _R(1,1) = spsi*stheta*sphi + cpsi*cphi; | ||
84 | _R(1,2) = ctheta*sphi; | ||
85 | _R(1,3) = REAL(0.0); | ||
86 | _R(2,0) = cpsi*stheta*cphi + spsi*sphi; | ||
87 | _R(2,1) = spsi*stheta*cphi - cpsi*sphi; | ||
88 | _R(2,2) = ctheta*cphi; | ||
89 | _R(2,3) = REAL(0.0); | ||
90 | } | ||
91 | |||
92 | |||
93 | void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, | ||
94 | dReal bx, dReal by, dReal bz) | ||
95 | { | ||
96 | dReal l,k; | ||
97 | dAASSERT (R); | ||
98 | l = dSqrt (ax*ax + ay*ay + az*az); | ||
99 | if (l <= REAL(0.0)) { | ||
100 | dDEBUGMSG ("zero length vector"); | ||
101 | return; | ||
102 | } | ||
103 | l = dRecip(l); | ||
104 | ax *= l; | ||
105 | ay *= l; | ||
106 | az *= l; | ||
107 | k = ax*bx + ay*by + az*bz; | ||
108 | bx -= k*ax; | ||
109 | by -= k*ay; | ||
110 | bz -= k*az; | ||
111 | l = dSqrt (bx*bx + by*by + bz*bz); | ||
112 | if (l <= REAL(0.0)) { | ||
113 | dDEBUGMSG ("zero length vector"); | ||
114 | return; | ||
115 | } | ||
116 | l = dRecip(l); | ||
117 | bx *= l; | ||
118 | by *= l; | ||
119 | bz *= l; | ||
120 | _R(0,0) = ax; | ||
121 | _R(1,0) = ay; | ||
122 | _R(2,0) = az; | ||
123 | _R(0,1) = bx; | ||
124 | _R(1,1) = by; | ||
125 | _R(2,1) = bz; | ||
126 | _R(0,2) = - by*az + ay*bz; | ||
127 | _R(1,2) = - bz*ax + az*bx; | ||
128 | _R(2,2) = - bx*ay + ax*by; | ||
129 | _R(0,3) = REAL(0.0); | ||
130 | _R(1,3) = REAL(0.0); | ||
131 | _R(2,3) = REAL(0.0); | ||
132 | } | ||
133 | |||
134 | |||
135 | void dRFromZAxis (dMatrix3 R, dReal ax, dReal ay, dReal az) | ||
136 | { | ||
137 | dVector3 n,p,q; | ||
138 | n[0] = ax; | ||
139 | n[1] = ay; | ||
140 | n[2] = az; | ||
141 | dNormalize3 (n); | ||
142 | dPlaneSpace (n,p,q); | ||
143 | _R(0,0) = p[0]; | ||
144 | _R(1,0) = p[1]; | ||
145 | _R(2,0) = p[2]; | ||
146 | _R(0,1) = q[0]; | ||
147 | _R(1,1) = q[1]; | ||
148 | _R(2,1) = q[2]; | ||
149 | _R(0,2) = n[0]; | ||
150 | _R(1,2) = n[1]; | ||
151 | _R(2,2) = n[2]; | ||
152 | _R(0,3) = REAL(0.0); | ||
153 | _R(1,3) = REAL(0.0); | ||
154 | _R(2,3) = REAL(0.0); | ||
155 | } | ||
156 | |||
157 | |||
158 | void dQSetIdentity (dQuaternion q) | ||
159 | { | ||
160 | dAASSERT (q); | ||
161 | q[0] = 1; | ||
162 | q[1] = 0; | ||
163 | q[2] = 0; | ||
164 | q[3] = 0; | ||
165 | } | ||
166 | |||
167 | |||
168 | void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, | ||
169 | dReal angle) | ||
170 | { | ||
171 | dAASSERT (q); | ||
172 | dReal l = ax*ax + ay*ay + az*az; | ||
173 | if (l > REAL(0.0)) { | ||
174 | angle *= REAL(0.5); | ||
175 | q[0] = dCos (angle); | ||
176 | l = dSin(angle) * dRecipSqrt(l); | ||
177 | q[1] = ax*l; | ||
178 | q[2] = ay*l; | ||
179 | q[3] = az*l; | ||
180 | } | ||
181 | else { | ||
182 | q[0] = 1; | ||
183 | q[1] = 0; | ||
184 | q[2] = 0; | ||
185 | q[3] = 0; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) | ||
191 | { | ||
192 | dAASSERT (qa && qb && qc); | ||
193 | qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; | ||
194 | qa[1] = qb[0]*qc[1] + qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; | ||
195 | qa[2] = qb[0]*qc[2] + qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; | ||
196 | qa[3] = qb[0]*qc[3] + qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; | ||
197 | } | ||
198 | |||
199 | |||
200 | void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) | ||
201 | { | ||
202 | dAASSERT (qa && qb && qc); | ||
203 | qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; | ||
204 | qa[1] = qb[0]*qc[1] - qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; | ||
205 | qa[2] = qb[0]*qc[2] - qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; | ||
206 | qa[3] = qb[0]*qc[3] - qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; | ||
207 | } | ||
208 | |||
209 | |||
210 | void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) | ||
211 | { | ||
212 | dAASSERT (qa && qb && qc); | ||
213 | qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; | ||
214 | qa[1] = -qb[0]*qc[1] + qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; | ||
215 | qa[2] = -qb[0]*qc[2] + qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; | ||
216 | qa[3] = -qb[0]*qc[3] + qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; | ||
217 | } | ||
218 | |||
219 | |||
220 | void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) | ||
221 | { | ||
222 | dAASSERT (qa && qb && qc); | ||
223 | qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; | ||
224 | qa[1] = -qb[0]*qc[1] - qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; | ||
225 | qa[2] = -qb[0]*qc[2] - qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; | ||
226 | qa[3] = -qb[0]*qc[3] - qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; | ||
227 | } | ||
228 | |||
229 | |||
230 | // dRfromQ(), dQfromR() and dDQfromW() are derived from equations in "An Introduction | ||
231 | // to Physically Based Modeling: Rigid Body Simulation - 1: Unconstrained | ||
232 | // Rigid Body Dynamics" by David Baraff, Robotics Institute, Carnegie Mellon | ||
233 | // University, 1997. | ||
234 | |||
235 | void dRfromQ (dMatrix3 R, const dQuaternion q) | ||
236 | { | ||
237 | dAASSERT (q && R); | ||
238 | // q = (s,vx,vy,vz) | ||
239 | dReal qq1 = 2*q[1]*q[1]; | ||
240 | dReal qq2 = 2*q[2]*q[2]; | ||
241 | dReal qq3 = 2*q[3]*q[3]; | ||
242 | _R(0,0) = 1 - qq2 - qq3; | ||
243 | _R(0,1) = 2*(q[1]*q[2] - q[0]*q[3]); | ||
244 | _R(0,2) = 2*(q[1]*q[3] + q[0]*q[2]); | ||
245 | _R(0,3) = REAL(0.0); | ||
246 | _R(1,0) = 2*(q[1]*q[2] + q[0]*q[3]); | ||
247 | _R(1,1) = 1 - qq1 - qq3; | ||
248 | _R(1,2) = 2*(q[2]*q[3] - q[0]*q[1]); | ||
249 | _R(1,3) = REAL(0.0); | ||
250 | _R(2,0) = 2*(q[1]*q[3] - q[0]*q[2]); | ||
251 | _R(2,1) = 2*(q[2]*q[3] + q[0]*q[1]); | ||
252 | _R(2,2) = 1 - qq1 - qq2; | ||
253 | _R(2,3) = REAL(0.0); | ||
254 | } | ||
255 | |||
256 | |||
257 | void dQfromR (dQuaternion q, const dMatrix3 R) | ||
258 | { | ||
259 | dAASSERT (q && R); | ||
260 | dReal tr,s; | ||
261 | tr = _R(0,0) + _R(1,1) + _R(2,2); | ||
262 | if (tr >= 0) { | ||
263 | s = dSqrt (tr + 1); | ||
264 | q[0] = REAL(0.5) * s; | ||
265 | s = REAL(0.5) * dRecip(s); | ||
266 | q[1] = (_R(2,1) - _R(1,2)) * s; | ||
267 | q[2] = (_R(0,2) - _R(2,0)) * s; | ||
268 | q[3] = (_R(1,0) - _R(0,1)) * s; | ||
269 | } | ||
270 | else { | ||
271 | // find the largest diagonal element and jump to the appropriate case | ||
272 | if (_R(1,1) > _R(0,0)) { | ||
273 | if (_R(2,2) > _R(1,1)) goto case_2; | ||
274 | goto case_1; | ||
275 | } | ||
276 | if (_R(2,2) > _R(0,0)) goto case_2; | ||
277 | goto case_0; | ||
278 | |||
279 | case_0: | ||
280 | s = dSqrt((_R(0,0) - (_R(1,1) + _R(2,2))) + 1); | ||
281 | q[1] = REAL(0.5) * s; | ||
282 | s = REAL(0.5) * dRecip(s); | ||
283 | q[2] = (_R(0,1) + _R(1,0)) * s; | ||
284 | q[3] = (_R(2,0) + _R(0,2)) * s; | ||
285 | q[0] = (_R(2,1) - _R(1,2)) * s; | ||
286 | return; | ||
287 | |||
288 | case_1: | ||
289 | s = dSqrt((_R(1,1) - (_R(2,2) + _R(0,0))) + 1); | ||
290 | q[2] = REAL(0.5) * s; | ||
291 | s = REAL(0.5) * dRecip(s); | ||
292 | q[3] = (_R(1,2) + _R(2,1)) * s; | ||
293 | q[1] = (_R(0,1) + _R(1,0)) * s; | ||
294 | q[0] = (_R(0,2) - _R(2,0)) * s; | ||
295 | return; | ||
296 | |||
297 | case_2: | ||
298 | s = dSqrt((_R(2,2) - (_R(0,0) + _R(1,1))) + 1); | ||
299 | q[3] = REAL(0.5) * s; | ||
300 | s = REAL(0.5) * dRecip(s); | ||
301 | q[1] = (_R(2,0) + _R(0,2)) * s; | ||
302 | q[2] = (_R(1,2) + _R(2,1)) * s; | ||
303 | q[0] = (_R(1,0) - _R(0,1)) * s; | ||
304 | return; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | |||
309 | void dDQfromW (dReal dq[4], const dVector3 w, const dQuaternion q) | ||
310 | { | ||
311 | dAASSERT (w && q && dq); | ||
312 | dq[0] = REAL(0.5)*(- w[0]*q[1] - w[1]*q[2] - w[2]*q[3]); | ||
313 | dq[1] = REAL(0.5)*( w[0]*q[0] + w[1]*q[3] - w[2]*q[2]); | ||
314 | dq[2] = REAL(0.5)*(- w[0]*q[3] + w[1]*q[0] + w[2]*q[1]); | ||
315 | dq[3] = REAL(0.5)*( w[0]*q[2] - w[1]*q[1] + w[2]*q[0]); | ||
316 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/scrapbook.cpp b/libraries/ode-0.9\/ode/src/scrapbook.cpp new file mode 100755 index 0000000..2621814 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/scrapbook.cpp | |||
@@ -0,0 +1,485 @@ | |||
1 | |||
2 | /* | ||
3 | |||
4 | this is code that was once useful but has now been obseleted. | ||
5 | |||
6 | this file should not be compiled as part of ODE! | ||
7 | |||
8 | */ | ||
9 | |||
10 | //*************************************************************************** | ||
11 | // intersect a line segment with a plane | ||
12 | |||
13 | extern "C" int dClipLineToBox (const dVector3 p1, const dVector3 p2, | ||
14 | const dVector3 p, const dMatrix3 R, | ||
15 | const dVector3 side) | ||
16 | { | ||
17 | // compute the start and end of the line (p1 and p2) relative to the box. | ||
18 | // we will do all subsequent computations in this box-relative coordinate | ||
19 | // system. we have to do a translation and rotation for each point. | ||
20 | dVector3 tmp,s,e; | ||
21 | tmp[0] = p1[0] - p[0]; | ||
22 | tmp[1] = p1[1] - p[1]; | ||
23 | tmp[2] = p1[2] - p[2]; | ||
24 | dMULTIPLY1_331 (s,R,tmp); | ||
25 | tmp[0] = p2[0] - p[0]; | ||
26 | tmp[1] = p2[1] - p[1]; | ||
27 | tmp[2] = p2[2] - p[2]; | ||
28 | dMULTIPLY1_331 (e,R,tmp); | ||
29 | |||
30 | // compute the vector 'v' from the start point to the end point | ||
31 | dVector3 v; | ||
32 | v[0] = e[0] - s[0]; | ||
33 | v[1] = e[1] - s[1]; | ||
34 | v[2] = e[2] - s[2]; | ||
35 | |||
36 | // a point on the line is defined by the parameter 't'. t=0 corresponds | ||
37 | // to the start of the line, t=1 corresponds to the end of the line. | ||
38 | // we will clip the line to the box by finding the range of t where a | ||
39 | // point on the line is inside the box. the currently known bounds for | ||
40 | // t and tlo..thi. | ||
41 | dReal tlo=0,thi=1; | ||
42 | |||
43 | // clip in the X/Y/Z direction | ||
44 | for (int i=0; i<3; i++) { | ||
45 | // first adjust s,e for the current t range. this is redundant for the | ||
46 | // first iteration, but never mind. | ||
47 | e[i] = s[i] + thi*v[i]; | ||
48 | s[i] = s[i] + tlo*v[i]; | ||
49 | // compute where t intersects the positive and negative sides. | ||
50 | dReal tp = ( side[i] - s[i])/v[i]; // @@@ handle case where denom=0 | ||
51 | dReal tm = (-side[i] - s[i])/v[i]; | ||
52 | // handle 9 intersection cases | ||
53 | if (s[i] <= -side[i]) { | ||
54 | tlo = tm; | ||
55 | if (e[i] <= -side[i]) return 0; | ||
56 | else if (e[i] >= side[i]) thi = tp; | ||
57 | } | ||
58 | else if (s[i] <= side[i]) { | ||
59 | if (e[i] <= -side[i]) thi = tm; | ||
60 | else if (e[i] >= side[i]) thi = tp; | ||
61 | } | ||
62 | else { | ||
63 | tlo = tp; | ||
64 | if (e[i] <= -side[i]) thi = tm; | ||
65 | else if (e[i] >= side[i]) return 0; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | //... @@@ AT HERE @@@ | ||
70 | |||
71 | return 1; | ||
72 | } | ||
73 | |||
74 | |||
75 | //*************************************************************************** | ||
76 | // a nice try at C-B collision. unfortunately it doesn't work. the logic | ||
77 | // for testing for line-box intersection is correct, but unfortunately the | ||
78 | // closest-point distance estimates are often too large. as a result contact | ||
79 | // points are placed incorrectly. | ||
80 | |||
81 | |||
82 | int dCollideCB (const dxGeom *o1, const dxGeom *o2, int flags, | ||
83 | dContactGeom *contact, int skip) | ||
84 | { | ||
85 | int i; | ||
86 | |||
87 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
88 | dIASSERT (o1->_class->num == dCCylinderClass); | ||
89 | dIASSERT (o2->_class->num == dBoxClass); | ||
90 | contact->g1 = const_cast<dxGeom*> (o1); | ||
91 | contact->g2 = const_cast<dxGeom*> (o2); | ||
92 | dxCCylinder *cyl = (dxCCylinder*) CLASSDATA(o1); | ||
93 | dxBox *box = (dxBox*) CLASSDATA(o2); | ||
94 | |||
95 | // get p1,p2 = cylinder axis endpoints, get radius | ||
96 | dVector3 p1,p2; | ||
97 | dReal clen = cyl->lz * REAL(0.5); | ||
98 | p1[0] = o1->pos[0] + clen * o1->R[2]; | ||
99 | p1[1] = o1->pos[1] + clen * o1->R[6]; | ||
100 | p1[2] = o1->pos[2] + clen * o1->R[10]; | ||
101 | p2[0] = o1->pos[0] - clen * o1->R[2]; | ||
102 | p2[1] = o1->pos[1] - clen * o1->R[6]; | ||
103 | p2[2] = o1->pos[2] - clen * o1->R[10]; | ||
104 | dReal radius = cyl->radius; | ||
105 | |||
106 | // copy out box center, rotation matrix, and side array | ||
107 | dReal *c = o2->pos; | ||
108 | dReal *R = o2->R; | ||
109 | dReal *side = box->side; | ||
110 | |||
111 | // compute the start and end of the line (p1 and p2) relative to the box. | ||
112 | // we will do all subsequent computations in this box-relative coordinate | ||
113 | // system. we have to do a translation and rotation for each point. | ||
114 | dVector3 tmp3,s,e; | ||
115 | tmp3[0] = p1[0] - c[0]; | ||
116 | tmp3[1] = p1[1] - c[1]; | ||
117 | tmp3[2] = p1[2] - c[2]; | ||
118 | dMULTIPLY1_331 (s,R,tmp3); | ||
119 | tmp3[0] = p2[0] - c[0]; | ||
120 | tmp3[1] = p2[1] - c[1]; | ||
121 | tmp3[2] = p2[2] - c[2]; | ||
122 | dMULTIPLY1_331 (e,R,tmp3); | ||
123 | |||
124 | // compute the vector 'v' from the start point to the end point | ||
125 | dVector3 v; | ||
126 | v[0] = e[0] - s[0]; | ||
127 | v[1] = e[1] - s[1]; | ||
128 | v[2] = e[2] - s[2]; | ||
129 | |||
130 | // compute the half-sides of the box | ||
131 | dReal S0 = side[0] * REAL(0.5); | ||
132 | dReal S1 = side[1] * REAL(0.5); | ||
133 | dReal S2 = side[2] * REAL(0.5); | ||
134 | |||
135 | // compute the size of the bounding box around the line segment | ||
136 | dReal B0 = dFabs (v[0]); | ||
137 | dReal B1 = dFabs (v[1]); | ||
138 | dReal B2 = dFabs (v[2]); | ||
139 | |||
140 | // for all 6 separation axes, measure the penetration depth. if any depth is | ||
141 | // less than 0 then the objects don't penetrate at all so we can just | ||
142 | // return 0. find the axis with the smallest depth, and record its normal. | ||
143 | |||
144 | // note: normalR is set to point to a column of R if that is the smallest | ||
145 | // depth normal so far. otherwise normalR is 0 and normalC is set to a | ||
146 | // vector relative to the box. invert_normal is 1 if the sign of the normal | ||
147 | // should be flipped. | ||
148 | |||
149 | dReal depth,trial_depth,tmp,length; | ||
150 | const dReal *normalR=0; | ||
151 | dVector3 normalC; | ||
152 | int invert_normal = 0; | ||
153 | int code = 0; // 0=no contact, 1-3=face contact, 4-6=edge contact | ||
154 | |||
155 | depth = dInfinity; | ||
156 | |||
157 | // look at face-normal axes | ||
158 | |||
159 | #undef TEST | ||
160 | #define TEST(center,depth_expr,norm,contact_code) \ | ||
161 | tmp = (center); \ | ||
162 | trial_depth = radius + REAL(0.5) * ((depth_expr) - dFabs(tmp)); \ | ||
163 | if (trial_depth < 0) return 0; \ | ||
164 | if (trial_depth < depth) { \ | ||
165 | depth = trial_depth; \ | ||
166 | normalR = (norm); \ | ||
167 | invert_normal = (tmp < 0); \ | ||
168 | code = contact_code; \ | ||
169 | } | ||
170 | |||
171 | TEST (s[0]+e[0], side[0] + B0, R+0, 1); | ||
172 | TEST (s[1]+e[1], side[1] + B1, R+1, 2); | ||
173 | TEST (s[2]+e[2], side[2] + B2, R+2, 3); | ||
174 | |||
175 | // look at v x box-edge axes | ||
176 | |||
177 | #undef TEST | ||
178 | #define TEST(box_radius,line_offset,nx,ny,nz,contact_code) \ | ||
179 | tmp = (line_offset); \ | ||
180 | trial_depth = (box_radius) - dFabs(tmp); \ | ||
181 | length = dSqrt ((nx)*(nx) + (ny)*(ny) + (nz)*(nz)); \ | ||
182 | if (length > 0) { \ | ||
183 | length = dRecip(length); \ | ||
184 | trial_depth = trial_depth * length + radius; \ | ||
185 | if (trial_depth < 0) return 0; \ | ||
186 | if (trial_depth < depth) { \ | ||
187 | depth = trial_depth; \ | ||
188 | normalR = 0; \ | ||
189 | normalC[0] = (nx)*length; \ | ||
190 | normalC[1] = (ny)*length; \ | ||
191 | normalC[2] = (nz)*length; \ | ||
192 | invert_normal = (tmp < 0); \ | ||
193 | code = contact_code; \ | ||
194 | } \ | ||
195 | } | ||
196 | |||
197 | TEST (B2*S1+B1*S2,v[1]*s[2]-v[2]*s[1], 0,-v[2],v[1], 4); | ||
198 | TEST (B2*S0+B0*S2,v[2]*s[0]-v[0]*s[2], v[2],0,-v[0], 5); | ||
199 | TEST (B1*S0+B0*S1,v[0]*s[1]-v[1]*s[0], -v[1],v[0],0, 6); | ||
200 | |||
201 | #undef TEST | ||
202 | |||
203 | // if we get to this point, the box and ccylinder interpenetrate. | ||
204 | // compute the normal in global coordinates. | ||
205 | dReal *normal = contact[0].normal; | ||
206 | if (normalR) { | ||
207 | normal[0] = normalR[0]; | ||
208 | normal[1] = normalR[4]; | ||
209 | normal[2] = normalR[8]; | ||
210 | } | ||
211 | else { | ||
212 | dMULTIPLY0_331 (normal,R,normalC); | ||
213 | } | ||
214 | if (invert_normal) { | ||
215 | normal[0] = -normal[0]; | ||
216 | normal[1] = -normal[1]; | ||
217 | normal[2] = -normal[2]; | ||
218 | } | ||
219 | |||
220 | // set the depth | ||
221 | contact[0].depth = depth; | ||
222 | |||
223 | if (code == 0) { | ||
224 | return 0; // should never get here | ||
225 | } | ||
226 | else if (code >= 4) { | ||
227 | // handle edge contacts | ||
228 | // find an endpoint q1 on the intersecting edge of the box | ||
229 | dVector3 q1; | ||
230 | dReal sign[3]; | ||
231 | for (i=0; i<3; i++) q1[i] = c[i]; | ||
232 | sign[0] = (dDOT14(normal,R+0) > 0) ? REAL(1.0) : REAL(-1.0); | ||
233 | for (i=0; i<3; i++) q1[i] += sign[0] * S0 * R[i*4]; | ||
234 | sign[1] = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
235 | for (i=0; i<3; i++) q1[i] += sign[1] * S1 * R[i*4+1]; | ||
236 | sign[2] = (dDOT14(normal,R+2) > 0) ? REAL(1.0) : REAL(-1.0); | ||
237 | for (i=0; i<3; i++) q1[i] += sign[2] * S2 * R[i*4+2]; | ||
238 | |||
239 | // find the other endpoint q2 of the intersecting edge | ||
240 | dVector3 q2; | ||
241 | for (i=0; i<3; i++) | ||
242 | q2[i] = q1[i] - R[code-4 + i*4] * (sign[code-4] * side[code-4]); | ||
243 | |||
244 | // determine the closest point between the box edge and the line segment | ||
245 | dVector3 cp1,cp2; | ||
246 | dClosestLineSegmentPoints (q1,q2, p1,p2, cp1,cp2); | ||
247 | for (i=0; i<3; i++) contact[0].pos[i] = cp1[i] - REAL(0.5)*normal[i]*depth; | ||
248 | return 1; | ||
249 | } | ||
250 | else { | ||
251 | // handle face contacts. | ||
252 | // @@@ temporary: make deepest vertex on the line the contact point. | ||
253 | // @@@ this kind of works, but we sometimes need two contact points for | ||
254 | // @@@ stability. | ||
255 | |||
256 | // compute 'v' in global coordinates | ||
257 | dVector3 gv; | ||
258 | for (i=0; i<3; i++) gv[i] = p2[i] - p1[i]; | ||
259 | |||
260 | if (dDOT (normal,gv) > 0) { | ||
261 | for (i=0; i<3; i++) | ||
262 | contact[0].pos[i] = p1[i] + (depth*REAL(0.5)-radius)*normal[i]; | ||
263 | } | ||
264 | else { | ||
265 | for (i=0; i<3; i++) | ||
266 | contact[0].pos[i] = p2[i] + (depth*REAL(0.5)-radius)*normal[i]; | ||
267 | } | ||
268 | return 1; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | //*************************************************************************** | ||
273 | // this function works, it's just not being used for anything at the moment: | ||
274 | |||
275 | // given a box (R,side), `R' is the rotation matrix for the box, and `side' | ||
276 | // is a vector of x/y/z side lengths, return the size of the interval of the | ||
277 | // box projected along the given axis. if the axis has unit length then the | ||
278 | // return value will be the actual diameter, otherwise the result will be | ||
279 | // scaled by the axis length. | ||
280 | |||
281 | static inline dReal boxDiameter (const dMatrix3 R, const dVector3 side, | ||
282 | const dVector3 axis) | ||
283 | { | ||
284 | dVector3 q; | ||
285 | dMULTIPLY1_331 (q,R,axis); // transform axis to body-relative | ||
286 | return dFabs(q[0])*side[0] + dFabs(q[1])*side[1] + dFabs(q[2])*side[2]; | ||
287 | } | ||
288 | |||
289 | //*************************************************************************** | ||
290 | // the old capped cylinder to capped cylinder collision code. this fails to | ||
291 | // detect cap-to-cap contact points when the cylinder axis are aligned, but | ||
292 | // other that that it is pretty robust. | ||
293 | |||
294 | // this returns at most one contact point when the two cylinder's axes are not | ||
295 | // aligned, and at most two (for stability) when they are aligned. | ||
296 | // the algorithm minimizes the distance between two "sample spheres" that are | ||
297 | // positioned along the cylinder axes according to: | ||
298 | // sphere1 = pos1 + alpha1 * axis1 | ||
299 | // sphere2 = pos2 + alpha2 * axis2 | ||
300 | // alpha1 and alpha2 are limited to +/- half the length of the cylinders. | ||
301 | // the algorithm works by finding a solution that has both alphas free, or | ||
302 | // a solution that has one or both alphas fixed to the ends of the cylinder. | ||
303 | |||
304 | int dCollideCCylinderCCylinder (dxGeom *o1, dxGeom *o2, | ||
305 | int flags, dContactGeom *contact, int skip) | ||
306 | { | ||
307 | int i; | ||
308 | const dReal tolerance = REAL(1e-5); | ||
309 | |||
310 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
311 | dIASSERT (o1->type == dCCylinderClass); | ||
312 | dIASSERT (o2->type == dCCylinderClass); | ||
313 | dxCCylinder *cyl1 = (dxCCylinder*) o1; | ||
314 | dxCCylinder *cyl2 = (dxCCylinder*) o2; | ||
315 | |||
316 | contact->g1 = o1; | ||
317 | contact->g2 = o2; | ||
318 | |||
319 | // copy out some variables, for convenience | ||
320 | dReal lz1 = cyl1->lz * REAL(0.5); | ||
321 | dReal lz2 = cyl2->lz * REAL(0.5); | ||
322 | dReal *pos1 = o1->pos; | ||
323 | dReal *pos2 = o2->pos; | ||
324 | dReal axis1[3],axis2[3]; | ||
325 | axis1[0] = o1->R[2]; | ||
326 | axis1[1] = o1->R[6]; | ||
327 | axis1[2] = o1->R[10]; | ||
328 | axis2[0] = o2->R[2]; | ||
329 | axis2[1] = o2->R[6]; | ||
330 | axis2[2] = o2->R[10]; | ||
331 | |||
332 | dReal alpha1,alpha2,sphere1[3],sphere2[3]; | ||
333 | int fix1 = 0; // 0 if alpha1 is free, +/-1 to fix at +/- lz1 | ||
334 | int fix2 = 0; // 0 if alpha2 is free, +/-1 to fix at +/- lz2 | ||
335 | |||
336 | for (int count=0; count<9; count++) { | ||
337 | // find a trial solution by fixing or not fixing the alphas | ||
338 | if (fix1) { | ||
339 | if (fix2) { | ||
340 | // alpha1 and alpha2 are fixed, so the solution is easy | ||
341 | if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1; | ||
342 | if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2; | ||
343 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
344 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
345 | } | ||
346 | else { | ||
347 | // fix alpha1 but let alpha2 be free | ||
348 | if (fix1 > 0) alpha1 = lz1; else alpha1 = -lz1; | ||
349 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
350 | alpha2 = (axis2[0]*(sphere1[0]-pos2[0]) + | ||
351 | axis2[1]*(sphere1[1]-pos2[1]) + | ||
352 | axis2[2]*(sphere1[2]-pos2[2])); | ||
353 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
354 | } | ||
355 | } | ||
356 | else { | ||
357 | if (fix2) { | ||
358 | // fix alpha2 but let alpha1 be free | ||
359 | if (fix2 > 0) alpha2 = lz2; else alpha2 = -lz2; | ||
360 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
361 | alpha1 = (axis1[0]*(sphere2[0]-pos1[0]) + | ||
362 | axis1[1]*(sphere2[1]-pos1[1]) + | ||
363 | axis1[2]*(sphere2[2]-pos1[2])); | ||
364 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
365 | } | ||
366 | else { | ||
367 | // let alpha1 and alpha2 be free | ||
368 | // compute determinant of d(d^2)\d(alpha) jacobian | ||
369 | dReal a1a2 = dDOT (axis1,axis2); | ||
370 | dReal det = REAL(1.0)-a1a2*a1a2; | ||
371 | if (det < tolerance) { | ||
372 | // the cylinder axes (almost) parallel, so we will generate up to two | ||
373 | // contacts. the solution matrix is rank deficient so alpha1 and | ||
374 | // alpha2 are related by: | ||
375 | // alpha2 = alpha1 + (pos1-pos2)'*axis1 (if axis1==axis2) | ||
376 | // or alpha2 = -(alpha1 + (pos1-pos2)'*axis1) (if axis1==-axis2) | ||
377 | // first compute where the two cylinders overlap in alpha1 space: | ||
378 | if (a1a2 < 0) { | ||
379 | axis2[0] = -axis2[0]; | ||
380 | axis2[1] = -axis2[1]; | ||
381 | axis2[2] = -axis2[2]; | ||
382 | } | ||
383 | dReal q[3]; | ||
384 | for (i=0; i<3; i++) q[i] = pos1[i]-pos2[i]; | ||
385 | dReal k = dDOT (axis1,q); | ||
386 | dReal a1lo = -lz1; | ||
387 | dReal a1hi = lz1; | ||
388 | dReal a2lo = -lz2 - k; | ||
389 | dReal a2hi = lz2 - k; | ||
390 | dReal lo = (a1lo > a2lo) ? a1lo : a2lo; | ||
391 | dReal hi = (a1hi < a2hi) ? a1hi : a2hi; | ||
392 | if (lo <= hi) { | ||
393 | int num_contacts = flags & NUMC_MASK; | ||
394 | if (num_contacts >= 2 && lo < hi) { | ||
395 | // generate up to two contacts. if one of those contacts is | ||
396 | // not made, fall back on the one-contact strategy. | ||
397 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + lo*axis1[i]; | ||
398 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + (lo+k)*axis2[i]; | ||
399 | int n1 = dCollideSpheres (sphere1,cyl1->radius, | ||
400 | sphere2,cyl2->radius,contact); | ||
401 | if (n1) { | ||
402 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + hi*axis1[i]; | ||
403 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + (hi+k)*axis2[i]; | ||
404 | dContactGeom *c2 = CONTACT(contact,skip); | ||
405 | int n2 = dCollideSpheres (sphere1,cyl1->radius, | ||
406 | sphere2,cyl2->radius, c2); | ||
407 | if (n2) { | ||
408 | c2->g1 = o1; | ||
409 | c2->g2 = o2; | ||
410 | return 2; | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | |||
415 | // just one contact to generate, so put it in the middle of | ||
416 | // the range | ||
417 | alpha1 = (lo + hi) * REAL(0.5); | ||
418 | alpha2 = alpha1 + k; | ||
419 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
420 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
421 | return dCollideSpheres (sphere1,cyl1->radius, | ||
422 | sphere2,cyl2->radius,contact); | ||
423 | } | ||
424 | else return 0; | ||
425 | } | ||
426 | det = REAL(1.0)/det; | ||
427 | dReal delta[3]; | ||
428 | for (i=0; i<3; i++) delta[i] = pos1[i] - pos2[i]; | ||
429 | dReal q1 = dDOT (delta,axis1); | ||
430 | dReal q2 = dDOT (delta,axis2); | ||
431 | alpha1 = det*(a1a2*q2-q1); | ||
432 | alpha2 = det*(q2-a1a2*q1); | ||
433 | for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; | ||
434 | for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | // if the alphas are outside their allowed ranges then fix them and | ||
439 | // try again | ||
440 | if (fix1==0) { | ||
441 | if (alpha1 < -lz1) { | ||
442 | fix1 = -1; | ||
443 | continue; | ||
444 | } | ||
445 | if (alpha1 > lz1) { | ||
446 | fix1 = 1; | ||
447 | continue; | ||
448 | } | ||
449 | } | ||
450 | if (fix2==0) { | ||
451 | if (alpha2 < -lz2) { | ||
452 | fix2 = -1; | ||
453 | continue; | ||
454 | } | ||
455 | if (alpha2 > lz2) { | ||
456 | fix2 = 1; | ||
457 | continue; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | // unfix the alpha variables if the local distance gradient indicates | ||
462 | // that we are not yet at the minimum | ||
463 | dReal tmp[3]; | ||
464 | for (i=0; i<3; i++) tmp[i] = sphere1[i] - sphere2[i]; | ||
465 | if (fix1) { | ||
466 | dReal gradient = dDOT (tmp,axis1); | ||
467 | if ((fix1 > 0 && gradient > 0) || (fix1 < 0 && gradient < 0)) { | ||
468 | fix1 = 0; | ||
469 | continue; | ||
470 | } | ||
471 | } | ||
472 | if (fix2) { | ||
473 | dReal gradient = -dDOT (tmp,axis2); | ||
474 | if ((fix2 > 0 && gradient > 0) || (fix2 < 0 && gradient < 0)) { | ||
475 | fix2 = 0; | ||
476 | continue; | ||
477 | } | ||
478 | } | ||
479 | return dCollideSpheres (sphere1,cyl1->radius,sphere2,cyl2->radius,contact); | ||
480 | } | ||
481 | // if we go through the loop too much, then give up. we should NEVER get to | ||
482 | // this point (i hope). | ||
483 | dMessage (0,"dCollideCC(): too many iterations"); | ||
484 | return 0; | ||
485 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/sphere.cpp b/libraries/ode-0.9\/ode/src/sphere.cpp new file mode 100755 index 0000000..fa25aac --- /dev/null +++ b/libraries/ode-0.9\/ode/src/sphere.cpp | |||
@@ -0,0 +1,241 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | standard ODE geometry primitives: public API and pairwise collision functions. | ||
26 | |||
27 | the rule is that only the low level primitive collision functions should set | ||
28 | dContactGeom::g1 and dContactGeom::g2. | ||
29 | |||
30 | */ | ||
31 | |||
32 | #include <ode/common.h> | ||
33 | #include <ode/collision.h> | ||
34 | #include <ode/matrix.h> | ||
35 | #include <ode/rotation.h> | ||
36 | #include <ode/odemath.h> | ||
37 | #include "collision_kernel.h" | ||
38 | #include "collision_std.h" | ||
39 | #include "collision_util.h" | ||
40 | |||
41 | #ifdef _MSC_VER | ||
42 | #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" | ||
43 | #endif | ||
44 | |||
45 | |||
46 | //**************************************************************************** | ||
47 | // sphere public API | ||
48 | |||
49 | dxSphere::dxSphere (dSpaceID space, dReal _radius) : dxGeom (space,1) | ||
50 | { | ||
51 | dAASSERT (_radius > 0); | ||
52 | type = dSphereClass; | ||
53 | radius = _radius; | ||
54 | } | ||
55 | |||
56 | |||
57 | void dxSphere::computeAABB() | ||
58 | { | ||
59 | aabb[0] = final_posr->pos[0] - radius; | ||
60 | aabb[1] = final_posr->pos[0] + radius; | ||
61 | aabb[2] = final_posr->pos[1] - radius; | ||
62 | aabb[3] = final_posr->pos[1] + radius; | ||
63 | aabb[4] = final_posr->pos[2] - radius; | ||
64 | aabb[5] = final_posr->pos[2] + radius; | ||
65 | } | ||
66 | |||
67 | |||
68 | dGeomID dCreateSphere (dSpaceID space, dReal radius) | ||
69 | { | ||
70 | return new dxSphere (space,radius); | ||
71 | } | ||
72 | |||
73 | |||
74 | void dGeomSphereSetRadius (dGeomID g, dReal radius) | ||
75 | { | ||
76 | dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); | ||
77 | dAASSERT (radius > 0); | ||
78 | dxSphere *s = (dxSphere*) g; | ||
79 | s->radius = radius; | ||
80 | dGeomMoved (g); | ||
81 | } | ||
82 | |||
83 | |||
84 | dReal dGeomSphereGetRadius (dGeomID g) | ||
85 | { | ||
86 | dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); | ||
87 | dxSphere *s = (dxSphere*) g; | ||
88 | return s->radius; | ||
89 | } | ||
90 | |||
91 | |||
92 | dReal dGeomSpherePointDepth (dGeomID g, dReal x, dReal y, dReal z) | ||
93 | { | ||
94 | dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); | ||
95 | g->recomputePosr(); | ||
96 | |||
97 | dxSphere *s = (dxSphere*) g; | ||
98 | dReal * pos = s->final_posr->pos; | ||
99 | return s->radius - dSqrt ((x-pos[0])*(x-pos[0]) + | ||
100 | (y-pos[1])*(y-pos[1]) + | ||
101 | (z-pos[2])*(z-pos[2])); | ||
102 | } | ||
103 | |||
104 | //**************************************************************************** | ||
105 | // pairwise collision functions for standard geom types | ||
106 | |||
107 | int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags, | ||
108 | dContactGeom *contact, int skip) | ||
109 | { | ||
110 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
111 | dIASSERT (o1->type == dSphereClass); | ||
112 | dIASSERT (o2->type == dSphereClass); | ||
113 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
114 | |||
115 | dxSphere *sphere1 = (dxSphere*) o1; | ||
116 | dxSphere *sphere2 = (dxSphere*) o2; | ||
117 | |||
118 | contact->g1 = o1; | ||
119 | contact->g2 = o2; | ||
120 | |||
121 | return dCollideSpheres (o1->final_posr->pos,sphere1->radius, | ||
122 | o2->final_posr->pos,sphere2->radius,contact); | ||
123 | } | ||
124 | |||
125 | |||
126 | int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags, | ||
127 | dContactGeom *contact, int skip) | ||
128 | { | ||
129 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
130 | dIASSERT (o1->type == dSphereClass); | ||
131 | dIASSERT (o2->type == dBoxClass); | ||
132 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
133 | |||
134 | // this is easy. get the sphere center `p' relative to the box, and then clip | ||
135 | // that to the boundary of the box (call that point `q'). if q is on the | ||
136 | // boundary of the box and |p-q| is <= sphere radius, they touch. | ||
137 | // if q is inside the box, the sphere is inside the box, so set a contact | ||
138 | // normal to push the sphere to the closest box face. | ||
139 | |||
140 | dVector3 l,t,p,q,r; | ||
141 | dReal depth; | ||
142 | int onborder = 0; | ||
143 | |||
144 | dxSphere *sphere = (dxSphere*) o1; | ||
145 | dxBox *box = (dxBox*) o2; | ||
146 | |||
147 | contact->g1 = o1; | ||
148 | contact->g2 = o2; | ||
149 | |||
150 | p[0] = o1->final_posr->pos[0] - o2->final_posr->pos[0]; | ||
151 | p[1] = o1->final_posr->pos[1] - o2->final_posr->pos[1]; | ||
152 | p[2] = o1->final_posr->pos[2] - o2->final_posr->pos[2]; | ||
153 | |||
154 | l[0] = box->side[0]*REAL(0.5); | ||
155 | t[0] = dDOT14(p,o2->final_posr->R); | ||
156 | if (t[0] < -l[0]) { t[0] = -l[0]; onborder = 1; } | ||
157 | if (t[0] > l[0]) { t[0] = l[0]; onborder = 1; } | ||
158 | |||
159 | l[1] = box->side[1]*REAL(0.5); | ||
160 | t[1] = dDOT14(p,o2->final_posr->R+1); | ||
161 | if (t[1] < -l[1]) { t[1] = -l[1]; onborder = 1; } | ||
162 | if (t[1] > l[1]) { t[1] = l[1]; onborder = 1; } | ||
163 | |||
164 | t[2] = dDOT14(p,o2->final_posr->R+2); | ||
165 | l[2] = box->side[2]*REAL(0.5); | ||
166 | if (t[2] < -l[2]) { t[2] = -l[2]; onborder = 1; } | ||
167 | if (t[2] > l[2]) { t[2] = l[2]; onborder = 1; } | ||
168 | |||
169 | if (!onborder) { | ||
170 | // sphere center inside box. find closest face to `t' | ||
171 | dReal min_distance = l[0] - dFabs(t[0]); | ||
172 | int mini = 0; | ||
173 | for (int i=1; i<3; i++) { | ||
174 | dReal face_distance = l[i] - dFabs(t[i]); | ||
175 | if (face_distance < min_distance) { | ||
176 | min_distance = face_distance; | ||
177 | mini = i; | ||
178 | } | ||
179 | } | ||
180 | // contact position = sphere center | ||
181 | contact->pos[0] = o1->final_posr->pos[0]; | ||
182 | contact->pos[1] = o1->final_posr->pos[1]; | ||
183 | contact->pos[2] = o1->final_posr->pos[2]; | ||
184 | // contact normal points to closest face | ||
185 | dVector3 tmp; | ||
186 | tmp[0] = 0; | ||
187 | tmp[1] = 0; | ||
188 | tmp[2] = 0; | ||
189 | tmp[mini] = (t[mini] > 0) ? REAL(1.0) : REAL(-1.0); | ||
190 | dMULTIPLY0_331 (contact->normal,o2->final_posr->R,tmp); | ||
191 | // contact depth = distance to wall along normal plus radius | ||
192 | contact->depth = min_distance + sphere->radius; | ||
193 | return 1; | ||
194 | } | ||
195 | |||
196 | t[3] = 0; //@@@ hmmm | ||
197 | dMULTIPLY0_331 (q,o2->final_posr->R,t); | ||
198 | r[0] = p[0] - q[0]; | ||
199 | r[1] = p[1] - q[1]; | ||
200 | r[2] = p[2] - q[2]; | ||
201 | depth = sphere->radius - dSqrt(dDOT(r,r)); | ||
202 | if (depth < 0) return 0; | ||
203 | contact->pos[0] = q[0] + o2->final_posr->pos[0]; | ||
204 | contact->pos[1] = q[1] + o2->final_posr->pos[1]; | ||
205 | contact->pos[2] = q[2] + o2->final_posr->pos[2]; | ||
206 | contact->normal[0] = r[0]; | ||
207 | contact->normal[1] = r[1]; | ||
208 | contact->normal[2] = r[2]; | ||
209 | dNormalize3 (contact->normal); | ||
210 | contact->depth = depth; | ||
211 | return 1; | ||
212 | } | ||
213 | |||
214 | |||
215 | int dCollideSpherePlane (dxGeom *o1, dxGeom *o2, int flags, | ||
216 | dContactGeom *contact, int skip) | ||
217 | { | ||
218 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
219 | dIASSERT (o1->type == dSphereClass); | ||
220 | dIASSERT (o2->type == dPlaneClass); | ||
221 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
222 | |||
223 | dxSphere *sphere = (dxSphere*) o1; | ||
224 | dxPlane *plane = (dxPlane*) o2; | ||
225 | |||
226 | contact->g1 = o1; | ||
227 | contact->g2 = o2; | ||
228 | dReal k = dDOT (o1->final_posr->pos,plane->p); | ||
229 | dReal depth = plane->p[3] - k + sphere->radius; | ||
230 | if (depth >= 0) { | ||
231 | contact->normal[0] = plane->p[0]; | ||
232 | contact->normal[1] = plane->p[1]; | ||
233 | contact->normal[2] = plane->p[2]; | ||
234 | contact->pos[0] = o1->final_posr->pos[0] - plane->p[0] * sphere->radius; | ||
235 | contact->pos[1] = o1->final_posr->pos[1] - plane->p[1] * sphere->radius; | ||
236 | contact->pos[2] = o1->final_posr->pos[2] - plane->p[2] * sphere->radius; | ||
237 | contact->depth = depth; | ||
238 | return 1; | ||
239 | } | ||
240 | else return 0; | ||
241 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/stack.cpp b/libraries/ode-0.9\/ode/src/stack.cpp new file mode 100755 index 0000000..e062f92 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/stack.cpp | |||
@@ -0,0 +1,114 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | @@@ this file should not be compiled any more @@@ | ||
24 | |||
25 | #include <string.h> | ||
26 | #include <errno.h> | ||
27 | #include "stack.h" | ||
28 | #include "ode/error.h" | ||
29 | #include "ode/config.h" | ||
30 | |||
31 | //**************************************************************************** | ||
32 | // unix version that uses mmap(). some systems have anonymous mmaps and some | ||
33 | // need to mmap /dev/zero. | ||
34 | |||
35 | #ifndef WIN32 | ||
36 | |||
37 | #include <unistd.h> | ||
38 | #include <sys/mman.h> | ||
39 | #include <sys/types.h> | ||
40 | #include <sys/stat.h> | ||
41 | #include <fcntl.h> | ||
42 | |||
43 | |||
44 | void dStack::init (int max_size) | ||
45 | { | ||
46 | if (sizeof(long int) != sizeof(char*)) dDebug (0,"internal"); | ||
47 | if (max_size <= 0) dDebug (0,"Stack::init() given size <= 0"); | ||
48 | |||
49 | #ifndef MMAP_ANONYMOUS | ||
50 | static int dev_zero_fd = -1; // cached file descriptor for /dev/zero | ||
51 | if (dev_zero_fd < 0) dev_zero_fd = open ("/dev/zero", O_RDWR); | ||
52 | if (dev_zero_fd < 0) dError (0,"can't open /dev/zero (%s)",strerror(errno)); | ||
53 | base = (char*) mmap (0,max_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, | ||
54 | dev_zero_fd,0); | ||
55 | #else | ||
56 | base = (char*) mmap (0,max_size, PROT_READ | PROT_WRITE, | ||
57 | MAP_PRIVATE | MAP_ANON,0,0); | ||
58 | #endif | ||
59 | |||
60 | if (int(base) == -1) dError (0,"Stack::init(), mmap() failed, " | ||
61 | "max_size=%d (%s)",max_size,strerror(errno)); | ||
62 | size = max_size; | ||
63 | pointer = base; | ||
64 | frame = 0; | ||
65 | } | ||
66 | |||
67 | |||
68 | void dStack::destroy() | ||
69 | { | ||
70 | munmap (base,size); | ||
71 | base = 0; | ||
72 | size = 0; | ||
73 | pointer = 0; | ||
74 | frame = 0; | ||
75 | } | ||
76 | |||
77 | #endif | ||
78 | |||
79 | //**************************************************************************** | ||
80 | |||
81 | #ifdef WIN32 | ||
82 | |||
83 | #include "windows.h" | ||
84 | |||
85 | |||
86 | void dStack::init (int max_size) | ||
87 | { | ||
88 | if (sizeof(LPVOID) != sizeof(char*)) dDebug (0,"internal"); | ||
89 | if (max_size <= 0) dDebug (0,"Stack::init() given size <= 0"); | ||
90 | base = (char*) VirtualAlloc (NULL,max_size,MEM_RESERVE,PAGE_READWRITE); | ||
91 | if (base == 0) dError (0,"Stack::init(), VirtualAlloc() failed, " | ||
92 | "max_size=%d",max_size); | ||
93 | size = max_size; | ||
94 | pointer = base; | ||
95 | frame = 0; | ||
96 | committed = 0; | ||
97 | |||
98 | // get page size | ||
99 | SYSTEM_INFO info; | ||
100 | GetSystemInfo (&info); | ||
101 | pagesize = info.dwPageSize; | ||
102 | } | ||
103 | |||
104 | |||
105 | void dStack::destroy() | ||
106 | { | ||
107 | VirtualFree (base,0,MEM_RELEASE); | ||
108 | base = 0; | ||
109 | size = 0; | ||
110 | pointer = 0; | ||
111 | frame = 0; | ||
112 | } | ||
113 | |||
114 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/stack.h b/libraries/ode-0.9\/ode/src/stack.h new file mode 100755 index 0000000..5afff41 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/stack.h | |||
@@ -0,0 +1,138 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* this comes from the `reuse' library. copy any changes back to the source. | ||
24 | |||
25 | these stack allocation functions are a replacement for alloca(), except that | ||
26 | they allocate memory from a separate pool. | ||
27 | |||
28 | advantages over alloca(): | ||
29 | - consecutive allocations are guaranteed to be contiguous with increasing | ||
30 | address. | ||
31 | - functions can allocate stack memory that is returned to the caller, | ||
32 | in other words pushing and popping stack frames is optional. | ||
33 | |||
34 | disadvantages compared to alloca(): | ||
35 | - less portable | ||
36 | - slightly slower, although still orders of magnitude faster than malloc(). | ||
37 | - longjmp() and exceptions do not deallocate stack memory (but who cares?). | ||
38 | |||
39 | just like alloca(): | ||
40 | - using too much stack memory does not fail gracefully, it fails with a | ||
41 | segfault. | ||
42 | |||
43 | */ | ||
44 | |||
45 | |||
46 | #ifndef _ODE_STACK_H_ | ||
47 | #define _ODE_STACK_H_ | ||
48 | |||
49 | |||
50 | #ifdef WIN32 | ||
51 | #include "windows.h" | ||
52 | #endif | ||
53 | |||
54 | |||
55 | struct dStack { | ||
56 | char *base; // bottom of the stack | ||
57 | int size; // maximum size of the stack | ||
58 | char *pointer; // current top of the stack | ||
59 | char *frame; // linked list of stack frame ptrs | ||
60 | # ifdef WIN32 // stuff for windows: | ||
61 | int pagesize; // - page size - this is ASSUMED to be a power of 2 | ||
62 | int committed; // - bytes committed in allocated region | ||
63 | #endif | ||
64 | |||
65 | // initialize the stack. `max_size' is the maximum size that the stack can | ||
66 | // reach. on unix and windows a `virtual' memory block of this size is | ||
67 | // mapped into the address space but does not actually consume physical | ||
68 | // memory until it is referenced - so it is safe to set this to a high value. | ||
69 | |||
70 | void init (int max_size); | ||
71 | |||
72 | |||
73 | // destroy the stack. this unmaps any virtual memory that was allocated. | ||
74 | |||
75 | void destroy(); | ||
76 | |||
77 | |||
78 | // allocate `size' bytes from the stack and return a pointer to the allocated | ||
79 | // memory. `size' must be >= 0. the returned pointer will be aligned to the | ||
80 | // size of a long int. | ||
81 | |||
82 | char * alloc (int size) | ||
83 | { | ||
84 | char *ret = pointer; | ||
85 | pointer += ((size-1) | (sizeof(long int)-1) )+1; | ||
86 | # ifdef WIN32 | ||
87 | // for windows we need to commit pages as they are required | ||
88 | if ((pointer-base) > committed) { | ||
89 | committed = ((pointer-base-1) | (pagesize-1))+1; // round up to pgsize | ||
90 | VirtualAlloc (base,committed,MEM_COMMIT,PAGE_READWRITE); | ||
91 | } | ||
92 | # endif | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | |||
97 | // return the address that will be returned by the next call to alloc() | ||
98 | |||
99 | char *nextAlloc() | ||
100 | { | ||
101 | return pointer; | ||
102 | } | ||
103 | |||
104 | |||
105 | // push and pop the current size of the stack. pushFrame() saves the current | ||
106 | // frame pointer on the stack, and popFrame() retrieves it. a typical | ||
107 | // stack-using function will bracket alloc() calls with pushFrame() and | ||
108 | // popFrame(). both functions return the current stack pointer - this should | ||
109 | // be the same value for the two bracketing calls. calling popFrame() too | ||
110 | // many times will result in a segfault. | ||
111 | |||
112 | char * pushFrame() | ||
113 | { | ||
114 | char *newframe = pointer; | ||
115 | char **addr = (char**) alloc (sizeof(char*)); | ||
116 | *addr = frame; | ||
117 | frame = newframe; | ||
118 | return newframe; | ||
119 | |||
120 | /* OLD CODE | ||
121 | *((char**)pointer) = frame; | ||
122 | frame = pointer; | ||
123 | char *ret = pointer; | ||
124 | pointer += sizeof(char*); | ||
125 | return ret; | ||
126 | */ | ||
127 | } | ||
128 | |||
129 | char * popFrame() | ||
130 | { | ||
131 | pointer = frame; | ||
132 | frame = *((char**)pointer); | ||
133 | return pointer; | ||
134 | } | ||
135 | }; | ||
136 | |||
137 | |||
138 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/step.cpp b/libraries/ode-0.9\/ode/src/step.cpp new file mode 100755 index 0000000..19d0473 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/step.cpp | |||
@@ -0,0 +1,1795 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include "objects.h" | ||
24 | #include "joint.h" | ||
25 | #include <ode/config.h> | ||
26 | #include <ode/odemath.h> | ||
27 | #include <ode/rotation.h> | ||
28 | #include <ode/timer.h> | ||
29 | #include <ode/error.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include "lcp.h" | ||
32 | #include "util.h" | ||
33 | |||
34 | //**************************************************************************** | ||
35 | // misc defines | ||
36 | |||
37 | #define FAST_FACTOR | ||
38 | //#define TIMING | ||
39 | |||
40 | // memory allocation system | ||
41 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
42 | unsigned int dMemoryFlag; | ||
43 | #define REPORT_OUT_OF_MEMORY fprintf(stderr, "Insufficient memory to complete rigid body simulation. Results will not be accurate.\n") | ||
44 | |||
45 | #define ALLOCA(t,v,s) t* v=(t*)malloc(s) | ||
46 | #define UNALLOCA(t) free(t) | ||
47 | |||
48 | #else | ||
49 | #define ALLOCA(t,v,s) t* v=(t*)dALLOCA16(s) | ||
50 | #define UNALLOCA(t) /* nothing */ | ||
51 | #endif | ||
52 | |||
53 | |||
54 | //**************************************************************************** | ||
55 | // debugging - comparison of various vectors and matrices produced by the | ||
56 | // slow and fast versions of the stepper. | ||
57 | |||
58 | //#define COMPARE_METHODS | ||
59 | |||
60 | #ifdef COMPARE_METHODS | ||
61 | #include "testing.h" | ||
62 | dMatrixComparison comparator; | ||
63 | #endif | ||
64 | |||
65 | // undef to use the fast decomposition | ||
66 | #define DIRECT_CHOLESKY | ||
67 | #undef REPORT_ERROR | ||
68 | |||
69 | //**************************************************************************** | ||
70 | // special matrix multipliers | ||
71 | |||
72 | // this assumes the 4th and 8th rows of B and C are zero. | ||
73 | |||
74 | static void Multiply2_p8r (dReal *A, dReal *B, dReal *C, | ||
75 | int p, int r, int Askip) | ||
76 | { | ||
77 | int i,j; | ||
78 | dReal sum,*bb,*cc; | ||
79 | dIASSERT (p>0 && r>0 && A && B && C); | ||
80 | bb = B; | ||
81 | for (i=p; i; i--) { | ||
82 | cc = C; | ||
83 | for (j=r; j; j--) { | ||
84 | sum = bb[0]*cc[0]; | ||
85 | sum += bb[1]*cc[1]; | ||
86 | sum += bb[2]*cc[2]; | ||
87 | sum += bb[4]*cc[4]; | ||
88 | sum += bb[5]*cc[5]; | ||
89 | sum += bb[6]*cc[6]; | ||
90 | *(A++) = sum; | ||
91 | cc += 8; | ||
92 | } | ||
93 | A += Askip - r; | ||
94 | bb += 8; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | // this assumes the 4th and 8th rows of B and C are zero. | ||
100 | |||
101 | static void MultiplyAdd2_p8r (dReal *A, dReal *B, dReal *C, | ||
102 | int p, int r, int Askip) | ||
103 | { | ||
104 | int i,j; | ||
105 | dReal sum,*bb,*cc; | ||
106 | dIASSERT (p>0 && r>0 && A && B && C); | ||
107 | bb = B; | ||
108 | for (i=p; i; i--) { | ||
109 | cc = C; | ||
110 | for (j=r; j; j--) { | ||
111 | sum = bb[0]*cc[0]; | ||
112 | sum += bb[1]*cc[1]; | ||
113 | sum += bb[2]*cc[2]; | ||
114 | sum += bb[4]*cc[4]; | ||
115 | sum += bb[5]*cc[5]; | ||
116 | sum += bb[6]*cc[6]; | ||
117 | *(A++) += sum; | ||
118 | cc += 8; | ||
119 | } | ||
120 | A += Askip - r; | ||
121 | bb += 8; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | |||
126 | // this assumes the 4th and 8th rows of B are zero. | ||
127 | |||
128 | static void Multiply0_p81 (dReal *A, dReal *B, dReal *C, int p) | ||
129 | { | ||
130 | int i; | ||
131 | dIASSERT (p>0 && A && B && C); | ||
132 | dReal sum; | ||
133 | for (i=p; i; i--) { | ||
134 | sum = B[0]*C[0]; | ||
135 | sum += B[1]*C[1]; | ||
136 | sum += B[2]*C[2]; | ||
137 | sum += B[4]*C[4]; | ||
138 | sum += B[5]*C[5]; | ||
139 | sum += B[6]*C[6]; | ||
140 | *(A++) = sum; | ||
141 | B += 8; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | |||
146 | // this assumes the 4th and 8th rows of B are zero. | ||
147 | |||
148 | static void MultiplyAdd0_p81 (dReal *A, dReal *B, dReal *C, int p) | ||
149 | { | ||
150 | int i; | ||
151 | dIASSERT (p>0 && A && B && C); | ||
152 | dReal sum; | ||
153 | for (i=p; i; i--) { | ||
154 | sum = B[0]*C[0]; | ||
155 | sum += B[1]*C[1]; | ||
156 | sum += B[2]*C[2]; | ||
157 | sum += B[4]*C[4]; | ||
158 | sum += B[5]*C[5]; | ||
159 | sum += B[6]*C[6]; | ||
160 | *(A++) += sum; | ||
161 | B += 8; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | |||
166 | // this assumes the 4th and 8th rows of B are zero. | ||
167 | |||
168 | static void MultiplyAdd1_8q1 (dReal *A, dReal *B, dReal *C, int q) | ||
169 | { | ||
170 | int k; | ||
171 | dReal sum; | ||
172 | dIASSERT (q>0 && A && B && C); | ||
173 | sum = 0; | ||
174 | for (k=0; k<q; k++) sum += B[k*8] * C[k]; | ||
175 | A[0] += sum; | ||
176 | sum = 0; | ||
177 | for (k=0; k<q; k++) sum += B[1+k*8] * C[k]; | ||
178 | A[1] += sum; | ||
179 | sum = 0; | ||
180 | for (k=0; k<q; k++) sum += B[2+k*8] * C[k]; | ||
181 | A[2] += sum; | ||
182 | sum = 0; | ||
183 | for (k=0; k<q; k++) sum += B[4+k*8] * C[k]; | ||
184 | A[4] += sum; | ||
185 | sum = 0; | ||
186 | for (k=0; k<q; k++) sum += B[5+k*8] * C[k]; | ||
187 | A[5] += sum; | ||
188 | sum = 0; | ||
189 | for (k=0; k<q; k++) sum += B[6+k*8] * C[k]; | ||
190 | A[6] += sum; | ||
191 | } | ||
192 | |||
193 | |||
194 | // this assumes the 4th and 8th rows of B are zero. | ||
195 | |||
196 | static void Multiply1_8q1 (dReal *A, dReal *B, dReal *C, int q) | ||
197 | { | ||
198 | int k; | ||
199 | dReal sum; | ||
200 | dIASSERT (q>0 && A && B && C); | ||
201 | sum = 0; | ||
202 | for (k=0; k<q; k++) sum += B[k*8] * C[k]; | ||
203 | A[0] = sum; | ||
204 | sum = 0; | ||
205 | for (k=0; k<q; k++) sum += B[1+k*8] * C[k]; | ||
206 | A[1] = sum; | ||
207 | sum = 0; | ||
208 | for (k=0; k<q; k++) sum += B[2+k*8] * C[k]; | ||
209 | A[2] = sum; | ||
210 | sum = 0; | ||
211 | for (k=0; k<q; k++) sum += B[4+k*8] * C[k]; | ||
212 | A[4] = sum; | ||
213 | sum = 0; | ||
214 | for (k=0; k<q; k++) sum += B[5+k*8] * C[k]; | ||
215 | A[5] = sum; | ||
216 | sum = 0; | ||
217 | for (k=0; k<q; k++) sum += B[6+k*8] * C[k]; | ||
218 | A[6] = sum; | ||
219 | } | ||
220 | |||
221 | //**************************************************************************** | ||
222 | // the slow, but sure way | ||
223 | // note that this does not do any joint feedback! | ||
224 | |||
225 | // given lists of bodies and joints that form an island, perform a first | ||
226 | // order timestep. | ||
227 | // | ||
228 | // `body' is the body array, `nb' is the size of the array. | ||
229 | // `_joint' is the body array, `nj' is the size of the array. | ||
230 | |||
231 | void dInternalStepIsland_x1 (dxWorld *world, dxBody * const *body, int nb, | ||
232 | dxJoint * const *_joint, int nj, dReal stepsize) | ||
233 | { | ||
234 | int i,j,k; | ||
235 | int n6 = 6*nb; | ||
236 | |||
237 | #ifdef TIMING | ||
238 | dTimerStart("preprocessing"); | ||
239 | #endif | ||
240 | |||
241 | // number all bodies in the body list - set their tag values | ||
242 | for (i=0; i<nb; i++) body[i]->tag = i; | ||
243 | |||
244 | // make a local copy of the joint array, because we might want to modify it. | ||
245 | // (the "dxJoint *const*" declaration says we're allowed to modify the joints | ||
246 | // but not the joint array, because the caller might need it unchanged). | ||
247 | ALLOCA(dxJoint*,joint,nj*sizeof(dxJoint*)); | ||
248 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
249 | if (joint == NULL) { | ||
250 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
251 | return; | ||
252 | } | ||
253 | #endif | ||
254 | memcpy (joint,_joint,nj * sizeof(dxJoint*)); | ||
255 | |||
256 | // for all bodies, compute the inertia tensor and its inverse in the global | ||
257 | // frame, and compute the rotational force and add it to the torque | ||
258 | // accumulator. | ||
259 | // @@@ check computation of rotational force. | ||
260 | ALLOCA(dReal,I,3*nb*4*sizeof(dReal)); | ||
261 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
262 | if (I == NULL) { | ||
263 | UNALLOCA(joint); | ||
264 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
265 | return; | ||
266 | } | ||
267 | #endif | ||
268 | ALLOCA(dReal,invI,3*nb*4*sizeof(dReal)); | ||
269 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
270 | if (invI == NULL) { | ||
271 | UNALLOCA(I); | ||
272 | UNALLOCA(joint); | ||
273 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
274 | return; | ||
275 | } | ||
276 | #endif | ||
277 | |||
278 | //dSetZero (I,3*nb*4); | ||
279 | //dSetZero (invI,3*nb*4); | ||
280 | for (i=0; i<nb; i++) { | ||
281 | dReal tmp[12]; | ||
282 | // compute inertia tensor in global frame | ||
283 | dMULTIPLY2_333 (tmp,body[i]->mass.I,body[i]->posr.R); | ||
284 | dMULTIPLY0_333 (I+i*12,body[i]->posr.R,tmp); | ||
285 | // compute inverse inertia tensor in global frame | ||
286 | dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->posr.R); | ||
287 | dMULTIPLY0_333 (invI+i*12,body[i]->posr.R,tmp); | ||
288 | // compute rotational force | ||
289 | dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); | ||
290 | dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); | ||
291 | } | ||
292 | |||
293 | // add the gravity force to all bodies | ||
294 | for (i=0; i<nb; i++) { | ||
295 | if ((body[i]->flags & dxBodyNoGravity)==0) { | ||
296 | body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; | ||
297 | body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; | ||
298 | body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | // get m = total constraint dimension, nub = number of unbounded variables. | ||
303 | // create constraint offset array and number-of-rows array for all joints. | ||
304 | // the constraints are re-ordered as follows: the purely unbounded | ||
305 | // constraints, the mixed unbounded + LCP constraints, and last the purely | ||
306 | // LCP constraints. | ||
307 | // | ||
308 | // joints with m=0 are inactive and are removed from the joints array | ||
309 | // entirely, so that the code that follows does not consider them. | ||
310 | int m = 0; | ||
311 | ALLOCA(dxJoint::Info1,info,nj*sizeof(dxJoint::Info1)); | ||
312 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
313 | if (info == NULL) { | ||
314 | UNALLOCA(invI); | ||
315 | UNALLOCA(I); | ||
316 | UNALLOCA(joint); | ||
317 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
318 | return; | ||
319 | } | ||
320 | #endif | ||
321 | |||
322 | ALLOCA(int,ofs,nj*sizeof(int)); | ||
323 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
324 | if (ofs == NULL) { | ||
325 | UNALLOCA(info); | ||
326 | UNALLOCA(invI); | ||
327 | UNALLOCA(I); | ||
328 | UNALLOCA(joint); | ||
329 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
330 | return; | ||
331 | } | ||
332 | #endif | ||
333 | |||
334 | for (i=0, j=0; j<nj; j++) { // i=dest, j=src | ||
335 | joint[j]->vtable->getInfo1 (joint[j],info+i); | ||
336 | dIASSERT (info[i].m >= 0 && info[i].m <= 6 && | ||
337 | info[i].nub >= 0 && info[i].nub <= info[i].m); | ||
338 | if (info[i].m > 0) { | ||
339 | joint[i] = joint[j]; | ||
340 | i++; | ||
341 | } | ||
342 | } | ||
343 | nj = i; | ||
344 | |||
345 | // the purely unbounded constraints | ||
346 | for (i=0; i<nj; i++) if (info[i].nub == info[i].m) { | ||
347 | ofs[i] = m; | ||
348 | m += info[i].m; | ||
349 | } | ||
350 | int nub = m; | ||
351 | // the mixed unbounded + LCP constraints | ||
352 | for (i=0; i<nj; i++) if (info[i].nub > 0 && info[i].nub < info[i].m) { | ||
353 | ofs[i] = m; | ||
354 | m += info[i].m; | ||
355 | } | ||
356 | // the purely LCP constraints | ||
357 | for (i=0; i<nj; i++) if (info[i].nub == 0) { | ||
358 | ofs[i] = m; | ||
359 | m += info[i].m; | ||
360 | } | ||
361 | |||
362 | // create (6*nb,6*nb) inverse mass matrix `invM', and fill it with mass | ||
363 | // parameters | ||
364 | #ifdef TIMING | ||
365 | dTimerNow ("create mass matrix"); | ||
366 | #endif | ||
367 | int nskip = dPAD (n6); | ||
368 | ALLOCA(dReal, invM, n6*nskip*sizeof(dReal)); | ||
369 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
370 | if (invM == NULL) { | ||
371 | UNALLOCA(ofs); | ||
372 | UNALLOCA(info); | ||
373 | UNALLOCA(invI); | ||
374 | UNALLOCA(I); | ||
375 | UNALLOCA(joint); | ||
376 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
377 | return; | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | dSetZero (invM,n6*nskip); | ||
382 | for (i=0; i<nb; i++) { | ||
383 | dReal *MM = invM+(i*6)*nskip+(i*6); | ||
384 | MM[0] = body[i]->invMass; | ||
385 | MM[nskip+1] = body[i]->invMass; | ||
386 | MM[2*nskip+2] = body[i]->invMass; | ||
387 | MM += 3*nskip+3; | ||
388 | for (j=0; j<3; j++) for (k=0; k<3; k++) { | ||
389 | MM[j*nskip+k] = invI[i*12+j*4+k]; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | // assemble some body vectors: fe = external forces, v = velocities | ||
394 | ALLOCA(dReal,fe,n6*sizeof(dReal)); | ||
395 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
396 | if (fe == NULL) { | ||
397 | UNALLOCA(invM); | ||
398 | UNALLOCA(ofs); | ||
399 | UNALLOCA(info); | ||
400 | UNALLOCA(invI); | ||
401 | UNALLOCA(I); | ||
402 | UNALLOCA(joint); | ||
403 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
404 | return; | ||
405 | } | ||
406 | #endif | ||
407 | |||
408 | ALLOCA(dReal,v,n6*sizeof(dReal)); | ||
409 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
410 | if (v == NULL) { | ||
411 | UNALLOCA(fe); | ||
412 | UNALLOCA(invM); | ||
413 | UNALLOCA(ofs); | ||
414 | UNALLOCA(info); | ||
415 | UNALLOCA(invI); | ||
416 | UNALLOCA(I); | ||
417 | UNALLOCA(joint); | ||
418 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
419 | return; | ||
420 | } | ||
421 | #endif | ||
422 | |||
423 | //dSetZero (fe,n6); | ||
424 | //dSetZero (v,n6); | ||
425 | for (i=0; i<nb; i++) { | ||
426 | for (j=0; j<3; j++) fe[i*6+j] = body[i]->facc[j]; | ||
427 | for (j=0; j<3; j++) fe[i*6+3+j] = body[i]->tacc[j]; | ||
428 | for (j=0; j<3; j++) v[i*6+j] = body[i]->lvel[j]; | ||
429 | for (j=0; j<3; j++) v[i*6+3+j] = body[i]->avel[j]; | ||
430 | } | ||
431 | |||
432 | // this will be set to the velocity update | ||
433 | ALLOCA(dReal,vnew,n6*sizeof(dReal)); | ||
434 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
435 | if (vnew == NULL) { | ||
436 | UNALLOCA(v); | ||
437 | UNALLOCA(fe); | ||
438 | UNALLOCA(invM); | ||
439 | UNALLOCA(ofs); | ||
440 | UNALLOCA(info); | ||
441 | UNALLOCA(invI); | ||
442 | UNALLOCA(I); | ||
443 | UNALLOCA(joint); | ||
444 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
445 | return; | ||
446 | } | ||
447 | #endif | ||
448 | dSetZero (vnew,n6); | ||
449 | |||
450 | // if there are constraints, compute cforce | ||
451 | if (m > 0) { | ||
452 | // create a constraint equation right hand side vector `c', a constraint | ||
453 | // force mixing vector `cfm', and LCP low and high bound vectors, and an | ||
454 | // 'findex' vector. | ||
455 | ALLOCA(dReal,c,m*sizeof(dReal)); | ||
456 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
457 | if (c == NULL) { | ||
458 | UNALLOCA(vnew); | ||
459 | UNALLOCA(v); | ||
460 | UNALLOCA(fe); | ||
461 | UNALLOCA(invM); | ||
462 | UNALLOCA(ofs); | ||
463 | UNALLOCA(info); | ||
464 | UNALLOCA(invI); | ||
465 | UNALLOCA(I); | ||
466 | UNALLOCA(joint); | ||
467 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
468 | return; | ||
469 | } | ||
470 | #endif | ||
471 | ALLOCA(dReal,cfm,m*sizeof(dReal)); | ||
472 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
473 | if (cfm == NULL) { | ||
474 | UNALLOCA(c); | ||
475 | UNALLOCA(vnew); | ||
476 | UNALLOCA(v); | ||
477 | UNALLOCA(fe); | ||
478 | UNALLOCA(invM); | ||
479 | UNALLOCA(ofs); | ||
480 | UNALLOCA(info); | ||
481 | UNALLOCA(invI); | ||
482 | UNALLOCA(I); | ||
483 | UNALLOCA(joint); | ||
484 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
485 | return; | ||
486 | } | ||
487 | #endif | ||
488 | ALLOCA(dReal,lo,m*sizeof(dReal)); | ||
489 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
490 | if (lo == NULL) { | ||
491 | UNALLOCA(cfm); | ||
492 | UNALLOCA(c); | ||
493 | UNALLOCA(vnew); | ||
494 | UNALLOCA(v); | ||
495 | UNALLOCA(fe); | ||
496 | UNALLOCA(invM); | ||
497 | UNALLOCA(ofs); | ||
498 | UNALLOCA(info); | ||
499 | UNALLOCA(invI); | ||
500 | UNALLOCA(I); | ||
501 | UNALLOCA(joint); | ||
502 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
503 | return; | ||
504 | } | ||
505 | #endif | ||
506 | ALLOCA(dReal,hi,m*sizeof(dReal)); | ||
507 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
508 | if (hi == NULL) { | ||
509 | UNALLOCA(lo); | ||
510 | UNALLOCA(cfm); | ||
511 | UNALLOCA(c); | ||
512 | UNALLOCA(vnew); | ||
513 | UNALLOCA(v); | ||
514 | UNALLOCA(fe); | ||
515 | UNALLOCA(invM); | ||
516 | UNALLOCA(ofs); | ||
517 | UNALLOCA(info); | ||
518 | UNALLOCA(invI); | ||
519 | UNALLOCA(I); | ||
520 | UNALLOCA(joint); | ||
521 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
522 | return; | ||
523 | } | ||
524 | #endif | ||
525 | ALLOCA(int,findex,m*sizeof(int)); | ||
526 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
527 | if (findex == NULL) { | ||
528 | UNALLOCA(hi); | ||
529 | UNALLOCA(lo); | ||
530 | UNALLOCA(cfm); | ||
531 | UNALLOCA(c); | ||
532 | UNALLOCA(vnew); | ||
533 | UNALLOCA(v); | ||
534 | UNALLOCA(fe); | ||
535 | UNALLOCA(invM); | ||
536 | UNALLOCA(ofs); | ||
537 | UNALLOCA(info); | ||
538 | UNALLOCA(invI); | ||
539 | UNALLOCA(I); | ||
540 | UNALLOCA(joint); | ||
541 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
542 | return; | ||
543 | } | ||
544 | #endif | ||
545 | dSetZero (c,m); | ||
546 | dSetValue (cfm,m,world->global_cfm); | ||
547 | dSetValue (lo,m,-dInfinity); | ||
548 | dSetValue (hi,m, dInfinity); | ||
549 | for (i=0; i<m; i++) findex[i] = -1; | ||
550 | |||
551 | // create (m,6*nb) jacobian mass matrix `J', and fill it with constraint | ||
552 | // data. also fill the c vector. | ||
553 | # ifdef TIMING | ||
554 | dTimerNow ("create J"); | ||
555 | # endif | ||
556 | ALLOCA(dReal,J,m*nskip*sizeof(dReal)); | ||
557 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
558 | if (J == NULL) { | ||
559 | UNALLOCA(findex); | ||
560 | UNALLOCA(hi); | ||
561 | UNALLOCA(lo); | ||
562 | UNALLOCA(cfm); | ||
563 | UNALLOCA(c); | ||
564 | UNALLOCA(vnew); | ||
565 | UNALLOCA(v); | ||
566 | UNALLOCA(fe); | ||
567 | UNALLOCA(invM); | ||
568 | UNALLOCA(ofs); | ||
569 | UNALLOCA(info); | ||
570 | UNALLOCA(invI); | ||
571 | UNALLOCA(I); | ||
572 | UNALLOCA(joint); | ||
573 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
574 | return; | ||
575 | } | ||
576 | #endif | ||
577 | dSetZero (J,m*nskip); | ||
578 | dxJoint::Info2 Jinfo; | ||
579 | Jinfo.rowskip = nskip; | ||
580 | Jinfo.fps = dRecip(stepsize); | ||
581 | Jinfo.erp = world->global_erp; | ||
582 | for (i=0; i<nj; i++) { | ||
583 | Jinfo.J1l = J + nskip*ofs[i] + 6*joint[i]->node[0].body->tag; | ||
584 | Jinfo.J1a = Jinfo.J1l + 3; | ||
585 | if (joint[i]->node[1].body) { | ||
586 | Jinfo.J2l = J + nskip*ofs[i] + 6*joint[i]->node[1].body->tag; | ||
587 | Jinfo.J2a = Jinfo.J2l + 3; | ||
588 | } | ||
589 | else { | ||
590 | Jinfo.J2l = 0; | ||
591 | Jinfo.J2a = 0; | ||
592 | } | ||
593 | Jinfo.c = c + ofs[i]; | ||
594 | Jinfo.cfm = cfm + ofs[i]; | ||
595 | Jinfo.lo = lo + ofs[i]; | ||
596 | Jinfo.hi = hi + ofs[i]; | ||
597 | Jinfo.findex = findex + ofs[i]; | ||
598 | joint[i]->vtable->getInfo2 (joint[i],&Jinfo); | ||
599 | // adjust returned findex values for global index numbering | ||
600 | for (j=0; j<info[i].m; j++) { | ||
601 | if (findex[ofs[i] + j] >= 0) findex[ofs[i] + j] += ofs[i]; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | // compute A = J*invM*J' | ||
606 | # ifdef TIMING | ||
607 | dTimerNow ("compute A"); | ||
608 | # endif | ||
609 | ALLOCA(dReal,JinvM,m*nskip*sizeof(dReal)); | ||
610 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
611 | if (JinvM == NULL) { | ||
612 | UNALLOCA(J); | ||
613 | UNALLOCA(findex); | ||
614 | UNALLOCA(hi); | ||
615 | UNALLOCA(lo); | ||
616 | UNALLOCA(cfm); | ||
617 | UNALLOCA(c); | ||
618 | UNALLOCA(vnew); | ||
619 | UNALLOCA(v); | ||
620 | UNALLOCA(fe); | ||
621 | UNALLOCA(invM); | ||
622 | UNALLOCA(ofs); | ||
623 | UNALLOCA(info); | ||
624 | UNALLOCA(invI); | ||
625 | UNALLOCA(I); | ||
626 | UNALLOCA(joint); | ||
627 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
628 | return; | ||
629 | } | ||
630 | #endif | ||
631 | //dSetZero (JinvM,m*nskip); | ||
632 | dMultiply0 (JinvM,J,invM,m,n6,n6); | ||
633 | int mskip = dPAD(m); | ||
634 | ALLOCA(dReal,A,m*mskip*sizeof(dReal)); | ||
635 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
636 | if (A == NULL) { | ||
637 | UNALLOCA(JinvM); | ||
638 | UNALLOCA(J); | ||
639 | UNALLOCA(findex); | ||
640 | UNALLOCA(hi); | ||
641 | UNALLOCA(lo); | ||
642 | UNALLOCA(cfm); | ||
643 | UNALLOCA(c); | ||
644 | UNALLOCA(vnew); | ||
645 | UNALLOCA(v); | ||
646 | UNALLOCA(fe); | ||
647 | UNALLOCA(invM); | ||
648 | UNALLOCA(ofs); | ||
649 | UNALLOCA(info); | ||
650 | UNALLOCA(invI); | ||
651 | UNALLOCA(I); | ||
652 | UNALLOCA(joint); | ||
653 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
654 | return; | ||
655 | } | ||
656 | #endif | ||
657 | //dSetZero (A,m*mskip); | ||
658 | dMultiply2 (A,JinvM,J,m,n6,m); | ||
659 | |||
660 | // add cfm to the diagonal of A | ||
661 | for (i=0; i<m; i++) A[i*mskip+i] += cfm[i] * Jinfo.fps; | ||
662 | |||
663 | # ifdef COMPARE_METHODS | ||
664 | comparator.nextMatrix (A,m,m,1,"A"); | ||
665 | # endif | ||
666 | |||
667 | // compute `rhs', the right hand side of the equation J*a=c | ||
668 | # ifdef TIMING | ||
669 | dTimerNow ("compute rhs"); | ||
670 | # endif | ||
671 | ALLOCA(dReal,tmp1,n6*sizeof(dReal)); | ||
672 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
673 | if (tmp1 == NULL) { | ||
674 | UNALLOCA(A); | ||
675 | UNALLOCA(JinvM); | ||
676 | UNALLOCA(J); | ||
677 | UNALLOCA(findex); | ||
678 | UNALLOCA(hi); | ||
679 | UNALLOCA(lo); | ||
680 | UNALLOCA(cfm); | ||
681 | UNALLOCA(c); | ||
682 | UNALLOCA(vnew); | ||
683 | UNALLOCA(v); | ||
684 | UNALLOCA(fe); | ||
685 | UNALLOCA(invM); | ||
686 | UNALLOCA(ofs); | ||
687 | UNALLOCA(info); | ||
688 | UNALLOCA(invI); | ||
689 | UNALLOCA(I); | ||
690 | UNALLOCA(joint); | ||
691 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
692 | return; | ||
693 | } | ||
694 | #endif | ||
695 | //dSetZero (tmp1,n6); | ||
696 | dMultiply0 (tmp1,invM,fe,n6,n6,1); | ||
697 | for (i=0; i<n6; i++) tmp1[i] += v[i]/stepsize; | ||
698 | ALLOCA(dReal,rhs,m*sizeof(dReal)); | ||
699 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
700 | if (rhs == NULL) { | ||
701 | UNALLOCA(tmp1); | ||
702 | UNALLOCA(A); | ||
703 | UNALLOCA(JinvM); | ||
704 | UNALLOCA(J); | ||
705 | UNALLOCA(findex); | ||
706 | UNALLOCA(hi); | ||
707 | UNALLOCA(lo); | ||
708 | UNALLOCA(cfm); | ||
709 | UNALLOCA(c); | ||
710 | UNALLOCA(vnew); | ||
711 | UNALLOCA(v); | ||
712 | UNALLOCA(fe); | ||
713 | UNALLOCA(invM); | ||
714 | UNALLOCA(ofs); | ||
715 | UNALLOCA(info); | ||
716 | UNALLOCA(invI); | ||
717 | UNALLOCA(I); | ||
718 | UNALLOCA(joint); | ||
719 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
720 | return; | ||
721 | } | ||
722 | #endif | ||
723 | //dSetZero (rhs,m); | ||
724 | dMultiply0 (rhs,J,tmp1,m,n6,1); | ||
725 | for (i=0; i<m; i++) rhs[i] = c[i]/stepsize - rhs[i]; | ||
726 | |||
727 | # ifdef COMPARE_METHODS | ||
728 | comparator.nextMatrix (c,m,1,0,"c"); | ||
729 | comparator.nextMatrix (rhs,m,1,0,"rhs"); | ||
730 | # endif | ||
731 | |||
732 | |||
733 | |||
734 | |||
735 | |||
736 | #ifndef DIRECT_CHOLESKY | ||
737 | // solve the LCP problem and get lambda. | ||
738 | // this will destroy A but that's okay | ||
739 | # ifdef TIMING | ||
740 | dTimerNow ("solving LCP problem"); | ||
741 | # endif | ||
742 | ALLOCA(dReal,lambda,m*sizeof(dReal)); | ||
743 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
744 | if (lambda == NULL) { | ||
745 | UNALLOCA(rhs); | ||
746 | UNALLOCA(tmp1); | ||
747 | UNALLOCA(A); | ||
748 | UNALLOCA(JinvM); | ||
749 | UNALLOCA(J); | ||
750 | UNALLOCA(findex); | ||
751 | UNALLOCA(hi); | ||
752 | UNALLOCA(lo); | ||
753 | UNALLOCA(cfm); | ||
754 | UNALLOCA(c); | ||
755 | UNALLOCA(vnew); | ||
756 | UNALLOCA(v); | ||
757 | UNALLOCA(fe); | ||
758 | UNALLOCA(invM); | ||
759 | UNALLOCA(ofs); | ||
760 | UNALLOCA(info); | ||
761 | UNALLOCA(invI); | ||
762 | UNALLOCA(I); | ||
763 | UNALLOCA(joint); | ||
764 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
765 | return; | ||
766 | } | ||
767 | #endif | ||
768 | ALLOCA(dReal,residual,m*sizeof(dReal)); | ||
769 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
770 | if (residual == NULL) { | ||
771 | UNALLOCA(lambda); | ||
772 | UNALLOCA(rhs); | ||
773 | UNALLOCA(tmp1); | ||
774 | UNALLOCA(A); | ||
775 | UNALLOCA(JinvM); | ||
776 | UNALLOCA(J); | ||
777 | UNALLOCA(findex); | ||
778 | UNALLOCA(hi); | ||
779 | UNALLOCA(lo); | ||
780 | UNALLOCA(cfm); | ||
781 | UNALLOCA(c); | ||
782 | UNALLOCA(vnew); | ||
783 | UNALLOCA(v); | ||
784 | UNALLOCA(fe); | ||
785 | UNALLOCA(invM); | ||
786 | UNALLOCA(ofs); | ||
787 | UNALLOCA(info); | ||
788 | UNALLOCA(invI); | ||
789 | UNALLOCA(I); | ||
790 | UNALLOCA(joint); | ||
791 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
792 | return; | ||
793 | } | ||
794 | #endif | ||
795 | dSolveLCP (m,A,lambda,rhs,residual,nub,lo,hi,findex); | ||
796 | UNALLOCA(residual); | ||
797 | UNALLOCA(lambda); | ||
798 | |||
799 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
800 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) | ||
801 | return; | ||
802 | #endif | ||
803 | |||
804 | |||
805 | #else | ||
806 | |||
807 | // OLD WAY - direct factor and solve | ||
808 | |||
809 | // factorize A (L*L'=A) | ||
810 | # ifdef TIMING | ||
811 | dTimerNow ("factorize A"); | ||
812 | # endif | ||
813 | ALLOCA(dReal,L,m*mskip*sizeof(dReal)); | ||
814 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
815 | if (L == NULL) { | ||
816 | UNALLOCA(rhs); | ||
817 | UNALLOCA(tmp1); | ||
818 | UNALLOCA(A); | ||
819 | UNALLOCA(JinvM); | ||
820 | UNALLOCA(J); | ||
821 | UNALLOCA(findex); | ||
822 | UNALLOCA(hi); | ||
823 | UNALLOCA(lo); | ||
824 | UNALLOCA(cfm); | ||
825 | UNALLOCA(c); | ||
826 | UNALLOCA(vnew); | ||
827 | UNALLOCA(v); | ||
828 | UNALLOCA(fe); | ||
829 | UNALLOCA(invM); | ||
830 | UNALLOCA(ofs); | ||
831 | UNALLOCA(info); | ||
832 | UNALLOCA(invI); | ||
833 | UNALLOCA(I); | ||
834 | UNALLOCA(joint); | ||
835 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
836 | return; | ||
837 | } | ||
838 | #endif | ||
839 | memcpy (L,A,m*mskip*sizeof(dReal)); | ||
840 | if (dFactorCholesky (L,m)==0) dDebug (0,"A is not positive definite"); | ||
841 | |||
842 | // compute lambda | ||
843 | # ifdef TIMING | ||
844 | dTimerNow ("compute lambda"); | ||
845 | # endif | ||
846 | ALLOCA(dReal,lambda,m*sizeof(dReal)); | ||
847 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
848 | if (lambda == NULL) { | ||
849 | UNALLOCA(L); | ||
850 | UNALLOCA(rhs); | ||
851 | UNALLOCA(tmp1); | ||
852 | UNALLOCA(A); | ||
853 | UNALLOCA(JinvM); | ||
854 | UNALLOCA(J); | ||
855 | UNALLOCA(findex); | ||
856 | UNALLOCA(hi); | ||
857 | UNALLOCA(lo); | ||
858 | UNALLOCA(cfm); | ||
859 | UNALLOCA(c); | ||
860 | UNALLOCA(vnew); | ||
861 | UNALLOCA(v); | ||
862 | UNALLOCA(fe); | ||
863 | UNALLOCA(invM); | ||
864 | UNALLOCA(ofs); | ||
865 | UNALLOCA(info); | ||
866 | UNALLOCA(invI); | ||
867 | UNALLOCA(I); | ||
868 | UNALLOCA(joint); | ||
869 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
870 | return; | ||
871 | } | ||
872 | #endif | ||
873 | memcpy (lambda,rhs,m * sizeof(dReal)); | ||
874 | dSolveCholesky (L,lambda,m); | ||
875 | #endif | ||
876 | |||
877 | # ifdef COMPARE_METHODS | ||
878 | comparator.nextMatrix (lambda,m,1,0,"lambda"); | ||
879 | # endif | ||
880 | |||
881 | // compute the velocity update `vnew' | ||
882 | # ifdef TIMING | ||
883 | dTimerNow ("compute velocity update"); | ||
884 | # endif | ||
885 | dMultiply1 (tmp1,J,lambda,n6,m,1); | ||
886 | for (i=0; i<n6; i++) tmp1[i] += fe[i]; | ||
887 | dMultiply0 (vnew,invM,tmp1,n6,n6,1); | ||
888 | for (i=0; i<n6; i++) vnew[i] = v[i] + stepsize*vnew[i]; | ||
889 | |||
890 | #ifdef REPORT_ERROR | ||
891 | // see if the constraint has worked: compute J*vnew and make sure it equals | ||
892 | // `c' (to within a certain tolerance). | ||
893 | # ifdef TIMING | ||
894 | dTimerNow ("verify constraint equation"); | ||
895 | # endif | ||
896 | dMultiply0 (tmp1,J,vnew,m,n6,1); | ||
897 | dReal err = 0; | ||
898 | for (i=0; i<m; i++) { | ||
899 | err += dFabs(tmp1[i]-c[i]); | ||
900 | } | ||
901 | printf ("total constraint error=%.6e\n",err); | ||
902 | #endif | ||
903 | |||
904 | UNALLOCA(c); | ||
905 | UNALLOCA(cfm); | ||
906 | UNALLOCA(lo); | ||
907 | UNALLOCA(hi); | ||
908 | UNALLOCA(findex); | ||
909 | UNALLOCA(J); | ||
910 | UNALLOCA(JinvM); | ||
911 | UNALLOCA(A); | ||
912 | UNALLOCA(tmp1); | ||
913 | UNALLOCA(rhs); | ||
914 | UNALLOCA(lambda); | ||
915 | UNALLOCA(L); | ||
916 | } | ||
917 | else { | ||
918 | // no constraints | ||
919 | dMultiply0 (vnew,invM,fe,n6,n6,1); | ||
920 | for (i=0; i<n6; i++) vnew[i] = v[i] + stepsize*vnew[i]; | ||
921 | } | ||
922 | |||
923 | #ifdef COMPARE_METHODS | ||
924 | comparator.nextMatrix (vnew,n6,1,0,"vnew"); | ||
925 | #endif | ||
926 | |||
927 | // apply the velocity update to the bodies | ||
928 | #ifdef TIMING | ||
929 | dTimerNow ("update velocity"); | ||
930 | #endif | ||
931 | for (i=0; i<nb; i++) { | ||
932 | for (j=0; j<3; j++) body[i]->lvel[j] = vnew[i*6+j]; | ||
933 | for (j=0; j<3; j++) body[i]->avel[j] = vnew[i*6+3+j]; | ||
934 | } | ||
935 | |||
936 | // update the position and orientation from the new linear/angular velocity | ||
937 | // (over the given timestep) | ||
938 | #ifdef TIMING | ||
939 | dTimerNow ("update position"); | ||
940 | #endif | ||
941 | for (i=0; i<nb; i++) dxStepBody (body[i],stepsize); | ||
942 | |||
943 | #ifdef TIMING | ||
944 | dTimerNow ("tidy up"); | ||
945 | #endif | ||
946 | |||
947 | // zero all force accumulators | ||
948 | for (i=0; i<nb; i++) { | ||
949 | body[i]->facc[0] = 0; | ||
950 | body[i]->facc[1] = 0; | ||
951 | body[i]->facc[2] = 0; | ||
952 | body[i]->facc[3] = 0; | ||
953 | body[i]->tacc[0] = 0; | ||
954 | body[i]->tacc[1] = 0; | ||
955 | body[i]->tacc[2] = 0; | ||
956 | body[i]->tacc[3] = 0; | ||
957 | } | ||
958 | |||
959 | #ifdef TIMING | ||
960 | dTimerEnd(); | ||
961 | if (m > 0) dTimerReport (stdout,1); | ||
962 | #endif | ||
963 | |||
964 | UNALLOCA(joint); | ||
965 | UNALLOCA(I); | ||
966 | UNALLOCA(invI); | ||
967 | UNALLOCA(info); | ||
968 | UNALLOCA(ofs); | ||
969 | UNALLOCA(invM); | ||
970 | UNALLOCA(fe); | ||
971 | UNALLOCA(v); | ||
972 | UNALLOCA(vnew); | ||
973 | } | ||
974 | |||
975 | //**************************************************************************** | ||
976 | // an optimized version of dInternalStepIsland1() | ||
977 | |||
978 | void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, | ||
979 | dxJoint * const *_joint, int nj, dReal stepsize) | ||
980 | { | ||
981 | int i,j,k; | ||
982 | #ifdef TIMING | ||
983 | dTimerStart("preprocessing"); | ||
984 | #endif | ||
985 | |||
986 | dReal stepsize1 = dRecip(stepsize); | ||
987 | |||
988 | // number all bodies in the body list - set their tag values | ||
989 | for (i=0; i<nb; i++) body[i]->tag = i; | ||
990 | |||
991 | // make a local copy of the joint array, because we might want to modify it. | ||
992 | // (the "dxJoint *const*" declaration says we're allowed to modify the joints | ||
993 | // but not the joint array, because the caller might need it unchanged). | ||
994 | ALLOCA(dxJoint*,joint,nj*sizeof(dxJoint*)); | ||
995 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
996 | if (joint == NULL) { | ||
997 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
998 | return; | ||
999 | } | ||
1000 | #endif | ||
1001 | memcpy (joint,_joint,nj * sizeof(dxJoint*)); | ||
1002 | |||
1003 | // for all bodies, compute the inertia tensor and its inverse in the global | ||
1004 | // frame, and compute the rotational force and add it to the torque | ||
1005 | // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. | ||
1006 | // @@@ check computation of rotational force. | ||
1007 | #ifdef dGYROSCOPIC | ||
1008 | ALLOCA(dReal,I,3*nb*4*sizeof(dReal)); | ||
1009 | # ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1010 | if (I == NULL) { | ||
1011 | UNALLOCA(joint); | ||
1012 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1013 | return; | ||
1014 | } | ||
1015 | # endif | ||
1016 | #else | ||
1017 | dReal *I = NULL; | ||
1018 | #endif // for dGYROSCOPIC | ||
1019 | |||
1020 | ALLOCA(dReal,invI,3*nb*4*sizeof(dReal)); | ||
1021 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1022 | if (invI == NULL) { | ||
1023 | UNALLOCA(I); | ||
1024 | UNALLOCA(joint); | ||
1025 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1026 | return; | ||
1027 | } | ||
1028 | #endif | ||
1029 | |||
1030 | //dSetZero (I,3*nb*4); | ||
1031 | //dSetZero (invI,3*nb*4); | ||
1032 | for (i=0; i<nb; i++) { | ||
1033 | dReal tmp[12]; | ||
1034 | |||
1035 | // compute inverse inertia tensor in global frame | ||
1036 | dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->posr.R); | ||
1037 | dMULTIPLY0_333 (invI+i*12,body[i]->posr.R,tmp); | ||
1038 | #ifdef dGYROSCOPIC | ||
1039 | // compute inertia tensor in global frame | ||
1040 | dMULTIPLY2_333 (tmp,body[i]->mass.I,body[i]->posr.R); | ||
1041 | dMULTIPLY0_333 (I+i*12,body[i]->posr.R,tmp); | ||
1042 | |||
1043 | // compute rotational force | ||
1044 | dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); | ||
1045 | dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); | ||
1046 | #endif | ||
1047 | } | ||
1048 | |||
1049 | // add the gravity force to all bodies | ||
1050 | for (i=0; i<nb; i++) { | ||
1051 | if ((body[i]->flags & dxBodyNoGravity)==0) { | ||
1052 | body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; | ||
1053 | body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; | ||
1054 | body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | // get m = total constraint dimension, nub = number of unbounded variables. | ||
1059 | // create constraint offset array and number-of-rows array for all joints. | ||
1060 | // the constraints are re-ordered as follows: the purely unbounded | ||
1061 | // constraints, the mixed unbounded + LCP constraints, and last the purely | ||
1062 | // LCP constraints. this assists the LCP solver to put all unbounded | ||
1063 | // variables at the start for a quick factorization. | ||
1064 | // | ||
1065 | // joints with m=0 are inactive and are removed from the joints array | ||
1066 | // entirely, so that the code that follows does not consider them. | ||
1067 | // also number all active joints in the joint list (set their tag values). | ||
1068 | // inactive joints receive a tag value of -1. | ||
1069 | |||
1070 | int m = 0; | ||
1071 | ALLOCA(dxJoint::Info1,info,nj*sizeof(dxJoint::Info1)); | ||
1072 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1073 | if (info == NULL) { | ||
1074 | UNALLOCA(invI); | ||
1075 | UNALLOCA(I); | ||
1076 | UNALLOCA(joint); | ||
1077 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1078 | return; | ||
1079 | } | ||
1080 | #endif | ||
1081 | ALLOCA(int,ofs,nj*sizeof(int)); | ||
1082 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1083 | if (ofs == NULL) { | ||
1084 | UNALLOCA(info); | ||
1085 | UNALLOCA(invI); | ||
1086 | UNALLOCA(I); | ||
1087 | UNALLOCA(joint); | ||
1088 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1089 | return; | ||
1090 | } | ||
1091 | #endif | ||
1092 | for (i=0, j=0; j<nj; j++) { // i=dest, j=src | ||
1093 | joint[j]->vtable->getInfo1 (joint[j],info+i); | ||
1094 | dIASSERT (info[i].m >= 0 && info[i].m <= 6 && | ||
1095 | info[i].nub >= 0 && info[i].nub <= info[i].m); | ||
1096 | if (info[i].m > 0) { | ||
1097 | joint[i] = joint[j]; | ||
1098 | joint[i]->tag = i; | ||
1099 | i++; | ||
1100 | } | ||
1101 | else { | ||
1102 | joint[j]->tag = -1; | ||
1103 | } | ||
1104 | } | ||
1105 | nj = i; | ||
1106 | |||
1107 | // the purely unbounded constraints | ||
1108 | for (i=0; i<nj; i++) if (info[i].nub == info[i].m) { | ||
1109 | ofs[i] = m; | ||
1110 | m += info[i].m; | ||
1111 | } | ||
1112 | int nub = m; | ||
1113 | // the mixed unbounded + LCP constraints | ||
1114 | for (i=0; i<nj; i++) if (info[i].nub > 0 && info[i].nub < info[i].m) { | ||
1115 | ofs[i] = m; | ||
1116 | m += info[i].m; | ||
1117 | } | ||
1118 | // the purely LCP constraints | ||
1119 | for (i=0; i<nj; i++) if (info[i].nub == 0) { | ||
1120 | ofs[i] = m; | ||
1121 | m += info[i].m; | ||
1122 | } | ||
1123 | |||
1124 | // this will be set to the force due to the constraints | ||
1125 | ALLOCA(dReal,cforce,nb*8*sizeof(dReal)); | ||
1126 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1127 | if (cforce == NULL) { | ||
1128 | UNALLOCA(ofs); | ||
1129 | UNALLOCA(info); | ||
1130 | UNALLOCA(invI); | ||
1131 | UNALLOCA(I); | ||
1132 | UNALLOCA(joint); | ||
1133 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1134 | return; | ||
1135 | } | ||
1136 | #endif | ||
1137 | dSetZero (cforce,nb*8); | ||
1138 | |||
1139 | // if there are constraints, compute cforce | ||
1140 | if (m > 0) { | ||
1141 | // create a constraint equation right hand side vector `c', a constraint | ||
1142 | // force mixing vector `cfm', and LCP low and high bound vectors, and an | ||
1143 | // 'findex' vector. | ||
1144 | ALLOCA(dReal,c,m*sizeof(dReal)); | ||
1145 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1146 | if (c == NULL) { | ||
1147 | UNALLOCA(cforce); | ||
1148 | UNALLOCA(ofs); | ||
1149 | UNALLOCA(info); | ||
1150 | UNALLOCA(invI); | ||
1151 | UNALLOCA(I); | ||
1152 | UNALLOCA(joint); | ||
1153 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1154 | return; | ||
1155 | } | ||
1156 | #endif | ||
1157 | ALLOCA(dReal,cfm,m*sizeof(dReal)); | ||
1158 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1159 | if (cfm == NULL) { | ||
1160 | UNALLOCA(c); | ||
1161 | UNALLOCA(cforce); | ||
1162 | UNALLOCA(ofs); | ||
1163 | UNALLOCA(info); | ||
1164 | UNALLOCA(invI); | ||
1165 | UNALLOCA(I); | ||
1166 | UNALLOCA(joint); | ||
1167 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1168 | return; | ||
1169 | } | ||
1170 | #endif | ||
1171 | ALLOCA(dReal,lo,m*sizeof(dReal)); | ||
1172 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1173 | if (lo == NULL) { | ||
1174 | UNALLOCA(cfm); | ||
1175 | UNALLOCA(c); | ||
1176 | UNALLOCA(cforce); | ||
1177 | UNALLOCA(ofs); | ||
1178 | UNALLOCA(info); | ||
1179 | UNALLOCA(invI); | ||
1180 | UNALLOCA(I); | ||
1181 | UNALLOCA(joint); | ||
1182 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1183 | return; | ||
1184 | } | ||
1185 | #endif | ||
1186 | ALLOCA(dReal,hi,m*sizeof(dReal)); | ||
1187 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1188 | if (hi == NULL) { | ||
1189 | UNALLOCA(lo); | ||
1190 | UNALLOCA(cfm); | ||
1191 | UNALLOCA(c); | ||
1192 | UNALLOCA(cforce); | ||
1193 | UNALLOCA(ofs); | ||
1194 | UNALLOCA(info); | ||
1195 | UNALLOCA(invI); | ||
1196 | UNALLOCA(I); | ||
1197 | UNALLOCA(joint); | ||
1198 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1199 | return; | ||
1200 | } | ||
1201 | #endif | ||
1202 | ALLOCA(int,findex,m*sizeof(int)); | ||
1203 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1204 | if (findex == NULL) { | ||
1205 | UNALLOCA(hi); | ||
1206 | UNALLOCA(lo); | ||
1207 | UNALLOCA(cfm); | ||
1208 | UNALLOCA(c); | ||
1209 | UNALLOCA(cforce); | ||
1210 | UNALLOCA(ofs); | ||
1211 | UNALLOCA(info); | ||
1212 | UNALLOCA(invI); | ||
1213 | UNALLOCA(I); | ||
1214 | UNALLOCA(joint); | ||
1215 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1216 | return; | ||
1217 | } | ||
1218 | #endif | ||
1219 | dSetZero (c,m); | ||
1220 | dSetValue (cfm,m,world->global_cfm); | ||
1221 | dSetValue (lo,m,-dInfinity); | ||
1222 | dSetValue (hi,m, dInfinity); | ||
1223 | for (i=0; i<m; i++) findex[i] = -1; | ||
1224 | |||
1225 | // get jacobian data from constraints. a (2*m)x8 matrix will be created | ||
1226 | // to store the two jacobian blocks from each constraint. it has this | ||
1227 | // format: | ||
1228 | // | ||
1229 | // l l l 0 a a a 0 \ . | ||
1230 | // l l l 0 a a a 0 }-- jacobian body 1 block for joint 0 (3 rows) | ||
1231 | // l l l 0 a a a 0 / | ||
1232 | // l l l 0 a a a 0 \ . | ||
1233 | // l l l 0 a a a 0 }-- jacobian body 2 block for joint 0 (3 rows) | ||
1234 | // l l l 0 a a a 0 / | ||
1235 | // l l l 0 a a a 0 }--- jacobian body 1 block for joint 1 (1 row) | ||
1236 | // l l l 0 a a a 0 }--- jacobian body 2 block for joint 1 (1 row) | ||
1237 | // etc... | ||
1238 | // | ||
1239 | // (lll) = linear jacobian data | ||
1240 | // (aaa) = angular jacobian data | ||
1241 | // | ||
1242 | # ifdef TIMING | ||
1243 | dTimerNow ("create J"); | ||
1244 | # endif | ||
1245 | ALLOCA(dReal,J,2*m*8*sizeof(dReal)); | ||
1246 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1247 | if (J == NULL) { | ||
1248 | UNALLOCA(findex); | ||
1249 | UNALLOCA(hi); | ||
1250 | UNALLOCA(lo); | ||
1251 | UNALLOCA(cfm); | ||
1252 | UNALLOCA(c); | ||
1253 | UNALLOCA(cforce); | ||
1254 | UNALLOCA(ofs); | ||
1255 | UNALLOCA(info); | ||
1256 | UNALLOCA(invI); | ||
1257 | UNALLOCA(I); | ||
1258 | UNALLOCA(joint); | ||
1259 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1260 | return; | ||
1261 | } | ||
1262 | #endif | ||
1263 | dSetZero (J,2*m*8); | ||
1264 | dxJoint::Info2 Jinfo; | ||
1265 | Jinfo.rowskip = 8; | ||
1266 | Jinfo.fps = stepsize1; | ||
1267 | Jinfo.erp = world->global_erp; | ||
1268 | for (i=0; i<nj; i++) { | ||
1269 | Jinfo.J1l = J + 2*8*ofs[i]; | ||
1270 | Jinfo.J1a = Jinfo.J1l + 4; | ||
1271 | Jinfo.J2l = Jinfo.J1l + 8*info[i].m; | ||
1272 | Jinfo.J2a = Jinfo.J2l + 4; | ||
1273 | Jinfo.c = c + ofs[i]; | ||
1274 | Jinfo.cfm = cfm + ofs[i]; | ||
1275 | Jinfo.lo = lo + ofs[i]; | ||
1276 | Jinfo.hi = hi + ofs[i]; | ||
1277 | Jinfo.findex = findex + ofs[i]; | ||
1278 | joint[i]->vtable->getInfo2 (joint[i],&Jinfo); | ||
1279 | // adjust returned findex values for global index numbering | ||
1280 | for (j=0; j<info[i].m; j++) { | ||
1281 | if (findex[ofs[i] + j] >= 0) findex[ofs[i] + j] += ofs[i]; | ||
1282 | } | ||
1283 | } | ||
1284 | |||
1285 | // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same | ||
1286 | // format as J so we just go through the constraints in J multiplying by | ||
1287 | // the appropriate scalars and matrices. | ||
1288 | # ifdef TIMING | ||
1289 | dTimerNow ("compute A"); | ||
1290 | # endif | ||
1291 | ALLOCA(dReal,JinvM,2*m*8*sizeof(dReal)); | ||
1292 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1293 | if (JinvM == NULL) { | ||
1294 | UNALLOCA(J); | ||
1295 | UNALLOCA(findex); | ||
1296 | UNALLOCA(hi); | ||
1297 | UNALLOCA(lo); | ||
1298 | UNALLOCA(cfm); | ||
1299 | UNALLOCA(c); | ||
1300 | UNALLOCA(cforce); | ||
1301 | UNALLOCA(ofs); | ||
1302 | UNALLOCA(info); | ||
1303 | UNALLOCA(invI); | ||
1304 | UNALLOCA(I); | ||
1305 | UNALLOCA(joint); | ||
1306 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1307 | return; | ||
1308 | } | ||
1309 | #endif | ||
1310 | dSetZero (JinvM,2*m*8); | ||
1311 | for (i=0; i<nj; i++) { | ||
1312 | int b = joint[i]->node[0].body->tag; | ||
1313 | dReal body_invMass = body[b]->invMass; | ||
1314 | dReal *body_invI = invI + b*12; | ||
1315 | dReal *Jsrc = J + 2*8*ofs[i]; | ||
1316 | dReal *Jdst = JinvM + 2*8*ofs[i]; | ||
1317 | for (j=info[i].m-1; j>=0; j--) { | ||
1318 | for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; | ||
1319 | dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); | ||
1320 | Jsrc += 8; | ||
1321 | Jdst += 8; | ||
1322 | } | ||
1323 | if (joint[i]->node[1].body) { | ||
1324 | b = joint[i]->node[1].body->tag; | ||
1325 | body_invMass = body[b]->invMass; | ||
1326 | body_invI = invI + b*12; | ||
1327 | for (j=info[i].m-1; j>=0; j--) { | ||
1328 | for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; | ||
1329 | dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); | ||
1330 | Jsrc += 8; | ||
1331 | Jdst += 8; | ||
1332 | } | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | // now compute A = JinvM * J'. A's rows and columns are grouped by joint, | ||
1337 | // i.e. in the same way as the rows of J. block (i,j) of A is only nonzero | ||
1338 | // if joints i and j have at least one body in common. this fact suggests | ||
1339 | // the algorithm used to fill A: | ||
1340 | // | ||
1341 | // for b = all bodies | ||
1342 | // n = number of joints attached to body b | ||
1343 | // for i = 1..n | ||
1344 | // for j = i+1..n | ||
1345 | // ii = actual joint number for i | ||
1346 | // jj = actual joint number for j | ||
1347 | // // (ii,jj) will be set to all pairs of joints around body b | ||
1348 | // compute blockwise: A(ii,jj) += JinvM(ii) * J(jj)' | ||
1349 | // | ||
1350 | // this algorithm catches all pairs of joints that have at least one body | ||
1351 | // in common. it does not compute the diagonal blocks of A however - | ||
1352 | // another similar algorithm does that. | ||
1353 | |||
1354 | int mskip = dPAD(m); | ||
1355 | ALLOCA(dReal,A,m*mskip*sizeof(dReal)); | ||
1356 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1357 | if (A == NULL) { | ||
1358 | UNALLOCA(JinvM); | ||
1359 | UNALLOCA(J); | ||
1360 | UNALLOCA(findex); | ||
1361 | UNALLOCA(hi); | ||
1362 | UNALLOCA(lo); | ||
1363 | UNALLOCA(cfm); | ||
1364 | UNALLOCA(c); | ||
1365 | UNALLOCA(cforce); | ||
1366 | UNALLOCA(ofs); | ||
1367 | UNALLOCA(info); | ||
1368 | UNALLOCA(invI); | ||
1369 | UNALLOCA(I); | ||
1370 | UNALLOCA(joint); | ||
1371 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1372 | return; | ||
1373 | } | ||
1374 | #endif | ||
1375 | dSetZero (A,m*mskip); | ||
1376 | for (i=0; i<nb; i++) { | ||
1377 | for (dxJointNode *n1=body[i]->firstjoint; n1; n1=n1->next) { | ||
1378 | for (dxJointNode *n2=n1->next; n2; n2=n2->next) { | ||
1379 | // get joint numbers and ensure ofs[j1] >= ofs[j2] | ||
1380 | int j1 = n1->joint->tag; | ||
1381 | int j2 = n2->joint->tag; | ||
1382 | if (ofs[j1] < ofs[j2]) { | ||
1383 | int tmp = j1; | ||
1384 | j1 = j2; | ||
1385 | j2 = tmp; | ||
1386 | } | ||
1387 | |||
1388 | // if either joint was tagged as -1 then it is an inactive (m=0) | ||
1389 | // joint that should not be considered | ||
1390 | if (j1==-1 || j2==-1) continue; | ||
1391 | |||
1392 | // determine if body i is the 1st or 2nd body of joints j1 and j2 | ||
1393 | int jb1 = (joint[j1]->node[1].body == body[i]); | ||
1394 | int jb2 = (joint[j2]->node[1].body == body[i]); | ||
1395 | // jb1/jb2 must be 0 for joints with only one body | ||
1396 | dIASSERT(joint[j1]->node[1].body || jb1==0); | ||
1397 | dIASSERT(joint[j2]->node[1].body || jb2==0); | ||
1398 | |||
1399 | // set block of A | ||
1400 | MultiplyAdd2_p8r (A + ofs[j1]*mskip + ofs[j2], | ||
1401 | JinvM + 2*8*ofs[j1] + jb1*8*info[j1].m, | ||
1402 | J + 2*8*ofs[j2] + jb2*8*info[j2].m, | ||
1403 | info[j1].m,info[j2].m, mskip); | ||
1404 | } | ||
1405 | } | ||
1406 | } | ||
1407 | // compute diagonal blocks of A | ||
1408 | for (i=0; i<nj; i++) { | ||
1409 | Multiply2_p8r (A + ofs[i]*(mskip+1), | ||
1410 | JinvM + 2*8*ofs[i], | ||
1411 | J + 2*8*ofs[i], | ||
1412 | info[i].m,info[i].m, mskip); | ||
1413 | if (joint[i]->node[1].body) { | ||
1414 | MultiplyAdd2_p8r (A + ofs[i]*(mskip+1), | ||
1415 | JinvM + 2*8*ofs[i] + 8*info[i].m, | ||
1416 | J + 2*8*ofs[i] + 8*info[i].m, | ||
1417 | info[i].m,info[i].m, mskip); | ||
1418 | } | ||
1419 | } | ||
1420 | |||
1421 | // add cfm to the diagonal of A | ||
1422 | for (i=0; i<m; i++) A[i*mskip+i] += cfm[i] * stepsize1; | ||
1423 | |||
1424 | # ifdef COMPARE_METHODS | ||
1425 | comparator.nextMatrix (A,m,m,1,"A"); | ||
1426 | # endif | ||
1427 | |||
1428 | // compute the right hand side `rhs' | ||
1429 | # ifdef TIMING | ||
1430 | dTimerNow ("compute rhs"); | ||
1431 | # endif | ||
1432 | ALLOCA(dReal,tmp1,nb*8*sizeof(dReal)); | ||
1433 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1434 | if (tmp1 == NULL) { | ||
1435 | UNALLOCA(A); | ||
1436 | UNALLOCA(JinvM); | ||
1437 | UNALLOCA(J); | ||
1438 | UNALLOCA(findex); | ||
1439 | UNALLOCA(hi); | ||
1440 | UNALLOCA(lo); | ||
1441 | UNALLOCA(cfm); | ||
1442 | UNALLOCA(c); | ||
1443 | UNALLOCA(cforce); | ||
1444 | UNALLOCA(ofs); | ||
1445 | UNALLOCA(info); | ||
1446 | UNALLOCA(invI); | ||
1447 | UNALLOCA(I); | ||
1448 | UNALLOCA(joint); | ||
1449 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1450 | return; | ||
1451 | } | ||
1452 | #endif | ||
1453 | //dSetZero (tmp1,nb*8); | ||
1454 | // put v/h + invM*fe into tmp1 | ||
1455 | for (i=0; i<nb; i++) { | ||
1456 | dReal body_invMass = body[i]->invMass; | ||
1457 | dReal *body_invI = invI + i*12; | ||
1458 | for (j=0; j<3; j++) tmp1[i*8+j] = body[i]->facc[j] * body_invMass + | ||
1459 | body[i]->lvel[j] * stepsize1; | ||
1460 | dMULTIPLY0_331 (tmp1 + i*8 + 4,body_invI,body[i]->tacc); | ||
1461 | for (j=0; j<3; j++) tmp1[i*8+4+j] += body[i]->avel[j] * stepsize1; | ||
1462 | } | ||
1463 | // put J*tmp1 into rhs | ||
1464 | ALLOCA(dReal,rhs,m*sizeof(dReal)); | ||
1465 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1466 | if (rhs == NULL) { | ||
1467 | UNALLOCA(tmp1); | ||
1468 | UNALLOCA(A); | ||
1469 | UNALLOCA(JinvM); | ||
1470 | UNALLOCA(J); | ||
1471 | UNALLOCA(findex); | ||
1472 | UNALLOCA(hi); | ||
1473 | UNALLOCA(lo); | ||
1474 | UNALLOCA(cfm); | ||
1475 | UNALLOCA(c); | ||
1476 | UNALLOCA(cforce); | ||
1477 | UNALLOCA(ofs); | ||
1478 | UNALLOCA(info); | ||
1479 | UNALLOCA(invI); | ||
1480 | UNALLOCA(I); | ||
1481 | UNALLOCA(joint); | ||
1482 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1483 | return; | ||
1484 | } | ||
1485 | #endif | ||
1486 | //dSetZero (rhs,m); | ||
1487 | for (i=0; i<nj; i++) { | ||
1488 | dReal *JJ = J + 2*8*ofs[i]; | ||
1489 | Multiply0_p81 (rhs+ofs[i],JJ, | ||
1490 | tmp1 + 8*joint[i]->node[0].body->tag, info[i].m); | ||
1491 | if (joint[i]->node[1].body) { | ||
1492 | MultiplyAdd0_p81 (rhs+ofs[i],JJ + 8*info[i].m, | ||
1493 | tmp1 + 8*joint[i]->node[1].body->tag, info[i].m); | ||
1494 | } | ||
1495 | } | ||
1496 | // complete rhs | ||
1497 | for (i=0; i<m; i++) rhs[i] = c[i]*stepsize1 - rhs[i]; | ||
1498 | |||
1499 | # ifdef COMPARE_METHODS | ||
1500 | comparator.nextMatrix (c,m,1,0,"c"); | ||
1501 | comparator.nextMatrix (rhs,m,1,0,"rhs"); | ||
1502 | # endif | ||
1503 | |||
1504 | // solve the LCP problem and get lambda. | ||
1505 | // this will destroy A but that's okay | ||
1506 | # ifdef TIMING | ||
1507 | dTimerNow ("solving LCP problem"); | ||
1508 | # endif | ||
1509 | ALLOCA(dReal,lambda,m*sizeof(dReal)); | ||
1510 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1511 | if (lambda == NULL) { | ||
1512 | UNALLOCA(rhs); | ||
1513 | UNALLOCA(tmp1); | ||
1514 | UNALLOCA(A); | ||
1515 | UNALLOCA(JinvM); | ||
1516 | UNALLOCA(J); | ||
1517 | UNALLOCA(findex); | ||
1518 | UNALLOCA(hi); | ||
1519 | UNALLOCA(lo); | ||
1520 | UNALLOCA(cfm); | ||
1521 | UNALLOCA(c); | ||
1522 | UNALLOCA(cforce); | ||
1523 | UNALLOCA(ofs); | ||
1524 | UNALLOCA(info); | ||
1525 | UNALLOCA(invI); | ||
1526 | UNALLOCA(I); | ||
1527 | UNALLOCA(joint); | ||
1528 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1529 | return; | ||
1530 | } | ||
1531 | #endif | ||
1532 | ALLOCA(dReal,residual,m*sizeof(dReal)); | ||
1533 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1534 | if (residual == NULL) { | ||
1535 | UNALLOCA(lambda); | ||
1536 | UNALLOCA(rhs); | ||
1537 | UNALLOCA(tmp1); | ||
1538 | UNALLOCA(A); | ||
1539 | UNALLOCA(JinvM); | ||
1540 | UNALLOCA(J); | ||
1541 | UNALLOCA(findex); | ||
1542 | UNALLOCA(hi); | ||
1543 | UNALLOCA(lo); | ||
1544 | UNALLOCA(cfm); | ||
1545 | UNALLOCA(c); | ||
1546 | UNALLOCA(cforce); | ||
1547 | UNALLOCA(ofs); | ||
1548 | UNALLOCA(info); | ||
1549 | UNALLOCA(invI); | ||
1550 | UNALLOCA(I); | ||
1551 | UNALLOCA(joint); | ||
1552 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1553 | return; | ||
1554 | } | ||
1555 | #endif | ||
1556 | dSolveLCP (m,A,lambda,rhs,residual,nub,lo,hi,findex); | ||
1557 | |||
1558 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1559 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) | ||
1560 | return; | ||
1561 | #endif | ||
1562 | |||
1563 | |||
1564 | // OLD WAY - direct factor and solve | ||
1565 | // | ||
1566 | // // factorize A (L*L'=A) | ||
1567 | //# ifdef TIMING | ||
1568 | // dTimerNow ("factorize A"); | ||
1569 | //# endif | ||
1570 | // dReal *L = (dReal*) ALLOCA (m*mskip*sizeof(dReal)); | ||
1571 | // memcpy (L,A,m*mskip*sizeof(dReal)); | ||
1572 | //# ifdef FAST_FACTOR | ||
1573 | // dFastFactorCholesky (L,m); // does not report non positive definiteness | ||
1574 | //# else | ||
1575 | // if (dFactorCholesky (L,m)==0) dDebug (0,"A is not positive definite"); | ||
1576 | //# endif | ||
1577 | // | ||
1578 | // // compute lambda | ||
1579 | //# ifdef TIMING | ||
1580 | // dTimerNow ("compute lambda"); | ||
1581 | //# endif | ||
1582 | // dReal *lambda = (dReal*) ALLOCA (m * sizeof(dReal)); | ||
1583 | // memcpy (lambda,rhs,m * sizeof(dReal)); | ||
1584 | // dSolveCholesky (L,lambda,m); | ||
1585 | |||
1586 | # ifdef COMPARE_METHODS | ||
1587 | comparator.nextMatrix (lambda,m,1,0,"lambda"); | ||
1588 | # endif | ||
1589 | |||
1590 | // compute the constraint force `cforce' | ||
1591 | # ifdef TIMING | ||
1592 | dTimerNow ("compute constraint force"); | ||
1593 | # endif | ||
1594 | // compute cforce = J'*lambda | ||
1595 | for (i=0; i<nj; i++) { | ||
1596 | dReal *JJ = J + 2*8*ofs[i]; | ||
1597 | dxBody* b1 = joint[i]->node[0].body; | ||
1598 | dxBody* b2 = joint[i]->node[1].body; | ||
1599 | dJointFeedback *fb = joint[i]->feedback; | ||
1600 | |||
1601 | if (fb) { | ||
1602 | // the user has requested feedback on the amount of force that this | ||
1603 | // joint is applying to the bodies. we use a slightly slower | ||
1604 | // computation that splits out the force components and puts them | ||
1605 | // in the feedback structure. | ||
1606 | dReal data1[8],data2[8]; | ||
1607 | Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); | ||
1608 | dReal *cf1 = cforce + 8*b1->tag; | ||
1609 | cf1[0] += (fb->f1[0] = data1[0]); | ||
1610 | cf1[1] += (fb->f1[1] = data1[1]); | ||
1611 | cf1[2] += (fb->f1[2] = data1[2]); | ||
1612 | cf1[4] += (fb->t1[0] = data1[4]); | ||
1613 | cf1[5] += (fb->t1[1] = data1[5]); | ||
1614 | cf1[6] += (fb->t1[2] = data1[6]); | ||
1615 | if (b2){ | ||
1616 | Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); | ||
1617 | dReal *cf2 = cforce + 8*b2->tag; | ||
1618 | cf2[0] += (fb->f2[0] = data2[0]); | ||
1619 | cf2[1] += (fb->f2[1] = data2[1]); | ||
1620 | cf2[2] += (fb->f2[2] = data2[2]); | ||
1621 | cf2[4] += (fb->t2[0] = data2[4]); | ||
1622 | cf2[5] += (fb->t2[1] = data2[5]); | ||
1623 | cf2[6] += (fb->t2[2] = data2[6]); | ||
1624 | } | ||
1625 | } | ||
1626 | else { | ||
1627 | // no feedback is required, let's compute cforce the faster way | ||
1628 | MultiplyAdd1_8q1 (cforce + 8*b1->tag,JJ, lambda+ofs[i], info[i].m); | ||
1629 | if (b2) { | ||
1630 | MultiplyAdd1_8q1 (cforce + 8*b2->tag, | ||
1631 | JJ + 8*info[i].m, lambda+ofs[i], info[i].m); | ||
1632 | } | ||
1633 | } | ||
1634 | } | ||
1635 | UNALLOCA(c); | ||
1636 | UNALLOCA(cfm); | ||
1637 | UNALLOCA(lo); | ||
1638 | UNALLOCA(hi); | ||
1639 | UNALLOCA(findex); | ||
1640 | UNALLOCA(J); | ||
1641 | UNALLOCA(JinvM); | ||
1642 | UNALLOCA(A); | ||
1643 | UNALLOCA(tmp1); | ||
1644 | UNALLOCA(rhs); | ||
1645 | UNALLOCA(lambda); | ||
1646 | UNALLOCA(residual); | ||
1647 | } | ||
1648 | |||
1649 | // compute the velocity update | ||
1650 | #ifdef TIMING | ||
1651 | dTimerNow ("compute velocity update"); | ||
1652 | #endif | ||
1653 | |||
1654 | // add fe to cforce | ||
1655 | for (i=0; i<nb; i++) { | ||
1656 | for (j=0; j<3; j++) cforce[i*8+j] += body[i]->facc[j]; | ||
1657 | for (j=0; j<3; j++) cforce[i*8+4+j] += body[i]->tacc[j]; | ||
1658 | } | ||
1659 | // multiply cforce by stepsize | ||
1660 | for (i=0; i < nb*8; i++) cforce[i] *= stepsize; | ||
1661 | // add invM * cforce to the body velocity | ||
1662 | for (i=0; i<nb; i++) { | ||
1663 | dReal body_invMass = body[i]->invMass; | ||
1664 | dReal *body_invI = invI + i*12; | ||
1665 | for (j=0; j<3; j++) body[i]->lvel[j] += body_invMass * cforce[i*8+j]; | ||
1666 | dMULTIPLYADD0_331 (body[i]->avel,body_invI,cforce+i*8+4); | ||
1667 | } | ||
1668 | |||
1669 | // update the position and orientation from the new linear/angular velocity | ||
1670 | // (over the given timestep) | ||
1671 | # ifdef TIMING | ||
1672 | dTimerNow ("update position"); | ||
1673 | # endif | ||
1674 | for (i=0; i<nb; i++) dxStepBody (body[i],stepsize); | ||
1675 | |||
1676 | #ifdef COMPARE_METHODS | ||
1677 | ALLOCA(dReal,tmp, ALLOCA (nb*6*sizeof(dReal)); | ||
1678 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1679 | if (tmp == NULL) { | ||
1680 | UNALLOCA(cforce); | ||
1681 | UNALLOCA(ofs); | ||
1682 | UNALLOCA(info); | ||
1683 | UNALLOCA(invI); | ||
1684 | UNALLOCA(I); | ||
1685 | UNALLOCA(joint); | ||
1686 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1687 | return; | ||
1688 | } | ||
1689 | #endif | ||
1690 | for (i=0; i<nb; i++) { | ||
1691 | for (j=0; j<3; j++) tmp_vnew[i*6+j] = body[i]->lvel[j]; | ||
1692 | for (j=0; j<3; j++) tmp_vnew[i*6+3+j] = body[i]->avel[j]; | ||
1693 | } | ||
1694 | comparator.nextMatrix (tmp_vnew,nb*6,1,0,"vnew"); | ||
1695 | UNALLOCA(tmp); | ||
1696 | #endif | ||
1697 | |||
1698 | #ifdef TIMING | ||
1699 | dTimerNow ("tidy up"); | ||
1700 | #endif | ||
1701 | |||
1702 | // zero all force accumulators | ||
1703 | for (i=0; i<nb; i++) { | ||
1704 | body[i]->facc[0] = 0; | ||
1705 | body[i]->facc[1] = 0; | ||
1706 | body[i]->facc[2] = 0; | ||
1707 | body[i]->facc[3] = 0; | ||
1708 | body[i]->tacc[0] = 0; | ||
1709 | body[i]->tacc[1] = 0; | ||
1710 | body[i]->tacc[2] = 0; | ||
1711 | body[i]->tacc[3] = 0; | ||
1712 | } | ||
1713 | |||
1714 | #ifdef TIMING | ||
1715 | dTimerEnd(); | ||
1716 | if (m > 0) dTimerReport (stdout,1); | ||
1717 | #endif | ||
1718 | |||
1719 | UNALLOCA(joint); | ||
1720 | UNALLOCA(I); | ||
1721 | UNALLOCA(invI); | ||
1722 | UNALLOCA(info); | ||
1723 | UNALLOCA(ofs); | ||
1724 | UNALLOCA(cforce); | ||
1725 | } | ||
1726 | |||
1727 | //**************************************************************************** | ||
1728 | |||
1729 | void dInternalStepIsland (dxWorld *world, dxBody * const *body, int nb, | ||
1730 | dxJoint * const *joint, int nj, dReal stepsize) | ||
1731 | { | ||
1732 | |||
1733 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1734 | dMemoryFlag = d_MEMORY_OK; | ||
1735 | #endif | ||
1736 | |||
1737 | #ifndef COMPARE_METHODS | ||
1738 | dInternalStepIsland_x2 (world,body,nb,joint,nj,stepsize); | ||
1739 | |||
1740 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1741 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1742 | REPORT_OUT_OF_MEMORY; | ||
1743 | return; | ||
1744 | } | ||
1745 | #endif | ||
1746 | |||
1747 | #endif | ||
1748 | |||
1749 | #ifdef COMPARE_METHODS | ||
1750 | int i; | ||
1751 | |||
1752 | // save body state | ||
1753 | ALLOCA(dxBody,state,nb*sizeof(dxBody)); | ||
1754 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1755 | if (state == NULL) { | ||
1756 | dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; | ||
1757 | REPORT_OUT_OF_MEMORY; | ||
1758 | return; | ||
1759 | } | ||
1760 | #endif | ||
1761 | for (i=0; i<nb; i++) memcpy (state+i,body[i],sizeof(dxBody)); | ||
1762 | |||
1763 | // take slow step | ||
1764 | comparator.reset(); | ||
1765 | dInternalStepIsland_x1 (world,body,nb,joint,nj,stepsize); | ||
1766 | comparator.end(); | ||
1767 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1768 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1769 | UNALLOCA(state); | ||
1770 | REPORT_OUT_OF_MEMORY; | ||
1771 | return; | ||
1772 | } | ||
1773 | #endif | ||
1774 | |||
1775 | // restore state | ||
1776 | for (i=0; i<nb; i++) memcpy (body[i],state+i,sizeof(dxBody)); | ||
1777 | |||
1778 | // take fast step | ||
1779 | dInternalStepIsland_x2 (world,body,nb,joint,nj,stepsize); | ||
1780 | comparator.end(); | ||
1781 | #ifdef dUSE_MALLOC_FOR_ALLOCA | ||
1782 | if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { | ||
1783 | UNALLOCA(state); | ||
1784 | REPORT_OUT_OF_MEMORY; | ||
1785 | return; | ||
1786 | } | ||
1787 | #endif | ||
1788 | |||
1789 | //comparator.dump(); | ||
1790 | //_exit (1); | ||
1791 | UNALLOCA(state); | ||
1792 | #endif | ||
1793 | } | ||
1794 | |||
1795 | |||
diff --git a/libraries/ode-0.9\/ode/src/step.h b/libraries/ode-0.9\/ode/src/step.h new file mode 100755 index 0000000..4947253 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/step.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifndef _ODE_STEP_H_ | ||
24 | #define _ODE_STEP_H_ | ||
25 | |||
26 | #include <ode/common.h> | ||
27 | |||
28 | |||
29 | void dInternalStepIsland (dxWorld *world, | ||
30 | dxBody * const *body, int nb, | ||
31 | dxJoint * const *joint, int nj, | ||
32 | dReal stepsize); | ||
33 | |||
34 | |||
35 | |||
36 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/stepfast.cpp b/libraries/ode-0.9\/ode/src/stepfast.cpp new file mode 100755 index 0000000..35c45db --- /dev/null +++ b/libraries/ode-0.9\/ode/src/stepfast.cpp | |||
@@ -0,0 +1,1139 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * Fast iterative solver, David Whittaker. Email: david@csworkbench.com * | ||
7 | * * | ||
8 | * This library is free software; you can redistribute it and/or * | ||
9 | * modify it under the terms of EITHER: * | ||
10 | * (1) The GNU Lesser General Public License as published by the Free * | ||
11 | * Software Foundation; either version 2.1 of the License, or (at * | ||
12 | * your option) any later version. The text of the GNU Lesser * | ||
13 | * General Public License is included with this library in the * | ||
14 | * file LICENSE.TXT. * | ||
15 | * (2) The BSD-style license that is included with this library in * | ||
16 | * the file LICENSE-BSD.TXT. * | ||
17 | * * | ||
18 | * This library is distributed in the hope that it will be useful, * | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
21 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
22 | * * | ||
23 | *************************************************************************/ | ||
24 | |||
25 | // This is the StepFast code by David Whittaker. This code is faster, but | ||
26 | // sometimes less stable than, the original "big matrix" code. | ||
27 | // Refer to the user's manual for more information. | ||
28 | // Note that this source file duplicates a lot of stuff from step.cpp, | ||
29 | // eventually we should move the common code to a third file. | ||
30 | |||
31 | #include "objects.h" | ||
32 | #include "joint.h" | ||
33 | #include <ode/config.h> | ||
34 | #include <ode/objects.h> | ||
35 | #include <ode/odemath.h> | ||
36 | #include <ode/rotation.h> | ||
37 | #include <ode/timer.h> | ||
38 | #include <ode/error.h> | ||
39 | #include <ode/matrix.h> | ||
40 | #include <ode/misc.h> | ||
41 | #include "lcp.h" | ||
42 | #include "step.h" | ||
43 | #include "util.h" | ||
44 | |||
45 | |||
46 | // misc defines | ||
47 | |||
48 | #define ALLOCA dALLOCA16 | ||
49 | |||
50 | #define RANDOM_JOINT_ORDER | ||
51 | //#define FAST_FACTOR //use a factorization approximation to the LCP solver (fast, theoretically less accurate) | ||
52 | #define SLOW_LCP //use the old LCP solver | ||
53 | //#define NO_ISLANDS //does not perform island creation code (3~4% of simulation time), body disabling doesn't work | ||
54 | //#define TIMING | ||
55 | |||
56 | |||
57 | static int autoEnableDepth = 2; | ||
58 | |||
59 | void dWorldSetAutoEnableDepthSF1 (dxWorld *world, int autodepth) | ||
60 | { | ||
61 | if (autodepth > 0) | ||
62 | autoEnableDepth = autodepth; | ||
63 | else | ||
64 | autoEnableDepth = 0; | ||
65 | } | ||
66 | |||
67 | int dWorldGetAutoEnableDepthSF1 (dxWorld *world) | ||
68 | { | ||
69 | return autoEnableDepth; | ||
70 | } | ||
71 | |||
72 | //little bit of math.... the _sym_ functions assume the return matrix will be symmetric | ||
73 | static void | ||
74 | Multiply2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) | ||
75 | { | ||
76 | int i, j; | ||
77 | dReal sum, *aa, *ad, *bb, *cc; | ||
78 | dIASSERT (p > 0 && A && B && C); | ||
79 | bb = B; | ||
80 | for (i = 0; i < p; i++) | ||
81 | { | ||
82 | //aa is going accross the matrix, ad down | ||
83 | aa = ad = A; | ||
84 | cc = C; | ||
85 | for (j = i; j < p; j++) | ||
86 | { | ||
87 | sum = bb[0] * cc[0]; | ||
88 | sum += bb[1] * cc[1]; | ||
89 | sum += bb[2] * cc[2]; | ||
90 | sum += bb[4] * cc[4]; | ||
91 | sum += bb[5] * cc[5]; | ||
92 | sum += bb[6] * cc[6]; | ||
93 | *(aa++) = *ad = sum; | ||
94 | ad += Askip; | ||
95 | cc += 8; | ||
96 | } | ||
97 | bb += 8; | ||
98 | A += Askip + 1; | ||
99 | C += 8; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | MultiplyAdd2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) | ||
105 | { | ||
106 | int i, j; | ||
107 | dReal sum, *aa, *ad, *bb, *cc; | ||
108 | dIASSERT (p > 0 && A && B && C); | ||
109 | bb = B; | ||
110 | for (i = 0; i < p; i++) | ||
111 | { | ||
112 | //aa is going accross the matrix, ad down | ||
113 | aa = ad = A; | ||
114 | cc = C; | ||
115 | for (j = i; j < p; j++) | ||
116 | { | ||
117 | sum = bb[0] * cc[0]; | ||
118 | sum += bb[1] * cc[1]; | ||
119 | sum += bb[2] * cc[2]; | ||
120 | sum += bb[4] * cc[4]; | ||
121 | sum += bb[5] * cc[5]; | ||
122 | sum += bb[6] * cc[6]; | ||
123 | *(aa++) += sum; | ||
124 | *ad += sum; | ||
125 | ad += Askip; | ||
126 | cc += 8; | ||
127 | } | ||
128 | bb += 8; | ||
129 | A += Askip + 1; | ||
130 | C += 8; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | |||
135 | // this assumes the 4th and 8th rows of B are zero. | ||
136 | |||
137 | static void | ||
138 | Multiply0_p81 (dReal * A, dReal * B, dReal * C, int p) | ||
139 | { | ||
140 | int i; | ||
141 | dIASSERT (p > 0 && A && B && C); | ||
142 | dReal sum; | ||
143 | for (i = p; i; i--) | ||
144 | { | ||
145 | sum = B[0] * C[0]; | ||
146 | sum += B[1] * C[1]; | ||
147 | sum += B[2] * C[2]; | ||
148 | sum += B[4] * C[4]; | ||
149 | sum += B[5] * C[5]; | ||
150 | sum += B[6] * C[6]; | ||
151 | *(A++) = sum; | ||
152 | B += 8; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | |||
157 | // this assumes the 4th and 8th rows of B are zero. | ||
158 | |||
159 | static void | ||
160 | MultiplyAdd0_p81 (dReal * A, dReal * B, dReal * C, int p) | ||
161 | { | ||
162 | int i; | ||
163 | dIASSERT (p > 0 && A && B && C); | ||
164 | dReal sum; | ||
165 | for (i = p; i; i--) | ||
166 | { | ||
167 | sum = B[0] * C[0]; | ||
168 | sum += B[1] * C[1]; | ||
169 | sum += B[2] * C[2]; | ||
170 | sum += B[4] * C[4]; | ||
171 | sum += B[5] * C[5]; | ||
172 | sum += B[6] * C[6]; | ||
173 | *(A++) += sum; | ||
174 | B += 8; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | |||
179 | // this assumes the 4th and 8th rows of B are zero. | ||
180 | |||
181 | static void | ||
182 | Multiply1_8q1 (dReal * A, dReal * B, dReal * C, int q) | ||
183 | { | ||
184 | int k; | ||
185 | dReal sum; | ||
186 | dIASSERT (q > 0 && A && B && C); | ||
187 | sum = 0; | ||
188 | for (k = 0; k < q; k++) | ||
189 | sum += B[k * 8] * C[k]; | ||
190 | A[0] = sum; | ||
191 | sum = 0; | ||
192 | for (k = 0; k < q; k++) | ||
193 | sum += B[1 + k * 8] * C[k]; | ||
194 | A[1] = sum; | ||
195 | sum = 0; | ||
196 | for (k = 0; k < q; k++) | ||
197 | sum += B[2 + k * 8] * C[k]; | ||
198 | A[2] = sum; | ||
199 | sum = 0; | ||
200 | for (k = 0; k < q; k++) | ||
201 | sum += B[4 + k * 8] * C[k]; | ||
202 | A[4] = sum; | ||
203 | sum = 0; | ||
204 | for (k = 0; k < q; k++) | ||
205 | sum += B[5 + k * 8] * C[k]; | ||
206 | A[5] = sum; | ||
207 | sum = 0; | ||
208 | for (k = 0; k < q; k++) | ||
209 | sum += B[6 + k * 8] * C[k]; | ||
210 | A[6] = sum; | ||
211 | } | ||
212 | |||
213 | //**************************************************************************** | ||
214 | // body rotation | ||
215 | |||
216 | // return sin(x)/x. this has a singularity at 0 so special handling is needed | ||
217 | // for small arguments. | ||
218 | |||
219 | static inline dReal | ||
220 | sinc (dReal x) | ||
221 | { | ||
222 | // if |x| < 1e-4 then use a taylor series expansion. this two term expansion | ||
223 | // is actually accurate to one LS bit within this range if double precision | ||
224 | // is being used - so don't worry! | ||
225 | if (dFabs (x) < 1.0e-4) | ||
226 | return REAL (1.0) - x * x * REAL (0.166666666666666666667); | ||
227 | else | ||
228 | return dSin (x) / x; | ||
229 | } | ||
230 | |||
231 | |||
232 | // given a body b, apply its linear and angular rotation over the time | ||
233 | // interval h, thereby adjusting its position and orientation. | ||
234 | |||
235 | static inline void | ||
236 | moveAndRotateBody (dxBody * b, dReal h) | ||
237 | { | ||
238 | int j; | ||
239 | |||
240 | // handle linear velocity | ||
241 | for (j = 0; j < 3; j++) | ||
242 | b->posr.pos[j] += h * b->lvel[j]; | ||
243 | |||
244 | if (b->flags & dxBodyFlagFiniteRotation) | ||
245 | { | ||
246 | dVector3 irv; // infitesimal rotation vector | ||
247 | dQuaternion q; // quaternion for finite rotation | ||
248 | |||
249 | if (b->flags & dxBodyFlagFiniteRotationAxis) | ||
250 | { | ||
251 | // split the angular velocity vector into a component along the finite | ||
252 | // rotation axis, and a component orthogonal to it. | ||
253 | dVector3 frv, irv; // finite rotation vector | ||
254 | dReal k = dDOT (b->finite_rot_axis, b->avel); | ||
255 | frv[0] = b->finite_rot_axis[0] * k; | ||
256 | frv[1] = b->finite_rot_axis[1] * k; | ||
257 | frv[2] = b->finite_rot_axis[2] * k; | ||
258 | irv[0] = b->avel[0] - frv[0]; | ||
259 | irv[1] = b->avel[1] - frv[1]; | ||
260 | irv[2] = b->avel[2] - frv[2]; | ||
261 | |||
262 | // make a rotation quaternion q that corresponds to frv * h. | ||
263 | // compare this with the full-finite-rotation case below. | ||
264 | h *= REAL (0.5); | ||
265 | dReal theta = k * h; | ||
266 | q[0] = dCos (theta); | ||
267 | dReal s = sinc (theta) * h; | ||
268 | q[1] = frv[0] * s; | ||
269 | q[2] = frv[1] * s; | ||
270 | q[3] = frv[2] * s; | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | // make a rotation quaternion q that corresponds to w * h | ||
275 | dReal wlen = dSqrt (b->avel[0] * b->avel[0] + b->avel[1] * b->avel[1] + b->avel[2] * b->avel[2]); | ||
276 | h *= REAL (0.5); | ||
277 | dReal theta = wlen * h; | ||
278 | q[0] = dCos (theta); | ||
279 | dReal s = sinc (theta) * h; | ||
280 | q[1] = b->avel[0] * s; | ||
281 | q[2] = b->avel[1] * s; | ||
282 | q[3] = b->avel[2] * s; | ||
283 | } | ||
284 | |||
285 | // do the finite rotation | ||
286 | dQuaternion q2; | ||
287 | dQMultiply0 (q2, q, b->q); | ||
288 | for (j = 0; j < 4; j++) | ||
289 | b->q[j] = q2[j]; | ||
290 | |||
291 | // do the infitesimal rotation if required | ||
292 | if (b->flags & dxBodyFlagFiniteRotationAxis) | ||
293 | { | ||
294 | dReal dq[4]; | ||
295 | dWtoDQ (irv, b->q, dq); | ||
296 | for (j = 0; j < 4; j++) | ||
297 | b->q[j] += h * dq[j]; | ||
298 | } | ||
299 | } | ||
300 | else | ||
301 | { | ||
302 | // the normal way - do an infitesimal rotation | ||
303 | dReal dq[4]; | ||
304 | dWtoDQ (b->avel, b->q, dq); | ||
305 | for (j = 0; j < 4; j++) | ||
306 | b->q[j] += h * dq[j]; | ||
307 | } | ||
308 | |||
309 | // normalize the quaternion and convert it to a rotation matrix | ||
310 | dNormalize4 (b->q); | ||
311 | dQtoR (b->q, b->posr.R); | ||
312 | |||
313 | // notify all attached geoms that this body has moved | ||
314 | for (dxGeom * geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) | ||
315 | dGeomMoved (geom); | ||
316 | } | ||
317 | |||
318 | //**************************************************************************** | ||
319 | //This is an implementation of the iterated/relaxation algorithm. | ||
320 | //Here is a quick overview of the algorithm per Sergi Valverde's posts to the | ||
321 | //mailing list: | ||
322 | // | ||
323 | // for i=0..N-1 do | ||
324 | // for c = 0..C-1 do | ||
325 | // Solve constraint c-th | ||
326 | // Apply forces to constraint bodies | ||
327 | // next | ||
328 | // next | ||
329 | // Integrate bodies | ||
330 | |||
331 | void | ||
332 | dInternalStepFast (dxWorld * world, dxBody * body[2], dReal * GI[2], dReal * GinvI[2], dxJoint * joint, dxJoint::Info1 info, dxJoint::Info2 Jinfo, dReal stepsize) | ||
333 | { | ||
334 | int i, j, k; | ||
335 | # ifdef TIMING | ||
336 | dTimerNow ("constraint preprocessing"); | ||
337 | # endif | ||
338 | |||
339 | dReal stepsize1 = dRecip (stepsize); | ||
340 | |||
341 | int m = info.m; | ||
342 | // nothing to do if no constraints. | ||
343 | if (m <= 0) | ||
344 | return; | ||
345 | |||
346 | int nub = 0; | ||
347 | if (info.nub == info.m) | ||
348 | nub = m; | ||
349 | |||
350 | // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same | ||
351 | // format as J so we just go through the constraints in J multiplying by | ||
352 | // the appropriate scalars and matrices. | ||
353 | # ifdef TIMING | ||
354 | dTimerNow ("compute A"); | ||
355 | # endif | ||
356 | dReal JinvM[2 * 6 * 8]; | ||
357 | //dSetZero (JinvM, 2 * m * 8); | ||
358 | |||
359 | dReal *Jsrc = Jinfo.J1l; | ||
360 | dReal *Jdst = JinvM; | ||
361 | if (body[0]) | ||
362 | { | ||
363 | for (j = m - 1; j >= 0; j--) | ||
364 | { | ||
365 | for (k = 0; k < 3; k++) | ||
366 | Jdst[k] = Jsrc[k] * body[0]->invMass; | ||
367 | dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[0]); | ||
368 | Jsrc += 8; | ||
369 | Jdst += 8; | ||
370 | } | ||
371 | } | ||
372 | if (body[1]) | ||
373 | { | ||
374 | Jsrc = Jinfo.J2l; | ||
375 | Jdst = JinvM + 8 * m; | ||
376 | for (j = m - 1; j >= 0; j--) | ||
377 | { | ||
378 | for (k = 0; k < 3; k++) | ||
379 | Jdst[k] = Jsrc[k] * body[1]->invMass; | ||
380 | dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[1]); | ||
381 | Jsrc += 8; | ||
382 | Jdst += 8; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | |||
387 | // now compute A = JinvM * J'. | ||
388 | int mskip = dPAD (m); | ||
389 | dReal A[6 * 8]; | ||
390 | //dSetZero (A, 6 * 8); | ||
391 | |||
392 | if (body[0]) { | ||
393 | Multiply2_sym_p8p (A, JinvM, Jinfo.J1l, m, mskip); | ||
394 | if (body[1]) | ||
395 | MultiplyAdd2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, | ||
396 | m, mskip); | ||
397 | } else { | ||
398 | if (body[1]) | ||
399 | Multiply2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, | ||
400 | m, mskip); | ||
401 | } | ||
402 | |||
403 | // add cfm to the diagonal of A | ||
404 | for (i = 0; i < m; i++) | ||
405 | A[i * mskip + i] += Jinfo.cfm[i] * stepsize1; | ||
406 | |||
407 | // compute the right hand side `rhs' | ||
408 | # ifdef TIMING | ||
409 | dTimerNow ("compute rhs"); | ||
410 | # endif | ||
411 | dReal tmp1[16]; | ||
412 | //dSetZero (tmp1, 16); | ||
413 | // put v/h + invM*fe into tmp1 | ||
414 | for (i = 0; i < 2; i++) | ||
415 | { | ||
416 | if (!body[i]) | ||
417 | continue; | ||
418 | for (j = 0; j < 3; j++) | ||
419 | tmp1[i * 8 + j] = body[i]->facc[j] * body[i]->invMass + body[i]->lvel[j] * stepsize1; | ||
420 | dMULTIPLY0_331 (tmp1 + i * 8 + 4, GinvI[i], body[i]->tacc); | ||
421 | for (j = 0; j < 3; j++) | ||
422 | tmp1[i * 8 + 4 + j] += body[i]->avel[j] * stepsize1; | ||
423 | } | ||
424 | // put J*tmp1 into rhs | ||
425 | dReal rhs[6]; | ||
426 | //dSetZero (rhs, 6); | ||
427 | |||
428 | if (body[0]) { | ||
429 | Multiply0_p81 (rhs, Jinfo.J1l, tmp1, m); | ||
430 | if (body[1]) | ||
431 | MultiplyAdd0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); | ||
432 | } else { | ||
433 | if (body[1]) | ||
434 | Multiply0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); | ||
435 | } | ||
436 | |||
437 | // complete rhs | ||
438 | for (i = 0; i < m; i++) | ||
439 | rhs[i] = Jinfo.c[i] * stepsize1 - rhs[i]; | ||
440 | |||
441 | #ifdef SLOW_LCP | ||
442 | // solve the LCP problem and get lambda. | ||
443 | // this will destroy A but that's okay | ||
444 | # ifdef TIMING | ||
445 | dTimerNow ("solving LCP problem"); | ||
446 | # endif | ||
447 | dReal *lambda = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
448 | dReal *residual = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
449 | dReal lo[6], hi[6]; | ||
450 | memcpy (lo, Jinfo.lo, m * sizeof (dReal)); | ||
451 | memcpy (hi, Jinfo.hi, m * sizeof (dReal)); | ||
452 | dSolveLCP (m, A, lambda, rhs, residual, nub, lo, hi, Jinfo.findex); | ||
453 | #endif | ||
454 | |||
455 | // LCP Solver replacement: | ||
456 | // This algorithm goes like this: | ||
457 | // Do a straightforward LDLT factorization of the matrix A, solving for | ||
458 | // A*x = rhs | ||
459 | // For each x[i] that is outside of the bounds of lo[i] and hi[i], | ||
460 | // clamp x[i] into that range. | ||
461 | // Substitute into A the now known x's | ||
462 | // subtract the residual away from the rhs. | ||
463 | // Remove row and column i from L, updating the factorization | ||
464 | // place the known x's at the end of the array, keeping up with location in p | ||
465 | // Repeat until all constraints have been clamped or all are within bounds | ||
466 | // | ||
467 | // This is probably only faster in the single joint case where only one repeat is | ||
468 | // the norm. | ||
469 | |||
470 | #ifdef FAST_FACTOR | ||
471 | // factorize A (L*D*L'=A) | ||
472 | # ifdef TIMING | ||
473 | dTimerNow ("factorize A"); | ||
474 | # endif | ||
475 | dReal d[6]; | ||
476 | dReal L[6 * 8]; | ||
477 | memcpy (L, A, m * mskip * sizeof (dReal)); | ||
478 | dFactorLDLT (L, d, m, mskip); | ||
479 | |||
480 | // compute lambda | ||
481 | # ifdef TIMING | ||
482 | dTimerNow ("compute lambda"); | ||
483 | # endif | ||
484 | |||
485 | int left = m; //constraints left to solve. | ||
486 | int remove[6]; | ||
487 | dReal lambda[6]; | ||
488 | dReal x[6]; | ||
489 | int p[6]; | ||
490 | for (i = 0; i < 6; i++) | ||
491 | p[i] = i; | ||
492 | while (true) | ||
493 | { | ||
494 | memcpy (x, rhs, left * sizeof (dReal)); | ||
495 | dSolveLDLT (L, d, x, left, mskip); | ||
496 | |||
497 | int fixed = 0; | ||
498 | for (i = 0; i < left; i++) | ||
499 | { | ||
500 | j = p[i]; | ||
501 | remove[i] = false; | ||
502 | // This isn't the exact same use of findex as dSolveLCP.... since x[findex] | ||
503 | // may change after I've already clamped x[i], but it should be close | ||
504 | if (Jinfo.findex[j] > -1) | ||
505 | { | ||
506 | dReal f = fabs (Jinfo.hi[j] * x[p[Jinfo.findex[j]]]); | ||
507 | if (x[i] > f) | ||
508 | x[i] = f; | ||
509 | else if (x[i] < -f) | ||
510 | x[i] = -f; | ||
511 | else | ||
512 | continue; | ||
513 | } | ||
514 | else | ||
515 | { | ||
516 | if (x[i] > Jinfo.hi[j]) | ||
517 | x[i] = Jinfo.hi[j]; | ||
518 | else if (x[i] < Jinfo.lo[j]) | ||
519 | x[i] = Jinfo.lo[j]; | ||
520 | else | ||
521 | continue; | ||
522 | } | ||
523 | remove[i] = true; | ||
524 | fixed++; | ||
525 | } | ||
526 | if (fixed == 0 || fixed == left) //no change or all constraints solved | ||
527 | break; | ||
528 | |||
529 | for (i = 0; i < left; i++) //sub in to right hand side. | ||
530 | if (remove[i]) | ||
531 | for (j = 0; j < left; j++) | ||
532 | if (!remove[j]) | ||
533 | rhs[j] -= A[j * mskip + i] * x[i]; | ||
534 | |||
535 | for (int r = left - 1; r >= 0; r--) //eliminate row/col for fixed variables | ||
536 | { | ||
537 | if (remove[r]) | ||
538 | { | ||
539 | //dRemoveLDLT adapted for use without row pointers. | ||
540 | if (r == left - 1) | ||
541 | { | ||
542 | left--; | ||
543 | continue; // deleting last row/col is easy | ||
544 | } | ||
545 | else if (r == 0) | ||
546 | { | ||
547 | dReal a[6]; | ||
548 | for (i = 0; i < left; i++) | ||
549 | a[i] = -A[i * mskip]; | ||
550 | a[0] += REAL (1.0); | ||
551 | dLDLTAddTL (L, d, a, left, mskip); | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | dReal t[6]; | ||
556 | dReal a[6]; | ||
557 | for (i = 0; i < r; i++) | ||
558 | t[i] = L[r * mskip + i] / d[i]; | ||
559 | for (i = 0; i < left - r; i++) | ||
560 | a[i] = dDot (L + (r + i) * mskip, t, r) - A[(r + i) * mskip + r]; | ||
561 | a[0] += REAL (1.0); | ||
562 | dLDLTAddTL (L + r * mskip + r, d + r, a, left - r, mskip); | ||
563 | } | ||
564 | |||
565 | dRemoveRowCol (L, left, mskip, r); | ||
566 | //end dRemoveLDLT | ||
567 | |||
568 | left--; | ||
569 | if (r < (left - 1)) | ||
570 | { | ||
571 | dReal tx = x[r]; | ||
572 | memmove (d + r, d + r + 1, (left - r) * sizeof (dReal)); | ||
573 | memmove (rhs + r, rhs + r + 1, (left - r) * sizeof (dReal)); | ||
574 | //x will get written over by rhs anyway, no need to move it around | ||
575 | //just store the fixed value we just discovered in it. | ||
576 | x[left] = tx; | ||
577 | for (i = 0; i < m; i++) | ||
578 | if (p[i] > r && p[i] <= left) | ||
579 | p[i]--; | ||
580 | p[r] = left; | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | for (i = 0; i < m; i++) | ||
587 | lambda[i] = x[p[i]]; | ||
588 | # endif | ||
589 | // compute the constraint force `cforce' | ||
590 | # ifdef TIMING | ||
591 | dTimerNow ("compute constraint force"); | ||
592 | #endif | ||
593 | |||
594 | // compute cforce = J'*lambda | ||
595 | dJointFeedback *fb = joint->feedback; | ||
596 | dReal cforce[16]; | ||
597 | //dSetZero (cforce, 16); | ||
598 | |||
599 | if (fb) | ||
600 | { | ||
601 | // the user has requested feedback on the amount of force that this | ||
602 | // joint is applying to the bodies. we use a slightly slower | ||
603 | // computation that splits out the force components and puts them | ||
604 | // in the feedback structure. | ||
605 | dReal data1[8], data2[8]; | ||
606 | if (body[0]) | ||
607 | { | ||
608 | Multiply1_8q1 (data1, Jinfo.J1l, lambda, m); | ||
609 | dReal *cf1 = cforce; | ||
610 | cf1[0] = (fb->f1[0] = data1[0]); | ||
611 | cf1[1] = (fb->f1[1] = data1[1]); | ||
612 | cf1[2] = (fb->f1[2] = data1[2]); | ||
613 | cf1[4] = (fb->t1[0] = data1[4]); | ||
614 | cf1[5] = (fb->t1[1] = data1[5]); | ||
615 | cf1[6] = (fb->t1[2] = data1[6]); | ||
616 | } | ||
617 | if (body[1]) | ||
618 | { | ||
619 | Multiply1_8q1 (data2, Jinfo.J2l, lambda, m); | ||
620 | dReal *cf2 = cforce + 8; | ||
621 | cf2[0] = (fb->f2[0] = data2[0]); | ||
622 | cf2[1] = (fb->f2[1] = data2[1]); | ||
623 | cf2[2] = (fb->f2[2] = data2[2]); | ||
624 | cf2[4] = (fb->t2[0] = data2[4]); | ||
625 | cf2[5] = (fb->t2[1] = data2[5]); | ||
626 | cf2[6] = (fb->t2[2] = data2[6]); | ||
627 | } | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | // no feedback is required, let's compute cforce the faster way | ||
632 | if (body[0]) | ||
633 | Multiply1_8q1 (cforce, Jinfo.J1l, lambda, m); | ||
634 | if (body[1]) | ||
635 | Multiply1_8q1 (cforce + 8, Jinfo.J2l, lambda, m); | ||
636 | } | ||
637 | |||
638 | for (i = 0; i < 2; i++) | ||
639 | { | ||
640 | if (!body[i]) | ||
641 | continue; | ||
642 | for (j = 0; j < 3; j++) | ||
643 | { | ||
644 | body[i]->facc[j] += cforce[i * 8 + j]; | ||
645 | body[i]->tacc[j] += cforce[i * 8 + 4 + j]; | ||
646 | } | ||
647 | } | ||
648 | } | ||
649 | |||
650 | void | ||
651 | dInternalStepIslandFast (dxWorld * world, dxBody * const *bodies, int nb, dxJoint * const *_joints, int nj, dReal stepsize, int maxiterations) | ||
652 | { | ||
653 | # ifdef TIMING | ||
654 | dTimerNow ("preprocessing"); | ||
655 | # endif | ||
656 | dxBody *bodyPair[2], *body; | ||
657 | dReal *GIPair[2], *GinvIPair[2]; | ||
658 | dxJoint *joint; | ||
659 | int iter, b, j, i; | ||
660 | dReal ministep = stepsize / maxiterations; | ||
661 | |||
662 | // make a local copy of the joint array, because we might want to modify it. | ||
663 | // (the "dxJoint *const*" declaration says we're allowed to modify the joints | ||
664 | // but not the joint array, because the caller might need it unchanged). | ||
665 | dxJoint **joints = (dxJoint **) ALLOCA (nj * sizeof (dxJoint *)); | ||
666 | memcpy (joints, _joints, nj * sizeof (dxJoint *)); | ||
667 | |||
668 | // get m = total constraint dimension, nub = number of unbounded variables. | ||
669 | // create constraint offset array and number-of-rows array for all joints. | ||
670 | // the constraints are re-ordered as follows: the purely unbounded | ||
671 | // constraints, the mixed unbounded + LCP constraints, and last the purely | ||
672 | // LCP constraints. this assists the LCP solver to put all unbounded | ||
673 | // variables at the start for a quick factorization. | ||
674 | // | ||
675 | // joints with m=0 are inactive and are removed from the joints array | ||
676 | // entirely, so that the code that follows does not consider them. | ||
677 | // also number all active joints in the joint list (set their tag values). | ||
678 | // inactive joints receive a tag value of -1. | ||
679 | |||
680 | int m = 0; | ||
681 | dxJoint::Info1 * info = (dxJoint::Info1 *) ALLOCA (nj * sizeof (dxJoint::Info1)); | ||
682 | int *ofs = (int *) ALLOCA (nj * sizeof (int)); | ||
683 | for (i = 0, j = 0; j < nj; j++) | ||
684 | { // i=dest, j=src | ||
685 | joints[j]->vtable->getInfo1 (joints[j], info + i); | ||
686 | dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); | ||
687 | if (info[i].m > 0) | ||
688 | { | ||
689 | joints[i] = joints[j]; | ||
690 | joints[i]->tag = i; | ||
691 | i++; | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | joints[j]->tag = -1; | ||
696 | } | ||
697 | } | ||
698 | nj = i; | ||
699 | |||
700 | // the purely unbounded constraints | ||
701 | for (i = 0; i < nj; i++) | ||
702 | { | ||
703 | ofs[i] = m; | ||
704 | m += info[i].m; | ||
705 | } | ||
706 | dReal *c = NULL; | ||
707 | dReal *cfm = NULL; | ||
708 | dReal *lo = NULL; | ||
709 | dReal *hi = NULL; | ||
710 | int *findex = NULL; | ||
711 | |||
712 | dReal *J = NULL; | ||
713 | dxJoint::Info2 * Jinfo = NULL; | ||
714 | |||
715 | if (m) | ||
716 | { | ||
717 | // create a constraint equation right hand side vector `c', a constraint | ||
718 | // force mixing vector `cfm', and LCP low and high bound vectors, and an | ||
719 | // 'findex' vector. | ||
720 | c = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
721 | cfm = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
722 | lo = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
723 | hi = (dReal *) ALLOCA (m * sizeof (dReal)); | ||
724 | findex = (int *) ALLOCA (m * sizeof (int)); | ||
725 | dSetZero (c, m); | ||
726 | dSetValue (cfm, m, world->global_cfm); | ||
727 | dSetValue (lo, m, -dInfinity); | ||
728 | dSetValue (hi, m, dInfinity); | ||
729 | for (i = 0; i < m; i++) | ||
730 | findex[i] = -1; | ||
731 | |||
732 | // get jacobian data from constraints. a (2*m)x8 matrix will be created | ||
733 | // to store the two jacobian blocks from each constraint. it has this | ||
734 | // format: | ||
735 | // | ||
736 | // l l l 0 a a a 0 \ . | ||
737 | // l l l 0 a a a 0 }-- jacobian body 1 block for joint 0 (3 rows) | ||
738 | // l l l 0 a a a 0 / | ||
739 | // l l l 0 a a a 0 \ . | ||
740 | // l l l 0 a a a 0 }-- jacobian body 2 block for joint 0 (3 rows) | ||
741 | // l l l 0 a a a 0 / | ||
742 | // l l l 0 a a a 0 }--- jacobian body 1 block for joint 1 (1 row) | ||
743 | // l l l 0 a a a 0 }--- jacobian body 2 block for joint 1 (1 row) | ||
744 | // etc... | ||
745 | // | ||
746 | // (lll) = linear jacobian data | ||
747 | // (aaa) = angular jacobian data | ||
748 | // | ||
749 | # ifdef TIMING | ||
750 | dTimerNow ("create J"); | ||
751 | # endif | ||
752 | J = (dReal *) ALLOCA (2 * m * 8 * sizeof (dReal)); | ||
753 | dSetZero (J, 2 * m * 8); | ||
754 | Jinfo = (dxJoint::Info2 *) ALLOCA (nj * sizeof (dxJoint::Info2)); | ||
755 | for (i = 0; i < nj; i++) | ||
756 | { | ||
757 | Jinfo[i].rowskip = 8; | ||
758 | Jinfo[i].fps = dRecip (stepsize); | ||
759 | Jinfo[i].erp = world->global_erp; | ||
760 | Jinfo[i].J1l = J + 2 * 8 * ofs[i]; | ||
761 | Jinfo[i].J1a = Jinfo[i].J1l + 4; | ||
762 | Jinfo[i].J2l = Jinfo[i].J1l + 8 * info[i].m; | ||
763 | Jinfo[i].J2a = Jinfo[i].J2l + 4; | ||
764 | Jinfo[i].c = c + ofs[i]; | ||
765 | Jinfo[i].cfm = cfm + ofs[i]; | ||
766 | Jinfo[i].lo = lo + ofs[i]; | ||
767 | Jinfo[i].hi = hi + ofs[i]; | ||
768 | Jinfo[i].findex = findex + ofs[i]; | ||
769 | //joints[i]->vtable->getInfo2 (joints[i], Jinfo+i); | ||
770 | } | ||
771 | |||
772 | } | ||
773 | |||
774 | dReal *saveFacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); | ||
775 | dReal *saveTacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); | ||
776 | dReal *globalI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); | ||
777 | dReal *globalInvI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); | ||
778 | for (b = 0; b < nb; b++) | ||
779 | { | ||
780 | for (i = 0; i < 4; i++) | ||
781 | { | ||
782 | saveFacc[b * 4 + i] = bodies[b]->facc[i]; | ||
783 | saveTacc[b * 4 + i] = bodies[b]->tacc[i]; | ||
784 | } | ||
785 | bodies[b]->tag = b; | ||
786 | } | ||
787 | |||
788 | for (iter = 0; iter < maxiterations; iter++) | ||
789 | { | ||
790 | # ifdef TIMING | ||
791 | dTimerNow ("applying inertia and gravity"); | ||
792 | # endif | ||
793 | dReal tmp[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
794 | |||
795 | for (b = 0; b < nb; b++) | ||
796 | { | ||
797 | body = bodies[b]; | ||
798 | |||
799 | // for all bodies, compute the inertia tensor and its inverse in the global | ||
800 | // frame, and compute the rotational force and add it to the torque | ||
801 | // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. | ||
802 | // @@@ check computation of rotational force. | ||
803 | |||
804 | // compute inertia tensor in global frame | ||
805 | dMULTIPLY2_333 (tmp, body->mass.I, body->posr.R); | ||
806 | dMULTIPLY0_333 (globalI + b * 12, body->posr.R, tmp); | ||
807 | // compute inverse inertia tensor in global frame | ||
808 | dMULTIPLY2_333 (tmp, body->invI, body->posr.R); | ||
809 | dMULTIPLY0_333 (globalInvI + b * 12, body->posr.R, tmp); | ||
810 | |||
811 | for (i = 0; i < 4; i++) | ||
812 | body->tacc[i] = saveTacc[b * 4 + i]; | ||
813 | #ifdef dGYROSCOPIC | ||
814 | // compute rotational force | ||
815 | dMULTIPLY0_331 (tmp, globalI + b * 12, body->avel); | ||
816 | dCROSS (body->tacc, -=, body->avel, tmp); | ||
817 | #endif | ||
818 | |||
819 | // add the gravity force to all bodies | ||
820 | if ((body->flags & dxBodyNoGravity) == 0) | ||
821 | { | ||
822 | body->facc[0] = saveFacc[b * 4 + 0] + body->mass.mass * world->gravity[0]; | ||
823 | body->facc[1] = saveFacc[b * 4 + 1] + body->mass.mass * world->gravity[1]; | ||
824 | body->facc[2] = saveFacc[b * 4 + 2] + body->mass.mass * world->gravity[2]; | ||
825 | body->facc[3] = 0; | ||
826 | } else { | ||
827 | body->facc[0] = saveFacc[b * 4 + 0]; | ||
828 | body->facc[1] = saveFacc[b * 4 + 1]; | ||
829 | body->facc[2] = saveFacc[b * 4 + 2]; | ||
830 | body->facc[3] = 0; | ||
831 | } | ||
832 | |||
833 | } | ||
834 | |||
835 | #ifdef RANDOM_JOINT_ORDER | ||
836 | #ifdef TIMING | ||
837 | dTimerNow ("randomizing joint order"); | ||
838 | #endif | ||
839 | //randomize the order of the joints by looping through the array | ||
840 | //and swapping the current joint pointer with a random one before it. | ||
841 | for (j = 0; j < nj; j++) | ||
842 | { | ||
843 | joint = joints[j]; | ||
844 | dxJoint::Info1 i1 = info[j]; | ||
845 | dxJoint::Info2 i2 = Jinfo[j]; | ||
846 | const int r = dRandInt(j+1); | ||
847 | dIASSERT (r < nj); | ||
848 | joints[j] = joints[r]; | ||
849 | info[j] = info[r]; | ||
850 | Jinfo[j] = Jinfo[r]; | ||
851 | joints[r] = joint; | ||
852 | info[r] = i1; | ||
853 | Jinfo[r] = i2; | ||
854 | } | ||
855 | #endif | ||
856 | |||
857 | //now iterate through the random ordered joint array we created. | ||
858 | for (j = 0; j < nj; j++) | ||
859 | { | ||
860 | #ifdef TIMING | ||
861 | dTimerNow ("setting up joint"); | ||
862 | #endif | ||
863 | joint = joints[j]; | ||
864 | bodyPair[0] = joint->node[0].body; | ||
865 | bodyPair[1] = joint->node[1].body; | ||
866 | |||
867 | if (bodyPair[0] && (bodyPair[0]->flags & dxBodyDisabled)) | ||
868 | bodyPair[0] = 0; | ||
869 | if (bodyPair[1] && (bodyPair[1]->flags & dxBodyDisabled)) | ||
870 | bodyPair[1] = 0; | ||
871 | |||
872 | //if this joint is not connected to any enabled bodies, skip it. | ||
873 | if (!bodyPair[0] && !bodyPair[1]) | ||
874 | continue; | ||
875 | |||
876 | if (bodyPair[0]) | ||
877 | { | ||
878 | GIPair[0] = globalI + bodyPair[0]->tag * 12; | ||
879 | GinvIPair[0] = globalInvI + bodyPair[0]->tag * 12; | ||
880 | } | ||
881 | if (bodyPair[1]) | ||
882 | { | ||
883 | GIPair[1] = globalI + bodyPair[1]->tag * 12; | ||
884 | GinvIPair[1] = globalInvI + bodyPair[1]->tag * 12; | ||
885 | } | ||
886 | |||
887 | joints[j]->vtable->getInfo2 (joints[j], Jinfo + j); | ||
888 | |||
889 | //dInternalStepIslandFast is an exact copy of the old routine with one | ||
890 | //modification: the calculated forces are added back to the facc and tacc | ||
891 | //vectors instead of applying them to the bodies and moving them. | ||
892 | if (info[j].m > 0) | ||
893 | { | ||
894 | dInternalStepFast (world, bodyPair, GIPair, GinvIPair, joint, info[j], Jinfo[j], ministep); | ||
895 | } | ||
896 | } | ||
897 | // } | ||
898 | # ifdef TIMING | ||
899 | dTimerNow ("moving bodies"); | ||
900 | # endif | ||
901 | //Now we can simulate all the free floating bodies, and move them. | ||
902 | for (b = 0; b < nb; b++) | ||
903 | { | ||
904 | body = bodies[b]; | ||
905 | |||
906 | for (i = 0; i < 4; i++) | ||
907 | { | ||
908 | body->facc[i] *= ministep; | ||
909 | body->tacc[i] *= ministep; | ||
910 | } | ||
911 | |||
912 | //apply torque | ||
913 | dMULTIPLYADD0_331 (body->avel, globalInvI + b * 12, body->tacc); | ||
914 | |||
915 | //apply force | ||
916 | for (i = 0; i < 3; i++) | ||
917 | body->lvel[i] += body->invMass * body->facc[i]; | ||
918 | |||
919 | //move It! | ||
920 | moveAndRotateBody (body, ministep); | ||
921 | } | ||
922 | } | ||
923 | for (b = 0; b < nb; b++) | ||
924 | for (j = 0; j < 4; j++) | ||
925 | bodies[b]->facc[j] = bodies[b]->tacc[j] = 0; | ||
926 | } | ||
927 | |||
928 | |||
929 | #ifdef NO_ISLANDS | ||
930 | |||
931 | // Since the iterative algorithm doesn't care about islands of bodies, this is a | ||
932 | // faster algorithm that just sends it all the joints and bodies in one array. | ||
933 | // It's downfall is it's inability to handle disabled bodies as well as the old one. | ||
934 | static void | ||
935 | processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) | ||
936 | { | ||
937 | // nothing to do if no bodies | ||
938 | if (world->nb <= 0) | ||
939 | return; | ||
940 | |||
941 | dInternalHandleAutoDisabling (world,stepsize); | ||
942 | |||
943 | # ifdef TIMING | ||
944 | dTimerStart ("creating joint and body arrays"); | ||
945 | # endif | ||
946 | dxBody **bodies, *body; | ||
947 | dxJoint **joints, *joint; | ||
948 | joints = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); | ||
949 | bodies = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); | ||
950 | |||
951 | int nj = 0; | ||
952 | for (joint = world->firstjoint; joint; joint = (dxJoint *) joint->next) | ||
953 | joints[nj++] = joint; | ||
954 | |||
955 | int nb = 0; | ||
956 | for (body = world->firstbody; body; body = (dxBody *) body->next) | ||
957 | bodies[nb++] = body; | ||
958 | |||
959 | dInternalStepIslandFast (world, bodies, nb, joints, nj, stepsize, maxiterations); | ||
960 | # ifdef TIMING | ||
961 | dTimerEnd (); | ||
962 | dTimerReport (stdout, 1); | ||
963 | # endif | ||
964 | } | ||
965 | |||
966 | #else | ||
967 | |||
968 | //**************************************************************************** | ||
969 | // island processing | ||
970 | |||
971 | // this groups all joints and bodies in a world into islands. all objects | ||
972 | // in an island are reachable by going through connected bodies and joints. | ||
973 | // each island can be simulated separately. | ||
974 | // note that joints that are not attached to anything will not be included | ||
975 | // in any island, an so they do not affect the simulation. | ||
976 | // | ||
977 | // this function starts new island from unvisited bodies. however, it will | ||
978 | // never start a new islands from a disabled body. thus islands of disabled | ||
979 | // bodies will not be included in the simulation. disabled bodies are | ||
980 | // re-enabled if they are found to be part of an active island. | ||
981 | |||
982 | static void | ||
983 | processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) | ||
984 | { | ||
985 | #ifdef TIMING | ||
986 | dTimerStart ("Island Setup"); | ||
987 | #endif | ||
988 | dxBody *b, *bb, **body; | ||
989 | dxJoint *j, **joint; | ||
990 | |||
991 | // nothing to do if no bodies | ||
992 | if (world->nb <= 0) | ||
993 | return; | ||
994 | |||
995 | dInternalHandleAutoDisabling (world,stepsize); | ||
996 | |||
997 | // make arrays for body and joint lists (for a single island) to go into | ||
998 | body = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); | ||
999 | joint = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); | ||
1000 | int bcount = 0; // number of bodies in `body' | ||
1001 | int jcount = 0; // number of joints in `joint' | ||
1002 | int tbcount = 0; | ||
1003 | int tjcount = 0; | ||
1004 | |||
1005 | // set all body/joint tags to 0 | ||
1006 | for (b = world->firstbody; b; b = (dxBody *) b->next) | ||
1007 | b->tag = 0; | ||
1008 | for (j = world->firstjoint; j; j = (dxJoint *) j->next) | ||
1009 | j->tag = 0; | ||
1010 | |||
1011 | // allocate a stack of unvisited bodies in the island. the maximum size of | ||
1012 | // the stack can be the lesser of the number of bodies or joints, because | ||
1013 | // new bodies are only ever added to the stack by going through untagged | ||
1014 | // joints. all the bodies in the stack must be tagged! | ||
1015 | int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; | ||
1016 | dxBody **stack = (dxBody **) ALLOCA (stackalloc * sizeof (dxBody *)); | ||
1017 | int *autostack = (int *) ALLOCA (stackalloc * sizeof (int)); | ||
1018 | |||
1019 | for (bb = world->firstbody; bb; bb = (dxBody *) bb->next) | ||
1020 | { | ||
1021 | #ifdef TIMING | ||
1022 | dTimerNow ("Island Processing"); | ||
1023 | #endif | ||
1024 | // get bb = the next enabled, untagged body, and tag it | ||
1025 | if (bb->tag || (bb->flags & dxBodyDisabled)) | ||
1026 | continue; | ||
1027 | bb->tag = 1; | ||
1028 | |||
1029 | // tag all bodies and joints starting from bb. | ||
1030 | int stacksize = 0; | ||
1031 | int autoDepth = autoEnableDepth; | ||
1032 | b = bb; | ||
1033 | body[0] = bb; | ||
1034 | bcount = 1; | ||
1035 | jcount = 0; | ||
1036 | goto quickstart; | ||
1037 | while (stacksize > 0) | ||
1038 | { | ||
1039 | b = stack[--stacksize]; // pop body off stack | ||
1040 | autoDepth = autostack[stacksize]; | ||
1041 | body[bcount++] = b; // put body on body list | ||
1042 | quickstart: | ||
1043 | |||
1044 | // traverse and tag all body's joints, add untagged connected bodies | ||
1045 | // to stack | ||
1046 | for (dxJointNode * n = b->firstjoint; n; n = n->next) | ||
1047 | { | ||
1048 | if (!n->joint->tag) | ||
1049 | { | ||
1050 | int thisDepth = autoEnableDepth; | ||
1051 | n->joint->tag = 1; | ||
1052 | joint[jcount++] = n->joint; | ||
1053 | if (n->body && !n->body->tag) | ||
1054 | { | ||
1055 | if (n->body->flags & dxBodyDisabled) | ||
1056 | thisDepth = autoDepth - 1; | ||
1057 | if (thisDepth < 0) | ||
1058 | continue; | ||
1059 | n->body->flags &= ~dxBodyDisabled; | ||
1060 | n->body->tag = 1; | ||
1061 | autostack[stacksize] = thisDepth; | ||
1062 | stack[stacksize++] = n->body; | ||
1063 | } | ||
1064 | } | ||
1065 | } | ||
1066 | dIASSERT (stacksize <= world->nb); | ||
1067 | dIASSERT (stacksize <= world->nj); | ||
1068 | } | ||
1069 | |||
1070 | // now do something with body and joint lists | ||
1071 | dInternalStepIslandFast (world, body, bcount, joint, jcount, stepsize, maxiterations); | ||
1072 | |||
1073 | // what we've just done may have altered the body/joint tag values. | ||
1074 | // we must make sure that these tags are nonzero. | ||
1075 | // also make sure all bodies are in the enabled state. | ||
1076 | int i; | ||
1077 | for (i = 0; i < bcount; i++) | ||
1078 | { | ||
1079 | body[i]->tag = 1; | ||
1080 | body[i]->flags &= ~dxBodyDisabled; | ||
1081 | } | ||
1082 | for (i = 0; i < jcount; i++) | ||
1083 | joint[i]->tag = 1; | ||
1084 | |||
1085 | tbcount += bcount; | ||
1086 | tjcount += jcount; | ||
1087 | } | ||
1088 | |||
1089 | #ifdef TIMING | ||
1090 | dMessage(0, "Total joints processed: %i, bodies: %i", tjcount, tbcount); | ||
1091 | #endif | ||
1092 | |||
1093 | // if debugging, check that all objects (except for disabled bodies, | ||
1094 | // unconnected joints, and joints that are connected to disabled bodies) | ||
1095 | // were tagged. | ||
1096 | # ifndef dNODEBUG | ||
1097 | for (b = world->firstbody; b; b = (dxBody *) b->next) | ||
1098 | { | ||
1099 | if (b->flags & dxBodyDisabled) | ||
1100 | { | ||
1101 | if (b->tag) | ||
1102 | dDebug (0, "disabled body tagged"); | ||
1103 | } | ||
1104 | else | ||
1105 | { | ||
1106 | if (!b->tag) | ||
1107 | dDebug (0, "enabled body not tagged"); | ||
1108 | } | ||
1109 | } | ||
1110 | for (j = world->firstjoint; j; j = (dxJoint *) j->next) | ||
1111 | { | ||
1112 | if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled) == 0) || (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled) == 0)) | ||
1113 | { | ||
1114 | if (!j->tag) | ||
1115 | dDebug (0, "attached enabled joint not tagged"); | ||
1116 | } | ||
1117 | else | ||
1118 | { | ||
1119 | if (j->tag) | ||
1120 | dDebug (0, "unattached or disabled joint tagged"); | ||
1121 | } | ||
1122 | } | ||
1123 | # endif | ||
1124 | |||
1125 | # ifdef TIMING | ||
1126 | dTimerEnd (); | ||
1127 | dTimerReport (stdout, 1); | ||
1128 | # endif | ||
1129 | } | ||
1130 | |||
1131 | #endif | ||
1132 | |||
1133 | |||
1134 | void dWorldStepFast1 (dWorldID w, dReal stepsize, int maxiterations) | ||
1135 | { | ||
1136 | dUASSERT (w, "bad world argument"); | ||
1137 | dUASSERT (stepsize > 0, "stepsize must be > 0"); | ||
1138 | processIslandsFast (w, stepsize, maxiterations); | ||
1139 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/testing.cpp b/libraries/ode-0.9\/ode/src/testing.cpp new file mode 100755 index 0000000..a22f865 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/testing.cpp | |||
@@ -0,0 +1,243 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include <ode/config.h> | ||
24 | #include <ode/misc.h> | ||
25 | #include <ode/memory.h> | ||
26 | #include "testing.h" | ||
27 | |||
28 | #ifdef dDOUBLE | ||
29 | static const dReal tol = 1.0e-9; | ||
30 | #else | ||
31 | static const dReal tol = 1.0e-5f; | ||
32 | #endif | ||
33 | |||
34 | |||
35 | // matrix header on the stack | ||
36 | |||
37 | struct dMatrixComparison::dMatInfo { | ||
38 | int n,m; // size of matrix | ||
39 | char name[128]; // name of the matrix | ||
40 | dReal *data; // matrix data | ||
41 | int size; // size of `data' | ||
42 | }; | ||
43 | |||
44 | |||
45 | |||
46 | dMatrixComparison::dMatrixComparison() | ||
47 | { | ||
48 | afterfirst = 0; | ||
49 | index = 0; | ||
50 | } | ||
51 | |||
52 | |||
53 | dMatrixComparison::~dMatrixComparison() | ||
54 | { | ||
55 | reset(); | ||
56 | } | ||
57 | |||
58 | |||
59 | dReal dMatrixComparison::nextMatrix (dReal *A, int n, int m, int lower_tri, | ||
60 | char *name, ...) | ||
61 | { | ||
62 | if (A==0 || n < 1 || m < 1 || name==0) dDebug (0,"bad args to nextMatrix"); | ||
63 | int num = n*dPAD(m); | ||
64 | |||
65 | if (afterfirst==0) { | ||
66 | dMatInfo *mi = (dMatInfo*) dAlloc (sizeof(dMatInfo)); | ||
67 | mi->n = n; | ||
68 | mi->m = m; | ||
69 | mi->size = num * sizeof(dReal); | ||
70 | mi->data = (dReal*) dAlloc (mi->size); | ||
71 | memcpy (mi->data,A,mi->size); | ||
72 | |||
73 | va_list ap; | ||
74 | va_start (ap,name); | ||
75 | vsprintf (mi->name,name,ap); | ||
76 | if (strlen(mi->name) >= sizeof (mi->name)) dDebug (0,"name too long"); | ||
77 | |||
78 | mat.push (mi); | ||
79 | return 0; | ||
80 | } | ||
81 | else { | ||
82 | if (lower_tri && n != m) | ||
83 | dDebug (0,"dMatrixComparison, lower triangular matrix must be square"); | ||
84 | if (index >= mat.size()) dDebug (0,"dMatrixComparison, too many matrices"); | ||
85 | dMatInfo *mp = mat[index]; | ||
86 | index++; | ||
87 | |||
88 | dMatInfo mi; | ||
89 | va_list ap; | ||
90 | va_start (ap,name); | ||
91 | vsprintf (mi.name,name,ap); | ||
92 | if (strlen(mi.name) >= sizeof (mi.name)) dDebug (0,"name too long"); | ||
93 | |||
94 | if (strcmp(mp->name,mi.name) != 0) | ||
95 | dDebug (0,"dMatrixComparison, name mismatch (\"%s\" and \"%s\")", | ||
96 | mp->name,mi.name); | ||
97 | if (mp->n != n || mp->m != m) | ||
98 | dDebug (0,"dMatrixComparison, size mismatch (%dx%d and %dx%d)", | ||
99 | mp->n,mp->m,n,m); | ||
100 | |||
101 | dReal maxdiff; | ||
102 | if (lower_tri) { | ||
103 | maxdiff = dMaxDifferenceLowerTriangle (A,mp->data,n); | ||
104 | } | ||
105 | else { | ||
106 | maxdiff = dMaxDifference (A,mp->data,n,m); | ||
107 | } | ||
108 | if (maxdiff > tol) | ||
109 | dDebug (0,"dMatrixComparison, matrix error (size=%dx%d, name=\"%s\", " | ||
110 | "error=%.4e)",n,m,mi.name,maxdiff); | ||
111 | return maxdiff; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | |||
116 | void dMatrixComparison::end() | ||
117 | { | ||
118 | if (mat.size() <= 0) dDebug (0,"no matrices in sequence"); | ||
119 | afterfirst = 1; | ||
120 | index = 0; | ||
121 | } | ||
122 | |||
123 | |||
124 | void dMatrixComparison::reset() | ||
125 | { | ||
126 | for (int i=0; i<mat.size(); i++) { | ||
127 | dFree (mat[i]->data,mat[i]->size); | ||
128 | dFree (mat[i],sizeof(dMatInfo)); | ||
129 | } | ||
130 | mat.setSize (0); | ||
131 | afterfirst = 0; | ||
132 | index = 0; | ||
133 | } | ||
134 | |||
135 | |||
136 | void dMatrixComparison::dump() | ||
137 | { | ||
138 | for (int i=0; i<mat.size(); i++) | ||
139 | printf ("%d: %s (%dx%d)\n",i,mat[i]->name,mat[i]->n,mat[i]->m); | ||
140 | } | ||
141 | |||
142 | //**************************************************************************** | ||
143 | // unit test | ||
144 | |||
145 | #include <setjmp.h> | ||
146 | |||
147 | static jmp_buf jump_buffer; | ||
148 | |||
149 | static void myDebug (int num, const char *msg, va_list ap) | ||
150 | { | ||
151 | // printf ("(Error %d: ",num); | ||
152 | // vprintf (msg,ap); | ||
153 | // printf (")\n"); | ||
154 | longjmp (jump_buffer,1); | ||
155 | } | ||
156 | |||
157 | |||
158 | extern "C" ODE_API void dTestMatrixComparison() | ||
159 | { | ||
160 | volatile int i; | ||
161 | printf ("dTestMatrixComparison()\n"); | ||
162 | dMessageFunction *orig_debug = dGetDebugHandler(); | ||
163 | |||
164 | dMatrixComparison mc; | ||
165 | dReal A[50*50]; | ||
166 | |||
167 | // make first sequence | ||
168 | unsigned long seed = dRandGetSeed(); | ||
169 | for (i=1; i<49; i++) { | ||
170 | dMakeRandomMatrix (A,i,i+1,1.0); | ||
171 | mc.nextMatrix (A,i,i+1,0,"A%d",i); | ||
172 | } | ||
173 | mc.end(); | ||
174 | |||
175 | //mc.dump(); | ||
176 | |||
177 | // test identical sequence | ||
178 | dSetDebugHandler (&myDebug); | ||
179 | dRandSetSeed (seed); | ||
180 | if (setjmp (jump_buffer)) { | ||
181 | printf ("\tFAILED (1)\n"); | ||
182 | } | ||
183 | else { | ||
184 | for (i=1; i<49; i++) { | ||
185 | dMakeRandomMatrix (A,i,i+1,1.0); | ||
186 | mc.nextMatrix (A,i,i+1,0,"A%d",i); | ||
187 | } | ||
188 | mc.end(); | ||
189 | printf ("\tpassed (1)\n"); | ||
190 | } | ||
191 | dSetDebugHandler (orig_debug); | ||
192 | |||
193 | // test broken sequences (with matrix error) | ||
194 | dRandSetSeed (seed); | ||
195 | volatile int passcount = 0; | ||
196 | for (i=1; i<49; i++) { | ||
197 | if (setjmp (jump_buffer)) { | ||
198 | passcount++; | ||
199 | } | ||
200 | else { | ||
201 | dSetDebugHandler (&myDebug); | ||
202 | dMakeRandomMatrix (A,i,i+1,1.0); | ||
203 | A[(i-1)*dPAD(i+1)+i] += REAL(0.01); | ||
204 | mc.nextMatrix (A,i,i+1,0,"A%d",i); | ||
205 | dSetDebugHandler (orig_debug); | ||
206 | } | ||
207 | } | ||
208 | mc.end(); | ||
209 | printf ("\t%s (2)\n",(passcount == 48) ? "passed" : "FAILED"); | ||
210 | |||
211 | // test broken sequences (with name error) | ||
212 | dRandSetSeed (seed); | ||
213 | passcount = 0; | ||
214 | for (i=1; i<49; i++) { | ||
215 | if (setjmp (jump_buffer)) { | ||
216 | passcount++; | ||
217 | } | ||
218 | else { | ||
219 | dSetDebugHandler (&myDebug); | ||
220 | dMakeRandomMatrix (A,i,i+1,1.0); | ||
221 | mc.nextMatrix (A,i,i+1,0,"B%d",i); | ||
222 | dSetDebugHandler (orig_debug); | ||
223 | } | ||
224 | } | ||
225 | mc.end(); | ||
226 | printf ("\t%s (3)\n",(passcount == 48) ? "passed" : "FAILED"); | ||
227 | |||
228 | // test identical sequence again | ||
229 | dSetDebugHandler (&myDebug); | ||
230 | dRandSetSeed (seed); | ||
231 | if (setjmp (jump_buffer)) { | ||
232 | printf ("\tFAILED (4)\n"); | ||
233 | } | ||
234 | else { | ||
235 | for (i=1; i<49; i++) { | ||
236 | dMakeRandomMatrix (A,i,i+1,1.0); | ||
237 | mc.nextMatrix (A,i,i+1,0,"A%d",i); | ||
238 | } | ||
239 | mc.end(); | ||
240 | printf ("\tpassed (4)\n"); | ||
241 | } | ||
242 | dSetDebugHandler (orig_debug); | ||
243 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/testing.h b/libraries/ode-0.9\/ode/src/testing.h new file mode 100755 index 0000000..4d19ff3 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/testing.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* stuff used for testing */ | ||
24 | |||
25 | #ifndef _ODE_TESTING_H_ | ||
26 | #define _ODE_TESTING_H_ | ||
27 | |||
28 | #include <ode/common.h> | ||
29 | #include "array.h" | ||
30 | |||
31 | |||
32 | // compare a sequence of named matrices/vectors, i.e. to make sure that two | ||
33 | // different pieces of code are giving the same results. | ||
34 | |||
35 | class dMatrixComparison { | ||
36 | struct dMatInfo; | ||
37 | dArray<dMatInfo*> mat; | ||
38 | int afterfirst,index; | ||
39 | |||
40 | public: | ||
41 | dMatrixComparison(); | ||
42 | ~dMatrixComparison(); | ||
43 | |||
44 | dReal nextMatrix (dReal *A, int n, int m, int lower_tri, char *name, ...); | ||
45 | // add a new n*m matrix A to the sequence. the name of the matrix is given | ||
46 | // by the printf-style arguments (name,...). if this is the first sequence | ||
47 | // then this object will simply record the matrices and return 0. | ||
48 | // if this the second or subsequent sequence then this object will compare | ||
49 | // the matrices with the first sequence, and report any differences. | ||
50 | // the matrix error will be returned. if `lower_tri' is 1 then only the | ||
51 | // lower triangle of the matrix (including the diagonal) will be compared | ||
52 | // (the matrix must be square). | ||
53 | |||
54 | void end(); | ||
55 | // end a sequence. | ||
56 | |||
57 | void reset(); | ||
58 | // restarts the object, so the next sequence will be the first sequence. | ||
59 | |||
60 | void dump(); | ||
61 | // print out info about all the matrices in the sequence | ||
62 | }; | ||
63 | |||
64 | |||
65 | #endif | ||
diff --git a/libraries/ode-0.9\/ode/src/timer.cpp b/libraries/ode-0.9\/ode/src/timer.cpp new file mode 100755 index 0000000..f754bf1 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/timer.cpp | |||
@@ -0,0 +1,421 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | |||
25 | TODO | ||
26 | ---- | ||
27 | |||
28 | * gettimeofday() and the pentium time stamp counter return the real time, | ||
29 | not the process time. fix this somehow! | ||
30 | |||
31 | */ | ||
32 | |||
33 | #include <ode/common.h> | ||
34 | #include <ode/timer.h> | ||
35 | |||
36 | // misc defines | ||
37 | #define ALLOCA dALLOCA16 | ||
38 | |||
39 | //**************************************************************************** | ||
40 | // implementation for windows based on the multimedia performance counter. | ||
41 | |||
42 | #ifdef WIN32 | ||
43 | |||
44 | #include "windows.h" | ||
45 | |||
46 | static inline void getClockCount (unsigned long cc[2]) | ||
47 | { | ||
48 | LARGE_INTEGER a; | ||
49 | QueryPerformanceCounter (&a); | ||
50 | cc[0] = a.LowPart; | ||
51 | cc[1] = a.HighPart; | ||
52 | } | ||
53 | |||
54 | |||
55 | static inline void serialize() | ||
56 | { | ||
57 | } | ||
58 | |||
59 | |||
60 | static inline double loadClockCount (unsigned long cc[2]) | ||
61 | { | ||
62 | LARGE_INTEGER a; | ||
63 | a.LowPart = cc[0]; | ||
64 | a.HighPart = cc[1]; | ||
65 | return double(a.QuadPart); | ||
66 | } | ||
67 | |||
68 | |||
69 | double dTimerResolution() | ||
70 | { | ||
71 | return 1.0/dTimerTicksPerSecond(); | ||
72 | } | ||
73 | |||
74 | |||
75 | double dTimerTicksPerSecond() | ||
76 | { | ||
77 | static int query=0; | ||
78 | static double hz=0.0; | ||
79 | if (!query) { | ||
80 | LARGE_INTEGER a; | ||
81 | QueryPerformanceFrequency (&a); | ||
82 | hz = double(a.QuadPart); | ||
83 | query = 1; | ||
84 | } | ||
85 | return hz; | ||
86 | } | ||
87 | |||
88 | #endif | ||
89 | |||
90 | //**************************************************************************** | ||
91 | // implementation based on the pentium time stamp counter. the timer functions | ||
92 | // can be serializing or non-serializing. serializing will ensure that all | ||
93 | // instructions have executed and data has been written back before the cpu | ||
94 | // time stamp counter is read. the CPUID instruction is used to serialize. | ||
95 | |||
96 | #if defined(PENTIUM) && !defined(WIN32) | ||
97 | |||
98 | // we need to know the clock rate so that the timing function can report | ||
99 | // accurate times. this number only needs to be set accurately if we're | ||
100 | // doing performance tests and care about real-world time numbers - otherwise, | ||
101 | // just ignore this. i have not worked out how to determine this number | ||
102 | // automatically yet. | ||
103 | |||
104 | #define PENTIUM_HZ (500e6) | ||
105 | |||
106 | static inline void getClockCount (unsigned long cc[2]) | ||
107 | { | ||
108 | #ifndef X86_64_SYSTEM | ||
109 | asm volatile ( | ||
110 | "rdtsc\n" | ||
111 | "movl %%eax,(%%esi)\n" | ||
112 | "movl %%edx,4(%%esi)\n" | ||
113 | : : "S" (cc) : "%eax","%edx","cc","memory"); | ||
114 | #else | ||
115 | asm volatile ( | ||
116 | "rdtsc\n" | ||
117 | "movl %%eax,(%%rsi)\n" | ||
118 | "movl %%edx,4(%%rsi)\n" | ||
119 | : : "S" (cc) : "%eax","%edx","cc","memory"); | ||
120 | #endif | ||
121 | } | ||
122 | |||
123 | |||
124 | static inline void serialize() | ||
125 | { | ||
126 | #ifndef X86_64_SYSTEM | ||
127 | asm volatile ( | ||
128 | "mov $0,%%eax\n" | ||
129 | "push %%ebx\n" | ||
130 | "cpuid\n" | ||
131 | "pop %%ebx\n" | ||
132 | : : : "%eax","%ecx","%edx","cc","memory"); | ||
133 | #else | ||
134 | asm volatile ( | ||
135 | "mov $0,%%rax\n" | ||
136 | "push %%rbx\n" | ||
137 | "cpuid\n" | ||
138 | "pop %%rbx\n" | ||
139 | : : : "%rax","%rcx","%rdx","cc","memory"); | ||
140 | #endif | ||
141 | } | ||
142 | |||
143 | |||
144 | static inline double loadClockCount (unsigned long a[2]) | ||
145 | { | ||
146 | double ret; | ||
147 | #ifndef X86_64_SYSTEM | ||
148 | asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : | ||
149 | "cc","memory"); | ||
150 | #else | ||
151 | asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : | ||
152 | "cc","memory"); | ||
153 | #endif | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | |||
158 | double dTimerResolution() | ||
159 | { | ||
160 | return 1.0/PENTIUM_HZ; | ||
161 | } | ||
162 | |||
163 | |||
164 | double dTimerTicksPerSecond() | ||
165 | { | ||
166 | return PENTIUM_HZ; | ||
167 | } | ||
168 | |||
169 | #endif | ||
170 | |||
171 | //**************************************************************************** | ||
172 | // otherwise, do the implementation based on gettimeofday(). | ||
173 | |||
174 | #if !defined(PENTIUM) && !defined(WIN32) | ||
175 | |||
176 | #ifndef macintosh | ||
177 | |||
178 | #include <sys/time.h> | ||
179 | #include <unistd.h> | ||
180 | |||
181 | |||
182 | static inline void getClockCount (unsigned long cc[2]) | ||
183 | { | ||
184 | struct timeval tv; | ||
185 | gettimeofday (&tv,0); | ||
186 | cc[0] = tv.tv_usec; | ||
187 | cc[1] = tv.tv_sec; | ||
188 | } | ||
189 | |||
190 | #else // macintosh | ||
191 | |||
192 | #include <MacTypes.h> | ||
193 | #include <Timer.h> | ||
194 | |||
195 | static inline void getClockCount (unsigned long cc[2]) | ||
196 | { | ||
197 | UnsignedWide ms; | ||
198 | Microseconds (&ms); | ||
199 | cc[1] = ms.lo / 1000000; | ||
200 | cc[0] = ms.lo - ( cc[1] * 1000000 ); | ||
201 | } | ||
202 | |||
203 | #endif | ||
204 | |||
205 | |||
206 | static inline void serialize() | ||
207 | { | ||
208 | } | ||
209 | |||
210 | |||
211 | static inline double loadClockCount (unsigned long a[2]) | ||
212 | { | ||
213 | return a[1]*1.0e6 + a[0]; | ||
214 | } | ||
215 | |||
216 | |||
217 | double dTimerResolution() | ||
218 | { | ||
219 | unsigned long cc1[2],cc2[2]; | ||
220 | getClockCount (cc1); | ||
221 | do { | ||
222 | getClockCount (cc2); | ||
223 | } | ||
224 | while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); | ||
225 | do { | ||
226 | getClockCount (cc1); | ||
227 | } | ||
228 | while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); | ||
229 | double t1 = loadClockCount (cc1); | ||
230 | double t2 = loadClockCount (cc2); | ||
231 | return (t1-t2) / dTimerTicksPerSecond(); | ||
232 | } | ||
233 | |||
234 | |||
235 | double dTimerTicksPerSecond() | ||
236 | { | ||
237 | return 1000000; | ||
238 | } | ||
239 | |||
240 | #endif | ||
241 | |||
242 | //**************************************************************************** | ||
243 | // stop watches | ||
244 | |||
245 | void dStopwatchReset (dStopwatch *s) | ||
246 | { | ||
247 | s->time = 0; | ||
248 | s->cc[0] = 0; | ||
249 | s->cc[1] = 0; | ||
250 | } | ||
251 | |||
252 | |||
253 | void dStopwatchStart (dStopwatch *s) | ||
254 | { | ||
255 | serialize(); | ||
256 | getClockCount (s->cc); | ||
257 | } | ||
258 | |||
259 | |||
260 | void dStopwatchStop (dStopwatch *s) | ||
261 | { | ||
262 | unsigned long cc[2]; | ||
263 | serialize(); | ||
264 | getClockCount (cc); | ||
265 | double t1 = loadClockCount (s->cc); | ||
266 | double t2 = loadClockCount (cc); | ||
267 | s->time += t2-t1; | ||
268 | } | ||
269 | |||
270 | |||
271 | double dStopwatchTime (dStopwatch *s) | ||
272 | { | ||
273 | return s->time / dTimerTicksPerSecond(); | ||
274 | } | ||
275 | |||
276 | //**************************************************************************** | ||
277 | // code timers | ||
278 | |||
279 | // maximum number of events to record | ||
280 | #define MAXNUM 100 | ||
281 | |||
282 | static int num = 0; // number of entries used in event array | ||
283 | static struct { | ||
284 | unsigned long cc[2]; // clock counts | ||
285 | double total_t; // total clocks used in this slot. | ||
286 | double total_p; // total percentage points used in this slot. | ||
287 | int count; // number of times this slot has been updated. | ||
288 | char *description; // pointer to static string | ||
289 | } event[MAXNUM]; | ||
290 | |||
291 | |||
292 | // make sure all slot totals and counts reset to 0 at start | ||
293 | |||
294 | static void initSlots() | ||
295 | { | ||
296 | static int initialized=0; | ||
297 | if (!initialized) { | ||
298 | for (int i=0; i<MAXNUM; i++) { | ||
299 | event[i].count = 0; | ||
300 | event[i].total_t = 0; | ||
301 | event[i].total_p = 0; | ||
302 | } | ||
303 | initialized = 1; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | |||
308 | void dTimerStart (const char *description) | ||
309 | { | ||
310 | initSlots(); | ||
311 | event[0].description = const_cast<char*> (description); | ||
312 | num = 1; | ||
313 | serialize(); | ||
314 | getClockCount (event[0].cc); | ||
315 | } | ||
316 | |||
317 | |||
318 | void dTimerNow (const char *description) | ||
319 | { | ||
320 | if (num < MAXNUM) { | ||
321 | // do not serialize | ||
322 | getClockCount (event[num].cc); | ||
323 | event[num].description = const_cast<char*> (description); | ||
324 | num++; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | |||
329 | void dTimerEnd() | ||
330 | { | ||
331 | if (num < MAXNUM) { | ||
332 | serialize(); | ||
333 | getClockCount (event[num].cc); | ||
334 | event[num].description = "TOTAL"; | ||
335 | num++; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | //**************************************************************************** | ||
340 | // print report | ||
341 | |||
342 | static void fprintDoubleWithPrefix (FILE *f, double a, char *fmt) | ||
343 | { | ||
344 | if (a >= 0.999999) { | ||
345 | fprintf (f,fmt,a); | ||
346 | return; | ||
347 | } | ||
348 | a *= 1000.0; | ||
349 | if (a >= 0.999999) { | ||
350 | fprintf (f,fmt,a); | ||
351 | fprintf (f,"m"); | ||
352 | return; | ||
353 | } | ||
354 | a *= 1000.0; | ||
355 | if (a >= 0.999999) { | ||
356 | fprintf (f,fmt,a); | ||
357 | fprintf (f,"u"); | ||
358 | return; | ||
359 | } | ||
360 | a *= 1000.0; | ||
361 | fprintf (f,fmt,a); | ||
362 | fprintf (f,"n"); | ||
363 | } | ||
364 | |||
365 | |||
366 | void dTimerReport (FILE *fout, int average) | ||
367 | { | ||
368 | int i; | ||
369 | size_t maxl; | ||
370 | double ccunit = 1.0/dTimerTicksPerSecond(); | ||
371 | fprintf (fout,"\nTimer Report ("); | ||
372 | fprintDoubleWithPrefix (fout,ccunit,"%.2f "); | ||
373 | fprintf (fout,"s resolution)\n------------\n"); | ||
374 | if (num < 1) return; | ||
375 | |||
376 | // get maximum description length | ||
377 | maxl = 0; | ||
378 | for (i=0; i<num; i++) { | ||
379 | size_t l = strlen (event[i].description); | ||
380 | if (l > maxl) maxl = l; | ||
381 | } | ||
382 | |||
383 | // calculate total time | ||
384 | double t1 = loadClockCount (event[0].cc); | ||
385 | double t2 = loadClockCount (event[num-1].cc); | ||
386 | double total = t2 - t1; | ||
387 | if (total <= 0) total = 1; | ||
388 | |||
389 | // compute time difference for all slots except the last one. update totals | ||
390 | double *times = (double*) ALLOCA (num * sizeof(double)); | ||
391 | for (i=0; i < (num-1); i++) { | ||
392 | double t1 = loadClockCount (event[i].cc); | ||
393 | double t2 = loadClockCount (event[i+1].cc); | ||
394 | times[i] = t2 - t1; | ||
395 | event[i].count++; | ||
396 | event[i].total_t += times[i]; | ||
397 | event[i].total_p += times[i]/total * 100.0; | ||
398 | } | ||
399 | |||
400 | // print report (with optional averages) | ||
401 | for (i=0; i<num; i++) { | ||
402 | double t,p; | ||
403 | if (i < (num-1)) { | ||
404 | t = times[i]; | ||
405 | p = t/total * 100.0; | ||
406 | } | ||
407 | else { | ||
408 | t = total; | ||
409 | p = 100.0; | ||
410 | } | ||
411 | fprintf (fout,"%-*s %7.2fms %6.2f%%",maxl,event[i].description, | ||
412 | t*ccunit * 1000.0, p); | ||
413 | if (average && i < (num-1)) { | ||
414 | fprintf (fout," (avg %7.2fms %6.2f%%)", | ||
415 | (event[i].total_t / event[i].count)*ccunit * 1000.0, | ||
416 | event[i].total_p / event[i].count); | ||
417 | } | ||
418 | fprintf (fout,"\n"); | ||
419 | } | ||
420 | fprintf (fout,"\n"); | ||
421 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/util.cpp b/libraries/ode-0.9\/ode/src/util.cpp new file mode 100755 index 0000000..c8d6230 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/util.cpp | |||
@@ -0,0 +1,374 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #include "ode/ode.h" | ||
24 | #include "objects.h" | ||
25 | #include "joint.h" | ||
26 | #include "util.h" | ||
27 | |||
28 | #define ALLOCA dALLOCA16 | ||
29 | |||
30 | //**************************************************************************** | ||
31 | // Auto disabling | ||
32 | |||
33 | void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize) | ||
34 | { | ||
35 | dxBody *bb; | ||
36 | for ( bb=world->firstbody; bb; bb=(dxBody*)bb->next ) | ||
37 | { | ||
38 | // don't freeze objects mid-air (patch 1586738) | ||
39 | if ( bb->firstjoint == NULL ) continue; | ||
40 | |||
41 | // nothing to do unless this body is currently enabled and has | ||
42 | // the auto-disable flag set | ||
43 | if ( (bb->flags & (dxBodyAutoDisable|dxBodyDisabled)) != dxBodyAutoDisable ) continue; | ||
44 | |||
45 | // if sampling / threshold testing is disabled, we can never sleep. | ||
46 | if ( bb->adis.average_samples == 0 ) continue; | ||
47 | |||
48 | // | ||
49 | // see if the body is idle | ||
50 | // | ||
51 | |||
52 | #ifndef dNODEBUG | ||
53 | // sanity check | ||
54 | if ( bb->average_counter >= bb->adis.average_samples ) | ||
55 | { | ||
56 | dUASSERT( bb->average_counter < bb->adis.average_samples, "buffer overflow" ); | ||
57 | |||
58 | // something is going wrong, reset the average-calculations | ||
59 | bb->average_ready = 0; // not ready for average calculation | ||
60 | bb->average_counter = 0; // reset the buffer index | ||
61 | } | ||
62 | #endif // dNODEBUG | ||
63 | |||
64 | // sample the linear and angular velocity | ||
65 | bb->average_lvel_buffer[bb->average_counter][0] = bb->lvel[0]; | ||
66 | bb->average_lvel_buffer[bb->average_counter][1] = bb->lvel[1]; | ||
67 | bb->average_lvel_buffer[bb->average_counter][2] = bb->lvel[2]; | ||
68 | bb->average_avel_buffer[bb->average_counter][0] = bb->avel[0]; | ||
69 | bb->average_avel_buffer[bb->average_counter][1] = bb->avel[1]; | ||
70 | bb->average_avel_buffer[bb->average_counter][2] = bb->avel[2]; | ||
71 | bb->average_counter++; | ||
72 | |||
73 | // buffer ready test | ||
74 | if ( bb->average_counter >= bb->adis.average_samples ) | ||
75 | { | ||
76 | bb->average_counter = 0; // fill the buffer from the beginning | ||
77 | bb->average_ready = 1; // this body is ready now for average calculation | ||
78 | } | ||
79 | |||
80 | int idle = 0; // Assume it's in motion unless we have samples to disprove it. | ||
81 | |||
82 | // enough samples? | ||
83 | if ( bb->average_ready ) | ||
84 | { | ||
85 | idle = 1; // Initial assumption: IDLE | ||
86 | |||
87 | // the sample buffers are filled and ready for calculation | ||
88 | dVector3 average_lvel, average_avel; | ||
89 | |||
90 | // Store first velocity samples | ||
91 | average_lvel[0] = bb->average_lvel_buffer[0][0]; | ||
92 | average_avel[0] = bb->average_avel_buffer[0][0]; | ||
93 | average_lvel[1] = bb->average_lvel_buffer[0][1]; | ||
94 | average_avel[1] = bb->average_avel_buffer[0][1]; | ||
95 | average_lvel[2] = bb->average_lvel_buffer[0][2]; | ||
96 | average_avel[2] = bb->average_avel_buffer[0][2]; | ||
97 | |||
98 | // If we're not in "instantaneous mode" | ||
99 | if ( bb->adis.average_samples > 1 ) | ||
100 | { | ||
101 | // add remaining velocities together | ||
102 | for ( unsigned int i = 1; i < bb->adis.average_samples; ++i ) | ||
103 | { | ||
104 | average_lvel[0] += bb->average_lvel_buffer[i][0]; | ||
105 | average_avel[0] += bb->average_avel_buffer[i][0]; | ||
106 | average_lvel[1] += bb->average_lvel_buffer[i][1]; | ||
107 | average_avel[1] += bb->average_avel_buffer[i][1]; | ||
108 | average_lvel[2] += bb->average_lvel_buffer[i][2]; | ||
109 | average_avel[2] += bb->average_avel_buffer[i][2]; | ||
110 | } | ||
111 | |||
112 | // make average | ||
113 | dReal r1 = dReal( 1.0 ) / dReal( bb->adis.average_samples ); | ||
114 | |||
115 | average_lvel[0] *= r1; | ||
116 | average_avel[0] *= r1; | ||
117 | average_lvel[1] *= r1; | ||
118 | average_avel[1] *= r1; | ||
119 | average_lvel[2] *= r1; | ||
120 | average_avel[2] *= r1; | ||
121 | } | ||
122 | |||
123 | // threshold test | ||
124 | dReal av_lspeed, av_aspeed; | ||
125 | av_lspeed = dDOT( average_lvel, average_lvel ); | ||
126 | if ( av_lspeed > bb->adis.linear_average_threshold ) | ||
127 | { | ||
128 | idle = 0; // average linear velocity is too high for idle | ||
129 | } | ||
130 | else | ||
131 | { | ||
132 | av_aspeed = dDOT( average_avel, average_avel ); | ||
133 | if ( av_aspeed > bb->adis.angular_average_threshold ) | ||
134 | { | ||
135 | idle = 0; // average angular velocity is too high for idle | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | |||
140 | // if it's idle, accumulate steps and time. | ||
141 | // these counters won't overflow because this code doesn't run for disabled bodies. | ||
142 | if (idle) { | ||
143 | bb->adis_stepsleft--; | ||
144 | bb->adis_timeleft -= stepsize; | ||
145 | } | ||
146 | else { | ||
147 | // Reset countdowns | ||
148 | bb->adis_stepsleft = bb->adis.idle_steps; | ||
149 | bb->adis_timeleft = bb->adis.idle_time; | ||
150 | } | ||
151 | |||
152 | // disable the body if it's idle for a long enough time | ||
153 | if ( bb->adis_stepsleft <= 0 && bb->adis_timeleft <= 0 ) | ||
154 | { | ||
155 | bb->flags |= dxBodyDisabled; // set the disable flag | ||
156 | |||
157 | // disabling bodies should also include resetting the velocity | ||
158 | // should prevent jittering in big "islands" | ||
159 | bb->lvel[0] = 0; | ||
160 | bb->lvel[1] = 0; | ||
161 | bb->lvel[2] = 0; | ||
162 | bb->avel[0] = 0; | ||
163 | bb->avel[1] = 0; | ||
164 | bb->avel[2] = 0; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | |||
170 | //**************************************************************************** | ||
171 | // body rotation | ||
172 | |||
173 | // return sin(x)/x. this has a singularity at 0 so special handling is needed | ||
174 | // for small arguments. | ||
175 | |||
176 | static inline dReal sinc (dReal x) | ||
177 | { | ||
178 | // if |x| < 1e-4 then use a taylor series expansion. this two term expansion | ||
179 | // is actually accurate to one LS bit within this range if double precision | ||
180 | // is being used - so don't worry! | ||
181 | if (dFabs(x) < 1.0e-4) return REAL(1.0) - x*x*REAL(0.166666666666666666667); | ||
182 | else return dSin(x)/x; | ||
183 | } | ||
184 | |||
185 | |||
186 | // given a body b, apply its linear and angular rotation over the time | ||
187 | // interval h, thereby adjusting its position and orientation. | ||
188 | |||
189 | void dxStepBody (dxBody *b, dReal h) | ||
190 | { | ||
191 | int j; | ||
192 | |||
193 | // handle linear velocity | ||
194 | for (j=0; j<3; j++) b->posr.pos[j] += h * b->lvel[j]; | ||
195 | |||
196 | if (b->flags & dxBodyFlagFiniteRotation) { | ||
197 | dVector3 irv; // infitesimal rotation vector | ||
198 | dQuaternion q; // quaternion for finite rotation | ||
199 | |||
200 | if (b->flags & dxBodyFlagFiniteRotationAxis) { | ||
201 | // split the angular velocity vector into a component along the finite | ||
202 | // rotation axis, and a component orthogonal to it. | ||
203 | dVector3 frv; // finite rotation vector | ||
204 | dReal k = dDOT (b->finite_rot_axis,b->avel); | ||
205 | frv[0] = b->finite_rot_axis[0] * k; | ||
206 | frv[1] = b->finite_rot_axis[1] * k; | ||
207 | frv[2] = b->finite_rot_axis[2] * k; | ||
208 | irv[0] = b->avel[0] - frv[0]; | ||
209 | irv[1] = b->avel[1] - frv[1]; | ||
210 | irv[2] = b->avel[2] - frv[2]; | ||
211 | |||
212 | // make a rotation quaternion q that corresponds to frv * h. | ||
213 | // compare this with the full-finite-rotation case below. | ||
214 | h *= REAL(0.5); | ||
215 | dReal theta = k * h; | ||
216 | q[0] = dCos(theta); | ||
217 | dReal s = sinc(theta) * h; | ||
218 | q[1] = frv[0] * s; | ||
219 | q[2] = frv[1] * s; | ||
220 | q[3] = frv[2] * s; | ||
221 | } | ||
222 | else { | ||
223 | // make a rotation quaternion q that corresponds to w * h | ||
224 | dReal wlen = dSqrt (b->avel[0]*b->avel[0] + b->avel[1]*b->avel[1] + | ||
225 | b->avel[2]*b->avel[2]); | ||
226 | h *= REAL(0.5); | ||
227 | dReal theta = wlen * h; | ||
228 | q[0] = dCos(theta); | ||
229 | dReal s = sinc(theta) * h; | ||
230 | q[1] = b->avel[0] * s; | ||
231 | q[2] = b->avel[1] * s; | ||
232 | q[3] = b->avel[2] * s; | ||
233 | } | ||
234 | |||
235 | // do the finite rotation | ||
236 | dQuaternion q2; | ||
237 | dQMultiply0 (q2,q,b->q); | ||
238 | for (j=0; j<4; j++) b->q[j] = q2[j]; | ||
239 | |||
240 | // do the infitesimal rotation if required | ||
241 | if (b->flags & dxBodyFlagFiniteRotationAxis) { | ||
242 | dReal dq[4]; | ||
243 | dWtoDQ (irv,b->q,dq); | ||
244 | for (j=0; j<4; j++) b->q[j] += h * dq[j]; | ||
245 | } | ||
246 | } | ||
247 | else { | ||
248 | // the normal way - do an infitesimal rotation | ||
249 | dReal dq[4]; | ||
250 | dWtoDQ (b->avel,b->q,dq); | ||
251 | for (j=0; j<4; j++) b->q[j] += h * dq[j]; | ||
252 | } | ||
253 | |||
254 | // normalize the quaternion and convert it to a rotation matrix | ||
255 | dNormalize4 (b->q); | ||
256 | dQtoR (b->q,b->posr.R); | ||
257 | |||
258 | // notify all attached geoms that this body has moved | ||
259 | for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) | ||
260 | dGeomMoved (geom); | ||
261 | } | ||
262 | |||
263 | //**************************************************************************** | ||
264 | // island processing | ||
265 | |||
266 | // this groups all joints and bodies in a world into islands. all objects | ||
267 | // in an island are reachable by going through connected bodies and joints. | ||
268 | // each island can be simulated separately. | ||
269 | // note that joints that are not attached to anything will not be included | ||
270 | // in any island, an so they do not affect the simulation. | ||
271 | // | ||
272 | // this function starts new island from unvisited bodies. however, it will | ||
273 | // never start a new islands from a disabled body. thus islands of disabled | ||
274 | // bodies will not be included in the simulation. disabled bodies are | ||
275 | // re-enabled if they are found to be part of an active island. | ||
276 | |||
277 | void dxProcessIslands (dxWorld *world, dReal stepsize, dstepper_fn_t stepper) | ||
278 | { | ||
279 | dxBody *b,*bb,**body; | ||
280 | dxJoint *j,**joint; | ||
281 | |||
282 | // nothing to do if no bodies | ||
283 | if (world->nb <= 0) return; | ||
284 | |||
285 | // handle auto-disabling of bodies | ||
286 | dInternalHandleAutoDisabling (world,stepsize); | ||
287 | |||
288 | // make arrays for body and joint lists (for a single island) to go into | ||
289 | body = (dxBody**) ALLOCA (world->nb * sizeof(dxBody*)); | ||
290 | joint = (dxJoint**) ALLOCA (world->nj * sizeof(dxJoint*)); | ||
291 | int bcount = 0; // number of bodies in `body' | ||
292 | int jcount = 0; // number of joints in `joint' | ||
293 | |||
294 | // set all body/joint tags to 0 | ||
295 | for (b=world->firstbody; b; b=(dxBody*)b->next) b->tag = 0; | ||
296 | for (j=world->firstjoint; j; j=(dxJoint*)j->next) j->tag = 0; | ||
297 | |||
298 | // allocate a stack of unvisited bodies in the island. the maximum size of | ||
299 | // the stack can be the lesser of the number of bodies or joints, because | ||
300 | // new bodies are only ever added to the stack by going through untagged | ||
301 | // joints. all the bodies in the stack must be tagged! | ||
302 | int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; | ||
303 | dxBody **stack = (dxBody**) ALLOCA (stackalloc * sizeof(dxBody*)); | ||
304 | |||
305 | for (bb=world->firstbody; bb; bb=(dxBody*)bb->next) { | ||
306 | // get bb = the next enabled, untagged body, and tag it | ||
307 | if (bb->tag || (bb->flags & dxBodyDisabled)) continue; | ||
308 | bb->tag = 1; | ||
309 | |||
310 | // tag all bodies and joints starting from bb. | ||
311 | int stacksize = 0; | ||
312 | b = bb; | ||
313 | body[0] = bb; | ||
314 | bcount = 1; | ||
315 | jcount = 0; | ||
316 | goto quickstart; | ||
317 | while (stacksize > 0) { | ||
318 | b = stack[--stacksize]; // pop body off stack | ||
319 | body[bcount++] = b; // put body on body list | ||
320 | quickstart: | ||
321 | |||
322 | // traverse and tag all body's joints, add untagged connected bodies | ||
323 | // to stack | ||
324 | for (dxJointNode *n=b->firstjoint; n; n=n->next) { | ||
325 | if (!n->joint->tag) { | ||
326 | n->joint->tag = 1; | ||
327 | joint[jcount++] = n->joint; | ||
328 | if (n->body && !n->body->tag) { | ||
329 | n->body->tag = 1; | ||
330 | stack[stacksize++] = n->body; | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | dIASSERT(stacksize <= world->nb); | ||
335 | dIASSERT(stacksize <= world->nj); | ||
336 | } | ||
337 | |||
338 | // now do something with body and joint lists | ||
339 | stepper (world,body,bcount,joint,jcount,stepsize); | ||
340 | |||
341 | // what we've just done may have altered the body/joint tag values. | ||
342 | // we must make sure that these tags are nonzero. | ||
343 | // also make sure all bodies are in the enabled state. | ||
344 | int i; | ||
345 | for (i=0; i<bcount; i++) { | ||
346 | body[i]->tag = 1; | ||
347 | body[i]->flags &= ~dxBodyDisabled; | ||
348 | } | ||
349 | for (i=0; i<jcount; i++) joint[i]->tag = 1; | ||
350 | } | ||
351 | |||
352 | // if debugging, check that all objects (except for disabled bodies, | ||
353 | // unconnected joints, and joints that are connected to disabled bodies) | ||
354 | // were tagged. | ||
355 | # ifndef dNODEBUG | ||
356 | for (b=world->firstbody; b; b=(dxBody*)b->next) { | ||
357 | if (b->flags & dxBodyDisabled) { | ||
358 | if (b->tag) dDebug (0,"disabled body tagged"); | ||
359 | } | ||
360 | else { | ||
361 | if (!b->tag) dDebug (0,"enabled body not tagged"); | ||
362 | } | ||
363 | } | ||
364 | for (j=world->firstjoint; j; j=(dxJoint*)j->next) { | ||
365 | if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled)==0) || | ||
366 | (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled)==0)) { | ||
367 | if (!j->tag) dDebug (0,"attached enabled joint not tagged"); | ||
368 | } | ||
369 | else { | ||
370 | if (j->tag) dDebug (0,"unattached or disabled joint tagged"); | ||
371 | } | ||
372 | } | ||
373 | # endif | ||
374 | } | ||
diff --git a/libraries/ode-0.9\/ode/src/util.h b/libraries/ode-0.9\/ode/src/util.h new file mode 100755 index 0000000..a8e6390 --- /dev/null +++ b/libraries/ode-0.9\/ode/src/util.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
6 | * This library is free software; you can redistribute it and/or * | ||
7 | * modify it under the terms of EITHER: * | ||
8 | * (1) The GNU Lesser General Public License as published by the Free * | ||
9 | * Software Foundation; either version 2.1 of the License, or (at * | ||
10 | * your option) any later version. The text of the GNU Lesser * | ||
11 | * General Public License is included with this library in the * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
16 | * This library is distributed in the hope that it will be useful, * | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * | ||
19 | * LICENSE.TXT and LICENSE-BSD.TXT for more details. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | #ifndef _ODE_UTIL_H_ | ||
24 | #define _ODE_UTIL_H_ | ||
25 | |||
26 | #include "objects.h" | ||
27 | |||
28 | |||
29 | void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize); | ||
30 | void dxStepBody (dxBody *b, dReal h); | ||
31 | |||
32 | typedef void (*dstepper_fn_t) (dxWorld *world, dxBody * const *body, int nb, | ||
33 | dxJoint * const *_joint, int nj, dReal stepsize); | ||
34 | |||
35 | void dxProcessIslands (dxWorld *world, dReal stepsize, dstepper_fn_t stepper); | ||
36 | |||
37 | |||
38 | #endif | ||