aboutsummaryrefslogtreecommitdiffstats
path: root/ardor3d-extras/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'ardor3d-extras/src/main/java/com')
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasNode.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasPacker.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasTextureParameter.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TexturePacker.java16
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TextureParameter.java19
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java10
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/AllowScaleFilter.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/MinMaxScaleFilter.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/PlaneBoundaryFilter.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/UpdateFilter.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/AbstractInteractWidget.java9
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/BasicFilterList.java4
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/CompoundInteractWidget.java16
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractArrow.java8
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractMatrix.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractRing.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveMultiPlanarWidget.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MovePlanarWidget.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveWidget.java14
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/RotateWidget.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/SimpleScaleWidget.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2DataStore.java12
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Frame.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Header.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Importer.java42
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Normals.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3DataStore.java48
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Frame.java45
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Header.java65
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Importer.java211
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Surface.java80
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Tag.java38
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjDataStore.java22
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjExporter.java403
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjGeometryStore.java41
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjImporter.java157
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjIndexSet.java14
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjMaterial.java84
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjSetManager.java13
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyDataStore.java50
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyEdgeInfo.java50
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyFaceInfo.java60
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyGeometryStore.java313
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyImporter.java1643
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyMaterial.java20
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlDataStore.java35
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlGeometryStore.java120
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlImporter.java545
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/AbstractMaterial.java244
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/FileHelper.java103
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/KeyframeController.java6
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvEdgeInfo.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvFaceInfo.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripInfo.java15
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripStartInfo.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripifier.java71
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvTriangleStripper.java16
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/PrimitiveGroup.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/VertexCache.java2
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/useful/TrailMesh.java4
61 files changed, 4214 insertions, 496 deletions
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasNode.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasNode.java
index f047859..62efc17 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasNode.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasNode.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasPacker.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasPacker.java
index cf11c06..230ad79 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasPacker.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasPacker.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasTextureParameter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasTextureParameter.java
index c45b4d6..55869c4 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasTextureParameter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/AtlasTextureParameter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TexturePacker.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TexturePacker.java
index 0e6771c..36d2025 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TexturePacker.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TexturePacker.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -12,6 +12,8 @@ package com.ardor3d.extension.atlas;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
@@ -31,8 +33,6 @@ import com.ardor3d.renderer.state.TextureState;
import com.ardor3d.scenegraph.Mesh;
import com.ardor3d.util.TextureManager;
import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
/**
* A tool that uses the AtlasNode/AtlasPacker algorithm to pack textures into texture atlases. It modifies the uv
@@ -69,15 +69,15 @@ public class TexturePacker {
private final List<AtlasPacker> packers;
private final List<ByteBuffer> dataBuffers;
- private final List<Texture> textures = Lists.newArrayList();
+ private final List<Texture> textures = new ArrayList<>();
public TexturePacker(final int atlasWidth, final int atlasHeight) {
this.atlasWidth = atlasWidth;
this.atlasHeight = atlasHeight;
- cachedAtlases = Maps.newHashMap();
- packers = Lists.newArrayList();
- dataBuffers = Lists.newArrayList();
+ cachedAtlases = new HashMap<>();
+ packers = new ArrayList<>();
+ dataBuffers = new ArrayList<>();
addPacker();
}
@@ -168,7 +168,7 @@ public class TexturePacker {
return;
}
- list = Lists.newArrayList();
+ list = new ArrayList<>();
cachedAtlases.put(parameterObject, list);
list.add(parameterObject);
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TextureParameter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TextureParameter.java
index 5679195..9cf8e5d 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TextureParameter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/atlas/TextureParameter.java
@@ -1,9 +1,9 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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>.
*/
@@ -11,6 +11,7 @@
package com.ardor3d.extension.atlas;
import java.nio.FloatBuffer;
+import java.util.Objects;
import com.ardor3d.image.Texture;
import com.ardor3d.renderer.state.RenderState;
@@ -88,10 +89,7 @@ public class TextureParameter {
@Override
public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (textureKey == null ? 0 : textureKey.hashCode());
- return result;
+ return Objects.hashCode(textureKey);
}
@Override
@@ -106,14 +104,7 @@ public class TextureParameter {
return false;
}
final TextureParameter other = (TextureParameter) obj;
- if (textureKey == null) {
- if (other.textureKey != null) {
- return false;
- }
- } else if (!textureKey.equals(other.textureKey)) {
- return false;
- }
- return true;
+ return Objects.equals(textureKey, other.textureKey);
}
public int getTargetTextureIndex() {
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
index 447a226..e924ede 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -10,6 +10,7 @@
package com.ardor3d.extension.interact;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -28,14 +29,13 @@ import com.ardor3d.renderer.Renderer;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.util.ReadOnlyTimer;
import com.google.common.base.Predicate;
-import com.google.common.collect.Lists;
public class InteractManager {
/**
* List of widgets currently managed by this manager.
*/
- protected final List<AbstractInteractWidget> _widgets = Lists.newArrayList();
+ protected final List<AbstractInteractWidget> _widgets = new ArrayList<>();
/**
* The logical layer used by this manager to receive input events prior to forwarding them to the scene.
@@ -66,7 +66,7 @@ public class InteractManager {
/**
* List of filters to modify state prior to applying to a Spatial target.
*/
- protected List<UpdateFilter> _filters = Lists.newArrayList();
+ protected List<UpdateFilter> _filters = new ArrayList<>();
public InteractManager() {
_state = new SpatialState();
@@ -129,11 +129,13 @@ public class InteractManager {
*/
private void setupLogicalLayer() {
_logicalLayer.registerTrigger(new InputTrigger(new Predicate<TwoInputStates>() {
+ @Override
public boolean apply(final TwoInputStates arg0) {
// always trigger this.
return true;
}
}, new TriggerAction() {
+ @Override
public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
if (_spatialTarget != null) {
_state.copyState(_spatialTarget);
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
index e3918d1..aa822a4 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/AllowScaleFilter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/AllowScaleFilter.java
index a1eae88..2105eaa 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/AllowScaleFilter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/AllowScaleFilter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/MinMaxScaleFilter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/MinMaxScaleFilter.java
index e823403..dab5583 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/MinMaxScaleFilter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/MinMaxScaleFilter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/PlaneBoundaryFilter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/PlaneBoundaryFilter.java
index 7be40f4..100b51e 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/PlaneBoundaryFilter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/PlaneBoundaryFilter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/UpdateFilter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/UpdateFilter.java
index 20d1644..0e4646a 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/UpdateFilter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/filter/UpdateFilter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/AbstractInteractWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/AbstractInteractWidget.java
index 87ffd1b..39c6372 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/AbstractInteractWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/AbstractInteractWidget.java
@@ -1,9 +1,9 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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>.
*/
@@ -57,7 +57,7 @@ public abstract class AbstractInteractWidget {
/**
* Use the given inputstates to determine if and how to activate this widget. If the widget uses the given input,
* inputConsumed should be set to "true" and applyFilters should be called by this method.
- *
+ *
* @param source
* the canvas that is our input source.
* @param inputStates
@@ -149,7 +149,8 @@ public abstract class AbstractInteractWidget {
}
protected Vector3 getLastPick() {
- if (_results.getNumber() > 0 && _results.getPickData(0).getIntersectionRecord().getNumberOfIntersections() > 0) {
+ if (_results.getNumber() > 0
+ && _results.getPickData(0).getIntersectionRecord().getNumberOfIntersections() > 0) {
return _results.getPickData(0).getIntersectionRecord().getIntersectionPoint(0);
}
return null;
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/BasicFilterList.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/BasicFilterList.java
index 3b13b9d..75f3364 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/BasicFilterList.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/BasicFilterList.java
@@ -10,15 +10,15 @@
package com.ardor3d.extension.interact.widget;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.ardor3d.extension.interact.InteractManager;
import com.ardor3d.extension.interact.filter.UpdateFilter;
-import com.google.common.collect.Lists;
public class BasicFilterList implements IFilterList {
- final List<UpdateFilter> _filters = Lists.newArrayList();
+ final List<UpdateFilter> _filters = new ArrayList<>();
public Iterator<UpdateFilter> iterator() {
return _filters.iterator();
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/CompoundInteractWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/CompoundInteractWidget.java
index 62a9684..bd45d6e 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/CompoundInteractWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/CompoundInteractWidget.java
@@ -1,15 +1,16 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.interact.widget;
+import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -28,7 +29,6 @@ import com.ardor3d.renderer.Renderer;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.util.ReadOnlyTimer;
-import com.google.common.collect.Maps;
public class CompoundInteractWidget extends AbstractInteractWidget {
@@ -39,12 +39,10 @@ public class CompoundInteractWidget extends AbstractInteractWidget {
public static double MIN_SCALE = 0.000001;
- protected Map<String, AbstractInteractWidget> _widgets = Maps.newHashMap();
+ protected Map<String, AbstractInteractWidget> _widgets = new HashMap<>();
protected AbstractInteractWidget _lastInputWidget = null;
- protected InteractMatrix _interactMatrix;
-
public CompoundInteractWidget() {
super(new BasicFilterList());
_handle = new Node("handleRoot");
@@ -52,7 +50,7 @@ public class CompoundInteractWidget extends AbstractInteractWidget {
@Override
public void addFilter(final UpdateFilter filter) {
- for(final AbstractInteractWidget widget : _widgets.values()) {
+ for (final AbstractInteractWidget widget : _widgets.values()) {
widget.addFilter(filter);
}
super.addFilter(filter);
@@ -60,7 +58,7 @@ public class CompoundInteractWidget extends AbstractInteractWidget {
@Override
public void removeFilter(final UpdateFilter filter) {
- for(final AbstractInteractWidget widget : _widgets.values()) {
+ for (final AbstractInteractWidget widget : _widgets.values()) {
widget.removeFilter(filter);
}
super.removeFilter(filter);
@@ -68,7 +66,7 @@ public class CompoundInteractWidget extends AbstractInteractWidget {
@Override
public void clearFilters() {
- for(final AbstractInteractWidget widget : _widgets.values()) {
+ for (final AbstractInteractWidget widget : _widgets.values()) {
widget.clearFilters();
}
super.clearFilters();
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractArrow.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractArrow.java
index 0fb6fa6..31d14a9 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractArrow.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractArrow.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -29,7 +29,7 @@ public class InteractArrow extends Arrow {
protected double _lengthGap = 0;
protected double _tipGap = 0;
- protected static final Quaternion rotator = new Quaternion().applyRotationX(MathUtils.HALF_PI);
+ protected static final Quaternion ROTATOR = new Quaternion().applyRotationX(MathUtils.HALF_PI);
public InteractArrow() {}
@@ -66,8 +66,8 @@ public class InteractArrow extends Arrow {
final double tipLength = _length / 2.0;
final Pyramid tip = new Pyramid("tip", 2 * _width, tipLength);
tip.getMeshData().translatePoints(0, _tipGap + _length + 0.5 * tipLength, 0);
- tip.getMeshData().rotatePoints(InteractArrow.rotator);
- tip.getMeshData().rotateNormals(InteractArrow.rotator);
+ tip.getMeshData().rotatePoints(InteractArrow.ROTATOR);
+ tip.getMeshData().rotateNormals(InteractArrow.ROTATOR);
attachChild(tip);
tip.updateModelBound();
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractMatrix.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractMatrix.java
index 944bd9d..6b9e235 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractMatrix.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractMatrix.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractRing.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractRing.java
index 983017a..1c3b42b 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractRing.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/InteractRing.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveMultiPlanarWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveMultiPlanarWidget.java
index f47be1b..c598e34 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveMultiPlanarWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveMultiPlanarWidget.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MovePlanarWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MovePlanarWidget.java
index 9787ea7..16b650f 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MovePlanarWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MovePlanarWidget.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveWidget.java
index e03e1bd..c06569d 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/MoveWidget.java
@@ -1,9 +1,9 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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>.
*/
@@ -278,16 +278,6 @@ public class MoveWidget extends AbstractInteractWidget {
return _calcVec3D.subtractLocal(_calcVec3C);
}
- @Override
- public void setInteractMatrix(final InteractMatrix matrix) {
- _interactMatrix = matrix;
- }
-
- @Override
- public InteractMatrix getInteractMatrix() {
- return _interactMatrix;
- }
-
public InteractArrow getXArrow() {
return _xArrow;
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/RotateWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/RotateWidget.java
index a684ef7..03287de 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/RotateWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/RotateWidget.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/SimpleScaleWidget.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/SimpleScaleWidget.java
index ffcc8bb..9f5fc3d 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/SimpleScaleWidget.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/widget/SimpleScaleWidget.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2DataStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2DataStore.java
index a2c12b1..1830aa6 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2DataStore.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2DataStore.java
@@ -1,33 +1,35 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.md2;
+import java.util.ArrayList;
import java.util.List;
import com.ardor3d.extension.model.util.KeyframeController;
import com.ardor3d.scenegraph.Mesh;
-import com.google.common.collect.Lists;
public class Md2DataStore {
private final Mesh _mainMesh;
private final KeyframeController<Mesh> _controller;
- private final List<String> _frameNames = Lists.newArrayList();
+ private final List<String> _frameNames;
- private final List<String> _skinNames = Lists.newArrayList();
+ private final List<String> _skinNames;
public Md2DataStore(final Mesh mainMesh, final KeyframeController<Mesh> controller) {
_mainMesh = mainMesh;
_controller = controller;
+ _frameNames = new ArrayList<>();
+ _skinNames = new ArrayList<>();
}
public Mesh getScene() {
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Frame.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Frame.java
index 8c6b8c1..d01871f 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Frame.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Frame.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Header.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Header.java
index 2dc7bf7..d520378 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Header.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Header.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Importer.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Importer.java
index 6270b66..b9adc18 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Importer.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Importer.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -11,13 +11,14 @@
package com.ardor3d.extension.model.md2;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.List;
import com.ardor3d.bounding.BoundingBox;
import com.ardor3d.extension.model.util.KeyframeController;
import com.ardor3d.image.Texture;
-import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.image.Texture.MinificationFilter;
+import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.math.Vector3;
import com.ardor3d.renderer.IndexMode;
import com.ardor3d.renderer.state.TextureState;
@@ -30,7 +31,6 @@ import com.ardor3d.util.TextureManager;
import com.ardor3d.util.resource.ResourceLocator;
import com.ardor3d.util.resource.ResourceLocatorTool;
import com.ardor3d.util.resource.ResourceSource;
-import com.google.common.collect.Lists;
public class Md2Importer {
@@ -112,10 +112,10 @@ public class Md2Importer {
final LittleEndianRandomAccessDataInput bis = new LittleEndianRandomAccessDataInput(md2Stream);
// parse the header
- final Md2Header header = new Md2Header(bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis
- .readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis
- .readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis
- .readInt());
+ final Md2Header header = new Md2Header(bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt());
// Check magic word and version
if (header.magic != ('2' << 24) + ('P' << 16) + ('D' << 8) + 'I') {
@@ -159,8 +159,8 @@ public class Md2Importer {
bis.seek(header.offsetGlCommands);
int length, absLength;
Md2GlCommand cmd;
- final List<Integer> fanIndices = Lists.newArrayList();
- final List<Integer> stripIndices = Lists.newArrayList();
+ final List<Integer> fanIndices = new ArrayList<>();
+ final List<Integer> stripIndices = new ArrayList<>();
for (int i = 0; i < header.numGlCommands; i++) {
length = bis.readInt();
if (length == 0) {
@@ -299,7 +299,7 @@ public class Md2Importer {
mesh.setName(resource.getName());
// Add controller
- final KeyframeController<Mesh> controller = new KeyframeController<Mesh>();
+ final KeyframeController<Mesh> controller = new KeyframeController<>();
mesh.addController(controller);
controller.setMorphingMesh(mesh);
controller.setInterpTex(false);
@@ -351,18 +351,19 @@ public class Md2Importer {
}
private Texture loadTexture(final String name) {
- Texture tex = null;
+ final ResourceSource source;
if (_textureLocator == null) {
- tex = TextureManager.load(name, getMinificationFilter(),
+ source = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_TEXTURE, name);
+ } else {
+ source = _textureLocator.locateResource(name);
+ }
+ final Texture tex;
+ if (source == null) {
+ tex = null;
+ } else {
+ tex = TextureManager.load(source, getMinificationFilter(),
isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
: TextureStoreFormat.GuessNoCompressedFormat, isFlipTextureVertically());
- } else {
- final ResourceSource source = _textureLocator.locateResource(name);
- if (source != null) {
- tex = TextureManager.load(source, getMinificationFilter(),
- isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
- : TextureStoreFormat.GuessNoCompressedFormat, isFlipTextureVertically());
- }
}
return tex;
}
@@ -378,8 +379,7 @@ public class Md2Importer {
private void addVert(final Md2GlCommand cmd, final Md2Frame frame, final int vertIndex, final FloatBufferData verts) {
final int index = cmd.vertIndices[vertIndex];
final byte[] vertData = frame.vertData;
- calcVert.set((vertData[index * 4 + 0] & 0xFF), (vertData[index * 4 + 1] & 0xFF),
- (vertData[index * 4 + 2] & 0xFF));
+ calcVert.set(vertData[index * 4 + 0] & 0xFF, vertData[index * 4 + 1] & 0xFF, vertData[index * 4 + 2] & 0xFF);
calcVert.multiplyLocal(frame.scale).addLocal(frame.translate);
verts.getBuffer().put(calcVert.getXf()).put(calcVert.getYf()).put(calcVert.getZf());
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Normals.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Normals.java
index fcb0f86..da2266c 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Normals.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md2/Md2Normals.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3DataStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3DataStore.java
new file mode 100644
index 0000000..5e5a954
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3DataStore.java
@@ -0,0 +1,48 @@
+/**
+ * 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.md3;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ardor3d.scenegraph.Node;
+
+public class Md3DataStore {
+
+ private final Node _mainNode;
+
+ private final List<String> _frameNames;
+
+ private final List<String> _skinNames;
+
+ public Md3DataStore(final Node mainNode) {
+ super();
+ _mainNode = mainNode;
+ _frameNames = new ArrayList<>();
+ _skinNames = new ArrayList<>();
+ }
+
+ public Node getScene() {
+ return _mainNode;
+ }
+
+ public List<String> getFrameNames() {
+ return _frameNames;
+ }
+
+ public int getFrameIndex(final String frameName) {
+ return _frameNames.indexOf(frameName);
+ }
+
+ public List<String> getSkinNames() {
+ return _skinNames;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Frame.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Frame.java
new file mode 100644
index 0000000..e24d903
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Frame.java
@@ -0,0 +1,45 @@
+/**
+ * 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.md3;
+
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.type.ReadOnlyVector3;
+
+/**
+ * frame of MD3: http://en.wikipedia.org/wiki/MD3_%28file_format%29#Frame
+ */
+final class Md3Frame {
+
+ /** First corner of the bounding box. */
+ final Vector3 _minBounds;
+ /** Second corner of the bounding box. */
+ final Vector3 _maxBounds;
+ /** Local origin, usually (0, 0, 0). */
+ final Vector3 _localOrigin;
+ /** Radius of the bounding sphere. */
+ final float _radius;
+ /** name */
+ final String _name;
+
+ Md3Frame(final ReadOnlyVector3 minBounds, final ReadOnlyVector3 maxBounds, final ReadOnlyVector3 localOrigin,
+ final float radius, final String name) {
+ super();
+ _minBounds = new Vector3();
+ _maxBounds = new Vector3();
+ _localOrigin = new Vector3();
+ _minBounds.set(minBounds);
+ _maxBounds.set(maxBounds);
+ _localOrigin.set(localOrigin);
+ _radius = radius;
+ _name = name;
+ }
+
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Header.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Header.java
new file mode 100644
index 0000000..b4d4cf6
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Header.java
@@ -0,0 +1,65 @@
+/**
+ * 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.md3;
+
+/**
+ * header of MD3: http://en.wikipedia.org/wiki/MD3_%28file_format%29#MD3_header
+ */
+final class Md3Header {
+ /** identifier of the file: magic number: "IDP3" */
+ final int _magic;
+ /** version number of the file */
+ final int _version;
+ /** name, usually its pathname in the PK3. ASCII character string, NULL-terminated (C-style) */
+ final String _name;
+ /** flags, unused yet */
+ final int _flags;
+ /** Number of Frame objects, with a maximum of MD3_MAX_FRAMES. Current value of MD3_MAX_FRAMES is 1024. */
+ final int _numFrames;
+ /**
+ * Number of Tag objects, with a maximum of MD3_MAX_TAGS. Current value of MD3_MAX_TAGS is 16. There is one set of
+ * tags per frame so the total number of tags to read is (NUM_TAGS * NUM_FRAMES).
+ */
+ final int _numTags;
+ /** Number of Surface objects, with a maximum of MD3_MAX_SURFACES. Current value of MD3_MAX_SURFACES is 32. */
+ final int _numSurfaces;
+ /** Number of Skin objects, unused */
+ final int _numSkins;
+ /**
+ * Relative offset from start of MD3 object where Frame objects start. The Frame objects are written sequentially,
+ * that is, when you read one Frame object, you do not need to seek() for the next object.
+ */
+ final int _offsetFrame;
+ /** Relative offset from start of MD3 where Tag objects start. Similarly written sequentially. */
+ final int _offsetTag;
+ /** Relative offset from start of MD3 where Surface objects start. Again, written sequentially. */
+ final int _offsetSurface;
+ /** Relative offset from start of MD3 to the end of the MD3 object */
+ final int _offsetEnd;
+
+ Md3Header(final int magic, final int version, final String name, final int flags, final int numFrames,
+ final int numTags, final int numSurfaces, final int numSkins, final int offsetFrame, final int offsetTag,
+ final int offsetSurface, final int offsetEnd) {
+ super();
+ _magic = magic;
+ _version = version;
+ _name = name;
+ _flags = flags;
+ _numFrames = numFrames;
+ _numTags = numTags;
+ _numSurfaces = numSurfaces;
+ _numSkins = numSkins;
+ _offsetFrame = offsetFrame;
+ _offsetTag = offsetTag;
+ _offsetSurface = offsetSurface;
+ _offsetEnd = offsetEnd;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Importer.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Importer.java
new file mode 100644
index 0000000..fb2ceea
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Importer.java
@@ -0,0 +1,211 @@
+/**
+ * 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.md3;
+
+import java.io.InputStream;
+
+import com.ardor3d.extension.model.util.KeyframeController;
+import com.ardor3d.math.Matrix3;
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.util.Ardor3dException;
+import com.ardor3d.util.LittleEndianRandomAccessDataInput;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.resource.ResourceLocator;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.ardor3d.util.resource.ResourceSource;
+
+/**
+ * http://education.mit.edu/starlogo-tng/shapes-tutorial/shapetutorial.html
+ */
+public class Md3Importer {
+
+ private static final float XYZ_SCALE = 1.0f / 64;
+
+ private ResourceLocator _modelLocator;
+
+ public void setModelLocator(final ResourceLocator locator) {
+ _modelLocator = locator;
+ }
+
+ /**
+ * Reads a MD3 file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @return an ObjGeometryStore data object containing the scene and other useful elements.
+ */
+ public Md3DataStore load(final String resource) {
+ final ResourceSource source;
+ if (_modelLocator == null) {
+ source = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, resource);
+ } else {
+ source = _modelLocator.locateResource(resource);
+ }
+
+ if (source == null) {
+ throw new Error("Unable to locate '" + resource + "'");
+ }
+
+ return load(source);
+ }
+
+ /**
+ * Reads an MD3 file from the given resource
+ *
+ * @param resource
+ * a resource pointing to the model we wish to load.
+ * @return an Md3DataStore data object containing the scene and other useful elements.
+ */
+ public Md3DataStore load(final ResourceSource resource) {
+ if (resource == null) {
+ throw new NullPointerException("Unable to load null resource");
+ }
+
+ try {
+ final InputStream md3Stream = resource.openStream();
+ if (md3Stream == null) {
+ throw new NullPointerException("Unable to load null streams");
+ }
+ final LittleEndianRandomAccessDataInput bis = new LittleEndianRandomAccessDataInput(md3Stream);
+
+ // parse the header
+ final Md3Header header = new Md3Header(bis.readInt(), bis.readInt(), bis.readString(64), bis.readInt(),
+ bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt(), bis.readInt());
+
+ // Check magic word and version
+ if (header._magic != ('3' << 24) + ('P' << 16) + ('D' << 8) + 'I') {
+ throw new Ardor3dException("Not an MD3 file.");
+ }
+ if (header._version != 15) {
+ throw new Ardor3dException("Invalid file version (Version not 15)!");
+ }
+
+ // Parse out frames
+ final Md3Frame[] frames = new Md3Frame[header._numFrames];
+ bis.seek(header._offsetFrame);
+ final Vector3 minBounds = new Vector3();
+ final Vector3 maxBounds = new Vector3();
+ final Vector3 localOrigin = new Vector3();
+ for (int i = 0; i < header._numFrames; i++) {
+ minBounds.set(bis.readFloat(), bis.readFloat(), bis.readFloat());
+ maxBounds.set(bis.readFloat(), bis.readFloat(), bis.readFloat());
+ localOrigin.set(bis.readFloat(), bis.readFloat(), bis.readFloat());
+ frames[i] = new Md3Frame(minBounds, maxBounds, localOrigin, bis.readFloat(), bis.readString(16));
+ }
+
+ // Parse out tags
+ final Md3Tag[][] tags = new Md3Tag[header._numFrames][header._numTags];
+ bis.seek(header._offsetTag);
+ final Vector3 origin = new Vector3();
+ final Matrix3 axis = new Matrix3();
+ for (int i = 0; i < header._numFrames; i++) {
+ for (int j = 0; j < header._numTags; j++) {
+ final String name = bis.readString(64).trim();
+ origin.set(bis.readFloat(), bis.readFloat(), bis.readFloat());
+ axis.set(bis.readFloat(), bis.readFloat(), bis.readFloat(), bis.readFloat(), bis.readFloat(),
+ bis.readFloat(), bis.readFloat(), bis.readFloat(), bis.readFloat());
+ tags[i][j] = new Md3Tag(name, origin, axis);
+ }
+ }
+
+ // Parse out surfaces
+ final Md3Surface[] surfaces = new Md3Surface[header._numSurfaces];
+ bis.seek(header._offsetSurface);
+ for (int i = 0; i < header._numSurfaces; i++) {
+ final int surfaceStart = bis.position();
+ final int magic = bis.readInt();
+ if (magic != ('3' << 24) + ('P' << 16) + ('D' << 8) + 'I') {
+ throw new Ardor3dException("Not an MD3 surface.");
+ }
+ surfaces[i] = new Md3Surface(magic, bis.readString(64), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(), bis.readInt(),
+ bis.readInt());
+ // Parse out shaders
+ bis.seek(surfaceStart + surfaces[i]._offsetShaders);
+ for (int j = 0; j < surfaces[i]._numShaders; j++) {
+ // final String name = bis.readString(64);
+ // final int index = bis.readInt();
+ // unused yet
+ }
+ // Parse out triangles
+ bis.seek(surfaceStart + surfaces[i]._offsetTriangles);
+ for (int j = 0; j < surfaces[i]._triIndexes.length; j++) {
+ surfaces[i]._triIndexes[j] = bis.readInt();
+ }
+ // Parse out texture coordinates
+ bis.seek(surfaceStart + surfaces[i]._offsetTexCoords);
+ for (int j = 0; j < surfaces[i]._texCoords.length; j++) {
+ surfaces[i]._texCoords[j] = new Vector2(bis.readFloat(), bis.readFloat());
+ }
+ // Parse out vertices
+ bis.seek(surfaceStart + surfaces[i]._offsetXyzNormals);
+ for (int j = 0; j < surfaces[i]._numFrames; j++) {
+ for (int k = 0; k < surfaces[i]._numVerts; k++) {
+ surfaces[i]._verts[j][k] = new Vector3(bis.readShort(), bis.readShort(), bis.readShort())
+ .multiplyLocal(Md3Importer.XYZ_SCALE);
+ final int zenith = bis.readByte();
+ final int azimuth = bis.readByte();
+ final float lat = (float) (zenith * 2 * Math.PI / 255);
+ final float lng = (float) (azimuth * 2 * Math.PI / 255);
+ surfaces[i]._norms[j][k] = new Vector3(Math.cos(lat) * Math.sin(lng), Math.sin(lat)
+ * Math.sin(lng), Math.cos(lng));
+ }
+ }
+ }
+
+ final Node node = new Node(header._name);
+ for (int i = 0; i < header._numSurfaces; i++) {
+ final Md3Surface surface = surfaces[i];
+ final KeyframeController<Mesh> controller = new KeyframeController<>();
+ final Mesh morphingMesh = new Mesh(surface._name);
+ morphingMesh.getMeshData().setIndexBuffer(BufferUtils.createIntBuffer(surface._triIndexes));
+ morphingMesh.getMeshData().setVertexBuffer(BufferUtils.createFloatBuffer(surface._verts[0]));
+ morphingMesh.getMeshData().setNormalBuffer(BufferUtils.createFloatBuffer(surface._norms[0]));
+ morphingMesh.getMeshData().setTextureBuffer(BufferUtils.createFloatBuffer(surface._texCoords), 0);
+ node.attachChild(morphingMesh);
+ controller.setMorphingMesh(morphingMesh);
+ for (int j = 0; j < surface._numFrames; j++) {
+ final Md3Frame frame = frames[j];
+ final Mesh mesh = new Mesh(frame._name);
+ mesh.getMeshData().setVertexBuffer(BufferUtils.createFloatBuffer(surface._verts[j]));
+ mesh.getMeshData().setNormalBuffer(BufferUtils.createFloatBuffer(surface._norms[j]));
+ controller.setKeyframe(j, mesh);
+ }
+ morphingMesh.addController(controller);
+ // TODO should I add a controller into the node?
+ }
+
+ // Make a store object to return
+ final Md3DataStore store = new Md3DataStore(node);
+
+ // store names
+ for (final Md3Frame frame : frames) {
+ store.getFrameNames().add(frame._name);
+ }
+
+ // TODO load the animation configuration file (animation.cfg): [sex f/m][first frame, num frames, looping
+ // frames, frames per second]
+
+ /**
+ * TODO there is one .skin file per MD3 file, it contains at most one line per surface (?) with the name and
+ * the texture filename (.jpg or .tga) and a tag per attachment to another MD3 file
+ */
+
+ return store;
+ } catch (final Exception e) {
+ throw new Error("Unable to load md3 resource from URL: " + resource, e);
+ }
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Surface.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Surface.java
new file mode 100644
index 0000000..b27dae9
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Surface.java
@@ -0,0 +1,80 @@
+/**
+ * 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.md3;
+
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+
+/**
+ * Surface of MD3: http://en.wikipedia.org/wiki/MD3_%28file_format%29#Surface
+ */
+final class Md3Surface {
+
+ final int _magic;
+ /** name */
+ final String _name;
+ /** flags */
+ final int _flags;
+ /** Number of animation frames. This should match NUM_FRAMES in the MD3 header. */
+ final int _numFrames;
+ /**
+ * Number of Shader objects defined in this Surface, with a limit of MD3_MAX_SHADERS. Current value of
+ * MD3_MAX_SHADERS is 256.
+ */
+ final int _numShaders;
+ /** Number of Vertex objects defined in this Surface, up to MD3_MAX_VERTS. Current value of MD3_MAX_VERTS is 4096. */
+ final int _numVerts;
+ /**
+ * Number of Triangle objects defined in this Surface, maximum of MD3_MAX_TRIANGLES. Current value of
+ * MD3_MAX_TRIANGLES is 8192.
+ */
+ final int _numTriangles;
+ /** Relative offset from SURFACE_START where the list of Triangle objects starts. */
+ final int _offsetTriangles;
+ /** Relative offset from SURFACE_START where the list of Shader objects starts. */
+ final int _offsetShaders;
+ /** Relative offset from SURFACE_START where the list of ST objects (s-t texture coordinates) starts. */
+ final int _offsetTexCoords;
+ /** Relative offset from SURFACE_START where the list of Vertex objects (X-Y-Z-N vertices) starts. */
+ final int _offsetXyzNormals;
+ /** Relative offset from SURFACE_START to where the Surface object ends. */
+ final int _offsetEnd;
+ /** Indices of triangles' vertices */
+ final int[] _triIndexes;
+ /** Texture coordinates of triangles' vertices */
+ final Vector2[] _texCoords;
+ /** Triangles' vertices */
+ final Vector3[][] _verts;
+ /** Triangles' normals */
+ final Vector3[][] _norms;
+
+ Md3Surface(final int magic, final String name, final int flags, final int numFrames, final int numShaders,
+ final int numVerts, final int numTriangles, final int offsetTriangles, final int offsetShaders,
+ final int offsetTexCoords, final int offsetXyzNormals, final int offsetEnd) {
+ super();
+ _magic = magic;
+ _name = name;
+ _flags = flags;
+ _numFrames = numFrames;
+ _numShaders = numShaders;
+ _numVerts = numVerts;
+ _numTriangles = numTriangles;
+ _offsetTriangles = offsetTriangles;
+ _offsetShaders = offsetShaders;
+ _offsetTexCoords = offsetTexCoords;
+ _offsetXyzNormals = offsetXyzNormals;
+ _offsetEnd = offsetEnd;
+ _triIndexes = new int[_numTriangles * 3];
+ _texCoords = new Vector2[_numVerts];
+ _verts = new Vector3[_numFrames][_numVerts];
+ _norms = new Vector3[_numFrames][_numVerts];
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Tag.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Tag.java
new file mode 100644
index 0000000..b4c25c8
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/md3/Md3Tag.java
@@ -0,0 +1,38 @@
+/**
+ * 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.md3;
+
+import com.ardor3d.math.Matrix3;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.type.ReadOnlyMatrix3;
+import com.ardor3d.math.type.ReadOnlyVector3;
+
+/**
+ * Tag of MD3: http://en.wikipedia.org/wiki/MD3_%28file_format%29#Tag
+ */
+final class Md3Tag {
+
+ /** name */
+ final String _name;
+ /** coordinates */
+ final Vector3 _origin;
+ /** 3x3 rotation matrix */
+ final Matrix3 _axis;
+
+ Md3Tag(final String name, final ReadOnlyVector3 origin, final ReadOnlyMatrix3 axis) {
+ super();
+ _origin = new Vector3();
+ _axis = new Matrix3();
+ _name = name;
+ _origin.set(origin);
+ _axis.set(axis);
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjDataStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjDataStore.java
index 0c9fa91..cc52553 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjDataStore.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjDataStore.java
@@ -1,25 +1,33 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.obj;
+import java.util.ArrayList;
import java.util.List;
import com.ardor3d.math.Vector3;
-import com.google.common.collect.Lists;
public class ObjDataStore {
- private final List<Vector3> _vertices = Lists.newArrayList();
- private final List<Vector3> _normals = Lists.newArrayList();
- private final List<Vector3> _generatedNormals = Lists.newArrayList();
- private final List<Vector3> _uvs = Lists.newArrayList();
+ private final List<Vector3> _vertices;
+ private final List<Vector3> _normals;
+ private final List<Vector3> _generatedNormals;
+ private final List<Vector3> _uvs;
+
+ public ObjDataStore() {
+ super();
+ _vertices = new ArrayList<>();
+ _normals = new ArrayList<>();
+ _generatedNormals = new ArrayList<>();
+ _uvs = new ArrayList<>();
+ }
public List<Vector3> getVertices() {
return _vertices;
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjExporter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjExporter.java
index 033727f..2683123 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjExporter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjExporter.java
@@ -1,9 +1,9 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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>.
*/
@@ -16,8 +16,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.logging.Logger;
import com.ardor3d.extension.model.util.KeyframeController;
@@ -36,7 +36,7 @@ import com.ardor3d.util.TextureKey;
* WaveFront OBJ exporter. It supports only the meshes. Several meshes can be exported into the same OBJ file. Only a
* few kinds of primitives are supported. N.B: If the texture is flipped in Ardor3D, you will have to flip it manually
* when loading the resulting OBJ file.
- *
+ *
* @author Julien Gouesse
*/
public class ObjExporter {
@@ -49,7 +49,7 @@ public class ObjExporter {
/**
* Save a mesh to a single WaveFront OBJ file and a MTL file
- *
+ *
* @param mesh
* mesh to export
* @param objFile
@@ -63,7 +63,7 @@ public class ObjExporter {
save(mesh, objFile, mtlFile, false, 0, true, null, null);
} else {
final KeyframeController<?> controller = (KeyframeController<?>) mesh.getController(0);
- final ArrayList<Mesh> meshList = new ArrayList<Mesh>();
+ final ArrayList<Mesh> meshList = new ArrayList<>();
for (final KeyframeController.PointInTime pit : controller._keyframes) {
if (pit != null && pit._newShape != null) {
meshList.add(pit._newShape);
@@ -75,7 +75,7 @@ public class ObjExporter {
/**
* Save several meshes to a single WaveFront OBJ file and a MTL file
- *
+ *
* @param meshList
* meshes to export
* @param objFile
@@ -91,7 +91,7 @@ public class ObjExporter {
if (!meshList.isEmpty()) {
int firstVertexIndex = 0;
boolean firstFiles = true;
- final List<ObjMaterial> materialList = new ArrayList<ObjMaterial>();
+ final List<ObjMaterial> materialList = new ArrayList<>();
for (final Mesh mesh : meshList) {
if (mesh != null) {
if (mesh.getControllerCount() == 0 || !(mesh.getController(0) instanceof KeyframeController)) {
@@ -101,7 +101,7 @@ public class ObjExporter {
firstVertexIndex += mesh.getMeshData().getVertexCount();
} else {
final KeyframeController<?> controller = (KeyframeController<?>) mesh.getController(0);
- final ArrayList<Mesh> subMeshList = new ArrayList<Mesh>();
+ final ArrayList<Mesh> subMeshList = new ArrayList<>();
for (final KeyframeController.PointInTime pit : controller._keyframes) {
if (pit != null && pit._newShape != null) {
subMeshList.add(pit._newShape);
@@ -122,7 +122,7 @@ public class ObjExporter {
/**
* Save a mesh to the given files.
- *
+ *
* @param mesh
* mesh to export
* @param objFile
@@ -155,199 +155,209 @@ public class ObjExporter {
parentDirectory.mkdirs();
}
}
- PrintWriter objPw = null, mtlPw = null;
try {
// fills the MTL file
final String mtlName;
if (mtlFile != null) {
- final FileOutputStream mtlOs = new FileOutputStream(mtlFile, append);
- mtlPw = new PrintWriter(new BufferedOutputStream(mtlOs));
- // writes some comments
- if (firstFiles) {
- mtlPw.println("# Ardor3D 1.0 MTL file");
- }
- final ObjMaterial currentMtl = new ObjMaterial(null);
- final MaterialState mtlState = (MaterialState) mesh.getLocalRenderState(StateType.Material);
- if (mtlState != null) {
- final ReadOnlyColorRGBA ambientColor = mtlState.getAmbient();
- if (ambientColor != null) {
- currentMtl.d = ambientColor.getAlpha();
- currentMtl.Ka = new float[] { ambientColor.getRed(), ambientColor.getGreen(),
- ambientColor.getBlue(), ambientColor.getAlpha() };
+ try (final FileOutputStream mtlOs = new FileOutputStream(mtlFile, append);
+ final PrintWriter mtlPw = new PrintWriter(new BufferedOutputStream(mtlOs))) {
+ // writes some comments
+ if (firstFiles) {
+ mtlPw.println("# Ardor3D 1.0 MTL file");
}
- final ReadOnlyColorRGBA diffuseColor = mtlState.getDiffuse();
- if (diffuseColor != null) {
- currentMtl.Kd = new float[] { diffuseColor.getRed(), diffuseColor.getGreen(),
- diffuseColor.getBlue(), diffuseColor.getAlpha() };
- }
- final ReadOnlyColorRGBA specularColor = mtlState.getSpecular();
- if (specularColor != null) {
- currentMtl.Ks = new float[] { specularColor.getRed(), specularColor.getGreen(),
- specularColor.getBlue(), specularColor.getAlpha() };
- }
- currentMtl.Ns = mtlState.getShininess();
- }
- if (customTextureName == null) {
- currentMtl.textureName = getLocalMeshTextureName(mesh);
- } else {
- currentMtl.textureName = customTextureName;
- }
- if (mesh.getSceneHints().getLightCombineMode() == LightCombineMode.Off) {
- // Color on and Ambient off
- currentMtl.illumType = 0;
- } else {
- // Color on and Ambient on
- currentMtl.illumType = 1;
- }
- ObjMaterial sameObjMtl = null;
- if (materialList != null && !materialList.isEmpty()) {
- for (final ObjMaterial mtl : materialList) {
- if (mtl.illumType == currentMtl.illumType && mtl.Ns == currentMtl.Ns
- && mtl.forceBlend == currentMtl.forceBlend && mtl.d == currentMtl.d
- && Arrays.equals(mtl.Ka, currentMtl.Ka) && Arrays.equals(mtl.Kd, currentMtl.Kd)
- && Arrays.equals(mtl.Ks, currentMtl.Ks)
- //&& Objects.equals(mtl.textureName, currentMtl.textureName)) {
- && mtl.textureName.equals(currentMtl.textureName)) {
- sameObjMtl = mtl;
- break;
+ final ObjMaterial currentMtl = new ObjMaterial(null);
+ final MaterialState mtlState = (MaterialState) mesh.getLocalRenderState(StateType.Material);
+ if (mtlState != null) {
+ final ReadOnlyColorRGBA ambientColor = mtlState.getAmbient();
+ if (ambientColor != null) {
+ currentMtl.setAmbientRed(ambientColor.getRed());
+ currentMtl.setAmbientGreen(ambientColor.getGreen());
+ currentMtl.setAmbientBlue(ambientColor.getBlue());
+ currentMtl.setAmbientAlpha(ambientColor.getAlpha());
+ }
+ final ReadOnlyColorRGBA diffuseColor = mtlState.getDiffuse();
+ if (diffuseColor != null) {
+ currentMtl.setDiffuseRed(diffuseColor.getRed());
+ currentMtl.setDiffuseGreen(diffuseColor.getGreen());
+ currentMtl.setDiffuseBlue(diffuseColor.getBlue());
+ currentMtl.setDiffuseAlpha(diffuseColor.getAlpha());
+ }
+ final ReadOnlyColorRGBA specularColor = mtlState.getSpecular();
+ if (specularColor != null) {
+ currentMtl.setSpecularRed(specularColor.getRed());
+ currentMtl.setSpecularGreen(specularColor.getGreen());
+ currentMtl.setSpecularBlue(specularColor.getBlue());
+ currentMtl.setSpecularAlpha(specularColor.getAlpha());
}
+ currentMtl.setShininess(mtlState.getShininess());
}
- }
- if (sameObjMtl == null) {
- // writes the new material library
- mtlName = mtlFile.getName().trim().replaceAll(" ", "") + "_"
- + (materialList == null ? 1 : materialList.size() + 1);
- if (materialList != null) {
- final ObjMaterial mtl = new ObjMaterial(mtlName);
- mtl.illumType = currentMtl.illumType;
- mtl.textureName = currentMtl.textureName;
- materialList.add(mtl);
+ if (customTextureName == null) {
+ currentMtl.setTextureName(getLocalMeshTextureName(mesh));
+ } else {
+ currentMtl.setTextureName(customTextureName);
}
- mtlPw.println("newmtl " + mtlName);
- if (currentMtl.Ns != -1) {
- mtlPw.println("Ns " + currentMtl.Ns);
+ if (mesh.getSceneHints().getLightCombineMode() == LightCombineMode.Off) {
+ // Color on and Ambient off
+ currentMtl.setIllumType(0);
+ } else {
+ // Color on and Ambient on
+ currentMtl.setIllumType(1);
}
- if (currentMtl.Ka != null) {
- mtlPw.print("Ka");
- for (final float KaCoef : currentMtl.Ka) {
- mtlPw.print(" " + KaCoef);
+ ObjMaterial sameObjMtl = null;
+ if (materialList != null && !materialList.isEmpty()) {
+ for (final ObjMaterial mtl : materialList) {
+ if (mtl.getIllumType() == currentMtl.getIllumType()
+ && mtl.getShininess() == currentMtl.getShininess()
+ && mtl.isForceBlend() == currentMtl.isForceBlend()
+ && mtl.getAmbientRed() == currentMtl.getAmbientRed()
+ && mtl.getAmbientGreen() == currentMtl.getAmbientGreen()
+ && mtl.getAmbientBlue() == currentMtl.getAmbientBlue()
+ && mtl.getAmbientAlpha() == currentMtl.getAmbientAlpha()
+ && mtl.getDiffuseRed() == currentMtl.getDiffuseRed()
+ && mtl.getDiffuseGreen() == currentMtl.getDiffuseGreen()
+ && mtl.getDiffuseBlue() == currentMtl.getDiffuseBlue()
+ && mtl.getDiffuseAlpha() == currentMtl.getDiffuseAlpha()
+ && mtl.getSpecularRed() == currentMtl.getSpecularRed()
+ && mtl.getSpecularGreen() == currentMtl.getSpecularGreen()
+ && mtl.getSpecularBlue() == currentMtl.getSpecularBlue()
+ && mtl.getSpecularAlpha() == currentMtl.getSpecularAlpha()
+ && mtl.getEmissiveRed() == currentMtl.getEmissiveRed()
+ && mtl.getEmissiveGreen() == currentMtl.getEmissiveGreen()
+ && mtl.getEmissiveBlue() == currentMtl.getEmissiveBlue()
+ && mtl.getEmissiveAlpha() == currentMtl.getEmissiveAlpha()
+ && Objects.equals(mtl.getTextureName(), currentMtl.getTextureName())) {
+ sameObjMtl = mtl;
+ break;
+ }
}
- mtlPw.println();
}
- if (currentMtl.Kd != null) {
- mtlPw.print("Kd");
- for (final float KdCoef : currentMtl.Kd) {
- mtlPw.print(" " + KdCoef);
+ if (sameObjMtl == null) {
+ // writes the new material library
+ mtlName = mtlFile.getName().trim().replaceAll(" ", "") + "_"
+ + (materialList == null ? 1 : materialList.size() + 1);
+ if (materialList != null) {
+ final ObjMaterial mtl = new ObjMaterial(mtlName);
+ mtl.setIllumType(currentMtl.getIllumType());
+ mtl.setTextureName(currentMtl.getTextureName());
+ materialList.add(mtl);
}
- mtlPw.println();
- }
- if (currentMtl.Ks != null) {
- mtlPw.print("Ks");
- for (final float KsCoef : currentMtl.Ks) {
- mtlPw.print(" " + KsCoef);
+ mtlPw.println("newmtl " + mtlName);
+ if (currentMtl.getShininess() != -1) {
+ mtlPw.println("Ns " + currentMtl.getShininess());
}
- mtlPw.println();
- }
- if (currentMtl.d != -1) {
- mtlPw.println("d " + currentMtl.d);
- }
- mtlPw.println("illum " + currentMtl.illumType);
- if (currentMtl.textureName != null) {
- mtlPw.println("map_Kd " + currentMtl.textureName);
+ if (currentMtl.getAmbientRed() != -1 && currentMtl.getAmbientGreen() != -1
+ && currentMtl.getAmbientBlue() != -1) {
+ mtlPw.println("Ka " + currentMtl.getAmbientRed() + " " + currentMtl.getAmbientGreen() + " "
+ + currentMtl.getAmbientBlue());
+ }
+ if (currentMtl.getDiffuseRed() != -1 && currentMtl.getDiffuseGreen() != -1
+ && currentMtl.getDiffuseBlue() != -1) {
+ mtlPw.println("Kd " + currentMtl.getDiffuseRed() + " " + currentMtl.getDiffuseGreen() + " "
+ + currentMtl.getDiffuseBlue());
+ }
+ if (currentMtl.getSpecularRed() != -1 && currentMtl.getSpecularGreen() != -1
+ && currentMtl.getSpecularBlue() != -1) {
+ mtlPw.println("Ks " + currentMtl.getSpecularRed() + " " + currentMtl.getSpecularGreen()
+ + " " + currentMtl.getSpecularBlue());
+ }
+ // exports only a consistent dissolve value when all alpha components are equal
+ if (currentMtl.getAmbientAlpha() != -1
+ && currentMtl.getAmbientAlpha() == currentMtl.getDiffuseAlpha()
+ && currentMtl.getDiffuseAlpha() == currentMtl.getSpecularAlpha()
+ && currentMtl.getSpecularAlpha() == currentMtl.getEmissiveAlpha()) {
+ mtlPw.println("d " + currentMtl.getAmbientAlpha());
+ }
+ mtlPw.println("illum " + currentMtl.getIllumType());
+ if (currentMtl.getTextureName() != null) {
+ mtlPw.println("map_Kd " + currentMtl.getTextureName());
+ }
+ } else {
+ mtlName = sameObjMtl.getName();
}
- } else {
- mtlName = sameObjMtl.getName();
}
} else {
mtlName = null;
}
- final FileOutputStream objOs = new FileOutputStream(objFile, append);
- objPw = new PrintWriter(new BufferedOutputStream(objOs));
- // writes some comments
- if (firstFiles) {
- objPw.println("# Ardor3D 1.0 OBJ file");
- objPw.println("# www.ardor3d.com");
- // writes the material file name if any
+ try (final FileOutputStream objOs = new FileOutputStream(objFile, append);
+ final PrintWriter objPw = new PrintWriter(new BufferedOutputStream(objOs))) {
+ // writes some comments
+ if (firstFiles) {
+ objPw.println("# Ardor3D 1.0 OBJ file");
+ objPw.println("# www.ardor3d.com");
+ // writes the material file name if any
+ if (mtlFile != null) {
+ final String mtlLibFilename = mtlFile.getName();
+ objPw.println("mtllib " + mtlLibFilename);
+ }
+ }
+ // writes the object name
+ final String objName;
+ String meshName = mesh.getName();
+ // removes all spaces from the mesh name
+ if (meshName != null && !meshName.isEmpty()) {
+ meshName = meshName.trim().replaceAll(" ", "");
+ }
+ if (meshName != null && !meshName.isEmpty()) {
+ objName = meshName;
+ } else {
+ objName = "obj_mesh" + mesh.hashCode();
+ }
+ objPw.println("o " + objName);
+ final MeshData meshData = mesh.getMeshData();
+ // writes the coordinates
+ final FloatBufferData verticesData = meshData.getVertexCoords();
+ if (verticesData == null) {
+ throw new IllegalArgumentException("cannot export a mesh with no vertices");
+ }
+ final int expectedTupleCount = verticesData.getTupleCount();
+ saveFloatBufferData(verticesData, objPw, "v", expectedTupleCount);
+ final FloatBufferData texCoordsData = meshData.getTextureCoords(0);
+ saveFloatBufferData(texCoordsData, objPw, "vt", expectedTupleCount);
+ final FloatBufferData normalsData = meshData.getNormalCoords();
+ saveFloatBufferData(normalsData, objPw, "vn", expectedTupleCount);
+ // writes the used material library
if (mtlFile != null) {
- final String mtlLibFilename = mtlFile.getName();
- objPw.println("mtllib " + mtlLibFilename);
+ objPw.println("usemtl " + mtlName);
}
- }
- // writes the object name
- final String objName;
- String meshName = mesh.getName();
- // removes all spaces from the mesh name
- if (meshName != null && !meshName.isEmpty()) {
- meshName = meshName.trim().replaceAll(" ", "");
- }
- if (meshName != null && !meshName.isEmpty()) {
- objName = meshName;
- } else {
- objName = "obj_mesh" + mesh.hashCode();
- }
- objPw.println("o " + objName);
- final MeshData meshData = mesh.getMeshData();
- // writes the coordinates
- final FloatBufferData verticesData = meshData.getVertexCoords();
- if (verticesData == null) {
- throw new IllegalArgumentException("cannot export a mesh with no vertices");
- }
- final int expectedTupleCount = verticesData.getTupleCount();
- saveFloatBufferData(verticesData, objPw, "v", expectedTupleCount);
- final FloatBufferData texCoordsData = meshData.getTextureCoords(0);
- saveFloatBufferData(texCoordsData, objPw, "vt", expectedTupleCount);
- final FloatBufferData normalsData = meshData.getNormalCoords();
- saveFloatBufferData(normalsData, objPw, "vn", expectedTupleCount);
- // writes the used material library
- if (mtlFile != null) {
- objPw.println("usemtl " + mtlName);
- }
- // writes the faces
- for (int sectionIndex = 0; sectionIndex < meshData.getSectionCount(); sectionIndex++) {
- final IndexMode indexMode = meshData.getIndexMode(sectionIndex);
- final int[] indices = new int[indexMode.getVertexCount()];
- switch (indexMode) {
- case TriangleFan:
- case Triangles:
- case TriangleStrip:
- case Quads:
- for (int primIndex = 0, primCount = meshData.getPrimitiveCount(sectionIndex); primIndex < primCount; primIndex++) {
- meshData.getPrimitiveIndices(primIndex, sectionIndex, indices);
- objPw.print("f");
- for (int vertexIndex = 0; vertexIndex < indices.length; vertexIndex++) {
- // indices start at 1 in the WaveFront OBJ format whereas indices start at 0 in
- // Ardor3D
- final int shiftedIndex = indices[vertexIndex] + 1 + firstVertexIndex;
- // vertex index
- objPw.print(" " + shiftedIndex);
- // texture coordinate index
- if (texCoordsData != null) {
- objPw.print("/" + shiftedIndex);
- }
- // normal coordinate index
- if (normalsData != null) {
- objPw.print("/" + shiftedIndex);
+ // writes the faces
+ for (int sectionIndex = 0; sectionIndex < meshData.getSectionCount(); sectionIndex++) {
+ final IndexMode indexMode = meshData.getIndexMode(sectionIndex);
+ final int[] indices = new int[indexMode.getVertexCount()];
+ switch (indexMode) {
+ case TriangleFan:
+ case Triangles:
+ case TriangleStrip:
+ case Quads:
+ for (int primIndex = 0, primCount = meshData
+ .getPrimitiveCount(sectionIndex); primIndex < primCount; primIndex++) {
+ meshData.getPrimitiveIndices(primIndex, sectionIndex, indices);
+ objPw.print("f");
+ for (int vertexIndex = 0; vertexIndex < indices.length; vertexIndex++) {
+ // indices start at 1 in the WaveFront OBJ format whereas indices start at 0 in
+ // Ardor3D
+ final int shiftedIndex = indices[vertexIndex] + 1 + firstVertexIndex;
+ // vertex index
+ objPw.print(" " + shiftedIndex);
+ // texture coordinate index
+ if (texCoordsData != null) {
+ objPw.print("/" + shiftedIndex);
+ }
+ // normal coordinate index
+ if (normalsData != null) {
+ objPw.print("/" + shiftedIndex);
+ }
}
+ objPw.println();
}
- objPw.println();
- }
- break;
- default:
- throw new IllegalArgumentException("index mode " + indexMode + " not supported");
+ break;
+ default:
+ throw new IllegalArgumentException("index mode " + indexMode + " not supported");
+ }
}
}
} catch (final Throwable t) {
throw new Error("Unable to save the mesh into an obj", t);
- } finally {
- if (objPw != null) {
- objPw.flush();
- objPw.close();
- }
- if (mtlPw != null) {
- mtlPw.flush();
- mtlPw.close();
- }
}
}
@@ -357,25 +367,30 @@ public class ObjExporter {
final TextureState textureState = (TextureState) mesh.getLocalRenderState(StateType.Texture);
if (textureState.isEnabled() && textureState.getTexture() != null) {
final TextureKey tKey = textureState.getTexture().getTextureKey();
- final String tmpTextureName = tKey.getSource().getName();
- final int lastIndexOfUnixPathSeparator = tmpTextureName.lastIndexOf('/');
- final int lastIndexOfWindowsPathSeparator = tmpTextureName.lastIndexOf('\\');
- if (lastIndexOfUnixPathSeparator != -1) {
- textureName = tmpTextureName.substring(lastIndexOfUnixPathSeparator + 1);
- } else {
- if (lastIndexOfWindowsPathSeparator != -1) {
- textureName = tmpTextureName.substring(lastIndexOfWindowsPathSeparator + 1);
+ if (tKey != null && tKey.getSource() != null) {
+ final String tmpTextureName = tKey.getSource().getName();
+ final int lastIndexOfUnixPathSeparator = tmpTextureName.lastIndexOf('/');
+ final int lastIndexOfWindowsPathSeparator = tmpTextureName.lastIndexOf('\\');
+ if (lastIndexOfUnixPathSeparator != -1) {
+ textureName = tmpTextureName.substring(lastIndexOfUnixPathSeparator + 1);
} else {
- textureName = tmpTextureName;
+ if (lastIndexOfWindowsPathSeparator != -1) {
+ textureName = tmpTextureName.substring(lastIndexOfWindowsPathSeparator + 1);
+ } else {
+ textureName = tmpTextureName;
+ }
+ }
+ if (tKey.isFlipped()) {
+ ObjExporter.logger.warning("The texture " + tmpTextureName
+ + " will have to be flipped manually when loading this OBJ file");
+ } else {
+ ObjExporter.logger.warning("The texture " + tmpTextureName
+ + " might need to be flipped manually when loading this OBJ file");
}
- }
- if (tKey.isFlipped()) {
- ObjExporter.logger.warning("The texture " + tmpTextureName
- + " will have to be flipped manually when loading this OBJ file");
} else {
- ObjExporter.logger.warning("The texture " + tmpTextureName
- + " might need to be flipped manually when loading this OBJ file");
+ textureName = null;
}
+
} else {
textureName = null;
}
@@ -394,9 +409,9 @@ public class ObjExporter {
final int tupleSize = data.getValuesPerTuple();
final int tupleCount = data.getTupleCount();
if (tupleCount < expectedTupleCount) {
- throw new IllegalArgumentException("[" + keyword
- + "] not enough data to match with the vertex count: " + tupleCount + " < "
- + expectedTupleCount);
+ throw new IllegalArgumentException(
+ "[" + keyword + "] not enough data to match with the vertex count: " + tupleCount + " < "
+ + expectedTupleCount);
} else {
if (tupleCount > expectedTupleCount) {
ObjExporter.logger.warning("[" + keyword + "] too much data to match with the vertex count: "
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjGeometryStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjGeometryStore.java
index bd96824..aced00f 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjGeometryStore.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjGeometryStore.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -12,7 +12,9 @@ package com.ardor3d.extension.model.obj;
import java.nio.Buffer;
import java.nio.FloatBuffer;
+import java.util.ArrayList;
import java.util.EnumSet;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -33,8 +35,6 @@ import com.ardor3d.util.geom.BufferUtils;
import com.ardor3d.util.geom.GeometryTool;
import com.ardor3d.util.geom.GeometryTool.MatchCondition;
import com.ardor3d.util.geom.VertGroupData;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
public class ObjGeometryStore {
private static final String DEFAULT_GROUP = "_default_";
@@ -45,7 +45,7 @@ public class ObjGeometryStore {
private int _totalLines = 0;
private int _totalMeshes = 0;
private final Node _root = new Node();
- private final Map<String, Spatial> _groupMap = Maps.newHashMap();
+ private final Map<String, Spatial> _groupMap = new HashMap<>();
private ObjMaterial _currentMaterial = new ObjMaterial("default");
private String _currentObjectName;
@@ -55,11 +55,18 @@ public class ObjGeometryStore {
private ObjSetManager _lineManager;
private ObjSetManager _pointManager;
- private final Map<String, ObjMaterial> materialLibrary = Maps.newHashMap();
- private final Map<Spatial, String> _materialMap = Maps.newHashMap();
+ private final Map<String, ObjMaterial> materialLibrary = new HashMap<>();
+ private final Map<Spatial, String> _materialMap = new HashMap<>();
+
+ private final GeometryTool _geometryTool;
public ObjGeometryStore() {
+ this(new GeometryTool());
+ }
+
+ public ObjGeometryStore(final GeometryTool geometryTool) {
super();
+ _geometryTool = geometryTool;
}
public Map<String, ObjMaterial> getMaterialLibrary() {
@@ -185,14 +192,14 @@ public class ObjGeometryStore {
}
final Point points = new Point(name, vertices, null, null, null);
- final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils.createIndexBufferData(_pointManager
- .getIndices().size(), vertices.length - 1);
+ final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils
+ .createIndexBufferData(_pointManager.getIndices().size(), vertices.length - 1);
for (final int index : _pointManager.getIndices()) {
indexBuffer.put(index);
}
points.getMeshData().setIndices(indexBuffer);
- GeometryTool.minimizeVerts(points, EnumSet.noneOf(MatchCondition.class));
+ _geometryTool.minimizeVerts(points, EnumSet.noneOf(MatchCondition.class));
applyCurrentMaterial(points);
mapToGroups(points);
@@ -226,8 +233,8 @@ public class ObjGeometryStore {
}
final Line line = new Line(name, vertices, null, null, hasUVs ? uvs : null);
- final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils.createIndexBufferData(_lineManager
- .getIndices().size(), vertices.length - 1);
+ final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils
+ .createIndexBufferData(_lineManager.getIndices().size(), vertices.length - 1);
for (final int index : _lineManager.getIndices()) {
indexBuffer.put(index);
}
@@ -240,7 +247,7 @@ public class ObjGeometryStore {
}
line.getMeshData().setIndexLengths(lengths);
}
- GeometryTool.minimizeVerts(line, EnumSet.of(MatchCondition.UVs));
+ _geometryTool.minimizeVerts(line, EnumSet.of(MatchCondition.UVs));
applyCurrentMaterial(line);
mapToGroups(line);
@@ -267,7 +274,7 @@ public class ObjGeometryStore {
int j = 0;
final long[] vertGroups = new long[_meshManager.getStore().size()];
- final List<Long> groups = Lists.newArrayList();
+ final List<Long> groups = new ArrayList<>();
Vector3 vector;
for (final ObjIndexSet set : _meshManager.getStore().keySet()) {
vertGroups[j] = set.getSmoothGroup();
@@ -302,8 +309,8 @@ public class ObjGeometryStore {
mesh.getMeshData().setTextureBuffer(uvs, 0);
}
- final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils.createIndexBufferData(_meshManager
- .getIndices().size(), _meshManager.getStore().size() - 1);
+ final IndexBufferData<? extends Buffer> indexBuffer = BufferUtils
+ .createIndexBufferData(_meshManager.getIndices().size(), _meshManager.getStore().size() - 1);
for (final int index : _meshManager.getIndices()) {
indexBuffer.put(index);
}
@@ -319,7 +326,7 @@ public class ObjGeometryStore {
groupData.setVertGroups(vertGroups);
groupData.setGroupConditions(VertGroupData.DEFAULT_GROUP,
EnumSet.of(MatchCondition.Normal, MatchCondition.UVs));
- GeometryTool.minimizeVerts(mesh, groupData);
+ _geometryTool.minimizeVerts(mesh, groupData);
applyCurrentMaterial(mesh);
mapToGroups(mesh);
@@ -349,7 +356,7 @@ public class ObjGeometryStore {
target.getSceneHints().setRenderBucketType(RenderBucketType.Transparent);
}
- if (_currentMaterial.illumType == 0) {
+ if (_currentMaterial.getIllumType() == 0) {
target.getSceneHints().setLightCombineMode(LightCombineMode.Off);
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjImporter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjImporter.java
index 4328e19..620ae55 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjImporter.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjImporter.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -12,6 +12,7 @@ package com.ardor3d.extension.model.obj;
import java.io.BufferedReader;
import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
@@ -21,10 +22,10 @@ import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.math.MathUtils;
import com.ardor3d.math.Vector3;
import com.ardor3d.util.TextureManager;
+import com.ardor3d.util.geom.GeometryTool;
import com.ardor3d.util.resource.ResourceLocator;
import com.ardor3d.util.resource.ResourceLocatorTool;
import com.ardor3d.util.resource.ResourceSource;
-import com.google.common.collect.Lists;
/**
* Wavefront OBJ importer. See <a href="http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/">the format spec</a>
@@ -48,24 +49,20 @@ public class ObjImporter {
return _loadTextures;
}
- public ObjImporter setLoadTextures(final boolean loadTextures) {
+ public void setLoadTextures(final boolean loadTextures) {
_loadTextures = loadTextures;
- return this;
}
- public ObjImporter setTextureLocator(final ResourceLocator locator) {
+ public void setTextureLocator(final ResourceLocator locator) {
_textureLocator = locator;
- return this;
}
- public ObjImporter setModelLocator(final ResourceLocator locator) {
+ public void setModelLocator(final ResourceLocator locator) {
_modelLocator = locator;
- return this;
}
- public ObjImporter setMaterialLocator(final ResourceLocator locator) {
+ public void setMaterialLocator(final ResourceLocator locator) {
_materialLocator = locator;
- return this;
}
public void setFlipTextureVertically(final boolean flipTextureVertically) {
@@ -108,6 +105,19 @@ public class ObjImporter {
* @return an ObjGeometryStore data object containing the scene and other useful elements.
*/
public ObjGeometryStore load(final String resource) {
+ return load(resource, new GeometryTool());
+ }
+
+ /**
+ * Reads a Wavefront OBJ file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @param geometryTool
+ * the geometry tool used to minimize the vertex count.
+ * @return an ObjGeometryStore data object containing the scene and other useful elements.
+ */
+ public ObjGeometryStore load(final String resource, final GeometryTool geometryTool) {
final ResourceSource source;
if (_modelLocator == null) {
source = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, resource);
@@ -119,7 +129,7 @@ public class ObjImporter {
throw new Error("Unable to locate '" + resource + "'");
}
- return load(source);
+ return load(source, geometryTool);
}
/**
@@ -130,11 +140,22 @@ public class ObjImporter {
* @return an ObjGeometryStore data object containing the scene and other useful elements.
*/
public ObjGeometryStore load(final ResourceSource resource) {
- try {
- final ObjGeometryStore store = new ObjGeometryStore();
- long currentSmoothGroup = -1;
+ return load(resource, new GeometryTool());
+ }
- final BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream()));
+ /**
+ * Reads a Wavefront OBJ file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @param geometryTool
+ * the geometry tool used to minimize the vertex count.
+ * @return an ObjGeometryStore data object containing the scene and other useful elements.
+ */
+ public ObjGeometryStore load(final ResourceSource resource, final GeometryTool geometryTool) {
+ try (final BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream()))) {
+ final ObjGeometryStore store = new ObjGeometryStore(geometryTool);
+ long currentSmoothGroup = -1;
String line;
int lineNo = 0;
while ((line = reader.readLine()) != null) {
@@ -204,7 +225,7 @@ public class ObjImporter {
else if ("cstype".equals(keyword)) {
// TODO: Add support for cstype
ObjImporter.logger
- .warning("ObjModelImporter: cstype not supported. (line " + lineNo + ") " + line);
+ .warning("ObjModelImporter: cstype not supported. (line " + lineNo + ") " + line);
}
// if degree
@@ -232,7 +253,7 @@ public class ObjImporter {
if (tokens.length < 2) {
store.setCurrentGroupNames(null);
continue;
- // throw new Error("wrong number of args. g must have at least 1 argument. (line " + lineNo
+ // throw new Error("wrong number of args. g must have at least 1 argument. (line " + lineNo
// + ") " + line);
}
@@ -245,7 +266,8 @@ public class ObjImporter {
// if smoothing group
else if ("s".equals(keyword)) {
if (tokens.length != 2) {
- throw new Error("wrong number of args. s must have 1 argument. (line " + lineNo + ") " + line);
+ throw new Error(
+ "wrong number of args. s must have 1 argument. (line " + lineNo + ") " + line);
}
if ("off".equalsIgnoreCase(tokens[1])) {
@@ -264,7 +286,8 @@ public class ObjImporter {
// if object name
else if ("o".equals(keyword)) {
if (tokens.length < 2) {
- throw new Error("wrong number of args. o must have 1 argument. (line " + lineNo + ") " + line);
+ throw new Error(
+ "wrong number of args. o must have 1 argument. (line " + lineNo + ") " + line);
}
store.setCurrentObjectName(tokens[1]);
}
@@ -287,8 +310,8 @@ public class ObjImporter {
// if use material command
else if ("usemtl".equals(keyword)) {
if (tokens.length != 2) {
- throw new Error("wrong number of args. usemtl must have 1 argument. (line " + lineNo + ") "
- + line);
+ throw new Error(
+ "wrong number of args. usemtl must have 1 argument. (line " + lineNo + ") " + line);
}
// set new material
@@ -300,12 +323,12 @@ public class ObjImporter {
// if point
else if ("p".equals(keyword) && tokens.length > 1) {
if (tokens.length < 2) {
- throw new Error("wrong number of args. p must have at least 1 vertex. (line " + lineNo + ") "
- + line);
+ throw new Error(
+ "wrong number of args. p must have at least 1 vertex. (line " + lineNo + ") " + line);
}
// Each token corresponds to 1 vertex entry
- final List<ObjIndexSet> indices = Lists.newArrayList();
+ final List<ObjIndexSet> indices = new ArrayList<>();
for (int i = 1; i < tokens.length; i++) {
indices.add(new ObjIndexSet(tokens[i], store.getDataStore(), currentSmoothGroup));
}
@@ -320,7 +343,7 @@ public class ObjImporter {
}
// Each token corresponds to 1 vertex entry and possibly one texture entry
- final List<ObjIndexSet> indices = Lists.newArrayList();
+ final List<ObjIndexSet> indices = new ArrayList<>();
for (int i = 1; i < tokens.length; i++) {
indices.add(new ObjIndexSet(tokens[i], store.getDataStore(), currentSmoothGroup));
}
@@ -335,7 +358,7 @@ public class ObjImporter {
}
// Each token corresponds to 1 vertex entry and possibly one texture entry and normal entry.
- final List<ObjIndexSet> indices = Lists.newArrayList();
+ final List<ObjIndexSet> indices = new ArrayList<>();
for (int i = 1; i < tokens.length; i++) {
indices.add(new ObjIndexSet(tokens[i], store.getDataStore(), currentSmoothGroup));
}
@@ -364,8 +387,8 @@ public class ObjImporter {
store.commitObjects();
store.cleanup();
return store;
- } catch (final Exception e) {
- throw new Error("Unable to load obj resource from URL: " + resource, e);
+ } catch (final Throwable t) {
+ throw new Error("Unable to load obj resource from URL: " + resource, t);
}
}
@@ -396,7 +419,7 @@ public class ObjImporter {
}
/**
- * Load a .mtl resource
+ * Load a .mtl resource, see <a href="http://paulbourke.net/dataformats/mtl/">the format specification</a>
*
* @param resource
* the mtl file to load, as a ResourceSource
@@ -453,58 +476,98 @@ public class ObjImporter {
// if ambient value
if ("Ka".equals(keyword)) {
- currentMaterial.Ka = new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]),
- Float.parseFloat(tokens[3]) };
+ currentMaterial.setAmbientRed(Float.parseFloat(tokens[1]));
+ currentMaterial.setAmbientGreen(Float.parseFloat(tokens[2]));
+ currentMaterial.setAmbientBlue(Float.parseFloat(tokens[3]));
}
// if diffuse value
else if ("Kd".equals(keyword)) {
- currentMaterial.Kd = new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]),
- Float.parseFloat(tokens[3]) };
+ currentMaterial.setDiffuseRed(Float.parseFloat(tokens[1]));
+ currentMaterial.setDiffuseGreen(Float.parseFloat(tokens[2]));
+ currentMaterial.setDiffuseBlue(Float.parseFloat(tokens[3]));
}
// if specular value
else if ("Ks".equals(keyword)) {
- currentMaterial.Ks = new float[] { Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]),
- Float.parseFloat(tokens[3]) };
+ currentMaterial.setSpecularRed(Float.parseFloat(tokens[1]));
+ currentMaterial.setSpecularGreen(Float.parseFloat(tokens[2]));
+ currentMaterial.setSpecularBlue(Float.parseFloat(tokens[3]));
+ }
+ // if transmission filter
+ else if ("Tf".equals(keyword)) {
+ // TODO: Add support for Tf
+ }
+ // if sharpness value
+ else if ("sharpness".equals(keyword)) {
+ // TODO: Add support for sharpness
+ }
+ // if optical density
+ else if ("Ni".equals(keyword)) {
+ // TODO: Add support for Ni
+ }
+ // if disp
+ else if ("disp".equals(keyword)) {
+ // TODO: Add support for disp
+ }
+ // if decal value
+ else if ("decal".equals(keyword)) {
+ // TODO: Add support for decal
+ }
+ // if bump
+ else if ("bump".equals(keyword)) {
+ // TODO: Add support for bump
}
-
// if illumination style
else if ("illum".equals(keyword)) {
- currentMaterial.illumType = Integer.parseInt(tokens[1]);
+ currentMaterial.setIllumType(Integer.parseInt(tokens[1]));
}
// if "dissolve" (alpha) value
else if ("d".equals(keyword)) {
- currentMaterial.d = Float.parseFloat(tokens[1]);
+ final float d;
+ if ("-halo".equalsIgnoreCase(tokens[1])) {
+ // TODO: Add support for halo
+ d = Float.parseFloat(tokens[2]);
+ } else {
+ d = Float.parseFloat(tokens[1]);
+ }
+ currentMaterial.setAmbientAlpha(d);
+ currentMaterial.setDiffuseAlpha(d);
+ currentMaterial.setSpecularAlpha(d);
+ currentMaterial.setEmissiveAlpha(d);
}
// if ambient value
else if ("Ns".equals(keyword)) {
final float Ns = Float.parseFloat(tokens[1]);
- currentMaterial.Ns = 128 * MathUtils.clamp(Ns, 0, _specularMax) / _specularMax;
+ currentMaterial.setShininess(128 * MathUtils.clamp(Ns, 0, _specularMax) / _specularMax);
}
// if we mapped a texture to alpha
else if ("map_d".equals(keyword)) {
// force blending... probably also used texture in map_Kd, etc.
- currentMaterial.forceBlend = true;
+ currentMaterial.setForceBlend(true);
}
// if texture
else if (isLoadTextures() && "map_Kd".equals(keyword)) {
// TODO: it's possible for map_Kd to have arguments, then filename.
final String textureName = line.substring("map_Kd".length()).trim();
- currentMaterial.textureName = textureName;
+ currentMaterial.setTextureName(textureName);
if (_textureLocator == null) {
- currentMaterial.map_Kd = TextureManager.load(textureName, getMinificationFilter(),
- isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
- : TextureStoreFormat.GuessNoCompressedFormat, isFlipTextureVertically());
+ currentMaterial
+ .setMap_Kd(TextureManager.load(textureName, getMinificationFilter(),
+ isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
+ : TextureStoreFormat.GuessNoCompressedFormat,
+ isFlipTextureVertically()));
} else {
final ResourceSource source = _textureLocator.locateResource(textureName);
- currentMaterial.map_Kd = TextureManager.load(source, getMinificationFilter(),
- isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
- : TextureStoreFormat.GuessNoCompressedFormat, isFlipTextureVertically());
+ currentMaterial
+ .setMap_Kd(TextureManager.load(source, getMinificationFilter(),
+ isUseCompression() ? TextureStoreFormat.GuessCompressedFormat
+ : TextureStoreFormat.GuessNoCompressedFormat,
+ isFlipTextureVertically()));
}
}
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjIndexSet.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjIndexSet.java
index 0e2bec1..ffd7576 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjIndexSet.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjIndexSet.java
@@ -1,15 +1,17 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.obj;
+import java.util.Objects;
+
public class ObjIndexSet {
private final int _vIndex, _vtIndex;
private final long _sGroup;
@@ -64,12 +66,8 @@ public class ObjIndexSet {
@Override
public int hashCode() {
- int result = 17;
- result += 31 * result + _vIndex;
- result += 31 * result + _vtIndex;
- result += 31 * result + _vnIndex;
- result += 31 * result + _sGroup;
- return result;
+ return Objects.hash(Integer.valueOf(getVIndex()), Integer.valueOf(getVtIndex()), Integer.valueOf(getVnIndex()),
+ Long.valueOf(getSmoothGroup()));
}
@Override
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjMaterial.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjMaterial.java
index f060cec..ccb8a46 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjMaterial.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjMaterial.java
@@ -1,54 +1,37 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.obj;
+import com.ardor3d.extension.model.util.AbstractMaterial;
import com.ardor3d.image.Texture;
-import com.ardor3d.math.ColorRGBA;
-import com.ardor3d.math.MathUtils;
-import com.ardor3d.renderer.state.BlendState;
-import com.ardor3d.renderer.state.MaterialState;
import com.ardor3d.renderer.state.TextureState;
-public class ObjMaterial {
+/**
+ * WaveFront OBJ material (MTL). <code>Ns</code> matches with the shininess, <code>d</code> matches with the alpha
+ * component(s), <code>Ka</code> matches with the ambient RGB components, <code>Kd</code> matches with the diffuse RGB
+ * components, <code>Ks</code> matches with the specular RGB components.
+ */
+public class ObjMaterial extends AbstractMaterial {
private final String name;
- float[] Ka = null;
- float[] Kd = null;
- float[] Ks = null;
- float Ns = -1;
-
- String textureName;
- Texture map_Kd = null;
+ private String textureName;
- int illumType = 2;
+ private Texture map_Kd;
- boolean forceBlend = false;
- float d = -1;
+ private int illumType;
public ObjMaterial(final String name) {
+ super();
this.name = name;
- }
-
- public BlendState getBlendState() {
- if (forceBlend || d != -1 && d < 1.0f) {
- final BlendState blend = new BlendState();
- blend.setBlendEnabled(true);
- blend.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
- blend.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
- blend.setTestEnabled(true);
- blend.setTestFunction(BlendState.TestFunction.GreaterThan);
- blend.setReference(0);
- return blend;
- }
- return null;
+ illumType = 2;
}
public TextureState getTextureState() {
@@ -60,29 +43,6 @@ public class ObjMaterial {
return null;
}
- public MaterialState getMaterialState() {
- if (Ka != null || Kd != null || Ks != null || d != -1 || Ns != -1) {
- final MaterialState material = new MaterialState();
- final float alpha = d != -1 ? MathUtils.clamp(d, 0, 1) : 1;
- if (Ka != null) {
- material.setAmbient(new ColorRGBA(Ka[0], Ka[1], Ka[2], alpha));
- }
- if (Kd != null) {
- material.setDiffuse(new ColorRGBA(Kd[0], Kd[1], Kd[2], alpha));
- }
- if (Ks != null) {
- material.setSpecular(new ColorRGBA(Ks[0], Ks[1], Ks[2], alpha));
- }
-
- if (Ns != -1) {
- material.setShininess(Ns);
- }
-
- return material;
- }
- return null;
- }
-
public String getName() {
return name;
}
@@ -91,7 +51,23 @@ public class ObjMaterial {
return textureName;
}
+ public void setTextureName(final String textureName) {
+ this.textureName = textureName;
+ }
+
public Texture getMap_Kd() {
return map_Kd;
}
+
+ public void setMap_Kd(final Texture map_Kd) {
+ this.map_Kd = map_Kd;
+ }
+
+ public int getIllumType() {
+ return illumType;
+ }
+
+ public void setIllumType(final int illumType) {
+ this.illumType = illumType;
+ }
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjSetManager.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjSetManager.java
index 116371d..e5abb85 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjSetManager.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/obj/ObjSetManager.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -10,16 +10,15 @@
package com.ardor3d.extension.model.obj;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
public class ObjSetManager {
- private final Map<ObjIndexSet, Integer> _store = Maps.newLinkedHashMap();
- private final List<Integer> _indices = Lists.newArrayList();
- private final List<Integer> _lengths = Lists.newArrayList();
+ private final Map<ObjIndexSet, Integer> _store = new LinkedHashMap<>();
+ private final List<Integer> _indices = new ArrayList<>();
+ private final List<Integer> _lengths = new ArrayList<>();
public int findSet(final ObjIndexSet set) {
if (_store.containsKey(set)) {
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyDataStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyDataStore.java
new file mode 100644
index 0000000..14cd03b
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyDataStore.java
@@ -0,0 +1,50 @@
+/**
+ * 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.ply;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+
+public class PlyDataStore {
+
+ private final List<Vector3> _vertices;
+ private final List<Vector3> _normals;
+ private final List<ColorRGBA> _colors;
+ private final List<Vector2> _textureCoordinates;
+
+ public PlyDataStore() {
+ super();
+ _vertices = new ArrayList<>();
+ _normals = new ArrayList<>();
+ _colors = new ArrayList<>();
+ _textureCoordinates = new ArrayList<>();
+ }
+
+ public List<Vector3> getVertices() {
+ return _vertices;
+ }
+
+ public List<Vector3> getNormals() {
+ return _normals;
+ }
+
+ public List<ColorRGBA> getColors() {
+ return _colors;
+ }
+
+ public List<Vector2> getTextureCoordinates() {
+ return _textureCoordinates;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyEdgeInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyEdgeInfo.java
new file mode 100644
index 0000000..e4f84f6
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyEdgeInfo.java
@@ -0,0 +1,50 @@
+/**
+ * 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.ply;
+
+import com.ardor3d.math.ColorRGBA;
+
+public class PlyEdgeInfo {
+
+ private Integer index1;
+
+ private Integer index2;
+
+ private ColorRGBA color;
+
+ public PlyEdgeInfo() {
+ super();
+ }
+
+ public Integer getIndex1() {
+ return index1;
+ }
+
+ public void setIndex1(final Integer index1) {
+ this.index1 = index1;
+ }
+
+ public Integer getIndex2() {
+ return index2;
+ }
+
+ public void setIndex2(final Integer index2) {
+ this.index2 = index2;
+ }
+
+ public ColorRGBA getColor() {
+ return color;
+ }
+
+ public void setColor(final ColorRGBA color) {
+ this.color = color;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyFaceInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyFaceInfo.java
new file mode 100644
index 0000000..75fc25d
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyFaceInfo.java
@@ -0,0 +1,60 @@
+/**
+ * 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.ply;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PlyFaceInfo {
+
+ private List<Integer> _vertexIndices;
+
+ private List<Integer> _materialIndices;
+
+ private List<Float> _textureCoordinates;
+
+ public PlyFaceInfo() {
+ super();
+ }
+
+ public void addVertexIndex(final int vertexIndex) {
+ if (_vertexIndices == null) {
+ _vertexIndices = new ArrayList<>();
+ }
+ _vertexIndices.add(Integer.valueOf(vertexIndex));
+ }
+
+ public List<Integer> getVertexIndices() {
+ return _vertexIndices;
+ }
+
+ public void addMaterialIndex(final int materialIndex) {
+ if (_materialIndices == null) {
+ _materialIndices = new ArrayList<>();
+ }
+ _materialIndices.add(Integer.valueOf(materialIndex));
+ }
+
+ public List<Integer> getMaterialIndices() {
+ return _materialIndices;
+ }
+
+ public void addTextureCoordinate(final float textureCoordinate) {
+ if (_textureCoordinates == null) {
+ _textureCoordinates = new ArrayList<>();
+ }
+ _textureCoordinates.add(Float.valueOf(textureCoordinate));
+ }
+
+ public List<Float> getTextureCoordinates() {
+ return _textureCoordinates;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyGeometryStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyGeometryStore.java
new file mode 100644
index 0000000..624665d
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyGeometryStore.java
@@ -0,0 +1,313 @@
+/**
+ * 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.ply;
+
+import java.nio.Buffer;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.image.Texture;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.renderer.IndexMode;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.scenegraph.IndexBufferData;
+import com.ardor3d.scenegraph.Line;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.util.geom.BufferUtils;
+import com.ardor3d.util.geom.GeometryTool;
+import com.ardor3d.util.geom.GeometryTool.MatchCondition;
+
+public class PlyGeometryStore {
+
+ private static final Logger LOGGER = Logger.getLogger(PlyGeometryStore.class.getName());
+
+ private int _totalMeshes = 0;
+
+ private int _totalLines = 0;
+
+ private final PlyDataStore _dataStore;
+
+ private final Node _root;
+
+ private final List<PlyMaterial> _materialLibrary;
+
+ private List<PlyFaceInfo> _plyFaceInfoList;
+
+ private List<PlyEdgeInfo> _plyEdgeInfoList;
+
+ private Texture _texture;
+
+ private String _textureName;
+
+ private final GeometryTool _geometryTool;
+
+ public PlyGeometryStore() {
+ this(new GeometryTool());
+ }
+
+ public PlyGeometryStore(final GeometryTool geometryTool) {
+ super();
+ _dataStore = new PlyDataStore();
+ _root = new Node();
+ _materialLibrary = new ArrayList<>();
+ _geometryTool = geometryTool;
+ }
+
+ public PlyDataStore getDataStore() {
+ return _dataStore;
+ }
+
+ public Node getScene() {
+ return _root;
+ }
+
+ public List<PlyMaterial> getMaterialLibrary() {
+ return _materialLibrary;
+ }
+
+ public String getTextureName() {
+ return _textureName;
+ }
+
+ public void setTextureName(final String textureName) {
+ _textureName = textureName;
+ }
+
+ public Texture getTexture() {
+ return _texture;
+ }
+
+ public void setTexture(final Texture texture) {
+ _texture = texture;
+ }
+
+ public TextureState getTextureState() {
+ if (_texture != null) {
+ final TextureState tState = new TextureState();
+ tState.setTexture(_texture, 0);
+ return tState;
+ }
+ return null;
+ }
+
+ void addLine(final PlyEdgeInfo edgeInfo) {
+ if (_plyEdgeInfoList == null) {
+ _plyEdgeInfoList = new ArrayList<>();
+ }
+ _plyEdgeInfoList.add(edgeInfo);
+ }
+
+ void addFace(final PlyFaceInfo faceInfo) {
+ if (_plyFaceInfoList == null) {
+ _plyFaceInfoList = new ArrayList<>();
+ }
+ _plyFaceInfoList.add(faceInfo);
+ }
+
+ @SuppressWarnings("null")
+ void commitObjects() {
+ if (_plyEdgeInfoList != null) {
+ final String name = "ply_line" + _totalLines;
+ boolean hasColors = false;
+ final boolean hasNormals = _dataStore.getNormals() != null && !_dataStore.getNormals().isEmpty();
+ final int vertexCount = _plyEdgeInfoList.size() * 2;
+ final Vector3[] vertices = new Vector3[vertexCount];
+ final Vector3[] normals = hasNormals ? null : new Vector3[vertexCount];
+ ReadOnlyColorRGBA[] colors = null;
+ final IndexBufferData<? extends Buffer> indices = BufferUtils.createIndexBufferData(vertexCount,
+ vertexCount - 1);
+ int edgeVertexIndex = 0;
+ for (final PlyEdgeInfo plyEdgeInfo : _plyEdgeInfoList) {
+ indices.put(edgeVertexIndex).put(edgeVertexIndex + 1);
+ vertices[edgeVertexIndex] = _dataStore.getVertices().get(plyEdgeInfo.getIndex1());
+ vertices[edgeVertexIndex + 1] = _dataStore.getVertices().get(plyEdgeInfo.getIndex2());
+ if (hasNormals) {
+ normals[edgeVertexIndex] = _dataStore.getNormals().get(plyEdgeInfo.getIndex1());
+ normals[edgeVertexIndex + 1] = _dataStore.getNormals().get(plyEdgeInfo.getIndex2());
+ }
+ if (plyEdgeInfo.getColor() != null) {
+ if (colors == null) {
+ colors = new ReadOnlyColorRGBA[vertexCount];
+ }
+ colors[edgeVertexIndex] = plyEdgeInfo.getColor();
+ colors[edgeVertexIndex + 1] = plyEdgeInfo.getColor();
+ hasColors = true;
+ }
+ edgeVertexIndex += 2;
+ }
+ final Line line = new Line(name, vertices, normals, colors, null);
+ indices.rewind();
+ line.getMeshData().setIndices(indices);
+ final EnumSet<MatchCondition> matchConditions = EnumSet.noneOf(MatchCondition.class);
+ if (hasNormals) {
+ matchConditions.add(MatchCondition.Normal);
+ }
+ if (hasColors) {
+ matchConditions.add(MatchCondition.Color);
+ }
+ _geometryTool.minimizeVerts(line, matchConditions);
+
+ final TextureState tState = getTextureState();
+ if (tState != null) {
+ line.setRenderState(tState);
+ }
+
+ line.updateModelBound();
+ _totalLines++;
+ _plyEdgeInfoList = null;
+ }
+ if (_plyFaceInfoList != null) {
+ final String name = "ply_mesh" + _totalMeshes;
+ final Mesh mesh = new Mesh(name);
+ boolean hasTexCoordsInFaces = false;
+ final boolean hasTexCoordsInVertices = _dataStore.getTextureCoordinates() != null
+ && !_dataStore.getTextureCoordinates().isEmpty();
+ final boolean hasNormals = _dataStore.getNormals() != null && !_dataStore.getNormals().isEmpty();
+ final boolean hasColors = _dataStore.getColors() != null && !_dataStore.getColors().isEmpty();
+ int vertexCount = 0;
+ for (final PlyFaceInfo plyFaceInfo : _plyFaceInfoList) {
+ vertexCount += plyFaceInfo.getVertexIndices().size();
+ if (plyFaceInfo.getTextureCoordinates() != null && !plyFaceInfo.getTextureCoordinates().isEmpty()) {
+ hasTexCoordsInFaces = true;
+ }
+ }
+ final FloatBuffer vertices = BufferUtils.createVector3Buffer(vertexCount);
+ final IndexBufferData<? extends Buffer> indices = BufferUtils.createIndexBufferData(vertexCount,
+ vertexCount - 1);
+
+ final FloatBuffer normals = hasNormals ? BufferUtils.createFloatBuffer(vertices.capacity()) : null;
+ final FloatBuffer colors = hasColors ? BufferUtils.createFloatBuffer(vertexCount * 4) : null;
+ final FloatBuffer uvs = hasTexCoordsInFaces || hasTexCoordsInVertices
+ ? BufferUtils.createFloatBuffer(vertexCount * 2) : null;
+
+ int dummyVertexIndex = 0;
+ final List<IndexMode> indexModeList = new ArrayList<>();
+ final List<Integer> indexLengthList = new ArrayList<>();
+ for (final PlyFaceInfo plyFaceInfo : _plyFaceInfoList) {
+ final IndexMode previousIndexMode = indexModeList.isEmpty() ? null
+ : indexModeList.get(indexModeList.size() - 1);
+ final IndexMode currentIndexMode;
+ switch (plyFaceInfo.getVertexIndices().size()) {
+ case 3: {
+ currentIndexMode = IndexMode.Triangles;
+ break;
+ }
+ case 4: {
+ currentIndexMode = IndexMode.Quads;
+ break;
+ }
+ default: {
+ currentIndexMode = null;
+ break;
+ }
+ }
+ if (currentIndexMode == null) {
+ PlyGeometryStore.LOGGER.log(Level.SEVERE,
+ "The index mode cannot be determined for a face containing "
+ + plyFaceInfo.getVertexIndices().size() + " vertices");
+ } else {
+ if (previousIndexMode == null || currentIndexMode != previousIndexMode) {
+ indexModeList.add(currentIndexMode);
+ indexLengthList.add(currentIndexMode.getVertexCount());
+ } else {
+ final int previousIndexLength = indexLengthList.get(indexLengthList.size() - 1).intValue();
+ final int currentIndexLength = previousIndexLength + currentIndexMode.getVertexCount();
+ indexLengthList.set(indexLengthList.size() - 1, Integer.valueOf(currentIndexLength));
+ }
+ for (final Integer vertexIndex : plyFaceInfo.getVertexIndices()) {
+ indices.put(dummyVertexIndex);
+ final Vector3 vertex = _dataStore.getVertices().get(vertexIndex.intValue());
+ vertices.put(vertex.getXf()).put(vertex.getYf()).put(vertex.getZf());
+ if (hasNormals) {
+ final Vector3 normal = _dataStore.getNormals().get(vertexIndex.intValue());
+ normals.put(normal.getXf()).put(normal.getYf()).put(normal.getZf());
+ }
+ if (hasColors) {
+ final ColorRGBA color = _dataStore.getColors().get(vertexIndex.intValue());
+ colors.put(color.getRed()).put(color.getGreen()).put(color.getBlue()).put(color.getAlpha());
+ }
+ if (hasTexCoordsInVertices) {
+ final Vector2 texCoords = _dataStore.getTextureCoordinates().get(vertexIndex.intValue());
+ uvs.put(texCoords.getXf()).put(texCoords.getYf());
+ }
+ dummyVertexIndex++;
+ }
+ if (hasTexCoordsInFaces) {
+ for (final Float texCoord : plyFaceInfo.getTextureCoordinates()) {
+ uvs.put(texCoord);
+ }
+ }
+ }
+ }
+
+ vertices.rewind();
+ mesh.getMeshData().setVertexBuffer(vertices);
+ indices.rewind();
+ mesh.getMeshData().setIndices(indices);
+ if (indexModeList.size() == 1) {
+ mesh.getMeshData().setIndexMode(indexModeList.get(0));
+ mesh.getMeshData().setIndexLengths(null);
+ } else {
+ mesh.getMeshData().setIndexModes(indexModeList.toArray(new IndexMode[indexModeList.size()]));
+ final int[] indexLengths = new int[indexLengthList.size()];
+ for (int indexLengthIndex = 0; indexLengthIndex < indexLengths.length; indexLengthIndex++) {
+ indexLengths[indexLengthIndex] = indexLengthList.get(indexLengthIndex).intValue();
+ }
+ mesh.getMeshData().setIndexLengths(indexLengths);
+ }
+ final EnumSet<MatchCondition> matchConditions = EnumSet.noneOf(MatchCondition.class);
+ if (hasNormals) {
+ normals.rewind();
+ mesh.getMeshData().setNormalBuffer(normals);
+ matchConditions.add(MatchCondition.Normal);
+ }
+ if (hasColors) {
+ colors.rewind();
+ mesh.getMeshData().setColorBuffer(colors);
+ matchConditions.add(MatchCondition.Color);
+ }
+ if (hasTexCoordsInFaces || hasTexCoordsInVertices) {
+ uvs.rewind();
+ mesh.getMeshData().setTextureBuffer(uvs, 0);
+ matchConditions.add(MatchCondition.UVs);
+ }
+
+ if (indexModeList.size() == 1) {
+ _geometryTool.minimizeVerts(mesh, matchConditions);
+ } else {
+ // FIXME unsure about minimizeVerts preserving the index modes
+ }
+
+ final TextureState tState = getTextureState();
+ if (tState != null) {
+ mesh.setRenderState(tState);
+ }
+
+ mesh.updateModelBound();
+ _root.attachChild(mesh);
+ _totalMeshes++;
+ _plyFaceInfoList = null;
+ }
+ }
+
+ void cleanup() {
+ _plyFaceInfoList = null;
+ _plyEdgeInfoList = null;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyImporter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyImporter.java
new file mode 100644
index 0000000..c4901b7
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyImporter.java
@@ -0,0 +1,1643 @@
+/**
+ * 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.ply;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.StandardCharsets;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.image.Texture;
+import com.ardor3d.image.Texture.MinificationFilter;
+import com.ardor3d.image.TextureStoreFormat;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector2;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.util.TextureManager;
+import com.ardor3d.util.geom.GeometryTool;
+import com.ardor3d.util.resource.ResourceLocator;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.ardor3d.util.resource.ResourceSource;
+
+/**
+ * PLY importer. See <a href="http://paulbourke.net/dataformats/ply/">the format spec</a>
+ *
+ * Note that the material indices are stored but not used to build the meshes as it's currently impossible to apply a
+ * material per vertex
+ */
+public class PlyImporter {
+
+ public static enum Format {
+ ASCII, BINARY_LITTLE_ENDIAN, BINARY_BIG_ENDIAN;
+ };
+
+ public static class FormatWithVersionNumber {
+
+ private final Format format;
+
+ private final double versionNumber;
+
+ public FormatWithVersionNumber(final Format format, final double versionNumber) {
+ super();
+ this.format = format;
+ this.versionNumber = versionNumber;
+ }
+
+ public Format getFormat() {
+ return format;
+ }
+
+ public double getVersionNumber() {
+ return versionNumber;
+ }
+ }
+
+ public static enum ListProperty {
+ /** indices of the vertices */
+ VERTEX_INDICES(Element.FACE, Element.CUSTOM),
+ /** indices of materials (not sure that it's really in the specification) */
+ MATERIAL_INDICES(Element.FACE, Element.CUSTOM),
+ /** texture coordinates (probably only supported by MeshLab) */
+ TEXCOORD(Element.FACE, Element.CUSTOM),
+ /** custom, i.e user-defined, not build-in, up to the developer to support it */
+ CUSTOM(Element.CUSTOM);
+ private final Element[] elements;
+
+ private ListProperty(final Element... elements) {
+ this.elements = elements;
+ }
+
+ public Element[] getElements() {
+ return elements;
+ }
+
+ public static ListProperty get(final String name) {
+ final String uppercaseName = name.toUpperCase();
+ ListProperty result = null;
+ try {
+ result = ListProperty.valueOf(uppercaseName);
+ } catch (final IllegalArgumentException iae) {
+ if ("VERTEX_INDEX".equals(uppercaseName) || "VERTEX_INDEXES".equals(uppercaseName)) {
+ result = VERTEX_INDICES;
+ } else if ("MATERIAL_INDEX".equals(uppercaseName) || "MATERIAL_INDEXES".equals(uppercaseName)) {
+ result = MATERIAL_INDICES;
+ } else {
+ result = CUSTOM;
+ }
+ }
+ return result;
+ }
+ }
+
+ public static enum ScalarProperty {
+ /** abscissa */
+ X(Element.VERTEX, Element.CUSTOM),
+ /** ordinate */
+ Y(Element.VERTEX, Element.CUSTOM),
+ /** applicate */
+ Z(Element.VERTEX, Element.CUSTOM),
+ /** normal x vector coordinate */
+ NX(Element.VERTEX, Element.CUSTOM),
+ /** normal y vector coordinate */
+ NY(Element.VERTEX, Element.CUSTOM),
+ /** normal z vector coordinate */
+ NZ(Element.VERTEX, Element.CUSTOM),
+ /** u texture coordinate */
+ S(Element.VERTEX, Element.CUSTOM),
+ /** v texture coordinate */
+ T(Element.VERTEX, Element.CUSTOM),
+ /** first vertex */
+ VERTEX1(Element.EDGE, Element.CUSTOM),
+ /** second vertex */
+ VERTEX2(Element.EDGE, Element.CUSTOM),
+ /** red color component */
+ RED(Element.VERTEX, Element.EDGE, Element.CUSTOM),
+ /** green color component */
+ GREEN(Element.VERTEX, Element.EDGE, Element.CUSTOM),
+ /** blue color component */
+ BLUE(Element.VERTEX, Element.EDGE, Element.CUSTOM),
+ /** material (ambient light) components */
+ AMBIENT_RED(Element.MATERIAL, Element.CUSTOM), AMBIENT_GREEN(Element.MATERIAL, Element.CUSTOM), AMBIENT_BLUE(Element.MATERIAL, Element.CUSTOM), AMBIENT_COEFF(Element.MATERIAL, Element.CUSTOM),
+ /** material (diffuse light) components */
+ DIFFUSE_RED(Element.MATERIAL, Element.CUSTOM), DIFFUSE_GREEN(Element.MATERIAL, Element.CUSTOM), DIFFUSE_BLUE(Element.MATERIAL, Element.CUSTOM), DIFFUSE_COEFF(Element.MATERIAL, Element.CUSTOM),
+ /** material (emissive light) components */
+ EMISSIVE_RED(Element.MATERIAL, Element.CUSTOM), EMISSIVE_GREEN(Element.MATERIAL, Element.CUSTOM), EMISSIVE_BLUE(Element.MATERIAL, Element.CUSTOM), EMISSIVE_COEFF(Element.MATERIAL, Element.CUSTOM),
+ /** material (specular light) components */
+ SPECULAR_RED(Element.MATERIAL, Element.CUSTOM), SPECULAR_GREEN(Element.MATERIAL, Element.CUSTOM), SPECULAR_BLUE(Element.MATERIAL, Element.CUSTOM), SPECULAR_COEFF(Element.MATERIAL, Element.CUSTOM), SPECULAR_POWER(Element.MATERIAL, Element.CUSTOM),
+ /** custom, i.e user-defined, not build-in, up to the developer to support it */
+ CUSTOM(Element.CUSTOM);
+ private final Element[] elements;
+
+ private ScalarProperty(final Element... elements) {
+ this.elements = elements;
+ }
+
+ public Element[] getElements() {
+ return elements;
+ }
+
+ public static ScalarProperty get(final String name) {
+ final String uppercaseName = name.toUpperCase();
+ ScalarProperty result = null;
+ try {
+ result = ScalarProperty.valueOf(uppercaseName);
+ } catch (final IllegalArgumentException iae) {
+ result = CUSTOM;
+ }
+ return result;
+ }
+ }
+
+ protected static class EnumWithKeyword<T extends Enum<?>> {
+
+ private final T enumKey;
+
+ private final String keyword;
+
+ protected EnumWithKeyword(final T enumKey, final String keyword) {
+ super();
+ this.enumKey = enumKey;
+ this.keyword = keyword;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(enumKey, keyword);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final EnumWithKeyword<?> other = (EnumWithKeyword<?>) obj;
+ return enumKey == other.enumKey && Objects.equals(keyword, other.keyword);
+ }
+
+ public T getEnumKey() {
+ return enumKey;
+ }
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ @Override
+ public String toString() {
+ return "'" + Objects.toString(enumKey) + "[" + Objects.toString(keyword) + "]'";
+ }
+ }
+
+ public static abstract class AbstractPropertyWithKeyword<T extends Enum<?>> extends EnumWithKeyword<T> {
+
+ private final Data data;
+
+ protected AbstractPropertyWithKeyword(final T enumKey, final String keyword, final Data data) {
+ super(enumKey, keyword);
+ this.data = data;
+ }
+
+ public Data getData() {
+ return data;
+ }
+
+ public abstract Element[] getElements();
+
+ @Override
+ public String toString() {
+ return "property " + super.toString() + " data type " + Objects.toString(getData());
+ }
+ }
+
+ public static class ScalarPropertyWithKeyword extends AbstractPropertyWithKeyword<ScalarProperty> {
+
+ public ScalarPropertyWithKeyword(final ScalarProperty scalarProperty, final String keyword, final Data data) {
+ super(scalarProperty, keyword, data);
+ }
+
+ @Override
+ public Element[] getElements() {
+ return getEnumKey() == null ? null : getEnumKey().getElements();
+ }
+
+ @Override
+ public String toString() {
+ return "scalar " + super.toString();
+ }
+ }
+
+ public static class ListPropertyWithKeyword extends AbstractPropertyWithKeyword<ListProperty> {
+
+ private final Data countData;
+
+ public ListPropertyWithKeyword(final ListProperty listProperty, final String keyword, final Data countData,
+ final Data data) {
+ super(listProperty, keyword, data);
+ this.countData = countData;
+ }
+
+ @Override
+ public Element[] getElements() {
+ return getEnumKey() == null ? null : getEnumKey().getElements();
+ }
+
+ public Data getCountData() {
+ return countData;
+ }
+
+ @Override
+ public String toString() {
+ return "list " + super.toString() + " index data type " + Objects.toString(countData);
+ }
+ }
+
+ public static enum Element {
+ VERTEX, FACE, EDGE, MATERIAL,
+ /** custom, i.e user-defined, not build-in, up to the developer to support it */
+ CUSTOM;
+
+ public static Element get(final String name) {
+ final String uppercaseName = name.toUpperCase();
+ Element result = null;
+ try {
+ result = Element.valueOf(uppercaseName);
+ } catch (final IllegalArgumentException iae) {
+ result = CUSTOM;
+ }
+ return result;
+ }
+ };
+
+ public static class ElementWithKeyword extends EnumWithKeyword<Element> {
+
+ public ElementWithKeyword(final Element element, final String keyword) {
+ super(element, keyword);
+ }
+
+ @Override
+ public String toString() {
+ return "element " + super.toString();
+ }
+ }
+
+ public static enum Data {
+
+ /** one byte signed integer */
+ CHAR,
+ /** one byte unsigned integer */
+ UCHAR,
+ /** two byte signed integer */
+ SHORT,
+ /** two byte unsigned integer */
+ USHORT,
+ /** four byte signed integer */
+ INT,
+ /** four byte unsigned integer */
+ UINT,
+ /** four byte floating point number */
+ FLOAT,
+ /** eight byte floating point number */
+ DOUBLE;
+
+ public static Data get(final String name) throws IllegalArgumentException {
+ final String uppercaseName = name.toUpperCase();
+ Data result = null;
+ try {
+ result = Data.valueOf(uppercaseName);
+ } catch (final IllegalArgumentException iae) {
+ switch (uppercaseName) {
+ case "INT8": {
+ result = CHAR;
+ break;
+ }
+ case "UINT8": {
+ result = UCHAR;
+ break;
+ }
+ case "INT16": {
+ result = SHORT;
+ break;
+ }
+ case "UINT16": {
+ result = USHORT;
+ break;
+ }
+ case "INT32": {
+ result = INT;
+ break;
+ }
+ case "UINT32": {
+ result = UINT;
+ break;
+ }
+ case "FLOAT32": {
+ result = FLOAT;
+ break;
+ }
+ case "FLOAT64": {
+ result = DOUBLE;
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException(
+ "'" + name + "' does not match with any data type supported by the PLY format");
+ }
+ }
+ }
+ return result;
+ }
+ }
+
+ public static interface PlyReader extends Closeable {
+ public double read(final Data data) throws IOException;
+ }
+
+ /**
+ * largely inspired of jPly's BinaryPlyInputStream, @see
+ * https://github.com/smurn/jPLY/blob/master/jply/src/main/java/org/smurn/jply/BinaryPlyInputStream.java
+ */
+ public static class BinaryPlyReader implements PlyReader {
+
+ private final ReadableByteChannel channel;
+
+ private final ByteBuffer buffer;
+
+ private static final int BUFFER_SIZE = 1024;
+
+ public BinaryPlyReader(final InputStream inputStream, final ByteOrder byteOrder) {
+ super();
+ channel = Channels.newChannel(inputStream);
+ buffer = ByteBuffer.allocate(BinaryPlyReader.BUFFER_SIZE);
+ buffer.order(byteOrder);
+ buffer.clear();
+ buffer.position(buffer.capacity());
+ }
+
+ @Override
+ public double read(final Data data) throws IOException {
+ switch (data) {
+ case CHAR:
+ ensureAvailable(1);
+ return buffer.get();
+ case UCHAR:
+ ensureAvailable(1);
+ return buffer.get() & 0x000000FF;
+ case SHORT:
+ ensureAvailable(2);
+ return buffer.getShort();
+ case USHORT:
+ ensureAvailable(2);
+ return buffer.getShort() & 0x0000FFFF;
+ case INT:
+ ensureAvailable(4);
+ return buffer.getInt();
+ case UINT:
+ ensureAvailable(4);
+ return ((long) buffer.getShort()) & 0x00000000FFFFFFFF;
+ case FLOAT:
+ ensureAvailable(4);
+ return buffer.getFloat();
+ case DOUBLE:
+ ensureAvailable(8);
+ return buffer.getDouble();
+ default:
+ throw new IllegalArgumentException("Unsupported type: " + data);
+ }
+ }
+
+ /**
+ * Ensures that a certain amount of bytes are in the buffer, ready to be read.
+ *
+ * @param bytes
+ * Minimal number of unread bytes required in the buffer.
+ * @see ByteBuffer#remaining()
+ * @throws IOException
+ * if reading sufficient more data into the buffer fails.
+ */
+ protected void ensureAvailable(final int bytes) throws IOException {
+ while (buffer.remaining() < bytes) {
+ buffer.compact();
+ if (channel.read(buffer) < 0) {
+ throw new EOFException();
+ }
+ buffer.flip();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ channel.close();
+ }
+ }
+
+ public static class AsciiPlyReader implements PlyReader {
+
+ private final PlyFileParser parser;
+ private final BufferedReader reader;
+
+ public AsciiPlyReader(final InputStream stream) {
+ super();
+ reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.US_ASCII));
+ parser = new PlyFileParser(reader);
+ }
+
+ @Override
+ public double read(final Data data) throws IOException {
+ do {
+ parser.nextToken();
+ } while (parser.ttype != StreamTokenizer.TT_WORD && parser.ttype != StreamTokenizer.TT_EOF);
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ try {
+ parser.nval = Double.valueOf(parser.sval).doubleValue();
+ return parser.nval;
+ } catch (final NumberFormatException nbe) {
+ throw new IOException("Unparsable string " + parser.sval, nbe);
+ }
+ } else {
+ throw new IOException("No number to read, end of file reached");
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ reader.close();
+ }
+ }
+
+ private static final Logger LOGGER = Logger.getLogger(PlyImporter.class.getName());
+
+ public static class PlyFileParser extends StreamTokenizer implements Closeable {
+
+ private final Reader reader;
+
+ /**
+ * Constructor.
+ *
+ * @param reader
+ * The Reader.
+ */
+ public PlyFileParser(final Reader reader) {
+ super(reader);
+ this.reader = reader;
+ resetSyntax();
+ eolIsSignificant(true);
+ lowerCaseMode(true);
+
+ // all printable ascii characters
+ wordChars('!', '~');
+
+ whitespaceChars(' ', ' ');
+ whitespaceChars('\n', '\n');
+ whitespaceChars('\r', '\r');
+ whitespaceChars('\t', '\t');
+ }
+
+ /**
+ * Gets a number from the stream. Need to extract numbers since they may be in scientific notation. The number
+ * is returned in nval.
+ *
+ * @return Logical-true if successful, else logical-false.
+ */
+ protected boolean getNumber() {
+ try {
+ nextToken();
+ if (ttype != StreamTokenizer.TT_WORD) {
+ return false;
+ }
+ nval = Double.valueOf(sval).doubleValue();
+ } catch (final IOException e) {
+ System.err.println(e.getMessage());
+ return false;
+ } catch (final NumberFormatException e) {
+ System.err.println(e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void close() throws IOException {
+ reader.close();
+ }
+ }
+
+ private ResourceLocator _modelLocator;
+
+ private ResourceLocator _textureLocator;
+
+ private boolean _flipTextureVertically;
+
+ private boolean _useCompression;
+
+ private MinificationFilter _minificationFilter;
+
+ /**
+ * Constructor.
+ */
+ public PlyImporter() {
+ super();
+ _flipTextureVertically = true;
+ _useCompression = true;
+ _minificationFilter = MinificationFilter.Trilinear;
+ }
+
+ /**
+ * Reads a PLY file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ *
+ * @return a PlyGeometryStore data object containing the scene and other useful elements.
+ */
+ public PlyGeometryStore load(final String resource) {
+ return load(resource, new GeometryTool());
+ }
+
+ /**
+ * Reads a PLY file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @param geometryTool
+ * the geometry tool to optimize the meshes
+ *
+ * @return a PlyGeometryStore data object containing the scene and other useful elements.
+ */
+ public PlyGeometryStore load(final String resource, final GeometryTool geometryTool) {
+ final ResourceSource source;
+ if (_modelLocator == null) {
+ source = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, resource);
+ } else {
+ source = _modelLocator.locateResource(resource);
+ }
+
+ if (source == null) {
+ throw new Error("Unable to locate '" + resource + "'");
+ }
+
+ return load(source, geometryTool);
+ }
+
+ /**
+ * Reads a PLY file from the given resource
+ *
+ * @param resource
+ * the resource to find.
+ *
+ * @return a PlyGeometryStore data object containing the scene and other useful elements.
+ */
+ public PlyGeometryStore load(final ResourceSource resource) {
+ return load(resource, new GeometryTool());
+ }
+
+ /**
+ * Reads a PLY file from the given resource
+ *
+ * @param resource
+ * the resource to find.
+ * @param geometryTool
+ * the geometry tool to optimize the meshes
+ *
+ * @return a PlyGeometryStore data object containing the scene and other useful elements.
+ */
+ @SuppressWarnings("resource")
+ public PlyGeometryStore load(final ResourceSource resource, final GeometryTool geometryTool) {
+ final PlyGeometryStore store = createGeometryStore(geometryTool);
+ try {
+ FormatWithVersionNumber formatWithVersionNumber = null;
+ final int firstLineOfBody;
+ final Map<ElementWithKeyword, Map.Entry<Integer, Set<AbstractPropertyWithKeyword<?>>>> elementMap = new LinkedHashMap<>();
+ try (final PlyFileParser parser = new PlyFileParser(
+ new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.US_ASCII)))) {
+ try {
+ // starts reading the header
+ parser.nextToken();
+ // reads "ply"
+ if ("ply".equals(parser.sval)) {
+ PlyImporter.LOGGER.log(Level.INFO, "ply keyword on line " + parser.lineno());
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE, "No ply keyword on line " + parser.lineno());
+ }
+ // reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line " + parser.lineno());
+ }
+ parser.nextToken();
+ // reads the rest of the header
+ while (parser.ttype != StreamTokenizer.TT_EOF && !"end_header".equals(parser.sval)) {
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ final int currentLineNumber = parser.lineno();
+ switch (parser.sval) {
+ case "comment": {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ if ("TextureFile".equals(parser.sval)) {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ final String textureName = parser.sval;
+ store.setTextureName(textureName);
+ final Texture texture;
+ if (_textureLocator == null) {
+ texture = TextureManager.load(textureName, getMinificationFilter(),
+ isUseCompression()
+ ? TextureStoreFormat.GuessCompressedFormat
+ : TextureStoreFormat.GuessNoCompressedFormat,
+ isFlipTextureVertically());
+ } else {
+ final ResourceSource source = _textureLocator
+ .locateResource(textureName);
+ texture = TextureManager.load(source, getMinificationFilter(),
+ isUseCompression()
+ ? TextureStoreFormat.GuessCompressedFormat
+ : TextureStoreFormat.GuessNoCompressedFormat,
+ isFlipTextureVertically());
+ }
+ store.setTexture(texture);
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "'TextureFile' comment with no texture file on line "
+ + currentLineNumber);
+ }
+ }
+ }
+ break;
+ }
+ case "format": {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ if (formatWithVersionNumber == null) {
+ Format format = null;
+ try {
+ format = Format.valueOf(parser.sval.toUpperCase());
+ } catch (final IllegalArgumentException iae) {
+ PlyImporter.LOGGER.log(Level.SEVERE, "Unknown format '" + parser.sval
+ + "' on line " + currentLineNumber + ": " + iae.getMessage());
+ }
+ final double versionNumber;
+ if (parser.getNumber()) {
+ versionNumber = parser.nval;
+ if (Double.compare(versionNumber, 1.0d) != 0) {
+ PlyImporter.LOGGER.log(Level.WARNING,
+ "Unsupported format version number '" + parser.nval
+ + "' on line " + currentLineNumber
+ + ". This importer supports only PLY 1.0");
+ }
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Format version number missing on line " + currentLineNumber
+ + "\n");
+ versionNumber = Double.NaN;
+ }
+ formatWithVersionNumber = new FormatWithVersionNumber(format,
+ versionNumber);
+ PlyImporter.LOGGER.log(Level.INFO,
+ "Format '" + (format == null ? "null" : format.name())
+ + "' version number '" + versionNumber
+ + "' detected on line " + currentLineNumber);
+ } else {
+ PlyImporter.LOGGER.log(Level.WARNING,
+ "Format already defined, format declaration ignored on line "
+ + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Format type (ascii, binary_big_endian or binary_little_endian) missing on line "
+ + currentLineNumber);
+ }
+ break;
+ }
+ case "element": {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ final String elementName = parser.sval;
+ final Element element = Element.get(elementName);
+ final ElementWithKeyword elementWithKeyword = new ElementWithKeyword(element,
+ elementName);
+ if (elementMap.containsKey(element)) {
+ PlyImporter.LOGGER.log(Level.WARNING,
+ elementWithKeyword
+ + " already defined, element declaration ignored on line "
+ + currentLineNumber);
+ } else {
+ final int elementCount;
+ if (parser.getNumber()) {
+ elementCount = (int) parser.nval;
+ if (elementCount < 0) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ elementWithKeyword + " count = " + elementCount
+ + " whereas it should be >= 0 on line "
+ + currentLineNumber);
+ }
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE, elementWithKeyword
+ + " count missing on line " + currentLineNumber);
+ elementCount = 0;
+ }
+ elementMap.put(elementWithKeyword,
+ new AbstractMap.SimpleEntry<Integer, Set<AbstractPropertyWithKeyword<?>>>(
+ Integer.valueOf(elementCount), null));
+ PlyImporter.LOGGER.log(Level.INFO,
+ elementWithKeyword + " detected on line " + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Element type (vertex, face or edge) missing on line "
+ + currentLineNumber);
+ }
+ break;
+ }
+ case "property": {
+ ElementWithKeyword latestInsertedElementWithKeyword = null;
+ for (final ElementWithKeyword elementWithKeyword : elementMap.keySet()) {
+ latestInsertedElementWithKeyword = elementWithKeyword;
+ }
+ if (latestInsertedElementWithKeyword == null) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Property definition not preceded by an element definition on line "
+ + currentLineNumber);
+ } else {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ if ("list".equals(parser.sval)) {
+ // list property, for face elements (vertex indices, texture
+ // coordinates, ...)
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ Data countData = null;
+ try {
+ countData = Data.get(parser.sval);
+ } catch (final IllegalArgumentException iae) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Count data type '" + parser.sval + "' unknown on line "
+ + currentLineNumber);
+ }
+ if (countData != null) {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ Data data = null;
+ try {
+ data = Data.get(parser.sval);
+ } catch (final IllegalArgumentException iae) {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Data type '" + parser.sval
+ + "' unknown on line "
+ + currentLineNumber);
+ }
+ if (data != null) {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ final String listPropertyName = parser.sval;
+ final ListProperty listProperty = ListProperty
+ .get(listPropertyName);
+ final ListPropertyWithKeyword listPropertyWithKeyword = new ListPropertyWithKeyword(
+ listProperty, listPropertyName, countData,
+ data);
+ if (Arrays.asList(listProperty.getElements())
+ .contains(latestInsertedElementWithKeyword
+ .getEnumKey())) {
+ final Entry<Integer, Set<AbstractPropertyWithKeyword<?>>> elementMapEntry = elementMap
+ .get(latestInsertedElementWithKeyword);
+ Set<AbstractPropertyWithKeyword<?>> propertySet = elementMapEntry
+ .getValue();
+ if (propertySet == null) {
+ propertySet = new LinkedHashSet<>();
+ elementMapEntry.setValue(propertySet);
+ }
+ propertySet.add(listPropertyWithKeyword);
+ PlyImporter.LOGGER.log(Level.INFO,
+ listPropertyWithKeyword
+ + " detected on line "
+ + currentLineNumber);
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Unexpected " + listPropertyWithKeyword
+ + " on line "
+ + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "List property keyword (vertex_indices, texcoord, ...) missing on line "
+ + currentLineNumber);
+ }
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Second data type (float32, int8, ...) missing on line "
+ + currentLineNumber);
+ }
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "First data type (float32, int8, ...) missing on line "
+ + currentLineNumber);
+ }
+ } else {
+ // scalar property (vertex coordinates, normal coordinates, ...)
+ Data data = null;
+ try {
+ data = Data.get(parser.sval);
+ } catch (final IllegalArgumentException iae) {
+ PlyImporter.LOGGER.log(Level.SEVERE, "Data type '" + parser.sval
+ + "' unknown on line " + currentLineNumber);
+ }
+ if (data != null) {
+ parser.nextToken();
+ if (parser.ttype == StreamTokenizer.TT_WORD) {
+ final String scalarPropertyName = parser.sval;
+ final ScalarProperty scalarProperty = ScalarProperty
+ .get(scalarPropertyName);
+ final ScalarPropertyWithKeyword scalarPropertyWithKeyword = new ScalarPropertyWithKeyword(
+ scalarProperty, scalarPropertyName, data);
+ if (Arrays.asList(scalarProperty.getElements()).contains(
+ latestInsertedElementWithKeyword.getEnumKey())) {
+ final Entry<Integer, Set<AbstractPropertyWithKeyword<?>>> elementMapValue = elementMap
+ .get(latestInsertedElementWithKeyword);
+ Set<AbstractPropertyWithKeyword<?>> propertySet = elementMapValue
+ .getValue();
+ if (propertySet == null) {
+ propertySet = new LinkedHashSet<>();
+ elementMapValue.setValue(propertySet);
+ }
+ propertySet.add(scalarPropertyWithKeyword);
+ PlyImporter.LOGGER.log(Level.INFO, scalarPropertyWithKeyword
+ + " detected on line " + currentLineNumber);
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Unexpected " + scalarPropertyWithKeyword + " in a "
+ + latestInsertedElementWithKeyword
+ + " on line " + currentLineNumber);
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Scalar property keyword (x, nx, vertex1, red, ...) missing on line "
+ + currentLineNumber);
+ }
+ }
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Property type (list) or scalar data type (float32, int8, ...) missing on line "
+ + currentLineNumber);
+ }
+ }
+ break;
+ }
+ default: {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "Unknown command '" + parser.sval + "' on line " + currentLineNumber);
+ break;
+ }
+ }
+ } else {
+ PlyImporter.LOGGER.log(Level.SEVERE,
+ "No word at the beginning of the line " + parser.lineno());
+ }
+ // reads the whole line, doesn't look at the content
+ while (parser.ttype != StreamTokenizer.TT_EOL) {
+ parser.nextToken();
+ }
+ // if there is still something to read, reads the next token
+ if (parser.ttype != StreamTokenizer.TT_EOF) {
+ parser.nextToken();
+ }
+ }
+ if ("end_header".equals(parser.sval)) {
+ PlyImporter.LOGGER.log(Level.INFO, "End of header on line " + parser.lineno());
+ do {
+ parser.nextToken();
+ } while (parser.ttype != StreamTokenizer.TT_EOL);
+ firstLineOfBody = parser.lineno();
+ } else {
+ throw new Exception("End of header not detected");
+ }
+ } catch (final IOException ioe) {
+ throw new Exception("IO Error on line " + parser.lineno(), ioe);
+ }
+ }
+ if (formatWithVersionNumber == null || formatWithVersionNumber.getFormat() == null) {
+ throw new Exception("Missing or malformed format in the header, cannot read the body of the PLY file");
+ } else {
+ // stores the number of the first line of the body, after the header
+ int currentLineNumber = firstLineOfBody;
+ // restarts the reading of the file from the beginning
+ try (final InputStream stream = resource.openStream()) {
+ // skips the lines of the header
+ for (int lineIndex = 1; lineIndex < currentLineNumber; lineIndex++) {
+ while (stream.read() != '\n') {
+ ;
+ }
+ }
+ // reads the lines after the header, the body
+ final PlyReader plyReader;
+ switch (formatWithVersionNumber.getFormat()) {
+ case ASCII: {
+ plyReader = new AsciiPlyReader(stream);
+ break;
+ }
+ case BINARY_BIG_ENDIAN: {
+ plyReader = new BinaryPlyReader(stream, ByteOrder.BIG_ENDIAN);
+ break;
+ }
+ case BINARY_LITTLE_ENDIAN: {
+ plyReader = new BinaryPlyReader(stream, ByteOrder.LITTLE_ENDIAN);
+ break;
+ }
+ default: {
+ throw new UnsupportedOperationException(
+ "Unsupported format " + formatWithVersionNumber.getFormat());
+ }
+ }
+ try {
+ for (final Entry<ElementWithKeyword, Entry<Integer, Set<AbstractPropertyWithKeyword<?>>>> elementMapEntry : elementMap
+ .entrySet()) {
+ final ElementWithKeyword elementWithKeyword = elementMapEntry.getKey();
+ final Set<AbstractPropertyWithKeyword<?>> propertiesWithKeywords = elementMapEntry
+ .getValue().getValue();
+ final int elementCount = elementMapEntry.getValue().getKey().intValue();
+ PlyImporter.LOGGER.log(Level.INFO, "Reading of " + elementCount + " elements ("
+ + elementWithKeyword + ") started on line " + currentLineNumber);
+ if (propertiesWithKeywords == null || propertiesWithKeywords.isEmpty()) {
+ PlyImporter.LOGGER.log(Level.SEVERE, elementWithKeyword
+ + " data with no property skipped on line " + currentLineNumber);
+ } else {
+ for (int elementIndex = 0; elementIndex < elementCount; elementIndex++) {
+ // reads one line
+ final List<Double> valueList = new ArrayList<>();
+ for (final AbstractPropertyWithKeyword<?> propertyWithKeyWord : propertiesWithKeywords) {
+ final Data scalarValueDataType = propertyWithKeyWord.getData();
+ if (propertyWithKeyWord instanceof ScalarPropertyWithKeyword) {
+ final double scalarValue = plyReader.read(scalarValueDataType);
+ valueList.add(Double.valueOf(scalarValue));
+ } else if (propertyWithKeyWord instanceof ListPropertyWithKeyword) {
+ final Data valueCountDataType = ((ListPropertyWithKeyword) propertyWithKeyWord)
+ .getCountData();
+ final double rawValueCount = plyReader.read(valueCountDataType);
+ valueList.add(Double.valueOf(rawValueCount));
+ final long valueCount = (long) rawValueCount;
+ for (int valueIndex = 0; valueIndex < valueCount; valueIndex++) {
+ final double scalarValue = plyReader.read(scalarValueDataType);
+ valueList.add(Double.valueOf(scalarValue));
+ }
+ }
+ }
+ if (!valueList.isEmpty()) {
+ // stores the values into an array
+ final double[] values = new double[valueList.size()];
+ for (int valueIndex = 0; valueIndex < values.length; valueIndex++) {
+ values[valueIndex] = valueList.get(valueIndex).doubleValue();
+ }
+ if (elementWithKeyword.getEnumKey() == Element.CUSTOM) {
+ processElementCustomData(formatWithVersionNumber, elementWithKeyword,
+ propertiesWithKeywords, values, currentLineNumber, store);
+ } else {
+ boolean hasBuildInProperties = false;
+ boolean hasCustomProperties = false;
+ for (final AbstractPropertyWithKeyword<?> currentProperty : propertiesWithKeywords) {
+ final boolean isCustom = currentProperty
+ .getEnumKey() == ScalarProperty.CUSTOM
+ || currentProperty.getEnumKey() == ListProperty.CUSTOM;
+ if (!hasCustomProperties && isCustom) {
+ hasCustomProperties = true;
+ }
+ if (!hasBuildInProperties && !isCustom) {
+ hasBuildInProperties = true;
+ }
+ if (hasBuildInProperties && hasCustomProperties) {
+ break;
+ }
+ }
+ if (hasBuildInProperties) {
+ processElementBuildInData(formatWithVersionNumber, elementWithKeyword,
+ propertiesWithKeywords, values, currentLineNumber, store);
+ }
+ if (hasCustomProperties) {
+ processElementCustomData(formatWithVersionNumber, elementWithKeyword,
+ propertiesWithKeywords, values, currentLineNumber, store);
+ }
+ }
+ }
+ currentLineNumber++;
+ }
+ }
+ }
+ } finally {
+ plyReader.close();
+ }
+ } catch (final IOException ioe) {
+ throw new Exception("IO Error on line " + currentLineNumber, ioe);
+ }
+ }
+ } catch (final Throwable t) {
+ throw new Error("Unable to load ply resource from URL: " + resource, t);
+ }
+ store.commitObjects();
+ store.cleanup();
+ return store;
+ }
+
+ protected PlyGeometryStore createGeometryStore(final GeometryTool geometryTool) {
+ return new PlyGeometryStore(geometryTool);
+ }
+
+ /**
+ * Processes the data within a build-in element, handles only the build-in properties whose behaviour is defined in
+ * the specification
+ *
+ * @param formatWithVersionNumber
+ * format with version number
+ * @param elementWithKeyword
+ * element and keyword
+ * @param elementProperties
+ * properties of the element
+ * @param values
+ * parsed values contained in a single line of file
+ * @param lineNumber
+ * number of the line in the PLY file being parsed
+ * @param store
+ * geometry store to fill during the process
+ */
+ protected void processElementBuildInData(final FormatWithVersionNumber formatWithVersionNumber,
+ final ElementWithKeyword elementWithKeyword, final Set<AbstractPropertyWithKeyword<?>> elementProperties,
+ final double[] values, final int lineNumber, final PlyGeometryStore store) {
+ Vector3 vertex = null;
+ Vector3 normal = null;
+ ColorRGBA color = null;
+ Vector2 texCoords = null;
+ PlyMaterial material = null;
+ PlyEdgeInfo edgeInfo = null;
+ PlyFaceInfo faceInfo = null;
+ final Iterator<AbstractPropertyWithKeyword<?>> elementPropertiesIterator = elementProperties.iterator();
+ final AbstractPropertyWithKeyword<?>[] valueProperties = new AbstractPropertyWithKeyword<?>[values.length];
+ int valueIndex = 0;
+ // loops on the properties
+ while (valueIndex < values.length && elementPropertiesIterator.hasNext()) {
+ final AbstractPropertyWithKeyword<?> elementProperty = elementPropertiesIterator.next();
+ if (elementProperty instanceof ScalarPropertyWithKeyword) {
+ valueProperties[valueIndex] = elementProperty;
+ valueIndex++;
+ } else if (elementProperty instanceof ListPropertyWithKeyword) {
+ // sets it to null so that it's skipped later as the value at this index is only used to know how much
+ // coordinates are in the list
+ valueProperties[valueIndex] = null;
+ // uses the list property in all concerned indices
+ final int listSize = (int) values[valueIndex];
+ for (int listIndex = 1; listIndex <= listSize; listIndex++) {
+ valueProperties[valueIndex + listIndex] = elementProperty;
+ }
+ valueIndex += 1 + listSize;
+ }
+ }
+ valueIndex = 0;
+ // loops on the real values
+ for (final double value : values) {
+ final AbstractPropertyWithKeyword<?> propertyWithKeyWord = valueProperties[valueIndex];
+ // it can be null when a value indicates the number of values in a list
+ if (propertyWithKeyWord != null) {
+ final Element[] propertyElements = propertyWithKeyWord.getElements();
+ if (propertyElements != null && propertyElements.length > 0
+ && Arrays.asList(propertyElements).contains(elementWithKeyword.getEnumKey())) {
+ switch (elementWithKeyword.getEnumKey()) {
+ case CUSTOM: {
+ throw new IllegalArgumentException("Custom data of the " + elementWithKeyword
+ + " passed to the method responsible for treating build-in data");
+ }
+ case MATERIAL: {
+ if (propertyWithKeyWord instanceof ScalarPropertyWithKeyword) {
+ final ScalarProperty scalarProperty = ((ScalarPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (scalarProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ case AMBIENT_RED: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setAmbientRed((float) (value / 255.0d));
+ break;
+ }
+ case AMBIENT_GREEN: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setAmbientGreen((float) (value / 255.0d));
+ break;
+ }
+ case AMBIENT_BLUE: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setAmbientBlue((float) (value / 255.0d));
+ break;
+ }
+ case AMBIENT_COEFF: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setAmbientAlpha((float) value);
+ break;
+ }
+ case DIFFUSE_RED: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setDiffuseRed((float) (value / 255.0d));
+ break;
+ }
+ case DIFFUSE_GREEN: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setDiffuseGreen((float) (value / 255.0d));
+ break;
+ }
+ case DIFFUSE_BLUE: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setDiffuseBlue((float) (value / 255.0d));
+ break;
+ }
+ case DIFFUSE_COEFF: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setDiffuseAlpha((float) value);
+ break;
+ }
+ case SPECULAR_RED: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setSpecularRed((float) (value / 255.0d));
+ break;
+ }
+ case SPECULAR_GREEN: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setSpecularGreen((float) (value / 255.0d));
+ break;
+ }
+ case SPECULAR_BLUE: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setSpecularBlue((float) (value / 255.0d));
+ break;
+ }
+ case SPECULAR_COEFF: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ material.setSpecularAlpha((float) value);
+ break;
+ }
+ case SPECULAR_POWER: {
+ if (material == null) {
+ material = new PlyMaterial();
+ store.getMaterialLibrary().add(material);
+ }
+ // not sure how to treat the specular power, 200 is the maximum specular value
+ // material.setShininess((float) (128 * MathUtils.clamp(value, 0, 200) / 200));
+ material.setShininess((float) value);
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ } else if (propertyWithKeyWord instanceof ListPropertyWithKeyword) {
+ final ListProperty listProperty = ((ListPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (listProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ }
+ break;
+ }
+ case EDGE: {
+ if (propertyWithKeyWord instanceof ScalarPropertyWithKeyword) {
+ final ScalarProperty scalarProperty = ((ScalarPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (scalarProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ case VERTEX1: {
+ if (edgeInfo == null) {
+ edgeInfo = new PlyEdgeInfo();
+ store.addLine(edgeInfo);
+ }
+ final Integer edgeIndex1 = Integer.valueOf((int) value);
+ edgeInfo.setIndex1(edgeIndex1);
+ break;
+ }
+ case VERTEX2: {
+ if (edgeInfo == null) {
+ edgeInfo = new PlyEdgeInfo();
+ store.addLine(edgeInfo);
+ }
+ final Integer edgeIndex2 = Integer.valueOf((int) value);
+ edgeInfo.setIndex2(edgeIndex2);
+ break;
+ }
+ case RED: {
+ final ColorRGBA edgeColor;
+ if (edgeInfo == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo = new PlyEdgeInfo();
+ edgeInfo.setColor(edgeColor);
+ store.addLine(edgeInfo);
+ } else {
+ if (edgeInfo.getColor() == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo.setColor(edgeColor);
+ } else {
+ edgeColor = edgeInfo.getColor();
+ }
+ }
+ edgeColor.setRed((float) (value / 255.0d));
+ break;
+ }
+ case GREEN: {
+ final ColorRGBA edgeColor;
+ if (edgeInfo == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo = new PlyEdgeInfo();
+ edgeInfo.setColor(edgeColor);
+ store.addLine(edgeInfo);
+ } else {
+ if (edgeInfo.getColor() == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo.setColor(edgeColor);
+ } else {
+ edgeColor = edgeInfo.getColor();
+ }
+ }
+ edgeColor.setGreen((float) (value / 255.0d));
+ break;
+ }
+ case BLUE: {
+ final ColorRGBA edgeColor;
+ if (edgeInfo == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo = new PlyEdgeInfo();
+ edgeInfo.setColor(edgeColor);
+ store.addLine(edgeInfo);
+ } else {
+ if (edgeInfo.getColor() == null) {
+ edgeColor = new ColorRGBA();
+ edgeInfo.setColor(edgeColor);
+ } else {
+ edgeColor = edgeInfo.getColor();
+ }
+ }
+ edgeColor.setBlue((float) (value / 255.0d));
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ } else if (propertyWithKeyWord instanceof ListPropertyWithKeyword) {
+ final ListProperty listProperty = ((ListPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (listProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ }
+ break;
+ }
+ case FACE: {
+ if (propertyWithKeyWord instanceof ScalarPropertyWithKeyword) {
+ final ScalarProperty scalarProperty = ((ScalarPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (scalarProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ } else if (propertyWithKeyWord instanceof ListPropertyWithKeyword) {
+ final ListProperty listProperty = ((ListPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (listProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ case VERTEX_INDICES: {
+ if (faceInfo == null) {
+ faceInfo = new PlyFaceInfo();
+ store.addFace(faceInfo);
+ }
+ faceInfo.addVertexIndex((int) value);
+ break;
+ }
+ case TEXCOORD: {
+ if (faceInfo == null) {
+ faceInfo = new PlyFaceInfo();
+ store.addFace(faceInfo);
+ }
+ faceInfo.addTextureCoordinate((float) value);
+ break;
+ }
+ case MATERIAL_INDICES: {
+ if (faceInfo == null) {
+ faceInfo = new PlyFaceInfo();
+ store.addFace(faceInfo);
+ }
+ faceInfo.addMaterialIndex((int) value);
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ }
+ break;
+ }
+ case VERTEX: {
+ if (propertyWithKeyWord instanceof ScalarPropertyWithKeyword) {
+ final ScalarProperty scalarProperty = ((ScalarPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (scalarProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ case X: {
+ if (vertex == null) {
+ vertex = new Vector3();
+ store.getDataStore().getVertices().add(vertex);
+ }
+ vertex.setX(value);
+ break;
+ }
+ case Y: {
+ if (vertex == null) {
+ vertex = new Vector3();
+ store.getDataStore().getVertices().add(vertex);
+ }
+ vertex.setY(value);
+ break;
+ }
+ case Z: {
+ if (vertex == null) {
+ vertex = new Vector3();
+ store.getDataStore().getVertices().add(vertex);
+ }
+ vertex.setZ(value);
+ break;
+ }
+ case NX: {
+ if (normal == null) {
+ normal = new Vector3();
+ store.getDataStore().getNormals().add(normal);
+ }
+ normal.setX(value);
+ break;
+ }
+ case NY: {
+ if (normal == null) {
+ normal = new Vector3();
+ store.getDataStore().getNormals().add(normal);
+ }
+ normal.setY(value);
+ break;
+ }
+ case NZ: {
+ if (normal == null) {
+ normal = new Vector3();
+ store.getDataStore().getNormals().add(normal);
+ }
+ normal.setZ(value);
+ break;
+ }
+ case S: {
+ if (texCoords == null) {
+ texCoords = new Vector2();
+ store.getDataStore().getTextureCoordinates().add(texCoords);
+ }
+ texCoords.setX(value);
+ break;
+ }
+ case T: {
+ if (texCoords == null) {
+ texCoords = new Vector2();
+ store.getDataStore().getTextureCoordinates().add(texCoords);
+ }
+ texCoords.setY(value);
+ break;
+ }
+ case RED: {
+ if (color == null) {
+ color = new ColorRGBA();
+ store.getDataStore().getColors().add(color);
+ }
+ color.setRed((float) (value / 255.0d));
+ break;
+ }
+ case GREEN: {
+ if (color == null) {
+ color = new ColorRGBA();
+ store.getDataStore().getColors().add(color);
+ }
+ color.setGreen((float) (value / 255.0d));
+ break;
+ }
+ case BLUE: {
+ if (color == null) {
+ color = new ColorRGBA();
+ store.getDataStore().getColors().add(color);
+ }
+ color.setBlue((float) (value / 255.0d));
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ } else if (propertyWithKeyWord instanceof ListPropertyWithKeyword) {
+ final ListProperty listProperty = ((ListPropertyWithKeyword) propertyWithKeyWord)
+ .getEnumKey();
+ switch (listProperty) {
+ case CUSTOM: {
+ PlyImporter.LOGGER.log(Level.FINE, "Custom data of the " + propertyWithKeyWord
+ + " skipped in the method responsible for treating build-in data");
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException(
+ "Missing implementation: the " + propertyWithKeyWord
+ + " is not supported by the " + elementWithKeyword + " yet");
+ }
+ }
+ break;
+ }
+ default:
+ PlyImporter.LOGGER.log(Level.SEVERE, "Element '" + elementWithKeyword.getEnumKey() + "["
+ + elementWithKeyword.getKeyword() + "]' unsupported on line " + lineNumber);
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "The " + propertyWithKeyWord + " is not supported by the " + elementWithKeyword);
+ }
+ }
+ valueIndex++;
+ }
+ }
+
+ /**
+ * Processes the data within a custom element or within a build-in element with custom properties. The default
+ * implementation just displays a warning message as it's up to the developer to manage the user-defined custom data
+ * whose behaviour isn't defined in the specification
+ *
+ * @param formatWithVersionNumber
+ * format with version number
+ * @param elementWithKeyword
+ * element and keyword
+ * @param elementProperties
+ * properties of the element
+ * @param values
+ * parsed values contained in a single line of file
+ * @param lineNumber
+ * number of the line in the PLY file being parsed
+ * @param store
+ * geometry store to fill during the process
+ */
+ protected void processElementCustomData(final FormatWithVersionNumber formatWithVersionNumber,
+ final ElementWithKeyword elementWithKeyword, final Set<AbstractPropertyWithKeyword<?>> elementProperties,
+ final double[] values, final int lineNumber, final PlyGeometryStore store) {
+ PlyImporter.LOGGER.log(Level.WARNING,
+ "'" + elementWithKeyword.getEnumKey().name() + "[" + elementWithKeyword.getKeyword()
+ + "]' ignored on line " + lineNumber + ". Override " + getClass().getCanonicalName()
+ + ".processElementCustomData() to remove this warning");
+ }
+
+ public void setModelLocator(final ResourceLocator locator) {
+ _modelLocator = locator;
+ }
+
+ public void setTextureLocator(final ResourceLocator locator) {
+ _textureLocator = locator;
+ }
+
+ public void setFlipTextureVertically(final boolean flipTextureVertically) {
+ _flipTextureVertically = flipTextureVertically;
+ }
+
+ public boolean isFlipTextureVertically() {
+ return _flipTextureVertically;
+ }
+
+ public void setUseCompression(final boolean useCompression) {
+ _useCompression = useCompression;
+ }
+
+ public boolean isUseCompression() {
+ return _useCompression;
+ }
+
+ public void setMinificationFilter(final MinificationFilter minificationFilter) {
+ _minificationFilter = minificationFilter;
+ }
+
+ public MinificationFilter getMinificationFilter() {
+ return _minificationFilter;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyMaterial.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyMaterial.java
new file mode 100644
index 0000000..ffa4f6c
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/ply/PlyMaterial.java
@@ -0,0 +1,20 @@
+/**
+ * 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.ply;
+
+import com.ardor3d.extension.model.util.AbstractMaterial;
+
+public class PlyMaterial extends AbstractMaterial {
+
+ public PlyMaterial() {
+ super();
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlDataStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlDataStore.java
new file mode 100644
index 0000000..52d6d0d
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlDataStore.java
@@ -0,0 +1,35 @@
+/**
+ * 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.stl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.ardor3d.math.Vector3;
+
+public class StlDataStore {
+ private final List<Vector3> _vertices;
+ private final List<Vector3> _normals;
+
+ public StlDataStore() {
+ super();
+ _vertices = new ArrayList<>();
+ _normals = new ArrayList<>();
+ }
+
+ public List<Vector3> getVertices() {
+ return _vertices;
+ }
+
+ public List<Vector3> getNormals() {
+ return _normals;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlGeometryStore.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlGeometryStore.java
new file mode 100644
index 0000000..3e7fe7a
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlGeometryStore.java
@@ -0,0 +1,120 @@
+/**
+ * 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.stl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.math.type.ReadOnlyColorRGBA;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.MeshData;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.util.geom.BufferUtils;
+
+public class StlGeometryStore {
+
+ private final StlDataStore _dataStore;
+
+ private final Node _root;
+
+ private String _currentObjectName;
+
+ public StlGeometryStore() {
+ super();
+ _dataStore = new StlDataStore();
+ _root = new Node();
+ }
+
+ public StlDataStore getDataStore() {
+ return _dataStore;
+ }
+
+ public Node getScene() {
+ return _root;
+ }
+
+ void setCurrentObjectName(final String name) {
+ commitObjects();
+ _currentObjectName = name;
+ }
+
+ void commitObjects() {
+ if (!_dataStore.getNormals().isEmpty()) {
+ final String name;
+ if (_currentObjectName == null) {
+ name = "stl_mesh";
+ } else {
+ name = _currentObjectName;
+ }
+
+ // mesh object to return
+ final Mesh mesh = new Mesh(name);
+ final MeshData meshData = mesh.getMeshData();
+
+ // allocate buffers
+ final int numberTriangles = _dataStore.getNormals().size();
+ final int vertexBufferSize = 3 * numberTriangles;
+ final FloatBuffer vertexBuffer = BufferUtils.createVector3Buffer(vertexBufferSize);
+ final FloatBuffer normalBuffer = BufferUtils.createVector3Buffer(vertexBufferSize);
+ final FloatBuffer colourBuffer = BufferUtils.createColorBuffer(vertexBufferSize);
+
+ // fill buffers
+ int vertexCount = 0;
+ int normalCount = 0;
+ int colourCount = 0;
+ Vector3 v0;
+ Vector3 v1;
+ Vector3 v2;
+ Vector3 n;
+ final ReadOnlyColorRGBA defaultColour = ColorRGBA.WHITE;
+ for (int i = 0; i < numberTriangles; i++) {
+ // triangle properties
+ v0 = _dataStore.getVertices().get(3 * i + 0);
+ v1 = _dataStore.getVertices().get(3 * i + 1);
+ v2 = _dataStore.getVertices().get(3 * i + 2);
+ n = _dataStore.getNormals().get(i);
+ // vertices
+ BufferUtils.setInBuffer(v0, vertexBuffer, vertexCount++);
+ BufferUtils.setInBuffer(v1, vertexBuffer, vertexCount++);
+ BufferUtils.setInBuffer(v2, vertexBuffer, vertexCount++);
+ // normals - 1 foreach vertex
+ BufferUtils.setInBuffer(n, normalBuffer, normalCount++);
+ BufferUtils.setInBuffer(n, normalBuffer, normalCount++);
+ BufferUtils.setInBuffer(n, normalBuffer, normalCount++);
+ // colours - 1 foreach vertex
+ BufferUtils.setInBuffer(defaultColour, colourBuffer, colourCount++);
+ BufferUtils.setInBuffer(defaultColour, colourBuffer, colourCount++);
+ BufferUtils.setInBuffer(defaultColour, colourBuffer, colourCount++);
+ }
+
+ meshData.setVertexBuffer(vertexBuffer);
+ meshData.setNormalBuffer(normalBuffer);
+ meshData.setColorBuffer(colourBuffer);
+
+ // indices buffer
+ final int[] indices = new int[vertexBufferSize];
+ for (int i = 0; i < vertexBufferSize; i++) {
+ indices[i] = i;
+ }
+ final IntBuffer iBuffer = BufferUtils.createIntBuffer(indices.length);
+ iBuffer.put(indices);
+ meshData.setIndexBuffer(iBuffer);
+
+ _root.attachChild(mesh);
+ }
+ }
+
+ void cleanup() {
+ _currentObjectName = null;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlImporter.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlImporter.java
new file mode 100644
index 0000000..a5aeed9
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/stl/StlImporter.java
@@ -0,0 +1,545 @@
+/**
+ * Copyright (c) 2008-2016 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.stl;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StreamTokenizer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.ardor3d.extension.model.util.FileHelper;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.util.resource.ResourceLocator;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.ardor3d.util.resource.ResourceSource;
+
+/**
+ * Reads an STL (STereoLithography) file and builds an Ardor3D Mesh. The STL format consists entirely of triangles and
+ * as a result is a simple format to handle. Also, it is widely supported by the CAD/CAM community.
+ *
+ * This class supports both ASCII and Binary formats and files residing either locally or on a network.
+ *
+ * Refer to <a href="http://en.wikipedia.org/wiki/STL_(file_format)" target="_blank>Wikipedia</a>. Several STL models
+ * can be downloaded freely from <a href="http://grabcad.com" target="_blank">GrabCAD</a>.
+ *
+ * @author gmseed
+ * @see StlFileParser
+ */
+public class StlImporter {
+
+ /**
+ * Extends StreamTokenizer for parsing STL files. The STL format for Ascii files is as follows:
+ *
+ * <pre>
+ * solid name
+ * ...
+ * facet normal ni nj nk
+ * outer loop
+ * vertex v1x v1y v1z
+ * vertex v2x v2y v2z
+ * vertex v3x v3y v3z
+ * endloop
+ * endfacet
+ * ...
+ * endsolid name
+ * </pre>
+ *
+ * @author gmseed
+ */
+ public static class StlFileParser extends StreamTokenizer {
+
+ /**
+ * Constructor.
+ *
+ * @param reader
+ * The Reader.
+ */
+ public StlFileParser(final Reader reader) {
+ super(reader);
+ resetSyntax();
+ eolIsSignificant(true);
+ lowerCaseMode(true);
+
+ // all printable ascii characters
+ wordChars('!', '~');
+
+ whitespaceChars(' ', ' ');
+ whitespaceChars('\n', '\n');
+ whitespaceChars('\r', '\r');
+ whitespaceChars('\t', '\t');
+ }
+
+ /**
+ * Gets a number from the stream. Need to extract numbers since they may be in scientific notation. The number
+ * is returned in nval.
+ *
+ * @return Logical-true if successful, else logical-false.
+ */
+ protected boolean getNumber() {
+ try {
+ nextToken();
+ if (ttype != StreamTokenizer.TT_WORD) {
+ return false;
+ }
+ nval = Double.valueOf(sval).doubleValue();
+ } catch (final IOException e) {
+ System.err.println(e.getMessage());
+ return false;
+ } catch (final NumberFormatException e) {
+ System.err.println(e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ // logger
+ private static final Logger LOGGER = Logger.getLogger(StlImporter.class.getName());
+
+ private static final String SOLID_KEYWORD = "solid";
+ private static final String[] END_SOLID_KEYWORD_PARTS = new String[] { "end", "solid" };
+ private static final String ENDSOLID_KEYWORD = "endsolid";
+ private static final String FACET_KEYWORD = "facet";
+ private static final String NORMAL_KEYWORD = "normal";
+ private static final String[] OUTER_LOOP_KEYWORD_PARTS = new String[] { "outer", "loop" };
+ private static final String VERTEX_KEYWORD = "vertex";
+ private static final String ENDLOOP_KEYWORD = "endloop";
+ private static final String ENDFACET_KEYWORD = "endfacet";
+
+ private ResourceLocator _modelLocator;
+
+ /**
+ * Constructor.
+ */
+ public StlImporter() {
+ super();
+ }
+
+ /**
+ * Reads a STL file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @return a StlGeometryStore data object containing the scene and other useful elements.
+ */
+ public StlGeometryStore load(final String resource) {
+ return load(resource, new FileHelper());
+ }
+
+ /**
+ * Reads a STL file from the given resource
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @param fileHelper
+ * the file helper used to determine whether the resource is an Ascii file or a binary file
+ *
+ * @return a StlGeometryStore data object containing the scene and other useful elements.
+ */
+ public StlGeometryStore load(final String resource, final FileHelper fileHelper) {
+ final ResourceSource source;
+ if (_modelLocator == null) {
+ source = ResourceLocatorTool.locateResource(ResourceLocatorTool.TYPE_MODEL, resource);
+ } else {
+ source = _modelLocator.locateResource(resource);
+ }
+
+ if (source == null) {
+ throw new Error("Unable to locate '" + resource + "'");
+ }
+
+ return load(source, fileHelper);
+ }
+
+ /**
+ * Reads a STL file from the given resource
+ *
+ * @param resource
+ * the resource to find.
+ * @return a StlGeometryStore data object containing the scene and other useful elements.
+ */
+ public StlGeometryStore load(final ResourceSource resource) {
+ return load(resource, new FileHelper());
+ }
+
+ /**
+ * Reads a STL file from the given resource
+ *
+ * @param resource
+ * the resource to find.
+ * @param fileHelper
+ * the file helper used to determine whether the resource is an Ascii file or a binary file
+ *
+ * @return a StlGeometryStore data object containing the scene and other useful elements.
+ */
+ public StlGeometryStore load(final ResourceSource resource, final FileHelper fileHelper) {
+ final boolean isAscii = fileHelper.isFilePureAscii(resource);
+ final StlGeometryStore store = new StlGeometryStore();
+ if (isAscii) { // Ascii file
+ try (final BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream()))) {
+ final StlFileParser parser = new StlFileParser(reader);
+ try {
+ parser.nextToken();
+ // read "solid"
+ if (parser.sval != null && StlImporter.SOLID_KEYWORD.equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.INFO, "solid keyword on line " + parser.lineno());
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Ascii file but no solid keyword on line " + parser.lineno());
+ }
+ parser.nextToken();
+ // read object name if any
+ if (parser.ttype != StreamTokenizer.TT_WORD) {
+ StlImporter.LOGGER.log(Level.WARNING,
+ "Format Warning: expecting the (optional) object name on line " + parser.lineno());
+ } else {
+ final String objectName = parser.sval;
+ store.setCurrentObjectName(objectName);
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line " + parser.lineno());
+ }
+ }
+ // read the rest of the file
+ parser.nextToken();
+ boolean endSolidFound = false;
+ // read all the facets
+ while (parser.ttype != StreamTokenizer.TT_EOF && !endSolidFound) {
+ endSolidFound = false;
+ // reads "endsolid"
+ if (StlImporter.ENDSOLID_KEYWORD.equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.INFO, "endsolid keyword on line " + parser.lineno());
+ endSolidFound = true;
+ } else {
+ // reads "end solid"
+ if (StlImporter.END_SOLID_KEYWORD_PARTS[0].equals(parser.sval)) {
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.END_SOLID_KEYWORD_PARTS[1].equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error:expecting 'end solid' on line " + parser.lineno());
+ } else {
+ StlImporter.LOGGER.log(Level.INFO, "end solid keyword on line " + parser.lineno());
+ endSolidFound = true;
+ }
+ } else {
+ // Reads "facet"
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || (!StlImporter.FACET_KEYWORD.equals(parser.sval)
+ && !StlImporter.END_SOLID_KEYWORD_PARTS[0].equals(parser.sval))) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error:expecting 'facet' on line " + parser.lineno());
+ } else {
+ parser.nextToken();
+ // Reads a normal
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.NORMAL_KEYWORD.equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error:expecting 'normal' on line " + parser.lineno());
+ } else {
+ if (parser.getNumber()) {
+ final Vector3 normal = new Vector3();
+ normal.setX(parser.nval);
+
+ if (parser.getNumber()) {
+ normal.setY(parser.nval);
+
+ if (parser.getNumber()) {
+ normal.setZ(parser.nval);
+
+ store.getDataStore().getNormals().add(normal);
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting normal z-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting normal y-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting normal x-component on line "
+ + parser.lineno());
+ }
+ }
+
+ parser.nextToken();
+ // Reads "outer loop" then EOL
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.OUTER_LOOP_KEYWORD_PARTS[0].equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting 'outer' on line " + parser.lineno());
+ } else {
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.OUTER_LOOP_KEYWORD_PARTS[1].equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error:expecting 'loop' on line " + parser.lineno());
+ } else {
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + parser.lineno());
+ }
+ }
+ }
+
+ parser.nextToken();
+ // Reads the first vertex
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.VERTEX_KEYWORD.equals(parser.sval)) {
+ System.err
+ .println("Format Error:expecting 'vertex' on line " + parser.lineno());
+ } else {
+ if (parser.getNumber()) {
+ final Vector3 vertex = new Vector3();
+ vertex.setX(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setY(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setZ(parser.nval);
+
+ store.getDataStore().getVertices().add(vertex);
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex z-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex y-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex x-component on line "
+ + parser.lineno());
+ }
+ }
+
+ parser.nextToken();
+ // Reads the second vertex
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.VERTEX_KEYWORD.equals(parser.sval)) {
+ System.err
+ .println("Format Error:expecting 'vertex' on line " + parser.lineno());
+ } else {
+ if (parser.getNumber()) {
+ final Vector3 vertex = new Vector3();
+ vertex.setX(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setY(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setZ(parser.nval);
+
+ store.getDataStore().getVertices().add(vertex);
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex z-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex y-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex x-component on line "
+ + parser.lineno());
+ }
+ }
+
+ parser.nextToken();
+ // Reads the third vertex
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.VERTEX_KEYWORD.equals(parser.sval)) {
+ System.err
+ .println("Format Error:expecting 'vertex' on line " + parser.lineno());
+ } else {
+ if (parser.getNumber()) {
+ final Vector3 vertex = new Vector3();
+ vertex.setX(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setY(parser.nval);
+
+ if (parser.getNumber()) {
+ vertex.setZ(parser.nval);
+
+ store.getDataStore().getVertices().add(vertex);
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex z-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex y-component on line "
+ + parser.lineno());
+ }
+ } else {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting vertex x-component on line "
+ + parser.lineno());
+ }
+ }
+
+ parser.nextToken();
+ // Reads "endloop" then EOL
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.ENDLOOP_KEYWORD.equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting 'endloop' on line " + parser.lineno());
+ } else {
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line " + parser.lineno());
+ }
+ }
+
+ parser.nextToken();
+ // Reads "endfacet" then EOL
+ if (parser.ttype != StreamTokenizer.TT_WORD
+ || !StlImporter.ENDFACET_KEYWORD.equals(parser.sval)) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error:expecting 'endfacet' on line " + parser.lineno());
+ } else {
+ // Reads the EOL for verifying that the file has a correct format
+ parser.nextToken();
+ if (parser.ttype != StreamTokenizer.TT_EOL) {
+ StlImporter.LOGGER.log(Level.SEVERE,
+ "Format Error: expecting End Of Line on line " + parser.lineno());
+ }
+ }
+ }
+ }
+ }
+ parser.nextToken();
+ }
+ } catch (final IOException e) {
+ StlImporter.LOGGER.log(Level.SEVERE, "IO Error on line " + parser.lineno() + ": " + e.getMessage());
+ }
+ } catch (final Throwable t) {
+ throw new Error("Unable to load stl resource from URL: " + resource, t);
+ }
+ } else { // Binary file
+ try (final InputStream data = resource.openStream()) {
+ ByteBuffer dataBuffer; // To read in the correct endianness
+ final byte[] info = new byte[80]; // Header data
+ final byte[] numberFaces = new byte[4]; // the number of faces
+ byte[] faceData; // face data
+ int numberTriangles; // First info (after the header) on the file
+
+ // the first 80 bytes aren't important (except if you want to support non standard colors)
+ if (80 != data.read(info)) {
+ throw new IOException("Format Error: 80 bytes expected");
+ } else {
+ // read number of faces, setting the correct order
+ data.read(numberFaces);
+ dataBuffer = ByteBuffer.wrap(numberFaces);
+ dataBuffer.order(ByteOrder.nativeOrder());
+
+ // allocate buffer for face data, with each face requiring 50 bytes
+ numberTriangles = dataBuffer.getInt();
+ faceData = new byte[50 * numberTriangles];
+
+ // read face data
+ data.read(faceData);
+ dataBuffer = ByteBuffer.wrap(faceData);
+ dataBuffer.order(ByteOrder.nativeOrder());
+
+ // read each facet noting that after each fact there are 2 bytes without information
+ // no need to skip for last iteration
+ for (int index = 0; index < numberTriangles; index++) {
+ try {
+ // Reads a facet from a binary file.
+ // normal
+ store.getDataStore().getNormals().add(
+ new Vector3(dataBuffer.getFloat(), dataBuffer.getFloat(), dataBuffer.getFloat()));
+ // 3 vertices
+ store.getDataStore().getVertices().add(
+ new Vector3(dataBuffer.getFloat(), dataBuffer.getFloat(), dataBuffer.getFloat()));
+ store.getDataStore().getVertices().add(
+ new Vector3(dataBuffer.getFloat(), dataBuffer.getFloat(), dataBuffer.getFloat()));
+ store.getDataStore().getVertices().add(
+ new Vector3(dataBuffer.getFloat(), dataBuffer.getFloat(), dataBuffer.getFloat()));
+ if (index != numberTriangles - 1) {
+ dataBuffer.get();
+ dataBuffer.get();
+ }
+ } catch (final Throwable t) {
+ throw new Exception("Format Error: iteration number " + index, t);
+ }
+ }
+ }
+ } catch (final Throwable t) {
+ throw new Error("Unable to load stl resource from URL: " + resource, t);
+ }
+ }
+
+ store.commitObjects();
+ store.cleanup();
+ return store;
+
+ }
+
+ public void setModelLocator(final ResourceLocator locator) {
+ _modelLocator = locator;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/AbstractMaterial.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/AbstractMaterial.java
new file mode 100644
index 0000000..c008479
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/AbstractMaterial.java
@@ -0,0 +1,244 @@
+/**
+ * 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.util;
+
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.renderer.state.BlendState;
+import com.ardor3d.renderer.state.MaterialState;
+
+/**
+ * common material parameters
+ */
+public abstract class AbstractMaterial {
+
+ private float ambientRed, ambientGreen, ambientBlue, ambientAlpha;
+
+ private float diffuseRed, diffuseGreen, diffuseBlue, diffuseAlpha;
+
+ private float emissiveRed, emissiveGreen, emissiveBlue, emissiveAlpha;
+
+ private float specularRed, specularGreen, specularBlue, specularAlpha;
+
+ private float shininess;
+
+ private boolean forceBlend;
+
+ protected AbstractMaterial() {
+ super();
+ ambientRed = -1;
+ ambientGreen = -1;
+ ambientBlue = -1;
+ ambientAlpha = -1;
+ diffuseRed = -1;
+ diffuseGreen = -1;
+ diffuseBlue = -1;
+ diffuseAlpha = -1;
+ emissiveRed = -1;
+ emissiveGreen = -1;
+ emissiveBlue = -1;
+ emissiveAlpha = -1;
+ specularRed = -1;
+ specularGreen = -1;
+ specularBlue = -1;
+ specularAlpha = -1;
+ shininess = -1;
+ }
+
+ public BlendState getBlendState() {
+ if (forceBlend || (ambientAlpha != -1 && ambientAlpha < 1.0f) || (diffuseAlpha != -1 && diffuseAlpha < 1.0f)
+ || (emissiveAlpha != -1 && emissiveAlpha < 1.0f) || (specularAlpha != -1 && specularAlpha < 1.0f)) {
+ final BlendState blend = new BlendState();
+ blend.setBlendEnabled(true);
+ blend.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
+ blend.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
+ blend.setTestEnabled(true);
+ blend.setTestFunction(BlendState.TestFunction.GreaterThan);
+ blend.setReference(0);
+ return blend;
+ }
+ return null;
+ }
+
+ public MaterialState getMaterialState() {
+ if ((ambientRed != -1 && ambientGreen != -1 && ambientBlue != -1)
+ || (diffuseRed != -1 && diffuseGreen != -1 && diffuseBlue != -1)
+ || (emissiveRed != -1 && emissiveGreen != -1 && emissiveBlue != -1)
+ || (specularRed != -1 && specularGreen != -1 && specularBlue != -1) || shininess != -1) {
+ final MaterialState material = new MaterialState();
+ if (ambientRed != -1 && ambientGreen != -1 && ambientBlue != -1) {
+ final float alpha = ambientAlpha == -1 ? 1 : MathUtils.clamp(ambientAlpha, 0, 1);
+ material.setAmbient(new ColorRGBA(ambientRed, ambientGreen, ambientBlue, alpha));
+ }
+ if (diffuseRed != -1 && diffuseGreen != -1 && diffuseBlue != -1) {
+ final float alpha = diffuseAlpha == -1 ? 1 : MathUtils.clamp(diffuseAlpha, 0, 1);
+ material.setDiffuse(new ColorRGBA(diffuseRed, diffuseGreen, diffuseBlue, alpha));
+ }
+ if (emissiveRed != -1 && emissiveGreen != -1 && emissiveBlue != -1) {
+ final float alpha = emissiveAlpha == -1 ? 1 : MathUtils.clamp(emissiveAlpha, 0, 1);
+ material.setEmissive(new ColorRGBA(emissiveRed, emissiveGreen, emissiveBlue, alpha));
+ }
+ if (specularRed != -1 && specularGreen != -1 && specularBlue != -1) {
+ final float alpha = specularAlpha == -1 ? 1 : MathUtils.clamp(specularAlpha, 0, 1);
+ material.setSpecular(new ColorRGBA(specularRed, specularGreen, specularBlue, alpha));
+ }
+ if (shininess != -1) {
+ material.setShininess(shininess);
+ }
+ return material;
+ }
+ return null;
+ }
+
+ public float getAmbientRed() {
+ return ambientRed;
+ }
+
+ public void setAmbientRed(final float ambientRed) {
+ this.ambientRed = ambientRed;
+ }
+
+ public float getAmbientGreen() {
+ return ambientGreen;
+ }
+
+ public void setAmbientGreen(final float ambientGreen) {
+ this.ambientGreen = ambientGreen;
+ }
+
+ public float getAmbientBlue() {
+ return ambientBlue;
+ }
+
+ public void setAmbientBlue(final float ambientBlue) {
+ this.ambientBlue = ambientBlue;
+ }
+
+ public float getDiffuseRed() {
+ return diffuseRed;
+ }
+
+ public void setDiffuseRed(final float diffuseRed) {
+ this.diffuseRed = diffuseRed;
+ }
+
+ public float getDiffuseGreen() {
+ return diffuseGreen;
+ }
+
+ public void setDiffuseGreen(final float diffuseGreen) {
+ this.diffuseGreen = diffuseGreen;
+ }
+
+ public float getDiffuseBlue() {
+ return diffuseBlue;
+ }
+
+ public void setDiffuseBlue(final float diffuseBlue) {
+ this.diffuseBlue = diffuseBlue;
+ }
+
+ public float getEmissiveRed() {
+ return emissiveRed;
+ }
+
+ public void setEmissiveRed(final float emissiveRed) {
+ this.emissiveRed = emissiveRed;
+ }
+
+ public float getEmissiveGreen() {
+ return emissiveGreen;
+ }
+
+ public void setEmissiveGreen(final float emissiveGreen) {
+ this.emissiveGreen = emissiveGreen;
+ }
+
+ public float getEmissiveBlue() {
+ return emissiveBlue;
+ }
+
+ public void setEmissiveBlue(final float emissiveBlue) {
+ this.emissiveBlue = emissiveBlue;
+ }
+
+ public float getSpecularRed() {
+ return specularRed;
+ }
+
+ public void setSpecularRed(final float specularRed) {
+ this.specularRed = specularRed;
+ }
+
+ public float getSpecularGreen() {
+ return specularGreen;
+ }
+
+ public void setSpecularGreen(final float specularGreen) {
+ this.specularGreen = specularGreen;
+ }
+
+ public float getSpecularBlue() {
+ return specularBlue;
+ }
+
+ public void setSpecularBlue(final float specularBlue) {
+ this.specularBlue = specularBlue;
+ }
+
+ public float getAmbientAlpha() {
+ return ambientAlpha;
+ }
+
+ public void setAmbientAlpha(final float ambientAlpha) {
+ this.ambientAlpha = ambientAlpha;
+ }
+
+ public float getDiffuseAlpha() {
+ return diffuseAlpha;
+ }
+
+ public void setDiffuseAlpha(final float diffuseAlpha) {
+ this.diffuseAlpha = diffuseAlpha;
+ }
+
+ public float getEmissiveAlpha() {
+ return emissiveAlpha;
+ }
+
+ public void setEmissiveAlpha(final float emissiveAlpha) {
+ this.emissiveAlpha = emissiveAlpha;
+ }
+
+ public float getSpecularAlpha() {
+ return specularAlpha;
+ }
+
+ public void setSpecularAlpha(final float specularAlpha) {
+ this.specularAlpha = specularAlpha;
+ }
+
+ public float getShininess() {
+ return shininess;
+ }
+
+ public void setShininess(final float shininess) {
+ this.shininess = shininess;
+ }
+
+ public boolean isForceBlend() {
+ return forceBlend;
+ }
+
+ public void setForceBlend(final boolean forceBlend) {
+ this.forceBlend = forceBlend;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/FileHelper.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/FileHelper.java
new file mode 100644
index 0000000..8a9c5cf
--- /dev/null
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/FileHelper.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2008-2016 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.util;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.StandardCharsets;
+
+import com.ardor3d.util.resource.ResourceSource;
+
+public class FileHelper {
+
+ /**
+ * Tests whether or not the specified string is pure ASCII. Uses the method discussed at:
+ *
+ * <pre>
+ * http://www.rgagnon.com/javadetails/java-0536.html
+ * http://stackoverflow.com/questions/3585053/in-java-is-it-possible-to-check-if-a-string-is-only-ascii
+ * </pre>
+ *
+ * @param string
+ * String to test.
+ * @return Logical-true if pure ASCII, else logical-false.
+ */
+ public boolean isStringPureAscii(final String string) {
+ final byte bytearray[] = string.getBytes();
+ final CharsetDecoder d = StandardCharsets.US_ASCII.newDecoder();
+ try {
+ final CharBuffer r = d.decode(ByteBuffer.wrap(bytearray));
+ r.toString();
+ } catch (final CharacterCodingException e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether or not the file with the specified filename is pure ASCII. The method used is to read the file a
+ * line at a time and test if each line is ASCII.
+ *
+ * @param filename
+ * File name.
+ * @return Logical-true if pure ASCII, else logical-false.
+ */
+ public boolean isFilePureAscii(final String filename) {
+ try (final FileInputStream fstream = new FileInputStream(filename);
+ final DataInputStream in = new DataInputStream(fstream);
+ final BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
+ String strLine;
+ // read file a line at a time
+ while ((strLine = br.readLine()) != null) {
+ final boolean isAscii = isStringPureAscii(strLine);
+ if (!isAscii) {
+ return false;
+ }
+ }
+ } catch (final Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether or not the file with the specified filename is pure ASCII. The method used is to read the file a
+ * line at a time and test if each line is ASCII.
+ *
+ * @param resource
+ * the name of the resource to find.
+ * @return Logical-true if pure ASCII, else logical-false.
+ */
+ public boolean isFilePureAscii(final ResourceSource resource) {
+ try (final InputStream inputStream = resource.openStream();
+ final DataInputStream in = new DataInputStream(inputStream);
+ final BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
+ String strLine;
+ // read file a line at a time
+ while ((strLine = br.readLine()) != null) {
+ final boolean isAscii = isStringPureAscii(strLine);
+ if (!isAscii) {
+ return false;
+ }
+ }
+ } catch (final Exception e) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/KeyframeController.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/KeyframeController.java
index 15c810a..e84db4f 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/KeyframeController.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/KeyframeController.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -127,7 +127,7 @@ public class KeyframeController<T extends Spatial> extends ComplexSpatialControl
*/
public KeyframeController() {
setSpeed(1);
- _keyframes = new ArrayList<PointInTime>();
+ _keyframes = new ArrayList<>();
_curFrame = 0;
setRepeatType(ComplexSpatialController.RepeatType.WRAP);
setMinTime(0);
@@ -245,7 +245,7 @@ public class KeyframeController<T extends Spatial> extends ComplexSpatialControl
}
Mesh begin = null, end = null;
if (_prevKeyframes == null) {
- _prevKeyframes = new ArrayList<PointInTime>();
+ _prevKeyframes = new ArrayList<>();
begin = new Mesh();
end = new Mesh();
} else {
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvEdgeInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvEdgeInfo.java
index ee49d56..9190145 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvEdgeInfo.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvEdgeInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvFaceInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvFaceInfo.java
index 688c73d..3f847ca 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvFaceInfo.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvFaceInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripInfo.java
index 2cf0e18..575cd87 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripInfo.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -10,13 +10,12 @@
package com.ardor3d.extension.model.util.nvtristrip;
+import java.util.ArrayList;
import java.util.List;
-import com.google.common.collect.Lists;
-
final class NvStripInfo {
NvStripStartInfo _startInfo;
- List<NvFaceInfo> _faces = Lists.newArrayList();
+ List<NvFaceInfo> _faces = new ArrayList<>();
int _stripId;
int _experimentId;
@@ -177,11 +176,11 @@ final class NvStripInfo {
*/
void build(final List<NvEdgeInfo> edgeInfos, final List<NvFaceInfo> faceInfos) {
// used in building the strips forward and backward
- final List<Integer> scratchIndices = Lists.newArrayList();
+ final List<Integer> scratchIndices = new ArrayList<>();
// build forward... start with the initial face
- final List<NvFaceInfo> forwardFaces = Lists.newArrayList();
- final List<NvFaceInfo> backwardFaces = Lists.newArrayList();
+ final List<NvFaceInfo> forwardFaces = new ArrayList<>();
+ final List<NvFaceInfo> backwardFaces = new ArrayList<>();
forwardFaces.add(_startInfo._startFace);
markTriangle(_startInfo._startFace);
@@ -251,7 +250,7 @@ final class NvStripInfo {
// tempAllFaces is going to be forwardFaces + backwardFaces
// it's used for Unique()
- final List<NvFaceInfo> tempAllFaces = Lists.newArrayList();
+ final List<NvFaceInfo> tempAllFaces = new ArrayList<>();
for (int i = 0; i < forwardFaces.size(); i++) {
tempAllFaces.add(forwardFaces.get(i));
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripStartInfo.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripStartInfo.java
index cecb0d3..7629d6d 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripStartInfo.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripStartInfo.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripifier.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripifier.java
index 8779e5e..fbdf921 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripifier.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvStripifier.java
@@ -1,22 +1,21 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * 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
+ * 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.util.nvtristrip;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
/**
* Ported from <a href="http://developer.nvidia.com/object/nvtristrip_library.html">NVIDIA's NvTriStrip Library</a>
*/
@@ -25,14 +24,14 @@ final class NvStripifier {
public static int CACHE_INEFFICIENCY = 6;
- protected List<Integer> _indices = Lists.newArrayList();
+ protected List<Integer> _indices = new ArrayList<>();
protected int _cacheSize;
protected int _minStripLength;
protected float _meshJump;
protected boolean _firstTimeResetPoint;
/**
- *
+ *
* @param in_indices
* the input indices of the mesh to stripify
* @param in_cacheSize
@@ -59,12 +58,12 @@ final class NvStripifier {
_indices = in_indices;
// build the stripification info
- final List<NvFaceInfo> allFaceInfos = Lists.newArrayList();
- final List<NvEdgeInfo> allEdgeInfos = Lists.newArrayList();
+ final List<NvFaceInfo> allFaceInfos = new ArrayList<>();
+ final List<NvEdgeInfo> allEdgeInfos = new ArrayList<>();
buildStripifyInfo(allFaceInfos, allEdgeInfos, maxIndex);
- final List<NvStripInfo> allStrips = Lists.newArrayList();
+ final List<NvStripInfo> allStrips = new ArrayList<>();
// stripify
findAllStrips(allStrips, allFaceInfos, allEdgeInfos, numSamples);
@@ -75,7 +74,7 @@ final class NvStripifier {
/**
* Generates actual strips from the list-in-strip-order.
- *
+ *
* @param allStrips
* @param stripIndices
* @param bStitchStrips
@@ -150,8 +149,8 @@ final class NvStripifier {
stripIndices.add(tFirstFace._v0);
// Check CW/CCW ordering
- if (NvStripifier.nextIsCW(stripIndices.size() - accountForNegatives) != NvStripifier.isCW(
- strip._faces.get(0), tFirstFace._v0, tFirstFace._v1)) {
+ if (NvStripifier.nextIsCW(stripIndices.size() - accountForNegatives) != NvStripifier
+ .isCW(strip._faces.get(0), tFirstFace._v0, tFirstFace._v1)) {
stripIndices.add(tFirstFace._v0);
}
}
@@ -325,7 +324,7 @@ final class NvStripifier {
}
/**
- *
+ *
* @param numIndices
* @return true if the next face should be ordered in CW fashion
*/
@@ -385,7 +384,7 @@ final class NvStripifier {
/**
* find the edge info for these two indices
- *
+ *
* @param edgeInfos
* @param v0
* @param v1
@@ -416,13 +415,14 @@ final class NvStripifier {
/**
* find the other face sharing these vertices
- *
+ *
* @param edgeInfos
* @param v0
* @param v1
* @param faceInfo
* @return
*/
+ @SuppressWarnings("null")
static NvFaceInfo findOtherFace(final List<NvEdgeInfo> edgeInfos, final int v0, final int v1,
final NvFaceInfo faceInfo) {
final NvEdgeInfo edgeInfo = NvStripifier.findEdgeInfo(edgeInfos, v0, v1);
@@ -439,7 +439,7 @@ final class NvStripifier {
/**
* A good reset point is one near other committed areas so that we know that when we've made the longest strips its
* because we're stripifying in the same general orientation.
- *
+ *
* @param faceInfos
* @param edgeInfos
* @return
@@ -494,11 +494,11 @@ final class NvStripifier {
/**
* Does the stripification, puts output strips into vector allStrips
- *
+ *
* Works by setting running a number of experiments in different areas of the mesh, and accepting the one which
* results in the longest strips. It then accepts this, and moves on to a different area of the mesh. We try to jump
* around the mesh some, to ensure that large open spans of strips get generated.
- *
+ *
* @param allStrips
* @param allFaceInfos
* @param allEdgeInfos
@@ -519,11 +519,11 @@ final class NvStripifier {
//
final List<NvStripInfo>[] experiments = new List[numSamples * 6];
for (int i = 0; i < experiments.length; i++) {
- experiments[i] = Lists.newArrayList();
+ experiments[i] = new ArrayList<>();
}
int experimentIndex = 0;
- final Set<NvFaceInfo> resetPoints = Sets.newHashSet();
+ final Set<NvFaceInfo> resetPoints = new HashSet<>();
for (int i = 0; i < numSamples; i++) {
// Try to find another good reset point.
@@ -641,7 +641,7 @@ final class NvStripifier {
/**
* Splits the input vector of strips (allBigStrips) into smaller, cache friendly pieces, then reorders these pieces
* to maximize cache hits. The final strips are stored in outStrips
- *
+ *
* @param allStrips
* @param outStrips
* @param edgeInfos
@@ -650,7 +650,7 @@ final class NvStripifier {
void splitUpStripsAndOptimize(final List<NvStripInfo> allStrips, final List<NvStripInfo> outStrips,
final List<NvEdgeInfo> edgeInfos, final List<NvFaceInfo> outFaceList) {
final int threshold = _cacheSize;
- final List<NvStripInfo> tempStrips = Lists.newArrayList();
+ final List<NvStripInfo> tempStrips = new ArrayList<>();
// split up strips into threshold-sized pieces
for (int i = 0; i < allStrips.size(); i++) {
@@ -681,9 +681,8 @@ final class NvStripifier {
degenerateCount++;
// last time or first time through, no need for a degenerate
- if ((faceCtr + 1 != threshold + j * threshold + degenerateCount || j == numTimes - 1
- && numLeftover < 4 && numLeftover > 0)
- && !bFirstTime) {
+ if ((faceCtr + 1 != threshold + j * threshold + degenerateCount
+ || j == numTimes - 1 && numLeftover < 4 && numLeftover > 0) && !bFirstTime) {
currentStrip._faces.add(allStripI._faces.get(faceCtr++));
} else {
++faceCtr;
@@ -747,7 +746,7 @@ final class NvStripifier {
}
// add small strips to face list
- final List<NvStripInfo> tempStrips2 = Lists.newArrayList();
+ final List<NvStripInfo> tempStrips2 = new ArrayList<>();
removeSmallStrips(tempStrips, tempStrips2, outFaceList);
outStrips.clear();
@@ -868,7 +867,7 @@ final class NvStripifier {
final List<NvFaceInfo> faceList) {
faceList.clear();
allBigStrips.clear(); // make sure these are empty
- final List<NvFaceInfo> tempFaceList = Lists.newArrayList();
+ final List<NvFaceInfo> tempFaceList = new ArrayList<>();
for (int i = 0; i < allStrips.size(); i++) {
final NvStripInfo allStripI = allStrips.get(i);
@@ -918,7 +917,7 @@ final class NvStripifier {
/**
* Finds the next face to start the next strip on.
- *
+ *
* @param faceInfos
* @param edgeInfos
* @param strip
@@ -962,7 +961,7 @@ final class NvStripifier {
/**
* "Commits" the input strips by setting their m_experimentId to -1 and adding to the allStrips vector
- *
+ *
* @param allStrips
* @param strips
*/
@@ -985,7 +984,7 @@ final class NvStripifier {
}
/**
- *
+ *
* @param strips
* @return the average strip size of the input vector of strips
*/
@@ -1000,7 +999,7 @@ final class NvStripifier {
/**
* Finds a good starting point, namely one which has only one neighbor
- *
+ *
* @param faceInfos
* @param edgeInfos
* @return
@@ -1038,7 +1037,7 @@ final class NvStripifier {
/**
* Updates the input vertex cache with this strip's vertices
- *
+ *
* @param vcache
* @param strip
*/
@@ -1050,7 +1049,7 @@ final class NvStripifier {
/**
* Updates the input vertex cache with this face's vertices
- *
+ *
* @param vcache
* @param face
*/
@@ -1120,7 +1119,7 @@ final class NvStripifier {
}
/**
- *
+ *
* @param face
* @param edgeInfoVec
* @return the number of neighbors that this face has
@@ -1145,7 +1144,7 @@ final class NvStripifier {
/**
* Builds the list of all face and edge infos
- *
+ *
* @param faceInfos
* @param edgeInfos
* @param maxIndex
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvTriangleStripper.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvTriangleStripper.java
index c12d86d..71f8870 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvTriangleStripper.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/NvTriangleStripper.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -10,6 +10,7 @@
package com.ardor3d.extension.model.util.nvtristrip;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@@ -22,7 +23,6 @@ import com.ardor3d.scenegraph.MeshData;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.scenegraph.visitor.Visitor;
import com.ardor3d.util.geom.BufferUtils;
-import com.google.common.collect.Lists;
/**
* Ported from <a href="http://developer.nvidia.com/object/nvtristrip_library.html">NVIDIA's NvTriStrip Library</a>
@@ -241,7 +241,7 @@ public class NvTriangleStripper implements Visitor {
PrimitiveGroup[] primGroups;
// put data in format that the stripifier likes
- final List<Integer> tempIndices = Lists.newArrayList();
+ final List<Integer> tempIndices = new ArrayList<>();
int maxIndex = 0;
for (int i = 0; i < in_indices.length; i++) {
tempIndices.add(in_indices[i]);
@@ -249,8 +249,8 @@ public class NvTriangleStripper implements Visitor {
maxIndex = in_indices[i];
}
}
- final List<NvStripInfo> tempStrips = Lists.newArrayList();
- final List<NvFaceInfo> tempFaces = Lists.newArrayList();
+ final List<NvStripInfo> tempStrips = new ArrayList<>();
+ final List<NvFaceInfo> tempFaces = new ArrayList<>();
final NvStripifier stripifier = new NvStripifier();
@@ -258,7 +258,7 @@ public class NvTriangleStripper implements Visitor {
stripifier.stripify(tempIndices, _cacheSize, _minStripSize, maxIndex, tempStrips, tempFaces);
// stitch strips together
- final List<Integer> stripIndices = Lists.newArrayList();
+ final List<Integer> stripIndices = new ArrayList<>();
int numSeparateStrips = 0;
if (_listsOnly) {
@@ -374,7 +374,7 @@ public class NvTriangleStripper implements Visitor {
final List<NvFaceInfo> in_bins[] = new List[NUMBINS];
for (int i = 0; i < NUMBINS; i++) {
- in_bins[i] = Lists.newArrayList();
+ in_bins[i] = new ArrayList<>();
}
// hash input indices on first index
@@ -525,7 +525,7 @@ public class NvTriangleStripper implements Visitor {
PrimitiveGroup[] strips = generateStrips(indices, false);
if (_reorderVertices) {
- final AtomicReference<int[]> newOrder = new AtomicReference<int[]>();
+ final AtomicReference<int[]> newOrder = new AtomicReference<>();
strips = remapIndices(strips, newOrder, md.getVertexCount());
// ask mesh to apply new vertex order
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/PrimitiveGroup.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/PrimitiveGroup.java
index 4ba92c2..1886f11 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/PrimitiveGroup.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/PrimitiveGroup.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/VertexCache.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/VertexCache.java
index ba93840..ae3a7ef 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/VertexCache.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/model/util/nvtristrip/VertexCache.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/useful/TrailMesh.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/useful/TrailMesh.java
index 558d9fb..da73655 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/useful/TrailMesh.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/useful/TrailMesh.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ * Copyright (c) 2008-2014 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
@@ -90,7 +90,7 @@ public class TrailMesh extends Mesh {
this.nrTrailSections = nrTrailSections;
trailVertices = nrTrailSections * 2;
- trailVectors = new LinkedList<TrailData>();
+ trailVectors = new LinkedList<>();
for (int i = 0; i < nrTrailSections; i++) {
trailVectors.add(new TrailData());
}