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