001/*
002 * Renderer 4. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.scene;
008
009import java.util.List;
010import java.util.ArrayList;
011
012/**
013   A {@code Scene} data structure is a {@link List} of {@link Position}
014   data structures and a {@link Camera} data structure.
015<p>
016   Each {@link Position} object represents a {@link Model} object in a
017   distinct position in three-dimensional camera space.
018<p>
019   Each {@link Model} object represents a distinct geometric object
020   in the scene.
021<p>
022   The {@link Camera} object determines a "view volume", which
023   determines how much of the scene is actually visible (to the
024   camera) and gets rendered into the framebuffer.
025*/
026public final class Scene
027{
028   public final String name;
029   public final Camera camera;
030   public final List<Position> positionList;
031
032   public boolean debug;
033
034   /**
035      Construct a {@code Scene} with a default perspective
036      {@link Camera} object.
037   */
038   public Scene()
039   {
040      this("",                 // name
041           Camera.projPerspective(),
042           new ArrayList<>(),  // positionList
043           false);             // debug
044   }
045
046
047   /**
048      Construct a {@code Scene} with a default perspective
049      {@link Camera} object and the given {@link String} name.
050
051      @param name  {@link String} name for this {@code Scene}
052      @throws NullPointerException if {@code name} is {@code null}
053   */
054   public Scene(final String name)
055   {
056      this(name,
057           Camera.projPerspective(),
058           new ArrayList<>(), // positionList
059           false);            // debug
060   }
061
062
063   /**
064      Construct a {@code Scene} with the given {@link Camera} object.
065
066      @param camera  {@link Camera} object for this {@code Scene}
067      @throws NullPointerException if {@code camera} is {@code null}
068   */
069   public Scene(final Camera camera)
070   {
071      this("",                // name
072           camera,
073           new ArrayList<>(), // positionList
074           false);            // debug
075   }
076
077
078   /**
079      Construct a {@code Scene} with the given {@link Camera} object
080      and the given {@link String} name.
081
082      @param name    {@link String} name for this {@code Scene}
083      @param camera  {@link Camera} object for this {@code Scene}
084      @throws NullPointerException if {@code name} is {@code null}
085      @throws NullPointerException if {@code camera} is {@code null}
086   */
087   public Scene(final String name,
088                final Camera camera)
089   {
090      this(name,
091           camera,
092           new ArrayList<>(), // positionList
093           false);            // debug
094   }
095
096
097   /**
098      Construct a {@code Scene} object with all the given data.
099
100      @param name          {@link String} name for this {@code Scene}
101      @param camera        {@link Camera} object for this {@code Scene}
102      @param positionList  {@link List} of {@link Position} objects
103      @param debug         debug status for this {@code Scene}
104      @throws NullPointerException if {@code camera} is {@code null}
105      @throws NullPointerException if {@code positionList} is {@code null}
106      @throws NullPointerException if {@code name} is {@code null}
107   */
108   public Scene(final String name,
109                final Camera camera,
110                final List<Position> positionList,
111                final boolean debug)
112   {
113      if (null == name)
114         throw new NullPointerException("name must not be null");
115      if (null == camera)
116         throw new NullPointerException("camera must not be null");
117      if (null == positionList)
118         throw new NullPointerException("positionList must not be null");
119
120      this.name = name;
121      this.camera = camera;
122      this.positionList = positionList;
123      this.debug = debug;
124   }
125
126
127   /**
128      Create a new {@code Scene} that is essentially the same as this
129      {@code Scene} but holding a refernece to the given {@link Camera}
130      object.
131
132      @param camera  {@link Camera} object for the new {@code Scene}
133      @return a new {@code Scene} object holding the given {@link Camera} object
134      @throws NullPointerException if {@code camera} is {@code null}
135   */
136   public Scene changeCamera(final Camera camera)
137   {
138      return new Scene(this.name,
139                       camera,
140                       this.positionList,
141                       this.debug);
142   }
143
144
145   /**
146      Get a reference to the {@link Position} object at the given index in this {@code Scene}'s
147      {@link List} of {@link Position}s.
148
149      @param index  index of the {@link Position} to return
150      @return {@link Position} at the specified index in the {@link List} of {@link Position}s
151      @throws IndexOutOfBoundsException if the index is out of range
152              {@code (index < 0 || index >= size())}
153   */
154   public Position getPosition(final int index)
155   {
156      return positionList.get(index);
157   }
158
159
160   /**
161      Set a reference to the given {@link Position} object at the given index in this {@code Scene}'s
162      {@link List} of {@link Position}s.
163
164      @param index     index of the {@link Position} to set
165      @param position  {@link Position} object to place at the specified index in the {@link List} of {@link Position}s
166      @throws NullPointerException if {@link Position} is {@code null}
167      @throws IndexOutOfBoundsException if the index is out of range
168              {@code (index < 0 || index >= size())}
169   */
170   public void setPosition(final int index, final Position position)
171   {
172      if (null == position)
173         throw new NullPointerException("Position must not be null");
174
175      positionList.set(index, position);
176   }
177
178
179   /**
180      Add a {@link Position} (or Positions) to this {@code Scene}.
181
182      @param pArray  array of {@link Position}s to add to this {@code Scene}
183      @throws NullPointerException if any {@link Position} is {@code null}
184   */
185   public void addPosition(final Position... pArray)
186   {
187      for (final Position position : pArray)
188      {
189         if (null == position)
190            throw new NullPointerException("Position must not be null");
191
192         positionList.add(position);
193      }
194   }
195
196
197   /**
198      Get a reference to the first {@link Model} object with the given name from
199      this {@code Scene}'s {@link List} of {@link Position}s.
200
201      @param name  {@link String} name of the {@link Model} to search for
202      @return a {@link Model} with the give name from the {@link List} of {@link Position}s
203   */
204   public Model getModelByName(final String name)
205   {
206      Model result = null;
207      for (final Position position : positionList)
208      {
209         if ( name.equals(position.getModel().name) )
210         {
211            result = position.getModel();
212            break;
213         }
214      }
215      return result;
216   }
217
218
219   /**
220      Get a reference to the first {@link Position} object that holds a {@link Model}
221      with the given name from this {@code Scene}'s {@link List} of {@link Position}s.
222
223      @param name  {@link String} name of the {@link Model} to search for
224      @return a {@link Model} with the give name from the {@link List} of {@link Position}s
225   */
226   public Position getPositionByModelName(final String name)
227   {
228      Position result = null;
229      for (final Position position : positionList)
230      {
231         if ( name.equals(position.getModel().name) )
232         {
233            result = position;
234            break;
235         }
236      }
237      return result;
238   }
239
240
241   /**
242      For debugging.
243
244      @return {@link String} representation of this {@code Scene} object
245   */
246   @Override
247   public String toString()
248   {
249      String result = "";
250      result += "Scene: " + name + "\n";
251      result += camera.toString() + "\n";
252      result += "This Scene has " + positionList.size() + " positions\n";
253      int i = 0;
254      for (final Position p : positionList)
255      {
256         result += "Position " + (i++) + "\n";
257         result += p.toString();
258      }
259      return result;
260   }
261}