/*******************************************************************************
* Copyright 2012 Daniel Heinrich.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.graphics.g3d.loaders.openctm;
import java.util.ArrayList;
import java.util.List;
import darwin.jopenctm.data.AttributeData;
import darwin.jopenctm.io.CtmFileReader;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.ModelLoaderHints;
import com.badlogic.gdx.graphics.g3d.loaders.ModelLoader;
import com.badlogic.gdx.graphics.g3d.model.Model;
import com.badlogic.gdx.graphics.g3d.model.still.StillModel;
import com.badlogic.gdx.graphics.g3d.model.still.StillSubMesh;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
import com.badlogic.gdx.utils.GdxRuntimeException;
import static darwin.jopenctm.data.Mesh.*;
/**
*
* @author Daniel Heinrich <dannynullzwo@gmail.com>
*/
public class CtmModelLoader implements ModelLoader {
@Override
public Model load(FileHandle file, ModelLoaderHints hints) {
CtmFileReader reader = new CtmFileReader(file.read());
try {
darwin.jopenctm.data.Mesh ctmMesh = reader.decode();
Mesh mesh = convert(ctmMesh);
StillSubMesh ssm = new StillSubMesh(reader.getFileComment(),
mesh, GL10.GL_TRIANGLES);
StillModel model = new StillModel(new StillSubMesh[]{ssm});
return model;
} catch (Throwable ex) {
throw new GdxRuntimeException("An error occured while loading model: "
+ file.name(), ex);
}
}
private Mesh convert(darwin.jopenctm.data.Mesh ctmMesh) {
if (ctmMesh.getVertexCount() > Short.MAX_VALUE) {
throw new GdxRuntimeException("The indices exceed the range of SHORT!");
}
List<VertexAttribute> vas = new ArrayList<VertexAttribute>();
VertexAttribute position = new VertexAttribute(Usage.Position,
CTM_POSITION_ELEMENT_COUNT,
ShaderProgram.POSITION_ATTRIBUTE);
vas.add(position);
VertexAttribute normal = null;
if (ctmMesh.hasNormals()) {
normal = new VertexAttribute(Usage.Normal,
CTM_NORMAL_ELEMENT_COUNT,
ShaderProgram.NORMAL_ATTRIBUTE);
vas.add(normal);
}
VertexAttribute[] uvs = new VertexAttribute[ctmMesh.getUVCount()];
if (ctmMesh.getUVCount() > 0) {
uvs[0] = new VertexAttribute(Usage.TextureCoordinates,
CTM_UV_ELEMENT_COUNT,
ShaderProgram.TEXCOORD_ATTRIBUTE);
vas.add(uvs[0]);
if (ctmMesh.getUVCount() > 1) {
for (int i = 1; i < ctmMesh.getUVCount(); ++i) {
AttributeData ad = ctmMesh.texcoordinates[i];
uvs[i] = new VertexAttribute(Usage.TextureCoordinates,
CTM_UV_ELEMENT_COUNT,
ad.name);
vas.add(uvs[i]);
}
}
}
VertexAttribute[] others = new VertexAttribute[ctmMesh.getAttrCount()];
for (int i = 0; i < ctmMesh.getAttrCount(); ++i) {
others[i] = new VertexAttribute(Usage.Generic,
CTM_ATTR_ELEMENT_COUNT,
ctmMesh.attributs[i].name);
vas.add(others[i]);
}
Mesh m = new Mesh(true, ctmMesh.getVertexCount(),
ctmMesh.getTriangleCount() * 3,
vas.toArray(new VertexAttribute[0]));
m.setIndices(convertIndices(ctmMesh.indices));
int vsize = m.getVertexSize() / 4;
float[] data = new float[vsize * ctmMesh.getVertexCount()];
for (int i = 0; i < ctmMesh.getVertexCount(); i++) {
//position data
System.arraycopy(ctmMesh.vertices, i * CTM_POSITION_ELEMENT_COUNT,
data, i * vsize, CTM_POSITION_ELEMENT_COUNT);
//normal
if (normal != null) {
System.arraycopy(ctmMesh.normals, i * CTM_NORMAL_ELEMENT_COUNT,
data, i * vsize + normal.offset / 4, CTM_NORMAL_ELEMENT_COUNT);
}
//uvs
for(VertexAttribute va: uvs)
{
AttributeData ad=ctmMesh.texcoordinates[i];
System.arraycopy(ad.values, i * CTM_UV_ELEMENT_COUNT,
data, i * vsize + va.offset / 4, CTM_UV_ELEMENT_COUNT);
}
//other
for(VertexAttribute va: others)
{
AttributeData ad=ctmMesh.attributs[i];
System.arraycopy(ad.values, i * CTM_ATTR_ELEMENT_COUNT,
data, i * vsize + va.offset / 4, CTM_ATTR_ELEMENT_COUNT);
}
}
m.setVertices(data);
return m;
}
private static short[] convertIndices(int[] ind) {
short[] r = new short[ind.length];
for (int i = 0; i < r.length; i++) {
r[i] = (short) ind[i];
}
return r;
}
}