outdated: 30. Collision Detection

≯℡__Kan透↙ 提交于 2020-03-06 03:34:50

这段代码花了我近一周时间学习。

球体之间的相互碰撞,球体与墙面之间的相互碰撞,球体与木桩之间的相互碰撞。小键盘+/-控制球体的timestep,也就是速度。UP/DOWN/LEFT/RIGHT控制camera,W/S/A/D控制位移。

F2控制camera跟进某个小球,可观察小球的碰撞路径。

一、碰撞检测

  • 平面
  • 圆柱
  • 移动的球体

二、基础物理模型

三、特效

  • 爆炸模型(Using A Fin-Tree Billboard Method)
  • 音效(Using The Windows Multimedia Library)

四、文件

  • 分为五个文件

demo.cpp                   : Main code

Image.cpp, Image.h     : Code to load bitmaps

Tmatrix.cpp, Tmatrix.h : Classes to handle rotations

Tray.cpp, Tray.h           : Classes to handle ray operation

Tvector.cpp, Tvector.h   : Classes to handle vector opertation

一、碰撞检测

碰撞检测在这里使用光线追踪算法,定义的‘光线’是一个有方向的标准化向量,其方程为:

(1)、平面---与平面碰撞:

(点积)

Xn是平面的法线向量,X是表面的点向量,d是来自并行系统中心的一个浮点数,表示法线的距离。

如果光线相交于平面上的一些点,那么这些点满足:

转换,

替换d,

最终,

由TestIntersectionPlane()函数实现。

(2)、光线---与圆柱碰撞:

TestIntersectionCylinder()函数实现。

(3)、球---与球碰撞:

球体的定义只有一个点和半径。由FindBallCol()函数实现。

计算每次开始碰撞之间的时间,可用Dst(球体从开始点到结束点的距离),Dsc(球体从碰撞点到下一个碰撞点的距离),T(时间步长),Tc(每次碰撞之间的时间)来表示,即公式

二、基础物理模型

(1)、碰撞应答

计算碰撞点后的向量R,需要I(碰撞前的向量),N(碰撞点处的法线)。即公式,

(2)、球体相互碰撞

U1和U2是两个球体碰撞前的速率方向,U1x,U1y是球1在x轴和y轴方向的速率投影,同样U2x,U2y是球2在x轴和y轴方向的速率投影。在接触瞬间,两个球心的距离为X_Axis。

V1和V2是两个球体碰撞后的速率方向,V1X,V2X,V1Y,V2Y都是在x轴和y轴方向的速率投影。M1和M2是两个球体的质量。

(3)、模拟重力下(欧拉方程)

三、特效

(1)、爆炸

每次碰撞在碰撞点上都有爆炸效果。

(2)、声音

每次爆炸调用。

四、文件

Image.cpp中bmp图片的格式标准http://www.martinreddy.net/gfx/2d/BMP.txt

Tmatrix.cpp给出了矩阵的转置,求行列式,相加相减,相乘etc。

Tray.cpp说明球体运动的轨迹,是否碰撞etc。

Tvector.cpp说明球体轨迹的具体向量以及各种运算。

下面为代码,修改部分位于双行星号内。

 1 #ifndef mathex_h
 2 
 3 #define mathex_h
 4 
 5 #include <math.h>
 6 
 7 #define EPSILON 1.0e-8
 8 
 9 #define ZERO EPSILON
10 
11 #define M_PI 3.1415926535
12 
13 #define VC 1
14 
15 #if VC
16 
17 #define bool int
18 #define false 0
19 #define true !false
20 
21 #endif
22 
23 template <class T> inline T limit(const T &x, const T &lower, const T &upper)
24 {
25     if (x < lower)
26         return lower;
27     if (x > upper)
28         return upper;
29     return x;
30 }
31 
32 template <class T> inline T sqr(const T &x)
33 {
34     return x * x;
35 }
36 
37 template <class T> inline T RadToDeg(const T &rad)
38 {
39     return (rad * 180.0f) / M_PI;
40 }
41 
42 template <class T> inline T DegToRad(const T &deg)
43 {
44     return (deg * M_PI) / 180.0f;
45 }
46 
47 #endif
Mathex.h
 1 #ifndef image_h
 2 
 3 #define image_h
 4 
 5 struct Image {
 6     unsigned long sizeX;
 7     unsigned long sizeY;
 8     char* data;
 9 };
10 
11 int ImageLoad(char* filename, Image* image);
12 
13 #endif
Image.h
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include "image.h"
 4 
 5 static unsigned int getint(FILE *fp)
 6 {
 7   int c, c1, c2, c3;
 8 
 9   // Get 4 bytes
10   c = getc(fp);  
11   c1 = getc(fp);  
12   c2 = getc(fp);  
13   c3 = getc(fp);
14   
15   return ((unsigned int) c) +   
16     (((unsigned int) c1) << 8) + 
17     (((unsigned int) c2) << 16) +
18     (((unsigned int) c3) << 24);
19 }
20 
21 static unsigned int getshort(FILE *fp)
22 {
23     int c, c1;
24     // Get 2 bytes
25     c = getc(fp);  
26     c1 = getc(fp);
27     return ((unsigned int) c) + (((unsigned int) c1) << 8);
28  
29 }
30 
31 int ImageLoad(char *filename, Image *image) {
32     FILE *file;
33     unsigned long size;                 // size of the image in bytes.
34     unsigned long i;                    // standard counter.
35     unsigned short int planes;          // number of planes in image (must be 1) 
36     unsigned short int bpp;             // number of bits per pixel (must be 24)
37     char temp;                          // temporary color storage for bgr-rgb conversion
38 
39     /* make sure the file is there.*/
40     if ((file = fopen(filename, "rb"))==NULL) {
41       printf("File Not Found : %s\n",filename);
42       return 0;
43     }
44     fseek(file, 18, SEEK_CUR);
45 
46     image->sizeX = getint (file);
47     printf("Width of %s: %lu\n", filename, image->sizeX);
48     
49     image->sizeY = getint (file);
50     printf("Height of %s: %lu\n", filename, image->sizeY);
51     
52     size = image->sizeX * image->sizeY * 3;
53 
54     // Read the planes
55     planes = getshort(file);
56     if (planes != 1) {
57         printf("Planes from %s is not 1: %u\n", filename, planes);
58         return 0;
59     }
60 
61     // Read the bpp
62     bpp = getshort(file);
63     if (bpp != 24) {
64         printf("Bpp from %s is not 24: %u\n", filename, bpp);
65         return 0;
66     }
67     
68     fseek(file, 24, SEEK_CUR);
69     
70     image->data = (char*) malloc(size);
71     if (image->data == NULL) {
72         printf("Error allocating memory for color-corrected image data");
73         return 0;    
74     }
75 
76     if ((i = fread(image->data, size, 1, file)) != 1) {
77         printf("Error reading image data from %s.\n", filename);
78         return 0;
79     }
80 
81     for (i = 0; i < size; i += 3) {
82         temp = image->data[i];
83         image->data[i] = image->data[i + 2];
84         image->data[i + 2] = temp;
85     }
86     return 1;
87 }
Image.cpp
 1 #ifndef matrix_h
 2 
 3 #define matrix_h
 4 
 5 #include <iostream>
 6 #include "Mathex.h"
 7 
 8 class TVector;
 9 
