/* * Warp.java * Copyright (C) 2003 * * $Id: Warp.java,v 1.1 2004-07-09 06:50:49 hzi 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 jake2.render.fastjogl; import java.nio.FloatBuffer; import jake2.Defines; import jake2.Globals; import jake2.game.GameBase; import jake2.render.glpoly_t; import jake2.render.image_t; import jake2.render.msurface_t; import jake2.util.Math3D; import net.java.games.jogl.GL; /** * 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 }; // gl_warp.c -- sky and water polygons //extern model_t *loadmodel; // Model.java 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; void BoundPoly(int numverts, float[][] verts, float[] mins, float[] maxs) { int i, j; float[] v; mins[0] = mins[1] = mins[2] = 9999; maxs[0] = maxs[1] = maxs[2] = -9999; for (i=0 ; i maxs[j]) maxs[j] = v[j]; } } } void SubdividePolygon(int numverts, float[][] verts) { int i, j, k; float[] mins = {0, 0, 0}; float[] maxs = {0, 0, 0}; float m; float[] v = {0, 0, 0}; float[][] front = new float[64][3]; float[][] back = new float[64][3]; int f, b; float[] dist = new float[64]; float frac; glpoly_t poly; float s, t; float[] total = {0, 0, 0}; float total_s, total_t; if (numverts > 60) ri.Sys_Error(Defines.ERR_DROP, "numverts = " + numverts); BoundPoly(numverts, verts, mins, maxs); // 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= 0) { Math3D.VectorCopy(v, front[f]); f++; } if (dist[j] <= 0) { Math3D.VectorCopy(v, back[b]); b++; } 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[b][k] = v[k] + frac*(verts[j+1][k] - v[k]); f++; b++; } } SubdividePolygon(f, front); SubdividePolygon(b, back); return; } // 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 poly = new glpoly_t(numverts + 2); poly.next = warpface.polys; warpface.polys = poly; poly.numverts = numverts + 2; Math3D.VectorClear(total); total_s = 0; total_t = 0; for (i=0 ; i 0) vec = loadmodel.vertexes[loadmodel.edges[lindex].v[0]].position; else vec = loadmodel.vertexes[loadmodel.edges[-lindex].v[1]].position; Math3D.VectorCopy(vec, verts[numverts]); numverts++; } SubdividePolygon(numverts, verts); } // ========================================================= //// speed up sin calculations - Ed // float r_turbsin[] = // { // #include "warpsin.h" // }; 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) { glpoly_t p, bp; float[] v; int i; float s = 0; float t = 0; float os, ot; float scroll; float rdt = r_newrefdef.time; 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 index; FloatBuffer texCoord = globalPolygonInterleavedBuf; for (bp=fa.polys ; bp != null ; bp=bp.next) { p = bp; index = p.pos * POLYGON_STRIDE; for (i=0; i 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 for (i=0 ; i 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]; void ClipSkyPolygon(int nump, float[][] vecs, int stage) { float[] norm; float[] v; boolean front, back; float d, e; int[] newc = { 0, 0 }; int i, j; if (nump > MAX_CLIP_VERTS-2) ri.Sys_Error(Defines.ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); if (stage == 6) { // fully clipped, so draw it DrawSkyPolygon(nump, vecs); return; } front = back = false; norm = skyclip[stage]; for (i=0 ; i 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]); newc[0] = newc[1] = 0; for (i=0; i sky_max) s = sky_max; if (t < sky_min) t = sky_min; else if (t > sky_max) t = sky_max; t = 1.0f - t; gl.glTexCoord2f (s, t); gl.glVertex3f(v[0], v[1], v[2]); } /* ============== R_DrawSkyBox ============== */ int[] skytexorder = {0,2,1,3,4,5}; 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 } gl.glPushMatrix (); gl.glTranslatef (r_origin[0], r_origin[1], r_origin[2]); gl.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); gl.glBegin(GL.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); gl.glEnd (); } gl.glPopMatrix (); } /* ============ R_SetSky ============ */ // 3dstudio environment map names String[] suf = {"rt", "bk", "lf", "ft", "up", "dn"}; protected void R_SetSky(String name, float rotate, float[] axis) { assert (axis.length == 3) : "vec3_t bug"; int i; String pathname; // strncpy (skyname, name, sizeof(skyname)-1); skyname = name; skyrotate = rotate; Math3D.VectorCopy(axis, skyaxis); for (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; } } } }