├── LICENSE ├── README.md ├── body.go ├── contact.go ├── example └── chain │ ├── chain.go │ └── chain.qml ├── geom.go ├── heightfield.go ├── joint.go ├── mass.go ├── ode.c ├── ode.go ├── space.go ├── trimesh.go └── world.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ian Remmler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ode 2 | === 3 | 4 | This is a Go binding for the Open Dynamics Engine 3D physics library. It 5 | sticks fairly closely to the development version of the ODE C API, with a few 6 | stylistic and idiomatic changes thrown in here and there where it seemed 7 | useful. 8 | 9 | Get ODE [here](http://bitbucket.org/odedevs/ode/). 10 | 11 | ODE must be compiled as a shared library with double precision support. 12 | Triangle mesh indices are expected to be 32 bit, which is the ODE default. The 13 | following will configure ODE with these options: 14 | 15 | `> cd /path/to/ode-src; ./configure --enable-double-precision --enable-shared` 16 | -------------------------------------------------------------------------------- /body.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | // extern void callMovedCallback(dBodyID body); 5 | import "C" 6 | 7 | import ( 8 | "unsafe" 9 | ) 10 | 11 | var ( 12 | bodyData = map[Body]interface{}{} 13 | movedCallbacks = map[Body]MovedCallback{} 14 | ) 15 | 16 | // Body represents a rigid body. 17 | type Body uintptr 18 | 19 | // MovedCallback is called when the body has moved. 20 | type MovedCallback func(b Body) 21 | 22 | //export movedCallback 23 | func movedCallback(c C.dBodyID) { 24 | body := cToBody(c) 25 | if cb, ok := movedCallbacks[body]; ok { 26 | cb(body) 27 | } 28 | } 29 | 30 | func cToBody(c C.dBodyID) Body { 31 | return Body(unsafe.Pointer(c)) 32 | } 33 | 34 | func (b Body) c() C.dBodyID { 35 | return C.dBodyID(unsafe.Pointer(b)) 36 | } 37 | 38 | // Destroy destroys the body. 39 | func (b Body) Destroy() { 40 | delete(bodyData, b) 41 | C.dBodyDestroy(b.c()) 42 | } 43 | 44 | // SetAutoDisableLinearThreshold sets the auto disable linear average threshold. 45 | func (b Body) SetAutoDisableLinearThreshold(thresh float64) { 46 | C.dBodySetAutoDisableLinearThreshold(b.c(), C.dReal(thresh)) 47 | } 48 | 49 | // AutoDisableLinearThreshold returns the auto disable linear average threshold. 50 | func (b Body) AutoDisableLinearThreshold() float64 { 51 | return float64(C.dBodyGetAutoDisableLinearThreshold(b.c())) 52 | } 53 | 54 | // SetAutoDisableAngularThreshold sets the auto disable angular average threshold. 55 | func (b Body) SetAutoDisableAngularThreshold(thresh float64) { 56 | C.dBodySetAutoDisableAngularThreshold(b.c(), C.dReal(thresh)) 57 | } 58 | 59 | // AutoDisableAngularThreshold returns the auto disable angular average threshold. 60 | func (b Body) AutoDisableAngularThreshold() float64 { 61 | return float64(C.dBodyGetAutoDisableAngularThreshold(b.c())) 62 | } 63 | 64 | // SetAutoAutoDisableAverageSamplesCount sets auto disable average sample count. 65 | func (b Body) SetAutoAutoDisableAverageSamplesCount(count int) { 66 | C.dBodySetAutoDisableAverageSamplesCount(b.c(), C.uint(count)) 67 | } 68 | 69 | // AutoDisableAverageSamplesCount returns the auto disable sample count. 70 | func (b Body) AutoDisableAverageSamplesCount() int { 71 | return int(C.dBodyGetAutoDisableAverageSamplesCount(b.c())) 72 | } 73 | 74 | // SetAutoDisableSteps sets the number of auto disable steps. 75 | func (b Body) SetAutoDisableSteps(steps int) { 76 | C.dBodySetAutoDisableSteps(b.c(), C.int(steps)) 77 | } 78 | 79 | // AutoDisableSteps returns the number of auto disable steps. 80 | func (b Body) AutoDisableSteps() int { 81 | return int(C.dBodyGetAutoDisableSteps(b.c())) 82 | } 83 | 84 | // SetAutoDisableTime sets the auto disable time. 85 | func (b Body) SetAutoDisableTime(time float64) { 86 | C.dBodySetAutoDisableTime(b.c(), C.dReal(time)) 87 | } 88 | 89 | // AutoDisableTime returns the auto disable time. 90 | func (b Body) AutoDisableTime() float64 { 91 | return float64(C.dBodyGetAutoDisableTime(b.c())) 92 | } 93 | 94 | // SetAutoDisable sets wether the body will be auto disabled. 95 | func (b Body) SetAutoDisable(doAutoDisable bool) { 96 | C.dBodySetAutoDisableFlag(b.c(), C.int(btoi(doAutoDisable))) 97 | } 98 | 99 | // AutoDisable returns whether the body will be auto disabled. 100 | func (b Body) AutoDisable() bool { 101 | return C.dBodyGetAutoDisableFlag(b.c()) != 0 102 | } 103 | 104 | // SetAutoDisableDefaults sets auto disable settings to default defaults. 105 | func (b Body) SetAutoDisableDefaults() { 106 | C.dBodySetAutoDisableDefaults(b.c()) 107 | } 108 | 109 | // World returns the world which contains the body. 110 | func (b Body) World() World { 111 | return cToWorld(C.dBodyGetWorld(b.c())) 112 | } 113 | 114 | // SetData associates user-specified data with the body. 115 | func (b Body) SetData(data interface{}) { 116 | bodyData[b] = data 117 | } 118 | 119 | // Data returns the user-specified data associated with the body. 120 | func (b Body) Data() interface{} { 121 | return bodyData[b] 122 | } 123 | 124 | // SetPosition sets the position. 125 | func (b Body) SetPosition(pos Vector3) { 126 | C.dBodySetPosition(b.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 127 | } 128 | 129 | // Position returns the position. 130 | func (b Body) Position() Vector3 { 131 | pos := NewVector3() 132 | C.dBodyCopyPosition(b.c(), (*C.dReal)(&pos[0])) 133 | return pos 134 | } 135 | 136 | // SetRotation sets the orientation represented by a rotation matrix. 137 | func (b Body) SetRotation(rot Matrix3) { 138 | C.dBodySetRotation(b.c(), (*C.dReal)(&rot[0][0])) 139 | } 140 | 141 | // Rotation returns the orientation represented by a rotation matrix. 142 | func (b Body) Rotation() Matrix3 { 143 | rot := NewMatrix3() 144 | C.dBodyCopyRotation(b.c(), (*C.dReal)(&rot[0][0])) 145 | return rot 146 | } 147 | 148 | // SetQuaternion sets the orientation represented by a quaternion. 149 | func (b Body) SetQuaternion(quat Quaternion) { 150 | C.dBodySetQuaternion(b.c(), (*C.dReal)(&quat[0])) 151 | } 152 | 153 | // Quaternion returns the orientation represented by a quaternion. 154 | func (b Body) Quaternion() Quaternion { 155 | quat := NewQuaternion() 156 | C.dBodyCopyQuaternion(b.c(), (*C.dReal)(&quat[0])) 157 | return quat 158 | } 159 | 160 | // SetLinearVelocity sets the linear velocity. 161 | func (b Body) SetLinearVelocity(vel Vector3) { 162 | C.dBodySetLinearVel(b.c(), C.dReal(vel[0]), C.dReal(vel[1]), C.dReal(vel[2])) 163 | } 164 | 165 | // LinearVelocity returns the linear velocity. 166 | func (b Body) LinearVelocity() Vector3 { 167 | return cToVector3(C.dBodyGetLinearVel(b.c())) 168 | } 169 | 170 | // SetAngularVelocity sets the angular velocity. 171 | func (b Body) SetAngularVelocity(vel Vector3) { 172 | C.dBodySetAngularVel(b.c(), C.dReal(vel[0]), C.dReal(vel[1]), C.dReal(vel[2])) 173 | } 174 | 175 | // AngularVel returns the angular velocity. 176 | func (b Body) AngularVel() Vector3 { 177 | return cToVector3(C.dBodyGetAngularVel(b.c())) 178 | } 179 | 180 | // SetMass sets the mass. 181 | func (b Body) SetMass(mass *Mass) { 182 | c := &C.dMass{} 183 | mass.toC(c) 184 | C.dBodySetMass(b.c(), c) 185 | } 186 | 187 | // Mass returns the mass. 188 | func (b Body) Mass() *Mass { 189 | mass := NewMass() 190 | c := &C.dMass{} 191 | C.dBodyGetMass(b.c(), c) 192 | mass.fromC(c) 193 | return mass 194 | } 195 | 196 | // SetForce sets the force acting on the center of mass. 197 | func (b Body) SetForce(force Vector3) { 198 | C.dBodySetForce(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2])) 199 | } 200 | 201 | // Force returns the force acting on the center of mass. 202 | func (b Body) Force() Vector3 { 203 | return cToVector3(C.dBodyGetForce(b.c())) 204 | } 205 | 206 | // SetTorque sets the torque acting on the center of mass. 207 | func (b Body) SetTorque(torque Vector3) { 208 | C.dBodySetTorque(b.c(), C.dReal(torque[0]), C.dReal(torque[1]), C.dReal(torque[2])) 209 | } 210 | 211 | // Torque returns the torque acting on the center of mass. 212 | func (b Body) Torque() Vector3 { 213 | return cToVector3(C.dBodyGetTorque(b.c())) 214 | } 215 | 216 | // RelPointPos returns the position in world coordinates of a point in body 217 | // coordinates. 218 | func (b Body) RelPointPos(pt Vector3) Vector3 { 219 | pos := NewVector3() 220 | C.dBodyGetRelPointPos(b.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), (*C.dReal)(&pos[0])) 221 | return pos 222 | } 223 | 224 | // RelPointVel returns the velocity in world coordinates of a point in body 225 | // coordinates. 226 | func (b Body) RelPointVel(pt Vector3) Vector3 { 227 | vel := NewVector3() 228 | C.dBodyGetRelPointVel(b.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), (*C.dReal)(&vel[0])) 229 | return vel 230 | } 231 | 232 | // PointVel returns the velocity in world coordinates of a point in world 233 | // coordinates. 234 | func (b Body) PointVel(pt Vector3) Vector3 { 235 | vel := NewVector3() 236 | C.dBodyGetPointVel(b.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), (*C.dReal)(&vel[0])) 237 | return vel 238 | } 239 | 240 | // PosRelPoint returns the position in body coordinates of a point in world 241 | // coordinates. 242 | func (b Body) PosRelPoint(pos Vector3) Vector3 { 243 | pt := NewVector3() 244 | C.dBodyGetPosRelPoint(b.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2]), (*C.dReal)(&pt[0])) 245 | return pt 246 | } 247 | 248 | // VectorToWorld converts a vector in body coordinates to world coordinates. 249 | func (b Body) VectorToWorld(vec Vector3) Vector3 { 250 | wld := NewVector3() 251 | C.dBodyVectorToWorld(b.c(), C.dReal(vec[0]), C.dReal(vec[1]), C.dReal(vec[2]), (*C.dReal)(&wld[0])) 252 | return wld 253 | } 254 | 255 | // VectorFromWorld converts a vector in world coordinates to body coordinates. 256 | func (b Body) VectorFromWorld(wld Vector3) Vector3 { 257 | vec := NewVector3() 258 | C.dBodyVectorFromWorld(b.c(), C.dReal(wld[0]), C.dReal(wld[1]), C.dReal(wld[2]), (*C.dReal)(&vec[0])) 259 | return vec 260 | } 261 | 262 | // SetFiniteRotationMode sets whether finite rotation mode is used. 263 | func (b Body) SetFiniteRotationMode(isFinite bool) { 264 | C.dBodySetFiniteRotationMode(b.c(), C.int(btoi(isFinite))) 265 | } 266 | 267 | // FiniteRotationMode returns whether finite rotation mode is used. 268 | func (b Body) FiniteRotationMode() bool { 269 | return C.dBodyGetFiniteRotationMode(b.c()) != 0 270 | } 271 | 272 | // SetFiniteRotationAxis sets the finite rotation axis. 273 | func (b Body) SetFiniteRotationAxis(axis Vector3) { 274 | C.dBodySetFiniteRotationAxis(b.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 275 | } 276 | 277 | // FiniteRotationAxis returns the finite rotation axis. 278 | func (b Body) FiniteRotationAxis() Vector3 { 279 | axis := NewVector3() 280 | C.dBodyGetFiniteRotationAxis(b.c(), (*C.dReal)(&axis[0])) 281 | return axis 282 | } 283 | 284 | // NumJoints returns the number of joints attached to the body. 285 | func (b Body) NumJoints() int { 286 | return int(C.dBodyGetNumJoints(b.c())) 287 | } 288 | 289 | // Joint returns the joint attached to the body, specified by index. 290 | func (b Body) Joint(index int) Joint { 291 | return cToJoint(C.dBodyGetJoint(b.c(), C.int(index))) 292 | } 293 | 294 | // SetKinematic sets whether the body is in kinematic mode. 295 | func (b Body) SetKinematic(isKinematic bool) { 296 | if isKinematic { 297 | C.dBodySetKinematic(b.c()) 298 | } else { 299 | C.dBodySetDynamic(b.c()) 300 | } 301 | } 302 | 303 | // Kinematic returns whether the body is in kinematic mode. 304 | func (b Body) Kinematic() bool { 305 | return bool(C.dBodyIsKinematic(b.c()) != 0) 306 | } 307 | 308 | // SetGravityEnabled sets whether gravity affects the body. 309 | func (b Body) SetGravityEnabled(isGravityEnabled bool) { 310 | C.dBodySetGravityMode(b.c(), C.int(btoi(isGravityEnabled))) 311 | } 312 | 313 | // GravityEnabled returns whether gravity affects the body. 314 | func (b Body) GravityEnabled() bool { 315 | return C.dBodyGetGravityMode(b.c()) != 0 316 | } 317 | 318 | // SetMovedCallback sets callback to call when the body has moved. 319 | func (b Body) SetMovedCallback(cb MovedCallback) { 320 | if cb == nil { 321 | C.dBodySetMovedCallback(b.c(), (*[0]byte)(nil)) // clear callback 322 | delete(movedCallbacks, b) 323 | } else { 324 | movedCallbacks[b] = cb 325 | C.dBodySetMovedCallback(b.c(), (*[0]byte)(unsafe.Pointer(C.callMovedCallback))) 326 | } 327 | } 328 | 329 | // FirstGeom returns the first geometry associated with the body. 330 | func (b Body) FirstGeom() Geom { 331 | return cToGeom(C.dBodyGetFirstGeom(b.c())) 332 | } 333 | 334 | // SetDampingDefaults sets damping settings to default values. 335 | func (b Body) SetDampingDefaults() { 336 | C.dBodySetDampingDefaults(b.c()) 337 | } 338 | 339 | // SetLinearDamping sets the linear damping scale. 340 | func (b Body) SetLinearDamping(scale float64) { 341 | C.dBodySetLinearDamping(b.c(), C.dReal(scale)) 342 | } 343 | 344 | // LinearDamping returns the linear damping scale. 345 | func (b Body) LinearDamping() float64 { 346 | return float64(C.dBodyGetLinearDamping(b.c())) 347 | } 348 | 349 | // SetAngularDamping sets the angular damping scale. 350 | func (b Body) SetAngularDamping(scale float64) { 351 | C.dBodySetAngularDamping(b.c(), C.dReal(scale)) 352 | } 353 | 354 | // AngularDamping returns the angular damping scale. 355 | func (b Body) AngularDamping() float64 { 356 | return float64(C.dBodyGetAngularDamping(b.c())) 357 | } 358 | 359 | // SetLinearDampingThreshold sets the linear damping threshold. 360 | func (b Body) SetLinearDampingThreshold(threshold float64) { 361 | C.dBodySetLinearDampingThreshold(b.c(), C.dReal(threshold)) 362 | } 363 | 364 | // LinearDampingThreshold returns the linear damping threshold. 365 | func (b Body) LinearDampingThreshold() float64 { 366 | return float64(C.dBodyGetLinearDampingThreshold(b.c())) 367 | } 368 | 369 | // SetAngularDampingThreshold sets the angular damping threshold. 370 | func (b Body) SetAngularDampingThreshold(threshold float64) { 371 | C.dBodySetAngularDampingThreshold(b.c(), C.dReal(threshold)) 372 | } 373 | 374 | // AngularDampingThreshold returns the angular damping threshold. 375 | func (b Body) AngularDampingThreshold() float64 { 376 | return float64(C.dBodyGetAngularDampingThreshold(b.c())) 377 | } 378 | 379 | // SetMaxAngularSpeed sets the maximum angular speed. 380 | func (b Body) SetMaxAngularSpeed(maxSpeed float64) { 381 | C.dBodySetMaxAngularSpeed(b.c(), C.dReal(maxSpeed)) 382 | } 383 | 384 | // MaxAngularSpeed returns the maximum angular speed. 385 | func (b Body) MaxAngularSpeed() float64 { 386 | return float64(C.dBodyGetMaxAngularSpeed(b.c())) 387 | } 388 | 389 | // SetGyroModeEnabled sets whether gyroscopic mode is enabled. 390 | func (b Body) SetGyroModeEnabled(isEnabled bool) { 391 | C.dBodySetGyroscopicMode(b.c(), C.int(btoi(isEnabled))) 392 | } 393 | 394 | // GyroModeEnabled returns whether gyroscopic mode is enabled. 395 | func (b Body) GyroModeEnabled() bool { 396 | return C.dBodyGetGyroscopicMode(b.c()) != 0 397 | } 398 | 399 | // Connected returns whether the body is connected to the given body by a 400 | // joint. 401 | func (b Body) Connected(other Body) bool { 402 | return C.dAreConnected(b.c(), other.c()) != 0 403 | } 404 | 405 | // ConnectedExcluding returns whether the body is connected to the given body 406 | // by a joint, except for joints of the given class. 407 | func (b Body) ConnectedExcluding(other Body, jointType int) bool { 408 | return C.dAreConnectedExcluding(b.c(), other.c(), C.int(jointType)) != 0 409 | } 410 | 411 | // AddForce adds a force in world coordinates at the center of mass. 412 | func (b Body) AddForce(force Vector3) { 413 | C.dBodyAddForce(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2])) 414 | } 415 | 416 | // AddRelForce adds a force in body coordinates at the center of mass. 417 | func (b Body) AddRelForce(force Vector3) { 418 | C.dBodyAddRelForce(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2])) 419 | } 420 | 421 | // AddTorque adds a torque in world coordinates at the center of mass. 422 | func (b Body) AddTorque(torque Vector3) { 423 | C.dBodyAddTorque(b.c(), C.dReal(torque[0]), C.dReal(torque[1]), C.dReal(torque[2])) 424 | } 425 | 426 | // AddRelTorque adds a torque in body coordinates at the center of mass. 427 | func (b Body) AddRelTorque(torque Vector3) { 428 | C.dBodyAddRelTorque(b.c(), C.dReal(torque[0]), C.dReal(torque[1]), C.dReal(torque[2])) 429 | } 430 | 431 | // AddForceAtPos adds a force in world coordinates at the position in world 432 | // coordinates. 433 | func (b Body) AddForceAtPos(force, pos Vector3) { 434 | C.dBodyAddForceAtPos(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2]), 435 | C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 436 | } 437 | 438 | // AddForceAtRelPos adds a force in world coordinates at the position in body 439 | // coordinates. 440 | func (b Body) AddForceAtRelPos(force, pos Vector3) { 441 | C.dBodyAddForceAtRelPos(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2]), 442 | C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 443 | } 444 | 445 | // AddRelForceAtPos adds a force in body coordinates at the position in world 446 | // coordinates. 447 | func (b Body) AddRelForceAtPos(force, pos Vector3) { 448 | C.dBodyAddRelForceAtPos(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2]), 449 | C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 450 | } 451 | 452 | // AddRelForceAtRelPos adds a force in body coordinates at the position in body coordinates. 453 | func (b Body) AddRelForceAtRelPos(force, pos Vector3) { 454 | C.dBodyAddRelForceAtRelPos(b.c(), C.dReal(force[0]), C.dReal(force[1]), C.dReal(force[2]), 455 | C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 456 | } 457 | 458 | // SetEnabled sets whether the body is enabled. 459 | func (b Body) SetEnabled(isEnabled bool) { 460 | if isEnabled { 461 | C.dBodyEnable(b.c()) 462 | } else { 463 | C.dBodyDisable(b.c()) 464 | } 465 | } 466 | 467 | // Enabled returns whether the body is enabled. 468 | func (b Body) Enabled() bool { 469 | return bool(C.dBodyIsEnabled(b.c()) != 0) 470 | } 471 | 472 | // ConnectingJoint returns the first joint connecting the body to the specified 473 | // body. 474 | func (b Body) ConnectingJoint(other Body) Joint { 475 | return cToJoint(C.dConnectingJoint(b.c(), other.c())) 476 | } 477 | 478 | // ConnectingJointList returns a list of joints connecting the body to the 479 | // specified body. 480 | func (b Body) ConnectingJointList(other Body) []Joint { 481 | jointList := []Joint{} 482 | for i := 0; i < b.NumJoints(); i++ { 483 | joint := b.Joint(i) 484 | for j := 0; j < joint.NumBodies(); j++ { 485 | if body := joint.Body(j); body == other { 486 | jointList = append(jointList, joint) 487 | break 488 | } 489 | } 490 | } 491 | return jointList 492 | } 493 | -------------------------------------------------------------------------------- /contact.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | import "C" 5 | 6 | // Contact parameter types 7 | const ( 8 | Mu2CtParam = C.dContactMu2 9 | AxisDepCtParam = C.dContactAxisDep 10 | FDir1CtParam = C.dContactFDir1 11 | BounceCtParam = C.dContactBounce 12 | SoftERPCtParam = C.dContactSoftERP 13 | SoftCFMCtParam = C.dContactSoftCFM 14 | Motion1CtParam = C.dContactMotion1 15 | Motion2CtParam = C.dContactMotion2 16 | MotionNCtParam = C.dContactMotionN 17 | Slip1CtParam = C.dContactSlip1 18 | Slip2CtParam = C.dContactSlip2 19 | RollingCtParam = C.dContactRolling 20 | Approx0CtParam = C.dContactApprox0 21 | Approx11CtParam = C.dContactApprox1_1 22 | Approx12CtParam = C.dContactApprox1_2 23 | Approx1NCtParam = C.dContactApprox1_N 24 | Approx1CtParam = C.dContactApprox1 25 | ) 26 | 27 | // SurfaceParameters represents the parameters of a contact surface. 28 | type SurfaceParameters struct { 29 | // must always be defined 30 | Mode int 31 | Mu float64 32 | 33 | // only defined if the corresponding flag is set in mode 34 | Mu2 float64 35 | Rho float64 36 | Rho2 float64 37 | RhoN float64 38 | Bounce float64 39 | BounceVel float64 40 | SoftErp float64 41 | SoftCfm float64 42 | Motion1 float64 43 | Motion2 float64 44 | MotionN float64 45 | Slip1 float64 46 | Slip2 float64 47 | } 48 | 49 | func (s *SurfaceParameters) fromC(c *C.dSurfaceParameters) { 50 | s.Mode = int(c.mode) 51 | s.Mu = float64(c.mu) 52 | s.Mu2 = float64(c.mu2) 53 | s.Rho = float64(c.rho) 54 | s.Rho2 = float64(c.rho2) 55 | s.RhoN = float64(c.rhoN) 56 | s.Bounce = float64(c.bounce) 57 | s.BounceVel = float64(c.bounce_vel) 58 | s.SoftErp = float64(c.soft_erp) 59 | s.SoftCfm = float64(c.soft_cfm) 60 | s.Motion1 = float64(c.motion1) 61 | s.Motion2 = float64(c.motion2) 62 | s.MotionN = float64(c.motionN) 63 | s.Slip1 = float64(c.slip1) 64 | s.Slip2 = float64(c.slip2) 65 | } 66 | 67 | func (s *SurfaceParameters) toC(c *C.dSurfaceParameters) { 68 | c.mode = C.int(s.Mode) 69 | c.mu = C.dReal(s.Mu) 70 | c.mu2 = C.dReal(s.Mu2) 71 | c.rho = C.dReal(s.Rho) 72 | c.rho2 = C.dReal(s.Rho2) 73 | c.rhoN = C.dReal(s.RhoN) 74 | c.bounce = C.dReal(s.Bounce) 75 | c.bounce_vel = C.dReal(s.BounceVel) 76 | c.soft_erp = C.dReal(s.SoftErp) 77 | c.soft_cfm = C.dReal(s.SoftCfm) 78 | c.motion1 = C.dReal(s.Motion1) 79 | c.motion2 = C.dReal(s.Motion2) 80 | c.motionN = C.dReal(s.MotionN) 81 | c.slip1 = C.dReal(s.Slip1) 82 | c.slip2 = C.dReal(s.Slip2) 83 | } 84 | 85 | // ContactGeom represents a contact point. 86 | type ContactGeom struct { 87 | Pos Vector3 88 | Normal Vector3 89 | Depth float64 90 | G1 Geom 91 | G2 Geom 92 | Side1 int 93 | Side2 int 94 | } 95 | 96 | // NewContactGeom returns a new ContactGeom. 97 | func NewContactGeom() *ContactGeom { 98 | return &ContactGeom{ 99 | Pos: NewVector3(), 100 | Normal: NewVector3(), 101 | } 102 | } 103 | 104 | func (g *ContactGeom) fromC(c *C.dContactGeom) { 105 | Vector(g.Pos).fromC(&c.pos[0]) 106 | Vector(g.Normal).fromC(&c.normal[0]) 107 | g.Depth = float64(c.depth) 108 | g.G1 = cToGeom(c.g1) 109 | g.G2 = cToGeom(c.g2) 110 | g.Side1 = int(c.side1) 111 | g.Side2 = int(c.side2) 112 | } 113 | 114 | func (g *ContactGeom) toC(c *C.dContactGeom) { 115 | Vector(g.Pos).toC((*C.dReal)(&c.pos[0])) 116 | Vector(g.Normal).toC((*C.dReal)(&c.normal[0])) 117 | c.depth = C.dReal(g.Depth) 118 | c.g1 = g.G1.c() 119 | c.g2 = g.G2.c() 120 | c.side1 = C.int(g.Side1) 121 | c.side2 = C.int(g.Side2) 122 | } 123 | 124 | // Contact represents a contact. 125 | type Contact struct { 126 | Surface SurfaceParameters 127 | Geom ContactGeom 128 | FDir1 Vector3 129 | } 130 | 131 | // NewContact returns a new Contact. 132 | func NewContact() *Contact { 133 | return &Contact{ 134 | FDir1: NewVector3(), 135 | Geom: *NewContactGeom(), 136 | } 137 | } 138 | 139 | func (c *Contact) fromC(cc *C.dContact) { 140 | c.Surface.fromC(&cc.surface) 141 | Vector(c.FDir1).fromC(&cc.fdir1[0]) 142 | c.Geom.fromC(&cc.geom) 143 | } 144 | 145 | func (c *Contact) toC(cc *C.dContact) { 146 | c.Surface.toC(&cc.surface) 147 | Vector(c.FDir1).toC(&cc.fdir1[0]) 148 | c.Geom.toC(&cc.geom) 149 | } 150 | -------------------------------------------------------------------------------- /example/chain/chain.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | 8 | "github.com/ianremmler/ode" 9 | "gopkg.in/qml.v1" 10 | "gopkg.in/qml.v1/gl/1.0" 11 | ) 12 | 13 | const ( 14 | numSpheres = 10 15 | sideLen = 0.2 16 | sphereMass = 1 17 | sphereRadius = 0.1732 18 | ) 19 | 20 | var ( 21 | world ode.World 22 | space ode.Space 23 | body []ode.Body 24 | joint []ode.BallJoint 25 | ctGrp ode.JointGroup 26 | sphere []ode.Sphere 27 | mass *ode.Mass 28 | angle float64 29 | ) 30 | 31 | func cb(data interface{}, obj1, obj2 ode.Geom) { 32 | contact := ode.NewContact() 33 | body1, body2 := obj1.Body(), obj2.Body() 34 | if body1 != 0 && body2 != 0 && body1.Connected(body2) { 35 | return 36 | } 37 | contact.Surface.Mode = 0 38 | contact.Surface.Mu = 0.1 39 | contact.Surface.Mu2 = 0 40 | cts := obj1.Collide(obj2, 1, 0) 41 | if len(cts) > 0 { 42 | contact.Geom = cts[0] 43 | ct := world.NewContactJoint(ctGrp, contact) 44 | ct.Attach(body1, body2) 45 | } 46 | } 47 | 48 | type Sim struct { 49 | qml.Object 50 | } 51 | 52 | func (s *Sim) Iter() { 53 | angle += 0.05 54 | body[len(body)-1].AddForce(ode.V3(0, 0, 1.5*(math.Sin(angle)+1))) 55 | space.Collide(0, cb) 56 | world.Step(0.05) 57 | ctGrp.Empty() 58 | } 59 | 60 | func (s *Sim) Paint(p *qml.Painter) { 61 | gl := GL.API(p) 62 | diffuseColor := []float32{0.5, 1, 1, 0} 63 | diffusePos := []float32{0, 0, 1, 0} 64 | 65 | gl.Rotated(-45, 1, 0, 0) 66 | 67 | gl.Lightfv(GL.LIGHT0, GL.DIFFUSE, diffuseColor) 68 | gl.Lightfv(GL.LIGHT0, GL.POSITION, diffusePos) 69 | gl.Enable(GL.LIGHT0) 70 | gl.Enable(GL.LIGHTING) 71 | gl.Enable(GL.DEPTH_TEST) 72 | gl.Enable(GL.NORMALIZE) 73 | 74 | gl.ClearColor(0, 0, 0, 0) 75 | gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT) 76 | 77 | width := float64(s.Int("width")) 78 | height := float64(s.Int("height")) 79 | 80 | gl.PushMatrix() 81 | scale := width / 5 82 | gl.Translated(0.5*width, 0.5*height, 0) 83 | gl.Scaled(scale, scale, scale) 84 | for i := range body { 85 | pos := body[i].Position() 86 | gl.PushMatrix() 87 | gl.Translated(pos[0], pos[1], pos[2]) 88 | gl.Scaled(sphereRadius, sphereRadius, sphereRadius) 89 | drawSphere(gl, 16, 16) 90 | gl.PopMatrix() 91 | } 92 | gl.PopMatrix() 93 | } 94 | 95 | func run() error { 96 | qml.RegisterTypes("GoExtensions", 1, 0, []qml.TypeSpec{{ 97 | Init: func(s *Sim, obj qml.Object) { s.Object = obj }, 98 | }}) 99 | 100 | engine := qml.NewEngine() 101 | component, err := engine.LoadFile("chain.qml") 102 | if err != nil { 103 | return err 104 | } 105 | 106 | win := component.CreateWindow(nil) 107 | win.Show() 108 | win.Wait() 109 | 110 | return nil 111 | } 112 | 113 | func drawSphere(gl *GL.GL, latSegs, lonSegs int) { 114 | for i := 0; i < latSegs; i++ { 115 | latFrac0, latFrac1 := float64(i)/float64(latSegs), float64(i+1)/float64(latSegs) 116 | latAngle0, latAngle1 := math.Pi*(latFrac0-0.5), math.Pi*(latFrac1-0.5) 117 | z0, z1 := math.Sin(latAngle0), math.Sin(latAngle1) 118 | r0, r1 := math.Cos(latAngle0), math.Cos(latAngle1) 119 | gl.Begin(GL.QUAD_STRIP) 120 | for j := 0; j <= lonSegs; j++ { 121 | lonFrac := float64(j) / float64(lonSegs) 122 | lonAngle := 2 * math.Pi * lonFrac 123 | x0, x1 := r0*math.Cos(lonAngle), r1*math.Cos(lonAngle) 124 | y0, y1 := r0*math.Sin(lonAngle), r1*math.Sin(lonAngle) 125 | gl.Normal3d(x0, y0, z0) 126 | gl.Vertex3d(x0, y0, z0) 127 | gl.Normal3d(x1, y1, z1) 128 | gl.Vertex3d(x1, y1, z1) 129 | } 130 | gl.End() 131 | } 132 | } 133 | 134 | func main() { 135 | ode.Init(0, ode.AllAFlag) 136 | 137 | world = ode.NewWorld() 138 | space = ode.NilSpace().NewHashSpace() 139 | body = make([]ode.Body, numSpheres) 140 | joint = make([]ode.BallJoint, numSpheres-1) 141 | ctGrp = ode.NewJointGroup(1000000) 142 | sphere = make([]ode.Sphere, numSpheres) 143 | mass = ode.NewMass() 144 | 145 | world.SetGravity(ode.V3(0, 0, -0.5)) 146 | space.NewPlane(ode.V4(0, 0, 1, 0)) 147 | 148 | for i := 0; i < numSpheres; i++ { 149 | k := float64(i) * sideLen 150 | body[i] = world.NewBody() 151 | body[i].SetPosition(ode.V3(k, k, k+0.4)) 152 | mass.SetBox(1, ode.V3(sideLen, sideLen, sideLen)) 153 | mass.Adjust(sphereMass) 154 | body[i].SetMass(mass) 155 | sphere[i] = space.NewSphere(sphereRadius) 156 | sphere[i].SetBody(body[i]) 157 | } 158 | 159 | for i := 0; i < numSpheres-1; i++ { 160 | joint[i] = world.NewBallJoint(ode.JointGroup(0)) 161 | joint[i].Attach(body[i], body[i+1]) 162 | k := (float64(i) + 0.5) * sideLen 163 | joint[i].SetAnchor(ode.V3(k, k, k+0.4)) 164 | } 165 | 166 | if err := qml.Run(run); err != nil { 167 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 168 | os.Exit(1) 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /example/chain/chain.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import GoExtensions 1.0 3 | 4 | Rectangle { 5 | width: 800 6 | height: 600 7 | color: "black" 8 | Sim { 9 | id: sim 10 | anchors.fill: parent 11 | } 12 | Timer { 13 | interval: 10; running: true; repeat: true 14 | onTriggered: { 15 | sim.iter() 16 | sim.update() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /geom.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | // extern void callNearCallback(void *data, dGeomID obj1, dGeomID obj2); 5 | import "C" 6 | 7 | import ( 8 | "unsafe" 9 | ) 10 | 11 | // Geometry classes 12 | const ( 13 | SphereClass = C.dSphereClass 14 | BoxClass = C.dBoxClass 15 | CapsuleClass = C.dCapsuleClass 16 | CylinderClass = C.dCylinderClass 17 | PlaneClass = C.dPlaneClass 18 | RayClass = C.dRayClass 19 | ConvexClass = C.dConvexClass 20 | TriMeshClass = C.dTriMeshClass 21 | HeightfieldClass = C.dHeightfieldClass 22 | SimpleSpaceClass = C.dSimpleSpaceClass 23 | HashSpaceClass = C.dHashSpaceClass 24 | SweepAndPruneSpaceClass = C.dSweepAndPruneSpaceClass 25 | QuadTreeSpaceClass = C.dQuadTreeSpaceClass 26 | 27 | NumClasses = C.dGeomNumClasses 28 | 29 | MaxUserClasses = C.dMaxUserClasses 30 | FirstUserClass = C.dFirstUserClass 31 | LastUserClass = C.dLastUserClass 32 | 33 | FirstSpaceClass = C.dFirstSpaceClass 34 | LastSpaceClass = C.dLastSpaceClass 35 | ) 36 | 37 | var ( 38 | geomData = map[Geom]interface{}{} 39 | ) 40 | 41 | // Geom represents rigid body geometry. 42 | type Geom interface { 43 | c() C.dGeomID 44 | Destroy() 45 | SetData(data interface{}) 46 | Data() interface{} 47 | SetBody(body Body) 48 | Body() Body 49 | SetPosition(pos Vector3) 50 | Position() Vector3 51 | SetRotation(rot Matrix3) 52 | Rotation() Matrix3 53 | SetQuaternion(quat Quaternion) 54 | Quaternion() Quaternion 55 | AABB() AABB 56 | IsSpace() bool 57 | Space() Space 58 | Class() int 59 | SetCategoryBits(bits int) 60 | SetCollideBits(bits int) 61 | CategoryBits() int 62 | CollideBits() int 63 | SetEnabled(isEnabled bool) 64 | Enabled() bool 65 | RelPointPos(pt Vector3) Vector3 66 | PosRelPoint(pos Vector3) Vector3 67 | VectorToWorld(vec Vector3) Vector3 68 | VectorFromWorld(wld Vector3) Vector3 69 | OffsetPosition() Vector3 70 | SetOffsetPosition(pos Vector3) 71 | OffsetRotation() Matrix3 72 | SetOffsetRotation(rot Matrix3) 73 | OffsetQuaternion() Quaternion 74 | SetOffsetQuaternion(quat Quaternion) 75 | SetOffsetWorldPosition(pos Vector3) 76 | SetOffsetWorldRotation(rot Matrix3) 77 | SetOffsetWorldQuaternion(quat Quaternion) 78 | ClearOffset() 79 | IsOffset() bool 80 | Collide(other Geom, maxContacts uint16, flags int) []ContactGeom 81 | Collide2(other Geom, data interface{}, cb NearCallback) 82 | Next() Geom 83 | } 84 | 85 | // GeomBase implements Geom, and is embedded by specific Geom types. 86 | type GeomBase uintptr 87 | 88 | func cToGeom(c C.dGeomID) Geom { 89 | base := GeomBase(unsafe.Pointer(c)) 90 | var g Geom 91 | switch int(C.dGeomGetClass(c)) { 92 | case SphereClass: 93 | g = Sphere{base} 94 | case BoxClass: 95 | g = Box{base} 96 | case CapsuleClass: 97 | g = Capsule{base} 98 | case CylinderClass: 99 | g = Cylinder{base} 100 | case PlaneClass: 101 | g = Plane{base} 102 | case RayClass: 103 | g = Ray{base} 104 | case HeightfieldClass: 105 | g = Heightfield{base} 106 | case TriMeshClass: 107 | g = TriMesh{base} 108 | default: 109 | g = base 110 | } 111 | return g 112 | } 113 | 114 | func (g GeomBase) c() C.dGeomID { 115 | return C.dGeomID(unsafe.Pointer(g)) 116 | } 117 | 118 | // Destroy destroys the GeomBase. 119 | func (g GeomBase) Destroy() { 120 | delete(geomData, g) 121 | C.dGeomDestroy(g.c()) 122 | } 123 | 124 | // SetData associates user-specified data with the geometry. 125 | func (g GeomBase) SetData(data interface{}) { 126 | geomData[g] = data 127 | } 128 | 129 | // Data returns the user-specified data associated with the geometry. 130 | func (g GeomBase) Data() interface{} { 131 | return geomData[g] 132 | } 133 | 134 | // SetBody sets the associated body. 135 | func (g GeomBase) SetBody(body Body) { 136 | C.dGeomSetBody(g.c(), body.c()) 137 | } 138 | 139 | // Body returns the body associated with the geometry. 140 | func (g GeomBase) Body() Body { 141 | return cToBody(C.dGeomGetBody(g.c())) 142 | } 143 | 144 | // SetPosition sets the position. 145 | func (g GeomBase) SetPosition(pos Vector3) { 146 | C.dGeomSetPosition(g.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 147 | } 148 | 149 | // Position returns the position. 150 | func (g GeomBase) Position() Vector3 { 151 | pos := NewVector3() 152 | C.dGeomCopyPosition(g.c(), (*C.dReal)(&pos[0])) 153 | return pos 154 | } 155 | 156 | // SetRotation sets the orientation represented by a rotation matrix. 157 | func (g GeomBase) SetRotation(rot Matrix3) { 158 | C.dGeomSetRotation(g.c(), (*C.dReal)(&rot[0][0])) 159 | } 160 | 161 | // Rotation returns the orientation represented by a rotation matrix. 162 | func (g GeomBase) Rotation() Matrix3 { 163 | rot := NewMatrix3() 164 | C.dGeomCopyRotation(g.c(), (*C.dReal)(&rot[0][0])) 165 | return rot 166 | } 167 | 168 | // SetQuaternion sets the orientation represented by a quaternion. 169 | func (g GeomBase) SetQuaternion(quat Quaternion) { 170 | C.dGeomSetQuaternion(g.c(), (*C.dReal)(&quat[0])) 171 | } 172 | 173 | // Quaternion returns the orientation represented by a quaternion. 174 | func (g GeomBase) Quaternion() Quaternion { 175 | quat := NewQuaternion() 176 | C.dGeomGetQuaternion(g.c(), (*C.dReal)(&quat[0])) 177 | return quat 178 | } 179 | 180 | // AABB returns the axis-aligned bounding box. 181 | func (g GeomBase) AABB() AABB { 182 | aabb := NewAABB() 183 | C.dGeomGetAABB(g.c(), (*C.dReal)(&aabb[0])) 184 | return aabb 185 | } 186 | 187 | // IsSpace returns whether the geometry is a space. 188 | func (g GeomBase) IsSpace() bool { 189 | return C.dGeomIsSpace(g.c()) != 0 190 | } 191 | 192 | // Space returns the containing space. 193 | func (g GeomBase) Space() Space { 194 | return cToSpace(C.dGeomGetSpace(g.c())) 195 | } 196 | 197 | // Class returns the geometry class. 198 | func (g GeomBase) Class() int { 199 | return int(C.dGeomGetClass(g.c())) 200 | } 201 | 202 | // SetCategoryBits sets the category bitfield. 203 | func (g GeomBase) SetCategoryBits(bits int) { 204 | C.dGeomSetCategoryBits(g.c(), C.ulong(bits)) 205 | } 206 | 207 | // CategoryBits returns the category bitfield. 208 | func (g GeomBase) CategoryBits() int { 209 | return int(C.dGeomGetCategoryBits(g.c())) 210 | } 211 | 212 | // SetCollideBits sets the collide bitfield. 213 | func (g GeomBase) SetCollideBits(bits int) { 214 | C.dGeomSetCollideBits(g.c(), C.ulong(bits)) 215 | } 216 | 217 | // CollideBits returns the collide bitfield. 218 | func (g GeomBase) CollideBits() int { 219 | return int(C.dGeomGetCollideBits(g.c())) 220 | } 221 | 222 | // SetEnabled sets whether the geometry is enabled. 223 | func (g GeomBase) SetEnabled(isEnabled bool) { 224 | if isEnabled { 225 | C.dGeomEnable(g.c()) 226 | } else { 227 | C.dGeomDisable(g.c()) 228 | } 229 | } 230 | 231 | // Enabled returns whether the geometry is enabled. 232 | func (g GeomBase) Enabled() bool { 233 | return bool(C.dGeomIsEnabled(g.c()) != 0) 234 | } 235 | 236 | // RelPointPos returns the position in world coordinates of a point in geometry 237 | // coordinates. 238 | func (g GeomBase) RelPointPos(pt Vector3) Vector3 { 239 | pos := NewVector3() 240 | C.dGeomGetRelPointPos(g.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), (*C.dReal)(&pos[0])) 241 | return pos 242 | } 243 | 244 | // PosRelPoint returns the position in geometry coordinates of a point in world 245 | // coordinates. 246 | func (g GeomBase) PosRelPoint(pos Vector3) Vector3 { 247 | pt := NewVector3() 248 | C.dGeomGetPosRelPoint(g.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2]), (*C.dReal)(&pt[0])) 249 | return pt 250 | } 251 | 252 | // VectorToWorld converts a vector in geometry coordinates to world 253 | // coordinates. 254 | func (g GeomBase) VectorToWorld(vec Vector3) Vector3 { 255 | wld := NewVector3() 256 | C.dGeomVectorToWorld(g.c(), C.dReal(vec[0]), C.dReal(vec[1]), C.dReal(vec[2]), (*C.dReal)(&wld[0])) 257 | return wld 258 | } 259 | 260 | // VectorFromWorld converts a vector in world coordinates to geometry 261 | // coordinates. 262 | func (g GeomBase) VectorFromWorld(wld Vector3) Vector3 { 263 | vec := NewVector3() 264 | C.dGeomVectorFromWorld(g.c(), C.dReal(wld[0]), C.dReal(wld[1]), C.dReal(wld[2]), (*C.dReal)(&vec[0])) 265 | return vec 266 | } 267 | 268 | // SetOffsetPosition sets the position offset from the body. 269 | func (g GeomBase) SetOffsetPosition(pos Vector3) { 270 | C.dGeomSetOffsetPosition(g.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 271 | } 272 | 273 | // OffsetPosition returns the position offset from the body. 274 | func (g GeomBase) OffsetPosition() Vector3 { 275 | pos := NewVector3() 276 | C.dGeomCopyOffsetPosition(g.c(), (*C.dReal)(&pos[0])) 277 | return pos 278 | } 279 | 280 | // SetOffsetRotation sets the orientation offset from the body represented by a 281 | // rotation matrix. 282 | func (g GeomBase) SetOffsetRotation(rot Matrix3) { 283 | C.dGeomSetOffsetRotation(g.c(), (*C.dReal)(&rot[0][0])) 284 | } 285 | 286 | // OffsetRotation returns the orientation offset from the body represented by a 287 | // rotation matrix. 288 | func (g GeomBase) OffsetRotation() Matrix3 { 289 | rot := NewMatrix3() 290 | C.dGeomCopyOffsetRotation(g.c(), (*C.dReal)(&rot[0][0])) 291 | return rot 292 | } 293 | 294 | // SetOffsetQuaternion sets the offset from the body orientation represented by 295 | // a quaternion. 296 | func (g GeomBase) SetOffsetQuaternion(quat Quaternion) { 297 | C.dGeomSetOffsetQuaternion(g.c(), (*C.dReal)(&quat[0])) 298 | } 299 | 300 | // OffsetQuaternion returns the orientation offset from the body represented by 301 | // a quaternion. 302 | func (g GeomBase) OffsetQuaternion() Quaternion { 303 | quat := NewQuaternion() 304 | C.dGeomGetOffsetQuaternion(g.c(), (*C.dReal)(&quat[0])) 305 | return quat 306 | } 307 | 308 | // SetOffsetWorldPosition sets the offset to the body position such that the 309 | // geom's world position is pos. 310 | func (g GeomBase) SetOffsetWorldPosition(pos Vector3) { 311 | C.dGeomSetOffsetWorldPosition(g.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2])) 312 | } 313 | 314 | // SetOffsetWorldRotation sets the offset to the body orientation such that the 315 | // geom's world orientation is represented by the matrix rot. 316 | func (g GeomBase) SetOffsetWorldRotation(rot Matrix3) { 317 | C.dGeomSetOffsetWorldRotation(g.c(), (*C.dReal)(&rot[0][0])) 318 | } 319 | 320 | // SetOffsetWorldQuaternion sets the offset to the body orientation such that 321 | // the geom's world orientation is represented by the quaternion quat. 322 | func (g GeomBase) SetOffsetWorldQuaternion(quat Quaternion) { 323 | C.dGeomSetOffsetWorldQuaternion(g.c(), (*C.dReal)(&quat[0])) 324 | } 325 | 326 | // ClearOffset removes the body offset. 327 | func (g GeomBase) ClearOffset() { 328 | C.dGeomClearOffset(g.c()) 329 | } 330 | 331 | // IsOffset returns whether a body offset has been created. 332 | func (g GeomBase) IsOffset() bool { 333 | return C.dGeomIsOffset(g.c()) != 0 334 | } 335 | 336 | // Collide tests for collision with the given geometry and returns a list of 337 | // contact points. 338 | func (g GeomBase) Collide(other Geom, maxContacts uint16, flags int) []ContactGeom { 339 | cts := make([]C.dContactGeom, maxContacts) 340 | numCts := int(C.dCollide(g.c(), other.c(), C.int(int(maxContacts)|flags), &cts[0], 341 | C.int(unsafe.Sizeof(cts[0])))) 342 | contacts := make([]ContactGeom, numCts) 343 | for i := range contacts { 344 | contacts[i] = *NewContactGeom() 345 | contacts[i].fromC(&cts[i]) 346 | } 347 | return contacts 348 | } 349 | 350 | // Collide2 tests for collision with the given geometry, applying cb for each 351 | // contact. 352 | func (g GeomBase) Collide2(other Geom, data interface{}, cb NearCallback) { 353 | cbData := &nearCallbackData{fn: cb, data: data} 354 | C.dSpaceCollide2(g.c(), other.c(), unsafe.Pointer(cbData), 355 | (*C.dNearCallback)(C.callNearCallback)) 356 | } 357 | 358 | // Next returns the next geometry. 359 | func (g GeomBase) Next() Geom { 360 | return cToGeom(C.dBodyGetNextGeom(g.c())) 361 | } 362 | 363 | // Sphere is a geometry representing a sphere. 364 | type Sphere struct { 365 | GeomBase 366 | } 367 | 368 | // SetRadius sets the radius. 369 | func (s Sphere) SetRadius(radius float64) { 370 | C.dGeomSphereSetRadius(s.c(), C.dReal(radius)) 371 | } 372 | 373 | // Radius returns the radius. 374 | func (s Sphere) Radius() float64 { 375 | return float64(C.dGeomSphereGetRadius(s.c())) 376 | } 377 | 378 | // SpherePointDepth returns the depth of the given point. 379 | func (s Sphere) SpherePointDepth(pt Vector3) float64 { 380 | return float64(C.dGeomSpherePointDepth(s.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]))) 381 | } 382 | 383 | // Box is a geometry representing a rectangular box. 384 | type Box struct { 385 | GeomBase 386 | } 387 | 388 | // SetLengths sets the lengths of the sides. 389 | func (b Box) SetLengths(lens Vector3) { 390 | C.dGeomBoxSetLengths(b.c(), C.dReal(lens[0]), C.dReal(lens[1]), C.dReal(lens[2])) 391 | } 392 | 393 | // Lengths returns the lengths of the sides. 394 | func (b Box) Lengths() Vector3 { 395 | lens := NewVector3() 396 | C.dGeomBoxGetLengths(b.c(), (*C.dReal)(&lens[0])) 397 | return lens 398 | } 399 | 400 | // PointDepth returns the depth of the given point. 401 | func (b Box) PointDepth(pt Vector3) float64 { 402 | return float64(C.dGeomBoxPointDepth(b.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]))) 403 | } 404 | 405 | // Plane is a geometry that represents a plane. 406 | type Plane struct { 407 | GeomBase 408 | } 409 | 410 | // SetParams sets plane parameters. 411 | func (p Plane) SetParams(params Vector4) { 412 | C.dGeomPlaneSetParams(p.c(), C.dReal(params[0]), C.dReal(params[1]), C.dReal(params[2]), C.dReal(params[3])) 413 | } 414 | 415 | // Params returns plane parameters. 416 | func (p Plane) Params() Vector4 { 417 | params := NewVector4() 418 | C.dGeomPlaneGetParams(p.c(), (*C.dReal)(¶ms[0])) 419 | return params 420 | } 421 | 422 | // PointDepth returns the depth of the given point. 423 | func (p Plane) PointDepth(pt Vector3) float64 { 424 | return float64(C.dGeomPlanePointDepth(p.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]))) 425 | } 426 | 427 | // Capsule is a geometry that represents a capsule (a cylinder with a half 428 | // sphere on each end). 429 | type Capsule struct { 430 | GeomBase 431 | } 432 | 433 | // SetParams sets the radius and length. 434 | func (c Capsule) SetParams(radius, length float64) { 435 | C.dGeomCapsuleSetParams(c.c(), C.dReal(radius), C.dReal(length)) 436 | } 437 | 438 | // Params returns the radius and length. 439 | func (c Capsule) Params() (float64, float64) { 440 | var radius, length float64 441 | C.dGeomCapsuleGetParams(c.c(), (*C.dReal)(&radius), (*C.dReal)(&length)) 442 | return radius, length 443 | } 444 | 445 | // PointDepth returns the depth of the given point. 446 | func (c Capsule) PointDepth(pt Vector3) float64 { 447 | return float64(C.dGeomCapsulePointDepth(c.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]))) 448 | } 449 | 450 | // Cylinder is a geometry that represents a cylider. 451 | type Cylinder struct { 452 | GeomBase 453 | } 454 | 455 | // SetParams sets the radius and length. 456 | func (c Cylinder) SetParams(radius, length float64) { 457 | C.dGeomCylinderSetParams(c.c(), C.dReal(radius), C.dReal(length)) 458 | } 459 | 460 | // Params returns the radius and length. 461 | func (c Cylinder) Params() (float64, float64) { 462 | var radius, length float64 463 | C.dGeomCylinderGetParams(c.c(), (*C.dReal)(&radius), (*C.dReal)(&length)) 464 | return radius, length 465 | } 466 | 467 | // Ray is a geometry representing a ray. 468 | type Ray struct { 469 | GeomBase 470 | } 471 | 472 | // SetPosDir sets the position and direction. 473 | func (r Ray) SetPosDir(pos, dir Vector3) { 474 | C.dGeomRaySet(r.c(), C.dReal(pos[0]), C.dReal(pos[1]), C.dReal(pos[2]), 475 | C.dReal(dir[0]), C.dReal(dir[1]), C.dReal(dir[2])) 476 | } 477 | 478 | // PosDir returns the position and direction. 479 | func (r Ray) PosDir() (Vector3, Vector3) { 480 | pos, dir := NewVector3(), NewVector3() 481 | C.dGeomRayGet(r.c(), (*C.dReal)(&pos[0]), (*C.dReal)(&dir[0])) 482 | return pos, dir 483 | } 484 | 485 | // SetLength sets the length. 486 | func (r Ray) SetLength(length float64) { 487 | C.dGeomRaySetLength(r.c(), C.dReal(length)) 488 | } 489 | 490 | // Length returns the length. 491 | func (r Ray) Length() float64 { 492 | return float64(C.dGeomRayGetLength(r.c())) 493 | } 494 | 495 | // SetFirstContact sets whether to stop collision detection after finding the 496 | // first contact point. 497 | func (r Ray) SetFirstContact(firstContact bool) { 498 | C.dGeomRaySetFirstContact(r.c(), C.int(btoi(firstContact))) 499 | } 500 | 501 | // FirstContact returns whether collision detection will stop after finding the 502 | // first contact. 503 | func (r Ray) FirstContact() bool { 504 | return C.dGeomRayGetFirstContact(r.c()) != 0 505 | } 506 | 507 | // SetBackfaceCull sets whether backface culling is enabled. 508 | func (r Ray) SetBackfaceCull(backfaceCull bool) { 509 | C.dGeomRaySetBackfaceCull(r.c(), C.int(btoi(backfaceCull))) 510 | } 511 | 512 | // BackfaceCull returns whether backface culling is enabled. 513 | func (r Ray) BackfaceCull() bool { 514 | return C.dGeomRayGetBackfaceCull(r.c()) != 0 515 | } 516 | 517 | // SetClosestHit sets whether to only report the closest hit. 518 | func (r Ray) SetClosestHit(closestHit bool) { 519 | C.dGeomRaySetClosestHit(r.c(), C.int(btoi(closestHit))) 520 | } 521 | 522 | // ClosestHit returns whether only the closest hit will be reported. 523 | func (r Ray) ClosestHit() bool { 524 | return C.dGeomRayGetClosestHit(r.c()) != 0 525 | } 526 | 527 | // Convex is a geometry representing a convex object. 528 | type Convex struct { 529 | GeomBase 530 | } 531 | 532 | // Set sets convex object data 533 | func (c Convex) Set(planes PlaneList, pts VertexList, polyList PolygonList) { 534 | C.dGeomSetConvex(c.c(), (*C.dReal)(&planes[0][0]), C.uint(len(planes)), 535 | (*C.dReal)(&pts[0][0]), C.uint(len(pts)), &polyList[0]) 536 | } 537 | -------------------------------------------------------------------------------- /heightfield.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | import "C" 5 | 6 | import ( 7 | "unsafe" 8 | ) 9 | 10 | // HeightfieldData represents heightfield data. 11 | type HeightfieldData uintptr 12 | 13 | func cToHeightfieldData(c C.dHeightfieldDataID) HeightfieldData { 14 | return HeightfieldData(unsafe.Pointer(c)) 15 | } 16 | 17 | func (h HeightfieldData) c() C.dHeightfieldDataID { 18 | return C.dHeightfieldDataID(unsafe.Pointer(h)) 19 | } 20 | 21 | // NewHeightfieldData returns a new HeightfieldData instance. 22 | func NewHeightfieldData() HeightfieldData { 23 | return cToHeightfieldData(C.dGeomHeightfieldDataCreate()) 24 | } 25 | 26 | // Destroy destroys the heightfield data. 27 | func (h *HeightfieldData) Destroy() { 28 | C.dGeomHeightfieldDataDestroy(h.c()) 29 | } 30 | 31 | // Heightfield is a geometry representing a heightfield. 32 | type Heightfield struct { 33 | GeomBase 34 | } 35 | 36 | // Build builds a heightfield data set. 37 | func (h Heightfield) Build(data HeightfieldData, heightSamples Matrix, 38 | width, depth, scale, offset, thickness float64, doWrap bool) { 39 | 40 | numWidthSamp, numDepthSamp := len(heightSamples), 0 41 | var heightSamplesPtr *C.double 42 | if numDepthSamp > 0 { 43 | numWidthSamp = len(heightSamples[0]) 44 | if numWidthSamp > 0 { 45 | heightSamplesPtr = (*C.double)(&heightSamples[0][0]) 46 | } 47 | } 48 | C.dGeomHeightfieldDataBuildDouble(data.c(), heightSamplesPtr, 1, 49 | C.dReal(width), C.dReal(depth), C.int(numWidthSamp), C.int(numDepthSamp), 50 | C.dReal(scale), C.dReal(offset), C.dReal(thickness), C.int(btoi(doWrap))) 51 | } 52 | 53 | // SetBounds sets the minimum and maximum height. 54 | func (h Heightfield) SetBounds(data HeightfieldData, minHeight, maxHeight float64) { 55 | C.dGeomHeightfieldDataSetBounds(data.c(), C.dReal(minHeight), C.dReal(maxHeight)) 56 | } 57 | 58 | // SetHeightfieldData associates a data set to the heightfield. 59 | func (h Heightfield) SetHeightfieldData(data HeightfieldData) { 60 | C.dGeomHeightfieldSetHeightfieldData(h.c(), data.c()) 61 | } 62 | 63 | // HeightfieldData returns the data set associated with the heightfield. 64 | func (h Heightfield) HeightfieldData() HeightfieldData { 65 | return cToHeightfieldData(C.dGeomHeightfieldGetHeightfieldData(h.c())) 66 | } 67 | -------------------------------------------------------------------------------- /joint.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | import "C" 5 | 6 | import ( 7 | "unsafe" 8 | ) 9 | 10 | // Joint types 11 | const ( 12 | BallJointType = C.dJointTypeBall 13 | HingeJointType = C.dJointTypeHinge 14 | SliderJointType = C.dJointTypeSlider 15 | ContactJointType = C.dJointTypeContact 16 | UniversalJointType = C.dJointTypeUniversal 17 | Hinge2JointType = C.dJointTypeHinge2 18 | FixedJointType = C.dJointTypeFixed 19 | NullJointType = C.dJointTypeNull 20 | AMotorJointType = C.dJointTypeAMotor 21 | LMotorJointType = C.dJointTypeLMotor 22 | Plane2DJointType = C.dJointTypePlane2D 23 | PRJointType = C.dJointTypePR 24 | PUJointType = C.dJointTypePU 25 | PistonJointType = C.dJointTypePiston 26 | DBallJointType = C.dJointTypeDBall 27 | DHingeJointType = C.dJointTypeDHinge 28 | TransmissionJointType = C.dJointTypeTransmission 29 | ) 30 | 31 | // Joint parameters 32 | const ( 33 | LoStopJtParam = C.dParamLoStop 34 | HiStopJtParam = C.dParamHiStop 35 | VelJtParam = C.dParamVel 36 | LoVelJtParam = C.dParamLoVel 37 | HiVelJtParam = C.dParamHiVel 38 | FMaxJtParam = C.dParamFMax 39 | FudgeFactorJtParam = C.dParamFudgeFactor 40 | BounceJtParam = C.dParamBounce 41 | CFMJtParam = C.dParamCFM 42 | StopERPJtParam = C.dParamStopERP 43 | StopCFMJtParam = C.dParamStopCFM 44 | SuspensionERPJtParam = C.dParamSuspensionERP 45 | SuspensionCFMJtParam = C.dParamSuspensionCFM 46 | ERPJtParam = C.dParamERP 47 | 48 | NumJtParams = C.dParamsInGroup 49 | 50 | JtParamGroup1 = C.dParamGroup1 51 | LoStopJtParam1 = C.dParamLoStop1 52 | HiStopJtParam1 = C.dParamHiStop1 53 | VelJtParam1 = C.dParamVel1 54 | LoVelJtParam1 = C.dParamLoVel1 55 | HiVelJtParam1 = C.dParamHiVel1 56 | FMaxJtParam1 = C.dParamFMax1 57 | FudgeFactorJtParam1 = C.dParamFudgeFactor1 58 | BounceJtParam1 = C.dParamBounce1 59 | CFMJtParam1 = C.dParamCFM1 60 | StopERPJtParam1 = C.dParamStopERP1 61 | StopCFMJtParam1 = C.dParamStopCFM1 62 | SuspensionERPJtParam1 = C.dParamSuspensionERP1 63 | SuspensionCFMJtParam1 = C.dParamSuspensionCFM1 64 | ERPJtParam1 = C.dParamERP1 65 | 66 | JtParamGroup2 = C.dParamGroup2 67 | LoStopJtParam2 = C.dParamLoStop2 68 | HiStopJtParam2 = C.dParamHiStop2 69 | VelJtParam2 = C.dParamVel2 70 | LoVelJtParam2 = C.dParamLoVel2 71 | HiVelJtParam2 = C.dParamHiVel2 72 | FMaxJtParam2 = C.dParamFMax2 73 | FudgeFactorJtParam2 = C.dParamFudgeFactor2 74 | BounceJtParam2 = C.dParamBounce2 75 | CFMJtParam2 = C.dParamCFM2 76 | StopERPJtParam2 = C.dParamStopERP2 77 | StopCFMJtParam2 = C.dParamStopCFM2 78 | SuspensionERPJtParam2 = C.dParamSuspensionERP2 79 | SuspensionCFMJtParam2 = C.dParamSuspensionCFM2 80 | ERPJtParam2 = C.dParamERP2 81 | 82 | JtParamGroup3 = C.dParamGroup3 83 | LoStopJtParam3 = C.dParamLoStop3 84 | HiStopJtParam3 = C.dParamHiStop3 85 | VelJtParam3 = C.dParamVel3 86 | LoVelJtParam3 = C.dParamLoVel3 87 | HiVelJtParam3 = C.dParamHiVel3 88 | FMaxJtParam3 = C.dParamFMax3 89 | FudgeFactorJtParam3 = C.dParamFudgeFactor3 90 | BounceJtParam3 = C.dParamBounce3 91 | CFMJtParam3 = C.dParamCFM3 92 | StopERPJtParam3 = C.dParamStopERP3 93 | StopCFMJtParam3 = C.dParamStopCFM3 94 | SuspensionERPJtParam3 = C.dParamSuspensionERP3 95 | SuspensionCFMJtParam3 = C.dParamSuspensionCFM3 96 | ERPJtParam3 = C.dParamERP3 97 | ) 98 | 99 | // Angular motor parameters 100 | const ( 101 | AMotorUser = C.dAMotorUser 102 | AMotorEuler = C.dAMotorEuler 103 | ) 104 | 105 | // Transmission parameters 106 | const ( 107 | TransmissionParallelAxes = C.dTransmissionParallelAxes 108 | TransmissionIntersectingAxes = C.dTransmissionIntersectingAxes 109 | TransmissionChainDrive = C.dTransmissionChainDrive 110 | ) 111 | 112 | var ( 113 | jointData = map[Joint]interface{}{} 114 | ) 115 | 116 | // JointFeedback represents feedback forces and torques associated with a 117 | // joint. 118 | type JointFeedback struct { 119 | Force1 Vector3 // force applied to body 1 120 | Torque1 Vector3 // torque applied to body 1 121 | Force2 Vector3 // force applied to body 2 122 | Torque2 Vector3 // torque applied to body 2 123 | } 124 | 125 | func (f *JointFeedback) fromC(c *C.dJointFeedback) { 126 | Vector(f.Force1).fromC(&c.f1[0]) 127 | Vector(f.Torque1).fromC(&c.t1[0]) 128 | Vector(f.Force2).fromC(&c.f2[0]) 129 | Vector(f.Torque2).fromC(&c.t2[0]) 130 | } 131 | 132 | func (f *JointFeedback) toC(c *C.dJointFeedback) { 133 | Vector(f.Force1).toC((*C.dReal)(&c.f1[0])) 134 | Vector(f.Torque1).toC((*C.dReal)(&c.t1[0])) 135 | Vector(f.Force2).toC((*C.dReal)(&c.f2[0])) 136 | Vector(f.Torque2).toC((*C.dReal)(&c.t2[0])) 137 | } 138 | 139 | // JointGroup represents a group of joints. 140 | type JointGroup uintptr 141 | 142 | // NewJointGroup returns a new JointGroup instance. 143 | func NewJointGroup(maxJoints int) JointGroup { 144 | return cToJointGroup(C.dJointGroupCreate(C.int(maxJoints))) 145 | } 146 | 147 | func cToJointGroup(c C.dJointGroupID) JointGroup { 148 | return JointGroup(unsafe.Pointer(c)) 149 | } 150 | 151 | func (g JointGroup) c() C.dJointGroupID { 152 | return C.dJointGroupID(unsafe.Pointer(g)) 153 | } 154 | 155 | // Destroy destroys the joint group. 156 | func (g JointGroup) Destroy() { 157 | C.dJointGroupDestroy(g.c()) 158 | } 159 | 160 | // Empty removes all joints from the group. 161 | func (g JointGroup) Empty() { 162 | C.dJointGroupEmpty(g.c()) 163 | } 164 | 165 | // Joint represents a joint. 166 | type Joint interface { 167 | c() C.dJointID 168 | Destroy() 169 | SetData(data interface{}) 170 | Data() interface{} 171 | NumBodies() int 172 | Attach(body1, body2 Body) 173 | SetEnabled(isEnabled bool) 174 | Enabled() bool 175 | Type() int 176 | Body(index int) Body 177 | SetFeedback(f *JointFeedback) 178 | Feedback() *JointFeedback 179 | } 180 | 181 | // JointBase implements Joint, and is embedded by specific Joint types. 182 | type JointBase uintptr 183 | 184 | func cToJoint(c C.dJointID) Joint { 185 | base := JointBase(unsafe.Pointer(c)) 186 | var j Joint 187 | switch int(C.dJointGetType(c)) { 188 | case BallJointType: 189 | j = BallJoint{base} 190 | case HingeJointType: 191 | j = HingeJoint{base} 192 | case SliderJointType: 193 | j = SliderJoint{base} 194 | case ContactJointType: 195 | j = ContactJoint{base} 196 | case UniversalJointType: 197 | j = UniversalJoint{base} 198 | case Hinge2JointType: 199 | j = Hinge2Joint{base} 200 | case FixedJointType: 201 | j = FixedJoint{base} 202 | case NullJointType: 203 | j = NullJoint{base} 204 | case AMotorJointType: 205 | j = AMotorJoint{base} 206 | case LMotorJointType: 207 | j = LMotorJoint{base} 208 | case Plane2DJointType: 209 | j = Plane2DJoint{base} 210 | case PRJointType: 211 | j = PRJoint{base} 212 | case PUJointType: 213 | j = PUJoint{base} 214 | case PistonJointType: 215 | j = PistonJoint{base} 216 | case DBallJointType: 217 | j = DBallJoint{base} 218 | case DHingeJointType: 219 | j = DHingeJoint{base} 220 | case TransmissionJointType: 221 | j = TransmissionJoint{base} 222 | default: 223 | j = base 224 | } 225 | return j 226 | } 227 | 228 | func (j JointBase) c() C.dJointID { 229 | return C.dJointID(unsafe.Pointer(j)) 230 | } 231 | 232 | // Destroy destroys the joint base. 233 | func (j JointBase) Destroy() { 234 | delete(jointData, j) 235 | C.dJointDestroy(j.c()) 236 | } 237 | 238 | // SetData associates user-specified data with the joint. 239 | func (j JointBase) SetData(data interface{}) { 240 | jointData[j] = data 241 | } 242 | 243 | // Data returns the user-specified data associated with the joint. 244 | func (j JointBase) Data() interface{} { 245 | return jointData[j] 246 | } 247 | 248 | // NumBodies returns the number of attached bodies. 249 | func (j JointBase) NumBodies() int { 250 | return int(C.dJointGetNumBodies(j.c())) 251 | } 252 | 253 | // Attach attaches two bodies with the joint. 254 | func (j JointBase) Attach(body1, body2 Body) { 255 | C.dJointAttach(j.c(), body1.c(), body2.c()) 256 | } 257 | 258 | // SetEnabled sets whether the joint is enabled. 259 | func (j JointBase) SetEnabled(isEnabled bool) { 260 | if isEnabled { 261 | C.dJointEnable(j.c()) 262 | } else { 263 | C.dJointDisable(j.c()) 264 | } 265 | } 266 | 267 | // Enabled returns whether the joint is enabled. 268 | func (j JointBase) Enabled() bool { 269 | return bool(C.dJointIsEnabled(j.c()) != 0) 270 | } 271 | 272 | // Type returns the joint type. 273 | func (j JointBase) Type() int { 274 | return int(C.dJointGetType(j.c())) 275 | } 276 | 277 | // Body returns the attached body, specified by index. 278 | func (j JointBase) Body(index int) Body { 279 | return cToBody(C.dJointGetBody(j.c(), C.int(index))) 280 | } 281 | 282 | // SetFeedback sets the feedback forces and torques. 283 | func (j JointBase) SetFeedback(f *JointFeedback) { 284 | c := &C.dJointFeedback{} 285 | f.toC(c) 286 | C.dJointSetFeedback(j.c(), c) 287 | } 288 | 289 | // Feedback returns the feedback forces and torques. 290 | func (j JointBase) Feedback() *JointFeedback { 291 | f := &JointFeedback{} 292 | f.fromC(C.dJointGetFeedback(j.c())) 293 | return f 294 | } 295 | 296 | // BallJoint implements a ball-and-socket joint. 297 | type BallJoint struct { 298 | JointBase 299 | } 300 | 301 | // SetParam sets a joint parameter. 302 | func (j BallJoint) SetParam(parameter int, value float64) { 303 | C.dJointSetBallParam(j.c(), C.int(parameter), C.dReal(value)) 304 | } 305 | 306 | // Param returns a joint parameter. 307 | func (j BallJoint) Param(parameter int) float64 { 308 | return float64(C.dJointGetBallParam(j.c(), C.int(parameter))) 309 | } 310 | 311 | // SetAnchor sets the anchor point for the first body. 312 | func (j BallJoint) SetAnchor(pt Vector3) { 313 | C.dJointSetBallAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 314 | } 315 | 316 | // Anchor returns the anchor point for the first body. 317 | func (j BallJoint) Anchor() Vector3 { 318 | pt := NewVector3() 319 | C.dJointGetBallAnchor(j.c(), (*C.dReal)(&pt[0])) 320 | return pt 321 | } 322 | 323 | // SetAnchor2 sets the anchor point for the second body. 324 | func (j BallJoint) SetAnchor2(pt Vector3) { 325 | C.dJointSetBallAnchor2(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 326 | } 327 | 328 | // Anchor2 returns the anchor point for the second body. 329 | func (j BallJoint) Anchor2() Vector3 { 330 | pt := NewVector3() 331 | C.dJointGetBallAnchor2(j.c(), (*C.dReal)(&pt[0])) 332 | return pt 333 | } 334 | 335 | // HingeJoint represents a hinge joint. 336 | type HingeJoint struct { 337 | JointBase 338 | } 339 | 340 | // SetParam sets a joint parameter. 341 | func (j HingeJoint) SetParam(parameter int, value float64) { 342 | C.dJointSetHingeParam(j.c(), C.int(parameter), C.dReal(value)) 343 | } 344 | 345 | // Param returns a joint parameter. 346 | func (j HingeJoint) Param(parameter int) float64 { 347 | return float64(C.dJointGetHingeParam(j.c(), C.int(parameter))) 348 | } 349 | 350 | // SetAnchor sets the anchor point. 351 | func (j HingeJoint) SetAnchor(pt Vector3) { 352 | C.dJointSetHingeAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 353 | } 354 | 355 | // SetAnchorDelta sets the hinge anchor delta. 356 | func (j HingeJoint) SetAnchorDelta(pt, delta Vector3) { 357 | C.dJointSetHingeAnchorDelta(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), 358 | C.dReal(delta[0]), C.dReal(delta[1]), C.dReal(delta[2])) 359 | } 360 | 361 | // Anchor returns the anchor point for the first body. 362 | func (j HingeJoint) Anchor() Vector3 { 363 | pt := NewVector3() 364 | C.dJointGetHingeAnchor(j.c(), (*C.dReal)(&pt[0])) 365 | return pt 366 | } 367 | 368 | // Anchor2 returns the anchor point for the second body. 369 | func (j HingeJoint) Anchor2() Vector3 { 370 | pt := NewVector3() 371 | C.dJointGetHingeAnchor2(j.c(), (*C.dReal)(&pt[0])) 372 | return pt 373 | } 374 | 375 | // SetAxis sets the hinge axis. 376 | func (j HingeJoint) SetAxis(axis Vector3) { 377 | C.dJointSetHingeAxis(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 378 | } 379 | 380 | // SetAxisOffset set the hinge axis as if the 2 bodies were already at angle appart. 381 | func (j HingeJoint) SetAxisOffset(axis Vector3, angle float64) { 382 | C.dJointSetHingeAxisOffset(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2]), 383 | C.dReal(angle)) 384 | } 385 | 386 | // Axis returns the hinge axis. 387 | func (j HingeJoint) Axis() Vector3 { 388 | axis := NewVector3() 389 | C.dJointGetHingeAxis(j.c(), (*C.dReal)(&axis[0])) 390 | return axis 391 | } 392 | 393 | // AddTorque adds a torque to the joint. 394 | func (j HingeJoint) AddTorque(torque float64) { 395 | C.dJointAddHingeTorque(j.c(), C.dReal(torque)) 396 | } 397 | 398 | // Angle returns the joint angle. 399 | func (j HingeJoint) Angle() float64 { 400 | return float64(C.dJointGetHingeAngle(j.c())) 401 | } 402 | 403 | // AngleRate returns the joint angle's rate of change. 404 | func (j HingeJoint) AngleRate() float64 { 405 | return float64(C.dJointGetHingeAngleRate(j.c())) 406 | } 407 | 408 | // SliderJoint represents a slider joints. 409 | type SliderJoint struct { 410 | JointBase 411 | } 412 | 413 | // SetParam sets a joint parameter. 414 | func (j SliderJoint) SetParam(parameter int, value float64) { 415 | C.dJointSetSliderParam(j.c(), C.int(parameter), C.dReal(value)) 416 | } 417 | 418 | // Param returns a joint parameter. 419 | func (j SliderJoint) Param(parameter int) float64 { 420 | return float64(C.dJointGetSliderParam(j.c(), C.int(parameter))) 421 | } 422 | 423 | // Position returns the slider position. 424 | func (j SliderJoint) Position() float64 { 425 | return float64(C.dJointGetSliderPosition(j.c())) 426 | } 427 | 428 | // PositionRate returns the slider position's rate of change. 429 | func (j SliderJoint) PositionRate() float64 { 430 | return float64(C.dJointGetSliderPositionRate(j.c())) 431 | } 432 | 433 | // SetAxis sets the slider axis. 434 | func (j SliderJoint) SetAxis(axis Vector3) { 435 | C.dJointSetSliderAxis(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 436 | } 437 | 438 | // SetAxisDelta sets the slider axis delta. 439 | func (j SliderJoint) SetAxisDelta(pt, delta Vector3) { 440 | C.dJointSetSliderAxisDelta(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), 441 | C.dReal(delta[0]), C.dReal(delta[1]), C.dReal(delta[2])) 442 | } 443 | 444 | // Axis returns the slider axis. 445 | func (j SliderJoint) Axis() Vector3 { 446 | axis := NewVector3() 447 | C.dJointGetSliderAxis(j.c(), (*C.dReal)(&axis[0])) 448 | return axis 449 | } 450 | 451 | // AddForce adds a force to the joint. 452 | func (j SliderJoint) AddForce(force float64) { 453 | C.dJointAddSliderForce(j.c(), C.dReal(force)) 454 | } 455 | 456 | // ContactJoint represents a contact joint. 457 | type ContactJoint struct { 458 | JointBase 459 | } 460 | 461 | // UniversalJoint represents a universal joint. 462 | type UniversalJoint struct { 463 | JointBase 464 | } 465 | 466 | // SetParam sets a joint parameter. 467 | func (j UniversalJoint) SetParam(parameter int, value float64) { 468 | C.dJointSetUniversalParam(j.c(), C.int(parameter), C.dReal(value)) 469 | } 470 | 471 | // Param returns a joint parameter. 472 | func (j UniversalJoint) Param(parameter int) float64 { 473 | return float64(C.dJointGetUniversalParam(j.c(), C.int(parameter))) 474 | } 475 | 476 | // SetAnchor sets the anchor point. 477 | func (j UniversalJoint) SetAnchor(pt Vector3) { 478 | C.dJointSetUniversalAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 479 | } 480 | 481 | // Anchor returns the anchor point for the first body. 482 | func (j UniversalJoint) Anchor() Vector3 { 483 | pt := NewVector3() 484 | C.dJointGetUniversalAnchor(j.c(), (*C.dReal)(&pt[0])) 485 | return pt 486 | } 487 | 488 | // Anchor2 returns the anchor point for the second body. 489 | func (j UniversalJoint) Anchor2() Vector3 { 490 | pt := NewVector3() 491 | C.dJointGetUniversalAnchor2(j.c(), (*C.dReal)(&pt[0])) 492 | return pt 493 | } 494 | 495 | // SetAxis1 sets the first axis. 496 | func (j UniversalJoint) SetAxis1(axis Vector3) { 497 | C.dJointSetUniversalAxis1(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 498 | } 499 | 500 | // SetAxis1Offset sets the first axis as if the 2 bodies were already at 501 | // offset1 and offset2 appart with respect to the first and second axes. 502 | func (j UniversalJoint) SetAxis1Offset(axis Vector3, offset1, offset2 float64) { 503 | C.dJointSetUniversalAxis1Offset(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2]), 504 | C.dReal(offset1), C.dReal(offset2)) 505 | } 506 | 507 | // Axis1 returns the first axis. 508 | func (j UniversalJoint) Axis1() Vector3 { 509 | axis := NewVector3() 510 | C.dJointGetUniversalAxis1(j.c(), (*C.dReal)(&axis[0])) 511 | return axis 512 | } 513 | 514 | // SetAxis2 sets the second axis. 515 | func (j UniversalJoint) SetAxis2(axis Vector3) { 516 | C.dJointSetUniversalAxis2(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 517 | } 518 | 519 | // SetAxis2Offset sets the second axis as if the 2 bodies were already at 520 | // offset1 and offset2 appart with respect to the first and second axes. 521 | func (j UniversalJoint) SetAxis2Offset(axis Vector3, offset1, offset2 float64) { 522 | C.dJointSetUniversalAxis2Offset(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2]), 523 | C.dReal(offset1), C.dReal(offset1)) 524 | } 525 | 526 | // Axis2 returns the second axis. 527 | func (j UniversalJoint) Axis2() Vector3 { 528 | axis := NewVector3() 529 | C.dJointGetUniversalAxis2(j.c(), (*C.dReal)(&axis[0])) 530 | return axis 531 | } 532 | 533 | // Angle1 returns the first angle. 534 | func (j UniversalJoint) Angle1() float64 { 535 | return float64(C.dJointGetUniversalAngle1(j.c())) 536 | } 537 | 538 | // Angle1Rate returns the first angle's rate of change. 539 | func (j UniversalJoint) Angle1Rate() float64 { 540 | return float64(C.dJointGetUniversalAngle1Rate(j.c())) 541 | } 542 | 543 | // Angle2 returns the second angle. 544 | func (j UniversalJoint) Angle2() float64 { 545 | return float64(C.dJointGetUniversalAngle2(j.c())) 546 | } 547 | 548 | // Angle2Rate returns the second angle's rate of change. 549 | func (j UniversalJoint) Angle2Rate() float64 { 550 | return float64(C.dJointGetUniversalAngle2Rate(j.c())) 551 | } 552 | 553 | // Angles returns the two angles. 554 | func (j UniversalJoint) Angles() (float64, float64) { 555 | var angle1, angle2 float64 556 | C.dJointGetUniversalAngles(j.c(), (*C.dReal)(&angle1), (*C.dReal)(&angle2)) 557 | return angle1, angle2 558 | } 559 | 560 | // AddTorques adds torques to the joint. 561 | func (j UniversalJoint) AddTorques(torque1, torque2 float64) { 562 | C.dJointAddUniversalTorques(j.c(), C.dReal(torque1), C.dReal(torque2)) 563 | } 564 | 565 | // Hinge2Joint represents two hinge joints in series. 566 | type Hinge2Joint struct { 567 | JointBase 568 | } 569 | 570 | // SetParam sets a joint parameter. 571 | func (j Hinge2Joint) SetParam(parameter int, value float64) { 572 | C.dJointSetHinge2Param(j.c(), C.int(parameter), C.dReal(value)) 573 | } 574 | 575 | // Param returns a joint parameter. 576 | func (j Hinge2Joint) Param(parameter int) float64 { 577 | return float64(C.dJointGetHinge2Param(j.c(), C.int(parameter))) 578 | } 579 | 580 | // SetAnchor sets the anchor point. 581 | func (j Hinge2Joint) SetAnchor(pt Vector3) { 582 | C.dJointSetHinge2Anchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 583 | } 584 | 585 | // Anchor returns the anchor point for the first body. 586 | func (j Hinge2Joint) Anchor() Vector3 { 587 | pt := NewVector3() 588 | C.dJointGetHinge2Anchor(j.c(), (*C.dReal)(&pt[0])) 589 | return pt 590 | } 591 | 592 | // Anchor2 returns the anchor point for the second body. 593 | func (j Hinge2Joint) Anchor2() Vector3 { 594 | pt := NewVector3() 595 | C.dJointGetHinge2Anchor2(j.c(), (*C.dReal)(&pt[0])) 596 | return pt 597 | } 598 | 599 | // SetAxis1 sets the first axis. 600 | func (j Hinge2Joint) SetAxis1(axis Vector3) { 601 | C.dJointSetHinge2Axis1(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 602 | } 603 | 604 | // Axis1 returns the first axis. 605 | func (j Hinge2Joint) Axis1() Vector3 { 606 | axis := NewVector3() 607 | C.dJointGetHinge2Axis1(j.c(), (*C.dReal)(&axis[0])) 608 | return axis 609 | } 610 | 611 | // SetAxis2 sets the second axis. 612 | func (j Hinge2Joint) SetAxis2(axis Vector3) { 613 | C.dJointSetHinge2Axis2(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 614 | } 615 | 616 | // Axis2 returns the second axis. 617 | func (j Hinge2Joint) Axis2() Vector3 { 618 | axis := NewVector3() 619 | C.dJointGetHinge2Axis2(j.c(), (*C.dReal)(&axis[0])) 620 | return axis 621 | } 622 | 623 | // Angle1 returns the first angle. 624 | func (j Hinge2Joint) Angle1() float64 { 625 | return float64(C.dJointGetHinge2Angle1(j.c())) 626 | } 627 | 628 | // Angle1Rate returns the first angle's rate of change. 629 | func (j Hinge2Joint) Angle1Rate() float64 { 630 | return float64(C.dJointGetHinge2Angle1Rate(j.c())) 631 | } 632 | 633 | // Angle2 returns the second angle. 634 | func (j Hinge2Joint) Angle2() float64 { 635 | return float64(C.dJointGetHinge2Angle2(j.c())) 636 | } 637 | 638 | // Angle2Rate returns the second angle's rate of change. 639 | func (j Hinge2Joint) Angle2Rate() float64 { 640 | return float64(C.dJointGetHinge2Angle2Rate(j.c())) 641 | } 642 | 643 | // AddTorques adds torques to the joint. 644 | func (j Hinge2Joint) AddTorques(torque1, torque2 float64) { 645 | C.dJointAddHinge2Torques(j.c(), C.dReal(torque1), C.dReal(torque2)) 646 | } 647 | 648 | // FixedJoint represents a fixed joint. 649 | type FixedJoint struct { 650 | JointBase 651 | } 652 | 653 | // SetParam sets a joint parameter. 654 | func (j FixedJoint) SetParam(parameter int, value float64) { 655 | C.dJointSetFixedParam(j.c(), C.int(parameter), C.dReal(value)) 656 | } 657 | 658 | // Param returns a joint parameter. 659 | func (j FixedJoint) Param(parameter int) float64 { 660 | return float64(C.dJointGetFixedParam(j.c(), C.int(parameter))) 661 | } 662 | 663 | // Fix fixes the joint in its current state. 664 | func (j FixedJoint) Fix() { 665 | C.dJointSetFixed(j.c()) 666 | } 667 | 668 | // NullJoint represents a null joint. 669 | type NullJoint struct { 670 | JointBase 671 | } 672 | 673 | // AMotorJoint represents an angular motor joint. 674 | type AMotorJoint struct { 675 | JointBase 676 | } 677 | 678 | // SetParam sets a joint parameter. 679 | func (j AMotorJoint) SetParam(parameter int, value float64) { 680 | C.dJointSetAMotorParam(j.c(), C.int(parameter), C.dReal(value)) 681 | } 682 | 683 | // Param returns a joint parameter. 684 | func (j AMotorJoint) Param(parameter int) float64 { 685 | return float64(C.dJointGetAMotorParam(j.c(), C.int(parameter))) 686 | } 687 | 688 | // SetNumAxes sets the number of axes. 689 | func (j AMotorJoint) SetNumAxes(num int) { 690 | C.dJointSetAMotorNumAxes(j.c(), C.int(num)) 691 | } 692 | 693 | // NumAxes returns the number of axes. 694 | func (j AMotorJoint) NumAxes() int { 695 | return int(C.dJointGetAMotorNumAxes(j.c())) 696 | } 697 | 698 | // SetAxis sets the given axis relative to body rel (1 or 2) or none (0). 699 | func (j AMotorJoint) SetAxis(num, rel int, axis Vector3) { 700 | C.dJointSetAMotorAxis(j.c(), C.int(num), C.int(rel), 701 | C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 702 | } 703 | 704 | // Axis returns the given axis. 705 | func (j AMotorJoint) Axis(num int) Vector3 { 706 | axis := NewVector3() 707 | C.dJointGetAMotorAxis(j.c(), C.int(num), (*C.dReal)(&axis[0])) 708 | return axis 709 | } 710 | 711 | // AxisRel returns the relative mode for the given axis. 712 | func (j AMotorJoint) AxisRel(num int) int { 713 | return int(C.dJointGetAMotorAxisRel(j.c(), C.int(num))) 714 | } 715 | 716 | // SetAngle sets the angle of the given axis. 717 | func (j AMotorJoint) SetAngle(num int, angle float64) { 718 | C.dJointSetAMotorAngle(j.c(), C.int(num), C.dReal(angle)) 719 | } 720 | 721 | // Angle returns the angle of the given axis. 722 | func (j AMotorJoint) Angle(num int) float64 { 723 | return float64(C.dJointGetAMotorAngle(j.c(), C.int(num))) 724 | } 725 | 726 | // AngleRate returns the angle's rate of change for the given axis. 727 | func (j AMotorJoint) AngleRate(num int) float64 { 728 | return float64(C.dJointGetAMotorAngleRate(j.c(), C.int(num))) 729 | } 730 | 731 | // SetMode sets the mode. 732 | func (j AMotorJoint) SetMode(mode int) { 733 | C.dJointSetAMotorMode(j.c(), C.int(mode)) 734 | } 735 | 736 | // Mode returns the mode. 737 | func (j AMotorJoint) Mode() int { 738 | return int(C.dJointGetAMotorMode(j.c())) 739 | } 740 | 741 | // AddTorques adds torques to the joint. 742 | func (j AMotorJoint) AddTorques(torque1, torque2, torque3 float64) { 743 | C.dJointAddAMotorTorques(j.c(), C.dReal(torque1), C.dReal(torque2), C.dReal(torque3)) 744 | } 745 | 746 | // LMotorJoint represents a linear motor joint. 747 | type LMotorJoint struct { 748 | JointBase 749 | } 750 | 751 | // SetParam sets a joint parameter. 752 | func (j LMotorJoint) SetParam(parameter int, value float64) { 753 | C.dJointSetLMotorParam(j.c(), C.int(parameter), C.dReal(value)) 754 | } 755 | 756 | // Param returns a joint parameter. 757 | func (j LMotorJoint) Param(parameter int) float64 { 758 | return float64(C.dJointGetLMotorParam(j.c(), C.int(parameter))) 759 | } 760 | 761 | // SetNumAxes sets the number of axes. 762 | func (j LMotorJoint) SetNumAxes(num int) { 763 | C.dJointSetLMotorNumAxes(j.c(), C.int(num)) 764 | } 765 | 766 | // NumAxes returns the number of axes. 767 | func (j LMotorJoint) NumAxes() int { 768 | return int(C.dJointGetLMotorNumAxes(j.c())) 769 | } 770 | 771 | // SetAxis sets the given axis relative to a body (1 or 2) or none (0). 772 | func (j LMotorJoint) SetAxis(num, rel int, axis Vector3) { 773 | C.dJointSetLMotorAxis(j.c(), C.int(num), C.int(rel), 774 | C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 775 | } 776 | 777 | // Axis returns the given axis. 778 | func (j LMotorJoint) Axis(num int) Vector3 { 779 | axis := NewVector3() 780 | C.dJointGetLMotorAxis(j.c(), C.int(num), (*C.dReal)(&axis[0])) 781 | return axis 782 | } 783 | 784 | // Plane2DJoint represents a plane joint. 785 | type Plane2DJoint struct { 786 | JointBase 787 | } 788 | 789 | // SetXParam sets a joint parameter. 790 | func (j Plane2DJoint) SetXParam(parameter int, value float64) { 791 | C.dJointSetPlane2DXParam(j.c(), C.int(parameter), C.dReal(value)) 792 | } 793 | 794 | // SetYParam sets a joint parameter. 795 | func (j Plane2DJoint) SetYParam(parameter int, value float64) { 796 | C.dJointSetPlane2DYParam(j.c(), C.int(parameter), C.dReal(value)) 797 | } 798 | 799 | // SetAngleParam sets a joint parameter. 800 | func (j Plane2DJoint) SetAngleParam(parameter int, value float64) { 801 | C.dJointSetPlane2DAngleParam(j.c(), C.int(parameter), C.dReal(value)) 802 | } 803 | 804 | // PRJoint represents a prismatic rotoide joint. 805 | type PRJoint struct { 806 | JointBase 807 | } 808 | 809 | // SetParam sets a joint parameter. 810 | func (j PRJoint) SetParam(parameter int, value float64) { 811 | C.dJointSetPRParam(j.c(), C.int(parameter), C.dReal(value)) 812 | } 813 | 814 | // Param returns a joint parameter. 815 | func (j PRJoint) Param(parameter int) float64 { 816 | return float64(C.dJointGetPRParam(j.c(), C.int(parameter))) 817 | } 818 | 819 | // SetAnchor sets the anchor point. 820 | func (j PRJoint) SetAnchor(pt Vector3) { 821 | C.dJointSetPRAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 822 | } 823 | 824 | // Anchor returns the anchor point. 825 | func (j PRJoint) Anchor() Vector3 { 826 | pt := NewVector3() 827 | C.dJointGetPRAnchor(j.c(), (*C.dReal)(&pt[0])) 828 | return pt 829 | } 830 | 831 | // SetAxis1 sets the first axis. 832 | func (j PRJoint) SetAxis1(axis Vector3) { 833 | C.dJointSetPRAxis1(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 834 | } 835 | 836 | // Axis1 returns the first axis. 837 | func (j PRJoint) Axis1() Vector3 { 838 | axis := NewVector3() 839 | C.dJointGetPRAxis1(j.c(), (*C.dReal)(&axis[0])) 840 | return axis 841 | } 842 | 843 | // SetAxis2 sets the second axis. 844 | func (j PRJoint) SetAxis2(axis Vector3) { 845 | C.dJointSetPRAxis2(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 846 | } 847 | 848 | // Axis2 returns the second axis. 849 | func (j PRJoint) Axis2() Vector3 { 850 | axis := NewVector3() 851 | C.dJointGetPRAxis2(j.c(), (*C.dReal)(&axis[0])) 852 | return axis 853 | } 854 | 855 | // Position returns the slider position. 856 | func (j PRJoint) Position() float64 { 857 | return float64(C.dJointGetPRPosition(j.c())) 858 | } 859 | 860 | // PositionRate returns the slider position's rate of change. 861 | func (j PRJoint) PositionRate() float64 { 862 | return float64(C.dJointGetPRPositionRate(j.c())) 863 | } 864 | 865 | // Angle returns the joint angle. 866 | func (j PRJoint) Angle() float64 { 867 | return float64(C.dJointGetPRAngle(j.c())) 868 | } 869 | 870 | // AngleRate returns the joint angle's rate of change. 871 | func (j PRJoint) AngleRate() float64 { 872 | return float64(C.dJointGetPRAngleRate(j.c())) 873 | } 874 | 875 | // AddTorque adds a torque to the joint. 876 | func (j PRJoint) AddTorque(torque float64) { 877 | C.dJointAddPRTorque(j.c(), C.dReal(torque)) 878 | } 879 | 880 | // PUJoint represents a prismatic universal joint. 881 | type PUJoint struct { 882 | JointBase 883 | } 884 | 885 | // SetParam sets a joint parameter. 886 | func (j PUJoint) SetParam(parameter int, value float64) { 887 | C.dJointSetPUParam(j.c(), C.int(parameter), C.dReal(value)) 888 | } 889 | 890 | // Param returns a joint parameter. 891 | func (j PUJoint) Param(parameter int) float64 { 892 | return float64(C.dJointGetPUParam(j.c(), C.int(parameter))) 893 | } 894 | 895 | // SetAnchor sets the anchor point. 896 | func (j PUJoint) SetAnchor(pt Vector3) { 897 | C.dJointSetPUAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 898 | } 899 | 900 | // Anchor returns the anchor point. 901 | func (j PUJoint) Anchor() Vector3 { 902 | pt := NewVector3() 903 | C.dJointGetPUAnchor(j.c(), (*C.dReal)(&pt[0])) 904 | return pt 905 | } 906 | 907 | // SetAnchorOffset sets the anchor as if the 2 bodies were already delta appart. 908 | func (j PUJoint) SetAnchorOffset(pt, delta Vector3) { 909 | C.dJointSetPUAnchorOffset(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), 910 | C.dReal(delta[0]), C.dReal(delta[1]), C.dReal(delta[2])) 911 | } 912 | 913 | // SetAxis1 sets the first axis. 914 | func (j PUJoint) SetAxis1(axis Vector3) { 915 | C.dJointSetPUAxis1(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 916 | } 917 | 918 | // Axis1 returns the first axis. 919 | func (j PUJoint) Axis1() Vector3 { 920 | axis := NewVector3() 921 | C.dJointGetPUAxis1(j.c(), (*C.dReal)(&axis[0])) 922 | return axis 923 | } 924 | 925 | // SetAxis2 sets the second axis. 926 | func (j PUJoint) SetAxis2(axis Vector3) { 927 | C.dJointSetPUAxis2(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 928 | } 929 | 930 | // Axis2 returns the second axis. 931 | func (j PUJoint) Axis2() Vector3 { 932 | axis := NewVector3() 933 | C.dJointGetPUAxis2(j.c(), (*C.dReal)(&axis[0])) 934 | return axis 935 | } 936 | 937 | // SetAxis3 sets the third (prismatic) axis. 938 | func (j PUJoint) SetAxis3(axis Vector3) { 939 | C.dJointSetPUAxis3(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 940 | } 941 | 942 | // Axis3 returns the third (prismatic) axis. 943 | func (j PUJoint) Axis3() Vector3 { 944 | axis := NewVector3() 945 | C.dJointGetPUAxis3(j.c(), (*C.dReal)(&axis[0])) 946 | return axis 947 | } 948 | 949 | // Position returns the joint position. 950 | func (j PUJoint) Position() float64 { 951 | return float64(C.dJointGetPUPosition(j.c())) 952 | } 953 | 954 | // PositionRate returns the joint position's rate of change. 955 | func (j PUJoint) PositionRate() float64 { 956 | return float64(C.dJointGetPUPositionRate(j.c())) 957 | } 958 | 959 | // Angle1 returns the first angle. 960 | func (j PUJoint) Angle1() float64 { 961 | return float64(C.dJointGetPUAngle1(j.c())) 962 | } 963 | 964 | // Angle1Rate returns the first angle's rate of change. 965 | func (j PUJoint) Angle1Rate() float64 { 966 | return float64(C.dJointGetPUAngle1Rate(j.c())) 967 | } 968 | 969 | // Angle2 returns the second angle. 970 | func (j PUJoint) Angle2() float64 { 971 | return float64(C.dJointGetPUAngle2(j.c())) 972 | } 973 | 974 | // Angle2Rate returns the second angle's rate of change. 975 | func (j PUJoint) Angle2Rate() float64 { 976 | return float64(C.dJointGetPUAngle2Rate(j.c())) 977 | } 978 | 979 | // Angles returns the two joint angles. 980 | func (j PUJoint) Angles() (float64, float64) { 981 | var angle1, angle2 float64 982 | C.dJointGetPUAngles(j.c(), (*C.dReal)(&angle1), (*C.dReal)(&angle2)) 983 | return angle1, angle2 984 | } 985 | 986 | // PistonJoint represents a piston joint. 987 | type PistonJoint struct { 988 | JointBase 989 | } 990 | 991 | // SetParam sets a joint parameter. 992 | func (j PistonJoint) SetParam(parameter int, value float64) { 993 | C.dJointSetPistonParam(j.c(), C.int(parameter), C.dReal(value)) 994 | } 995 | 996 | // Param returns a joint parameter. 997 | func (j PistonJoint) Param(parameter int) float64 { 998 | return float64(C.dJointGetPistonParam(j.c(), C.int(parameter))) 999 | } 1000 | 1001 | // SetAnchor sets the anchor point. 1002 | func (j PistonJoint) SetAnchor(pt Vector3) { 1003 | C.dJointSetPistonAnchor(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1004 | } 1005 | 1006 | // SetAnchorOffset sets the anchor as if the 2 bodies were already delta appart. 1007 | func (j PistonJoint) SetAnchorOffset(pt, delta Vector3) { 1008 | C.dJointSetPistonAnchorOffset(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2]), 1009 | C.dReal(delta[0]), C.dReal(delta[1]), C.dReal(delta[2])) 1010 | } 1011 | 1012 | // Anchor2 returns the anchor point for the second body. 1013 | func (j PistonJoint) Anchor2() Vector3 { 1014 | pt := NewVector3() 1015 | C.dJointGetPistonAnchor2(j.c(), (*C.dReal)(&pt[0])) 1016 | return pt 1017 | } 1018 | 1019 | // SetAxis sets the piston axis. 1020 | func (j PistonJoint) SetAxis(axis Vector3) { 1021 | C.dJointSetPistonAxis(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 1022 | } 1023 | 1024 | // Axis returns the piston axis. 1025 | func (j PistonJoint) Axis() Vector3 { 1026 | axis := NewVector3() 1027 | C.dJointGetPistonAxis(j.c(), (*C.dReal)(&axis[0])) 1028 | return axis 1029 | } 1030 | 1031 | // Position returns the piston position. 1032 | func (j PistonJoint) Position() float64 { 1033 | return float64(C.dJointGetPistonPosition(j.c())) 1034 | } 1035 | 1036 | // PositionRate returns the piston position's rate of change. 1037 | func (j PistonJoint) PositionRate() float64 { 1038 | return float64(C.dJointGetPistonPositionRate(j.c())) 1039 | } 1040 | 1041 | // Angle returns the joint angle. 1042 | func (j PistonJoint) Angle() float64 { 1043 | return float64(C.dJointGetPistonAngle(j.c())) 1044 | } 1045 | 1046 | // AngleRate returns the joint angle's rate of change. 1047 | func (j PistonJoint) AngleRate() float64 { 1048 | return float64(C.dJointGetPistonAngleRate(j.c())) 1049 | } 1050 | 1051 | // AddForce adds a force to the joint. 1052 | func (j PistonJoint) AddForce(force float64) { 1053 | C.dJointAddPistonForce(j.c(), C.dReal(force)) 1054 | } 1055 | 1056 | // DBallJoint represents a double ball joint. 1057 | type DBallJoint struct { 1058 | JointBase 1059 | } 1060 | 1061 | // SetParam sets a joint parameter. 1062 | func (j DBallJoint) SetParam(parameter int, value float64) { 1063 | C.dJointSetDBallParam(j.c(), C.int(parameter), C.dReal(value)) 1064 | } 1065 | 1066 | // Param returns a joint parameter. 1067 | func (j DBallJoint) Param(parameter int) float64 { 1068 | return float64(C.dJointGetDBallParam(j.c(), C.int(parameter))) 1069 | } 1070 | 1071 | // SetAnchor1 sets the anchor point for the first body. 1072 | func (j DBallJoint) SetAnchor1(pt Vector3) { 1073 | C.dJointSetDBallAnchor1(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1074 | } 1075 | 1076 | // Anchor1 returns the anchor point for the first body. 1077 | func (j DBallJoint) Anchor1() Vector3 { 1078 | pt := NewVector3() 1079 | C.dJointGetDBallAnchor1(j.c(), (*C.dReal)(&pt[0])) 1080 | return pt 1081 | } 1082 | 1083 | // SetAnchor2 sets the anchor point for the second body. 1084 | func (j DBallJoint) SetAnchor2(pt Vector3) { 1085 | C.dJointSetDBallAnchor2(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1086 | } 1087 | 1088 | // Anchor2 returns the anchor point for the second body. 1089 | func (j DBallJoint) Anchor2() Vector3 { 1090 | pt := NewVector3() 1091 | C.dJointGetDBallAnchor2(j.c(), (*C.dReal)(&pt[0])) 1092 | return pt 1093 | } 1094 | 1095 | // Distance returns the joint distance. 1096 | func (j DBallJoint) Distance() float64 { 1097 | return float64(C.dJointGetDBallDistance(j.c())) 1098 | } 1099 | 1100 | // DHingeJoint represents a double hinge joint. 1101 | type DHingeJoint struct { 1102 | JointBase 1103 | } 1104 | 1105 | // SetParam sets a joint parameter. 1106 | func (j DHingeJoint) SetParam(parameter int, value float64) { 1107 | C.dJointSetDHingeParam(j.c(), C.int(parameter), C.dReal(value)) 1108 | } 1109 | 1110 | // Param returns a joint parameter. 1111 | func (j DHingeJoint) Param(parameter int) float64 { 1112 | return float64(C.dJointGetDHingeParam(j.c(), C.int(parameter))) 1113 | } 1114 | 1115 | // SetAxis sets the joint axis. 1116 | func (j DHingeJoint) SetAxis(axis Vector3) { 1117 | C.dJointSetDHingeAxis(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 1118 | } 1119 | 1120 | // Axis returns the joint axis. 1121 | func (j DHingeJoint) Axis() Vector3 { 1122 | axis := NewVector3() 1123 | C.dJointGetDHingeAxis(j.c(), (*C.dReal)(&axis[0])) 1124 | return axis 1125 | } 1126 | 1127 | // SetAnchor1 sets the anchor point for the first body. 1128 | func (j DHingeJoint) SetAnchor1(pt Vector3) { 1129 | C.dJointSetDHingeAnchor1(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1130 | } 1131 | 1132 | // Anchor1 returns the anchor point for the first body. 1133 | func (j DHingeJoint) Anchor1() Vector3 { 1134 | pt := NewVector3() 1135 | C.dJointGetDHingeAnchor1(j.c(), (*C.dReal)(&pt[0])) 1136 | return pt 1137 | } 1138 | 1139 | // SetAnchor2 sets the anchor point for the second body. 1140 | func (j DHingeJoint) SetAnchor2(pt Vector3) { 1141 | C.dJointSetDHingeAnchor2(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1142 | } 1143 | 1144 | // Anchor2 returns the anchor point for the second body. 1145 | func (j DHingeJoint) Anchor2() Vector3 { 1146 | pt := NewVector3() 1147 | C.dJointGetDHingeAnchor2(j.c(), (*C.dReal)(&pt[0])) 1148 | return pt 1149 | } 1150 | 1151 | // Distance returns the joint distance. 1152 | func (j DHingeJoint) Distance() float64 { 1153 | return float64(C.dJointGetDHingeDistance(j.c())) 1154 | } 1155 | 1156 | // TransmissionJoint represents a transmission joint. 1157 | type TransmissionJoint struct { 1158 | JointBase 1159 | } 1160 | 1161 | // SetParam sets a joint parameter. 1162 | func (j TransmissionJoint) SetParam(parameter int, value float64) { 1163 | C.dJointSetTransmissionParam(j.c(), C.int(parameter), C.dReal(value)) 1164 | } 1165 | 1166 | // Param returns a joint parameter. 1167 | func (j TransmissionJoint) Param(parameter int) float64 { 1168 | return float64(C.dJointGetTransmissionParam(j.c(), C.int(parameter))) 1169 | } 1170 | 1171 | // SetAxis sets the common axis. 1172 | func (j TransmissionJoint) SetAxis(axis Vector3) { 1173 | C.dJointSetTransmissionAxis(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 1174 | } 1175 | 1176 | // Axis returns the common axis. 1177 | func (j TransmissionJoint) Axis() Vector3 { 1178 | axis := NewVector3() 1179 | C.dJointGetTransmissionAxis(j.c(), (*C.dReal)(&axis[0])) 1180 | return axis 1181 | } 1182 | 1183 | // SetAxis1 sets the first axis. 1184 | func (j TransmissionJoint) SetAxis1(axis Vector3) { 1185 | C.dJointSetTransmissionAxis1(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 1186 | } 1187 | 1188 | // Axis1 returns the first axis. 1189 | func (j TransmissionJoint) Axis1() Vector3 { 1190 | axis := NewVector3() 1191 | C.dJointGetTransmissionAxis1(j.c(), (*C.dReal)(&axis[0])) 1192 | return axis 1193 | } 1194 | 1195 | // SetAxis2 sets the second axis. 1196 | func (j TransmissionJoint) SetAxis2(axis Vector3) { 1197 | C.dJointSetTransmissionAxis2(j.c(), C.dReal(axis[0]), C.dReal(axis[1]), C.dReal(axis[2])) 1198 | } 1199 | 1200 | // Axis2 returns the second axis. 1201 | func (j TransmissionJoint) Axis2() Vector3 { 1202 | axis := NewVector3() 1203 | C.dJointGetTransmissionAxis2(j.c(), (*C.dReal)(&axis[0])) 1204 | return axis 1205 | } 1206 | 1207 | // SetAnchor1 sets the anchor point for the first body. 1208 | func (j TransmissionJoint) SetAnchor1(pt Vector3) { 1209 | C.dJointSetTransmissionAnchor1(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1210 | } 1211 | 1212 | // Anchor1 returns the anchor point for the first body. 1213 | func (j TransmissionJoint) Anchor1() Vector3 { 1214 | pt := NewVector3() 1215 | C.dJointGetTransmissionAnchor1(j.c(), (*C.dReal)(&pt[0])) 1216 | return pt 1217 | } 1218 | 1219 | // SetAnchor2 sets the anchor point for the second body. 1220 | func (j TransmissionJoint) SetAnchor2(pt Vector3) { 1221 | C.dJointSetTransmissionAnchor2(j.c(), C.dReal(pt[0]), C.dReal(pt[1]), C.dReal(pt[2])) 1222 | } 1223 | 1224 | // Anchor2 returns the anchor point for the second body. 1225 | func (j TransmissionJoint) Anchor2() Vector3 { 1226 | pt := NewVector3() 1227 | C.dJointGetTransmissionAnchor2(j.c(), (*C.dReal)(&pt[0])) 1228 | return pt 1229 | } 1230 | 1231 | // ContactPoint1 returns the contact point on the first wheel. 1232 | func (j TransmissionJoint) ContactPoint1() Vector3 { 1233 | pt := NewVector3() 1234 | C.dJointGetTransmissionContactPoint1(j.c(), (*C.dReal)(&pt[0])) 1235 | return pt 1236 | } 1237 | 1238 | // ContactPoint2 returns the contact point on the second wheel. 1239 | func (j TransmissionJoint) ContactPoint2() Vector3 { 1240 | pt := NewVector3() 1241 | C.dJointGetTransmissionContactPoint2(j.c(), (*C.dReal)(&pt[0])) 1242 | return pt 1243 | } 1244 | 1245 | // Angle1 returns the angle of the first wheel. 1246 | func (j TransmissionJoint) Angle1() float64 { 1247 | return float64(C.dJointGetTransmissionAngle1(j.c())) 1248 | } 1249 | 1250 | // Angle2 returns the angle of the second wheel. 1251 | func (j TransmissionJoint) Angle2() float64 { 1252 | return float64(C.dJointGetTransmissionAngle2(j.c())) 1253 | } 1254 | 1255 | // SetRadius1 sets the radius of the first wheel. 1256 | func (j TransmissionJoint) SetRadius1(radius float64) { 1257 | C.dJointSetTransmissionRadius1(j.c(), C.dReal(radius)) 1258 | } 1259 | 1260 | // Radius1 returns the radius of the first wheel. 1261 | func (j TransmissionJoint) Radius1() float64 { 1262 | return float64(C.dJointGetTransmissionRadius1(j.c())) 1263 | } 1264 | 1265 | // SetRadius2 sets the radius of the second wheel. 1266 | func (j TransmissionJoint) SetRadius2(radius float64) { 1267 | C.dJointSetTransmissionRadius2(j.c(), C.dReal(radius)) 1268 | } 1269 | 1270 | // Radius2 returns the radius of the second wheel. 1271 | func (j TransmissionJoint) Radius2() float64 { 1272 | return float64(C.dJointGetTransmissionRadius2(j.c())) 1273 | } 1274 | 1275 | // SetMode sets the transmission mode. 1276 | func (j TransmissionJoint) SetMode(mode int) { 1277 | C.dJointSetTransmissionMode(j.c(), C.int(mode)) 1278 | } 1279 | 1280 | // Mode returns the transmission mode. 1281 | func (j TransmissionJoint) Mode() int { 1282 | return int(C.dJointGetTransmissionMode(j.c())) 1283 | } 1284 | 1285 | // SetRatio sets the gear ratio. 1286 | func (j TransmissionJoint) SetRatio(ratio float64) { 1287 | C.dJointSetTransmissionRatio(j.c(), C.dReal(ratio)) 1288 | } 1289 | 1290 | // Ratio returns the gear ratio. 1291 | func (j TransmissionJoint) Ratio() float64 { 1292 | return float64(C.dJointGetTransmissionRatio(j.c())) 1293 | } 1294 | 1295 | // SetBacklash set the backlash (gear tooth play distance). 1296 | func (j TransmissionJoint) SetBacklash(backlash float64) { 1297 | C.dJointSetTransmissionBacklash(j.c(), C.dReal(backlash)) 1298 | } 1299 | 1300 | // Backlash returns the backlash (gear tooth play distance). 1301 | func (j TransmissionJoint) Backlash() float64 { 1302 | return float64(C.dJointGetTransmissionBacklash(j.c())) 1303 | } 1304 | -------------------------------------------------------------------------------- /mass.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | import "C" 5 | 6 | // Mass represents object mass properties. 7 | type Mass struct { 8 | Center Vector3 9 | Inertia Matrix3 10 | Mass float64 11 | } 12 | 13 | func (m *Mass) toC(c *C.dMass) { 14 | c.mass = C.dReal(m.Mass) 15 | Vector(m.Center).toC((*C.dReal)(&c.c[0])) 16 | Matrix(m.Inertia).toC((*C.dReal)(&c.I[0])) 17 | } 18 | 19 | func (m *Mass) fromC(c *C.dMass) { 20 | m.Mass = float64(c.mass) 21 | Vector(m.Center).fromC((*C.dReal)(&c.c[0])) 22 | Matrix(m.Inertia).fromC((*C.dReal)(&c.I[0])) 23 | } 24 | 25 | // NewMass returns a new Mass instance. 26 | func NewMass() *Mass { 27 | return &Mass{ 28 | Center: NewVector3(), 29 | Inertia: NewMatrix3(), 30 | } 31 | } 32 | 33 | // Check returns whether the mass's parameter values are valid. 34 | func (m *Mass) Check() bool { 35 | c := &C.dMass{} 36 | m.toC(c) 37 | return C.dMassCheck(c) != 0 38 | } 39 | 40 | // SetZero sets the mass to 0. 41 | func (m *Mass) SetZero() { 42 | c := &C.dMass{} 43 | C.dMassSetZero(c) 44 | m.fromC(c) 45 | } 46 | 47 | // SetParams sets the mass parameters. 48 | func (m *Mass) SetParams(mass float64, com Vector3, inert Matrix3) { 49 | c := &C.dMass{} 50 | C.dMassSetParameters(c, C.dReal(mass), 51 | C.dReal(com[0]), C.dReal(com[1]), C.dReal(com[2]), 52 | C.dReal(inert[0][0]), C.dReal(inert[1][1]), C.dReal(inert[2][2]), 53 | C.dReal(inert[0][1]), C.dReal(inert[0][2]), C.dReal(inert[1][3])) 54 | m.fromC(c) 55 | } 56 | 57 | // SetSphere sets the mass for a sphere of given properties. 58 | func (m *Mass) SetSphere(density, radius float64) { 59 | c := &C.dMass{} 60 | C.dMassSetSphere(c, C.dReal(density), C.dReal(radius)) 61 | m.fromC(c) 62 | } 63 | 64 | // SetSphereTotal sets the mass for a sphere of given properties. 65 | func (m *Mass) SetSphereTotal(totalMass, radius float64) { 66 | c := &C.dMass{} 67 | C.dMassSetSphereTotal(c, C.dReal(totalMass), C.dReal(radius)) 68 | m.fromC(c) 69 | } 70 | 71 | // SetCapsule sets the mass for a capsule of given properties. 72 | func (m *Mass) SetCapsule(density float64, direction int, radius, length float64) { 73 | c := &C.dMass{} 74 | C.dMassSetCapsule(c, C.dReal(density), C.int(direction), C.dReal(radius), 75 | C.dReal(length)) 76 | m.fromC(c) 77 | } 78 | 79 | // SetCapsuleTotal sets the mass for a capsule of given properties. 80 | func (m *Mass) SetCapsuleTotal(totalMass float64, direction int, radius, length float64) { 81 | c := &C.dMass{} 82 | C.dMassSetCapsuleTotal(c, C.dReal(totalMass), C.int(direction), C.dReal(radius), 83 | C.dReal(length)) 84 | m.fromC(c) 85 | } 86 | 87 | // SetCylinder sets the mass for a cylinder of given properties. 88 | func (m *Mass) SetCylinder(density float64, direction int, radius, length float64) { 89 | c := &C.dMass{} 90 | C.dMassSetCylinder(c, C.dReal(density), C.int(direction), C.dReal(radius), 91 | C.dReal(length)) 92 | m.fromC(c) 93 | } 94 | 95 | // SetCylinderTotal sets the mass for a cylinder of given properties. 96 | func (m *Mass) SetCylinderTotal(totalMass float64, direction int, radius, length float64) { 97 | c := &C.dMass{} 98 | C.dMassSetCylinderTotal(c, C.dReal(totalMass), C.int(direction), C.dReal(radius), 99 | C.dReal(length)) 100 | m.fromC(c) 101 | } 102 | 103 | // SetBox sets the mass for a box of given properties. 104 | func (m *Mass) SetBox(density float64, lens Vector3) { 105 | c := &C.dMass{} 106 | C.dMassSetBox(c, C.dReal(density), 107 | C.dReal(lens[0]), C.dReal(lens[1]), C.dReal(lens[2])) 108 | m.fromC(c) 109 | } 110 | 111 | // SetBoxTotal sets the mass for a box of given properties. 112 | func (m *Mass) SetBoxTotal(totalMass float64, lens Vector3) { 113 | c := &C.dMass{} 114 | C.dMassSetBoxTotal(c, C.dReal(totalMass), 115 | C.dReal(lens[0]), C.dReal(lens[1]), C.dReal(lens[2])) 116 | m.fromC(c) 117 | } 118 | 119 | // SetTrimesh sets the mass for the given triangle mesh. 120 | func (m *Mass) SetTriMesh(density float64, mesh TriMesh) { 121 | c := &C.dMass{} 122 | C.dMassSetTrimesh(c, C.dReal(density), mesh.c()) 123 | m.fromC(c) 124 | } 125 | 126 | // SetTrimeshTotal sets the mass for the given triangle mesh. 127 | func (m *Mass) SetTriMeshTotal(totalMass float64, mesh TriMesh) { 128 | c := &C.dMass{} 129 | C.dMassSetTrimeshTotal(c, C.dReal(totalMass), mesh.c()) 130 | m.fromC(c) 131 | } 132 | 133 | // Adjust sets parameters based on the given total mass. 134 | func (m *Mass) Adjust(mass float64) { 135 | c := &C.dMass{} 136 | m.toC(c) 137 | C.dMassAdjust(c, C.dReal(mass)) 138 | m.fromC(c) 139 | } 140 | 141 | // Translate translates the mass by vec. 142 | func (m *Mass) Translate(vec Vector3) { 143 | c := &C.dMass{} 144 | m.toC(c) 145 | C.dMassTranslate(c, C.dReal(vec[0]), C.dReal(vec[1]), C.dReal(vec[2])) 146 | m.fromC(c) 147 | } 148 | 149 | // Rotate rotates the mass by rot. 150 | func (m *Mass) Rotate(rot Matrix3) { 151 | c := &C.dMass{} 152 | m.toC(c) 153 | C.dMassRotate(c, (*C.dReal)(&rot[0][0])) 154 | m.fromC(c) 155 | } 156 | 157 | // Add adds the other mass to this mass. 158 | func (m *Mass) Add(other *Mass) { 159 | c, oc := &C.dMass{}, &C.dMass{} 160 | m.toC(c) 161 | other.toC(oc) 162 | C.dMassAdd(c, oc) 163 | m.fromC(c) 164 | } 165 | -------------------------------------------------------------------------------- /ode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "_cgo_export.h" 4 | 5 | void callNearCallback(void *data, dGeomID obj1, dGeomID obj2) { 6 | nearCallback(data, obj1, obj2); 7 | } 8 | 9 | void callMovedCallback(dBodyID body) { 10 | movedCallback(body); 11 | } 12 | 13 | int callTriCallback(dGeomID mesh, dGeomID other, int index) { 14 | return triCallback(mesh, other, index); 15 | } 16 | 17 | int callTriRayCallback(dGeomID mesh, dGeomID ray, int index, dReal u, dReal v) { 18 | return triRayCallback(mesh, ray, index, u, v); 19 | } 20 | -------------------------------------------------------------------------------- /ode.go: -------------------------------------------------------------------------------- 1 | // Package ode provide a Go interface to the Open Dynamics Engine library. 2 | // See the ODE documentation for more information. 3 | package ode 4 | 5 | // #cgo LDFLAGS: -lode 6 | // #include 7 | import "C" 8 | 9 | import ( 10 | "unsafe" 11 | ) 12 | 13 | // Initialization flags 14 | const ( 15 | ManualThreadCleanupIFlag = C.dInitFlagManualThreadCleanup 16 | ) 17 | 18 | // Allocation flags 19 | const ( 20 | BasicDataAFlag = C.dAllocateFlagBasicData 21 | CollisionDataAFlag = C.dAllocateFlagCollisionData 22 | AllAFlag = C.dAllocateMaskAll 23 | ) 24 | 25 | // Short constructor aliases for convenience 26 | var ( 27 | V3 = NewVector3 28 | V4 = NewVector4 29 | M3 = NewMatrix3 30 | M4 = NewMatrix4 31 | Q = NewQuaternion 32 | BB = NewAABB 33 | ) 34 | 35 | // NearCallback is a callback type for handling potential object collisions. 36 | type NearCallback func(data interface{}, obj1, obj2 Geom) 37 | 38 | type nearCallbackData struct { 39 | data interface{} 40 | fn NearCallback 41 | } 42 | 43 | //export nearCallback 44 | func nearCallback(data unsafe.Pointer, obj1, obj2 C.dGeomID) { 45 | cbData := (*nearCallbackData)(data) 46 | cbData.fn(cbData.data, cToGeom(obj1), cToGeom(obj2)) 47 | } 48 | 49 | // round num up to nearest multiple of align 50 | func alignNum(num, align int) int { 51 | return (num + (align - 1)) &^ (align - 1) 52 | } 53 | 54 | // Vector represents a double precision vector. 55 | type Vector []float64 56 | 57 | // NewVector returns a new Vector instance. 58 | func NewVector(size, align int, vals ...float64) Vector { 59 | alignSize := alignNum(size, align) 60 | v := make(Vector, size, alignSize) 61 | copy(v, vals) 62 | return v 63 | } 64 | 65 | func (v Vector) convertC(c *C.dReal, toC bool) { 66 | for i := range v { 67 | if toC { 68 | *c = C.dReal(v[i]) 69 | } else { 70 | v[i] = float64(*c) 71 | } 72 | c = (*C.dReal)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + unsafe.Sizeof(*c))) 73 | } 74 | } 75 | 76 | func (v Vector) toC(c *C.dReal) { 77 | v.convertC(c, true) 78 | } 79 | 80 | func (v Vector) fromC(c *C.dReal) { 81 | v.convertC(c, false) 82 | } 83 | 84 | // Vector3 represents a 3 component vector. 85 | type Vector3 Vector 86 | 87 | func cToVector3(a *C.dReal) Vector3 { 88 | vec := NewVector3() 89 | Vector(vec).fromC(a) 90 | return vec 91 | } 92 | 93 | // NewVector3 returns a new Vector3 instance. 94 | func NewVector3(vals ...float64) Vector3 { 95 | return Vector3(NewVector(3, 4, vals...)) 96 | } 97 | 98 | // Vector4 represents a 4 component vector. 99 | type Vector4 Vector 100 | 101 | // NewVector4 returns a new Vector4 instance. 102 | func NewVector4(vals ...float64) Vector4 { 103 | return Vector4(NewVector(4, 4, vals...)) 104 | } 105 | 106 | // Quaternion represents a quaternion. 107 | type Quaternion Vector 108 | 109 | // NewQuaternion returns a new Quaternion instance. 110 | func NewQuaternion(vals ...float64) Quaternion { 111 | return Quaternion(NewVector(4, 1, vals...)) 112 | } 113 | 114 | // AABB represents an axis-aligned bounding box. 115 | type AABB Vector 116 | 117 | // NewAABB returns a new AABB instance. 118 | func NewAABB(vals ...float64) AABB { 119 | return AABB(NewVector(6, 1, vals...)) 120 | } 121 | 122 | // Matrix represents a double precision matrix. 123 | type Matrix [][]float64 124 | 125 | // NewVector returns a new Matrix instance. 126 | func NewMatrix(numRows, numCols, align int, vals ...float64) Matrix { 127 | mat := make(Matrix, numRows) 128 | numAlignCols := alignNum(numCols, align) 129 | elts := make([]float64, numAlignCols*numRows) 130 | for i := range mat { 131 | mat[i], elts = elts[:numCols:numAlignCols], elts[numAlignCols:] 132 | n := numCols 133 | if len(vals) < numCols { 134 | n = len(vals) 135 | } 136 | copy(mat[i], vals[:n]) 137 | vals = vals[n:] 138 | } 139 | return mat 140 | } 141 | 142 | func (m Matrix) convertC(c *C.dReal, toC bool) { 143 | for i := range m { 144 | for j := 0; j < cap(m[i]); j++ { 145 | if j < len(m[i]) { 146 | if toC { 147 | *c = C.dReal(m[i][j]) 148 | } else { 149 | m[i][j] = float64(*c) 150 | } 151 | } 152 | c = (*C.dReal)(unsafe.Pointer(uintptr(unsafe.Pointer(c)) + unsafe.Sizeof(*c))) 153 | } 154 | } 155 | } 156 | 157 | func (m Matrix) toC(c *C.dReal) { 158 | m.convertC(c, true) 159 | } 160 | 161 | func (m Matrix) fromC(c *C.dReal) { 162 | m.convertC(c, false) 163 | } 164 | 165 | // Matrix3 represents a 3x3 matrix. 166 | type Matrix3 Matrix 167 | 168 | // NewMatrix3 returns a new Matrix3 instance. 169 | func NewMatrix3(vals ...float64) Matrix3 { 170 | return Matrix3(NewMatrix(3, 3, 4, vals...)) 171 | } 172 | 173 | // Matrix4 represents a 4x4 matrix. 174 | type Matrix4 Matrix 175 | 176 | // NewMatrix4 returns a new Matrix4 instance. 177 | func NewMatrix4(vals ...float64) Matrix4 { 178 | return Matrix4(NewMatrix(4, 4, 4, vals...)) 179 | } 180 | 181 | // VertexList represents a list of 3D vertices. 182 | type VertexList Matrix 183 | 184 | // NewVertexList returns a new VertexList instance. 185 | func NewVertexList(size int, vals ...float64) VertexList { 186 | return VertexList(NewMatrix(size, 3, 1, vals...)) 187 | } 188 | 189 | // PlaneList represents a list of plane definitions. 190 | type PlaneList Matrix 191 | 192 | // NewPlaneList returns a new PlaneList instance. 193 | func NewPlaneList(size int, vals ...float64) PlaneList { 194 | return PlaneList(NewMatrix(size, 4, 1, vals...)) 195 | } 196 | 197 | // TriVertexIndexList represents a list of triangle vertex indices. 198 | type TriVertexIndexList [][]uint32 199 | 200 | // NewTriVertexIndexList returns a new TriVertexIndexList instance. 201 | func NewTriVertexIndexList(size int, indices ...uint32) TriVertexIndexList { 202 | list := make(TriVertexIndexList, size) 203 | elts := make([]uint32, 3*size) 204 | for i := range list { 205 | list[i], elts = elts[:3], elts[3:] 206 | n := 3 207 | if len(indices) < 3 { 208 | n = len(indices) 209 | } 210 | copy(list[i], indices[:n]) 211 | indices = indices[n:] 212 | } 213 | return list 214 | } 215 | 216 | // PolygonList represents a list of polygon definitions 217 | type PolygonList []C.uint 218 | 219 | // Init initializes ODE. 220 | func Init(initFlags, allocFlags int) { 221 | C.dInitODE2(C.uint(initFlags)) 222 | C.dAllocateODEDataForThread(C.uint(allocFlags)) 223 | } 224 | 225 | // Close releases ODE resources. 226 | func Close() { 227 | C.dCloseODE() 228 | } 229 | 230 | // CleanupAllDataForThread manually releases ODE resources for the current thread. 231 | func CleanupAllDataForThread() { 232 | C.dCleanupODEAllDataForThread() 233 | } 234 | 235 | func btoi(b bool) int { 236 | if b { 237 | return 1 238 | } 239 | return 0 240 | } 241 | -------------------------------------------------------------------------------- /space.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | // extern void callNearCallback(void *data, dGeomID obj1, dGeomID obj2); 5 | import "C" 6 | 7 | import ( 8 | "unsafe" 9 | ) 10 | 11 | // Sweep and prune axis orders 12 | const ( 13 | SAPAxesXYZ = C.dSAP_AXES_XYZ 14 | SAPAxesXZY = C.dSAP_AXES_XZY 15 | SAPAxesYXZ = C.dSAP_AXES_YXZ 16 | SAPAxesYZX = C.dSAP_AXES_YZX 17 | SAPAxesZXY = C.dSAP_AXES_ZXY 18 | SAPAxesZYX = C.dSAP_AXES_ZYX 19 | ) 20 | 21 | // Space represents a space containing bodies. 22 | type Space interface { 23 | c() C.dSpaceID 24 | Destroy() 25 | SetCleanup(mode bool) 26 | Cleanup() bool 27 | SetManualCleanup(mode bool) 28 | SetSublevel(sublevel int) 29 | Sublevel() int 30 | ManualCleanup() bool 31 | Clean() 32 | Class() int 33 | Add(g Geom) 34 | Remove(g Geom) 35 | Query(g Geom) bool 36 | NumGeoms(g Geom) int 37 | Geom(index int) Geom 38 | Collide(data interface{}, cb NearCallback) 39 | NewSphere(radius float64) Sphere 40 | NewBox(lens Vector3) Box 41 | NewPlane(params Vector4) Plane 42 | NewCapsule(radius, length float64) Capsule 43 | NewCylinder(radius, length float64) Cylinder 44 | NewRay(length float64) Ray 45 | NewHeightfield(data HeightfieldData, placeable bool) Heightfield 46 | NewSimpleSpace() SimpleSpace 47 | NewHashSpace() HashSpace 48 | NewQuadTreeSpace(center, extents Vector3, depth int) QuadTreeSpace 49 | NewSweepAndPruneSpace(axisOrder int) SweepAndPruneSpace 50 | } 51 | 52 | // SpaceBase implements Space, and is embedded by specific Space types. 53 | type SpaceBase uintptr 54 | 55 | func cToSpace(c C.dSpaceID) Space { 56 | base := SpaceBase(unsafe.Pointer(c)) 57 | var s Space 58 | switch int(C.dSpaceGetClass(c)) { 59 | case SimpleSpaceClass: 60 | s = SimpleSpace{base} 61 | case HashSpaceClass: 62 | s = HashSpace{base} 63 | case QuadTreeSpaceClass: 64 | s = QuadTreeSpace{base} 65 | case SweepAndPruneSpaceClass: 66 | s = SweepAndPruneSpace{base} 67 | default: 68 | s = base 69 | } 70 | return s 71 | } 72 | 73 | // NilSpace returns the top level "0" space 74 | func NilSpace() Space { 75 | return SpaceBase(0) 76 | } 77 | 78 | func (s SpaceBase) c() C.dSpaceID { 79 | return C.dSpaceID(unsafe.Pointer(s)) 80 | } 81 | 82 | // Destroy destroys the space. 83 | func (s SpaceBase) Destroy() { 84 | C.dSpaceDestroy(s.c()) 85 | } 86 | 87 | // SetCleanup sets whether contained objects will be destroyed. 88 | func (s SpaceBase) SetCleanup(mode bool) { 89 | C.dSpaceSetCleanup(s.c(), C.int(btoi(mode))) 90 | } 91 | 92 | // Cleanup returns whether contained objects will be destroyed. 93 | func (s SpaceBase) Cleanup() bool { 94 | return C.dSpaceGetCleanup(s.c()) != 0 95 | } 96 | 97 | // SetManualCleanup sets whether this space is marked for manual cleanup. 98 | func (s SpaceBase) SetManualCleanup(mode bool) { 99 | C.dSpaceSetManualCleanup(s.c(), C.int(btoi(mode))) 100 | } 101 | 102 | // ManualCleanup returns whether this space is marked for manual cleanup. 103 | func (s SpaceBase) ManualCleanup() bool { 104 | return C.dSpaceGetManualCleanup(s.c()) != 0 105 | } 106 | 107 | // SetSublevel sets the sublevel for this space. 108 | func (s SpaceBase) SetSublevel(sublevel int) { 109 | C.dSpaceSetSublevel(s.c(), C.int(sublevel)) 110 | } 111 | 112 | // Sublevel returns the sublevel for this space. 113 | func (s SpaceBase) Sublevel() int { 114 | return int(C.dSpaceGetSublevel(s.c())) 115 | } 116 | 117 | // Clean cleans the space. 118 | func (s SpaceBase) Clean() { 119 | C.dSpaceClean(s.c()) 120 | } 121 | 122 | // Class returns the space class. 123 | func (s SpaceBase) Class() int { 124 | return int(C.dSpaceGetClass(s.c())) 125 | } 126 | 127 | // Add adds a geometry to the space. 128 | func (s SpaceBase) Add(g Geom) { 129 | C.dSpaceAdd(s.c(), g.c()) 130 | } 131 | 132 | // Remove removes a geometry from the space. 133 | func (s SpaceBase) Remove(g Geom) { 134 | C.dSpaceRemove(s.c(), g.c()) 135 | } 136 | 137 | // Query returns whether a geometry is contained in the space. 138 | func (s SpaceBase) Query(g Geom) bool { 139 | return C.dSpaceQuery(s.c(), g.c()) != 0 140 | } 141 | 142 | // NumGeoms returns the number of geometries contained in the space. 143 | func (s SpaceBase) NumGeoms(g Geom) int { 144 | return int(C.dSpaceGetNumGeoms(s.c())) 145 | } 146 | 147 | // Geom returns the specified contained geometry. 148 | func (s SpaceBase) Geom(index int) Geom { 149 | return cToGeom(C.dSpaceGetGeom(s.c(), C.int(index))) 150 | } 151 | 152 | // Collide tests for collision between contained objects. 153 | func (s SpaceBase) Collide(data interface{}, cb NearCallback) { 154 | cbData := &nearCallbackData{fn: cb, data: data} 155 | C.dSpaceCollide(s.c(), unsafe.Pointer(cbData), 156 | (*C.dNearCallback)(C.callNearCallback)) 157 | } 158 | 159 | // NewSphere returns a new Sphere instance. 160 | func (s SpaceBase) NewSphere(radius float64) Sphere { 161 | return cToGeom(C.dCreateSphere(s.c(), C.dReal(radius))).(Sphere) 162 | } 163 | 164 | // NewBox returns a new Box instance. 165 | func (s SpaceBase) NewBox(lens Vector3) Box { 166 | return cToGeom(C.dCreateBox(s.c(), C.dReal(lens[0]), C.dReal(lens[1]), C.dReal(lens[2]))).(Box) 167 | } 168 | 169 | // NewPlane returns a new Plane instance. 170 | func (s SpaceBase) NewPlane(params Vector4) Plane { 171 | return cToGeom(C.dCreatePlane(s.c(), C.dReal(params[0]), C.dReal(params[1]), 172 | C.dReal(params[2]), C.dReal(params[3]))).(Plane) 173 | } 174 | 175 | // NewCapsule returns a new Capsule instance. 176 | func (s SpaceBase) NewCapsule(radius, length float64) Capsule { 177 | return cToGeom(C.dCreateCapsule(s.c(), C.dReal(radius), C.dReal(length))).(Capsule) 178 | } 179 | 180 | // NewCylinder returns a new Cylinder instance. 181 | func (s SpaceBase) NewCylinder(radius, length float64) Cylinder { 182 | return cToGeom(C.dCreateCylinder(s.c(), C.dReal(radius), C.dReal(length))).(Cylinder) 183 | } 184 | 185 | // NewRay returns a new Ray instance. 186 | func (s SpaceBase) NewRay(length float64) Ray { 187 | return cToGeom(C.dCreateRay(s.c(), C.dReal(length))).(Ray) 188 | } 189 | 190 | // NewHeightfield returns a new Heightfield instance. 191 | func (s SpaceBase) NewHeightfield(data HeightfieldData, placeable bool) Heightfield { 192 | return cToGeom(C.dCreateHeightfield(s.c(), data.c(), C.int(btoi(placeable)))).(Heightfield) 193 | } 194 | 195 | // NewConvex returns a new Convex instance. 196 | func (s SpaceBase) NewConvex(planes PlaneList, pts VertexList, polyList PolygonList) Convex { 197 | return cToGeom(C.dCreateConvex(s.c(), (*C.dReal)(&planes[0][0]), C.uint(len(planes)), 198 | (*C.dReal)(&pts[0][0]), C.uint(len(pts)), &polyList[0])).(Convex) 199 | } 200 | 201 | // NewTriMesh returns a new TriMesh instance. 202 | func (s SpaceBase) NewTriMesh(data TriMeshData) TriMesh { 203 | return cToGeom(C.dCreateTriMesh(s.c(), data.c(), nil, nil, nil)).(TriMesh) 204 | } 205 | 206 | // NewSimpleSpace returns a new SimpleSpace instance. 207 | func (s SpaceBase) NewSimpleSpace() SimpleSpace { 208 | return cToSpace(C.dSimpleSpaceCreate(s.c())).(SimpleSpace) 209 | } 210 | 211 | // NewHashSpace returns a new HashSpace instance. 212 | func (s SpaceBase) NewHashSpace() HashSpace { 213 | return cToSpace(C.dHashSpaceCreate(s.c())).(HashSpace) 214 | } 215 | 216 | // NewQuadTreeSpace returns a new QuadTreeSpace instance. 217 | func (s SpaceBase) NewQuadTreeSpace(center, extents Vector3, depth int) QuadTreeSpace { 218 | return cToSpace(C.dQuadTreeSpaceCreate(s.c(), (*C.dReal)(¢er[0]), 219 | (*C.dReal)(&extents[0]), C.int(depth))).(QuadTreeSpace) 220 | } 221 | 222 | // NewSweepAndPruneSpace returns a new SweepAndPruneSpace instance. 223 | func (s SpaceBase) NewSweepAndPruneSpace(axisOrder int) SweepAndPruneSpace { 224 | return cToSpace(C.dSweepAndPruneSpaceCreate(s.c(), C.int(axisOrder))).(SweepAndPruneSpace) 225 | } 226 | 227 | // SimpleSpace represents a simple space. 228 | type SimpleSpace struct { 229 | SpaceBase 230 | } 231 | 232 | // HashSpace represents a hash space. 233 | type HashSpace struct { 234 | SpaceBase 235 | } 236 | 237 | // SetLevels sets the minimum and maximum levels. 238 | func (s HashSpace) SetLevels(min, max int) { 239 | C.dHashSpaceSetLevels(s.c(), C.int(min), C.int(max)) 240 | } 241 | 242 | // Levels returns the minimum and maximum levels. 243 | func (s HashSpace) Levels() (int, int) { 244 | var min, max C.int 245 | C.dHashSpaceGetLevels(s.c(), &min, &max) 246 | return int(min), int(max) 247 | } 248 | 249 | // QuadTreeSpace represents a quad tree space. 250 | type QuadTreeSpace struct { 251 | SpaceBase 252 | } 253 | 254 | // SweepAndPruneSpace represents a sweep and prune space. 255 | type SweepAndPruneSpace struct { 256 | SpaceBase 257 | } 258 | -------------------------------------------------------------------------------- /trimesh.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | // extern int callTriCallback(dGeomID mesh, dGeomID other, int index); 5 | // extern int callTriRayCallback(dGeomID mesh, dGeomID ray, int index, dReal u, dReal v); 6 | import "C" 7 | 8 | import ( 9 | "unsafe" 10 | ) 11 | 12 | var ( 13 | triCallbacks = map[TriMesh]TriCallback{} 14 | triRayCallbacks = map[TriMesh]TriRayCallback{} 15 | ) 16 | 17 | // TriMeshData represents triangle mesh data. 18 | type TriMeshData uintptr 19 | 20 | func cToTriMeshData(c C.dTriMeshDataID) TriMeshData { 21 | return TriMeshData(unsafe.Pointer(c)) 22 | } 23 | 24 | func (t TriMeshData) c() C.dTriMeshDataID { 25 | return C.dTriMeshDataID(unsafe.Pointer(t)) 26 | } 27 | 28 | // NewTriMeshData returns a new TriMeshData instance. 29 | func NewTriMeshData() TriMeshData { 30 | return cToTriMeshData(C.dGeomTriMeshDataCreate()) 31 | } 32 | 33 | // Destroy destroys the triangle mesh data. 34 | func (t TriMeshData) Destroy() { 35 | C.dGeomTriMeshDataDestroy(t.c()) 36 | } 37 | 38 | // Build builds a triangle mesh from the given data. 39 | func (t TriMeshData) Build(verts VertexList, tris TriVertexIndexList) { 40 | C.dGeomTriMeshDataBuildSimple(t.c(), (*C.dReal)(&verts[0][0]), C.int(len(verts)), 41 | (*C.dTriIndex)(&tris[0][0]), C.int(len(tris))) 42 | } 43 | 44 | // Preprocess preprocesses the triangle mesh data. 45 | func (t TriMeshData) Preprocess() { 46 | C.dGeomTriMeshDataPreprocess(t.c()) 47 | } 48 | 49 | // Update updates the triangle mesh data. 50 | func (t TriMeshData) Update() { 51 | C.dGeomTriMeshDataUpdate(t.c()) 52 | } 53 | 54 | // TriMesh is a geometry representing a triangle mesh. 55 | type TriMesh struct { 56 | GeomBase 57 | } 58 | 59 | // TriCallback is called to determine whether to collide a triangle with 60 | // another geometry. 61 | type TriCallback func(mesh TriMesh, other Geom, index int) bool 62 | 63 | //export triCallback 64 | func triCallback(c C.dGeomID, other C.dGeomID, index C.int) C.int { 65 | mesh := cToGeom(c).(TriMesh) 66 | cb, ok := triCallbacks[mesh] 67 | if !ok { 68 | return 0 69 | } 70 | return C.int(btoi(cb(mesh, cToGeom(other), int(index)))) 71 | } 72 | 73 | // TriRayCallback is called to determine whether to collide a triangle with a 74 | // ray at a given point. 75 | type TriRayCallback func(mesh TriMesh, ray Ray, index int, u, v float64) bool 76 | 77 | //export triRayCallback 78 | func triRayCallback(c C.dGeomID, ray C.dGeomID, index C.int, u, v C.dReal) C.int { 79 | mesh := cToGeom(c).(TriMesh) 80 | cb, ok := triRayCallbacks[mesh] 81 | if !ok { 82 | return 0 83 | } 84 | return C.int(btoi(cb(mesh, cToGeom(ray).(Ray), int(index), float64(u), float64(v)))) 85 | } 86 | 87 | // SetLastTransform sets the last transform. 88 | func (t TriMesh) SetLastTransform(xform Matrix4) { 89 | C.dGeomTriMeshSetLastTransform(t.c(), (*C.dReal)(&xform[0][0])) 90 | } 91 | 92 | // LastTransform returns the last transform. 93 | func (t TriMesh) LastTransform() Matrix4 { 94 | xform := NewMatrix4() 95 | c := C.dGeomTriMeshGetLastTransform(t.c()) 96 | Matrix(xform).fromC(c) 97 | return xform 98 | } 99 | 100 | // SetTriCallback sets the triangle collision callback. 101 | func (t TriMesh) SetTriCallback(cb TriCallback) { 102 | if cb == nil { 103 | C.dGeomTriMeshSetCallback(t.c(), nil) // clear callback 104 | delete(triCallbacks, t) 105 | } else { 106 | triCallbacks[t] = cb 107 | C.dGeomTriMeshSetCallback(t.c(), (*C.dTriCallback)(C.callTriCallback)) 108 | } 109 | } 110 | 111 | // TriCallback returns the triangle collision callback. 112 | func (t TriMesh) TriCallback() TriCallback { 113 | return triCallbacks[t] 114 | } 115 | 116 | // SetTriRayCallback sets the triangle/ray collision callback. 117 | func (t TriMesh) SetTriRayCallback(cb TriRayCallback) { 118 | if cb == nil { 119 | C.dGeomTriMeshSetCallback(t.c(), nil) // clear callback 120 | delete(triRayCallbacks, t) 121 | } else { 122 | triRayCallbacks[t] = cb 123 | C.dGeomTriMeshSetRayCallback(t.c(), (*C.dTriRayCallback)(C.callTriRayCallback)) 124 | } 125 | } 126 | 127 | // TriRayCallback returns the triangle/ray collision callback. 128 | func (t TriMesh) TriRayCallback() TriRayCallback { 129 | return triRayCallbacks[t] 130 | } 131 | 132 | // SetMeshData sets the mesh data. 133 | func (t TriMesh) SetMeshData(data TriMeshData) { 134 | C.dGeomTriMeshSetData(t.c(), data.c()) 135 | } 136 | 137 | // MeshData returns the mesh data. 138 | func (t TriMesh) MeshData() TriMeshData { 139 | return cToTriMeshData(C.dGeomTriMeshGetData(t.c())) 140 | } 141 | 142 | // SetTCEnabled sets whether temporal coherence is enabled for the given 143 | // geometry class. 144 | func (t TriMesh) SetTCEnabled(class int, isEnabled bool) { 145 | C.dGeomTriMeshEnableTC(t.c(), C.int(class), C.int(btoi(isEnabled))) 146 | } 147 | 148 | // TCEnabled returns whether temporal coherence is enabled for the given 149 | // geometry class. 150 | func (t TriMesh) TCEnabled(class int) bool { 151 | return C.dGeomTriMeshIsTCEnabled(t.c(), C.int(class)) != 0 152 | } 153 | 154 | // ClearTCCache clears the temporal coherence cache. 155 | func (t TriMesh) ClearTCCache() { 156 | C.dGeomTriMeshClearTCCache(t.c()) 157 | } 158 | 159 | // Triangle returns a triangle in the mesh by index. 160 | func (t TriMesh) Triangle(index int) (Vector3, Vector3, Vector3) { 161 | c0, c1, c2 := &C.dVector3{}, &C.dVector3{}, &C.dVector3{} 162 | v0, v1, v2 := NewVector3(), NewVector3(), NewVector3() 163 | C.dGeomTriMeshGetTriangle(t.c(), C.int(index), c0, c1, c2) 164 | Vector(v0).fromC(&c0[0]) 165 | Vector(v1).fromC(&c1[0]) 166 | Vector(v2).fromC(&c2[0]) 167 | return v0, v1, v2 168 | } 169 | 170 | // Point returns a point on the specified triangle at the given barycentric coordinates. 171 | func (t TriMesh) Point(index int, u, v float64) Vector3 { 172 | pt := NewVector3() 173 | C.dGeomTriMeshGetPoint(t.c(), C.int(index), C.dReal(u), C.dReal(v), (*C.dReal)(&pt[0])) 174 | return pt 175 | } 176 | 177 | // TriangleCount returns the number of triangles in the mesh. 178 | func (t TriMesh) TriangleCount() int { 179 | return int(C.dGeomTriMeshGetTriangleCount(t.c())) 180 | } 181 | -------------------------------------------------------------------------------- /world.go: -------------------------------------------------------------------------------- 1 | package ode 2 | 3 | // #include 4 | import "C" 5 | 6 | import ( 7 | "unsafe" 8 | ) 9 | 10 | // World constants 11 | const ( 12 | WorldStepThreadCountUnlimited = C.dWORLDSTEP_THREADCOUNT_UNLIMITED 13 | ) 14 | 15 | var ( 16 | worldData = map[World]interface{}{} 17 | ) 18 | 19 | // World represents a simulation world. 20 | type World uintptr 21 | 22 | // NewWorld returns a new World instance. 23 | func NewWorld() World { 24 | return cToWorld(C.dWorldCreate()) 25 | } 26 | 27 | func cToWorld(c C.dWorldID) World { 28 | return World(unsafe.Pointer(c)) 29 | } 30 | 31 | func (w World) c() C.dWorldID { 32 | return C.dWorldID(unsafe.Pointer(w)) 33 | } 34 | 35 | // Destroy destroys the world. 36 | func (w World) Destroy() { 37 | delete(worldData, w) 38 | C.dWorldDestroy(w.c()) 39 | } 40 | 41 | // SetData associates user-specified data with the world. 42 | func (w World) SetData(data interface{}) { 43 | worldData[w] = data 44 | } 45 | 46 | // Data returns the user-specified data associated with the world. 47 | func (w World) Data() interface{} { 48 | return worldData[w] 49 | } 50 | 51 | // NewBody returns a new Body instance. 52 | func (w World) NewBody() Body { 53 | return cToBody(C.dBodyCreate(w.c())) 54 | } 55 | 56 | // SetGravity sets the gravity vector. 57 | func (w World) SetGravity(grav Vector3) { 58 | C.dWorldSetGravity(w.c(), C.dReal(grav[0]), C.dReal(grav[1]), C.dReal(grav[2])) 59 | } 60 | 61 | // Gravity returns the gravity vector. 62 | func (w World) Gravity() Vector3 { 63 | grav := NewVector3() 64 | C.dWorldGetGravity(w.c(), (*C.dReal)(&grav[0])) 65 | return grav 66 | } 67 | 68 | // SetERP sets the error reduction parameter. 69 | func (w World) SetERP(erp float64) { 70 | C.dWorldSetERP(w.c(), C.dReal(erp)) 71 | } 72 | 73 | // ERP returns the error reduction parameter. 74 | func (w World) ERP() float64 { 75 | return float64(C.dWorldGetERP(w.c())) 76 | } 77 | 78 | // SetCFM sets the constraint force mixing value. 79 | func (w World) SetCFM(cfm float64) { 80 | C.dWorldSetCFM(w.c(), C.dReal(cfm)) 81 | } 82 | 83 | // CFM returns the constraint force mixing value. 84 | func (w World) CFM() float64 { 85 | return float64(C.dWorldGetCFM(w.c())) 86 | } 87 | 88 | // SetStepIslandsProcessingMaxThreadCount sets the maximum number of threads to 89 | // use for island stepping. 90 | func (w World) SetStepIslandsProcessingMaxThreadCount(count int) { 91 | C.dWorldSetStepIslandsProcessingMaxThreadCount(w.c(), C.unsigned(count)) 92 | } 93 | 94 | // StepIslandsProcessingMaxThreadCount returns the maximum number of threads to 95 | // use for island stepping. 96 | func (w World) StepIslandsProcessingMaxThreadCount() int { 97 | return int(C.dWorldGetStepIslandsProcessingMaxThreadCount(w.c())) 98 | } 99 | 100 | // UseSharedWorkingMemory enables sharing working memory with another world, 101 | // and returns whether the operation succeeded. 102 | func (w World) UseSharedWorkingMemory(from World) bool { 103 | return C.dWorldUseSharedWorkingMemory(w.c(), from.c()) != 0 104 | } 105 | 106 | // CleanupWorkingMemory cleans up the world's working memory. 107 | func (w World) CleanupWorkingMemory() { 108 | C.dWorldCleanupWorkingMemory(w.c()) 109 | } 110 | 111 | // Step executes a simulation step, and returns whether the operation 112 | // succeeded. 113 | func (w World) Step(stepSize float64) bool { 114 | return C.dWorldStep(w.c(), C.dReal(stepSize)) != 0 115 | } 116 | 117 | // QuickStep executes a simulation quick step, and returns whether the 118 | // operation succeeded. 119 | func (w World) QuickStep(stepSize float64) bool { 120 | return C.dWorldQuickStep(w.c(), C.dReal(stepSize)) != 0 121 | } 122 | 123 | // ImpulseToForce converts an impulse to a force over a step duration. 124 | func (w World) ImpulseToForce(stepSize float64, impulse Vector3) Vector3 { 125 | force := NewVector3() 126 | C.dWorldImpulseToForce(w.c(), C.dReal(stepSize), 127 | C.dReal(impulse[0]), C.dReal(impulse[1]), C.dReal(impulse[2]), 128 | (*C.dReal)(&force[0])) 129 | return force 130 | } 131 | 132 | // SetQuickStepNumIterations sets the number of iterations to execute during a 133 | // quick step. 134 | func (w World) SetQuickStepNumIterations(num int) { 135 | C.dWorldSetQuickStepNumIterations(w.c(), C.int(num)) 136 | } 137 | 138 | // QuickStepNumIterations returns the number of iterations to execute during a 139 | // quick step. 140 | func (w World) QuickStepNumIterations() int { 141 | return int(C.dWorldGetQuickStepNumIterations(w.c())) 142 | } 143 | 144 | // SetQuickStepW sets the over-relaxation parameter. 145 | func (w World) SetQuickStepW(overRelaxation float64) { 146 | C.dWorldSetQuickStepW(w.c(), C.dReal(overRelaxation)) 147 | } 148 | 149 | // QuickStepW returns the over-relaxation parameter. 150 | func (w World) QuickStepW() float64 { 151 | return float64(C.dWorldGetQuickStepW(w.c())) 152 | } 153 | 154 | // SetContactMaxCorrectingVelocity sets the maximum correcting velocity that 155 | // contacts are allowed to generate. 156 | func (w World) SetContactMaxCorrectingVelocity(overRelaxation float64) { 157 | C.dWorldSetContactMaxCorrectingVel(w.c(), C.dReal(overRelaxation)) 158 | } 159 | 160 | // ContactMaxCorrectingVelocity returns the maximum correcting velocity that 161 | // contacts are allowed to generate. 162 | func (w World) ContactMaxCorrectingVelocity() float64 { 163 | return float64(C.dWorldGetContactMaxCorrectingVel(w.c())) 164 | } 165 | 166 | // SetContactSurfaceLayer sets the depth of the surface layer around all 167 | // geometry objects. 168 | func (w World) SetContactSurfaceLayer(depth float64) { 169 | C.dWorldSetContactSurfaceLayer(w.c(), C.dReal(depth)) 170 | } 171 | 172 | // ContactSurfaceLayer returns the depth of the surface layer around all 173 | // geometry objects. 174 | func (w World) ContactSurfaceLayer() float64 { 175 | return float64(C.dWorldGetContactSurfaceLayer(w.c())) 176 | } 177 | 178 | // SetAutoDisableLinearThreshold sets the auto disable linear average threshold. 179 | func (w World) SetAutoDisableLinearThreshold(linearThreshold float64) { 180 | C.dWorldSetAutoDisableLinearThreshold(w.c(), C.dReal(linearThreshold)) 181 | } 182 | 183 | // AutoDisableLinearThreshold returns the auto disable linear average threshold. 184 | func (w World) AutoDisableLinearThreshold() float64 { 185 | return float64(C.dWorldGetAutoDisableLinearThreshold(w.c())) 186 | } 187 | 188 | // SetAutoDisableAngularThreshold sets the auto disable angular average threshold. 189 | func (w World) SetAutoDisableAngularThreshold(angularThreshold float64) { 190 | C.dWorldSetAutoDisableAngularThreshold(w.c(), C.dReal(angularThreshold)) 191 | } 192 | 193 | // AutoDisableAngularThreshold returns the auto disable angular average threshold. 194 | func (w World) AutoDisableAngularThreshold() float64 { 195 | return float64(C.dWorldGetAutoDisableAngularThreshold(w.c())) 196 | } 197 | 198 | // SetAutoAutoDisableAverageSamplesCount sets auto disable average sample count. 199 | func (w World) SetAutoAutoDisableAverageSamplesCount(averageSamplesCount bool) { 200 | C.dWorldSetAutoDisableAverageSamplesCount(w.c(), C.unsigned(btoi(averageSamplesCount))) 201 | } 202 | 203 | // AutoDisableAverageSamplesCount returns the auto disable sample count. 204 | func (w World) AutoDisableAverageSamplesCount() bool { 205 | return C.dWorldGetAutoDisableAverageSamplesCount(w.c()) != 0 206 | } 207 | 208 | // SetAutoDisableSteps sets the number of auto disable steps. 209 | func (w World) SetAutoDisableSteps(steps int) { 210 | C.dWorldSetAutoDisableSteps(w.c(), C.int(steps)) 211 | } 212 | 213 | // AutoDisableSteps returns the number of auto disable steps. 214 | func (w World) AutoDisableSteps() int { 215 | return int(C.dWorldGetAutoDisableSteps(w.c())) 216 | } 217 | 218 | // SetAutoDisableTime sets the auto disable time. 219 | func (w World) SetAutoDisableTime(time float64) { 220 | C.dWorldSetAutoDisableTime(w.c(), C.dReal(time)) 221 | } 222 | 223 | // AutoDisableTime returns the auto disable time. 224 | func (w World) AutoDisableTime() float64 { 225 | return float64(C.dWorldGetAutoDisableTime(w.c())) 226 | } 227 | 228 | // SetAutoDisable sets wether the body will be auto disabled. 229 | func (w World) SetAutoDisable(doAutoDisable bool) { 230 | C.dWorldSetAutoDisableFlag(w.c(), C.int(btoi(doAutoDisable))) 231 | } 232 | 233 | // AutoDisable returns whether the body will be auto disabled. 234 | func (w World) AutoDisable() bool { 235 | return C.dWorldGetAutoDisableFlag(w.c()) != 0 236 | } 237 | 238 | // SetLinearDamping sets the linear damping scale. 239 | func (w World) SetLinearDamping(scale float64) { 240 | C.dWorldSetLinearDamping(w.c(), C.dReal(scale)) 241 | } 242 | 243 | // LinearDamping returns the linear damping scale. 244 | func (w World) LinearDamping() float64 { 245 | return float64(C.dWorldGetLinearDamping(w.c())) 246 | } 247 | 248 | // SetAngularDamping sets the angular damping scale. 249 | func (w World) SetAngularDamping(scale float64) { 250 | C.dWorldSetAngularDamping(w.c(), C.dReal(scale)) 251 | } 252 | 253 | // AngularDamping returns the angular damping scale. 254 | func (w World) AngularDamping() float64 { 255 | return float64(C.dWorldGetAngularDamping(w.c())) 256 | } 257 | 258 | // SetLinearDampingThreshold sets the linear damping threshold. 259 | func (w World) SetLinearDampingThreshold(threshold float64) { 260 | C.dWorldSetLinearDampingThreshold(w.c(), C.dReal(threshold)) 261 | } 262 | 263 | // LinearDampingThreshold returns the linear damping threshold. 264 | func (w World) LinearDampingThreshold() float64 { 265 | return float64(C.dWorldGetLinearDampingThreshold(w.c())) 266 | } 267 | 268 | // SetAngularDampingThreshold sets the angular damping threshold. 269 | func (w World) SetAngularDampingThreshold(threshold float64) { 270 | C.dWorldSetAngularDampingThreshold(w.c(), C.dReal(threshold)) 271 | } 272 | 273 | // AngularDampingThreshold returns the angular damping threshold. 274 | func (w World) AngularDampingThreshold() float64 { 275 | return float64(C.dWorldGetAngularDampingThreshold(w.c())) 276 | } 277 | 278 | // SetMaxAngularSpeed sets the maximum angular speed. 279 | func (w World) SetMaxAngularSpeed(maxSpeed float64) { 280 | C.dWorldSetMaxAngularSpeed(w.c(), C.dReal(maxSpeed)) 281 | } 282 | 283 | // MaxAngularSpeed returns the maximum angular speed. 284 | func (w World) MaxAngularSpeed() float64 { 285 | return float64(C.dWorldGetMaxAngularSpeed(w.c())) 286 | } 287 | 288 | // NewBallJoint returns a new BallJoint instance 289 | func (w World) NewBallJoint(group JointGroup) BallJoint { 290 | return cToJoint(C.dJointCreateBall(w.c(), group.c())).(BallJoint) 291 | } 292 | 293 | // NewHingeJoint returns a new HingeJoint instance 294 | func (w World) NewHingeJoint(group JointGroup) HingeJoint { 295 | return cToJoint(C.dJointCreateHinge(w.c(), group.c())).(HingeJoint) 296 | } 297 | 298 | // NewSliderJoint returns a new SliderJoint instance 299 | func (w World) NewSliderJoint(group JointGroup) SliderJoint { 300 | return cToJoint(C.dJointCreateSlider(w.c(), group.c())).(SliderJoint) 301 | } 302 | 303 | // NewContactJoint returns a new ContactJoint instance 304 | func (w World) NewContactJoint(group JointGroup, contact *Contact) ContactJoint { 305 | c := &C.dContact{} 306 | contact.toC(c) 307 | return cToJoint(C.dJointCreateContact(w.c(), group.c(), c)).(ContactJoint) 308 | } 309 | 310 | // NewUniversalJoint returns a new UniversalJoint instance 311 | func (w World) NewUniversalJoint(group JointGroup) UniversalJoint { 312 | return cToJoint(C.dJointCreateUniversal(w.c(), group.c())).(UniversalJoint) 313 | } 314 | 315 | // NewHinge2Joint returns a new Hinge2Joint instance 316 | func (w World) NewHinge2Joint(group JointGroup) Hinge2Joint { 317 | return cToJoint(C.dJointCreateHinge2(w.c(), group.c())).(Hinge2Joint) 318 | } 319 | 320 | // NewFixedJoint returns a new FixedJoint instance 321 | func (w World) NewFixedJoint(group JointGroup) FixedJoint { 322 | return cToJoint(C.dJointCreateFixed(w.c(), group.c())).(FixedJoint) 323 | } 324 | 325 | // NewNullJoint returns a new NullJoint instance 326 | func (w World) NewNullJoint(group JointGroup) NullJoint { 327 | return cToJoint(C.dJointCreateNull(w.c(), group.c())).(NullJoint) 328 | } 329 | 330 | // NewAMotorJoint returns a new AMotorJoint instance 331 | func (w World) NewAMotorJoint(group JointGroup) AMotorJoint { 332 | return cToJoint(C.dJointCreateAMotor(w.c(), group.c())).(AMotorJoint) 333 | } 334 | 335 | // NewLMotorJoint returns a new LMotorJoint instance 336 | func (w World) NewLMotorJoint(group JointGroup) LMotorJoint { 337 | return cToJoint(C.dJointCreateLMotor(w.c(), group.c())).(LMotorJoint) 338 | } 339 | 340 | // NewPlane2DJoint returns a new Plane2DJoint instance 341 | func (w World) NewPlane2DJoint(group JointGroup) Plane2DJoint { 342 | return cToJoint(C.dJointCreatePlane2D(w.c(), group.c())).(Plane2DJoint) 343 | } 344 | 345 | // NewPRJoint returns a new PRJoint instance 346 | func (w World) NewPRJoint(group JointGroup) PRJoint { 347 | return cToJoint(C.dJointCreatePR(w.c(), group.c())).(PRJoint) 348 | } 349 | 350 | // NewPUJoint returns a new PUJoint instance 351 | func (w World) NewPUJoint(group JointGroup) PUJoint { 352 | return cToJoint(C.dJointCreatePU(w.c(), group.c())).(PUJoint) 353 | } 354 | 355 | // NewPistonJoint returns a new PistonJoint instance 356 | func (w World) NewPistonJoint(group JointGroup) PistonJoint { 357 | return cToJoint(C.dJointCreatePiston(w.c(), group.c())).(PistonJoint) 358 | } 359 | 360 | // NewDBallJoint returns a new DBallJoint instance 361 | func (w World) NewDBallJoint(group JointGroup) DBallJoint { 362 | return cToJoint(C.dJointCreateDBall(w.c(), group.c())).(DBallJoint) 363 | } 364 | 365 | // NewDHingeJoint returns a new DHingeJoint instance 366 | func (w World) NewDHingeJoint(group JointGroup) DHingeJoint { 367 | return cToJoint(C.dJointCreateDHinge(w.c(), group.c())).(DHingeJoint) 368 | } 369 | 370 | // NewTransmissionJoint returns a new TransmissionJoint instance 371 | func (w World) NewTransmissionJoint(group JointGroup) TransmissionJoint { 372 | return cToJoint(C.dJointCreateTransmission(w.c(), group.c())).(TransmissionJoint) 373 | } 374 | --------------------------------------------------------------------------------