10 class TMatrix33 {
11     // Stream
12     friend std::ostream& operator<<(std::ostream& out, const TMatrix33& o) { return o.write(out); }
13     friend std::istream& operator>>(std::istream& in, TMatrix33& o) { return o.read(in); }
14 
15 private:
16     double _Mx[3][3];
17 
18     // Input output
19     std::ostream& write(std::ostream& out) const;
20     std::istream& read(std::istream& in);
21 
22 public:
23     // Constructors
24     TMatrix33();
25     TMatrix33(double Phi, double Theta, double Psi);
26     TMatrix33(double mx00, double mx01, double mx02, double mx10, double mx11, double mx12, 
27         double mx20, double mx21, double mx22);
28 
29     // Selectors
30     double operator()(int Row, int Column) const { return _Mx[Row][Column]; }
31     double& operator()(int Row, int Column) { return _Mx[Row][Column]; }
32 
33     // Optimised artimtric methods
34     static TMatrix33& add(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result);
35     static TMatrix33& subtract(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result);
36     static TMatrix33& multiply(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result);
37     static TMatrix33& multiply(const TMatrix33& m1, const double& scale, TMatrix33& result);
38     static TVector& multiply(const TMatrix33& m1, const TVector& v, TVector& result);
39 
40     // Matrix arithmetic
41     TMatrix33& operator+=(const TMatrix33& m) { return add(*this, m, *this); }
42     TMatrix33& operator-=(const TMatrix33& m) { return subtract(*this, m, *this); }
43     TMatrix33& operator*=(const TMatrix33& m) { TMatrix33 tm(*this);  return multiply(tm, m, *this); }
44     TMatrix33& operator*=(const double& scale) { return multiply(*this, scale, *this); }
45 
46     TMatrix33& operator+(const TMatrix33& m) { TMatrix33 tm; return add(*this, m, tm); }
47     TMatrix33& operator-(const TMatrix33& m) { TMatrix33 tm; return subtract(*this, m, tm); }
48     TMatrix33& operator*(const TMatrix33& m) { TMatrix33 tm;  return multiply(*this, m, tm); }
49     TMatrix33& operator*(const double& scale) { TMatrix33 tm; return multiply(*this, scale, tm); }
50     
51     TVector operator*(const TVector& v) const;
52 
53     // Determinants
54     double determinant() const;
55     static double determinant(const TMatrix33& m) { return m.determinant(); }
56 
57     // Transpose
58     TMatrix33& transpose();
59     static TMatrix33& transpose(const TMatrix33& m, TMatrix33& result) { result = m; return result.transpose(); }
60     static TMatrix33 transpose(const TMatrix33& m) { return TMatrix33(m).transpose(); }
61 
62     // Inverse
63     static TMatrix33& TMatrix33::inverse(const TMatrix33& m1, TMatrix33& result);
64     static TMatrix33 TMatrix33::inverse(const TMatrix33& m1) { TMatrix33 tm; return inverse(m1, tm); }
65     TMatrix33 inverse() const { TMatrix33 tm; return inverse(*this, tm); }
66 };
67 
68 #endif
Tmatrix.h
  1 #include "Tmatrix.h"
  2 #include "Tvector.h"
  3 
  4 TMatrix33::TMatrix33()
  5 {
  6     _Mx[0][0] = 1.0; _Mx[0][1] = 0.0; _Mx[0][2] = 0.0;
  7     _Mx[1][0] = 0.0; _Mx[1][1] = 1.0; _Mx[1][2] = 0.0;
  8     _Mx[2][0] = 0.0; _Mx[2][1] = 0.0; _Mx[2][2] = 1.0;
  9 }
 10 
 11 TMatrix33::TMatrix33(double mx00, double mx01, double mx02, double mx10, 
 12     double mx11, double mx12, double mx20, double mx21, double mx22)
 13 {
 14     _Mx[0][0] = mx00; _Mx[0][1] = mx01; _Mx[0][2] = mx02;
 15     _Mx[1][0] = mx10; _Mx[1][1] = mx11; _Mx[1][2] = mx12;
 16     _Mx[2][0] = mx20; _Mx[2][1] = mx21; _Mx[2][2] = mx22;
 17 }
 18 
 19 TMatrix33::TMatrix33(double Phi, double Theta, double Psi)
 20 {
 21     double c1 = cos(Phi), s1 = sin(Phi), c2 = cos(Theta), s2 = sin(Theta), c3 = cos(Psi), s3 = sin(Psi);
 22 
 23     _Mx[0][0] = c2 * c3; _Mx[0][1] = -c2 * s3; _Mx[0][2] = s2;
 24     _Mx[1][0] = s1 * s2 * c3 + c1 * s3; _Mx[1][1] = -s1 * s2 * s3 + c1 * c3; _Mx[1][2] = -s1 * c2;
 25     _Mx[2][0] = -c1 * s2 * c3 + s1 * s3; _Mx[2][1] = c1 * s2 * s3 + s1 * c3; _Mx[2][2] = c1 * c2;
 26 }
 27 
 28 TMatrix33& TMatrix33::add(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result)
 29 {
 30     result._Mx[0][0] = m1._Mx[0][0] + m2._Mx[0][0];
 31     result._Mx[0][1] = m1._Mx[0][1] + m2._Mx[0][1];
 32     result._Mx[0][2] = m1._Mx[0][2] + m2._Mx[0][2];
 33 
 34     result._Mx[1][0] = m1._Mx[1][0] + m2._Mx[1][0];
 35     result._Mx[1][1] = m1._Mx[1][1] + m2._Mx[1][1];
 36     result._Mx[1][2] = m1._Mx[1][2] + m2._Mx[1][2];
 37 
 38     result._Mx[2][0] = m1._Mx[2][0] + m2._Mx[2][0];
 39     result._Mx[2][1] = m1._Mx[2][1] + m2._Mx[2][1];
 40     result._Mx[2][2] = m1._Mx[2][2] + m2._Mx[2][2];
 41     return result;
 42 }
 43 
 44 TMatrix33& TMatrix33::subtract(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result)
 45 {
 46     result._Mx[0][0] = m1._Mx[0][0] - m2._Mx[0][0];
 47     result._Mx[0][1] = m1._Mx[0][1] - m2._Mx[0][1];
 48     result._Mx[0][2] = m1._Mx[0][2] - m2._Mx[0][2];
 49 
 50     result._Mx[1][0] = m1._Mx[1][0] - m2._Mx[1][0];
 51     result._Mx[1][1] = m1._Mx[1][1] - m2._Mx[1][1];
 52     result._Mx[1][2] = m1._Mx[1][2] - m2._Mx[1][2];
 53 
 54     result._Mx[2][0] = m1._Mx[2][0] - m2._Mx[2][0];
 55     result._Mx[2][1] = m1._Mx[2][1] - m2._Mx[2][1];
 56     result._Mx[2][2] = m1._Mx[2][2] - m2._Mx[2][2];
 57     return result;
 58 }
 59 
 60 TMatrix33& TMatrix33::multiply(const TMatrix33& m1, const TMatrix33& m2, TMatrix33& result)
 61 {
 62     result._Mx[0][0] = m1._Mx[0][0] * m2._Mx[0][0] + m1._Mx[0][1] * m2._Mx[1][0] + m1._Mx[0][2] * m2._Mx[2][0];
 63     result._Mx[1][0] = m1._Mx[1][0] * m2._Mx[0][0] + m1._Mx[1][1] * m2._Mx[1][0] + m1._Mx[1][2] * m2._Mx[2][0];
 64     result._Mx[2][0] = m1._Mx[2][0] * m2._Mx[0][0] + m1._Mx[2][1] * m2._Mx[1][0] + m1._Mx[2][2] * m2._Mx[2][0];
 65 
 66     result._Mx[0][1] = m1._Mx[0][0] * m2._Mx[0][1] + m1._Mx[0][1] * m2._Mx[1][1] + m1._Mx[0][2] * m2._Mx[2][1];
 67     result._Mx[1][1] = m1._Mx[1][0] * m2._Mx[0][1] + m1._Mx[1][1] * m2._Mx[1][1] + m1._Mx[1][2] * m2._Mx[2][1];
 68     result._Mx[2][1] = m1._Mx[2][0] * m2._Mx[0][1] + m1._Mx[2][1] * m2._Mx[1][1] + m1._Mx[2][2] * m2._Mx[2][1];
 69 
 70     result._Mx[0][2] = m1._Mx[0][0] * m2._Mx[0][2] + m1._Mx[0][1] * m2._Mx[1][2] + m1._Mx[0][2] * m2._Mx[2][2];
 71     result._Mx[1][2] = m1._Mx[1][0] * m2._Mx[0][2] + m1._Mx[1][1] * m2._Mx[1][2] + m1._Mx[1][2] * m2._Mx[2][2];
 72     result._Mx[2][2] = m1._Mx[2][0] * m2._Mx[0][2] + m1._Mx[2][1] * m2._Mx[1][2] + m1._Mx[2][2] * m2._Mx[2][2];
 73     return result;
 74 }
 75 
 76 TMatrix33& TMatrix33::multiply(const TMatrix33& m1, const double& scale, TMatrix33& result)
 77 {
 78     result._Mx[0][0] = m1._Mx[0][0] * scale;
 79     result._Mx[0][1] = m1._Mx[0][1] * scale;
 80     result._Mx[0][2] = m1._Mx[0][2] * scale;
 81 
 82     result._Mx[1][0] = m1._Mx[1][0] * scale;
 83     result._Mx[1][1] = m1._Mx[1][1] * scale;
 84     result._Mx[1][2] = m1._Mx[1][2] * scale;
 85 
 86     result._Mx[2][0] = m1._Mx[2][0] * scale;
 87     result._Mx[2][1] = m1._Mx[2][1] * scale;
 88     result._Mx[2][2] = m1._Mx[2][2] * scale;
 89     return result;
 90 }
 91 
 92 TVector& TMatrix33::multiply(const TMatrix33& m1, const TVector& v, TVector& result)
 93 {
 94     result = TVector(
 95         m1._Mx[0][0] * v.X() + m1._Mx[0][1] * v.Y() + m1._Mx[0][2] * v.Z(),
 96         m1._Mx[1][0] * v.X() + m1._Mx[1][1] * v.Y() + m1._Mx[1][2] * v.Z(),
 97         m1._Mx[2][0] * v.X() + m1._Mx[2][1] * v.Y() + m1._Mx[2][2] * v.Z());
 98     return result;
 99 }
100 
101 double TMatrix33::determinant() const {
102     return _Mx[0][0] * (_Mx[1][1] * _Mx[2][2] - _Mx[1][2] * _Mx[2][1])
103         - _Mx[0][1] * (_Mx[1][0] * _Mx[2][2] - _Mx[1][2] * _Mx[2][0])
104         + _Mx[0][2] * (_Mx[1][0] * _Mx[2][1] - _Mx[1][1] * _Mx[2][0]);
105 }
106 
107 TMatrix33& TMatrix33::transpose() {
108     double t;
109     t = _Mx[0][2]; _Mx[0][2] = _Mx[2][0]; _Mx[2][0] = t;
110     t = _Mx[0][1]; _Mx[0][1] = _Mx[1][0]; _Mx[1][0] = t;
111     t = _Mx[1][2]; _Mx[1][2] = _Mx[2][1]; _Mx[2][1] = t;
112     return *this;
113 }
114 
115 TMatrix33& TMatrix33::inverse(const TMatrix33& m1, TMatrix33& result)
116 {
117     double det = m1.determinant();
118 
119     if (fabs(det) < EPSILON) {
120         result = TMatrix33();
121         return result;
122     }
123     else {
124         result._Mx[0][0] = m1._Mx[1][1] * m1._Mx[2][2] - m1._Mx[1][2] * m1._Mx[2][1];
125         result._Mx[0][1] = m1._Mx[2][1] * m1._Mx[0][2] - m1._Mx[2][2] * m1._Mx[0][1];
126         result._Mx[0][2] = m1._Mx[0][1] * m1._Mx[1][2] - m1._Mx[0][2] * m1._Mx[1][1];
127 
128         result._Mx[1][0] = m1._Mx[1][2] * m1._Mx[2][0] - m1._Mx[1][0] * m1._Mx[2][2];
129         result._Mx[1][1] = m1._Mx[2][2] * m1._Mx[0][0] - m1._Mx[2][0] * m1._Mx[0][2];
130         result._Mx[1][2] = m1._Mx[0][2] * m1._Mx[1][0] - m1._Mx[0][0] * m1._Mx[1][2];
131 
132         result._Mx[2][0] = m1._Mx[1][0] * m1._Mx[2][1] - m1._Mx[1][1] * m1._Mx[2][0];
133         result._Mx[2][1] = m1._Mx[2][0] * m1._Mx[0][1] - m1._Mx[2][1] * m1._Mx[0][0];
134         result._Mx[2][2] = m1._Mx[0][0] * m1._Mx[1][1] - m1._Mx[0][1] * m1._Mx[1][0];
135         return multiply(result, 1.0 / det, result);
136     }
137 }
138 
139 TVector TMatrix33::operator*(const TVector& v) const
140 {
141     TVector tv;
142     return multiply(*this, v, tv);
143 }
144 
145 std::ostream& TMatrix33::write(std::ostream& out) const
146 {
147     return out << "(" << _Mx[0][0] << "," << _Mx[0][1] << "," << _Mx[0][2] << ")" << std::endl
148         << "(" << _Mx[1][0] << "," << _Mx[1][1] << "," << _Mx[1][2] << ")" << std::endl
149         << "(" << _Mx[2][0] << "," << _Mx[2][1] << "," << _Mx[2][2] << ")" << std::endl;
150 }
151 
152 std::istream& TMatrix33::read(std::istream& in)
153 {
154     char ch;
155     return in >> ch >> _Mx[0][0] >> ch >> _Mx[0][1] >> ch >> _Mx[0][2] >> ch
156         >> ch >> _Mx[1][0] >> ch >> _Mx[1][1] >> ch >> _Mx[1][2] >> ch
157         >> ch >> _Mx[2][0] >> ch >> _Mx[2][1] >> ch >> _Mx[2][2] >> ch;
158 }
Tmatrix.cpp
 1 #ifndef tray_h
 2 
 3 #define tray_h
 4 
 5 #include <iostream>
 6 #include "Mathex.h"
 7 #include "Tvector.h"
 8 
 9 class TRay {
10     // Streaming
11     friend std::ostream& operator<<(std::ostream& out, const TRay& o) { return o.write(out); }
12     friend std::istream& operator>>(std::istream& in, TRay& o) { return o.read(in); }
13 
14 private:
15     TVector _P;    // Any point on the line
16     TVector _V;    // Direction of the line
17     
18     // Input and output
19     std::ostream& write(std::ostream& out) const;
20     std::istream& read(std::istream& in);
21 
22 public:
23     // Constructors
24     TRay() {}
25 
26     // Line between two points OR point and a direction
27     TRay(const TVector& point1, const TVector& point2);
28 
29     // Adjacent points on both lines
30     bool adjacentPoints(const TRay& ray, TVector& point1, TVector& point2) const;
31 
32     //Unary operator
33     static TRay& invert(const TRay& r, TRay& result) {
34         result._P = r._P; TVector::invert(r._V, result._V); return result;
35     }
36     TRay operator-() const { return invert(*this, TRay()); }
37 
38     // Selectors
39     TVector P() const { return _P; }
40     TVector V() const { return _V; }
41     int isValid() const { return V().isUnit() && P().isValid(); }
42 
43     // Distance
44     double dist(const TRay& ray) const;
45     double dist(const TVector& point) const;
46 };
47 
48 #endif
Tray.h
 1 #include <math.h>
 2 #include "Tray.h"
 3 #include "Mathex.h"
 4 
 5 // Line between two  point OR point and direction
 6 TRay::TRay(const TVector& point1, const TVector& point2) : _P(point1)
 7 {
 8     _V = (point2.isUnit() ? point2 : TVector::unit(point2 - point1));
 9 }
