Package org.jnode.games.rubik

Source Code of org.jnode.games.rubik.Rubik

/*
* $Id$
*
* Copyright (C) 2003-2014 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);
    }
}
TOP

Related Classes of org.jnode.games.rubik.Rubik

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.