Example usage for org.apache.commons.math3.geometry.euclidean.threed Vector3D getX

List of usage examples for org.apache.commons.math3.geometry.euclidean.threed Vector3D getX

Introduction

In this page you can find the example usage for org.apache.commons.math3.geometry.euclidean.threed Vector3D getX.

Prototype

public double getX() 

Source Link

Document

Get the abscissa of the vector.

Usage

From source file:org.jtrfp.trcl.obj.DEFObject.java

private void fallingObjectBehavior() {
    canTurn = false;/*from  w  w w  .  jav a  2 s.c o m*/
    mobile = false;//Technically wrong but propulsion is unneeded.
    //addBehavior(new PulledDownByGravityBehavior());
    final MovesByVelocity mbv = new MovesByVelocity();
    mbv.setVelocity(new Vector3D(3500, -100000, 5000));
    addBehavior(mbv);
    //addBehavior(new VelocityDragBehavior().setDragCoefficient(.99)); // For some reason it falls like pine tar
    addBehavior(new DamageableBehavior().setMaxHealth(10).setHealth(10));
    addBehavior(new DeathBehavior());
    addBehavior(new CollidesWithTerrain().setIgnoreCeiling(true));
    addBehavior(new DamagedByCollisionWithSurface());
    addBehavior(new RotationalMomentumBehavior().setEquatorialMomentum(.01).setLateralMomentum(.02)
            .setPolarMomentum(.03));
    {
        final DEFObject thisObject = this;
        final TR thisTr = getTr();
        addBehavior(new ResetsRandomlyAfterDeath().setMinWaitMillis(1000).setMaxWaitMillis(5000)
                .setRunOnReset(new Runnable() {
                    @Override
                    public void run() {
                        final Vector3D centerPos = thisObject.probeForBehavior(DeathBehavior.class)
                                .getLocationOfLastDeath();
                        thisObject.probeForBehavior(MovesByVelocity.class)
                                .setVelocity(new Vector3D(7000, -200000, 1000));
                        final double[] pos = thisObject.getPosition();
                        pos[0] = centerPos.getX() + Math.random() * TR.mapSquareSize * 3
                                - TR.mapSquareSize * 1.5;
                        pos[1] = thisTr.getWorld().sizeY / 2 + thisTr.getWorld().sizeY * (Math.random()) * .3;
                        pos[2] = centerPos.getZ() + Math.random() * TR.mapSquareSize * 3
                                - TR.mapSquareSize * 1.5;
                        thisObject.notifyPositionChange();
                    }//end run()
                }));
    }
}

From source file:org.jtrfp.trcl.obj.Explosion.java

public Explosion(TR tr, ExplosionType type) {
    super(tr, type.getMillisPerFrame(), type.getAnimationFiles().length);
    final Vector3D origin = type.getOrigin();
    this.setModelOffset(origin.getX() * type.getBillboardSize().getWidth() * -.5,
            origin.getY() * type.getBillboardSize().getHeight() * -.5, origin.getZ());
    this.type = type;
    setBillboardSize(type.getBillboardSize());
    if (type.isRandomRotate())
        setRotation(2 * Math.PI * Math.random());
    String[] aniFiles = type.getAnimationFiles();
    Texture[] frames = new Texture[aniFiles.length];
    try {//www . j  a  va 2s .  c  o m
        for (int i = 0; i < aniFiles.length; i++) {
            frames[i] = frame(aniFiles[i]);
        }
    } //end try{}
    catch (Exception e) {
        e.printStackTrace();
    }
    setTexture(new AnimatedTexture(getSequencer(), frames), true);
}

From source file:org.jtrfp.trcl.obj.ExplosionSystem.java

