aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/light/LightList.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/light/LightList.java')
-rw-r--r--engine/src/core/com/jme3/light/LightList.java336
1 files changed, 336 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/light/LightList.java b/engine/src/core/com/jme3/light/LightList.java
new file mode 100644
index 0000000..00b6b4d
--- /dev/null
+++ b/engine/src/core/com/jme3/light/LightList.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.light;
+
+import com.jme3.export.*;
+import com.jme3.scene.Spatial;
+import com.jme3.util.SortUtil;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * <code>LightList</code> is used internally by {@link Spatial}s to manage
+ * lights that are attached to them.
+ *
+ * @author Kirill Vainer
+ */
+public final class LightList implements Iterable<Light>, Savable, Cloneable {
+
+ private Light[] list, tlist;
+ private float[] distToOwner;
+ private int listSize;
+ private Spatial owner;
+
+ private static final int DEFAULT_SIZE = 1;
+
+ private static final Comparator<Light> c = new Comparator<Light>() {
+ /**
+ * This assumes lastDistance have been computed in a previous step.
+ */
+ public int compare(Light l1, Light l2) {
+ if (l1.lastDistance < l2.lastDistance)
+ return -1;
+ else if (l1.lastDistance > l2.lastDistance)
+ return 1;
+ else
+ return 0;
+ }
+ };
+
+ /**
+ * Default constructor for serialization. Do not use
+ */
+ public LightList(){
+ }
+
+ /**
+ * Creates a <code>LightList</code> for the given {@link Spatial}.
+ *
+ * @param owner The spatial owner
+ */
+ public LightList(Spatial owner) {
+ listSize = 0;
+ list = new Light[DEFAULT_SIZE];
+ distToOwner = new float[DEFAULT_SIZE];
+ Arrays.fill(distToOwner, Float.NEGATIVE_INFINITY);
+ this.owner = owner;
+ }
+
+ /**
+ * Set the owner of the LightList. Only used for cloning.
+ * @param owner
+ */
+ public void setOwner(Spatial owner){
+ this.owner = owner;
+ }
+
+ private void doubleSize(){
+ Light[] temp = new Light[list.length * 2];
+ float[] temp2 = new float[list.length * 2];
+ System.arraycopy(list, 0, temp, 0, list.length);
+ System.arraycopy(distToOwner, 0, temp2, 0, list.length);
+ list = temp;
+ distToOwner = temp2;
+ }
+
+ /**
+ * Adds a light to the list. List size is doubled if there is no room.
+ *
+ * @param l
+ * The light to add.
+ */
+ public void add(Light l) {
+ if (listSize == list.length) {
+ doubleSize();
+ }
+ list[listSize] = l;
+ distToOwner[listSize++] = Float.NEGATIVE_INFINITY;
+ }
+
+ /**
+ * Remove the light at the given index.
+ *
+ * @param index
+ */
+ public void remove(int index){
+ if (index >= listSize || index < 0)
+ throw new IndexOutOfBoundsException();
+
+ listSize --;
+ if (index == listSize){
+ list[listSize] = null;
+ return;
+ }
+
+ for (int i = index; i < listSize; i++){
+ list[i] = list[i+1];
+ }
+ list[listSize] = null;
+ }
+
+ /**
+ * Removes the given light from the LightList.
+ *
+ * @param l the light to remove
+ */
+ public void remove(Light l){
+ for (int i = 0; i < listSize; i++){
+ if (list[i] == l){
+ remove(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * @return The size of the list.
+ */
+ public int size(){
+ return listSize;
+ }
+
+ /**
+ * @return the light at the given index.
+ * @throws IndexOutOfBoundsException If the given index is outside bounds.
+ */
+ public Light get(int num){
+ if (num >= listSize || num < 0)
+ throw new IndexOutOfBoundsException();
+
+ return list[num];
+ }
+
+ /**
+ * Resets list size to 0.
+ */
+ public void clear() {
+ if (listSize == 0)
+ return;
+
+ for (int i = 0; i < listSize; i++)
+ list[i] = null;
+
+ if (tlist != null)
+ Arrays.fill(tlist, null);
+
+ listSize = 0;
+ }
+
+ /**
+ * Sorts the elements in the list acording to their Comparator.
+ * There are two reasons why lights should be resorted.
+ * First, if the lights have moved, that means their distance to
+ * the spatial changed.
+ * Second, if the spatial itself moved, it means the distance from it to
+ * the individual lights might have changed.
+ *
+ *
+ * @param transformChanged Whether the spatial's transform has changed
+ */
+ public void sort(boolean transformChanged) {
+ if (listSize > 1) {
+ // resize or populate our temporary array as necessary
+ if (tlist == null || tlist.length != list.length) {
+ tlist = list.clone();
+ } else {
+ System.arraycopy(list, 0, tlist, 0, list.length);
+ }
+
+ if (transformChanged){
+ // check distance of each light
+ for (int i = 0; i < listSize; i++){
+ list[i].computeLastDistance(owner);
+ }
+ }
+
+ // now merge sort tlist into list
+ SortUtil.msort(tlist, list, 0, listSize - 1, c);
+ }
+ }
+
+ /**
+ * Updates a "world-space" light list, using the spatial's local-space
+ * light list and its parent's world-space light list.
+ *
+ * @param local
+ * @param parent
+ */
+ public void update(LightList local, LightList parent){
+ // clear the list as it will be reconstructed
+ // using the arguments
+ clear();
+
+ while (list.length <= local.listSize){
+ doubleSize();
+ }
+
+ // add the lights from the local list
+ System.arraycopy(local.list, 0, list, 0, local.listSize);
+ for (int i = 0; i < local.listSize; i++){
+// list[i] = local.list[i];
+ distToOwner[i] = Float.NEGATIVE_INFINITY;
+ }
+
+ // if the spatial has a parent node, add the lights
+ // from the parent list as well
+ if (parent != null){
+ int sz = local.listSize + parent.listSize;
+ while (list.length <= sz)
+ doubleSize();
+
+ for (int i = 0; i < parent.listSize; i++){
+ int p = i + local.listSize;
+ list[p] = parent.list[i];
+ distToOwner[p] = Float.NEGATIVE_INFINITY;
+ }
+
+ listSize = local.listSize + parent.listSize;
+ }else{
+ listSize = local.listSize;
+ }
+ }
+
+ /**
+ * Returns an iterator that can be used to iterate over this LightList.
+ *
+ * @return an iterator that can be used to iterate over this LightList.
+ */
+ public Iterator<Light> iterator() {
+ return new Iterator<Light>(){
+
+ int index = 0;
+
+ public boolean hasNext() {
+ return index < size();
+ }
+
+ public Light next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ return list[index++];
+ }
+
+ public void remove() {
+ LightList.this.remove(--index);
+ }
+ };
+ }
+
+ @Override
+ public LightList clone(){
+ try{
+ LightList clone = (LightList) super.clone();
+
+ clone.owner = null;
+ clone.list = list.clone();
+ clone.distToOwner = distToOwner.clone();
+ clone.tlist = null; // list used for sorting only
+
+ return clone;
+ }catch (CloneNotSupportedException ex){
+ throw new AssertionError();
+ }
+ }
+
+ public void write(JmeExporter ex) throws IOException {
+ OutputCapsule oc = ex.getCapsule(this);
+// oc.write(owner, "owner", null);
+
+ ArrayList<Light> lights = new ArrayList<Light>();
+ for (int i = 0; i < listSize; i++){
+ lights.add(list[i]);
+ }
+ oc.writeSavableArrayList(lights, "lights", null);
+ }
+
+ public void read(JmeImporter im) throws IOException {
+ InputCapsule ic = im.getCapsule(this);
+// owner = (Spatial) ic.readSavable("owner", null);
+
+ List<Light> lights = ic.readSavableArrayList("lights", null);
+ listSize = lights.size();
+
+ // NOTE: make sure the array has a length of at least 1
+ int arraySize = Math.max(DEFAULT_SIZE, listSize);
+ list = new Light[arraySize];
+ distToOwner = new float[arraySize];
+
+ for (int i = 0; i < listSize; i++){
+ list[i] = lights.get(i);
+ }
+
+ Arrays.fill(distToOwner, Float.NEGATIVE_INFINITY);
+ }
+
+}