/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.games.rubik; import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; import java.awt.Dimension; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; /** * Rubik's Cube 3D simulator. * Adapted to JNode by Levente S\u00e1ntha. * * @author Karl H\u00f6rnell, March 11 1996 (Last modified October 6) * */ public final class Rubik extends JComponent { private static final long serialVersionUID = 1L; int i, j, k, n, o, p, q, lastX, lastY, dx, dy; int rectX[], rectY[]; Color colList[], bgcolor; final double sideVec[] = {0, 0, 1, 0, 0, -1, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0}; // Normal vectors final double corners[] = {-1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1}; // Vertex co-ordinates double topCorners[], botCorners[]; final int sides[] = {4, 5, 6, 7, 3, 2, 1, 0, 0, 1, 5, 4, 1, 2, 6, 5, 2, 3, 7, 6, 0, 4, 7, 3}; final int nextSide[] = {2, 3, 4, 5, 4, 3, 2, 5, 1, 3, 0, 5, 1, 4, 0, 2, 1, 5, 0, 3, 2, 0, 4, 1}; final int mainBlocks[] = {0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3}; final int twistDir[] = {-1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1}; final int colDir[] = {-1, -1, 1, -1, 1, -1}; final int circleOrder[] = {0, 1, 2, 5, 8, 7, 6, 3}; int topBlocks[], botBlocks[]; int sideCols[], sideW, sideH; int dragReg, twistSide = -1; int nearSide[], buffer[]; // Which side belongs to dragCorn double dragCorn[], dragDir[]; double eye[] = {0.3651, 0.1826, -0.9129}; // Initial observer co-ordinate axes (view) double eX[] = {0.9309, -0.0716, 0.3581}; // (sideways) double eY[]; // (vertical) double Teye[], TeX[], TeY[]; double light[], temp[] = {0, 0, 0}, temp2[] = {0, 0, 0}, newCoord[]; double sx, sy, sdxh, sdyh, sdxv, sdyv, d, t1, t2, t3, t4, t5, t6; double phi, phibase = 0, Cphi, Sphi, currDragDir[]; boolean naturalState = true, twisting = false, OKtoDrag = false; Math m; Graphics offGraphics; Image offImage; /** * Initialization of the component. */ public void init() { enableEvents(AWTEvent.KEY_EVENT_MASK); setFocusable(true); enableEvents(AWTEvent.FOCUS_EVENT_MASK); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent event) { if (SwingUtilities.isLeftMouseButton(event)) { if (Rubik.this.contains(event.getX(), event.getY())) { if (!Rubik.this.hasFocus() && Rubik.this.isRequestFocusEnabled()) { Rubik.this.requestFocus(); } } } Rubik.this.mousePressed(event.getX(), event.getY()); } public void mouseReleased(MouseEvent event) { Rubik.this.mouseReleased(event.getX(), event.getY()); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent event) { Rubik.this.mouseDragged(event.getX(), event.getY()); } }); addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent event) { Rubik.this.keyPressed(event.getKeyChar()); } }); rectX = new int[4]; rectY = new int[4]; // Projected co-ordinates (on screen) newCoord = new double[16]; dragDir = new double[24]; dragCorn = new double[96]; // Vertex co-ordinate storage topCorners = new double[24]; // for sub-cubes during twist botCorners = new double[24]; topBlocks = new int[24]; botBlocks = new int[24]; buffer = new int[12]; nearSide = new int[12]; light = new double[3]; Teye = new double[3]; TeX = new double[3]; TeY = new double[3]; currDragDir = new double[2]; eY = new double[3]; vecProd(eye, 0, eX, 0, eY, 0); // Fix y axis of observer co-ordinate system normalize(eY, 0); colList = new Color[120]; for (i = 0; i < 20; i++) { colList[i] = new Color(103 + i * 8, 103 + i * 8, 103 + i * 8); // White colList[i + 20] = new Color(i * 6, i * 6, 84 + i * 9); // Blue colList[i + 40] = new Color(84 + i * 9, i * 5, i * 5); // Red colList[i + 60] = new Color(i * 6, 84 + i * 9, i * 6); // Green colList[i + 80] = new Color(84 + i * 9, 84 + i * 9, i * 6); // Yellow colList[i + 100] = new Color(84 + i * 9, 55 + i * 8, i * 3); // Orange } sideCols = new int[54]; for (i = 0; i < 54; i++) sideCols[i] = i / 9; bgcolor = findBGColor(); setSize(125, 125); repaint(); } /** * Convert hexadecimal RGB parameter to color. * @return */ public Color findBGColor() { int hex[]; String s, h = "0123456789abcdef"; Color c; hex = new int[6]; s = null; //getParameter("bgcolor"); if ((s != null) && (s.length() == 6)) { for (i = 0; i < 6; i++) for (j = 0; j < 16; j++) if (Character.toLowerCase(s.charAt(i)) == h.charAt(j)) hex[i] = j; c = new Color(hex[0] * 16 + hex[1], hex[2] * 16 + hex[3], hex[4] * 16 + hex[5]); } else c = Color.lightGray; // Default return c; } // Various vector manipulation functions /** * */ public double scalProd(double v1[], int ix1, double v2[], int ix2) { return v1[ix1] * v2[ix2] + v1[ix1 + 1] * v2[ix2 + 1] + v1[ix1 + 2] * v2[ix2 + 2]; } /** * * @param v * @param ix * @return */ public double vNorm(double v[], int ix) { return Math.sqrt(v[ix] * v[ix] + v[ix + 1] * v[ix + 1] + v[ix + 2] * v[ix + 2]); } /** * * @param v1 * @param ix1 * @param v2 * @param ix2 * @return */ public double cosAng(double v1[], int ix1, double v2[], int ix2) { return scalProd(v1, ix1, v2, ix2) / (vNorm(v1, ix1) * vNorm(v2, ix2)); } /** * * @param v * @param ix */ public void normalize(double v[], int ix) { double t = vNorm(v, ix); v[ix] = v[ix] / t; v[ix + 1] = v[ix + 1] / t; v[ix + 2] = v[ix + 2] / t; } /** * * @param v * @param ix * @param a */ public void scalMult(double v[], int ix, double a) { v[ix] = v[ix] * a; v[ix + 1] = v[ix + 1] * a; v[ix + 2] = v[ix + 2] * a; } /** * * @param v1 * @param ix1 * @param v2 * @param ix2 */ public void addVec(double v1[], int ix1, double v2[], int ix2) { v2[ix2] += v1[ix1]; v2[ix2 + 1] += v1[ix1 + 1]; v2[ix2 + 2] += v1[ix1 + 2]; } /** * * @param v1 * @param ix1 * @param v2 * @param ix2 */ public void subVec(double v1[], int ix1, double v2[], int ix2) { v2[ix2] -= v1[ix1]; v2[ix2 + 1] -= v1[ix1 + 1]; v2[ix2 + 2] -= v1[ix1 + 2]; } /** * * @param v1 * @param ix1 * @param v2 * @param ix2 */ public void copyVec(double v1[], int ix1, double v2[], int ix2) { v2[ix2] = v1[ix1]; v2[ix2 + 1] = v1[ix1 + 1]; v2[ix2 + 2] = v1[ix1 + 2]; } /** * * @param v1 * @param ix1 * @param v2 * @param ix2 * @param v3 * @param ix3 */ public void vecProd(double v1[], int ix1, double v2[], int ix2, double v3[], int ix3) { v3[ix3] = v1[ix1 + 1] * v2[ix2 + 2] - v1[ix1 + 2] * v2[ix2 + 1]; v3[ix3 + 1] = v1[ix1 + 2] * v2[ix2] - v1[ix1] * v2[ix2 + 2]; v3[ix3 + 2] = v1[ix1] * v2[ix2 + 1] - v1[ix1 + 1] * v2[ix2]; } /** * Produce large and small sub-cube for twisting. */ public void cutUpCube() { boolean check; // Copy main coordinate data for (i = 0; i < 24; i++) { topCorners[i] = corners[i]; botCorners[i] = corners[i]; } copyVec(sideVec, 3 * twistSide, temp, 0); // Start manipulating and build new parts copyVec(temp, 0, temp2, 0); // Fix new co-ordinates. Some need to be altered. scalMult(temp, 0, 1.3333); scalMult(temp2, 0, 0.6667); for (i = 0; i < 8; i++) { check = false; for (j = 0; j < 4; j++) if (i == sides[twistSide * 4 + j]) check = true; if (check) subVec(temp2, 0, botCorners, i * 3); else addVec(temp, 0, topCorners, i * 3); } // The sub-cubes need information about which colored fields belong to them. // Fix the sub-cube blockings. First copy data from main for (i = 0; i < 24; i++) { topBlocks[i] = mainBlocks[i]; // Large sub-cube data botBlocks[i] = mainBlocks[i]; // Small sub-cube data } for (i = 0; i < 6; i++) { if (i == twistSide) { botBlocks[i * 4 + 1] = 0; // Large sub-cube is blank on top botBlocks[i * 4 + 3] = 0; } else { k = -1; for (j = 0; j < 4; j++) if (nextSide[i * 4 + j] == twistSide) k = j; // Twisted side adjacent to... switch (k) { // Up side? case 0: { topBlocks[i * 4 + 3] = 1; botBlocks[i * 4 + 2] = 1; break; } // Right side? case 1: { topBlocks[i * 4] = 2; botBlocks[i * 4 + 1] = 2; break; } // Down side? case 2: { topBlocks[i * 4 + 2] = 2; botBlocks[i * 4 + 3] = 2; break; } // Left side? case 3: { topBlocks[i * 4 + 1] = 1; botBlocks[i * 4] = 1; break; } // None case -1: { topBlocks[i * 4 + 1] = 0; // Small sub-cube is blank on bottom topBlocks[i * 4 + 3] = 0; break; } } } } } /** * * @param key * @return */ public boolean keyPressed(int key) { // Restore if (key == 114) { twisting = false; naturalState = true; for (i = 0; i < 54; i++) sideCols[i] = i / 9; repaint(); } else if (key == 115) { // Scramble twisting = false; naturalState = true; for (i = 0; i < 20; i++) colorTwist((int) (Math.random() * 6), (int) (Math.random() * 3 + 1)); repaint(); } return false; } /** * * @param x * @param y * @return */ public boolean mouseDragged(int x, int y) { boolean check; double x1, x2, y1, y2, alpha, beta; if ((!twisting) && (OKtoDrag)) { OKtoDrag = false; check = false; // Check if inside a drag region for (i = 0; i < dragReg; i++) { x1 = dragCorn[i * 8 + 1] - dragCorn[i * 8]; x2 = dragCorn[i * 8 + 5] - dragCorn[i * 8 + 4]; y1 = dragCorn[i * 8 + 3] - dragCorn[i * 8]; y2 = dragCorn[i * 8 + 7] - dragCorn[i * 8 + 4]; alpha = (y2 * (lastX - dragCorn[i * 8]) - y1 * (lastY - dragCorn[i * 8 + 4])) / (x1 * y2 - y1 * x2); beta = (-x2 * (lastX - dragCorn[i * 8]) + x1 * (lastY - dragCorn[i * 8 + 4])) / (x1 * y2 - y1 * x2); if ((alpha > 0) && (alpha < 1) && (beta > 0) && (beta < 1)) // We're in { currDragDir[0] = dragDir[i * 2]; currDragDir[1] = dragDir[i * 2 + 1]; d = currDragDir[0] * (x - lastX) + currDragDir[1] * (y - lastY); d = d * d / ((currDragDir[0] * currDragDir[0] + currDragDir[1] * currDragDir[1]) * ((x - lastX) * (x - lastX) + (y - lastY) * (y - lastY))); if (d > 0.6) { check = true; twistSide = nearSide[i]; i = 100; } } } // We're twisting if (check) { // The cube still hasn't been split up if (naturalState) { cutUpCube(); naturalState = false; } twisting = true; phi = 0.02 * (currDragDir[0] * (x - lastX) + currDragDir[1] * (y - lastY)) / Math.sqrt(currDragDir[0] * currDragDir[0] + currDragDir[1] * currDragDir[1]); repaint(); return false; } } OKtoDrag = false; // Normal rotation if (!twisting) { dx = lastX - x; // Vertical shift copyVec(eX, 0, temp, 0); scalMult(temp, 0, ((double) dx) * 0.016); addVec(temp, 0, eye, 0); vecProd(eY, 0, eye, 0, eX, 0); normalize(eX, 0); normalize(eye, 0); dy = y - lastY; // Horizontal shift copyVec(eY, 0, temp, 0); scalMult(temp, 0, ((double) dy) * 0.016); addVec(temp, 0, eye, 0); vecProd(eye, 0, eX, 0, eY, 0); normalize(eY, 0); normalize(eye, 0); lastX = x; lastY = y; repaint(); } else { // Twist, compute twisting angle phi phi = 0.02 * (currDragDir[0] * (x - lastX) + currDragDir[1] * (y - lastY)) / Math.sqrt(currDragDir[0] * currDragDir[0] + currDragDir[1] * currDragDir[1]); repaint(); } return false; } /** * * @param x * @param y * @return */ public boolean mousePressed(int x, int y) { lastX = x; lastY = y; OKtoDrag = true; return false; } /** * * @param x * @param y * @return */ public boolean mouseReleased(int x, int y) { int quads; double qu; // We have let go of the mouse when twisting if (twisting) { twisting = false; phibase += phi; // Save twist angle phi = 0; qu = phibase; while (qu < 0) qu += 125.662; quads = ((int) (qu * 3.183)); // Close enough to a corner? if (((quads % 5) == 0) || ((quads % 5) == 4)) { quads = ((quads + 1) / 5) % 4; if (colDir[twistSide] < 0) quads = (4 - quads) % 4; phibase = 0; naturalState = true; // Return the cube to its natural state colorTwist(twistSide, quads); // and shift the colored fields } repaint(); } return false; } /** * Shift colored fields. * @param sideNum * @param quads */ public void colorTwist(int sideNum, int quads) { int i, j, k, l = 0; k = quads * 2; // quads = number of 90-degree multiples for (i = 0; i < 8; i++) { buffer[k] = sideCols[sideNum * 9 + circleOrder[i]]; k = (k + 1) % 8; } for (i = 0; i < 8; i++) sideCols[sideNum * 9 + circleOrder[i]] = buffer[i]; k = quads * 3; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) if (nextSide[nextSide[sideNum * 4 + i] * 4 + j] == sideNum) l = j; for (j = 0; j < 3; j++) { switch (l) { case 0: buffer[k] = sideCols[nextSide[sideNum * 4 + i] * 9 + j]; break; case 1: buffer[k] = sideCols[nextSide[sideNum * 4 + i] * 9 + 2 + 3 * j]; break; case 2: buffer[k] = sideCols[nextSide[sideNum * 4 + i] * 9 + 8 - j]; break; case 3: buffer[k] = sideCols[nextSide[sideNum * 4 + i] * 9 + 6 - 3 * j]; break; default: break; } k = (k + 1) % 12; } } k = 0; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) if (nextSide[nextSide[sideNum * 4 + i] * 4 + j] == sideNum) l = j; for (j = 0; j < 3; j++) { switch (l) { case 0: sideCols[nextSide[sideNum * 4 + i] * 9 + j] = buffer[k]; break; case 1: sideCols[nextSide[sideNum * 4 + i] * 9 + 2 + 3 * j] = buffer[k]; break; case 2: sideCols[nextSide[sideNum * 4 + i] * 9 + 8 - j] = buffer[k]; break; case 3: sideCols[nextSide[sideNum * 4 + i] * 9 + 6 - 3 * j] = buffer[k]; break; default: break; } k++; } } } /** * */ public void paintComponent(Graphics g) { dragReg = 0; if (offGraphics == null) { // Double buffer offImage = createImage(120, 120); offGraphics = offImage.getGraphics(); } offGraphics.setColor(bgcolor); // Clear drawing buffer offGraphics.fillRect(0, 0, 120, 120); if (naturalState) fixBlock(eye, eX, eY, corners, mainBlocks, 0); // Draw cube else { copyVec(eye, 0, Teye, 0); // In twisted state? Compute top observer copyVec(eX, 0, TeX, 0); Cphi = Math.cos(phi + phibase); Sphi = -Math.sin(phi + phibase); // Twist around which axis? switch (twistSide) { case 0: // z Teye[0] = Cphi * eye[0] + Sphi * eye[1]; TeX[0] = Cphi * eX[0] + Sphi * eX[1]; Teye[1] = -Sphi * eye[0] + Cphi * eye[1]; TeX[1] = -Sphi * eX[0] + Cphi * eX[1]; break; case 1: // -z Teye[0] = Cphi * eye[0] - Sphi * eye[1]; TeX[0] = Cphi * eX[0] - Sphi * eX[1]; Teye[1] = Sphi * eye[0] + Cphi * eye[1]; TeX[1] = Sphi * eX[0] + Cphi * eX[1]; break; case 2: // -y Teye[0] = Cphi * eye[0] - Sphi * eye[2]; TeX[0] = Cphi * eX[0] - Sphi * eX[2]; Teye[2] = Sphi * eye[0] + Cphi * eye[2]; TeX[2] = Sphi * eX[0] + Cphi * eX[2]; break; case 3: // x Teye[1] = Cphi * eye[1] + Sphi * eye[2]; TeX[1] = Cphi * eX[1] + Sphi * eX[2]; Teye[2] = -Sphi * eye[1] + Cphi * eye[2]; TeX[2] = -Sphi * eX[1] + Cphi * eX[2]; break; case 4: // y Teye[0] = Cphi * eye[0] + Sphi * eye[2]; TeX[0] = Cphi * eX[0] + Sphi * eX[2]; Teye[2] = -Sphi * eye[0] + Cphi * eye[2]; TeX[2] = -Sphi * eX[0] + Cphi * eX[2]; break; case 5: // -x Teye[1] = Cphi * eye[1] - Sphi * eye[2]; TeX[1] = Cphi * eX[1] - Sphi * eX[2]; Teye[2] = Sphi * eye[1] + Cphi * eye[2]; TeX[2] = Sphi * eX[1] + Cphi * eX[2]; break; default: break; } vecProd(Teye, 0, TeX, 0, TeY, 0); if (scalProd(eye, 0, sideVec, twistSide * 3) < 0) // Top facing away? Draw it first { fixBlock(Teye, TeX, TeY, topCorners, topBlocks, 2); fixBlock(eye, eX, eY, botCorners, botBlocks, 1); } else { fixBlock(eye, eX, eY, botCorners, botBlocks, 1); fixBlock(Teye, TeX, TeY, topCorners, topBlocks, 2); } } g.drawImage(offImage, 0, 0, this); } /** * */ public void update(Graphics g) { paint(g); } /** * Draw cube or sub-cube. * @param beye * @param beX * @param beY * @param bcorners * @param bblocks * @param mode */ public void fixBlock(double beye[], double beX[], double beY[], double bcorners[], int bblocks[], int mode) { copyVec(beye, 0, light, 0); scalMult(light, 0, -3); addVec(beX, 0, light, 0); subVec(beY, 0, light, 0); // Project 3D co-ordinates into 2D screen ones for (i = 0; i < 8; i++) { newCoord[i * 2] = (60 + 35.1 * scalProd(bcorners, i * 3, beX, 0)); newCoord[i * 2 + 1] = (60 - 35.1 * scalProd(bcorners, i * 3, beY, 0)); } for (i = 0; i < 6; i++) { // Face towards us? Draw it. if (scalProd(beye, 0, sideVec, 3 * i) > 0.001) { k = (int) (9.6 * (1 - cosAng(light, 0, sideVec, 3 * i))); offGraphics.setColor(Color.black); // Find corner co-ordinates for (j = 0; j < 4; j++) { rectX[j] = (int) newCoord[2 * sides[i * 4 + j]]; rectY[j] = (int) newCoord[2 * sides[i * 4 + j] + 1]; } offGraphics.fillPolygon(rectX, rectY, 4); // First draw black sideW = bblocks[i * 4 + 1] - bblocks[i * 4]; sideH = bblocks[i * 4 + 3] - bblocks[i * 4 + 2]; if (sideW > 0) { sx = newCoord[2 * sides[i * 4]]; sy = newCoord[2 * sides[i * 4] + 1]; sdxh = (newCoord[2 * sides[i * 4 + 1]] - sx) / sideW; sdxv = (newCoord[2 * sides[i * 4 + 3]] - sx) / sideH; sdyh = (newCoord[2 * sides[i * 4 + 1] + 1] - sy) / sideW; sdyv = (newCoord[2 * sides[i * 4 + 3] + 1] - sy) / sideH; p = bblocks[i * 4 + 2]; // Then draw colored fields for (n = 0; n < sideH; n++) { q = bblocks[i * 4]; for (o = 0; o < sideW; o++) { rectX[0] = (int) (sx + (o + 0.1) * sdxh + (n + 0.1) * sdxv); rectX[1] = (int) (sx + (o + 0.9) * sdxh + (n + 0.1) * sdxv); rectX[2] = (int) (sx + (o + 0.9) * sdxh + (n + 0.9) * sdxv); rectX[3] = (int) (sx + (o + 0.1) * sdxh + (n + 0.9) * sdxv); rectY[0] = (int) (sy + (o + 0.1) * sdyh + (n + 0.1) * sdyv); rectY[1] = (int) (sy + (o + 0.9) * sdyh + (n + 0.1) * sdyv); rectY[2] = (int) (sy + (o + 0.9) * sdyh + (n + 0.9) * sdyv); rectY[3] = (int) (sy + (o + 0.1) * sdyh + (n + 0.9) * sdyv); offGraphics.setColor(colList[20 * sideCols[i * 9 + p * 3 + q] + k]); offGraphics.fillPolygon(rectX, rectY, 4); q++; } p++; } } // Determine allowed drag regions and directions switch (mode) { case 0: // Just the normal cube t1 = sx; t2 = sy; t3 = sdxh; t4 = sdyh; t5 = sdxv; t6 = sdyv; for (j = 0; j < 4; j++) { dragCorn[8 * dragReg] = t1; dragCorn[8 * dragReg + 4] = t2; dragCorn[8 * dragReg + 3] = t1 + t5; dragCorn[8 * dragReg + 7] = t2 + t6; t1 = t1 + t3 * 3; t2 = t2 + t4 * 3; dragCorn[8 * dragReg + 1] = t1; dragCorn[8 * dragReg + 5] = t2; dragCorn[8 * dragReg + 2] = t1 + t5; dragCorn[8 * dragReg + 6] = t2 + t6; dragDir[dragReg * 2] = t3 * twistDir[i * 4 + j]; dragDir[dragReg * 2 + 1] = t4 * twistDir[i * 4 + j]; d = t3; t3 = t5; t5 = -d; d = t4; t4 = t6; t6 = -d; nearSide[dragReg] = nextSide[i * 4 + j]; dragReg++; } break; case 1: // The large sub-cube break; case 2: // The small sub-cube (twistable part) if ((i != twistSide) && (sideW > 0)) { if (sideW == 3) // Determine positive drag direction if (bblocks[i * 4 + 2] == 0) { dragDir[dragReg * 2] = sdxh * twistDir[i * 4]; dragDir[dragReg * 2 + 1] = sdyh * twistDir[i * 4]; } else { dragDir[dragReg * 2] = -sdxh * twistDir[i * 4 + 2]; dragDir[dragReg * 2 + 1] = -sdyh * twistDir[i * 4 + 2]; } else if (bblocks[i * 4] == 0) { dragDir[dragReg * 2] = -sdxv * twistDir[i * 4 + 3]; dragDir[dragReg * 2 + 1] = -sdyv * twistDir[i * 4 + 3]; } else { dragDir[dragReg * 2] = sdxv * twistDir[i * 4 + 1]; dragDir[dragReg * 2 + 1] = sdyv * twistDir[i * 4 + 1]; } for (j = 0; j < 4; j++) { dragCorn[dragReg * 8 + j] = newCoord[2 * sides[i * 4 + j]]; dragCorn[dragReg * 8 + 4 + j] = newCoord[2 * sides[i * 4 + j] + 1]; } nearSide[dragReg] = twistSide; dragReg++; } break; default: break; } } } } /** * * @param argv */ public static void main(String[] argv) { JFrame f = new JFrame("Rubik's Cube"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Rubik rubik = new Rubik(); rubik.init(); rubik.setPreferredSize(new Dimension(120, 120)); f.add(rubik, BorderLayout.CENTER); rubik.requestFocus(); f.pack(); f.setVisible(true); } }