mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-23 04:11:53 +00:00
9ae7e2621d
Lots of changes. CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit. Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit. Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
4145 lines
104 KiB
C
4145 lines
104 KiB
C
#include "quakedef.h"
|
|
#ifdef RGLQUAKE
|
|
#include "glquake.h"
|
|
#include "shader.h"
|
|
|
|
//these are shared with gl_rsurf - move to header
|
|
void R_MirrorChain (msurface_t *s);
|
|
void GL_SelectTexture (GLenum target);
|
|
void R_RenderDynamicLightmaps (msurface_t *fa);
|
|
void R_BlendLightmaps (void);
|
|
|
|
extern qboolean r_inmirror;
|
|
extern int gldepthfunc;
|
|
extern int *lightmap_textures;
|
|
extern int lightmap_bytes; // 1, 2, or 4
|
|
|
|
extern cvar_t gl_detail;
|
|
extern cvar_t r_fb_bmodels;
|
|
extern cvar_t gl_part_flame;
|
|
|
|
extern cvar_t gl_part_flame;
|
|
extern cvar_t gl_maxshadowlights;
|
|
extern cvar_t r_shadow_realtime_world;
|
|
extern int detailtexture;
|
|
//end header confict
|
|
|
|
extern cvar_t gl_schematics;
|
|
extern cvar_t r_drawflat;
|
|
extern cvar_t r_wallcolour;
|
|
extern cvar_t r_floorcolour;
|
|
|
|
extern lightmapinfo_t **lightmap;
|
|
|
|
extern model_t *currentmodel;
|
|
extern int *deluxmap_textures;
|
|
|
|
extern int normalisationCubeMap;
|
|
|
|
int r_shadowframe;
|
|
|
|
int shadowsurfcount;
|
|
int shadowedgecount;
|
|
int shadowlightfaces;
|
|
int shadowemittedeges;
|
|
|
|
int ppl_specular_fragmentprogram;
|
|
|
|
//#define glBegin glEnd
|
|
|
|
|
|
typedef struct shadowmesh_s {
|
|
int numindicies;
|
|
int *indicies;
|
|
vec3_t *verts;
|
|
} shadowmesh_t;
|
|
|
|
|
|
#define Q2RF_WEAPONMODEL 4 // only draw through eyes
|
|
|
|
struct {
|
|
short count;
|
|
short count2;
|
|
short next;
|
|
short prev;
|
|
} edge[MAX_MAP_EDGES];
|
|
int firstedge;
|
|
|
|
vec3_t lightorg = {0, 0, 0};
|
|
float lightradius;
|
|
|
|
|
|
|
|
typedef struct {
|
|
float xyz[3]; //xyz world coordinates
|
|
float stw[2]; //base texture/normalmap/specular map st coords
|
|
float stl[3]; //lightmap/deluxmap st coords (or attenuated distance*colour)
|
|
float ncm[3]; //normalisation cube map (reflected light dir)
|
|
} surfvertexarray_t;
|
|
|
|
#define MAXARRAYVERTS 2048
|
|
static surfvertexarray_t varray_v[MAXARRAYVERTS];
|
|
static unsigned int varray_i[MAXARRAYVERTS];
|
|
static unsigned int varray_i_forward[MAXARRAYVERTS];
|
|
static unsigned int varray_i_polytotri[MAXARRAYVERTS]; //012 023 034 045...
|
|
int varray_ic;
|
|
int varray_vc;
|
|
|
|
#define inline static
|
|
|
|
extern qboolean varrayactive; //used by the backend
|
|
|
|
inline void PPL_EnableVertexArrays(void)
|
|
{
|
|
varrayactive = false;
|
|
|
|
qglDisableClientState(GL_COLOR_ARRAY);
|
|
qglEnableClientState(GL_VERTEX_ARRAY);
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->xyz);
|
|
qglDisableClientState( GL_COLOR_ARRAY );
|
|
}
|
|
inline void PPL_FlushArrays(void)
|
|
{
|
|
if (varray_ic)
|
|
qglDrawElements(GL_TRIANGLES, varray_ic, GL_UNSIGNED_INT, varray_i);
|
|
varray_ic = 0;
|
|
varray_vc = 0;
|
|
}
|
|
static void PPL_GenerateArrays(msurface_t *surf)
|
|
{
|
|
glpoly_t *p;
|
|
int vi;
|
|
int vc_s;
|
|
float *v;
|
|
|
|
if (!surf->polys)
|
|
{ //hmm. mesh mode.
|
|
if (!surf->mesh)
|
|
return;
|
|
if (surf->mesh->numindexes > MAXARRAYVERTS)
|
|
return;
|
|
if (surf->mesh->numvertexes > MAXARRAYVERTS)
|
|
return;
|
|
if (!surf->mesh->st_array)
|
|
return;
|
|
if (!surf->mesh->lmst_array)
|
|
return;
|
|
if (varray_ic) //FIXME: go muuuch faster please
|
|
PPL_FlushArrays();
|
|
for (vi = 0; vi < surf->mesh->numindexes; vi++)
|
|
varray_i[vi] = surf->mesh->indexes[vi];
|
|
for (vi = 0; vi < surf->mesh->numvertexes; vi++)
|
|
{
|
|
VectorCopy(surf->mesh->xyz_array[vi], varray_v[vi].xyz);
|
|
varray_v[vi].stw[0] = surf->mesh->st_array[vi][0];
|
|
varray_v[vi].stw[1] = surf->mesh->st_array[vi][1];
|
|
varray_v[vi].stl[0] = surf->mesh->lmst_array[vi][0];
|
|
varray_v[vi].stl[1] = surf->mesh->lmst_array[vi][1];
|
|
}
|
|
|
|
varray_vc = surf->mesh->numvertexes;
|
|
varray_ic = surf->mesh->numindexes;
|
|
|
|
return;
|
|
}
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
if (varray_ic + p->numverts*3>MAXARRAYVERTS)
|
|
{
|
|
PPL_FlushArrays();
|
|
}
|
|
|
|
vc_s = varray_vc;
|
|
v = p->verts[0];
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
|
|
{
|
|
varray_i[varray_ic] = vc_s;
|
|
varray_i[varray_ic+1] = varray_vc-1;
|
|
varray_i[varray_ic+2] = varray_vc;
|
|
varray_ic+=3;
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
varray_vc++;
|
|
}
|
|
}
|
|
}
|
|
#ifdef SPECULAR
|
|
//same as above, but also generates cubemap texture coords for light reflection (based on blinn's formula)
|
|
static void PPL_GenerateArraysBlinnCubeMap(msurface_t *surf)
|
|
{
|
|
glpoly_t *p;
|
|
int vi;
|
|
int vc_s;
|
|
float *v;
|
|
|
|
vec3_t eye, halfdir;
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
if (varray_ic + p->numverts*3>MAXARRAYVERTS)
|
|
{
|
|
PPL_FlushArrays();
|
|
}
|
|
|
|
vc_s = varray_vc;
|
|
v = p->verts[0];
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
VectorSubtract(r_refdef.vieworg, v, eye);
|
|
VectorNormalize(eye);
|
|
VectorAdd(eye, (v+7), halfdir);
|
|
// VectorCopy(eye, halfdir);
|
|
varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
|
|
varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
|
|
else
|
|
varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
VectorSubtract(r_refdef.vieworg, v, eye);
|
|
VectorNormalize(eye);
|
|
VectorAdd(eye, (v+7), halfdir);
|
|
varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
|
|
varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
|
|
else
|
|
varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
|
|
{
|
|
varray_i[varray_ic] = vc_s;
|
|
varray_i[varray_ic+1] = varray_vc-1;
|
|
varray_i[varray_ic+2] = varray_vc;
|
|
varray_ic+=3;
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
varray_v[varray_vc].stl[0] = v[5];
|
|
varray_v[varray_vc].stl[1] = v[6];
|
|
VectorSubtract(r_refdef.vieworg, v, eye);
|
|
VectorNormalize(eye);
|
|
VectorAdd(eye, (v+7), halfdir);
|
|
varray_v[varray_vc].ncm[0] = DotProduct(surf->texinfo->vecs[0], halfdir);
|
|
varray_v[varray_vc].ncm[1] = DotProduct(surf->texinfo->vecs[1], halfdir);
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
varray_v[varray_vc].ncm[2] = -DotProduct(surf->plane->normal, halfdir);
|
|
else
|
|
varray_v[varray_vc].ncm[2] = DotProduct(surf->plane->normal, halfdir);
|
|
varray_vc++;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
/*
|
|
static void PPL_BaseChain_NoLightmap(msurface_t *first, texture_t *tex)
|
|
{
|
|
Sys_Error("1 TMU is disabled for now (surface has no lightmap)\n");
|
|
}
|
|
*/
|
|
|
|
static void PPL_BaseChain_NoBump_1TMU(msurface_t *first, texture_t *tex)
|
|
{
|
|
int vi;
|
|
glRect_t *theRect;
|
|
msurface_t *s;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
qglDisable(GL_BLEND);
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_TexEnv(GL_REPLACE);
|
|
GL_Bind (tex->gl_texturenum);
|
|
|
|
for (s=first; s ; s=s->texturechain)
|
|
{
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
qglEnable(GL_BLEND);
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
if (gl_lightmap_format == GL_LUMINANCE || gl_lightmap_format == GL_RGB)
|
|
qglBlendFunc (GL_ZERO, GL_SRC_COLOR);
|
|
else if (gl_lightmap_format == GL_INTENSITY)
|
|
{
|
|
qglColor4f (0,0,0,1);
|
|
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
else if (gl_lightmap_format == GL_RGBA)
|
|
qglBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
vi = -1;
|
|
for (s=first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
static void PPL_BaseChain_NoBump_2TMU(msurface_t *s, texture_t *tex)
|
|
{
|
|
int vi;
|
|
glRect_t *theRect;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
if (tex->alphaed)
|
|
{
|
|
qglEnable(GL_BLEND);
|
|
GL_TexEnv(GL_MODULATE);
|
|
}
|
|
else
|
|
{
|
|
qglDisable(GL_BLEND);
|
|
GL_TexEnv(GL_REPLACE);
|
|
}
|
|
|
|
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
vi = -1;
|
|
for (; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
if (vi<0)
|
|
qglEnable(GL_TEXTURE_2D);
|
|
vi = s->lightmaptexturenum;
|
|
|
|
if (vi>=0)
|
|
{
|
|
GL_Bind(lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
else
|
|
qglDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
|
|
static void PPL_BaseChain_Bump_2TMU(msurface_t *first, texture_t *tex)
|
|
{
|
|
int vi;
|
|
glRect_t *theRect;
|
|
msurface_t *s;
|
|
PPL_EnableVertexArrays();
|
|
|
|
if (tex->alphaed)
|
|
{
|
|
qglEnable(GL_BLEND);
|
|
GL_TexEnv(GL_MODULATE);
|
|
}
|
|
else
|
|
{
|
|
qglDisable(GL_BLEND);
|
|
GL_TexEnv(GL_REPLACE);
|
|
}
|
|
|
|
//Bind normal map to texture unit 0
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
|
|
vi = -1;
|
|
for (s=first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_Bind(deluxmap_textures[vi] );
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
vi = -1;
|
|
for (s=first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_Bind(lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
}
|
|
|
|
static void PPL_BaseChain_Bump_4TMU(msurface_t *s, texture_t *tex)
|
|
{
|
|
int vi;
|
|
glRect_t *theRect;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
//Bind normal map to texture unit 0
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_REPLACE);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
//1 gets the deluxmap
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
//2 gets the diffusemap
|
|
GL_MBind(GL_TEXTURE2_ARB, tex->gl_texturenum);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
//3 gets the lightmap
|
|
GL_SelectTexture(GL_TEXTURE3_ARB);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
vi = -1;
|
|
for (; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_MBind(GL_TEXTURE1_ARB, deluxmap_textures[vi] );
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
GL_MBind(GL_TEXTURE3_ARB, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
GL_SelectTexture(GL_TEXTURE3_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
}
|
|
|
|
#ifdef SPECULAR
|
|
//Draw a texture chain with specular exponant 1.
|
|
//erm...
|
|
//this uses the wrong stuff to work on gf4tis.
|
|
/*
|
|
static void PPL_BaseChain_Specular_4TMU(msurface_t *first, texture_t *tex)
|
|
{
|
|
//if I ever do write this function, It'll take a couple of passes.
|
|
int vi;
|
|
glRect_t *theRect;
|
|
msurface_t *s;
|
|
|
|
glColorMask(1,1,1,0);
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error before PPL_BaseChain_Specular\n");
|
|
|
|
//first 4 texture units: (N.((L+V)/2))^2
|
|
glDisable(GL_BLEND);
|
|
qglActiveTextureARB(GL_TEXTURE0_ARB);
|
|
GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap);
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_REPLACE);
|
|
qglClientActiveTextureARB(GL_TEXTURE0_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error binding dot3 tmu1\n");
|
|
|
|
qglActiveTextureARB(GL_TEXTURE1_ARB);
|
|
glDisable(GL_TEXTURE_2D);
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
glEnable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
if (qglGetError())
|
|
Con_Printf("Error binding dot3 cubemap\n");
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
if (qglGetError())
|
|
Con_Printf("Error binding dot3 combine\n");
|
|
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error binding dot3 tmu2\n");
|
|
|
|
//prev*prev (the exponential)
|
|
qglActiveTextureARB(GL_TEXTURE2_ARB);
|
|
GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumbumpmap); //need to bind something.
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error binding prev*prev\n");
|
|
|
|
qglActiveTextureARB(GL_TEXTURE3_ARB);
|
|
GL_BindType(GL_TEXTURE_2D, tex->gl_texturenumspec);
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
qglClientActiveTextureARB(GL_TEXTURE3_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error binding specular in PPL_BaseChain_Specular\n");
|
|
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
PPL_GenerateArraysBlinnCubeMap(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
|
// Add normal dot delux times diffusemap then multiple the entire lot by the lightmap.
|
|
qglActiveTextureARB(GL_TEXTURE0_ARB);
|
|
GL_TexEnv(GL_REPLACE);
|
|
|
|
qglActiveTextureARB(GL_TEXTURE1_ARB);
|
|
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
qglActiveTextureARB(GL_TEXTURE2_ARB);
|
|
glEnable(GL_TEXTURE_2D);
|
|
GL_BindType(GL_TEXTURE_2D, tex->gl_texturenum);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
qglClientActiveTextureARB(GL_TEXTURE2_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
qglActiveTextureARB(GL_TEXTURE3_ARB);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glDisable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
qglClientActiveTextureARB(GL_TEXTURE3_ARB);
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
vi = -1;
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
qglActiveTextureARB(GL_TEXTURE1_ARB);
|
|
GL_BindType(GL_TEXTURE_2D, deluxmap_textures[vi] );
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
qglActiveTextureARB(GL_TEXTURE3_ARB);
|
|
GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
glColorMask(1,1,1,0);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("Error drawing in PPL_BaseChain_Specular\n");
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
qglClientActiveTextureARB(GL_TEXTURE2_ARB);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
qglActiveTextureARB(GL_TEXTURE0_ARB);
|
|
qglClientActiveTextureARB(GL_TEXTURE0_ARB);
|
|
}
|
|
*/
|
|
|
|
void PPL_LoadSpecularFragmentProgram(void)
|
|
{
|
|
GLint errorPos, isNative;
|
|
int i;
|
|
const char *error;
|
|
|
|
//What should the minimum resource limits be?
|
|
|
|
//RESOLVED: 10 attributes, 24 parameters, 4 texture indirections,
|
|
//48 ALU instructions, 24 texture instructions, and 16 temporaries.
|
|
|
|
//16 temps? hmm. that means we should be keeping the indirections instead of temp usage.
|
|
//temps should be same speed, indirections could prevent texture loading for a bit.
|
|
|
|
char *fp =
|
|
//FP to do:
|
|
//(diffuse*n.l + gloss*(n.h)^8)*lm
|
|
//note excessive temp reuse...
|
|
"!!ARBfp1.0\n"
|
|
|
|
"PARAM c0 = {2, 1, 8, 0};\n"
|
|
"TEMP R0;\n"
|
|
"TEMP R1;\n"
|
|
"TEMP R2;\n"
|
|
"TEX R0.xyz, fragment.texcoord[0], texture[1], 2D;\n"
|
|
"TEX R1.xyz, fragment.texcoord[1], texture[3], 2D;\n"
|
|
"MAD R0.xyz, R0, c0.x, -c0.y;\n"
|
|
"MAD R1.xyz, R1, c0.x, -c0.y;\n"
|
|
"DP3 R0.w, R0, R1;\n"
|
|
"DP3 R1.x, fragment.texcoord[2], fragment.texcoord[2];\n"
|
|
"RSQ R1.x, R1.x;\n"
|
|
"MUL R1.xyz, R1.x, fragment.texcoord[2];\n"
|
|
"DP3 R0.x, R1, R0;\n"
|
|
"POW R0.x, R0.x, c0.z;\n"
|
|
"TEX R1.xyz, fragment.texcoord[0], texture[4], 2D;\n"
|
|
"TEX R2.xyz, fragment.texcoord[0], texture[0], 2D;\n"
|
|
"MUL R0.xyz, R0.x, R1;\n"
|
|
"MAD R0.xyz, R2, R0.w, R0;\n"
|
|
"TEX R1.xyz, fragment.texcoord[1], texture[2], 2D;\n"
|
|
"MUL result.color.xyz, R0, R1;\n"
|
|
|
|
//that's all folks.
|
|
"END";
|
|
|
|
ppl_specular_fragmentprogram = 0;
|
|
|
|
for (i = 0; i < MAXARRAYVERTS; i++)
|
|
{
|
|
varray_i_forward[i] = i;
|
|
}
|
|
for (i = 0; i < MAXARRAYVERTS/3; i++)
|
|
{
|
|
varray_i_polytotri[i*3+0] = 0;
|
|
varray_i_polytotri[i*3+1] = i+1;
|
|
varray_i_polytotri[i*3+2] = i+2;
|
|
}
|
|
|
|
if (!gl_config.arb_fragment_program)
|
|
return;
|
|
|
|
qglEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
qglGenProgramsARB( 1, &ppl_specular_fragmentprogram );
|
|
qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ppl_specular_fragmentprogram);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error binding fragment program\n");
|
|
|
|
qglProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, strlen(fp), fp);
|
|
if (qglGetError())
|
|
{
|
|
qglGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
|
|
error = qglGetString(GL_PROGRAM_ERROR_STRING_ARB);
|
|
Con_Printf("Fragment program error \'%s\'\n", error);
|
|
ppl_specular_fragmentprogram = 0;
|
|
}
|
|
else
|
|
{
|
|
qglGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);
|
|
if (!isNative)
|
|
Con_Printf("Warning: Fragment program is emulated. You will likly experience poor performace.\n");
|
|
}
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error loading fragment program\n");
|
|
|
|
qglDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
}
|
|
|
|
static void PPL_BaseChain_Specular_FP(msurface_t *s, texture_t *tex)
|
|
{
|
|
int vi;
|
|
glRect_t *theRect;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
qglEnable(GL_FRAGMENT_PROGRAM_ARB);
|
|
qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, ppl_specular_fragmentprogram);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on shadow lighting\n");
|
|
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_MBind(GL_TEXTURE1_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
|
|
|
|
//qglActiveTextureARB(GL_TEXTURE2_ARB);
|
|
//GL_BindType(GL_TEXTURE_2D, ); //lightmap
|
|
|
|
//qglActiveTextureARB(GL_TEXTURE3_ARB);
|
|
//GL_BindType(GL_TEXTURE_2D, ); //deluxmap
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on shadow lighting\n");
|
|
|
|
GL_MBind(GL_TEXTURE4_ARB, tex->gl_texturenumspec);
|
|
|
|
GL_SelectTexture(GL_TEXTURE5_ARB);
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
|
|
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on shadow lighting\n");
|
|
|
|
vi = -1;
|
|
for (; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] );
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
GL_MBind(GL_TEXTURE2_ARB, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
PPL_GenerateArraysBlinnCubeMap(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on shadow lighting\n");
|
|
|
|
qglDisable(GL_FRAGMENT_PROGRAM_ARB);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on shadow lighting\n");
|
|
}
|
|
|
|
#define GL_MODULATE_ADD_ATI 0x8744
|
|
//we actually only use 7, so nur.
|
|
static void PPL_BaseChain_Specular_8TMU(msurface_t *first, texture_t *tex)
|
|
{ //uses blinn shading instead of phong. This way we don't have to generate lots of complex stuff.
|
|
int vi;
|
|
glRect_t *theRect;
|
|
msurface_t *s;
|
|
|
|
// float fourhalffloats[4] = {0.5,0.5,0.5,0.5};
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
/* lets do things in parallel.
|
|
normalmap -> rgb
|
|
rgb . halfvector -> alpha
|
|
alpha*alpha -> alpha normalmap -> rgb
|
|
(alpha*alpha -> alpha) rgb . luxmap -> rgb
|
|
alpha*gloss -> alpha rgb * diffuse -> rgb
|
|
rgb + alpha -> rgb
|
|
rgb * lightmap -> rgb
|
|
|
|
//note: crossbar could use third input texture removing the first tmu.
|
|
//note: could combine3 combine the last two?
|
|
//note: 5 tmus: not enough to work on a gf4.
|
|
*/
|
|
qglDisable(GL_BLEND);
|
|
|
|
//0 takes a normalmap
|
|
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
GL_TexEnv(GL_REPLACE);
|
|
|
|
//1 takes a cubemap for specular half-vectors.
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGBA_ARB); //writes alpha
|
|
|
|
//2 takes a normalmap
|
|
GL_MBind(GL_TEXTURE2_ARB, tex->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); //square the alpha
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
|
|
|
|
//3 takes the deluxmap
|
|
GL_SelectTexture(GL_TEXTURE3_ARB);
|
|
qglEnable(GL_TEXTURE_2D); //bind with the surface texturenum
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); //square the alpha again.
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
|
|
|
|
//4 multiplies with diffuse
|
|
GL_MBind(GL_TEXTURE4_ARB, tex->gl_texturenum);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
//nothing to the alpha (square yet again?)
|
|
// glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
// glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); //square the alpha again.
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
|
|
|
|
//5 halves rgb and alpha (so that adding will not clamp)
|
|
GL_MBind(GL_TEXTURE5_ARB, tex->gl_texturenum); //need to bind something.
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
/* glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, fourhalffloats);
|
|
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_CONSTANT_ARB);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
*/
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_CONSTANT_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_ALPHA);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE);
|
|
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
|
|
|
|
//6 adds rgb and alpha, using the glossmap...
|
|
GL_MBind(GL_TEXTURE6_ARB, tex->gl_texturenumspec);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
//broken diffuse + specular
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE_ADD_ATI);
|
|
//perfect diffuse
|
|
/* GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
|
|
*/
|
|
//perfect specular
|
|
/* GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_ALPHA);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
*/
|
|
//7 multiplies by lightmap
|
|
GL_SelectTexture(GL_TEXTURE7_ARB);
|
|
qglEnable(GL_TEXTURE_2D); //bind with the surface texturenum
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
GL_TexEnv(GL_COMBINE_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_ONE_MINUS_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
vi = -1;
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] );
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
GL_MBind(GL_TEXTURE7_ARB, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
PPL_GenerateArraysBlinnCubeMap(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
|
|
qglColorMask(1,1,1,0);
|
|
|
|
for (vi = 7; vi > 0; vi--)
|
|
{
|
|
GL_SelectTexture(GL_TEXTURE0_ARB+vi);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);//1
|
|
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
}
|
|
#endif
|
|
|
|
//single textured.
|
|
static void PPL_BaseChain_Flat(msurface_t *first)
|
|
{
|
|
static vec_t wallcolour[4] = {0,0,0,1};
|
|
static vec_t floorcolour[4] = {0,0,0,1};
|
|
msurface_t *s;
|
|
int iswall = -1;
|
|
int vi=-10;
|
|
glRect_t *theRect;
|
|
|
|
if (r_wallcolour.modified)
|
|
{
|
|
char *s;
|
|
r_wallcolour.modified = false;
|
|
|
|
s = COM_Parse(r_wallcolour.string);
|
|
wallcolour[0] = atof(com_token);
|
|
s = COM_Parse(s);
|
|
wallcolour[1] = atof(com_token);
|
|
s = COM_Parse(s);
|
|
wallcolour[2] = atof(com_token);
|
|
}
|
|
if (r_floorcolour.modified)
|
|
{
|
|
char *s;
|
|
r_floorcolour.modified = false;
|
|
|
|
s = COM_Parse(r_floorcolour.string);
|
|
floorcolour[0] = atof(com_token);
|
|
s = COM_Parse(s);
|
|
floorcolour[1] = atof(com_token);
|
|
s = COM_Parse(s);
|
|
floorcolour[2] = atof(com_token);
|
|
}
|
|
|
|
PPL_EnableVertexArrays();
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
if (vi < 0)
|
|
qglEnable(GL_TEXTURE_2D);
|
|
else if (s->lightmaptexturenum < 0)
|
|
qglDisable(GL_TEXTURE_2D);
|
|
vi = s->lightmaptexturenum;
|
|
|
|
if (vi>=0)
|
|
{
|
|
GL_Bind(lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((s->plane->normal[2]*s->plane->normal[2]) <= 0.5*0.5)
|
|
{
|
|
if (iswall != 0)
|
|
{
|
|
PPL_FlushArrays();
|
|
iswall=0;
|
|
qglColor4fv(wallcolour);
|
|
}
|
|
}
|
|
else if (iswall != 1)
|
|
{
|
|
PPL_FlushArrays();
|
|
iswall=1;
|
|
qglColor4fv(floorcolour);
|
|
}
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglColor3f(1,1,1);
|
|
}
|
|
|
|
static void PPL_BaseChain_NPR_Sketch(msurface_t *first)
|
|
{
|
|
msurface_t *s;
|
|
int vi=-10;
|
|
int i;
|
|
glRect_t *theRect;
|
|
|
|
static int textures[10];
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
if (r_drawflat.modified) //reload textures
|
|
{
|
|
r_drawflat.modified = false;
|
|
for (i = 0; i < sizeof(textures)/sizeof(textures[0]); i++)
|
|
{
|
|
textures[i] = Mod_LoadHiResTexture(va("sketch%i", i+1), true, false, false);
|
|
if (!textures[i])
|
|
{
|
|
int data[128*128];
|
|
FILE *file;
|
|
unsigned char *f;
|
|
int p;
|
|
|
|
file = fopen(va("textures/tex%i_3_128_128.raw", i+1), "rb");
|
|
|
|
if (file)
|
|
{
|
|
f = Hunk_TempAlloc(128*128*3);
|
|
if (fread(f, 128*3, 128, file) == 128)
|
|
{
|
|
for (p = 0; p < 128*128; p++)
|
|
data[p] = LittleLong(f[p*3] + (f[p*3+1]<<8) + (f[p*3+2]<<16) + (255<<24));
|
|
textures[i] = GL_LoadTexture32 (va("textures/tex%i_3_128_128.raw", i+1), 128, 128, data, true, false);
|
|
}
|
|
fclose(file);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
//draw the surface properly
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
|
|
qglColor3f(1,1,1);
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
PPL_FlushArrays();
|
|
vi = s->lightmaptexturenum;
|
|
|
|
GL_MBind(GL_TEXTURE0_ARB, textures[rand()%10]);
|
|
|
|
if (vi < 0)
|
|
GL_MBind(GL_TEXTURE1_ARB, 0 );
|
|
else
|
|
{
|
|
GL_MBind(GL_TEXTURE1_ARB, lightmap_textures[vi] );
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
}
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
qglDisableClientState(GL_VERTEX_ARRAY);
|
|
qglDisableClientState(GL_COLOR_ARRAY);
|
|
|
|
//draw some extra lines around the edge for added coolness.
|
|
qglColor3f(0,0,0);
|
|
if (first->texinfo->texture->shader)
|
|
{
|
|
for (vi = 0; vi < 2; vi++)
|
|
{
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (!s->mesh)
|
|
continue;
|
|
|
|
for (i=0; i<s->mesh->numindexes; i+=3)
|
|
{
|
|
qglBegin(GL_LINE_LOOP);
|
|
qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+0]][0]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+0]][1]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+0]][2]+5*(rand()/(float)RAND_MAX-0.5));
|
|
qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+1]][0]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+1]][1]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+1]][2]+5*(rand()/(float)RAND_MAX-0.5));
|
|
qglVertex3f(s->mesh->xyz_array[s->mesh->indexes[i+2]][0]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+2]][1]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->mesh->xyz_array[s->mesh->indexes[i+2]][2]+5*(rand()/(float)RAND_MAX-0.5));
|
|
qglEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
for (vi = 0; vi < 5; vi++)
|
|
{
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (!s->polys)
|
|
continue;
|
|
qglBegin(GL_LINE_LOOP);
|
|
for (i=s->polys->numverts-1; i>=0; i--)
|
|
qglVertex3f( s->polys->verts[i][0]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->polys->verts[i][1]+5*(rand()/(float)RAND_MAX-0.5),
|
|
s->polys->verts[i][2]+5*(rand()/(float)RAND_MAX-0.5));
|
|
qglEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
qglEnable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
static void PPL_BaseTextureChain(msurface_t *first)
|
|
{
|
|
extern cvar_t gl_bump, gl_specular;
|
|
texture_t *t;
|
|
if (r_drawflat.value)
|
|
{
|
|
if (r_drawflat.value == 2)
|
|
{
|
|
if (gl_mtexarbable >= 2) //shiesh!.
|
|
{
|
|
PPL_BaseChain_NPR_Sketch(first);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PPL_BaseChain_Flat(first); //who cares about texture? :/
|
|
return;
|
|
}
|
|
}
|
|
#ifdef Q3SHADERS
|
|
if (first->texinfo->texture->shader)
|
|
{
|
|
meshbuffer_t mb;
|
|
msurface_t *s;
|
|
int vi=-1;
|
|
int redraw = false;
|
|
|
|
glRect_t *theRect;
|
|
if (first->texinfo->texture->shader->flags & SHADER_FLARE )
|
|
return;
|
|
|
|
if (!varrayactive)
|
|
R_IBrokeTheArrays();
|
|
|
|
mb.entity = &r_worldentity;
|
|
mb.shader = first->texinfo->texture->shader;
|
|
mb.mesh = NULL;
|
|
mb.fog = NULL;
|
|
mb.infokey = -2;
|
|
mb.dlightbits = 0;
|
|
|
|
GL_DisableMultitexture();
|
|
|
|
qglShadeModel(GL_SMOOTH);
|
|
|
|
{
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
if (vi != s->lightmaptexturenum)
|
|
{
|
|
vi = s->lightmaptexturenum;
|
|
if (vi >= 0)
|
|
{
|
|
if (lightmap[vi]->deluxmodified)
|
|
{
|
|
GL_BindType(GL_TEXTURE_2D, deluxmap_textures[vi] );
|
|
lightmap[vi]->deluxmodified = false;
|
|
theRect = &lightmap[vi]->deluxrectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, GL_RGB, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->deluxmaps+(theRect->t) *LMBLOCK_WIDTH*3);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
if (lightmap[vi]->modified)
|
|
{
|
|
GL_BindType(GL_TEXTURE_2D, lightmap_textures[vi] );
|
|
lightmap[vi]->modified = false;
|
|
theRect = &lightmap[vi]->rectchange;
|
|
qglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t,
|
|
LMBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,
|
|
lightmap[vi]->lightmaps+(theRect->t) *LMBLOCK_WIDTH*lightmap_bytes);
|
|
theRect->l = LMBLOCK_WIDTH;
|
|
theRect->t = LMBLOCK_HEIGHT;
|
|
theRect->h = 0;
|
|
theRect->w = 0;
|
|
}
|
|
}
|
|
}
|
|
if (s->flags&SURF_DRAWALPHA || !(mb.shader->sort & SHADER_SORT_OPAQUE))
|
|
{
|
|
extern msurface_t *r_alpha_surfaces;
|
|
s->nextalphasurface = r_alpha_surfaces;
|
|
r_alpha_surfaces = s;
|
|
s->ownerent = &r_worldentity;
|
|
continue;
|
|
}
|
|
|
|
if (s->mesh)
|
|
{
|
|
redraw = mb.fog != s->fog || mb.infokey != vi|| mb.shader->flags&SHADER_DEFORMV_BULGE;
|
|
|
|
if (redraw)
|
|
{
|
|
if (mb.mesh)
|
|
R_RenderMeshBuffer ( &mb, false );
|
|
redraw = false;
|
|
}
|
|
|
|
mb.infokey = vi;
|
|
mb.mesh = s->mesh;
|
|
mb.fog = s->fog;
|
|
R_PushMesh(s->mesh, mb.shader->features);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mb.mesh)
|
|
R_RenderMeshBuffer ( &mb, false );
|
|
return;
|
|
}
|
|
#endif
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
t = GLR_TextureAnimation (first->texinfo->texture);
|
|
|
|
if (first->flags & SURF_DRAWTURB)
|
|
{
|
|
GL_DisableMultitexture();
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
GL_Bind (t->gl_texturenum);
|
|
for (; first ; first=first->texturechain)
|
|
EmitWaterPolys (first, currententity->alpha);
|
|
|
|
qglDisable(GL_BLEND);
|
|
qglColor4f(1,1,1, 1);
|
|
|
|
t->texturechain = NULL; //no lighting effects. (good job these don't animate eh?)
|
|
return;
|
|
}
|
|
/* else if (s->lightmaptexturenum < 0) //no lightmap
|
|
{
|
|
PPL_BaseChain_NoLightmap(first, t);
|
|
}*/
|
|
else if (gl_mtexarbable < 2)
|
|
{ //multitexture isn't supported.
|
|
PPL_BaseChain_NoBump_1TMU(first, t);
|
|
}
|
|
else
|
|
{
|
|
if (gl_bump.value && currentmodel->deluxdata && t->gl_texturenumbumpmap)
|
|
{
|
|
if (gl_mtexarbable>=4)
|
|
{
|
|
if (t->gl_texturenumspec && gl_specular.value)
|
|
{
|
|
if (ppl_specular_fragmentprogram)
|
|
PPL_BaseChain_Specular_FP(first, t);
|
|
else if (gl_mtexarbable>=8)
|
|
PPL_BaseChain_Specular_8TMU(first, t);
|
|
else
|
|
PPL_BaseChain_Bump_4TMU(first, t); //can't do specular.
|
|
}
|
|
else
|
|
PPL_BaseChain_Bump_4TMU(first, t);
|
|
}
|
|
else
|
|
PPL_BaseChain_Bump_2TMU(first, t);
|
|
}
|
|
else
|
|
{
|
|
PPL_BaseChain_NoBump_2TMU(first, t);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void PPL_FullBrightTextureChain(msurface_t *first)
|
|
{
|
|
texture_t *t;
|
|
msurface_t *s;
|
|
|
|
t = GLR_TextureAnimation (first->texinfo->texture);
|
|
|
|
if (detailtexture && gl_detail.value)
|
|
{
|
|
GL_Bind(detailtexture);
|
|
qglBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
|
|
|
|
PPL_EnableVertexArrays();
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
}
|
|
|
|
if (t->gl_texturenumfb && r_fb_bmodels.value && cls.allow_luma)
|
|
{
|
|
GL_Bind(t->gl_texturenumfb);
|
|
qglBlendFunc(GL_ONE, GL_ONE);
|
|
|
|
PPL_EnableVertexArrays();
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
PPL_GenerateArrays(s);
|
|
}
|
|
PPL_FlushArrays();
|
|
}
|
|
}
|
|
|
|
//requires multitexture
|
|
void PPL_BaseTextures(model_t *model)
|
|
{
|
|
int i;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
GL_DoSwap();
|
|
|
|
qglDisable(GL_BLEND);
|
|
qglColor4f(1,1,1, 1);
|
|
// qglDepthFunc(GL_LESS);
|
|
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
qglShadeModel(GL_FLAT);
|
|
|
|
currentmodel = model;
|
|
currententity->alpha = 1;
|
|
|
|
if (model == cl.worldmodel && skytexturenum>=0)
|
|
{
|
|
t = model->textures[skytexturenum];
|
|
if (t)
|
|
{
|
|
s = t->texturechain;
|
|
if (s)
|
|
{
|
|
t->texturechain = NULL;
|
|
R_DrawSkyChain (s);
|
|
}
|
|
}
|
|
}
|
|
if (!r_inmirror && mirrortexturenum>=0 && model == cl.worldmodel && r_mirroralpha.value != 1.0)
|
|
{
|
|
t = model->textures[mirrortexturenum];
|
|
if (t)
|
|
{
|
|
s = t->texturechain;
|
|
if (s)
|
|
{
|
|
t->texturechain = NULL;
|
|
R_MirrorChain (s);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
|
{
|
|
t = model->textures[i];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
|
|
if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0)
|
|
continue; // draw translucent water later
|
|
|
|
PPL_BaseTextureChain(s);
|
|
}
|
|
|
|
GL_DisableMultitexture();
|
|
}
|
|
|
|
void PPL_BaseBModelTextures(entity_t *e)
|
|
{
|
|
extern msurface_t *r_alpha_surfaces;
|
|
int i, k;
|
|
model_t *model;
|
|
msurface_t *s;
|
|
msurface_t *chain = NULL;
|
|
|
|
qglPushMatrix();
|
|
R_RotateForEntity(e);
|
|
currentmodel = model = e->model;
|
|
s = model->surfaces+model->firstmodelsurface;
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
if (currententity->alpha<1)
|
|
{
|
|
qglEnable(GL_BLEND);
|
|
qglColor4f(1, 1, 1, currententity->alpha);
|
|
}
|
|
else
|
|
{
|
|
qglDisable(GL_BLEND);
|
|
qglColor4f(1, 1, 1, 1);
|
|
}
|
|
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
// calculate dynamic lighting for bmodel if it's not an
|
|
// instanced model
|
|
if (currentmodel->firstmodelsurface != 0 && r_dynamic.value)
|
|
{
|
|
for (k=0 ; k<MAX_DLIGHTS ; k++)
|
|
{
|
|
if (!cl_dlights[k].radius)
|
|
continue;
|
|
if (cl_dlights[k].nodynamic)
|
|
continue;
|
|
|
|
currentmodel->funcs.MarkLights (&cl_dlights[k], 1<<k,
|
|
currentmodel->nodes + currentmodel->hulls[0].firstclipnode);
|
|
}
|
|
}
|
|
|
|
//update lightmaps.
|
|
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
|
|
R_RenderDynamicLightmaps (s);
|
|
|
|
|
|
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
|
|
{
|
|
if (s->texinfo->flags & SURF_TRANS33 || s->texinfo->flags & SURF_TRANS66)
|
|
{
|
|
s->ownerent = currententity;
|
|
s->nextalphasurface = r_alpha_surfaces;
|
|
r_alpha_surfaces = s;
|
|
continue;
|
|
}
|
|
else if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next
|
|
{
|
|
PPL_BaseTextureChain(chain);
|
|
chain = NULL;
|
|
}
|
|
|
|
s->texturechain = chain;
|
|
chain = s;
|
|
}
|
|
|
|
if (chain)
|
|
PPL_BaseTextureChain(chain);
|
|
|
|
qglPopMatrix();
|
|
GL_DisableMultitexture();
|
|
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
if (!varrayactive)
|
|
R_IBrokeTheArrays();
|
|
}
|
|
|
|
void PPL_BaseEntTextures(void)
|
|
{
|
|
extern qboolean r_inmirror;
|
|
extern model_t *currentmodel;
|
|
int i,j;
|
|
|
|
if (!r_drawentities.value)
|
|
return;
|
|
|
|
// draw sprites seperately, because of alpha blending
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
{
|
|
currententity = &cl_visedicts[i];
|
|
|
|
if (r_inmirror)
|
|
{
|
|
if (currententity->flags & Q2RF_WEAPONMODEL)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
if (currententity->keynum == r_refdef.currentplayernum+1)
|
|
continue;
|
|
#else
|
|
j = currententity->keynum;
|
|
while(j)
|
|
{
|
|
|
|
if (j == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1)))
|
|
break;
|
|
|
|
j = cl.lerpents[j].tagent;
|
|
}
|
|
if (j)
|
|
continue;
|
|
#endif
|
|
if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
|
|
continue;
|
|
if (!Cam_DrawPlayer(0, currententity->keynum-1))
|
|
continue;
|
|
}
|
|
|
|
if (!currententity->model)
|
|
continue;
|
|
|
|
|
|
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
|
|
{
|
|
if (currententity->model->particleeffect>=0)
|
|
{
|
|
if (currententity->model->particleengulphs)
|
|
{
|
|
if (gl_part_flame.value)
|
|
{ //particle effect is addedin GLR_DrawEntitiesOnList. Is this so wrong?
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (currententity->model->type)
|
|
{
|
|
case mod_alias:
|
|
if (!varrayactive)
|
|
R_IBrokeTheArrays();
|
|
R_DrawGAliasModel (currententity);
|
|
break;
|
|
|
|
case mod_brush:
|
|
PPL_BaseBModelTextures (currententity);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
currentmodel = cl.worldmodel;
|
|
}
|
|
|
|
#ifdef PPL
|
|
static void PPL_GenerateLightArrays(msurface_t *surf, vec3_t relativelightorigin, dlight_t *light, vec3_t colour)
|
|
{
|
|
glpoly_t *p;
|
|
int vi;
|
|
int vc_s;
|
|
float *v;
|
|
|
|
vec3_t lightdir;
|
|
float dist;
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
shadowlightfaces++;
|
|
|
|
if (varray_ic + p->numverts*3>MAXARRAYVERTS)
|
|
{
|
|
PPL_FlushArrays();
|
|
}
|
|
|
|
vc_s = varray_vc;
|
|
v = p->verts[0];
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
lightdir[0] = relativelightorigin[0] - v[0];
|
|
lightdir[1] = relativelightorigin[1] - v[1];
|
|
lightdir[2] = relativelightorigin[2] - v[2];
|
|
dist = 1-(sqrt( (lightdir[0])*(lightdir[0]) +
|
|
(lightdir[1])*(lightdir[1]) +
|
|
(lightdir[2])*(lightdir[2])) / light->radius);
|
|
VectorNormalize(lightdir);
|
|
varray_v[varray_vc].stl[0] = colour[0]*dist;
|
|
varray_v[varray_vc].stl[1] = colour[1]*dist;
|
|
varray_v[varray_vc].stl[2] = colour[2]*dist;
|
|
varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
|
|
varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
|
|
varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
|
|
|
|
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
lightdir[0] = relativelightorigin[0] - v[0];
|
|
lightdir[1] = relativelightorigin[1] - v[1];
|
|
lightdir[2] = relativelightorigin[2] - v[2];
|
|
dist = 1-(sqrt( (lightdir[0])*(lightdir[0]) +
|
|
(lightdir[1])*(lightdir[1]) +
|
|
(lightdir[2])*(lightdir[2])) / light->radius);
|
|
VectorNormalize(lightdir);
|
|
varray_v[varray_vc].stl[0] = colour[0]*dist;
|
|
varray_v[varray_vc].stl[1] = colour[1]*dist;
|
|
varray_v[varray_vc].stl[2] = colour[2]*dist;
|
|
varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
|
|
varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
|
|
varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
|
|
varray_vc++;
|
|
v += VERTEXSIZE;
|
|
for (vi=2 ; vi<p->numverts ; vi++, v+= VERTEXSIZE)
|
|
{
|
|
varray_i[varray_ic] = vc_s;
|
|
varray_i[varray_ic+1] = varray_vc-1;
|
|
varray_i[varray_ic+2] = varray_vc;
|
|
varray_ic+=3;
|
|
|
|
varray_v[varray_vc].xyz[0] = v[0];
|
|
varray_v[varray_vc].xyz[1] = v[1];
|
|
varray_v[varray_vc].xyz[2] = v[2];
|
|
varray_v[varray_vc].stw[0] = v[3];
|
|
varray_v[varray_vc].stw[1] = v[4];
|
|
lightdir[0] = relativelightorigin[0] - v[0];
|
|
lightdir[1] = relativelightorigin[1] - v[1];
|
|
lightdir[2] = relativelightorigin[2] - v[2];
|
|
dist = 1-(sqrt( (lightdir[0])*(lightdir[0]) +
|
|
(lightdir[1])*(lightdir[1]) +
|
|
(lightdir[2])*(lightdir[2])) / light->radius);
|
|
VectorNormalize(lightdir);
|
|
varray_v[varray_vc].stl[0] = colour[0]*dist;
|
|
varray_v[varray_vc].stl[1] = colour[1]*dist;
|
|
varray_v[varray_vc].stl[2] = colour[2]*dist;
|
|
varray_v[varray_vc].ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
|
|
varray_v[varray_vc].ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
|
|
varray_v[varray_vc].ncm[2] = DotProduct(lightdir, surf->normal);
|
|
varray_vc++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PPL_LightTextures(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour)
|
|
{
|
|
int i;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
vec3_t relativelightorigin;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
VectorSubtract(light->origin, modelorigin, relativelightorigin);
|
|
qglShadeModel(GL_SMOOTH);
|
|
for (i=0 ; i<model->numtextures ; i++)
|
|
{
|
|
t = model->textures[i];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
|
|
if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0)
|
|
continue; // draw translucent water later
|
|
|
|
|
|
{
|
|
extern int normalisationCubeMap;
|
|
|
|
t = GLR_TextureAnimation (t);
|
|
|
|
|
|
qglEnableClientState(GL_COLOR_ARRAY);
|
|
qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
if (t->gl_texturenumbumpmap && gl_mtexarbable>3)
|
|
{
|
|
GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
//Set up texture environment to do (tex0 dot tex1)*color
|
|
GL_TexEnv(GL_REPLACE); //make texture normalmap available.
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
GL_TexEnv(GL_COMBINE_ARB); //normalisation cubemap . normalmap
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
|
|
|
|
GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap); //a dummy
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB); //bumps * color (the attenuation)
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
}
|
|
else
|
|
{
|
|
if (gl_mtexarbable>3)
|
|
{
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
}
|
|
|
|
for (; s; s=s->texturechain)
|
|
{
|
|
|
|
if (s->shadowframe != r_shadowframe)
|
|
continue;
|
|
|
|
/* if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
|
|
fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
|
|
fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
|
|
continue;*/
|
|
|
|
|
|
if (s->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius)
|
|
continue;
|
|
}
|
|
PPL_GenerateLightArrays(s, relativelightorigin, light, colour);
|
|
}
|
|
PPL_FlushArrays();
|
|
}
|
|
}
|
|
|
|
if (gl_mtexarbable>2)
|
|
{
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
void PPL_LightBModelTextures(entity_t *e, dlight_t *light, vec3_t colour)
|
|
{
|
|
int i;
|
|
model_t *model = e->model;
|
|
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
vec3_t relativelightorigin;
|
|
|
|
qglPushMatrix();
|
|
R_RotateForEntity(e);
|
|
qglColor4f(1, 1, 1, 1);
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
|
|
VectorSubtract(light->origin, e->origin, relativelightorigin);
|
|
qglShadeModel(GL_SMOOTH);
|
|
|
|
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
|
|
{
|
|
t = GLR_TextureAnimation (s->texinfo->texture);
|
|
|
|
qglEnableClientState(GL_COLOR_ARRAY);
|
|
qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
|
|
if (t->gl_texturenumbumpmap && gl_mtexarbable>3)
|
|
{
|
|
GL_MBind(GL_TEXTURE0_ARB, t->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
//Set up texture environment to do (tex0 dot tex1)*color
|
|
GL_TexEnv(GL_REPLACE); //make texture normalmap available.
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);
|
|
qglEnable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
GL_TexEnv(GL_COMBINE_ARB); //normalisation cubemap * normalmap
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->ncm);
|
|
|
|
GL_MBind(GL_TEXTURE2_ARB, t->gl_texturenumbumpmap);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_COMBINE_ARB); //bumps * color (the attenuation)
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PRIMARY_COLOR_ARB); //(doesn't actually use the bound texture)
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);
|
|
qglTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE);
|
|
|
|
GL_MBind(GL_TEXTURE3_ARB, t->gl_texturenum);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
}
|
|
else
|
|
{
|
|
if (gl_mtexarbable>3)
|
|
{
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
|
|
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stw);
|
|
}
|
|
|
|
// for (; s; s=s->texturechain)
|
|
{
|
|
|
|
// if (s->shadowframe != r_shadowframe)
|
|
// continue;
|
|
|
|
/* if (fabs(s->center[0] - lightorg[0]) > lightradius+s->radius ||
|
|
fabs(s->center[1] - lightorg[1]) > lightradius+s->radius ||
|
|
fabs(s->center[2] - lightorg[2]) > lightradius+s->radius)
|
|
continue;*/
|
|
|
|
|
|
if (s->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (-DotProduct(s->plane->normal, relativelightorigin)+s->plane->dist > lightradius)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(s->plane->normal, relativelightorigin)-s->plane->dist > lightradius)
|
|
continue;
|
|
}
|
|
PPL_GenerateLightArrays(s, relativelightorigin, light, colour);
|
|
}
|
|
PPL_FlushArrays();
|
|
}
|
|
|
|
if (gl_mtexarbable>2)
|
|
{
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
|
|
GL_SelectTexture(GL_TEXTURE2_ARB);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
GL_SelectTexture(GL_TEXTURE1_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
|
|
|
|
GL_SelectTexture(GL_TEXTURE0_ARB);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
qglPopMatrix();
|
|
}
|
|
|
|
//draw the bumps on the models for each light.
|
|
void PPL_DrawEntLighting(dlight_t *light, vec3_t colour)
|
|
{
|
|
int i;
|
|
|
|
PPL_LightTextures(cl.worldmodel, r_worldentity.origin, light, colour);
|
|
|
|
if (!r_drawentities.value)
|
|
return;
|
|
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
{
|
|
currententity = &cl_visedicts[i];
|
|
|
|
if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
|
|
continue;
|
|
|
|
if (!Cam_DrawPlayer(0, currententity->keynum-1))
|
|
continue;
|
|
|
|
if (!currententity->model)
|
|
continue;
|
|
|
|
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
|
|
{
|
|
if (currententity->model->particleeffect>=0)
|
|
{
|
|
if (currententity->model->particleengulphs)
|
|
{
|
|
if (gl_part_flame.value)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (currententity->model->type)
|
|
{
|
|
case mod_alias:
|
|
if (!varrayactive)
|
|
R_IBrokeTheArrays();
|
|
R_DrawGAliasModelLighting (currententity, light->origin, colour, light->radius);
|
|
break;
|
|
|
|
case mod_brush:
|
|
PPL_LightBModelTextures (currententity, light, colour);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void PPL_FullBrights(model_t *model)
|
|
{
|
|
int tn;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
|
|
qglColor3f(1,1,1);
|
|
|
|
qglDepthMask(0); //don't bother writing depth
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
qglShadeModel(GL_FLAT);
|
|
|
|
qglEnable(GL_BLEND);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
for (tn=0 ; tn<model->numtextures ; tn++)
|
|
{
|
|
t = model->textures[tn];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
|
|
if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0)
|
|
continue; // draw translucent water later
|
|
|
|
PPL_FullBrightTextureChain(s);
|
|
|
|
t->texturechain=NULL;
|
|
}
|
|
|
|
GL_TexEnv(GL_REPLACE);
|
|
qglDepthMask(1);
|
|
}
|
|
|
|
void PPL_FullBrightBModelTextures(entity_t *e)
|
|
{
|
|
int i;
|
|
model_t *model;
|
|
msurface_t *s;
|
|
msurface_t *chain = NULL;
|
|
|
|
qglPushMatrix();
|
|
R_RotateForEntity(e);
|
|
currentmodel = model = e->model;
|
|
s = model->surfaces+model->firstmodelsurface;
|
|
|
|
qglColor4f(1, 1, 1, 1);
|
|
qglDepthMask(0); //don't bother writing depth
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
qglShadeModel(GL_FLAT);
|
|
|
|
qglEnable(GL_BLEND);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
|
|
{
|
|
if (chain && s->texinfo->texture != chain->texinfo->texture) //last surface or not the same as the next
|
|
{
|
|
PPL_FullBrightTextureChain(chain);
|
|
chain = NULL;
|
|
}
|
|
|
|
s->texturechain = chain;
|
|
chain = s;
|
|
}
|
|
|
|
if (chain)
|
|
PPL_FullBrightTextureChain(chain);
|
|
|
|
qglPopMatrix();
|
|
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
qglDepthMask(1);
|
|
}
|
|
|
|
//draw the bumps on the models for each light.
|
|
void PPL_DrawEntFullBrights(void)
|
|
{
|
|
int i;
|
|
|
|
PPL_FullBrights(cl.worldmodel);
|
|
|
|
if (!r_drawentities.value)
|
|
return;
|
|
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
{
|
|
currententity = &cl_visedicts[i];
|
|
|
|
if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
|
|
continue;
|
|
|
|
if (!Cam_DrawPlayer(0, currententity->keynum-1))
|
|
continue;
|
|
|
|
if (!currententity->model)
|
|
continue;
|
|
|
|
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
|
|
{
|
|
if (currententity->model->particleeffect>=0)
|
|
{
|
|
if (currententity->model->particleengulphs)
|
|
{
|
|
if (gl_part_flame.value)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (currententity->model->type)
|
|
{
|
|
case mod_alias:
|
|
// R_DrawGAliasModelLighting (currententity);
|
|
break;
|
|
|
|
case mod_brush:
|
|
PPL_FullBrightBModelTextures (currententity);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PPL_SchematicsTextureChain(msurface_t *first)
|
|
{
|
|
extern int char_texture;
|
|
msurface_t *s;
|
|
int v1, v2;
|
|
float len;
|
|
unsigned char str[64];
|
|
int sl, c;
|
|
vec3_t dir;
|
|
vec3_t pos, v;
|
|
const float size = 0.0625;
|
|
float frow, fcol;
|
|
|
|
|
|
qglEnable(GL_TEXTURE_2D);
|
|
GL_Bind(char_texture);
|
|
qglEnable(GL_ALPHA_TEST);
|
|
|
|
if (qglPolygonOffset)
|
|
qglPolygonOffset(-1, 0);
|
|
qglEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
frow = rand()/(float)RAND_MAX;
|
|
frow=frow/2+0.5;
|
|
qglColor3f(frow, frow, 0);
|
|
|
|
if (gl_schematics.value != 2)
|
|
{
|
|
qglBegin(GL_QUADS);
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
for (v1 = 0; v1 < s->polys->numverts; v1++)
|
|
{
|
|
v2 = v1+1;
|
|
if (v2 == s->polys->numverts)
|
|
v2 = 0; //wrapped.
|
|
VectorSubtract(s->polys->verts[v1], s->polys->verts[v2], dir);
|
|
len = Length(dir);
|
|
VectorNormalize(dir);
|
|
sprintf(str, "%i", (len<1)?1:(int)len);
|
|
sl = strlen(str);
|
|
VectorMA(s->polys->verts[v2], len/2 + sl*4, dir, pos);
|
|
|
|
for (c = 0; c < sl; c++)
|
|
{
|
|
frow = (str[c]>>4)*size;
|
|
fcol = (str[c]&15)*size;
|
|
|
|
qglTexCoord2f (fcol, frow + size);
|
|
qglVertex3fv(pos);
|
|
VectorMA(pos, 8, s->normal, v);
|
|
qglTexCoord2f (fcol, frow);
|
|
qglVertex3fv(v);
|
|
VectorMA(pos, -8, dir, pos);
|
|
VectorMA(pos, 8, s->normal, v);
|
|
qglTexCoord2f (fcol + size, frow);
|
|
qglVertex3fv(v);
|
|
qglTexCoord2f (fcol + size, frow + size);
|
|
qglVertex3fv(pos);
|
|
}
|
|
}
|
|
}
|
|
qglEnd();
|
|
}
|
|
|
|
qglDisable(GL_POLYGON_OFFSET_FILL);
|
|
qglEnable(GL_POLYGON_OFFSET_LINE);
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
qglBegin(GL_LINES);
|
|
for (s = first; s ; s=s->texturechain)
|
|
{
|
|
for (v1 = 0; v1 < s->polys->numverts; v1++)
|
|
{
|
|
v2 = v1+1;
|
|
if (v2 == s->polys->numverts)
|
|
v2 = 0; //wrapped.
|
|
VectorSubtract(s->polys->verts[v2], s->polys->verts[v1], dir);
|
|
len = Length(dir);
|
|
VectorNormalize(dir);
|
|
|
|
if (gl_schematics.value != 2)
|
|
{
|
|
sprintf(str, "%i", (len<1)?1:(int)len);
|
|
sl = strlen(str);
|
|
}
|
|
else
|
|
sl = 0;
|
|
|
|
//left side. (find arrowhead part)
|
|
VectorMA(s->polys->verts[v1], 4, s->normal, pos);
|
|
|
|
VectorMA(pos, 4, dir, v);
|
|
VectorMA(v, -4, s->normal, v);
|
|
qglVertex3fv(v);
|
|
qglVertex3fv(pos);
|
|
|
|
VectorMA(v, 8, s->normal, v);
|
|
qglVertex3fv(v);
|
|
qglVertex3fv(pos);
|
|
|
|
//the line
|
|
qglVertex3fv(pos);
|
|
VectorMA(pos, len/2 - sl*4, dir, pos);
|
|
qglVertex3fv(pos);
|
|
|
|
//right hand side.
|
|
VectorMA(s->polys->verts[v2], 4, s->normal, pos);
|
|
|
|
VectorMA(pos, -4, dir, v);
|
|
VectorMA(v, -4, s->normal, v);
|
|
qglVertex3fv(v);
|
|
qglVertex3fv(pos);
|
|
|
|
VectorMA(v, 8, s->normal, v);
|
|
qglVertex3fv(v);
|
|
qglVertex3fv(pos);
|
|
|
|
//the line
|
|
qglVertex3fv(pos);
|
|
VectorMA(pos, -(len/2 - sl*4), dir, pos);
|
|
qglVertex3fv(pos);
|
|
|
|
}
|
|
}
|
|
qglEnd();
|
|
qglDisable(GL_POLYGON_OFFSET_LINE);
|
|
}
|
|
|
|
// :)
|
|
void PPL_Schematics(void)
|
|
{
|
|
int tn;
|
|
msurface_t *s;
|
|
texture_t *t;
|
|
model_t *model;
|
|
|
|
qglColor3f(1,1,1);
|
|
|
|
qglDepthMask(0); //don't bother writing depth
|
|
|
|
GL_TexEnv(GL_MODULATE);
|
|
|
|
qglShadeModel(GL_FLAT);
|
|
|
|
qglEnable(GL_BLEND);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
|
|
model = cl.worldmodel;
|
|
for (tn=0 ; tn<model->numtextures ; tn++)
|
|
{
|
|
t = model->textures[tn];
|
|
if (!t)
|
|
continue;
|
|
s = t->texturechain;
|
|
if (!s)
|
|
continue;
|
|
|
|
PPL_SchematicsTextureChain(s);
|
|
|
|
t->texturechain=NULL;
|
|
}
|
|
|
|
GL_TexEnv(GL_REPLACE);
|
|
qglDepthMask(1);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef PPL
|
|
|
|
|
|
|
|
|
|
|
|
qboolean PPL_VisOverlaps(qbyte *v1, qbyte *v2)
|
|
{
|
|
int i, m;
|
|
m = (cl.worldmodel->numleafs-1)>>3;
|
|
for (i=0 ; i<m ; i++)
|
|
{
|
|
if (v1[i] & v2[i])
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void PPL_RecursiveWorldNode_r (mnode_t *node)
|
|
{
|
|
int c, side;
|
|
mplane_t *plane;
|
|
msurface_t *surf, **mark;
|
|
mleaf_t *pleaf;
|
|
double dot;
|
|
glpoly_t *p;
|
|
int v;
|
|
|
|
float *v1;
|
|
vec3_t v3;
|
|
|
|
if (node->shadowframe != r_shadowframe)
|
|
return;
|
|
|
|
if (node->contents == Q1CONTENTS_SOLID)
|
|
return; // solid
|
|
|
|
|
|
//if light areabox is outside node, ignore node + children
|
|
for (c = 0; c < 3; c++)
|
|
{
|
|
if (lightorg[c] + lightradius < node->minmaxs[c])
|
|
return;
|
|
if (lightorg[c] - lightradius > node->minmaxs[3+c])
|
|
return;
|
|
}
|
|
|
|
// if a leaf node, draw stuff
|
|
if (node->contents < 0)
|
|
{
|
|
pleaf = (mleaf_t *)node;
|
|
|
|
mark = pleaf->firstmarksurface;
|
|
c = pleaf->nummarksurfaces;
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
(*mark++)->shadowframe = r_shadowframe;
|
|
} while (--c);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// node is just a decision point, so go down the apropriate sides
|
|
|
|
// find which side of the node we are on
|
|
plane = node->plane;
|
|
|
|
switch (plane->type)
|
|
{
|
|
case PLANE_X:
|
|
dot = modelorg[0] - plane->dist;
|
|
break;
|
|
case PLANE_Y:
|
|
dot = modelorg[1] - plane->dist;
|
|
break;
|
|
case PLANE_Z:
|
|
dot = modelorg[2] - plane->dist;
|
|
break;
|
|
default:
|
|
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
|
break;
|
|
}
|
|
|
|
if (dot >= 0)
|
|
side = 0;
|
|
else
|
|
side = 1;
|
|
|
|
// recurse down the children, front side first
|
|
PPL_RecursiveWorldNode_r (node->children[side]);
|
|
|
|
// draw stuff
|
|
c = node->numsurfaces;
|
|
|
|
if (c)
|
|
{
|
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
|
|
|
{
|
|
for ( ; c ; c--, surf++)
|
|
{
|
|
if (surf->shadowframe != r_shadowframe)
|
|
continue;
|
|
|
|
// if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
|
|
// continue; // wrong side
|
|
|
|
// if (surf->flags & SURF_PLANEBACK)
|
|
// continue;
|
|
|
|
if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED))
|
|
{ // no shadows
|
|
continue;
|
|
}
|
|
|
|
//is the light on the right side?
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (-DotProduct(surf->plane->normal, lightorg)+surf->plane->dist >= lightradius)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= lightradius)
|
|
continue;
|
|
}
|
|
|
|
/* if (fabs(surf->center[0] - lightorg[0]) > lightradius+surf->radius ||
|
|
fabs(surf->center[1] - lightorg[1]) > lightradius+surf->radius ||
|
|
fabs(surf->center[2] - lightorg[2]) > lightradius+surf->radius)
|
|
continue;
|
|
*/
|
|
#define PROJECTION_DISTANCE (float)(lightradius*2)//0x7fffffff
|
|
|
|
//build a list of the edges that are to be drawn.
|
|
for (v = 0; v < surf->numedges; v++)
|
|
{
|
|
int e, delta;
|
|
shadowemittedeges++;
|
|
e = cl.worldmodel->surfedges[surf->firstedge+v];
|
|
//negative edge means backwards edge.
|
|
if (e < 0)
|
|
{
|
|
e=-e;
|
|
delta = -1;
|
|
}
|
|
else
|
|
{
|
|
delta = 1;
|
|
}
|
|
|
|
if (!edge[e].count)
|
|
{
|
|
if (firstedge)
|
|
edge[firstedge].prev = e;
|
|
edge[e].next = firstedge;
|
|
edge[e].prev = 0;
|
|
firstedge = e;
|
|
edge[e].count = delta;
|
|
}
|
|
else
|
|
{
|
|
edge[e].count += delta;
|
|
|
|
if (!edge[e].count) //unlink
|
|
{
|
|
if (edge[e].next)
|
|
{
|
|
edge[edge[e].next].prev = edge[e].prev;
|
|
}
|
|
if (edge[e].prev)
|
|
edge[edge[e].prev].next = edge[e].next;
|
|
else
|
|
firstedge = edge[e].next;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
shadowsurfcount++;
|
|
|
|
//front face
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts[0]);
|
|
qglDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
|
|
|
|
//back (depth precision doesn't matter)
|
|
qglBegin(GL_POLYGON);
|
|
for (v = p->numverts-1; v >=0; v--)
|
|
{
|
|
v1 = p->verts[v];
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
}
|
|
qglEnd();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// recurse down the back side
|
|
PPL_RecursiveWorldNode_r (node->children[!side]);
|
|
}
|
|
|
|
//2 changes, but otherwise the same
|
|
void PPL_RecursiveWorldNodeQ2_r (mnode_t *node)
|
|
{
|
|
int c, side;
|
|
mplane_t *plane;
|
|
msurface_t *surf, **mark;
|
|
mleaf_t *pleaf;
|
|
double dot;
|
|
glpoly_t *p;
|
|
int v;
|
|
|
|
float *v1;
|
|
vec3_t v3;
|
|
|
|
if (node->contents == Q2CONTENTS_SOLID)
|
|
return; // solid
|
|
|
|
if (node->shadowframe != r_shadowframe)
|
|
return;
|
|
// if (R_CullBox (node->minmaxs, node->minmaxs+3))
|
|
// return;
|
|
|
|
// if a leaf node, draw stuff
|
|
if (node->contents != -1)
|
|
{
|
|
pleaf = (mleaf_t *)node;
|
|
|
|
mark = pleaf->firstmarksurface;
|
|
c = pleaf->nummarksurfaces;
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
(*mark++)->shadowframe = r_shadowframe;
|
|
} while (--c);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// node is just a decision point, so go down the apropriate sides
|
|
|
|
// find which side of the node we are on
|
|
plane = node->plane;
|
|
|
|
switch (plane->type)
|
|
{
|
|
case PLANE_X:
|
|
dot = modelorg[0] - plane->dist;
|
|
break;
|
|
case PLANE_Y:
|
|
dot = modelorg[1] - plane->dist;
|
|
break;
|
|
case PLANE_Z:
|
|
dot = modelorg[2] - plane->dist;
|
|
break;
|
|
default:
|
|
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
|
break;
|
|
}
|
|
|
|
if (dot >= 0)
|
|
side = 0;
|
|
else
|
|
side = 1;
|
|
|
|
// recurse down the children, front side first
|
|
PPL_RecursiveWorldNodeQ2_r (node->children[side]);
|
|
|
|
// draw stuff
|
|
c = node->numsurfaces;
|
|
|
|
if (c)
|
|
{
|
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
|
|
|
{
|
|
for ( ; c ; c--, surf++)
|
|
{
|
|
if (surf->shadowframe != r_shadowframe)
|
|
continue;
|
|
/*
|
|
if (surf->lightframe == r_shadowframe) //done this one!
|
|
continue;
|
|
surf->lightframe = r_shadowframe;
|
|
*/
|
|
// if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
|
|
// continue; // wrong side
|
|
|
|
// if (surf->flags & SURF_PLANEBACK)
|
|
// continue;
|
|
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= 0)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= 0)
|
|
continue;
|
|
}
|
|
//#define PROJECTION_DISTANCE (float)0x7fffffff
|
|
if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED))
|
|
{ // no shadows
|
|
continue;
|
|
}
|
|
|
|
//build a list of the edges that are to be drawn.
|
|
for (v = 0; v < surf->numedges; v++)
|
|
{
|
|
int e, delta;
|
|
e = cl.worldmodel->surfedges[surf->firstedge+v];
|
|
//negative edge means backwards edge.
|
|
if (e < 0)
|
|
{
|
|
e=-e;
|
|
delta = -1;
|
|
}
|
|
else
|
|
{
|
|
delta = 1;
|
|
}
|
|
|
|
if (!edge[e].count)
|
|
{
|
|
if (firstedge)
|
|
edge[firstedge].prev = e;
|
|
edge[e].next = firstedge;
|
|
edge[e].prev = 0;
|
|
firstedge = e;
|
|
edge[e].count = delta;
|
|
}
|
|
else
|
|
{
|
|
edge[e].count += delta;
|
|
|
|
if (!edge[e].count) //unlink
|
|
{
|
|
if (edge[e].next)
|
|
{
|
|
edge[edge[e].next].prev = edge[e].prev;
|
|
}
|
|
if (edge[e].prev)
|
|
edge[edge[e].prev].next = edge[e].next;
|
|
else
|
|
firstedge = edge[e].next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
//front face
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts);
|
|
qglDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
|
|
|
|
//back
|
|
qglBegin(GL_POLYGON);
|
|
for (v = p->numverts-1; v >=0; v--)
|
|
{
|
|
v1 = p->verts[v];
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
}
|
|
qglEnd();
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// recurse down the back side
|
|
PPL_RecursiveWorldNodeQ2_r (node->children[!side]);
|
|
}
|
|
|
|
void PPL_RecursiveWorldNodeQ3_r (mnode_t *node)
|
|
{
|
|
int c, side;
|
|
mplane_t *plane;
|
|
msurface_t *surf, **mark;
|
|
mleaf_t *pleaf;
|
|
double dot;
|
|
glpoly_t *p;
|
|
int v;
|
|
|
|
float *v2;
|
|
vec3_t v4;
|
|
|
|
float *v1;
|
|
vec3_t v3;
|
|
|
|
if (node->contents == Q2CONTENTS_SOLID)
|
|
return; // solid
|
|
|
|
if (node->shadowframe != r_shadowframe)
|
|
return;
|
|
// if (R_CullBox (node->minmaxs, node->minmaxs+3))
|
|
// return;
|
|
|
|
// if a leaf node, draw stuff
|
|
if (node->contents != -1)
|
|
{
|
|
pleaf = (mleaf_t *)node;
|
|
|
|
mark = pleaf->firstmarksurface;
|
|
c = pleaf->nummarksurfaces;
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
surf = *mark;
|
|
(*mark++)->shadowframe = r_shadowframe;
|
|
|
|
/* if (surf->shadowframe != r_shadowframe)
|
|
continue;
|
|
*/
|
|
// if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
|
|
// continue; // wrong side
|
|
|
|
// if (surf->flags & SURF_PLANEBACK)
|
|
// continue;
|
|
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= -lightradius)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= lightradius)
|
|
continue;
|
|
}
|
|
//#define PROJECTION_DISTANCE (float)0x7fffffff
|
|
/*if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED))
|
|
{ // no shadows
|
|
continue;
|
|
}*/
|
|
|
|
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
//front face
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*VERTEXSIZE, p->verts);
|
|
qglDrawElements(GL_TRIANGLES, (p->numverts-2)*3, GL_UNSIGNED_INT, varray_i_polytotri);
|
|
//fixme...
|
|
for (v = 0; v < p->numverts; v++)
|
|
{
|
|
//border
|
|
v1 = p->verts[v];
|
|
v2 = p->verts[( v+1 )%p->numverts];
|
|
|
|
//get positions of v3 and v4 based on the light position
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
//Now draw the quad from the two verts to the projected light
|
|
//verts
|
|
qglBegin( GL_QUAD_STRIP );
|
|
qglVertex3f( v1[0], v1[1], v1[2] );
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
qglVertex3f( v2[0], v2[1], v2[2] );
|
|
qglVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
|
|
qglEnd();
|
|
}
|
|
|
|
//back
|
|
qglBegin(GL_POLYGON);
|
|
for (v = p->numverts-1; v >=0; v--)
|
|
{
|
|
v1 = p->verts[v];
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
}
|
|
qglEnd();
|
|
|
|
}
|
|
} while (--c);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// node is just a decision point, so go down the apropriate sides
|
|
|
|
// find which side of the node we are on
|
|
plane = node->plane;
|
|
|
|
switch (plane->type)
|
|
{
|
|
case PLANE_X:
|
|
dot = modelorg[0] - plane->dist;
|
|
break;
|
|
case PLANE_Y:
|
|
dot = modelorg[1] - plane->dist;
|
|
break;
|
|
case PLANE_Z:
|
|
dot = modelorg[2] - plane->dist;
|
|
break;
|
|
default:
|
|
dot = DotProduct (modelorg, plane->normal) - plane->dist;
|
|
break;
|
|
}
|
|
|
|
if (dot >= 0)
|
|
side = 0;
|
|
else
|
|
side = 1;
|
|
|
|
// recurse down the children, front side first
|
|
PPL_RecursiveWorldNodeQ3_r (node->children[side]);
|
|
|
|
// draw stuff
|
|
/* c = node->numsurfaces;
|
|
|
|
if (c)
|
|
{
|
|
surf = cl.worldmodel->surfaces + node->firstsurface;
|
|
|
|
{
|
|
for ( ; c ; c--, surf++)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
// recurse down the back side
|
|
PPL_RecursiveWorldNodeQ3_r (node->children[!side]);
|
|
}
|
|
|
|
void PPL_RecursiveWorldNode (dlight_t *dl)
|
|
{
|
|
float *v1, *v2;
|
|
vec3_t v3, v4;
|
|
|
|
if (dl->worldshadowmesh)
|
|
{
|
|
qglEnableClientState(GL_VERTEX_ARRAY);
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(vec3_t), dl->worldshadowmesh->verts);
|
|
qglDrawElements(GL_TRIANGLES, dl->worldshadowmesh->numindicies, GL_UNSIGNED_INT, dl->worldshadowmesh->indicies);
|
|
return;
|
|
}
|
|
|
|
lightradius = dl->radius;
|
|
|
|
lightorg[0] = dl->origin[0]+0.5;
|
|
lightorg[1] = dl->origin[1]+0.5;
|
|
lightorg[2] = dl->origin[2]+0.5;
|
|
|
|
modelorg[0] = lightorg[0];
|
|
modelorg[1] = lightorg[1];
|
|
modelorg[2] = lightorg[2];
|
|
|
|
qglEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
if (cl.worldmodel->fromgame == fg_quake3)
|
|
PPL_RecursiveWorldNodeQ3_r(cl.worldmodel->nodes);
|
|
else if (cl.worldmodel->fromgame == fg_quake2)
|
|
PPL_RecursiveWorldNodeQ2_r(cl.worldmodel->nodes);
|
|
else
|
|
PPL_RecursiveWorldNode_r(cl.worldmodel->nodes);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v[0].xyz);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
while(firstedge)
|
|
{
|
|
//border
|
|
v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[firstedge].v[0]].position;
|
|
v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[firstedge].v[1]].position;
|
|
|
|
//get positions of v3 and v4 based on the light position
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
if (varray_vc + 4>MAXARRAYVERTS)
|
|
{
|
|
qglDrawElements(GL_QUADS, varray_vc, GL_UNSIGNED_INT, varray_i_forward);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
varray_vc=0;
|
|
}
|
|
|
|
if (edge[firstedge].count > 0)
|
|
{
|
|
varray_v[varray_vc].xyz[0] = v1[0]+v3[0];
|
|
varray_v[varray_vc].xyz[1] = v1[1]+v3[1];
|
|
varray_v[varray_vc].xyz[2] = v1[2]+v3[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v2[0]+v4[0];
|
|
varray_v[varray_vc].xyz[1] = v2[1]+v4[1];
|
|
varray_v[varray_vc].xyz[2] = v2[2]+v4[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v2[0];
|
|
varray_v[varray_vc].xyz[1] = v2[1];
|
|
varray_v[varray_vc].xyz[2] = v2[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v1[0];
|
|
varray_v[varray_vc].xyz[1] = v1[1];
|
|
varray_v[varray_vc].xyz[2] = v1[2];
|
|
varray_vc++;
|
|
}
|
|
else
|
|
{
|
|
varray_v[varray_vc].xyz[0] = v1[0];
|
|
varray_v[varray_vc].xyz[1] = v1[1];
|
|
varray_v[varray_vc].xyz[2] = v1[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v2[0];
|
|
varray_v[varray_vc].xyz[1] = v2[1];
|
|
varray_v[varray_vc].xyz[2] = v2[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v2[0]+v4[0];
|
|
varray_v[varray_vc].xyz[1] = v2[1]+v4[1];
|
|
varray_v[varray_vc].xyz[2] = v2[2]+v4[2];
|
|
varray_vc++;
|
|
varray_v[varray_vc].xyz[0] = v1[0]+v3[0];
|
|
varray_v[varray_vc].xyz[1] = v1[1]+v3[1];
|
|
varray_v[varray_vc].xyz[2] = v1[2]+v3[2];
|
|
varray_vc++;
|
|
}
|
|
edge[firstedge].count=0;
|
|
|
|
firstedge = edge[firstedge].next;
|
|
|
|
shadowedgecount++;
|
|
}
|
|
qglDrawElements(GL_QUADS, varray_vc, GL_UNSIGNED_INT, varray_i_forward);
|
|
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
|
|
varray_vc=0;
|
|
|
|
firstedge=0;
|
|
}
|
|
|
|
void PPL_DrawBrushModel(dlight_t *dl, entity_t *e)
|
|
{
|
|
glpoly_t *p;
|
|
int v;
|
|
float *v1, *v2;
|
|
vec3_t v3, v4;
|
|
|
|
int i;
|
|
model_t *model;
|
|
msurface_t *surf;
|
|
|
|
RotateLightVector(e->angles, e->origin, dl->origin, lightorg);
|
|
|
|
qglPushMatrix();
|
|
R_RotateForEntity(e);
|
|
model = e->model;
|
|
surf = model->surfaces+model->firstmodelsurface;
|
|
for (i = 0; i < model->nummodelsurfaces; i++, surf++)
|
|
{
|
|
if (surf->flags & SURF_PLANEBACK)
|
|
{//inverted normal.
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist >= -0.1)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (DotProduct(surf->plane->normal, lightorg)-surf->plane->dist <= 0.1)
|
|
continue;
|
|
}
|
|
//#define PROJECTION_DISTANCE (float)0x7fffffff
|
|
if (surf->flags & (SURF_DRAWALPHA | SURF_DRAWTILED))
|
|
{ // no shadows
|
|
continue;
|
|
}
|
|
|
|
for (p = surf->polys; p; p=p->next)
|
|
{
|
|
//front face
|
|
qglVertexPointer(3, GL_FLOAT, sizeof(p->verts[0]), p->verts[0]);
|
|
qglDrawElements(GL_POLYGON, p->numverts, GL_UNSIGNED_INT, varray_i_forward);
|
|
/* glBegin(GL_POLYGON);
|
|
for (v = 0; v < p->numverts; v++)
|
|
glVertex3fv(p->verts[v]);
|
|
glEnd();*/
|
|
|
|
for (v = 0; v < p->numverts; v++)
|
|
{
|
|
//border
|
|
v1 = p->verts[v];
|
|
v2 = p->verts[( v+1 )%p->numverts];
|
|
|
|
//get positions of v3 and v4 based on the light position
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
v4[0] = ( v2[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v4[1] = ( v2[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v4[2] = ( v2[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
//Now draw the quad from the two verts to the projected light
|
|
//verts
|
|
qglBegin( GL_QUAD_STRIP );
|
|
qglVertex3f( v1[0], v1[1], v1[2] );
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
qglVertex3f( v2[0], v2[1], v2[2] );
|
|
qglVertex3f( v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2] );
|
|
qglEnd();
|
|
}
|
|
|
|
//back
|
|
|
|
qglBegin(GL_POLYGON);
|
|
for (v = p->numverts-1; v >=0; v--)
|
|
{
|
|
v1 = p->verts[v];
|
|
v3[0] = ( v1[0]-lightorg[0] )*PROJECTION_DISTANCE;
|
|
v3[1] = ( v1[1]-lightorg[1] )*PROJECTION_DISTANCE;
|
|
v3[2] = ( v1[2]-lightorg[2] )*PROJECTION_DISTANCE;
|
|
|
|
qglVertex3f( v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2] );
|
|
}
|
|
qglEnd();
|
|
|
|
}
|
|
}
|
|
qglPopMatrix();
|
|
}
|
|
|
|
void PPL_DrawShadowMeshes(dlight_t *dl)
|
|
{
|
|
int i;
|
|
|
|
if (!r_drawentities.value)
|
|
return;
|
|
|
|
// draw sprites seperately, because of alpha blending
|
|
for (i=0 ; i<cl_numvisedicts ; i++)
|
|
{
|
|
currententity = &cl_visedicts[i];
|
|
|
|
if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
|
|
continue;
|
|
|
|
if (!currententity->model)
|
|
continue;
|
|
|
|
if (dl->key == currententity->keynum)
|
|
continue;
|
|
|
|
if (currententity->flags & Q2RF_WEAPONMODEL)
|
|
continue; //weapon models don't cast shadows.
|
|
|
|
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
|
|
{
|
|
if (currententity->model->particleeffect>=0)
|
|
{
|
|
if (currententity->model->particleengulphs)
|
|
{
|
|
if (gl_part_flame.value)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (currententity->model->type)
|
|
{
|
|
case mod_alias:
|
|
R_DrawGAliasShadowVolume (currententity, dl->origin, dl->radius);
|
|
break;
|
|
|
|
case mod_brush:
|
|
PPL_DrawBrushModel (dl, currententity);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PPL_UpdateNodeShadowFrames(qbyte *lvis)
|
|
{
|
|
int i;
|
|
mnode_t *node;
|
|
|
|
|
|
|
|
#ifdef Q3BSPS
|
|
if (cl.worldmodel->fromgame == fg_quake3)
|
|
{
|
|
mleaf_t *leaf;
|
|
r_shadowframe++;
|
|
for (i=0, leaf=cl.worldmodel->leafs; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
{
|
|
node = (mnode_t *)leaf;
|
|
while (node)
|
|
{
|
|
if (node->shadowframe == r_shadowframe)
|
|
break;
|
|
node->shadowframe = r_shadowframe;
|
|
node = node->parent;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
#ifdef Q2BSPS
|
|
if (cl.worldmodel->fromgame == fg_quake2)
|
|
{
|
|
mleaf_t *leaf;
|
|
int cluster;
|
|
r_shadowframe++;
|
|
|
|
for (i=0, leaf=cl.worldmodel->leafs; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
{
|
|
cluster = leaf->cluster;
|
|
if (cluster == -1)
|
|
continue;
|
|
if (lvis[cluster>>3] & (1<<(cluster&7)))
|
|
{
|
|
node = (mnode_t *)leaf;
|
|
do
|
|
{
|
|
if (node->shadowframe == r_shadowframe)
|
|
break;
|
|
node->shadowframe = r_shadowframe;
|
|
node = node->parent;
|
|
} while (node);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (r_novis.value != 2)
|
|
{
|
|
r_shadowframe++;
|
|
|
|
//variation on mark leaves
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++)
|
|
{
|
|
if (lvis[i>>3] & (1<<(i&7)))// && vvis[i>>3] & (1<<(i&7)))
|
|
{
|
|
node = (mnode_t *)&cl.worldmodel->leafs[i+1];
|
|
do
|
|
{
|
|
if (node->shadowframe == r_shadowframe)
|
|
break;
|
|
node->shadowframe = r_shadowframe;
|
|
node = node->parent;
|
|
} while (node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if 1 //DP's stolen code
|
|
static void GL_Scissor (int x, int y, int width, int height)
|
|
{
|
|
#if 0 //visible scissors
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
glOrtho (0, glwidth, glheight, 0, -99999, 99999);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
// GL_Set2D();
|
|
|
|
glColor4f(1,1,1,1);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE );
|
|
glDisable(GL_TEXTURE_2D);
|
|
GL_TexEnv(GL_REPLACE);
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex2f(x, y);
|
|
glVertex2f(x+glwidth, y);
|
|
glVertex2f(x+glwidth, y+glheight);
|
|
glVertex2f(x, y+glheight);
|
|
glEnd();
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPopMatrix();
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPopMatrix();
|
|
#endif
|
|
qglScissor(x, glheight - (y + height),width,height);
|
|
}
|
|
|
|
#define BoxesOverlap(a,b,c,d) ((a)[0] <= (d)[0] && (b)[0] >= (c)[0] && (a)[1] <= (d)[1] && (b)[1] >= (c)[1] && (a)[2] <= (d)[2] && (b)[2] >= (c)[2])
|
|
qboolean PPL_ScissorForBox(vec3_t mins, vec3_t maxs)
|
|
{
|
|
int i, ix1, iy1, ix2, iy2;
|
|
float x1, y1, x2, y2, x, y, f;
|
|
vec3_t smins, smaxs;
|
|
vec4_t v, v2;
|
|
int r_view_x = 0;
|
|
int r_view_y = 0;
|
|
int r_view_width = glwidth;
|
|
int r_view_height = glheight;
|
|
if (0)//!r_shadow_scissor.integer)
|
|
{
|
|
GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
|
|
return false;
|
|
}
|
|
// if view is inside the box, just say yes it's visible
|
|
if (BoxesOverlap(r_refdef.vieworg, r_refdef.vieworg, mins, maxs))
|
|
{
|
|
GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
|
|
return false;
|
|
}
|
|
for (i = 0;i < 3;i++)
|
|
{
|
|
if (vpn[i] >= 0)
|
|
{
|
|
v[i] = mins[i];
|
|
v2[i] = maxs[i];
|
|
}
|
|
else
|
|
{
|
|
v[i] = maxs[i];
|
|
v2[i] = mins[i];
|
|
}
|
|
}
|
|
f = DotProduct(vpn, r_refdef.vieworg) + 1;
|
|
if (DotProduct(vpn, v2) <= f)
|
|
{
|
|
// entirely behind nearclip plane
|
|
GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
|
|
return true;
|
|
}
|
|
if (DotProduct(vpn, v) >= f)
|
|
{
|
|
// entirely infront of nearclip plane
|
|
x1 = y1 = x2 = y2 = 0;
|
|
for (i = 0;i < 8;i++)
|
|
{
|
|
v[0] = (i & 1) ? mins[0] : maxs[0];
|
|
v[1] = (i & 2) ? mins[1] : maxs[1];
|
|
v[2] = (i & 4) ? mins[2] : maxs[2];
|
|
v[3] = 1.0f;
|
|
ML_Project(v, v2, r_refdef.viewangles, r_refdef.vieworg, (float)vid.width/vid.height, r_refdef.fov_y);
|
|
v2[0]*=r_view_width;
|
|
v2[1]*=r_view_height;
|
|
// GL_TransformToScreen(v, v2);
|
|
//Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
|
|
x = v2[0];
|
|
y = v2[1];
|
|
if (i)
|
|
{
|
|
if (x1 > x) x1 = x;
|
|
if (x2 < x) x2 = x;
|
|
if (y1 > y) y1 = y;
|
|
if (y2 < y) y2 = y;
|
|
}
|
|
else
|
|
{
|
|
x1 = x2 = x;
|
|
y1 = y2 = y;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// clipped by nearclip plane
|
|
// this is nasty and crude...
|
|
// create viewspace bbox
|
|
for (i = 0;i < 8;i++)
|
|
{
|
|
v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_refdef.vieworg[0];
|
|
v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_refdef.vieworg[1];
|
|
v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_refdef.vieworg[2];
|
|
v2[0] = DotProduct(v, vright);
|
|
v2[1] = DotProduct(v, vup);
|
|
v2[2] = DotProduct(v, vpn);
|
|
if (i)
|
|
{
|
|
if (smins[0] > v2[0]) smins[0] = v2[0];
|
|
if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
|
|
if (smins[1] > v2[1]) smins[1] = v2[1];
|
|
if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
|
|
if (smins[2] > v2[2]) smins[2] = v2[2];
|
|
if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
|
|
}
|
|
else
|
|
{
|
|
smins[0] = smaxs[0] = v2[0];
|
|
smins[1] = smaxs[1] = v2[1];
|
|
smins[2] = smaxs[2] = v2[2];
|
|
}
|
|
}
|
|
// now we have a bbox in viewspace
|
|
// clip it to the view plane
|
|
if (smins[2] < 1)
|
|
smins[2] = 1;
|
|
// return true if that culled the box
|
|
if (smins[2] >= smaxs[2])
|
|
return true;
|
|
// ok some of it is infront of the view, transform each corner back to
|
|
// worldspace and then to screenspace and make screen rect
|
|
// initialize these variables just to avoid compiler warnings
|
|
x1 = y1 = x2 = y2 = 0;
|
|
for (i = 0;i < 8;i++)
|
|
{
|
|
v2[0] = (i & 1) ? smins[0] : smaxs[0];
|
|
v2[1] = (i & 2) ? smins[1] : smaxs[1];
|
|
v2[2] = (i & 4) ? smins[2] : smaxs[2];
|
|
v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_refdef.vieworg[0];
|
|
v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_refdef.vieworg[1];
|
|
v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_refdef.vieworg[2];
|
|
v[3] = 1.0f;
|
|
ML_Project(v, v2, r_refdef.viewangles, r_refdef.vieworg, vid.width/vid.height, r_refdef.fov_y);
|
|
v2[0]*=r_view_width;
|
|
v2[1]*=r_view_height;
|
|
// GL_TransformToScreen(v, v2);
|
|
//Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
|
|
x = v2[0];
|
|
y = v2[1];
|
|
if (i)
|
|
{
|
|
if (x1 > x) x1 = x;
|
|
if (x2 < x) x2 = x;
|
|
if (y1 > y) y1 = y;
|
|
if (y2 < y) y2 = y;
|
|
}
|
|
else
|
|
{
|
|
x1 = x2 = x;
|
|
y1 = y2 = y;
|
|
}
|
|
}
|
|
#if 0
|
|
// this code doesn't handle boxes with any points behind view properly
|
|
x1 = 1000;x2 = -1000;
|
|
y1 = 1000;y2 = -1000;
|
|
for (i = 0;i < 8;i++)
|
|
{
|
|
v[0] = (i & 1) ? mins[0] : maxs[0];
|
|
v[1] = (i & 2) ? mins[1] : maxs[1];
|
|
v[2] = (i & 4) ? mins[2] : maxs[2];
|
|
v[3] = 1.0f;
|
|
GL_TransformToScreen(v, v2);
|
|
v2[0]*=r_view_width;
|
|
v2[1]*=r_view_height;
|
|
//Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
|
|
if (v2[2] > 0)
|
|
{
|
|
x = v2[0];
|
|
y = v2[1];
|
|
|
|
if (x1 > x) x1 = x;
|
|
if (x2 < x) x2 = x;
|
|
if (y1 > y) y1 = y;
|
|
if (y2 < y) y2 = y;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
ix1 = x1 - 1.0f;
|
|
iy1 = y1 - 1.0f;
|
|
ix2 = x2 + 1.0f;
|
|
iy2 = y2 + 1.0f;
|
|
//Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
|
|
if (ix1 < r_view_x) ix1 = r_view_x;
|
|
if (iy1 < r_view_y) iy1 = r_view_y;
|
|
if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
|
|
if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
|
|
if (ix2 <= ix1 || iy2 <= iy1)
|
|
return true;
|
|
// set up the scissor rectangle
|
|
qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
|
|
//qglEnable(GL_SCISSOR_TEST);
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void CL_NewDlight (int key, float x, float y, float z, float radius, float time,
|
|
int type);
|
|
//generates stencil shadows of the world geometry.
|
|
//redraws world geometry
|
|
void PPL_AddLight(dlight_t *dl)
|
|
{
|
|
int i;
|
|
int sdecrw;
|
|
int sincrw;
|
|
int leaf;
|
|
qbyte *lvis;
|
|
qbyte *vvis;
|
|
vec3_t colour;
|
|
|
|
qbyte lvisb[MAX_MAP_LEAFS/8];
|
|
qbyte vvisb[MAX_MAP_LEAFS/8];
|
|
|
|
vec3_t mins;
|
|
vec3_t maxs;
|
|
|
|
mins[0] = dl->origin[0] - dl->radius;
|
|
mins[1] = dl->origin[1] - dl->radius;
|
|
mins[2] = dl->origin[2] - dl->radius;
|
|
|
|
maxs[0] = dl->origin[0] + dl->radius;
|
|
maxs[1] = dl->origin[1] + dl->radius;
|
|
maxs[2] = dl->origin[2] + dl->radius;
|
|
|
|
colour[0] = dl->color[0];
|
|
colour[1] = dl->color[1];
|
|
colour[2] = dl->color[2];
|
|
if (dl->style)
|
|
{
|
|
if (cl_lightstyle[dl->style-1].colour & 1)
|
|
colour[0] *= d_lightstylevalue[dl->style-1]/255.0f;
|
|
else
|
|
colour[0] = 0;
|
|
if (cl_lightstyle[dl->style-1].colour & 2)
|
|
colour[1] *= d_lightstylevalue[dl->style-1]/255.0f;
|
|
else
|
|
colour[1] = 0;
|
|
if (cl_lightstyle[dl->style-1].colour & 4)
|
|
colour[2] *= d_lightstylevalue[dl->style-1]/255.0f;
|
|
else
|
|
colour[2] = 0;
|
|
}
|
|
|
|
if (colour[0] < 0.1 && colour[1] < 0.1 && colour[2] < 0.1)
|
|
return; //just switch these off.
|
|
|
|
if (PPL_ScissorForBox(mins, maxs))
|
|
return; //was culled.
|
|
|
|
if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
|
|
i = cl.worldmodel->funcs.LeafForPoint(r_refdef.vieworg, cl.worldmodel);
|
|
else
|
|
i = r_viewleaf - cl.worldmodel->leafs;
|
|
|
|
leaf = cl.worldmodel->funcs.LeafForPoint(dl->origin, cl.worldmodel);
|
|
lvis = cl.worldmodel->funcs.LeafPVS(leaf, cl.worldmodel, lvisb);
|
|
vvis = cl.worldmodel->funcs.LeafPVS(i, cl.worldmodel, vvisb);
|
|
|
|
// if (!(lvis[i>>3] & (1<<(i&7)))) //light might not be visible, but it's effects probably should be.
|
|
// return;
|
|
if (!PPL_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect.
|
|
return;
|
|
|
|
PPL_EnableVertexArrays();
|
|
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
// if (1)
|
|
// goto noshadows;
|
|
|
|
qglEnable(GL_SCISSOR_TEST);
|
|
|
|
|
|
qglDisable(GL_BLEND);
|
|
qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
|
|
qglDepthMask(0);
|
|
|
|
if (gldepthfunc==GL_LEQUAL)
|
|
qglDepthFunc(GL_LESS);
|
|
else
|
|
qglDepthFunc(GL_GREATER);
|
|
qglEnable(GL_DEPTH_TEST);
|
|
qglEnable(GL_STENCIL_TEST);
|
|
|
|
sincrw = GL_INCR;
|
|
sdecrw = GL_DECR;
|
|
if (gl_config.ext_stencil_wrap)
|
|
{ //minamlise damage...
|
|
sincrw = GL_INCR_WRAP_EXT;
|
|
sdecrw = GL_DECR_WRAP_EXT;
|
|
}
|
|
//our stencil writes.
|
|
|
|
#ifdef _DEBUG
|
|
if (r_shadows.value == 666) //testing (visible shadow volumes)
|
|
{
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
|
qglColor3f(dl->color[0], dl->color[1], dl->color[2]);
|
|
qglDisable(GL_STENCIL_TEST);
|
|
qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
PPL_RecursiveWorldNode(dl);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
PPL_DrawShadowMeshes(dl);
|
|
if (qglGetError())
|
|
Con_Printf("GL Error on entities\n");
|
|
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
}
|
|
else
|
|
#endif
|
|
|
|
if (qglStencilOpSeparateATI && !((int)r_shadows.value & 2))//GL_ATI_separate_stencil
|
|
{
|
|
qglClearStencil(0);
|
|
qglClear(GL_STENCIL_BUFFER_BIT);
|
|
qglDisable(GL_CULL_FACE);
|
|
|
|
qglStencilFunc( GL_ALWAYS, 1, ~0 );
|
|
|
|
qglStencilOpSeparateATI(GL_BACK, GL_KEEP, sincrw, GL_KEEP);
|
|
qglStencilOpSeparateATI(GL_FRONT, GL_KEEP, sdecrw, GL_KEEP);
|
|
PPL_UpdateNodeShadowFrames(lvisb);
|
|
PPL_RecursiveWorldNode(dl);
|
|
PPL_DrawShadowMeshes(dl);
|
|
qglStencilOpSeparateATI(GL_FRONT_AND_BACK, GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
qglEnable(GL_CULL_FACE);
|
|
|
|
qglStencilFunc( GL_EQUAL, 0, ~0 );
|
|
}
|
|
else if (qglActiveStencilFaceEXT && !((int)r_shadows.value & 2)) //NVidias variation on a theme. (GFFX class)
|
|
{
|
|
qglClearStencil(0);
|
|
qglClear(GL_STENCIL_BUFFER_BIT);
|
|
qglDisable(GL_CULL_FACE);
|
|
|
|
qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
|
|
|
|
qglActiveStencilFaceEXT(GL_BACK);
|
|
qglStencilOp(GL_KEEP, sincrw, GL_KEEP);
|
|
qglStencilFunc( GL_ALWAYS, 1, ~0 );
|
|
|
|
qglActiveStencilFaceEXT(GL_FRONT);
|
|
qglStencilOp(GL_KEEP, sdecrw, GL_KEEP);
|
|
qglStencilFunc( GL_ALWAYS, 1, ~0 );
|
|
|
|
PPL_UpdateNodeShadowFrames(lvisb);
|
|
PPL_RecursiveWorldNode(dl);
|
|
PPL_DrawShadowMeshes(dl);
|
|
|
|
qglActiveStencilFaceEXT(GL_BACK);
|
|
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
qglActiveStencilFaceEXT(GL_FRONT);
|
|
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
|
|
|
|
qglEnable(GL_CULL_FACE);
|
|
|
|
qglActiveStencilFaceEXT(GL_BACK);
|
|
qglStencilFunc( GL_EQUAL, 0, ~0 );
|
|
}
|
|
else //your graphics card sucks and lacks efficient stencil shadow techniques.
|
|
{ //centered around 0. Will only be increased then decreased less.
|
|
qglClearStencil(0);
|
|
qglClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
qglEnable(GL_CULL_FACE);
|
|
|
|
qglStencilFunc( GL_ALWAYS, 0, ~0 );
|
|
|
|
shadowsurfcount = 0;
|
|
qglCullFace(GL_BACK);
|
|
qglStencilOp(GL_KEEP, sincrw, GL_KEEP);
|
|
PPL_UpdateNodeShadowFrames(lvis);
|
|
PPL_RecursiveWorldNode(dl);
|
|
PPL_DrawShadowMeshes(dl);
|
|
|
|
shadowsurfcount=0;
|
|
qglCullFace(GL_FRONT);
|
|
qglStencilOp(GL_KEEP, sdecrw, GL_KEEP);
|
|
PPL_UpdateNodeShadowFrames(lvis);
|
|
PPL_RecursiveWorldNode(dl);
|
|
PPL_DrawShadowMeshes(dl);
|
|
|
|
qglStencilFunc( GL_EQUAL, 0, ~0 );
|
|
}
|
|
//end stencil writing.
|
|
|
|
qglEnable(GL_DEPTH_TEST);
|
|
qglDepthMask(0);
|
|
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
|
qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
|
|
qglCullFace(GL_FRONT);
|
|
|
|
//noshadows:
|
|
qglColor3f(1,1,1);
|
|
|
|
qglEnable(GL_BLEND);
|
|
qglBlendFunc(GL_ONE, GL_ONE);
|
|
qglColor4f(dl->color[0], dl->color[1], dl->color[2], 1);
|
|
qglDepthFunc(GL_EQUAL);
|
|
|
|
lightorg[0] = dl->origin[0]+0.5;
|
|
lightorg[1] = dl->origin[1]+0.5;
|
|
lightorg[2] = dl->origin[2]+0.5;
|
|
|
|
PPL_DrawEntLighting(dl, colour);
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
qglDepthMask(1);
|
|
qglDepthFunc(gldepthfunc);
|
|
qglEnable(GL_DEPTH_TEST);
|
|
|
|
qglDisable(GL_STENCIL_TEST);
|
|
qglStencilFunc( GL_ALWAYS, 0, ~0 );
|
|
|
|
qglDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
#endif
|
|
|
|
void GL_CheckTMUIs0(void);
|
|
|
|
void PPL_DrawWorld (void)
|
|
{
|
|
RSpeedLocals();
|
|
dlight_t *l;
|
|
#if 0
|
|
dlight_t *lc, *furthestprev;
|
|
float furthest;
|
|
#endif
|
|
int i;
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
int maxshadowlights = gl_maxshadowlights.value;
|
|
|
|
if (!lightmap)
|
|
{
|
|
R_PreNewMap();
|
|
R_NewMap();
|
|
return; // :/
|
|
}
|
|
|
|
if (maxshadowlights < 1)
|
|
maxshadowlights = 1;
|
|
// if (qglGetError())
|
|
// Con_Printf("GL Error before world\n");
|
|
//glColorMask(0,0,0,0);
|
|
|
|
RSpeedRemark();
|
|
TRACE(("dbg: calling PPL_BaseTextures\n"));
|
|
PPL_BaseTextures(cl.worldmodel);
|
|
RSpeedEnd(RSPEED_WORLD);
|
|
|
|
// if (qglGetError())
|
|
// Con_Printf("GL Error during base textures\n");
|
|
//glColorMask(1,1,1,1);
|
|
|
|
RSpeedRemark();
|
|
TRACE(("dbg: calling PPL_BaseEntTextures\n"));
|
|
PPL_BaseEntTextures();
|
|
RSpeedEnd(RSPEED_ENTITIES);
|
|
|
|
// CL_NewDlightRGB(1, r_refdef.vieworg[0], r_refdef.vieworg[1]-16, r_refdef.vieworg[2]-24, 128, 1, 1, 1, 1);
|
|
|
|
// if (qglGetError())
|
|
// Con_Printf("GL Error on entities\n");
|
|
|
|
#ifdef PPL
|
|
RSpeedRemark();
|
|
if (r_shadows.value && qglStencilFunc && gl_canstencil)
|
|
{
|
|
if (cl.worldmodel->fromgame == fg_quake || cl.worldmodel->fromgame == fg_halflife || cl.worldmodel->fromgame == fg_quake2 /*|| cl.worldmodel->fromgame == fg_quake3*/)
|
|
{
|
|
// lc = NULL;
|
|
for (l = cl_dlights, i=0 ; i<MAX_DLIGHTS ; i++, l++)
|
|
{
|
|
if (!l->radius || l->noppl)
|
|
continue;
|
|
if (l->color[0]<0)
|
|
continue; //quick check for darklight
|
|
|
|
if (l->isstatic)
|
|
{
|
|
if (!r_shadow_realtime_world.value)
|
|
continue;
|
|
}
|
|
|
|
mins[0] = l->origin[0] - l->radius;
|
|
mins[1] = l->origin[1] - l->radius;
|
|
mins[2] = l->origin[2] - l->radius;
|
|
maxs[0] = l->origin[0] + l->radius;
|
|
maxs[1] = l->origin[1] + l->radius;
|
|
maxs[2] = l->origin[2] + l->radius;
|
|
if (R_CullBox(mins, maxs))
|
|
continue;
|
|
// if (R_CullSphere(l->origin, l->radius*1.1))
|
|
// continue;
|
|
|
|
#if 1
|
|
if (!maxshadowlights--)
|
|
continue;
|
|
#else
|
|
VectorSubtract(l->origin, r_refdef.vieworg, mins)
|
|
l->dist = Length(mins);
|
|
VectorNormalize(mins);
|
|
l->dist*=1-sqrt(DotProduct(vpn, mins)*DotProduct(vpn, mins));
|
|
|
|
l->next = lc;
|
|
lc = l;
|
|
maxshadowlights--;
|
|
}
|
|
while (maxshadowlights<0)//ooer... we exceeded our quota... strip the furthest ones out.
|
|
{
|
|
furthest = lc->dist;
|
|
furthestprev=NULL;
|
|
for (l = lc; l->next; l = l->next)
|
|
{
|
|
if (l->next->dist > furthest)
|
|
{
|
|
furthest = l->next->dist;
|
|
furthestprev = l;
|
|
}
|
|
}
|
|
if (furthestprev)
|
|
furthestprev->next = furthestprev->next->next;
|
|
else
|
|
lc = lc->next;
|
|
|
|
maxshadowlights++;
|
|
}
|
|
|
|
for (l = lc; l; l = l->next) //we now have our quotaed list
|
|
{
|
|
#endif
|
|
if(!l->isstatic)
|
|
{
|
|
l->color[0]*=10;
|
|
l->color[1]*=10;
|
|
l->color[2]*=10;
|
|
}
|
|
TRACE(("dbg: calling PPL_AddLight\n"));
|
|
PPL_AddLight(l);
|
|
if(!l->isstatic)
|
|
{
|
|
l->color[0]/=10;
|
|
l->color[1]/=10;
|
|
l->color[2]/=10;
|
|
}
|
|
}
|
|
qglEnable(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
qglDisableClientState(GL_COLOR_ARRAY);
|
|
}
|
|
RSpeedEnd(RSPEED_STENCILSHADOWS);
|
|
#endif
|
|
|
|
// if (qglGetError())
|
|
// Con_Printf("GL Error on shadow lighting\n");
|
|
|
|
RSpeedRemark();
|
|
|
|
if (gl_schematics.value)
|
|
PPL_Schematics();
|
|
|
|
TRACE(("dbg: calling PPL_DrawEntFullBrights\n"));
|
|
PPL_DrawEntFullBrights();
|
|
|
|
RSpeedEnd(RSPEED_FULLBRIGHTS);
|
|
|
|
// if (qglGetError())
|
|
// Con_Printf("GL Error on fullbrights/details\n");
|
|
|
|
// Con_Printf("%i %i(%i) %i\n", shadowsurfcount, shadowedgecount, shadowemittedeges, shadowlightfaces);
|
|
|
|
RQuantAdd(RQUANT_SHADOWFACES, shadowsurfcount);
|
|
RQuantAdd(RQUANT_SHADOWEDGES, shadowedgecount);
|
|
RQuantAdd(RQUANT_LITFACES, shadowlightfaces);
|
|
|
|
shadowsurfcount = 0;
|
|
shadowedgecount = 0;
|
|
shadowlightfaces = 0;
|
|
shadowemittedeges = 0;
|
|
|
|
GL_CheckTMUIs0();
|
|
|
|
R_IBrokeTheArrays();
|
|
}
|
|
#endif
|