public Explosion triggerExplosion(Vector3D loc, ExplosionType type) {
    if (!isNewExplosionFeasible(loc, type))
        return null;
    indices[type.ordinal()]++;/* www . ja  v  a 2s .  co  m*/
    indices[type.ordinal()] %= MAX_EXPLOSIONS_PER_POOL;
    Explosion result = allExplosions[type.ordinal()][indices[type.ordinal()]];
    result.destroy();
    result.reset();
    result.setPosition(loc.getX(), loc.getY(), loc.getZ());
    result.notifyPositionChange();
    final SmokeSystem sf = tr.getResourceManager().getSmokeSystem();
    final int NUM_PUFFS = 1;

    for (int i = 0; i < NUM_PUFFS; i++) {
        sf.triggerSmoke(loc.add(new Vector3D(Math.random() * 10000 - 5000, Math.random() * 10000 - 5000,
                Math.random() * 10000 - 5000)), SmokeType.Puff);
    } //end for(i)

    add(result);
    return result;
}

From source file:org.jtrfp.trcl.obj.TunnelSegment.java

private static Model createModel(Segment s, double segLen, TextureDescription[] tunnelTexturePalette,
        double endX, double endY, final TR tr) {
    Model mainModel = new Model(true, tr);
    mainModel.setDebugName("tunnelSegment main.");
    final int numPolys = s.getNumPolygons();
    double startWidth = getStartWidth(s);
    double startHeight = getStartHeight(s);
    double endWidth = getEndWidth(s);
    double endHeight = getEndHeight(s);
    final FlickerLightType lightType = s.getFlickerLightType();
    // TODO: Cleanup.
    final double startAngle1 = ((double) s.getStartAngle1() / 65535.) * 2. * Math.PI;
    final double startAngle2 = ((double) s.getStartAngle2() / 65535.) * 2. * Math.PI;
    final double startAngle = startAngle1;
    final double endAngle1 = ((double) s.getEndAngle1() / 65535.) * 2. * Math.PI;
    final double endAngle2 = ((double) s.getEndAngle2() / 65535.) * 2. * Math.PI;
    double endAngle = endAngle1;
    final double dAngleStart = (startAngle2 - startAngle1) / (double) numPolys;
    final double dAngleEnd = (endAngle2 - endAngle1) / (double) numPolys;
    final double startX = 0;
    final double startY = 0;
    final double zStart = 0;
    final double zEnd = segLen;
    final int numPolygonsMinusOne = s.getNumPolygons() - 1;
    final int lightPoly = s.getLightPolygon();
    final boolean hasLight = lightPoly != -1;
    if (hasLight) {
        mainModel.setAnimateUV(true);//from  www .j a v  a  2s .  c o  m
        mainModel.setSmoothAnimation(false);
        if (lightType == FlickerLightType.noLight) {
            //Do nothing.
        } else if (lightType == FlickerLightType.off1p5Sec) {
            mainModel.setController(new Controller() {
                private final int off = (int) (Math.random() * 2000);

                @Override
                public double getCurrentFrame() {
                    return (off + System.currentTimeMillis() % 2000) > 1500 ? 1 : 0;
                }

                @Override
                public void setDebugMode(boolean b) {
                    //Not implemented.
                }
            });
        } else if (lightType == FlickerLightType.on1p5Sec) {
            mainModel.setController(new Controller() {
                private final int off = (int) (Math.random() * 2000);

                @Override
                public double getCurrentFrame() {
                    return (off + System.currentTimeMillis() % 2000) < 1500 ? 1 : 0;
                }

                @Override
                public void setDebugMode(boolean b) {
                    //Not implemented.
                }
            });
        } else if (lightType == FlickerLightType.on1Sec) {
            mainModel.setController(new Controller() {
                private final int off = (int) (Math.random() * 2000);

                @Override
                public double getCurrentFrame() {
                    return (off + System.currentTimeMillis() % 2000) > 1000 ? 1 : 0;
                }

                @Override
                public void setDebugMode(boolean b) {
                    //Not implemented.
                }
            });
        }
    } //end (has light)
    final double[] noLightU = new double[] { 1, 1, 0, 0 };
    final double[] noLightV = new double[] { 0, 1, 1, 0 };
    final double[] lightOffU = new double[] { 1, 1, .5, .5 };
    final double[] lightOffV = new double[] { .5, 1, 1, .5 };
    final double[] lightOnU = new double[] { .5, .5, 0, 0 };
    final double[] lightOnV = new double[] { .5, 1, 1, .5 };

    double rotPeriod = (1000. * 32768.) / (double) s.getRotationSpeed();
    final boolean reverseDirection = rotPeriod < 0;
    if (reverseDirection)
        rotPeriod *= -1;
    final int numFramesIfRotating = 30;
    final int numFramesIfStatic = 2;
    final boolean isRotating = !Double.isInfinite(rotPeriod);
    int numAnimFrames = isRotating ? numFramesIfRotating : numFramesIfStatic;
    if (isRotating)
        mainModel.setFrameDelayInMillis((int) (rotPeriod / (numAnimFrames)));
    final double animationDeltaRadians = isRotating
            ? ((reverseDirection ? 1 : -1) * (2 * Math.PI) / (double) numAnimFrames)
            : 0;
    //FRAME LOOP
    for (int frameIndex = 0; frameIndex < numAnimFrames; frameIndex++) {
        final Model m = new Model(false, tr);
        m.setDebugName("TunnelSegment frame " + frameIndex + " of " + numAnimFrames);
        final double frameAngleDeltaRadians = animationDeltaRadians * (double) frameIndex;
        double frameStartAngle = startAngle + frameAngleDeltaRadians;
        double frameEndAngle = endAngle + frameAngleDeltaRadians;
        final double frameStartAngle1 = startAngle1 + frameAngleDeltaRadians;
        final double frameStartAngle2 = startAngle2 + frameAngleDeltaRadians;
        final double frameEndAngle1 = endAngle + frameAngleDeltaRadians;
        double[] thisU = noLightU, thisV = noLightV;//Changeable u/v references, default to noLight
        // Poly quads
        for (int pi = 0; pi < numPolygonsMinusOne; pi++) {
            Vector3D p0 = segPoint(frameStartAngle, zStart, startWidth, startHeight, startX, startY);
            Vector3D p1 = segPoint(frameEndAngle, zEnd, endWidth, endHeight, endX, endY);
            Vector3D p2 = segPoint(frameEndAngle + dAngleEnd, zEnd, endWidth, endHeight, endX, endY);
            Vector3D p3 = segPoint(frameStartAngle + dAngleStart, zStart, startWidth, startHeight, startX,
                    startY);

            TextureDescription tex = tunnelTexturePalette[s.getPolyTextureIndices().get(pi)];

            if (pi == lightPoly && lightType != FlickerLightType.noLight) {
                if (frameIndex == 0) {
                    thisU = lightOnU;
                    thisV = lightOnV;
                } else {
                    thisU = lightOffU;
                    thisV = lightOffV;
                }
                /*try {
                            
                    final int flickerThresh = flt == FlickerLightType.off1p5Sec ? (int) (-.3 * (double) Integer.MAX_VALUE)
                       : flt == FlickerLightType.on1p5Sec ? (int) (.4 * (double) Integer.MAX_VALUE)
                          : flt == FlickerLightType.on1Sec ? (int) (.25 * (double) Integer.MAX_VALUE)
                             : Integer.MAX_VALUE;
                        
                    m.addTickableAnimator(new Tickable() {
                   @Override
                   public void tick() {
                       if (flickerRandom.transfer(Math.abs((int) System
                          .currentTimeMillis())) > flickerThresh)
                      st.setFrame(1);
                       else
                      st.setFrame(0);
                   }
                           
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }*/
            } else {
                thisU = noLightU;
                thisV = noLightV;
            } // No light

            m.addTriangles(Triangle.quad2Triangles(new double[] { p3.getX(), p2.getX(), p1.getX(), p0.getX() },
                    new double[] { p3.getY(), p2.getY(), p1.getY(), p0.getY() },
                    new double[] { p3.getZ(), p2.getZ(), p1.getZ(), p0.getZ() }, thisU, thisV, tex,
                    RenderMode.DYNAMIC,
                    new Vector3D[] {
                            new Vector3D(Math.cos(frameStartAngle + dAngleStart),
                                    -Math.sin(frameStartAngle + dAngleStart), 0),
                            new Vector3D(Math.cos(frameEndAngle + dAngleEnd),
                                    -Math.sin(frameEndAngle + dAngleEnd), 0),
                            new Vector3D(Math.cos(frameEndAngle), -Math.sin(frameEndAngle), 0),
                            new Vector3D(Math.cos(frameStartAngle), -Math.sin(frameStartAngle), 0) },
                    0));
            frameStartAngle += dAngleStart;
            frameEndAngle += dAngleEnd;
        } // for(polygons)
        if (s.isCutout()) {
            // The slice quad
            // INWARD
            Vector3D p0 = segPoint(frameStartAngle, zStart, startWidth, startHeight, startX, startY);
            Vector3D p1 = segPoint(frameEndAngle, zEnd, endWidth, endHeight, endX, endY);
            Vector3D p2 = segPoint(frameEndAngle1, zEnd, 0, 0, endX, endY);
            Vector3D p3 = segPoint(frameStartAngle1, zStart, 0, 0, startX, startY);
            m.addTriangles(Triangle.quad2Triangles(new double[] { p3.getX(), p2.getX(), p1.getX(), p0.getX() },
                    new double[] { p3.getY(), p2.getY(), p1.getY(), p0.getY() },
                    new double[] { p3.getZ(), p2.getZ(), p1.getZ(), p0.getZ() },

                    new double[] { 1, 1, 0, 0 }, new double[] { 0, 1, 1, 0 },
                    tunnelTexturePalette[s.getPolyTextureIndices().get(numPolygonsMinusOne)],
                    RenderMode.DYNAMIC,
                    new Vector3D[] {
                            new Vector3D(Math.cos(frameStartAngle + dAngleStart),
                                    -Math.sin(frameStartAngle + dAngleStart), 0),
                            new Vector3D(Math.cos(frameEndAngle + dAngleEnd),
                                    -Math.sin(frameEndAngle + dAngleEnd), 0),
                            new Vector3D(Math.cos(frameEndAngle), -Math.sin(frameEndAngle), 0),
                            new Vector3D(Math.cos(frameStartAngle), -Math.sin(frameStartAngle), 0) },
                    0));
            // OUTWARD
            p3 = segPoint(frameStartAngle1, zStart, startWidth, startHeight, startX, startY);
            p2 = segPoint(frameEndAngle1, zEnd, endWidth, endHeight, endX, endY);
            p1 = segPoint(frameEndAngle1, zEnd, 0, 0, endX, endY);
            p0 = segPoint(frameStartAngle1, zStart, 0, 0, startX, startY);
            m.addTriangles(Triangle.quad2Triangles(new double[] { p3.getX(), p2.getX(), p1.getX(), p0.getX() },
                    new double[] { p3.getY(), p2.getY(), p1.getY(), p0.getY() },
                    new double[] { p3.getZ(), p2.getZ(), p1.getZ(), p0.getZ() },

                    new double[] { 1, 1, 0, 0 }, new double[] { 0, 1, 1, 0 },
                    tunnelTexturePalette[s.getPolyTextureIndices().get(numPolygonsMinusOne)],
                    RenderMode.DYNAMIC,
                    new Vector3D[] {
                            new Vector3D(Math.cos(frameStartAngle + dAngleStart),
                                    -Math.sin(frameStartAngle + dAngleStart), 0),
                            new Vector3D(Math.cos(frameEndAngle + dAngleEnd),
                                    -Math.sin(frameEndAngle + dAngleEnd), 0),
                            new Vector3D(Math.cos(frameEndAngle), -Math.sin(frameEndAngle), 0),
                            new Vector3D(Math.cos(frameStartAngle), -Math.sin(frameStartAngle), 0) },
                    0));
        } else {
            // The slice quad
            Vector3D p0 = segPoint(frameStartAngle, zStart, startWidth, startHeight, startX, startY);
            Vector3D p1 = segPoint(frameEndAngle, zEnd, endWidth, endHeight, endX, endY);
            Vector3D p2 = segPoint(frameEndAngle1, zEnd, endWidth, endHeight, endX, endY);
            Vector3D p3 = segPoint(frameStartAngle1, zStart, startWidth, startHeight, startX, startY);
            m.addTriangles(Triangle.quad2Triangles(new double[] { p3.getX(), p2.getX(), p1.getX(), p0.getX() },
                    new double[] { p3.getY(), p2.getY(), p1.getY(), p0.getY() },
                    new double[] { p3.getZ(), p2.getZ(), p1.getZ(), p0.getZ() },

                    new double[] { 1, 1, 0, 0 }, new double[] { 0, 1, 1, 0 },
                    tunnelTexturePalette[s.getPolyTextureIndices().get(numPolygonsMinusOne)],
                    RenderMode.DYNAMIC,
                    new Vector3D[] {
                            new Vector3D(Math.cos(frameStartAngle + dAngleStart),
                                    -Math.sin(frameStartAngle + dAngleStart), 0),
                            new Vector3D(Math.cos(frameEndAngle + dAngleEnd),
                                    -Math.sin(frameEndAngle + dAngleEnd), 0),
                            new Vector3D(Math.cos(frameEndAngle), -Math.sin(frameEndAngle), 0),
                            new Vector3D(Math.cos(frameStartAngle), -Math.sin(frameStartAngle), 0) },
                    0));
        } //end !cutout
          //if(numAnimFrames!=1)//Push frame if animated.
        mainModel.addFrame(m);
    } //end for(frames)
    return mainModel;
}

From source file:org.jtrfp.trcl.obj.WorldObject.java

protected void attemptLoop() {
    if (LOOP) {//w w  w  .j ava 2 s  .  c o  m
        final Vector3D camPos = tr.mainRenderer.get().getCamera().getCameraPosition();
        double delta = position[0] - camPos.getX();
        if (delta > TR.mapWidth / 2.) {
            position[0] -= TR.mapWidth;
            needToRecalcMatrix = true;
        } else if (delta < -TR.mapWidth / 2.) {
            position[0] += TR.mapWidth;
            needToRecalcMatrix = true;
        }
        delta = position[1] - camPos.getY();
        if (delta > TR.mapWidth / 2.) {
            position[1] -= TR.mapWidth;
            needToRecalcMatrix = true;
        } else if (delta < -TR.mapWidth / 2.) {
            position[1] += TR.mapWidth;
            needToRecalcMatrix = true;
        }
        delta = position[2] - camPos.getZ();
        if (delta > TR.mapWidth / 2.) {
            position[2] -= TR.mapWidth;
            needToRecalcMatrix = true;
        } else if (delta < -TR.mapWidth / 2.) {
            position[2] += TR.mapWidth;
            needToRecalcMatrix = true;
        }
    } //end if(LOOP)
}

From source file:org.jtrfp.trcl.obj.WorldObject.java

