159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins.blender.curves; 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.Material; 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.RenderState.FaceCullMode; 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Spline.SplineType; 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.*; 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Geometry; 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh; 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type; 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.AbstractBlenderHelper; 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.BlenderContext; 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.exceptions.BlenderFileException; 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.file.*; 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.materials.MaterialHelper; 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.meshes.MeshHelper; 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.plugins.blender.objects.Properties; 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.shape.Curve; 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.shape.Surface; 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils; 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer; 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.IntBuffer; 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.HashMap; 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List; 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map; 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map.Entry; 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * A class that is used in mesh calculations. 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Marcin Roguski 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class CurvesHelper extends AbstractBlenderHelper { 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger LOGGER = Logger.getLogger(CurvesHelper.class.getName()); 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** Minimum basis U function degree for NURBS curves and surfaces. */ 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int minimumBasisUFunctionDegree = 4; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** Minimum basis V function degree for NURBS curves and surfaces. */ 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected int minimumBasisVFunctionDegree = 4; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This constructor parses the given blender version and stores the result. Some functionalities may differ in 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * different blender versions. 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderVersion 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the version read from the blend file 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param fixUpAxis 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * a variable that indicates if the Y asxis is the UP axis or not 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public CurvesHelper(String blenderVersion, boolean fixUpAxis) { 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super(blenderVersion, fixUpAxis); 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method converts given curve structure into a list of geometries representing the curve. The list is used here because on object 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * can have several separate curves. 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param curveStructure 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the curve structure 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return a list of geometries repreenting a single curve object 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws BlenderFileException 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public List<Geometry> toCurve(Structure curveStructure, BlenderContext blenderContext) throws BlenderFileException { 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String name = curveStructure.getName(); 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int flag = ((Number) curveStructure.getFieldValue("flag")).intValue(); 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean is3D = (flag & 0x01) != 0; 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean isFront = (flag & 0x02) != 0 && !is3D; 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean isBack = (flag & 0x04) != 0 && !is3D; 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (isFront) { 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta LOGGER.warning("No front face in curve implemented yet!");//TODO: implement front face 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (isBack) { 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta LOGGER.warning("No back face in curve implemented yet!");//TODO: implement back face 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //reading nurbs (and sorting them by material) 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Structure> nurbStructures = ((Structure) curveStructure.getFieldValue("nurb")).evaluateListBase(blenderContext); 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Map<Number, List<Structure>> nurbs = new HashMap<Number, List<Structure>>(); 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Structure nurb : nurbStructures) { 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Number matNumber = (Number) nurb.getFieldValue("mat_nr"); 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Structure> nurbList = nurbs.get(matNumber); 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (nurbList == null) { 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbList = new ArrayList<Structure>(); 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbs.put(matNumber, nurbList); 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbList.add(nurb); 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //getting materials 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class); 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Material[] materials = materialHelper.getMaterials(curveStructure, blenderContext); 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (materials == null) { 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta materials = new Material[]{blenderContext.getDefaultMaterial().clone()}; 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Material material : materials) { 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta material.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //getting or creating bevel object 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> bevelObject = null; 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pBevelObject = (Pointer) curveStructure.getFieldValue("bevobj"); 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pBevelObject.isNotNull()) { 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pBevelStructure = (Pointer) pBevelObject.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("data"); 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Structure bevelStructure = pBevelStructure.fetchData(blenderContext.getInputStream()).get(0); 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bevelObject = this.toCurve(bevelStructure, blenderContext); 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int bevResol = ((Number) curveStructure.getFieldValue("bevresol")).intValue(); 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float extrude = ((Number) curveStructure.getFieldValue("ext1")).floatValue(); 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float bevelDepth = ((Number) curveStructure.getFieldValue("ext2")).floatValue(); 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bevelDepth > 0.0f) { 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float handlerLength = bevelDepth / 2.0f; 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Vector3f> conrtolPoints = new ArrayList<Vector3f>(extrude > 0.0f ? 19 : 13); 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, extrude, 0)); 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, handlerLength + extrude, 0)); 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-handlerLength, bevelDepth + extrude, 0)); 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(0, bevelDepth + extrude, 0)); 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(handlerLength, bevelDepth + extrude, 0)); 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, extrude + handlerLength, 0)); 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, extrude, 0)); 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, extrude - handlerLength, 0)); 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (extrude > 0.0f) { 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, -extrude + handlerLength, 0)); 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, -extrude, 0)); 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(bevelDepth, -extrude - handlerLength, 0)); 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(handlerLength, -bevelDepth - extrude, 0)); 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(0, -bevelDepth - extrude, 0)); 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-handlerLength, -bevelDepth - extrude, 0)); 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, -handlerLength - extrude, 0)); 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, -extrude, 0)); 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (extrude > 0.0f) { 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, handlerLength - extrude, 0)); 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, -handlerLength + extrude, 0)); 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta conrtolPoints.add(new Vector3f(-bevelDepth, extrude, 0)); 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spline bevelSpline = new Spline(SplineType.Bezier, conrtolPoints, 0, false); 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Curve bevelCurve = new Curve(bevelSpline, bevResol); 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bevelObject = new ArrayList<Geometry>(1); 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bevelObject.add(new Geometry("", bevelCurve)); 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (extrude > 0.0f) { 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spline bevelSpline = new Spline(SplineType.Linear, new Vector3f[]{ 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Vector3f(0, extrude, 0), new Vector3f(0, -extrude, 0) 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }, 1, false); 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Curve bevelCurve = new Curve(bevelSpline, bevResol); 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bevelObject = new ArrayList<Geometry>(1); 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bevelObject.add(new Geometry("", bevelCurve)); 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //getting taper object 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Curve taperObject = null; 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pTaperObject = (Pointer) curveStructure.getFieldValue("taperobj"); 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bevelObject != null && pTaperObject.isNotNull()) { 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pTaperStructure = (Pointer) pTaperObject.fetchData(blenderContext.getInputStream()).get(0).getFieldValue("data"); 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Structure taperStructure = pTaperStructure.fetchData(blenderContext.getInputStream()).get(0); 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta taperObject = this.loadTaperObject(taperStructure, blenderContext); 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f loc = this.getLoc(curveStructure); 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //creating the result curves 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> result = new ArrayList<Geometry>(nurbs.size()); 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Entry<Number, List<Structure>> nurbEntry : nurbs.entrySet()) { 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Structure nurb : nurbEntry.getValue()) { 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int type = ((Number) nurb.getFieldValue("type")).intValue(); 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> nurbGeoms = null; 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if ((type & 0x01) != 0) {//Bezier curve 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbGeoms = this.loadBezierCurve(loc, nurb, bevelObject, taperObject, blenderContext); 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if ((type & 0x04) != 0) {//NURBS 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbGeoms = this.loadNurb(loc, nurb, bevelObject, taperObject, blenderContext); 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (nurbGeoms != null) {//setting the name and assigning materials 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Geometry nurbGeom : nurbGeoms) { 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbGeom.setMaterial(materials[nurbEntry.getKey().intValue()]); 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nurbGeom.setName(name); 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result.add(nurbGeom); 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //reading custom properties 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Properties properties = this.loadProperties(curveStructure, blenderContext); 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if(properties != null && properties.getValue() != null) { 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for(Geometry geom : result) { 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geom.setUserData("properties", properties); 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return result; 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method loads the bezier curve. 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param loc 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the translation of the curve 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param nurb 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the nurb structure 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param bevelObject 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bevel object 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperObject 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper object 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return a list of geometries representing the curves 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws BlenderFileException 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * an exception is thrown when there are problems with the blender file 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected List<Geometry> loadBezierCurve(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject, 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BlenderContext blenderContext) throws BlenderFileException { 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt"); 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> result = new ArrayList<Geometry>(); 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pBezierTriple.isNotNull()) { 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean smooth = (((Number) nurb.getFlatFieldValue("flag")).intValue() & 0x01) != 0; 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int resolution = ((Number) nurb.getFieldValue("resolu")).intValue(); 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean cyclic = (((Number) nurb.getFieldValue("flagu")).intValue() & 0x01) != 0; 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //creating the curve object 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(blenderContext.getInputStream()), 3); 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Vector3f> controlPoints = bezierCurve.getControlPoints(); 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (cyclic) { 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //copy the first three points at the end 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < 3; ++i) { 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.add(controlPoints.get(i)); 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //removing the first and last handles 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.remove(0); 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.remove(controlPoints.size() - 1); 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //creating curve 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spline spline = new Spline(SplineType.Bezier, controlPoints, 0, false); 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Curve curve = new Curve(spline, resolution); 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bevelObject == null) {//creating a normal curve 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry curveGeometry = new Geometry(null, curve); 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result.add(curveGeometry); 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TODO: use front and back flags; surface excluding algorithm for bezier circles should be added 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else {//creating curve with bevel and taper shape 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result = this.applyBevelAndTaper(curve, bevelObject, taperObject, smooth, blenderContext); 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return result; 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method loads the NURBS curve or surface. 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param loc 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * object's location 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param nurb 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the NURBS data structure 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param bevelObject 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bevel object to be applied 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperObject 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper object to be applied 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return a list of geometries that represents the loaded NURBS curve or surface 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws BlenderFileException 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * an exception is throw when problems with blender loaded data occurs 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @SuppressWarnings("unchecked") 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected List<Geometry> loadNurb(Vector3f loc, Structure nurb, List<Geometry> bevelObject, Curve taperObject, 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BlenderContext blenderContext) throws BlenderFileException { 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //loading the knots 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Float>[] knots = new List[2]; 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer[] pKnots = new Pointer[]{(Pointer) nurb.getFieldValue("knotsu"), (Pointer) nurb.getFieldValue("knotsv")}; 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < knots.length; ++i) { 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pKnots[i].isNotNull()) { 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FileBlockHeader fileBlockHeader = blenderContext.getFileBlock(pKnots[i].getOldMemoryAddress()); 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BlenderInputStream blenderInputStream = blenderContext.getInputStream(); 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta blenderInputStream.setPosition(fileBlockHeader.getBlockPosition()); 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int knotsAmount = fileBlockHeader.getCount() * fileBlockHeader.getSize() / 4; 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta knots[i] = new ArrayList<Float>(knotsAmount); 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < knotsAmount; ++j) { 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta knots[i].add(Float.valueOf(blenderInputStream.readFloat())); 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //loading the flags and orders (basis functions degrees) 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int flagU = ((Number) nurb.getFieldValue("flagu")).intValue(); 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int flagV = ((Number) nurb.getFieldValue("flagv")).intValue(); 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int orderU = ((Number) nurb.getFieldValue("orderu")).intValue(); 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int orderV = ((Number) nurb.getFieldValue("orderv")).intValue(); 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //loading control points and their weights 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pntsU = ((Number) nurb.getFieldValue("pntsu")).intValue(); 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pntsV = ((Number) nurb.getFieldValue("pntsv")).intValue(); 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Structure> bPoints = ((Pointer) nurb.getFieldValue("bp")).fetchData(blenderContext.getInputStream()); 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<List<Vector4f>> controlPoints = new ArrayList<List<Vector4f>>(pntsV); 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < pntsV; ++i) { 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Vector4f> uControlPoints = new ArrayList<Vector4f>(pntsU); 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < pntsU; ++j) { 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DynamicArray<Float> vec = (DynamicArray<Float>) bPoints.get(j + i * pntsU).getFieldValue("vec"); 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (fixUpAxis) { 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(2).floatValue(), -vec.get(1).floatValue(), vec.get(3).floatValue())); 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta uControlPoints.add(new Vector4f(vec.get(0).floatValue(), vec.get(1).floatValue(), vec.get(2).floatValue(), vec.get(3).floatValue())); 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if ((flagU & 0x01) != 0) { 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int k = 0; k < orderU - 1; ++k) { 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta uControlPoints.add(uControlPoints.get(k)); 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.add(uControlPoints); 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if ((flagV & 0x01) != 0) { 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int k = 0; k < orderV - 1; ++k) { 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.add(controlPoints.get(k)); 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int resolu = ((Number) nurb.getFieldValue("resolu")).intValue() + 1; 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> result; 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (knots[1] == null) {//creating the curve 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spline nurbSpline = new Spline(controlPoints.get(0), knots[0]); 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Curve nurbCurve = new Curve(nurbSpline, resolu); 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bevelObject != null) { 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result = this.applyBevelAndTaper(nurbCurve, bevelObject, taperObject, true, blenderContext);//TODO: smooth 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result = new ArrayList<Geometry>(1); 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry nurbGeometry = new Geometry("", nurbCurve); 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result.add(nurbGeometry); 33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else {//creating the nurb surface 33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int resolv = ((Number) nurb.getFieldValue("resolv")).intValue() + 1; 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Surface nurbSurface = Surface.createNurbsSurface(controlPoints, knots, resolu, resolv, orderU, orderV); 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry nurbGeometry = new Geometry("", nurbSurface); 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result = new ArrayList<Geometry>(1); 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result.add(nurbGeometry); 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return result; 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method returns the taper scale that should be applied to the object. 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperPoints 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper points 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperLength 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper curve length 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param percent 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the percent of way along the whole taper curve 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param store 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the vector where the result will be stored 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected float getTaperScale(float[] taperPoints, float taperLength, float percent) { 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float length = taperLength * percent; 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float currentLength = 0; 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f p = new Vector3f(); 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i; 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (i = 0; i < taperPoints.length - 6 && currentLength < length; i += 3) { 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta p.set(taperPoints[i], taperPoints[i + 1], taperPoints[i + 2]); 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta p.subtractLocal(taperPoints[i + 3], taperPoints[i + 4], taperPoints[i + 5]); 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentLength += p.length(); 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta currentLength -= p.length(); 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float leftLength = length - currentLength; 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float percentOnSegment = p.length() == 0 ? 0 : leftLength / p.length(); 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f store = FastMath.interpolateLinear(percentOnSegment, 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Vector3f(taperPoints[i], taperPoints[i + 1], taperPoints[i + 2]), 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta new Vector3f(taperPoints[i + 3], taperPoints[i + 4], taperPoints[i + 5])); 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return store.y; 37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method applies bevel and taper objects to the curve. 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param curve 37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the curve we apply the objects to 37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param bevelObject 37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the bevel object 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperObject 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper object 38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param smooth 38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the smooth flag 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return a list of geometries representing the beveled and/or tapered curve 38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected List<Geometry> applyBevelAndTaper(Curve curve, List<Geometry> bevelObject, Curve taperObject, 38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta boolean smooth, BlenderContext blenderContext) { 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] curvePoints = BufferUtils.getFloatArray(curve.getFloatBuffer(Type.Position)); 39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta MeshHelper meshHelper = blenderContext.getHelper(MeshHelper.class); 39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float curveLength = curve.getLength(); 39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TODO: use the smooth var 39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //taper data 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] taperPoints = null; 39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float taperLength = 0; 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (taperObject != null) { 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta taperPoints = BufferUtils.getFloatArray(taperObject.getFloatBuffer(Type.Position)); 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta taperLength = taperObject.getLength(); 40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //several objects can be allocated only once 40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f p = new Vector3f(); 40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f z = new Vector3f(0, 0, 1); 40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f negativeY = new Vector3f(0, -1, 0); 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Matrix4f m = new Matrix4f(); 40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float lengthAlongCurve = 0, taperScale = 1.0f; 40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Quaternion planeRotation = new Quaternion(); 41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Quaternion zRotation = new Quaternion(); 41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] temp = new float[]{0, 0, 0, 1}; 41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Map<Vector3f, Vector3f> normalMap = new HashMap<Vector3f, Vector3f>();//normalMap merges normals of faces that will be rendered smooth 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer[] vertexBuffers = new FloatBuffer[bevelObject.size()]; 41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer[] normalBuffers = new FloatBuffer[bevelObject.size()]; 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta IntBuffer[] indexBuffers = new IntBuffer[bevelObject.size()]; 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int geomIndex = 0; geomIndex < bevelObject.size(); ++geomIndex) { 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh mesh = bevelObject.get(geomIndex).getMesh(); 41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer positions = mesh.getFloatBuffer(Type.Position); 42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] vertices = BufferUtils.getFloatArray(positions); 42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < curvePoints.length; i += 3) { 42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta p.set(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]); 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f v; 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i == 0) { 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = new Vector3f(curvePoints[3] - p.x, curvePoints[4] - p.y, curvePoints[5] - p.z); 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (i + 3 >= curvePoints.length) { 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = new Vector3f(p.x - curvePoints[i - 3], p.y - curvePoints[i - 2], p.z - curvePoints[i - 1]); 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta lengthAlongCurve += v.length(); 43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v = new Vector3f(curvePoints[i + 3] - curvePoints[i - 3], 43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta curvePoints[i + 4] - curvePoints[i - 2], 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta curvePoints[i + 5] - curvePoints[i - 1]); 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta lengthAlongCurve += new Vector3f(curvePoints[i + 3] - p.x, curvePoints[i + 4] - p.y, curvePoints[i + 5] - p.z).length(); 43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v.normalizeLocal(); 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float angle = FastMath.acos(v.dot(z)); 43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta v.crossLocal(z).normalizeLocal();//v is the rotation axis now 44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta planeRotation.fromAngleAxis(angle, v); 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f zAxisRotationVector = negativeY.cross(v).normalizeLocal(); 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float zAxisRotationAngle = FastMath.acos(negativeY.dot(v)); 44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta zRotation.fromAngleAxis(zAxisRotationAngle, zAxisRotationVector); 44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //point transformation matrix 44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (taperPoints != null) { 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta taperScale = this.getTaperScale(taperPoints, taperLength, lengthAlongCurve / curveLength); 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta m.set(Matrix4f.IDENTITY); 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta m.setRotationQuaternion(planeRotation.multLocal(zRotation)); 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta m.setTranslation(p); 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //these vertices need to be thrown on XY plane 45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //and moved to the origin of [p1.x, p1.y] on the plane 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f[] verts = new Vector3f[vertices.length / 3]; 45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int j = 0; j < verts.length; ++j) { 45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta temp[0] = vertices[j * 3] * taperScale; 45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta temp[1] = vertices[j * 3 + 1] * taperScale; 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta temp[2] = 0; 46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta m.mult(temp);//the result is stored in the array 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (fixUpAxis) {//TODO: not the other way ??? 46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta verts[j] = new Vector3f(temp[0], temp[1], temp[2]); 46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta verts[j] = new Vector3f(temp[0], temp[2], -temp[1]); 46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (vertexBuffers[geomIndex] == null) { 46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vertexBuffers[geomIndex] = BufferUtils.createFloatBuffer(verts.length * curvePoints.length); 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer buffer = BufferUtils.createFloatBuffer(verts); 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vertexBuffers[geomIndex].put(buffer); 47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //adding indexes 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta IntBuffer indexBuffer = indexBuffers[geomIndex]; 47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (indexBuffer == null) { 47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //the amount of faces in the final mesh is the amount of edges in the bevel curve 47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //(which is less by 1 than its number of vertices) 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //multiplied by 2 (because each edge has two faces assigned on both sides) 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //and multiplied by the amount of bevel curve repeats which is equal to the amount of vertices on the target curve 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //finally we need to subtract the bevel edges amount 2 times because the border edges have only one face attached 48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //and at last multiply everything by 3 because each face needs 3 indexes to be described 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int bevelCurveEdgesAmount = verts.length - 1; 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer = BufferUtils.createIntBuffer(((bevelCurveEdgesAmount << 1) * curvePoints.length - bevelCurveEdgesAmount << 1) * 3); 48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffers[geomIndex] = indexBuffer; 48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int pointOffset = i / 3 * verts.length; 48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (i + 3 < curvePoints.length) { 48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int index = 0; index < verts.length - 1; ++index) { 49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(index + pointOffset); 49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(index + pointOffset + 1); 49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(verts.length + index + pointOffset); 49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(verts.length + index + pointOffset); 49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(index + pointOffset + 1); 49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta indexBuffer.put(verts.length + index + pointOffset + 1); 49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //calculating the normals 50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int geomIndex = 0; geomIndex < bevelObject.size(); ++geomIndex) { 50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f[] allVerts = BufferUtils.getVector3Array(vertexBuffers[geomIndex]); 50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int[] allIndices = BufferUtils.getIntArray(indexBuffers[geomIndex]); 50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < allIndices.length - 3; i += 3) { 50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f n = FastMath.computeNormal(allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]); 50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta meshHelper.addNormal(n, normalMap, smooth, allVerts[allIndices[i]], allVerts[allIndices[i + 1]], allVerts[allIndices[i + 2]]); 50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (normalBuffers[geomIndex] == null) { 51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalBuffers[geomIndex] = BufferUtils.createFloatBuffer(allVerts.length * 3); 51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Vector3f v : allVerts) { 51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector3f n = normalMap.get(v); 51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalBuffers[geomIndex].put(n.x); 51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalBuffers[geomIndex].put(n.y); 51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normalBuffers[geomIndex].put(n.z); 51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> result = new ArrayList<Geometry>(vertexBuffers.length); 52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Float oneReferenceToCurveLength = new Float(curveLength);//its important for array modifier to use one reference here 52259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < vertexBuffers.length; ++i) { 52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh mesh = new Mesh(); 52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.setBuffer(Type.Position, 3, vertexBuffers[i]); 52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.setBuffer(Type.Index, 3, indexBuffers[i]); 52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.setBuffer(Type.Normal, 3, normalBuffers[i]); 52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry g = new Geometry("g" + i, mesh); 52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta g.setUserData("curveLength", oneReferenceToCurveLength); 52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta g.updateModelBound(); 53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta result.add(g); 53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return result; 53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method loads the taper object. 53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param taperStructure 53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the taper structure 54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param blenderContext 54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the blender context 54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the taper object 54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @throws BlenderFileException 54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Curve loadTaperObject(Structure taperStructure, BlenderContext blenderContext) throws BlenderFileException { 54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //reading nurbs 54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Structure> nurbStructures = ((Structure) taperStructure.getFieldValue("nurb")).evaluateListBase(blenderContext); 54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Structure nurb : nurbStructures) { 54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Pointer pBezierTriple = (Pointer) nurb.getFieldValue("bezt"); 55059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (pBezierTriple.isNotNull()) { 55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //creating the curve object 55259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta BezierCurve bezierCurve = new BezierCurve(0, pBezierTriple.fetchData(blenderContext.getInputStream()), 3); 55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Vector3f> controlPoints = bezierCurve.getControlPoints(); 55459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //removing the first and last handles 55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.remove(0); 55659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta controlPoints.remove(controlPoints.size() - 1); 55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 55859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //return the first taper curve that has more than 3 control points 55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (controlPoints.size() > 3) { 56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spline spline = new Spline(SplineType.Bezier, controlPoints, 0, false); 56159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int resolution = ((Number) taperStructure.getFieldValue("resolu")).intValue(); 56259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Curve(spline, resolution); 56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 56759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 56859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 57059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * This method returns the translation of the curve. The UP axis is taken into account here. 57159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param curveStructure 57259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the curve structure 57359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return curve translation 57459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 57559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @SuppressWarnings("unchecked") 57659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected Vector3f getLoc(Structure curveStructure) { 57759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta DynamicArray<Number> locArray = (DynamicArray<Number>) curveStructure.getFieldValue("loc"); 57859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (fixUpAxis) { 57959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Vector3f(locArray.get(0).floatValue(), locArray.get(1).floatValue(), -locArray.get(2).floatValue()); 58059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 58159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return new Vector3f(locArray.get(0).floatValue(), locArray.get(2).floatValue(), locArray.get(1).floatValue()); 58259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 58659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean shouldBeLoaded(Structure structure, BlenderContext blenderContext) { 58759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 58859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}