org.free.jake2.render.lwjgl.Warp.java Source code

Java tutorial

Introduction

Here is the source code for org.free.jake2.render.lwjgl.Warp.java

Source

/*
 * Warp.java
 * Copyright (C) 2003
 *
 * $Id: Warp.java,v 1.5 2005/01/17 15:42:29 cawe Exp $
 */
/*
Copyright (C) 1997-2001 Id Software, Inc.
    
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
See the GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    
 */
package org.free.jake2.render.lwjgl;

import org.free.jake2.Defines;
import org.free.jake2.Globals;
import org.free.jake2.qcommon.Com;
import org.free.jake2.render.*;
import org.free.jake2.util.Math3D;
import org.free.jake2.util.Vec3Cache;

import org.lwjgl.opengl.GL11;

/**
 * Warp
 *
 * @author cwei
 */
public abstract class Warp extends Model {
    // warpsin.h

    public static final float[] SIN = { 0f, 0.19633f, 0.392541f, 0.588517f, 0.784137f, 0.979285f, 1.17384f, 1.3677f,
            1.56072f, 1.75281f, 1.94384f, 2.1337f, 2.32228f, 2.50945f, 2.69512f, 2.87916f, 3.06147f, 3.24193f,
            3.42044f, 3.59689f, 3.77117f, 3.94319f, 4.11282f, 4.27998f, 4.44456f, 4.60647f, 4.76559f, 4.92185f,
            5.07515f, 5.22538f, 5.37247f, 5.51632f, 5.65685f, 5.79398f, 5.92761f, 6.05767f, 6.18408f, 6.30677f,
            6.42566f, 6.54068f, 6.65176f, 6.75883f, 6.86183f, 6.9607f, 7.05537f, 7.14579f, 7.23191f, 7.31368f,
            7.39104f, 7.46394f, 7.53235f, 7.59623f, 7.65552f, 7.71021f, 7.76025f, 7.80562f, 7.84628f, 7.88222f,
            7.91341f, 7.93984f, 7.96148f, 7.97832f, 7.99036f, 7.99759f, 8f, 7.99759f, 7.99036f, 7.97832f, 7.96148f,
            7.93984f, 7.91341f, 7.88222f, 7.84628f, 7.80562f, 7.76025f, 7.71021f, 7.65552f, 7.59623f, 7.53235f,
            7.46394f, 7.39104f, 7.31368f, 7.23191f, 7.14579f, 7.05537f, 6.9607f, 6.86183f, 6.75883f, 6.65176f,
            6.54068f, 6.42566f, 6.30677f, 6.18408f, 6.05767f, 5.92761f, 5.79398f, 5.65685f, 5.51632f, 5.37247f,
            5.22538f, 5.07515f, 4.92185f, 4.76559f, 4.60647f, 4.44456f, 4.27998f, 4.11282f, 3.94319f, 3.77117f,
            3.59689f, 3.42044f, 3.24193f, 3.06147f, 2.87916f, 2.69512f, 2.50945f, 2.32228f, 2.1337f, 1.94384f,
            1.75281f, 1.56072f, 1.3677f, 1.17384f, 0.979285f, 0.784137f, 0.588517f, 0.392541f, 0.19633f,
            9.79717e-16f, -0.19633f, -0.392541f, -0.588517f, -0.784137f, -0.979285f, -1.17384f, -1.3677f, -1.56072f,
            -1.75281f, -1.94384f, -2.1337f, -2.32228f, -2.50945f, -2.69512f, -2.87916f, -3.06147f, -3.24193f,
            -3.42044f, -3.59689f, -3.77117f, -3.94319f, -4.11282f, -4.27998f, -4.44456f, -4.60647f, -4.76559f,
            -4.92185f, -5.07515f, -5.22538f, -5.37247f, -5.51632f, -5.65685f, -5.79398f, -5.92761f, -6.05767f,
            -6.18408f, -6.30677f, -6.42566f, -6.54068f, -6.65176f, -6.75883f, -6.86183f, -6.9607f, -7.05537f,
            -7.14579f, -7.23191f, -7.31368f, -7.39104f, -7.46394f, -7.53235f, -7.59623f, -7.65552f, -7.71021f,
            -7.76025f, -7.80562f, -7.84628f, -7.88222f, -7.91341f, -7.93984f, -7.96148f, -7.97832f, -7.99036f,
            -7.99759f, -8f, -7.99759f, -7.99036f, -7.97832f, -7.96148f, -7.93984f, -7.91341f, -7.88222f, -7.84628f,
            -7.80562f, -7.76025f, -7.71021f, -7.65552f, -7.59623f, -7.53235f, -7.46394f, -7.39104f, -7.31368f,
            -7.23191f, -7.14579f, -7.05537f, -6.9607f, -6.86183f, -6.75883f, -6.65176f, -6.54068f, -6.42566f,
            -6.30677f, -6.18408f, -6.05767f, -5.92761f, -5.79398f, -5.65685f, -5.51632f, -5.37247f, -5.22538f,
            -5.07515f, -4.92185f, -4.76559f, -4.60647f, -4.44456f, -4.27998f, -4.11282f, -3.94319f, -3.77117f,
            -3.59689f, -3.42044f, -3.24193f, -3.06147f, -2.87916f, -2.69512f, -2.50945f, -2.32228f, -2.1337f,
            -1.94384f, -1.75281f, -1.56072f, -1.3677f, -1.17384f, -0.979285f, -0.784137f, -0.588517f, -0.392541f,
            -0.19633f };
    String skyname;
    float skyrotate;
    float[] skyaxis = { 0, 0, 0 };
    image_t[] sky_images = new image_t[6];
    msurface_t warpface;
    static final int SUBDIVIDE_SIZE = 64;