/**
 * @param heading//from   w w w. j  a v a 2s. c  o  m
 *            the heading to set
 */
public synchronized void setHeading(Vector3D nHeading) {
    heading[0] = nHeading.getX();
    heading[1] = nHeading.getY();
    heading[2] = nHeading.getZ();
    needToRecalcMatrix = true;
}

From source file:org.jtrfp.trcl.obj.WorldObject.java

/**
 * @param top//  w  ww. j a  v  a  2  s  .c om
 *            the top to set
 */
public synchronized void setTop(Vector3D nTop) {
    top[0] = nTop.getX();
    top[1] = nTop.getY();
    top[2] = nTop.getZ();
    needToRecalcMatrix = true;
}

From source file:org.jtrfp.trcl.obj.WorldObject.java

public synchronized void movePositionBy(Vector3D delta) {
    position[0] += delta.getX();
    position[1] += delta.getY();/*from  www  .  ja v a 2  s  .  c  om*/
    position[2] += delta.getZ();
    notifyPositionChange();
}

From source file:org.jtrfp.trcl.SpacePartitioningGrid.java

public SpacePartitioningGrid(Vector3D size, double squareSize, double viewingRadius) {
    setSquareSize(squareSize);//from  w  w  w.  ja v a  2s .  c  o m
    setSquaresX((int) (size.getX() / squareSize));
    setSquaresY((int) (size.getY() / squareSize));
    setSquaresZ((int) (size.getZ() / squareSize));
    setViewingRadius(viewingRadius);

    allocateSquares();
}

