aboutsummaryrefslogtreecommitdiffstats
path: root/ardor3d-extras
diff options
context:
space:
mode:
authorJulien Gouesse <[email protected]>2023-03-08 23:52:22 +0100
committerJulien Gouesse <[email protected]>2023-03-08 23:52:22 +0100
commite7b631c42fc83a6d8a9485a5b6c3d26dbdb5bc76 (patch)
tree6e8cd991e00f576eff9aff7dce28a516a7dd26af /ardor3d-extras
parent7d0fd92ececa9499150cc7a4132ed5b3e7c67a4d (diff)
Detects the 64 distinct off keywords in the OFF importer, clarifies which ones are fully supported
Diffstat (limited to 'ardor3d-extras')
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffDimensionInfo.java614
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffGeometryStore.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java444
3 files changed, 721 insertions, 339 deletions
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffDimensionInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffDimensionInfo.java
new file mode 100644
index 0000000..7f11e2b
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffDimensionInfo.java
@@ -0,0 +1,614 @@
+/**
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.model.off;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * off dimension information, i.e sizes of the components
+ */
+final class OffDimensionInfo {
+
+ enum OffKeywordVertexDataComponentId {
+ /**
+ * color
+ */
+ COLOR,
+ /**
+ * normal
+ */
+ NORMAL,
+ /**
+ * texture
+ */
+ TEXTURE;
+ }
+
+ /**
+ * The off keyword indicates which data is available for each vertex except vertex coordinates which are mandatory
+ */
+ private enum OffKeyword {
+ /**
+ * 3D
+ */
+ _OFF(3, false,
+ Stream.<OffKeywordVertexDataComponentId> empty().collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D
+ */
+ _4OFF(4, true,
+ Stream.<OffKeywordVertexDataComponentId> empty().collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D
+ */
+ _nOFF(-1, false,
+ Stream.<OffKeywordVertexDataComponentId> empty().collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D
+ */
+ _4nOFF(-1, true,
+ Stream.<OffKeywordVertexDataComponentId> empty().collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, colors
+ */
+ _COFF(3, false,
+ Stream.of(OffKeywordVertexDataComponentId.COLOR).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, colors
+ */
+ _C4OFF(4, true,
+ Stream.of(OffKeywordVertexDataComponentId.COLOR).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors
+ */
+ _CnOFF(-1, false,
+ Stream.of(OffKeywordVertexDataComponentId.COLOR).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors
+ */
+ _C4nOFF(-1, true,
+ Stream.of(OffKeywordVertexDataComponentId.COLOR).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, colors + normals
+ */
+ _CNOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, colors + normals
+ */
+ _CN4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + normals
+ */
+ _CNnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + normals
+ */
+ _CN4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, colors + normals + textures
+ */
+ _CNSTOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, colors + normals + textures
+ */
+ _CNST4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + normals + textures
+ */
+ _CNSTnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + normals + textures
+ */
+ _CNST4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, colors + textures
+ */
+ _CSTOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, colors + textures
+ */
+ _CST4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + textures
+ */
+ _CSTnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + textures
+ */
+ _CST4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, colors + textures + normals
+ */
+ _CSTNOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, colors + textures + normals
+ */
+ _CSTN4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + textures + normals
+ */
+ _CSTNnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, colors + textures + normals
+ */
+ _CSTN4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.COLOR, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, normals
+ */
+ _NOFF(3, false,
+ Stream.of(OffKeywordVertexDataComponentId.NORMAL).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, normals
+ */
+ _N4OFF(4, true,
+ Stream.of(OffKeywordVertexDataComponentId.NORMAL).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals
+ */
+ _NnOFF(-1, false,
+ Stream.of(OffKeywordVertexDataComponentId.NORMAL).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals
+ */
+ _N4nOFF(-1, true,
+ Stream.of(OffKeywordVertexDataComponentId.NORMAL).collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, normals + colors
+ */
+ _NCOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, normals + colors
+ */
+ _NC4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + colors
+ */
+ _NCnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + colors
+ */
+ _NC4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, normals + colors + textures
+ */
+ _NCSTOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, normals + colors + textures
+ */
+ _NCST4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + colors + textures
+ */
+ _NCSTnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + colors + textures
+ */
+ _NCST4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, normals + textures
+ */
+ _NSTOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, normals + textures
+ */
+ _NST4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + textures
+ */
+ _NSTnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + textures
+ */
+ _NST4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, normals + textures + colors
+ */
+ _NSTCOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, normals + textures + colors
+ */
+ _NSTC4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + textures + colors
+ */
+ _NSTCnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, normals + textures + colors
+ */
+ _NSTC4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.NORMAL, OffKeywordVertexDataComponentId.TEXTURE,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, textures
+ */
+ _STOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, textures
+ */
+ _ST4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures
+ */
+ _STnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures
+ */
+ _ST4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, textures + colors
+ */
+ _STCOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, textures + colors
+ */
+ _STC4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + colors
+ */
+ _STCnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + colors
+ */
+ _STC4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, textures + colors + normals
+ */
+ _STCNOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, textures + colors + normals
+ */
+ _STCN4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + colors + normals
+ */
+ _STCNnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + colors + normals
+ */
+ _STCN4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.COLOR,
+ OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, textures + normals
+ */
+ _STNOFF(3, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, textures + normals
+ */
+ _STN4OFF(4, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + normals
+ */
+ _STNnOFF(-1, false, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + normals
+ */
+ _STN4nOFF(-1, true, Stream.of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 3D, textures + normals + colors
+ */
+ _STNCOFF(
+ 3, false, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * 4D, textures + normals + colors
+ */
+ _STNC4OFF(
+ 4, true, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + normals + colors
+ */
+ _STNCnOFF(
+ -1, false, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new))),
+ /**
+ * ?D, textures + normals + colors
+ */
+ _STNC4nOFF(
+ -1, true, Stream
+ .of(OffKeywordVertexDataComponentId.TEXTURE, OffKeywordVertexDataComponentId.NORMAL,
+ OffKeywordVertexDataComponentId.COLOR)
+ .collect(Collectors.toCollection(LinkedHashSet::new)));
+
+ /**
+ * set of components indicating whether colors, normals and textures are expected on the vertices
+ */
+ private final LinkedHashSet<OffKeywordVertexDataComponentId> componentSet;
+ /**
+ * text of the keyword as found in the very beginning of the file
+ */
+ private final String keywordText;
+
+ /**
+ * vertex values per tuple, either 3 or 4, -1 if unknown yet
+ */
+ private final int vertexValuesPerTuple;
+
+ private final boolean homogeneousComponent;
+
+ /**
+ * minimum color values per tuple, either 0 or 1
+ */
+ private final int minColorValuesPerTuple;
+
+ /**
+ * maximum color values per tuple, either 0, 1 or 4, color map, RGB and RGBA colors are supported
+ */
+ private final int maxColorValuesPerTuple;
+
+ /**
+ * texture values per tuple, either 0 or 2
+ */
+ private final int textureValuesPerTuple;
+
+ private OffKeyword(final int vertexValuesPerTuple, final boolean homogeneousComponent,
+ final LinkedHashSet<OffKeywordVertexDataComponentId> componentSet) {
+ this.vertexValuesPerTuple = vertexValuesPerTuple;
+ this.componentSet = componentSet;
+ // 1 color component for an index in a color map
+ minColorValuesPerTuple = componentSet.contains(OffKeywordVertexDataComponentId.COLOR) ? 1 : 0;
+ // 4 color components for RGBA
+ maxColorValuesPerTuple = componentSet.contains(OffKeywordVertexDataComponentId.COLOR) ? 4 : 0;
+ // u and v texture coordinates
+ textureValuesPerTuple = componentSet.contains(OffKeywordVertexDataComponentId.TEXTURE) ? 2 : 0;
+ keywordText = name().substring(1);
+ this.homogeneousComponent = homogeneousComponent;
+ }
+
+ String getKeywordText() {
+ return keywordText;
+ }
+
+ int getVertexValuesPerTuple() {
+ return vertexValuesPerTuple;
+ }
+
+ int getMinColorValuesPerTuple() {
+ return minColorValuesPerTuple;
+ }
+
+ int getMaxColorValuesPerTuple() {
+ return maxColorValuesPerTuple;
+ }
+
+ int getTextureValuesPerTuple() {
+ return textureValuesPerTuple;
+ }
+
+ LinkedHashSet<OffKeywordVertexDataComponentId> getComponentSet() {
+ return componentSet;
+ }
+
+ boolean hasHomogeneousComponent() {
+ return homogeneousComponent;
+ }
+ }
+
+ private final OffKeyword offKeyword;
+
+ /**
+ * indicates whether the off keyword has been deduced and is not in the file
+ */
+ private final boolean deduced;
+
+ private int vertexValuesPerTuple;
+
+ private int normalValuesPerTuple;
+
+ private int minValuesPerVertexLine;
+
+ private int maxValuesPerVertexLine;
+
+ /**
+ * Constructor
+ *
+ * @param parsedText
+ * text of the off keyword
+ */
+ OffDimensionInfo(final String parsedText) {
+ super();
+ final OffKeyword offKeywordInFile = Arrays.stream(OffKeyword.values())
+ .filter((final OffKeyword offKeyword) -> offKeyword.getKeywordText().equals(parsedText)).findFirst()
+ .orElse(null);
+ if (offKeywordInFile == null) {
+ deduced = true;
+ // when there is no off keyword in the file, it takes OFF keyword's behaviour
+ offKeyword = OffKeyword._OFF;
+ } else {
+ deduced = false;
+ offKeyword = offKeywordInFile;
+ }
+ if (offKeyword.getVertexValuesPerTuple() <= 0) {
+ // it will have to be set later when nDim is known
+ vertexValuesPerTuple = -1;
+ } else {
+ // number of dimensions from the off keyword
+ vertexValuesPerTuple = offKeyword.getVertexValuesPerTuple();
+ compute();
+ }
+ }
+
+ private final void compute() {
+ normalValuesPerTuple = offKeyword.getComponentSet().contains(OffKeywordVertexDataComponentId.NORMAL)
+ ? vertexValuesPerTuple
+ : 0;
+ final int valuesPerVertexLineExcludingColorValues = vertexValuesPerTuple + normalValuesPerTuple
+ + offKeyword.getTextureValuesPerTuple();
+ minValuesPerVertexLine = valuesPerVertexLineExcludingColorValues + offKeyword.getMinColorValuesPerTuple();
+ maxValuesPerVertexLine = valuesPerVertexLineExcludingColorValues + offKeyword.getMaxColorValuesPerTuple();
+ }
+
+ boolean needDimensionNumber() {
+ return vertexValuesPerTuple == -1;
+ }
+
+ void useDimensionNumber(final int nDim) {
+ if (vertexValuesPerTuple == -1) {
+ if (nDim <= 0) {
+ throw new IllegalArgumentException("Illegal dimension number " + nDim);
+ }
+ // if 4nOFF (4 => hasHomogeneousComponent(), nOFF => nDim), each vertex has Ndim+1 components
+ vertexValuesPerTuple = nDim + (hasHomogeneousComponent() ? 1 : 0);
+ compute();
+ } else {
+ throw new IllegalArgumentException("Illegal dimension number " + nDim
+ + ", unneeded when using the off keyword " + offKeyword.getKeywordText());
+ }
+ }
+
+ boolean isDeduced() {
+ return deduced;
+ }
+
+ int computeColorValuesPerTuple(final int totalValuesPerVertexLine) throws IOException {
+ if (totalValuesPerVertexLine < minValuesPerVertexLine) {
+ throw new IOException("Premature end of (vertex) line, expected at least " + minValuesPerVertexLine
+ + " values, got " + totalValuesPerVertexLine);
+ }
+ if (maxValuesPerVertexLine < totalValuesPerVertexLine) {
+ throw new IOException("Too much values per (vertex) line, expected at most " + maxValuesPerVertexLine
+ + " values, got " + totalValuesPerVertexLine);
+ }
+ return totalValuesPerVertexLine - vertexValuesPerTuple - normalValuesPerTuple
+ - offKeyword.textureValuesPerTuple;
+ }
+
+ int getVertexValuesPerTuple() {
+ return vertexValuesPerTuple;
+ }
+
+ int getNormalValuesPerTuple() {
+ return normalValuesPerTuple;
+ }
+
+ int getTextureValuesPerTuple() {
+ return offKeyword.getTextureValuesPerTuple();
+ }
+
+ boolean hasHomogeneousComponent() {
+ return offKeyword.hasHomogeneousComponent();
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffGeometryStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffGeometryStore.java
index d884aff..883f068 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffGeometryStore.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffGeometryStore.java
@@ -240,7 +240,7 @@ public class OffGeometryStore {
}
if (indexModeList.size() == 1) {
- _geometryTool.minimizeVerts(mesh, matchConditions);
+ // _geometryTool.minimizeVerts(mesh, matchConditions);
} else {
// FIXME unsure about minimizeVerts preserving the index modes
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java
index 944cdeb..32f1fbb 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java
@@ -18,14 +18,11 @@ import java.io.Reader;
import java.io.StreamTokenizer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-import java.util.stream.Stream;
import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.Vector2;
@@ -43,264 +40,10 @@ import com.ardor3d.util.resource.ResourceSource;
*
* N.B: supports only the ASCII file format as there's a lack of available binary files to make some tests and the
* specification mentions some constants in the include file named "off.h" but it's not included in Geomview's source
- * code
+ * code. It supports only 1D, 2D and 3D without homogeneous coordinates.
*/
public class OffImporter {
- private enum OffKeywordVertexDataComponentId {
- /**
- * color
- */
- COLOR("C"),
- /**
- * normal
- */
- NORMAL("N"),
- /**
- * texture
- */
- TEXTURE("ST");
-
- private final String keywordText;
-
- private OffKeywordVertexDataComponentId(final String keywordText) {
- this.keywordText = keywordText;
- }
-
- public String getKeywordText() {
- return keywordText;
- }
- }
-
- static {
- // TODO use OffKeywordVertexDataComponentId to generate all possible combinations with OFF and 4OFF
- for (final String componentId0 : Stream.concat(Stream.of(" "), Arrays
- .stream(OffKeywordVertexDataComponentId.values()).map(OffKeywordVertexDataComponentId::getKeywordText))
- .toArray(String[]::new)) {
- for (final String componentId1 : Stream
- .concat(Stream.of(" "), Arrays.stream(OffKeywordVertexDataComponentId.values())
- .map(OffKeywordVertexDataComponentId::getKeywordText))
- .toArray(String[]::new)) {
- for (final String componentId2 : Stream
- .concat(Stream.of(" "), Arrays.stream(OffKeywordVertexDataComponentId.values())
- .map(OffKeywordVertexDataComponentId::getKeywordText))
- .toArray(String[]::new)) {
- // FIXME
- if (!componentId0.equals(componentId1) && !componentId1.equals(componentId2)
- && !componentId0.equals(componentId2)) {
- for (final String offWithoutOrWithDim : new String[] { "OFF", "4OFF" }) {
- System.out.println(
- "_" + componentId0 + componentId1 + componentId2 + offWithoutOrWithDim + ",");
- }
- }
- }
- }
- }
- }
-
- /**
- * The off keyword indicates which data is available for each vertex except vertex coordinates which are mandatory
- */
- private enum OffKeyword {
- /**
- * colors + normals
- */
- _CNOFF(),
- /**
- * colors + normals
- */
- _CN4OFF(),
- /**
- * colors
- */
- _COFF(),
- /**
- * colors
- */
- _C4OFF(),
- /**
- * normals
- */
- _NOFF(),
- /**
- * normals + colors
- */
- _NCOFF(),
- /**
- * normals
- */
- _N4OFF(),
- /**
- *
- */
- _OFF(),
- /**
- * texture coordinates + colors + normals
- */
- _STCNOFF(),
- /**
- * texture coordinates + colors + normals
- */
- _STCN4OFF(),
- /**
- * texture coordinates + colors
- */
- _STCOFF(),
- /**
- * texture coordinates + colors
- */
- _STC4OFF(),
- /**
- * texture coordinates + normals + colors
- */
- _STNCOFF(),
- /**
- * texture coordinates + normals + colors
- */
- _STNC4OFF(),
- /**
- * texture coordinates + normals
- */
- _STNOFF(),
- /**
- * texture coordinates + normals
- */
- _STN4OFF(),
- /**
- * texture coordinates
- */
- _STOFF(),
- /**
- * texture coordinates
- */
- _ST4OFF(),
- /**
- *
- */
- _4OFF();
-
- /**
- * text of the keyword as found in the very beginning of the file
- */
- private final String keywordText;
-
- /**
- * vertex values per tuple, either 3 or 4
- */
- private final int vertexValuesPerTuple;
-
- /**
- * normal values per tuple, either 0, 3 or 4
- */
- private final int normalValuesPerTuple;
-
- /**
- * minimum color values per tuple, either 0 or 1
- */
- private final int minColorValuesPerTuple;
-
- /**
- * maximum color values per tuple, either 0, 1 or 4, color map, RGB and RGBA colors are supported
- */
- private final int maxColorValuesPerTuple;
-
- /**
- * texture values per tuple, either 0 or 2
- */
- private final int textureValuesPerTuple;
-
- private OffKeyword() {
- final String offSuffix;
- if (name().endsWith("nOFF")) {
- throw new UnsupportedOperationException("nOFF not supported, must end with either OFF or 4OFF");
- } else if (name().endsWith("4OFF")) {
- vertexValuesPerTuple = 4;
- offSuffix = "4OFF";
- } else if (name().endsWith("OFF")) {
- vertexValuesPerTuple = 3;
- offSuffix = "OFF";
- } else {
- throw new UnsupportedOperationException(
- "Unsupported off keyword " + name() + ", must end with either OFF or 4OFF");
- }
- final String vertexDataComponentIds;
- if (name().length() == offSuffix.length() + 1) {
- vertexDataComponentIds = "";
- } else {
- vertexDataComponentIds = name().substring(1, name().length() - offSuffix.length());
- }
- if (vertexDataComponentIds.chars()
- .anyMatch((final int vertexDataComponentId) -> IntStream.of('N', 'C', 'S', 'T')
- .noneMatch((final int supportedChar) -> vertexDataComponentId == supportedChar))) {
- throw new UnsupportedOperationException("Unsupported off keyword " + name()
- + ", the first part should contain only the characters N, C, S and T at most once each");
- }
- int tmpNormalValuesPerTuple = 0;
- int tmpMinColorValuesPerTuple = 0;
- int tmpMaxColorValuesPerTuple = 0;
- int tmpTextureValuesPerTuple = 0;
- for (final String vertexDataComponentIdCandidate : new String[] { "N", "C", "ST" }) {
- final int firstIndexOfVertexDataComponentIdCandidate = vertexDataComponentIds
- .indexOf(vertexDataComponentIdCandidate);
- if (firstIndexOfVertexDataComponentIdCandidate != -1) {
- final int lastIndexOfVertexDataComponentIdCandidate = vertexDataComponentIds
- .lastIndexOf(vertexDataComponentIdCandidate);
- // if the candidate appears exactly once
- if (firstIndexOfVertexDataComponentIdCandidate == lastIndexOfVertexDataComponentIdCandidate) {
- switch (vertexDataComponentIdCandidate) {
- case "N":
- tmpNormalValuesPerTuple = vertexValuesPerTuple;
- break;
- case "C":
- tmpMinColorValuesPerTuple = 1;// 1 color component for an index in a color map
- tmpMaxColorValuesPerTuple = 4;// 4 color components for RGBA
- break;
- case "ST":
- tmpTextureValuesPerTuple = 2;// u and v texture coordinates
- break;
- default:
- // cannot happen
- break;
- }
- } else {
- throw new UnsupportedOperationException("Unsupported off keyword " + name()
- + ", the first part should contain N, C and ST at most once each. "
- + vertexDataComponentIdCandidate + " appears more than once.");
- }
- }
- }
- normalValuesPerTuple = tmpNormalValuesPerTuple;
- minColorValuesPerTuple = tmpMinColorValuesPerTuple;
- maxColorValuesPerTuple = tmpMaxColorValuesPerTuple;
- textureValuesPerTuple = tmpTextureValuesPerTuple;
- keywordText = name().substring(1);
- }
-
- public String getKeywordText() {
- return keywordText;
- }
-
- public int getVertexValuesPerTuple() {
- return vertexValuesPerTuple;
- }
-
- public int getNormalValuesPerTuple() {
- return normalValuesPerTuple;
- }
-
- public int getMinColorValuesPerTuple() {
- return minColorValuesPerTuple;
- }
-
- public int getMaxColorValuesPerTuple() {
- return maxColorValuesPerTuple;
- }
-
- public int getTextureValuesPerTuple() {
- return textureValuesPerTuple;
- }
- }
-
private static final Logger LOGGER = Logger.getLogger(OffImporter.class.getName());
public static class OffFileParser extends StreamTokenizer implements Closeable {
@@ -427,11 +170,14 @@ public class OffImporter {
"Premature end of file, expected an optional off keyword followed by three integers vertex_count face_count edge_count");
}
final String unhandledFirstParsedValue;
- final OffKeyword offKeywordInFile = Arrays.stream(OffKeyword.values())
- .filter((final OffKeyword offKeyword) -> offKeyword.getKeywordText().equals(parser.sval))
- .findFirst().orElse(null);
// tries to read an (optional) off keyword
- if (offKeywordInFile == null) {
+ // FIXME try to read nDim
+ final OffDimensionInfo offDimensionInfo = new OffDimensionInfo(parser.sval);
+ if (offDimensionInfo.hasHomogeneousComponent()) {
+ throw new IOException(
+ "Homogeneous coordinates aren't supported whereas " + parser.sval + " requires it");
+ }
+ if (offDimensionInfo.isDeduced()) {
// no *off keyword
OffImporter.LOGGER.log(Level.INFO, "No off keyword on line " + parser.lineno());
unhandledFirstParsedValue = parser.sval;
@@ -461,6 +207,17 @@ public class OffImporter {
throw new IOException(
"Premature end of line, expected three integers vertex_count face_count edge_count");
} else {
+ if (offDimensionInfo.needDimensionNumber()) {
+ offDimensionInfo.useDimensionNumber(Integer.parseInt(parser.sval));
+ do {
+ parser.nextToken();
+ } while (parser.ttype != StreamTokenizer.TT_WORD
+ && parser.ttype != StreamTokenizer.TT_EOF);
+ if (parser.ttype == StreamTokenizer.TT_EOF) {
+ throw new IOException(
+ "Premature end of line, expected three integers vertex_count face_count edge_count");
+ }
+ }
numberOfVertices = Integer.valueOf(parser.sval);
parser.nextToken();
}
@@ -470,6 +227,17 @@ public class OffImporter {
}
} else {
if (unhandledFirstParsedValue == null) {
+ if (offDimensionInfo.needDimensionNumber()) {
+ offDimensionInfo.useDimensionNumber(Integer.parseInt(parser.sval));
+ do {
+ parser.nextToken();
+ } while (parser.ttype != StreamTokenizer.TT_WORD
+ && parser.ttype != StreamTokenizer.TT_EOF);
+ if (parser.ttype == StreamTokenizer.TT_EOF) {
+ throw new IOException(
+ "Premature end of line, expected three integers vertex_count face_count edge_count");
+ }
+ }
// *off keyword and three integers on the first line, rare scenario:
// *OFF vertex_count face_count edge_count
// reads the 3 integer values on the first uncommented line, most common scenario
@@ -507,15 +275,13 @@ public class OffImporter {
if (parser.ttype == StreamTokenizer.TT_EOF) {
throw new IOException("Premature end of file, no vertex has been declared");
}
- // when there is no off keyword in the file, it takes off keyword's behaviour
- final OffKeyword offKeyword = Optional.ofNullable(offKeywordInFile).orElse(OffKeyword._OFF);
- // computes the expected value counts per line of vertex definition
- final int expectedValueCountPerVertexLineExcludingColorValues = offKeyword.getVertexValuesPerTuple()
- + offKeyword.getNormalValuesPerTuple() + offKeyword.getTextureValuesPerTuple();
- final int minExpectedValueCountPerVertexLine = expectedValueCountPerVertexLineExcludingColorValues
- + offKeyword.getMinColorValuesPerTuple();
- final int maxExpectedValueCountPerVertexLine = expectedValueCountPerVertexLineExcludingColorValues
- + offKeyword.getMaxColorValuesPerTuple();
+ // before going further, ensures that the number of components inside the vertices is supported
+ if (offDimensionInfo.getVertexValuesPerTuple() < 1
+ || 3 < offDimensionInfo.getVertexValuesPerTuple()) {
+ throw new IOException("The off keyword " + parser.sval
+ + " requires the unsupported number of components per vertex or dimension "
+ + offDimensionInfo.getVertexValuesPerTuple());
+ }
// reads the vertices, normals, colors and/or texture coordinates for each vertex in that order
// FIXME handle other orders
for (int vertexIndex = 0; vertexIndex < numberOfVertices.intValue(); vertexIndex++) {
@@ -551,75 +317,77 @@ public class OffImporter {
break;
}
} while (goOn);
- if (minExpectedValueCountPerVertexLine <= valueList.size()) {
- if (valueList.size() <= maxExpectedValueCountPerVertexLine) {
- OffImporter.LOGGER.log(Level.INFO, "Coords: "
- + valueList.stream().map(Number::toString).collect(Collectors.joining(" ")));
- if (offKeyword.getVertexValuesPerTuple() == 3) {
- store.getDataStore().getVertices().add(new Vector3(valueList.get(0).doubleValue(),
- valueList.get(1).doubleValue(), valueList.get(2).doubleValue()));
- } else {
- // TODO 4D
- }
- int nextIndex = offKeyword.getVertexValuesPerTuple();
- switch (offKeyword.getNormalValuesPerTuple()) {
- case 0:
- // nothing to do
- break;
- case 3:
- store.getDataStore().getNormals()
- .add(new Vector3(valueList.get(nextIndex).doubleValue(),
- valueList.get(nextIndex + 1).doubleValue(),
- valueList.get(nextIndex + 2).doubleValue()));
- break;
- case 4:
- // TODO 4D
- break;
- }
- nextIndex += offKeyword.getNormalValuesPerTuple();
- final int colorValuesPerTuple = valueList.size() - offKeyword.getVertexValuesPerTuple()
- - offKeyword.getNormalValuesPerTuple() - offKeyword.getTextureValuesPerTuple();
- switch (colorValuesPerTuple) {
- case 0:
- // nothing to do
- break;
- case 1:
- // TODO store the color index somewhere
- break;
- case 3:
- final ColorRGBA rgb = new ColorRGBA(valueList.get(nextIndex).floatValue(),
- valueList.get(nextIndex + 1).floatValue(),
- valueList.get(nextIndex + 2).floatValue(), 0.0f);
- if (valueList.get(nextIndex) instanceof Integer) {
- rgb.divideLocal(255.0f);
- }
- rgb.setAlpha(1.0f);
- store.getDataStore().getColors().add(rgb);
- break;
- case 4:
- final ColorRGBA rgba = new ColorRGBA(valueList.get(nextIndex).floatValue(),
- valueList.get(nextIndex + 1).floatValue(),
- valueList.get(nextIndex + 2).floatValue(),
- valueList.get(nextIndex + 3).floatValue());
- if (valueList.get(nextIndex) instanceof Integer) {
- rgba.divideLocal(255.0f);
- }
- store.getDataStore().getColors().add(rgba);
- break;
+ final int colorValuesPerTuple = offDimensionInfo.computeColorValuesPerTuple(valueList.size());
+ OffImporter.LOGGER.log(Level.INFO,
+ "Coords: " + valueList.stream().map(Number::toString).collect(Collectors.joining(" ")));
+ switch (offDimensionInfo.getVertexValuesPerTuple()) {
+ case 1:
+ store.getDataStore().getVertices()
+ .add(new Vector3(valueList.get(0).doubleValue(), 0.0d, 0.0d));
+ case 2:
+ store.getDataStore().getVertices().add(new Vector3(valueList.get(0).doubleValue(),
+ valueList.get(1).doubleValue(), 0.0d));
+ break;
+ case 3:
+ store.getDataStore().getVertices().add(new Vector3(valueList.get(0).doubleValue(),
+ valueList.get(1).doubleValue(), valueList.get(2).doubleValue()));
+ break;
+ }
+ int nextIndex = offDimensionInfo.getVertexValuesPerTuple();
+ switch (offDimensionInfo.getNormalValuesPerTuple()) {
+ case 0:
+ // nothing to do
+ break;
+ case 1:
+ store.getDataStore().getNormals()
+ .add(new Vector3(valueList.get(nextIndex).doubleValue(), 0.0d, 0.0d));
+ break;
+ case 2:
+ store.getDataStore().getNormals()
+ .add(new Vector3(valueList.get(nextIndex).doubleValue(),
+ valueList.get(nextIndex + 1).doubleValue(), 0.0d));
+ break;
+ case 3:
+ store.getDataStore().getNormals()
+ .add(new Vector3(valueList.get(nextIndex).doubleValue(),
+ valueList.get(nextIndex + 1).doubleValue(),
+ valueList.get(nextIndex + 2).doubleValue()));
+ break;
+ }
+ nextIndex += offDimensionInfo.getNormalValuesPerTuple();
+ switch (colorValuesPerTuple) {
+ case 0:
+ // nothing to do
+ break;
+ case 1:
+ // TODO store the color index somewhere
+ break;
+ case 3:
+ final ColorRGBA rgb = new ColorRGBA(valueList.get(nextIndex).floatValue(),
+ valueList.get(nextIndex + 1).floatValue(),
+ valueList.get(nextIndex + 2).floatValue(), 0.0f);
+ if (valueList.get(nextIndex) instanceof Integer) {
+ rgb.divideLocal(255.0f);
}
- nextIndex += colorValuesPerTuple;
- if (offKeyword.getTextureValuesPerTuple() == 2) {
- store.getDataStore().getTextureCoordinates()
- .add(new Vector2(valueList.get(nextIndex).doubleValue(),
- valueList.get(nextIndex + 1).doubleValue()));
+ rgb.setAlpha(1.0f);
+ store.getDataStore().getColors().add(rgb);
+ break;
+ case 4:
+ final ColorRGBA rgba = new ColorRGBA(valueList.get(nextIndex).floatValue(),
+ valueList.get(nextIndex + 1).floatValue(),
+ valueList.get(nextIndex + 2).floatValue(),
+ valueList.get(nextIndex + 3).floatValue());
+ if (valueList.get(nextIndex) instanceof Integer) {
+ rgba.divideLocal(255.0f);
}
- } else {
- throw new IOException("Too much values per (vertex) line, expected at most "
- + maxExpectedValueCountPerVertexLine + " values, got " + valueList.size());
- }
- } else {
- throw new IOException("Premature end of (vertex) line, expected at least "
- + minExpectedValueCountPerVertexLine + " values, got " + valueList.size());
+ store.getDataStore().getColors().add(rgba);
+ break;
+ }
+ nextIndex += colorValuesPerTuple;
+ if (offDimensionInfo.getTextureValuesPerTuple() == 2) {
+ store.getDataStore().getTextureCoordinates()
+ .add(new Vector2(valueList.get(nextIndex).doubleValue(),
+ valueList.get(nextIndex + 1).doubleValue()));
}
}
for (int faceIndex = 0; faceIndex < numberOfFaces.intValue(); faceIndex++) {