    /**
     * BoundPoly
     * @param numverts
     * @param verts
     * @param mins
     * @param maxs
     */
    void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) {
        mins[0] = mins[1] = mins[2] = 9999;
        maxs[0] = maxs[1] = maxs[2] = -9999;

        int j;
        float[] v10;
        for (int i = 0; i < numverts; i++) {
            v10 = verts[i];
            for (j = 0; j < 3; j++) {
                if (v10[j] < mins[j]) {
                    mins[j] = v10[j];
                }
                if (v10[j] > maxs[j]) {
                    maxs[j] = v10[j];
                }
            }
        }
    }

    /**
     * SubdividePolygon
     * @param numverts
     * @param verts
     */
    void SubdividePolygon(int numverts, float[][] verts) {
        int i, j, k;
        float m;
        float[][] front = new float[64][3];
        float[][] back = new float[64][3];

        int f, b1;
        float[] dist = new float[64];
        float frac;

        if (numverts > 60) {
            Com.Error(Defines.ERR_DROP, "numverts = " + numverts);
        }

        float[] mins = Vec3Cache.get();
        float[] maxs = Vec3Cache.get();

        BoundPoly(numverts, verts, mins, maxs);
        float[] v12;
        // x,y und z
        for (i = 0; i < 3; i++) {
            m = (mins[i] + maxs[i]) * 0.5f;
            m = SUBDIVIDE_SIZE * (float) Math.floor(m / SUBDIVIDE_SIZE + 0.5f);
            if (maxs[i] - m < 8) {
                continue;
            }
            if (m - mins[i] < 8) {
                continue;
            }

            // cut it
            for (j = 0; j < numverts; j++) {
                dist[j] = verts[j][i] - m;
            }

            // wrap cases
            dist[j] = dist[0];

            Math3D.VectorCopy(verts[0], verts[numverts]);

            f = b1 = 0;
            for (j = 0; j < numverts; j++) {
                v12 = verts[j];
                if (dist[j] >= 0) {
                    Math3D.VectorCopy(v12, front[f]);
                    f++;
                }
                if (dist[j] <= 0) {
                    Math3D.VectorCopy(v12, back[b1]);
                    b1++;
                }
                if (dist[j] == 0 || dist[j + 1] == 0) {
                    continue;
                }

                if ((dist[j] > 0) != (dist[j + 1] > 0)) {
                    // clip point
                    frac = dist[j] / (dist[j] - dist[j + 1]);
                    for (k = 0; k < 3; k++) {
                        front[f][k] = back[b1][k] = v12[k] + frac * (verts[j + 1][k] - v12[k]);
                    }

                    f++;
                    b1++;
                }
            }

            SubdividePolygon(f, front);
            SubdividePolygon(b1, back);

            Vec3Cache.release(2); // mins, maxs
            return;
        }

        Vec3Cache.release(2); // mins, maxs

        // add a point in the center to help keep warp valid

        // wird im Konstruktor erschlagen
        // poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float));

        // init polys
        glpoly_t poly = Polygon.create(numverts + 2);

        poly.next = warpface.polys;
        warpface.polys = poly;

        float[] total = Vec3Cache.get();
        Math3D.VectorClear(total);
        float total_s = 0;
        float total_t = 0;
        float s, t;
        for (i = 0; i < numverts; i++) {
            poly.x(i + 1, verts[i][0]);
            poly.y(i + 1, verts[i][1]);
            poly.z(i + 1, verts[i][2]);
            s = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[0]);
            t = Math3D.DotProduct(verts[i], warpface.texinfo.vecs[1]);

            total_s += s;
            total_t += t;
            Math3D.VectorAdd(total, verts[i], total);

            poly.s1(i + 1, s);
            poly.t1(i + 1, t);
        }

        float scale = 1.0f / numverts;
        poly.x(0, total[0] * scale);
        poly.y(0, total[1] * scale);
        poly.z(0, total[2] * scale);
        poly.s1(0, total_s * scale);
        poly.t1(0, total_t * scale);

        poly.x(i + 1, poly.x(1));
        poly.y(i + 1, poly.y(1));
        poly.z(i + 1, poly.z(1));
        poly.s1(i + 1, poly.s1(1));
        poly.t1(i + 1, poly.t1(1));
        poly.s2(i + 1, poly.s2(1));
        poly.t2(i + 1, poly.t2(1));

        Vec3Cache.release(); // total
    }

    private final float[][] tmpVerts = new float[64][3];

    /**
     * GL_SubdivideSurface
     * Breaks a polygon up along axial 64 unit
     * boundaries so that turbulent and sky warps
     * can be done reasonably.
     */
    void GL_SubdivideSurface(msurface_t fa) {
        float[][] verts1 = tmpVerts;
        float[] vec;
        warpface = fa;
        //
        // convert edges back to a normal polygon
        //
        int numverts = 0;
        for (int i = 0; i < fa.numedges; i++) {
            int lindex = loadmodel.surfedges[fa.firstedge + i];

            if (lindex > 0) {
                vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position;
            } else {
                vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position;
            }
            Math3D.VectorCopy(vec, verts1[numverts]);
            numverts++;
        }
        SubdividePolygon(numverts, verts1);
    }

    // =========================================================
    static final float TURBSCALE = (float) (256.0f / (2 * Math.PI));

    /**
     * EmitWaterPolys
     * Does a water warp on the pre-fragmented glpoly_t chain
     */
    void EmitWaterPolys(msurface_t fa) {
        float rdt = r_newrefdef.time;

        float scroll;
        if ((fa.texinfo.flags & Defines.SURF_FLOWING) != 0) {
            scroll = -64 * ((r_newrefdef.time * 0.5f) - (int) (r_newrefdef.time * 0.5f));
        } else {
            scroll = 0;
        }

        int i;
        float s, t, os, ot;
        glpoly_t p, bp;
        for (bp = fa.polys; bp != null; bp = bp.next) {
            p = bp;

            GL11.glBegin(GL11.GL_TRIANGLE_FAN);
            for (i = 0; i < p.numverts; i++) {
                os = p.s1(i);
                ot = p.t1(i);

                s = os + Warp.SIN[(int) ((ot * 0.125f + r_newrefdef.time) * TURBSCALE) & 255];
                s += scroll;
                s *= (1.0f / 64);

                t = ot + Warp.SIN[(int) ((os * 0.125f + rdt) * TURBSCALE) & 255];
                t *= (1.0f / 64);

                GL11.glTexCoord2f(s, t);
                GL11.glVertex3f(p.x(i), p.y(i), p.z(i));
            }
            GL11.glEnd();
        }
    }

    //     ===================================================================
    float[][] skyclip = { { 1, 1, 0 }, { 1, -1, 0 }, { 0, -1, 1 }, { 0, 1, 1 }, { 1, 0, 1 }, { -1, 0, 1 } };
    int c_sky;
    // 1 = s, 2 = t, 3 = 2048
    int[][] st_to_vec = { { 3, -1, 2 }, { -3, 1, 2 }, { 1, 3, 2 }, { -1, -3, 2 }, { -2, -1, 3 }, // 0 degrees yaw, look straight up
            { 2, -1, -3 } // look straight down
    };
    int[][] vec_to_st = { { -2, 3, 1 }, { 2, 3, -1 }, { 1, 3, 2 }, { -1, 3, -2 }, { -2, -1, 3 }, { -2, 1, -3 } };
    float[][] skymins = new float[2][6];
    float[][] skymaxs = new float[2][6];
    float sky_min, sky_max;
    // stack variable
    private final float[] v = { 0, 0, 0 };
    private final float[] av = { 0, 0, 0 };

    /**
     * DrawSkyPolygon
     * @param nump
     * @param vecs
     */
    void DrawSkyPolygon(int nump, float[][] vecs) {
        c_sky++;
        // decide which face it maps to
        Math3D.VectorCopy(Globals.vec3_origin, v);
        int i, axis;
        for (i = 0; i < nump; i++) {
            Math3D.VectorAdd(vecs[i], v, v);
        }
        av[0] = Math.abs(v[0]);
        av[1] = Math.abs(v[1]);
        av[2] = Math.abs(v[2]);
        if (av[0] > av[1] && av[0] > av[2]) {
            if (v[0] < 0) {
                axis = 1;
            } else {
                axis = 0;
            }
        } else if (av[1] > av[2] && av[1] > av[0]) {
            if (v[1] < 0) {
                axis = 3;
            } else {
                axis = 2;
            }
        } else {
            if (v[2] < 0) {
                axis = 5;
            } else {
                axis = 4;
            }
        }

        // project new texture coords
        float s, t, dv;
        int j;
        for (i = 0; i < nump; i++) {
            j = vec_to_st[axis][2];
            if (j > 0) {
                dv = vecs[i][j - 1];
            } else {
                dv = -vecs[i][-j - 1];
            }
            if (dv < 0.001f) {
                continue; // don't divide by zero
            }
            j = vec_to_st[axis][0];
            if (j < 0) {
                s = -vecs[i][-j - 1] / dv;
            } else {
                s = vecs[i][j - 1] / dv;
            }
            j = vec_to_st[axis][1];
            if (j < 0) {
                t = -vecs[i][-j - 1] / dv;
            } else {
                t = vecs[i][j - 1] / dv;
            }

            if (s < skymins[0][axis]) {
                skymins[0][axis] = s;
            }
            if (t < skymins[1][axis]) {
                skymins[1][axis] = t;
            }
            if (s > skymaxs[0][axis]) {
                skymaxs[0][axis] = s;
            }
            if (t > skymaxs[1][axis]) {
                skymaxs[1][axis] = t;
            }
        }
    }

    static final float ON_EPSILON = 0.1f; // point on plane side epsilon
    static final int MAX_CLIP_VERTS = 64;
    static final int SIDE_BACK = 1;
    static final int SIDE_FRONT = 0;
    static final int SIDE_ON = 2;
    float[] dists = new float[MAX_CLIP_VERTS];
    int[] sides = new int[MAX_CLIP_VERTS];
    float[][][][] newv = new float[6][2][MAX_CLIP_VERTS][3];

    /**
     * ClipSkyPolygon
     * @param nump
     * @param vecs
     * @param stage
     */
    void ClipSkyPolygon(int nump, float[][] vecs, int stage) {
        if (nump > MAX_CLIP_VERTS - 2) {
            Com.Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
        }
        if (stage == 6) { // fully clipped, so draw it
            DrawSkyPolygon(nump, vecs);
            return;
        }

        boolean front = false;
        boolean back = false;
        float[] norm = skyclip[stage];

        int i;
        float d;
        for (i = 0; i < nump; i++) {
            d = Math3D.DotProduct(vecs[i], norm);
            if (d > ON_EPSILON) {
                front = true;
                sides[i] = SIDE_FRONT;
            } else if (d < -ON_EPSILON) {
                back = true;
                sides[i] = SIDE_BACK;
            } else {
                sides[i] = SIDE_ON;
            }
            dists[i] = d;
        }

        if (!front || !back) { // not clipped
            ClipSkyPolygon(nump, vecs, stage + 1);
            return;
        }

        // clip it
        sides[i] = sides[0];
        dists[i] = dists[0];
        Math3D.VectorCopy(vecs[0], vecs[i]);

        int newc0 = 0;
        int newc1 = 0;
        float[] v13;
        float e;
        int j;
        for (i = 0; i < nump; i++) {
            v13 = vecs[i];
            switch (sides[i]) {
            case SIDE_FRONT:
                Math3D.VectorCopy(v13, newv[stage][0][newc0]);
                newc0++;
                break;
            case SIDE_BACK:
                Math3D.VectorCopy(v13, newv[stage][1][newc1]);
                newc1++;
                break;
            case SIDE_ON:
                Math3D.VectorCopy(v13, newv[stage][0][newc0]);
                newc0++;
                Math3D.VectorCopy(v13, newv[stage][1][newc1]);
                newc1++;
                break;
            }

            if (sides[i] == SIDE_ON || sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) {
                continue;
            }

            d = dists[i] / (dists[i] - dists[i + 1]);
            for (j = 0; j < 3; j++) {
                e = v13[j] + d * (vecs[i + 1][j] - v13[j]);
                newv[stage][0][newc0][j] = e;
                newv[stage][1][newc1][j] = e;
            }
            newc0++;
            newc1++;
        }

        // continue
        ClipSkyPolygon(newc0, newv[stage][0], stage + 1);
        ClipSkyPolygon(newc1, newv[stage][1], stage + 1);
    }

    float[][] verts = new float[MAX_CLIP_VERTS][3];

    /**
     * R_AddSkySurface
     */
    void R_AddSkySurface(msurface_t fa) {
        // calculate vertex values for sky box
        for (glpoly_t p = fa.polys; p != null; p = p.next) {
            for (int i = 0; i < p.numverts; i++) {
                verts[i][0] = p.x(i) - r_origin[0];
                verts[i][1] = p.y(i) - r_origin[1];
                verts[i][2] = p.z(i) - r_origin[2];
            }
            ClipSkyPolygon(p.numverts, verts, 0);
        }
    }

    /**
     * R_ClearSkyBox
     */
    void R_ClearSkyBox() {
        float[] skymins0 = skymins[0];
        float[] skymins1 = skymins[1];
        float[] skymaxs0 = skymaxs[0];
        float[] skymaxs1 = skymaxs[1];

        for (int i = 0; i < 6; i++) {
            skymins0[i] = skymins1[i] = 9999;
            skymaxs0[i] = skymaxs1[i] = -9999;
        }
    }

    // stack variable
    private final float[] v1 = { 0, 0, 0 };
    private final float[] b = { 0, 0, 0 };

    /**
     * MakeSkyVec
     * @param s
     * @param t
     * @param axis
     */
    void MakeSkyVec(float s, float t, int axis) {
        b[0] = s * 2300;
        b[1] = t * 2300;
        b[2] = 2300;

        int j, k;
        for (j = 0; j < 3; j++) {
            k = st_to_vec[axis][j];
            if (k < 0) {
                v1[j] = -b[-k - 1];
            } else {
                v1[j] = b[k - 1];
            }
        }

        // avoid bilerp seam
        s = (s + 1) * 0.5f;
        t = (t + 1) * 0.5f;

        if (s < sky_min) {
            s = sky_min;
        } else if (s > sky_max) {
            s = sky_max;
        }
        if (t < sky_min) {
            t = sky_min;
        } else if (t > sky_max) {
            t = sky_max;
        }

        t = 1.0f - t;
        GL11.glTexCoord2f(s, t);
        GL11.glVertex3f(v1[0], v1[1], v1[2]);
    }

    int[] skytexorder = { 0, 2, 1, 3, 4, 5 };

    /**
     * R_DrawSkyBox
     */
    void R_DrawSkyBox() {
        int i;

        if (skyrotate != 0) { // check for no sky at all
            for (i = 0; i < 6; i++) {
                if (skymins[0][i] < skymaxs[0][i] && skymins[1][i] < skymaxs[1][i]) {
                    break;
                }
            }
            if (i == 6) {
                return; // nothing visible
            }
        }

        GL11.glPushMatrix();
        GL11.glTranslatef(r_origin[0], r_origin[1], r_origin[2]);
        GL11.glRotatef(r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]);

        for (i = 0; i < 6; i++) {
            if (skyrotate != 0) { // hack, forces full sky to draw when rotating
                skymins[0][i] = -1;
                skymins[1][i] = -1;
                skymaxs[0][i] = 1;
                skymaxs[1][i] = 1;
            }

            if (skymins[0][i] >= skymaxs[0][i] || skymins[1][i] >= skymaxs[1][i]) {
                continue;
            }

            GL_Bind(sky_images[skytexorder[i]].texnum);

            GL11.glBegin(GL11.GL_QUADS);
            MakeSkyVec(skymins[0][i], skymins[1][i], i);
            MakeSkyVec(skymins[0][i], skymaxs[1][i], i);
            MakeSkyVec(skymaxs[0][i], skymaxs[1][i], i);
            MakeSkyVec(skymaxs[0][i], skymins[1][i], i);
            GL11.glEnd();
        }
        GL11.glPopMatrix();
    }

    // 3dstudio environment map names
    String[] suf = { "rt", "bk", "lf", "ft", "up", "dn" };

    /**
     * R_SetSky
     * @param name
     * @param rotate
     * @param axis
     */
    protected void R_SetSky(String name, float rotate, float[] axis) {
        assert (axis.length == 3) : "vec3_t bug";
        String pathname;
        skyname = name;

        skyrotate = rotate;
        Math3D.VectorCopy(axis, skyaxis);

        for (int i = 0; i < 6; i++) {
            // chop down rotating skies for less memory
            if (gl_skymip.value != 0 || skyrotate != 0) {
                gl_picmip.value++;
            }

            if (qglColorTableEXT && gl_ext_palettedtexture.value != 0) {
                //   Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]);
                pathname = "env/" + skyname + suf[i] + ".pcx";
            } else {
                // Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]);
                pathname = "env/" + skyname + suf[i] + ".tga";
            }

            sky_images[i] = GL_FindImage(pathname, it_sky);

            if (sky_images[i] == null) {
                sky_images[i] = r_notexture;
            }

            if (gl_skymip.value != 0 || skyrotate != 0) { // take less memory
                gl_picmip.value--;
                sky_min = 1.0f / 256;
                sky_max = 255.0f / 256;
            } else {
                sky_min = 1.0f / 512;
                sky_max = 511.0f / 512;
            }
        }
    }
}