📄 objtojme.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.
*/
package com.jmex.model.converters;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.logging.Logger;
import com.jme.bounding.BoundingBox;
import com.jme.image.Image;
import com.jme.image.Texture;
import com.jme.image.Texture2D;
import com.jme.math.Vector2f;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.TexCoords;
import com.jme.scene.TriMesh;
import com.jme.scene.state.BlendState;
import com.jme.scene.state.MaterialState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.system.dummy.DummySystemProvider;
import com.jme.util.TextureKey;
import com.jme.util.TextureManager;
import com.jme.util.export.binary.BinaryExporter;
import com.jme.util.geom.BufferUtils;
import com.jme.util.geom.GeometryTool;
/**
* Started Date: Jul 17, 2004<br>
* <br>
* Converts .obj files into .jme binary format. In order for ObjToJme to find
* the .mtl library, you must specify the "mtllib" tag to the baseURL where the
* mtl libraries are to be found: eg.
* setProperty("mtllib",new File("c:/my material dir/").toURL());
*
* Textures will be loaded from the directory indicated in the model unless you
* specify a directory to load them from via setting a property: eg.
* setProperty("texdir", new File("c:/my texdir/").toURL());
*
* @author Jack Lindamood
* @author Joshua Slack - revamped to improve speed
*/
public class ObjToJme extends FormatConverter {
private static final Logger logger = Logger.getLogger(ObjToJme.class
.getName());
private BufferedReader inFile;
/** Every vertex in the file */
private ArrayList<Vector3f> vertexList = new ArrayList<Vector3f>();
/** Every texture coordinate in the file */
private ArrayList<Vector2f> textureList = new ArrayList<Vector2f>();
/** Every normal in the file */
private ArrayList<Vector3f> normalList = new ArrayList<Vector3f>();
/** Generated normals */
private ArrayList<Vector3f> genNormalList = new ArrayList<Vector3f>();
/** Last 'material' flag in the file */
private MaterialGrouping curGroup;
/** Last 'Object' name in the file */
private String curObjectName = null;
/** Last 'Group' name in the file */
private String curGroupName = null;
/** Default material group for groups without a material */
private MaterialGrouping defaultMaterialGroup;
/** Maps material names to the actual material object * */
private HashMap<String, MaterialGrouping> materialNames = new HashMap<String, MaterialGrouping>();
/** Maps Materials to their vertex usage * */
private HashMap<MaterialGrouping, ArraySet> materialSets = new HashMap<MaterialGrouping, ArraySet>();
/** Reference to the renderer for creating RenderState objects **/
private Renderer renderer;
private boolean generateMissingNormals = true;
/**
* Converts an Obj file to jME format. The syntax is: "ObjToJme file.obj
* outfile.jme".
*
* @param args
* The array of parameters
*/
public static void main(String[] args) {
DisplaySystem.getDisplaySystem(DummySystemProvider.DUMMY_SYSTEM_IDENTIFIER);
new ObjToJme().attemptFileConvert(args);
}
/**
* Converts an .obj file to .jme format. If you wish to use a .mtl to load
* the obj's material information please specify the base url where the .mtl
* is located with setProperty("mtllib",new URL(baseURL))
*
* @param format
* The .obj file's stream.
* @param jMEFormat
* The .jme file's stream.
* @throws IOException
* If anything bad happens.
*/
@Override
public void convert(InputStream format, OutputStream jMEFormat)
throws IOException {
renderer = DisplaySystem.getDisplaySystem().getRenderer();
defaultMaterialGroup = new MaterialGrouping();
vertexList.clear();
textureList.clear();
normalList.clear();
genNormalList.clear();
materialSets.clear();
materialNames.clear();
inFile = new BufferedReader(new InputStreamReader(format));
String in;
curGroup = defaultMaterialGroup;
materialSets.put(defaultMaterialGroup, new ArraySet());
while ((in = inFile.readLine()) != null) {
processLine(in);
}
BinaryExporter.getInstance().save(buildStructure(),jMEFormat);
nullAll();
}
/**
* Nulls all to let the gc do its job.
*
* @throws IOException
*/
private void nullAll() throws IOException {
vertexList.clear();
textureList.clear();
normalList.clear();
genNormalList.clear();
curGroup = null;
materialSets.clear();
materialNames.clear();
inFile.close();
inFile = null;
defaultMaterialGroup = null;
renderer = null;
}
/**
* Converts the structures of the .obj file to a scene to write
*
* @return The TriMesh or Node that represents the .obj file.
*/
private Spatial buildStructure() {
Node toReturn = new Node("obj file");
Object[] o = materialSets.keySet().toArray();
for (int i = 0; i < o.length; i++) {
MaterialGrouping thisGroup = (MaterialGrouping) o[i];
ArraySet thisSet = materialSets.get(thisGroup);
if (thisSet.indexes.size() < 3)
continue;
TriMesh thisMesh = new TriMesh(thisSet.objName == null ? "temp" + i : thisSet.objName);
Vector3f[] vert = new Vector3f[thisSet.sets.size()];
Vector3f[] norm = new Vector3f[vert.length];
Vector2f[] text = new Vector2f[vert.length];
boolean hasNorm = false, hasTex = false;
int j = 0;
for (IndexSet set : thisSet.sets) {
vert[j] = vertexList.get(set.vIndex);
if (set.nIndex >= 0) {
norm[j] = normalList.get(set.nIndex);
hasNorm = true;
} else if (set.nIndex < -1) {
norm[j] = genNormalList.get((-1*set.nIndex)-2);
hasNorm = true;
}
if (set.tIndex >= 0) {
text[j] = textureList.get(set.tIndex);
hasTex = true;
}
j++;
}
int[] indexes = new int[thisSet.indexes.size()];
for (j = 0; j < thisSet.indexes.size(); j++)
indexes[j] = thisSet.indexes.get(j);
thisMesh.reconstruct(BufferUtils.createFloatBuffer(vert),
hasNorm ? BufferUtils.createFloatBuffer(norm) : null,
null,
hasTex ? TexCoords.makeNew(text) : null,
BufferUtils.createIntBuffer(indexes));
if (properties.get("sillycolors") != null)
thisMesh.setRandomColors();
if (thisGroup.ts != null)
thisMesh.setRenderState(thisGroup.ts);
thisMesh.setRenderState(thisGroup.m);
if (thisGroup.as != null) {
thisMesh.setRenderState(thisGroup.as);
thisMesh.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);
}
thisMesh.setModelBound(new BoundingBox());
thisMesh.updateModelBound();
GeometryTool.minimizeVerts(thisMesh, GeometryTool.MV_SAME_COLORS | GeometryTool.MV_SAME_NORMALS | GeometryTool.MV_SAME_TEXS);
toReturn.attachChild(thisMesh);
}
if (toReturn.getQuantity() == 1)
return toReturn.getChild(0);
return toReturn;
}
/**
* Processes a line of text in the .obj file.
*
* @param s
* The line of text in the file.
* @throws IOException
*/
private void processLine(String s) throws IOException {
if (s == null)
return;
if (s.length() == 0)
return;
String[] parts = s.split("\\s+");
parts = removeEmpty(parts);
if (parts.length == 0) return;
if (parts[0].charAt(0) == '#')
return;
if ("v".equals(parts[0])) {
addVertextoList(parts);
return;
} else if ("vt".equals(parts[0])) {
addTextoList(parts);
return;
} else if ("vn".equals(parts[0])) {
addNormalToList(parts);
return;
} else if ("g".equals(parts[0])) {
// see what the material name is if there isn't a name, assume its
// the default group
if (parts.length >= 2 && materialNames.get(parts[1]) != null) {
curGroupName = parts[1];
curGroup = materialNames.get(parts[1]);
}
else
setDefaultGroup();
return;
} else if ("f".equals(parts[0])) {
addFaces(parts);
return;
} else if ("mtllib".equals(parts[0])) {
loadMaterials(parts);
return;
} else if ("newmtl".equals(parts[0])) {
addMaterial(parts);
return;
} else if ("usemtl".equals(parts[0])) {
if (materialNames.get(parts[1]) != null)
curGroup = materialNames.get(parts[1]);
else
setDefaultGroup();
return;
} else if ("Ka".equals(parts[0])) {
curGroup.m.setAmbient(new ColorRGBA(Float.parseFloat(parts[1]),
Float.parseFloat(parts[2]), Float.parseFloat(parts[3]), 1));
return;
} else if ("Kd".equals(parts[0])) {
curGroup.m.setDiffuse(new ColorRGBA(Float.parseFloat(parts[1]),
Float.parseFloat(parts[2]), Float.parseFloat(parts[3]), 1));
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -