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}