/*
 * Renderer 5. The MIT License.
 * Copyright (c) 2022 rlkraft@pnw.edu
 * See LICENSE for details.
*/

import renderer.scene.*;
import renderer.scene.util.Assets;
import renderer.scene.util.ModelShading;
import renderer.scene.util.DrawSceneGraph;
import renderer.models_L.*;
import renderer.pipeline.*;
import renderer.framebuffer.*;

import java.awt.Color;
import java.io.File;

/**
   Compare with
      http://threejs.org/examples/#webgl_geometries
   or
      https://stemkoski.github.io/Three.js/Shapes.html
   or
      http://www.smartjava.org/ltjs/chapter-02/04-geometries.html
*/
public class Geometries_R5
{
   private static final String assets = Assets.getPath();

   public static void main(String[] args)
   {
      // Set up the camera's view frustum.
      final double right  = 2.0;
      final double left   = -right;
      final double top    = 1.0;
      final double bottom = -top;
      final Scene scene = new Scene("Geometries_R5",
                                    Camera.projPerspective(left, right, bottom, top));
/*
      final double fov    = 90.0;
      final double aspect = 2.0;
      final Scene scene = new Scene("Geometries_R5",
                                    Camera.projPerspective(fov, aspect));
*/
      // Create a two-dimensional array of Models.
      final Model[][] model = new Model[5][3];

      // row 0 (front row in the image)
      model[0][0] = new TriangularPrism(1.0, 1.0, 10);
      ModelShading.setColor(model[0][0],
                            Color.green.darker().darker());

      model[0][1] = new Cylinder(0.5, 1.0, 30, 30);
      ModelShading.setColor(model[0][1],
                            Color.blue.brighter().brighter());

      model[0][2] = new ObjSimpleModel(new File(
                          assets + "great_rhombicosidodecahedron.obj"));
      ModelShading.setColor(model[0][2], Color.red);

      // row 1
      model[1][0] = new GRSModel(new File(
                          assets + "grs/bronto.grs"));
      ModelShading.setColor(model[1][0], Color.red);

      model[1][1] = new ObjSimpleModel(new File(
                          assets + "horse.obj"));
      ModelShading.setColor(model[1][1], Color.pink.darker());

      model[1][2] = new ConeFrustum(0.5, 1.0, 1.0, 10, 10);
      ModelShading.setColor(model[1][2], Color.orange.darker());

      // row 2
      model[2][0] = new Torus(0.75, 0.25, 30, 30);
      ModelShading.setColor(model[2][0], Color.gray);

      model[2][1] = new Octahedron(6);
      ModelShading.setColor(model[2][1], Color.green);

      model[2][2] = new Box(1.0, 1.0, 1.0);
      ModelShading.setRandomPrimitiveColors(model[2][2]);

      // row 3 (back row in the image)
      model[3][0] = new ParametricCurve(
                t -> 0.3*(Math.sin(t) + 2*Math.sin(2*t)) + 0.1*Math.sin(t/6),
                t -> 0.3*(Math.cos(t) - 2*Math.cos(2*t)) + 0.1*Math.sin(t/6),
                t -> 0.3*(-Math.sin(3*t)),
                0, 6*Math.PI, 120);
      ModelShading.setRandomPrimitiveColors(model[3][0]);

      model[3][1] = new ObjSimpleModel(new File(
                          assets + "small_rhombicosidodecahedron.obj"));
      ModelShading.setColor(model[3][1], Color.magenta);

      model[3][2] = new SurfaceOfRevolution(
                t -> 1.5*(0.5 + 0.15 * Math.sin(10*t+1.0)*Math.sin(5*t+0.5)),
                -0.1, 0.9,
                30, 30);
      ModelShading.setColor(model[3][2], Color.blue);

      // row 4 (last row in first image)
      model[4][0] = new Cone(0.5, 1.0, 30, 30);
      ModelShading.setColor(model[4][0], Color.yellow);

      model[4][1] = new Tetrahedron(12, 12);
      ModelShading.setColor(model[4][1],
                            Color.green.brighter().brighter());

      model[4][2] = new Sphere(1.0, 30, 30);
      ModelShading.setColor(model[4][2],
                            Color.cyan.brighter().brighter());

      // Create x, y and z axes.
      final Position xyzAxes = new Position(
                                  new Axes3D(6, -6, 6, 0, 7, -7, Color.red),
                                  new Vector(0, -3, -10));

      // Create a horizontal coordinate plane model.
      final Position xzPlane = new Position(
                                  new PanelXZ(-6, 6, -7, 7),
                                  new Vector(0, -3, -10));
      ModelShading.setColor(xzPlane.getModel(), Color.darkGray);

      // Add the positions (and their models) to the Scene.
      scene.addPosition(xzPlane,  // draw the grid first
                        xyzAxes); // draw the axes on top of the grid

      for (int i = model.length - 1; i >= 0; --i) // from back to front
      {
         for (int j = 0; j < model[i].length; ++j)
         {
            scene.addPosition(
               new Position(
                      model[i][j],
                      "p["+i+"]["+j+"]",
                      new Vector(-4 + 4*j,
                                 -3,
                                 -4 - 3*i)));
         }
      }

      DrawSceneGraph.drawVertexList = false;
      DrawSceneGraph.draw(scene, "Geometries_R5_SG");

      // Create a framebuffer to render our scene into.
      final int width  = 1800;
      final int height =  900;
      final FrameBuffer fb = new FrameBuffer(width, height, Color.black);

      // Render
      Rasterize.doAntiAliasing = true;
      Rasterize.doGamma = true;
      Pipeline.render(scene, fb);
      fb.dumpFB2File("Geometries_R5.ppm");
      System.out.println("Saved " + "Geometries_R5.ppm");
   }
}
