Hi all! I was just remembering that a year ago i wrote a importer class for 3dsmax ase models. I know it’s not documented and would need a lot of refactoring (should use more stuff already implemented in jme and be turned into a standard loader class) but for now it WORKS! So maybe it is usefull to anybody out there struggling with importing 3dsmax models
It does only Vertex (Position/Normal/Texturecoordinate) information - no animations or other stuff though! I used it with 3dsmax 2012 but should work with other versions also
Maybe some day i will find time to rewrite it (or feel free to do it yourself if you want!)
FileReader.java
[java]
/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FileReader
{
public static String readFile(
final String path)
{
try{
File f = new File(path);
final InputStream inputStream = new FileInputStream(f);
final InputStreamReader inputStreamReader = new InputStreamReader(
inputStream);
final BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);
String nextLine;
final StringBuilder body = new StringBuilder();
try
{
while ((nextLine = bufferedReader.readLine()) != null)
{
body.append(nextLine);
body.append('\n');
}
}
catch (IOException e)
{
return null;
}
return body.toString();
}catch (Exception e){
e.printStackTrace();
return null;
}}
}
[/java]
StringUtil.java
[java]/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package util;
/**
*
-
@author Naas
*/
public class StringUtil {public final static char BLOCK_STARTMARK = ‘{’;
public final static char BLOCK_ENDMARK = ‘}’;public static String extractBlock(String input, String blockBegin) {
int nameStart = input.indexOf(blockBegin); int nameEnd = nameStart + blockBegin.length(); int contentStart = input.indexOf(BLOCK_STARTMARK, nameEnd) + 1; int contentEnd = getBlockEndMarkPosition(input, contentStart - 1) - 1; if (nameStart >= 0 && contentEnd > contentStart) { return input.substring(contentStart, contentEnd); } else { throw new UnsupportedOperationException("Der Block " + blockBegin + " konnte nicht extrahiert werden! String: \n" + input); }
}
public static int getBlockEndMarkPosition(String input, int searchBegin) {
int start = input.indexOf(BLOCK_STARTMARK, searchBegin); //int position = start; boolean found = false; //int nextEndMark = start + 1; //int lastStartMark = start; int startMarkCount = 1; int endMarkCount = 0; int position = start + 1; char c; while (!found && (startMarkCount > endMarkCount) && position currentOffsetIndex) && position 32 && c< 127) { if(offsets[currentOffsetIndex]==stringsFound){ if (lastCharEmpty) { strings[currentOffsetIndex] = ""; } strings[currentOffsetIndex] += c;} lastCharEmpty = false; } else { if (!lastCharEmpty) { if(stringsFound==offsets[currentOffsetIndex]){ currentOffsetIndex++; } stringsFound++; lastCharEmpty = true; } } position++; } return strings;
}
public static String[] extractStringsFromLines(String input, int startPosition, int[] offsets, int lines) {
boolean lineEnd = false;
boolean lastCharEmpty = true;
int stringsFound = 0;
int position = startPosition;
//int lastOffset = offsets[offsets.length-1];
int currentOffsetIndex;
int stringsPerLine = offsets.length;
char c =' ';
String[] strings = new String[stringsPerLine * lines];for (int lineIndex = 0; lineIndex currentOffsetIndex) && position 32 && c< 127) { // wenn gerade die vorgegebene Offsetposition erreicht ist fuelle den String if(offsets[currentOffsetIndex]==stringsFound){ if (lastCharEmpty) { strings[stringsPerLine*lineIndex +currentOffsetIndex] = ""; } strings[stringsPerLine*lineIndex +currentOffsetIndex] += c;} lastCharEmpty = false; } else { if (!lastCharEmpty) { // am ende des Wortes schließe ab und warte auf das naechste wort am richtigen Offset if(stringsFound==offsets[currentOffsetIndex]){ // System.out.println(" last string read: "+strings[stringsPerLine*lineIndex +currentOffsetIndex]+" line: "+lineIndex+" stringsFound: "+stringsFound+" currentOffsetIndex: "+currentOffsetIndex); currentOffsetIndex++; } stringsFound++; lastCharEmpty = true; } } position++; } // ggf. bis zum Ende der Zeile gehen while(c!='\n'){ c = input.charAt(position); position++; } } return strings;
}
public static short[] stringsToShort(String[] strings) {
short[] result = new short[strings.length];
for (int i = 0; i < strings.length; i++) {
result[i] = Short.parseShort(strings[i]);
}
return result;
}public static int[] stringsToInt(String[] strings) {
int[] result = new int[strings.length];
for (int i = 0; i < strings.length; i++) {
result[i] = Integer.parseInt(strings[i]);
}
return result;
}public static float[] stringsToFloat(String[] strings) {
float[] result = new float[strings.length];
for (int i = 0; i < strings.length; i++) {
result[i] = Float.parseFloat(strings[i]);
}
return result;
}
}
[/java]
AseImporter.java
[java]
/*
- To change this template, choose Tools | Templates
- and open the template in the editor.
*/
package import;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
import util.FileReader;
import util.StringUtil;
import java.nio.FloatBuffer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/**
*
-
@author Naas
*/
public class AseImporter {public static Mesh importAseFile(String path) {
String aseString = FileReader.readFile(path); return aseToMesh(aseString,1.0f);
}
public static Mesh aseToMesh(String aseString,float scale) {
float[] color = new float[]{1.0f, 1.0f, 1.0f, 1.0f}; String meshString = StringUtil.extractBlock(aseString, "MESH"); int vertexNumber = StringUtil.extractIntsFromLine(meshString, "MESH_NUMVERTEX", 0, new int[]{0})[0]; int faceNumber = StringUtil.extractIntsFromLine(meshString, "MESH_NUMFACES", 0, new int[]{0})[0]; int tVertexNumber = StringUtil.extractIntsFromLine(meshString, "MESH_NUMTVERTEX", 0, new int[]{0})[0]; String vertexBlock = StringUtil.extractBlock(meshString, "MESH_VERTEX_LIST"); float[] vertexes = StringUtil.stringsToFloat(StringUtil.extractStringsFromLines(vertexBlock, 1, new int[]{2, 3, 4}, vertexNumber)); String faceBlock = StringUtil.extractBlock(meshString, "MESH_FACE_LIST"); short[] faces = StringUtil.stringsToShort(StringUtil.extractStringsFromLines(faceBlock, 1, new int[]{3, 5, 7}, faceNumber)); String[] smoothGroupStrings = StringUtil.extractStringsFromLines(faceBlock, 1, new int[]{15}, faceNumber); for (int i = 0; i < smoothGroupStrings.length; i++) { char testC = smoothGroupStrings[i].charAt(0); if (!((47 < testC) && (testC < 58))) { smoothGroupStrings[i] = "-1"; } } short[] smoothGroups = StringUtil.stringsToShort(smoothGroupStrings); String tTextureCoordsBlock = StringUtil.extractBlock(meshString, "MESH_TVERTLIST"); float[] tTextureCoords = StringUtil.stringsToFloat(StringUtil.extractStringsFromLines(tTextureCoordsBlock, 1, new int[]{2, 3}, tVertexNumber));// 3. koordinate ist immer 0 (wahrscheinlich fuer 3d Textur od so) String tFacesBlock = StringUtil.extractBlock(meshString, "MESH_TFACELIST"); short[] tfaces = StringUtil.stringsToShort(StringUtil.extractStringsFromLines(tFacesBlock, 1, new int[]{2, 3, 4}, faceNumber));// 3. koordinate ist immer 0 (wahrscheinlich fuer 3d Textur od so) String tNormalsBlock = StringUtil.extractBlock(meshString, "MESH_NORMALS"); float[] tNormals = StringUtil.stringsToFloat(StringUtil.extractStringsFromLines(tNormalsBlock, 1, new int[]{2, 3, 4}, faceNumber * 4));// 3. koordinate ist immer 0 (wahrscheinlich fuer 3d Textur od so) int smoothGroupCount = 0; // Anzahl der Smoothgroups herausfinden for (int faceIndex = 0; faceIndex smoothGroupCount) { smoothGroupCount = smoothGroups[faceIndex]; } } // Eine Collection erstellen, aus der man rauslesen kann welche der einzelnen SmoothGroups zugehoerigen Vertexes von welchen Faces benutzt werden List smoothGroupVertexFaces = new LinkedList(); for (int i = 0; i <= smoothGroupCount; i++) { smoothGroupVertexFaces.add(new HashMap()); } for (int faceIndex = 0; faceIndex 0) { int[] vertexIndexes = {faces[3 * faceIndex + 0], faces[3 * faceIndex + 1], faces[3 * faceIndex + 2]}; for (int i = 0; i < 3; i++) { int vertexIndex = vertexIndexes[i]; if (!smoothGroupVertexFaces.get(smoothGroup).containsKey(vertexIndex)) { smoothGroupVertexFaces.get(smoothGroup).put(vertexIndex, new LinkedList()); } smoothGroupVertexFaces.get(smoothGroup).get(vertexIndex).add(faceIndex); } } } float[] normals = new float[faceNumber * 3 * 3]; for (int smoothGroupIndex = 1; smoothGroupIndex <= smoothGroupCount; smoothGroupIndex++) { HashMap vertexFaceMap = smoothGroupVertexFaces.get(smoothGroupIndex); for (Iterator it = vertexFaceMap.keySet().iterator(); it.hasNext();) { int vertexIndex = it.next(); List facesList = vertexFaceMap.get(vertexIndex); for (int triangleVertexIndex = 0; triangleVertexIndex 1) { for (Iterator it1 = facesList.iterator(); it1.hasNext();) { int faceIndex = it1.next(); normals[3 * (3 * faceIndex + triangleVertexIndex) + 0] = tNormals[3 * (4 * faceIndex + triangleVertexIndex + 1) + 0]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 1] = tNormals[3 * (4 * faceIndex + triangleVertexIndex + 1) + 1]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 2] = tNormals[3 * (4 * faceIndex + triangleVertexIndex + 1) + 2]; } } else { if(facesList.size() == 1){ int faceIndex = facesList.iterator().next(); normals[3 * (3 * faceIndex + triangleVertexIndex) + 0] = tNormals[3 * (4 * faceIndex ) + 0]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 1] = tNormals[3 * (4 * faceIndex ) + 1]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 2] = tNormals[3 * (4 * faceIndex ) + 2];} } } } } //setze die Normalen der Faces ohne Smoothgroups = Face Normal for (int faceIndex = 0; faceIndex < faceNumber; faceIndex++) { int smoothGroup = smoothGroups[faceIndex]; if (smoothGroup == -1) { // System.out.println(" face "+faceIndex+" no smoothGroup"); for (int triangleVertexIndex = 0; triangleVertexIndex < 3; triangleVertexIndex++) { normals[3 * (3 * faceIndex + triangleVertexIndex) + 0] = tNormals[3 * (4 * faceIndex ) + 0]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 1] = tNormals[3 * (4 * faceIndex ) + 1]; normals[3 * (3 * faceIndex + triangleVertexIndex) + 2] = tNormals[3 * (4 * faceIndex ) + 2]; } } } Mesh mesh = new Mesh(); mesh.setMode(Mesh.Mode.Triangles); FloatBuffer vertexBuffer = BufferUtils.createFloatBuffer( 3 * 3 * faceNumber); FloatBuffer texCoordBuffer = BufferUtils.createFloatBuffer( 2 * 3 * faceNumber); FloatBuffer normalBuffer = BufferUtils.createFloatBuffer( 3 * 3 * faceNumber); FloatBuffer colorBuffer = BufferUtils.createFloatBuffer( 4 * 3 * faceNumber); for (int faceIndex = 0; faceIndex < faceNumber; faceIndex++) { int a, b, c, ta, tb, tc; a = faces[3 * faceIndex + 0]; b = faces[3 * faceIndex + 1]; c = faces[3 * faceIndex + 2]; ta = tfaces[3 * faceIndex + 0]; tb = tfaces[3 * faceIndex + 1]; tc = tfaces[3 * faceIndex + 2]; vertexBuffer.put(scale*vertexes[3 * a + 0]).put(scale*vertexes[3 * a + 1]).put(scale*vertexes[3 * a + 2]); vertexBuffer.put(scale*vertexes[3 * b + 0]).put(scale*vertexes[3 * b + 1]).put(scale*vertexes[3 * b + 2]); vertexBuffer.put(scale*vertexes[3 * c + 0]).put(scale*vertexes[3 * c + 1]).put(scale*vertexes[3 * c + 2]); texCoordBuffer.put(tTextureCoords[2 * ta + 0]).put(tTextureCoords[2 * ta + 1]); texCoordBuffer.put(tTextureCoords[2 * tb + 0]).put(tTextureCoords[2 * tb + 1]); texCoordBuffer.put(tTextureCoords[2 * tc + 0]).put(tTextureCoords[2 * tc + 1]); normalBuffer.put(normals[3 * (3 * faceIndex + 0) + 0]).put(normals[3 * (3 * faceIndex + 0) + 1]).put(normals[3 * (3 * faceIndex + 0) + 2]); normalBuffer.put(normals[3 * (3 * faceIndex + 1) + 0]).put(normals[3 * (3 * faceIndex + 1) + 1]).put(normals[3 * (3 * faceIndex + 1) + 2]); normalBuffer.put(normals[3 * (3 * faceIndex + 2) + 0]).put(normals[3 * (3 * faceIndex + 2) + 1]).put(normals[3 * (3 * faceIndex + 2) + 2]); colorBuffer.put(color[0]).put(color[1]).put(color[2]).put(color[3]); colorBuffer.put(color[0]).put(color[1]).put(color[2]).put(color[3]); colorBuffer.put(color[0]).put(color[1]).put(color[2]).put(color[3]); } mesh.setBuffer(Type.Position, 3, vertexBuffer); mesh.setBuffer(Type.Normal, 3, normalBuffer); mesh.setBuffer(Type.Color, 4, colorBuffer); mesh.setBuffer(Type.TexCoord, 2, texCoordBuffer); return mesh;
}
}
[/java]
Use it like this :
[java]
Geometry geom= new Geometry("GeomName",AseImporter.importAseFile("filepath/model.ase"));
[/java]
I know the extra file reader class is bad and also bad is not using the AssetManager
shame on me!