3dsmax .ase importer

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 :slight_smile:
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, &quot;MESH&quot;);
    
     int vertexNumber = StringUtil.extractIntsFromLine(meshString, &quot;MESH_NUMVERTEX&quot;, 0, new int[]{0})[0];
     int faceNumber = StringUtil.extractIntsFromLine(meshString, &quot;MESH_NUMFACES&quot;, 0, new int[]{0})[0];
     int tVertexNumber = StringUtil.extractIntsFromLine(meshString, &quot;MESH_NUMTVERTEX&quot;, 0, new int[]{0})[0];
    
     String vertexBlock = StringUtil.extractBlock(meshString, &quot;MESH_VERTEX_LIST&quot;);
     float[] vertexes = StringUtil.stringsToFloat(StringUtil.extractStringsFromLines(vertexBlock, 1, new int[]{2, 3, 4}, vertexNumber));
    
    
    
     String faceBlock = StringUtil.extractBlock(meshString, &quot;MESH_FACE_LIST&quot;);
    
    
     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 &lt; smoothGroupStrings.length; i++) {
    
         char testC = smoothGroupStrings[i].charAt(0);
    
         if (!((47 &lt; testC) &amp;&amp; (testC &lt; 58))) {
    
             smoothGroupStrings[i] = &quot;-1&quot;;
         }
    
     }
    
    
     short[] smoothGroups = StringUtil.stringsToShort(smoothGroupStrings);
    
    
     String tTextureCoordsBlock = StringUtil.extractBlock(meshString, &quot;MESH_TVERTLIST&quot;);
    
    
     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, &quot;MESH_TFACELIST&quot;);
    
    
     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, &quot;MESH_NORMALS&quot;);
    
    
     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 &lt;= 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 &lt; 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 &lt;= 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 &lt; faceNumber; faceIndex++) {
    
         int smoothGroup = smoothGroups[faceIndex];
         if (smoothGroup == -1) {
             // System.out.println(&quot; face &quot;+faceIndex+&quot; no smoothGroup&quot;);
             for (int triangleVertexIndex = 0; triangleVertexIndex &lt; 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 &lt; 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 :frowning: and also bad is not using the AssetManager :frowning: shame on me!