/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* 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 the 'Xith3D Project Group' 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) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.loaders.models.impl.dae;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import org.jagatoo.loaders.models.collada.datastructs.AssetFolder;
import org.jagatoo.loaders.models.collada.datastructs.effects.Effect;
import org.jagatoo.loaders.models.collada.datastructs.effects.Profile;
import org.jagatoo.loaders.models.collada.datastructs.effects.ProfileCommon;
import org.jagatoo.loaders.models.collada.datastructs.effects.ShadingParameters;
import org.jagatoo.loaders.models.collada.datastructs.geometries.Mesh;
import org.jagatoo.loaders.models.collada.datastructs.geometries.PolygonsGeometry;
import org.jagatoo.loaders.models.collada.datastructs.geometries.TrianglesGeometry;
import org.jagatoo.loaders.models.collada.datastructs.images.Surface;
import org.jagatoo.loaders.models.collada.datastructs.visualscenes.AbstractInstance;
import org.jagatoo.loaders.models.collada.datastructs.visualscenes.ControllerInstance;
import org.jagatoo.loaders.models.collada.datastructs.visualscenes.GeometryInstance;
import org.openmali.vecmath2.Matrix4f;
import org.xith3d.loaders.texture.TextureLoader;
import org.xith3d.scenegraph.Appearance;
import org.xith3d.scenegraph.Geometry;
import org.xith3d.scenegraph.Group;
import org.xith3d.scenegraph.Material;
import org.xith3d.scenegraph.Shape3D;
import org.xith3d.scenegraph.Transform;
import org.xith3d.scenegraph.TransparencyAttributes;
import org.xith3d.scenegraph.TriangleArray;
/**
* This class is used to retrieve Xith3D models from a File
* object, which corresponds to the data loaded from an XML object.
*
* @author Amos Wenger (aka BlueSky)
*/
class DaeConverter
{
public static org.xith3d.scenegraph.Material toXith3D(ShadingParameters parameters, String name)
{
org.xith3d.scenegraph.Material material = new Material();
material.setAmbientColor(parameters.ambient);
material.setDiffuseColor(parameters.diffuse);
material.setSpecularColor(parameters.specular);
material.setShininess(parameters.shininess);
material.setEmissiveColor(parameters.emission);
material.setName(name);
return material;
}
/**
* Creates a Xith3D Appearance from informations.
*
* @param material
*
* @return the Appearance
*/
public static Appearance toXith3D( org.jagatoo.loaders.models.collada.datastructs.materials.Material material )
{
if (material == null)
{
Appearance app = new Appearance(); // blank appearance
app.setColor(.5f,.5f,.5f);
return app;
}
AssetFolder file = material.getFile();
Appearance app = new Appearance();
String texture = null;
String effectUrl = material.getEffect();
Effect effect = ( effectUrl.length() == 0 ) ?
file.getLibraryEffects().getEffects().values().iterator().next() :
file.getLibraryEffects().getEffects().get( material.getEffect() );
for ( Profile profile : effect.profiles )
{
if ( profile instanceof ProfileCommon )
{
// we don't really support all of these different shading models specifically, so I'm
// just going to plug in whichever one was specified.
ProfileCommon profileCommon = (ProfileCommon)profile;
if (profileCommon.technique.blinn != null)
{
app.setMaterial(toXith3D(profileCommon.technique.blinn, effectUrl));
} else if (profileCommon.technique.lambert != null)
{
app.setMaterial(toXith3D(profileCommon.technique.lambert, effectUrl));
} else if (profileCommon.technique.phong != null)
{
app.setMaterial(toXith3D(profileCommon.technique.phong, effectUrl));
} else if (profileCommon.technique.constant != null)
{
app.setMaterial(toXith3D(profileCommon.technique.constant, effectUrl));
} else
{
app.setMaterial( new Material(true));
}
app.getMaterial().setColorTarget(Material.AMBIENT);
for ( Surface surface : profileCommon.getSurfaces().values() )
{
for ( String imageId : surface.imageIds )
{
if ( texture == null )
{
texture = file.getLibraryImages().getImages().get( imageId );
//System.out.println( "Found texture : " + texture );
}
else
{
System.err.println( "Ignoring extra texture : " + file.getLibraryImages().getImages().get( imageId ) );
}
}
}
}
else
{
System.err.println( "Ignoring profile type : " + profile.getClass().getName() );
}
}
if ( texture != null )
{
try
{
File textureFile = new File(file.getBasePath().toExternalForm(), texture);
URL textureURL = textureFile.toURI().toURL();
app.setTexture( TextureLoader.getInstance().loadTexture( textureURL ) );
}
catch ( MalformedURLException e )
{
e.printStackTrace();
}
}
// else
// {
// System.out.println( "No texture found" );
// }
if ( ( app.getTexture() != null ) && ( app.getTexture().getFormat().hasAlpha() ) )
{
app.getTransparencyAttributes( true ).setMode( TransparencyAttributes.BLENDED );
}
return ( app );
}
public static Group toXith3D( org.jagatoo.loaders.models.collada.datastructs.visualscenes.Node node, Map< AbstractInstance, Group > instanceMap )
{
Group grp = null;
if(node.getTransform().getMatrixTransform().getMatrix().equals( Matrix4f.IDENTITY ))
{
grp = new Group();
}
else
{
Transform trans = new Transform();
trans.setMatrix( node.getTransform().getMatrixTransform().getMatrix() );
grp = trans;
}
for ( org.jagatoo.loaders.models.collada.datastructs.visualscenes.Node n: node.getChildren() )
{
grp.addChild( toXith3D( n, instanceMap ) );
}
for ( org.jagatoo.loaders.models.collada.datastructs.visualscenes.AbstractInstance ai: node.getGeometryInstances() )
{
grp.addChild( toXith3D( ai, instanceMap ) );
}
for ( org.jagatoo.loaders.models.collada.datastructs.visualscenes.AbstractInstance ai: node.getControllerInstances() )
{
grp.addChild( toXith3D( ai, instanceMap ) );
}
return grp;
}
public static Group toXith3D( org.jagatoo.loaders.models.collada.datastructs.visualscenes.AbstractInstance instance, Map< AbstractInstance, Group > instanceMap )
{
Geometry geom = null;
Appearance app = null;
Group geometryGroup = null;
if (instance instanceof GeometryInstance) {
geometryGroup = new Group();
GeometryInstance colladaGINode = (GeometryInstance) instance;
ArrayList<org.jagatoo.loaders.models.collada.datastructs.geometries.Geometry> geomList = colladaGINode
.getGeometry();
if (geomList != null) {
if (geomList.size() > 1) {
for (int i = 0; i < geomList.size(); i++) {
geom = DaeConverter.toXith3D(geomList.get(i));
app = DaeConverter
.toXith3D(colladaGINode.getMaterial(geomList.get(i).material));
if (geom != null) {
geometryGroup.addChild(new Shape3D(geom, app));
}
}
instanceMap.put(colladaGINode, geometryGroup);
} else if (geomList.size() == 1) {
geom = DaeConverter.toXith3D(geomList.get(0));
app = DaeConverter.toXith3D(colladaGINode.getMaterial(geomList.get(0).material));
if (geom != null) {
geometryGroup.addChild(new Shape3D(geom, app));
instanceMap.put(colladaGINode, geometryGroup);
}
}
}
}
else if ( instance instanceof ControllerInstance )
{
geometryGroup = new Group();
ControllerInstance colladaCINode = (ControllerInstance)instance;
/*
* Here goes the initialization of the Xith3D geometry that
* should be updated by the controller.
* The geom is just initial : it will be updated whenever animations are played on the model.
* But the number of vertices, normals, etc.. will stay the same.
*/
colladaCINode.getController().updateDestinationGeometry( 5000 );
geom = DaeConverter.toXith3D( colladaCINode.getController().getDestinationGeometry() );
app = DaeConverter.toXith3D( colladaCINode.getMaterial() );
geometryGroup.addChild(new Shape3D( geom, app ));
instanceMap.put( colladaCINode, geometryGroup );
}
else
{
throw new Error( "Type " + instance.getClass().getSimpleName() + " not implemented yet." );
}
return geometryGroup;
}
/**
* Creates a Xith3D geometry from a Geometry information.
*
* @param geometry
*
* @return A Xith3D geometry from the given informations
*/
public static Geometry toXith3D( org.jagatoo.loaders.models.collada.datastructs.geometries.Geometry geometry )
{
if ( geometry instanceof PolygonsGeometry )
{
throw new Error( "PolygonsGeometry isn't supported yet ! If you're e.g. exporting from blender," +
"\n try to select the option \"Triangles\" : THAT is supported."
);
}
else if ( geometry instanceof TrianglesGeometry )
{
return ( createGeometryFromTriangles( (TrianglesGeometry)geometry ) );
}
else if ( geometry == null )
{
//throw new Error( "This Geometry is null." );
// you will hit this case if you are using unsupported geometry
return null;
}
else
{
throw new Error( geometry.getClass().getSimpleName() + " isn't supported yet ! If you're e.g. exporting from blender," +
"\n try to select the option \"Triangles\" : THAT is supported."
);
}
}
/**
* Creates a Xith3D geometry from a Geometry information.
*
* @param geometry
*
* @return A Xith3D geometry from the given informations
*/
public static void update( org.jagatoo.loaders.models.collada.datastructs.geometries.Geometry geometry, Geometry xithGeometry )
{
if ( geometry instanceof PolygonsGeometry )
{
throw new Error( "PolygonsGeometry isn't supported yet ! If you're e.g. exporting from blender," +
"\n try to select the option \"Triangles\" : THAT is supported."
);
}
else if ( geometry instanceof TrianglesGeometry )
{
updateGeometryFromTriangles( (TrianglesGeometry)geometry, xithGeometry );
}
else if ( geometry == null )
{
throw new Error( "This Geometry is null." );
}
else
{
throw new Error(geometry.getClass().getSimpleName()+" isn't supported yet ! If you're e.g. exporting from blender," +
"\n try to select the option \"Triangles\" : THAT is supported.");
}
}
/**
* Creates a Xith3D geometry from informations (triangles).
*
* @param geometry
*
* @return A Xith3D geometry from the given informations
*
* @throws Error (We never know)
*/
private static void updateGeometryFromTriangles(TrianglesGeometry geometry, Geometry xithGeometry) {
Mesh mesh = geometry.getMesh();
int indexCount = mesh.getVertexIndices().length;
// VERTICES
float[] realVertices = null;
if ( mesh.getVertexIndices() != null )
{
realVertices = new float[indexCount * 3];
float[] fs = mesh.getSources().getVertices();
for ( int i = 0; i < indexCount; i++ )
{
int j = mesh.getVertexIndices()[i];
realVertices[i * 3] = fs[j * 3];
realVertices[i * 3 + 1] = fs[j * 3 + 1];
realVertices[i * 3 + 2] = fs[j * 3 + 2];
}
}
else
{
throw new Error( "Huh.. we have no vertices... Your file has a problem :)" );
}
// NORMALS
float[] realNormals = null;
if ( mesh.getNormalIndices() != null )
{
realNormals = new float[indexCount * 3];
float[] fs = mesh.getSources().getNormals();
for ( int i = 0; i < indexCount; i++ )
{
int j = mesh.getNormalIndices()[i];
realNormals[i * 3] = fs[j * 3];
realNormals[i * 3 + 1] = fs[j * 3 + 1];
realNormals[i * 3 + 2] = fs[j * 3 + 2];
}
}
// COLORS
float[] realColors = null;
if ( mesh.getColorIndices() != null )
{
realColors = new float[indexCount * 4];
float[] fs = mesh.getSources().getColors();
for ( int i = 0; i < indexCount; i++ )
{
int j = mesh.getColorIndices()[i];
realColors[i * 3] = fs[j * 3];
realColors[i * 3 + 1] = fs[j * 3 + 1];
realColors[i * 3 + 2] = fs[j * 3 + 2];
realColors[i * 3 + 3] = fs[j * 3 + 2];
}
}
// UVS
float[][] realUVs = null;
if (( mesh.getUVIndices() != null ) && ( mesh.getUVIndices().length > 0 ) )
{
realUVs = new float[ mesh.getUVIndices().length ][ indexCount * 2 ];
for ( int j = 0; j < mesh.getUVIndices().length; j++ )
{
float[] fs = mesh.getSources().getUVs()[ j ];
for ( int i = 0; i < indexCount; i++ )
{
int k = mesh.getUVIndices()[j][i];
realUVs[j][i * 2] = fs[k * 2];
realUVs[j][i * 2 + 1] = fs[k * 2 + 1];
}
}
}
/*
* Xith3D part
*/
// VERTICES
if ( mesh.getVertexIndices() != null )
{
xithGeometry.setCoordinates( 0, realVertices );
}
// NORMALS
if ( mesh.getNormalIndices() != null )
{
xithGeometry.setNormals( 0, realNormals );
}
// COLORS
if ( mesh.getColorIndices() != null )
{
xithGeometry.setColors( 0, 4, realColors );
}
// UVS
if ( ( mesh.getUVIndices() != null ) && ( mesh.getUVIndices().length > 0 ) )
{
for ( int i = 0; i < realUVs.length; i++ )
{
xithGeometry.setTextureCoordinates( i, 0, 2, realUVs[i] );
}
}
}
/**
* Creates a Xith3D geometry from informations (triangles).
*
* @param geometry
*
* @return A Xith3D geometry from the given informations
*
* @throws Error (We never know)
*/
private static Geometry createGeometryFromTriangles( TrianglesGeometry geometry )
{
int indexCount = geometry.getMesh().getVertexIndices().length;
/*
* Xith3D part
*/
Geometry xithGeometry = new TriangleArray(indexCount);
updateGeometryFromTriangles( geometry, xithGeometry );
return ( xithGeometry );
}
/** This class cannot be instantiated, it's static only */
private DaeConverter() {}
}