001/*
002 * Renderer 4. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.pipeline;
008
009import renderer.scene.*;
010import renderer.scene.primitives.Point;
011import renderer.framebuffer.*;
012import static renderer.pipeline.PipelineLogger.*;
013
014import java.awt.Color;
015
016/**
017   Rasterize a projected {@link Point} into shaded pixels
018   in a {@link FrameBuffer.Viewport}, but (optionally)
019   do not rasterize any part of the {@link Point} that
020   is not contained in the {@link Camera}'s view rectangle.
021*/
022public class Rasterize_Clip_Point
023{
024   /**
025      Rasterize a {@link Point} into shaded pixels
026      in a {@link FrameBuffer.Viewport}.
027
028      @param model  {@link Model} that the {@link Point} {@code pt} comes from
029      @param pt     {@code Point} to rasterize into the {@code FrameBuffer.Viewport}
030      @param vp     {@link FrameBuffer.Viewport} to hold rasterized, shaded pixels
031   */
032   public static void rasterize(final Model model,
033                                final Point pt,
034                                final FrameBuffer.Viewport vp)
035   {
036      final String     CLIPPED = "Clip: ";
037      final String NOT_CLIPPED = "      ";
038
039      // Make local copies of several values.
040      final int w = vp.getWidthVP();
041      final int h = vp.getHeightVP();
042
043      final int vIndex = pt.vIndexList.get(0);
044      final Vertex v = model.vertexList.get(vIndex);
045
046      final int cIndex = pt.cIndexList.get(0);
047      final float[] c = model.colorList.get(cIndex).getRGBComponents(null);
048      float r = c[0], g = c[1], b = c[2];
049
050      if (Rasterize.doGamma)
051      {
052         // Apply gamma-encoding (gamma-compression) to the two colors.
053         // https://www.scratchapixel.com/lessons/digital-imaging/digital-images
054         // http://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/
055         final double gammaInv = 1.0 / Rasterize.GAMMA;
056         r = (float)Math.pow(r, gammaInv);
057         g = (float)Math.pow(g, gammaInv);
058         b = (float)Math.pow(b, gammaInv);
059      }
060
061      // Transform the vertex to the pixel-plane coordinate system.
062      double x = 0.5 + w/2.001 * (v.x + 1); // x_pp = 0.5 + w/2 * (x_p+1)
063      double y = 0.5 + h/2.001 * (v.y + 1); // y_pp = 0.5 + h/2 * (y_p+1)
064      // NOTE: Notice the 2.001 fudge factor in the last two equations.
065      // This is explained on page 142 of
066      //    "Jim Blinn's Corner: A Trip Down The Graphics Pipeline"
067      //     by Jim Blinn, 1996, Morgan Kaufmann Publishers.
068
069      if (Rasterize.debug)
070      {
071         logMessage(String.format("(x_pp, y_pp) = (%9.4f, %9.4f)", x, y));
072      }
073
074      // Round the point's coordinates to the nearest logical pixel.
075      x = Math.round( x );
076      y = Math.round( y );
077
078      final int radius = pt.radius;
079
080      for (int y_ = (int)y - radius; y_ <= (int)y + radius; ++y_)
081      {
082         for (int x_ = (int)x - radius; x_ <= (int)x + radius; ++x_)
083         {
084            if (Rasterize.debug)
085            {
086               final String clippedMessage;
087               if ( ! Rasterize.doClipping
088                 || (x_ > 0 && x_ <= w && y_ > 0 && y_ <= h) ) // clipping test
089               {
090                  clippedMessage = NOT_CLIPPED;
091               }
092               else
093               {
094                  clippedMessage = CLIPPED;
095               }
096               logPixel(clippedMessage, x, y, x_ - 1, h - y_, r, g, b, vp);
097            }
098            // Log the pixel before setting it so that an array out-
099            // of-bounds error will be right after the pixel's address.
100
101            if ( ! Rasterize.doClipping
102              || (x_ > 0 && x_ <= w && y_ > 0 && y_ <= h) ) // clipping test
103            {
104               vp.setPixelVP(x_ - 1, h - y_, new Color(r, g, b));
105            }
106         }
107      }
108   }
109
110
111
112   // Private default constructor to enforce noninstantiable class.
113   // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch.
114   private Rasterize_Clip_Point() {
115      throw new AssertionError();
116   }
117}