/*
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.
*/
/* Modifications
Copyright 2003-2004 Bytonic Software
Copyright 2010 Google Inc.
*/
package com.googlecode.gwtquake.shared.render;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.googlecode.gwtquake.shared.client.EntityType;
import com.googlecode.gwtquake.shared.client.Window;
import com.googlecode.gwtquake.shared.common.Constants;
import com.googlecode.gwtquake.shared.common.QuakeFiles;
import com.googlecode.gwtquake.shared.util.Lib;
import com.googlecode.gwtquake.shared.util.Math3D;
/**
* Mesh
*
* @author cwei
*/
public class Mesh {
static float[][] r_avertexnormals = GlConstants.VERTEXNORMALS;
static float[] shadevector = {0, 0, 0};
static float[] shadelight = {0, 0, 0};
static float[][] r_avertexnormal_dots = GlConstants.VERTEXNORMAL_DOTS;
static float[] shadedots = r_avertexnormal_dots[0];
/**
* GL_LerpVerts
* @param nverts
* @param ov
* @param verts
* @param move
* @param frontv
* @param backv
*/
static void GL_LerpVerts(int nverts, int[] ov, int[] v, float[] move, float[] frontv, float[] backv )
{
FloatBuffer lerp = vertexArrayBuf;
lerp.limit((nverts << 2) - nverts); // nverts * 3
int ovv, vv;
//PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0 )
{
float[] normal;
int j = 0;
for (int i=0 ; i < nverts; i++/* , v++, ov++, lerp+=4 */)
{
vv = v[i];
normal = r_avertexnormals[(vv >>> 24 ) & 0xFF];
ovv = ov[i];
lerp.put(j, move[0] + (ovv & 0xFF)* backv[0] + (vv & 0xFF) * frontv[0] + normal[0] * Constants.POWERSUIT_SCALE);
lerp.put(j + 1, move[1] + ((ovv >>> 8) & 0xFF) * backv[1] + ((vv >>> 8) & 0xFF) * frontv[1] + normal[1] * Constants.POWERSUIT_SCALE);
lerp.put(j + 2, move[2] + ((ovv >>> 16) & 0xFF) * backv[2] + ((vv >>> 16) & 0xFF) * frontv[2] + normal[2] * Constants.POWERSUIT_SCALE);
j += 3;
}
}
else
{
int j = 0;
for (int i=0 ; i < nverts; i++ /* , v++, ov++, lerp+=4 */)
{
ovv = ov[i];
vv = v[i];
lerp.put(j, move[0] + (ovv & 0xFF)* backv[0] + (vv & 0xFF)*frontv[0]);
lerp.put(j + 1, move[1] + ((ovv >>> 8) & 0xFF)* backv[1] + ((vv >>> 8) & 0xFF)*frontv[1]);
lerp.put(j + 2, move[2] + ((ovv >>> 16) & 0xFF)* backv[2] + ((vv >>> 16) & 0xFF)*frontv[2]);
j += 3;
}
}
}
static FloatBuffer colorArrayBuf;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 4);
static FloatBuffer vertexArrayBuf;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 3);
static FloatBuffer textureArrayBuf;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 2);
static FloatBuffer colorArrayBuf2;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 4);
static FloatBuffer vertexArrayBuf2;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 3);
static FloatBuffer textureArrayBuf2;// = gl.createFloatBuffer(qfiles.MAX_VERTS * 2);
static public void init() {
colorArrayBuf = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 4);
vertexArrayBuf = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 3);
textureArrayBuf = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 2);
int FACTOR = 4;
colorArrayBuf2 = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 4 *FACTOR);
vertexArrayBuf2 = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 3 * FACTOR);
textureArrayBuf2 = Lib.newFloatBuffer(QuakeFiles.MAX_VERTS * 2 * FACTOR);
}
static boolean isFilled = false;
static float[] tmpVec = {0, 0, 0};
static float[][] vectors = {
{0, 0, 0}, {0, 0, 0}, {0, 0, 0} // 3 mal vec3_t
};
// stack variable
static float[] move = {0, 0, 0}; // vec3_t
static float[] frontv = {0, 0, 0}; // vec3_t
static float[] backv = {0, 0, 0}; // vec3_t
/**
* GL_DrawAliasFrameLerp
*
* interpolates between two frames and origins
* FIXME: batch lerp all vertexes
*/
static void GL_DrawAliasFrameLerp(QuakeFiles.dmdl_t paliashdr, float backlerp)
{
QuakeFiles.daliasframe_t frame = paliashdr.aliasFrames[GlState.currententity.frame];
int[] verts = frame.verts;
QuakeFiles.daliasframe_t oldframe = paliashdr.aliasFrames[GlState.currententity.oldframe];
int[] ov = oldframe.verts;
float alpha;
if ((GlState.currententity.flags & Constants.RF_TRANSLUCENT) != 0)
alpha = GlState.currententity.alpha;
else
alpha = 1.0f;
// PMM - added double shell
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0)
GlState.gl.glDisable( Gl1Context.GL_TEXTURE_2D );
float frontlerp = 1.0f - backlerp;
// move should be the delta back to the previous frame * backlerp
Math3D.VectorSubtract (GlState.currententity.oldorigin, GlState.currententity.origin, frontv);
Math3D.AngleVectors (GlState.currententity.angles, vectors[0], vectors[1], vectors[2]);
move[0] = Math3D.DotProduct (frontv, vectors[0]); // forward
move[1] = -Math3D.DotProduct (frontv, vectors[1]); // left
move[2] = Math3D.DotProduct (frontv, vectors[2]); // up
Math3D.VectorAdd (move, oldframe.translate, move);
for (int i=0 ; i<3 ; i++)
{
move[i] = backlerp*move[i] + frontlerp*frame.translate[i];
frontv[i] = frontlerp*frame.scale[i];
backv[i] = backlerp*oldframe.scale[i];
}
// ab hier wird optimiert
GL_LerpVerts( paliashdr.num_xyz, ov, verts, move, frontv, backv );
int num_xyz = paliashdr.num_xyz;
vertexArrayBuf.limit(num_xyz * 3);
//gl.glEnableClientState( GLAdapter.GL_VERTEX_ARRAY );
GlState.gl.glVertexPointer( 3, 0, vertexArrayBuf );
// PMM - added double damage shell
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0)
{
GlState.gl.glColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );
}
else
{
GlState.gl.glEnableClientState( Gl1Context.GL_COLOR_ARRAY );
FloatBuffer color = colorArrayBuf;
color.limit(num_xyz * 4);
GlState.gl.glColorPointer( 4, 0, color );
//
// pre light everything
//
float l;
int j = 0;
for (int i = 0; i < num_xyz; i++ )
{
l = shadedots[(verts[i] >>> 24) & 0xFF];
color.put(j, l * shadelight[0]);
color.put(j + 1, l * shadelight[1]);
color.put(j + 2, l * shadelight[2]);
color.put(j + 3, alpha);
j += 4;
}
}
GlState.gl.glClientActiveTexture(Gl1Context.GL_TEXTURE0);
FloatBuffer dstTextureCoords = textureArrayBuf;
GlState.gl.glTexCoordPointer( 2, 0, dstTextureCoords);
GlState.gl.glEnableClientState( Gl1Context.GL_TEXTURE_COORD_ARRAY);
int pos = 0;
int[] counts = paliashdr.counts;
ShortBuffer srcIndexBuf = null;
FloatBuffer srcTextureCoords = paliashdr.textureCoordBuf;
int dstIndex = 0;
int srcIndex = 0;
int count;
int mode;
int size = counts.length;
for (int j = 0; j < size; j++) {
dstTextureCoords.limit(num_xyz * 2);
// get the vertex count and primitive type
count = counts[j];
if (count == 0)
break; // done
srcIndexBuf = paliashdr.indexElements[j];
mode = Gl1Context.GL_TRIANGLE_STRIP;
if (count < 0) {
mode = Gl1Context.GL_TRIANGLE_FAN;
count = -count;
}
srcIndex = pos << 1;
srcIndex--;
int minIdx = 99999;
int maxIdx = 0;
for (int k = 0; k < count; k++) {
dstIndex = srcIndexBuf.get(k) << 1;
if (dstIndex < minIdx) {
minIdx = dstIndex;
}
if (dstIndex > maxIdx) {
maxIdx = dstIndex;
}
dstTextureCoords.put(dstIndex, srcTextureCoords.get(++srcIndex));
dstTextureCoords.put(++dstIndex, srcTextureCoords.get(++srcIndex));
}
//gl.updatTCBuffer(dstTextureCoords, minIdx, maxIdx - minIdx + 2);
dstTextureCoords.limit(maxIdx + 2);
GlState.gl.glTexCoordPointer( 2, 0, dstTextureCoords);
GlState.gl.glDrawElements(mode, srcIndexBuf);
pos += count;
}
// PMM - added double damage shell
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0 )
GlState.gl.glEnable( Gl1Context.GL_TEXTURE_2D );
GlState.gl.glDisableClientState( Gl1Context.GL_COLOR_ARRAY );
}
/**
* GL_DrawAliasFrameLerp with drawArrays
*/
static void GL_DrawAliasFrameLerpDA(QuakeFiles.dmdl_t paliashdr, float backlerp)
{
QuakeFiles.daliasframe_t frame = paliashdr.aliasFrames[GlState.currententity.frame];
int[] verts = frame.verts;
QuakeFiles.daliasframe_t oldframe = paliashdr.aliasFrames[GlState.currententity.oldframe];
int[] ov = oldframe.verts;
float alpha;
if ((GlState.currententity.flags & Constants.RF_TRANSLUCENT) != 0)
alpha = GlState.currententity.alpha;
else
alpha = 1.0f;
// PMM - added double shell
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0)
GlState.gl.glDisable( Gl1Context.GL_TEXTURE_2D );
float frontlerp = 1.0f - backlerp;
// move should be the delta back to the previous frame * backlerp
Math3D.VectorSubtract (GlState.currententity.oldorigin, GlState.currententity.origin, frontv);
Math3D.AngleVectors (GlState.currententity.angles, vectors[0], vectors[1], vectors[2]);
move[0] = Math3D.DotProduct (frontv, vectors[0]); // forward
move[1] = -Math3D.DotProduct (frontv, vectors[1]); // left
move[2] = Math3D.DotProduct (frontv, vectors[2]); // up
Math3D.VectorAdd (move, oldframe.translate, move);
for (int i=0 ; i<3 ; i++)
{
move[i] = backlerp*move[i] + frontlerp*frame.translate[i];
frontv[i] = frontlerp*frame.scale[i];
backv[i] = backlerp*oldframe.scale[i];
}
// ab hier wird optimiert
GL_LerpVerts( paliashdr.num_xyz, ov, verts, move, frontv, backv );
int num_xyz = paliashdr.num_xyz;
FloatBuffer vertices = vertexArrayBuf;
// PMM - added double damage shell
boolean hasColorArray;
FloatBuffer color = colorArrayBuf;
hasColorArray = (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) == 0;
if (hasColorArray) {
//
// pre light everything
//
float l;
int j = 0;
for (int i = 0; i < num_xyz; i++ )
{
l = shadedots[(verts[i] >>> 24) & 0xFF];
color.put(j, l * shadelight[0]);
color.put(j + 1, l * shadelight[1]);
color.put(j + 2, l * shadelight[2]);
color.put(j + 3, alpha);
j += 4;
}
} else {
GlState.gl.glColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );
}
int pos = 0;
int[] counts = paliashdr.counts;
FloatBuffer dstVertexCoords = vertexArrayBuf2;
FloatBuffer dstColors = colorArrayBuf2;
dstVertexCoords.clear();
dstColors.clear();
int count;
int mode;
int size = counts.length;
for (int j = 0; j < size; j++) {
// get the vertex count and primitive type
count = counts[j];
if (count == 0)
break; // done
ShortBuffer srcIndexBuf = paliashdr.indexElements[j];
if (count < 0) {
count = -count;
}
for (int k = 0; k < count; k++) {
int srcIndex = srcIndexBuf.get(k);
if (hasColorArray) {
int cSrcIndex = srcIndex * 4;
dstColors.put(color.get(cSrcIndex));
dstColors.put(color.get(cSrcIndex+1));
dstColors.put(color.get(cSrcIndex+2));
dstColors.put(color.get(cSrcIndex+3));
}
int vSrcIndex = srcIndex * 3;
dstVertexCoords.put(vertices.get(vSrcIndex));
dstVertexCoords.put(vertices.get(vSrcIndex+1));
dstVertexCoords.put(vertices.get(vSrcIndex+2));
}
//gl.updatTCBuffer(dstTextureCoords, minIdx, maxIdx - minIdx + 2);
pos += count;
}
if (hasColorArray) {
GlState.gl.glEnableClientState( Gl1Context.GL_COLOR_ARRAY );
dstColors.flip();
GlState.gl.glColorPointer(4, 0, dstColors);
}
GlState.gl.glClientActiveTexture(Gl1Context.GL_TEXTURE0);
GlState.gl.glEnableClientState( Gl1Context.GL_TEXTURE_COORD_ARRAY);
FloatBuffer tc0 = paliashdr.textureCoordBuf;
int limit = tc0.limit();
tc0.limit(tc0.position() + pos * 2);
GlState.gl.glVertexAttribPointer(Gl1Context.ARRAY_TEXCOORD_0, 2, Gl1Context.GL_FLOAT, false, 0, 0,
paliashdr.textureCoordBuf, paliashdr.staticTextureBufId);
tc0.limit(limit);
dstVertexCoords.flip();
GlState.gl.glVertexPointer(3, 0, dstVertexCoords);
pos = 0;
for (int j = 0; j < size; j++) {
// get the vertex count and primitive type
count = counts[j];
if (count == 0)
break; // done
mode = Gl1Context.GL_TRIANGLE_STRIP;
if (count < 0) {
mode = Gl1Context.GL_TRIANGLE_FAN;
count = -count;
}
GlState.gl.glDrawArrays(mode, pos, count);
pos += count;
}
// PMM - added double damage shell
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_RED | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE | Constants.RF_SHELL_HALF_DAM)) != 0 )
GlState.gl.glEnable( Gl1Context.GL_TEXTURE_2D );
GlState.gl.glDisableClientState( Gl1Context.GL_COLOR_ARRAY );
}
static private final float[] point = {0, 0, 0};
/**
* GL_DrawAliasShadow
*/
static void GL_DrawAliasShadow(QuakeFiles.dmdl_t paliashdr, int posenum)
{
float lheight = GlState.currententity.origin[2] - DynamicLights.lightspot[2];
// qfiles.daliasframe_t frame = paliashdr.aliasFrames[currententity.frame];
int[] order = paliashdr.glCmds;
float height = -lheight + 1.0f;
int orderIndex = 0;
int index = 0;
// TODO shadow drawing with vertex arrays
int count;
while (true)
{
// get the vertex count and primitive type
count = order[orderIndex++];
if (count == 0)
break; // done
if (count < 0)
{
count = -count;
GlState.gl.glBegin (Gl1Context.GL_TRIANGLE_FAN);
}
else
GlState.gl.glBegin (Gl1Context.GL_TRIANGLE_STRIP);
do
{
index = order[orderIndex + 2] * 3;
point[0] = vertexArrayBuf.get(index);
point[1] = vertexArrayBuf.get(index + 1);
point[2] = vertexArrayBuf.get(index + 2);
point[0] -= shadevector[0]*(point[2]+lheight);
point[1] -= shadevector[1]*(point[2]+lheight);
point[2] = height;
GlState.gl.glVertex3f(point[0], point[1], point[2]);
orderIndex += 3;
} while (--count != 0);
GlState.gl.glEnd ();
}
}
// TODO sync with jogl renderer. hoz
// stack variable
private static final float[] mins = { 0, 0, 0 };
private static final float[] maxs = { 0, 0, 0 };
/**
* R_CullAliasModel
*/
static boolean R_CullAliasModel(EntityType e) {
QuakeFiles.dmdl_t paliashdr = (QuakeFiles.dmdl_t) GlState.currentmodel.extradata;
if ((e.frame >= paliashdr.num_frames) || (e.frame < 0)) {
Window.Printf(Constants.PRINT_ALL, "R_CullAliasModel " + GlState.currentmodel.name + ": no such frame " + e.frame + '\n');
e.frame = 0;
}
if ((e.oldframe >= paliashdr.num_frames) || (e.oldframe < 0)) {
Window.Printf(Constants.PRINT_ALL, "R_CullAliasModel " + GlState.currentmodel.name + ": no such oldframe " + e.oldframe + '\n');
e.oldframe = 0;
}
QuakeFiles.daliasframe_t pframe = paliashdr.aliasFrames[e.frame];
QuakeFiles.daliasframe_t poldframe = paliashdr.aliasFrames[e.oldframe];
/*
** compute axially aligned mins and maxs
*/
if (pframe == poldframe) {
for (int i = 0; i < 3; i++) {
mins[i] = pframe.translate[i];
maxs[i] = mins[i] + pframe.scale[i] * 255;
}
} else {
float thismaxs, oldmaxs;
for (int i = 0; i < 3; i++) {
thismaxs = pframe.translate[i] + pframe.scale[i] * 255;
oldmaxs = poldframe.translate[i] + poldframe.scale[i] * 255;
if (pframe.translate[i] < poldframe.translate[i])
mins[i] = pframe.translate[i];
else
mins[i] = poldframe.translate[i];
if (thismaxs > oldmaxs)
maxs[i] = thismaxs;
else
maxs[i] = oldmaxs;
}
}
/*
** compute a full bounding box
*/
float[] tmp;
for (int i = 0; i < 8; i++) {
tmp = bbox[i];
if ((i & 1) != 0)
tmp[0] = mins[0];
else
tmp[0] = maxs[0];
if ((i & 2) != 0)
tmp[1] = mins[1];
else
tmp[1] = maxs[1];
if ((i & 4) != 0)
tmp[2] = mins[2];
else
tmp[2] = maxs[2];
}
/*
** rotate the bounding box
*/
tmp = mins;
Math3D.VectorCopy(e.angles, tmp);
tmp[GlConstants.YAW] = -tmp[GlConstants.YAW];
Math3D.AngleVectors(tmp, vectors[0], vectors[1], vectors[2]);
for (int i = 0; i < 8; i++) {
Math3D.VectorCopy(bbox[i], tmp);
bbox[i][0] = Math3D.DotProduct(vectors[0], tmp);
bbox[i][1] = -Math3D.DotProduct(vectors[1], tmp);
bbox[i][2] = Math3D.DotProduct(vectors[2], tmp);
Math3D.VectorAdd(e.origin, bbox[i], bbox[i]);
}
int f, mask;
int aggregatemask = ~0; // 0xFFFFFFFF
for (int p = 0; p < 8; p++) {
mask = 0;
for (f = 0; f < 4; f++) {
float dp = Math3D.DotProduct(GlState.frustum[f].normal, bbox[p]);
if ((dp - GlState.frustum[f].dist) < 0) {
mask |= (1 << f);
}
}
aggregatemask &= mask;
}
if (aggregatemask != 0) {
return true;
}
return false;
}
// bounding box
static float[][] bbox = {
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
};
// TODO sync with jogl renderer. hoz
/**
* R_DrawAliasModel
*/
static void R_DrawAliasModel(EntityType e)
{
if ( ( e.flags & Constants.RF_WEAPONMODEL ) == 0)
{
if ( R_CullAliasModel(e) )
return;
}
if ( (e.flags & Constants.RF_WEAPONMODEL) != 0 )
{
if ( GlConfig.r_lefthand.value == 2.0f )
return;
}
QuakeFiles.dmdl_t paliashdr = (QuakeFiles.dmdl_t)GlState.currentmodel.extradata;
//
// get lighting information
//
// PMM - rewrote, reordered to handle new shells & mixing
// PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy
//
int i;
if ( (GlState.currententity.flags & ( Constants.RF_SHELL_HALF_DAM | Constants.RF_SHELL_GREEN | Constants.RF_SHELL_RED | Constants.RF_SHELL_BLUE | Constants.RF_SHELL_DOUBLE )) != 0 )
{
Math3D.VectorClear(shadelight);
if ((GlState.currententity.flags & Constants.RF_SHELL_HALF_DAM) != 0)
{
shadelight[0] = 0.56f;
shadelight[1] = 0.59f;
shadelight[2] = 0.45f;
}
if ( (GlState.currententity.flags & Constants.RF_SHELL_DOUBLE) != 0 )
{
shadelight[0] = 0.9f;
shadelight[1] = 0.7f;
}
if ( (GlState.currententity.flags & Constants.RF_SHELL_RED) != 0 )
shadelight[0] = 1.0f;
if ( (GlState.currententity.flags & Constants.RF_SHELL_GREEN) != 0 )
shadelight[1] = 1.0f;
if ( (GlState.currententity.flags & Constants.RF_SHELL_BLUE) != 0 )
shadelight[2] = 1.0f;
}
else if ( (GlState.currententity.flags & Constants.RF_FULLBRIGHT) != 0 )
{
for (i=0 ; i<3 ; i++)
shadelight[i] = 1.0f;
}
else
{
DynamicLights.R_LightPoint (GlState.currententity.origin, shadelight);
// player lighting hack for communication back to server
// big hack!
if ( (GlState.currententity.flags & Constants.RF_WEAPONMODEL) != 0 )
{
// pick the greatest component, which should be the same
// as the mono value returned by software
if (shadelight[0] > shadelight[1])
{
if (shadelight[0] > shadelight[2])
GlConfig.r_lightlevel.value = 150*shadelight[0];
else
GlConfig.r_lightlevel.value = 150*shadelight[2];
}
else
{
if (shadelight[1] > shadelight[2])
GlConfig.r_lightlevel.value = 150*shadelight[1];
else
GlConfig.r_lightlevel.value = 150*shadelight[2];
}
}
if ( GlConfig.gl_monolightmap.string.charAt(0) != '0' )
{
float s = shadelight[0];
if ( s < shadelight[1] )
s = shadelight[1];
if ( s < shadelight[2] )
s = shadelight[2];
shadelight[0] = s;
shadelight[1] = s;
shadelight[2] = s;
}
}
if ( (GlState.currententity.flags & Constants.RF_MINLIGHT) != 0 )
{
for (i=0 ; i<3 ; i++)
if (shadelight[i] > 0.1f)
break;
if (i == 3)
{
shadelight[0] = 0.1f;
shadelight[1] = 0.1f;
shadelight[2] = 0.1f;
}
}
if ( (GlState.currententity.flags & Constants.RF_GLOW) != 0 )
{ // bonus items will pulse with time
float scale;
float min;
scale = (float)(0.1f * Math.sin(GlState.r_newrefdef.time*7));
for (i=0 ; i<3 ; i++)
{
min = shadelight[i] * 0.8f;
shadelight[i] += scale;
if (shadelight[i] < min)
shadelight[i] = min;
}
}
// =================
// PGM ir goggles color override
if ( (GlState.r_newrefdef.rdflags & Constants.RDF_IRGOGGLES) != 0 && (GlState.currententity.flags & Constants.RF_IR_VISIBLE) != 0)
{
shadelight[0] = 1.0f;
shadelight[1] = 0.0f;
shadelight[2] = 0.0f;
}
// PGM
// =================
shadedots = r_avertexnormal_dots[((int)(GlState.currententity.angles[1] * (GlConstants.SHADEDOT_QUANT / 360.0))) & (GlConstants.SHADEDOT_QUANT - 1)];
float an = (float)(GlState.currententity.angles[1]/180*Math.PI);
shadevector[0] = (float)Math.cos(-an);
shadevector[1] = (float)Math.sin(-an);
shadevector[2] = 1;
Math3D.VectorNormalize(shadevector);
//
// locate the proper data
//
GlState.c_alias_polys += paliashdr.num_tris;
//
// draw all the triangles
//
if ( (GlState.currententity.flags & Constants.RF_DEPTHHACK) != 0) // hack the depth range to prevent view model from poking into walls
GlState.gl.glDepthRange(GlState.gldepthmin, (float) (GlState.gldepthmin + 0.3*(GlState.gldepthmax-GlState.gldepthmin)));
if ( (GlState.currententity.flags & Constants.RF_WEAPONMODEL) != 0 && (GlConfig.r_lefthand.value == 1.0f) )
{
GlState.gl.glMatrixMode( Gl1Context.GL_PROJECTION );
GlState.gl.glPushMatrix();
GlState.gl.glLoadIdentity();
GlState.gl.glScalef( -1, 1, 1 );
Entities.MYgluPerspective( GlState.r_newrefdef.fov_y, ( float ) GlState.r_newrefdef.width / GlState.r_newrefdef.height, 4, 4096);
GlState.gl.glMatrixMode( Gl1Context.GL_MODELVIEW );
GlState.gl.glCullFace( Gl1Context.GL_BACK );
}
GlState.gl.glPushMatrix ();
e.angles[GlConstants.PITCH] = -e.angles[GlConstants.PITCH]; // sigh.
Entities.rotateForEntity (e);
e.angles[GlConstants.PITCH] = -e.angles[GlConstants.PITCH]; // sigh.
Image skin;
// select skin
if (GlState.currententity.skin != null)
skin = GlState.currententity.skin; // custom player skin
else
{
if (GlState.currententity.skinnum >= QuakeFiles.MAX_MD2SKINS)
skin = GlState.currentmodel.skins[0];
else
{
skin = GlState.currentmodel.skins[GlState.currententity.skinnum];
if (skin == null)
skin = GlState.currentmodel.skins[0];
}
}
if (skin == null)
skin = GlState.r_notexture; // fallback...
Images.GL_Bind(skin.texnum);
// draw it
GlState.gl.glShadeModel (Gl1Context.GL_SMOOTH);
Images.GL_TexEnv( Gl1Context.GL_MODULATE );
if ( (GlState.currententity.flags & Constants.RF_TRANSLUCENT) != 0 )
{
GlState.gl.glEnable (Gl1Context.GL_BLEND);
}
if ( (GlState.currententity.frame >= paliashdr.num_frames)
|| (GlState.currententity.frame < 0) )
{
Window.Printf (Constants.PRINT_ALL, "R_DrawAliasModel " + GlState.currentmodel.name +": no such frame " + GlState.currententity.frame + '\n');
GlState.currententity.frame = 0;
GlState.currententity.oldframe = 0;
}
if ( (GlState.currententity.oldframe >= paliashdr.num_frames)
|| (GlState.currententity.oldframe < 0))
{
Window.Printf (Constants.PRINT_ALL, "R_DrawAliasModel " + GlState.currentmodel.name +": no such oldframe " + GlState.currententity.oldframe + '\n');
GlState.currententity.frame = 0;
GlState.currententity.oldframe = 0;
}
if ( GlConfig.r_lerpmodels.value == 0.0f)
GlState.currententity.backlerp = 0;
GL_DrawAliasFrameLerpDA(paliashdr, GlState.currententity.backlerp);
Images.GL_TexEnv( Gl1Context.GL_REPLACE );
GlState.gl.glShadeModel (Gl1Context.GL_FLAT);
GlState.gl.glPopMatrix ();
if ( ( GlState.currententity.flags & Constants.RF_WEAPONMODEL ) != 0 && ( GlConfig.r_lefthand.value == 1.0F ) )
{
GlState.gl.glMatrixMode( Gl1Context.GL_PROJECTION );
GlState.gl.glPopMatrix();
GlState.gl.glMatrixMode( Gl1Context.GL_MODELVIEW );
GlState.gl.glCullFace( Gl1Context.GL_FRONT );
}
if ( (GlState.currententity.flags & Constants.RF_TRANSLUCENT) != 0 )
{
GlState.gl.glDisable (Gl1Context.GL_BLEND);
}
if ( (GlState.currententity.flags & Constants.RF_DEPTHHACK) != 0)
GlState.gl.glDepthRange (GlState.gldepthmin, GlState.gldepthmax);
if ( GlConfig.gl_shadows.value != 0.0f && (GlState.currententity.flags & (Constants.RF_TRANSLUCENT | Constants.RF_WEAPONMODEL)) == 0)
{
GlState.gl.glPushMatrix ();
Entities.rotateForEntity (e);
GlState.gl.glDisable (Gl1Context.GL_TEXTURE_2D);
GlState.gl.glEnable (Gl1Context.GL_BLEND);
GlState.gl.glColor4f (0,0,0,0.5f);
GL_DrawAliasShadow (paliashdr, GlState.currententity.frame );
GlState.gl.glEnable (Gl1Context.GL_TEXTURE_2D);
GlState.gl.glDisable (Gl1Context.GL_BLEND);
GlState.gl.glPopMatrix ();
}
GlState.gl.glColor4f (1,1,1,1);
}
}