com.jme3.scene.plugins.ogre.MeshLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jme3-plugins Show documentation
Show all versions of jme3-plugins Show documentation
jMonkeyEngine is a 3-D game engine for adventurous Java developers
/*
* Copyright (c) 2009-2021 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.jme3.scene.plugins.ogre;
import com.jme3.anim.*;
import com.jme3.asset.*;
import com.jme3.material.Material;
import com.jme3.material.MaterialList;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.*;
import com.jme3.scene.VertexBuffer.*;
import com.jme3.scene.plugins.ogre.matext.OgreMaterialKey;
import com.jme3.util.*;
import com.jme3.util.IntMap.Entry;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.jme3.util.xml.SAXUtil.*;
/**
* Loads Ogre3D mesh.xml files.
*/
public class MeshLoader extends DefaultHandler implements AssetLoader {
private static final Logger logger = Logger.getLogger(MeshLoader.class.getName());
public static boolean AUTO_INTERLEAVE = true;
private static final Type[] TEXCOORD_TYPES =
new Type[]{
Type.TexCoord,
Type.TexCoord2,
Type.TexCoord3,
Type.TexCoord4,
Type.TexCoord5,
Type.TexCoord6,
Type.TexCoord7,
Type.TexCoord8,};
private AssetKey key;
private String meshName;
private String folderName;
private AssetManager assetManager;
private MaterialList materialList;
// Data per submesh/sharedgeom
private ShortBuffer sb;
private IntBuffer ib;
private FloatBuffer fb;
private VertexBuffer vb;
private Mesh mesh;
private Geometry geom;
private ByteBuffer indicesData;
private FloatBuffer weightsFloatData;
private boolean actuallyHasWeights = false;
private int vertCount;
private boolean usesSharedVerts;
private boolean usesBigIndices;
private boolean submeshNamesHack;
// Global data
private Mesh sharedMesh;
private int meshIndex = 0;
private int texCoordIndex = 0;
private String ignoreUntilEnd = null;
private List geoms = new ArrayList<>();
private ArrayList usesSharedMesh = new ArrayList<>();
private IntMap> lodLevels = new IntMap<>();
private AnimData animData;
public MeshLoader() {
super();
}
@Override
public void startDocument() {
geoms.clear();
lodLevels.clear();
sb = null;
ib = null;
fb = null;
vb = null;
mesh = null;
geom = null;
sharedMesh = null;
usesSharedMesh.clear();
usesSharedVerts = false;
vertCount = 0;
meshIndex = 0;
texCoordIndex = 0;
ignoreUntilEnd = null;
animData = null;
actuallyHasWeights = false;
submeshNamesHack = false;
indicesData = null;
weightsFloatData = null;
}
@Override
public void endDocument() {
}
private void pushIndex(int index) {
if (ib != null) {
ib.put(index);
} else {
sb.put((short) index);
}
}
private void pushFace(String v1, String v2, String v3) throws SAXException {
// TODO: fan/strip support
switch (mesh.getMode()) {
case Triangles:
pushIndex(parseInt(v1));
pushIndex(parseInt(v2));
pushIndex(parseInt(v3));
break;
case Lines:
pushIndex(parseInt(v1));
pushIndex(parseInt(v2));
break;
case Points:
pushIndex(parseInt(v1));
break;
}
}
// private boolean isUsingSharedVerts(Geometry geom) {
// Old code for buffer sharer
//return geom.getUserData(UserData.JME_SHAREDMESH) != null;
// }
private void startFaces(String count) throws SAXException {
int numFaces = parseInt(count);
int indicesPerFace = 0;
switch (mesh.getMode()) {
case Triangles:
indicesPerFace = 3;
break;
case Lines:
indicesPerFace = 2;
break;
case Points:
indicesPerFace = 1;
break;
default:
throw new SAXException("Strips or fans not supported!");
}
int numIndices = indicesPerFace * numFaces;
vb = new VertexBuffer(VertexBuffer.Type.Index);
if (!usesBigIndices) {
sb = BufferUtils.createShortBuffer(numIndices);
ib = null;
vb.setupData(Usage.Static, indicesPerFace, Format.UnsignedShort, sb);
} else {
ib = BufferUtils.createIntBuffer(numIndices);
sb = null;
vb.setupData(Usage.Static, indicesPerFace, Format.UnsignedInt, ib);
}
mesh.setBuffer(vb);
}
private void applyMaterial(Geometry geom, String matName) {
Material mat = null;
if (matName == null) {
// no material specified. use placeholder.
mat = null;
} else if (matName.endsWith(".j3m")) {
// load as native jme3 material instance
try {
mat = assetManager.loadMaterial(matName);
} catch (AssetNotFoundException ex) {
// Warning will be raised (see below)
if (!ex.getMessage().equals(matName)) {
throw ex;
}
}
} else {
if (materialList != null) {
mat = materialList.get(matName);
}
}
if (mat == null) {
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{matName, key});
mat = PlaceholderAssets.getPlaceholderMaterial(assetManager);
//mat.setKey(new MaterialKey(matName));
}
if (mat.isTransparent()) {
geom.setQueueBucket(Bucket.Transparent);
}
if(mat.isReceivesShadows()){
geom.setShadowMode(RenderQueue.ShadowMode.Receive);
}
geom.setMaterial(mat);
}
private void startSubMesh(String matName, String usesharedvertices, String use32bitIndices, String opType) throws SAXException {
mesh = new Mesh();
if (opType == null || opType.equals("triangle_list")) {
mesh.setMode(Mesh.Mode.Triangles);
//} else if (opType.equals("triangle_strip")) {
// mesh.setMode(Mesh.Mode.TriangleStrip);
//} else if (opType.equals("triangle_fan")) {
// mesh.setMode(Mesh.Mode.TriangleFan);
} else if (opType.equals("line_list")) {
mesh.setMode(Mesh.Mode.Lines);
} else {
throw new SAXException("Unsupported operation type: " + opType);
}
usesBigIndices = parseBool(use32bitIndices, false);
usesSharedVerts = parseBool(usesharedvertices, false);
if (usesSharedVerts) {
usesSharedMesh.add(true);
// Old code for buffer sharer
// import vertexbuffers from shared geom
// IntMap sharedBufs = sharedMesh.getBuffers();
// for (Entry entry : sharedBufs) {
// mesh.setBuffer(entry.getValue());
// }
} else {
usesSharedMesh.add(false);
}
if (meshName == null) {
geom = new Geometry("OgreSubmesh-" + (++meshIndex), mesh);
} else {
geom = new Geometry(meshName + "-geom-" + (++meshIndex), mesh);
}
if (usesSharedVerts) {
// Old code for buffer sharer
// this mesh is shared!
//geom.setUserData(UserData.JME_SHAREDMESH, sharedMesh);
}
applyMaterial(geom, matName);
geoms.add(geom);
}
private void startSharedGeom(String vertexCount) throws SAXException {
sharedMesh = new Mesh();
vertCount = parseInt(vertexCount);
usesSharedVerts = false;
geom = null;
mesh = sharedMesh;
}
private void startGeometry(String vertexCount) throws SAXException {
vertCount = parseInt(vertexCount);
}
/**
* Normalizes weights if needed and finds largest amount of weights used for
* all vertices in the buffer.
*/
private void endBoneAssigns() {
// if (mesh != sharedMesh && isUsingSharedVerts(geom)) {
// return;
// }
if (!actuallyHasWeights) {
// No weights were actually written (the tag didn't have any entries)
// remove those buffers
mesh.clearBuffer(Type.BoneIndex);
mesh.clearBuffer(Type.BoneWeight);
weightsFloatData = null;
indicesData = null;
return;
}
//int vertCount = mesh.getVertexCount();
int maxWeightsPerVert = 0;
weightsFloatData.rewind();
for (int v = 0; v < vertCount; v++) {
float w0 = weightsFloatData.get(),
w1 = weightsFloatData.get(),
w2 = weightsFloatData.get(),
w3 = weightsFloatData.get();
if (w3 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 4);
} else if (w2 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 3);
} else if (w1 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 2);
} else if (w0 != 0) {
maxWeightsPerVert = Math.max(maxWeightsPerVert, 1);
}
float sum = w0 + w1 + w2 + w3;
if (sum != 1f) {
weightsFloatData.position(weightsFloatData.position() - 4);
// Compute new weights based on sum.
float sumToB = sum == 0 ? 0 : 1f / sum;
weightsFloatData.put(w0 * sumToB);
weightsFloatData.put(w1 * sumToB);
weightsFloatData.put(w2 * sumToB);
weightsFloatData.put(w3 * sumToB);
}
}
weightsFloatData.rewind();
actuallyHasWeights = false;
weightsFloatData = null;
indicesData = null;
mesh.setMaxNumWeights(maxWeightsPerVert);
}
private void startBoneAssigns() {
if (mesh != sharedMesh && usesSharedVerts) {
// will use bone assignments from shared mesh (?)
return;
}
// current mesh will have bone assigns
//int vertCount = mesh.getVertexCount();
// each vertex has
// - 4 bone weights
// - 4 bone indices
// create array-backed buffers for software skinning for access speed
weightsFloatData = FloatBuffer.allocate(vertCount * 4);
indicesData = ByteBuffer.allocate(vertCount * 4);
VertexBuffer weights = new VertexBuffer(Type.BoneWeight);
VertexBuffer indices = new VertexBuffer(Type.BoneIndex);
weights.setupData(Usage.CpuOnly, 4, Format.Float, weightsFloatData);
indices.setupData(Usage.CpuOnly, 4, Format.UnsignedByte, indicesData);
mesh.setBuffer(weights);
mesh.setBuffer(indices);
//creating empty buffers for HW skinning
//the buffers will be setup if ever used.
VertexBuffer weightsHW = new VertexBuffer(Type.HWBoneWeight);
VertexBuffer indicesHW = new VertexBuffer(Type.HWBoneIndex);
//setting usage to cpuOnly so that the buffer is not send empty to the GPU
indicesHW.setUsage(Usage.CpuOnly);
weightsHW.setUsage(Usage.CpuOnly);
mesh.setBuffer(weightsHW);
mesh.setBuffer(indicesHW);
}
private void startVertexBuffer(Attributes attribs) throws SAXException {
if (parseBool(attribs.getValue("positions"), false)) {
vb = new VertexBuffer(Type.Position);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("normals"), false)) {
vb = new VertexBuffer(Type.Normal);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("colours_diffuse"), false)) {
vb = new VertexBuffer(Type.Color);
fb = BufferUtils.createFloatBuffer(vertCount * 4);
vb.setupData(Usage.Static, 4, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("tangents"), false)) {
int dimensions = parseInt(attribs.getValue("tangent_dimensions"), 3);
vb = new VertexBuffer(Type.Tangent);
fb = BufferUtils.createFloatBuffer(vertCount * dimensions);
vb.setupData(Usage.Static, dimensions, Format.Float, fb);
mesh.setBuffer(vb);
}
if (parseBool(attribs.getValue("binormals"), false)) {
vb = new VertexBuffer(Type.Binormal);
fb = BufferUtils.createFloatBuffer(vertCount * 3);
vb.setupData(Usage.Static, 3, Format.Float, fb);
mesh.setBuffer(vb);
}
int texCoords = parseInt(attribs.getValue("texture_coords"), 0);
for (int i = 0; i < texCoords; i++) {
String dimsStr = attribs.getValue("texture_coord_dimensions_" + i);
if (dimsStr != null && dimsStr.startsWith("float")) {
dimsStr = dimsStr.substring("float".length());
}
int dims = parseInt(dimsStr, 2);
if (dims < 1 || dims > 4) {
throw new SAXException("Texture coord dimensions must be 1 <= dims <= 4");
}
if (i <= 7) {
vb = new VertexBuffer(TEXCOORD_TYPES[i]);
} else {
// more than 8 texture coordinates are not supported by ogre.
throw new SAXException("More than 8 texture coordinates not supported");
}
fb = BufferUtils.createFloatBuffer(vertCount * dims);
vb.setupData(Usage.Static, dims, Format.Float, fb);
mesh.setBuffer(vb);
}
}
private void startVertex() {
texCoordIndex = 0;
}
private void pushAttrib(Type type, Attributes attribs) throws SAXException {
try {
FloatBuffer buf = (FloatBuffer) mesh.getBuffer(type).getData();
buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
} catch (Exception ex) {
throw new SAXException("Failed to push attrib", ex);
}
}
private void pushTangent(Attributes attribs) throws SAXException {
try {
VertexBuffer tangentBuf = mesh.getBuffer(Type.Tangent);
FloatBuffer buf = (FloatBuffer) tangentBuf.getData();
buf.put(parseFloat(attribs.getValue("x"))).put(parseFloat(attribs.getValue("y"))).put(parseFloat(attribs.getValue("z")));
if (tangentBuf.getNumComponents() == 4) {
buf.put(parseFloat(attribs.getValue("w")));
}
} catch (Exception ex) {
throw new SAXException("Failed to push attrib", ex);
}
}
private void pushTexCoord(Attributes attribs) throws SAXException {
if (texCoordIndex >= 8) {
return; // More than 8 not supported by ogre.
}
Type type = TEXCOORD_TYPES[texCoordIndex];
VertexBuffer tcvb = mesh.getBuffer(type);
FloatBuffer buf = (FloatBuffer) tcvb.getData();
buf.put(parseFloat(attribs.getValue("u")));
if (tcvb.getNumComponents() >= 2) {
buf.put(parseFloat(attribs.getValue("v")));
if (tcvb.getNumComponents() >= 3) {
buf.put(parseFloat(attribs.getValue("w")));
if (tcvb.getNumComponents() == 4) {
buf.put(parseFloat(attribs.getValue("x")));
}
}
}
texCoordIndex++;
}
private void pushColor(Attributes attribs) throws SAXException {
FloatBuffer buf = (FloatBuffer) mesh.getBuffer(Type.Color).getData();
String value = parseString(attribs.getValue("value"));
String[] vals = value.split("\\s");
if (vals.length != 3 && vals.length != 4) {
throw new SAXException("Color value must contain 3 or 4 components");
}
ColorRGBA color = new ColorRGBA();
color.r = parseFloat(vals[0]);
color.g = parseFloat(vals[1]);
color.b = parseFloat(vals[2]);
if (vals.length == 3) {
color.a = 1f;
} else {
color.a = parseFloat(vals[3]);
}
buf.put(color.r).put(color.g).put(color.b).put(color.a);
}
private void startLodFaceList(String submeshIndex, String numFaces) {
int index = Integer.parseInt(submeshIndex);
mesh = geoms.get(index).getMesh();
int faceCount = Integer.parseInt(numFaces);
VertexBuffer originalIndexBuffer = mesh.getBuffer(Type.Index);
vb = new VertexBuffer(VertexBuffer.Type.Index);
if (originalIndexBuffer.getFormat() == Format.UnsignedInt) {
// LOD buffer should also be integer
ib = BufferUtils.createIntBuffer(faceCount * 3);
sb = null;
vb.setupData(Usage.Static, 3, Format.UnsignedInt, ib);
} else {
sb = BufferUtils.createShortBuffer(faceCount * 3);
ib = null;
vb.setupData(Usage.Static, 3, Format.UnsignedShort, sb);
}
List levels = lodLevels.get(index);
if (levels == null) {
// Create the LOD levels list
levels = new ArrayList();
// Add the first LOD level (always the original index buffer)
levels.add(originalIndexBuffer);
lodLevels.put(index, levels);
}
levels.add(vb);
}
private void startLevelOfDetail(String numLevels) {
// numLevels = Integer.parseInt(numLevels);
}
private void endLevelOfDetail() {
// set the lod data for each mesh
for (Entry> entry : lodLevels) {
Mesh m = geoms.get(entry.getKey()).getMesh();
List levels = entry.getValue();
VertexBuffer[] levelArray = new VertexBuffer[levels.size()];
levels.toArray(levelArray);
m.setLodLevels(levelArray);
}
}
private void startLodGenerated(String depthsqr) {
}
private void pushBoneAssign(String vertIndex, String boneIndex, String weight) throws SAXException {
int vert = parseInt(vertIndex);
float w = parseFloat(weight);
byte bone = (byte) parseInt(boneIndex);
assert bone >= 0;
assert vert >= 0 && vert < mesh.getVertexCount();
int i;
float v = 0;
// see which weights are unused for a given bone
for (i = vert * 4; i < vert * 4 + 4; i++) {
v = weightsFloatData.get(i);
if (v == 0) {
break;
}
}
if (v != 0) {
logger.log(Level.WARNING, "Vertex {0} has more than 4 weights per vertex! Ignoring..", vert);
return;
}
weightsFloatData.put(i, w);
indicesData.put(i, bone);
actuallyHasWeights = true;
}
private void startSkeleton(String name) {
AssetKey assetKey = new AssetKey<>(folderName + name + ".xml");
try {
animData = assetManager.loadAsset(assetKey);
} catch (AssetNotFoundException ex) {
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{assetKey, key});
animData = null;
}
}
private void startSubmeshName(String indexStr, String nameStr) {
int index = Integer.parseInt(indexStr);
if (index >= geoms.size()) {
logger.log(Level.WARNING, "Submesh name index is larger than number of geometries: {0} >= {1}",
new Object[]{index, geoms.size()});
} else {
geoms.get(index).setName(nameStr);
}
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException {
if (ignoreUntilEnd != null) {
return;
}
if (qName.equals("texcoord")) {
pushTexCoord(attribs);
} else if (qName.equals("vertexboneassignment")) {
pushBoneAssign(attribs.getValue("vertexindex"),
attribs.getValue("boneindex"),
attribs.getValue("weight"));
} else if (qName.equals("face")) {
pushFace(attribs.getValue("v1"),
attribs.getValue("v2"),
attribs.getValue("v3"));
} else if (qName.equals("position")) {
pushAttrib(Type.Position, attribs);
} else if (qName.equals("normal")) {
pushAttrib(Type.Normal, attribs);
} else if (qName.equals("tangent")) {
pushTangent(attribs);
} else if (qName.equals("binormal")) {
pushAttrib(Type.Binormal, attribs);
} else if (qName.equals("colour_diffuse")) {
pushColor(attribs);
} else if (qName.equals("vertex")) {
startVertex();
} else if (qName.equals("faces")) {
startFaces(attribs.getValue("count"));
} else if (qName.equals("geometry")) {
String count = attribs.getValue("vertexcount");
if (count == null) {
count = attribs.getValue("count");
}
startGeometry(count);
} else if (qName.equals("vertexbuffer")) {
startVertexBuffer(attribs);
} else if (qName.equals("lodfacelist")) {
startLodFaceList(attribs.getValue("submeshindex"),
attribs.getValue("numfaces"));
} else if (qName.equals("lodgenerated")) {
startLodGenerated(attribs.getValue("fromdepthsquared"));
} else if (qName.equals("levelofdetail")) {
startLevelOfDetail(attribs.getValue("numlevels"));
} else if (qName.equals("boneassignments")) {
startBoneAssigns();
} else if (qName.equals("submesh")) {
if (submeshNamesHack) {
// Hack for blender2ogre only
startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
} else {
startSubMesh(attribs.getValue("material"),
attribs.getValue("usesharedvertices"),
attribs.getValue("use32bitindexes"),
attribs.getValue("operationtype"));
}
} else if (qName.equals("sharedgeometry")) {
String count = attribs.getValue("vertexcount");
if (count == null) {
count = attribs.getValue("count");
}
if (count != null && !count.equals("0")) {
startSharedGeom(count);
}
} else if (qName.equals("submeshes")) {
// ok
} else if (qName.equals("skeletonlink")) {
startSkeleton(attribs.getValue("name"));
} else if (qName.equals("submeshnames")) {
// ok
// setting submeshNamesHack to true will make "submesh" tag be interpreted
// as a "submeshname" tag.
submeshNamesHack = true;
} else if (qName.equals("submeshname")) {
startSubmeshName(attribs.getValue("index"), attribs.getValue("name"));
} else if (qName.equals("mesh")) {
// ok
} else {
logger.log(Level.WARNING, "Unknown tag: {0}. Ignoring.", qName);
ignoreUntilEnd = qName;
}
}
@Override
public void endElement(String uri, String name, String qName) {
if (ignoreUntilEnd != null) {
if (ignoreUntilEnd.equals(qName)) {
ignoreUntilEnd = null;
}
return;
}
// If submesh hack is enabled, ignore any submesh/submeshes
// end tags.
if (qName.equals("submesh") && !submeshNamesHack) {
usesBigIndices = false;
geom = null;
mesh = null;
} else if (qName.equals("submeshes") && !submeshNamesHack) {
// IMPORTANT: restore shared mesh, for use with shared bone weights
geom = null;
mesh = sharedMesh;
usesSharedVerts = false;
} else if (qName.equals("faces")) {
if (ib != null) {
ib.flip();
} else {
sb.flip();
}
vb = null;
ib = null;
sb = null;
} else if (qName.equals("vertexbuffer")) {
fb = null;
vb = null;
} else if (qName.equals("geometry")
|| qName.equals("sharedgeometry")) {
// finish writing to buffers
for (VertexBuffer buf : mesh.getBufferList().getArray()) {
Buffer data = buf.getData();
if (data.position() != 0) {
data.flip();
}
}
mesh.updateBound();
mesh.setStatic();
if (qName.equals("sharedgeometry")) {
geom = null;
mesh = null;
}
} else if (qName.equals("lodfacelist")) {
sb.flip();
vb = null;
sb = null;
} else if (qName.equals("levelofdetail")) {
endLevelOfDetail();
} else if (qName.equals("boneassignments")) {
endBoneAssigns();
} else if (qName.equals("submeshnames")) {
// Restore default handling for "submesh" tag.
submeshNamesHack = false;
}
}
@Override
public void characters(char ch[], int start, int length) {
}
private Node compileModel() {
Node model = new Node(meshName + "-ogremesh");
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = g.getMesh();
// New code for buffer extract
if (sharedMesh != null && usesSharedMesh.get(i)) {
m.extractVertexData(sharedMesh);
}
model.attachChild(geoms.get(i));
}
// Do not attach shared geometry to the node!
if (animData != null) {
// This model uses animation
for (int i = 0; i < geoms.size(); i++) {
Geometry g = geoms.get(i);
Mesh m = geoms.get(i).getMesh();
m.generateBindPose();
}
// Put the animations in the AnimControl
HashMap anims = new HashMap<>();
ArrayList animList = animData.anims;
for (int i = 0; i < animList.size(); i++) {
AnimClip anim = animList.get(i);
anims.put(anim.getName(), anim);
}
AnimComposer composer = new AnimComposer();
for (AnimClip clip : anims.values()) {
composer.addAnimClip(clip);
}
model.addControl(composer);
// Put the skeleton in the skeleton control
SkinningControl skinningControl = new SkinningControl(animData.armature);
// This will acquire the targets from the node
model.addControl(skinningControl);
}
return model;
}
@Override
public Object load(AssetInfo info) throws IOException {
try {
key = info.getKey();
meshName = key.getName();
folderName = key.getFolder();
String ext = key.getExtension();
meshName = meshName.substring(0, meshName.length() - ext.length() - 1);
if (folderName != null && folderName.length() > 0) {
meshName = meshName.substring(folderName.length());
}
assetManager = info.getManager();
if (key instanceof OgreMeshKey) {
// OgreMeshKey is being used, try getting the material list
// from it
OgreMeshKey meshKey = (OgreMeshKey) key;
materialList = meshKey.getMaterialList();
String materialName = meshKey.getMaterialName();
// Material list not set but material name is available
if (materialList == null && materialName != null) {
OgreMaterialKey materialKey = new OgreMaterialKey(folderName + materialName + ".material");
try {
materialList = assetManager.loadAsset(materialKey);
} catch (AssetNotFoundException e) {
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{materialKey, key});
}
}
} else {
// Make sure to reset it to null so that previous state
// doesn't leak onto this one
materialList = null;
}
// If for some reason material list could not be found through
// OgreMeshKey, or if regular ModelKey specified, load using
// default method.
if (materialList == null) {
OgreMaterialKey materialKey = new OgreMaterialKey(folderName + meshName + ".material");
try {
materialList = assetManager.loadAsset(materialKey);
} catch (AssetNotFoundException e) {
logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{materialKey, key});
}
}
// Added by larynx 25.06.2011
// Android needs the namespace aware flag set to true
// Kirill 30.06.2011
// Now, hack is applied for both desktop and android to avoid
// checking with JmeSystem.
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
XMLReader xr = factory.newSAXParser().getXMLReader();
xr.setContentHandler(this);
xr.setErrorHandler(this);
InputStreamReader r = null;
try {
r = new InputStreamReader(info.openStream());
xr.parse(new InputSource(r));
} finally {
if (r != null) {
r.close();
}
}
return compileModel();
} catch (SAXException | ParserConfigurationException ex) {
IOException ioEx = new IOException("Error while parsing Ogre3D mesh.xml");
ioEx.initCause(ex);
throw ioEx;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy