mirror of
https://github.com/nzp-team/quakespasm.git
synced 2024-11-25 05:11:07 +00:00
1470 lines
42 KiB
C
1470 lines
42 KiB
C
/*
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
|
|
|
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
|
|
extern cvar_t scr_fov_viewmodel; //sB porting seperate viewmodel FOV
|
|
extern cvar_t scr_fov;
|
|
|
|
extern float fog_red;
|
|
extern float fog_green;
|
|
extern float fog_blue;
|
|
|
|
#include "mathlib.h"
|
|
|
|
//up to 16 color translated skins
|
|
gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz -- changed to an array of pointers
|
|
|
|
#define NUMVERTEXNORMALS 162
|
|
|
|
float r_avertexnormals[NUMVERTEXNORMALS][3] =
|
|
{
|
|
#include "anorms.h"
|
|
};
|
|
|
|
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] =
|
|
{
|
|
#include "anorm_dots.h"
|
|
};
|
|
|
|
extern vec3_t lightspot;
|
|
|
|
float *shadedots = r_avertexnormal_dots[0];
|
|
vec3_t shadevector;
|
|
|
|
extern int zombie_skins[2][2];
|
|
|
|
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
|
|
|
|
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 GLuint useAlphaTestLoc;
|
|
static GLuint aliasgrayscale_enableLoc;
|
|
#ifdef VITA
|
|
static GLuint fogDensityLoc;
|
|
static GLuint fogRedLoc;
|
|
static GLuint fogGreenLoc;
|
|
static GLuint fogBlueLoc;
|
|
#endif
|
|
|
|
#define pose1VertexAttrIndex 0
|
|
#define pose1NormalAttrIndex 1
|
|
#define pose2VertexAttrIndex 2
|
|
#define pose2NormalAttrIndex 3
|
|
#define texCoordsAttrIndex 4
|
|
|
|
/*
|
|
=============
|
|
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)
|
|
{
|
|
const int xyzoffs = offsetof (meshxyz_t, xyz);
|
|
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)
|
|
{
|
|
const int normaloffs = offsetof (meshxyz_t, normal);
|
|
return (void *)(currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + normaloffs);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
GLAlias_CreateShaders
|
|
=============
|
|
*/
|
|
void GLAlias_CreateShaders (void)
|
|
{
|
|
const glsl_attrib_binding_t bindings[] = {
|
|
{ "TexCoords", texCoordsAttrIndex },
|
|
{ "Pose1Vert", pose1VertexAttrIndex },
|
|
{ "Pose1Normal", pose1NormalAttrIndex },
|
|
{ "Pose2Vert", pose2VertexAttrIndex },
|
|
{ "Pose2Normal", pose2NormalAttrIndex }
|
|
};
|
|
#ifdef VITA
|
|
const GLchar *vertSource = \
|
|
"uniform float Blend;\n"
|
|
"uniform float3 ShadeVector;\n"
|
|
"uniform float4 LightColor;\n"
|
|
"uniform float4x4 gl_ModelViewProjectionMatrix;\n"
|
|
"\n"
|
|
"float r_avertexnormal_dot(float3 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"
|
|
" float4 TexCoords,\n"
|
|
" float4 Pose1Vert,\n"
|
|
" float3 Pose1Normal,\n"
|
|
" float4 Pose2Vert,\n"
|
|
" float3 Pose2Normal,\n"
|
|
" float2 out gl_TexCoord : TEXCOORD0,\n"
|
|
" float4 out gl_Position : POSITION,\n"
|
|
" float4 out gl_FrontColor : COLOR\n"
|
|
") {\n"
|
|
" gl_TexCoord = TexCoords.xy;\n"
|
|
" float4 lerpedVert = lerp(float4(Pose1Vert.xyz, 1.0), float4(Pose2Vert.xyz, 1.0), Blend);\n"
|
|
" gl_Position = mul(gl_ModelViewProjectionMatrix, lerpedVert);\n"
|
|
" float dot1 = r_avertexnormal_dot(Pose1Normal);\n"
|
|
" float dot2 = r_avertexnormal_dot(Pose2Normal);\n"
|
|
" gl_FrontColor = LightColor * float4(float3(lerp(dot1, dot2, Blend)), 1.0);\n"
|
|
"}\n";
|
|
|
|
const GLchar *fragSource = \
|
|
"uniform sampler2D Tex;\n"
|
|
"uniform sampler2D FullbrightTex;\n"
|
|
"uniform int UseFullbrightTex;\n"
|
|
"uniform int UseOverbright;\n"
|
|
"uniform int UseAlphaTest;\n"
|
|
"uniform int gs_mod;\n"
|
|
"uniform float fog_density;\n"
|
|
"uniform float fog_red;\n"
|
|
"uniform float fog_green;\n"
|
|
"uniform float fog_blue;\n"
|
|
"\n"
|
|
"float4 main(\n"
|
|
" float4 coords : WPOS,\n"
|
|
" float2 gl_TexCoord : TEXCOORD0,\n"
|
|
" float4 gl_Color : COLOR\n"
|
|
") {\n"
|
|
" float4 result = tex2D(Tex, gl_TexCoord);\n"
|
|
" if (UseAlphaTest && (result.a < 0.666))\n"
|
|
" discard;\n"
|
|
" result *= gl_Color;\n"
|
|
" if (UseOverbright)\n"
|
|
" result.rgb *= 2.0;\n"
|
|
" if (UseFullbrightTex)\n"
|
|
" result += tex2D(FullbrightTex, gl_TexCoord);\n"
|
|
" result = clamp(result, 0.0, 1.0);\n"
|
|
" float FogFragCoord = coords.z / coords.w;\n"
|
|
" float fog = exp(-fog_density * fog_density * FogFragCoord * FogFragCoord);\n"
|
|
" fog = clamp(fog, 0.0, 1.0);\n"
|
|
" result = lerp(float4(fog_red, fog_green, fog_blue, 1.0), result, fog);\n"
|
|
" result.a = gl_Color.a;\n" // FIXME: This will make almost transparent things cut holes though heavy fog
|
|
" if (gs_mod) {\n"
|
|
" float value = clamp((result.r * 0.33) + (result.g * 0.55) + (result.b * 0.11), 0.0, 1.0);\n"
|
|
" result.r = value;\n"
|
|
" result.g = value;\n"
|
|
" result.b = value;\n"
|
|
" }"
|
|
" return result;\n"
|
|
"}\n";
|
|
#else
|
|
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"
|
|
"\n"
|
|
"varying float FogFragCoord;\n"
|
|
"\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(vec4(Pose1Vert.xyz, 1.0), vec4(Pose2Vert.xyz, 1.0), Blend);\n"
|
|
" gl_Position = gl_ModelViewProjectionMatrix * lerpedVert;\n"
|
|
" FogFragCoord = gl_Position.w;\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"
|
|
"}\n";
|
|
|
|
const GLchar *fragSource = \
|
|
"#version 110\n"
|
|
"\n"
|
|
"uniform sampler2D Tex;\n"
|
|
"uniform sampler2D FullbrightTex;\n"
|
|
"uniform bool UseFullbrightTex;\n"
|
|
"uniform bool UseOverbright;\n"
|
|
"uniform bool UseAlphaTest;\n"
|
|
"uniform bool gs_mod;\n"
|
|
"\n"
|
|
"varying float FogFragCoord;\n"
|
|
"\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n"
|
|
" if (UseAlphaTest && (result.a < 0.666))\n"
|
|
" discard;\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"
|
|
" float fog = exp(-gl_Fog.density * gl_Fog.density * FogFragCoord * FogFragCoord);\n"
|
|
" fog = clamp(fog, 0.0, 1.0);\n"
|
|
" result = mix(gl_Fog.color, result, fog);\n"
|
|
" result.a = gl_Color.a;\n" // FIXME: This will make almost transparent things cut holes though heavy fog
|
|
" if (gs_mod) {\n"
|
|
" float value = clamp((result.r * 0.33) + (result.g * 0.55) + (result.b * 0.11), 0.0, 1.0);\n"
|
|
" result.r = value;\n"
|
|
" result.g = value;\n"
|
|
" result.b = value;\n"
|
|
" }"
|
|
" gl_FragColor = result;\n"
|
|
"}\n";
|
|
#endif
|
|
|
|
if (!gl_glsl_alias_able)
|
|
return;
|
|
|
|
r_alias_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings);
|
|
|
|
if (r_alias_program != 0)
|
|
{
|
|
// get uniform locations
|
|
blendLoc = GL_GetUniformLocation (&r_alias_program, "Blend");
|
|
shadevectorLoc = GL_GetUniformLocation (&r_alias_program, "ShadeVector");
|
|
lightColorLoc = GL_GetUniformLocation (&r_alias_program, "LightColor");
|
|
//#ifndef VITA
|
|
texLoc = GL_GetUniformLocation (&r_alias_program, "Tex");
|
|
fullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "FullbrightTex");
|
|
//#endif
|
|
useFullbrightTexLoc = GL_GetUniformLocation (&r_alias_program, "UseFullbrightTex");
|
|
useOverbrightLoc = GL_GetUniformLocation (&r_alias_program, "UseOverbright");
|
|
useAlphaTestLoc = GL_GetUniformLocation (&r_alias_program, "UseAlphaTest");
|
|
aliasgrayscale_enableLoc = GL_GetUniformLocation (&r_alias_program, "gs_mod");
|
|
#ifdef VITA
|
|
fogDensityLoc = GL_GetUniformLocation(&r_alias_program, "fog_density");
|
|
fogRedLoc = GL_GetUniformLocation(&r_alias_program, "fog_red");
|
|
fogGreenLoc = GL_GetUniformLocation(&r_alias_program, "fog_green");
|
|
fogBlueLoc = GL_GetUniformLocation(&r_alias_program, "fog_blue");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
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, currententity->model->meshvbo);
|
|
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, currententity->model->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);
|
|
//#ifndef VITA
|
|
GL_Uniform1iFunc (texLoc, 0);
|
|
GL_Uniform1iFunc (fullbrightTexLoc, 1);
|
|
//#endif
|
|
GL_Uniform1iFunc (useFullbrightTexLoc, (fb != NULL) ? 1 : 0);
|
|
GL_Uniform1fFunc (useOverbrightLoc, overbright ? 1 : 0);
|
|
GL_Uniform1iFunc (useAlphaTestLoc, (currententity->model->flags & MF_HOLEY) ? 1 : 0);
|
|
#ifdef VITA
|
|
GL_Uniform1fFunc (fogDensityLoc, Fog_GetDensity() / 64.0f);
|
|
GL_Uniform1fFunc (fogRedLoc, fog_red / 64.0f);
|
|
GL_Uniform1fFunc (fogGreenLoc, fog_green / 64.0f);
|
|
GL_Uniform1fFunc (fogBlueLoc, fog_blue / 64.0f);
|
|
#endif
|
|
// naievil -- experimental grayscale mod
|
|
GL_Uniform1fFunc (aliasgrayscale_enableLoc, /*sv_player->v.renderGrayscale*/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;
|
|
}
|
|
|
|
/*
|
|
=============
|
|
GL_DrawAliasFrame -- johnfitz -- rewritten to support colored light, lerping, entalpha, multitexture, and r_drawflat
|
|
=============
|
|
*/
|
|
void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
|
|
{
|
|
float vertcolor[4];
|
|
trivertx_t *verts1, *verts2;
|
|
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);
|
|
verts2 = verts1; // avoid bogus compiler warning
|
|
verts1 += lerpdata.pose1 * paliashdr->poseverts;
|
|
blend = iblend = 0; // avoid bogus compiler warning
|
|
}
|
|
|
|
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)
|
|
{
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, u, v);
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, u, v);
|
|
}
|
|
else
|
|
glTexCoord2f (u, v);
|
|
|
|
commands += 2;
|
|
|
|
if (shading)
|
|
{
|
|
if (r_drawflat_cheatsafe)
|
|
{
|
|
srand(count * (unsigned int)(src_offset_t)commands);
|
|
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 for '%s'\n", frame, e->model->name);
|
|
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;
|
|
int quantizedangle;
|
|
float radiansangle;
|
|
|
|
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);
|
|
add = cl_dlights[i].radius - VectorLength(dist);
|
|
if (add > 0)
|
|
VectorMA (lightcolor, add, cl_dlights[i].color, lightcolor);
|
|
}
|
|
}
|
|
|
|
// cypress -- limit light value on all ents, not
|
|
// just viewmodel.
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// cypress -- re-te EF_FULLBRIGHT support
|
|
// TODO: potentially just block dlights from colorizing
|
|
if (e->effects & EF_FULLBRIGHT) {
|
|
lightcolor[0] = 400.0f;
|
|
lightcolor[1] = 400.0f;
|
|
lightcolor[2] = 400.0f;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
R_DrawTransparentAliasModel
|
|
blubs: used for semitransparent fullbright models (like their sprite counterparts)
|
|
=================
|
|
*/
|
|
|
|
void R_DrawTransparentAliasModel (entity_t *e)
|
|
{
|
|
/*
|
|
model_t *clmodel;
|
|
vec3_t mins, maxs;
|
|
aliashdr_t *paliashdr;
|
|
float an;
|
|
int anim;
|
|
|
|
clmodel = e->model;
|
|
|
|
VectorAdd (e->origin, clmodel->mins, mins);
|
|
VectorAdd (e->origin, clmodel->maxs, maxs);
|
|
|
|
if (R_CullBox(mins, maxs))
|
|
return;
|
|
|
|
VectorCopy (e->origin, r_entorigin);
|
|
VectorSubtract (r_origin, r_entorigin, modelorg);
|
|
|
|
//
|
|
// get lighting information
|
|
// LordHavoc: .lit support begin
|
|
//ambientlight = shadelight = R_LightPoint (e->origin); // LordHavoc: original code, removed shadelight and ambientlight
|
|
R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this
|
|
// LordHavoc: .lit support end
|
|
lightcolor[0] = lightcolor[1] = lightcolor[2] = 256;
|
|
shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
|
|
// LordHavoc: .lit support begin
|
|
//shadelight = shadelight / 200.0; // LordHavoc: original code
|
|
VectorScale(lightcolor, 1.0f / 200.0f, lightcolor);
|
|
// LordHavoc: .lit support end
|
|
an = e->angles[1]/180*M_PI;
|
|
shadevector[0] = cosf(-an);
|
|
shadevector[1] = sinf(-an);
|
|
shadevector[2] = 1;
|
|
VectorNormalize (shadevector);
|
|
// locate the proper data//
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
c_alias_polys += paliashdr->numtris;
|
|
// draw all the triangles//
|
|
sceGumPushMatrix();
|
|
R_InterpolateEntity(e,0);
|
|
const ScePspFVector3 translation =
|
|
{
|
|
paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]
|
|
};
|
|
sceGumTranslate(&translation);
|
|
const ScePspFVector3 scaling =
|
|
{
|
|
paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]
|
|
};
|
|
sceGumScale(&scaling);
|
|
|
|
//for models(pink transparency)
|
|
nsceGuEnable(GU_BLEND);
|
|
sceGuEnable(GU_ALPHA_TEST);
|
|
sceGuAlphaFunc(GU_GREATER, 0, 0xff);
|
|
|
|
sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA);
|
|
|
|
//st1x:now quake transparency is working
|
|
//force_fullbright
|
|
//sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
|
|
|
|
sceGuShadeModel(GU_SMOOTH);
|
|
sceGumUpdateMatrix();
|
|
IgnoreInterpolatioFrame(e, paliashdr);
|
|
anim = (int)(cl.time*10) & 3;
|
|
GL_Bind(paliashdr->gl_texturenum[e->skinnum][anim]);
|
|
//Rendering block
|
|
if (r_i_model_animation.value)
|
|
{
|
|
R_SetupAliasBlendedFrame (e->frame, paliashdr, e, e->angles[0], e->angles[1]);
|
|
}
|
|
else
|
|
{
|
|
if (r_ipolations.value)//blubs: seems like we don't even use InterpolatedFrames.
|
|
{
|
|
if (r_asynch.value)
|
|
{
|
|
if (e->interpolation >= r_ipolations.value)
|
|
{
|
|
e->last_frame = e->current_frame;
|
|
e->current_frame = e->frame;
|
|
e->interpolation = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (e->frame != e->current_frame)
|
|
{
|
|
e->last_frame = e->current_frame;
|
|
e->current_frame = e->frame;
|
|
e->interpolation = 1;
|
|
}
|
|
}
|
|
R_SetupAliasInterpolatedFrame (e->current_frame,e->last_frame,e->interpolation,paliashdr);
|
|
}
|
|
else
|
|
R_SetupAliasFrame (e->frame, paliashdr, e->angles[0], e->angles[1]);
|
|
}
|
|
sceGumPopMatrix();
|
|
sceGumUpdateMatrix();
|
|
|
|
//st1x:now quake transparency is working
|
|
sceGuAlphaFunc(GU_GREATER, 0, 0xff);
|
|
sceGuDisable(GU_ALPHA_TEST);
|
|
sceGuTexFunc(GU_TFX_REPLACE , GU_TCC_RGBA);
|
|
sceGuShadeModel(GU_FLAT);
|
|
|
|
// else if(ISGLOW(e))
|
|
{
|
|
sceGuDepthMask(GU_FALSE);
|
|
//sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
|
|
//sceGuDisable (GU_BLEND);
|
|
}
|
|
sceGuTexFunc(GU_TFX_REPLACE, GU_TCC_RGBA);
|
|
sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0);
|
|
|
|
sceGuDisable(GU_BLEND);
|
|
*/
|
|
|
|
aliashdr_t *paliashdr;
|
|
int i, anim, skinnum;
|
|
gltexture_t *tx, *fb;
|
|
lerpdata_t lerpdata;
|
|
qboolean alphatest = !!(e->model->flags & MF_HOLEY);
|
|
|
|
//
|
|
// 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
|
|
//
|
|
glPushMatrix ();
|
|
R_RotateForEntity (lerpdata.origin, lerpdata.angles, e->scale);
|
|
|
|
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
|
|
//
|
|
#ifndef VITA
|
|
if (gl_smoothmodels.value && !r_drawflat_cheatsafe)
|
|
glShadeModel (GL_SMOOTH);
|
|
if (gl_affinemodels.value)
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
#endif
|
|
//
|
|
// set up lighting
|
|
//
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
R_SetupAliasLighting (e);
|
|
|
|
//
|
|
// set up textures
|
|
//
|
|
GL_DisableMultitexture();
|
|
anim = (int)(cl.time*10) & 3;
|
|
skinnum = e->skinnum;
|
|
if ((skinnum >= paliashdr->numskins) || (skinnum < 0))
|
|
{
|
|
Con_DPrintf ("R_DrawAliasModel: no such skin # %d for '%s'\n", skinnum, e->model->name);
|
|
// ericw -- display skin 0 for winquake compatibility
|
|
skinnum = 0;
|
|
}
|
|
tx = paliashdr->gltextures[skinnum][anim];
|
|
|
|
//
|
|
// draw it
|
|
//
|
|
GL_Bind (tx);
|
|
glEnable(GL_BLEND);
|
|
glDisable (GL_ALPHA_TEST);
|
|
glDepthMask(GL_FALSE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
GL_DrawAliasFrame (paliashdr, lerpdata);
|
|
|
|
cleanup:
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
#ifndef VITA
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
glShadeModel (GL_FLAT);
|
|
#endif
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
glColor3f(1,1,1);
|
|
glPopMatrix ();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
R_DrawZombieLimb
|
|
|
|
=====================
|
|
*/
|
|
//Blubs Z hacks: need this declaration.
|
|
qmodel_t *Mod_FindName (char *name);
|
|
|
|
|
|
void R_DrawZombieLimb (entity_t *e,int which)
|
|
{
|
|
|
|
//entity_t *e;
|
|
qmodel_t *clmodel;
|
|
aliashdr_t *paliashdr;
|
|
entity_t *limb_ent;
|
|
lerpdata_t lerpdata;
|
|
|
|
//e = &cl_entities[ent];
|
|
//clmodel = e->model;
|
|
|
|
if(which == 1)
|
|
limb_ent = &cl_entities[e->z_head];
|
|
else if(which == 2)
|
|
limb_ent = &cl_entities[e->z_larm];
|
|
else if(which == 3)
|
|
limb_ent = &cl_entities[e->z_rarm];
|
|
else
|
|
return;
|
|
|
|
clmodel = limb_ent->model;
|
|
if(clmodel == NULL)
|
|
return;
|
|
|
|
VectorCopy (e->origin, r_entorigin);
|
|
VectorSubtract (r_origin, r_entorigin, modelorg);
|
|
|
|
// locate the proper data
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (clmodel);//e->model
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
|
R_SetupEntityTransform (e, &lerpdata);
|
|
|
|
glPushMatrix ();
|
|
|
|
R_RotateForEntity (lerpdata.origin, lerpdata.angles, e->scale);
|
|
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
|
|
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;
|
|
|
|
//blubs disabled
|
|
/*if (r_i_model_transform.value)
|
|
R_BlendedRotateForEntity (e, 0);
|
|
else
|
|
R_RotateForEntity (e, 0);*/
|
|
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
R_SetupAliasLighting (e);
|
|
|
|
glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
glScalef(paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);
|
|
|
|
//R_SetupAliasFrame (paliashdr, e->frame, &lerpdata);
|
|
//R_SetupEntityTransform (e, &lerpdata);
|
|
GL_DrawAliasFrame(paliashdr, lerpdata);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
#ifndef VITA
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
glShadeModel (GL_FLAT);
|
|
#endif
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
|
|
//t3 += Sys_FloatTime();
|
|
glPopMatrix ();
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
R_DrawAliasModel -- johnfitz -- almost completely rewritten
|
|
=================
|
|
*/
|
|
|
|
//extern int doZHack;
|
|
extern qboolean model_is_zombie(char name[MAX_QPATH]);
|
|
void R_DrawAliasModel (entity_t *e)
|
|
{
|
|
aliashdr_t *paliashdr;
|
|
int i, anim, skinnum;
|
|
char specChar;
|
|
gltexture_t *tx, *fb;
|
|
lerpdata_t lerpdata;
|
|
qboolean alphatest = !!(e->model->flags & MF_HOLEY);
|
|
//qmodel_t *clmodel;
|
|
vec3_t mins, maxs;
|
|
|
|
//clmodel = e->model;
|
|
|
|
//
|
|
// setup pose/lerp data -- do it first so we don't miss updates due to culling
|
|
//
|
|
/*specChar = clmodel->name[strlen(clmodel->name) - 5];
|
|
if(doZHack && specChar == '#')
|
|
{
|
|
if(clmodel->name[strlen(clmodel->name) - 6] == 'c')
|
|
paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zcfull.mdl"));
|
|
else
|
|
paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zfull.mdl"));
|
|
}
|
|
else*/
|
|
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
|
|
//
|
|
glPushMatrix ();
|
|
R_RotateForEntity (lerpdata.origin, lerpdata.angles, ENTSCALE_DEFAULT);
|
|
/* //sB needs fixing in Quakespasm but fuck GL bro
|
|
//specChar = clmodel->name[strlen(clmodel->name) - 5];
|
|
if(doZHack && specChar == '#')
|
|
{
|
|
if(clmodel->name[strlen(clmodel->name) - 6] == 'c')
|
|
paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zcfull.mdl"));
|
|
else
|
|
paliashdr = (aliashdr_t *) Mod_Extradata(Mod_FindName("models/ai/zfull.mdl"));
|
|
}
|
|
else*/
|
|
paliashdr = (aliashdr_t *)Mod_Extradata (e->model);
|
|
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
|
|
//glPushMatrix ();
|
|
|
|
//
|
|
// random stuff
|
|
//
|
|
#ifndef VITA
|
|
if (gl_smoothmodels.value && !r_drawflat_cheatsafe)
|
|
glShadeModel (GL_SMOOTH);
|
|
if (gl_affinemodels.value)
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
#endif
|
|
overbright = gl_overbright_models.value;
|
|
shading = true;
|
|
|
|
//sB porting viewmodel FOV from 3ds build
|
|
// Special handling of view model to keep FOV from altering look. Pretty good. Not perfect but rather close.
|
|
if ((e == &cl.viewent || e == &cl.viewent2) && scr_fov_viewmodel.value) {
|
|
float scale = 1.0f / tan (DEG2RAD (scr_fov.value / 2.0f)) * scr_fov_viewmodel.value / 90.0f;
|
|
if (e->scale != ENTSCALE_DEFAULT && e->scale != 0) scale *= ENTSCALE_DECODE(e->scale);
|
|
glTranslatef (paliashdr->scale_origin[0] * scale, paliashdr->scale_origin[1], paliashdr->scale_origin[2]);
|
|
glScalef (paliashdr->scale[0] * scale, paliashdr->scale[1], paliashdr->scale[2]);
|
|
} else {
|
|
float scale = 1.0f;
|
|
if (e->scale != ENTSCALE_DEFAULT && e->scale != 0) scale *= ENTSCALE_DECODE(e->scale);
|
|
glTranslatef (paliashdr->scale_origin[0] * scale, paliashdr->scale_origin[1] * scale, paliashdr->scale_origin[2] * scale);
|
|
glScalef (paliashdr->scale[0] * scale, paliashdr->scale[1] * scale, paliashdr->scale[2] * scale);
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
else if (alphatest)
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
//
|
|
// set up lighting
|
|
//
|
|
rs_aliaspolys += paliashdr->numtris;
|
|
R_SetupAliasLighting (e);
|
|
|
|
//
|
|
// set up textures
|
|
//
|
|
GL_DisableMultitexture();
|
|
|
|
anim = (int)(cl.time*10) & 3;
|
|
skinnum = e->skinnum;
|
|
if (((skinnum >= paliashdr->numskins) || (skinnum < 0)) && !model_is_zombie(e->model->name))
|
|
{
|
|
Con_DPrintf ("R_DrawAliasModel: no such skin # %d for '%s'\n", skinnum, e->model->name);
|
|
// ericw -- display skin 0 for winquake compatibility
|
|
skinnum = 0;
|
|
}
|
|
tx = paliashdr->gltextures[skinnum][anim];
|
|
fb = paliashdr->fbtextures[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);
|
|
}
|
|
// call fast path if possible. if the shader compliation failed for some reason,
|
|
// r_alias_program will be 0.
|
|
else if (r_alias_program != 0)
|
|
{
|
|
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata, tx, fb);
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
//glPopMatrix ();
|
|
/*
|
|
if (doZHack == 0 && specChar == '#')//if we're drawing zombie, also draw its limbs in one call
|
|
{
|
|
if(e->z_head)
|
|
R_DrawZombieLimb(e,1);
|
|
if(e->z_larm)
|
|
R_DrawZombieLimb(e,2);
|
|
if(e->z_rarm)
|
|
R_DrawZombieLimb(e,3);
|
|
}*/
|
|
|
|
cleanup:
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
#ifndef VITA
|
|
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
|
|
glShadeModel (GL_FLAT);
|
|
#endif
|
|
glDepthMask(GL_TRUE);
|
|
glDisable(GL_BLEND);
|
|
if (alphatest)
|
|
glDisable (GL_ALPHA_TEST);
|
|
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
|
|
glPushMatrix ();
|
|
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);
|
|
|
|
glPushMatrix ();
|
|
R_RotateForEntity (lerpdata.origin,lerpdata.angles, e->scale);
|
|
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 ();
|
|
}
|
|
|