Skip to main content

dx9/core/
prim.rs

1//! prim.rs
2
3pub mod xmat;
4
5use crate::core::*;
6// use crate::w32a::*;
7use std::{result::Result, error::Error};
8use std::{ffi};
9
10/// D3DX_PI
11pub const D3DX_PI: f32 = std::f32::consts::PI;
12
13/// rad
14#[inline]
15pub fn rad(a: f32) -> f32 {
16  a * D3DX_PI / 180.0f32 // instead of unsafe { D3DXToRadian(a) }
17}
18
19/// normalize_deg
20pub fn normalize_deg(a: f32) -> f32 {
21  let p = 180.0f32;
22  let p2 = 2.0f32 * p;
23  let mut a = a;
24  while a > p { a -= p2 }
25  while a < -p { a += p2 }
26  a
27}
28
29/// normalize_rad
30pub fn normalize_rad(th: f32) -> f32 {
31  let pi = std::f32::consts::PI;
32  let pi2 = 2.0f32 * pi;
33  let mut th = th;
34  while th > pi { th -= pi2 }
35  while th < -pi { th += pi2 }
36  th
37}
38
39/// prec_eq
40#[inline]
41pub fn prec_eq(a: f32, b: f32, p: f32) -> bool {
42  prec_diff(a, b, p) == 0.0f32
43}
44
45/// prec_diff
46pub fn prec_diff(a: f32, b: f32, p: f32) -> f32 {
47  if a == b { 0.0 }
48  else {
49    let f = a - b;
50    if f > 0.0 { if p > f { 0.0 } else { f } }
51    else { if p > -f { 0.0 } else { f } }
52  }
53}
54
55/// toarray macro
56#[macro_export]
57macro_rules! toarray {
58  ($o:expr) => { $o.collect::<Vec<_>>().try_into().expect("toarray") };
59}
60pub use toarray;
61
62/// XV2ULL
63#[derive(Clone)]
64pub struct XV2ULL (pub [ffi::c_ulonglong; 2]);
65
66/// trait Ptr for XV2ULL
67impl Ptr<u64> for XV2ULL {
68  /// ptr
69  #[inline]
70  fn ptr(&self) -> *const u64 { self as *const XV2ULL as *const u64 }
71  /// ptr_mut
72  #[inline]
73  fn ptr_mut(&mut self) -> *mut u64 { self as *mut XV2ULL as *mut u64 }
74}
75
76/// trait Dump for XV2ULL
77impl Dump for XV2ULL {
78  /// dump
79  fn dump(&self) -> String {
80    let mut p = DispMatParam{m: self.voidp(), w: SZU64, rows: 1, cols: 2,
81      fmt: "%016llx\0".as_ptr(), di: 16, df: 0, r: 0, c: 0};
82    let f = cb_xll;
83    let mut s = [0u8; SZBUF];
84unsafe {
85    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
86    String::from_utf8(s[..l].to_vec()).expect("utf8")
87}
88  }
89}
90
91/// trait Disp for XV2ULL
92impl Disp for XV2ULL {
93  /// disp
94  fn disp(&self, di: usize, df: usize) -> String {
95    let fmt = format!("%{}llu\0", di).as_str().as_ptr();
96    let mut p = DispMatParam{m: self.voidp(), w: SZU64, rows: 1, cols: 2,
97      fmt, di, df, r: 0, c: 0};
98    let f = cb_u64; // (by di) same as cb_ull (by fmt)
99    let mut s = [0u8; SZBUF];
100unsafe {
101    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
102    String::from_utf8(s[..l].to_vec()).expect("utf8")
103}
104  }
105}
106
107/// trait Display for XV2ULL
108impl std::fmt::Display for XV2ULL {
109  /// fmt
110  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111    write!(f, "{}", self.disp(21, 0))
112  }
113}
114
115/// trait Debug for XV2ULL
116impl std::fmt::Debug for XV2ULL {
117  /// fmt
118  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119    write!(f, "{}", self.disp(21, 0))
120  }
121}
122
123/// XV2LL
124#[derive(Clone)]
125pub struct XV2LL (pub [ffi::c_longlong; 2]);
126
127/// trait Ptr for XV2LL
128impl Ptr<i64> for XV2LL {
129  /// ptr
130  #[inline]
131  fn ptr(&self) -> *const i64 { self as *const XV2LL as *const i64 }
132  /// ptr_mut
133  #[inline]
134  fn ptr_mut(&mut self) -> *mut i64 { self as *mut XV2LL as *mut i64 }
135}
136
137/// trait Dump for XV2LL
138impl Dump for XV2LL {
139  /// dump
140  fn dump(&self) -> String {
141    let mut p = DispMatParam{m: self.voidp(), w: SZI64, rows: 1, cols: 2,
142      fmt: "%016llx\0".as_ptr(), di: 16, df: 0, r: 0, c: 0};
143    let f = cb_xll;
144    let mut s = [0u8; SZBUF];
145unsafe {
146    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
147    String::from_utf8(s[..l].to_vec()).expect("utf8")
148}
149  }
150}
151
152/// trait Disp for XV2LL
153impl Disp for XV2LL {
154  /// disp
155  fn disp(&self, di: usize, df: usize) -> String {
156    let fmt = format!("%{}lld\0", di).as_str().as_ptr();
157    let mut p = DispMatParam{m: self.voidp(), w: SZI64, rows: 1, cols: 2,
158      fmt, di, df, r: 0, c: 0};
159    let f = cb_i64; // (by di) same as cb_ll (by fmt)
160    let mut s = [0u8; SZBUF];
161unsafe {
162    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
163    String::from_utf8(s[..l].to_vec()).expect("utf8")
164}
165  }
166}
167
168/// trait Display for XV2LL
169impl std::fmt::Display for XV2LL {
170  /// fmt
171  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172    write!(f, "{}", self.disp(21, 0))
173  }
174}
175
176/// trait Debug for XV2LL
177impl std::fmt::Debug for XV2LL {
178  /// fmt
179  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180    write!(f, "{}", self.disp(21, 0))
181  }
182}
183
184/// XV2U
185#[derive(Clone)]
186pub struct XV2U (pub [ffi::c_uint; 2]);
187
188/// trait Ptr for XV2U
189impl Ptr<u32> for XV2U {
190  /// ptr
191  #[inline]
192  fn ptr(&self) -> *const u32 { self as *const XV2U as *const u32 }
193  /// ptr_mut
194  #[inline]
195  fn ptr_mut(&mut self) -> *mut u32 { self as *mut XV2U as *mut u32 }
196}
197
198/// trait Dump for XV2U
199impl Dump for XV2U {
200  /// dump
201  fn dump(&self) -> String {
202    let mut p = DispMatParam{m: self.voidp(), w: SZU32, rows: 1, cols: 2,
203      fmt: "%08x\0".as_ptr(), di: 8, df: 0, r: 0, c: 0};
204    let f = cb_x;
205    let mut s = [0u8; SZBUF];
206unsafe {
207    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
208    String::from_utf8(s[..l].to_vec()).expect("utf8")
209}
210  }
211}
212
213/// trait Disp for XV2U
214impl Disp for XV2U {
215  /// disp
216  fn disp(&self, di: usize, df: usize) -> String {
217    let fmt = format!("%{}lu\0", di).as_str().as_ptr();
218    let mut p = DispMatParam{m: self.voidp(), w: SZU32, rows: 1, cols: 2,
219      fmt, di, df, r: 0, c: 0};
220    let f = cb_u32; // (by di) same as cb_u (by fmt)
221    let mut s = [0u8; SZBUF];
222unsafe {
223    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
224    String::from_utf8(s[..l].to_vec()).expect("utf8")
225}
226  }
227}
228
229/// trait Display for XV2U
230impl std::fmt::Display for XV2U {
231  /// fmt
232  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233    write!(f, "{}", self.disp(17, 0))
234  }
235}
236
237/// trait Debug for XV2U
238impl std::fmt::Debug for XV2U {
239  /// fmt
240  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241    write!(f, "{}", self.disp(17, 0))
242  }
243}
244
245/// XV2I
246#[derive(Clone)]
247pub struct XV2I (pub [ffi::c_int; 2]);
248
249/// trait Ptr for XV2I
250impl Ptr<i32> for XV2I {
251  /// ptr
252  #[inline]
253  fn ptr(&self) -> *const i32 { self as *const XV2I as *const i32 }
254  /// ptr_mut
255  #[inline]
256  fn ptr_mut(&mut self) -> *mut i32 { self as *mut XV2I as *mut i32 }
257}
258
259/// trait Dump for XV2I
260impl Dump for XV2I {
261  /// dump
262  fn dump(&self) -> String {
263    let mut p = DispMatParam{m: self.voidp(), w: SZI32, rows: 1, cols: 2,
264      fmt: "%08x\0".as_ptr(), di: 8, df: 0, r: 0, c: 0};
265    let f = cb_x;
266    let mut s = [0u8; SZBUF];
267unsafe {
268    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
269    String::from_utf8(s[..l].to_vec()).expect("utf8")
270}
271  }
272}
273
274/// trait Disp for XV2I
275impl Disp for XV2I {
276  /// disp
277  fn disp(&self, di: usize, df: usize) -> String {
278    let fmt = format!("%{}ld\0", di).as_str().as_ptr();
279    let mut p = DispMatParam{m: self.voidp(), w: SZI32, rows: 1, cols: 2,
280      fmt, di, df, r: 0, c: 0};
281    let f = cb_i32; // (by di) same as cb_i (by fmt)
282    let mut s = [0u8; SZBUF];
283unsafe {
284    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
285    String::from_utf8(s[..l].to_vec()).expect("utf8")
286}
287  }
288}
289
290/// trait Display for XV2I
291impl std::fmt::Display for XV2I {
292  /// fmt
293  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294    write!(f, "{}", self.disp(17, 0))
295  }
296}
297
298/// trait Debug for XV2I
299impl std::fmt::Debug for XV2I {
300  /// fmt
301  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302    write!(f, "{}", self.disp(17, 0))
303  }
304}
305
306/// XV2F32
307#[derive(Clone)]
308pub struct XV2F32 (pub [ffi::c_float; 2]);
309
310/// trait Ptr for XV2F32
311impl Ptr<f32> for XV2F32 {
312  /// ptr
313  #[inline]
314  fn ptr(&self) -> *const f32 { self as *const XV2F32 as *const f32 }
315  /// ptr_mut
316  #[inline]
317  fn ptr_mut(&mut self) -> *mut f32 { self as *mut XV2F32 as *mut f32 }
318}
319
320/// trait Dump for XV2F32
321impl Dump for XV2F32 {
322  /// dump
323  fn dump(&self) -> String {
324    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 2,
325      fmt: "%08x\0".as_ptr(), di: 8, df: 0, r: 0, c: 0};
326    let f = cb_x;
327    let mut s = [0u8; SZBUF];
328unsafe {
329    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
330    String::from_utf8(s[..l].to_vec()).expect("utf8")
331}
332  }
333}
334
335/// trait Disp for XV2F32
336impl Disp for XV2F32 {
337  /// disp
338  fn disp(&self, di: usize, df: usize) -> String {
339    let fmt = format!("%{}.{}f\0", di, df).as_str().as_ptr();
340    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 2,
341      fmt, di, df, r: 0, c: 0};
342    let f = cb_f32; // (by di df) same as cb_f (by fmt)
343    let mut s = [0u8; SZBUF];
344unsafe {
345    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
346    String::from_utf8(s[..l].to_vec()).expect("utf8")
347}
348  }
349}
350
351/// trait Display for XV2F32
352impl std::fmt::Display for XV2F32 {
353  /// fmt
354  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
355    write!(f, "{}", self.disp(17, 7))
356  }
357}
358
359/// trait Debug for XV2F32
360impl std::fmt::Debug for XV2F32 {
361  /// fmt
362  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363    write!(f, "{}", self.disp(17, 7))
364  }
365}
366
367/// XV3F32
368#[derive(Clone)]
369pub struct XV3F32 (pub [ffi::c_float; 3]);
370
371/// XV3F32
372impl XV3F32 {
373  /// o (create new instance)
374  #[inline]
375  pub fn o() -> Self {
376    XV3F32([0.0f32; 3])
377  }
378
379  /// prec_diff (create new instance)
380  pub fn prec_diff(&self, b: &Self, p: f32) -> Result<Self, Box<dyn Error>> {
381    Ok(XV3F32(
382/*
383      toarray!(self.0.iter().enumerate().map(|(i, &f)|
384        prec_diff(f, b.0[i], p)))
385*/
386      toarray!(self.0.iter().zip(b.0.iter()).map(|(&f, &g)|
387        prec_diff(f, g, p)))
388    ))
389  }
390
391  /// prec_eq
392  #[inline]
393  pub fn prec_eq(&self, b: &Self, p: f32) ->
394    Result<bool, Box<dyn Error>> {
395    Ok(self.prec_diff(b, p)?.0 == XV3F32::o().0)
396  }
397
398  /// prec_eq_array
399  #[inline]
400  pub fn prec_eq_array(&self, b: &[f32; 3], p: f32) ->
401    Result<bool, Box<dyn Error>> {
402    self.prec_eq(&XV3F32(*b), p)
403  }
404
405  /// dot (create new instance)
406  pub fn dot(&self, b: &Self) -> f32 {
407    self.0.iter().zip(b.0.iter()).map(|(&f, &g)| f * g).sum()
408  }
409
410  /// cross (create new instance)
411  pub fn cross(&self, b: &Self) -> Self {
412    let [x0, y0, z0] = self.0;
413    let [x1, y1, z1] = b.0;
414    XV3F32([y0 * z1 - z0 * y1, z0 * x1 - x0 * z1, x0 * y1 - y0 * x1])
415  }
416
417  /// norm (create new instance)
418  #[inline]
419  pub fn norm(&self, b: &Self) -> Result<Self, Box<dyn Error>> {
420    self.cross(b).normalize()
421  }
422
423  /// normalize (create new instance)
424  pub fn normalize(&self) -> Result<Self, Box<dyn Error>> {
425    let a = self.0;
426    let r = f32::sqrt(a.into_iter().map(|f| f * f).sum());
427    Ok(XV3F32(toarray!(a.into_iter().map(|f| f / r))))
428  }
429
430  /// set_normalize
431  #[inline]
432  pub fn set_normalize(&mut self) -> Result<&mut Self, Box<dyn Error>> {
433    self.0 = self.normalize()?.0;
434    Ok(self)
435  }
436}
437
438/// trait TryFrom for XV3F32
439impl TryFrom<XV4F32> for XV3F32 {
440  type Error = Box<dyn Error>;
441
442  /// try_from (create new instance)
443  fn try_from(v: XV4F32) -> Result<Self, Self::Error> {
444    let v = v.0;
445    Ok(XV3F32([v[0], v[1], v[2]])) // no care v[3] (assume always 1)
446  }
447}
448
449/// trait Ptr for XV3F32
450impl Ptr<f32> for XV3F32 {
451  /// ptr
452  #[inline]
453  fn ptr(&self) -> *const f32 { self as *const XV3F32 as *const f32 }
454  /// ptr_mut
455  #[inline]
456  fn ptr_mut(&mut self) -> *mut f32 { self as *mut XV3F32 as *mut f32 }
457}
458
459/// trait Dump for XV3F32
460impl Dump for XV3F32 {
461  /// dump
462  fn dump(&self) -> String {
463    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 3,
464      fmt: "%08x\0".as_ptr(), di: 8, df: 0, r: 0, c: 0};
465    let f = cb_x;
466    let mut s = [0u8; SZBUF];
467unsafe {
468    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
469    String::from_utf8(s[..l].to_vec()).expect("utf8")
470}
471  }
472}
473
474/// trait Disp for XV3F32
475impl Disp for XV3F32 {
476  /// disp
477  fn disp(&self, di: usize, df: usize) -> String {
478    let fmt = format!("%{}.{}f\0", di, df).as_str().as_ptr();
479    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 3,
480      fmt, di, df, r: 0, c: 0};
481    let f = cb_f32; // (by di df) same as cb_f (by fmt)
482    let mut s = [0u8; SZBUF];
483unsafe {
484    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
485    String::from_utf8(s[..l].to_vec()).expect("utf8")
486}
487  }
488}
489
490/// trait Display for XV3F32
491impl std::fmt::Display for XV3F32 {
492  /// fmt
493  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
494    write!(f, "{}", self.disp(17, 7))
495  }
496}
497
498/// trait Debug for XV3F32
499impl std::fmt::Debug for XV3F32 {
500  /// fmt
501  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
502    write!(f, "{}", self.disp(17, 7))
503  }
504}
505
506/// XV4F32
507#[derive(Clone)]
508pub struct XV4F32 (pub [ffi::c_float; 4]);
509
510/// XV4F32
511impl XV4F32 {
512  /// o (create new instance)
513  #[inline]
514  pub fn o() -> Self {
515    XV4F32([0.0f32; 4])
516  }
517
518  /// i as quaternion (create new instance)
519  #[inline]
520  pub fn i() -> Self {
521    XV4F32([0.0f32, 0.0f32, 0.0f32, 1.0f32])
522  }
523
524  /// prec_diff (create new instance)
525  pub fn prec_diff(&self, b: &Self, p: f32) -> Result<Self, Box<dyn Error>> {
526    Ok(XV4F32(
527/*
528      toarray!(self.0.iter().enumerate().map(|(i, &f)|
529        prec_diff(f, b.0[i], p)))
530*/
531      toarray!(self.0.iter().zip(b.0.iter()).map(|(&f, &g)|
532        prec_diff(f, g, p)))
533    ))
534  }
535
536  /// prec_eq
537  #[inline]
538  pub fn prec_eq(&self, b: &Self, p: f32) ->
539    Result<bool, Box<dyn Error>> {
540    Ok(self.prec_diff(b, p)?.0 == XV4F32::o().0)
541  }
542
543  /// prec_eq_array
544  #[inline]
545  pub fn prec_eq_array(&self, b: &[f32; 4], p: f32) ->
546    Result<bool, Box<dyn Error>> {
547    self.prec_eq(&XV4F32(*b), p)
548  }
549
550  /// dot (create new instance)
551  pub fn dot(self, b: &Self) -> f32 {
552    self.0.iter().zip(b.0.iter()).map(|(&f, &g)| f * g).sum()
553  }
554
555  /// cross3 (create new instance)
556  pub fn cross3(self, b: &Self) -> Self {
557    let [x0, y0, z0, _w0] = self.0;
558    let [x1, y1, z1, _w1] = b.0;
559    let w = 1.0f32; // no care w0 w1
560    XV4F32([y0 * z1 - z0 * y1, z0 * x1 - x0 * z1, x0 * y1 - y0 * x1, w])
561  }
562
563  /// norm3 (create new instance)
564  #[inline]
565  pub fn norm3(self, b: &Self) -> Result<Self, Box<dyn Error>> {
566    self.cross3(b).normalize3()
567  }
568
569  /// normalize3 as quaternion (create new instance)
570  #[inline]
571  pub fn normalize3(self) -> Result<Self, Box<dyn Error>> {
572    XV4F32::try_from(XV3F32::try_from(self)?.normalize()?)
573  }
574
575  /// normalize as XV4F32 (create new instance)
576  pub fn normalize(&self) -> Result<Self, Box<dyn Error>> {
577    let mut q = Self::o();
578unsafe {
579    if isnull!(D3DXQuaternionNormalize(
580      q.ptr_mut() as *mut D3DXQUATERNION,
581      self.ptr() as *const D3DXQUATERNION
582    )) { Err("normalize".into()) }
583    else { Ok(q) }
584}
585  }
586
587  /// set_normalize as XV4F32
588  pub fn set_normalize(&mut self) -> Result<&mut Self, Box<dyn Error>> {
589unsafe {
590    if isnull!(D3DXQuaternionNormalize(
591      self.ptr_mut() as *mut D3DXQUATERNION,
592      self.ptr() as *const D3DXQUATERNION
593    )) { Err("set_normalize".into()) }
594    else { Ok(self) }
595}
596  }
597
598  /// inverse (create new instance)
599  pub fn inverse(&self) -> Result<Self, Box<dyn Error>> {
600    let mut q = Self::o();
601unsafe {
602    if isnull!(D3DXQuaternionInverse(
603      q.ptr_mut() as *mut D3DXQUATERNION,
604      self.ptr() as *const D3DXQUATERNION
605    )) { Err("inverse".into()) }
606    else { Ok(q) }
607}
608  }
609
610  /// conjugate (create new instance) [i, j, k, r] instead of [r, i, j, k]
611  #[inline]
612  pub fn conjugate(&self) -> Result<Self, Box<dyn Error>> {
613    let q = self.0;
614    Ok(XV4F32([-q[0], -q[1], -q[2], q[3]]))
615//    Ok(XV4F32([q[0], -q[1], -q[2], -q[3]]))
616  }
617
618  /// quaternion (create new instance) [i, j, k, r] instead of [r, i, j, k]
619  pub fn quaternion(axis: &XV3F32, th: f32) -> Result<Self, Box<dyn Error>> {
620    let a = axis.normalize()?.0;
621    let r = th / 2.0f32;
622    let c = f32::cos(r);
623    let s = f32::sin(r);
624    Ok(XV4F32([a[0] * s, a[1] * s, a[2] * s, c]))
625//    Ok(XV4F32([c, a[0] * s, a[1] * s, a[2] * s]))
626  }
627
628  /// quaternion_m (create new instance) [i, j, k, r] instead of [r, i, j, k]
629  pub fn quaternion_m(m: &XMat44F32, prec: f32) ->
630    Result<Self, Box<dyn Error>> {
631    let q = m.transpose()?.0; // transposed from Qt for DirectX (mul P Qt)
632    let (xs, ys, zs, c); // needless mut when all will be assigned once
633    let cc = (q[0][0] + q[1][1] + q[2][2] + q[3][3]) / 4.0f32;
634    if prec_eq(cc, 0.0f32, prec) {
635      c = 0.0f32;
636      let xsxs = - (q[1][1] + q[2][2]) / 2.0f32;
637      if prec_eq(xsxs, 0.0f32, prec) {
638        xs = 0.0f32;
639        let ysys = (q[3][3] - q[2][2]) / 2.0f32;
640        if prec_eq(ysys, 0.0f32, prec) {
641          ys = 0.0f32;
642          zs = 1.0f32;
643        }else if ysys > 0.0f32 {
644          ys = f32::sqrt(ysys); // positive only
645          zs = q[1][2] / (ys * 2.0f32);
646        }else{ // ysys < 0.0f32
647          return Err("not a rotation matrix".into());
648        }
649      }else if xsxs > 0.0f32 {
650        xs = f32::sqrt(xsxs); // positive only
651        let xs2 = xs * 2.0f32;
652        ys = q[0][1] / xs2;
653        zs = q[0][2] / xs2;
654      }else{ // xsxs < 0.0f32
655        return Err("not a rotation matrix".into());
656      }
657    }else if cc > 0.0f32 {
658      c = f32::sqrt(cc); // positive only
659      let c4 = c * 4.0f32;
660      xs = (q[2][1] - q[1][2]) / c4;
661      ys = (q[0][2] - q[2][0]) / c4;
662      zs = (q[1][0] - q[0][1]) / c4;
663    }else{ // cc < 0.0f32
664      return Err("not a rotation matrix".into());
665    }
666    Ok(XV4F32([xs, ys, zs, c]))
667  }
668
669  /// rotation_axis (quaternion rotation axis) (create new instance)
670  pub fn rotation_axis(axis: &XV3F32, th: f32) ->
671    Result<Self, Box<dyn Error>> {
672    let mut q = Self::o();
673unsafe {
674    if isnull!(D3DXQuaternionRotationAxis(
675      q.ptr_mut() as *mut D3DXQUATERNION,
676      axis.ptr() as *const D3DXVECTOR3,
677      th
678    )) { Err("quaternion rotation axis".into()) }
679    else { Ok(q) }
680}
681  }
682
683  /// set_rotation_axis (quaternion rotation axis)
684  pub fn set_rotation_axis(&mut self, axis: &XV3F32, th: f32) ->
685    Result<&mut Self, Box<dyn Error>> {
686unsafe {
687    if isnull!(D3DXQuaternionRotationAxis(
688      self.ptr_mut() as *mut D3DXQUATERNION,
689      axis.ptr() as *const D3DXVECTOR3,
690      th
691    )) { Err("quaternion set rotation axis".into()) }
692    else { Ok(self) }
693}
694  }
695
696  /// mul (create new instance) [i, j, k, r] instead of [r, i, j, k]
697  /// mul quaternion and quaternion (***NOT same as dot***)
698  /// a.mul(b) means (a * b) for GL (b * a) for DirectX
699  #[inline]
700  pub fn mul(&self, b: &Self) ->
701    Result<Self, Box<dyn Error>> {
702    XMat44F32::quaternion_r(self)?.mulmv(b) // (mul Qr(a) v(b)) for DirectX
703//    XMat44F32::quaternion_l(b)?.mulmv(self) // (mul Ql(b) v(a)) for DirectX
704//    XMat44F32::quaternion_l(self)?.mulmv(b) // (mul Ql(a) v(b)) for GL differ
705  }
706
707  /// q_mul (quaternion multiply) (create new instance) (***NOT same as dot***)
708  pub fn q_mul(&self, b: &Self) ->
709    Result<Self, Box<dyn Error>> {
710    let mut q = Self::o();
711unsafe {
712    if isnull!(D3DXQuaternionMultiply(
713      q.ptr_mut() as *mut D3DXQUATERNION,
714      self.ptr() as *const D3DXQUATERNION,
715      b.ptr() as *const D3DXQUATERNION
716    )) { Err("quaternion multiply".into()) }
717    else { Ok(q) }
718}
719  }
720
721  /// set_q_mul (quaternion multiply)
722  pub fn set_q_mul(&mut self, b: &Self) ->
723    Result<&mut Self, Box<dyn Error>> {
724unsafe {
725    if isnull!(D3DXQuaternionMultiply(
726      self.ptr_mut() as *mut D3DXQUATERNION,
727      self.ptr() as *const D3DXQUATERNION,
728      b.ptr() as *const D3DXQUATERNION
729    )) { Err("set_q_mul".into()) }
730    else { Ok(self) }
731}
732  }
733}
734
735/// trait TryFrom for XV4F32
736impl TryFrom<XMat44F32> for XV4F32 {
737  type Error = Box<dyn Error>;
738
739  /// try_from rotation matrix into quaternion (create new instance)
740  fn try_from(m: XMat44F32) -> Result<Self, Self::Error> {
741    let mut q = Self::o();
742unsafe {
743    if isnull!(D3DXQuaternionRotationMatrix(
744      q.ptr_mut() as *mut D3DXQUATERNION,
745      m.ptr() as *const D3DXMATRIX
746    )) { Err("quaternion rotation matrix".into()) }
747    else { Ok(q) }
748}
749  }
750}
751
752/// trait TryFrom for XV4F32
753impl TryFrom<XV3F32> for XV4F32 {
754  type Error = Box<dyn Error>;
755
756  /// try_from (create new instance)
757  fn try_from(v: XV3F32) -> Result<Self, Self::Error> {
758    let v = v.0;
759    Ok(XV4F32([v[0], v[1], v[2], 1.0f32])) // force set v[3] (assume always 1)
760  }
761}
762
763/// trait Ptr for XV4F32
764impl Ptr<f32> for XV4F32 {
765  /// ptr
766  #[inline]
767  fn ptr(&self) -> *const f32 { self as *const XV4F32 as *const f32 }
768  /// ptr_mut
769  #[inline]
770  fn ptr_mut(&mut self) -> *mut f32 { self as *mut XV4F32 as *mut f32 }
771}
772
773/// trait Dump for XV4F32
774impl Dump for XV4F32 {
775  /// dump
776  fn dump(&self) -> String {
777    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 4,
778      fmt: "%08x\0".as_ptr(), di: 8, df: 0, r: 0, c: 0};
779    let f = cb_x;
780    let mut s = [0u8; SZBUF];
781unsafe {
782    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
783    String::from_utf8(s[..l].to_vec()).expect("utf8")
784}
785  }
786}
787
788/// trait Disp for XV4F32
789impl Disp for XV4F32 {
790  /// disp
791  fn disp(&self, di: usize, df: usize) -> String {
792    let fmt = format!("%{}.{}f\0", di, df).as_str().as_ptr();
793    let mut p = DispMatParam{m: self.voidp(), w: SZF32, rows: 1, cols: 4,
794      fmt, di, df, r: 0, c: 0};
795    let f = cb_f32; // (by di df) same as cb_f (by fmt)
796    let mut s = [0u8; SZBUF];
797unsafe {
798    let l = disp_mat(&mut s as *mut u8, SZBUF, &mut p, Some(f));
799    String::from_utf8(s[..l].to_vec()).expect("utf8")
800}
801  }
802}
803
804/// trait Display for XV4F32
805impl std::fmt::Display for XV4F32 {
806  /// fmt
807  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
808    write!(f, "{}", self.disp(17, 7))
809  }
810}
811
812/// trait Debug for XV4F32
813impl std::fmt::Debug for XV4F32 {
814  /// fmt
815  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
816    write!(f, "{}", self.disp(17, 7))
817  }
818}