10 
11 bool TRay::adjacentPoints(const TRay& ray, TVector& point1, TVector& point2) const
12 {
13     if (isValid() && ray.isValid()) {
14         double temp = TVector::dot(_V, ray._V);
15         double temp2 = 1.0 - sqr(temp);
16         TVector tv;                    // Temporary vector to enable of optimised routines
17 
18         // Check for parallel rays
19         if (fabs(temp2) < EPSILON) {
20             double mu = TVector::dot(_V, _P - ray._P) / temp;
21             point1 = _P;
22             
23             TVector::add(ray._P, TVector::multiply(ray._V, mu, tv), point2);
24         }
25         else {
26             double a = TVector::dot(_V, TVector::subtract(ray._P, _P, tv));
27             double b = TVector::dot(ray._V, TVector::subtract(_P, ray._P, tv));
28             double mu = (b + temp * a) / temp2;
29             double lambda = (a + temp * b) / temp2;
30             TVector::add(_P, TVector::multiply(_V, lambda, tv), point1);
31             TVector::add(ray._P, TVector::multiply(ray._V, mu, tv), point2);
32         }
33         return true;
34     }
35     return false;
36 }
37 
38 // Distance between two rays
39 double TRay::dist(const TRay& ray) const
40 {
41     TVector point1, point2;
42 
43     if (adjacentPoints(ray, point1, point2))
44         return point1.dist(point2);
45     else
46         return 0.0;
47 }
48 
49 // Distance between a ray and a point
50 double TRay::dist(const TVector& point) const
51 {
52     if (isValid() && point.isValid()) {
53         TVector tv, point2;
54         double lambda = TVector::dot(_V, point - _P);
55 
56         TVector::add(_P, TVector::multiply(_V, lambda, tv), point2);
57         return point.dist(point2);
58     }
59     return 0.0;
60 }
61 
62 // Streaming
63 std::ostream& TRay::write(std::ostream& out) const
64 {
65     return isValid() ? out << "(p=" << _P << ",V=" << _V << ")" : out << "Invalid";
66 }
67 
68 std::istream& TRay::read(std::istream& in)
69 {
70     char buf[20], ch;
71 
72     in >> ch;
73     if (ch != 'I')
74         in >> ch >> ch >> _P >> ch >> ch >> _V;
75     else {
76         *this = TRay();
77         in.get(buf, 20, 'd');
78     }
79     return in >> ch;
80 }
Tray.cpp
 1 #ifndef tvector_h
 2 
 3 #define tvector_h
 4 
 5 #include <iostream>
 6 #include <math.h>
 7 #include "Mathex.h"
 8 
 9 class TRay;
10 
11 class TVector {
12     // Streaming
13 
14     friend std::ostream& operator<<(std::ostream& out, const TVector& o) { return o.write(out); }
15     friend std::istream& operator>>(std::istream& in, TVector& o) { return o.read(in); }
16 
17 public:
18     enum TStatus { INVALID, DEFAULT, UNIT };
19 
20 private:
21     double _x, _y, _z;
22     TStatus _Status;
23 
24     // Constructors
25     TVector(double x, double y, double z, TStatus s) : _x(x), _y(y), _z(z), _Status(s) {}
26 
27     // Input and output
28     std::ostream& write(std::ostream& out) const;
29     std::istream& read(std::istream& in);
30 
31 public:
32     // Constructors
33     TVector() : _x(0.0), _y(0.0), _z(0.0), _Status(INVALID) {}
34     TVector(double x, double y, double z) : _x(x), _y(y), _z(z), _Status(DEFAULT) {}
35 
36     // Mid Point between two lines
37     TVector(const TRay& line1, const TRay& line2);
38 
39     // Selectors
40     double X() const { return _x; }
41     double Y() const { return _y; }
42     double Z() const { return _z; }
43 
44     int isUnit() const { return _Status == UNIT; }
45     int isDefault() const { return _Status == DEFAULT; }
46     int isValid() const { return _Status != INVALID; }
47 
48     // Change the status of a vector
49     TVector& unit();
50     static TVector& unit(const TVector& v, TVector& result) { result = v; return result.unit(); }
51     static TVector unit(const TVector& v) { return TVector(v).unit(); }
52 
53     TVector& Default();
54     static TVector Default(const TVector& v, TVector& result) { result = v; return result.Default(); }
55     static TVector Default(const TVector& v) { return TVector(v).Default(); }
56 
57     // Magnitude
58     double mag() const { return (isValid() ? (isUnit() ? 1.0 : sqrt(sqr(X()) + sqr(Y()) + sqr(Z()))) : 0.0); }
59     double magSqr() const { return (isValid() ? (isUnit() ? 1.0 : sqr(X()) + sqr(Y()) + sqr(Z())) : 0.0); }
60 
61     // Dot or scalar product
62     double dot(const TVector& v) const {
63         return ((isValid() && isValid()) ? (X() * v.X() + Y() * v.Y() + Z() * v.Z()) : 0.0);
64     }
65     static double dot(const TVector& v1, const TVector& v2) { return v1.dot(v2); }
66 
67     //Distance between two vector
68     double dist(const TVector& v) const { return (*this - v).mag(); }
69     double sidtSqr(const TVector& v) const { return (*this - v).magSqr(); }
70 
71     // Optimised arithmetic methods
72     static TVector& invert(const TVector& v1, TVector& result);
73     static TVector& add(const TVector& v1, const TVector& v2, TVector& result);
74     static TVector& subtract(const TVector& v1, const TVector& v2, TVector& result);
75     static TVector& cross(const TVector& v1, const TVector& v2, TVector& result);
76     static TVector& multiply(const TVector& v1, const double& scale, TVector& result);
77 
78     // Vector arithmetic, addition, subtraction and vector product
79     TVector operator-(const TVector& v) const { TVector tv; return subtract(*this, v, tv); }
80     TVector operator+(const TVector& v) const { TVector tv; return add(*this, v, tv); }
81     TVector operator*(const TVector& v) const { TVector tv; return cross(*this, v, tv); }
82     TVector operator*(const double& scale) const { TVector tv; return multiply(*this, scale, tv); }
83     TVector& operator+=(const TVector& v) { return add(*this, v, *this); }
84     TVector& operator-=(const TVector& v) { return subtract(*this, v, *this); }
85     TVector& operator*=(const TVector& v) { TVector tv(*this); return cross(tv, v, *this); }
86     TVector& operator*=(const double& scale) { return multiply(*this, scale, *this); }
87     TVector operator-() const { return invert(*this, TVector()); }
88 };
89 #endif
Tvector.h
  1 #include "Tvector.h"
  2 #include "Tray.h"
  3 
  4 // Mid point between two rays
  5 TVector::TVector(const TRay& ray1, const TRay& ray2)
  6 {
  7     TVector point1, point2;
  8 
  9     if (ray1.adjacentPoints(ray2, point1, point2))
 10         *this = (point1 + point2) * 0.5;
 11     else
 12         *this = TVector();
 13 }
 14 
 15 // Make a unit vector
 16 TVector& TVector::unit()
 17 {
 18     if (isDefault()) {
 19         double rep = mag();
 20         if (rep < EPSILON) {
 21             _x = 0.0;
 22             _y = 0.0;
 23             _z = 0.0;
 24         }
 25         else {
 26             double temp = 1.0 / rep;
 27             _x *= temp;
 28             _y *= temp;
 29             _z *= temp;
 30         }
 31         _Status = UNIT;
 32     }
 33     return *this;
 34 }
 35 
 36 // Make a default vector
 37 TVector& TVector::Default()
 38 {
 39     if (isUnit())
 40         _Status = DEFAULT;
 41     return *this;
 42 }
 43 
 44 TVector& TVector::invert(const TVector& v1, TVector& result)
 45 {
 46     if (v1.isValid()) {
 47         result._x = -v1._x;
 48         result._y = -v1._y;
 49         result._z = -v1._z;
 50         result._Status = v1._Status;
 51     }
 52     else {
 53         result = TVector();
 54     }
 55     return result;
 56 }
 57 
 58 TVector& TVector::add(const TVector& v1, const TVector& v2, TVector& result)
 59 {
 60     if (v1.isValid() && v2.isValid()) {
 61         result._x = v1._x + v2._x;
 62         result._y = v1._y + v2._y;
 63         result._z = v1._z + v2._z;
 64         result._Status = DEFAULT;
 65     }
 66     else {
 67         result = TVector();
 68     }
 69     return result;
 70 }
 71 
 72 TVector& TVector::subtract(const TVector& v1, const TVector& v2, TVector& result)
 73 {
 74     if (v1.isValid() && v2.isValid()) {
 75         result._x = v1._x - v2._x;
 76         result._y = v1._y - v2._y;
 77         result._z = v1._z - v2._z;
 78         result._Status = DEFAULT;
 79     }
 80     else {
 81         result = TVector();
 82     }
 83     return result;
 84 }
 85 
 86 TVector& TVector::cross(const TVector& v1, const TVector& v2, TVector& result)
 87 {
 88     if (v1.isValid() && v2.isValid()) {
 89         result._x = v1._y * v2._z - v1._z * v2._y;
 90         result._y = v1._z * v2._x - v1._x * v2._z;
 91         result._z = v1._x * v2._y - v1._y * v2._x;
 92         result._Status = DEFAULT;
 93     }
 94     else {
 95         result = TVector();
 96     }
 97     return result;
 98 }
 99 
