/ecere/src/gfx/3D/Matrix.ec

https://github.com/redj/ecere-sdk · C · 310 lines · 259 code · 36 blank · 15 comment · 40 complexity · f54c96a7b4e1a011c1c80ab7eda6ca17 MD5 · raw file

  1. namespace gfx3D;
  2. import "Display"
  3. public union Matrix
  4. {
  5. double array[16];
  6. double m[4][4];
  7. const char * OnGetString(char * string, void * fieldData, ObjectNotationType * onType)
  8. {
  9. bool spacing = false; //true;
  10. int y, x;
  11. string[0] = 0;
  12. strcat(string, spacing ? "{\n" : "{ ");
  13. for(y = 0; y < 4; y++)
  14. {
  15. strcat(string, spacing ? " { " : "{ ");
  16. for(x = 0; x < 4; x++)
  17. {
  18. char member[256];
  19. const char * s = m[y][x].OnGetString(member, null, null);
  20. strcat(string, s);
  21. if(x < 3) strcat(string, ", ");
  22. }
  23. strcat(string, " }");
  24. if(y < 3) strcat(string, ", ");
  25. if(spacing) strcat(string, "\n");
  26. }
  27. strcat(string, spacing ? "}\n" : " }");
  28. return string;
  29. }
  30. void Identity()
  31. {
  32. FillBytesBy4(this, 0, sizeof(Matrix) >> 2);
  33. m[0][0]=m[1][1]=m[2][2]=m[3][3]=1;
  34. }
  35. void Transpose(const Matrix source)
  36. {
  37. int i,j;
  38. for(i=0; i<4; i++)
  39. for(j=0; j<4; j++)
  40. m[j][i] = source.m[i][j];
  41. }
  42. void Multiply(const Matrix a, const Matrix b)
  43. {
  44. // We need a full matrix multiplication for the Projection matrix
  45. m[0][0]=a.m[0][0]*b.m[0][0] + a.m[0][1]*b.m[1][0] + a.m[0][2]*b.m[2][0] + a.m[0][3]*b.m[3][0];
  46. m[0][1]=a.m[0][0]*b.m[0][1] + a.m[0][1]*b.m[1][1] + a.m[0][2]*b.m[2][1] + a.m[0][3]*b.m[3][1];
  47. m[0][2]=a.m[0][0]*b.m[0][2] + a.m[0][1]*b.m[1][2] + a.m[0][2]*b.m[2][2] + a.m[0][3]*b.m[3][2];
  48. m[0][3]=a.m[0][0]*b.m[0][3] + a.m[0][1]*b.m[1][3] + a.m[0][2]*b.m[2][3] + a.m[0][3]*b.m[3][3];
  49. m[1][0]=a.m[1][0]*b.m[0][0] + a.m[1][1]*b.m[1][0] + a.m[1][2]*b.m[2][0] + a.m[1][3]*b.m[3][0];
  50. m[1][1]=a.m[1][0]*b.m[0][1] + a.m[1][1]*b.m[1][1] + a.m[1][2]*b.m[2][1] + a.m[1][3]*b.m[3][1];
  51. m[1][2]=a.m[1][0]*b.m[0][2] + a.m[1][1]*b.m[1][2] + a.m[1][2]*b.m[2][2] + a.m[1][3]*b.m[3][2];
  52. m[1][3]=a.m[1][0]*b.m[0][3] + a.m[1][1]*b.m[1][3] + a.m[1][2]*b.m[2][3] + a.m[1][3]*b.m[3][3];
  53. m[2][0]=a.m[2][0]*b.m[0][0] + a.m[2][1]*b.m[1][0] + a.m[2][2]*b.m[2][0] + a.m[2][3]*b.m[3][0];
  54. m[2][1]=a.m[2][0]*b.m[0][1] + a.m[2][1]*b.m[1][1] + a.m[2][2]*b.m[2][1] + a.m[2][3]*b.m[3][1];
  55. m[2][2]=a.m[2][0]*b.m[0][2] + a.m[2][1]*b.m[1][2] + a.m[2][2]*b.m[2][2] + a.m[2][3]*b.m[3][2];
  56. m[2][3]=a.m[2][0]*b.m[0][3] + a.m[2][1]*b.m[1][3] + a.m[2][2]*b.m[2][3] + a.m[2][3]*b.m[3][3];
  57. m[3][0]=a.m[3][0]*b.m[0][0] + a.m[3][1]*b.m[1][0] + a.m[3][2]*b.m[2][0] + a.m[3][3]*b.m[3][0];
  58. m[3][1]=a.m[3][0]*b.m[0][1] + a.m[3][1]*b.m[1][1] + a.m[3][2]*b.m[2][1] + a.m[3][3]*b.m[3][1];
  59. m[3][2]=a.m[3][0]*b.m[0][2] + a.m[3][1]*b.m[1][2] + a.m[3][2]*b.m[2][2] + a.m[3][3]*b.m[3][2];
  60. m[3][3]=a.m[3][0]*b.m[0][3] + a.m[3][1]*b.m[1][3] + a.m[3][2]*b.m[2][3] + a.m[3][3]*b.m[3][3];
  61. }
  62. void Multiply3x4(const Matrix a, const Matrix b)
  63. {
  64. m[0][0]=a.m[0][0]*b.m[0][0] + a.m[0][1]*b.m[1][0] + a.m[0][2]*b.m[2][0];
  65. m[0][1]=a.m[0][0]*b.m[0][1] + a.m[0][1]*b.m[1][1] + a.m[0][2]*b.m[2][1];
  66. m[0][2]=a.m[0][0]*b.m[0][2] + a.m[0][1]*b.m[1][2] + a.m[0][2]*b.m[2][2];
  67. m[0][3]=0;
  68. m[1][0]=a.m[1][0]*b.m[0][0] + a.m[1][1]*b.m[1][0] + a.m[1][2]*b.m[2][0];
  69. m[1][1]=a.m[1][0]*b.m[0][1] + a.m[1][1]*b.m[1][1] + a.m[1][2]*b.m[2][1];
  70. m[1][2]=a.m[1][0]*b.m[0][2] + a.m[1][1]*b.m[1][2] + a.m[1][2]*b.m[2][2];
  71. m[1][3]=0;
  72. m[2][0]=a.m[2][0]*b.m[0][0] + a.m[2][1]*b.m[1][0] + a.m[2][2]*b.m[2][0];
  73. m[2][1]=a.m[2][0]*b.m[0][1] + a.m[2][1]*b.m[1][1] + a.m[2][2]*b.m[2][1];
  74. m[2][2]=a.m[2][0]*b.m[0][2] + a.m[2][1]*b.m[1][2] + a.m[2][2]*b.m[2][2];
  75. m[2][3]=0;
  76. m[3][0]=a.m[3][0]*b.m[0][0] + a.m[3][1]*b.m[1][0] + a.m[3][2]*b.m[2][0] + b.m[3][0];
  77. m[3][1]=a.m[3][0]*b.m[0][1] + a.m[3][1]*b.m[1][1] + a.m[3][2]*b.m[2][1] + b.m[3][1];
  78. m[3][2]=a.m[3][0]*b.m[0][2] + a.m[3][1]*b.m[1][2] + a.m[3][2]*b.m[2][2] + b.m[3][2];
  79. m[3][3]=1;
  80. }
  81. void RotationQuaternion(const Quaternion quat)
  82. {
  83. double xx = quat.x*quat.x, yy = quat.y*quat.y, zz = quat.z*quat.z;
  84. double xy = quat.x*quat.y, xz = quat.x*quat.z, yz = quat.y*quat.z;
  85. double wx = quat.w*quat.x, wy = quat.w*quat.y, wz = quat.w*quat.z;
  86. m[0][0] = (double) (1 - 2 * ( yy + zz ));
  87. m[0][1] = (double) ( 2 * ( xy - wz ));
  88. m[0][2] = (double) ( 2 * ( xz + wy ));
  89. m[1][0] = (double) ( 2 * ( xy + wz ));
  90. m[1][1] = (double) (1 - 2 * ( xx + zz ));
  91. m[1][2] = (double) ( 2 * ( yz - wx ));
  92. m[2][0] = (double) ( 2 * ( xz - wy ));
  93. m[2][1] = (double) ( 2 * ( yz + wx ));
  94. m[2][2] = (double) (1 - 2 * ( xx + yy ));
  95. m[0][3] = m[1][3] = m[2][3] = 0.0f;
  96. m[3][0] = m[3][1] = m[3][2] = 0.0f;
  97. m[3][3] = 1.0f;
  98. }
  99. void Translate(double tx, double ty, double tz)
  100. {
  101. m[3][0] += tx; m[3][1] += ty; m[3][2] += tz;
  102. }
  103. void Scale(double sx, double sy, double sz)
  104. {
  105. m[0][0] *= sx; m[1][0] *= sx; m[2][0] *= sx; m[3][0] *= sx;
  106. m[0][1] *= sy; m[1][1] *= sy; m[2][1] *= sy; m[3][1] *= sy;
  107. m[0][2] *= sz; m[1][2] *= sz; m[2][2] *= sz; m[3][2] *= sz;
  108. }
  109. void Rotate(const Quaternion quat)
  110. {
  111. Matrix rmat;
  112. Matrix mat1;
  113. rmat.RotationQuaternion(quat);
  114. mat1.Multiply3x4(this, rmat);
  115. this = mat1;
  116. }
  117. double Determinant(void)
  118. {
  119. double result = 0, i = 1;
  120. int n;
  121. for(n = 0; n < 4; n++, i *= -1)
  122. {
  123. double det;
  124. double msub3[3][3];
  125. int di, dj;
  126. for(di = 0; di < 3; di++)
  127. {
  128. for(dj = 0; dj < 3; dj++)
  129. {
  130. int si = di + ( ( di >= 0 ) ? 1 : 0 );
  131. int sj = dj + ( ( dj >= n ) ? 1 : 0 );
  132. msub3[di][dj] = m[si][sj];
  133. }
  134. }
  135. det = msub3[0][0] * ( msub3[1][1]*msub3[2][2] - msub3[2][1]*msub3[1][2] )
  136. - msub3[0][1] * ( msub3[1][0]*msub3[2][2] - msub3[2][0]*msub3[1][2] )
  137. + msub3[0][2] * ( msub3[1][0]*msub3[2][1] - msub3[2][0]*msub3[1][1] );
  138. result += m[0][n] * det * i;
  139. }
  140. return result;
  141. }
  142. void Inverse(const Matrix source)
  143. {
  144. double det = source.Determinant(); // FIXME: Get should be fine with const objects
  145. // if(Abs(det) < 0.0005)
  146. if(Abs(det) < 0.00000000000001)
  147. Identity();
  148. else
  149. {
  150. int i, j, sign;
  151. for ( i = 0; i < 4; i++ )
  152. for ( j = 0; j < 4; j++ )
  153. {
  154. int di, dj;
  155. double msub3[3][3];
  156. double m3det;
  157. sign = 1 - ( (i+j) % 2 ) * 2;
  158. for(di = 0; di < 3; di++)
  159. {
  160. for(dj = 0; dj < 3; dj++)
  161. {
  162. int si = di + ( ( di >= i ) ? 1 : 0 );
  163. int sj = dj + ( ( dj >= j ) ? 1 : 0 );
  164. msub3[di][dj] = source.m[si][sj];
  165. }
  166. }
  167. m3det = msub3[0][0] * ( msub3[1][1]*msub3[2][2] - msub3[2][1]*msub3[1][2] )
  168. - msub3[0][1] * ( msub3[1][0]*msub3[2][2] - msub3[2][0]*msub3[1][2] )
  169. + msub3[0][2] * ( msub3[1][0]*msub3[2][1] - msub3[2][0]*msub3[1][1] );
  170. m[j][i] = m3det * sign / det;
  171. }
  172. }
  173. }
  174. void InverseTransposeTransform(const Matrix source)
  175. {
  176. Vector3D x { source.array[0], source.array[1], source.array[ 2] };
  177. Vector3D y { source.array[4], source.array[5], source.array[ 6] };
  178. Vector3D z { source.array[8], source.array[9], source.array[10] };
  179. Vector3D s2
  180. {
  181. x.x * x.x + x.y * x.y + x.z * x.z,
  182. y.x * y.x + y.y * y.y + y.z * y.z,
  183. z.x * z.x + z.y * z.y + z.z * z.z
  184. };
  185. double ix = 1.0 / s2.x, iy = 1.0 / s2.y, iz = 1.0 / s2.z;
  186. array[0] = x.x * ix; array[1] = x.y * ix; array[ 2] = x.z * ix;
  187. array[4] = y.x * iy; array[5] = y.y * iy; array[ 6] = y.z * iy;
  188. array[8] = z.x * iz; array[9] = z.y * iz; array[10] = z.z * iz;
  189. }
  190. void ToEuler(Euler euler)
  191. {
  192. /*if(fabs(m[2][1]) <= 1.0 - 0.000005)
  193. {
  194. euler.yaw = atan2(-m[2][0], m[2][2]);
  195. euler.pitch = asin ( m[2][1]);
  196. euler.roll = atan2(-m[0][1], m[1][1]);
  197. }
  198. else
  199. {
  200. euler.yaw = acos(m[0][0]);
  201. euler.pitch = Pi/2;
  202. euler.roll = 0;
  203. }
  204. */
  205. euler.FromMatrix(this, yxz);
  206. }
  207. property Quaternion
  208. {
  209. set { RotationQuaternion(value); }
  210. get { value.RotationMatrix(this); }
  211. }
  212. private:
  213. property Vector3D translation
  214. {
  215. get { value = { m[3][0], m[3][1], m[3][2] }; }
  216. }
  217. void extractScaling(Matrix r, Vector3D scaling)
  218. {
  219. Vector3D x { m[0][0], m[0][1], m[0][2] };
  220. Vector3D y { m[1][0], m[1][1], m[1][2] };
  221. Vector3D z { m[2][0], m[2][1], m[2][2] };
  222. Vector3D s
  223. {
  224. x = sqrt(x.x * x.x + x.y * x.y + x.z * x.z),
  225. y = sqrt(y.x * y.x + y.y * y.y + y.z * y.z),
  226. z = sqrt(z.x * z.x + z.y * z.y + z.z * z.z)
  227. };
  228. Vector3D orth;
  229. { double ix = 1.0 / s.x; x.x *= ix; x.y *= ix; x.z *= ix; }
  230. { double iy = 1.0 / s.y; y.x *= iy; y.y *= iy; y.z *= iy; }
  231. { double iz = 1.0 / s.z; z.x *= iz; z.y *= iz; z.z *= iz; }
  232. orth.CrossProduct(z, y);
  233. if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(x.x)) ||
  234. (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(x.y)) ||
  235. (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(x.z)))
  236. {
  237. x = orth;
  238. s.x *= -1;
  239. }
  240. orth.CrossProduct(x, z);
  241. if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(y.x)) ||
  242. (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(y.y)) ||
  243. (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(y.z)))
  244. {
  245. y = orth;
  246. s.y *= -1;
  247. }
  248. orth.CrossProduct(x, y);
  249. if((Abs(orth.x) > 0.00001 && Sgn(orth.x) != Sgn(z.x)) ||
  250. (Abs(orth.y) > 0.00001 && Sgn(orth.y) != Sgn(z.y)) ||
  251. (Abs(orth.z) > 0.00001 && Sgn(orth.z) != Sgn(z.z)))
  252. {
  253. z = orth;
  254. s.z *= -1;
  255. }
  256. if(scaling != null)
  257. scaling = s;
  258. if(r != null)
  259. {
  260. r.m[0][0] = x.x, r.m[0][1] = x.y, r.m[0][2] = x.z, r.m[0][3] = 0;
  261. r.m[1][0] = y.x, r.m[1][1] = y.y, r.m[1][2] = y.z, r.m[1][3] = 0;
  262. r.m[2][0] = z.x, r.m[2][1] = z.y, r.m[2][2] = z.z, r.m[2][3] = 0;
  263. r.m[3][0] = 0, r.m[3][1] = 0, r.m[3][2] = 0, r.m[3][3] = 1;
  264. }
  265. }
  266. property Vector3D scaling
  267. {
  268. get { extractScaling(null, value); }
  269. }
  270. property Quaternion orientation // This assumes it is a rotation matrix only!
  271. {
  272. get { value.RotationMatrix(this); }
  273. }
  274. };