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

📄 md2tojme.java

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

package com.jmex.model.converters;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;

import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.TexCoords;
import com.jme.scene.TriMesh;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.system.dummy.DummySystemProvider;
import com.jme.util.BinaryFileReader;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.geom.BufferUtils;
import com.jmex.model.animation.KeyframeController;

/**
 * Started Date: Jun 14, 2004<br>
 * <br>
 * This class converts a .md2 file to jME's binary format.
 * 
 * @author Jack Lindamood
 */
public class Md2ToJme extends FormatConverter {
    
    private static final Logger logger = Logger.getLogger(Md2ToJme.class
            .getName());

    /**
     * Converts an Md2 file to jME format. The syntax is: "Md2ToJme drfreak.md2
     * outfile.jme".
     * 
     * @param args
     *            The array of parameters
     */
    public static void main(String[] args) {
    	DisplaySystem.getDisplaySystem(DummySystemProvider.DUMMY_SYSTEM_IDENTIFIER);
        new Md2ToJme().attemptFileConvert(args);
    }

    /**
     * It creates a node from a .md2 stream and then writes that node to the
     * given OutputStream in jME's binary format.
     * 
     * @param Md2Stream
     *            A stream representing the .md2 file
     * @param o
     *            The stream to write it's binary equivalent to
     * @throws java.io.IOException
     *             If anything funky goes wrong with reading information
     */
    public void convert(InputStream Md2Stream, OutputStream o)
            throws IOException {
        if (Md2Stream == null)
            throw new NullPointerException("Unable to load null streams");
        Md2ConverterCopy mcc = new Md2ConverterCopy(Md2Stream);
        Node newnode = new Node(mcc.mesh.getName());
        newnode.attachChild(mcc.mesh);
        BinaryExporter.getInstance().save(newnode, o);
    }

    /**
     * 95% a Copy/paste of the .md2 loader by Mark Powell modifyed for
     * efficiency (use of empty TriMesh) and VertexController as well as a few
     * tiny adjustments here and there on memory.
     * 
     * @author Mark Powell
     * @author Jack Lindamood
     */
    private static class Md2ConverterCopy {
        private static final long serialVersionUID = 1L;

        private BinaryFileReader bis = null;

        private Header header;

        private Vector2f[] texCoords;
        private Md2Face[] triangles;
        private Md2Frame[] frames;

        // holds each keyframe.
        private TriMesh[] triMesh;
        // controller responsible for handling keyframe morphing.
        private KeyframeController controller;

        public TriMesh mesh;

        /**
         * Loads an MD2 model. The corresponding <code>TriMesh</code> objects
         * are created and attached to the model. Each keyframe is then loaded
         * and assigned to a <code>KeyframeController</code>. MD2 does not
         * keep track of it's own texture or material settings, so the user is
         * responsible for setting these.
         * 
         * @param input
         *            the InputStream of the file to load.
         */
        public Md2ConverterCopy(InputStream input) {

            if (null == input) {
                throw new JmeException("Null data. Cannot load.");
            }

            mesh = new TriMesh("MD2 mesh" + new Random().nextInt());

            bis = new BinaryFileReader(input);

            header = new Header();

            if (header.version != 8) {
                throw new JmeException("Invalid file format (Version not 8)!");
            }

            parseMesh();
            convertDataStructures();

            triangles = null;
            texCoords = null;
            frames = null;
        }

        /**
         * <code>getAnimationController</code> returns the animation
         * controller used for MD2 animation (VertexKeyframeController).
         * 
         * @return
         * @see com.jmex.model.Model#getAnimationController()
         */
        public Controller getAnimationController() {
            return controller;
        }

