📄 x3dtojme.java
字号:
/*
* Copyright (c) 2003-2009 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* X3D model file loader for jMonkeyEngine (http://www.jmonkeyengine.com),
* written by Michael Sattler.
* This loader is supposed to support as many of X3D's features as possible,
* but currently only a subset of the features that could be implemented in jME
* is supported. Thus, you are encouraged to extend this loader at will to be
* able to use more features. All I'm asking is two things: 1) A little credit ;)
* And 2) Please stick to Sun's code conventions when editing this class
* (http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html).
*/
package com.jmex.model.converters;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import com.jme.bounding.BoundingBox;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.image.Texture2D;
import com.jme.light.DirectionalLight;
import com.jme.light.Light;
import com.jme.light.PointLight;
import com.jme.light.SimpleLightNode;
import com.jme.light.SpotLight;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Geometry;
import com.jme.scene.Line;
import com.jme.scene.Spatial;
import com.jme.scene.SwitchNode;
import com.jme.scene.TexCoords;
import com.jme.scene.TriMesh;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Cone;
import com.jme.scene.shape.Cylinder;
import com.jme.scene.shape.Disk;
import com.jme.scene.shape.Sphere;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.CullState;
import com.jme.scene.state.LightState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.BumpMapColorController;
import com.jme.util.CloneImportExport;
import com.jme.util.TextureKey;
import com.jme.util.TextureManager;
import com.jme.util.export.Savable;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.geom.BufferUtils;
import com.jme.util.geom.NonIndexedNormalGenerator;
import com.jme.util.geom.NormalGenerator;
/**
* A Loader class to load models from XML-encoded X3D files (see <a
* href="http://www.web3d.org/x3d/specifications/ISO-IEC-19775-X3DAbstractSpecification/X3D.html">this
* link</a> for the specification) into jME.<br />
* <br />
* This Loader is designed to be able to load the geometry and lights contained
* in an X3D file and set the necessary properties to properly set up a model
* for jME. It uses as many of the features of X3D as possible.<br />
* <br />
* X3D is based on the ISO standard VRML97 (see <a
* href="http://www.web3d.org/x3d/specifications/vrml/ISO-IEC-14772-VRML97/">the
* ISO specification</a>), which was originally created as a language for
* describing interactive 3D scenes. The goal of X3D was to split up the VRML
* functionality into several Components (e.g. a Core Component, the Grouping
* Component, the Geometry3D Component, the Texturing Component, and so on). The
* Components are grouped into Profiles, which can be used to tell the X3D
* browser which set of Components to load (e.g. the Interchange Profile, which
* is used for basic geometry, the Immersive Profile, which supports more
* geometry features and additionally interaction functionality, and so on).<br />
* However, this loader is NOT designed to support certain Profiles or
* Components. Instead it tries to load all the features that can be realized in
* jME.<br />
* <br />
* The loader currently supports the following functions and X3D Elements:
* <ul>
* <li>Grouping (<i>Group</i>, <i>StaticGroup</i>, <i>Switch</i>,
* <i>Transform</i>) and definition of bounding boxes for groups. In
* <i>Transform</i>, the use of the <i>center</i> and <i>scaleOrientation</i>
* attributes is NOT supported</li>
* <li>3D solid geometry (<i>Box</i>, <i>Cone</i>, <i>Cylinder</i>,
* <i>Sphere</i>, <i>IndexedFaceSet</i>). In <i>Cylinder</i>, the attributes
* <i>side</i>, <i>bottom</i> and <i>top</i> are currently not fully
* supported: If either <i>bottom</i> or <i>top</i> is <code>false</code>,
* the bottom AND top of the cylinder are removed; <i>side</i> is ignored
* altogether.</li>
* <li>Line geometry (<i>LineSet</i>)</li>
* <li>Appearance properties (<i>Shape</i>, <i>Appearance</i>, <i>Material</i>)
* and bounding boxes for shapes</li>
* <li>Texturing of geometry (<i>ImageTexture</i>, <i>MultiTexture</i>). The
* use of <i>MultiTextureCoordinate</i> to specify different tex coords for the
* textures of a <i>MultiTexture</i> is currently not supported; not sure if
* this feature can be implemented in the future</li>
* <li>Lights (<i>DirectionalLight</i>, <i>PointLight</i> and <i>SpotLight</i>).
* <i>DirectionalLight</i> lights the whole scene instead of just its sibling
* nodes in the scenegraph. For <i>PointLight</i> the attribute <i>radius</i>
* is not supported. For <i>SpotLight</i> the attributes <i>radius</i> and
* <i>beamWidth</i> are not supported. </li>
* </ul>
* <br />
* The fields <i>DEF</i> and <i>USE</i> are actually supported too, but there
* is one limitation with the USE of Objects with bump maps: The
* BumpMapColorController attached to bumpmapped objects is not cloned by
* CloneImportExport. When you try to re-USE a bumpmapped Appearance for a
* different object, you can add a BumpMapColorController yourself to fix this
* issue. This also applies to the method
* {@link #convert(InputStream, OutputStream)}: As this method uses a binary
* exporter to write the parsed scene to the output stream, the
* BumpMapColorController gets lost here too, so you have to set it again in
* order to display the bump maps properly. <br />
*
* @version 2008-03-11
* @author Michael Sattler
* @author Stephen Larson (LineSet, some bugfixes)
*/
public class X3dToJme extends FormatConverter {
private static final Logger logger = Logger.getLogger(X3dToJme.class
.getName());
/**
* A regular expression that can be used in String's split-method. It causes
* the method to split at any sequence of spaces, linefeeds or carriage
* returns or a combination.
*/
private static final String WHITESPACE_REGEX = "\\s+";
/**
* A regular expression that can be used in String's split-method. It causes
* the method to split at any sequence of whitespace characters (see
* <code>WHITESPACE_REGEX</code> or a comma (either with whitespaces or
* not).
*/
private static final String WHITESPACE_COMMA_REGEX = "(\\s*,\\s*)|\\s+";
/** A List of all X3D scene node types this loader understands. */
private static final String[] SCENE_NODE_TYPES = { "Group", "StaticGroup",
"Transform", "Switch", "Shape", "DirectionalLight", "PointLight",
"SpotLight" };
/**
* A list of geometry node types this loader understands. The most
* frequently used types are at the beginning of the array for performance
* reasons.
*/
private static final String[] GEOMETRY_TYPES = { "Box", "IndexedFaceSet",
"Sphere", "Cylinder", "Cone", "LineSet" };
/** The default number of samples used for jME Spheres along the Z axis */
private static final int SPHERE_Z_SAMPLES = 16;
/** The default number of radial samples used for jME Spheres */
private static final int SPHERE_RADIAL_SAMPLES = 16;
/** The default number of samples used for jME Cylinders along the axis */
private static final int CYLINDER_AXIS_SAMPLES = 2;
/** The default number of radial samples used for jME Cylinders */
private static final int CYLINDER_RADIAL_SAMPLES = 20;
private DocumentBuilder documentBuilder;
/**
* Stores Objects ((arrays of) byte arrays) defined in the X3D file using
* DEF
*/
private Hashtable<String, Object> defs = new Hashtable<String, Object>();
/**
* Maps the paths of texture files to the InputStreams holding the texture
* data
*/
private Map<String, InputStream> texData;
/** The LightState all Lights in the scene are attached to */
private LightState lightState;
/**
* A normal generator used to generate the normals for IndexedFaceSets that
* do not define normals themselves.
*/
private NormalGenerator normalGenerator = new NormalGenerator();
/**
* A normal generator used to generate the normals for IndexedFaceSets that
* do not define normals themselves but use normal, color or texCoord
* indices.
*/
private NonIndexedNormalGenerator nonIndexedNormalGenerator = new NonIndexedNormalGenerator();
/**
* Indicates whether the shape currently processed contains a Bump Map
* Texture and therefore the Geometry needs a BumpMapColorController
*/
private boolean createBumpController = false;
/**
* Indicates whether the appearance attributes for the currently processed
* geometry contain transparency and therefore the geometry has to be added
* to the transparency render queue
*/
private boolean addToTransparentQueue = false;
/**
* Creates the X3DLoader.
*
* @throws InstantiationException
* In case the XML DocumentBuilder cannot be instantiated
*/
public X3dToJme() throws InstantiationException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
documentBuilder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new InstantiationException("X3DLoader creation failed: "
+ "Unable to instantiate XML DocumentBuilder!");
}
}
/**
* Passes an <code>EntityResolver</code> to the
* <code>DocumentBuilder</code> used to parse the X3D files' XML
* structure. Using a resolver can save a lot of time when parsing X3D
* files, because usually an HTTP connection to the Web3D.org server is
* opened to get the DTD files for X3D. If you specify a resolver, you can
* provide the DTDs on the local file system, for example.<br />
* For details on how an EntityResolver works, please refer to the J2SE API
* documentation.<br />
* The utility class <code>X3DResolver</code> can be used to provide a
* mapping of the file names to <code>InputStreams</code> containing the
* files; see the documentation there.<br />
* The DTDs usually needed for X3D parsing are:
* <ul>
* <li>x3d-3.0.dtd</li>
* <li>x3d-3.0-InputOutputFields.dtd</li>
* <li>x3d-3.0-Web3dExtensionsPrivate.dtd</li>
* <li>x3d-3.0-Web3dExtensionsPublic.dtd</li>
* </ul>
*
* @param resolver
* An <code>EntityResolver</code> to resolve the DTD references
* for X3D
*/
public void setDTDResolver(EntityResolver resolver) {
documentBuilder.setEntityResolver(resolver);
}
/**
* Converts the .x3d file read from the specified InputStream to the .jme
* format and writes it to the specified OutputStream. If the model contains
* any textures, please specify the folder containing the textures with
* <code>setProperty("textures", new URL(folder))</code>. If you use this
* method instead of {@link #loadScene(InputStream, Map, LightState)}, any
* lights in the scene will always be attached to a LightState at the root
* of this scene, thus only lighting the X3D scene itself and not the scene
* containing it. Additionally, any <code>BumpMapColorController</code>s
* created while loading the model will get lost in the exporting process,
* so if the model contains any bump maps, the controller has to be set
* manually when the exported model is being re-imported.
*
* @param in
* The InputStream to read the .x3d file from
* @param jmeOut
* The OutputStream to write the .jme model to
* @throws IOException
* If an error occurs
*/
@Override
public void convert(InputStream in, OutputStream jmeOut) throws IOException {
try {
Spatial scene = loadScene(in, null, null);
BinaryExporter.getInstance().save(scene, jmeOut);
} catch (Exception e) {
logger.info("Unable to load file: " + e.getMessage());
e.printStackTrace();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -