⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x3dtojme.java

📁 java 3d game jme 工程开发源代码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * 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 + -