From source file:org.jtrfp.trcl.TerrainSystem.java

public TerrainSystem(final InterpolatingAltitudeMap altitude, final TextureMesh textureMesh,
        final double gridSquareSize, final SpacePartitioningGrid parent,
        final RenderableSpacePartitioningGrid terrainMirror, final TR tr, final TDFFile tdf,
        final boolean flatShading, final LoadingProgressReporter terrainReporter) {
    super(parent);
    final int numCores = Runtime.getRuntime().availableProcessors();
    this.tr = tr;
    final int width = (int) altitude.getWidth();
    int height = (int) altitude.getHeight();
    this.gridSquareSize = gridSquareSize;
    this.heightScalar = tr.getWorld().sizeY / 2;
    final int chunkSideLength = TR.terrainChunkSideLengthInSquares;
    final double u[] = { 0, 1, 1, 0 };
    final double v[] = { 0, 0, 1, 1 };
    final double cu[] = { 0, 1, 1, 0 };
    final double cv[] = { 1, 1, 0, 0 };

    // Come up with a point list for tunnel entrances and exits
    TDFFile.Tunnel[] tunnels = tdf.getTunnels();
    final HashMap<Integer, TunnelPoint> points = new HashMap<Integer, TunnelPoint>();
    final HashMap<String, TDFFile.Tunnel> tunnelsByName = new HashMap<String, TDFFile.Tunnel>();
    if (tunnels != null) {// Null means no tunnels
        for (int i = 0; i < tunnels.length; i++) {
            final TDFFile.Tunnel tun = tunnels[i];
            if (tun.getEntranceLogic() != TunnelLogic.invisible) {
                final TunnelPoint tp = new TunnelPoint(tun, true);
                points.put(tp.hashCode(), tp);
            }/*from w w  w .  j av  a2s .  c om*/
            if (tun.getExitLogic() != TunnelLogic.invisible) {
                final TunnelPoint tp = new TunnelPoint(tun, false);
                points.put(tp.hashCode(), tp);
                tunnelsByName.put(tun.getTunnelLVLFile(), tunnels[i]);
            } //end if(invisible)
        } // end for(tunnels)
    } // end if(tunnels)

    final LoadingProgressReporter[] reporters = terrainReporter.generateSubReporters(256 / chunkSideLength);
    int reporterIndex = 0;
    TRFutureTask<Void>[] rowTasks = new TRFutureTask[numCores * 2];
    int taskIdx = 0;
    // For each chunk
    for (int gZ = 0; gZ < height; gZ += chunkSideLength) {
        reporters[reporterIndex++].complete();
        final int _gZ = gZ;
        rowTasks[taskIdx++] = tr.getThreadManager().submitToThreadPool(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                for (int gX = 0; gX < width; gX += chunkSideLength) {
                    // GROUND
                    {// Start scope
                        final double objectX = Math
                                .round(((double) gX + ((double) chunkSideLength / 2.)) * gridSquareSize);
                        final double objectZ = Math
                                .round(((double) _gZ + ((double) chunkSideLength / 2.)) * gridSquareSize);
                        final double objectY = Math.round(altitude.heightAt(gX, _gZ) * heightScalar);
                        final Model m = new Model(false, tr);
                        // for each square
                        for (int cZ = _gZ; cZ < _gZ + chunkSideLength; cZ++) {
                            for (int cX = gX; cX < gX + chunkSideLength; cX++) {
                                final double hTL = altitude.heightAt(cX, cZ) * heightScalar;
                                final double hTR = altitude.heightAt((cX + 1), cZ) * heightScalar;
                                final double hBR = altitude.heightAt((cX + 1), (cZ + 1)) * heightScalar;
                                final double hBL = altitude.heightAt(cX, (cZ + 1)) * heightScalar;
                                final double xPos = cX * gridSquareSize;
                                final double zPos = cZ * gridSquareSize;

                                Vector3D norm0, norm1, norm2, norm3;
                                Vector3D norm = altitude.normalAt(cX, cZ);
                                norm3 = new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3).normalize();
                                norm = altitude.normalAt(cX + 1, cZ);
                                norm2 = new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3).normalize();
                                norm = altitude.normalAt(cX + 1, cZ + 1);
                                norm1 = new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3).normalize();
                                norm = altitude.normalAt(cX, cZ + 1);
                                norm0 = new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3).normalize();

                                if (flatShading)
                                    norm0 = norm1 = norm2 = norm3 = altitude.normalAt(cX + .5, cZ + .5);

                                final Integer tpi = cX + cZ * 256;
                                TextureDescription td = (TextureDescription) (points.containsKey(tpi)
                                        ? points.get(tpi).getTexture()
                                        : textureMesh.textureAt(cX, cZ));
                                Triangle[] tris = Triangle.quad2Triangles(
                                        // COUNTER-CLOCKWISE
                                        // //x
                                        new double[] { xPos - objectX, xPos + gridSquareSize - objectX,
                                                xPos + gridSquareSize - objectX, xPos - objectX },
                                        new double[] { hBL - objectY, hBR - objectY, hTR - objectY,
                                                hTL - objectY },
                                        new double[] { zPos + gridSquareSize - objectZ,
                                                zPos + gridSquareSize - objectZ, zPos - objectZ,
                                                zPos - objectZ },
                                        u, v, td, RenderMode.STATIC,
                                        new Vector3D[] { norm0, norm1, norm2, norm3 }, cX + cZ % 4);
                                m.addTriangle(tris[0]);
                                m.addTriangle(tris[1]);
                            } // end for(cX)
                        } // end for(cZ)
                          // Add to grid
                        if (m.finalizeModel().getTriangleList() != null) {
                            final TerrainChunk chunkToAdd = new TerrainChunk(tr, m, altitude);
                            final double[] chunkPos = chunkToAdd.getPosition();
                            chunkPos[0] = objectX;
                            chunkPos[1] = objectY;
                            chunkPos[2] = objectZ;
                            chunkToAdd.notifyPositionChange();
                            add(chunkToAdd);
                        } else {
                            System.out.println("Rejected chunk: " + m.getDebugName());
                        }
                    } // end scope

                    {// start scope ///// CEILING
                        final double objectX = Math
                                .round(((double) gX + ((double) chunkSideLength / 2.)) * gridSquareSize);
                        final double objectZ = Math
                                .round(((double) _gZ + ((double) chunkSideLength / 2.)) * gridSquareSize);
                        final double objectY = Math
                                .round((2. - altitude.heightAt(gX, _gZ)) * heightScalar + Y_NUDGE);
                        final Model m = new Model(false, tr);
                        // for each square
                        for (int cZ = _gZ; cZ < _gZ + chunkSideLength; cZ++) {
                            for (int cX = gX; cX < gX + chunkSideLength; cX++) {
                                final double hTL = (2. - altitude.heightAt(cX, cZ)) * heightScalar + Y_NUDGE;
                                final double hTR = (2. - altitude.heightAt((cX + 1), cZ)) * heightScalar
                                        + Y_NUDGE;
                                final double hBR = (2. - altitude.heightAt((cX + 1), (cZ + 1))) * heightScalar
                                        + Y_NUDGE;
                                final double hBL = (2. - altitude.heightAt(cX, (cZ + 1))) * heightScalar
                                        + Y_NUDGE;
                                final double xPos = cX * gridSquareSize;
                                final double zPos = cZ * gridSquareSize;

                                Vector3D norm0, norm1, norm2, norm3;
                                Vector3D norm = altitude.normalAt(cX, cZ);
                                norm3 = altitude.heightAt(cX, cZ) < .9
                                        ? new Vector3D(norm.getX() * 3, norm.getY() * -1, norm.getZ() * 3)
                                                .normalize()
                                        : new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3)
                                                .normalize();
                                norm = altitude.normalAt(cX + 1, cZ);
                                norm2 = altitude.heightAt(cX + 1, cZ) < .9
                                        ? new Vector3D(norm.getX() * 3, norm.getY() * -1, norm.getZ() * 3)
                                                .normalize()
                                        : new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3)
                                                .normalize();
                                norm = altitude.normalAt(cX + 1, cZ + 1);
                                norm1 = altitude.heightAt(cX + 1, cZ + 1) < .9
                                        ? new Vector3D(norm.getX() * 3, norm.getY() * -1, norm.getZ() * 3)
                                                .normalize()
                                        : new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3)
                                                .normalize();
                                norm = altitude.normalAt(cX, cZ + 1);
                                norm0 = altitude.heightAt(cX, cZ + 1) < .9
                                        ? new Vector3D(norm.getX() * 3, norm.getY() * -1, norm.getZ() * 3)
                                                .normalize()
                                        : new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3)
                                                .normalize();

                                if (flatShading)
                                    norm0 = norm1 = norm2 = norm3 = altitude.normalAt(cX + .5, cZ + .5);

                                // Ceiling texture cell X (Z in this engine) value
                                // is offset by 10.
                                // No tunnelpoints on ceiling
                                TextureDescription td = (TextureDescription) (textureMesh.textureAt(cX,
                                        cZ + 10));
                                norm = new Vector3D(norm.getX() * 3, norm.getY(), norm.getZ() * 3).normalize();// Exaggerate
                                // features.
                                Triangle[] tris = Triangle.quad2Triangles(
                                        // CLOCKWISE (else backface culling will eat
                                        // it)
                                        new double[] { xPos - objectX, xPos + gridSquareSize - objectX,
                                                xPos + gridSquareSize - objectX, xPos - objectX }, // x
                                        new double[] { hTL - objectY, hTR - objectY, hBR - objectY,
                                                hBL - objectY },
                                        new double[] { zPos - objectZ, zPos - objectZ,
                                                zPos + gridSquareSize - objectZ,
                                                zPos + gridSquareSize - objectZ },
                                        cu, cv, td, RenderMode.STATIC,
                                        new Vector3D[] { norm3, norm2, norm1, norm0 }, cX + cZ % 4);
                                m.addTriangle(tris[0]);
                                m.addTriangle(tris[1]);
                            } // end for(cX)
                        } // end for(cZ)
                          // Add to grid
                        if (m.finalizeModel().getTriangleList() != null) {
                            final TerrainChunk chunkToAdd = new TerrainChunk(tr, m, altitude);
                            final double[] chunkPos = chunkToAdd.getPosition();
                            chunkPos[0] = objectX;
                            chunkPos[1] = objectY;
                            chunkPos[2] = objectZ;
                            chunkToAdd.notifyPositionChange();
                            chunkToAdd.setCeiling(true);
                            terrainMirror.add(chunkToAdd);
                        } else {
                            System.out.println("Rejected chunk: " + m.getDebugName());
                        }
                    } // end scope(CEILING)
                } // end for(gX)
                return null;
            }
        });
        if (taskIdx >= rowTasks.length)
            taskIdx = 0;
    } // end for(gZ)
    terrainMirror.deactivate();
}