fix ebn warnings regarding includes
[kdegames.git] / kubrick / src / gameglview.cpp
blobdd63bddbda6ff70188cc0c890c95977c749b1d9e
1 /*******************************************************************************
2 Copyright 2008 Ian Wadham <ianw2@optusnet.com.au>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *******************************************************************************/
19 // Local includes
20 #include "gameglview.h"
22 // Qt includes
23 #include <QStringList>
24 #include <QPoint>
25 #include <QImage>
26 #include <QLabel>
27 #include <QMouseEvent>
29 // C++ includes
30 #include <iostream>
32 GameGLView::GameGLView(Game * g, QWidget * parent)
33 : QGLWidget(QGLFormat (QGL::AlphaChannel), parent),
34 bgColor (QColor (0, 0, 35))
36 // Save a pointer to the Game object that controls everything.
37 game = g;
39 this->setMinimumSize (450, 300);
41 // Set the amount of bevelling on a cubie's edge to its default value.
42 bevelAmount = 0.125;
44 // Set colors to full intensity (no blinking).
45 blinkIntensity = 1.0;
47 // Note: Do not use OpenGL functions here.
48 // Initialize OpenGL in initializeGL() instead!
50 const GLubyte * v = glGetString(GL_VERSION);
51 printf ("GL Version %s\n", v);
55 void GameGLView::initializeGL()
57 // Make glClear() clear to a deep-blue background.
58 qglClearColor (bgColor);
60 // Disable dithering which is usually not needed
61 glDisable(GL_DITHER);
63 // Set up fixed lighting.
64 glMatrixMode(GL_MODELVIEW);
65 glLoadIdentity();
66 turnOnLighting();
70 void GameGLView::resizeGL(int w, int h)
72 // Make use of the whole view.
73 glViewport(0, 0, w, h);
75 // Setup a 3D projection matrix
76 glMatrixMode(GL_PROJECTION);
77 glLoadIdentity();
78 gluPerspective(viewAngle, ((GLdouble)w)/((GLdouble)h), minZ, maxZ);
79 glMatrixMode(GL_MODELVIEW);
81 // Re-position the view-labels.
82 game->setSceneLabels ();
86 float GameGLView::colors [7] [3] = {
87 {0.2, 0.2, 0.2}, // Dark grey.
88 {1.0, 0.5, 0.1}, // Orange.
89 {0.7, 0.0, 0.0}, // Red.
90 {1.0, 1.0, 0.0}, // Yellow.
91 {0.0, 0.5, 0.0}, // Green.
92 {0.0, 0.0, 0.8}, // Blue.
93 {0.9, 0.9, 0.8} // Off-white.
97 void GameGLView::paintGL()
99 // Clear the view.
100 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
102 // Reset the modelview matrix. By doing so we also reset the "camera" that
103 // is the eye position, so that it is now at (0,0,0), which is also the
104 // center of the screen. We are looking down the negative Z axis, towards
105 // (0,0,-1), with "up" being at (0,1,0).
106 glLoadIdentity();
108 if (checkGLError()) {
109 std::cerr << "OpenGL error detected before drawScene()" << std::endl;
112 game->drawScene ();
114 if (checkGLError()) {
115 std::cerr << "OpenGL error detected after drawScene()" << std::endl;
120 void GameGLView::dumpExtensions()
122 // OpenGL Extension detection.
123 QString s = (const char*)glGetString(GL_EXTENSIONS);
124 s += " ";
125 s += (const char*)gluGetString(GLU_EXTENSIONS);
126 QStringList extensions = s.split (" ", QString::SkipEmptyParts);
127 for (int i = 0; i < extensions.count(); i++)
129 std::cout << extensions[i].toLatin1().data() << std::endl;
133 static bool printed = false;
135 static float ambient[] = {0.0, 0.0, 0.0, 1.0};
136 static float diffuse[] = {1.0, 1.0, 1.0, 1.0};
138 // Directional light, at infinity (parameter 4, w=0.0), shining
139 // towards -Z. No attenuation. Diffuse, no spotlight effect.
140 static float position0[] = {0.0, 0.0, 1.0, 0.0};
142 // With lights off, 100% ambient gives a flat, dull, fairly well-lit picture.
143 // With lights on, it makes little difference to specular effect, but makes
144 // the strong colors of stickers look a bit washed out. So choose 60%.
145 static float lmodel_ambient[] = {0.6, 0.6, 0.6, 1.0};
147 // Controls SPREAD of specular reflections (128.0 = small highlight).
148 static float material_shininess = 60.0;
150 // Controls intensity and color of specular reflections.
151 static float material_specular[] = {0.5, 0.6, 0.5, 1.0};
153 // Trying to light the insides of the cubies is a waste of time.
154 static float lmodel_twoside[] = {GL_FALSE};
156 void GameGLView::turnOnLighting ()
158 // There is just one light.
159 glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
160 glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
161 glLightfv (GL_LIGHT0, GL_POSITION, position0);
163 glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
164 glLightModelfv (GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
166 // This gives a rolling-sheen effect to the specularity.
167 // Not all stickers on a face light up at once.
168 glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
170 glEnable (GL_LIGHTING);
171 glEnable (GL_LIGHT0);
173 glEnable (GL_DEPTH_TEST);
174 glEnable (GL_NORMALIZE);
176 // Do not render the backs (interiors) of cubie and sticker faces. The
177 // "front" faces are those for which the order of drawing of the vertices
178 // is anti-clockwise, as seen from the outside looking towards the centre.
179 glEnable (GL_CULL_FACE);
181 glShadeModel (GL_FLAT);
182 glMaterialf (GL_FRONT, GL_SHININESS, material_shininess);
183 glMaterialfv (GL_FRONT, GL_SPECULAR, material_specular);
185 // This tracks color CHANGES and updates the corresponding glMaterial*.
186 glEnable (GL_COLOR_MATERIAL);
187 glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
191 QPoint GameGLView::getMousePosition ()
193 QPoint p;
194 p = mapFromGlobal (QCursor::pos()); // Convert to window co-ordinates.
196 // Convert Y co-ordinate to OpenGL convention (zero at bottom of window).
197 p.setY (height() - p.y());
198 return p;
202 void GameGLView::pushGLMatrix ()
204 glPushMatrix();
208 void GameGLView::moveGLView (float xChange, float yChange, float zChange)
210 glTranslatef (xChange, yChange, zChange);
214 void GameGLView::rotateGLView (float degrees, float x, float y, float z)
216 glRotatef (degrees, x, y, z);
220 void GameGLView::popGLMatrix ()
222 glPopMatrix();
226 void GameGLView::setBevelAmount (int bevelPerCent)
228 bevelAmount = ((float) bevelPerCent)/100.0;
232 void GameGLView::drawACubie (float size, float centre[], int axis, int angle)
234 float lenA = 0.5 * size; // Half of a cubie's outside dimension.
235 float bevel = bevelAmount * lenA; // The size of the bevel at the edges.
236 float lenB = lenA - bevel; // Half of a face's inside dimension.
238 float p[nAxes]; // The point to be drawn currently.
239 float normal[nAxes]; // The current normal vector (used in lighting).
240 // Needs to be of length 1 for best results.
241 float r2 = 0.7071067; // (1 / sqrt (2.0)), used for bevel normals.
242 float r3 = 0.5773502; // (1 / sqrt (3.0)), used for corner normals.
244 printed = true; // Suppress printing of co-ordinates.
246 // If the cubie is moving, rotate it around the required axis of the cube.
247 if (angle != 0) {
248 GLfloat v [nAxes] = {0.0, 0.0, 0.0};
249 v [axis] = 1.0;
250 glPushMatrix();
251 glRotatef ((GLfloat) (-angle), v[0], v[1], v[2]);
254 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
255 glPushMatrix();
257 glColor3fv (colors [0]); // The base color of a cubie, without stickers.
259 // Bring the centre to the origin during drawing.
260 glTranslatef ((GLfloat) centre[X],
261 (GLfloat) centre[Y],
262 (GLfloat) centre[Z]);
264 // Draw three pairs of faces of the cubie and twelve bevelled edges.
265 glBegin(GL_QUADS);
266 LOOP (axis, 3) {
268 // The coordinate on the axis thru the face does not change, but we must
269 // work out what the other two coordinates are, in cyclical order: i.e.
270 // X-axis (0) --> Y,Z (coordinates 1 and 2 change),
271 // Y-axis (1) --> Z,X (coordinates 2 and 0 change),
272 // Z-axis (2) --> X,Y (coordinates 0 and 1 change).
274 int coord1 = 0;
275 int coord2 = 0;
277 // Draw two opposite faces of the cubie and two bevelled edges each.
278 LOOP (face, 2) {
280 // Draw one face of the cubie.
281 // For (i,j) = (0,0), (0,1), (1,0) and (1,1), we will get values
282 // (i,k) = (0,0), (0,1), (1,1) and (1,0) and will be drawing
283 // vertices going around a square face of the cubie.
285 normal[coord1] = 0.0;
286 normal[coord2] = 0.0;
287 normal[axis] = (2*face -1) * 1.0; // -1.0 or +1.0.
288 glNormal3fv (normal); // Used by lighting.
290 p[axis] = (2*face-1) * lenA; // Value -lenA or +lenA.
291 // The axes are chosen so that the vertices go in "GL front face"
292 // order (ie. anti-clockwise), as viewed from outside the cubie.
293 if (p[axis] > 0.0) {
294 coord1 = (axis + 2) % 3;
295 coord2 = (axis + 1) % 3;
297 else {
298 coord1 = (axis + 1) % 3;
299 coord2 = (axis + 2) % 3;
302 LOOP (i, 2) {
303 p[coord1] = (2*i-1) * lenB; // Value -lenB or +lenB.
304 LOOP (j, 2) {
305 int k = (i + j) % 2; // Takes values 0 1 1 0.
306 p[coord2] = (2*k-1) * lenB; // Value -lenB or +lenB.
307 glVertex3fv (p); // Draw one of 4 vertices.
308 if (! printed)
309 printf("Axis[%d] %5.2f %5.2f %5.2f\n",
310 axis, p[X], p[Y], p[Z]);
314 // Draw two of this face's bevelled edges.
315 // Eventually, for 6 faces, all 12 edges will have been drawn.
316 coord1 = (axis + 1) % 3;
317 coord2 = (axis + 2) % 3;
318 normal[axis] = (2*face -1) * r2;
319 LOOP (edge, 2) {
320 normal[coord1] = (2*edge -1) * r2;
321 normal[coord2] = 0.0;
322 glNormal3fv (normal); // Used by lighting.
324 LOOP (i, 2) {
325 p[axis] = (2*face-1) * (lenA - ((edge + i)%2) * bevel);
326 p[coord1] = (2*edge-1) * lenB + (edge - i) * bevel;
327 LOOP (j, 2) {
328 int k = (i + j) % 2; // Takes values 0 1 1 0.
329 // p[coord2] = -lenB, +lenB, +lenB, -lenB on the + face
330 // and = +lenB, -lenB, -lenB, +lenB on the - face,
331 // thus ensuring anti-clockwise drawing of all 4 bevels
332 // as you view each face from the outside loooking in.
333 p[coord2] = (2*face -1) * (2*k-1) * lenB;
334 glVertex3fv (p); // Draw 1 of 4 vertices.
335 if (! printed)
336 printf("Edge[%d] %5.2f %5.2f %5.2f\n",
337 edge, p[X], p[Y], p[Z]);
340 } // END (edge, 2)
342 } // END (face, 2)
344 } // END (axis, 3)
346 glEnd();
348 // Draw the 8 chiselled corners on the back and front faces of the cubie.
349 glBegin(GL_TRIANGLES);
350 LOOP (face, 2) {
351 float z = ((float) 2*face-1); // Z direction: +r3 or -r3.
352 LOOP (i, 2) {
353 float x = ((float) 2*i-1); // X direction: +r3 or -r3.
354 LOOP (j, 2) {
355 float y = ((float) 2*j-1); // Y direction: +r3 or -r3.
357 glNormal3f (x*r3, y*r3, z*r3); // Used by lighting.
359 // Draw the triangular facet at this corner of the face.
360 // The vertices must go in "GL front face" order (ie. anti-
361 // clockwise), as viewed from outside the cubie.
363 if ((x * y * z) > 0.0) {
364 // If 0 or 2 negatives, go round the vertices one way.
365 glVertex3f (x*lenA, y*lenB, z*lenB); // A
366 glVertex3f (x*lenB, y*lenA, z*lenB); // B
367 glVertex3f (x*lenB, y*lenB, z*lenA); // C
369 else {
370 // If 1 or 3 negatives, go round the vertices the other way.
371 glVertex3f (x*lenA, y*lenB, z*lenB); // A
372 glVertex3f (x*lenB, y*lenB, z*lenA); // C
373 glVertex3f (x*lenB, y*lenA, z*lenB); // B
375 // if (! printed)
376 // printf("Corner[%d] %5.2f %5.2f %5.2f\n",
377 // face, x, y, z);
380 } // END (face, 2)
382 glEnd();
384 printed = true;
385 glPopAttrib();
386 glPopMatrix();
387 checkGLError();
391 void GameGLView::finishCubie ()
393 // If the cubie just drawn is moving, restore the OpenGL co-ordinate axes.
394 glPopMatrix();
398 void GameGLView::drawASticker (float size, int color, bool blinking,
399 int faceNormal[], float faceCentre [])
401 float lenA = 0.5 * size; // Half of a cubie's outside dimension.
402 float bevel = bevelAmount * lenA; // The size of the bevel at the edges.
403 float lenB = lenA - bevel; // Half the sticker's dimension.
405 float p[nAxes]; // The point to be drawn currently.
406 float normal[nAxes]; // The normal vector (used in lighting).
408 int axis1 = 0, axis2 = 1; // Two axes in the plane of the sticker.
410 float mColor [3];
412 glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT);
413 glPushMatrix();
415 // Set the color of this sticker.
416 if (blinking) {
417 LOOP (i, 3) {
418 mColor [i] = blinkIntensity * colors [color] [i];
420 glColor3fv (mColor); // Dimmed color.
422 else {
423 glColor3fv (colors [color]); // Normal color.
426 // Bring the centre of the sticker to the origin during drawing.
427 glTranslatef ((GLfloat) faceCentre[X],
428 (GLfloat) faceCentre[Y],
429 (GLfloat) faceCentre[Z]);
431 LOOP (axis, 3) {
432 normal [axis] = 0.0;
433 if (faceNormal [axis] != 0) {
434 // One component of the faceNormal vector is 1: the others are zero.
435 normal [axis] = (float) faceNormal [axis];
437 // The sticker is offset from the cubie's face, along the normal.
438 p [axis] = 0.01 * size * normal [axis];
440 // The coordinate on the normal does not change, but we must work
441 // out what the other two coordinates are, in cyclical order: i.e.
442 // X-axis (0) --> Y,Z (coordinates 1 and 2 change),
443 // Y-axis (1) --> Z,X (coordinates 2 and 0 change),
444 // Z-axis (2) --> X,Y (coordinates 0 and 1 change).
446 // Ensure that the outside face of the sticker is drawn in
447 // anti-clockwise sequence, so GL_CULL_FACE culls the inside one.
449 if (faceNormal [axis] > 0) {
450 axis1 = (axis + 1) % 3;
451 axis2 = (axis + 2) % 3;
453 else {
454 axis2 = (axis + 1) % 3;
455 axis1 = (axis + 2) % 3;
460 glBegin(GL_QUADS);
461 glNormal3fv (normal); // Used by lighting.
463 p [axis1] = + lenB; // Set the first vertex of the sticker.
464 p [axis2] = + lenB;
465 glVertex3fv (p); // Draw the first vertex, eg. (+X,+Y) quadrant.
466 p [axis1] = - lenB;
467 glVertex3fv (p); // Draw the second vertex, eg. (+X,-Y) quadrant.
468 p [axis2] = - lenB;
469 glVertex3fv (p); // Draw the third vertex, eg. (-X,-Y) quadrant.
470 p [axis1] = + lenB;
471 glVertex3fv (p); // Draw the fourth vertex, eg. (+X,-Y) quadrant.
473 glEnd();
475 glPopAttrib();
476 glPopMatrix();
477 checkGLError();
481 void GameGLView::setBlinkIntensity (float intensity)
483 blinkIntensity = intensity;
487 bool GameGLView::checkGLError()
489 GLenum error = glGetError();
490 if (error != GL_NO_ERROR)
492 // std::cerr << "An OpenGL error occurred" << std::endl;
493 return true;
495 return false;
499 void GameGLView::mousePressEvent(QMouseEvent* e)
501 // Convert Y co-ordinate to OpenGL convention (zero at bottom of window).
502 game->handleMouseEvent (ButtonDown, e->button(),
503 e->pos().x(), height() - e->pos().y());
507 void GameGLView::mouseReleaseEvent(QMouseEvent* e)
509 // Convert Y co-ordinate to OpenGL convention (zero at bottom of window).
510 game->handleMouseEvent (ButtonUp, e->button(),
511 e->pos().x(), height() - e->pos().y());
514 // End gameglview.cpp