这次的代码没有按照辅导代码中的来。
VK_LEFT/VK_RIGHT/VK_UP/VK_DOWN控制长方体旋转,W/S/A/D/Q/E控制球移动,小键盘的8/5/4/6/7/9控制长方体移动,I/K/J/L/U/O控制光源移动。
在InitGLObject()函数中使用到的readObject()函数、setConnectivity()函数和calculatePlane()函数在3object.h中所写。
readObject()函数在.txt文件中读取物体顶点数、顶点坐标、平面数、vertexIndices以及顶点normals。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
bool readObject(const char* filename, ShadowedObject& object) { FILE* pInputFile = fopen(filename, "r"); if (!pInputFile) { std::cerr << "Unable to open the object file: " << filename << std::endl; return false; } // Read vertices fscanf(pInputFile, "%d", &object.nVertices); object.pVertices = new Point3f[object.nVertices]; for (int i = 0; i < object.nVertices; ++i) { fscanf(pInputFile, "%f", &object.pVertices[i].x); fscanf(pInputFile, "%f", &object.pVertices[i].y); fscanf(pInputFile, "%f", &object.pVertices[i].z); } // Read faces fscanf(pInputFile, "%d", &object.nFaces); object.pFaces = new Face[object.nFaces]; for (int i = 0; i < object.nFaces; ++i) { Face* pFace = &object.pFaces[i]; for (int j = 0; j < 3; ++j) { pFace->neighbourIndices[j] = -1; // No neighbour set up fscanf(pInputFile, "%d", &pFace->vertexIndices[j]); pFace->vertexIndices[j]--; } for (int j = 0; j < 3; ++j) { fscanf(pInputFile, "%f", &pFace->normals[j].x); fscanf(pInputFile, "%f", &pFace->normals[j].y); fscanf(pInputFile, "%f", &pFace->normals[j].z); } } return true; }
三个物体的txt文件:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
8 -1 1 -1 1 1 -1 1 1 1 -1 1 1 -1 -1 -1 1 -1 -1 1 -1 1 -1 -1 1 12 1 3 2 0 1 0 0 1 0 0 1 0 1 4 3 0 1 0 0 1 0 0 1 0 5 6 7 0 -1 0 0 -1 0 0 -1 0 5 7 8 0 -1 0 0 -1 0 0 -1 0 5 4 1 -1 0 0 -1 0 0 -1 0 0 5 8 4 -1 0 0 -1 0 0 -1 0 0 3 6 2 1 0 0 1 0 0 1 0 0 3 7 6 1 0 0 1 0 0 1 0 0 5 1 2 0 0 -1 0 0 -1 0 0 -1 5 2 6 0 0 -1 0 0 -1 0 0 -1 3 4 8 0 0 1 0 0 1 0 0 1 3 8 7 0 0 1 0 0 1 0 0 1
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
16 -2 0.2 -0.2 2 0.2 -0.2 2 0.2 0.2 -2 0.2 0.2 -2 -0.2 -0.2 2 -0.2 -0.2 2 -0.2 0.2 -2 -0.2 0.2 -0.2 2 -0.2 0.2 2 -0.2 0.2 2 0.2 -0.2 2 0.2 -0.2 -2 -0.2 0.2 -2 -0.2 0.2 -2 0.2 -0.2 -2 0.2 24 1 3 2 0 1 0 0 1 0 0 1 0 1 4 3 0 1 0 0 1 0 0 1 0 5 6 7 0 -1 0 0 -1 0 0 -1 0 5 7 8 0 -1 0 0 -1 0 0 -1 0 5 4 1 -1 0 0 -1 0 0 -1 0 0 5 8 4 -1 0 0 -1 0 0 -1 0 0 3 6 2 1 0 0 1 0 0 1 0 0 3 7 6 1 0 0 1 0 0 1 0 0 5 1 2 0 0 -1 0 0 -1 0 0 -1 5 2 6 0 0 -1 0 0 -1 0 0 -1 3 4 8 0 0 1 0 0 1 0 0 1 3 8 7 0 0 1 0 0 1 0 0 1 9 11 10 0 1 0 0 1 0 0 1 0 9 12 11 0 1 0 0 1 0 0 1 0 13 14 15 0 -1 0 0 -1 0 0 -1 0 13 15 16 0 -1 0 0 -1 0 0 -1 0 13 12 9 -1 0 0 -1 0 0 -1 0 0 13 16 12 -1 0 0 -1 0 0 -1 0 0 11 14 10 1 0 0 1 0 0 1 0 0 11 15 14 1 0 0 1 0 0 1 0 0 13 9 10 0 0 -1 0 0 -1 0 0 -1 13 10 14 0 0 -1 0 0 -1 0 0 -1 11 12 16 0 0 1 0 0 1 0 0 1 11 16 15 0 0 1 0 0 1 0 0 1
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
24 -2 0.2 -0.2 2 0.2 -0.2 2 0.2 0.2 -2 0.2 0.2 -2 -0.2 -0.2 2 -0.2 -0.2 2 -0.2 0.2 -2 -0.2 0.2 -0.2 2 -0.2 0.2 2 -0.2 0.2 2 0.2 -0.2 2 0.2 -0.2 -2 -0.2 0.2 -2 -0.2 0.2 -2 0.2 -0.2 -2 0.2 -0.2 0.2 -2 0.2 0.2 -2 0.2 0.2 2 -0.2 0.2 2 -0.2 -0.2 -2 0.2 -0.2 -2 0.2 -0.2 2 -0.2 -0.2 2 36 1 3 2 0 1 0 0 1 0 0 1 0 1 4 3 0 1 0 0 1 0 0 1 0 5 6 7 0 -1 0 0 -1 0 0 -1 0 5 7 8 0 -1 0 0 -1 0 0 -1 0 5 4 1 -1 0 0 -1 0 0 -1 0 0 5 8 4 -1 0 0 -1 0 0 -1 0 0 3 6 2 1 0 0 1 0 0 1 0 0 3 7 6 1 0 0 1 0 0 1 0 0 5 1 2 0 0 -1 0 0 -1 0 0 -1 5 2 6 0 0 -1 0 0 -1 0 0 -1 3 4 8 0 0 1 0 0 1 0 0 1 3 8 7 0 0 1 0 0 1 0 0 1 9 11 10 0 1 0 0 1 0 0 1 0 9 12 11 0 1 0 0 1 0 0 1 0 13 14 15 0 -1 0 0 -1 0 0 -1 0 13 15 16 0 -1 0 0 -1 0 0 -1 0 13 12 9 -1 0 0 -1 0 0 -1 0 0 13 16 12 -1 0 0 -1 0 0 -1 0 0 11 14 10 1 0 0 1 0 0 1 0 0 11 15 14 1 0 0 1 0 0 1 0 0 13 9 10 0 0 -1 0 0 -1 0 0 -1 13 10 14 0 0 -1 0 0 -1 0 0 -1 11 12 16 0 0 1 0 0 1 0 0 1 11 16 15 0 0 1 0 0 1 0 0 1 17 19 18 0 1 0 0 1 0 0 1 0 17 20 19 0 1 0 0 1 0 0 1 0 21 22 23 0 -1 0 0 -1 0 0 -1 0 21 23 24 0 -1 0 0 -1 0 0 -1 0 21 20 17 -1 0 0 -1 0 0 -1 0 0 21 24 20 -1 0 0 -1 0 0 -1 0 0 19 22 18 1 0 0 1 0 0 1 0 0 19 23 22 1 0 0 1 0 0 1 0 0 21 17 18 0 0 -1 0 0 -1 0 0 -1 21 18 22 0 0 -1 0 0 -1 0 0 -1 19 20 24 0 0 1 0 0 1 0 0 1 19 24 23 0 0 1 0 0 1 0 0 1
setConnectivity()函数判断每个面的每条边是否是同一条边来设定每个面是否连接(连通)。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
void setConnectivity(ShadowedObject& object) { for (int faceA = 0; faceA < object.nFaces; ++faceA) { for (int edgeA = 0; edgeA < 3; ++edgeA) { if (!object.pFaces[faceA].neighbourIndices[edgeA]) { for (int faceB = faceA; faceB < object.nFaces; ++faceB) { for (int edgeB = 0; edgeB < 3; ++edgeB) { int vertA1 = object.pFaces[faceA].vertexIndices[edgeA]; int vertA2 = object.pFaces[faceA].vertexIndices[(edgeA + 1) % 3]; int vertB1 = object.pFaces[faceB].vertexIndices[edgeB]; int vertB2 = object.pFaces[faceB].vertexIndices[(edgeB + 1) % 3]; // Check If They Are Neighbours - IE, The Edges Are The Same if ((vertA1 == vertB1 && vertA2 == vertB2) || (vertA1 == vertB2 && vertA2 == vertB1)) { // They are neighbours object.pFaces[faceA].neighbourIndices[edgeA] = faceB; object.pFaces[faceB].neighbourIndices[edgeB] = faceA; //edgeFound = true; //break; } } } } } } }
calculatePlane()函数计算平面方程系数,很简单,用行列式计算就可以,下面为计算系数的过程,
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
void calculatePlane(const ShadowedObject& object, Face& face) { // Get shortened names for the vertices of the face const Point3f& v1 = object.pVertices[face.vertexIndices[0]]; const Point3f& v2 = object.pVertices[face.vertexIndices[1]]; const Point3f& v3 = object.pVertices[face.vertexIndices[2]]; face.PlaneEquation.a = v1.y * (v2.z - v3.z) + v2.y * (v3.z - v1.z) + v3.y * (v1.z - v2.z); face.PlaneEquation.b = v1.z * (v2.x - v3.x) + v2.z * (v3.x - v1.x) + v3.z * (v1.x - v2.x); face.PlaneEquation.c = v1.x * (v2.y - v3.y) + v2.x * (v3.y - v1.y) + v3.x * (v1.y - v2.y); face.PlaneEquation.d = -(v1.x * (v2.y * v3.z - v3.y * v2.z) + v2.x * (v3.y * v1.z - v1.y * v3.z) + v3.x * (v1.y * v2.z - v2.y * v1.z)); }
提前说下,两个向量的叉积与两个向量垂直,即平面的法向量。即,
已知三角形的三个点,求平面方程(系数)。
可由行列式得,
即平面方程系数,
在InitGL()函数中,glMaterialfv()函数为灯光模型添加材质,其原型为,
void WINAPI glMaterialfv( GLenum face, GLenum pname, const GLint *params );
glCullFace()函数选定正面或反面,来接收灯光效果,前提先要打开GL_CULL_FACE功能。
在DrawGLScene()函数中,glLightfv()函数设置灯光效果LightPos、LightAmb、LightDif或LightSpc,也只能用点光,别的看不出效果区别。
glGetFloatv()函数返回值或参数选择过的值。
glGetFloatv(GL_MODELVIEW_MATRIX, Minv);
这行代码返回一个4X4维矩阵,即GL_MODELVIEW_MATRIX:The params parameter returns 16 values: the modelview matrix on the top of the modelview matrix stack.即在前面的glPushMatrix()函数推进栈的矩阵。
glDepthMask()函数开启或关闭写入深度缓存。
VMatMult()函数实现一个4X4维矩阵和4维向量的相乘。
在castShadow()函数中,glPushAttrib()函数和glPopAttrib()函数作用相反,是对属性栈的操作。在原文中,作用为开启和关闭各项的功能。
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT);
glPopAttrib();
glFrontFace()函数,用来指定多边形在窗口坐标中是否顺时针旋转。GL_CCW逆时针,GL_CW顺时针。
下面为代码,两个文件分为头文件和cpp文件,同样修改部分位于双行星号内。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #ifndef _3DOBJECT_H_ 2 #define _3DOBJECT_H 3 4 #include <iostream> 5 #include <stdio.h> 6 #include <math.h> 7 #include <GL\glut.h> 8 #pragma comment(lib, "legacy_stdio_definitions.lib") 9 10 //3D-coordinate 11 struct Point3f { 12 float x, y, z; 13 }; 14 15 // Plane equation ax + by + cz + d = 0 16 struct PlaneEq { 17 float a, b, c, d; 18 }; 19 20 // Object's face 21 struct Face { 22 int vertexIndices[3]; // Index of each vertex within the triangle of this face 23 Point3f normals[3]; // Normals of each vertex 24 PlaneEq PlaneEquation; 25 int neighbourIndices[3]; // Index of each face that neighbour 26 bool visible; // Is the face visible by the light 27 }; 28 29 struct ShadowedObject { 30 int nVertices; 31 Point3f* pVertices; // Dynamically Allocated 32 int nFaces; 33 Face* pFaces; // Dynamically Allocated 34 }; 35 36 bool readObject(const char* filename, ShadowedObject& object) 37 { 38 FILE* pInputFile = fopen(filename, "r"); 39 40 if (!pInputFile) { 41 std::cerr << "Unable to open the object file: " << filename << std::endl; 42 return false; 43 } 44 // Read vertices 45 fscanf(pInputFile, "%d", &object.nVertices); 46 object.pVertices = new Point3f[object.nVertices]; 47 48 for (int i = 0; i < object.nVertices; ++i) { 49 fscanf(pInputFile, "%f", &object.pVertices[i].x); 50 fscanf(pInputFile, "%f", &object.pVertices[i].y); 51 fscanf(pInputFile, "%f", &object.pVertices[i].z); 52 } 53 // Read faces 54 fscanf(pInputFile, "%d", &object.nFaces); 55 object.pFaces = new Face[object.nFaces]; 56 57 for (int i = 0; i < object.nFaces; ++i) { 58 Face* pFace = &object.pFaces[i]; 59 for (int j = 0; j < 3; ++j) { 60 pFace->neighbourIndices[j] = 0; // No neighbour set up 61 fscanf(pInputFile, "%d", &pFace->vertexIndices[j]); 62 pFace->PlaneEquation.a = pFace->PlaneEquation.b = pFace->PlaneEquation.c = pFace->PlaneEquation.d = 0; 63 pFace->visible = false; 64 // pFace->vertexIndices[j]--; 65 } 66 67 for (int j = 0; j < 3; ++j) { 68 fscanf(pInputFile, "%f", &pFace->normals[j].x); 69 fscanf(pInputFile, "%f", &pFace->normals[j].y); 70 fscanf(pInputFile, "%f", &pFace->normals[j].z); 71 } 72 } 73 return true; 74 } 75 76 void killObject(ShadowedObject& object) 77 { 78 delete[] object.pFaces; 79 object.nFaces = 0; 80 object.pFaces = NULL; 81 delete[] object.pVertices; 82 object.nVertices = 0; 83 object.pVertices = NULL; 84 } 85 86 void setConnectivity(ShadowedObject& object) 87 { 88 for (int faceA = 0; faceA < object.nFaces; ++faceA) { 89 for (int edgeA = 0; edgeA < 3; ++edgeA) { 90 if (!object.pFaces[faceA].neighbourIndices[edgeA]) { 91 for (int faceB = faceA; faceB < object.nFaces; ++faceB) { 92 for (int edgeB = 0; edgeB < 3; ++edgeB) { 93 int vertA1 = object.pFaces[faceA].vertexIndices[edgeA]; 94 int vertA2 = object.pFaces[faceA].vertexIndices[(edgeA + 1) % 3]; 95 int vertB1 = object.pFaces[faceB].vertexIndices[edgeB]; 96 int vertB2 = object.pFaces[faceB].vertexIndices[(edgeB + 1) % 3]; 97 // Check If They Are Neighbours - IE, The Edges Are The Same 98 if ((vertA1 == vertB1 && vertA2 == vertB2) || (vertA1 == vertB2 && vertA2 == vertB1)) 99 { 100 // They are neighbours 101 object.pFaces[faceA].neighbourIndices[edgeA] = faceB + 1; 102 object.pFaces[faceB].neighbourIndices[edgeB] = faceA + 1; 103 //edgeFound = true; 104 //break; 105 } 106 } 107 } 108 } 109 } 110 } 111 } 112 113 void drawObject(const ShadowedObject& object) 114 { 115 glBegin(GL_TRIANGLES); 116 for (int i = 0; i < object.nFaces; ++i) { 117 const Face& face = object.pFaces[i]; 118 for (int j = 0; j < 3; ++j) { 119 const Point3f& vertex = object.pVertices[face.vertexIndices[j]-1]; 120 glNormal3f(face.normals[j].x, face.normals[j].y, face.normals[j].z); 121 glVertex3f(vertex.x, vertex.y, vertex.z); 122 } 123 } 124 glEnd(); 125 } 126 127 void calculatePlane(const ShadowedObject object, Face& face) 128 { 129 // Get shortened names for the vertices of the face 130 const Point3f& v1 = object.pVertices[face.vertexIndices[0]-1]; 131 const Point3f& v2 = object.pVertices[face.vertexIndices[1]-1]; 132 const Point3f& v3 = object.pVertices[face.vertexIndices[2]-1]; 133 134 face.PlaneEquation.a = v1.y * (v2.z - v3.z) + v2.y * (v3.z - v1.z) + v3.y * (v1.z - v2.z); 135 face.PlaneEquation.b = v1.z * (v2.x - v3.x) + v2.z * (v3.x - v1.x) + v3.z * (v1.x - v2.x); 136 face.PlaneEquation.c = v1.x * (v2.y - v3.y) + v2.x * (v3.y - v1.y) + v3.x * (v1.y - v2.y); 137 face.PlaneEquation.d = -(v1.x * (v2.y * v3.z - v3.y * v2.z) + v2.x * (v3.y * v1.z - v1.y * v3.z) + 138 v3.x * (v1.y * v2.z - v2.y * v1.z)); 139 } 140 141 void doShadowPass(ShadowedObject& object, GLfloat* lightPosition) 142 { 143 for (int i = 0; i < object.nFaces; ++i) { 144 const Face& face = object.pFaces[i]; 145 if (face.visible) { 146 // Go through each edge 147 for (int j = 0; j < 3; ++j) { 148 int neighbourIndex = face.neighbourIndices[j]; 149 if (!neighbourIndex || object.pFaces[neighbourIndex-1].visible == false) { 150 // Get the points on the edge 151 const Point3f& v1 = object.pVertices[face.vertexIndices[j]-1]; 152 const Point3f& v2 = object.pVertices[face.vertexIndices[(j + 1) % 3]-1]; 153 // Calculate the two vertices in distance 154 Point3f v3, v4; 155 v3.x = (v1.x - lightPosition[0]) * 10000000; 156 v3.y = (v1.y - lightPosition[1]) * 10000000; 157 v3.z = (v1.z - lightPosition[2]) * 10000000; 158 159 v4.x = (v2.x - lightPosition[0]) * 10000000; 160 v4.y = (v2.y - lightPosition[1]) * 10000000; 161 v4.z = (v2.z - lightPosition[2]) * 10000000; 162 163 // Draw the quadrilateral (as a triangle strip) 164 glBegin(GL_TRIANGLE_STRIP); 165 glVertex3f(v1.x, v1.y, v1.z); 166 glVertex3f(v1.x + v3.x, v1.y + v3.y, v1.z + v3.z); 167 glVertex3f(v2.x, v2.y, v2.z); 168 glVertex3f(v2.x + v4.x, v2.y + v4.y, v2.z + v4.z); 169 glEnd(); 170 } 171 } 172 } 173 } 174 } 175 176 177 void castShadow(ShadowedObject& object, GLfloat* lightPosition) 178 { 179 // Determine which faces are visible by the light 180 for (int i = 0; i < object.nFaces; ++i) { 181 const PlaneEq& plane = object.pFaces[i].PlaneEquation; 182 GLfloat side = plane.a * lightPosition[0] + plane.b * lightPosition[1] + 183 plane.c * lightPosition[2] + plane.d; 184 if (side > 0) 185 object.pFaces[i].visible = true; 186 else 187 object.pFaces[i].visible = false; 188 } 189 glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | 190 GL_STENCIL_BUFFER_BIT); 191 glDisable(GL_LIGHTING); 192 glDepthMask(GL_FALSE); // Turn off writing to the depth-buffer 193 glDepthFunc(GL_LEQUAL); 194 glEnable(GL_STENCIL_TEST); // Trun on 195 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); 196 glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFFL); 197 //First pass.Increase stencil value int the shadow 198 glFrontFace(GL_CCW); 199 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 200 doShadowPass(object, lightPosition); 201 // Scend pass. Decrease stencil value in the shadow 202 glFrontFace(GL_CW); 203 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); 204 doShadowPass(object, lightPosition); 205 206 glFrontFace(GL_CCW); 207 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Enable rendering 208 // Draw a shadowing rectangle covering the entire screen 209 glColor4f(0.0f, 0.0f, 0.0f, 0.4f); 210 glEnable(GL_BLEND); 211 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 212 glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFFL); 213 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 214 glPushMatrix(); 215 glLoadIdentity(); 216 glBegin(GL_TRIANGLE_STRIP); 217 glVertex3f(-0.1f, 0.1f, -0.1f); 218 glVertex3f(-0.1f, -0.1f, -0.1f); 219 glVertex3f(0.1f, 0.1f, -0.1f); 220 glVertex3f(0.1f, -0.1f, -0.1f); 221 glEnd(); 222 glPopMatrix(); 223 glPopAttrib(); 224 } 225 #endif // !_3DOBJECT_H_
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <windows.h> 2 #include <gl/glew.h> 3 #include <GL/GLUAX.H> 4 #include "C:\Users\lenovo\Desktop\OpenGL\OpenGL\3Dobject.h" 5 6 /* 7 * Every OpenGL program is linked to a Rendering Context. 8 * A Rendering Context is what links OpenGL calls to the Device Context. 9 * In order for your program to draw to a Window you need to create a Device Context. 10 * The DC connects the Window to the GDI (Graphics Device Interface). 11 */ 12 13 HGLRC hRC = NULL; // Permanent rendering context 14 HDC hDC = NULL; // Private GDI device context 15 HWND hWnd = NULL; // Holds our window handle 16 HINSTANCE hInstance; // Holds the instance of the application 17 18 /* 19 * It's important to make this global so that each procedure knows if 20 * the program is running in fullscreen mode or not. 21 */ 22 23 bool keys[256]; // Array used for the keyboard routine 24 bool active = TRUE; // Window active flag set to TRUE by default 25 bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default 26 /******************************************************************************************************************************************/ 27 /******************************************************************************************************************************************/ 28 typedef float GLvector4f[4]; 29 typedef float GLmatrix16f[16]; 30 31 ShadowedObject object; 32 GLfloat xrot = 0; 33 GLfloat yrot = 0; 34 GLfloat xspeed = 0; 35 GLfloat yspeed = 0; 36 37 // Light parameters 38 GLfloat LightPos[] = { 0.0f, 5.0f, -4.0f, 1.0f }; 39 GLfloat LightAmb[] = { 0.2f, 0.2f, 0.2f, 1.0f }; 40 GLfloat LightDif[] = { 0.6f, 0.6f, 0.6f, 1.0f }; 41 GLfloat LightSpc[] = { -0.2f, -0.2f, -0.2f, 1.0f }; // Specular light 42 43 GLfloat MatAmb[] = { 0.4f, 0.4f, 0.4f, 1.0f }; 44 GLfloat MatDif[] = { 0.2f, 0.6f, 0.9f, 1.0f }; 45 GLfloat MatSpc[] = { 0.0f, 0.0f, 0.0f, 1.0f }; 46 GLfloat MatShn[] = { 0.0f }; // Material - shininess 47 48 float ObjectPosition[] = { -2.0f, -2.0f, -5.0f }; 49 50 GLUquadricObj * q; // Quadratic for drawing a sphere 51 52 float SpherePosition[] = { -4.0f, -5.0f, -6.0f }; 53 54 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc 55 /******************************************************************************************************************************************/ 56 /******************************************************************************************************************************************/ 57 GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialize the GL window 58 { 59 if (height == 0) { // Prevent a divide by zero by 60 height = 1; // Making height equal one 61 } 62 63 glViewport(0, 0, width, height); // Reset the current viewport 64 65 /* 66 * The following lines set the screen up for a perspective view. 67 * Meaning things in the distance get smaller. This creates a realistic looking scene. 68 * The perspective is calculated with a 45 degree viewing angle based on 69 * the windows width and height. The 0.1f, 100.0f is the starting point and 70 * ending point for how deep we can draw into the screen. 71 * 72 * The projection matrix is responsible for adding perspective to our scene. 73 * glLoadIdentity() restores the selected matrix to it's original state. 74 * The modelview matrix is where our object information is stored. 75 * Lastly we reset the modelview matrix. 76 */ 77 78 glMatrixMode(GL_PROJECTION); // Select the projection matrix 79 glLoadIdentity(); // Reset the projection matrix 80 81 // Calculate the aspect ratio of the window 82 gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); 83 // glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f); // Create orhto 640X480 view (0, 0, at the top) 84 85 glMatrixMode(GL_MODELVIEW); // Seclet the modelview matrix 86 glLoadIdentity(); // Reset the modelview matrix 87 } 88 /******************************************************************************************************************************************/ 89 /******************************************************************************************************************************************/ 90 void VMatMult(GLmatrix16f M, GLvector4f v) 91 { 92 GLfloat res[4]; 93 res[0] = M[0] * v[0] + M[4] * v[1] + M[8] * v[2] + M[12] * v[3]; 94 res[1] = M[1] * v[0] + M[5] * v[1] + M[9] * v[2] + M[13] * v[3]; 95 res[2] = M[2] * v[0] + M[6] * v[1] + M[10] * v[2] + M[14] * v[3]; 96 res[3] = M[3] * v[0] + M[7] * v[1] + M[11] * v[2] + M[15] * v[3]; 97 v[0] = res[0]; 98 v[1] = res[1]; 99 v[2] = res[2]; 100 v[3] = res[3]; 101 } 102 103 int InitGLObject() 104 { 105 if (!readObject("Data/Object2.txt", object)) { 106 return false; 107 } 108 setConnectivity(object); // Set face to face connectivity 109 110 for (int i = 0; i < object.nFaces; ++i) { 111 calculatePlane(object, object.pFaces[i]); // Compute plane equations for all faces 112 } 113 return true; 114 } 115 116 int InitGL(GLvoid) // All setup for OpenGL goes here 117 { 118 if (!InitGLObject()) { 119 return false; 120 } 121 122 glShadeModel(GL_SMOOTH); 123 glClearColor(0.0f, 0.0f, 0.0f, 0.5); // Background 124 glClearDepth(1.0f); // Depth buffer setup 125 glClearStencil(0); // Clear the stencil buffer to 0 126 glEnable(GL_DEPTH_TEST); 127 glDepthFunc(GL_LEQUAL); 128 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 129 130 131 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmb); 132 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDif); 133 glLightfv(GL_LIGHT1, GL_POSITION, LightPos); 134 glLightfv(GL_LIGHT1, GL_SPECULAR, LightSpc); 135 136 glEnable(GL_LIGHT1); 137 glEnable(GL_LIGHTING); 138 139 glMaterialfv(GL_FRONT, GL_AMBIENT, MatAmb); // Set material ambience 140 glMaterialfv(GL_FRONT, GL_DIFFUSE, MatDif); // Set material diffuse 141 glMaterialfv(GL_FRONT, GL_SPECULAR, MatSpc); // Set material specular 142 glMaterialfv(GL_FRONT, GL_SHININESS, MatShn); // Set material shininess 143 144 glCullFace(GL_BACK); // Set culling face to back face 145 glEnable(GL_CULL_FACE); 146 glClearColor(0.1f, 1.0f, 0.5f, 1.0f); // Greenish color 147 148 q = gluNewQuadric(); 149 gluQuadricNormals(q, GL_SMOOTH); // Generate smooth Normals for the quad 150 gluQuadricTexture(q, GL_FALSE); // Disable auto texture coords for the quad 151 152 return TRUE; 153 } 154 155 void DrawGLRoom() 156 { 157 glBegin(GL_QUADS); 158 // Floor 159 glNormal3f(0.0f, 1.0f, 0.0f); 160 glVertex3f(-10.0f, -10.0f, -20.0f); 161 glVertex3f(-10.0f, -10.0f, 20.0f); 162 glVertex3f(10.0f, -10.0f, 20.0f); 163 glVertex3f(10.0f, -10.0f, -20.0f); 164 // Ceiling 165 glNormal3f(0.0f, -1.0f, 0.0f); 166 glVertex3f(-10.0f, 10.0f, 20.0f); 167 glVertex3f(-10.0f, 10.0f, -20.0f); 168 glVertex3f(10.0f, 10.0f, -20.0f); 169 glVertex3f(10.0f, 10.0f, 20.0f); 170 // Front Wall 171 glNormal3f(0.0f, 0.0f, 1.0f); 172 glVertex3f(-10.0f, 10.0f, -20.0f); 173 glVertex3f(-10.0f, -10.0f, -20.0f); 174 glVertex3f(10.0f, -10.0f, -20.0f); 175 glVertex3f(10.0f, 10.0f, -20.0f); 176 // Back Wall 177 glNormal3f(0.0f, 0.0f, -1.0f); 178 glVertex3f(10.0f, 10.0f, 20.0f); 179 glVertex3f(10.0f, -10.0f, 20.0f); 180 glVertex3f(-10.0f, -10.0f, 20.0f); 181 glVertex3f(-10.0f, 10.0f, 20.0f); 182 // Left Wall 183 glNormal3f(1.0f, 0.0f, 0.0f); 184 glVertex3f(-10.0f, 10.0f, 20.0f); 185 glVertex3f(-10.0f, -10.0f, 20.0f); 186 glVertex3f(-10.0f, -10.0f, -20.0f); 187 glVertex3f(-10.0f, 10.0f, -20.0f); 188 // Right Wall 189 glNormal3f(-1.0f, 0.0f, 0.0f); 190 glVertex3f(10.0f, 10.0f, -20.0f); 191 glVertex3f(10.0f, -10.0f, -20.0f); 192 glVertex3f(10.0f, -10.0f, 20.0f); 193 glVertex3f(10.0f, 10.0f, 20.0f); 194 glEnd(); 195 } 196 197 /* 198 * For now all we will do is clear the screen to the color we previously decided on, 199 * clear the depth buffer and reset the scene. We wont draw anything yet. 200 */ 201 bool DrawGLScene(GLvoid) // Here's where we do all the drawing 202 { 203 GLmatrix16f Minv; 204 GLvector4f wlp, lp; 205 206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 207 208 glLoadIdentity(); 209 glTranslatef(0.0f, 0.0f, -20.0f); 210 glLightfv(GL_LIGHT1, GL_POSITION, LightPos); 211 glTranslatef(SpherePosition[0], SpherePosition[1], SpherePosition[2]); 212 gluSphere(q, 1.5f, 32, 16); 213 214 glLoadIdentity(); 215 glRotatef(-yrot, 0.0f, 1.0f, 0.0f); 216 glRotatef(-xrot, 1.0f, 0.0f, 0.0f); 217 glGetFloatv(GL_MODELVIEW_MATRIX, Minv); 218 219 lp[0] = LightPos[0]; 220 lp[1] = LightPos[1]; 221 lp[2] = LightPos[2]; 222 lp[3] = LightPos[3]; 223 VMatMult(Minv, lp); 224 glTranslatef(-ObjectPosition[0], -ObjectPosition[1], -ObjectPosition[2]); 225 glGetFloatv(GL_MODELVIEW_MATRIX, Minv); 226 227 wlp[0] = 0.0f; 228 wlp[1] = 0.0f; 229 wlp[2] = 0.0f; 230 wlp[3] = 1.0f; 231 VMatMult(Minv, wlp); 232 233 lp[0] += wlp[0]; 234 lp[1] += wlp[1]; 235 lp[2] += wlp[2]; 236 237 glColor4f(0.7f, 0.4f, 0.0f, 1.0f); 238 glLoadIdentity(); 239 glTranslatef(0.0f, 0.0f, -20.0f); 240 DrawGLRoom(); 241 glTranslatef(ObjectPosition[0], ObjectPosition[1], ObjectPosition[2]); 242 glRotatef(xrot, 1.0f, 0.0f, 0.0f); 243 glRotatef(yrot, 0.0f, 1.0f, 0.0f); 244 drawObject(object); 245 castShadow(object, lp); 246 247 glColor4f(0.7f, 0.4f, 0.0f, 1.0f); 248 glDisable(GL_LIGHTING); 249 glDepthMask(GL_FALSE); 250 glTranslatef(lp[0], lp[1], lp[2]); 251 252 gluSphere(q, 0.2f, 16, 8); 253 glEnable(GL_LIGHTING); 254 glDepthMask(GL_TRUE); 255 xrot += xspeed; 256 yrot += yspeed; 257 glFlush(); 258 return true; 259 } 260 261 void ProcessKeyboard() 262 { 263 // Spin object 264 if (keys[VK_LEFT]) yspeed -= 0.001f; 265 if (keys[VK_RIGHT]) yspeed += 0.001f; 266 if (keys[VK_UP]) xspeed -= 0.001f; 267 if (keys[VK_DOWN]) xspeed += 0.001f; 268 269 // Adjust light's position 270 if (keys['L']) LightPos[0] += 0.01f; 271 if (keys['J']) LightPos[0] -= 0.01f; 272 if (keys['I']) LightPos[1] += 0.01f; 273 if (keys['K']) LightPos[1] -= 0.01f; 274 if (keys['O']) LightPos[2] += 0.01f; 275 if (keys['U']) LightPos[2] -= 0.01f; 276 277 // Adjust object's position 278 if (keys[VK_NUMPAD6]) ObjectPosition[0] += 0.01f; 279 if (keys[VK_NUMPAD4]) ObjectPosition[0] -= 0.01f; 280 if (keys[VK_NUMPAD8]) ObjectPosition[1] += 0.01f; 281 if (keys[VK_NUMPAD5]) ObjectPosition[1] -= 0.01f; 282 if (keys[VK_NUMPAD9]) ObjectPosition[2] += 0.01f; 283 if (keys[VK_NUMPAD7]) ObjectPosition[2] -= 0.01f; 284 285 // Adjust ball's position 286 if (keys['D']) SpherePosition[0] += 0.01f; 287 if (keys['A']) SpherePosition[0] -= 0.01f; 288 if (keys['W']) SpherePosition[1] += 0.01f; 289 if (keys['S']) SpherePosition[1] -= 0.01f; 290 if (keys['E']) SpherePosition[2] += 0.01f; 291 if (keys['Q']) SpherePosition[2] -= 0.01f; 292 } 293 294 /******************************************************************************************************************************************/ 295 /******************************************************************************************************************************************/ 296 /* 297 * The job of KillGLWindow() is to release the Rendering Context, 298 * the Device Context and finally the Window Handle. 299 */ 300 301 GLvoid KillGLWindow(GLvoid) // Properly kill the window 302 { 303 if (fullscreen) { // Are we in fullscreen mode 304 305 /* 306 * We use ChangeDisplaySettings(NULL,0) to return us to our original desktop. 307 * After we've switched back to the desktop we make the cursor visible again. 308 */ 309 310 ChangeDisplaySettings(NULL, 0); // if so switch back to the desktop 311 ShowCursor(TRUE); // Show mouse pointer 312 } 313 314 if (hRC) { // Do we have a rendering context 315 if (!wglMakeCurrent(NULL, NULL)) { // Are we able to release the DC and RC contexts 316 MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 317 } 318 319 if (!wglDeleteContext(hRC)) { // Are we able to delete the RC 320 MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 321 hRC = NULL; // Set RC to NULL 322 } 323 324 if (hDC && !ReleaseDC(hWnd, hDC)) { // Are we able to release the DC 325 MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 326 hDC = NULL; // Set DC to NULL 327 } 328 if (hWnd && !DestroyWindow(hWnd)) { // Are we able to destroy the window 329 MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 330 hWnd = NULL; // Set hWnd to NULL 331 } 332 333 if (!UnregisterClass("OpenGL", hInstance)) { // Are we able to unregister class 334 MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); 335 hInstance = NULL; // Set hInstance to NULL 336 } 337 } 338 //******************************************************************************************************************************************/ 339 //******************************************************************************************************************************************/ 340 killObject(object); 341 //******************************************************************************************************************************************/ 342 //******************************************************************************************************************************************/ 343 } 344 345 /* 346 * The next section of code creates our OpenGL Window. 347 */ 348 349 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag) 350 { 351 /* 352 * Find a pixel format that matches the one we want 353 */ 354 GLuint PixelFormat; // Holds the result after serching for a match 355 356 /* 357 * Before you create a window, you MUST register a Class for the window 358 */ 359 WNDCLASS wc; // Windows class structure 360 361 /* 362 * dwExStyle and dwStyle will store the Extended and normal Window Style Information. 363 */ 364 DWORD dwExStyle; // Window extend style 365 DWORD dwStyle; // Window style 366 367 368 RECT WindowRect; // Grabs rectangle upper left/lower right values 369 WindowRect.left = (long)0; // Set left value to 0 370 WindowRect.right = (long)width; // Set right value to requested width 371 WindowRect.top = (long)0; // Set top value to 0 372 WindowRect.bottom = (long)height; // Set bottom value to requested height 373 374 fullscreen = fullscreenflag; // Set the global fullscreen flag 375 376 /* 377 * The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 378 * CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 379 * WndProc is the procedure that watches for messages in our program. 380 * No extra Window data is used so we zero the two fields. Then we set the instance. 381 * Next we set hIcon to NULL meaning we don't want an ICON in the Window, 382 * and for a mouse pointer we use the standard arrow. The background color doesn't matter 383 * (we set that in GL). We don't want a menu in this Window so we set it to NULL, 384 * and the class name can be any name you want. I'll use "OpenGL" for simplicity. 385 */ 386 hInstance = GetModuleHandle(NULL); // Grab an instance for our window 387 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw on move, and own DC for window 388 wc.lpfnWndProc = (WNDPROC)WndProc; // WndProc handles message 389 wc.cbClsExtra = 0; // No extra window date 390 wc.cbWndExtra = 0; // No extra window date 391 wc.hInstance = hInstance; // set the instance 392 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load the default icon 393 wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the arrow pointer 394 wc.hbrBackground = NULL; // No background requried for GL 395 wc.lpszMenuName = NULL; // We don't want a menu 396 wc.lpszClassName = "OpenGL"; // set the class name 397 398 if (!RegisterClass(&wc)) { // Attempt to register the window class 399 MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 400 return FALSE; // Exit and return false 401 } 402 403 if (fullscreen) { // attempt fullsreen model 404 405 /* 406 T* here are a few very important things you should keep in mind when switching to full screen mode. 407 * Make sure the width and height that you use in fullscreen mode is the same as 408 * the width and height you plan to use for your window, and most importantly, 409 * set fullscreen mode BEFORE you create your window. 410 */ 411 DEVMODE dmScreenSettings; // Device mode 412 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared 413 dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size of devmode structure 414 dmScreenSettings.dmPelsWidth = width; // Select window width 415 dmScreenSettings.dmPelsHeight = height; // Select window height 416 dmScreenSettings.dmBitsPerPel = bits; // Select bits per pixel 417 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 418 419 /* 420 * In the line below ChangeDisplaySettings tries to switch to a mode that matches 421 * what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 422 * because it's supposed to remove the start bar at the bottom of the screen, 423 * plus it doesn't move or resize the windows on your desktop when you switch to 424 * fullscreen mode and back. 425 */ 426 //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar 427 if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { 428 //If the mode fails, offer two options. Quit or run in a window 429 if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use" 430 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES) 431 { 432 fullscreen = FALSE; // Select windowed mode (fullscreen=FLASE) 433 } 434 else { 435 // Pop up a message box letting user know the programe is closing. 436 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP); 437 return FALSE; // Exit and return FALSE 438 } 439 } 440 } 441 442 if (fullscreen) { // Are we still in fullscreen mode 443 444 /* 445 * If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 446 * which force a top level window down to the taskbar once our window is visible. 447 * For the window style we'll create a WS_POPUP window. 448 * This type of window has no border around it, making it perfect for fullscreen mode. 449 450 * Finally, we disable the mouse pointer. If your program is not interactive, 451 * it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though. 452 */ 453 dwExStyle = WS_EX_APPWINDOW; // Window extended style 454 dwStyle = WS_POPUP; // Window style 455 ShowCursor(FALSE); // Hide mosue pointer 456 } 457 else { 458 459 /* 460 * If we're using a window instead of fullscreen mode, 461 * we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 462 * For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 463 * WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 464 * window menu, and minimize / maximize buttons. 465 */ 466 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style 467 dwStyle = WS_OVERLAPPEDWINDOW; // Window style 468 } 469 470 /* 471 * By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 472 * instead, the window will be made larger to account for the pixels needed to draw the window border. 473 * In fullscreen mode, this command has no effect. 474 */ 475 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust window to true resqusted 476 477 /* 478 * WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 479 * These styles prevent other windows from drawing over or into our OpenGL Window. 480 */ 481 if (!(hWnd = CreateWindowEx(dwExStyle, // Extended style for the window 482 "OpenGL", // Class name 483 title, // Window title 484 WS_CLIPSIBLINGS | // Requried window style 485 WS_CLIPCHILDREN | // Requried window style 486 dwStyle, // Select window style 487 0, 0, // Window position 488 WindowRect.right - WindowRect.left, // Calculate adjusted window width 489 WindowRect.bottom - WindowRect.top, // Calculate adjusted window height 490 NULL, // No parent window 491 NULL, // No menu 492 hInstance, // Instance 493 NULL))) // Don't pass anything to WM_CREATE 494 { 495 KillGLWindow(); //Reset the display 496 MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 497 return FALSE; // Retrurn FALSE; 498 } 499 500 /* 501 * aside from the stencil buffer and the (slow) accumulation buffer 502 */ 503 static PIXELFORMATDESCRIPTOR pfd = // pfd tells windows how we want things to be 504 { 505 sizeof(PIXELFORMATDESCRIPTOR), // Size of this pixel format descriptor 506 1, // Version number 507 PFD_DRAW_TO_WINDOW | // Format must support window 508 PFD_SUPPORT_OPENGL | // Format must support OpenGL 509 PFD_DOUBLEBUFFER, // Must support double buffer 510 PFD_TYPE_RGBA, // Request an RGBA format 511 bits, // Select our color depth 512 0, 0, 0, 0, 0, 0, // Color bits ignored 513 0, // No alpha buffer 514 0, // shift bit ignored 515 0, // No accumulation buffer 516 0, 0, 0, 0, // Accumulation bits ignored 517 16, // 16Bits Z_Buffer (depth buffer) 518 1, // stencil buffer 519 0, // No auxiliary buffer 520 PFD_MAIN_PLANE, // Main drawing layer 521 0, // Reserved 522 0, 0, 0 // Layer makes ignored 523 }; 524 525 if (!(hDC = GetDC(hWnd))) { // Did we get a device context 526 KillGLWindow(); // Reset the display 527 MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 528 return FALSE; // Return FALSE 529 } 530 531 if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { // Did window find a matching pixel format 532 KillGLWindow(); // Reset the display 533 MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 534 return FALSE; // Return FALSE; 535 } 536 537 if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { // Are we able to set the pixel format 538 KillGLWindow(); // Reset the display 539 MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 540 return FALSE; // Return FALSE; 541 } 542 543 if (!(hRC = wglCreateContext(hDC))) { // Are we able to rendering context 544 KillGLWindow(); // Reset the display 545 MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 546 return FALSE; // Return FASLE; 547 } 548 549 if (!wglMakeCurrent(hDC, hRC)) { // Try to activate the rendering context 550 KillGLWindow(); // Reset the display 551 MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 552 return FALSE; // Return FALSE 553 } 554 555 /* 556 * ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen. 557 */ 558 ShowWindow(hWnd, SW_SHOW); // Show the window 559 SetForegroundWindow(hWnd); // slightly higher priority 560 SetFocus(hWnd); // Sets keyboard focus to the window 561 ReSizeGLScene(width, height); // Set up our perspective GL screen 562 563 /* 564 * we can set up lighting, textures, and anything else that needs to be setup in InitGL(). 565 */ 566 if (!InitGL()) { // Initialize our newly created GL window 567 KillGLWindow(); // Reset the display 568 MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION); 569 return FALSE; // Return FALSE 570 } 571 return TRUE; 572 } 573 574 LRESULT CALLBACK WndProc(HWND hWnd, // Handle for this window 575 UINT uMsg, // Message for this window 576 WPARAM wParam, // Additional message information 577 LPARAM lParam) // Additional message information 578 { 579 switch (uMsg) { // Check for window message 580 case WM_ACTIVATE: { // Check minimization state 581 if (!HIWORD(wParam)) { 582 active = TRUE; // Program is active 583 } 584 else { 585 active = FALSE; // Program is no longer active 586 } 587 return 0; // Return to the message loop 588 } 589 case WM_SYSCOMMAND: { // Intercept system commands 590 switch (wParam) { // Check system calls 591 case SC_SCREENSAVE: // Screensaver trying to start 592 case SC_MONITORPOWER: // Monitor trying to enter powersave 593 return 0; // Prevent form happening 594 } 595 break; // Exit 596 } 597 case WM_CLOSE: { // Did we receive a close message 598 PostQuitMessage(0); // Send a quit message 599 return 0; 600 } 601 case WM_KEYDOWN: { // Is a key being held down 602 keys[wParam] = TRUE; // if so, mark it as TRUE 603 return 0; // Jump back 604 } 605 case WM_KEYUP: { // Has a key been released 606 keys[wParam] = FALSE; // if so, mark it as FALSE 607 return 0; // Jump back 608 } 609 case WM_SIZE: { // Resize the OpenGL window 610 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord = width HiWord = height 611 return 0; // Jump back 612 } 613 } 614 return DefWindowProc(hWnd, uMsg, wParam, lParam); // Pass all unhandled message to DefWindwProc 615 } 616 617 int WINAPI WinMain(HINSTANCE hInstance, // Instance 618 HINSTANCE hPrevInstance, // Previous instance 619 LPSTR lpCmdLine, // Command line parameters 620 int nCmdShow) // Window show state 621 { 622 MSG msg; // Window message structure 623 BOOL done = FALSE; // Bool variable to exit loop 624 // Ask the user which screen mode they prefer 625 if (MessageBox(NULL, "Would you like to run in fullscreen mode?", 626 "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO) 627 { 628 fullscreen = FALSE; // Window mode 629 } 630 // Create our OpenGL window 631 if (!CreateGLWindow("3D Shapes", 800, 600, 32, fullscreen)) { // (Modified) 632 return 0; // Quit if window was not create 633 } 634 while (!done) { // Loop that runs until donw = TRUE 635 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // Is there a message wating 636 if (msg.message == WM_QUIT) { // Havw we received a quit message 637 done = TRUE; // if so done = TRUE 638 } 639 else { // If not, deal with window message 640 TranslateMessage(&msg); // Translate message 641 DispatchMessage(&msg); // Dispatch message 642 } 643 } 644 else { 645 // Draw the scene. Watch for ESC key and quit message from DrawGLScene() 646 if (active) { // Program active 647 if (keys[VK_ESCAPE]) { // Was ESC pressed 648 done = TRUE; // ESC signalled a quit 649 } 650 else { // Not time to quit, update screen 651 DrawGLScene(); // Draw scene 652 SwapBuffers(hDC); // Swap buffers (double buffering) 653 ProcessKeyboard(); 654 } 655 } 656 /* 657 * It allows us to press the F1 key to switch from fullscreen mode to 658 * windowed mode or windowed mode to fullscreen mode. 659 */ 660 if (keys[VK_F1]) { // Is F1 being pressed 661 keys[VK_F1] = FALSE; // If so make key FASLE 662 KillGLWindow(); // Kill our current window 663 fullscreen = !fullscreen; // Toggle fullscreen / window mode 664 //Recreate our OpenGL window(modified) 665 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) { 666 return 0; // Quit if window was not create 667 } 668 } 669 } 670 } 671 // Shutdown 672 KillGLWindow(); // Kill the window 673 return (msg.wParam); // Exit the program 674 }
Thanks for Nehe's tutorials, this is his home.