1 /*
   2  *
   3  * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  *   - Redistributions of source code must retain the above copyright
  10  *     notice, this list of conditions and the following disclaimer.
  11  *
  12  *   - Redistributions in binary form must reproduce the above copyright
  13  *     notice, this list of conditions and the following disclaimer in the
  14  *     documentation and/or other materials provided with the distribution.
  15  *
  16  *   - Neither the name of Oracle nor the names of its
  17  *     contributors may be used to endorse or promote products derived
  18  *     from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 package java2d.demos.Colors;
  33 
  34 
  35 import static java.lang.Math.PI;
  36 import static java.lang.Math.abs;
  37 import static java.lang.Math.cos;
  38 import static java.lang.Math.min;
  39 import static java.lang.Math.random;
  40 import static java.lang.Math.sin;
  41 import static java.lang.Math.sqrt;
  42 import java.awt.Color;
  43 import java.awt.Graphics2D;
  44 import java2d.AnimatingSurface;
  45 
  46 
  47 /**
  48  * 3D objects with color & lighting translated, rotated and scaled.
  49  */
  50 @SuppressWarnings("serial")
  51 public class Rotator3D extends AnimatingSurface {
  52 
  53     private Objects3D objs[] = new Objects3D[3];
  54     private static final int[][][] polygons = {
  55         // Solid cube
  56         { { 5, 1, 15, 13, 21, 23, 15 },
  57             { 5, 2, 21, 13, 19, 27, 21 },
  58             { 5, 3, 23, 15, 17, 25, 23 },
  59             { 5, 4, 19, 13, 15, 17, 19 },
  60             { 5, 5, 27, 21, 23, 25, 27 },
  61             { 5, 6, 27, 19, 17, 25, 27 } },
  62         // Polygonal faces cube
  63         { { 5, 1, 21, 13, 19, 27, 21 },
  64             { 5, 5, 23, 15, 17, 25, 23 },
  65             { 4, 0, 15, 14, 16, 15 }, { 7, 6, 16, 14, 13, 12, 18, 17, 16 }, { 4,
  66                 0, 12, 19, 18, 12 },
  67             { 4, 2, 22, 21, 20, 22 }, { 7, 0, 24, 23, 22, 20, 27, 26, 24 }, { 4,
  68                 2, 24, 26, 25, 24 },
  69             { 4, 3, 15, 13, 23, 15 }, { 4, 0, 23, 13, 21, 23 },
  70             { 5, 0, 27, 26, 18, 19, 27 }, { 5, 4, 25, 17, 18, 26, 25 } },
  71         // Octahedron
  72         { { 4, 3, 18, 21, 16, 18 }, { 4, 1, 20, 16, 18, 20 },
  73             { 4, 1, 18, 21, 16, 18 }, { 4, 3, 20, 17, 19, 20 },
  74             { 4, 2, 20, 26, 27, 20 }, { 5, 3, 26, 18, 16, 27, 26 },
  75             { 5, 0, 17, 24, 25, 19, 17 }, { 4, 3, 21, 25, 24, 21 },
  76             { 4, 4, 18, 21, 22, 18 }, { 4, 2, 22, 21, 17, 22 },
  77             { 4, 5, 20, 23, 16, 20 }, { 4, 1, 20, 23, 19, 20 },
  78             { 4, 6, 21, 23, 16, 21 }, { 4, 4, 21, 23, 19, 21 },
  79             { 4, 5, 20, 18, 22, 20 }, { 4, 6, 20, 22, 17, 20 } }
  80     };
  81     private static final double[][][] points = {
  82         // Points for solid cube & polygonal faces cube
  83         { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 },
  84             { 0, 0, -1 }, { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 },
  85             { 0, 0, 1 }, { 0, 0, -1 }, { 1, 1, 0 }, { 1, 1, 1 }, { 0, 1, 1 },
  86             { -1, 1, 1 }, { -1, 1, 0 }, { -1, 1, -1 }, { 0, 1, -1 },
  87             { 1, 1, -1 },
  88             { 1, -1, 0 }, { 1, -1, 1 }, { 0, -1, 1 }, { -1, -1, 1 },
  89             { -1, -1, 0 },
  90             { -1, -1, -1 }, { 0, -1, -1 }, { 1, -1, -1 } },
  91         // Points for octahedron
  92         { { 0, 0, 1 }, { 0, 0, -1 }, { -0.8165, 0.4714, 0.33333 },
  93             { 0.8165, -0.4714, -0.33333 }, { 0.8165, 0.4714, 0.33333 },
  94             { -0.8165, -0.4714, -0.33333 }, { 0, -0.9428, 0.3333 },
  95             { 0, 0.9428, -0.33333 }, { 0, 0, 1 }, { 0, 0, -1 },
  96             { -0.8165, 0.4714, 0.33333 }, { 0.8165, -0.4714, -0.33333 },
  97             { 0.8165, 0.4714, 0.33333 }, { -0.8165, -0.4714, -0.33333 },
  98             { 0, -0.9428, 0.33333 }, { 0, 0.9428, -0.33333 },
  99             { -1.2247, -0.7071, 1 }, { 1.2247, 0.7071, -1 },
 100             { 0, 1.4142, 1 }, { 0, -1.4142, -1 }, { -1.2247, 0.7071, -1 },
 101             { 1.2247, -0.7071, 1 }, { 0.61237, 1.06066, 0 },
 102             { -0.61237, -1.06066, 0 }, { 1.2247, 0, 0 },
 103             { 0.61237, -1.06066, 0 }, { -0.61237, 1.06066, 0 },
 104             { -1.2247, 0, 0 } }
 105     };
 106     private static final int[][][] faces = {
 107         // Solid cube
 108         { { 1, 1 }, { 1, 2 }, { 1, 3 }, { 1, 4 }, { 1, 0 }, { 1, 5 } },
 109         // Polygonal faces cube
 110         { { 1, 0 }, { 1, 1 }, { 3, 2, 3, 4 }, { 3, 5, 6, 7 }, { 2, 8, 9 }, { 2,
 111                 10, 11 } },
 112         // Octahedron
 113         { { 1, 2 }, { 1, 3 }, { 2, 4, 5 }, { 2, 6, 7 }, { 2, 8, 9 },
 114             { 2, 10, 11 }, { 2, 12, 13 }, { 2, 14, 15 } }, };
 115 
 116     public Rotator3D() {
 117         setBackground(Color.white);
 118     }
 119 
 120     @Override
 121     public void reset(int w, int h) {
 122         objs[0] = new Objects3D(polygons[0], points[0], faces[0], w, h);
 123         objs[1] = new Objects3D(polygons[1], points[0], faces[1], w, h);
 124         objs[2] = new Objects3D(polygons[2], points[1], faces[2], w, h);
 125     }
 126 
 127     @Override
 128     public void step(int w, int h) {
 129         for (Objects3D obj : objs) {
 130             if (obj != null) {
 131                 obj.step(w, h);
 132             }
 133         }
 134     }
 135 
 136     @Override
 137     public void render(int w, int h, Graphics2D g2) {
 138         for (Objects3D obj : objs) {
 139             if (obj != null) {
 140                 obj.render(g2);
 141             }
 142         }
 143     }
 144 
 145     public static void main(String argv[]) {
 146         createDemoFrame(new Rotator3D());
 147     }
 148 
 149 
 150     /**
 151      * 3D Objects : Solid Cube, Cube & Octahedron with polygonal faces.
 152      */
 153     public class Objects3D {
 154 
 155         private final int UP = 0;
 156         private final int DOWN = 1;
 157         private int[][] polygons;
 158         private double[][] points;
 159         private int npoint;
 160         private int[][] faces;
 161         private int nface;
 162         private int ncolour = 10;
 163         private Color[][] colours = new Color[ncolour][7];
 164         private double[] lightvec = { 0, 1, 1 };
 165         private double Zeye = 10;
 166         private double angle;
 167         private Matrix3D orient, tmp, tmp2, tmp3;
 168         private int scaleDirection;
 169         private double scale, scaleAmt;
 170         private double ix = 3.0, iy = 3.0;
 171         private double[][] rotPts;
 172         private int[][] scrPts;
 173         private int xx[] = new int[20];
 174         private int yy[] = new int[20];
 175         private double x, y;
 176         private int p, j;
 177         private int colour;
 178         private double bounce, persp;
 179 
 180         public Objects3D(int[][] polygons,
 181                 double[][] points,
 182                 int[][] faces,
 183                 int w,
 184                 int h) {
 185 
 186             this.polygons = polygons;
 187             this.points = points;
 188             this.faces = faces;
 189             npoint = points.length;
 190             nface = faces.length;
 191 
 192             x = w * random();
 193             y = h * random();
 194 
 195             ix = random() > 0.5 ? ix : -ix;
 196             iy = random() > 0.5 ? iy : -iy;
 197 
 198             rotPts = new double[npoint][3];
 199             scrPts = new int[npoint][2];
 200 
 201             for (int i = 0; i < ncolour; i++) {
 202                 int val = 255 - (ncolour - i - 1) * 100 / ncolour;
 203                 Color[] c = {
 204                     new Color(val, val, val), // white
 205                     new Color(val, 0, 0), // red
 206                     new Color(0, val, 0), // green
 207                     new Color(0, 0, val), // blue
 208                     new Color(val, val, 0), // yellow
 209                     new Color(0, val, val), // cyan
 210                     new Color(val, 0, val) // magenta
 211                 };
 212                 colours[i] = c;
 213             }
 214 
 215             double len = sqrt(lightvec[0] * lightvec[0] + lightvec[1]
 216                     * lightvec[1] + lightvec[2] * lightvec[2]);
 217             lightvec[0] = lightvec[0] / len;
 218             lightvec[1] = lightvec[1] / len;
 219             lightvec[2] = lightvec[2] / len;
 220 
 221             double max = 0;
 222             for (int i = 0; i < npoint; i++) {
 223                 len = sqrt(points[i][0] * points[i][0] + points[i][1]
 224                         * points[i][1] + points[i][2] * points[i][2]);
 225                 if (len > max) {
 226                     max = len;
 227                 }
 228             }
 229 
 230             for (int i = 0; i < nface; i++) {
 231                 len = sqrt(points[i][0] * points[i][0] + points[i][1]
 232                         * points[i][1] + points[i][2] * points[i][2]);
 233                 points[i][0] = points[i][0] / len;
 234                 points[i][1] = points[i][1] / len;
 235                 points[i][2] = points[i][2] / len;
 236             }
 237 
 238             orient = new Matrix3D();
 239             tmp = new Matrix3D();
 240             tmp2 = new Matrix3D();
 241             tmp3 = new Matrix3D();
 242             tmp.Rotation(2, 0, PI / 50);
 243             CalcScrPts((double) w / 3, (double) h / 3, 0);
 244 
 245             scale = min(w / 3 / max / 1.2, h / 3 / max / 1.2);
 246             scaleAmt = scale;
 247             scale *= random() * 1.5;
 248             scaleDirection = scaleAmt < scale ? DOWN : UP;
 249         }
 250 
 251         private Color getColour(int f, int index) {
 252             colour = (int) ((rotPts[f][0] * lightvec[0] + rotPts[f][1]
 253                     * lightvec[1] + rotPts[f][2] * lightvec[2]) * ncolour);
 254             if (colour < 0) {
 255                 colour = 0;
 256             }
 257             if (colour > ncolour - 1) {
 258                 colour = ncolour - 1;
 259             }
 260             return colours[colour][polygons[faces[f][index]][1]];
 261         }
 262 
 263         private void CalcScrPts(double x, double y, double z) {
 264             for (p = 0; p < npoint; p++) {
 265 
 266                 rotPts[p][2] = points[p][0] * orient.M[2][0]
 267                         + points[p][1] * orient.M[2][1]
 268                         + points[p][2] * orient.M[2][2];
 269 
 270                 rotPts[p][0] = points[p][0] * orient.M[0][0]
 271                         + points[p][1] * orient.M[0][1]
 272                         + points[p][2] * orient.M[0][2];
 273 
 274                 rotPts[p][1] = -points[p][0] * orient.M[1][0]
 275                         - points[p][1] * orient.M[1][1]
 276                         - points[p][2] * orient.M[1][2];
 277             }
 278             for (p = nface; p < npoint; p++) {
 279                 rotPts[p][2] += z;
 280                 persp = (Zeye - rotPts[p][2]) / (scale * Zeye);
 281                 scrPts[p][0] = (int) (rotPts[p][0] / persp + x);
 282                 scrPts[p][1] = (int) (rotPts[p][1] / persp + y);
 283             }
 284         }
 285 
 286         private boolean faceUp(int f) {
 287             return (rotPts[f][0] * rotPts[nface + f][0] + rotPts[f][1] * rotPts[nface
 288                     + f][1] + rotPts[f][2] * (rotPts[nface + f][2] - Zeye) < 0);
 289         }
 290 
 291         public void step(int w, int h) {
 292             x += ix;
 293             y += iy;
 294             if (x > w - scale) {
 295                 x = w - scale - 1;
 296                 ix = -w / 100 - 1;
 297             }
 298             if (x - scale < 0) {
 299                 x = 2 + scale;
 300                 ix = w / 100 + random() * 3;
 301             }
 302             if (y > h - scale) {
 303                 y = h - scale - 2;
 304                 iy = -h / 100 - 1;
 305             }
 306             if (y - scale < 0) {
 307                 y = 2 + scale;
 308                 iy = h / 100 + random() * 3;
 309             }
 310 
 311             angle += random() * 0.15;
 312             tmp3.Rotation(1, 2, angle);
 313             tmp2.Rotation(1, 0, angle * sqrt(2) / 2);
 314             tmp.Rotation(0, 2, angle * PI / 4);
 315             orient.M = tmp3.Times(tmp2.Times(tmp.M));
 316             bounce = abs(cos(0.5 * (angle))) * 2 - 1;
 317 
 318             if (scale > scaleAmt * 1.4) {
 319                 scaleDirection = DOWN;
 320             }
 321             if (scale < scaleAmt * 0.4) {
 322                 scaleDirection = UP;
 323             }
 324             if (scaleDirection == UP) {
 325                 scale += random();
 326             }
 327             if (scaleDirection == DOWN) {
 328                 scale -= random();
 329             }
 330 
 331             CalcScrPts(x, y, bounce);
 332         }
 333 
 334         public void render(Graphics2D g2) {
 335             for (int f = 0; f < nface; f++) {
 336                 if (faceUp(f)) {
 337                     for (j = 1; j < faces[f][0] + 1; j++) {
 338                         DrawPoly(g2, faces[f][j], getColour(f, j));
 339                     }
 340                 }
 341             }
 342         }
 343 
 344         private void DrawPoly(Graphics2D g2, int poly, Color colour) {
 345             for (int point = 2; point < polygons[poly][0] + 2; point++) {
 346                 xx[point - 2] = scrPts[polygons[poly][point]][0];
 347                 yy[point - 2] = scrPts[polygons[poly][point]][1];
 348             }
 349             g2.setColor(colour);
 350             g2.fillPolygon(xx, yy, polygons[poly][0]);
 351             g2.setColor(Color.black);
 352             g2.drawPolygon(xx, yy, polygons[poly][0]);
 353         }
 354 
 355 
 356         /**
 357          * A 3D matrix object.
 358          */
 359         public class Matrix3D {
 360 
 361             public double[][] M = { { 1, 0, 0 },
 362                 { 0, 1, 0 },
 363                 { 0, 0, 1 } };
 364             private double[][] tmp = new double[3][3];
 365             private int row, col, k;
 366 
 367             public void Rotation(int i, int j, double angle) {
 368                 for (row = 0; row < 3; row++) {
 369                     for (col = 0; col < 3; col++) {
 370                         if (row != col) {
 371                             M[row][col] = 0.0;
 372                         } else {
 373                             M[row][col] = 1.0;
 374                         }
 375                     }
 376                 }
 377                 M[i][i] = cos(angle);
 378                 M[j][j] = cos(angle);
 379                 M[i][j] = sin(angle);
 380                 M[j][i] = -sin(angle);
 381             }
 382 
 383             public double[][] Times(double[][] N) {
 384                 for (row = 0; row < 3; row++) {
 385                     for (col = 0; col < 3; col++) {
 386                         tmp[row][col] = 0.0;
 387                         for (k = 0; k < 3; k++) {
 388                             tmp[row][col] += M[row][k] * N[k][col];
 389                         }
 390                     }
 391                 }
 392                 return tmp;
 393             }
 394         } // End Matrix3D
 395     } // End Objects3D
 396 } // End Rotator3D
 397