fix ebn warnings regarding includes
[kdegames.git] / kubrick / src / cube.cpp
blob3d85ae5236a5ba38df91f6763b92e2a52685c86d
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 // Own header
20 #include "cube.h"
22 // The RubikCube object uses the sqrt() function.
23 #include <math.h>
24 #include <stdlib.h>
26 // Local includes
27 #include "gameglview.h"
29 // Create a Cube
31 Cube::Cube (QObject * parent, int xlen, int ylen, int zlen)
32 : QObject (parent)
34 sizes [X] = xlen;
35 sizes [Y] = ylen;
36 sizes [Z] = zlen;
38 // Generate a list of all the cubies in the cube.
39 // Set the centres of cubies at +ve and -ve co-ords around (0,0,0),
40 // as documented in "game.h". The cubie dimensions are 2x2x2. Each
41 // cubie's centre co-ordinate is (2*index - end-face-pos + 1).
42 int centre [nAxes];
44 while (! cubies.isEmpty()) {
45 delete cubies.takeFirst();
47 LOOP (i, sizes [X]) {
48 centre [X] = 2*i - sizes [X] + 1;
49 LOOP (j, sizes [Y]) {
50 centre [Y] = 2*j - sizes [Y] + 1;
51 LOOP (k, sizes [Z]) {
52 centre [Z] = 2*k - sizes [Z] + 1;
53 cubies.append (new Cubie (centre));
58 addStickers (); // Add colored stickers to the faces.
60 setBlinkingOff ();
61 moveInProgressAxis = Z; // Front face (+Z).
62 moveInProgressSlice = sizes[Z] - 1;
63 moveInProgressAngle = 0;
66 Cube::~Cube ()
68 while (! cubies.isEmpty()) {
69 delete cubies.takeFirst();
73 void Cube::moveSlice (Axis axis, int location, Rotation direction)
75 // If single-slice and not square, rotate 180 degrees rather than 90.
76 if ((location != WHOLE_CUBE) &&
77 (sizes [(axis + 1)%nAxes] != sizes [(axis + 2)%nAxes])) {
78 direction = ONE_EIGHTY;
81 // Rotate all cubies that are in the required slice.
82 foreach (Cubie * cubie, cubies) {
83 cubie->rotate (axis, location, direction);
85 setBlinkingOff ();
88 void Cube::addStickers ()
90 int color = INTERNAL; // ie. Zero.
92 // Add stickers to cube faces in the order of axes X/Y/Z then -ve/+ve end.
93 LOOP (n, nAxes) {
94 LOOP (minusPlus, 2) {
95 int sign = 2*minusPlus - 1; // sign = -1 or +1.
96 int location = sign * sizes [n];
98 color++; // FaceColor enum 1 --> 6.
99 foreach (Cubie * cubie, cubies) {
100 cubie->addSticker ((FaceColor) color, (Axis) n, location, sign);
107 void Cube::drawCube (GameGLView * gameGLView, float cubieSize)
109 // For each cubie in the cube ...
110 foreach (Cubie * cubie, cubies) {
112 if (cubie->hasNoStickers()) {
113 // This cubie is deep inside the cube: save time by not drawing it.
114 continue;
117 // Draw the cubie and its stickers.
118 cubie->drawCubie (gameGLView, cubieSize,
119 moveInProgressAxis, moveInProgressSlice, moveInProgressAngle);
124 bool Cube::findSticker (double position [], float myCubieSize,
125 int faceCentre [])
127 bool result = false;
128 double location [nAxes];
129 double distance = sqrt ((double) 2.0);
130 double d;
132 // Calculate the position in the cube's internal co-ordinate system.
133 LOOP (i, nAxes) {
134 location [i] = (position [i] / myCubieSize) * 2.0;
135 // IDW faceCentre [i] = 0; // Return zeroes if no sticker is found.
138 foreach (Cubie * cubie, cubies) {
139 d = cubie->findCloserSticker (distance, location, faceCentre);
140 if (d < distance) {
141 distance = d;
142 result = true;
146 return (result);
150 void Cube::setMoveInProgress (Axis axis, int location)
152 setBlinkingOff ();
153 moveInProgressAxis = axis;
154 moveInProgressSlice = location;
158 void Cube::setMoveAngle (int angle)
160 moveInProgressAngle = angle;
164 void Cube::setBlinkingOn (Axis axis, int location)
166 foreach (Cubie * cubie, cubies) {
167 cubie->setBlinkingOn (axis, location, sizes[axis]);
172 void Cube::setBlinkingOff ()
174 foreach (Cubie * cubie, cubies) {
175 cubie->setBlinkingOff ();
180 int Cube::faceNormal (int faceCentre [3])
182 LOOP (i, nAxes) {
183 if (abs(faceCentre [i]) == sizes [i]) {
184 return i;
187 return 0;
191 double Cube::convToOpenGL (int internalCoord, double cubieSize)
193 return ((double) internalCoord / 2.0) * cubieSize;
196 Cubie::Cubie (int centre [nAxes])
198 LOOP (i, nAxes) {
199 originalCentre [i] = centre [i];
200 currentCentre [i] = centre [i];
205 Cubie::~Cubie ()
207 while (! stickers.isEmpty()) {
208 delete stickers.takeFirst();
213 void Cubie::rotate (Axis axis, int location, Rotation direction)
215 // Cubie moves only if it is in the required slice or in a whole-cube move.
216 if ((location != WHOLE_CUBE) && (currentCentre [axis] != location)) {
217 return;
220 // The co-ordinate on the axis of rotation does not change, but we must
221 // work out what the other two co-ordinates are, in cyclical order: i.e.
222 // X-axis (0) --> Y,Z (co-ordinates 1 and 2 change),
223 // Y-axis (1) --> Z,X (co-ordinates 2 and 0 change),
224 // Z-axis (2) --> X,Y (co-ordinates 0 and 1 change).
226 Axis coord1 = (Axis) ((axis + 1) % nAxes);
227 Axis coord2 = (Axis) ((axis + 2) % nAxes);
228 int temp;
230 switch (direction) {
231 case (ANTICLOCKWISE): // eg. around the Z-axis, X --> Y and Y --> -X.
232 temp = currentCentre [coord1];
233 currentCentre [coord1] = - currentCentre [coord2];
234 currentCentre [coord2] = + temp;
235 foreach (Sticker * s, stickers) {
236 temp = s->currentFaceCentre [coord1];
237 s->currentFaceCentre [coord1] = - s->currentFaceCentre [coord2];
238 s->currentFaceCentre [coord2] = + temp;
240 break;
241 case (CLOCKWISE): // eg. around the Z-axis, X --> -Y and Y --> X.
242 temp = currentCentre [coord1];
243 currentCentre [coord1] = + currentCentre [coord2];
244 currentCentre [coord2] = - temp;
245 foreach (Sticker * s, stickers) {
246 temp = s->currentFaceCentre [coord1];
247 s->currentFaceCentre [coord1] = + s->currentFaceCentre [coord2];
248 s->currentFaceCentre [coord2] = - temp;
250 break;
251 case (ONE_EIGHTY): // eg. around the Z-axis, X --> -X and Y --> -Y.
252 currentCentre [coord1] = - currentCentre [coord1];
253 currentCentre [coord2] = - currentCentre [coord2];
254 foreach (Sticker * s, stickers) {
255 s->currentFaceCentre [coord1] = - s->currentFaceCentre [coord1];
256 s->currentFaceCentre [coord2] = - s->currentFaceCentre [coord2];
258 break;
259 default:
260 break;
265 void Cubie::addSticker (FaceColor color, Axis axis, int location, int sign)
267 // The cubie will get a sticker only if it is on the required face.
268 if (originalCentre [axis] != (location - sign)) {
269 return;
272 // Create a sticker.
273 Sticker * s = new Sticker;
274 s->color = color;
275 s->blinking = false;
276 LOOP (n, nAxes) {
277 // The co-ordinates not on "axis" are the same as at the cubie's centre.
278 s->originalFaceCentre [n] = originalCentre [n];
279 s->currentFaceCentre [n] = originalCentre [n];
282 // The co-ordinate on "axis" is offset by -1 or +1 from the cubie's centre.
283 s->originalFaceCentre [axis] = location;
284 s->currentFaceCentre [axis] = location;
286 // Put the sticker on the cubie.
287 stickers.append (s);
291 bool Cubie::hasNoStickers ()
293 return (stickers.isEmpty ());
297 void Cubie::drawCubie (GameGLView * gameGLView, float cubieSize,
298 Axis axis, int slice, int angle)
300 float centre [nAxes];
302 // Calculate the centre of the cubie in OpenGL co-ordinates.
303 LOOP (i, nAxes) {
304 centre [i] = ((float) currentCentre [i]) * cubieSize / 2.0;
307 // If this cubie is in a moving slice, set its animation angle.
308 int myAngle = 0;
309 if ((angle != 0) && ((slice == WHOLE_CUBE) ||
310 (currentCentre [axis] == slice))) {
311 myAngle = angle;
314 // Draw this cubie in color zero (grey plastic color).
315 gameGLView->drawACubie (cubieSize, centre, axis, myAngle);
317 float faceCentre [nAxes];
318 int faceNormal [nAxes];
320 // For each sticker on this cubie (there may be 0->3 stickers) ...
321 foreach (Sticker * sticker, stickers) {
323 // Calculate the integer unit-vector normal to this sticker's face
324 // and the centre of the face, in floating OpenGL co-ordinates.
325 LOOP (j, nAxes) {
326 faceNormal [j] = sticker->currentFaceCentre [j] - currentCentre [j];
327 faceCentre [j] = ((float) sticker->currentFaceCentre [j]) *
328 cubieSize / 2.0;
331 // Draw this sticker in the required color, blink-intensity and size.
332 gameGLView->drawASticker (cubieSize, (int) sticker->color,
333 sticker->blinking, faceNormal, faceCentre);
336 // If cubie is moving, re-align the OpenGL axes with the rest of the cube.
337 if (myAngle != 0) {
338 gameGLView->finishCubie ();
343 double Cubie::findCloserSticker (double distance, double location [],
344 int faceCentre [])
346 double len = 0.0;
347 double dmin = distance;
348 Sticker * foundSticker = 0;
350 foreach (Sticker * sticker, stickers) {
351 double d = 0.0;
352 LOOP (n, nAxes) {
353 len = location[n] - sticker->currentFaceCentre[n];
354 d = d + len * len;
356 d = sqrt (d);
357 if (d < dmin) {
358 dmin = d;
359 foundSticker = sticker;
363 if (foundSticker != 0) {
364 LOOP (n, nAxes) {
365 faceCentre[n] = foundSticker->currentFaceCentre[n];
369 return (dmin);
373 void Cubie::setBlinkingOn (Axis axis, int location, int cubeBoundary)
375 // Exit if the cubie is not in the slice that is going to move.
376 if ((location != WHOLE_CUBE) && (currentCentre [axis] != location)) {
377 return;
380 // If the sticker is on the outside edges of the slice, make it blink, but
381 // not if it is perpendicular to the move-axis (ie. on the slice's face).
382 foreach (Sticker * sticker, stickers) {
383 if (abs(sticker->currentFaceCentre [axis]) != cubeBoundary) {
384 sticker->blinking = true;
390 void Cubie::setBlinkingOff ()
392 foreach (Sticker * sticker, stickers) {
393 sticker->blinking = false;
398 void Cubie::printAll ()
400 printf ("%2d %2d %2d -> %2d %2d %2d Stickers: ",
401 originalCentre[X], originalCentre[Y], originalCentre[Z],
402 currentCentre[X], currentCentre[Y], currentCentre[Z]);
404 if (stickers.isEmpty ()) {
405 printf ("<NONE>\n");
407 else {
408 foreach (Sticker * sticker, stickers) {
409 printf ("<%d> at ", (int) sticker->color);
410 LOOP (n, nAxes) {
411 printf ("%2d ", sticker->currentFaceCentre [n]);
414 printf ("\n");
419 void Cubie::printChanges ()
421 bool moved = false;
423 // Check if the cubie's centre is in a new position.
424 LOOP (i, nAxes) {
425 if (currentCentre [i] != originalCentre [i])
426 moved = true;
429 // Check if the cubie is back where it was but has been given a twist.
430 if (! moved) {
431 foreach (Sticker * s, stickers) {
432 LOOP (i, nAxes) {
433 if (s->currentFaceCentre [i] != s->originalFaceCentre [i])
434 moved = true;
439 // If anything has changed, print the cubie.
440 if (moved) {
441 printAll ();