org.jtrfp.trcl.obj.TunnelSegment.java Source code

Java tutorial

Introduction

Here is the source code for org.jtrfp.trcl.obj.TunnelSegment.java

Source

/*******************************************************************************
 * This file is part of TERMINAL RECALL
 * Copyright (c) 2012-2014 Chuck Ritola
 * Part of the jTRFP.org project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     chuck - initial API and implementation
 ******************************************************************************/
package org.jtrfp.trcl.obj;

import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.jtrfp.trcl.Controller;
import org.jtrfp.trcl.RenderMode;
import org.jtrfp.trcl.Triangle;
import org.jtrfp.trcl.beh.Behavior;
import org.jtrfp.trcl.beh.CollisionBehavior;
import org.jtrfp.trcl.core.TR;
import org.jtrfp.trcl.core.TextureDescription;
import org.jtrfp.trcl.file.TNLFile.Segment;
import org.jtrfp.trcl.file.TNLFile.Segment.FlickerLightType;
import org.jtrfp.trcl.gpu.Model;
import org.jtrfp.trcl.math.IntRandomTransferFunction;

public class TunnelSegment extends WorldObject {
    public static final int TUNNEL_DIA_SCALAR = 128;
    public static final int TUNNEL_SEG_LEN = 65535;
    Segment segment;
    private final double segmentLength;
    private final double endX, endY;

    public TunnelSegment(TR tr, Segment s, TextureDescription[] tunnelTexturePalette, double segLen, double endX,
            double endY) {
        super(tr, createModel(s, segLen, tunnelTexturePalette, endX, endY, tr));
        segmentLength = segLen;
        this.endX = endX;
        this.endY = endY;
        this.segment = s;
        addBehavior(new TunnelSegmentBehavior());
    }

    private static class TunnelSegmentBehavior extends Behavior implements CollisionBehavior {

        @Override
        public void proposeCollision(WorldObject other) {//DUMMY
        }

    }

    public static double getStartWidth(Segment s) {
        return TR.legacy2Modern(s.getStartWidth() * TUNNEL_DIA_SCALAR * 3);
    }

    public static double getEndWidth(Segment s) {
        return TR.legacy2Modern(s.getEndWidth() * TUNNEL_DIA_SCALAR * 3);
    }

    public static double getStartHeight(Segment s) {
        return TR.legacy2Modern(s.getStartHeight() * TUNNEL_DIA_SCALAR * 3);
    }

    public static double getEndHeight(Segment s) {
        return TR.legacy2Modern(s.getEndHeight() * TUNNEL_DIA_SCALAR * 3);
    }

    private static final IntRandomTransferFunction flickerRandom = new IntRandomTransferFunction();

    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);
            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;
    }//end createModel()

    private static Vector3D segPoint(double angle, double z, double w, double h, double x, double y) {
        return new Vector3D(-Math.cos(angle) * w + x, Math.sin(angle) * h + y, z);
    }

    public Segment getSegmentData() {
        return segment;
    }

    public double getSegmentLength() {
        return segmentLength;
    }

    public double getEndX() {
        return endX;
    }

    public double getEndY() {
        return endY;
    }
}// end TunnelSegment