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}