100 TVector& TVector::multiply(const TVector& v1, const double& scale, TVector& result)
101 {
102     if (v1.isValid()) {
103         result._x = v1._x * scale;
104         result._y = v1._y * scale;
105         result._z = v1._z * scale;
106         result._Status = DEFAULT;
107     }
108     else {
109         result = TVector();
110     }
111     return result;
112 }
113 
114 // Streaming
115 std:: ostream& TVector::write(std::ostream& out) const
116 {
117     if (isValid()) {
118         if (isUnit())
119             return out << "<" << X() << "," << Y() << "," << Z() << ">";
120         else
121             return out << "[" << X() << "," << Y() << "," << Z() << "]";
122     }
123     return out << "Invalid";
124 }
125 
126 std::istream& TVector::read(std::istream& in)
127 {
128     char buf[20], ch, ch2;
129     
130     in >> ch2;
131     if (ch2 != 'I') {
132         double x, y, z;
133         in >> x >> ch >> y >> ch >> z;
134         *this = TVector(x, y, z);
135 
136         if (ch2 == '<')
137             unit();
138     }
139     else {
140         *this = TVector();
141         in.get(buf, 20, 'd'); // Character stream, characters and  character with Stop sign 
142     }
143     return in >> ch;
144 }
Tvector.cpp
   1 /******************************************************************************************************************************************/
   2 /******************************************************************************************************************************************/
   3 #include <windows.h>
   4 #include <math.h>
   5 #include <stdio.h>
   6 #include <stdlib.h>
   7 #include <gl/glew.h>
   8 #include <GL\glut.h>
   9 #include "Tvector.h"
  10 #include "Tray.h"
  11 #include "Tmatrix.h"
  12 #include "Image.h"
  13 #include <mmsystem.h>
  14 
  15 #pragma comment(lib, "legacy_stdio_definitions.lib")
  16 
  17 /*
  18 *  Every OpenGL program is linked to a Rendering Context.
  19 *  A Rendering Context is what links OpenGL calls to the Device Context.
  20 *  In order for your program to draw to a Window you need to create a Device Context.
  21 *  The DC connects the Window to the GDI (Graphics Device Interface).
  22 */
  23 
  24 HGLRC     hRC = NULL;         // Permanent rendering context
  25 HDC       hDC = NULL;         // Private GDI device context
  26 HWND      hWnd = NULL;        // Holds our window handle
  27 HINSTANCE hInstance;          // Holds the instance of the application
  28 
  29 /*
  30 *  It's important to make this global so that each procedure knows if
  31 *  the program is running in fullscreen mode or not.
  32 */
  33 
  34 bool keys[256];         // Array used for the keyboard routine
  35 bool active = TRUE;     // Window active flag set to TRUE by default
  36 bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default
  37 
  38 DEVMODE DMsaved;        // Saves the previous sacreen settings
  39 
  40 GLfloat spec[] = { 1.0f, 1.0f, 1.0f, 1.0f };       // Specular highlight of balls
  41 GLfloat posl[] = { 0, 400, 0, 1 };                 // Position of light
  42 GLfloat amb[] = { 0.2f, 0.2f, 0.2f, 1.0f };        // Global ambient
  43 GLfloat amb2[] = { 0.3f, 0.3f, 0.3f, 1.0f };       // Ambient of lightsource
  44 
  45 GLfloat rotx;
  46 GLfloat position_x;
  47 
  48 TVector dir(0, 0, -10);                     // Initial direction of camera
  49 TVector pos(0, -50, 1000);                  // Initial position of camera
  50 float camera_rotation = 0;                  // Holds rotation around the Y aixs
  51 
  52 TVector veloc(0.5, -0.1, 0.5);              // Initial velocity of balls
  53 TVector accel(0, -0.05, 0);                 // acceleration ie. gravity of balls
  54 
  55 TVector ArrayVel[10];                       // Holds velocity of balls
  56 TVector ArrayPos[10];                       // Position of balls
  57 TVector OldPos[10];                         // Old position f balls
  58 int NrOfBalls;                              // Numbers of balls
  59 double Time = 0.6;                          // Timestep of simulation
  60 int hook_toball1 = 0;                       // Hook camera on ball
  61 int sounds = 1;                             // Sound on/off
  62 
  63 struct Plane {
  64     TVector    _Position;
  65     TVector _Normal;
  66 };
  67 
  68 struct Cylinder {
  69     TVector _Position;
  70     TVector _Axis;
  71     double _Radius;
  72 };
  73 
  74 struct Explosion {
  75     TVector _Position;
  76     float _Alpha;
  77     float _Scale;
  78 };
  79 
  80 Plane pl1, pl2, pl3, pl4, pl5;            // Room
  81 Cylinder cyl1, cyl2, cyl3;                // The 3 cylinder of the room
  82 GLUquadricObj* cylinder_obj;              // Quadratic object
  83 GLuint texture[4];                        // Stores texture objects
  84 GLuint displayList;                       // Display list
  85 Explosion ExplosionArray[20];             // Holds max 20 explosion ay once
  86 
  87 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc
  88 
  89                                                       /* Init variables */
  90 void InitVars()
  91 {
  92     // Create planes
  93     pl1._Position = TVector(0, -300, 0);
  94     pl1._Normal = TVector(0, 1, 0);
  95     pl2._Position = TVector(300, 0, 0);
  96     pl2._Normal = TVector(-1, 0, 0);
  97     pl3._Position = TVector(-300, 0, 0);
  98     pl3._Normal = TVector(1, 0, 0);
  99     pl4._Position = TVector(0, 0, 300);
 100     pl4._Normal = TVector(0, 0, -1);
 101     pl5._Position = TVector(0, 0, -300);
 102     pl5._Normal = TVector(0, 0, 1);
 103 
 104     // Create cylinders
 105     cyl1._Position = TVector(0, 0, 0);
 106     cyl1._Axis = TVector(0, 1, 0);
 107     cyl1._Radius = 60 + 20;
 108     cyl2._Position = TVector(200, -300, 0);
 109     cyl2._Axis = TVector(0, 0, 1);
 110     cyl2._Radius = 60 + 20;
 111     cyl3._Position = TVector(-200, 0, 0);
 112     cyl3._Axis = TVector(0, 1, 1);
 113     cyl3._Axis.unit();
 114     cyl3._Radius = 30 + 20;
 115 
 116     // Create quadratic object
 117     cylinder_obj = gluNewQuadric();
 118     gluQuadricTexture(cylinder_obj, GL_TRUE);
 119 
 120     // Set initial position and velocities of balls
 121     // alse initialize array which holds explosions
 122     NrOfBalls = 10;
 123 
 124     ArrayVel[0] = veloc;
 125     ArrayPos[0] = TVector(199, 180, 10);
 126     ExplosionArray[0]._Alpha = 0;
 127     ExplosionArray[0]._Scale = 1;
 128 
 129     ArrayVel[1] = veloc;
 130     ArrayPos[1] = TVector(0, 150, 100);
 131     ExplosionArray[1]._Alpha = 0;
 132     ExplosionArray[1]._Scale = 1;
 133 
 134     ArrayVel[2] = veloc;
 135     ArrayPos[2] = TVector(-100, 180, -100);
 136     ExplosionArray[2]._Alpha = 0;
 137     ExplosionArray[2]._Scale = 1;
 138 
 139     for (int i = 3; i<10; i++)
 140     {
 141         ArrayVel[i] = veloc;
 142         ArrayPos[i] = TVector(-500 + i * 75, 300, -500 + i * 50);
 143         ExplosionArray[i]._Alpha = 0;
 144         ExplosionArray[i]._Scale = 1;
 145     }
 146     for (int i = 10; i<20; i++)
 147     {
 148         ExplosionArray[i]._Alpha = 0;
 149         ExplosionArray[i]._Scale = 1;
 150     }
 151 }
 152 
 153 /* Find if any of the current balls intersect with each other in the current timestep*/
 154 /* Return the index of the 2 intersecting balls, the point and time of intersecting. */
 155 int FindBallCol(TVector& point, double& TimePoint, double& Time2, int& BallNr1, int& BallNr2)
 156 {
 157     TVector RelativeV;
 158     TRay rays;
 159     double MyTime = 0.0;
 160     double Add = Time2 / 150.0;
 161     double Timedummy = 10000;
 162     double Timedummy2 = -1;
 163     TVector posi;
 164 
 165     // Test all balls against each other in 150 small steps
 166     for (int i = 0; i < NrOfBalls - 1; ++i) {
 167         for (int j = i + 1; j < NrOfBalls; ++j) {
 168             RelativeV = ArrayVel[i] - ArrayVel[j];
 169             rays = TRay(OldPos[i], TVector::unit(RelativeV));
 170             MyTime = 0.0;
 171 
 172             if ((rays.dist(OldPos[j])) > 40)
 173                 continue;
 174             while (MyTime < Time2) {
 175                 MyTime += Add;
 176                 posi = OldPos[i] + RelativeV * MyTime;
 177                 if (posi.dist(OldPos[j]) <= 40) {
 178                     point = posi;
 179                     if ((MyTime - Add) < Timedummy)
 180                         Timedummy = MyTime - Add;
 181                     BallNr1 = i;
 182                     BallNr2 = j;
 183                     break;
 184                 }
 185             }
 186         }
 187     }
 188     if (Timedummy != 10000) {
 189         TimePoint = Timedummy;
 190         return 1;
 191     }
 192     return 0;
 193 }
 194 
 195 // Fast intersection function between ray/plane
 196 int TestIntersectionPlane(const Plane& plane, const TVector& position, const TVector& direction,
 197     double& lambda, TVector& pNormal)
 198 {
 199     double DotProduct = direction.dot(plane._Normal);
 200     double l2;
 201 
 202     // Determine if ray paralle to plane
 203     if ((DotProduct < ZERO) && (DotProduct > -ZERO))
 204         return 0;
 205 
 206     l2 = (plane._Normal.dot(plane._Position - position)) / DotProduct;
 207 
 208     if (l2 < -ZERO)
 209         return 0;
 210     pNormal = plane._Normal;
 211     lambda = l2;
 212     return 1;
 213 }
 214 
 215 /* Fast intersection function between ray/cylinder */
 216 int TestIntersectionCylinder(const Cylinder& cylinder, const TVector& position, const TVector& direction,
 217     double& lambda, TVector& pNormal, TVector& newposition)
 218 {
 219     TVector RC;
 220     double d;
 221     double t, s;
 222     TVector n, D, O;
 223     double ln;
 224     double in, out;
 225 
 226     TVector::subtract(position, cylinder._Position, RC);
 227     TVector::cross(direction, cylinder._Axis, n);
 228 
 229     ln = n.mag();
 230     if ((ln < ZERO) && (ln > -ZERO))
 231         return 0;
 232 
 233     n.unit();
 234     d = fabs(RC.dot(n));
 235 
 236     if (d <= cylinder._Radius) {
 237         TVector::cross(RC, cylinder._Axis, O);
 238         t = -O.dot(n) / ln;
 239         TVector::cross(n, cylinder._Axis, O);
 240         O.unit();
 241         s = fabs(sqrt(cylinder._Radius*cylinder._Radius - d * d) / direction.dot(O));
 242 
 243         in = t - s;
 244         out = t + s;
 245         if (in < -ZERO) {
 246             if (out < -ZERO)
 247                 return 0;
 248             else
 249                 lambda = out;
 250         }
 251         else {
 252             if (out<-ZERO) {
 253                 lambda = in;
 254             }
 255             else {
 256                 if (in<out)
 257                     lambda = in;
 258                 else
 259                     lambda = out;
 260             }
 261         }
 262         newposition = position + direction * lambda;
 263         TVector HB = newposition - cylinder._Position;
 264         pNormal = HB - cylinder._Axis * (HB.dot(cylinder._Axis));
 265         pNormal.unit();
 266         return 1;
 267     }
 268     return 0;
 269 }
 270 
 271 /* Main loop of simulation moves. finds the collisions */
 272 /* and responses of the objects in the current time step */
 273 void idle()
 274 {
 275     double rt, rt2, rt4, lambda = 10000;
 276     TVector norm, uveloc;
 277     TVector normal, point, time;
 278     double RestTime, BallTime;
 279     TVector Pos2;
 280     int BallNr = 0;
 281     int dummy = 0;
 282     int BallColNr1, BallColNr2;
 283     TVector Nc;
 284 
 285     RestTime = Time;
 286     lambda = 10000;
 287 
 288     // Compute velocity for next tiemstep using Euler equation
 289     for (int j = 0; j < NrOfBalls; ++j)
 290         ArrayVel[j] += accel * RestTime;
 291 
 292     // While timestep not over
 293     while (RestTime > ZERO) {
 294         lambda = 10000;
 295         // For all the balls find closest intersection between balls and planes/cylinders
 296         for (int i = 0; i < NrOfBalls; ++i) {
 297             // Compute new position and distance
 298             OldPos[i] = ArrayPos[i];
 299             TVector::unit(ArrayVel[i], uveloc);
 300             ArrayPos[i] = ArrayPos[i] + ArrayVel[i] * RestTime;
 301             rt2 = OldPos[i].dist(ArrayPos[i]);
 302 
 303             // Test if collision occured between ball and ball 5 planes
 304             if (TestIntersectionPlane(pl1, OldPos[i], uveloc, rt, norm)) {
 305                 // Find intersection time
 306                 rt4 = rt * RestTime / rt2;
 307                 // If smaller than the one already stored replace and in tiemstep
 308                 if (rt4 <= lambda) {
 309                     if (rt4 <= RestTime + ZERO) {
 310                         if (!((rt < ZERO) && (uveloc.dot(norm) > ZERO))) {
 311                             normal = norm;
 312                             point = OldPos[i] + uveloc * rt;
 313                             lambda = rt4;
 314                             BallNr = i;
 315                         }
 316                     }
 317                 }
 318             }
 319             if (TestIntersectionPlane(pl2, OldPos[i], uveloc, rt, norm)) {
 320                 rt4 = rt * RestTime / rt2;
 321                 if (rt4 <= lambda) {
 322                     if (rt4 <= RestTime + ZERO) {
 323                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO)))
 324                         {
 325                             normal = norm;
 326                             point = OldPos[i] + uveloc * rt;
 327                             lambda = rt4;
 328                             BallNr = i;
 329                             dummy = 1;
 330                         }
 331                     }
 332                 }
 333             }
 334             if (TestIntersectionPlane(pl3, OldPos[i], uveloc, rt, norm)) {
 335                 rt4 = rt*RestTime / rt2;
 336                 if (rt4 <= lambda) {
 337                     if (rt4 <= RestTime + ZERO) {
 338                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 339                             normal = norm;
 340                             point = OldPos[i] + uveloc * rt;
 341                             lambda = rt4;
 342                             BallNr = i;
 343                         }
 344                     }
 345                 }
 346             }
 347             if (TestIntersectionPlane(pl4, OldPos[i], uveloc, rt, norm)) {
 348                 rt4 = rt*RestTime / rt2;
 349                 if (rt4 <= lambda) {
 350                     if (rt4 <= RestTime + ZERO) {
 351                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 352                             normal = norm;
 353                             point = OldPos[i] + uveloc * rt;
 354                             lambda = rt4;
 355                             BallNr = i;
 356                         }
 357                     }
 358                 }
 359             }
 360             if (TestIntersectionPlane(pl5, OldPos[i], uveloc, rt, norm)) {
 361                 rt4 = rt*RestTime / rt2;
 362                 if (rt4 <= lambda) {
 363                     if (rt4 <= RestTime + ZERO) {
 364                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 365                             normal = norm;
 366                             point = OldPos[i] + uveloc * rt;
 367                             lambda = rt4;
 368                             BallNr = i;
 369                         }
 370                     }
 371                 }
 372             }
 373             // Now test intersection with the 3 cylinders
 374             if (TestIntersectionCylinder(cyl1, OldPos[i], uveloc, rt, norm, Nc)) {
 375                 rt4 = rt * RestTime / rt2;
 376                 if (rt4 <= lambda) {
 377                     if (rt4 <= RestTime + ZERO) {
 378                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 379                             normal = norm;
 380                             point = Nc;
 381                             lambda = rt4;
 382                             BallNr = i;
 383                         }
 384                     }
 385                 }
 386             }
 387             if (TestIntersectionCylinder(cyl2, OldPos[i], uveloc, rt, norm, Nc)) {
 388                 rt4 = rt * RestTime / rt2;
 389                 if (rt4 <= lambda) {
 390                     if (rt4 <= RestTime + ZERO) {
 391                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 392                             normal = norm;
 393                             point = Nc;
 394                             lambda = rt4;
 395                             BallNr = i;
 396                         }
 397                     }
 398                 }
 399             }
 400             if (TestIntersectionCylinder(cyl3, OldPos[i], uveloc, rt, norm, Nc)) {
 401                 rt4 = rt * RestTime / rt2;
 402                 if (rt4 <= lambda) {
 403                     if (rt4 <= RestTime + ZERO) {
 404                         if (!((rt <= ZERO) && (uveloc.dot(norm)>ZERO))) {
 405                             normal = norm;
 406                             point = Nc;
 407                             lambda = rt4;
 408                             BallNr = i;
 409                         }
 410                     }
 411                 }
 412             }
 413         }
 414         // After all balls were teste with planes/cylinder test for collision
 415         // between them and replace if collision time smaller
 416         if (FindBallCol(Pos2, BallTime, RestTime, BallColNr1, BallColNr2)) {
 417             if (sounds)
 418                 PlaySound("Data/Explode.wav", NULL, SND_FILENAME | SND_ASYNC);
 419             if ((lambda == 10000) || (lambda > BallTime)) {
 420                 RestTime = RestTime - BallTime;
 421 
 422                 TVector pb1, pb2, xaxis, U1x, U1y, U2x, U2y, V1x, V1y, V2x, V2y;
 423                 double a, b;
 424 
 425                 pb1 = OldPos[BallColNr1] + ArrayVel[BallColNr1] * BallTime;
 426                 pb2 = OldPos[BallColNr2] + ArrayVel[BallColNr2] * BallTime;
 427                 xaxis = (pb2 - pb1).unit();
 428 
 429                 a = xaxis.dot(ArrayVel[BallColNr1]);
 430                 U1x = xaxis * a;
 431                 U1y = ArrayVel[BallColNr1] - U1x;
 432 
 433                 xaxis = (pb1 - pb2).unit();
 434                 b = xaxis.dot(ArrayVel[BallColNr2]);
 435                 U2x = xaxis * b;
 436                 U2y = ArrayVel[BallColNr2] - U2x;
 437 
 438                 V1x = (U1x + U2x - (U1x - U2x)) * 0.5;
 439                 V2x = (U1x + U2x - (U2x - U1x)) * 0.5;
 440                 V1y = U1y;
 441                 V2y = U2y;
 442 
 443                 for (int j = 0; j < NrOfBalls; j++)
 444                     ArrayPos[j] = OldPos[j] + ArrayVel[j] * BallTime;
 445 
 446                 ArrayVel[BallColNr1] = V1x + V1y;
 447                 ArrayVel[BallColNr2] = V2x + V2y;
 448 
 449                 // Update explosion array
 450                 for (int j = 0; j < 20; j++) {
 451                     if (ExplosionArray[j]._Alpha <= 0) {
 452                         ExplosionArray[j]._Alpha = 1;
 453                         ExplosionArray[j]._Position = ArrayPos[BallColNr1];
 454                         ExplosionArray[j]._Scale = 1;
 455                         break;
 456                     }
 457                 }
 458                 continue;
 459             }
 460         }
 461         // End of tests 
 462         // If test occured move simulation for the correct timestep
 463         // and compute response for the colliding ball
 464         if (lambda != 10000)
 465         {
 466             RestTime -= lambda;
 467 
 468             for (int j = 0; j < NrOfBalls; j++)
 469                 ArrayPos[j] = OldPos[j] + ArrayVel[j] * lambda;
 470 
 471             rt2 = ArrayVel[BallNr].mag();
 472             ArrayVel[BallNr].unit();
 473             ArrayVel[BallNr] = TVector::unit((normal * (2 * normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr]);
 474             ArrayVel[BallNr] = ArrayVel[BallNr] * rt2;
 475 
 476             // Update explosion array
 477             for (int j = 0; j < 20; j++) {
 478                 if (ExplosionArray[j]._Alpha <= 0) {
 479                     ExplosionArray[j]._Alpha = 1;
 480                     ExplosionArray[j]._Position = point;
 481                     ExplosionArray[j]._Scale = 1;
 482                     break;
 483                 }
 484             }
 485         }
 486         else {
 487             RestTime = 0;
 488         }
 489     }
 490 }
 491 
 492 /* Load bitmaps and convert to textures */
 493 void LoadGLTextures()
 494 {
 495     Image *image1, *image2, *image3, *image4;
 496 
 497     // allocate space for texture
 498     image1 = (Image *)malloc(sizeof(Image));
 499     image2 = (Image *)malloc(sizeof(Image));
 500     image3 = (Image *)malloc(sizeof(Image));
 501     image4 = (Image *)malloc(sizeof(Image));
 502     if (image1 == NULL || image2 == NULL || image3 == NULL || image4 == NULL) {
 503         printf("Error allocating space for image");
 504         exit(0);
 505     }
 506 
 507     if (!ImageLoad("data/marble.bmp", image1) || !ImageLoad("data/spark.bmp", image2) ||
 508         !ImageLoad("data/boden.bmp", image3) || !ImageLoad("data/wand.bmp", image4)) {
 509         exit(1);
 510     }
 511 
 512     glGenTextures(2, &texture[0]);
 513     glBindTexture(GL_TEXTURE_2D, texture[0]);
 514 
 515     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 516     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 517     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 518     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 519 
 520     glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
 521 
 522     glBindTexture(GL_TEXTURE_2D, texture[1]);
 523 
 524     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 525     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 526     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 527     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 528 
 529     glTexImage2D(GL_TEXTURE_2D, 0, 3, image2->sizeX, image2->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image2->data);
 530 
 531 
 532     glGenTextures(2, &texture[2]);
 533     glBindTexture(GL_TEXTURE_2D, texture[2]);
 534 
 535     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 536     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 537     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 538     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 539 
 540     glTexImage2D(GL_TEXTURE_2D, 0, 3, image3->sizeX, image3->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image3->data);
 541 
 542     glBindTexture(GL_TEXTURE_2D, texture[3]);
 543 
 544     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 545     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 546     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
 547     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 548 
 549     glTexImage2D(GL_TEXTURE_2D, 0, 3, image4->sizeX, image4->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image4->data);
 550 
 551     free(image1->data);
 552     free(image1);
 553     free(image2->data);
 554     free(image2);
 555     free(image3->data);
 556     free(image3);
 557     free(image4->data);
 558     free(image4);
 559 }
 560 
 561 int ProcessKeys()
 562 {
 563     if (keys['W'])
 564         pos += TVector(0, 0, -1);
 565     if (keys['S'])
 566         pos += TVector(0, 0, 1);
 567     if (keys['A']) 
 568         position_x += 1;
 569     if (keys['D'])
 570         position_x -= 1;
 571     if (keys[VK_UP])
 572         rotx += 0.1;
 573     if (keys[VK_DOWN])
 574         rotx -= 0.1;
 575     if (keys[VK_LEFT])
 576         camera_rotation += 0.1;
 577     if (keys[VK_RIGHT])
 578         camera_rotation -= 0.1;
 579     if (keys[VK_ADD]) {
 580         Time += 0.1;
 581         if (Time >= 10.0)
 582             Time = 10.0;
 583         keys[VK_ADD] = FALSE;
 584     }
 585     if (keys[VK_SUBTRACT]) {
 586         Time -= 0.1;
 587         if (Time <= 0.1)
 588             Time = 0.0;
 589         keys[VK_SUBTRACT] = FALSE;
 590     }
 591     if (keys[VK_F3]) {
 592         sounds ^= 1;
 593         keys[VK_F3] = FALSE;
 594     }
 595     if (keys[VK_F2]) {
 596         hook_toball1 ^= 1;
 597         camera_rotation = 0;
 598         keys[VK_F2] = FALSE;
 599     }
 600     return 1;
 601 }
 602 
 603 
 604 /******************************************************************************************************************************************/
 605 /******************************************************************************************************************************************/
 606 GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // Resize and initialize the GL window
 607 {
 608     if (height == 0) {                                // Prevent a divide by zero by
 609         height = 1;                                   // Making height equal one
 610     }
 611 
 612     glViewport(0, 0, width, height);                  // Reset the current viewport
 613 
 614     /*
 615     *  The following lines set the screen up for a perspective view.
 616     *  Meaning things in the distance get smaller. This creates a realistic looking scene.
 617     *  The perspective is calculated with a 45 degree viewing angle based on
 618     *  the windows width and height. The 0.1f, 100.0f is the starting point and
 619     *  ending point for how deep we can draw into the screen.
 620     *
 621     *  The projection matrix is responsible for adding perspective to our scene.
 622     *  glLoadIdentity() restores the selected matrix to it's original state.
 623     *  The modelview matrix is where our object information is stored.
 624     *   Lastly we reset the modelview matrix.
 625     */
 626 
 627     glMatrixMode(GL_PROJECTION);                      // Select the projection matrix
 628     glLoadIdentity();                                 // Reset the projection matrix
 629 
 630                                                       // Calculate the aspect ratio of the window
 631     gluPerspective(50.0f, (GLfloat)width / (GLfloat)height, 10.0f, 1700.0f);
 632     //    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);  // Create orhto 640X480 view (0, 0, at the top)
 633 
 634     glMatrixMode(GL_MODELVIEW);                       // Seclet the modelview matrix
 635     glLoadIdentity();                                 // Reset the modelview matrix
 636 }
 637 /******************************************************************************************************************************************/
 638 /******************************************************************************************************************************************/
 639 
 640 int InitGL(GLvoid)                                    // All setup for OpenGL goes here
 641 {
 642     float df = 100.0f;
 643 
 644     glClearDepth(1.0f);                               // Depth buffer setup
 645     glEnable(GL_DEPTH_TEST);
 646     glDepthFunc(GL_LEQUAL);
 647     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
 648 
 649     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);             // Background
 650     glMatrixMode(GL_MODELVIEW);
 651     glLoadIdentity();
 652 
 653     glShadeModel(GL_SMOOTH);
 654     glEnable(GL_CULL_FACE);
 655     glEnable(GL_DEPTH_TEST);
 656 
 657     glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
 658     glMaterialfv(GL_FRONT, GL_SHININESS, &df);
 659 
 660     glEnable(GL_LIGHTING);
 661     glLightfv(GL_LIGHT0, GL_POSITION, posl);
 662     glLightfv(GL_LIGHT0, GL_AMBIENT, amb2);
 663     glEnable(GL_LIGHT0);
 664 
 665     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
 666     glEnable(GL_COLOR_MATERIAL);
 667     glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 668 
 669     glEnable(GL_BLEND);
 670     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 671 
 672     glEnable(GL_TEXTURE_2D);
 673     LoadGLTextures();
 674 
 675     // Construct billboared explosion primitive as display list
 676     // 4 quads at right angles to each other
 677     glNewList(displayList = glGenLists(1), GL_COMPILE);
 678     glBegin(GL_QUADS);
 679     glRotatef(-45, 0, 1, 0);
 680     glNormal3f(0, 0, 1);
 681     glTexCoord2f(0.0f, 0.0f); glVertex3f(-50, -40, 0);
 682     glTexCoord2f(0.0f, 1.0f); glVertex3f(50, -40, 0);
 683     glTexCoord2f(1.0f, 1.0f); glVertex3f(50, 40, 0);
 684     glTexCoord2f(1.0f, 0.0f); glVertex3f(-50, 40, 0);
 685     glNormal3f(0, 0, -1);
 686     glTexCoord2f(0.0f, 0.0f); glVertex3f(-50, 40, 0);
 687     glTexCoord2f(0.0f, 1.0f); glVertex3f(50, 40, 0);
 688     glTexCoord2f(1.0f, 1.0f); glVertex3f(50, -40, 0);
 689     glTexCoord2f(1.0f, 0.0f); glVertex3f(-50, -40, 0);
 690 
 691     glNormal3f(1, 0, 0);
 692     glTexCoord2f(0.0f, 0.0f); glVertex3f(0, -40, 50);
 693     glTexCoord2f(0.0f, 1.0f); glVertex3f(0, -40, -50);
 694     glTexCoord2f(1.0f, 1.0f); glVertex3f(0, 40, -50);
 695     glTexCoord2f(1.0f, 0.0f); glVertex3f(0, 40, 50);
 696     glNormal3f(-1, 0, 0);
 697     glTexCoord2f(0.0f, 0.0f); glVertex3f(0, 40, 50);
 698     glTexCoord2f(0.0f, 1.0f); glVertex3f(0, 40, -50);
 699     glTexCoord2f(1.0f, 1.0f); glVertex3f(0, -40, -50);
 700     glTexCoord2f(1.0f, 0.0f); glVertex3f(0, -40, 50);
 701     glEnd();
 702     glEndList();
 703 
 704     return TRUE;
 705 }
 706 
 707 /*
 708 *  For now all we will do is clear the screen to the color we previously decided on,
 709 *  clear the depth buffer and reset the scene. We wont draw anything yet.
 710 */
 711 bool DrawGLScene(GLvoid)                                  // Here's where we do all the drawing
 712 {
 713     glMatrixMode(GL_MODELVIEW);
 714     glLoadIdentity();
 715 
 716     // Set camera in hookhmode
 717     if (hook_toball1) {
 718         TVector unit_followvector = ArrayVel[0];
 719         unit_followvector.unit();
 720         gluLookAt(ArrayPos[0].X() + 250, ArrayPos[0].Y() + 250, ArrayPos[0].Z(),
 721             ArrayPos[0].X() + ArrayVel[0].X(), ArrayPos[0].Y() + ArrayVel[0].Y(),
 722             ArrayPos[0].Z() + ArrayVel[0].Z(), 0, 1, 0);
 723     }
 724     else {
 725         gluLookAt(pos.X(), pos.Y(), pos.Z(), pos.X() + dir.X(), pos.Y() + dir.Y(),
 726             pos.Z() + dir.Z(), 0.0, 1.0, 0.0);
 727     }
 728 
 729     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 730     glRotatef(camera_rotation, 0, 1, 0);
 731     glRotatef(rotx, 1, 0, 0);
 732     glTranslatef(position_x, 0, 0);
 733     // Render balls
 734     for (int i = 0; i < NrOfBalls; ++i) {
 735         switch (i) {
 736         case 1: glColor3f(1.0f, 1.0f, 1.0f); break;
 737         case 2: glColor3f(1.0f, 1.0f, 0.0f); break;
 738         case 3: glColor3f(0.0f, 1.0f, 1.0f); break;
 739         case 4: glColor3f(0.0f, 1.0f, 0.0f); break;
 740         case 5: glColor3f(0.0f, 0.0f, 1.0f); break;
 741         case 6: glColor3f(0.65f, 0.2f, 0.3f); break;
 742         case 7: glColor3f(1.0f, 0.0f, 1.0f); break;
 743         case 8: glColor3f(0.0f, 0.7f, 0.4f); break;
 744         default: glColor3f(1.0f, 0, 0);
 745         }
 746         glPushMatrix();
 747         glTranslated(ArrayPos[i].X(), ArrayPos[i].Y(), ArrayPos[i].Z());
 748         gluSphere(cylinder_obj, 20, 20, 20);
 749         glPopMatrix();
 750     }
 751 
 752     glEnable(GL_TEXTURE_2D);
 753 
 754     // Render walls with texture
 755     glBindTexture(GL_TEXTURE_2D, texture[3]);
 756     glColor3f(1, 1, 1);
 757     glBegin(GL_QUADS);
 758     glTexCoord2f(1.0f, 0.0f); glVertex3f(320, 320, 320);
 759     glTexCoord2f(1.0f, 1.0f); glVertex3f(320, -320, 320);
 760     glTexCoord2f(0.0f, 1.0f); glVertex3f(-320, -320, 320);
 761     glTexCoord2f(0.0f, 0.0f); glVertex3f(-320, 320, 320);
 762 
 763     glTexCoord2f(1.0f, 0.0f); glVertex3f(-320, 320, -320);
 764     glTexCoord2f(1.0f, 1.0f); glVertex3f(-320, -320, -320);
 765     glTexCoord2f(0.0f, 1.0f); glVertex3f(320, -320, -320);
 766     glTexCoord2f(0.0f, 0.0f); glVertex3f(320, 320, -320);
 767 
 768     glTexCoord2f(1.0f, 0.0f); glVertex3f(320, 320, -320);
 769     glTexCoord2f(1.0f, 1.0f); glVertex3f(320, -320, -320);
 770     glTexCoord2f(0.0f, 1.0f); glVertex3f(320, -320, 320);
 771     glTexCoord2f(0.0f, 0.0f); glVertex3f(320, 320, 320);
 772 
 773     glTexCoord2f(1.0f, 0.0f); glVertex3f(-320, 320, 320);
 774     glTexCoord2f(1.0f, 1.0f); glVertex3f(-320, -320, 320);
 775     glTexCoord2f(0.0f, 1.0f); glVertex3f(-320, -320, -320);
 776     glTexCoord2f(0.0f, 0.0f); glVertex3f(-320, 320, -320);
 777     glEnd();
 778 
 779     // Render floor with color
 780     glBindTexture(GL_TEXTURE_2D, texture[2]);
 781     glBegin(GL_QUADS);
 782     glTexCoord2f(1.0f, 0.0f); glVertex3f(-320, -320, 320);
 783     glTexCoord2f(1.0f, 1.0f); glVertex3f(320, -320, 320);
 784     glTexCoord2f(0.0f, 1.0f); glVertex3f(320, -320, -320);
 785     glTexCoord2f(0.0f, 0.0f); glVertex3f(-320, -320, -320);
 786     glEnd();
 787 
 788 
 789     // Render columns
 790     glBindTexture(GL_TEXTURE_2D, texture[0]);
 791     glColor3f(0.5, 0.5, 0.5);
 792     glPushMatrix();
 793     glRotatef(90, 1, 0, 0);
 794     glTranslatef(0, 0, -500);
 795     gluCylinder(cylinder_obj, 60, 60, 1000, 20, 2);
 796     glPopMatrix();
 797 
 798     glPushMatrix();
 799     glTranslatef(200, -300, -500);
 800     gluCylinder(cylinder_obj, 60, 60, 1000, 20, 2);
 801     glPopMatrix();
 802 
 803     glPushMatrix();
 804     glTranslatef(-200, 0, 0);
 805     glRotatef(135, 1, 0, 0);
 806     glTranslatef(0, 0, -500);
 807     gluCylinder(cylinder_obj, 30, 30, 1000, 20, 2);
 808     glPopMatrix();
 809 
 810     // Render explosions
 811     glEnable(GL_BLEND);
 812     glDepthMask(GL_FALSE);
 813     glBindTexture(GL_TEXTURE_2D, texture[1]);
 814     for (int i = 0; i < 20; i++)
 815     {
 816         if (ExplosionArray[i]._Alpha >= 0)
 817         {
 818             glPushMatrix();
 819             ExplosionArray[i]._Alpha -= 0.01f;
 820             ExplosionArray[i]._Scale += 0.03f;
 821             glColor4f(1, 1, 0, ExplosionArray[i]._Alpha);
 822             glScalef(ExplosionArray[i]._Scale, ExplosionArray[i]._Scale, ExplosionArray[i]._Scale);
 823             glTranslatef((float)ExplosionArray[i]._Position.X() / ExplosionArray[i]._Scale,
 824                 (float)ExplosionArray[i]._Position.Y() / ExplosionArray[i]._Scale,
 825                 (float)ExplosionArray[i]._Position.Z() / ExplosionArray[i]._Scale);
 826             glCallList(displayList);
 827             glPopMatrix();
 828         }
 829     }
 830     glDepthMask(GL_TRUE);
 831     glDisable(GL_BLEND);
 832     glDisable(GL_TEXTURE_2D);
 833     return true;
 834 }
 835 //******************************************************************************************************************************************/
 836 //******************************************************************************************************************************************/
 837 /*
 838 *  The job of KillGLWindow() is to release the Rendering Context,
 839 *  the Device Context and finally the Window Handle.
 840 */
 841 
 842 GLvoid KillGLWindow(GLvoid)                             // Properly kill the window
 843 {
 844     if (fullscreen) {                                   // Are we in fullscreen mode
 845         if (!ChangeDisplaySettings(NULL, CDS_TEST)) {   // If the shortcut doesn't work
 846             ChangeDisplaySettings(NULL, CDS_RESET);     // Do it anyway (to get the values out of the registry)
 847             ChangeDisplaySettings(&DMsaved, CDS_RESET);
 848         }
 849         else {
 850             ChangeDisplaySettings(NULL, CDS_RESET);                  // If so switch back to the desktop
 851         }
 852         /*
 853         *  We use ChangeDisplaySettings(NULL,0) to return us to our original desktop.
 854         *  After we've switched back to the desktop we make the cursor visible again.
 855         */
 856         ShowCursor(TRUE);                                // Show mouse pointer
 857     }
 858 
 859     if (hRC) {                                           // Do we have a rendering context
 860         if (!wglMakeCurrent(NULL, NULL)) {                // Are we able to release the DC and RC contexts
 861             MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 862         }
 863 
 864         if (!wglDeleteContext(hRC)) {                     // Are we able to delete the RC
 865             MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 866             hRC = NULL;                                  // Set RC to NULL
 867         }
 868 
 869         if (hDC && !ReleaseDC(hWnd, hDC)) {              // Are we able to release the DC
 870             MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 871             hDC = NULL;                                  // Set DC to NULL
 872         }
 873         if (hWnd && !DestroyWindow(hWnd)) {              // Are we able to destroy the window
 874             MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 875             hWnd = NULL;                                 // Set hWnd to NULL
 876         }
 877 
 878         if (!UnregisterClass("OpenGL", hInstance)) {     // Are we able to unregister class
 879             MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 880             hInstance = NULL;                            // Set hInstance to NULL
 881         }
 882     }
 883 }
 884 /*
 885 * The next section of code creates our OpenGL Window.
 886 */
 887 
 888 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
 889 {
 890     /*
 891     * Find  a pixel format that matches the one we want
 892     */
 893     GLuint PixelFormat;                                  // Holds the result after serching for a match
 894 
 895     /*
 896     * Before you create a window, you MUST register a Class for the window
 897     */
 898     WNDCLASS wc;                                         // Windows class structure
 899 
 900     /*
 901     *  dwExStyle and dwStyle will store the Extended and normal Window Style Information.
 902     */
 903     DWORD dwExStyle;                                     // Window extend style
 904     DWORD dwStyle;                                       // Window style
 905 
 906 
 907     RECT WindowRect;                                     // Grabs rectangle upper left/lower right values
 908     WindowRect.left = (long)0;                           // Set left value to 0
 909     WindowRect.right = (long)width;                      // Set right value to requested width
 910     WindowRect.top = (long)0;                            // Set top value to 0
 911     WindowRect.bottom = (long)height;                    // Set bottom value to requested height
 912 
 913     fullscreen = fullscreenflag;                         // Set the global fullscreen flag
 914 
 915     /*
 916     *  The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized.
 917     *  CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications.
 918     *  WndProc is the procedure that watches for messages in our program.
 919     *  No extra Window data is used so we zero the two fields. Then we set the instance.
 920     *  Next we set hIcon to NULL meaning we don't want an ICON in the Window,
 921     *  and for a mouse pointer we use the standard arrow. The background color doesn't matter
 922     *  (we set that in GL). We don't want a menu in this Window so we set it to NULL,
 923     *  and the class name can be any name you want. I'll use "OpenGL" for simplicity.
 924     */
 925     hInstance = GetModuleHandle(NULL);                   // Grab an instance for our window
 926     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;       // Redraw on move, and own DC for window
 927     wc.lpfnWndProc = (WNDPROC)WndProc;                   // WndProc handles message
 928     wc.cbClsExtra = 0;                                   // No extra window date
 929     wc.cbWndExtra = 0;                                   // No extra window date
 930     wc.hInstance = hInstance;                            // set the instance
 931     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);              // Load the default icon
 932     wc.hCursor = LoadCursor(NULL, IDC_ARROW);            // Load the arrow pointer
 933     wc.hbrBackground = NULL;                             // No background requried for GL
 934     wc.lpszMenuName = NULL;                              // We don't want a menu
 935     wc.lpszClassName = "OpenGL";                         // set the class name
 936 
 937     EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DMsaved);  // Save the current display state
 938 
 939     if (!RegisterClass(&wc)) {                           // Attempt to register the window class
 940         MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 941         return FALSE;                                    // Exit and return false
 942     }
 943 
 944     if (fullscreen) {                                    // attempt fullsreen model
 945 
 946         /*
 947         *  There are a few very important things you should keep in mind when switching to full screen mode.
 948         *  Make sure the width and height that you use in fullscreen mode is the same as
 949         *  the width and height you plan to use for your window, and most importantly,
 950         *  set fullscreen mode BEFORE you create your window.
 951         */
 952         DEVMODE dmScreenSettings;                        // Device mode
 953         memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared
 954         dmScreenSettings.dmSize = sizeof(dmScreenSettings);     // Size of devmode structure
 955         dmScreenSettings.dmPelsWidth = width;            // Select window width
 956         dmScreenSettings.dmPelsHeight = height;          // Select window height
 957         dmScreenSettings.dmBitsPerPel = bits;            // Select bits per pixel
 958         dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
 959 
 960         /*
 961         *  In the line below ChangeDisplaySettings tries to switch to a mode that matches
 962         *  what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes,
 963         *  because it's supposed to remove the start bar at the bottom of the screen,
 964         *  plus it doesn't move or resize the windows on your desktop when you switch to
 965         *  fullscreen mode and back.
 966         */
 967         //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar
 968         if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
 969             //If the mode fails, offer two options. Quit or run in a window
 970             if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use"
 971                 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
 972             {
 973                 fullscreen = FALSE;                       // Select windowed mode (fullscreen=FLASE)
 974             }
 975             else {
 976                 // Pop up a message box letting user know the programe is closing.
 977                 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);
 978                 return FALSE;                             // Exit and return FALSE
 979             }
 980         }
 981     }
 982 
 983     if (fullscreen) {                                     // Are we still in fullscreen mode
 984 
 985         /*
 986         *  If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW,
 987         *  which force a top level window down to the taskbar once our window is visible.
 988         *  For the window style we'll create a WS_POPUP window.
 989         *  This type of window has no border around it, making it perfect for fullscreen mode.
 990 
 991         *  Finally, we disable the mouse pointer. If your program is not interactive,
 992         *  it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though.
 993         */
 994         dwExStyle = WS_EX_APPWINDOW;                      // Window extended style
 995         dwStyle = WS_POPUP;                               // Window style
 996         ShowCursor(FALSE);                                // Hide mosue pointer 
 997     }
 998     else {
 999 
1000         /*
1001         *  If we're using a window instead of fullscreen mode,
1002         *  we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look.
1003         *  For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP.
1004         *  WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border,
1005         *  window menu, and minimize / maximize buttons.
1006         */
1007         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window extended style
1008         dwStyle = WS_OVERLAPPEDWINDOW;                    // Window style
1009     }
1010 
1011     /*
1012     *  By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders,
1013     *  instead, the window will be made larger to account for the pixels needed to draw the window border.
1014     *  In fullscreen mode, this command has no effect.
1015     */
1016     AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust window to true resqusted
1017 
1018     /*
1019     *  WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly.
1020     *  These styles prevent other windows from drawing over or into our OpenGL Window.
1021     */
1022     if (!(hWnd = CreateWindowEx(dwExStyle,                // Extended style for the window
1023         "OpenGL",                                         // Class name
1024         title,                                            // Window title
1025         WS_CLIPSIBLINGS |                                 // Requried window style
1026         WS_CLIPCHILDREN |                                 // Requried window style
1027         dwStyle,                                          // Select window style
1028         0, 0,                                             // Window position
1029         WindowRect.right - WindowRect.left,               // Calculate adjusted window width
1030         WindowRect.bottom - WindowRect.top,               // Calculate adjusted window height
1031         NULL,                                             // No parent window
1032         NULL,                                             // No menu
1033         hInstance,                                        // Instance
1034         NULL)))                                           // Don't pass anything to WM_CREATE
1035     {
1036         KillGLWindow();                                   //Reset the display
1037         MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1038         return FALSE;                                     // Retrurn FALSE;
1039     }
1040 
1041     /*
1042     *  aside from the stencil buffer and the (slow) accumulation buffer
1043     */
1044     static PIXELFORMATDESCRIPTOR pfd =                    // pfd tells windows how we want things to be 
1045     {
1046         sizeof(PIXELFORMATDESCRIPTOR),                    // Size of this pixel format descriptor
1047         1,                                                // Version number
1048         PFD_DRAW_TO_WINDOW |                              // Format must support window
1049         PFD_SUPPORT_OPENGL |                              // Format must support OpenGL
1050         PFD_DOUBLEBUFFER,                                 // Must support double buffer
1051         PFD_TYPE_RGBA,                                    // Request an RGBA format
1052         bits,                                             // Select our color depth
1053         0, 0, 0, 0, 0, 0,                                 // Color bits ignored
1054         0,                                                // No alpha buffer
1055         0,                                                // shift bit ignored
1056         0,                                                // No accumulation buffer
1057         0, 0, 0, 0,                                       // Accumulation bits ignored
1058         16,                                               // 16Bits Z_Buffer (depth buffer)
1059         0,                                                // No stencil buffer
1060         0,                                                // No auxiliary buffer
1061         PFD_MAIN_PLANE,                                   // Main drawing layer
1062         0,                                                // Reserved
1063         0, 0, 0                                           // Layer makes ignored
1064     };
1065 
1066     if (!(hDC = GetDC(hWnd))) {                           // Did we get a device context
1067         KillGLWindow();                                   // Reset the display
1068         MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1069         return FALSE;                                     // Return FALSE
1070     }
1071 
1072     if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {  // Did window find a matching pixel format
1073         KillGLWindow();                                   // Reset the display
1074         MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1075         return FALSE;                                     // Return FALSE;
1076     }
1077 
1078     if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {        // Are we able to set the pixel format
1079         KillGLWindow();                                   // Reset the display
1080         MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1081         return FALSE;                                     // Return FALSE;
1082     }
1083 
1084     if (!(hRC = wglCreateContext(hDC))) {                 // Are we able to rendering context
1085         KillGLWindow();                                   // Reset the display
1086         MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1087         return FALSE;                                     // Return FASLE;
1088     }
1089 
1090     if (!wglMakeCurrent(hDC, hRC)) {                      // Try to activate the rendering context
1091         KillGLWindow();                                   // Reset the display
1092         MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1093         return FALSE;                                     // Return FALSE    
1094     }
1095 
1096     /*
1097     *  ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.
1098     */
1099     ShowWindow(hWnd, SW_SHOW);                            // Show the window
1100     SetForegroundWindow(hWnd);                            // slightly higher priority
1101     SetFocus(hWnd);                                       // Sets keyboard focus to the window
1102     ReSizeGLScene(width, height);                         // Set up our perspective GL screen
1103 
1104     /*
1105     *  we can set up lighting, textures, and anything else that needs to be setup in InitGL().
1106     */
1107     if (!InitGL()) {                                      // Initialize our newly created GL window
1108         KillGLWindow();                                   // Reset the display
1109         MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1110         return FALSE;                                     // Return FALSE
1111     }
1112     return TRUE;
1113 }
1114 
1115 LRESULT CALLBACK WndProc(HWND hWnd,                       // Handle for this window
1116     UINT uMsg,                                            // Message for this window
1117     WPARAM wParam,                                        // Additional message information
1118     LPARAM lParam)                                        // Additional message information
1119 {
1120     switch (uMsg) {                                       // Check for window message
1121     case WM_ACTIVATE: {                               // Check minimization state
1122         if (!HIWORD(wParam)) {
1123             active = TRUE;                            // Program is active
1124         }
1125         else {
1126             active = FALSE;                           // Program is no longer active
1127         }
1128         return 0;                                     // Return to the message loop
1129     }
1130     case WM_SYSCOMMAND: {                             // Intercept system commands
1131         switch (wParam) {                             // Check system calls
1132         case SC_SCREENSAVE:                       // Screensaver trying to start
1133         case SC_MONITORPOWER:                     // Monitor trying to enter powersave
1134             return 0;                                 // Prevent form happening
1135         }
1136         break;                                        // Exit
1137     }
1138     case WM_CLOSE: {                                  // Did we receive a close message
1139         PostQuitMessage(0);                           // Send a quit message
1140         return 0;
1141     }
1142     case WM_KEYDOWN: {                                // Is a key being held down
1143         keys[wParam] = TRUE;                          // if so, mark it as TRUE
1144         return 0;                                     // Jump back
1145     }
1146     case WM_KEYUP: {                                  // Has a key been released
1147         keys[wParam] = FALSE;                         // if so, mark it as FALSE
1148         return 0;                                     // Jump back
1149     }
1150     case WM_SIZE: {                                   // Resize the OpenGL window
1151         ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));   // LoWord = width HiWord = height
1152         return 0;                                     // Jump back
1153     }
1154     }
1155     return DefWindowProc(hWnd, uMsg, wParam, lParam);     // Pass all unhandled message to DefWindwProc
1156 }
1157 
1158 int WINAPI WinMain(HINSTANCE hInstance,                   // Instance
1159     HINSTANCE hPrevInstance,                              // Previous instance
1160     LPSTR lpCmdLine,                                      // Command line parameters
1161     int nCmdShow)                                         // Window show state
1162 {
1163     MSG msg;                                              // Window message structure
1164     BOOL done = FALSE;                                    // Bool variable to exit loop
1165                                                           // Ask the user which screen mode they prefer
1166     if (MessageBox(NULL, "Would you like to run in fullscreen mode?",
1167         "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
1168     {
1169         fullscreen = FALSE;                               // Window mode
1170     }
1171 //******************************************************************************************************************************************/
1172 //******************************************************************************************************************************************/
1173     InitVars();           // Initialize variables
1174 
1175                           // Create our OpenGL window
1176     if (!CreateGLWindow("3D Shapes", 800, 600, 32, fullscreen)) {  // (Modified)
1177         return 0;                                         // Quit if window was not create
1178     }
1179     while (!done) {                                       // Loop that runs until donw = TRUE
1180         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {   // Is there a message wating
1181             if (msg.message == WM_QUIT) {                 // Havw we received a quit message
1182                 done = TRUE;                              // if so done  = TRUE
1183             }
1184             else {                                        // If not, deal with window message
1185                 TranslateMessage(&msg);                   // Translate message
1186                 DispatchMessage(&msg);                    // Dispatch message
1187             }
1188         }
1189         else {
1190             // Draw the scene. Watch for ESC key and quit message from DrawGLScene()
1191             if (active) {                                 // Program active
1192                 if (keys[VK_ESCAPE]) {                    // Was ESC pressed
1193                     done = TRUE;                          // ESC signalled a quit
1194                 }
1195                 else {                                    // Not time to quit, update screen
1196                     idle();                             // Advance Simulation
1197                     DrawGLScene();                        // Draw scene
1198                     SwapBuffers(hDC);                     // Swap buffers (double buffering)
1199                 }
1200             }
1201 //******************************************************************************************************************************************/
1202 //******************************************************************************************************************************************/
1203             if (!ProcessKeys())
1204                 return 0;
1205             /*
1206             *  It allows us to press the F1 key to switch from fullscreen mode to
1207             *  windowed mode or windowed mode to fullscreen mode.
1208             */
1209             if (keys[VK_F1]) {                            // Is F1 being pressed
1210                 keys[VK_F1] = FALSE;                      // If so make key FASLE
1211                 KillGLWindow();                           // Kill our current window
1212                 fullscreen = !fullscreen;                 // Toggle fullscreen / window mode
1213                                                           //Recreate our OpenGL window(modified)
1214                 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {
1215                     return 0;                             // Quit if window was not create
1216                 }
1217             }
1218         }
1219     }
1220     // Shutdown
1221     KillGLWindow();                                       // Kill the window
1222     glDeleteTextures(4, texture);
1223 //******************************************************************************************************************************************/
1224 //******************************************************************************************************************************************/
1225     return (msg.wParam);                                  // Exit the program
1226 }
Main

 

Thanks for Nehe's tutorials, this is his home.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!