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

import renderer.scene.*;
import renderer.models_L.Disk;
import renderer.pipeline.*;
import renderer.framebuffer.*;

import java.awt.Color;

/**
  The example demonstrates a form of "cropping".
<p>
  This program keeps the aspect ratio and the size of
  the complete circle at a constant SIZE by SIZE pixels
  (where SIZE is the initial size of the framebuffer).
<p>
  If the program window is smaller than SIZE by SIZE pixels,
  then only part of the complete circle is shown in the
  program window. Our view of the scene gets "cropped" by
  the camera's view rectangle to fit inside of the screen
  window.
<p>
  Run this program and resize the window so that it is
  smaller than SIZE by SIZE and see what happens.
<p>
  This program has nine modes for how it anchors the circle
  in the program's window.
<p>
   Mode 1 anchors the circle in the upper left-hand corner
   of the framebuffer.
<p>
   Mode 2 anchors the circle at the center of the top edge
   of the framebuffer.
<p>
   Mode 3 anchors the circle in the upper right-hand corner
   of the framebuffer.
<p>
   Mode 4 anchors the circle at the center of the right edge
   of the framebuffer.
<p>
   Mode 5 anchors the circle in the lower right-hand corner
   of the framebuffer.
<p>
   Mode 6 anchors the circle at the center of the bottom edge
   of the framebuffer.
<p>
   Mode 7 anchors the circle in the lower left-hand corner
   of the framebuffer.
<p>
   Mode 8 anchors the circle at the center of the left edge
   of the framebuffer.
<p>
   Mode 9 anchors the circle at the center of the framebuffer.
<p>
  As the user changes the shape (the aspect ratio) and size of
  the program window, the code in the componentResized() event
  handler needs to change the size and location of the
  framebuffer's viewport (within the framebuffer) and also the
  size and location of the camera's view volume (within view
  space).
<p>
  We create this effect in the setupViewing() method (called
  by the componentResized() event handler) by using the
  FrameBuffer's setViewport() method and the Camera's
  projOrtho() method.
*/
@SuppressWarnings("serial")
public class Circle_v3_Crop extends Circle_v0_Abstract
{
   /**
      This constructor instantiates the Scene object
      and initializes it with appropriate geometry.
      Then this constructor instantiates the GUI.
   */
   public Circle_v3_Crop()
   {
      super("Renderer 5 - Crop");
      print_help_message();
   }


   /**
      Get in one place the code to set up
      the view volume and the viewport.
   */
   @Override protected void setupViewing()
   {
      // Get the size of the FrameBuffer.
      final FrameBuffer fb = fbp.getFrameBuffer();
      final int wFB = fb.getWidthFB();
      final int hFB = fb.getHeightFB();

      // Compute the size of the viewport. (SIZE is
      // the initial size for the framebuffer.)
      final int wVP = (wFB < SIZE) ? wFB : SIZE;
      final int hVP = (hFB < SIZE) ? hFB : SIZE;

      if (mode == 1)
      {
         // 1. upper left-hand corner
         fb.setViewport(0, 0, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -1,                      // left
                             -1 + (2.0 * wVP) / SIZE, // right
                              1 - (2.0 * hVP) / SIZE, // bottom
                              1));                    // top
      }
      else if (mode == 2)
      {
         // 2. center of the top edge
         fb.setViewport((wFB - wVP)/2, 0, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                             -wVP / (double)SIZE,     // left
                              wVP / (double)SIZE,     // right
                              1 - (2.0 * hVP) / SIZE, // bottom
                              1));                    // top
      }
      else if (mode == 3)
      {
         // 3. upper right-hand corner
         fb.setViewport(wFB - wVP, 0, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1 - (2.0 * wVP) / SIZE, // left
                              1,                      // right
                              1 - (2.0 * hVP) / SIZE, // bottom
                              1));                    // top
      }
      else if (mode == 4)
      {
         // 4. center of the right edge
         fb.setViewport(wFB - wVP, (hFB - hVP)/2, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1 - (2.0 * wVP) / SIZE, // left
                              1,                      // right
                             -hVP / (double)SIZE,     // bottom
                              hVP / (double)SIZE));   // top
      }
      else if (mode == 5)
      {
         // 5. lower right-hand corner
         fb.setViewport(wFB - wVP, hFB - hVP, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                              1 - (2.0 * wVP) / SIZE,   // left
                              1,                        // right
                             -1,                        // bottom
                             -1 + (2.0 * hVP) / SIZE)); // top
      }
      else if (mode == 6)
      {
         // 6. center of the bottom edge
         fb.setViewport((wFB - wVP)/2, hFB - hVP, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                            -wVP / (double)SIZE,       // left
                             wVP / (double)SIZE,       // right
                            -1,                        // bottom
                            -1 + (2.0 * hVP) / SIZE)); // top
      }
      else if (mode == 7)
      {
         // 7. lower left-hand corner
         fb.setViewport(0, hFB - hVP, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                            -1,                        // left
                            -1 + (2.0 * wVP) / SIZE,   // right
                            -1,                        // bottom
                            -1 + (2.0 * hVP) / SIZE)); // top
      }
      else if (mode == 8)
      {
         // 8. centered of the left edge
         fb.setViewport(0, (hFB - hVP)/2, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                            -1,                      // left
                            -1 + (2.0 * wVP) / SIZE, // right
                            -hVP / (double)SIZE,     // bottom
                             hVP / (double)SIZE));   // top
      }
      else if (mode == 9)
      {
         // 9. center of the framebuffer
         fb.setViewport((wFB - wVP)/2, (hFB - hVP)/2, wVP, hVP);
         scene = scene.changeCamera(
                     Camera.projOrtho(
                            -wVP / (double)SIZE,   // left
                             wVP / (double)SIZE,   // right
                            -hVP / (double)SIZE,   // bottom
                             hVP / (double)SIZE)); // top
      }

      super.setupViewing();
   }


   /**
      Create an instance of this class which has
      the affect of creating the GUI application.
   */
   public static void main(String[] args)
   {
      // We need to call the program's constructor in the
      // Java GUI Event Dispatch Thread, otherwise we get a
      // race condition between the constructor (running in
      // the main() thread) and the very first ComponentEvent
      // (running in the EDT).
      javax.swing.SwingUtilities.invokeLater(
         () -> new Circle_v3_Crop()
      );
   }
}
