diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/com/sun/javafx/collections/ArrayListenerHelper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/com/sun/javafx/collections/ArrayListenerHelper.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.javafx.collections; + +import com.sun.javafx.binding.ExpressionHelperBase; +import java.util.Arrays; +import javafx.beans.InvalidationListener; +import javafx.collections.ArrayChangeListener; +import javafx.collections.ObservableArray; + +/** + * + * @author akouznet + */ +public abstract class ArrayListenerHelper extends ExpressionHelperBase { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Static methods + + public static ArrayListenerHelper addListener(ArrayListenerHelper helper, T observable, InvalidationListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + return (helper == null)? new ArrayListenerHelper.SingleInvalidation(observable, listener) : helper.addListener(listener); + } + + public static ArrayListenerHelper removeListener(ArrayListenerHelper helper, InvalidationListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + return (helper == null)? null : helper.removeListener(listener); + } + + public static ArrayListenerHelper addListener(ArrayListenerHelper helper, T observable, ArrayChangeListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + return (helper == null)? new ArrayListenerHelper.SingleChange(observable, listener) : helper.addListener(listener); + } + + public static ArrayListenerHelper removeListener(ArrayListenerHelper helper, ArrayChangeListener listener) { + if (listener == null) { + throw new NullPointerException(); + } + return (helper == null)? null : helper.removeListener(listener); + } + + public static void fireValueChangedEvent(ArrayListenerHelper helper, boolean sizeChanged, int from, int to) { + if (helper != null) { + helper.fireValueChangedEvent(sizeChanged, from, to); + } + } + + public static boolean hasListeners(ArrayListenerHelper helper) { + return helper != null; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Common implementations + + protected final T observable; + + public ArrayListenerHelper(T observable) { + this.observable = observable; + } + + protected abstract ArrayListenerHelper addListener(InvalidationListener listener); + protected abstract ArrayListenerHelper removeListener(InvalidationListener listener); + + protected abstract ArrayListenerHelper addListener(ArrayChangeListener listener); + protected abstract ArrayListenerHelper removeListener(ArrayChangeListener listener); + + protected abstract void fireValueChangedEvent(boolean sizeChanged, int from, int to); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Implementations + + private static class SingleInvalidation extends ArrayListenerHelper { + + private final InvalidationListener listener; + + private SingleInvalidation(T observable, InvalidationListener listener) { + super(observable); + this.listener = listener; + } + + @Override + protected ArrayListenerHelper addListener(InvalidationListener listener) { + return new Generic(observable, this.listener, listener); + } + + @Override + protected ArrayListenerHelper removeListener(InvalidationListener listener) { + return (listener.equals(this.listener))? null : this; + } + + @Override + protected ArrayListenerHelper addListener(ArrayChangeListener listener) { + return new Generic(observable, this.listener, listener); + } + + @Override + protected ArrayListenerHelper removeListener(ArrayChangeListener listener) { + return this; + } + + @Override + protected void fireValueChangedEvent(boolean sizeChanged, int from, int to) { + listener.invalidated(observable); + } + } + + private static class SingleChange extends ArrayListenerHelper { + + private final ArrayChangeListener listener; + + private SingleChange(T observable, ArrayChangeListener listener) { + super(observable); + this.listener = listener; + } + + @Override + protected ArrayListenerHelper addListener(InvalidationListener listener) { + return new Generic(observable, listener, this.listener); + } + + @Override + protected ArrayListenerHelper removeListener(InvalidationListener listener) { + return this; + } + + @Override + protected ArrayListenerHelper addListener(ArrayChangeListener listener) { + return new Generic(observable, this.listener, listener); + } + + @Override + protected ArrayListenerHelper removeListener(ArrayChangeListener listener) { + return (listener.equals(this.listener))? null : this; + } + + @Override + protected void fireValueChangedEvent(boolean sizeChanged, int from, int to) { + listener.onChanged(observable, sizeChanged, from, to); + } + } + + private static class Generic extends ArrayListenerHelper { + + private InvalidationListener[] invalidationListeners; + private ArrayChangeListener[] changeListeners; + private int invalidationSize; + private int changeSize; + private boolean locked; + + private Generic(T observable, InvalidationListener listener0, InvalidationListener listener1) { + super(observable); + this.invalidationListeners = new InvalidationListener[] {listener0, listener1}; + this.invalidationSize = 2; + } + + private Generic(T observable, ArrayChangeListener listener0, ArrayChangeListener listener1) { + super(observable); + this.changeListeners = new ArrayChangeListener[] {listener0, listener1}; + this.changeSize = 2; + } + + private Generic(T observable, InvalidationListener invalidationListener, ArrayChangeListener changeListener) { + super(observable); + this.invalidationListeners = new InvalidationListener[] {invalidationListener}; + this.invalidationSize = 1; + this.changeListeners = new ArrayChangeListener[] {changeListener}; + this.changeSize = 1; + } + + @Override + protected Generic addListener(InvalidationListener listener) { + if (invalidationListeners == null) { + invalidationListeners = new InvalidationListener[] {listener}; + invalidationSize = 1; + } else { + final int oldCapacity = invalidationListeners.length; + if (locked) { + final int newCapacity = (invalidationSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1; + invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity); + } else if (invalidationSize == oldCapacity) { + invalidationSize = trim(invalidationSize, invalidationListeners); + if (invalidationSize == oldCapacity) { + final int newCapacity = (oldCapacity * 3)/2 + 1; + invalidationListeners = Arrays.copyOf(invalidationListeners, newCapacity); + } + } + invalidationListeners[invalidationSize++] = listener; + } + return this; + } + + @Override + protected ArrayListenerHelper removeListener(InvalidationListener listener) { + if (invalidationListeners != null) { + for (int index = 0; index < invalidationSize; index++) { + if (listener.equals(invalidationListeners[index])) { + if (invalidationSize == 1) { + if (changeSize == 1) { + return new SingleChange(observable, changeListeners[0]); + } + invalidationListeners = null; + invalidationSize = 0; + } else if ((invalidationSize == 2) && (changeSize == 0)) { + return new SingleInvalidation(observable, invalidationListeners[1-index]); + } else { + final int numMoved = invalidationSize - index - 1; + final InvalidationListener[] oldListeners = invalidationListeners; + if (locked) { + invalidationListeners = new InvalidationListener[invalidationListeners.length]; + System.arraycopy(oldListeners, 0, invalidationListeners, 0, index+1); + } + if (numMoved > 0) { + System.arraycopy(oldListeners, index+1, invalidationListeners, index, numMoved); + } + invalidationSize--; + if (!locked) { + invalidationListeners[invalidationSize] = null; // Let gc do its work + } + } + break; + } + } + } + return this; + } + + @Override + protected ArrayListenerHelper addListener(ArrayChangeListener listener) { + if (changeListeners == null) { + changeListeners = new ArrayChangeListener[] {listener}; + changeSize = 1; + } else { + final int oldCapacity = changeListeners.length; + if (locked) { + final int newCapacity = (changeSize < oldCapacity)? oldCapacity : (oldCapacity * 3)/2 + 1; + changeListeners = Arrays.copyOf(changeListeners, newCapacity); + } else if (changeSize == oldCapacity) { + changeSize = trim(changeSize, changeListeners); + if (changeSize == oldCapacity) { + final int newCapacity = (oldCapacity * 3)/2 + 1; + changeListeners = Arrays.copyOf(changeListeners, newCapacity); + } + } + changeListeners[changeSize++] = listener; + } + return this; + } + + @Override + protected ArrayListenerHelper removeListener(ArrayChangeListener listener) { + if (changeListeners != null) { + for (int index = 0; index < changeSize; index++) { + if (listener.equals(changeListeners[index])) { + if (changeSize == 1) { + if (invalidationSize == 1) { + return new SingleInvalidation(observable, invalidationListeners[0]); + } + changeListeners = null; + changeSize = 0; + } else if ((changeSize == 2) && (invalidationSize == 0)) { + return new SingleChange(observable, changeListeners[1-index]); + } else { + final int numMoved = changeSize - index - 1; + final ArrayChangeListener[] oldListeners = changeListeners; + if (locked) { + changeListeners = new ArrayChangeListener[changeListeners.length]; + System.arraycopy(oldListeners, 0, changeListeners, 0, index+1); + } + if (numMoved > 0) { + System.arraycopy(oldListeners, index+1, changeListeners, index, numMoved); + } + changeSize--; + if (!locked) { + changeListeners[changeSize] = null; // Let gc do its work + } + } + break; + } + } + } + return this; + } + + @Override + protected void fireValueChangedEvent(boolean sizeChanged, int from, int to) { + final InvalidationListener[] curInvalidationList = invalidationListeners; + final int curInvalidationSize = invalidationSize; + final ArrayChangeListener[] curChangeList = changeListeners; + final int curChangeSize = changeSize; + + try { + locked = true; + for (int i = 0; i < curInvalidationSize; i++) { + curInvalidationList[i].invalidated(observable); + } + for (int i = 0; i < curChangeSize; i++) { + curChangeList[i].onChanged(observable, sizeChanged, from, to); + } + } finally { + locked = false; + } + } + } +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/com/sun/javafx/collections/FloatArraySyncer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/com/sun/javafx/collections/FloatArraySyncer.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.javafx.collections; + +/** + * + * @author akouznet + */ +public interface FloatArraySyncer { + + /** + * This method is used to sync arrays on pulses. This method expects + * the same array was synced before. The usage is similar to toArray method + * so always use it as following: {@code dest = source.syncTo(dest);} + * @param array previously synced array + * @return a synced array, which is the same or new array (depending on + * the change). + */ + float[] syncTo(float[] array); +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/com/sun/javafx/collections/IntegerArraySyncer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/com/sun/javafx/collections/IntegerArraySyncer.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.javafx.collections; + + +/** + * + * @author akouznet + */ +public interface IntegerArraySyncer { + + /** + * This method is used to sync arrays on pulses. This method expects + * the same array was synced before. The usage is similar to toArray method + * so always use it as following: {@code dest = source.syncTo(dest);} + * @param array previously synced array + * @return a synced array, which is the same or new array (depending on + * the change). + */ + int[] syncTo(int[] array); +} \ No newline at end of file diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ArrayChangeListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ArrayChangeListener.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + +/** + * Interface that receives notifications of changes to an ObservableArray. + */ +public interface ArrayChangeListener { + + /** + * Called after a change has been made to an ObservableArray. + * + * @param sizeChanged indicates size of array changed + * @param from A beginning (inclusive) of an interval related to the change + * @param to An end (exclusive) of an interval related to the change. + */ + public void onChanged(T observableArray, boolean sizeChanged, int from, int to); +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableArray.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + + +import javafx.beans.Observable; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ReadOnlyIntegerProperty; + + +/** + * + * @author akouznet + */ +public interface ObservableArray extends Observable { + + public void addListener(ArrayChangeListener listener); + + public void removeListener(ArrayChangeListener listener); + + /** + * Sets new length of data in this array. This method creates new array + * if necessary and copies existing data into it. To avoid data copying + * set size to 0 before setting it to new value. + */ + public void setSize(int value); + + /** + * Retrieves length of data in this array + * @return length of data in this array + */ + public int size(); + + public ReadOnlyIntegerProperty sizeProperty(); +} \ No newline at end of file diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableArrayBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableArrayBase.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + + +import com.sun.javafx.collections.ArrayListenerHelper; +import javafx.beans.InvalidationListener; +import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyIntegerWrapper; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + + +/** + * + * @author akouznet + */ +public abstract class ObservableArrayBase implements ObservableArray { + + protected ArrayListenerHelper listenerHelper; + + public ObservableArrayBase() { + } + + /** + * Length of data in this array. Is less or equal to an array length. + * Setting different size will force {@code ObservableArray} to create array + * of given size and copy existing data into it. To avoid data copying + * set size to 0 before setting it to new value. + */ + private final ReadOnlyIntegerWrapper size = new ReadOnlyIntegerWrapper(this, "size", 0); + + /** + * Retrieves length of this array + * @return array length + */ + @Override + public final int size() { + return size.get(); + } + + @Override + public ReadOnlyIntegerProperty sizeProperty() { + return size.getReadOnlyProperty(); + } + + protected ReadOnlyIntegerWrapper sizePropertyImpl() { + return size; + } + + @Override public void addListener(InvalidationListener listener) { + listenerHelper = ArrayListenerHelper.addListener(listenerHelper, this, listener); + } + + @Override public void removeListener(InvalidationListener listener) { + listenerHelper = ArrayListenerHelper.removeListener(listenerHelper, listener); + } + + @Override + public void addListener(ArrayChangeListener listener) { + listenerHelper = ArrayListenerHelper.addListener(listenerHelper, this, listener); + } + + @Override + public void removeListener(ArrayChangeListener listener) { + listenerHelper = ArrayListenerHelper.removeListener(listenerHelper, listener); + } +} \ No newline at end of file diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableFloatArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableFloatArray.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + +/** + * + * @author akouznet + */ +public interface ObservableFloatArray extends ObservableArray { + + public void copyTo(int srcPos, float[] dest, int destPos, int length); + + public float[] get(); + + public float getValue(int index); + + /** + * Sets the array of this {@code TriangleMesh} + * + * @param array source array of components_per_element * n values containing n new array. + */ + public void set(float[] array); + + /** + * Sets the array associated with this {@code FloatArray} + * starting at the specified {@code index} using data in {@code array} + * starting at index {@code start} for {@code length} number of array. + * + * @param index the starting destination index in this TriangleMesh's array array + * @param array source array of floats containing the new array + * @param start starting source index in the array array. + * @param length number of point elements to be copied. + */ + public void set(int index, float[] array, int start, int length); + + public void setValue(int index, float value); + + /** + * Gets the array of this {@code TriangleMesh} + * + * @param array a float array that will receive the array + * if it not null and has sufficient capacity. + * @return a float array of array + */ + public float[] toArray(float[] array); + + /** + * Gets the array associated with this {@code TriangleMesh} starting at the + * specified {@code index} for {@code length} number of array. + * + * @param index starting source array index in this {@code TriangleMesh} + * @param array destination array that will receive this {@code TriangleMesh}'s array data + * @param length number of point elements to be copied + * @return a float array + */ + public float[] toArray(int index, float[] array, int length); + +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableFloatArrayBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableFloatArrayBase.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + + +import com.sun.javafx.collections.ArrayListenerHelper; + + +/** + * + * @author akouznet + */ +public class ObservableFloatArrayBase extends ObservableArrayBase implements ObservableFloatArray { + + private float[] array; + + public ObservableFloatArrayBase() { + } + + /** + * Sets the array of this {@code TriangleMesh} + * + * @param array source array of components_per_element * n values containing n new array. + */ + @Override + public final void set(float[] array) { + boolean sizeChanged = this.array == null || size() != array.length; + + if ((this.array == null) || (this.array.length < array.length)) { + this.array = new float[array.length]; + } + System.arraycopy(array, 0, this.array, 0, array.length); + // Store the valid elements count. + // Note this.array.length can be bigger than array.length. + sizePropertyImpl().set(array.length); + + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, sizeChanged, 0, size()); + } + + /** + * Sets the array associated with this {@code FloatArray} + * starting at the specified {@code index} using data in {@code array} + * starting at index {@code start} for {@code length} number of array. + * + * @param index the starting destination index in this TriangleMesh's array array + * @param array source array of floats containing the new array + * @param start starting source index in the array array. + * @param length number of point elements to be copied. + */ + @Override + public final void set(int index, float[] array, + int start, int length) { + + System.arraycopy(array, start, this.array, index, length); + + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, false, index, index + length); + } + + @Override + public final float[] get() { + return toArray(null); + } + + /** + * Gets the array of this {@code TriangleMesh} + * + * @param array a float array that will receive the array + * if it not null and has sufficient capacity. + * @return a float array of array + */ + @Override + public final float[] toArray(float[] array) { + if (this.array == null) { + return null; + } + if ((array == null) || (size() > array.length)) { + array = new float[size()]; + } + System.arraycopy(this.array, 0, array, 0, size()); + return array; + } + + @Override + public final float getValue(int index) { + return array[index]; + } + + @Override + public final void setValue(int index, float value) { + array[index] = value; + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, false, index, index + 1); + } + + /** + * Gets the array associated with this {@code TriangleMesh} starting at the + * specified {@code index} for {@code length} number of array. + * + * @param index starting source array index in this {@code TriangleMesh} + * @param array destination array that will receive this {@code TriangleMesh}'s array data + * @param length number of point elements to be copied + * @return a float array + */ + @Override + public final float[] toArray(int index, float[] array, int length) { + if (this.array == null) { + return null; + } + System.arraycopy(this.array, index, array, 0, length); + return array; + } + + @Override + public final void copyTo(int srcPos, float[] dest, int destPos, int length) { + if (this.array == null) { + return; + } + System.arraycopy(this.array, srcPos, dest, destPos, length); + } + + @Override + public void setSize(int newSize) { + int oldSize = size(); + int minSize = Math.min(oldSize, newSize); + if (array == null) { + array = new float[newSize]; + } else if (array.length != newSize) { + float[] newArray = new float[newSize]; + System.arraycopy(array, 0, newArray, 0, minSize); + array = newArray; + } + sizePropertyImpl().set(newSize); + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, oldSize != newSize, minSize, minSize); + } +} \ No newline at end of file diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableIntegerArray.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableIntegerArray.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + +/** + * + * @author akouznet + */ +public interface ObservableIntegerArray extends ObservableArray { + + public void copyTo(int srcPos, int[] dest, int destPos, int length); + + public int[] get(); + + public int getValue(int index); + + /** + * Sets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh}. + * + * @param array source array of components_per_element * n indices + * (3 point indices and 3 texCood indices) containing n new array + */ + public void set(int[] array); + + /** + * Sets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh} + * starting at the specified{@code index} using data in {@code array} + * starting at index {@code start} for {@code length} number of array. + * + * @param index the starting destination index in this TriangleMesh's array array + * @param array an int array containing the new interleaved vertices + * @param start starting source index in the array array. + * @param length number of interleaved vertex elements to be copied + */ + public void set(int index, int[] array, int start, int length); + + public void setValue(int index, int value); + + /** + * Gets the array, indices into the points and texCoords arrays, of this + * {@code TriangleMesh} + * + * @param array an int array that will receive the array if it not null and + * has sufficient capacity. + * @return an int array of array + * + */ + public int[] toArray(int[] array); + + /** + * Gets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh} starting at the specified + * {@code index} for {@code length} number of array. + * + * @param index starting source array index in this {@code TriangleMesh} + * @param array destination array that will receive this {@code TriangleMesh}'s array data + * @param length number of face elements to be copied + * @return an int array + */ + public int[] toArray(int index, int[] array, int length); + +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-beans/src/javafx/collections/ObservableIntegerArrayBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javafx-beans/src/javafx/collections/ObservableIntegerArrayBase.java Wed Apr 24 16:25:35 2013 -0700 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package javafx.collections; + +import com.sun.javafx.collections.ArrayListenerHelper; + + +/** + * + * @author akouznet + */ +public class ObservableIntegerArrayBase extends ObservableArrayBase implements ObservableIntegerArray { + + private int[] array; + + public ObservableIntegerArrayBase() { + } + + /** + * Sets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh}. + * + * @param array source array of components_per_element * n indices + * (3 point indices and 3 texCood indices) containing n new array + */ + @Override + public final void set(int[] array) { + boolean sizeChanged = this.array == null || size() != array.length; + if ((this.array == null) || (this.array.length < array.length)) { + this.array = new int[array.length]; + } + System.arraycopy(array, 0, this.array, 0, array.length); + // Store the valid face count. + // Note this.array.length can be bigger than array.length. + sizePropertyImpl().set(array.length); + + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, sizeChanged, 0, size()); + } + + /** + * Sets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh} + * starting at the specified{@code index} using data in {@code array} + * starting at index {@code start} for {@code length} number of array. + * + * @param index the starting destination index in this TriangleMesh's array array + * @param array an int array containing the new interleaved vertices + * @param start starting source index in the array array. + * @param length number of interleaved vertex elements to be copied + */ + @Override + public final void set(int index, int[] array, int start, int length) { + + System.arraycopy(array, start, this.array, index, length); + + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, false, index, index + length); + } + + @Override + public final int[] get() { + return toArray(null); + } + + /** + * Gets the array, indices into the points and texCoords arrays, of this + * {@code TriangleMesh} + * + * @param array an int array that will receive the array if it not null and + * has sufficient capacity. + * @return an int array of array + * + */ + @Override + public final int[] toArray(int[] array) { + if (this.array == null) { + return null; + } + if ((array == null) || (size() > array.length)) { + array = new int[size()]; + } + System.arraycopy(this.array, 0, array, 0, size()); + return array; + } + + @Override + public final int getValue(int index) { + return array[index]; + } + + @Override + public final void setValue(int index, int value) { + array[index] = value; + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, false, index, index + 1); + } + + + /** + * Gets the array, indices into the points and texCoords arrays, + * associated with this {@code TriangleMesh} starting at the specified + * {@code index} for {@code length} number of array. + * + * @param index starting source array index in this {@code TriangleMesh} + * @param array destination array that will receive this {@code TriangleMesh}'s array data + * @param length number of face elements to be copied + * @return an int array + */ + @Override + public final int[] toArray(int index, int[] array, int length) { + if (this.array == null) { + return null; + } + System.arraycopy(this.array, index, array, 0, length); + return array; + } + + @Override + public final void copyTo(int srcPos, int[] dest, int destPos, int length) { + if (this.array == null) { + return; + } + System.arraycopy(this.array, srcPos, dest, destPos, length); + } + + @Override + public void setSize(int newSize) { + int oldSize = size(); + int minSize = Math.min(oldSize, newSize); + if (array == null) { + array = new int[newSize]; + } else if (array.length != newSize) { + int[] newArray = new int[newSize]; + System.arraycopy(array, 0, newArray, 0, minSize); + array = newArray; + } + sizePropertyImpl().set(newSize); + ArrayListenerHelper.fireValueChangedEvent(listenerHelper, oldSize != newSize, minSize, minSize); + } +} diff -r f947046c87fb -r 6a3fa7cf8343 javafx-fxml/src/com/sun/javafx/fxml/builder/TriangleMeshBuilder.java --- a/javafx-fxml/src/com/sun/javafx/fxml/builder/TriangleMeshBuilder.java Tue Apr 23 09:46:17 2013 -0700 +++ b/javafx-fxml/src/com/sun/javafx/fxml/builder/TriangleMeshBuilder.java Wed Apr 24 16:25:35 2013 -0700 @@ -45,7 +45,7 @@ public TriangleMesh build() { TriangleMesh mesh = new TriangleMesh(points, texCoords, faces); if (faceSmoothingGroups != null) { - mesh.setFaceSmoothingGroups(faceSmoothingGroups); + mesh.getFaceSmoothingGroups().set(faceSmoothingGroups); } return mesh; } diff -r f947046c87fb -r 6a3fa7cf8343 javafx-sg-common/build-closed.xml --- a/javafx-sg-common/build-closed.xml Tue Apr 23 09:46:17 2013 -0700 +++ b/javafx-sg-common/build-closed.xml Wed Apr 24 16:25:35 2013 -0700 @@ -5,6 +5,7 @@ diff -r f947046c87fb -r 6a3fa7cf8343 javafx-sg-common/project.properties --- a/javafx-sg-common/project.properties Tue Apr 23 09:46:17 2013 -0700 +++ b/javafx-sg-common/project.properties Wed Apr 24 16:25:35 2013 -0700 @@ -1,6 +1,7 @@ JFXRT_HOME=\ ${runtime.dist.root.dir}/../artifacts/sdk/rt javac.classpath=\ + ${rt.dist.root.dir}/javafx-beans/dist/javafx-beans.jar:\ ${rt.dist.root.dir}/javafx-geom/dist/javafx-geom.jar:\ ${rt.dist.root.dir}/javafx-logging/dist/javafx-logging.jar:\ ${rt.dist.root.dir}/decora-runtime/dist/decora-runtime.jar:\ @@ -8,5 +9,4 @@ ${JFXRT_HOME}/lib/ext/jfxrt.jar javac.test.additional.classpath=\ ${rt.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar:\ - ${rt.dist.root.dir}/javafx-sg-prism/dist/javafx-sg-prism.jar:\ - ${rt.dist.root.dir}/javafx-beans/dist/javafx-beans.jar + ${rt.dist.root.dir}/javafx-sg-prism/dist/javafx-sg-prism.jar \ No newline at end of file diff -r f947046c87fb -r 6a3fa7cf8343 javafx-sg-common/src/com/sun/javafx/sg/PGTriangleMesh.java --- a/javafx-sg-common/src/com/sun/javafx/sg/PGTriangleMesh.java Tue Apr 23 09:46:17 2013 -0700 +++ b/javafx-sg-common/src/com/sun/javafx/sg/PGTriangleMesh.java Wed Apr 24 16:25:35 2013 -0700 @@ -25,16 +25,17 @@ package com.sun.javafx.sg; + +import com.sun.javafx.collections.FloatArraySyncer; +import com.sun.javafx.collections.IntegerArraySyncer; + + /** * TODO: 3D - Need documentation */ public interface PGTriangleMesh { - public void setPoints(float[] points); - public void setPoints(float[] points, int index, int length); - public void setTexCoords(float[] texCoords); - public void setTexCoords(float[] texCoords, int index, int length); - public void setFaces(int[] faces); - public void setFaces(int[] faces, int index, int length); - public void setFaceSmoothingGroups(int[] faceSmoothingGroups); - public void setFaceSmoothingGroups(int[] faceSmoothingGroups, int index, int length); + public void syncPoints(FloatArraySyncer array); + public void syncTexCoords(FloatArraySyncer array); + public void syncFaces(IntegerArraySyncer array); + public void syncFaceSmoothingGroups(IntegerArraySyncer array); } diff -r f947046c87fb -r 6a3fa7cf8343 javafx-sg-prism/build-closed.xml --- a/javafx-sg-prism/build-closed.xml Tue Apr 23 09:46:17 2013 -0700 +++ b/javafx-sg-prism/build-closed.xml Wed Apr 24 16:25:35 2013 -0700 @@ -6,6 +6,7 @@ = points.length) || ((startOffset + lengthInFloatUnit) > points.length)) { - throw new IllegalArgumentException("start or (start + length) is out of range for input points"); - } - int indexOffset = index * NUM_COMPONENTS_PER_POINT; - int pointCountInFloatUnit = getPointCount() * NUM_COMPONENTS_PER_POINT; - if ((indexOffset >= pointCountInFloatUnit) || - ((indexOffset + lengthInFloatUnit) > pointCountInFloatUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's points"); - } - System.arraycopy(points, startOffset, this.points, indexOffset, lengthInFloatUnit); - - if (pointRangeInfos == null) { - pointRangeInfos = new int[MAX_RANGE_SIZE]; - } - - if (!pointUpdateRange) { - pointsDirty = pointUpdateRange = true; - pointRangeInfos[RANGE_INDEX] = index; - pointRangeInfos[RANGE_LENGTH] = length; - } else { - pointsDirty = true; - int fromIndex = Math.min(pointRangeInfos[RANGE_INDEX], index); - int toIndex = Math.max(pointRangeInfos[RANGE_INDEX] + pointRangeInfos[RANGE_LENGTH], index + length); - pointRangeInfos[RANGE_INDEX] = fromIndex; - pointRangeInfos[RANGE_LENGTH] = toIndex - fromIndex; - } - - setDirty(true); - } - - /** - * Gets the points of this {@code TriangleMesh} - * - * @param points a float array that will receive the points - * if it not null and has sufficient capacity. - * @return a float array of points - */ - public final float[] getPoints(float[] points) { - if (this.points == null) { - return null; - } - int pointCountInFloatUnit = getPointCount() * NUM_COMPONENTS_PER_POINT; - if ((points == null) || (pointCountInFloatUnit > points.length)) { - points = new float[pointCountInFloatUnit]; - } - System.arraycopy(this.points, 0, points, 0, pointCountInFloatUnit); + * @return {@code ObservableFloatArray} of points where each point is + * represented by 3 float values x, y and z, in that order. + */ + public ObservableFloatArrayBase getPoints() { return points; } /** - * Gets the points associated with this {@code TriangleMesh} starting at the - * specified {@code index} for {@code length} number of points. - * - * @param index starting source points index in this {@code TriangleMesh} - * @param points destination array that will receive this {@code TriangleMesh}'s points data - * @param length number of point elements to be copied - * @return a float array of points - */ - public final float[] getPoints(int index, float[] points, int length) { - if (index < 0 || length < 0) { - throw new IllegalArgumentException("index and length have to be non-zero"); - } - - int lengthInFloatUnit = length * NUM_COMPONENTS_PER_POINT; - if (lengthInFloatUnit > points.length) { - throw new IllegalArgumentException("length is out of range for input points"); - } - int indexOffset = index * NUM_COMPONENTS_PER_POINT; - int pointCountInFloatUnit = getPointCount() * NUM_COMPONENTS_PER_POINT; - if ((indexOffset >= pointCountInFloatUnit) || - ((indexOffset + lengthInFloatUnit) > pointCountInFloatUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's points"); - } - - if (this.points == null) { - return null; - } - System.arraycopy(this.points, indexOffset, points, 0, lengthInFloatUnit); - return points; - } - - /** - * Sets the texture coordinates of this {@code TriangleMesh}. - * - * @param texCoords source array of NUM_COMPONENTS_PER_TEXCOORD * n values containing n new texCoords. - */ - public final void setTexCoords(float[] texCoords) { - // Check that texCoords.length is divisible by NUM_COMPONENTS_PER_TEXCOORD - if ((texCoords.length % NUM_COMPONENTS_PER_TEXCOORD) != 0) { - throw new IllegalArgumentException("texCoords.length has to be divisible by NUM_COMPONENTS_PER_TEXCOORD." - +" It is to store multiple u and v texture coordinates of this mesh"); - } - - if ((this.texCoords == null) || (this.texCoords.length < texCoords.length)) { - this.texCoords = new float[texCoords.length]; - } - System.arraycopy(texCoords, 0, this.texCoords, 0, texCoords.length); - // Store the valid texCoords count. - // Note this.texCoords.length can be bigger than texCoords.length. - setTexCoordCount(texCoords.length / NUM_COMPONENTS_PER_TEXCOORD); - - texCoordsDirty = true; - setDirty(true); - } - - /** - * Sets the texture coordinates associated with this {@code TriangleMesh} - * starting at the specified {@code index} using data in {@code texCoords} - * starting at index {@code start} for {@code length} number of texCoords. - * - * @param index the starting destination index in this TriangleMesh's texCoords array - * @param texCoords an float array containing the new texture coordinates - * @param start starting source index in the texture coordinates array - * @param length number of texCoord elements to be copied. - */ - public final void setTexCoords(int index, float[] texCoords, int start, - int length) { - if (index < 0 || start < 0 || length < 0) { - throw new IllegalArgumentException("index, start and length have to be non-zero"); - } - int startOffset = start * NUM_COMPONENTS_PER_TEXCOORD; - int lengthInFloatUnit = length * NUM_COMPONENTS_PER_TEXCOORD; - if ((startOffset >= texCoords.length) || ((startOffset + lengthInFloatUnit) > texCoords.length)) { - throw new IllegalArgumentException("start or (start + length) is out of range for input texCoords"); - } - int indexOffset = index * NUM_COMPONENTS_PER_TEXCOORD; - int texCoordCountInFloatUnit = getTexCoordCount() * NUM_COMPONENTS_PER_TEXCOORD; - if ((indexOffset >= texCoordCountInFloatUnit) || - ((indexOffset + lengthInFloatUnit) > texCoordCountInFloatUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's texCoords"); - } - System.arraycopy(texCoords, startOffset, this.texCoords, indexOffset, lengthInFloatUnit); - - if (texCoordRangeInfos == null) { - texCoordRangeInfos = new int[MAX_RANGE_SIZE]; - } - if (!texCoordUpdateRange) { - texCoordsDirty = texCoordUpdateRange = true; - texCoordRangeInfos[RANGE_INDEX] = index; - texCoordRangeInfos[RANGE_LENGTH] = length; - } else { - texCoordsDirty = true; - int fromIndex = Math.min(texCoordRangeInfos[RANGE_INDEX], index); - int toIndex = Math.max(texCoordRangeInfos[RANGE_INDEX] + texCoordRangeInfos[RANGE_LENGTH], index + length); - texCoordRangeInfos[RANGE_INDEX] = fromIndex; - texCoordRangeInfos[RANGE_LENGTH] = toIndex - fromIndex; - } - setDirty(true); - } - - /** - * Gets the texture coordinates of this {@code TriangleMesh}. + * Gets the {@code ObservableFloatArray} of texture coordinates of this {@code TriangleMesh}. * - * @param texCoords a float array that will receive the texture coordinates - * if it not null and has sufficient capacity - * @return a float array of texture coordinates - */ - public final float[] getTexCoords(float[] texCoords) { - if (this.texCoords == null) { - return null; - } - - int texCoordCountInFloatUnit = getTexCoordCount() * NUM_COMPONENTS_PER_TEXCOORD; - if ((texCoords == null) || (texCoordCountInFloatUnit > texCoords.length)) { - texCoords = new float[texCoordCountInFloatUnit]; - } - System.arraycopy(this.texCoords, 0, texCoords, 0, texCoordCountInFloatUnit); + * @return {@code ObservableFloatArray} array of texture coordinates + * where each texture coordinate is represented by 2 float values: u and v, + * in that order + */ + public ObservableFloatArrayBase getTexCoords() { return texCoords; } - + /** - * Gets the texture coordinates associated with this {@code TriangleMesh} - * starting at the specified {@code index} for {@code length} number of - * texCoords. - * - * @param index starting source texCoords index in this {@code TriangleMesh} - * @param texCoords destination array that will receive this {@code TriangleMesh}'s texCoords data - * @param length number of texCoord elements to be copied - * @return a float array of texture coordinates - */ - public final float[] getTexCoords(int index, float[] texCoords, int length) { - if (index < 0 || length < 0) { - throw new IllegalArgumentException("index and length have to be non-zero"); - } - - int lengthInFloatUnit = length * NUM_COMPONENTS_PER_TEXCOORD; - if (lengthInFloatUnit > texCoords.length) { - throw new IllegalArgumentException("length is out of range for input texCoords"); - } - int indexOffset = index * NUM_COMPONENTS_PER_TEXCOORD; - int texCoordCountInFloatUnit = getTexCoordCount() * NUM_COMPONENTS_PER_TEXCOORD; - if ((indexOffset >= texCoordCountInFloatUnit) || - ((indexOffset + lengthInFloatUnit) > texCoordCountInFloatUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's texCoords"); - } - - if (this.texCoords == null) { - return null; - } - System.arraycopy(this.texCoords, indexOffset, texCoords, 0, lengthInFloatUnit); - return texCoords; - } - - /** - * Sets the faces, indices into the points and texCoords arrays, - * associated with this {@code TriangleMesh}. - * - * @param faces source array of NUM_COMPONENTS_PER_FACE * n indices - * (3 point indices and 3 texCood indices) containing n new faces - */ - public final void setFaces(int[] faces) { - // Check that faces.length is divisible by NUM_COMPONENTS_PER_FACE - if ((faces.length % NUM_COMPONENTS_PER_FACE) != 0) { - throw new IllegalArgumentException("faces.length has to be divisible by NUM_COMPONENTS_PER_FACE."); - } - - if ((this.faces == null) || (this.faces.length < faces.length)) { - this.faces = new int[faces.length]; - } - System.arraycopy(faces, 0, this.faces, 0, faces.length); - // Store the valid face count. - // Note this.faces.length can be bigger than faces.length. - setFaceCount(faces.length / NUM_COMPONENTS_PER_FACE); - - facesDirty = true; - setDirty(true); - } - - /** - * Sets the faces, indices into the points and texCoords arrays, - * associated with this {@code TriangleMesh} - * starting at the specified{@code index} using data in {@code faces} - * starting at index {@code start} for {@code length} number of faces. - * - * @param index the starting destination index in this TriangleMesh's faces array - * @param faces an int array containing the new interleaved vertices - * @param start starting source index in the faces array. - * @param length number of interleaved vertex elements to be copied - */ - public final void setFaces(int index, int[] faces, int start, int length) { - if (index < 0 || start < 0 || length < 0) { - throw new IllegalArgumentException("index, start and length have to be non-zero"); - } - int startOffset = start * NUM_COMPONENTS_PER_FACE; - int lengthInIntUnit = length * NUM_COMPONENTS_PER_FACE; - if ((startOffset >= faces.length) || ((startOffset + lengthInIntUnit) > faces.length)) { - throw new IllegalArgumentException("start or (start + length) is out of range for input faces"); - } - int indexOffset = index * NUM_COMPONENTS_PER_FACE; - int faceCountInIntUnit = getFaceCount() * NUM_COMPONENTS_PER_FACE; - if ((indexOffset >= faceCountInIntUnit) || - ((indexOffset + lengthInIntUnit) > faceCountInIntUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's faces"); - } - System.arraycopy(faces, startOffset, this.faces, indexOffset, lengthInIntUnit); - - if (faceRangeInfos == null) { - faceRangeInfos = new int[MAX_RANGE_SIZE]; - } - if (!faceUpdateRange) { - facesDirty = faceUpdateRange = true; - faceRangeInfos[RANGE_INDEX] = index; - faceRangeInfos[RANGE_LENGTH] = length; - } else { - facesDirty = true; - int fromIndex = Math.min(faceRangeInfos[RANGE_INDEX], index); - int toIndex = Math.max(faceRangeInfos[RANGE_INDEX] + faceRangeInfos[RANGE_LENGTH], index + length); - faceRangeInfos[RANGE_INDEX] = fromIndex; - faceRangeInfos[RANGE_LENGTH] = toIndex - fromIndex; - } - setDirty(true); - } - - /** - * Gets the faces, indices into the points and texCoords arrays, of this - * {@code TriangleMesh} + * Gets the {@code ObservableIntegerArray} of faces, indices into the points + * and texCoords arrays, of this {@code TriangleMesh} * - * @param faces an int array that will receive the faces if it not null and - * has sufficient capacity. - * @return an int array of faces - * - */ - public final int[] getFaces(int[] faces) { - if (this.faces == null) { - return null; - } - - int faceCountInIntUnit = getFaceCount() * NUM_COMPONENTS_PER_FACE; - if ((faces == null) || (faceCountInIntUnit > faces.length)) { - faces = new int[faceCountInIntUnit]; - } - System.arraycopy(this.faces, 0, faces, 0, faceCountInIntUnit); + * @return {@code ObservableIntegerArray} of faces where each face is + * 6 integers p0, t0, p1, t1, p3, t3, where p0, p1 and p2 are indices of + * points in points {@code ObservableFloatArray} and t0, t1 and t2 are + * indices of texture coordinates in texCoords {@code ObservableFloatArray}. + * Both indices are in terms of elements (points or textCoords), not individual + * floats. + */ + public ObservableIntegerArrayBase getFaces() { return faces; } /** - * Gets the faces, indices into the points and texCoords arrays, - * associated with this {@code TriangleMesh} starting at the specified - * {@code index} for {@code length} number of faces. - * - * @param index starting source faces index in this {@code TriangleMesh} - * @param faces destination array that will receive this {@code TriangleMesh}'s faces data - * @param length number of face elements to be copied - * @return an int array of faces - */ - public final int[] getFaces(int index, int[] faces, int length) { - if (index < 0 || length < 0) { - throw new IllegalArgumentException("index and length have to be non-zero"); - } - - int lengthInIntUnit = length * NUM_COMPONENTS_PER_FACE; - if (lengthInIntUnit > faces.length) { - throw new IllegalArgumentException("length is out of range for input faces"); - } - int indexOffset = index * NUM_COMPONENTS_PER_FACE; - int faceCountInIntUnit = getFaceCount() * NUM_COMPONENTS_PER_FACE; - if ((indexOffset >= faceCountInIntUnit) || - ((indexOffset + lengthInIntUnit) > faceCountInIntUnit)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's faces"); - } - - if (this.faces == null) { - return null; - } - System.arraycopy(this.faces, indexOffset, faces, 0, lengthInIntUnit); - return faces; - } - - /** - * Sets the face smoothing group for each face in this {@code TriangleMesh} + * Gets the {@code ObservableIntegerArray} of face smoothing groups + * of this {@code TriangleMesh}. * Smoothing affects how a mesh is rendered but it does not effect its * geometry. The face smoothing group value is used to control the smoothing * between adjacent faces. @@ -627,155 +166,23 @@ * when adjacent pair of faces shared a smoothing group. Otherwise the faces * are rendered with a hard edge between them. * - * A null faceSmoothingGroups implies all faces in this mesh have a + * An empty faceSmoothingGroups implies all faces in this mesh have a * smoothing group value of 1. * - * Note: If faceSmoothingGroups is not null, faceSmoothingGroups.length must + * Note: If faceSmoothingGroups is not empty, faceSmoothingGroups.length must * be equal to faces.length/NUM_COMPONENTS_PER_FACE. - */ - public final void setFaceSmoothingGroups(int[] faceSmoothingGroups) { - if (faceSmoothingGroups == null) { - this.faceSmoothingGroups = null; - setFaceSmoothingGroupCount(0); - } else { - // Check that faceSmoothingGroups.length is 1/NUM_COMPONENTS_PER_FACE of faces.length - if (faceSmoothingGroups.length != (faces.length / NUM_COMPONENTS_PER_FACE)) { - throw new IllegalArgumentException("faceSmoothingGroups.length has to be equal to (faces.length / NUM_COMPONENTS_PER_FACE)."); - } - - if ((this.faceSmoothingGroups == null) - || (this.faceSmoothingGroups.length < faceSmoothingGroups.length)) { - this.faceSmoothingGroups = new int[faceSmoothingGroups.length]; - } - System.arraycopy(faceSmoothingGroups, 0, this.faceSmoothingGroups, 0, faceSmoothingGroups.length); - // Store the valid faceSmoothingGroup count. - // Note this.faceSmoothingGroups.length can be bigger than faceSmoothingGroups.length. - setFaceSmoothingGroupCount(faceSmoothingGroups.length); - } - - fsgDirty = true; - setDirty(true); - } - - /** - * Sets the faceSmoothingGroups associated with this {@code TriangleMesh} - * starting at the specified {@code index} using data in {@code faceSmoothingGroups} - * starting at index {@code start} for {@code length} number of faceSmoothingGroups. - * The face smoothing group value is used to control the smoothing - * between adjacent faces. - * - * The face smoothing group is represented by an array of bits and up to 32 - * unique groups is possible. The face smoothing group value can range from - * zero to all 32 groups. A face is said to belong to a group is by having - * the associated bit set. A value of 0 implies no smoothing group or hard - * edges. A face can have no or more smoothing groups. Smoothing is applied - * when adjacent pair of faces shared a smoothing group. Otherwise the faces - * are rendered with a hard edge between them. - * - * @param index the starting destination index in this TriangleMesh's faceSmoothingGroups array - * @param points source array of floats containing the new faceSmoothingGroups - * @param start starting source index in the faceSmoothingGroups array. - * @param length number of faceSmoothingGroup elements to be copied. - */ - public final void setFaceSmoothingGroups(int index, int[] faceSmoothingGroups, - int start, int length) { - - if (index < 0 || start < 0 || length < 0) { - throw new IllegalArgumentException("index, start and length have to be non-zero"); - } - - if ((start >= faceSmoothingGroups.length) || ((start + length) > faceSmoothingGroups.length)) { - throw new IllegalArgumentException("start or (start + length) is out of range for input faceSmoothingGroups"); - } - int fsgCount = getFaceSmoothingGroupCount(); - if ((index >= fsgCount) || - ((index + length) > fsgCount)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's faceSmoothingGroups"); - } - - System.arraycopy(faceSmoothingGroups, start, this.faceSmoothingGroups, index, length); - - if (fsgRangeInfos == null) { - fsgRangeInfos = new int[MAX_RANGE_SIZE]; - } - if (!fsgUpdateRange) { - fsgDirty = fsgUpdateRange = true; - fsgRangeInfos[RANGE_INDEX] = index; - fsgRangeInfos[RANGE_LENGTH] = length; - } else { - fsgDirty = true; - int fromIndex = Math.min(fsgRangeInfos[RANGE_INDEX], index); - int toIndex = Math.max(fsgRangeInfos[RANGE_INDEX] + fsgRangeInfos[RANGE_LENGTH], index + length); - fsgRangeInfos[RANGE_INDEX] = fromIndex; - fsgRangeInfos[RANGE_LENGTH] = toIndex - fromIndex; - } - setDirty(true); - } - - /** - * Gets the face smoothing group for each face in this {@code TriangleMesh} - * @return an int array to smoothing group bits for each face - */ - public final int[] getFaceSmoothingGroups(int[] faceSmoothingGroups) { - if (this.faceSmoothingGroups == null) { - return null; - } - - int fsgCount = getFaceSmoothingGroupCount(); - if ((faceSmoothingGroups == null) || - (fsgCount > faceSmoothingGroups.length)) { - faceSmoothingGroups = new int[fsgCount]; - } - System.arraycopy(this.faceSmoothingGroups, 0, faceSmoothingGroups, 0, fsgCount); + */ + public ObservableIntegerArrayBase getFaceSmoothingGroups() { return faceSmoothingGroups; } - /** - * Gets the face smoothing group for each face in this {@code TriangleMesh} - * starting at the specified {@code index} for {@code length} number of face - * smoothing groups. - * - * @param index starting source face smoothing groups index in this {@code TriangleMesh} - * @param faceSmoothingGroups destination array that will receive this - * {@code TriangleMesh}'s faceSmoothingGroups data - * @param length number of faceSmoothingGroup elements to be copied - * @return an int array of faceSmoothingGroups - */ - public final int[] getFaceSmoothingGroups(int index, int[] faceSmoothingGroups, int length) { - if (index < 0 || length < 0) { - throw new IllegalArgumentException("index and length have to be non-zero"); - } - - if (length > faceSmoothingGroups.length) { - throw new IllegalArgumentException("length is out of range for input faceSmoothingGroups"); - } - - int fsgCount = getFaceSmoothingGroupCount(); - if ((index >= fsgCount) || ((index + length) > fsgCount)) { - throw new IllegalArgumentException("index or (index + length) is out of range for this triangle mesh's faceSmoothingGroups"); - } - - if (this.faceSmoothingGroups == null) { - return null; - } - System.arraycopy(this.faceSmoothingGroups, index, faceSmoothingGroups, 0, length); - return faceSmoothingGroups; - } - - @Override - void setDirty(boolean value) { + @Override void setDirty(boolean value) { super.setDirty(value); if (!value) { // false - pointsDirty = false; - texCoordsDirty = false; - facesDirty = false; - fsgDirty = false; - pointUpdateRange = false; - texCoordUpdateRange = false; - faceUpdateRange = false; - fsgUpdateRange = false; - // We don't clear up XXXPartialUpdateInfos array since we will - // overwrite every element when we update the array. + points.setDirty(false); + texCoords.setDirty(false); + faces.setDirty(false); + faceSmoothingGroups.setDirty(false); } } @@ -831,42 +238,18 @@ PGTriangleMesh pgTriMesh = impl_getPGTriangleMesh(); // sync points - if (pointsDirty) { - if (pointUpdateRange) { - pgTriMesh.setPoints(points, pointRangeInfos[RANGE_INDEX], - pointRangeInfos[RANGE_LENGTH]); - } else { - pgTriMesh.setPoints(points); - } + if (points.dirty) { + pgTriMesh.syncPoints(points); } - // sync texCoords - if (texCoordsDirty) { - if (texCoordUpdateRange) { - pgTriMesh.setTexCoords(texCoords, texCoordRangeInfos[RANGE_INDEX], - texCoordRangeInfos[RANGE_LENGTH]); - } else { - pgTriMesh.setTexCoords(texCoords); - } + if (texCoords.dirty) { + pgTriMesh.syncTexCoords(texCoords); } - // sync faces - if (facesDirty) { - if (faceUpdateRange) { - pgTriMesh.setFaces(faces, faceRangeInfos[RANGE_INDEX], - faceRangeInfos[RANGE_LENGTH]); - } else { - pgTriMesh.setFaces(faces); - } + if (faces.dirty) { + pgTriMesh.syncFaces(faces); } - // sync faceSmoothingGroups - if (fsgDirty) { - if (fsgUpdateRange) { - pgTriMesh.setFaceSmoothingGroups(faceSmoothingGroups, fsgRangeInfos[RANGE_INDEX], - fsgRangeInfos[RANGE_LENGTH]); - } else { - pgTriMesh.setFaceSmoothingGroups(faceSmoothingGroups); - } + if (faceSmoothingGroups.dirty) { + pgTriMesh.syncFaceSmoothingGroups(faceSmoothingGroups); } - setDirty(false); } @@ -875,9 +258,9 @@ if (isDirty() || cachedBounds == null) { cachedBounds = new BoxBounds(); - final double len = points.length; - for (int i = 0; i < len; i += 3) { - cachedBounds.add(points[i], points[i + 1], points[i + 2]); + final double len = points.size(); + for (int i = 0; i < len; i += NUM_COMPONENTS_PER_POINT) { + cachedBounds.add(points.getValue(i), points.getValue(i + 1), points.getValue(i + 2)); } } return bounds.deriveWithNewBounds(cachedBounds); @@ -934,13 +317,13 @@ PickRay pickRay, Point3D origin, Point3D dir, int faceIndex, CullFace cullFace, Node candidate, boolean reportFace, PickResultChooser result) { - final int v0Idx = faces[faceIndex] * 3; - final int v1Idx = faces[faceIndex + 2] * 3; - final int v2Idx = faces[faceIndex + 4] * 3; + final int v0Idx = faces.getValue(faceIndex) * NUM_COMPONENTS_PER_POINT; + final int v1Idx = faces.getValue(faceIndex + 2) * NUM_COMPONENTS_PER_POINT; + final int v2Idx = faces.getValue(faceIndex + 4) * NUM_COMPONENTS_PER_POINT; - final Point3D v0 = new Point3D(points[v0Idx], points[v0Idx + 1], points[v0Idx + 2]); - final Point3D v1 = new Point3D(points[v1Idx], points[v1Idx + 1], points[v1Idx + 2]); - final Point3D v2 = new Point3D(points[v2Idx], points[v2Idx + 1], points[v2Idx + 2]); + final Point3D v0 = new Point3D(points.getValue(v0Idx), points.getValue(v0Idx + 1), points.getValue(v0Idx + 2)); + final Point3D v1 = new Point3D(points.getValue(v1Idx), points.getValue(v1Idx + 1), points.getValue(v1Idx + 2)); + final Point3D v2 = new Point3D(points.getValue(v2Idx), points.getValue(v2Idx + 1), points.getValue(v2Idx + 2)); final Point3D e1 = v1.subtract(v0); final Point3D e2 = v2.subtract(v0); @@ -1028,13 +411,13 @@ // Obtain the texture triangle - final int t0Idx = faces[faceIndex + 1] * 2; - final int t1Idx = faces[faceIndex + 3] * 2; - final int t2Idx = faces[faceIndex + 5] * 2; + final int t0Idx = faces.getValue(faceIndex + 1) * NUM_COMPONENTS_PER_TEXCOORD; + final int t1Idx = faces.getValue(faceIndex + 3) * NUM_COMPONENTS_PER_TEXCOORD; + final int t2Idx = faces.getValue(faceIndex + 5) * NUM_COMPONENTS_PER_TEXCOORD; - final Point2D u0 = new Point2D(texCoords[t0Idx], texCoords[t0Idx + 1]); - final Point2D u1 = new Point2D(texCoords[t1Idx], texCoords[t1Idx + 1]); - final Point2D u2 = new Point2D(texCoords[t2Idx], texCoords[t2Idx + 1]); + final Point2D u0 = new Point2D(texCoords.getValue(t0Idx), texCoords.getValue(t0Idx + 1)); + final Point2D u1 = new Point2D(texCoords.getValue(t1Idx), texCoords.getValue(t1Idx + 1)); + final Point2D u2 = new Point2D(texCoords.getValue(t2Idx), texCoords.getValue(t2Idx + 1)); final Point2D txCentroid = computeCentroid(u0, u1, u2); @@ -1082,7 +465,7 @@ Node candidate, CullFace cullFace, boolean reportFace) { boolean found = false; - final int size = faces.length; + final int size = faces.size(); final Vec3d o = pickRay.getOriginNoClone(); final Point3D origin = new Point3D(o.x, o.y, o.z); @@ -1099,4 +482,154 @@ return found; } + + private class FloatArray extends ObservableFloatArrayBase implements ArrayChangeListener, FloatArraySyncer { + + { + addListener(this); + } + + private boolean dirty; + /** + * Array was replaced + * @return true if array was replaced; false otherwise + */ + private boolean dirtyInFull; + private int dirtyRangeFrom; + private int dirtyRangeLength; + + private void markDirty() { + dirty = true; + TriangleMesh.this.setDirty(true); + } + + /** + * @param dirty if true, the whole collection is marked as dirty; + * if false, the whole collection is marked as not-dirty + */ + public final void setDirty(boolean dirty) { + this.dirtyInFull = dirty; + if (dirty) { + markDirty(); + dirtyRangeFrom = 0; + dirtyRangeLength = size(); + } else { + this.dirty = false; + dirtyRangeFrom = dirtyRangeLength = 0; + } + } + + /** + * Adds a dirty range + * @param from index of the first modified element + * @param length length of the modified range + */ + protected final void addDirtyRange(int from, int length) { + if (length > 0 && !dirtyInFull) { + markDirty(); + if (dirtyRangeLength == 0) { + dirtyRangeFrom = from; + dirtyRangeLength = length; + } else { + int fromIndex = Math.min(dirtyRangeFrom, from); + int toIndex = Math.max(dirtyRangeFrom + dirtyRangeLength, from + length); + dirtyRangeFrom = fromIndex; + dirtyRangeLength = toIndex - fromIndex; + } + } + } + + @Override + public void onChanged(ObservableFloatArray observableArray, boolean sizeChanged, int from, int to) { + if (sizeChanged) { + setDirty(true); + } else { + addDirtyRange(from, to - from); + } + } + + @Override + public float[] syncTo(float[] array) { + if (dirtyInFull || array == null || array.length != size()) { + return toArray(array); + } + copyTo(dirtyRangeFrom, array, dirtyRangeFrom, dirtyRangeLength); + return array; + } + } + + private class IntegerArray extends ObservableIntegerArrayBase implements ArrayChangeListener, IntegerArraySyncer { + + { + addListener(this); + } + + private boolean dirty; + /** + * Array was replaced + * @return true if array was replaced; false otherwise + */ + private boolean dirtyInFull; + private int dirtyRangeFrom; + private int dirtyRangeLength; + + private void markDirty() { + dirty = true; + TriangleMesh.this.setDirty(true); + } + + /** + * @param dirty if true, the whole collection is marked as dirty; + * if false, the whole collection is marked as not-dirty + */ + public final void setDirty(boolean dirty) { + this.dirtyInFull = dirty; + if (dirty) { + markDirty(); + dirtyRangeFrom = 0; + dirtyRangeLength = size(); + } else { + this.dirty = false; + dirtyRangeFrom = dirtyRangeLength = 0; + } + } + + /** + * Adds a dirty range + * @param from index of the first modified element + * @param length length of the modified range + */ + protected final void addDirtyRange(int from, int length) { + if (length > 0 && !dirtyInFull) { + markDirty(); + if (dirtyRangeLength == 0) { + dirtyRangeFrom = from; + dirtyRangeLength = length; + } else { + int fromIndex = Math.min(dirtyRangeFrom, from); + int toIndex = Math.max(dirtyRangeFrom + dirtyRangeLength, from + length); + dirtyRangeFrom = fromIndex; + dirtyRangeLength = toIndex - fromIndex; + } + } + } + + @Override + public void onChanged(ObservableIntegerArray observableArray, boolean sizeChanged, int from, int to) { + if (sizeChanged) { + setDirty(true); + } else { + addDirtyRange(from, to - from); + } + } + + @Override + public int[] syncTo(int[] array) { + if (dirtyInFull || array == null || array.length != size()) { + return toArray(array); + } + copyTo(dirtyRangeFrom, array, dirtyRangeFrom, dirtyRangeLength); + return array; + } + } } diff -r f947046c87fb -r 6a3fa7cf8343 prism-common/src/com/sun/prism/impl/BaseMesh.java --- a/prism-common/src/com/sun/prism/impl/BaseMesh.java Tue Apr 23 09:46:17 2013 -0700 +++ b/prism-common/src/com/sun/prism/impl/BaseMesh.java Wed Apr 24 16:25:35 2013 -0700 @@ -77,7 +77,7 @@ this.pos = pos; this.uv = uv; this.faces = faces; - this.smoothing = smoothing; + this.smoothing = smoothing != null && smoothing.length >= nFaces ? smoothing : null; // System.err.println("*********** MeshBase.buildGeometry() ....."); // MeshData.cc diff -r f947046c87fb -r 6a3fa7cf8343 test-stub-toolkit/build-closed.xml --- a/test-stub-toolkit/build-closed.xml Tue Apr 23 09:46:17 2013 -0700 +++ b/test-stub-toolkit/build-closed.xml Wed Apr 24 16:25:35 2013 -0700 @@ -5,6 +5,7 @@