├── README.md ├── Selection.cpp ├── Selection.h ├── imgs ├── example1.png ├── example2.png └── example3.png ├── main.cpp ├── math3d.cpp ├── math3d.h └── tools ├── CHiResTimer.h └── CVector.h /README.md: -------------------------------------------------------------------------------- 1 | Introduction: 2 | 3 | 用openGL实现从三维点到屏幕坐标的映射,以达到拾取三维点的目的,可以精确的选中三维世界中的物体。 4 | 5 | tools文件下,包含常用的类代码,可以借鉴;目前包括 6 | 获取windows下精确的时间; 7 | 处理三维数据的vector类; 8 | 9 | Install: 10 | 11 | 配置openGL,然后直接将以上代码加入工程中即可; 12 | 13 | Snapshot: 14 | 15 | 给出一些测试效果图。 16 | ![image](https://github.com/baiyang/opengl/raw/master/imgs/example1.png) 17 | ![image](https://github.com/baiyang/opengl/raw/master/imgs/example2.png) 18 | ![image](https://github.com/baiyang/opengl/raw/master/imgs/example3.png) 19 | 20 | -------------------------------------------------------------------------------- /Selection.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/Selection.cpp -------------------------------------------------------------------------------- /Selection.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/Selection.h -------------------------------------------------------------------------------- /imgs/example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/imgs/example1.png -------------------------------------------------------------------------------- /imgs/example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/imgs/example2.png -------------------------------------------------------------------------------- /imgs/example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/imgs/example3.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/baiyang/opengl/8ad73c83c8222ec2a67dcdbc4d762db0a4249a86/main.cpp -------------------------------------------------------------------------------- /math3d.cpp: -------------------------------------------------------------------------------- 1 | // math3d.cpp 2 | // Math3D Library, version 0.95 3 | 4 | /* Copyright (c) 2007-2009, Richard S. Wright Jr. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list 11 | of conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, this list 14 | of conditions and the following disclaimer in the documentation and/or other 15 | materials provided with the distribution. 16 | 17 | Neither the name of Richard S. Wright Jr. nor the names of other contributors may be used 18 | to endorse or promote products derived from this software without specific prior 19 | written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 22 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Implementation file for the Math3d library. The C-Runtime has math.h, these routines 33 | // are meant to suppliment math.h by adding geometry/math routines 34 | // useful for graphics, simulation, and physics applications (3D stuff). 35 | // This library is meant to be useful on Win32, Mac OS X, various Linux/Unix distros, 36 | // and mobile platforms. Although designed with OpenGL in mind, there are no OpenGL 37 | // dependencies. Other than standard math routines, the only other outside routine 38 | // used is memcpy (for faster copying of vector arrays). 39 | // Most of the library is inlined. Some functions however are here as I judged them 40 | // too big to be inlined all over the place... nothing prevents anyone from changing 41 | // this if it better fits their project requirements. 42 | // Richard S. Wright Jr. 43 | 44 | // Most functions are in-lined... and are defined here 45 | #include 46 | 47 | 48 | //////////////////////////////////////////////////////////// 49 | // LoadIdentity 50 | // For 3x3 and 4x4 float and double matricies. 51 | // 3x3 float 52 | void m3dLoadIdentity33(M3DMatrix33f m) 53 | { 54 | // Don't be fooled, this is still column major 55 | static M3DMatrix33f identity = { 1.0f, 0.0f, 0.0f , 56 | 0.0f, 1.0f, 0.0f, 57 | 0.0f, 0.0f, 1.0f }; 58 | 59 | memcpy(m, identity, sizeof(M3DMatrix33f)); 60 | } 61 | 62 | // 3x3 double 63 | void m3dLoadIdentity33(M3DMatrix33d m) 64 | { 65 | // Don't be fooled, this is still column major 66 | static M3DMatrix33d identity = { 1.0, 0.0, 0.0 , 67 | 0.0, 1.0, 0.0, 68 | 0.0, 0.0, 1.0 }; 69 | 70 | memcpy(m, identity, sizeof(M3DMatrix33d)); 71 | } 72 | 73 | // 4x4 float 74 | void m3dLoadIdentity44(M3DMatrix44f m) 75 | { 76 | // Don't be fooled, this is still column major 77 | static M3DMatrix44f identity = { 1.0f, 0.0f, 0.0f, 0.0f, 78 | 0.0f, 1.0f, 0.0f, 0.0f, 79 | 0.0f, 0.0f, 1.0f, 0.0f, 80 | 0.0f, 0.0f, 0.0f, 1.0f }; 81 | 82 | memcpy(m, identity, sizeof(M3DMatrix44f)); 83 | } 84 | 85 | // 4x4 double 86 | void m3dLoadIdentity44(M3DMatrix44d m) 87 | { 88 | static M3DMatrix44d identity = { 1.0, 0.0, 0.0, 0.0, 89 | 0.0, 1.0, 0.0, 0.0, 90 | 0.0, 0.0, 1.0, 0.0, 91 | 0.0, 0.0, 0.0, 1.0 }; 92 | 93 | memcpy(m, identity, sizeof(M3DMatrix44d)); 94 | } 95 | 96 | 97 | //////////////////////////////////////////////////////////////////////// 98 | // Return the square of the distance between two points 99 | // Should these be inlined...? 100 | float m3dGetDistanceSquared3(const M3DVector3f u, const M3DVector3f v) 101 | { 102 | float x = u[0] - v[0]; 103 | x = x*x; 104 | 105 | float y = u[1] - v[1]; 106 | y = y*y; 107 | 108 | float z = u[2] - v[2]; 109 | z = z*z; 110 | 111 | return (x + y + z); 112 | } 113 | 114 | // Ditto above, but for doubles 115 | double m3dGetDistanceSquared3(const M3DVector3d u, const M3DVector3d v) 116 | { 117 | double x = u[0] - v[0]; 118 | x = x*x; 119 | 120 | double y = u[1] - v[1]; 121 | y = y*y; 122 | 123 | double z = u[2] - v[2]; 124 | z = z*z; 125 | 126 | return (x + y + z); 127 | } 128 | 129 | #define A(row,col) a[(col<<2)+row] 130 | #define B(row,col) b[(col<<2)+row] 131 | #define P(row,col) product[(col<<2)+row] 132 | 133 | /////////////////////////////////////////////////////////////////////////////// 134 | // Multiply two 4x4 matricies 135 | void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b ) 136 | { 137 | for (int i = 0; i < 4; i++) { 138 | float ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); 139 | P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); 140 | P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); 141 | P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); 142 | P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); 143 | } 144 | } 145 | 146 | // Ditto above, but for doubles 147 | void m3dMatrixMultiply44(M3DMatrix44d product, const M3DMatrix44d a, const M3DMatrix44d b ) 148 | { 149 | for (int i = 0; i < 4; i++) { 150 | double ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3); 151 | P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0); 152 | P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1); 153 | P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2); 154 | P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3); 155 | } 156 | } 157 | #undef A 158 | #undef B 159 | #undef P 160 | 161 | 162 | #define A33(row,col) a[(col*3)+row] 163 | #define B33(row,col) b[(col*3)+row] 164 | #define P33(row,col) product[(col*3)+row] 165 | 166 | /////////////////////////////////////////////////////////////////////////////// 167 | // Multiply two 3x3 matricies 168 | void m3dMatrixMultiply33(M3DMatrix33f product, const M3DMatrix33f a, const M3DMatrix33f b ) 169 | { 170 | for (int i = 0; i < 3; i++) { 171 | float ai0=A33(i,0), ai1=A33(i,1), ai2=A33(i,2); 172 | P33(i,0) = ai0 * B33(0,0) + ai1 * B33(1,0) + ai2 * B33(2,0); 173 | P33(i,1) = ai0 * B33(0,1) + ai1 * B33(1,1) + ai2 * B33(2,1); 174 | P33(i,2) = ai0 * B33(0,2) + ai1 * B33(1,2) + ai2 * B33(2,2); 175 | } 176 | } 177 | 178 | // Ditto above, but for doubles 179 | void m3dMatrixMultiply33(M3DMatrix33d product, const M3DMatrix33d a, const M3DMatrix33d b ) 180 | { 181 | for (int i = 0; i < 3; i++) { 182 | double ai0=A33(i,0), ai1=A33(i,1), ai2=A33(i,2); 183 | P33(i,0) = ai0 * B33(0,0) + ai1 * B33(1,0) + ai2 * B33(2,0); 184 | P33(i,1) = ai0 * B33(0,1) + ai1 * B33(1,1) + ai2 * B33(2,1); 185 | P33(i,2) = ai0 * B33(0,2) + ai1 * B33(1,2) + ai2 * B33(2,2); 186 | } 187 | } 188 | 189 | #undef A33 190 | #undef B33 191 | #undef P33 192 | 193 | 194 | 195 | //////////////////////////////////////////////////////////////////////////////////////////// 196 | // Create a projection matrix 197 | // Similiar to the old gluPerspective... fov is in radians btw... 198 | void m3dMakePerspectiveMatrix(M3DMatrix44f mProjection, float fFov, float fAspect, float zMin, float zMax) 199 | { 200 | m3dLoadIdentity44(mProjection); // Fastest way to get most valid values already in place 201 | 202 | float yMax = zMin * tanf(fFov * 0.5f); 203 | float yMin = -yMax; 204 | float xMin = yMin * fAspect; 205 | float xMax = -xMin; 206 | 207 | mProjection[0] = (2.0f * zMin) / (xMax - xMin); 208 | mProjection[5] = (2.0f * zMin) / (yMax - yMin); 209 | mProjection[8] = (xMax + xMin) / (xMax - xMin); 210 | mProjection[9] = (yMax + yMin) / (yMax - yMin); 211 | mProjection[10] = -((zMax + zMin) / (zMax - zMin)); 212 | mProjection[11] = -1.0f; 213 | mProjection[14] = -((2.0f * (zMax*zMin))/(zMax - zMin)); 214 | mProjection[15] = 0.0f; 215 | } 216 | 217 | /////////////////////////////////////////////////////////////////////////////// 218 | // Make a orthographic projection matrix 219 | void m3dMakeOrthographicMatrix(M3DMatrix44f mProjection, float xMin, float xMax, float yMin, float yMax, float zMin, float zMax) 220 | { 221 | m3dLoadIdentity44(mProjection); 222 | 223 | mProjection[0] = 2.0f / (xMax - xMin); 224 | mProjection[5] = 2.0f / (yMax - yMin); 225 | mProjection[10] = -2.0f / (zMax - zMin); 226 | mProjection[12] = -((xMax + xMin)/(xMax - xMin)); 227 | mProjection[13] = -((yMax + yMin)/(yMax - yMin)); 228 | mProjection[14] = -((zMax + zMin)/(zMax - zMin)); 229 | mProjection[15] = 1.0f; 230 | } 231 | 232 | 233 | 234 | #define M33(row,col) m[col*3+row] 235 | /////////////////////////////////////////////////////////////////////////////// 236 | // Creates a 3x3 rotation matrix, takes radians NOT degrees 237 | void m3dRotationMatrix33(M3DMatrix33f m, float angle, float x, float y, float z) 238 | { 239 | 240 | float mag, s, c; 241 | float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; 242 | 243 | s = float(sin(angle)); 244 | c = float(cos(angle)); 245 | 246 | mag = float(sqrt( x*x + y*y + z*z )); 247 | 248 | // Identity matrix 249 | if (mag == 0.0f) { 250 | m3dLoadIdentity33(m); 251 | return; 252 | } 253 | 254 | // Rotation matrix is normalized 255 | x /= mag; 256 | y /= mag; 257 | z /= mag; 258 | 259 | xx = x * x; 260 | yy = y * y; 261 | zz = z * z; 262 | xy = x * y; 263 | yz = y * z; 264 | zx = z * x; 265 | xs = x * s; 266 | ys = y * s; 267 | zs = z * s; 268 | one_c = 1.0f - c; 269 | 270 | M33(0,0) = (one_c * xx) + c; 271 | M33(0,1) = (one_c * xy) - zs; 272 | M33(0,2) = (one_c * zx) + ys; 273 | 274 | M33(1,0) = (one_c * xy) + zs; 275 | M33(1,1) = (one_c * yy) + c; 276 | M33(1,2) = (one_c * yz) - xs; 277 | 278 | M33(2,0) = (one_c * zx) - ys; 279 | M33(2,1) = (one_c * yz) + xs; 280 | M33(2,2) = (one_c * zz) + c; 281 | } 282 | 283 | #undef M33 284 | 285 | /////////////////////////////////////////////////////////////////////////////// 286 | // Creates a 4x4 rotation matrix, takes radians NOT degrees 287 | void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z) 288 | { 289 | float mag, s, c; 290 | float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; 291 | 292 | s = float(sin(angle)); 293 | c = float(cos(angle)); 294 | 295 | mag = float(sqrt( x*x + y*y + z*z )); 296 | 297 | // Identity matrix 298 | if (mag == 0.0f) { 299 | m3dLoadIdentity44(m); 300 | return; 301 | } 302 | 303 | // Rotation matrix is normalized 304 | x /= mag; 305 | y /= mag; 306 | z /= mag; 307 | 308 | #define M(row,col) m[col*4+row] 309 | 310 | xx = x * x; 311 | yy = y * y; 312 | zz = z * z; 313 | xy = x * y; 314 | yz = y * z; 315 | zx = z * x; 316 | xs = x * s; 317 | ys = y * s; 318 | zs = z * s; 319 | one_c = 1.0f - c; 320 | 321 | M(0,0) = (one_c * xx) + c; 322 | M(0,1) = (one_c * xy) - zs; 323 | M(0,2) = (one_c * zx) + ys; 324 | M(0,3) = 0.0f; 325 | 326 | M(1,0) = (one_c * xy) + zs; 327 | M(1,1) = (one_c * yy) + c; 328 | M(1,2) = (one_c * yz) - xs; 329 | M(1,3) = 0.0f; 330 | 331 | M(2,0) = (one_c * zx) - ys; 332 | M(2,1) = (one_c * yz) + xs; 333 | M(2,2) = (one_c * zz) + c; 334 | M(2,3) = 0.0f; 335 | 336 | M(3,0) = 0.0f; 337 | M(3,1) = 0.0f; 338 | M(3,2) = 0.0f; 339 | M(3,3) = 1.0f; 340 | 341 | #undef M 342 | } 343 | 344 | 345 | 346 | /////////////////////////////////////////////////////////////////////////////// 347 | // Ditto above, but for doubles 348 | void m3dRotationMatrix33(M3DMatrix33d m, double angle, double x, double y, double z) 349 | { 350 | double mag, s, c; 351 | double xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; 352 | 353 | s = sin(angle); 354 | c = cos(angle); 355 | 356 | mag = sqrt( x*x + y*y + z*z ); 357 | 358 | // Identity matrix 359 | if (mag == 0.0) { 360 | m3dLoadIdentity33(m); 361 | return; 362 | } 363 | 364 | // Rotation matrix is normalized 365 | x /= mag; 366 | y /= mag; 367 | z /= mag; 368 | 369 | #define M(row,col) m[col*3+row] 370 | 371 | xx = x * x; 372 | yy = y * y; 373 | zz = z * z; 374 | xy = x * y; 375 | yz = y * z; 376 | zx = z * x; 377 | xs = x * s; 378 | ys = y * s; 379 | zs = z * s; 380 | one_c = 1.0 - c; 381 | 382 | M(0,0) = (one_c * xx) + c; 383 | M(0,1) = (one_c * xy) - zs; 384 | M(0,2) = (one_c * zx) + ys; 385 | 386 | M(1,0) = (one_c * xy) + zs; 387 | M(1,1) = (one_c * yy) + c; 388 | M(1,2) = (one_c * yz) - xs; 389 | 390 | M(2,0) = (one_c * zx) - ys; 391 | M(2,1) = (one_c * yz) + xs; 392 | M(2,2) = (one_c * zz) + c; 393 | 394 | #undef M 395 | } 396 | 397 | 398 | /////////////////////////////////////////////////////////////////////////////// 399 | // Creates a 4x4 rotation matrix, takes radians NOT degrees 400 | void m3dRotationMatrix44(M3DMatrix44d m, double angle, double x, double y, double z) 401 | { 402 | double mag, s, c; 403 | double xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c; 404 | 405 | s = sin(angle); 406 | c = cos(angle); 407 | 408 | mag = sqrt( x*x + y*y + z*z ); 409 | 410 | // Identity matrix 411 | if (mag == 0.0) { 412 | m3dLoadIdentity44(m); 413 | return; 414 | } 415 | 416 | // Rotation matrix is normalized 417 | x /= mag; 418 | y /= mag; 419 | z /= mag; 420 | 421 | #define M(row,col) m[col*4+row] 422 | 423 | xx = x * x; 424 | yy = y * y; 425 | zz = z * z; 426 | xy = x * y; 427 | yz = y * z; 428 | zx = z * x; 429 | xs = x * s; 430 | ys = y * s; 431 | zs = z * s; 432 | one_c = 1.0f - c; 433 | 434 | M(0,0) = (one_c * xx) + c; 435 | M(0,1) = (one_c * xy) - zs; 436 | M(0,2) = (one_c * zx) + ys; 437 | M(0,3) = 0.0; 438 | 439 | M(1,0) = (one_c * xy) + zs; 440 | M(1,1) = (one_c * yy) + c; 441 | M(1,2) = (one_c * yz) - xs; 442 | M(1,3) = 0.0; 443 | 444 | M(2,0) = (one_c * zx) - ys; 445 | M(2,1) = (one_c * yz) + xs; 446 | M(2,2) = (one_c * zz) + c; 447 | M(2,3) = 0.0; 448 | 449 | M(3,0) = 0.0; 450 | M(3,1) = 0.0; 451 | M(3,2) = 0.0; 452 | M(3,3) = 1.0; 453 | 454 | #undef M 455 | } 456 | 457 | //////////////////////////////////////////////////////////////////////////// 458 | /// This function is not exported by library, just for this modules use only 459 | // 3x3 determinant 460 | static float DetIJ(const M3DMatrix44f m, const int i, const int j) 461 | { 462 | int x, y, ii, jj; 463 | float ret, mat[3][3]; 464 | 465 | x = 0; 466 | for (ii = 0; ii < 4; ii++) 467 | { 468 | if (ii == i) continue; 469 | y = 0; 470 | for (jj = 0; jj < 4; jj++) 471 | { 472 | if (jj == j) continue; 473 | mat[x][y] = m[(ii*4)+jj]; 474 | y++; 475 | } 476 | x++; 477 | } 478 | 479 | ret = mat[0][0]*(mat[1][1]*mat[2][2]-mat[2][1]*mat[1][2]); 480 | ret -= mat[0][1]*(mat[1][0]*mat[2][2]-mat[2][0]*mat[1][2]); 481 | ret += mat[0][2]*(mat[1][0]*mat[2][1]-mat[2][0]*mat[1][1]); 482 | 483 | return ret; 484 | } 485 | 486 | 487 | //////////////////////////////////////////////////////////////////////////// 488 | /// This function is not exported by library, just for this modules use only 489 | // 3x3 determinant 490 | static double DetIJ(const M3DMatrix44d m, const int i, const int j) 491 | { 492 | int x, y, ii, jj; 493 | double ret, mat[3][3]; 494 | 495 | x = 0; 496 | for (ii = 0; ii < 4; ii++) 497 | { 498 | if (ii == i) continue; 499 | y = 0; 500 | for (jj = 0; jj < 4; jj++) 501 | { 502 | if (jj == j) continue; 503 | mat[x][y] = m[(ii*4)+jj]; 504 | y++; 505 | } 506 | x++; 507 | } 508 | 509 | ret = mat[0][0]*(mat[1][1]*mat[2][2]-mat[2][1]*mat[1][2]); 510 | ret -= mat[0][1]*(mat[1][0]*mat[2][2]-mat[2][0]*mat[1][2]); 511 | ret += mat[0][2]*(mat[1][0]*mat[2][1]-mat[2][0]*mat[1][1]); 512 | 513 | return ret; 514 | } 515 | 516 | //////////////////////////////////////////////////////////////////////////// 517 | /// 518 | // Invert matrix 519 | void m3dInvertMatrix44(M3DMatrix44f mInverse, const M3DMatrix44f m) 520 | { 521 | int i, j; 522 | float det, detij; 523 | 524 | // calculate 4x4 determinant 525 | det = 0.0f; 526 | for (i = 0; i < 4; i++) 527 | { 528 | det += (i & 0x1) ? (-m[i] * DetIJ(m, 0, i)) : (m[i] * DetIJ(m, 0,i)); 529 | } 530 | det = 1.0f / det; 531 | 532 | // calculate inverse 533 | for (i = 0; i < 4; i++) 534 | { 535 | for (j = 0; j < 4; j++) 536 | { 537 | detij = DetIJ(m, j, i); 538 | mInverse[(i*4)+j] = ((i+j) & 0x1) ? (-detij * det) : (detij *det); 539 | } 540 | } 541 | } 542 | 543 | //////////////////////////////////////////////////////////////////////////// 544 | /// 545 | // Invert matrix 546 | void m3dInvertMatrix44(M3DMatrix44d mInverse, const M3DMatrix44d m) 547 | { 548 | int i, j; 549 | double det, detij; 550 | 551 | // calculate 4x4 determinant 552 | det = 0.0; 553 | for (i = 0; i < 4; i++) 554 | { 555 | det += (i & 0x1) ? (-m[i] * DetIJ(m, 0, i)) : (m[i] * DetIJ(m, 0,i)); 556 | } 557 | det = 1.0 / det; 558 | 559 | // calculate inverse 560 | for (i = 0; i < 4; i++) 561 | { 562 | for (j = 0; j < 4; j++) 563 | { 564 | detij = DetIJ(m, j, i); 565 | mInverse[(i*4)+j] = ((i+j) & 0x1) ? (-detij * det) : (detij *det); 566 | } 567 | } 568 | } 569 | 570 | 571 | /////////////////////////////////////////////////////////////////////////////////////// 572 | // Get Window coordinates, discard Z... 573 | void m3dProjectXY(M3DVector2f vPointOut, const M3DMatrix44f mModelView, const M3DMatrix44f mProjection, const int iViewPort[4], const M3DVector3f vPointIn) 574 | { 575 | M3DVector4f vBack, vForth; 576 | 577 | memcpy(vBack, vPointIn, sizeof(float)*3); 578 | vBack[3] = 1.0f; 579 | 580 | m3dTransformVector4(vForth, vBack, mModelView); 581 | m3dTransformVector4(vBack, vForth, mProjection); 582 | 583 | if(!m3dCloseEnough(vBack[3], 0.0f, 0.000001f)) { 584 | float div = 1.0f / vBack[3]; 585 | vBack[0] *= div; 586 | vBack[1] *= div; 587 | //vBack[2] *= div; 588 | } 589 | 590 | vPointOut[0] = float(iViewPort[0])+(1.0f+float(vBack[0]))*float(iViewPort[2])/2.0f; 591 | vPointOut[1] = float(iViewPort[1])+(1.0f+float(vBack[1]))*float(iViewPort[3])/2.0f; 592 | 593 | // This was put in for Grand Tour... I think it's right. 594 | // .... please report any bugs 595 | if(iViewPort[0] != 0) // Cast to float is expensive... avoid if posssible 596 | vPointOut[0] -= float(iViewPort[0]); 597 | 598 | if(iViewPort[1] != 0) 599 | vPointOut[1] -= float(iViewPort[1]); 600 | } 601 | 602 | /////////////////////////////////////////////////////////////////////////////////////// 603 | // Get window coordinates, we also want Z.... 604 | void m3dProjectXYZ(M3DVector3f vPointOut, const M3DMatrix44f mModelView, const M3DMatrix44f mProjection, const int iViewPort[4], const M3DVector3f vPointIn) 605 | { 606 | M3DVector4f vBack, vForth; 607 | 608 | memcpy(vBack, vPointIn, sizeof(float)*3); 609 | vBack[3] = 1.0f; 610 | 611 | m3dTransformVector4(vForth, vBack, mModelView); 612 | m3dTransformVector4(vBack, vForth, mProjection); 613 | 614 | if(!m3dCloseEnough(vBack[3], 0.0f, 0.000001f)) { 615 | float div = 1.0f / vBack[3]; 616 | vBack[0] *= div; 617 | vBack[1] *= div; 618 | vBack[2] *= div; 619 | } 620 | 621 | vPointOut[0] = float(iViewPort[0])+(1.0f+float(vBack[0]))*float(iViewPort[2])/2.0f; 622 | vPointOut[1] = float(iViewPort[1])+(1.0f+float(vBack[1]))*float(iViewPort[3])/2.0f; 623 | 624 | if(iViewPort[0] != 0) // Cast to float is expensive... avoid if posssible 625 | vPointOut[0] -= float(iViewPort[0]); 626 | 627 | if(iViewPort[1] != 0) 628 | vPointOut[1] -= float(iViewPort[1]); 629 | 630 | vPointOut[2] = vBack[2]; 631 | } 632 | 633 | 634 | 635 | /////////////////////////////////////////////////////////////////////////////// 636 | /////////////////////////////////////////////////////////////////////////////// 637 | // Misc. Utilities 638 | /////////////////////////////////////////////////////////////////////////////// 639 | // Calculates the normal of a triangle specified by the three points 640 | // p1, p2, and p3. Each pointer points to an array of three floats. The 641 | // triangle is assumed to be wound counter clockwise. 642 | void m3dFindNormal(M3DVector3f result, const M3DVector3f point1, const M3DVector3f point2, 643 | const M3DVector3f point3) 644 | { 645 | M3DVector3f v1,v2; // Temporary vectors 646 | 647 | // Calculate two vectors from the three points. Assumes counter clockwise 648 | // winding! 649 | v1[0] = point1[0] - point2[0]; 650 | v1[1] = point1[1] - point2[1]; 651 | v1[2] = point1[2] - point2[2]; 652 | 653 | v2[0] = point2[0] - point3[0]; 654 | v2[1] = point2[1] - point3[1]; 655 | v2[2] = point2[2] - point3[2]; 656 | 657 | // Take the cross product of the two vectors to get 658 | // the normal vector. 659 | m3dCrossProduct3(result, v1, v2); 660 | } 661 | 662 | 663 | 664 | // Ditto above, but for doubles 665 | void m3dFindNormal(M3DVector3d result, const M3DVector3d point1, const M3DVector3d point2, 666 | const M3DVector3d point3) 667 | { 668 | M3DVector3d v1,v2; // Temporary vectors 669 | 670 | // Calculate two vectors from the three points. Assumes counter clockwise 671 | // winding! 672 | v1[0] = point1[0] - point2[0]; 673 | v1[1] = point1[1] - point2[1]; 674 | v1[2] = point1[2] - point2[2]; 675 | 676 | v2[0] = point2[0] - point3[0]; 677 | v2[1] = point2[1] - point3[1]; 678 | v2[2] = point2[2] - point3[2]; 679 | 680 | // Take the cross product of the two vectors to get 681 | // the normal vector. 682 | m3dCrossProduct3(result, v1, v2); 683 | } 684 | 685 | 686 | 687 | ///////////////////////////////////////////////////////////////////////////////////////// 688 | // Calculate the plane equation of the plane that the three specified points lay in. The 689 | // points are given in clockwise winding order, with normal pointing out of clockwise face 690 | // planeEq contains the A,B,C, and D of the plane equation coefficients 691 | void m3dGetPlaneEquation(M3DVector4f planeEq, const M3DVector3f p1, const M3DVector3f p2, const M3DVector3f p3) 692 | { 693 | // Get two vectors... do the cross product 694 | M3DVector3f v1, v2; 695 | 696 | // V1 = p3 - p1 697 | v1[0] = p3[0] - p1[0]; 698 | v1[1] = p3[1] - p1[1]; 699 | v1[2] = p3[2] - p1[2]; 700 | 701 | // V2 = P2 - p1 702 | v2[0] = p2[0] - p1[0]; 703 | v2[1] = p2[1] - p1[1]; 704 | v2[2] = p2[2] - p1[2]; 705 | 706 | // Unit normal to plane - Not sure which is the best way here 707 | m3dCrossProduct3(planeEq, v1, v2); 708 | m3dNormalizeVector3(planeEq); 709 | 710 | // Back substitute to get D 711 | planeEq[3] = -(planeEq[0] * p3[0] + planeEq[1] * p3[1] + planeEq[2] * p3[2]); 712 | } 713 | 714 | 715 | // Ditto above, but for doubles 716 | void m3dGetPlaneEquation(M3DVector4d planeEq, const M3DVector3d p1, const M3DVector3d p2, const M3DVector3d p3) 717 | { 718 | // Get two vectors... do the cross product 719 | M3DVector3d v1, v2; 720 | 721 | // V1 = p3 - p1 722 | v1[0] = p3[0] - p1[0]; 723 | v1[1] = p3[1] - p1[1]; 724 | v1[2] = p3[2] - p1[2]; 725 | 726 | // V2 = P2 - p1 727 | v2[0] = p2[0] - p1[0]; 728 | v2[1] = p2[1] - p1[1]; 729 | v2[2] = p2[2] - p1[2]; 730 | 731 | // Unit normal to plane - Not sure which is the best way here 732 | m3dCrossProduct3(planeEq, v1, v2); 733 | m3dNormalizeVector3(planeEq); 734 | // Back substitute to get D 735 | planeEq[3] = -(planeEq[0] * p3[0] + planeEq[1] * p3[1] + planeEq[2] * p3[2]); 736 | } 737 | 738 | 739 | ////////////////////////////////////////////////////////////////////////////////////////////////// 740 | // This function does a three dimensional Catmull-Rom curve interpolation. Pass four points, and a 741 | // floating point number between 0.0 and 1.0. The curve is interpolated between the middle two points. 742 | // Coded by RSW 743 | void m3dCatmullRom(M3DVector3f vOut, const M3DVector3f vP0, const M3DVector3f vP1, const M3DVector3f vP2, const M3DVector3f vP3, float t) 744 | { 745 | float t2 = t * t; 746 | float t3 = t2 * t; 747 | 748 | // X 749 | vOut[0] = 0.5f * ( ( 2.0f * vP1[0]) + 750 | (-vP0[0] + vP2[0]) * t + 751 | (2.0f * vP0[0] - 5.0f *vP1[0] + 4.0f * vP2[0] - vP3[0]) * t2 + 752 | (-vP0[0] + 3.0f*vP1[0] - 3.0f *vP2[0] + vP3[0]) * t3); 753 | // Y 754 | vOut[1] = 0.5f * ( ( 2.0f * vP1[1]) + 755 | (-vP0[1] + vP2[1]) * t + 756 | (2.0f * vP0[1] - 5.0f *vP1[1] + 4.0f * vP2[1] - vP3[1]) * t2 + 757 | (-vP0[1] + 3.0f*vP1[1] - 3.0f *vP2[1] + vP3[1]) * t3); 758 | 759 | // Z 760 | vOut[2] = 0.5f * ( ( 2.0f * vP1[2]) + 761 | (-vP0[2] + vP2[2]) * t + 762 | (2.0f * vP0[2] - 5.0f *vP1[2] + 4.0f * vP2[2] - vP3[2]) * t2 + 763 | (-vP0[2] + 3.0f*vP1[2] - 3.0f *vP2[2] + vP3[2]) * t3); 764 | } 765 | 766 | 767 | ////////////////////////////////////////////////////////////////////////////////////////////////// 768 | // This function does a three dimensional Catmull-Rom curve interpolation. Pass four points, and a 769 | // floating point number between 0.0 and 1.0. The curve is interpolated between the middle two points. 770 | // Coded by RSW 771 | void m3dCatmullRom(M3DVector3d vOut, const M3DVector3d vP0, const M3DVector3d vP1, const M3DVector3d vP2, const M3DVector3d vP3, double t) 772 | { 773 | double t2 = t * t; 774 | double t3 = t2 * t; 775 | 776 | // X 777 | vOut[0] = 0.5 * ( ( 2.0 * vP1[0]) + 778 | (-vP0[0] + vP2[0]) * t + 779 | (2.0 * vP0[0] - 5.0 *vP1[0] + 4.0 * vP2[0] - vP3[0]) * t2 + 780 | (-vP0[0] + 3.0*vP1[0] - 3.0 *vP2[0] + vP3[0]) * t3); 781 | // Y 782 | vOut[1] = 0.5 * ( ( 2.0 * vP1[1]) + 783 | (-vP0[1] + vP2[1]) * t + 784 | (2.0 * vP0[1] - 5.0 *vP1[1] + 4.0 * vP2[1] - vP3[1]) * t2 + 785 | (-vP0[1] + 3*vP1[1] - 3.0 *vP2[1] + vP3[1]) * t3); 786 | 787 | // Z 788 | vOut[2] = 0.5 * ( ( 2.0 * vP1[2]) + 789 | (-vP0[2] + vP2[2]) * t + 790 | (2.0 * vP0[2] - 5.0 *vP1[2] + 4.0 * vP2[2] - vP3[2]) * t2 + 791 | (-vP0[2] + 3.0*vP1[2] - 3.0 *vP2[2] + vP3[2]) * t3); 792 | } 793 | 794 | 795 | /////////////////////////////////////////////////////////////////////////////// 796 | // Determine if the ray (starting at point) intersects the sphere centered at 797 | // sphereCenter with radius sphereRadius 798 | // Return value is < 0 if the ray does not intersect 799 | // Return value is 0.0 if ray is tangent 800 | // Positive value is distance to the intersection point 801 | // Algorithm from "3D Math Primer for Graphics and Game Development" 802 | double m3dRaySphereTest(const M3DVector3d point, const M3DVector3d ray, const M3DVector3d sphereCenter, double sphereRadius) 803 | { 804 | //m3dNormalizeVector(ray); // Make sure ray is unit length 805 | 806 | M3DVector3d rayToCenter; // Ray to center of sphere 807 | rayToCenter[0] = sphereCenter[0] - point[0]; 808 | rayToCenter[1] = sphereCenter[1] - point[1]; 809 | rayToCenter[2] = sphereCenter[2] - point[2]; 810 | 811 | // Project rayToCenter on ray to test 812 | double a = m3dDotProduct3(rayToCenter, ray); 813 | 814 | // Distance to center of sphere 815 | double distance2 = m3dDotProduct3(rayToCenter, rayToCenter); // Or length 816 | 817 | 818 | double dRet = (sphereRadius * sphereRadius) - distance2 + (a*a); 819 | 820 | if(dRet > 0.0) // Return distance to intersection 821 | dRet = a - sqrt(dRet); 822 | 823 | return dRet; 824 | } 825 | 826 | /////////////////////////////////////////////////////////////////////////////// 827 | // Determine if the ray (starting at point) intersects the sphere centered at 828 | // ditto above, but uses floating point math 829 | float m3dRaySphereTest(const M3DVector3f point, const M3DVector3f ray, const M3DVector3f sphereCenter, float sphereRadius) 830 | { 831 | //m3dNormalizeVectorf(ray); // Make sure ray is unit length 832 | 833 | M3DVector3f rayToCenter; // Ray to center of sphere 834 | rayToCenter[0] = sphereCenter[0] - point[0]; 835 | rayToCenter[1] = sphereCenter[1] - point[1]; 836 | rayToCenter[2] = sphereCenter[2] - point[2]; 837 | 838 | // Project rayToCenter on ray to test 839 | float a = m3dDotProduct3(rayToCenter, ray); 840 | 841 | // Distance to center of sphere 842 | float distance2 = m3dDotProduct3(rayToCenter, rayToCenter); // Or length 843 | 844 | float dRet = (sphereRadius * sphereRadius) - distance2 + (a*a); 845 | 846 | if(dRet > 0.0) // Return distance to intersection 847 | dRet = a - sqrtf(dRet); 848 | 849 | return dRet; 850 | } 851 | 852 | 853 | /////////////////////////////////////////////////////////////////////////////////////////////////// 854 | // Calculate the tangent basis for a triangle on the surface of a model 855 | // This vector is needed for most normal mapping shaders 856 | void m3dCalculateTangentBasis(M3DVector3f vTangent, const M3DVector3f vTriangle[3], const M3DVector2f vTexCoords[3], const M3DVector3f N) 857 | { 858 | M3DVector3f dv2v1, dv3v1; 859 | float dc2c1t, dc2c1b, dc3c1t, dc3c1b; 860 | float M; 861 | 862 | m3dSubtractVectors3(dv2v1, vTriangle[1], vTriangle[0]); 863 | m3dSubtractVectors3(dv3v1, vTriangle[2], vTriangle[0]); 864 | 865 | dc2c1t = vTexCoords[1][0] - vTexCoords[0][0]; 866 | dc2c1b = vTexCoords[1][1] - vTexCoords[0][1]; 867 | dc3c1t = vTexCoords[2][0] - vTexCoords[0][0]; 868 | dc3c1b = vTexCoords[2][1] - vTexCoords[0][1]; 869 | 870 | M = (dc2c1t * dc3c1b) - (dc3c1t * dc2c1b); 871 | M = 1.0f / M; 872 | 873 | m3dScaleVector3(dv2v1, dc3c1b); 874 | m3dScaleVector3(dv3v1, dc2c1b); 875 | 876 | m3dSubtractVectors3(vTangent, dv2v1, dv3v1); 877 | m3dScaleVector3(vTangent, M); // This potentially changes the direction of the vector 878 | m3dNormalizeVector3(vTangent); 879 | 880 | M3DVector3f B; 881 | m3dCrossProduct3(B, N, vTangent); 882 | m3dCrossProduct3(vTangent, B, N); 883 | m3dNormalizeVector3(vTangent); 884 | } 885 | 886 | 887 | //////////////////////////////////////////////////////////////////////////// 888 | // Smoothly step between 0 and 1 between edge1 and edge 2 889 | double m3dSmoothStep(const double edge1, const double edge2, const double x) 890 | { 891 | double t; 892 | t = (x - edge1) / (edge2 - edge1); 893 | if(t > 1.0) 894 | t = 1.0; 895 | 896 | if(t < 0.0) 897 | t = 0.0f; 898 | 899 | return t * t * ( 3.0 - 2.0 * t); 900 | } 901 | 902 | //////////////////////////////////////////////////////////////////////////// 903 | // Smoothly step between 0 and 1 between edge1 and edge 2 904 | float m3dSmoothStep(const float edge1, const float edge2, const float x) 905 | { 906 | float t; 907 | t = (x - edge1) / (edge2 - edge1); 908 | if(t > 1.0f) 909 | t = 1.0f; 910 | 911 | if(t < 0.0) 912 | t = 0.0f; 913 | 914 | return t * t * ( 3.0f - 2.0f * t); 915 | } 916 | 917 | 918 | 919 | /////////////////////////////////////////////////////////////////////////// 920 | // Creae a projection to "squish" an object into the plane. 921 | // Use m3dGetPlaneEquationf(planeEq, point1, point2, point3); 922 | // to get a plane equation. 923 | void m3dMakePlanarShadowMatrix(M3DMatrix44f proj, const M3DVector4f planeEq, const M3DVector3f vLightPos) 924 | { 925 | // These just make the code below easier to read. They will be 926 | // removed by the optimizer. 927 | float a = planeEq[0]; 928 | float b = planeEq[1]; 929 | float c = planeEq[2]; 930 | float d = planeEq[3]; 931 | 932 | float dx = -vLightPos[0]; 933 | float dy = -vLightPos[1]; 934 | float dz = -vLightPos[2]; 935 | 936 | // Now build the projection matrix 937 | proj[0] = b * dy + c * dz; 938 | proj[1] = -a * dy; 939 | proj[2] = -a * dz; 940 | proj[3] = 0.0; 941 | 942 | proj[4] = -b * dx; 943 | proj[5] = a * dx + c * dz; 944 | proj[6] = -b * dz; 945 | proj[7] = 0.0; 946 | 947 | proj[8] = -c * dx; 948 | proj[9] = -c * dy; 949 | proj[10] = a * dx + b * dy; 950 | proj[11] = 0.0; 951 | 952 | proj[12] = -d * dx; 953 | proj[13] = -d * dy; 954 | proj[14] = -d * dz; 955 | proj[15] = a * dx + b * dy + c * dz; 956 | // Shadow matrix ready 957 | } 958 | 959 | 960 | /////////////////////////////////////////////////////////////////////////// 961 | // Creae a projection to "squish" an object into the plane. 962 | // Use m3dGetPlaneEquationd(planeEq, point1, point2, point3); 963 | // to get a plane equation. 964 | void m3dMakePlanarShadowMatrix(M3DMatrix44d proj, const M3DVector4d planeEq, const M3DVector3f vLightPos) 965 | { 966 | // These just make the code below easier to read. They will be 967 | // removed by the optimizer. 968 | double a = planeEq[0]; 969 | double b = planeEq[1]; 970 | double c = planeEq[2]; 971 | double d = planeEq[3]; 972 | 973 | double dx = -vLightPos[0]; 974 | double dy = -vLightPos[1]; 975 | double dz = -vLightPos[2]; 976 | 977 | // Now build the projection matrix 978 | proj[0] = b * dy + c * dz; 979 | proj[1] = -a * dy; 980 | proj[2] = -a * dz; 981 | proj[3] = 0.0; 982 | 983 | proj[4] = -b * dx; 984 | proj[5] = a * dx + c * dz; 985 | proj[6] = -b * dz; 986 | proj[7] = 0.0; 987 | 988 | proj[8] = -c * dx; 989 | proj[9] = -c * dy; 990 | proj[10] = a * dx + b * dy; 991 | proj[11] = 0.0; 992 | 993 | proj[12] = -d * dx; 994 | proj[13] = -d * dy; 995 | proj[14] = -d * dz; 996 | proj[15] = a * dx + b * dy + c * dz; 997 | // Shadow matrix ready 998 | } 999 | 1000 | 1001 | ///////////////////////////////////////////////////////////////////////////// 1002 | // I want to know the point on a ray, closest to another given point in space. 1003 | // As a bonus, return the distance squared of the two points. 1004 | // In: vRayOrigin is the origin of the ray. 1005 | // In: vUnitRayDir is the unit vector of the ray 1006 | // In: vPointInSpace is the point in space 1007 | // Out: vPointOnRay is the poing on the ray closest to vPointInSpace 1008 | // Return: The square of the distance to the ray 1009 | double m3dClosestPointOnRay(M3DVector3d vPointOnRay, const M3DVector3d vRayOrigin, const M3DVector3d vUnitRayDir, 1010 | const M3DVector3d vPointInSpace) 1011 | { 1012 | M3DVector3d v; 1013 | m3dSubtractVectors3(v, vPointInSpace, vRayOrigin); 1014 | 1015 | double t = m3dDotProduct3(vUnitRayDir, v); 1016 | 1017 | // This is the point on the ray 1018 | vPointOnRay[0] = vRayOrigin[0] + (t * vUnitRayDir[0]); 1019 | vPointOnRay[1] = vRayOrigin[1] + (t * vUnitRayDir[1]); 1020 | vPointOnRay[2] = vRayOrigin[2] + (t * vUnitRayDir[2]); 1021 | 1022 | return m3dGetDistanceSquared3(vPointOnRay, vPointInSpace); 1023 | } 1024 | 1025 | // ditto above... but with floats 1026 | float m3dClosestPointOnRay(M3DVector3f vPointOnRay, const M3DVector3f vRayOrigin, const M3DVector3f vUnitRayDir, 1027 | const M3DVector3f vPointInSpace) 1028 | { 1029 | M3DVector3f v; 1030 | m3dSubtractVectors3(v, vPointInSpace, vRayOrigin); 1031 | 1032 | float t = m3dDotProduct3(vUnitRayDir, v); 1033 | 1034 | // This is the point on the ray 1035 | vPointOnRay[0] = vRayOrigin[0] + (t * vUnitRayDir[0]); 1036 | vPointOnRay[1] = vRayOrigin[1] + (t * vUnitRayDir[1]); 1037 | vPointOnRay[2] = vRayOrigin[2] + (t * vUnitRayDir[2]); 1038 | 1039 | return m3dGetDistanceSquared3(vPointOnRay, vPointInSpace); 1040 | } 1041 | -------------------------------------------------------------------------------- /math3d.h: -------------------------------------------------------------------------------- 1 | // Math3d.h 2 | // Math3D Library, version 0.95 3 | 4 | /* Copyright (c) 2009, Richard S. Wright Jr. 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this list 11 | of conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, this list 14 | of conditions and the following disclaimer in the documentation and/or other 15 | materials provided with the distribution. 16 | 17 | Neither the name of Richard S. Wright Jr. nor the names of other contributors may be used 18 | to endorse or promote products derived from this software without specific prior 19 | written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 22 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24 | SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 27 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | // Header file for the Math3d library. The C-Runtime has math.h, this file and the 33 | // accompanying math3d.cpp are meant to suppliment math.h by adding geometry/math routines 34 | // useful for graphics, simulation, and physics applications (3D stuff). 35 | // This library is meant to be useful on Win32, Mac OS X, various Linux/Unix distros, 36 | // and mobile platforms. Although designed with OpenGL in mind, there are no OpenGL 37 | // dependencies. Other than standard math routines, the only other outside routine 38 | // used is memcpy (for faster copying of vector arrays). 39 | // Richard S. Wright Jr. 40 | 41 | #ifndef _MATH3D_LIBRARY__ 42 | #define _MATH3D_LIBRARY__ 43 | 44 | #include 45 | #include // Memcpy lives here on most systems 46 | 47 | /////////////////////////////////////////////////////////////////////////////// 48 | // Data structures and containers 49 | // Much thought went into how these are declared. Many libraries declare these 50 | // as structures with x, y, z data members. However structure alignment issues 51 | // could limit the portability of code based on such structures, or the binary 52 | // compatibility of data files (more likely) that contain such structures across 53 | // compilers/platforms. Arrays are always tightly packed, and are more efficient 54 | // for moving blocks of data around (usually). 55 | // Sigh... yes, I probably should use GLfloat, etc. But that requires that we 56 | // always include OpenGL. Since this library is also useful for non-graphical 57 | // applications, I shall risk the wrath of the portability gods... 58 | 59 | typedef float M3DVector2f[2]; // 3D points = 3D Vectors, but we need a 60 | typedef double M3DVector2d[2]; // 2D representations sometimes... (x,y) order 61 | 62 | typedef float M3DVector3f[3]; // Vector of three floats (x, y, z) 63 | typedef double M3DVector3d[3]; // Vector of three doubles (x, y, z) 64 | 65 | typedef float M3DVector4f[4]; // Lesser used... Do we really need these? 66 | typedef double M3DVector4d[4]; // Yes, occasionaly we do need a trailing w component 67 | 68 | 69 | 70 | // 3x3 matrix - column major. X vector is 0, 1, 2, etc. 71 | // 0 3 6 72 | // 1 4 7 73 | // 2 5 8 74 | typedef float M3DMatrix33f[9]; // A 3 x 3 matrix, column major (floats) - OpenGL Style 75 | typedef double M3DMatrix33d[9]; // A 3 x 3 matrix, column major (doubles) - OpenGL Style 76 | 77 | 78 | // 4x4 matrix - column major. X vector is 0, 1, 2, etc. 79 | // 0 4 8 12 80 | // 1 5 9 13 81 | // 2 6 10 14 82 | // 3 7 11 15 83 | typedef float M3DMatrix44f[16]; // A 4 X 4 matrix, column major (floats) - OpenGL style 84 | typedef double M3DMatrix44d[16]; // A 4 x 4 matrix, column major (doubles) - OpenGL style 85 | 86 | 87 | /////////////////////////////////////////////////////////////////////////////// 88 | // Useful constants 89 | #define M3D_PI (3.14159265358979323846) 90 | #define M3D_2PI (2.0 * M3D_PI) 91 | #define M3D_PI_DIV_180 (0.017453292519943296) 92 | #define M3D_INV_PI_DIV_180 (57.2957795130823229) 93 | 94 | 95 | /////////////////////////////////////////////////////////////////////////////// 96 | // Useful shortcuts and macros 97 | // Radians are king... but we need a way to swap back and forth for programmers and presentation. 98 | // Leaving these as Macros instead of inline functions, causes constants 99 | // to be evaluated at compile time instead of run time, e.g. m3dDegToRad(90.0) 100 | #define m3dDegToRad(x) ((x)*M3D_PI_DIV_180) 101 | #define m3dRadToDeg(x) ((x)*M3D_INV_PI_DIV_180) 102 | 103 | // Hour angles 104 | #define m3dHrToDeg(x) ((x) * (1.0 / 15.0)) 105 | #define m3dHrToRad(x) m3dDegToRad(m3dHrToDeg(x)) 106 | 107 | #define m3dDegToHr(x) ((x) * 15.0)) 108 | #define m3dRadToHr(x) m3dDegToHr(m3dRadToDeg(x)) 109 | 110 | 111 | // Returns the same number if it is a power of 112 | // two. Returns a larger integer if it is not a 113 | // power of two. The larger integer is the next 114 | // highest power of two. 115 | inline unsigned int m3dIsPOW2(unsigned int iValue) 116 | { 117 | unsigned int nPow2 = 1; 118 | 119 | while(iValue > nPow2) 120 | nPow2 = (nPow2 << 1); 121 | 122 | return nPow2; 123 | } 124 | 125 | 126 | /////////////////////////////////////////////////////////////////////////////// 127 | // Inline accessor functions (Macros) for people who just can't count to 3 or 4 128 | // Really... you should learn to count before you learn to program ;-) 129 | // 0 = x 130 | // 1 = y 131 | // 2 = z 132 | // 3 = w 133 | #define m3dGetVectorX(v) (v[0]) 134 | #define m3dGetVectorY(v) (v[1]) 135 | #define m3dGetVectorZ(v) (v[2]) 136 | #define m3dGetVectorW(v) (v[3]) 137 | 138 | #define m3dSetVectorX(v, x) ((v)[0] = (x)) 139 | #define m3dSetVectorY(v, y) ((v)[1] = (y)) 140 | #define m3dSetVectorZ(v, z) ((v)[2] = (z)) 141 | #define m3dSetVectorW(v, w) ((v)[3] = (w)) 142 | 143 | /////////////////////////////////////////////////////////////////////////////// 144 | // Inline vector functions 145 | // Load Vector with (x, y, z, w). 146 | inline void m3dLoadVector2(M3DVector2f v, const float x, const float y) 147 | { v[0] = x; v[1] = y; } 148 | inline void m3dLoadVector2(M3DVector2d v, const float x, const float y) 149 | { v[0] = x; v[1] = y; } 150 | inline void m3dLoadVector3(M3DVector3f v, const float x, const float y, const float z) 151 | { v[0] = x; v[1] = y; v[2] = z; } 152 | inline void m3dLoadVector3(M3DVector3d v, const double x, const double y, const double z) 153 | { v[0] = x; v[1] = y; v[2] = z; } 154 | inline void m3dLoadVector4(M3DVector4f v, const float x, const float y, const float z, const float w) 155 | { v[0] = x; v[1] = y; v[2] = z; v[3] = w;} 156 | inline void m3dLoadVector4(M3DVector4d v, const double x, const double y, const double z, const double w) 157 | { v[0] = x; v[1] = y; v[2] = z; v[3] = w;} 158 | 159 | 160 | //////////////////////////////////////////////////////////////////////////////// 161 | // Copy vector src into vector dst 162 | inline void m3dCopyVector2(M3DVector2f dst, const M3DVector2f src) { memcpy(dst, src, sizeof(M3DVector2f)); } 163 | inline void m3dCopyVector2(M3DVector2d dst, const M3DVector2d src) { memcpy(dst, src, sizeof(M3DVector2d)); } 164 | 165 | inline void m3dCopyVector3(M3DVector3f dst, const M3DVector3f src) { memcpy(dst, src, sizeof(M3DVector3f)); } 166 | inline void m3dCopyVector3(M3DVector3d dst, const M3DVector3d src) { memcpy(dst, src, sizeof(M3DVector3d)); } 167 | 168 | inline void m3dCopyVector4(M3DVector4f dst, const M3DVector4f src) { memcpy(dst, src, sizeof(M3DVector4f)); } 169 | inline void m3dCopyVector4(M3DVector4d dst, const M3DVector4d src) { memcpy(dst, src, sizeof(M3DVector4d)); } 170 | 171 | 172 | //////////////////////////////////////////////////////////////////////////////// 173 | // Add Vectors (r, a, b) r = a + b 174 | inline void m3dAddVectors2(M3DVector2f r, const M3DVector2f a, const M3DVector2f b) 175 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; } 176 | inline void m3dAddVectors2(M3DVector2d r, const M3DVector2d a, const M3DVector2d b) 177 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; } 178 | 179 | inline void m3dAddVectors3(M3DVector3f r, const M3DVector3f a, const M3DVector3f b) 180 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; } 181 | inline void m3dAddVectors3(M3DVector3d r, const M3DVector3d a, const M3DVector3d b) 182 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; } 183 | 184 | inline void m3dAddVectors4(M3DVector4f r, const M3DVector4f a, const M3DVector4f b) 185 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; r[3] = a[3] + b[3]; } 186 | inline void m3dAddVectors4(M3DVector4d r, const M3DVector4d a, const M3DVector4d b) 187 | { r[0] = a[0] + b[0]; r[1] = a[1] + b[1]; r[2] = a[2] + b[2]; r[3] = a[3] + b[3]; } 188 | 189 | //////////////////////////////////////////////////////////////////////////////// 190 | // Subtract Vectors (r, a, b) r = a - b 191 | inline void m3dSubtractVectors2(M3DVector2f r, const M3DVector2f a, const M3DVector2f b) 192 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; } 193 | inline void m3dSubtractVectors2(M3DVector2d r, const M3DVector2d a, const M3DVector2d b) 194 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; } 195 | 196 | inline void m3dSubtractVectors3(M3DVector3f r, const M3DVector3f a, const M3DVector3f b) 197 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; r[2] = a[2] - b[2]; } 198 | inline void m3dSubtractVectors3(M3DVector3d r, const M3DVector3d a, const M3DVector3d b) 199 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; r[2] = a[2] - b[2]; } 200 | 201 | inline void m3dSubtractVectors4(M3DVector4f r, const M3DVector4f a, const M3DVector4f b) 202 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; r[2] = a[2] - b[2]; r[3] = a[3] - b[3]; } 203 | inline void m3dSubtractVectors4(M3DVector4d r, const M3DVector4d a, const M3DVector4d b) 204 | { r[0] = a[0] - b[0]; r[1] = a[1] - b[1]; r[2] = a[2] - b[2]; r[3] = a[3] - b[3]; } 205 | 206 | 207 | 208 | /////////////////////////////////////////////////////////////////////////////////////// 209 | // Scale Vectors (in place) 210 | inline void m3dScaleVector2(M3DVector2f v, const float scale) 211 | { v[0] *= scale; v[1] *= scale; } 212 | inline void m3dScaleVector2(M3DVector2d v, const double scale) 213 | { v[0] *= scale; v[1] *= scale; } 214 | 215 | inline void m3dScaleVector3(M3DVector3f v, const float scale) 216 | { v[0] *= scale; v[1] *= scale; v[2] *= scale; } 217 | inline void m3dScaleVector3(M3DVector3d v, const double scale) 218 | { v[0] *= scale; v[1] *= scale; v[2] *= scale; } 219 | 220 | inline void m3dScaleVector4(M3DVector4f v, const float scale) 221 | { v[0] *= scale; v[1] *= scale; v[2] *= scale; v[3] *= scale; } 222 | inline void m3dScaleVector4(M3DVector4d v, const double scale) 223 | { v[0] *= scale; v[1] *= scale; v[2] *= scale; v[3] *= scale; } 224 | 225 | 226 | ////////////////////////////////////////////////////////////////////////////////////// 227 | // Cross Product 228 | // u x v = result 229 | // 3 component vectors only. 230 | inline void m3dCrossProduct3(M3DVector3f result, const M3DVector3f u, const M3DVector3f v) 231 | { 232 | result[0] = u[1]*v[2] - v[1]*u[2]; 233 | result[1] = -u[0]*v[2] + v[0]*u[2]; 234 | result[2] = u[0]*v[1] - v[0]*u[1]; 235 | } 236 | 237 | inline void m3dCrossProduct3(M3DVector3d result, const M3DVector3d u, const M3DVector3d v) 238 | { 239 | result[0] = u[1]*v[2] - v[1]*u[2]; 240 | result[1] = -u[0]*v[2] + v[0]*u[2]; 241 | result[2] = u[0]*v[1] - v[0]*u[1]; 242 | } 243 | 244 | ////////////////////////////////////////////////////////////////////////////////////// 245 | // Dot Product, only for three component vectors 246 | // return u dot v 247 | inline float m3dDotProduct3(const M3DVector3f u, const M3DVector3f v) 248 | { return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; } 249 | 250 | inline double m3dDotProduct3(const M3DVector3d u, const M3DVector3d v) 251 | { return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; } 252 | 253 | ////////////////////////////////////////////////////////////////////////////////////// 254 | // Angle between vectors, only for three component vectors. Angle is in radians... 255 | inline float m3dGetAngleBetweenVectors3(const M3DVector3f u, const M3DVector3f v) 256 | { 257 | float dTemp = m3dDotProduct3(u, v); 258 | return float(acos(double(dTemp))); // Double cast just gets rid of compiler warning, no real need 259 | } 260 | 261 | inline double m3dGetAngleBetweenVectors3(const M3DVector3d u, const M3DVector3d v) 262 | { 263 | double dTemp = m3dDotProduct3(u, v); 264 | return acos(dTemp); 265 | } 266 | 267 | ////////////////////////////////////////////////////////////////////////////////////// 268 | // Get Square of a vectors length 269 | // Only for three component vectors 270 | inline float m3dGetVectorLengthSquared3(const M3DVector3f u) 271 | { return (u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]); } 272 | 273 | inline double m3dGetVectorLengthSquared3(const M3DVector3d u) 274 | { return (u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]); } 275 | 276 | ////////////////////////////////////////////////////////////////////////////////////// 277 | // Get lenght of vector 278 | // Only for three component vectors. 279 | inline float m3dGetVectorLength3(const M3DVector3f u) 280 | { return sqrtf(m3dGetVectorLengthSquared3(u)); } 281 | 282 | inline double m3dGetVectorLength3(const M3DVector3d u) 283 | { return sqrt(m3dGetVectorLengthSquared3(u)); } 284 | 285 | ////////////////////////////////////////////////////////////////////////////////////// 286 | // Normalize a vector 287 | // Scale a vector to unit length. Easy, just scale the vector by it's length 288 | inline void m3dNormalizeVector3(M3DVector3f u) 289 | { m3dScaleVector3(u, 1.0f / m3dGetVectorLength3(u)); } 290 | 291 | inline void m3dNormalizeVector3(M3DVector3d u) 292 | { m3dScaleVector3(u, 1.0 / m3dGetVectorLength3(u)); } 293 | 294 | 295 | ////////////////////////////////////////////////////////////////////////////////////// 296 | // Get the distance between two points. The distance between two points is just 297 | // the magnitude of the difference between two vectors 298 | // Located in math.cpp 299 | float m3dGetDistanceSquared3(const M3DVector3f u, const M3DVector3f v); 300 | double m3dGetDistanceSquared3(const M3DVector3d u, const M3DVector3d v); 301 | 302 | inline double m3dGetDistance3(const M3DVector3d u, const M3DVector3d v) 303 | { return sqrt(m3dGetDistanceSquared3(u, v)); } 304 | 305 | inline float m3dGetDistance3(const M3DVector3f u, const M3DVector3f v) 306 | { return sqrtf(m3dGetDistanceSquared3(u, v)); } 307 | 308 | inline float m3dGetMagnitudeSquared3(const M3DVector3f u) { return u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; } 309 | inline double m3dGetMagnitudeSquared3(const M3DVector3d u) { return u[0]*u[0] + u[1]*u[1] + u[2]*u[2]; } 310 | 311 | inline float m3dGetMagnitude3(const M3DVector3f u) { return sqrtf(m3dGetMagnitudeSquared3(u)); } 312 | inline double m3dGetMagnitude3(const M3DVector3d u) { return sqrt(m3dGetMagnitudeSquared3(u)); } 313 | 314 | 315 | 316 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 317 | // Matrix functions 318 | // Both floating point and double precision 3x3 and 4x4 matricies are supported. 319 | // No support is included for arbitrarily dimensioned matricies on purpose, since 320 | // the 3x3 and 4x4 matrix routines are the most common for the purposes of this 321 | // library. Matrices are column major, like OpenGL matrices. 322 | // Unlike the vector functions, some of these are going to have to not be inlined, 323 | // although many will be. 324 | 325 | // Copy Matrix 326 | // Brain-dead memcpy 327 | inline void m3dCopyMatrix33(M3DMatrix33f dst, const M3DMatrix33f src) 328 | { memcpy(dst, src, sizeof(M3DMatrix33f)); } 329 | 330 | inline void m3dCopyMatrix33(M3DMatrix33d dst, const M3DMatrix33d src) 331 | { memcpy(dst, src, sizeof(M3DMatrix33d)); } 332 | 333 | inline void m3dCopyMatrix44(M3DMatrix44f dst, const M3DMatrix44f src) 334 | { memcpy(dst, src, sizeof(M3DMatrix44f)); } 335 | 336 | inline void m3dCopyMatrix44(M3DMatrix44d dst, const M3DMatrix44d src) 337 | { memcpy(dst, src, sizeof(M3DMatrix44d)); } 338 | 339 | // LoadIdentity 340 | // Implemented in Math3d.cpp 341 | void m3dLoadIdentity33(M3DMatrix33f m); 342 | void m3dLoadIdentity33(M3DMatrix33d m); 343 | void m3dLoadIdentity44(M3DMatrix44f m); 344 | void m3dLoadIdentity44(M3DMatrix44d m); 345 | 346 | ///////////////////////////////////////////////////////////////////////////// 347 | // Get/Set Column. 348 | inline void m3dGetMatrixColumn33(M3DVector3f dst, const M3DMatrix33f src, const int column) 349 | { memcpy(dst, src + (3 * column), sizeof(float) * 3); } 350 | 351 | inline void m3dGetMatrixColumn33(M3DVector3d dst, const M3DMatrix33d src, const int column) 352 | { memcpy(dst, src + (3 * column), sizeof(double) * 3); } 353 | 354 | inline void m3dSetMatrixColumn33(M3DMatrix33f dst, const M3DVector3f src, const int column) 355 | { memcpy(dst + (3 * column), src, sizeof(float) * 3); } 356 | 357 | inline void m3dSetMatrixColumn33(M3DMatrix33d dst, const M3DVector3d src, const int column) 358 | { memcpy(dst + (3 * column), src, sizeof(double) * 3); } 359 | 360 | inline void m3dGetMatrixColumn44(M3DVector4f dst, const M3DMatrix44f src, const int column) 361 | { memcpy(dst, src + (4 * column), sizeof(float) * 4); } 362 | 363 | inline void m3dGetMatrixColumn44(M3DVector4d dst, const M3DMatrix44d src, const int column) 364 | { memcpy(dst, src + (4 * column), sizeof(double) * 4); } 365 | 366 | inline void m3dSetMatrixColumn44(M3DMatrix44f dst, const M3DVector4f src, const int column) 367 | { memcpy(dst + (4 * column), src, sizeof(float) * 4); } 368 | 369 | inline void m3dSetMatrixColumn44(M3DMatrix44d dst, const M3DVector4d src, const int column) 370 | { memcpy(dst + (4 * column), src, sizeof(double) * 4); } 371 | 372 | 373 | /////////////////////////////////////////////////////////////////////////////// 374 | // Extract a rotation matrix from a 4x4 matrix 375 | // Extracts the rotation matrix (3x3) from a 4x4 matrix 376 | inline void m3dExtractRotationMatrix33(M3DMatrix33f dst, const M3DMatrix44f src) 377 | { 378 | memcpy(dst, src, sizeof(float) * 3); // X column 379 | memcpy(dst + 3, src + 4, sizeof(float) * 3); // Y column 380 | memcpy(dst + 6, src + 8, sizeof(float) * 3); // Z column 381 | } 382 | 383 | // Ditto above, but for doubles 384 | inline void m3dExtractRotationMatrix33(M3DMatrix33d dst, const M3DMatrix44d src) 385 | { 386 | memcpy(dst, src, sizeof(double) * 3); // X column 387 | memcpy(dst + 3, src + 4, sizeof(double) * 3); // Y column 388 | memcpy(dst + 6, src + 8, sizeof(double) * 3); // Z column 389 | } 390 | 391 | // Inject Rotation (3x3) into a full 4x4 matrix... 392 | inline void m3dInjectRotationMatrix44(M3DMatrix44f dst, const M3DMatrix33f src) 393 | { 394 | memcpy(dst, src, sizeof(float) * 4); 395 | memcpy(dst + 4, src + 4, sizeof(float) * 4); 396 | memcpy(dst + 8, src + 8, sizeof(float) * 4); 397 | } 398 | 399 | // Ditto above for doubles 400 | inline void m3dInjectRotationMatrix44(M3DMatrix44d dst, const M3DMatrix33d src) 401 | { 402 | memcpy(dst, src, sizeof(double) * 4); 403 | memcpy(dst + 4, src + 4, sizeof(double) * 4); 404 | memcpy(dst + 8, src + 8, sizeof(double) * 4); 405 | } 406 | 407 | //////////////////////////////////////////////////////////////////////////////// 408 | // MultMatrix 409 | // Implemented in Math.cpp 410 | void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b); 411 | void m3dMatrixMultiply44(M3DMatrix44d product, const M3DMatrix44d a, const M3DMatrix44d b); 412 | void m3dMatrixMultiply33(M3DMatrix33f product, const M3DMatrix33f a, const M3DMatrix33f b); 413 | void m3dMatrixMultiply33(M3DMatrix33d product, const M3DMatrix33d a, const M3DMatrix33d b); 414 | 415 | 416 | // Transform - Does rotation and translation via a 4x4 matrix. Transforms 417 | // a point or vector. 418 | // By-the-way __inline means I'm asking the compiler to do a cost/benefit analysis. If 419 | // these are used frequently, they may not be inlined to save memory. I'm experimenting 420 | // with this.... 421 | // Just transform a 3 compoment vector 422 | __inline void m3dTransformVector3(M3DVector3f vOut, const M3DVector3f v, const M3DMatrix44f m) 423 | { 424 | vOut[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12];// * v[3]; // Assuming 1 425 | vOut[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13];// * v[3]; 426 | vOut[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14];// * v[3]; 427 | //vOut[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; 428 | } 429 | 430 | // Ditto above, but for doubles 431 | __inline void m3dTransformVector3(M3DVector3d vOut, const M3DVector3d v, const M3DMatrix44d m) 432 | { 433 | vOut[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12];// * v[3]; 434 | vOut[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13];// * v[3]; 435 | vOut[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14];// * v[3]; 436 | //vOut[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; 437 | } 438 | 439 | // Full four component transform 440 | __inline void m3dTransformVector4(M3DVector4f vOut, const M3DVector4f v, const M3DMatrix44f m) 441 | { 442 | vOut[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3]; 443 | vOut[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3]; 444 | vOut[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3]; 445 | vOut[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; 446 | } 447 | 448 | // Ditto above, but for doubles 449 | __inline void m3dTransformVector4(M3DVector4d vOut, const M3DVector4d v, const M3DMatrix44d m) 450 | { 451 | vOut[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3]; 452 | vOut[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3]; 453 | vOut[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3]; 454 | vOut[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; 455 | } 456 | 457 | 458 | 459 | // Just do the rotation, not the translation... this is usually done with a 3x3 460 | // Matrix. 461 | __inline void m3dRotateVector(M3DVector3f vOut, const M3DVector3f p, const M3DMatrix33f m) 462 | { 463 | vOut[0] = m[0] * p[0] + m[3] * p[1] + m[6] * p[2]; 464 | vOut[1] = m[1] * p[0] + m[4] * p[1] + m[7] * p[2]; 465 | vOut[2] = m[2] * p[0] + m[5] * p[1] + m[8] * p[2]; 466 | } 467 | 468 | // Ditto above, but for doubles 469 | __inline void m3dRotateVector(M3DVector3d vOut, const M3DVector3d p, const M3DMatrix33d m) 470 | { 471 | vOut[0] = m[0] * p[0] + m[3] * p[1] + m[6] * p[2]; 472 | vOut[1] = m[1] * p[0] + m[4] * p[1] + m[7] * p[2]; 473 | vOut[2] = m[2] * p[0] + m[5] * p[1] + m[8] * p[2]; 474 | } 475 | 476 | 477 | // Create a Scaling Matrix 478 | inline void m3dScaleMatrix33(M3DMatrix33f m, float xScale, float yScale, float zScale) 479 | { m3dLoadIdentity33(m); m[0] = xScale; m[4] = yScale; m[8] = zScale; } 480 | 481 | inline void m3dScaleMatrix33(M3DMatrix33f m, const M3DVector3f vScale) 482 | { m3dLoadIdentity33(m); m[0] = vScale[0]; m[4] = vScale[1]; m[8] = vScale[2]; } 483 | 484 | inline void m3dScaleMatrix33(M3DMatrix33d m, double xScale, double yScale, double zScale) 485 | { m3dLoadIdentity33(m); m[0] = xScale; m[4] = yScale; m[8] = zScale; } 486 | 487 | inline void m3dScaleMatrix33(M3DMatrix33d m, const M3DVector3d vScale) 488 | { m3dLoadIdentity33(m); m[0] = vScale[0]; m[4] = vScale[1]; m[8] = vScale[2]; } 489 | 490 | inline void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale) 491 | { m3dLoadIdentity44(m); m[0] = xScale; m[5] = yScale; m[10] = zScale; } 492 | 493 | inline void m3dScaleMatrix44(M3DMatrix44f m, const M3DVector3f vScale) 494 | { m3dLoadIdentity44(m); m[0] = vScale[0]; m[5] = vScale[1]; m[10] = vScale[2]; } 495 | 496 | inline void m3dScaleMatrix44(M3DMatrix44d m, double xScale, double yScale, double zScale) 497 | { m3dLoadIdentity44(m); m[0] = xScale; m[5] = yScale; m[10] = zScale; } 498 | 499 | inline void m3dScaleMatrix44(M3DMatrix44d m, const M3DVector3d vScale) 500 | { m3dLoadIdentity44(m); m[0] = vScale[0]; m[5] = vScale[1]; m[10] = vScale[2]; } 501 | 502 | 503 | void m3dMakePerspectiveMatrix(M3DMatrix44f mProjection, float fFov, float fAspect, float zMin, float zMax); 504 | void m3dMakeOrthographicMatrix(M3DMatrix44f mProjection, float xMin, float xMax, float yMin, float yMax, float zMin, float zMax); 505 | 506 | 507 | // Create a Rotation matrix 508 | // Implemented in math3d.cpp 509 | void m3dRotationMatrix33(M3DMatrix33f m, float angle, float x, float y, float z); 510 | void m3dRotationMatrix33(M3DMatrix33d m, double angle, double x, double y, double z); 511 | void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z); 512 | void m3dRotationMatrix44(M3DMatrix44d m, double angle, double x, double y, double z); 513 | 514 | // Create a Translation matrix. Only 4x4 matrices have translation components 515 | inline void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z) 516 | { m3dLoadIdentity44(m); m[12] = x; m[13] = y; m[14] = z; } 517 | 518 | inline void m3dTranslationMatrix44(M3DMatrix44d m, double x, double y, double z) 519 | { m3dLoadIdentity44(m); m[12] = x; m[13] = y; m[14] = z; } 520 | 521 | void m3dInvertMatrix44(M3DMatrix44f mInverse, const M3DMatrix44f m); 522 | void m3dInvertMatrix44(M3DMatrix44d mInverse, const M3DMatrix44d m); 523 | 524 | /////////////////////////////////////////////////////////////////////////////// 525 | /////////////////////////////////////////////////////////////////////////////// 526 | /////////////////////////////////////////////////////////////////////////////// 527 | // Other Miscellaneous functions 528 | 529 | // Find a normal from three points 530 | // Implemented in math3d.cpp 531 | void m3dFindNormal(M3DVector3f result, const M3DVector3f point1, const M3DVector3f point2, 532 | const M3DVector3f point3); 533 | void m3dFindNormal(M3DVector3d result, const M3DVector3d point1, const M3DVector3d point2, 534 | const M3DVector3d point3); 535 | 536 | 537 | // Calculates the signed distance of a point to a plane 538 | inline float m3dGetDistanceToPlane(const M3DVector3f point, const M3DVector4f plane) 539 | { return point[0]*plane[0] + point[1]*plane[1] + point[2]*plane[2] + plane[3]; } 540 | 541 | inline double m3dGetDistanceToPlane(const M3DVector3d point, const M3DVector4d plane) 542 | { return point[0]*plane[0] + point[1]*plane[1] + point[2]*plane[2] + plane[3]; } 543 | 544 | 545 | // Get plane equation from three points 546 | void m3dGetPlaneEquation(M3DVector4f planeEq, const M3DVector3f p1, const M3DVector3f p2, const M3DVector3f p3); 547 | void m3dGetPlaneEquation(M3DVector4d planeEq, const M3DVector3d p1, const M3DVector3d p2, const M3DVector3d p3); 548 | 549 | // Determine if a ray intersects a sphere 550 | // Return value is < 0 if the ray does not intersect 551 | // Return value is 0.0 if ray is tangent 552 | // Positive value is distance to the intersection point 553 | double m3dRaySphereTest(const M3DVector3d point, const M3DVector3d ray, const M3DVector3d sphereCenter, double sphereRadius); 554 | float m3dRaySphereTest(const M3DVector3f point, const M3DVector3f ray, const M3DVector3f sphereCenter, float sphereRadius); 555 | 556 | 557 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 558 | // Faster (and one shortcut) replacements for gluProject 559 | void m3dProjectXY( M3DVector2f vPointOut, const M3DMatrix44f mModelView, const M3DMatrix44f mProjection, const int iViewPort[4], const M3DVector3f vPointIn); 560 | void m3dProjectXYZ(M3DVector3f vPointOut, const M3DMatrix44f mModelView, const M3DMatrix44f mProjection, const int iViewPort[4], const M3DVector3f vPointIn); 561 | 562 | 563 | ////////////////////////////////////////////////////////////////////////////////////////////////// 564 | // This function does a three dimensional Catmull-Rom "spline" interpolation between p1 and p2 565 | void m3dCatmullRom(M3DVector3f vOut, const M3DVector3f vP0, const M3DVector3f vP1, const M3DVector3f vP2, const M3DVector3f vP3, float t); 566 | void m3dCatmullRom(M3DVector3d vOut, const M3DVector3d vP0, const M3DVector3d vP1, const M3DVector3d vP2, const M3DVector3d vP3, double t); 567 | 568 | ////////////////////////////////////////////////////////////////////////////////////////////////// 569 | // Compare floats and doubles... 570 | inline bool m3dCloseEnough(const float fCandidate, const float fCompare, const float fEpsilon) 571 | { 572 | return (fabs(fCandidate - fCompare) < fEpsilon); 573 | } 574 | 575 | inline bool m3dCloseEnough(const double dCandidate, const double dCompare, const double dEpsilon) 576 | { 577 | return (fabs(dCandidate - dCompare) < dEpsilon); 578 | } 579 | 580 | //////////////////////////////////////////////////////////////////////////// 581 | // Used for normal mapping. Finds the tangent bases for a triangle... 582 | // Only a floating point implementation is provided. This has no practical use as doubles. 583 | void m3dCalculateTangentBasis(M3DVector3f vTangent, const M3DVector3f pvTriangle[3], const M3DVector2f pvTexCoords[3], const M3DVector3f N); 584 | 585 | //////////////////////////////////////////////////////////////////////////// 586 | // Smoothly step between 0 and 1 between edge1 and edge 2 587 | double m3dSmoothStep(const double edge1, const double edge2, const double x); 588 | float m3dSmoothStep(const float edge1, const float edge2, const float x); 589 | 590 | ///////////////////////////////////////////////////////////////////////////// 591 | // Planar shadow Matrix 592 | void m3dMakePlanarShadowMatrix(M3DMatrix44d proj, const M3DVector4d planeEq, const M3DVector3d vLightPos); 593 | void m3dMakePlanarShadowMatrix(M3DMatrix44f proj, const M3DVector4f planeEq, const M3DVector3f vLightPos); 594 | 595 | ///////////////////////////////////////////////////////////////////////////// 596 | // Closest point on a ray to another point in space 597 | double m3dClosestPointOnRay(M3DVector3d vPointOnRay, const M3DVector3d vRayOrigin, const M3DVector3d vUnitRayDir, 598 | const M3DVector3d vPointInSpace); 599 | 600 | float m3dClosestPointOnRay(M3DVector3f vPointOnRay, const M3DVector3f vRayOrigin, const M3DVector3f vUnitRayDir, 601 | const M3DVector3f vPointInSpace); 602 | 603 | #endif 604 | -------------------------------------------------------------------------------- /tools/CHiResTimer.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | HiResTimer.h 3 | 4 | Wrapper for the high-resolution timer. Can't be used if the hi-res timer 5 | doesn't exist. 6 | 7 | Author : Dave Astle 8 | Date : 2/1/2001 9 | 10 | Written for OpenGL Game Programming 11 | *****************************************************************************/ 12 | 13 | #ifndef __TIMER_H_INCLUDED__ 14 | #define __TIMER_H_INCLUDED__ 15 | 16 | #include 17 | 18 | 19 | class CHiResTimer 20 | { 21 | public: 22 | CHiResTimer() {} 23 | ~CHiResTimer() {} 24 | 25 | /***************************************************************************** 26 | Init() 27 | 28 | If the hi-res timer is present, the tick rate is stored and the function 29 | returns true. Otherwise, the function returns false, and the timer should 30 | not be used. 31 | *****************************************************************************/ 32 | bool Init() 33 | { 34 | if (!QueryPerformanceFrequency(&m_ticksPerSecond)) 35 | { 36 | // system doesn't support hi-res timer 37 | return false; 38 | } 39 | else 40 | { 41 | QueryPerformanceCounter(&m_startTime); 42 | return true; 43 | } 44 | } // end Init() 45 | 46 | 47 | float GetElapsedSeconds(unsigned long elapsedFrames = 1) 48 | { 49 | static LARGE_INTEGER s_lastTime = m_startTime; 50 | LARGE_INTEGER currentTime; 51 | 52 | QueryPerformanceCounter(¤tTime); 53 | 54 | float seconds = ((float)currentTime.QuadPart - (float)s_lastTime.QuadPart) / (float)m_ticksPerSecond.QuadPart; 55 | 56 | // reset the timer 57 | s_lastTime = currentTime; 58 | 59 | return seconds; 60 | } // end GetElapsedSeconds() 61 | 62 | 63 | /*************************************************************************** 64 | GetFPS() 65 | 66 | Returns the average frames per second over elapsedFrames, which defaults to 67 | one. If this is not called every frame, the client should track the number 68 | of frames itself, and reset the value after this is called. 69 | ***************************************************************************/ 70 | float GetFPS(unsigned long elapsedFrames = 1) 71 | { 72 | static LARGE_INTEGER s_lastTime = m_startTime; 73 | LARGE_INTEGER currentTime; 74 | 75 | QueryPerformanceCounter(¤tTime); 76 | 77 | float fps = (float)elapsedFrames * (float)m_ticksPerSecond.QuadPart / ((float)currentTime.QuadPart - (float)s_lastTime.QuadPart); 78 | 79 | // reset the timer 80 | s_lastTime = currentTime; 81 | 82 | return fps; 83 | } // end GetFPS 84 | 85 | 86 | /*************************************************************************** 87 | LockFPS() 88 | 89 | Used to lock the frame rate to a set amount. This will block until enough 90 | time has passed to ensure that the fps won't go over the requested amount. 91 | Note that this can only keep the fps from going above the specified level; 92 | it can still drop below it. It is assumed that if used, this function will 93 | be called every frame. The value returned is the instantaneous fps, which 94 | will be <= targetFPS. 95 | ***************************************************************************/ 96 | float LockFPS(unsigned char targetFPS) 97 | { 98 | if (targetFPS == 0) 99 | targetFPS = 1; 100 | 101 | static LARGE_INTEGER s_lastTime = m_startTime; 102 | LARGE_INTEGER currentTime; 103 | float fps; 104 | 105 | // delay to maintain a constant frame rate 106 | do { 107 | QueryPerformanceCounter(¤tTime); 108 | fps = (float)m_ticksPerSecond.QuadPart/((float)(currentTime.QuadPart - s_lastTime.QuadPart)); 109 | } while (fps > (float)targetFPS); 110 | 111 | // reset the timer 112 | s_lastTime = m_startTime; 113 | 114 | return fps; 115 | } // end LockFPS() 116 | 117 | 118 | private: 119 | LARGE_INTEGER m_startTime; 120 | LARGE_INTEGER m_ticksPerSecond; 121 | }; 122 | 123 | #endif // __TIMER_H_INCLUDED_ 124 | -------------------------------------------------------------------------------- /tools/CVector.h: -------------------------------------------------------------------------------- 1 | #ifndef __CVECTOR_H 2 | #define __CVECTOR_H 3 | 4 | #include 5 | 6 | 7 | typedef float scalar_t; 8 | 9 | class CVector 10 | { 11 | public: 12 | scalar_t x; 13 | scalar_t y; 14 | scalar_t z; // x,y,z coordinates 15 | 16 | public: 17 | CVector(scalar_t a = 0, scalar_t b = 0, scalar_t c = 0) : x(a), y(b), z(c) {} 18 | CVector(const CVector &vec) : x(vec.x), y(vec.y), z(vec.z) {} 19 | 20 | // vector assignment 21 | const CVector &operator=(const CVector &vec) 22 | { 23 | x = vec.x; 24 | y = vec.y; 25 | z = vec.z; 26 | 27 | return *this; 28 | } 29 | 30 | // vecector equality 31 | const bool operator==(const CVector &vec) const 32 | { 33 | return ((x == vec.x) && (y == vec.y) && (z == vec.z)); 34 | } 35 | 36 | // vecector inequality 37 | const bool operator!=(const CVector &vec) const 38 | { 39 | return !(*this == vec); 40 | } 41 | 42 | // vector add 43 | const CVector operator+(const CVector &vec) const 44 | { 45 | return CVector(x + vec.x, y + vec.y, z + vec.z); 46 | } 47 | 48 | // vector add (opposite of negation) 49 | const CVector operator+() const 50 | { 51 | return CVector(*this); 52 | } 53 | 54 | // vector increment 55 | const CVector& operator+=(const CVector& vec) 56 | { x += vec.x; 57 | y += vec.y; 58 | z += vec.z; 59 | return *this; 60 | } 61 | 62 | // vector subtraction 63 | const CVector operator-(const CVector& vec) const 64 | { 65 | return CVector(x - vec.x, y - vec.y, z - vec.z); 66 | } 67 | 68 | // vector negation 69 | const CVector operator-() const 70 | { 71 | return CVector(-x, -y, -z); 72 | } 73 | 74 | // vector decrement 75 | const CVector &operator-=(const CVector& vec) 76 | { 77 | x -= vec.x; 78 | y -= vec.y; 79 | z -= vec.z; 80 | 81 | return *this; 82 | } 83 | 84 | // scalar self-multiply 85 | const CVector &operator*=(const scalar_t &s) 86 | { 87 | x *= s; 88 | y *= s; 89 | z *= s; 90 | 91 | return *this; 92 | } 93 | 94 | // scalar self-divecide 95 | const CVector &operator/=(const scalar_t &s) 96 | { 97 | const float recip = 1/s; // for speed, one divecision 98 | 99 | x *= recip; 100 | y *= recip; 101 | z *= recip; 102 | 103 | return *this; 104 | } 105 | 106 | // post multiply by scalar 107 | const CVector operator*(const scalar_t &s) const 108 | { 109 | return CVector(x*s, y*s, z*s); 110 | } 111 | 112 | // pre multiply by scalar 113 | friend inline const CVector operator*(const scalar_t &s, const CVector &vec) 114 | { 115 | return vec*s; 116 | } 117 | 118 | /* friend inline const CVector operator*(const CVector &vec, const scalar_t &s) 119 | { 120 | return CVector(vec.x*s, vec.y*s, vec.z*s); 121 | } 122 | 123 | */ // divecide by scalar 124 | const CVector operator/(scalar_t s) const 125 | { 126 | s = 1/s; 127 | 128 | return CVector(s*x, s*y, s*z); 129 | } 130 | 131 | // cross product 132 | const CVector CrossProduct(const CVector &vec) const 133 | { 134 | return CVector(y*vec.z - z*vec.y, z*vec.x - x*vec.z, x*vec.y - y*vec.x); 135 | } 136 | 137 | // cross product 138 | const CVector operator^(const CVector &vec) const 139 | { 140 | return CVector(y*vec.z - z*vec.y, z*vec.x - x*vec.z, x*vec.y - y*vec.x); 141 | } 142 | 143 | // dot product 144 | const scalar_t DotProduct(const CVector &vec) const 145 | { 146 | return x*vec.x + y*vec.y + z*vec.z; 147 | } 148 | 149 | // dot product 150 | const scalar_t operator%(const CVector &vec) const 151 | { 152 | return x*vec.x + y*vec.y + z*vec.z; 153 | } 154 | 155 | 156 | // length of vector 157 | const scalar_t Length() const 158 | { 159 | return (scalar_t)sqrt((double)(x*x + y*y + z*z)); 160 | } 161 | 162 | // return the unit vector 163 | const CVector UnitVector() const 164 | { 165 | return (*this) / Length(); 166 | } 167 | 168 | // normalize this vector 169 | void Normalize() 170 | { 171 | (*this) /= Length(); 172 | } 173 | 174 | const scalar_t operator!() const 175 | { 176 | return sqrtf(x*x + y*y + z*z); 177 | } 178 | 179 | // return vector with specified length 180 | const CVector operator | (const scalar_t length) const 181 | { 182 | return *this * (length / !(*this)); 183 | } 184 | 185 | // set length of vector equal to length 186 | const CVector& operator |= (const float length) 187 | { 188 | return *this = *this | length; 189 | } 190 | 191 | // return angle between two vectors 192 | const float inline Angle(const CVector& normal) const 193 | { 194 | return acosf(*this % normal); 195 | } 196 | 197 | // reflect this vector off surface with normal vector 198 | const CVector inline Reflection(const CVector& normal) const 199 | { 200 | const CVector vec(*this | 1); // normalize this vector 201 | return (vec - normal * 2.0 * (vec % normal)) * !*this; 202 | } 203 | 204 | }; 205 | 206 | #endif --------------------------------------------------------------------------------