dromaeo-3d-cube.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // 3D Cube Rotation
  2. // http://www.speich.net/computer/moztesting/3d.htm
  3. // Created by Simon Speich
  4. var Q = new Array();
  5. var MTrans = new Array(); // transformation matrix
  6. var MQube = new Array(); // position information of qube
  7. var I = new Array(); // entity matrix
  8. var Origin = new Object();
  9. var Testing = new Object();
  10. var LoopTimer;
  11. var DisplArea = new Object();
  12. DisplArea.Width = 300;
  13. DisplArea.Height = 300;
  14. function DrawLine(From, To) {
  15. var x1 = From.V[0];
  16. var x2 = To.V[0];
  17. var y1 = From.V[1];
  18. var y2 = To.V[1];
  19. var dx = Math.abs(x2 - x1);
  20. var dy = Math.abs(y2 - y1);
  21. var x = x1;
  22. var y = y1;
  23. var IncX1, IncY1;
  24. var IncX2, IncY2;
  25. var Den;
  26. var Num;
  27. var NumAdd;
  28. var NumPix;
  29. if (x2 >= x1) { IncX1 = 1; IncX2 = 1; }
  30. else { IncX1 = -1; IncX2 = -1; }
  31. if (y2 >= y1) { IncY1 = 1; IncY2 = 1; }
  32. else { IncY1 = -1; IncY2 = -1; }
  33. if (dx >= dy) {
  34. IncX1 = 0;
  35. IncY2 = 0;
  36. Den = dx;
  37. Num = dx / 2;
  38. NumAdd = dy;
  39. NumPix = dx;
  40. }
  41. else {
  42. IncX2 = 0;
  43. IncY1 = 0;
  44. Den = dy;
  45. Num = dy / 2;
  46. NumAdd = dx;
  47. NumPix = dy;
  48. }
  49. NumPix = Math.round(Q.LastPx + NumPix);
  50. var i = Q.LastPx;
  51. for (; i < NumPix; i++) {
  52. Num += NumAdd;
  53. if (Num >= Den) {
  54. Num -= Den;
  55. x += IncX1;
  56. y += IncY1;
  57. }
  58. x += IncX2;
  59. y += IncY2;
  60. }
  61. Q.LastPx = NumPix;
  62. }
  63. function CalcCross(V0, V1) {
  64. var Cross = new Array();
  65. Cross[0] = V0[1] * V1[2] - V0[2] * V1[1];
  66. Cross[1] = V0[2] * V1[0] - V0[0] * V1[2];
  67. Cross[2] = V0[0] * V1[1] - V0[1] * V1[0];
  68. return Cross;
  69. }
  70. function CalcNormal(V0, V1, V2) {
  71. var A = new Array(); var B = new Array();
  72. for (var i = 0; i < 3; i++) {
  73. A[i] = V0[i] - V1[i];
  74. B[i] = V2[i] - V1[i];
  75. }
  76. A = CalcCross(A, B);
  77. var Length = Math.sqrt(A[0] * A[0] + A[1] * A[1] + A[2] * A[2]);
  78. for (var i = 0; i < 3; i++) A[i] = A[i] / Length;
  79. A[3] = 1;
  80. return A;
  81. }
  82. function CreateP(X, Y, Z) {
  83. this.V = [X, Y, Z, 1];
  84. }
  85. // mulitplies two matrices
  86. function MMulti(M1, M2) {
  87. var M = [[], [], [], []];
  88. var i = 0;
  89. var j = 0;
  90. for (; i < 4; i++) {
  91. j = 0;
  92. for (; j < 4; j++) M[i][j] = M1[i][0] * M2[0][j] + M1[i][1] * M2[1][j] + M1[i][2] * M2[2][j] + M1[i][3] * M2[3][j];
  93. }
  94. return M;
  95. }
  96. //multiplies matrix with vector
  97. function VMulti(M, V) {
  98. var Vect = new Array();
  99. var i = 0;
  100. for (; i < 4; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3];
  101. return Vect;
  102. }
  103. function VMulti2(M, V) {
  104. var Vect = new Array();
  105. var i = 0;
  106. for (; i < 3; i++) Vect[i] = M[i][0] * V[0] + M[i][1] * V[1] + M[i][2] * V[2];
  107. return Vect;
  108. }
  109. // add to matrices
  110. function MAdd(M1, M2) {
  111. var M = [[], [], [], []];
  112. var i = 0;
  113. var j = 0;
  114. for (; i < 4; i++) {
  115. j = 0;
  116. for (; j < 4; j++) M[i][j] = M1[i][j] + M2[i][j];
  117. }
  118. return M;
  119. }
  120. function Translate(M, Dx, Dy, Dz) {
  121. var T = [
  122. [1, 0, 0, Dx],
  123. [0, 1, 0, Dy],
  124. [0, 0, 1, Dz],
  125. [0, 0, 0, 1]
  126. ];
  127. return MMulti(T, M);
  128. }
  129. function RotateX(M, Phi) {
  130. var a = Phi;
  131. a *= Math.PI / 180;
  132. var Cos = Math.cos(a);
  133. var Sin = Math.sin(a);
  134. var R = [
  135. [1, 0, 0, 0],
  136. [0, Cos, -Sin, 0],
  137. [0, Sin, Cos, 0],
  138. [0, 0, 0, 1]
  139. ];
  140. return MMulti(R, M);
  141. }
  142. function RotateY(M, Phi) {
  143. var a = Phi;
  144. a *= Math.PI / 180;
  145. var Cos = Math.cos(a);
  146. var Sin = Math.sin(a);
  147. var R = [
  148. [Cos, 0, Sin, 0],
  149. [0, 1, 0, 0],
  150. [-Sin, 0, Cos, 0],
  151. [0, 0, 0, 1]
  152. ];
  153. return MMulti(R, M);
  154. }
  155. function RotateZ(M, Phi) {
  156. var a = Phi;
  157. a *= Math.PI / 180;
  158. var Cos = Math.cos(a);
  159. var Sin = Math.sin(a);
  160. var R = [
  161. [Cos, -Sin, 0, 0],
  162. [Sin, Cos, 0, 0],
  163. [0, 0, 1, 0],
  164. [0, 0, 0, 1]
  165. ];
  166. return MMulti(R, M);
  167. }
  168. function DrawQube() {
  169. // calc current normals
  170. var CurN = new Array();
  171. var i = 5;
  172. Q.LastPx = 0;
  173. for (; i > -1; i--) CurN[i] = VMulti2(MQube, Q.Normal[i]);
  174. if (CurN[0][2] < 0) {
  175. if (!Q.Line[0]) { DrawLine(Q[0], Q[1]); Q.Line[0] = true; };
  176. if (!Q.Line[1]) { DrawLine(Q[1], Q[2]); Q.Line[1] = true; };
  177. if (!Q.Line[2]) { DrawLine(Q[2], Q[3]); Q.Line[2] = true; };
  178. if (!Q.Line[3]) { DrawLine(Q[3], Q[0]); Q.Line[3] = true; };
  179. }
  180. if (CurN[1][2] < 0) {
  181. if (!Q.Line[2]) { DrawLine(Q[3], Q[2]); Q.Line[2] = true; };
  182. if (!Q.Line[9]) { DrawLine(Q[2], Q[6]); Q.Line[9] = true; };
  183. if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; };
  184. if (!Q.Line[10]) { DrawLine(Q[7], Q[3]); Q.Line[10] = true; };
  185. }
  186. if (CurN[2][2] < 0) {
  187. if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; };
  188. if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; };
  189. if (!Q.Line[6]) { DrawLine(Q[6], Q[7]); Q.Line[6] = true; };
  190. if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; };
  191. }
  192. if (CurN[3][2] < 0) {
  193. if (!Q.Line[4]) { DrawLine(Q[4], Q[5]); Q.Line[4] = true; };
  194. if (!Q.Line[8]) { DrawLine(Q[5], Q[1]); Q.Line[8] = true; };
  195. if (!Q.Line[0]) { DrawLine(Q[1], Q[0]); Q.Line[0] = true; };
  196. if (!Q.Line[11]) { DrawLine(Q[0], Q[4]); Q.Line[11] = true; };
  197. }
  198. if (CurN[4][2] < 0) {
  199. if (!Q.Line[11]) { DrawLine(Q[4], Q[0]); Q.Line[11] = true; };
  200. if (!Q.Line[3]) { DrawLine(Q[0], Q[3]); Q.Line[3] = true; };
  201. if (!Q.Line[10]) { DrawLine(Q[3], Q[7]); Q.Line[10] = true; };
  202. if (!Q.Line[7]) { DrawLine(Q[7], Q[4]); Q.Line[7] = true; };
  203. }
  204. if (CurN[5][2] < 0) {
  205. if (!Q.Line[8]) { DrawLine(Q[1], Q[5]); Q.Line[8] = true; };
  206. if (!Q.Line[5]) { DrawLine(Q[5], Q[6]); Q.Line[5] = true; };
  207. if (!Q.Line[9]) { DrawLine(Q[6], Q[2]); Q.Line[9] = true; };
  208. if (!Q.Line[1]) { DrawLine(Q[2], Q[1]); Q.Line[1] = true; };
  209. }
  210. Q.Line = [false, false, false, false, false, false, false, false, false, false, false, false];
  211. Q.LastPx = 0;
  212. }
  213. function Loop() {
  214. if (Testing.LoopCount > Testing.LoopMax) return;
  215. var TestingStr = String(Testing.LoopCount);
  216. while (TestingStr.length < 3) TestingStr = "0" + TestingStr;
  217. MTrans = Translate(I, -Q[8].V[0], -Q[8].V[1], -Q[8].V[2]);
  218. MTrans = RotateX(MTrans, 1);
  219. MTrans = RotateY(MTrans, 3);
  220. MTrans = RotateZ(MTrans, 5);
  221. MTrans = Translate(MTrans, Q[8].V[0], Q[8].V[1], Q[8].V[2]);
  222. MQube = MMulti(MTrans, MQube);
  223. var i = 8;
  224. for (; i > -1; i--) {
  225. Q[i].V = VMulti(MTrans, Q[i].V);
  226. }
  227. DrawQube();
  228. Testing.LoopCount++;
  229. Loop();
  230. }
  231. function Init(CubeSize) {
  232. // init/reset vars
  233. Origin.V = [150, 150, 20, 1];
  234. Testing.LoopCount = 0;
  235. Testing.LoopMax = 50;
  236. Testing.TimeMax = 0;
  237. Testing.TimeAvg = 0;
  238. Testing.TimeMin = 0;
  239. Testing.TimeTemp = 0;
  240. Testing.TimeTotal = 0;
  241. Testing.Init = false;
  242. // transformation matrix
  243. MTrans = [
  244. [1, 0, 0, 0],
  245. [0, 1, 0, 0],
  246. [0, 0, 1, 0],
  247. [0, 0, 0, 1]
  248. ];
  249. // position information of qube
  250. MQube = [
  251. [1, 0, 0, 0],
  252. [0, 1, 0, 0],
  253. [0, 0, 1, 0],
  254. [0, 0, 0, 1]
  255. ];
  256. // entity matrix
  257. I = [
  258. [1, 0, 0, 0],
  259. [0, 1, 0, 0],
  260. [0, 0, 1, 0],
  261. [0, 0, 0, 1]
  262. ];
  263. // create qube
  264. Q[0] = new CreateP(-CubeSize, -CubeSize, CubeSize);
  265. Q[1] = new CreateP(-CubeSize, CubeSize, CubeSize);
  266. Q[2] = new CreateP(CubeSize, CubeSize, CubeSize);
  267. Q[3] = new CreateP(CubeSize, -CubeSize, CubeSize);
  268. Q[4] = new CreateP(-CubeSize, -CubeSize, -CubeSize);
  269. Q[5] = new CreateP(-CubeSize, CubeSize, -CubeSize);
  270. Q[6] = new CreateP(CubeSize, CubeSize, -CubeSize);
  271. Q[7] = new CreateP(CubeSize, -CubeSize, -CubeSize);
  272. // center of gravity
  273. Q[8] = new CreateP(0, 0, 0);
  274. // anti-clockwise edge check
  275. Q.Edge = [[0, 1, 2], [3, 2, 6], [7, 6, 5], [4, 5, 1], [4, 0, 3], [1, 5, 6]];
  276. // calculate squad normals
  277. Q.Normal = new Array();
  278. for (var i = 0; i < Q.Edge.length; i++) Q.Normal[i] = CalcNormal(Q[Q.Edge[i][0]].V, Q[Q.Edge[i][1]].V, Q[Q.Edge[i][2]].V);
  279. // line drawn ?
  280. Q.Line = [false, false, false, false, false, false, false, false, false, false, false, false];
  281. // create line pixels
  282. Q.NumPx = 9 * 2 * CubeSize;
  283. for (var i = 0; i < Q.NumPx; i++) new CreateP(0, 0, 0);
  284. MTrans = Translate(MTrans, Origin.V[0], Origin.V[1], Origin.V[2]);
  285. MQube = MMulti(MTrans, MQube);
  286. var i = 0;
  287. for (; i < 9; i++) {
  288. Q[i].V = VMulti(MTrans, Q[i].V);
  289. }
  290. DrawQube();
  291. Testing.Init = true;
  292. Loop();
  293. }
  294. startTest("dromaeo-3d-cube", '979cd0f1');
  295. test("Rotate 3D Cube", function () {
  296. Init(20);
  297. });
  298. endTest();