        /**
         * <code>parseMesh</code> reads the MD2 file and builds the necessary
         * data structures. These structures are specific to MD2 and therefore
         * require later conversion to jME data structures.
         */
        private void parseMesh() {
            String[] skins = new String[header.numSkins];
            texCoords = new Vector2f[header.numTexCoords];
            triangles = new Md2Face[header.numTriangles];
            frames = new Md2Frame[header.numFrames];

            // start with skins. Move the file pointer to the correct position.
            bis.setOffset(header.offsetSkins);

            // Read in each skin for this model
            for (int j = 0; j < header.numSkins; j++) {
                skins[j] = bis.readString(64);
            }

            // Now read in texture coordinates.
            bis.setOffset(header.offsetTexCoords);
            for (int j = 0; j < header.numTexCoords; j++) {
                texCoords[j] = new Vector2f();
                texCoords[j].x = (float) bis.readShort();
                texCoords[j].y = (float) bis.readShort();
            }

            // read the vertex data.
            bis.setOffset(header.offsetTriangles);
            for (int j = 0; j < header.numTriangles; j++) {
                triangles[j] = new Md2Face();
            }

            bis.setOffset(header.offsetFrames);
            // Each keyframe has the same type of data, so read each
            // keyframe one at a time.
            for (int i = 0; i < header.numFrames; i++) {
                VectorKeyframe frame = new VectorKeyframe();
                frames[i] = new Md2Frame();

                frames[i].vertices = new Triangle[header.numVertices];
                Vector3f[] aliasVertices = new Vector3f[header.numVertices];
                int[] aliasLightNormals = new int[header.numVertices];

                // Read in the first frame of animation
                for (int j = 0; j < header.numVertices; j++) {
                    aliasVertices[j] = new Vector3f(bis.readByte(), bis
                            .readByte(), bis.readByte());
                    aliasLightNormals[j] = bis.readByte();
                }

                // Copy the name of the animation to our frames array
                frames[i].name = frame.name;
                Triangle[] verices = frames[i].vertices;

                for (int j = 0; j < header.numVertices; j++) {
                    verices[j] = new Triangle();
                    verices[j].vertex.x = aliasVertices[j].x * frame.scale.x
                            + frame.translate.x;
                    verices[j].vertex.z = -1
                            * (aliasVertices[j].y * frame.scale.y + frame.translate.y);
                    verices[j].vertex.y = aliasVertices[j].z * frame.scale.z
                            + frame.translate.z;

                    if (aliasLightNormals[j] < norms.length) {
                        verices[j].normal.x = norms[aliasLightNormals[j]][0];
                        verices[j].normal.y = norms[aliasLightNormals[j]][2];
                        verices[j].normal.z = -norms[aliasLightNormals[j]][1];
                    } else {
                        verices[j].normal.set(0, 1, 0); // DEFAULT?
                        logger.warning("Referenced an invalid normal: "+aliasLightNormals[j]);
                    }
                }
            }

            // TODO: Read OPENGL commands here...
            bis.setOffset(header.offsetGlCommands);

        }

        private static class VectorTex {
            private VectorTex(final int vIndex, final int tIndex) {
                v = vIndex;
                t = tIndex;
            }

            public boolean equals(final Object o) {
                if (this == o)
                    return true;
                if (o == null || getClass() != o.getClass())
                    return false;

                final VectorTex that = (VectorTex) o;

                if (t != that.t)
                    return false;
                if (v != that.v)
                    return false;

                return true;
            }

            public int hashCode() {
                int l_result;
                l_result = v;
                l_result = 31 * l_result + t;
                return l_result;
            }

            int v;
            int t;

            public boolean matches(final Md2Face face, final int faceVert) {
                return face.vertexIndices[faceVert] == v
                        && face.textureIndices[faceVert] == t;
            }
        }

        /**
         * <code>convertDataStructures</code> takes the loaded MD2 data and
         * converts it into jME data.
         */
        private void convertDataStructures() {
            triMesh = new TriMesh[header.numFrames];
            List<VectorTex> vectorTexcoords = new ArrayList<VectorTex>();
            controller = new KeyframeController();
            for (int i = 0; i < header.numFrames; i++) {
                int numOfVerts = header.numVertices;
                int numTexVertex = header.numTexCoords;
                if (i != 0)
                    triMesh[i] = new TriMesh();
                else
                    triMesh[i] = mesh;
                Vector3f[] uniqueVerts = new Vector3f[numOfVerts];
                Vector3f[] uniqueNorms = new Vector3f[numOfVerts];
                Vector2f[] texVerts = new Vector2f[numTexVertex];

                // assign a vector array for the trimesh.
                for (int j = 0; j < numOfVerts; j++) {
                    if (i != 0) {
                        uniqueVerts[j] = frames[i].vertices[j].vertex;
                        uniqueNorms[j] = frames[i].vertices[j].normal;
                    } else {
                        uniqueVerts[j] = new Vector3f(
                                frames[i].vertices[j].vertex);
                        uniqueNorms[j] = new Vector3f(
                                frames[i].vertices[j].normal);
                    }
                }

                if (i == 0) {
                    // texture coordinates.
                    for (int j = 0; j < numTexVertex; j++) {
                        texVerts[j] = new Vector2f();
                        texVerts[j].x = texCoords[j].x / (header.skinWidth);
                        texVerts[j].y = 1 - texCoords[j].y
                                / (header.skinHeight);
                    }

                    // collect all used combinations of vertices and texcoords
                    if (numTexVertex != 0) {
                        for (int j = 0; j < header.numTriangles; j++) {
                            for (int k = 0; k < 3; k++) {
                                final VectorTex l_tex = new VectorTex(
                                        triangles[j].vertexIndices[k],
                                        triangles[j].textureIndices[k]);
                                if (!vectorTexcoords.contains(l_tex)) {
                                    vectorTexcoords.add(l_tex);
                                }
                            }
                        }
                    }
                    // build indices
                    List<Integer> indices = new ArrayList<Integer>();
                    for (int j = 0; j < header.numTriangles; j++) {
                        for (int k = 0; k < 3; k++) {
                            for (int i1 = 0; i1 < vectorTexcoords.size(); i1++) {
                                VectorTex vectorTexcoord = vectorTexcoords
                                        .get(i1);
                                if (vectorTexcoord.matches(triangles[j], k)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -