2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
2014-09-22 08:55:46 +00:00
|
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
//r_alias.c -- alias model rendering
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
|
|
|
|
|
|
|
extern cvar_t r_drawflat, gl_overbright_models, gl_fullbrights, r_lerpmodels, r_lerpmove; //johnfitz
|
|
|
|
|
|
|
|
//up to 16 color translated skins
|
|
|
|
gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz -- changed to an array of pointers
|
|
|
|
|
|
|
|
#define NUMVERTEXNORMALS 162
|
|
|
|
|
2014-09-22 08:55:46 +00:00
|
|
|
float r_avertexnormals[NUMVERTEXNORMALS][3] =
|
|
|
|
{
|
2010-02-15 23:26:55 +00:00
|
|
|
#include "anorms.h"
|
|
|
|
};
|
|
|
|
|
|
|
|
vec3_t shadevector;
|
|
|
|
|
|
|
|
extern vec3_t lightcolor; //johnfitz -- replaces "float shadelight" for lit support
|
|
|
|
|
|
|
|
// precalculated dot products for quantized angles
|
|
|
|
#define SHADEDOT_QUANT 16
|
|
|
|
float r_avertexnormal_dots[SHADEDOT_QUANT][256] =
|
2014-09-22 08:55:46 +00:00
|
|
|
{
|
2010-02-15 23:26:55 +00:00
|
|
|
#include "anorm_dots.h"
|
2014-09-22 08:55:46 +00:00
|
|
|
};
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
extern vec3_t lightspot;
|
|
|
|
|
|
|
|
float *shadedots = r_avertexnormal_dots[0];
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
vec3_t shadevector;
|
2010-02-15 23:26:55 +00:00
|
|
|
float entalpha; //johnfitz
|
|
|
|
|
|
|
|
qboolean overbright; //johnfitz
|
|
|
|
|
|
|
|
qboolean shading = true; //johnfitz -- if false, disable vertex shading for various reasons (fullbright, r_lightmap, showtris, etc)
|
|
|
|
|
|
|
|
//johnfitz -- struct for passing lerp information to drawing functions
|
|
|
|
typedef struct {
|
|
|
|
short pose1;
|
|
|
|
short pose2;
|
|
|
|
float blend;
|
|
|
|
vec3_t origin;
|
|
|
|
vec3_t angles;
|
|
|
|
} lerpdata_t;
|
|
|
|
//johnfitz
|
|
|
|
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
static GLuint r_alias_program;
|
|
|
|
|
|
|
|
// uniforms used in vert shader
|
|
|
|
static GLuint blendLoc;
|
|
|
|
static GLuint shadevectorLoc;
|
|
|
|
static GLuint lightColorLoc;
|
|
|
|
|
|
|
|
// uniforms used in frag shader
|
|
|
|
static GLuint texLoc;
|
|
|
|
static GLuint fullbrightTexLoc;
|
|
|
|
static GLuint useFullbrightTexLoc;
|
|
|
|
static GLuint useOverbrightLoc;
|
|
|
|
|
|
|
|
static const GLint pose1VertexAttrIndex = 0;
|
|
|
|
static const GLint pose1NormalAttrIndex = 1;
|
|
|
|
static const GLint pose2VertexAttrIndex = 2;
|
|
|
|
static const GLint pose2NormalAttrIndex = 3;
|
|
|
|
static const GLint texCoordsAttrIndex = 4;
|
|
|
|
|
|
|
|
extern GLuint r_meshvbo;
|
|
|
|
extern GLuint r_meshindexesvbo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GLARB_GetXYZOffset
|
|
|
|
|
|
|
|
Returns the offset of the first vertex's meshxyz_t.xyz in the vbo for the given
|
|
|
|
model and pose.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static void *GLARB_GetXYZOffset (aliashdr_t *hdr, int pose)
|
|
|
|
{
|
|
|
|
meshxyz_t dummy;
|
|
|
|
int xyzoffs = ((char*)&dummy.xyz - (char*)&dummy);
|
|
|
|
return (void *) (currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + xyzoffs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GLARB_GetNormalOffset
|
|
|
|
|
|
|
|
Returns the offset of the first vertex's meshxyz_t.normal in the vbo for the
|
|
|
|
given model and pose.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static void *GLARB_GetNormalOffset (aliashdr_t *hdr, int pose)
|
|
|
|
{
|
|
|
|
meshxyz_t dummy;
|
|
|
|
int normaloffs = ((char*)&dummy.normal - (char*)&dummy);
|
|
|
|
return (void *)(currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + normaloffs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GLAlias_SupportsShaders
|
|
|
|
|
|
|
|
Returns whether OpenGL has the capabilities we need for the shader path.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
qboolean GLAlias_SupportsShaders (void)
|
|
|
|
{
|
|
|
|
return gl_glsl_able && gl_vbo_able && gl_max_texture_units >= 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GLAlias_GetUniformLocation
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static GLint GLAlias_GetUniformLocation (const char *name)
|
|
|
|
{
|
|
|
|
GLint location;
|
|
|
|
location = GL_GetUniformLocationFunc(r_alias_program, name);
|
|
|
|
if (location == -1)
|
|
|
|
{
|
|
|
|
Con_Warning("GL_GetUniformLocationFunc %s failed", name);
|
|
|
|
r_alias_program = 0;
|
|
|
|
}
|
|
|
|
return location;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GLAlias_CreateShaders
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GLAlias_CreateShaders (void)
|
|
|
|
{
|
|
|
|
const glsl_attrib_binding_t bindings[] = {
|
|
|
|
{ "TexCoords", texCoordsAttrIndex },
|
|
|
|
{ "Pose1Vert", pose1VertexAttrIndex },
|
|
|
|
{ "Pose1Normal", pose1NormalAttrIndex },
|
|
|
|
{ "Pose2Vert", pose2VertexAttrIndex },
|
|
|
|
{ "Pose2Normal", pose2NormalAttrIndex }
|
|
|
|
};
|
|
|
|
|
|
|
|
const GLchar *vertSource = \
|
|
|
|
"#version 110\n"
|
|
|
|
"\n"
|
|
|
|
"uniform float Blend;\n"
|
|
|
|
"uniform vec3 ShadeVector;\n"
|
|
|
|
"uniform vec4 LightColor;\n"
|
|
|
|
"attribute vec4 TexCoords; // only xy are used \n"
|
|
|
|
"attribute vec4 Pose1Vert;\n"
|
|
|
|
"attribute vec3 Pose1Normal;\n"
|
|
|
|
"attribute vec4 Pose2Vert;\n"
|
|
|
|
"attribute vec3 Pose2Normal;\n"
|
|
|
|
"float r_avertexnormal_dot(vec3 vertexnormal) // from MH \n"
|
|
|
|
"{\n"
|
|
|
|
" float dot = dot(vertexnormal, ShadeVector);\n"
|
|
|
|
" // wtf - this reproduces anorm_dots within as reasonable a degree of tolerance as the >= 0 case\n"
|
|
|
|
" if (dot < 0.0)\n"
|
|
|
|
" return 1.0 + dot * (13.0 / 44.0);\n"
|
|
|
|
" else\n"
|
|
|
|
" return 1.0 + dot;\n"
|
|
|
|
"}\n"
|
|
|
|
"void main()\n"
|
|
|
|
"{\n"
|
|
|
|
" gl_TexCoord[0] = TexCoords;\n"
|
|
|
|
" vec4 lerpedVert = mix(Pose1Vert, Pose2Vert, Blend);\n"
|
|
|
|
" gl_Position = gl_ModelViewProjectionMatrix * lerpedVert;\n"
|
|
|
|
" float dot1 = r_avertexnormal_dot(Pose1Normal);\n"
|
|
|
|
" float dot2 = r_avertexnormal_dot(Pose2Normal);\n"
|
|
|
|
" gl_FrontColor = LightColor * vec4(vec3(mix(dot1, dot2, Blend)), 1.0);\n"
|
|
|
|
" // fog\n"
|
|
|
|
" vec3 ecPosition = vec3(gl_ModelViewMatrix * lerpedVert);\n"
|
|
|
|
" gl_FogFragCoord = abs(ecPosition.z);\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
const GLchar *fragSource = \
|
|
|
|
"#version 110\n"
|
|
|
|
"\n"
|
|
|
|
"uniform sampler2D Tex;\n"
|
|
|
|
"uniform sampler2D FullbrightTex;\n"
|
|
|
|
"uniform bool UseFullbrightTex;\n"
|
|
|
|
"uniform bool UseOverbright;\n"
|
|
|
|
"void main()\n"
|
|
|
|
"{\n"
|
|
|
|
" vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n"
|
|
|
|
" result *= gl_Color;\n"
|
|
|
|
" if (UseOverbright)\n"
|
|
|
|
" result.rgb *= 2.0;\n"
|
|
|
|
" if (UseFullbrightTex)\n"
|
|
|
|
" result += texture2D(FullbrightTex, gl_TexCoord[0].xy);\n"
|
|
|
|
" result = clamp(result, 0.0, 1.0);\n"
|
|
|
|
" // apply GL_EXP2 fog (from the orange book)\n"
|
|
|
|
" float fog = exp(-gl_Fog.density * gl_Fog.density * gl_FogFragCoord * gl_FogFragCoord);\n"
|
|
|
|
" fog = clamp(fog, 0.0, 1.0);\n"
|
|
|
|
" result = vec4(mix(gl_Fog.color.rgb, result.rgb, fog), result.a);\n"
|
|
|
|
" gl_FragColor = result;\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
if (!GLAlias_SupportsShaders())
|
|
|
|
return;
|
|
|
|
|
|
|
|
r_alias_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings);
|
|
|
|
|
|
|
|
if (r_alias_program != 0)
|
|
|
|
{
|
|
|
|
// get uniform locations
|
|
|
|
blendLoc = GLAlias_GetUniformLocation ("Blend");
|
|
|
|
shadevectorLoc = GLAlias_GetUniformLocation ("ShadeVector");
|
|
|
|
lightColorLoc = GLAlias_GetUniformLocation ("LightColor");
|
|
|
|
texLoc = GLAlias_GetUniformLocation("Tex");
|
|
|
|
fullbrightTexLoc = GLAlias_GetUniformLocation("FullbrightTex");
|
|
|
|
useFullbrightTexLoc = GLAlias_GetUniformLocation("UseFullbrightTex");
|
|
|
|
useOverbrightLoc = GLAlias_GetUniformLocation("UseOverbright");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GL_DrawAliasFrame_GLSL -- ericw
|
|
|
|
|
|
|
|
Optimized alias model drawing codepath.
|
|
|
|
Compared to the original GL_DrawAliasFrame, this makes 1 draw call,
|
|
|
|
no vertex data is uploaded (it's already in the r_meshvbo and r_meshindexesvbo
|
|
|
|
static VBOs), and lerping and lighting is done in the vertex shader.
|
|
|
|
|
|
|
|
Supports optional overbright, optional fullbright pixels.
|
|
|
|
|
|
|
|
Based on code by MH from RMQEngine
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltexture_t *tx, gltexture_t *fb)
|
|
|
|
{
|
|
|
|
float blend;
|
|
|
|
|
|
|
|
if (lerpdata.pose1 != lerpdata.pose2)
|
|
|
|
{
|
|
|
|
blend = lerpdata.blend;
|
|
|
|
}
|
|
|
|
else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled
|
|
|
|
{
|
|
|
|
blend = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_UseProgramFunc (r_alias_program);
|
|
|
|
|
|
|
|
GL_BindBuffer (GL_ARRAY_BUFFER, r_meshvbo);
|
|
|
|
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, r_meshindexesvbo);
|
|
|
|
|
|
|
|
GL_EnableVertexAttribArrayFunc (texCoordsAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (pose1VertexAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (pose2VertexAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
|
|
|
|
|
|
|
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, 0, (void *)(intptr_t)currententity->model->vbostofs);
|
|
|
|
GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose1));
|
|
|
|
GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose2));
|
|
|
|
// GL_TRUE to normalize the signed bytes to [-1 .. 1]
|
|
|
|
GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose1));
|
|
|
|
GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 4, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose2));
|
|
|
|
|
|
|
|
// set uniforms
|
|
|
|
GL_Uniform1fFunc (blendLoc, blend);
|
|
|
|
GL_Uniform3fFunc (shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]);
|
|
|
|
GL_Uniform4fFunc (lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha);
|
|
|
|
GL_Uniform1iFunc (texLoc, 0);
|
|
|
|
GL_Uniform1iFunc (fullbrightTexLoc, 1);
|
|
|
|
GL_Uniform1iFunc (useFullbrightTexLoc, (fb != NULL) ? 1 : 0);
|
|
|
|
GL_Uniform1fFunc (useOverbrightLoc, overbright ? 1 : 0);
|
|
|
|
|
|
|
|
// set textures
|
|
|
|
GL_SelectTexture (GL_TEXTURE0);
|
|
|
|
GL_Bind (tx);
|
|
|
|
|
|
|
|
if (fb)
|
|
|
|
{
|
|
|
|
GL_SelectTexture (GL_TEXTURE1);
|
|
|
|
GL_Bind (fb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// draw
|
|
|
|
glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, (void *)(intptr_t)currententity->model->vboindexofs);
|
|
|
|
|
|
|
|
// clean up
|
|
|
|
GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (pose1VertexAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (pose2VertexAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (pose1NormalAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (pose2NormalAttrIndex);
|
|
|
|
|
|
|
|
GL_UseProgramFunc (0);
|
|
|
|
GL_SelectTexture (GL_TEXTURE0);
|
|
|
|
|
|
|
|
rs_aliaspasses += paliashdr->numtris;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GL_DrawAliasFrame -- johnfitz -- rewritten to support colored light, lerping, entalpha, multitexture, and r_drawflat
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
|
|
|
{
|
2010-04-26 13:44:24 +00:00
|
|
|
float vertcolor[4];
|
|
|
|
trivertx_t *verts1, *verts2;
|
2010-02-15 23:26:55 +00:00
|
|
|
int *commands;
|
|
|
|
int count;
|
|
|
|
float u,v;
|
|
|
|
float blend, iblend;
|
|
|
|
qboolean lerping;
|
|
|
|
|
|
|
|
if (lerpdata.pose1 != lerpdata.pose2)
|
|
|
|
{
|
|
|
|
lerping = true;
|
|
|
|
verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
|
|
|
|
verts2 = verts1;
|
|
|
|
verts1 += lerpdata.pose1 * paliashdr->poseverts;
|
|
|
|
verts2 += lerpdata.pose2 * paliashdr->poseverts;
|
|
|
|
blend = lerpdata.blend;
|
|
|
|
iblend = 1.0f - blend;
|
|
|
|
}
|
|
|
|
else // poses the same means either 1. the entity has paused its animation, or 2. r_lerpmodels is disabled
|
|
|
|
{
|
|
|
|
lerping = false;
|
|
|
|
verts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);
|
2010-04-26 14:02:37 +00:00
|
|
|
verts2 = verts1; // avoid bogus compiler warning
|
2010-02-15 23:26:55 +00:00
|
|
|
verts1 += lerpdata.pose1 * paliashdr->poseverts;
|
2010-04-26 13:44:24 +00:00
|
|
|
blend = iblend = 0; // avoid bogus compiler warning
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
commands = (int *)((byte *)paliashdr + paliashdr->commands);
|
|
|
|
|
|
|
|
vertcolor[3] = entalpha; //never changes, so there's no need to put this inside the loop
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
// get the vertex count and primitive type
|
|
|
|
count = *commands++;
|
|
|
|
if (!count)
|
|
|
|
break; // done
|
|
|
|
|
|
|
|
if (count < 0)
|
|
|
|
{
|
|
|
|
count = -count;
|
|
|
|
glBegin (GL_TRIANGLE_FAN);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
glBegin (GL_TRIANGLE_STRIP);
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
u = ((float *)commands)[0];
|
|
|
|
v = ((float *)commands)[1];
|
|
|
|
if (mtexenabled)
|
|
|
|
{
|
2014-08-30 08:00:34 +00:00
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, u, v);
|
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, u, v);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
glTexCoord2f (u, v);
|
|
|
|
|
|
|
|
commands += 2;
|
|
|
|
|
|
|
|
if (shading)
|
|
|
|
{
|
|
|
|
if (r_drawflat_cheatsafe)
|
|
|
|
{
|
64 bit compatibility effort, 2/nn: type correctness work in common.h,
gl_draw.c, gl_model.c, gl_sky.c, gl_texmgr.c, gl_texmgr.h, r_alias.c,
r_brush.c, r_part.c, r_world.c, snd_mem.c. next step will be server
side (progs) work which is actually the heart of the problems.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@34 af15c1b1-3010-417e-b628-4374ebc0bcbd
2010-02-16 21:26:11 +00:00
|
|
|
srand(count * (unsigned int)(src_offset_t)commands);
|
2010-02-15 23:26:55 +00:00
|
|
|
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
|
|
|
}
|
|
|
|
else if (lerping)
|
|
|
|
{
|
|
|
|
vertcolor[0] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[0];
|
|
|
|
vertcolor[1] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[1];
|
|
|
|
vertcolor[2] = (shadedots[verts1->lightnormalindex]*iblend + shadedots[verts2->lightnormalindex]*blend) * lightcolor[2];
|
|
|
|
glColor4fv (vertcolor);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vertcolor[0] = shadedots[verts1->lightnormalindex] * lightcolor[0];
|
|
|
|
vertcolor[1] = shadedots[verts1->lightnormalindex] * lightcolor[1];
|
|
|
|
vertcolor[2] = shadedots[verts1->lightnormalindex] * lightcolor[2];
|
|
|
|
glColor4fv (vertcolor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lerping)
|
|
|
|
{
|
|
|
|
glVertex3f (verts1->v[0]*iblend + verts2->v[0]*blend,
|
|
|
|
verts1->v[1]*iblend + verts2->v[1]*blend,
|
|
|
|
verts1->v[2]*iblend + verts2->v[2]*blend);
|
|
|
|
verts1++;
|
|
|
|
verts2++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glVertex3f (verts1->v[0], verts1->v[1], verts1->v[2]);
|
|
|
|
verts1++;
|
|
|
|
}
|
|
|
|
} while (--count);
|
|
|
|
|
|
|
|
glEnd ();
|
|
|
|
}
|
|
|
|
|
|
|
|
rs_aliaspasses += paliashdr->numtris;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_SetupAliasFrame -- johnfitz -- rewritten to support lerping
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_SetupAliasFrame (aliashdr_t *paliashdr, int frame, lerpdata_t *lerpdata)
|
|
|
|
{
|
|
|
|
entity_t *e = currententity;
|
|
|
|
int posenum, numposes;
|
|
|
|
|
|
|
|
if ((frame >= paliashdr->numframes) || (frame < 0))
|
|
|
|
{
|
|
|
|
Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame);
|
|
|
|
frame = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
posenum = paliashdr->frames[frame].firstpose;
|
|
|
|
numposes = paliashdr->frames[frame].numposes;
|
|
|
|
|
|
|
|
if (numposes > 1)
|
|
|
|
{
|
|
|
|
e->lerptime = paliashdr->frames[frame].interval;
|
|
|
|
posenum += (int)(cl.time / e->lerptime) % numposes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
e->lerptime = 0.1;
|
|
|
|
|
|
|
|
if (e->lerpflags & LERP_RESETANIM) //kill any lerp in progress
|
|
|
|
{
|
|
|
|
e->lerpstart = 0;
|
|
|
|
e->previouspose = posenum;
|
|
|
|
e->currentpose = posenum;
|
|
|
|
e->lerpflags -= LERP_RESETANIM;
|
|
|
|
}
|
|
|
|
else if (e->currentpose != posenum) // pose changed, start new lerp
|
|
|
|
{
|
|
|
|
if (e->lerpflags & LERP_RESETANIM2) //defer lerping one more time
|
|
|
|
{
|
|
|
|
e->lerpstart = 0;
|
|
|
|
e->previouspose = posenum;
|
|
|
|
e->currentpose = posenum;
|
|
|
|
e->lerpflags -= LERP_RESETANIM2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
e->lerpstart = cl.time;
|
|
|
|
e->previouspose = e->currentpose;
|
|
|
|
e->currentpose = posenum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//set up values
|
|
|
|
if (r_lerpmodels.value && !(e->model->flags & MOD_NOLERP && r_lerpmodels.value != 2))
|
|
|
|
{
|
|
|
|
if (e->lerpflags & LERP_FINISH && numposes == 1)
|
|
|
|
lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / (e->lerpfinish - e->lerpstart), 1);
|
|
|
|
else
|
|
|
|
lerpdata->blend = CLAMP (0, (cl.time - e->lerpstart) / e->lerptime, 1);
|
|
|
|
lerpdata->pose1 = e->previouspose;
|
|
|
|
lerpdata->pose2 = e->currentpose;
|
|
|
|
}
|
|
|
|
else //don't lerp
|
|
|
|
{
|
|
|
|
lerpdata->blend = 1;
|
|
|
|
lerpdata->pose1 = posenum;
|
|
|
|
lerpdata->pose2 = posenum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_SetupEntityTransform -- johnfitz -- set up transform part of lerpdata
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_SetupEntityTransform (entity_t *e, lerpdata_t *lerpdata)
|
|
|
|
{
|
|
|
|
float blend;
|
|
|
|
vec3_t d;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// if LERP_RESETMOVE, kill any lerps in progress
|
|
|
|
if (e->lerpflags & LERP_RESETMOVE)
|
|
|
|
{
|
|
|
|
e->movelerpstart = 0;
|
|
|
|
VectorCopy (e->origin, e->previousorigin);
|
|
|
|
VectorCopy (e->origin, e->currentorigin);
|
|
|
|
VectorCopy (e->angles, e->previousangles);
|
|
|
|
VectorCopy (e->angles, e->currentangles);
|
|
|
|
e->lerpflags -= LERP_RESETMOVE;
|
|
|
|
}
|
|
|
|
else if (!VectorCompare (e->origin, e->currentorigin) || !VectorCompare (e->angles, e->currentangles)) // origin/angles changed, start new lerp
|
|
|
|
{
|
|
|
|
e->movelerpstart = cl.time;
|
|
|
|
VectorCopy (e->currentorigin, e->previousorigin);
|
|
|
|
VectorCopy (e->origin, e->currentorigin);
|
|
|
|
VectorCopy (e->currentangles, e->previousangles);
|
|
|
|
VectorCopy (e->angles, e->currentangles);
|
|
|
|
}
|
|
|
|
|
|
|
|
//set up values
|
|
|
|
if (r_lerpmove.value && e != &cl.viewent && e->lerpflags & LERP_MOVESTEP)
|
|
|
|
{
|
|
|
|
if (e->lerpflags & LERP_FINISH)
|
|
|
|
blend = CLAMP (0, (cl.time - e->movelerpstart) / (e->lerpfinish - e->movelerpstart), 1);
|
|
|
|
else
|
|
|
|
blend = CLAMP (0, (cl.time - e->movelerpstart) / 0.1, 1);
|
|
|
|
|
|
|
|
//translation
|
|
|
|
VectorSubtract (e->currentorigin, e->previousorigin, d);
|
|
|
|
lerpdata->origin[0] = e->previousorigin[0] + d[0] * blend;
|
|
|
|
lerpdata->origin[1] = e->previousorigin[1] + d[1] * blend;
|
|
|
|
lerpdata->origin[2] = e->previousorigin[2] + d[2] * blend;
|
|
|
|
|
|
|
|
//rotation
|
|
|
|
VectorSubtract (e->currentangles, e->previousangles, d);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
if (d[i] > 180) d[i] -= 360;
|
|
|
|
if (d[i] < -180) d[i] += 360;
|
|
|
|
}
|
|
|
|
lerpdata->angles[0] = e->previousangles[0] + d[0] * blend;
|
|
|
|
lerpdata->angles[1] = e->previousangles[1] + d[1] * blend;
|
|
|
|
lerpdata->angles[2] = e->previousangles[2] + d[2] * blend;
|
|
|
|
}
|
|
|
|
else //don't lerp
|
|
|
|
{
|
|
|
|
VectorCopy (e->origin, lerpdata->origin);
|
|
|
|
VectorCopy (e->angles, lerpdata->angles);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_SetupAliasLighting -- johnfitz -- broken out from R_DrawAliasModel and rewritten
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_SetupAliasLighting (entity_t *e)
|
|
|
|
{
|
|
|
|
vec3_t dist;
|
|
|
|
float add;
|
|
|
|
int i;
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
int quantizedangle;
|
|
|
|
float radiansangle;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
R_LightPoint (e->origin);
|
|
|
|
|
|
|
|
//add dlights
|
|
|
|
for (i=0 ; i<MAX_DLIGHTS ; i++)
|
|
|
|
{
|
|
|
|
if (cl_dlights[i].die >= cl.time)
|
|
|
|
{
|
|
|
|
VectorSubtract (currententity->origin, cl_dlights[i].origin, dist);
|
2010-08-01 19:22:46 +00:00
|
|
|
add = cl_dlights[i].radius - VectorLength(dist);
|
2010-02-15 23:26:55 +00:00
|
|
|
if (add > 0)
|
|
|
|
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// minimum light value on gun (24)
|
|
|
|
if (e == &cl.viewent)
|
|
|
|
{
|
|
|
|
add = 72.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
|
|
|
|
if (add > 0.0f)
|
|
|
|
{
|
|
|
|
lightcolor[0] += add / 3.0f;
|
|
|
|
lightcolor[1] += add / 3.0f;
|
|
|
|
lightcolor[2] += add / 3.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// minimum light value on players (8)
|
|
|
|
if (currententity > cl_entities && currententity <= cl_entities + cl.maxclients)
|
|
|
|
{
|
|
|
|
add = 24.0f - (lightcolor[0] + lightcolor[1] + lightcolor[2]);
|
|
|
|
if (add > 0.0f)
|
|
|
|
{
|
|
|
|
lightcolor[0] += add / 3.0f;
|
|
|
|
lightcolor[1] += add / 3.0f;
|
|
|
|
lightcolor[2] += add / 3.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// clamp lighting so it doesn't overbright as much (96)
|
|
|
|
if (overbright)
|
|
|
|
{
|
|
|
|
add = 288.0f / (lightcolor[0] + lightcolor[1] + lightcolor[2]);
|
|
|
|
if (add < 1.0f)
|
|
|
|
VectorScale(lightcolor, add, lightcolor);
|
|
|
|
}
|
|
|
|
|
|
|
|
//hack up the brightness when fullbrights but no overbrights (256)
|
|
|
|
if (gl_fullbrights.value && !gl_overbright_models.value)
|
|
|
|
if (e->model->flags & MOD_FBRIGHTHACK)
|
|
|
|
{
|
|
|
|
lightcolor[0] = 256.0f;
|
|
|
|
lightcolor[1] = 256.0f;
|
|
|
|
lightcolor[2] = 256.0f;
|
|
|
|
}
|
|
|
|
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
quantizedangle = ((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1);
|
|
|
|
|
|
|
|
//ericw -- shadevector is passed to the shader to compute shadedots inside the
|
|
|
|
//shader, see GLAlias_CreateShaders()
|
|
|
|
radiansangle = (quantizedangle / 16.0) * 2.0 * 3.14159;
|
|
|
|
shadevector[0] = cos(-radiansangle);
|
|
|
|
shadevector[1] = sin(-radiansangle);
|
|
|
|
shadevector[2] = 1;
|
|
|
|
VectorNormalize(shadevector);
|
|
|
|
//ericw --
|
|
|
|
|
|
|
|
shadedots = r_avertexnormal_dots[quantizedangle];
|
|
|
|
VectorScale (lightcolor, 1.0f / 200.0f, lightcolor);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_DrawAliasModel -- johnfitz -- almost completely rewritten
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_DrawAliasModel (entity_t *e)
|
|
|
|
{
|
|
|
|
aliashdr_t *paliashdr;
|
|
|
|
int i, anim;
|
|
|
|
gltexture_t *tx, *fb;
|
|
|
|
lerpdata_t lerpdata;
|
|
|
|
|
|
|
|
//
|
|
|
|
// setup pose/lerp data -- do it first so we don't miss updates due to culling
|
|
|
|
//
|
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
|
|
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
|
|
|
R_SetupEntityTransform (e, &lerpdata);
|
|
|
|
|
|
|
|
//
|
|
|
|
// cull it
|
|
|
|
//
|
|
|
|
if (R_CullModelForEntity(e))
|
|
|
|
return;
|
|
|
|
|
|
|
|
//
|
|
|
|
// transform it
|
|
|
|
//
|
2014-08-30 08:00:34 +00:00
|
|
|
glPushMatrix ();
|
2010-02-15 23:26:55 +00:00
|
|
|
R_RotateForEntity (lerpdata.origin, lerpdata.angles);
|
|
|
|
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
|
|
|
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
|
|
|
|
|
|
|
//
|
|
|
|
// random stuff
|
|
|
|
//
|
|
|
|
if (gl_smoothmodels.value && !r_drawflat_cheatsafe)
|
|
|
|
glShadeModel (GL_SMOOTH);
|
|
|
|
if (gl_affinemodels.value)
|
|
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
|
|
overbright = gl_overbright_models.value;
|
|
|
|
shading = true;
|
|
|
|
|
|
|
|
//
|
|
|
|
// set up for alpha blending
|
|
|
|
//
|
|
|
|
if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) //no alpha in drawflat or lightmap mode
|
|
|
|
entalpha = 1;
|
|
|
|
else
|
|
|
|
entalpha = ENTALPHA_DECODE(e->alpha);
|
|
|
|
if (entalpha == 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (entalpha < 1)
|
|
|
|
{
|
|
|
|
if (!gl_texture_env_combine) overbright = false; //overbright can't be done in a single pass without combiners
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// set up lighting
|
|
|
|
//
|
|
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
|
|
R_SetupAliasLighting (e);
|
|
|
|
|
|
|
|
//
|
|
|
|
// set up textures
|
|
|
|
//
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
anim = (int)(cl.time*10) & 3;
|
|
|
|
tx = paliashdr->gltextures[e->skinnum][anim];
|
|
|
|
fb = paliashdr->fbtextures[e->skinnum][anim];
|
|
|
|
if (e->colormap != vid.colormap && !gl_nocolors.value)
|
|
|
|
{
|
|
|
|
i = e - cl_entities;
|
|
|
|
if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */)
|
|
|
|
tx = playertextures[i - 1];
|
|
|
|
}
|
|
|
|
if (!gl_fullbrights.value)
|
|
|
|
fb = NULL;
|
|
|
|
|
|
|
|
//
|
|
|
|
// draw it
|
|
|
|
//
|
|
|
|
if (r_drawflat_cheatsafe)
|
|
|
|
{
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
srand((int) (cl.time * 1000)); //restore randomness
|
|
|
|
}
|
|
|
|
else if (r_fullbright_cheatsafe)
|
|
|
|
{
|
|
|
|
GL_Bind (tx);
|
|
|
|
shading = false;
|
|
|
|
glColor4f(1,1,1,entalpha);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
if (fb)
|
|
|
|
{
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_Bind(fb);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glColor3f(entalpha,entalpha,entalpha);
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (r_lightmap_cheatsafe)
|
|
|
|
{
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
|
|
shading = false;
|
|
|
|
glColor3f(1,1,1);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
}
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
// call fast path if possible. if the shader compliation failed for some reason,
|
|
|
|
// r_alias_program will be 0.
|
|
|
|
else if (GLAlias_SupportsShaders() && (r_alias_program != 0))
|
|
|
|
{
|
|
|
|
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb);
|
|
|
|
}
|
2010-02-15 23:26:55 +00:00
|
|
|
else if (overbright)
|
|
|
|
{
|
|
|
|
if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass
|
|
|
|
{
|
|
|
|
GL_Bind (tx);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
|
|
|
GL_EnableMultitexture(); // selects TEXTURE1
|
|
|
|
GL_Bind (fb);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
|
|
|
else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass
|
|
|
|
{
|
|
|
|
// first pass
|
|
|
|
GL_Bind(tx);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
// second pass
|
|
|
|
if (fb)
|
|
|
|
{
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_Bind(fb);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
shading = false;
|
|
|
|
glColor3f(entalpha,entalpha,entalpha);
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else //case 3: overbright in two passes, then fullbright pass
|
|
|
|
{
|
|
|
|
// first pass
|
|
|
|
GL_Bind(tx);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
// second pass -- additive with black fog, to double the object colors but not the fog color
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
// third pass
|
|
|
|
if (fb)
|
|
|
|
{
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_Bind(fb);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
shading = false;
|
|
|
|
glColor3f(entalpha,entalpha,entalpha);
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture
|
|
|
|
{
|
|
|
|
GL_DisableMultitexture(); // selects TEXTURE0
|
|
|
|
GL_Bind (tx);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_EnableMultitexture(); // selects TEXTURE1
|
|
|
|
GL_Bind (fb);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
|
|
|
else //case 5: fullbright mask without multitexture
|
|
|
|
{
|
|
|
|
// first pass
|
|
|
|
GL_Bind(tx);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
// second pass
|
|
|
|
if (fb)
|
|
|
|
{
|
|
|
|
GL_Bind(fb);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
shading = false;
|
|
|
|
glColor3f(entalpha,entalpha,entalpha);
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
|
|
glShadeModel (GL_FLAT);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glColor3f(1,1,1);
|
|
|
|
glPopMatrix ();
|
|
|
|
}
|
|
|
|
|
|
|
|
//johnfitz -- values for shadow matrix
|
|
|
|
#define SHADOW_SKEW_X -0.7 //skew along x axis. -0.7 to mimic glquake shadows
|
|
|
|
#define SHADOW_SKEW_Y 0 //skew along y axis. 0 to mimic glquake shadows
|
|
|
|
#define SHADOW_VSCALE 0 //0=completely flat
|
|
|
|
#define SHADOW_HEIGHT 0.1 //how far above the floor to render the shadow
|
|
|
|
//johnfitz
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
GL_DrawAliasShadow -- johnfitz -- rewritten
|
|
|
|
|
|
|
|
TODO: orient shadow onto "lightplane" (a global mplane_t*)
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GL_DrawAliasShadow (entity_t *e)
|
|
|
|
{
|
|
|
|
float shadowmatrix[16] = {1, 0, 0, 0,
|
|
|
|
0, 1, 0, 0,
|
|
|
|
SHADOW_SKEW_X, SHADOW_SKEW_Y, SHADOW_VSCALE, 0,
|
|
|
|
0, 0, SHADOW_HEIGHT, 1};
|
|
|
|
float lheight;
|
|
|
|
aliashdr_t *paliashdr;
|
|
|
|
lerpdata_t lerpdata;
|
|
|
|
|
|
|
|
if (R_CullModelForEntity(e))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (e == &cl.viewent || e->model->flags & MOD_NOSHADOW)
|
|
|
|
return;
|
|
|
|
|
|
|
|
entalpha = ENTALPHA_DECODE(e->alpha);
|
|
|
|
if (entalpha == 0) return;
|
|
|
|
|
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
|
|
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
|
|
|
R_SetupEntityTransform (e, &lerpdata);
|
|
|
|
R_LightPoint (e->origin);
|
|
|
|
lheight = currententity->origin[2] - lightspot[2];
|
|
|
|
|
|
|
|
// set up matrix
|
2014-08-30 08:00:34 +00:00
|
|
|
glPushMatrix ();
|
2010-02-15 23:26:55 +00:00
|
|
|
glTranslatef (lerpdata.origin[0], lerpdata.origin[1], lerpdata.origin[2]);
|
|
|
|
glTranslatef (0,0,-lheight);
|
|
|
|
glMultMatrixf (shadowmatrix);
|
|
|
|
glTranslatef (0,0,lheight);
|
|
|
|
glRotatef (lerpdata.angles[1], 0, 0, 1);
|
|
|
|
glRotatef (-lerpdata.angles[0], 0, 1, 0);
|
|
|
|
glRotatef (lerpdata.angles[2], 1, 0, 0);
|
|
|
|
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
|
|
|
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
|
|
|
|
|
|
|
// draw it
|
|
|
|
glDepthMask(GL_FALSE);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
GL_DisableMultitexture ();
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
|
|
shading = false;
|
|
|
|
glColor4f(0,0,0,entalpha * 0.5);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
|
|
|
|
//clean up
|
|
|
|
glPopMatrix ();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
R_DrawAliasModel_ShowTris -- johnfitz
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void R_DrawAliasModel_ShowTris (entity_t *e)
|
|
|
|
{
|
|
|
|
aliashdr_t *paliashdr;
|
|
|
|
lerpdata_t lerpdata;
|
|
|
|
|
|
|
|
if (R_CullModelForEntity(e))
|
|
|
|
return;
|
|
|
|
|
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
|
|
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
|
|
|
R_SetupEntityTransform (e, &lerpdata);
|
|
|
|
|
2014-08-30 08:00:34 +00:00
|
|
|
glPushMatrix ();
|
2010-02-15 23:26:55 +00:00
|
|
|
R_RotateForEntity (lerpdata.origin,lerpdata.angles);
|
|
|
|
glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
|
|
|
glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
|
|
|
|
|
|
|
shading = false;
|
|
|
|
glColor3f(1,1,1);
|
|
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
|
|
|
|
glPopMatrix ();
|
2010-02-16 12:24:38 +00:00
|
|
|
}
|
|
|
|
|