diff options
-rw-r--r-- | ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/SimpleOffExample.java | 2 | ||||
-rw-r--r-- | ardor3d-extras/src/main/java/com/ardor3d/extension/model/off/OffImporter.java | 229 |
2 files changed, 182 insertions, 49 deletions
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/SimpleOffExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/SimpleOffExample.java index 46e0c29..c8b3f19 100644 --- a/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/SimpleOffExample.java +++ b/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/SimpleOffExample.java @@ -36,7 +36,7 @@ public class SimpleOffExample extends ExampleBase { // Load the OFF scene final long time = System.currentTimeMillis(); final OffImporter importer = new OffImporter(); - final OffGeometryStore storage = importer.load("off/toilet.off"); + final OffGeometryStore storage = importer.load("off/cube.off"); System.out.println("Importing Took " + (System.currentTimeMillis() - time) + " ms"); final Node model = storage.getScene(); 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 10d837a..944cdeb 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 @@ -25,6 +25,7 @@ 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; @@ -46,68 +47,142 @@ import com.ardor3d.util.resource.ResourceSource; */ 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 */ - _OFF("off", 3, 0, 0, 0), + _CNOFF(), /** - * + * colors + normals */ - _COFF("coff", 3, 0, 4, 0), + _CN4OFF(), /** - * + * colors */ - _CNOFF("cnoff", 3, 3, 4, 0), + _COFF(), /** - * + * colors */ - _NOFF("noff", 3, 3, 0, 0), + _C4OFF(), /** - * - */ - _STCOFF("coff", 3, 0, 4, 2), + * normals + */ + _NOFF(), /** - * - */ - _STCNOFF("cnoff", 3, 3, 4, 2), + * normals + colors + */ + _NCOFF(), /** - * - */ - _STNOFF("noff", 3, 3, 0, 2), + * normals + */ + _N4OFF(), /** * */ - _4OFF("4off", 4, 0, 0, 0), + _OFF(), /** - * + * texture coordinates + colors + normals */ - _C4OFF("c4off", 4, 0, 4, 0), + _STCNOFF(), /** - * + * texture coordinates + colors + normals */ - _CN4OFF("cn4off", 4, 4, 4, 0), + _STCN4OFF(), /** - * + * texture coordinates + colors + */ + _STCOFF(), + /** + * texture coordinates + colors */ - _N4OFF("n4off", 4, 4, 0, 0), + _STC4OFF(), /** - * - */ - _STC4OFF("c4off", 4, 0, 4, 2), + * texture coordinates + normals + colors + */ + _STNCOFF(), + /** + * texture coordinates + normals + colors + */ + _STNC4OFF(), /** - * - */ - _STCN4OFF("cn4off", 4, 4, 4, 2), + * texture coordinates + normals + */ + _STNOFF(), /** - * - */ - _STN4OFF("n4off", 4, 4, 0, 2); + * texture coordinates + normals + */ + _STN4OFF(), + /** + * texture coordinates + */ + _STOFF(), + /** + * texture coordinates + */ + _ST4OFF(), + /** + * + */ + _4OFF(); /** - * lowercase text of the keyword as found in the very beginning of the file + * text of the keyword as found in the very beginning of the file */ - private final String lowercaseKeywordText; + private final String keywordText; /** * vertex values per tuple, either 3 or 4 @@ -134,18 +209,75 @@ public class OffImporter { */ private final int textureValuesPerTuple; - private OffKeyword(final String lowercaseKeywordText, final int vertexValuesPerTuple, - final int normalValuesPerTuple, final int maxColorValuesPerTuple, final int textureValuesPerTuple) { - this.lowercaseKeywordText = lowercaseKeywordText; - this.vertexValuesPerTuple = vertexValuesPerTuple; - this.normalValuesPerTuple = normalValuesPerTuple; - minColorValuesPerTuple = Math.min(1, maxColorValuesPerTuple); - this.maxColorValuesPerTuple = maxColorValuesPerTuple; - this.textureValuesPerTuple = 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 getLowercaseKeywordText() { - return lowercaseKeywordText; + public String getKeywordText() { + return keywordText; } public int getVertexValuesPerTuple() { @@ -186,7 +318,8 @@ public class OffImporter { this.reader = reader; resetSyntax(); eolIsSignificant(true); - lowerCaseMode(true); + // doesn't modify the case to avoid ambiguities between nOFF and NOFF + lowerCaseMode(false); // all printable ascii characters wordChars('!', '~'); @@ -294,8 +427,8 @@ 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.getLowercaseKeywordText().equals(parser.sval)) + 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) { |