diff --git a/jgltf-impl-v2/src/main/java/de/javagl/jgltf/impl/v2/Accessor.java b/jgltf-impl-v2/src/main/java/de/javagl/jgltf/impl/v2/Accessor.java
index 4d732537..ad33a753 100644
--- a/jgltf-impl-v2/src/main/java/de/javagl/jgltf/impl/v2/Accessor.java
+++ b/jgltf-impl-v2/src/main/java/de/javagl/jgltf/impl/v2/Accessor.java
@@ -168,7 +168,7 @@ public void setComponentType(Integer componentType) {
if (componentType == null) {
throw new NullPointerException((("Invalid value for componentType: "+ componentType)+", may not be null"));
}
- if ((((((componentType!= 5120)&&(componentType!= 5121))&&(componentType!= 5122))&&(componentType!= 5123))&&(componentType!= 5125))&&(componentType!= 5126)) {
+ if ((((((componentType!= 5120)&&(componentType!= 5121))&&(componentType!= 5122))&&(componentType!= 5123))&&(componentType!= 5125))&&(componentType!= 5126)&&(componentType!= 5130)) {
throw new IllegalArgumentException((("Invalid value for componentType: "+ componentType)+", valid: [5120, 5121, 5122, 5123, 5125, 5126]"));
}
this.componentType = componentType;
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDatas.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDatas.java
index 23a2266c..12712aa2 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDatas.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDatas.java
@@ -86,6 +86,10 @@ public static AccessorData create(
{
return createFloat(accessorModel, byteBuffer);
}
+ if (accessorModel.getComponentDataType() == double.class)
+ {
+ return createDouble(accessorModel, byteBuffer);
+ }
// Should never happen
logger.severe("Invalid component data type: "
+ accessorModel.getComponentDataType());
@@ -138,6 +142,12 @@ public static AccessorData create(
componentType, bufferViewData, byteOffset, count,
elementType, byteStride);
}
+ if (isDoubleType(componentType))
+ {
+ return new AccessorDoubleData(
+ componentType, bufferViewData, byteOffset, count,
+ elementType, byteStride);
+ }
throw new IllegalArgumentException(
"Not a valid component type: " + componentType);
}
@@ -197,6 +207,17 @@ public static boolean isFloatType(int type)
return type == GltfConstants.GL_FLOAT;
}
+ /**
+ * Returns whether the given constant is GL_DOUBLE.
+ *
+ * @param type The type constant
+ * @return Whether the type is a double type
+ */
+ public static boolean isDoubleType(int type)
+ {
+ return type == GltfConstants.GL_DOUBLE;
+ }
+
/**
* Returns whether the given constant is GL_UNSIGNED_BYTE,
* GL_UNSIGNED_SHORT or GL_UNSIGNED_INT.
@@ -288,6 +309,24 @@ static void validateFloatType(int type)
}
}
+ /**
+ * Make sure that the given type is GL_DOUBLE, and throw an
+ * IllegalArgumentException if this is not the case.
+ *
+ * @param type The type constant
+ * @throws IllegalArgumentException If the given type is not
+ * GL_DOUBLE
+ */
+ static void validateDoubleType(int type)
+ {
+ if (!isDoubleType(type))
+ {
+ throw new IllegalArgumentException(
+ "The type is not GL_DOUBLE, but " +
+ GltfConstants.stringFor(type));
+ }
+ }
+
/**
@@ -432,6 +471,8 @@ public static AccessorFloatData createFloat(AccessorModel accessorModel)
* @return The {@link AccessorFloatData}
* @throws NullPointerException If any argument is null
* @throws IllegalArgumentException If the
+ * {@link AccessorModel#getComponentType() component type} of the given
+ * accessorModel is not GL_FLOAT
*/
private static AccessorFloatData createFloat(
AccessorModel accessorModel, ByteBuffer bufferViewByteBuffer)
@@ -444,6 +485,29 @@ private static AccessorFloatData createFloat(
accessorModel.getByteStride());
}
+ /**
+ * Creates an {@link AccessorDoubleData} for the given {@link AccessorModel}
+ *
+ * @param accessorModel The {@link AccessorModel}
+ * @param bufferViewByteBuffer The byte buffer of the
+ * {@link BufferViewModel} referenced by the {@link AccessorModel}
+ * @return The {@link AccessorDoubleData}
+ * @throws NullPointerException If any argument is null
+ * @throws IllegalArgumentException If the
+ * {@link AccessorModel#getComponentType() component type} of the given
+ * accessorModel is not GL_DOUBLE
+ */
+ private static AccessorDoubleData createDouble(
+ AccessorModel accessorModel, ByteBuffer bufferViewByteBuffer)
+ {
+ return new AccessorDoubleData(accessorModel.getComponentType(),
+ bufferViewByteBuffer,
+ accessorModel.getByteOffset(),
+ accessorModel.getCount(),
+ accessorModel.getElementType(),
+ accessorModel.getByteStride());
+ }
+
/**
* Validate that the given {@link AccessorModel} parameters are valid for
* accessing a buffer with the given capacity
@@ -512,6 +576,13 @@ public static Number[] computeMin(AccessorData accessorData)
return NumberArrays.asNumbers(
accessorFloatData.computeMin());
}
+ if (accessorData instanceof AccessorDoubleData)
+ {
+ AccessorDoubleData accessorDoubleData =
+ (AccessorDoubleData) accessorData;
+ return NumberArrays.asNumbers(
+ accessorDoubleData.computeMin());
+ }
throw new IllegalArgumentException(
"Invalid data type: " + accessorData);
}
@@ -554,6 +625,13 @@ public static Number[] computeMax(AccessorData accessorData)
return NumberArrays.asNumbers(
accessorFloatData.computeMax());
}
+ if (accessorData instanceof AccessorDoubleData)
+ {
+ AccessorDoubleData accessorDoubleData =
+ (AccessorDoubleData) accessorData;
+ return NumberArrays.asNumbers(
+ accessorDoubleData.computeMax());
+ }
throw new IllegalArgumentException(
"Invalid data type: " + accessorData);
}
@@ -565,6 +643,7 @@ public static Number[] computeMax(AccessorData accessorData)
* {@link AccessorShortData#createString(Locale, String, int)},
* {@link AccessorIntData#createString(Locale, String, int)} or
* {@link AccessorFloatData#createString(Locale, String, int)},
+ * {@link AccessorDoubleData#createString(Locale, String, int)},
* depending on the type of the given data, with an unspecified
* format string.
*
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDoubleData.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDoubleData.java
new file mode 100644
index 00000000..57af57ae
--- /dev/null
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/AccessorDoubleData.java
@@ -0,0 +1,251 @@
+/*
+ * www.javagl.de - JglTF
+ *
+ * Copyright 2015-2016 Marco Hutter - http://www.javagl.de
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+package de.javagl.jgltf.model;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * A class for accessing the data that is described by an accessor.
+ * It allows accessing the byte buffer of the buffer view of the
+ * accessor, depending on the accessor parameters.
+ *
+ * This data consists of several elements (for example, 3D double vectors),
+ * which consist of several components (for example, the 3 double values).
+ */
+public final class AccessorDoubleData
+ extends AbstractAccessorData
+ implements AccessorData
+{
+ /**
+ * Creates a new instance for accessing the data in the given
+ * byte buffer, according to the rules described by the given
+ * accessor parameters.
+ * @param componentType The component type
+ * @param bufferViewByteBuffer The byte buffer of the buffer view
+ * @param byteOffset The byte offset in the buffer view
+ * @param numElements The number of elements
+ * @param elementType The {@link ElementType}
+ * @param byteStride The byte stride between two elements. If this
+ * is null or 0, then the stride will
+ * be the size of one element.
+ *
+ * @throws NullPointerException If the bufferViewByteBuffer is
+ * null
+ * @throws IllegalArgumentException If the component type is not
+ * GL_DOUBLE
+ * @throws IllegalArgumentException If the given byte buffer does not
+ * have a sufficient capacity to provide the data for the accessor
+ */
+ public AccessorDoubleData(int componentType,
+ ByteBuffer bufferViewByteBuffer, int byteOffset, int numElements,
+ ElementType elementType, Integer byteStride)
+ {
+ super(componentType, double.class, bufferViewByteBuffer, byteOffset,
+ numElements, elementType, Double.BYTES, byteStride);
+ AccessorDatas.validateDoubleType(componentType);
+
+ int numBytesPerElement =
+ getNumComponentsPerElement() * getNumBytesPerComponent();
+ AccessorDatas.validateCapacity(byteOffset, getNumElements(),
+ numBytesPerElement, getByteStridePerElement(),
+ bufferViewByteBuffer.capacity());
+ }
+
+ /**
+ * Returns the value of the specified component of the specified element
+ *
+ * @param elementIndex The element index
+ * @param componentIndex The component index
+ * @return The value
+ * @throws IndexOutOfBoundsException If the given indices cause the
+ * underlying buffer to be accessed out of bounds
+ */
+ public double get(int elementIndex, int componentIndex)
+ {
+ int byteIndex = getByteIndex(elementIndex, componentIndex);
+ return getBufferViewByteBuffer().getDouble(byteIndex);
+ }
+
+ /**
+ * Returns the value of the specified component
+ *
+ * @param globalComponentIndex The global component index
+ * @return The value
+ * @throws IndexOutOfBoundsException If the given index causes the
+ * underlying buffer to be accessed out of bounds
+ */
+ public double get(int globalComponentIndex)
+ {
+ int elementIndex =
+ globalComponentIndex / getNumComponentsPerElement();
+ int componentIndex =
+ globalComponentIndex % getNumComponentsPerElement();
+ return get(elementIndex, componentIndex);
+ }
+
+ /**
+ * Set the value of the specified component of the specified element
+ *
+ * @param elementIndex The element index
+ * @param componentIndex The component index
+ * @param value The value
+ * @throws IndexOutOfBoundsException If the given indices cause the
+ * underlying buffer to be accessed out of bounds
+ */
+ public void set(int elementIndex, int componentIndex, double value)
+ {
+ int byteIndex = getByteIndex(elementIndex, componentIndex);
+ getBufferViewByteBuffer().putDouble(byteIndex, value);
+ }
+
+ /**
+ * Set the value of the specified component
+ *
+ * @param globalComponentIndex The global component index
+ * @param value The value
+ * @throws IndexOutOfBoundsException If the given index causes the
+ * underlying buffer to be accessed out of bounds
+ */
+ public void set(int globalComponentIndex, double value)
+ {
+ int elementIndex =
+ globalComponentIndex / getNumComponentsPerElement();
+ int componentIndex =
+ globalComponentIndex % getNumComponentsPerElement();
+ set(elementIndex, componentIndex, value);
+ }
+
+
+ /**
+ * Returns an array containing the minimum component values of all elements
+ * of this accessor data. This will be an array whose length is the
+ * {@link #getNumComponentsPerElement() number of components per element}.
+ *
+ * @return The minimum values
+ */
+ public double[] computeMin()
+ {
+ double result[] = new double[getNumComponentsPerElement()];
+ Arrays.fill(result, Double.MAX_VALUE);
+ for (int e = 0; e < getNumElements(); e++)
+ {
+ for (int c = 0; c < getNumComponentsPerElement(); c++)
+ {
+ result[c] = Math.min(result[c], get(e, c));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns an array containing the maximum component values of all elements
+ * of this accessor data. This will be an array whose length is the
+ * {@link #getNumComponentsPerElement() number of components per element}.
+ *
+ * @return The minimum values
+ */
+ public double[] computeMax()
+ {
+ double result[] = new double[getNumComponentsPerElement()];
+ Arrays.fill(result, -Double.MAX_VALUE);
+ for (int e = 0; e < getNumElements(); e++)
+ {
+ for (int c = 0; c < getNumComponentsPerElement(); c++)
+ {
+ result[c] = Math.max(result[c], get(e, c));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public ByteBuffer createByteBuffer()
+ {
+ int totalNumComponents = getTotalNumComponents();
+ int totalBytes = totalNumComponents * getNumBytesPerComponent();
+ ByteBuffer result = ByteBuffer.allocateDirect(totalBytes)
+ .order(ByteOrder.nativeOrder());
+ for (int i=0; i 0)
+ {
+ sb.append(", ");
+ if (elementsPerRow > 0 && (e % elementsPerRow) == 0)
+ {
+ sb.append("\n ");
+ }
+ }
+ if (nc > 1)
+ {
+ sb.append("(");
+ }
+ for (int c = 0; c < nc; c++)
+ {
+ if (c > 0)
+ {
+ sb.append(", ");
+ }
+ double component = get(e, c);
+ sb.append(String.format(locale, format, component));
+ }
+ if (nc > 1)
+ {
+ sb.append(")");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/Accessors.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/Accessors.java
index c5bfd6ce..78abd718 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/Accessors.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/Accessors.java
@@ -100,6 +100,7 @@ public static int getNumBytesForAccessorComponentType(int componentType)
case GltfConstants.GL_INT: return 4;
case GltfConstants.GL_UNSIGNED_INT: return 4;
case GltfConstants.GL_FLOAT: return 4;
+ case GltfConstants.GL_DOUBLE: return 8;
default:
break;
}
@@ -118,6 +119,7 @@ public static int getNumBytesForAccessorComponentType(int componentType)
* GL_INT : int.class
* GL_UNSIGNED_INT : int.class
* GL_FLOAT : float.class
+ * GL_DOUBLE : double.class
*
*
* @param componentType The component type
@@ -137,6 +139,7 @@ public static Class> getDataTypeForAccessorComponentType(
case GltfConstants.GL_INT: return int.class;
case GltfConstants.GL_UNSIGNED_INT: return int.class;
case GltfConstants.GL_FLOAT: return float.class;
+ case GltfConstants.GL_DOUBLE: return double.class;
default:
break;
}
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/GltfConstants.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/GltfConstants.java
index 45e6fc52..5677b31c 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/GltfConstants.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/GltfConstants.java
@@ -89,7 +89,10 @@ public class GltfConstants
*/
public static final int GL_FLOAT = 5126;
-
+ /**
+ * The GL_DOUBLE constant (5130)
+ */
+ public static final int GL_DOUBLE = 5130;
/**
* The GL_FLOAT_VEC2 constant (35664)
@@ -510,6 +513,7 @@ public static String stringFor(int constant)
case GL_INT : return "GL_INT";
case GL_UNSIGNED_INT : return "GL_UNSIGNED_INT";
case GL_FLOAT : return "GL_FLOAT";
+ case GL_DOUBLE : return "GL_DOUBLE";
case GL_FLOAT_VEC2 : return "GL_FLOAT_VEC2";
case GL_FLOAT_VEC3 : return "GL_FLOAT_VEC3";
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/NumberArrays.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/NumberArrays.java
index 71bbde14..736ddb1a 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/NumberArrays.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/NumberArrays.java
@@ -79,6 +79,22 @@ static Number[] asNumbers(float array[])
return result;
}
+ /**
+ * Convert the given array into a Number array
+ *
+ * @param array The array
+ * @return The result
+ */
+ static Number[] asNumbers(double array[])
+ {
+ Number result[] = new Number[array.length];
+ for (int i = 0; i < array.length; i++)
+ {
+ result[i] = array[i];
+ }
+ return result;
+ }
+
/**
* Private constructor to prevent instantiation
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/io/Buffers.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/io/Buffers.java
index 16fc263d..69b45390 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/io/Buffers.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/io/Buffers.java
@@ -29,6 +29,7 @@
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
@@ -229,6 +230,23 @@ public static ByteBuffer createByteBufferFrom(FloatBuffer buffer)
return byteBuffer;
}
+ /**
+ * Create a new direct byte buffer with native byte order that has the
+ * same contents as the given double buffer.
+ *
+ * @param buffer The input buffer
+ * @return The new byte buffer
+ */
+ public static ByteBuffer createByteBufferFrom(DoubleBuffer buffer)
+ {
+ ByteBuffer byteBuffer =
+ ByteBuffer.allocateDirect(buffer.capacity() * Double.BYTES);
+ DoubleBuffer doubleBuffer =
+ byteBuffer.order(ByteOrder.nativeOrder()).asDoubleBuffer();
+ doubleBuffer.put(buffer.slice());
+ return byteBuffer;
+ }
+
/**
* Create a new direct byte buffer with native byte order that has the
* same contents as the given int buffer.
diff --git a/jgltf-model/src/main/java/de/javagl/jgltf/model/structure/BufferStructureBuilder.java b/jgltf-model/src/main/java/de/javagl/jgltf/model/structure/BufferStructureBuilder.java
index d68b3241..8fd8fc2b 100644
--- a/jgltf-model/src/main/java/de/javagl/jgltf/model/structure/BufferStructureBuilder.java
+++ b/jgltf-model/src/main/java/de/javagl/jgltf/model/structure/BufferStructureBuilder.java
@@ -27,6 +27,7 @@
package de.javagl.jgltf.model.structure;
import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
@@ -196,6 +197,32 @@ public AccessorModel createAccessorModel(
return createAccessorModel(idPrefix, componentType, type, byteBuffer);
}
+ /**
+ * Create an {@link AccessorModel} in the {@link BufferStructure} that
+ * is currently being built.
+ *
+ * @param idPrefix The ID prefix of the {@link AccessorModel}
+ * @param data The actual data
+ * @param type The type of the data, as a string corresponding to
+ * the {@link ElementType} of the accessor
+ * @return The {@link AccessorModel}
+ */
+ public AccessorModel createAccessorModel(
+ String idPrefix, double data[], String type)
+ {
+ ElementType elementType = ElementType.valueOf(type);
+ int numComponents = elementType.getNumComponents();
+ if (data.length % numComponents != 0)
+ {
+ throw new IllegalArgumentException("Invalid data for type " + type
+ + ". The data.length is not divisble by " + numComponents);
+ }
+ int componentType = GltfConstants.GL_DOUBLE;
+ ByteBuffer byteBuffer =
+ Buffers.createByteBufferFrom(DoubleBuffer.wrap(data));
+ return createAccessorModel(idPrefix, componentType, type, byteBuffer);
+ }
+
/**
* Create an {@link AccessorModel} in the {@link BufferStructure} that
* is currently being built, using the component type