001/*
002 * Renderer 9. 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.util.CheckModel;
011import renderer.framebuffer.*;
012import static renderer.pipeline.PipelineLogger.*;
013
014import java.awt.Color;
015
016/**
017   This renderer takes as its input a {@link Scene} data structure
018   and a {@link FrameBuffer.Viewport} within a {@link FrameBuffer}
019   data structure. This renderer mutates the {@link FrameBuffer.Viewport}
020   so that it is filled in with the rendered image of the geometric
021   scene represented by the {@link Scene} object.
022<p>
023   This implements our seventh rendering pipeline. It converts the
024   transformation stage {@link Model2World} to use {@link Matrix}
025   transformations instead of just using {@link Vector} translations.
026   There are still seven pipeline stages.
027*/
028public final class Pipeline2
029{
030   // Mostly for compatibility with renderers 1 through 3.
031   public static Color DEFAULT_COLOR = Color.white;
032
033   // Make all the intermediate Scene objects
034   // available for special effects processing.
035   public static Scene scene1 = null;
036   public static Scene scene2 = null;
037   public static Scene scene3 = null;
038   public static Scene scene4 = null;
039   public static Scene scene5 = null;
040   public static Scene scene6 = null;
041
042   /**
043      Mutate the {@link FrameBuffer}'s default {@link FrameBuffer.Viewport}
044      so that it holds the rendered image of the {@link Scene} object.
045
046      @param scene  {@link Scene} object to render
047      @param fb     {@link FrameBuffer} to hold rendered image of the {@link Scene}
048   */
049   public static void render(final Scene scene, final FrameBuffer fb)
050   {
051      render(scene, fb.vp); // render into the default viewport
052   }
053
054
055   /**
056      Mutate the {@link FrameBuffer}'s given {@link FrameBuffer.Viewport}
057      so that it holds the rendered image of the {@link Scene} object.
058
059      @param scene  {@link Scene} object to render
060      @param vp     {@link FrameBuffer.Viewport} to hold rendered image of the {@link Scene}
061   */
062   public static void render(final Scene scene, final FrameBuffer.Viewport vp)
063   {
064      PipelineLogger.debugScene = scene.debug;
065
066      logMessage("\n= Begin Rendering of Scene (Pipeline 2): " + scene.name + " =");
067
068      logMessage("- Current Camera:\n" + scene.camera);
069
070      scene1 = new Scene(scene.name, scene.camera);
071
072      logMessage("== 1. Begin model-to-world transformation of Scene ====");
073      for (final Position position : scene.positionList)
074      {
075         PipelineLogger.debugPosition = position.debug;
076
077         if ( position.visible )
078         {
079            logMessage("==== 1. Render position: "
080                             + position.name + " ====");
081
082            logMessage("---- Transformation matrix:\n" + position.getMatrix());
083
084            if ( position.getModel().visible )
085            {
086               logMessage("==== 1. Model-to-world transform of: "
087                                + position.getModel().name + " ====");
088
089               CheckModel.check(position.getModel());
090
091               // Mostly for compatibility with renderers 1 through 3.
092               if (  position.getModel().colorList.isEmpty()
093                 && !position.getModel().vertexList.isEmpty())
094               {
095                  for (int i = 0; i < position.getModel().vertexList.size(); ++i)
096                  {
097                     position.getModel().addColor( DEFAULT_COLOR );
098                  }
099                  System.err.println("***WARNING: Added default color to model: "
100                                    + position.getModel().name + ".");
101               }
102
103               logVertexList("0. Model    ", position.getModel());
104
105               final Model tempModel = Model2World.model2world(position);
106
107               logVertexList("1. World     ", tempModel);
108
109               scene1.addPosition( new Position(tempModel) );
110
111               logMessage("==== 1. End Model: "
112                                + tempModel.name + " ====");
113            }
114            else
115            {
116               logMessage("==== 1. Hidden model: "
117                                + position.getModel().name + " ====");
118            }
119
120            logMessage("==== 1. End position: "
121                             + position.name + " ====");
122         }
123         else
124         {
125            logMessage("==== 1. Hidden position: "
126                             + position.name + " ====");
127         }
128      }
129      logMessage("== 1. End model-to-world transformation of Scene ====");
130
131      scene2 = new Scene(scene.name, scene.camera);
132
133      logMessage("== 2. Begin world-to-view transformation of Scene ====");
134      for (final Position position : scene1.positionList)
135      {
136         logMessage("==== 2. Transform model: "
137                          + position.getModel().name + " ====");
138
139         final Model tempModel = World2View.world2view(position.getModel(),
140                                                       scene.camera);
141
142         logVertexList("2. View   ", tempModel);
143
144         scene2.addPosition( new Position(tempModel) );
145
146         logMessage("==== 2. End Model: " + tempModel.name + " ====");
147      }
148      logMessage("== 2. End view-to-camera transformation of Scene ====");
149
150      scene3 = new Scene(scene.name, scene.camera);
151
152      logMessage("== 3. Begin view-to-camera transformation of Scene ====");
153      for (final Position position : scene2.positionList)
154      {
155         logMessage("==== 3. Transform model: "
156                          + position.getModel().name + " ====");
157
158         final Model tempModel = View2Camera.view2camera(position.getModel(),
159                                                         scene.camera);
160
161         logVertexList("3. Camera   ", tempModel);
162         logColorList("3. Camera   ", tempModel);
163         logPrimitiveList("3. Camera   ", tempModel);
164
165         scene3.addPosition( new Position(tempModel) );
166
167         logMessage("==== 3. End Model: " + tempModel.name + " ====");
168      }
169      logMessage("== 3. End view-to-camera transformation of Scene ====");
170
171      scene4 = new Scene(scene.name, scene.camera);
172
173      logMessage("== 4. Begin near-plane clipping of Scene ====");
174      for (final Position position : scene3.positionList)
175      {
176         logMessage("==== 4. Near_Clip model: "
177                          + position.getModel().name + " ====");
178
179         final Model tempModel = NearClip.clip(position.getModel(),
180                                               scene.camera);
181
182         logVertexList("4.  Near_Clipped  ", tempModel);
183         logColorList("4.  Near_Clipped  ", tempModel);
184         logPrimitiveList("4.  Near_Clipped  ", tempModel);
185
186         scene4.addPosition( new Position(tempModel) );
187
188         logMessage("==== 4. End Model: " + tempModel.name + " ====");
189      }
190      logMessage("== 4. End near-plane clipping of Scene ====");
191
192      scene5 = new Scene(scene.name, scene.camera);
193
194      logMessage("== 5. Begin projection transformation of Scene ====");
195      for (final Position position : scene4.positionList)
196      {
197         logMessage("==== 5. Project model: "
198                          + position.getModel().name + " ====");
199
200         final Model tempModel = Projection.project(position.getModel(),
201                                                    scene.camera);
202
203         logVertexList("5. Projected", tempModel);
204       //logPrimitiveList("5. Projected  ", tempModel);
205
206         scene5.addPosition( new Position(tempModel) );
207
208         logMessage("==== 5. End Model: " + tempModel.name + " ====");
209      }
210      logMessage("== 5. End projection transformation of Scene ====");
211
212      scene6 = new Scene(scene.name, scene.camera);
213
214      logMessage("== 6. Begin clipping of Scene ====");
215      for (final Position position : scene5.positionList)
216      {
217         logMessage("==== 6. Clip model: "
218                          + position.getModel().name + " ====");
219
220         final Model tempModel = Clip.clip(position.getModel());
221
222         logVertexList("6. Clipped  ", tempModel);
223         logColorList("6. Clipped  ", tempModel);
224         logPrimitiveList("6. Clipped  ", tempModel);
225
226         scene6.addPosition( new Position(tempModel) );
227
228         logMessage("==== 6. End Model: " + tempModel.name + " ====");
229      }
230      logMessage("== 6. End clipping of Scene ====");
231
232      logMessage("== 7. Begin rasterization of Scene ====");
233      for (final Position position : scene6.positionList)
234      {
235         logMessage("==== 7. Rasterize model: "
236                          + position.getModel().name + " ====");
237
238         Rasterize.rasterize(position.getModel(), vp);
239
240         logMessage("==== 7. End Model: "
241                          + position.getModel().name + " ====");
242      }
243      logMessage("== 7. End rasterization of Scene ====");
244
245      logMessage("= End Rendering of Scene (Pipeline 2) =");
246   }
247
248
249
250   // Private default constructor to enforce noninstantiable class.
251   // See Item 4 in "Effective Java", 3rd Ed, Joshua Bloch.
252   private Pipeline2() {
253      throw new AssertionError();
254   }
255}