oyk/
ode.rs

1//! ode integrates bindings to cppbridge and cppode
2//!
3//! oyk is replaced to submodule of crate ode-rs after version 1.0.1
4//!
5//! - cc-rs https://crates.io/crates/cc
6//! - bindgen https://crates.io/crates/bindgen
7//!
8//! # cc-rs
9//!
10//! - include/bridge.hpp
11//! - src/bridge.cpp
12//!
13//! # bindgen
14//!
15//! from
16//!
17//!  - include/bridge.hpp
18//!
19//! to
20//!
21//!  - include/bridge_bindings.rs
22//!
23//! # Requirements
24//!
25//! in the running directory
26//!
27//! - ode.dll
28//! - libstdc++-6.dll
29//! - libgcc_s_seh-1.dll
30//! - libwinpthread-1.dll
31//!
32
33#![allow(unused)]
34// #![allow(unused_imports)]
35// #![allow(unused_attributes)]
36#![allow(non_snake_case)]
37#![allow(non_camel_case_types)]
38#![allow(non_upper_case_globals)]
39
40// mod cppbridge;
41// use cppbridge::*;
42// pub use cppbridge::{Bridge, bput};
43
44//pub use ode_base::ode::*;
45use ode_base::ode::{self, *};
46pub use ode::{convexfvp, trimeshvi};
47pub use ode::{dBodyID, dGeomID, dTriIndex};
48pub use ode::{dMatrix4, dMatrix3, dVector4, dVector3, dReal}; // 16 12 4 4
49pub use ode::{dQuaternion};
50
51#[warn(unused)]
52// #[warn(unused_imports)]
53// #[warn(unused_attributes)]
54#[warn(non_snake_case)]
55#[warn(non_camel_case_types)]
56#[warn(non_upper_case_globals)]
57
58use std::error::Error;
59
60// pub mod err in ode_base::ode::err
61pub use ode::err::{self, *};
62
63// pub mod mat in ode_base::ode::mat
64pub use ode::mat::{self, *};
65
66// pub mod prim in ode_base::ode::prim
67use ode::prim::{self, *};
68pub use prim::{Matrix4, M4I, Matrix3, M3I, Quaternion, QI};
69pub use prim::{PId, PI, PIh, PIt, PIq, PIx};
70pub use prim::{PIh3, PIt2, PIt4, PIt5, PIq3, PIx5};
71
72// pub mod krp in ode_base::ode::krp
73use ode::krp::{self, *};
74pub use krp::{Krp, KRPnk, KRP100, KRP095, KRP080, KRP001};
75
76pub mod trimeshconvex;
77use trimeshconvex::*;
78pub use trimeshconvex::{TriMesh, Convex};
79pub use trimeshconvex::{custom, tetra, cube, icosahedron, bunny};
80
81pub mod meta;
82use meta::*;
83pub use meta::{MetaInf, MetaConvex, MetaTriMesh, MetaComposite};
84pub use meta::{MetaSphere, MetaBox, MetaCapsule, MetaCylinder, MetaPlane};
85
86pub mod cls;
87use cls::*;
88pub use cls::{obg::{Obg, Gws}, AsPtr};
89
90pub mod ds;
91use ds::*;
92pub use ds::{Tdrawstuff, TdrawstuffSetter};
93
94use std::collections::hash_map::Entry;
95use std::collections::HashMap; // with #[derive(PartialEq, Eq, Hash)] struct
96use std::collections::btree_map::Entry as BTreeEntry;
97use std::collections::BTreeMap;
98use std::collections::VecDeque;
99
100use asciiz::u8z::{U8zBuf, u8zz::{CArgsBuf}};
101
102use std::ffi::{c_void, c_int};
103
104pub extern crate impl_sim;
105// pub use impl_sim::{impl_sim_fn, impl_sim_derive};
106
107use once_cell::sync::Lazy;
108
109/// unsafe static mut OYK_MUT (management ODE singleton instance)
110pub static mut OYK_MUT: Lazy<Vec<ODE>> = Lazy::new(|| vec![ODE::new(0.002)]);
111
112/// help default defined key set
113const KEY_HELP: &str = "
114  default defined key set
115  ctrl + 'P': pause on/off
116  ctrl + 'O': single step
117  ctrl + 'S': shadow on/off
118  ctrl + 'T': texture on/off
119  'w': wireframe (trimesh) solid/wireframe (show hidden face edge)
120  'p': wireframe (all) polyfill/wireframe (not show hidden face edge)
121  'v': show viewpoint (current num pos hpr)
122  's': change viewpoint (8 pattern preset/set)
123  'r': reset
124  '?': help (this message)
125";
126
127/// ODE singleton
128pub struct ODE { // unsafe
129  ds: Option<Box<dyn Tdrawstuff>>, // trait Tdrawstuff (for late binding)
130  sim: Option<Box<dyn Sim>>, // trait Sim must have callback functions
131  ptt: Option<U8zBuf>, // relative path to textures
132  wire_solid: i32, // 0: wireframe, 1: solid (for bunny)
133  polyfill_wireframe: i32, // 0: solid, 1: wireframe (for all)
134  sw_viewpoint: usize, // switch viewpoint
135  /// viewpoint(s)
136  pub cams: BTreeMap<usize, Cam>,
137  rgts: HashMap<dGeomID, dGeomID>, // reverse geom gtrans dGeomGetGeomTransform
138  mgms: HashMap<dGeomID, Box<dyn MetaInf>>, // metainf(s) material(s) mapped
139  obgs: HashMap<dBodyID, Obg>, // object(s) mapped (obg has key: String)
140  mbgs: BTreeMap<String, dBodyID>, // object id(s) ordered mapped (key: cloned)
141  vbgs: VecDeque<dBodyID>, // object id(s) ordered (drawing order)
142  modified: bool, // modify() is_modified()
143  gws: Gws, // singleton
144  /// step
145  pub t_delta: dReal
146}
147
148/// $rs is Sim instance, $rf is callback function in Sim
149#[macro_export]
150macro_rules! ode_sim {
151  ($rs: ident, $rf: ident) => {
152    match &mut $rs.sim {
153      Some(s) => s.$rf(),
154      None => $rs.$rf()
155    }
156  };
157  ($rs: ident, $rf: ident, $($e:expr),+) => {
158    match &mut $rs.sim {
159      Some(s) => s.$rf($($e),+),
160      None => $rs.$rf($($e),+)
161    }
162  };
163}
164// pub use ode_sim;
165
166/// ODE singleton getter (mutable)
167#[macro_export]
168macro_rules! ode_mut {
169  () => { (&mut OYK_MUT)[0] };
170}
171// pub use ode_mut;
172
173/// ODE singleton getter (immutable)
174#[macro_export]
175macro_rules! ode_ {
176  () => { (&OYK_MUT)[0] };
177}
178// pub use ode_;
179
180/// ODE attribute getter (mutable)
181#[macro_export]
182macro_rules! ode_get_mut {
183  ($src: ident) => { (&mut OYK_MUT)[0].$src };
184}
185// pub use ode_get_mut;
186
187/// ODE attribute getter (immutable)
188#[macro_export]
189macro_rules! ode_get {
190  ($src: ident) => { (&OYK_MUT)[0].$src };
191}
192// pub use ode_get;
193
194// #[macro_export]
195macro_rules! ode_gws_set {
196  ($dst: ident, $src: expr) => {
197//  unsafe { (&mut OYK_MUT)[0].gws.$dst = $src as usize } // use outside unsafe
198    (&mut OYK_MUT)[0].gws.$dst = $src as usize
199  };
200}
201// pub use ode_gws_set;
202
203// #[macro_export]
204macro_rules! ode_gws_get {
205  ($src: ident, $dst: ty) => {
206//    unsafe { (&OYK_MUT)[0].gws.$src as $dst } // use outside unsafe
207    (&OYK_MUT)[0].gws.$src as $dst
208  };
209}
210// pub use ode_gws_get;
211
212// #[macro_export]
213macro_rules! gws_dump {
214  () => {
215unsafe {
216    let gws: &mut Gws = &mut ode_get_mut!(gws);
217/*
218    ostatln!("0x{:016x}", gws.world);
219    ostatln!("0x{:016x}", gws.space);
220    ostatln!("0x{:016x}", gws.ground);
221    ostatln!("0x{:016x}", gws.contactgroup);
222    ostatln!("0x{:016x}", gws.num_contact);
223*/
224    ostatln!("{:018p}", gws.world());
225    ostatln!("{:018p}", gws.space());
226    ostatln!("{:018p}", gws.ground());
227    ostatln!("{:018p}", gws.contactgroup());
228    ostatln!("{:018p}", gws.num_contact());
229}
230    ()
231  };
232}
233// pub use gws_dump;
234
235/// singleton interface
236impl ODE {
237
238/// construct (must not call it, auto instanciate by once_cell lazy)
239pub fn new(delta: dReal) -> ODE {
240  ostatln!("new ODE");
241  unsafe { dInitODE2(0); }
242  ODE{ds: None, sim: None, ptt: None,
243    wire_solid: 1, polyfill_wireframe: 0, sw_viewpoint: 0,
244    cams: vec![
245      Cam::new(vec![5.0, 0.0, 2.0], vec![-180.0, 0.0, 0.0]),
246      Cam::new(vec![0.0, 0.0, 20.0], vec![-180.0, -30.0, 0.0]),
247      Cam::new(vec![5.36, 2.02, 4.28], vec![-162.0, -31.0, 0.0]),
248      Cam::new(vec![-8.3, -14.1, 3.1], vec![84.5, 1.0, 0.0]),
249      Cam::new(vec![4.0, 3.0, 5.0], vec![-150.0, -30.0, 3.0]),
250      Cam::new(vec![10.0, 10.0, 5.0], vec![-150.0, 0.0, 3.0]),
251      Cam::new(vec![-20.0, -20.0, 10.0], vec![45.0, -15.0, 0.0])
252    ].into_iter().enumerate().collect(), // to BTreeMap<usize, Cam>
253    rgts: vec![].into_iter().collect(), mgms: vec![].into_iter().collect(),
254    obgs: vec![].into_iter().collect(), mbgs: vec![].into_iter().collect(),
255    vbgs: vec![].try_into().unwrap_or_else(|o: std::convert::Infallible|
256      panic!("Expected VecDeque<dBodyID> from vec![] Infallible ({:?})", o)),
257    modified: false, gws: Gws::new(256), t_delta: delta}
258}
259
260/// ds trait Tdrawstuff getter
261pub fn ds_as_ref() -> &'static Box<dyn Tdrawstuff> {
262unsafe {
263  ode_get!(ds).as_ref().expect("get ds trait Tdrawstuff")
264}
265}
266
267/// ODE initialize
268/// - drawstuff: change drawstuff
269/// - delta: default 0.002
270/// - num_contact: default 12
271pub fn open(drawstuff: impl Tdrawstuff + 'static,
272  delta: dReal, qsw: dReal, qsni: usize, cmcv: dReal, csl: dReal,
273  num_contact: usize) {
274unsafe {
275  ODE::set_drawstuff(&mut ode_get_mut!(ds), drawstuff);
276
277  ode_get_mut!(t_delta) = delta;
278  // need this code (do nothing) to create instance
279  let gws: &mut Gws = &mut ode_get_mut!(gws);
280  gws.world_(0 as dWorldID); // force call new before create_world
281/*
282  // need this code (do nothing) to create instance
283  let v = &mut OYK_MUT;
284  v[0].gws.world_(0 as dWorldID); // force call new before create_world
285  drop(v);
286*/
287}
288  ODE::create_world(qsw, qsni, cmcv, csl, num_contact);
289//  gws_dump!();
290}
291
292/// ODE finalize
293pub fn close() {
294  ODE::clear_obgs();
295  ODE::clear_contactgroup();
296  ODE::destroy_world();
297unsafe {
298  // need this code (drop element) to drop instance
299  let v = &mut OYK_MUT;
300  drop(&v[0]); // need it otherwise never called destructor
301  v.pop();
302  drop(v);
303}
304}
305
306/// auto called by ODE::open() (custom start callback to create your objects)
307pub fn create_world(qsw: dReal, qsni: usize, cmcv: dReal, csl: dReal,
308  num_contact: usize) {
309  ostatln!("create world");
310unsafe {
311  let gws: &mut Gws = &mut ode_get_mut!(gws);
312  gws.world_(dWorldCreate());
313  let wld = gws.world();
314  dWorldSetGravity(wld, 0.0, 0.0, -9.8);
315  ostatln!("QSW: {}", dWorldGetQuickStepW(wld)); // dReal 1.3
316  dWorldSetQuickStepW(wld, qsw); // over_relaxation
317  ostatln!("QSNI: {}", dWorldGetQuickStepNumIterations(wld)); // c_int 20
318  dWorldSetQuickStepNumIterations(wld, qsni as c_int);
319  ostatln!("CMCV: {}", dWorldGetContactMaxCorrectingVel(wld)); // dReal inf
320  dWorldSetContactMaxCorrectingVel(wld, cmcv); // vel: inf or 1e-3 or 1e-2 ...
321  ostatln!("CSL: {}", dWorldGetContactSurfaceLayer(wld)); // dReal 0
322  dWorldSetContactSurfaceLayer(wld, csl); // depth
323  gws.space_(dHashSpaceCreate(0 as dSpaceID));
324  dSpaceSetCleanup(gws.space(), 1);
325  gws.ground_(dCreatePlane(gws.space(), 0.0, 0.0, 1.0, 0.0));
326  gws.contactgroup_(dJointGroupCreate(0));
327  gws.num_contact_(num_contact);
328  gws.contacts = (0..num_contact).into_iter().map(|_|
329    dContact::new()
330  ).collect::<Vec<_>>(); // replace vec
331}
332}
333
334/// auto called by ODE::close()
335pub fn destroy_world() {
336  ostatln!("destroy world");
337unsafe {
338  let gws: &mut Gws = &mut ode_get_mut!(gws);
339  // dGeomDestroy(gws.ground());
340  dSpaceDestroy(gws.space());
341  dWorldDestroy(gws.world());
342}
343}
344
345/// modify
346pub fn modify(&mut self) {
347  self.modified = true;
348}
349
350/// is modified (set false when f is false, otherwise through)
351pub fn is_modified(&mut self, f: bool) -> bool {
352  let r = self.modified;
353  if r { self.modified = f; }
354  r
355}
356
357/// number of elements
358pub fn num(&self) -> usize {
359  self.obgs.len()
360}
361
362/// reg mgm (MetaInf, TCMaterial) (geom to HashMap) returns color
363pub fn reg_mgm(&mut self, geom: dGeomID, mi: Box<dyn MetaInf>) -> dVector4 {
364  let col = mi.get_tcm().col;
365  // self.mgms.entry(geom).or_insert_with(|| mi);
366  match self.mgms.entry(geom) { // expect geom is never duplicated
367    Entry::Occupied(mut oe) => {
368      let e = oe.get_mut();
369      println!("mgms {:?} already exists. skipped", geom); // just in case
370      e
371    },
372    Entry::Vacant(ve) => { ve.insert(mi) }
373  };
374  col
375}
376
377/// reg obg (body to HashMap, BTreeMap, and VecDeque) returns body
378pub fn reg_obg(&mut self, obg: Obg) -> dBodyID {
379  let id = obg.body();
380  let obgs: &mut HashMap<dBodyID, Obg> = &mut self.obgs;
381  // let key = obgs.entry(id).or_insert(obg).key.clone();
382  let key = match obgs.entry(id) { // expect id is never duplicated
383    Entry::Occupied(oe) => {
384      let k = oe.get().key.clone();
385      println!("obgs {:?}[{}] already exists. skipped", id, k); // just in case
386      k
387    },
388    Entry::Vacant(ve) => { ve.insert(obg).key.clone() }
389  };
390  let mbgs: &mut BTreeMap<String, dBodyID> = &mut self.mbgs;
391  // mbgs.insert(key, id);
392  match mbgs.entry(key.clone()) { // expect key is never duplicated
393    BTreeEntry::Occupied(mut oe) => {
394      let mut e = oe.get_mut();
395      println!("mbgs [{}] already exists. replaced", key); // warning
396      *e = id;
397      e
398    },
399    BTreeEntry::Vacant(ve) => { ve.insert(id) }
400  };
401  let vbgs: &mut VecDeque<dBodyID> = &mut self.vbgs;
402  vbgs.push_back(id);
403  self.modify();
404  id
405}
406
407/// create primitive object (register it to show on the ODE space world)
408/// - fmdm: true as m, false as dm
409pub fn creator_dm(&mut self, key: &str, mi: Box<dyn MetaInf>, fmdm: bool) ->
410  (dBodyID, dGeomID, Box<dMass>) {
411  let gws: &mut Gws = &mut self.gws;
412  let world: dWorldID = gws.world();
413  let space: dSpaceID = if key == "" { 0 as dSpaceID } else { gws.space() };
414  let body: dBodyID;
415  let geom: dGeomID;
416  let mut mass: Box<dMass> = Box::new(dMass::new());
417unsafe {
418  geom = match mi.id() {
419    MetaId::Sphere => {
420      let ms = mi.as_sphere();
421      if fmdm {
422        dMassSetSphereTotal(&mut *mass, ms.dm, ms.r); // dm as m
423      }else{
424        dMassSetSphere(&mut *mass, ms.dm, ms.r);
425      }
426      dCreateSphere(space, ms.r)
427    },
428    MetaId::Box => {
429      let mb = mi.as_box();
430      if fmdm {
431        dMassSetBoxTotal(&mut *mass, mb.dm,
432          mb.lxyz[0], mb.lxyz[1], mb.lxyz[2]); // dm as m
433      }else{
434        dMassSetBox(&mut *mass, mb.dm, mb.lxyz[0], mb.lxyz[1], mb.lxyz[2]);
435      }
436      dCreateBox(space, mb.lxyz[0], mb.lxyz[1], mb.lxyz[2])
437    },
438    MetaId::Capsule => {
439      let mc = mi.as_capsule();
440      dMassSetCapsule(&mut *mass, mc.dm, 3, mc.r, mc.l);
441      dCreateCapsule(space, mc.r, mc.l)
442    },
443    MetaId::Cylinder => {
444      let mc = mi.as_cylinder();
445      dMassSetCylinder(&mut *mass, mc.dm, 3, mc.r, mc.l);
446      dCreateCylinder(space, mc.r, mc.l)
447    },
448    MetaId::Plane => {
449      let mp = mi.as_plane();
450      if fmdm {
451        dMassSetBoxTotal(&mut *mass, mp.dm,
452          mp.lxyz[0], mp.lxyz[1], mp.lxyz[2]); // dm as m
453      }else{
454        dMassSetBox(&mut *mass, mp.dm, mp.lxyz[0], mp.lxyz[1], mp.lxyz[2]);
455      }
456      dCreatePlane(space, mp.norm[0], mp.norm[1], mp.norm[2], mp.norm[3])
457    },
458    MetaId::Convex => {
459      let mc = mi.as_convex();
460      let g: dGeomID = CreateGeomConvexFromFVP(space, mc.fvp);
461      MassSetConvexAsTrimesh(&mut *mass, mc.dm, mc.fvp);
462      dGeomSetPosition(g, -mass.c[0], -mass.c[1], -mass.c[2]); // ***
463      dMassTranslate(&mut *mass, -mass.c[0], -mass.c[1], -mass.c[2]); // ***
464      g
465    },
466    MetaId::TriMesh => {
467      let mt = mi.as_trimesh();
468      let g: dGeomID = CreateGeomTrimeshFromVI(space, mt.tmv);
469      dMassSetTrimesh(&mut *mass, mt.dm, g);
470      dGeomSetPosition(g, -mass.c[0], -mass.c[1], -mass.c[2]); // ***
471      dMassTranslate(&mut *mass, -mass.c[0], -mass.c[1], -mass.c[2]); // ***
472      g
473    },
474    MetaId::Composite => {
475      panic!("use creator_composite for {:?}", mi.id());
476    },
477    _ => { panic!("creator not implemented for {:?}", mi.id()); }
478  };
479}
480  let col = self.reg_mgm(geom, mi); // must call reg_mgm when not use col
481  (if key == "" {
482    0 as dBodyID
483  }else{
484unsafe {
485    body = dBodyCreate(world);
486    dBodySetMass(body, &*mass);
487    dGeomSetBody(geom, body);
488    if !self.get_krp(geom).g { dBodyDisable(body); } // care no id
489}
490    let obg: Obg = Obg::new(key, body, geom, col);
491    self.reg_obg(obg)
492  }, geom, mass)
493}
494
495/// create primitive object as m (register it to show on the ODE space world)
496pub fn creator_m(&mut self, key: &str, mi: Box<dyn MetaInf>) ->
497  (dBodyID, dGeomID, Box<dMass>) {
498  self.creator_dm(key, mi, true)
499}
500
501/// create primitive object as dm (register it to show on the ODE space world)
502pub fn creator(&mut self, key: &str, mi: Box<dyn MetaInf>) ->
503  (dBodyID, dGeomID, Box<dMass>) {
504  self.creator_dm(key, mi, false)
505}
506
507/// create composite object (register it to show on the ODE space world)
508pub fn creator_composite(&mut self, key: &str, mi: Box<dyn MetaInf>) ->
509  (dBodyID, dGeomID, Box<dMass>) {
510  let gws: &mut Gws = &mut self.gws;
511  let world: dWorldID = gws.world();
512  let space: dSpaceID = gws.space();
513  let body: dBodyID;
514  let geom: dGeomID;
515  let mut mass: Box<dMass> = Box::new(dMass::new());
516  // to keep order
517  let mut gto: VecDeque<dGeomID> = vec![].try_into().unwrap(); // no or_else
518  // gtrans, {gsub, o}
519  let mut gts: HashMap<dGeomID, GeomOffset> = vec![].into_iter().collect();
520unsafe {
521  body = dBodyCreate(world);
522}
523  geom = match mi.id() {
524    MetaId::Composite => {
525      let mc = mi.as_composite();
526unsafe {
527      for (j, emi) in mc.elems.iter().enumerate() {
528        let gtrans: dGeomID = dCreateGeomTransform(space);
529        dGeomTransformSetCleanup(gtrans, 1);
530        let (_, gsub, mut subm) = self.creator("", emi.dup());
531        dGeomTransformSetGeom(gtrans, gsub);
532        gto.push_front(gtrans); // first <-> last gto.push_back(gtrans);
533        let o = &mc.ofs[j];
534        gts.entry(gtrans).or_insert_with(|| GeomOffset{gsub: gsub, o: o});
535        dGeomSetPosition(gsub, o[0], o[1], o[2]);
536        dMassTranslate(&mut *subm, o[0], o[1], o[2]);
537        let q = &mc.qs[j];
538        // dQSetIdentity(q.as_ptr_mut());
539        // dQFromAxisAndAngle(q.as_ptr_mut(), , , , M_PI / 2.0);
540        dGeomSetQuaternion(gsub, q.as_ptr() as *mut dReal);
541        dMassRotate(&mut *subm, dMatrix3::from_Q(*q).as_ptr() as *mut dReal);
542        dMassAdd(&mut *mass, &*subm);
543        self.rgts.entry(gsub).or_insert(gtrans); // reverse geom gtrans
544      }
545      0 as dGeomID // composite Obg has no geom
546}
547    },
548    _ => { panic!("use creator for {:?}", mi.id()); }
549  };
550unsafe {
551  // adjust from CG != (0, 0, 0)
552  for (gtrans, gso) in &gts {
553    let o = gso.o;
554    dGeomSetPosition(gso.gsub, o[0]-mass.c[0], o[1]-mass.c[1], o[2]-mass.c[2]);
555  }
556  dMassTranslate(&mut *mass, -mass.c[0], -mass.c[1], -mass.c[2]);
557  dBodySetMass(body, &*mass); // CG == (0, 0, 0)
558  for gtrans in &gto {
559    dGeomSetBody(*gtrans, body);
560  }
561  if !self.get_krp(gts[&gto[0]].gsub).g { dBodyDisable(body); } // care no id
562}
563  gts.clear();
564  gto.clear();
565  let col = mi.get_tcm().col;
566  let obg: Obg = Obg::new(key, body, geom, col);
567  (self.reg_obg(obg), geom, mass)
568}
569
570/// search grand parent body
571/// (must check 0 as dBodyID later on the receiver)
572pub fn get_grand_parent(&self, id: dGeomID) -> dBodyID {
573unsafe {
574  let mut b: dBodyID = dGeomGetBody(id);
575  if b == 0 as dBodyID { // assume sub geom in the GeomTransform
576    b = match self.rgts.get(&id) { // reverse geom gtrans
577    None => 0 as dBodyID, // must check 0 as dBodyID later on the receiver
578    Some(&g) => dGeomGetBody(g)
579    };
580  }
581  b
582}
583}
584
585/// search ancestor (parent and grand parent) body
586/// (must check 0 as dBodyID later on the receiver)
587pub fn get_ancestor(&self, id: dGeomID) -> (dBodyID, dBodyID) {
588unsafe {
589  let p: dBodyID = dGeomGetBody(id);
590  // assume sub geom in the GeomTransform
591  let gp: dBodyID = match self.rgts.get(&id) { // reverse geom gtrans
592  None => 0 as dBodyID, // must check 0 as dBodyID later on the receiver
593  Some(&g) => dGeomGetBody(g)
594  };
595  (p, gp)
596}
597}
598
599/// is space (Geom)
600pub fn is_space(&self, o: dGeomID) -> bool {
601  unsafe { dGeomIsSpace(o) != 0 }
602}
603
604/// get ground (from Gws)
605pub fn get_ground(&self) -> dGeomID {
606  let gws = &self.gws;
607  gws.ground()
608}
609
610/// get contactgroup (from Gws)
611pub fn get_contactgroup(&self) -> dJointGroupID {
612  let gws = &self.gws;
613  gws.contactgroup()
614}
615
616/// get contacts
617pub fn get_contacts(&mut self, o1: dGeomID, o2: dGeomID) -> i32 {
618  let gws = &mut self.gws;
619  let sz: i32 = std::mem::size_of::<dContact>() as i32;
620unsafe {
621  dCollide(o1, o2, gws.num_contact() as i32, &mut gws.contacts[0].geom, sz)
622}
623}
624
625/// ref contacts mut
626pub fn ref_contacts_mut(&mut self) -> &mut Vec<dContact> {
627  &mut self.gws.contacts
628}
629
630/// ref contacts
631pub fn ref_contacts(&self) -> &Vec<dContact> {
632  &self.gws.contacts
633}
634
635/// get body num joints
636pub fn get_body_num_joints(&self, b: dBodyID) -> usize {
637  unsafe { dBodyGetNumJoints(b) as usize } // c_int
638}
639
640/// get body joint
641pub fn get_body_joint(&self, b: dBodyID, i: usize) -> dJointID {
642  unsafe { dBodyGetJoint(b, i as c_int) }
643}
644
645/// get joint num bodies
646pub fn get_joint_num_bodies(&self, joint: dJointID) -> usize {
647  unsafe { dJointGetNumBodies(joint) as usize }
648}
649
650/// get joint body
651pub fn get_joint_body(&self, joint: dJointID, i: usize) -> dBodyID {
652  unsafe { dJointGetBody(joint, i as c_int) }
653}
654
655/// is joint enabled
656pub fn is_joint_enabled(&self, joint: dJointID) -> bool {
657  unsafe { dJointIsEnabled(joint) != 0 }
658}
659
660/// get joint type
661pub fn get_joint_type(&self, joint: dJointID) -> dJointType {
662  unsafe { dJointGetType(joint) }
663}
664
665/// get joint data
666pub fn get_joint_data(&self, joint: dJointID) -> *mut c_void {
667  unsafe { dJointGetData(joint) }
668}
669
670/// search bounce (especially support GeomTransform)
671pub fn get_bounce(&self, id: dGeomID) -> dReal {
672  let gid: dGeomID = match unsafe { dGeomGetClass(id) } {
673    dGeomTransformClass => unsafe { dGeomTransformGetGeom(id) },
674    _ => id
675  }; // GeomTransform is never registered
676  match self.get_mgm(gid) {
677    Err(_) => KRP100.bounce, // will not be arrived here (check class before)
678    Ok(mgm) => mgm.get_krp().bounce
679  }
680}
681
682/// search mu (especially support GeomTransform)
683pub fn get_mu(&self, id: dGeomID) -> dReal {
684  let gid: dGeomID = match unsafe { dGeomGetClass(id) } {
685    dGeomTransformClass => unsafe { dGeomTransformGetGeom(id) },
686    _ => id
687  }; // GeomTransform is never registered
688  match self.get_mgm(gid) {
689    Err(_) => KRP100.mu, // will not be arrived here (check class before)
690    Ok(mgm) => mgm.get_krp().mu
691  }
692}
693
694/// search Krp mut (from HashMap)
695pub fn get_krp_mut(&mut self, id: dGeomID) -> &mut Krp {
696  // self.get_mgm_mut(id).unwrap().get_krp_mut() // no care or_else
697  match self.get_mgm_mut(id) {
698    Err(_) => panic!("unregistered dGeomID MetaInf"), // cannot use &mut KRP100
699    Ok(mgm) => mgm.get_krp_mut()
700  }
701}
702
703/// search Krp (from HashMap)
704pub fn get_krp(&self, id: dGeomID) -> &Krp {
705  // self.get_mgm(id).unwrap().get_krp() // no care or_else
706  match self.get_mgm(id) {
707    Err(_) => &KRP100, // or raise panic!
708    Ok(mgm) => mgm.get_krp()
709  }
710}
711
712/// search MetaInf, TCMaterial mut (from HashMap)
713pub fn get_mgm_mut(&mut self, id: dGeomID) ->
714  Result<&mut Box<dyn MetaInf>, Box<dyn Error>> {
715  let mgms: &mut HashMap<dGeomID, Box<dyn MetaInf>> = &mut self.mgms;
716  Ok(mgms.get_mut(&id).ok_or(ODEError::no_mgm_id(id))?)
717}
718
719/// search MetaInf, TCMaterial (from HashMap)
720pub fn get_mgm(&self, id: dGeomID) ->
721  Result<&Box<dyn MetaInf>, Box<dyn Error>> {
722  let mgms: &HashMap<dGeomID, Box<dyn MetaInf>> = &self.mgms;
723  Ok(mgms.get(&id).ok_or(ODEError::no_mgm_id(id))?)
724}
725
726/// search id (from BTreeMap)
727pub fn get_id(&self, k: String) -> Result<dBodyID, Box<dyn Error>> {
728  let mbgs: &BTreeMap<String, dBodyID> = &self.mbgs;
729  // not use mbgs[&k]
730  Ok(*mbgs.get(&k).ok_or(ODEError::no_key(k))?)
731}
732
733/// search object mut (from HashMap)
734pub fn get_mut(&mut self, id: dBodyID) -> Result<&mut Obg, Box<dyn Error>> {
735  let obgs: &mut HashMap<dBodyID, Obg> = &mut self.obgs;
736  Ok(obgs.get_mut(&id).ok_or(ODEError::no_id(id))?)
737}
738
739/// search object mut (from BTreeMap and HashMap)
740pub fn find_mut(&mut self, k: String) -> Result<&mut Obg, Box<dyn Error>> {
741  let id: dBodyID = self.get_id(k)?;
742  self.get_mut(id)
743}
744
745/// search object (from HashMap)
746pub fn get(&self, id: dBodyID) -> Result<&Obg, Box<dyn Error>> {
747  let obgs: &HashMap<dBodyID, Obg> = &self.obgs;
748  Ok(obgs.get(&id).ok_or(ODEError::no_id(id))?)
749}
750
751/// search object (from BTreeMap and HashMap)
752pub fn find(&self, k: String) -> Result<&Obg, Box<dyn Error>> {
753  let id: dBodyID = self.get_id(k)?;
754  self.get(id)
755}
756
757/// each_id (may use immutable result with get_mut to avoid dup mutable borrow)
758/// - la: FnMut(key: &amp;str, id: dBodyID) -&gt; bool
759pub fn each_id<F>(&self, mut la: F) -> Vec<dBodyID>
760  where F: FnMut(&str, dBodyID) -> bool {
761  let mut r: Vec<dBodyID> = vec![];
762  for (k, v) in &self.mbgs {
763    r.push(if la(k, *v) { *v } else { 0 as dBodyID });
764  }
765  r
766}
767
768/// each (can break by result of lambda)
769/// - la: FnMut(key: &amp;str, id: dBodyID, obg: &amp;Obg) -&gt; bool
770pub fn each<F>(&self, mut la: F) -> bool
771  where F: FnMut(&str, dBodyID, &Obg) -> bool {
772  for (k, v) in &self.mbgs {
773    match self.get(*v) {
774      Err(e) => { println!("{}", e); }, // may not be arrived here
775      Ok(obg) => { if !la(k, *v, obg) { return false; } }
776    }
777  }
778  true
779}
780
781/// each geom in body (can break by result of lambda)
782/// - la: FnMut(g: dGeomID, obg: &amp;Obg) -&gt; bool
783pub fn each_geom<F>(&self, obg: &Obg, mut la: F) -> bool
784  where F: FnMut(dGeomID, &Obg) -> bool {
785unsafe {
786  let mut geom: dGeomID = dBodyGetFirstGeom(obg.body());
787  while(geom != 0 as dGeomID){
788    let nextgeom: dGeomID = dBodyGetNextGeom(geom);
789    if !la(geom, obg) { return false; }
790    geom = nextgeom;
791  }
792  true
793}
794}
795
796/// destroy object (not unregister)
797pub fn destroy_obg(obg: &Obg) {
798unsafe {
799  // dGeomDestroy(obg.geom()); // not use it
800  let mut geom: dGeomID = dBodyGetFirstGeom(obg.body());
801  while(geom != 0 as dGeomID){
802    let nextgeom: dGeomID = dBodyGetNextGeom(geom);
803    // dGeomTriMeshDataDestroy(tmd); // when geom has dTriMeshDataID tmd
804    // UnMapGeomTriMesh(geom); // needless (to be deleted in clear_obgs())
805    // UnMapGeomConvex(geom); // needless (to be deleted in clear_obgs())
806    dGeomDestroy(geom);
807    geom = nextgeom;
808  }
809  dBodyDestroy(obg.body());
810}
811}
812
813/// unregister object
814/// - f: true with destroy
815pub fn unregister_obg(&mut self, obg: &Obg, f: bool) -> Option<Obg> {
816unsafe {
817  let b = obg.body();
818  let rgts: &mut HashMap<dGeomID, dGeomID> = &mut ode_get_mut!(rgts);
819  let mgms: &mut HashMap<dGeomID, Box<dyn MetaInf>> = &mut ode_get_mut!(mgms);
820  self.each_geom(obg, |g, _o| {
821    rgts.remove(&g); // gsub, gtrans
822    mgms.remove(&g); // geom, metainf
823    true
824  });
825  let vbgs: &mut VecDeque<dBodyID> = &mut ode_get_mut!(vbgs);
826  match vbgs.iter().position(|&e| e == b) {
827  None => (),
828  Some(i) => { vbgs.remove(i); }
829  }
830  let mbgs: &mut BTreeMap<String, dBodyID> = &mut ode_get_mut!(mbgs);
831  mbgs.remove(&obg.key); // key, body
832  let obgs: &mut HashMap<dBodyID, Obg> = &mut ode_get_mut!(obgs);
833  match obgs.remove(&b) { // body, Obg
834  None => None,
835  Some(obg) => if f { ODE::destroy_obg(&obg); None } else { Some(obg) }
836  }
837}
838}
839
840/// unregister object by id (not destroy)
841/// - f: true with destroy
842pub fn unregister_obg_by_id(&mut self, id: dBodyID, f: bool) -> Option<Obg> {
843  // let obg = self.obgs.get(&id); // cannot use immut and mut at the same time
844unsafe {
845  let obgs: &mut HashMap<dBodyID, Obg> = &mut ode_get_mut!(obgs); // avoid it
846  match obgs.get(&id) {
847  None => None,
848  Some(obg) => self.unregister_obg(obg, f)
849  }
850}
851}
852
853/// destroy and unregister all objects
854pub fn clear_obgs() {
855unsafe {
856  let obgs: &HashMap<dBodyID, Obg> = &ode_get!(obgs);
857  for (id, obg) in obgs {
858    ODE::destroy_obg(obg); // not obgs.remove(id);
859  }
860  let obgs: &mut HashMap<dBodyID, Obg> = &mut ode_get_mut!(obgs);
861  obgs.clear();
862  let mbgs: &mut BTreeMap<String, dBodyID> = &mut ode_get_mut!(mbgs);
863  mbgs.clear();
864  let vbgs: &mut VecDeque<dBodyID> = &mut ode_get_mut!(vbgs);
865  vbgs.clear();
866  let mgms: &mut HashMap<dGeomID, Box<dyn MetaInf>> = &mut ode_get_mut!(mgms);
867  mgms.clear();
868  let rgts: &mut HashMap<dGeomID, dGeomID> = &mut ode_get_mut!(rgts);
869  rgts.clear();
870  let rode: &mut ODE = &mut ode_mut!();
871  rode.modify();
872}
873}
874
875/// destroy contact group and re initialize it
876pub fn clear_contactgroup() {
877unsafe {
878  let gws: &mut Gws = &mut ode_get_mut!(gws);
879  dJointGroupDestroy(gws.contactgroup());
880  gws.contactgroup_(dJointGroupCreate(0));
881}
882}
883
884/// set viewpoint (from the current viewpoint Cam[sw_viewpoint])
885pub fn viewpoint_() {
886  let ds = ODE::ds_as_ref();
887unsafe {
888  let sw_viewpoint: &usize = &ode_get!(sw_viewpoint);
889  let cams: &mut BTreeMap<usize, Cam> = &mut ode_get_mut!(cams);
890  let cam = cams.get_mut(sw_viewpoint).unwrap(); // &mut cams[sw_viewpoint];
891  let pos: &mut [f32] = &mut cam.pos;
892  let ypr: &mut [f32] = &mut cam.ypr;
893  ds.SetViewpoint(pos as *mut [f32] as *mut f32, ypr as *mut [f32] as *mut f32);
894}
895}
896
897/// get viewpoint (f: true, save to the current viewpoint Cam[sw_viewpoint])
898pub fn viewpoint(f: bool) {
899  let ds = ODE::ds_as_ref();
900unsafe {
901  let p: &mut [f32] = &mut vec![0.0; 4];
902  let y: &mut [f32] = &mut vec![0.0; 4];
903  ds.GetViewpoint(p as *mut [f32] as *mut f32, y as *mut [f32] as *mut f32);
904  let sw_viewpoint: &usize = &ode_get!(sw_viewpoint);
905  println!("viewpoint {} {:?}, {:?}", *sw_viewpoint, p, y);
906  match f {
907    true => {
908      let cams: &mut BTreeMap<usize, Cam> = &mut ode_get_mut!(cams);
909      let cam = cams.get_mut(sw_viewpoint).unwrap(); // &mut cams[sw_viewpoint];
910      cam.pos = p.to_vec();
911      cam.ypr = y.to_vec();
912    },
913    _ => {}
914  }
915}
916}
917
918/// default simulation loop
919pub fn sim_loop(
920  width: i32, height: i32,
921  r_sim: Option<Box<dyn Sim>>,
922  a: &[u8]) {
923  let ds = ODE::ds_as_ref();
924unsafe {
925  let sim: &mut Option<Box<dyn Sim>> = &mut ode_get_mut!(sim);
926  *sim = r_sim;
927  let ptt: &mut Option<U8zBuf> = &mut ode_get_mut!(ptt);
928  *ptt = Some(U8zBuf::from_u8array(a)); // to keep lifetime
929  let mut dsfn: dsFunctions_C = dsFunctions_C{
930    version: DS_VERSION,
931    start: Some(c_start_callback), // Option<unsafe extern "C" fn()>
932    step: Some(c_step_callback), // Option<unsafe extern "C" fn(i32)>
933    command: Some(c_command_callback), // Option<unsafe extern "C" fn(i32)>
934    stop: Some(c_stop_callback), // Option<unsafe extern "C" fn()>
935    path_to_textures: ptt.as_ref().expect("not init").as_i8p()
936  };
937
938  let mut cab: CArgsBuf = CArgsBuf::from(&std::env::args().collect());
939  ds.SimulationLoop(cab.as_argc(), cab.as_argv_ptr_mut(),
940    width, height, &mut dsfn);
941}
942}
943
944} // impl ODE
945
946/// binding finalize ODE (auto called)
947impl Drop for ODE {
948  fn drop(&mut self) {
949    unsafe { dCloseODE(); }
950    ostatln!("dropped ODE");
951  }
952}
953
954/// trait Sim must have callback functions
955pub trait Sim {
956  /// self.super mutable
957  fn super_mut(&mut self) -> &mut ODE {
958unsafe {
959    &mut ode_mut!()
960}
961  }
962
963  /// self.super immutable
964  fn super_get(&self) -> &ODE {
965unsafe {
966    &ode_!()
967}
968  }
969
970  /// set pos and rotation (dMatrix3)
971  fn set_pos_R(&mut self, b: dBodyID, p: dVector3, m: dMatrix3) {
972    self.super_mut().get_mut(b).expect("no body").set_pos(p).set_rot(m);
973  }
974
975  /// set pos and rotation (dQuaternion)
976  fn set_pos_Q(&mut self, b: dBodyID, p: dVector3, q: dQuaternion) {
977    self.super_mut().get_mut(b).expect("no body").set_pos(p).set_quaternion(q);
978  }
979
980  /// draw_geom function
981  fn draw_geom(&self, geom: dGeomID,
982    pos: Option<*const dReal>, rot: Option<*const dReal>, ws: i32);
983  /// draw default function
984  fn draw_objects(&mut self);
985  /// start default callback function
986  fn start_callback(&mut self);
987  /// near default callback function
988  fn near_callback(&mut self, dat: *mut c_void, o1: dGeomID, o2: dGeomID);
989  /// step default callback function
990  fn step_callback(&mut self, pause: i32);
991  /// command default callback function
992  fn command_callback(&mut self, cmd: i32);
993  /// stop default callback function
994  fn stop_callback(&mut self);
995}
996
997/// trait Sim must have callback functions
998impl Sim for ODE {
999
1000/// implements drawing composite
1001/// wire_solid i32 false/true for bunny
1002fn draw_objects(&mut self) {
1003  ostatln!("called default draw");
1004  let wire_solid = self.wire_solid; // for bunny
1005  let obgs = &self.obgs;
1006  let vbgs = &self.vbgs;
1007  for id in vbgs { // drawing order
1008    let obg = &obgs[&id];
1009unsafe {
1010    let mut g = dBodyGetFirstGeom(obg.body());
1011    while g != 0 as dGeomID {
1012      self.draw_geom(g, None, None, wire_solid);
1013      g = dBodyGetNextGeom(g);
1014    }
1015}
1016  }
1017}
1018
1019/// draw_geom (called by draw_objects and recursive)
1020fn draw_geom(&self, geom: dGeomID,
1021  pos: Option<*const dReal>, rot: Option<*const dReal>, ws: i32) {
1022  if geom == 0 as dGeomID { return; }
1023  let ds = ODE::ds_as_ref();
1024unsafe {
1025  let pos: *const dReal = pos.unwrap_or_else(|| dGeomGetPosition(geom));
1026  let rot: *const dReal = rot.unwrap_or_else(|| dGeomGetRotation(geom));
1027  let col: &dVector4 = match self.get_mgm(geom) {
1028    Err(e) => {
1029      let obg = self.get(dGeomGetBody(geom)).unwrap(); // must care ok_or
1030      &obg.col
1031    },
1032    Ok(mgm) => {
1033      let tcm = mgm.get_tcm();
1034      ds.SetTexture(tcm.tex);
1035      &tcm.col
1036    }
1037  };
1038  let c: Vec<f32> = col.into_iter().map(|v| *v as f32).collect();
1039  ds.SetColorAlpha(c[0], c[1], c[2], c[3]);
1040  let cls = dGeomGetClass(geom);
1041  match cls {
1042    dSphereClass => {
1043      let radius: dReal = dGeomSphereGetRadius(geom);
1044      ds.DrawSphereD(pos, rot, radius as f32);
1045    },
1046    dBoxClass => {
1047      let mut lxyz: dVector3 = [0.0; 4];
1048      dGeomBoxGetLengths(geom, lxyz.as_ptr_mut());
1049      ds.DrawBoxD(pos, rot, lxyz.as_ptr());
1050    },
1051    dCapsuleClass => {
1052      let mut r: dReal = 0.0;
1053      let mut l: dReal = 0.0;
1054      dGeomCapsuleGetParams(geom, &mut r as *mut dReal, &mut l as *mut dReal);
1055      ds.DrawCapsuleD(pos, rot, l as f32, r as f32);
1056    },
1057    dCylinderClass => {
1058      let mut r: dReal = 0.0;
1059      let mut l: dReal = 0.0;
1060      dGeomCylinderGetParams(geom, &mut r as *mut dReal, &mut l as *mut dReal);
1061      ds.DrawCylinderD(pos, rot, l as f32, r as f32);
1062    },
1063    dPlaneClass => {
1064      let mut norm: dVector4 = [0.0; 4];
1065      dGeomPlaneGetParams(geom, norm.as_ptr_mut());
1066      // (a Plane is not a Box) dGeomBoxGetLengths
1067      let lxyz: dVector3 = [10.0, 10.0, 0.05, 0.0]; // ***
1068      ds.DrawBoxD(pos, rot, lxyz.as_ptr());
1069    },
1070    dRayClass => {
1071      println!("not implemented class: {}", cls);
1072    },
1073    dConvexClass => {
1074      match self.get_mgm(geom) {
1075        Err(e) => { println!("not found convex {:?} geomID {:?}", e, geom); },
1076        Ok(mgm) => {
1077          let fvp: &convexfvp = &*mgm.as_convex().fvp;
1078          ds.DrawConvexD(pos, rot,
1079            fvp.faces, fvp.faceCount, fvp.vtx, fvp.vtxCount, fvp.polygons);
1080        }
1081      }
1082    },
1083    dGeomTransformClass => {
1084      let gt: dGeomID = dGeomTransformGetGeom(geom);
1085      let gtpos: *const dReal = dGeomGetPosition(gt);
1086      let gtrot: *const dReal = dGeomGetRotation(gt);
1087      let mut rpos = dVector3::multiply0_331_pp(rot, gtpos);
1088      let ppos = std::slice::from_raw_parts(pos, 4); // must be in unsafe
1089      for i in 0..4 { rpos[i] += ppos[i]; }
1090      let rrot = dMatrix3::multiply0_333_pp(rot, gtrot);
1091      self.draw_geom(gt, Some(rpos.as_ptr()), Some(rrot.as_ptr()), ws);
1092    },
1093    dTriMeshClass => {
1094      match self.get_mgm(geom) {
1095        Err(e) => { println!("not found trimesh {:?} geomID {:?}", e, geom); },
1096        Ok(mgm) => {
1097          let tmv: &trimeshvi = &*mgm.as_trimesh().tmv;
1098/* (C)
1099    int is_composite = (dGeomGetSpace(geom) == 0);
1100    dVector3 tpos = {0.0, 0.0, 0.0};
1101    dMatrix3 trot;
1102    dRSetIdentity(trot);
1103    int triCount = dGeomTriMeshGetTriangleCount(geom);
1104    for(int i = 0; i < triCount; ++i){
1105      dVector3 v0, v1, v2;
1106      dGeomTriMeshGetTriangle(geom, i, &v0, &v1, &v2); // already transformed
1107      if(!is_composite) dsDrawTriangleD(tpos, trot, v0, v1, v2, ws); // top
1108      else dsDrawTriangleD(pos, rot, v0, v1, v2, ws); // in the dTransformClass
1109    }
1110*/
1111          let vtx = tmv.as_slice_vtx();
1112          let p = tmv.as_slice_indices();
1113          for i in 0..p.len()/3 {
1114            let idx = [p[i*3] as usize, p[i*3+1] as usize, p[i*3+2] as usize];
1115            let v: [[dReal; 3]; 3] = [
1116              [vtx[idx[0] * 3 + 0], vtx[idx[0] * 3 + 1], vtx[idx[0] * 3 + 2]],
1117              [vtx[idx[1] * 3 + 0], vtx[idx[1] * 3 + 1], vtx[idx[1] * 3 + 2]],
1118              [vtx[idx[2] * 3 + 0], vtx[idx[2] * 3 + 1], vtx[idx[2] * 3 + 2]]];
1119            ds.DrawTriangleD(pos, rot,
1120              v[0].as_ptr(), v[1].as_ptr(), v[2].as_ptr(), ws);
1121          }
1122        }
1123      }
1124    },
1125    dHeightfieldClass => {
1126      println!("not implemented class: {}", cls);
1127    },
1128    _ => { println!("unknown class: {}", cls); }
1129  }
1130}
1131}
1132
1133/// start default callback function
1134fn start_callback(&mut self) {
1135  ostatln!("called default start");
1136  let ds = ODE::ds_as_ref();
1137  ODE::viewpoint_();
1138unsafe {
1139  ds.SetSphereQuality(3); // default sphere 1
1140  ds.SetCapsuleQuality(3); // default capsule 3
1141}
1142}
1143
1144/// near default callback function
1145fn near_callback(&mut self, dat: *mut c_void, o1: dGeomID, o2: dGeomID) {
1146  ostatln!("called default near");
1147  let gws = &self.gws;
1148  let world: dWorldID = gws.world();
1149  let contactgroup: dJointGroupID = gws.contactgroup();
1150  let ground: dGeomID = gws.ground();
1151unsafe {
1152  if dGeomIsSpace(o1) != 0 || dGeomIsSpace(o2) != 0 {
1153    dSpaceCollide2(o1, o2, dat, Some(c_near_callback));
1154    if dGeomIsSpace(o1) != 0 {
1155      dSpaceCollide(o1 as dSpaceID, dat, Some(c_near_callback));
1156    }
1157    if dGeomIsSpace(o2) != 0 {
1158      dSpaceCollide(o2 as dSpaceID, dat, Some(c_near_callback));
1159    }
1160    return;
1161  }
1162  let n = self.get_contacts(o1, o2);
1163  if ground == o1 || ground == o2 { // vs ground
1164    let id: dGeomID = if ground == o1 { o2 } else { o1 };
1165    let bounce: dReal = self.get_bounce(id);
1166    let mu: dReal = self.get_mu(id);
1167    for i in 0..n as usize {
1168      let p: &mut dContact = &mut self.gws.contacts[i];
1169      p.surface.mode = dContactBounce | dContactSoftERP | dContactSoftCFM;
1170      p.surface.bounce = bounce; // or 0.0
1171      p.surface.bounce_vel = 1e-2; // 1e-3 or 0.0 minimum velocity for bounce
1172      p.surface.mu = mu; // or dInfinity or 0.5
1173      p.surface.soft_erp = 0.2; // default 0.2 (0.1 to 0.8)
1174      p.surface.soft_cfm = 1e-3; // default 1e-5f32 or 1e-10f64 (1e-9 to 1.0)
1175      let c: dJointID = dJointCreateContact(world, contactgroup, p);
1176      // dJointAttach(c, dGeomGetBody(p.geom.g1), dGeomGetBody(p.geom.g2));
1177      dJointAttach(c, dGeomGetBody(o1), dGeomGetBody(o2));
1178    }
1179  }else{
1180    let bounce: dReal = self.get_bounce(o1) * self.get_bounce(o2);
1181    let mu: dReal = dReal::min(self.get_mu(o1), self.get_mu(o2));
1182    for i in 0..n as usize {
1183      let p: &mut dContact = &mut self.gws.contacts[i];
1184      p.surface.mode = dContactBounce; // | dContactSoftERP | dContactSoftCFM;
1185      p.surface.bounce = bounce; // or 0.0
1186      p.surface.bounce_vel = 1e-2; // 1e-3 or 0.0 minimum velocity for bounce
1187      p.surface.mu = mu; // or dInfinity or 0.5
1188/*
1189      p.surface.soft_erp = 0.2; // default 0.2 (0.1 to 0.8)
1190      p.surface.soft_cfm = 1e-3; // default 1e-5f32 or 1e-10f64 (1e-9 to 1.0)
1191*/
1192      let c: dJointID = dJointCreateContact(world, contactgroup, p);
1193      // dJointAttach(c, dGeomGetBody(p.geom.g1), dGeomGetBody(p.geom.g2));
1194      dJointAttach(c, dGeomGetBody(o1), dGeomGetBody(o2));
1195    }
1196  }
1197}
1198}
1199
1200/// step default callback function
1201fn step_callback(&mut self, pause: i32) {
1202  ostatln!("called default step");
1203  let gws = &self.gws;
1204  let t_delta = &self.t_delta;
1205  if pause != 1 {
1206    let mut tmp: HashMap<dBodyID, dVector3> = vec![].into_iter().collect();
1207    for (id, mi) in &self.mgms {
1208      if !mi.get_krp().k {
1209        let b: dBodyID = self.get_grand_parent(*id);
1210        if b == 0 as dBodyID { continue; }
1211        tmp.entry(b).or_insert(Obg::get_pos_mut_by_id(b)); // pass mut as const
1212      }
1213    }
1214unsafe {
1215    dSpaceCollide(gws.space(), 0 as *mut c_void, Some(c_near_callback));
1216    dWorldStep(gws.world(), *t_delta);
1217    // dWorldQuickStep(gws.world(), *t_delta);
1218    dJointGroupEmpty(gws.contactgroup());
1219}
1220    for (&b, p) in &tmp { Obg::set_pos_by_id(b, p); }
1221  }
1222  ode_sim!(self, draw_objects)
1223}
1224
1225/// command default callback function
1226fn command_callback(&mut self, cmd: i32) {
1227  ostatln!("called default command");
1228  let ds = ODE::ds_as_ref();
1229  match cmd as u8 as char {
1230    'p' => {
1231unsafe {
1232      let polyfill_wireframe: &mut i32 = &mut ode_get_mut!(polyfill_wireframe);
1233      *polyfill_wireframe = 1 - *polyfill_wireframe;
1234      ds.SetDrawMode(*polyfill_wireframe);
1235}
1236    },
1237    'w' => {
1238unsafe {
1239      let wire_solid: &mut i32 = &mut ode_get_mut!(wire_solid);
1240      *wire_solid = 1 - *wire_solid;
1241}
1242    },
1243    'v' => {
1244      ODE::viewpoint(false);
1245    },
1246    's' => {
1247      ODE::viewpoint(true);
1248unsafe {
1249      let sw_viewpoint: &mut usize = &mut ode_get_mut!(sw_viewpoint);
1250      *sw_viewpoint = (*sw_viewpoint + 1) % self.cams.len();
1251}
1252      ODE::viewpoint_();
1253      ODE::viewpoint(false);
1254    },
1255    'r' => {
1256      ODE::clear_obgs();
1257      ODE::clear_contactgroup();
1258      ode_sim!(self, start_callback)
1259    },
1260    '?' => {
1261      println!("{}", KEY_HELP);
1262    },
1263    _ => {}
1264  }
1265}
1266
1267/// stop default callback function
1268fn stop_callback(&mut self) {
1269  ostatln!("called default stop");
1270}
1271
1272} // impl Sim for ODE
1273
1274unsafe extern "C"
1275fn c_start_callback() {
1276  let rode: &mut ODE = &mut ode_mut!();
1277  ode_sim!(rode, start_callback)
1278}
1279
1280unsafe extern "C"
1281fn c_near_callback(dat: *mut c_void, o1: dGeomID, o2: dGeomID) {
1282  let rode: &mut ODE = &mut ode_mut!();
1283  ode_sim!(rode, near_callback, dat, o1, o2)
1284}
1285
1286unsafe extern "C"
1287fn c_step_callback(pause: i32) {
1288  let rode: &mut ODE = &mut ode_mut!();
1289  ode_sim!(rode, step_callback, pause)
1290}
1291
1292unsafe extern "C"
1293fn c_command_callback(cmd: i32) {
1294  let rode: &mut ODE = &mut ode_mut!();
1295  ode_sim!(rode, command_callback, cmd)
1296}
1297
1298unsafe extern "C"
1299fn c_stop_callback() {
1300  let rode: &mut ODE = &mut ode_mut!();
1301  ode_sim!(rode, stop_callback)
1302}
1303
1304/// for debug output status
1305#[macro_export]
1306macro_rules! ostat {
1307  // ($($e:expr),+) => { print!($($e),*); };
1308  ($($e:expr),+) => {};
1309}
1310pub use ostat;
1311
1312/// for debug output status with ln
1313#[macro_export]
1314macro_rules! ostatln {
1315  // ($($e:expr),+) => { println!($($e),*); };
1316  ($($e:expr),+) => {};
1317}
1318pub use ostatln;