1
0
Fork 0
forked from fte/fteqw
fteqw/engine/gl/gl_ppl.c
Spoike b5ac90d523 More stuff broken.
Added control over texture coords on particles. Switched them to batch based on common render state. Less state changes there now.
Inverted sorting, to aid depth culling.
fullbrights use vbos too now.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3261 fc73d0e0-1445-4013-8a0c-d673dee63da5
2009-07-11 20:56:09 +00:00

5581 lines
140 KiB
C

//FIXME: Light visibility is decided from weather the light's pvs overlaps the view pvs.
//This doesn't take light radius into account. This means that lights around corners that will never be visible are drawn in full per-pixel goodness.
//This is bad. lights*3, 33% framerate for no worthwhile effect.
#include "quakedef.h"
#ifndef NEWBACKEND
#ifdef RGLQUAKE
#include "glquake.h"
#include "shader.h"
#include "renderque.h"
#define qglGetError() 0
//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, int shift);
void R_BlendLightmaps (void);
void PPL_BeginShadowMesh(dlight_t *dl);
void PPL_FinishShadowMesh(dlight_t *dl);
void PPL_FlushShadowMesh(dlight_t *dl);
void PPL_Shadow_Cache_Surface(msurface_t *surf); //only caches for lighting
void PPL_Shadow_Cache_Leaf(mleaf_t *leaf);
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 gl_detailscale;
extern cvar_t gl_overbright, gl_overbright_all;
extern cvar_t r_fb_bmodels;
extern cvar_t gl_part_flame;
extern cvar_t gl_maxshadowlights;
extern cvar_t r_shadow_realtime_world;
extern cvar_t r_shadow_realtime_world_lightmaps;
extern cvar_t r_shadow_glsl_offsetmapping;
extern cvar_t r_shadow_glsl_offsetmapping_scale;
extern cvar_t r_shadow_glsl_offsetmapping_bias;
extern int detailtexture;
extern cvar_t gl_bump;
extern cvar_t gl_specular;
extern cvar_t gl_mylumassuck;
//end header confict
extern cvar_t gl_schematics;
extern cvar_t r_drawflat;
extern cvar_t r_wallcolour;
extern cvar_t r_floorcolour;
float r_lightmapintensity; //1 or r_shadow_realtime_world_lightmaps
int overbright;
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_shader;
int ppl_specular_shader_vieworg;
int ppl_specular_shader_texr;
int ppl_specular_shader_texu;
int ppl_specular_shader_texf;
int GLR_LightmapShift (model_t *model);
//#define glBegin glEnd
qboolean PPL_ShouldDraw(void)
{
if (r_inmirror)
{
if (currententity->flags & Q2RF_WEAPONMODEL)
return false;
}
else
{
if (currententity->flags & Q2RF_WEAPONMODEL && r_secondaryview >= 2)
return false;
if (currententity->flags & Q2RF_EXTERNALMODEL && r_secondaryview != 3)
return false;
// if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1)))
// return false;
// if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
// continue;
if (!Cam_DrawPlayer(r_refdef.currentplayernum, currententity->keynum-1))
return false;
}
return true;
}
typedef struct {
int count;
msurface_t **s;
} shadowmeshsurfs_t;
typedef struct shadowmesh_s {
int numindicies;
int numverts;
int *indicies;
vec3_t *verts;
//we also have a list of all the surfaces that this light lights.
int numsurftextures;
shadowmeshsurfs_t *litsurfs;
unsigned char *litleaves;
} shadowmesh_t;
#define Q2RF_WEAPONMODEL 4 // only draw through eyes
struct {
short count;
short count2;
int next;
int 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 index_t 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);
}
inline void PPL_FlushArrays(void)
{
if (varray_ic)
qglDrawElements(GL_TRIANGLES, varray_ic, GL_INDEX_TYPE, varray_i);
varray_ic = 0;
varray_vc = 0;
}
static void PPL_GenerateArrays(msurface_t *surf)
{
int vi;
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;
}
static void PPL_GenerateDetailArrays(msurface_t *surf)
{
int vi;
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]*gl_detailscale.value;
varray_v[vi].stw[1] = surf->mesh->st_array[vi][1]*gl_detailscale.value;
}
varray_vc = surf->mesh->numvertexes;
varray_ic = surf->mesh->numindexes;
}
/*
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->tn.base);
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)
{ //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying.
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);
GL_SelectTexture(GL_TEXTURE1_ARB);
GL_TexEnv(GL_MODULATE);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
vi = -1;
for (; s ; s=s->texturechain)
{
if (vi != s->lightmaptexturenum)
{
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);
}
qglClientActiveTextureARB(GL_TEXTURE0_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
//qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
qglDisable(GL_TEXTURE_2D);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
GL_SelectTexture(GL_TEXTURE0_ARB);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
}*/
#if 0
static void PPL_BaseChain_NoBump_2TMU_Overbright(msurface_t *s, texture_t *tex)
{ //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying.
int vi;
glRect_t *theRect;
PPL_EnableVertexArrays();
if (tex->alphaed || currententity->shaderRGBAf[3]<1)
{
if (*tex->name == '{')
{
qglEnable(GL_ALPHA_TEST);
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
}
else
{
qglEnable(GL_BLEND);
GL_TexEnv(GL_MODULATE);
}
}
else
{
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
}
GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
GL_SelectTexture(GL_TEXTURE1_ARB);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
GL_TexEnv(GL_MODULATE);
/* if (currententity->shaderRGBAf[3]<1)
{
s->lightmaptexturenum = -1;
qglBlendFunc(GL_SRC_COLOR, GL_ONE);
}
*/
if (overbright != 1)
{
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_MODULATE);
qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, overbright); //this is the key
}
vi = -1;
for (; s ; s=s->texturechain)
{
if (!s->mesh) //urm.
continue;
if (s->mesh->numvertexes <= 1)
continue;
if (vi != s->lightmaptexturenum)
{
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);
}
qglClientActiveTextureARB(GL_TEXTURE0_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
if (overbright != 1)
{
qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1); //just in case
GL_TexEnv(GL_MODULATE);
}
qglDisable(GL_TEXTURE_2D);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
GL_SelectTexture(GL_TEXTURE0_ARB);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (tex->alphaed)
qglDisable(GL_ALPHA_TEST);
}
#endif
static void PPL_BaseChain_NoBump_2TMU_Overbright(msurface_t *s, texture_t *tex, vbo_t *vbo)
{ //doesn't merge surfaces, but tells gl to do each vertex arrayed surface individually, which means no vertex copying.
int vi;
glRect_t *theRect;
// int first = 0, last = 0;
qglDisableClientState(GL_COLOR_ARRAY);
qglEnableClientState(GL_VERTEX_ARRAY);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vbo->vboe);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vbocoord);
qglVertexPointer(3, GL_FLOAT, 0, vbo->coord);
if (tex->alphaed || currententity->shaderRGBAf[3]<1)
{
if (*tex->name == '{')
{
qglEnable(GL_ALPHA_TEST);
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
}
else
{
qglEnable(GL_BLEND);
GL_TexEnv(GL_MODULATE);
}
}
else
{
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
}
GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vbotexcoord);
qglTexCoordPointer(2, GL_FLOAT, 0, vbo->texcoord);
GL_SelectTexture(GL_TEXTURE1_ARB);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vbolmcoord);
qglTexCoordPointer(2, GL_FLOAT, 0, vbo->lmcoord);
GL_TexEnv(GL_MODULATE);
/* if (currententity->shaderRGBAf[3]<1)
{
s->lightmaptexturenum = -1;
qglBlendFunc(GL_SRC_COLOR, GL_ONE);
}
*/
if (overbright != 1)
{
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_MODULATE);
qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, overbright); //this is the key
}
// numidxs = 0;
vi = -1;
for (; s ; s=s->texturechain)
{
if (!s->mesh) //urm.
continue;
if (s->mesh->numvertexes <= 1)
continue;
if (vi != s->lightmaptexturenum)
{
// if (last != first)
// qglDrawElements(GL_TRIANGLES, last - first, GL_INDEX_TYPE, (index_t*)(first*sizeof(index_t)));
// last = first;
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);
}
qglDrawRangeElements(GL_TRIANGLES, s->mesh->vbofirstvert, s->mesh->vbofirstvert+s->mesh->numvertexes-1, s->mesh->numindexes, GL_INDEX_TYPE, vbo->indicies + s->mesh->vbofirstelement);
// if (s->mesh->vbofirstelement != last)
// {
// if (last != first)
// qglDrawElements(GL_TRIANGLES, last - first, GL_INDEX_TYPE, (index_t*)(first*sizeof(index_t)));
// first = s->mesh->vbofirstelement;
// last = first;
// }
// last += s->mesh->numindexes;
}
// if (last != first)
// qglDrawElements(GL_TRIANGLES, last - first, GL_INDEX_TYPE, (index_t*)(first*sizeof(index_t)));
//rebinding vbos is meant to be cheap, thankfully
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
if (overbright != 1)
{
qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1); //just in case
GL_TexEnv(GL_MODULATE);
}
//tmu 1 should be selected here
qglDisable(GL_TEXTURE_2D);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
GL_SelectTexture(GL_TEXTURE0_ARB);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
qglDisable(GL_TEXTURE_2D);
if (tex->alphaed)
qglDisable(GL_ALPHA_TEST);
}
/*
static void PPL_BaseChain_NoBump_2TMU_TEST(msurface_t *s, texture_t *tex)
{ //this was just me testing efficiency between arrays/glbegin.
int vi, i;
glRect_t *theRect;
PPL_EnableVertexArrays();
if (tex->alphaed)
{
qglEnable(GL_BLEND);
GL_TexEnv(GL_MODULATE);
}
else
{
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
}
qglCullFace(GL_BACK);
GL_MBind(GL_TEXTURE0_ARB, tex->gl_texturenum);
GL_SelectTexture(GL_TEXTURE1_ARB);
GL_TexEnv(GL_MODULATE);
vi = -1;
for (; s ; s=s->texturechain)
{
if (vi != s->lightmaptexturenum)
{
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);
}
qglBegin(GL_POLYGON);
switch(s->mesh->numvertexes)
{
default:
for (i = s->mesh->numvertexes-1; i >= 6; i--)
{
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[i][0], s->mesh->st_array[i][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[i][0], s->mesh->lmst_array[i][1]);
qglVertex3fv(s->mesh->xyz_array[i]);
}
case 6:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[5][0], s->mesh->st_array[5][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[5][0], s->mesh->lmst_array[5][1]);
qglVertex3fv(s->mesh->xyz_array[5]);
case 5:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[4][0], s->mesh->st_array[4][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[4][0], s->mesh->lmst_array[4][1]);
qglVertex3fv(s->mesh->xyz_array[4]);
case 4:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[3][0], s->mesh->st_array[3][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[3][0], s->mesh->lmst_array[3][1]);
qglVertex3fv(s->mesh->xyz_array[3]);
case 3:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[2][0], s->mesh->st_array[2][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[2][0], s->mesh->lmst_array[2][1]);
qglVertex3fv(s->mesh->xyz_array[2]);
case 2:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[1][0], s->mesh->st_array[1][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[1][0], s->mesh->lmst_array[1][1]);
qglVertex3fv(s->mesh->xyz_array[1]);
case 1:
qglMultiTexCoord2fARB(GL_TEXTURE0_ARB, s->mesh->st_array[0][0], s->mesh->st_array[0][1]);
qglMultiTexCoord2fARB(GL_TEXTURE1_ARB, s->mesh->lmst_array[0][0], s->mesh->lmst_array[0][1]);
qglVertex3fv(s->mesh->xyz_array[0]);
case 0:
break;
}
qglEnd();
}
qglDisable(GL_TEXTURE_2D);
GL_SelectTexture(GL_TEXTURE0_ARB);
}
*/
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->tn.bump);
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_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);
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_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;
}
}
PPL_GenerateArrays(s);
}
PPL_FlushArrays();
qglEnable(GL_BLEND);
qglBlendFunc(GL_DST_COLOR, GL_ZERO);
GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
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();
qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglDisable(GL_BLEND);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
qglDisable(GL_TEXTURE_2D);
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->tn.bump);
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->tn.base);
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);
GL_TexEnv(GL_MODULATE);
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)
{
//#define SMOOOOOTH //define this to calculate everything per-pixel as opposed to interpolating the halfdir
char *vert =
"varying vec2 tcbase;\n"
"varying vec2 tclm;\n"
"uniform vec3 vieworg;\n"
#ifdef SMOOOOOTH
"varying vec3 fragpos;\n"
"varying vec3 norm;\n"
#else
"uniform vec3 texr, texu, texf;\n"
"varying vec3 halfnorm;\n"
#endif
"void main (void)\n"
"{\n"
" gl_Position = ftransform();\n"
" tcbase = gl_MultiTexCoord0.xy;\n" //pass the texture coords straight through
" tclm = gl_MultiTexCoord1.xy;\n"
#ifdef SMOOOOOTH
" fragpos = vec3(gl_Vertex.xyz);\n"
"norm = gl_Normal;\n"
#else
" vec3 eye = normalize(vieworg - vec3(gl_Vertex.xyz));\n"
" vec3 halfdir = (eye + texf) / 2.0;\n"
" halfnorm.x = dot(texr, halfdir);\n" //put halfnorm into object space
" halfnorm.y = dot(texu, halfdir);\n"
" halfnorm.z = dot(texf, halfdir);\n"
#endif
"}\n"
;
/*
VectorSubtract(r_refdef.vieworg, v, eye);
VectorNormalize(eye);
VectorAdd(eye, (v+7), halfdir); //v+7 is the light dir (or plane normal)
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);
*/
char *frag =
"uniform sampler2D baset;\n"
"uniform sampler2D bumpt;\n"
"uniform sampler2D lightmapt;\n"
"uniform sampler2D deluxt;\n"
"uniform sampler2D speculart;\n"
"varying vec2 tcbase;\n"
"varying vec2 tclm;\n"
#ifdef SMOOOOOTH
"uniform vec3 vieworg;\n"
"varying vec3 fragpos;\n"
"uniform vec3 texr, texu, texf;\n"
#else
"varying vec3 halfnorm;\n"
#endif
"void main (void)\n"
"{\n"
" vec3 bases = vec3(texture2D(baset, tcbase));\n"
" vec3 bumps = vec3(texture2D(bumpt, tcbase)) * 2.0 - 1.0;\n"
" vec3 deluxs = vec3(texture2D(deluxt, tclm)) * 2.0 - 1.0;\n"
" vec3 lms = vec3(texture2D(lightmapt, tclm));\n"
" vec3 specs = vec3(texture2D(speculart, tcbase));\n"
" vec3 diff, spec;\n"
#ifdef SMOOOOOTH
" vec3 eye = normalize(vieworg - fragpos);\n"
" vec3 halfdir = (eye + texf) / 2.0;\n"
" vec3 halfnorm;\n"
" halfnorm.x = dot(texr, halfdir);\n" //put halfnorm into object space
" halfnorm.y = dot(texu, halfdir);\n"
" halfnorm.z = dot(texf, halfdir);\n"
#endif
" diff = bases * dot(bumps, deluxs);\n"
" float dv = dot(normalize(halfnorm), bumps);\n"
" spec = pow(dv, 16.0) * specs;\n"
" gl_FragColor = vec4((diff+spec)*lms, 1.0);\n"
"}\n"
;
ppl_specular_shader = GLSlang_CreateProgram(NULL, vert, frag);
if (ppl_specular_shader)
{
GLSlang_UseProgram(ppl_specular_shader);
qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "baset"), 0);
qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "bumpt"), 1);
qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "lightmapt"), 2);
qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "deluxt"), 3);
qglUniform1iARB(qglGetUniformLocationARB(ppl_specular_shader, "speculart"), 4);
ppl_specular_shader_vieworg = qglGetUniformLocationARB(ppl_specular_shader, "vieworg");
ppl_specular_shader_texr = qglGetUniformLocationARB(ppl_specular_shader, "texr");
ppl_specular_shader_texu = qglGetUniformLocationARB(ppl_specular_shader, "texu");
ppl_specular_shader_texf = qglGetUniformLocationARB(ppl_specular_shader, "texf");
GLSlang_UseProgram(0);
}
}
static void PPL_BaseChain_Specular_FP(msurface_t *s, texture_t *tex)
{
int vi;
glRect_t *theRect;
PPL_EnableVertexArrays();
GLSlang_UseProgram(ppl_specular_shader);
if (qglGetError())
Con_Printf("GL Error on shadow lighting\n");
GL_MBind(GL_TEXTURE0_ARB, tex->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
GL_MBind(GL_TEXTURE1_ARB, tex->tn.bump);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
// GL_MBind(GL_TEXTURE2_ARB, lightmap_textures[vi] );
// GL_MBind(GL_TEXTURE3_ARB, deluxmap_textures[vi] );
GL_MBind(GL_TEXTURE4_ARB, tex->tn.specular);
qglUniform3fvARB(ppl_specular_shader_vieworg, 1, r_refdef.vieworg);
if (qglGetError())
Con_Printf("GL Error early during PPL_BaseChain_Specular_FP\n");
vi = -1;
for (; s ; s=s->texturechain)
{
if (vi != s->lightmaptexturenum)
{
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;
}
}
qglUniform3fvARB(ppl_specular_shader_texr, 1, s->texinfo->vecs[0]);
qglUniform3fvARB(ppl_specular_shader_texu, 1, s->texinfo->vecs[1]);
if (s->flags & SURF_PLANEBACK)
qglUniform3fARB(ppl_specular_shader_texf, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]);
else
qglUniform3fvARB(ppl_specular_shader_texf, 1, s->plane->normal);
qglClientActiveTextureARB(GL_TEXTURE0_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglClientActiveTextureARB(GL_TEXTURE1_ARB);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
GLSlang_UseProgram(0);
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 specular lighting\n");
}
#endif
static vec_t wallcolour[4] = {0,0,0,1};
static vec_t floorcolour[4] = {0,0,0,1};
static int walltexture = 0;
static int floortexture = 0;
static qboolean simpletextures = false;
//single textured.
void GLR_Wallcolour_Callback(struct cvar_s *var, char *oldvalue)
{
SCR_StringToRGB(var->string, wallcolour, 255);
}
void GLR_Floorcolour_Callback(struct cvar_s *var, char *oldvalue)
{
SCR_StringToRGB(var->string, floorcolour, 255);
}
void GLR_Walltexture_Callback(struct cvar_s *var, char *oldvalue)
{
if (!var->string[0])
{
walltexture = 0;
if (!floortexture)
simpletextures = false;
return;
}
walltexture = Mod_LoadHiResTexture(var->string, NULL, true, false, true);
if (walltexture)
simpletextures = true;
}
void GLR_Floortexture_Callback(struct cvar_s *var, char *oldvalue)
{
if (!var->string[0])
{
floortexture = 0;
if (!walltexture)
simpletextures = false;
return;
}
floortexture = Mod_LoadHiResTexture(var->string, NULL, true, false, true);
if (floortexture)
simpletextures = true;
}
static void PPL_BaseChain_Flat(msurface_t *first)
{
msurface_t *s;
int iswall = -1;
int vi=-10;
glRect_t *theRect;
if (!r_lightmapintensity)
{ //these are bad. :(
PPL_EnableVertexArrays();
qglColor4f(0,0,0,1);
qglDisable(GL_TEXTURE_2D); //texturing? who wants texturing?!?!
for (s = first; s ; s=s->texturechain)
PPL_GenerateArrays(s);
PPL_FlushArrays();
qglEnable(GL_TEXTURE_2D);
return;
}
PPL_EnableVertexArrays();
GL_TexEnv(GL_MODULATE);
for (s = first; s ; s=s->texturechain)
{
if (s->mesh->numvertexes < 3) continue;
if (vi != s->lightmaptexturenum)
{
if (vi < 0)
{
qglEnable(GL_TEXTURE_2D);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
vi = s->lightmaptexturenum;
if (s->lightmaptexturenum < 0)
{
qglDisable(GL_TEXTURE_2D);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
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] <= 0.5)
{
if (iswall != 0)
{
iswall=0;
qglColor4fv(wallcolour);
}
}
else if (iswall != 1)
{
iswall=1;
qglColor4fv(floorcolour);
}
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->lmst_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawRangeElements(GL_TRIANGLES, 0, s->mesh->numvertexes, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
qglColor3f(1,1,1);
}
static int nprtextures[10];
void GLR_Drawflat_Callback(struct cvar_s *var, char *oldvalue)
{
int i;
if (var->value != 2)
return;
for (i = 0; i < sizeof(nprtextures)/sizeof(nprtextures[0]); i++)
{
nprtextures[i] = Mod_LoadHiResTexture(va("sketch%i", i+1), "sketch", true, false, false);
if (!nprtextures[i])
{
int data[128*128];
FILE *file;
unsigned char *f;
int p;
file = fopen(va("nprtextures/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));
nprtextures[i] = GL_LoadTexture32 (va("textures/tex%i_3_128_128.raw", i+1), 128, 128, data, true, false);
}
fclose(file);
}
}
}
}
static void PPL_BaseChain_SimpleTexture(msurface_t *first)
{
msurface_t *s;
int vi=-10;
int iswall;
int oldwall=-1;
glRect_t *theRect;
GL_SelectTexture(GL_TEXTURE0_ARB);
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);
for (s = first; s ; s=s->texturechain)
{
if (s->plane->normal[2] <= 0.5)
iswall = 1;
else
iswall = 0;
if (vi != s->lightmaptexturenum || iswall != oldwall)
{
PPL_FlushArrays();
vi = s->lightmaptexturenum;
oldwall = iswall;
if (iswall)
{
GL_MBind(GL_TEXTURE0_ARB, walltexture);
qglColor4fv(wallcolour);
}
else
{
GL_MBind(GL_TEXTURE0_ARB, floortexture);
qglColor4fv(floorcolour);
}
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);
qglDisableClientState(GL_VERTEX_ARRAY);
qglDisable(GL_TEXTURE_2D);
qglColor3f(1,1,1);
GL_SelectTexture(GL_TEXTURE0_ARB);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
qglDisableClientState(GL_VERTEX_ARRAY);
qglEnable(GL_TEXTURE_2D);
qglColor3f(1,1,1);
}
static void PPL_BaseChain_NPR_Sketch(msurface_t *first)
{
msurface_t *s;
int vi=-10;
int i;
glRect_t *theRect;
GL_SelectTexture(GL_TEXTURE0_ARB);
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, nprtextures[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);
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();
}
}
}
qglEnable(GL_TEXTURE_2D);
}
static void PPL_BaseTextureChain(msurface_t *first)
{
texture_t *ot = first->texinfo->texture;
texture_t *t;
#ifdef Q3SHADERS
shader_t *shader;
#endif
if (r_drawflat.value||!r_lightmapintensity)
{
if (r_drawflat.value == 2)
{
if (gl_mtexarbable >= 2) //shiesh!.
{
PPL_BaseChain_NPR_Sketch(first);
return;
}
}
else if (!(first->flags & SURF_NOFLAT))
{
if (gl_mtexarbable >= 2 && simpletextures)
PPL_BaseChain_SimpleTexture(first);
else
PPL_BaseChain_Flat(first); //who cares about texture? :/
return;
}
}
t = R_TextureAnimation (ot);
#ifdef Q3SHADERS
shader = t->shader;
if (shader)// && shader->style != SSTYLE_LIGHTMAPPED)
{
meshbuffer_t mb;
msurface_t *s;
int vi=-1;
int redraw = false;
int dlb;
glRect_t *theRect;
if (shader->flags & SHADER_FLARE )
{
dlight_t *dl;
while(first)
{ //a quick hack to convert to a dlight
dl = CL_AllocDlight(0);
VectorCopy(first->mesh->xyz_array[0], dl->origin);
dl->color[0] = 0.2;
dl->color[1] = 0.2;
dl->color[2] = 0.2;
dl->radius = 50;
//flashblend only
dl->flags = LFLAG_ALLOW_FLASH;
first = first->texturechain;
}
return;
}
if (!varrayactive)
R_IBrokeTheArrays();
mb.entity = &r_worldentity;
mb.shader = shader;
mb.mesh = NULL;
mb.fog = NULL;
mb.infokey = -2;
if (first->dlightframe == r_framecount)
mb.dlightbits = first->dlightbits;
else
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 (gl_bump.value)
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->mesh)
{
if (s->dlightframe == r_framecount)
dlb = s->dlightbits;
else
dlb = 0;
redraw = mb.dlightbits != dlb || mb.fog != s->fog || mb.infokey != vi||R_MeshWillExceed(s->mesh);
if (redraw)
{
if (mb.mesh)
R_RenderMeshBuffer ( &mb, false );
redraw = false;
}
mb.infokey = vi;
mb.mesh = s->mesh;
mb.fog = s->fog;
mb.dlightbits = dlb;
R_PushMesh(s->mesh, mb.shader->features);
}
}
}
if (mb.mesh)
R_RenderMeshBuffer ( &mb, false );
return;
}
#endif
qglEnable(GL_TEXTURE_2D);
if (first->flags & SURF_DRAWTURB)
{
GL_DisableMultitexture();
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
GL_Bind (t->tn.base);
for (; first ; first=first->texturechain)
EmitWaterPolys (first, currententity->shaderRGBAf[3]);
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->tn.bump)
{
if (gl_mtexarbable>=4)
{
if (t->tn.specular && gl_specular.value)
{
if (ppl_specular_shader)
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_TEST(first, t);
// PPL_BaseChain_NoBump_2TMU(first, t);
PPL_BaseChain_NoBump_2TMU_Overbright(first, t, &ot->vbo);
}
}
}
static void PPL_FullBrightTextureChain(msurface_t *first)
{
texture_t *ot = first->texinfo->texture;
texture_t *t;
msurface_t *s;
t = R_TextureAnimation (ot);
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_GenerateDetailArrays(s);
}
PPL_FlushArrays();
}
if (t->tn.fullbright && r_fb_bmodels.value && cls.allow_luma)
{
GL_Bind(t->tn.fullbright);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE);
if (gl_mylumassuck.value)
qglEnable(GL_ALPHA_TEST);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ot->vbo.vboe);
qglEnableClientState(GL_VERTEX_ARRAY);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, ot->vbo.vbocoord);
qglVertexPointer(3, GL_FLOAT, 0, ot->vbo.coord);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, ot->vbo.vbotexcoord);
qglTexCoordPointer(2, GL_FLOAT, 0, ot->vbo.texcoord);
for (s = first; s ; s=s->texturechain)
{
qglDrawRangeElements(GL_TRIANGLES, s->mesh->vbofirstvert, s->mesh->vbofirstvert+s->mesh->numvertexes-1, s->mesh->numindexes, GL_INDEX_TYPE, ot->vbo.indicies + s->mesh->vbofirstelement);
}
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
if (gl_mylumassuck.value)
qglDisable(GL_ALPHA_TEST);
}
}
//requires multitexture
void PPL_BaseTextures(model_t *model)
{
int i;
msurface_t *s;
texture_t *t;
currententity = &r_worldentity;
GL_DoSwap();
currententity->shaderRGBAf[0] = 1;
currententity->shaderRGBAf[1] = 1;
currententity->shaderRGBAf[2] = 1;
currententity->shaderRGBAf[3] = 1;
qglDisable(GL_BLEND);
qglDisable(GL_ALPHA_TEST);
qglColor4fv(currententity->shaderRGBAf);
// qglDepthFunc(GL_LESS);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglShadeModel(GL_FLAT);
overbright = 1;
if (gl_overbright_all.value || (model->engineflags & MDLF_NEEDOVERBRIGHT))
{
if (gl_overbright.value>=2)
overbright = 4;
else if (gl_overbright.value)
overbright = 2;
}
currentmodel = model;
if (model == cl.worldmodel && skytexturenum>=0)
{
t = model->textures[skytexturenum];
if (t)
{
s = t->texturechain;
if (s)
{
t->texturechain = NULL;
GL_DrawSkyChain (s);
}
}
}
if (mirrortexturenum>=0 && model == cl.worldmodel && r_mirroralpha.value != 1.0)
{
t = model->textures[mirrortexturenum];
if (t)
{
s = t->texturechain;
if (s)
{
t->texturechain = NULL;
if (!r_inmirror)
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 cvar_t r_drawflat_nonworldmodel;
extern msurface_t *r_alpha_surfaces;
int i, k;
int shift;
int sflags;
model_t *model;
msurface_t *s;
msurface_t *chain = NULL;
qglPushMatrix();
R_RotateForEntity(e);
currentmodel = model = e->model;
s = model->surfaces+model->firstmodelsurface;
shift = GLR_LightmapShift(currentmodel);
if (currententity->drawflags & DRF_TRANSLUCENT)
currententity->shaderRGBAf[3]=0.5;
if ((currententity->drawflags & MLS_ABSLIGHT) == MLS_ABSLIGHT)
{
currententity->shaderRGBAf[0] =
currententity->shaderRGBAf[1] =
currententity->shaderRGBAf[2] = currententity->abslight/255.0f;
}
if (currententity->shaderRGBAf[3]<1)
{
GL_TexEnv(GL_MODULATE);
qglEnable(GL_BLEND);
}
else
{
GL_TexEnv(GL_REPLACE);
qglDisable(GL_BLEND);
}
qglColor4fv(currententity->shaderRGBAf);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// calculate dynamic lighting for bmodel if it's not an
// instanced model
if (model->fromgame != fg_quake3)
{
if (currentmodel->nummodelsurfaces != 0 && r_dynamic.value)
{
for (k=0 ; k<dlights_software ; k++)
{
if (!cl_dlights[k].radius)
continue;
if (!(cl_dlights[k].flags & LFLAG_ALLOW_LMHACK))
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, shift);
}
if (!r_drawflat_nonworldmodel.value && (!cl.worldmodel->submodels || model->submodels != cl.worldmodel->submodels))
sflags = SURF_NOFLAT;
else
sflags = 0;
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
{
if (s->texinfo->flags & (SURF_TRANS33 | 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->flags |= sflags;
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();
}
#ifdef Q3SHADERS
void R_DrawLightning(entity_t *e)
{
vec3_t v;
vec3_t dir, cr;
float scale = e->scale;
float length;
vec3_t points[4];
vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
index_t indexarray[6] = {0, 1, 2, 0, 2, 3};
mesh_t mesh;
meshbuffer_t mb;
if (!e->forcedshader)
return;
if (!scale)
scale = 10;
VectorSubtract(e->origin, e->oldorigin, dir);
length = Length(dir);
//this seems to be about right.
texcoords[2][0] = length/128;
texcoords[3][0] = length/128;
VectorSubtract(r_refdef.vieworg, e->origin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->origin, -scale/2, cr, points[0]);
VectorMA(e->origin, scale/2, cr, points[1]);
VectorSubtract(r_refdef.vieworg, e->oldorigin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->oldorigin, scale/2, cr, points[2]);
VectorMA(e->oldorigin, -scale/2, cr, points[3]);
mesh.xyz_array = points;
mesh.indexes = indexarray;
mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]);
mesh.colors_array = NULL;
mesh.lmst_array = NULL;
mesh.normals_array = NULL;
mesh.numvertexes = 4;
mesh.st_array = texcoords;
mb.entity = e;
mb.mesh = &mesh;
mb.shader = e->forcedshader;
mb.infokey = 0;
mb.fog = NULL;
mb.infokey = currententity->keynum;
mb.dlightbits = 0;
R_IBrokeTheArrays();
R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED);
R_RenderMeshBuffer ( &mb, false );
}
void R_DrawRailCore(entity_t *e)
{
vec3_t v;
vec3_t dir, cr;
float scale = e->scale;
float length;
mesh_t mesh;
meshbuffer_t mb;
vec3_t points[4];
vec2_t texcoords[4] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
index_t indexarray[6] = {0, 1, 2, 0, 2, 3};
int colors[4];
qbyte colorsb[4];
if (!e->forcedshader)
return;
if (!scale)
scale = 10;
VectorSubtract(e->origin, e->oldorigin, dir);
length = Length(dir);
//this seems to be about right.
texcoords[2][0] = length/128;
texcoords[3][0] = length/128;
VectorSubtract(r_refdef.vieworg, e->origin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->origin, -scale/2, cr, points[0]);
VectorMA(e->origin, scale/2, cr, points[1]);
VectorSubtract(r_refdef.vieworg, e->oldorigin, v);
CrossProduct(v, dir, cr);
VectorNormalize(cr);
VectorMA(e->oldorigin, scale/2, cr, points[2]);
VectorMA(e->oldorigin, -scale/2, cr, points[3]);
colorsb[0] = e->shaderRGBAf[0]*255;
colorsb[1] = e->shaderRGBAf[1]*255;
colorsb[2] = e->shaderRGBAf[2]*255;
colorsb[3] = e->shaderRGBAf[3]*255;
colors[0] = colors[1] = colors[2] = colors[3] = *(int*)colorsb;
mesh.xyz_array = points;
mesh.indexes = indexarray;
mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]);
mesh.colors_array = (byte_vec4_t*)colors;
mesh.lmst_array = NULL;
mesh.normals_array = NULL;
mesh.numvertexes = 4;
mesh.st_array = texcoords;
mb.entity = e;
mb.mesh = &mesh;
mb.shader = e->forcedshader;
mb.infokey = 0;
mb.fog = NULL;
mb.infokey = currententity->keynum;
mb.dlightbits = 0;
R_IBrokeTheArrays();
R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED | MF_COLORS);
R_RenderMeshBuffer ( &mb, false );
}
#endif
void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );
void PerpendicularVector( vec3_t dst, const vec3_t src );
void R_DrawBeam( entity_t *e )
{
#define NUM_BEAM_SEGS 6
int i;
float r, g, b;
vec3_t perpvec;
vec3_t direction, normalized_direction;
vec3_t points[NUM_BEAM_SEGS*2];
vec3_t oldorigin, origin;
float scale;
oldorigin[0] = e->oldorigin[0];
oldorigin[1] = e->oldorigin[1];
oldorigin[2] = e->oldorigin[2];
origin[0] = e->origin[0];
origin[1] = e->origin[1];
origin[2] = e->origin[2];
normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
if ( VectorNormalize( normalized_direction ) == 0 )
return;
PerpendicularVector( perpvec, normalized_direction );
scale = e->scale;
if (!scale)
scale = e->framestate.g[FS_REG].frame[0];
if (!scale)
scale = 6;
VectorScale( perpvec, scale / 2, perpvec );
for ( i = 0; i < 6; i++ )
{
RotatePointAroundVector( points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
VectorAdd( points[i], origin, points[i] );
VectorAdd( points[i], direction, points[i+NUM_BEAM_SEGS] );
}
#ifdef Q3SHADERS
if (e->forcedshader)
{
index_t indexarray[NUM_BEAM_SEGS*6];
vec2_t texcoords[NUM_BEAM_SEGS*2];
mesh_t mesh;
meshbuffer_t mb;
mesh.xyz_array = points;
mesh.indexes = indexarray;
mesh.numindexes = sizeof(indexarray)/sizeof(indexarray[0]);
mesh.colors_array = NULL;
mesh.lmst_array = NULL;
mesh.normals_array = NULL;
mesh.numvertexes = NUM_BEAM_SEGS*2;
mesh.st_array = texcoords;
mb.entity = e;
mb.mesh = &mesh;
mb.shader = e->forcedshader;
mb.infokey = 0;
mb.fog = NULL;
mb.infokey = currententity->keynum;
mb.dlightbits = 0;
for (i = 0; i < NUM_BEAM_SEGS; i++)
{
indexarray[i*6+0] = i+0;
indexarray[i*6+1] = (i+1)%NUM_BEAM_SEGS;
indexarray[i*6+2] = indexarray[i*6+1]+NUM_BEAM_SEGS;
indexarray[i*6+3] = indexarray[i*6+0];
indexarray[i*6+4] = indexarray[i*6+2];
indexarray[i*6+5] = i+0+NUM_BEAM_SEGS;
texcoords[i][1] = (float)i/NUM_BEAM_SEGS+0.35;
texcoords[i][0] = 0;
texcoords[i+NUM_BEAM_SEGS][1] = (float)i/NUM_BEAM_SEGS+0.35;
texcoords[i+NUM_BEAM_SEGS][0] = 1;
}
R_IBrokeTheArrays();
R_PushMesh(&mesh, mb.shader->features | MF_NONBATCHED);
R_RenderMeshBuffer ( &mb, false );
}
else
#endif
{
qglDisable( GL_TEXTURE_2D );
qglEnable( GL_BLEND );
qglDepthMask( GL_FALSE );
qglDisable(GL_ALPHA_TEST);
r = ( d_8to24rgbtable[e->skinnum & 0xFF] ) & 0xFF;
g = ( d_8to24rgbtable[e->skinnum & 0xFF] >> 8 ) & 0xFF;
b = ( d_8to24rgbtable[e->skinnum & 0xFF] >> 16 ) & 0xFF;
r *= e->shaderRGBAf[0]/255.0F;
g *= e->shaderRGBAf[1]/255.0F;
b *= e->shaderRGBAf[2]/255.0F;
qglColor4f( r, g, b, e->shaderRGBAf[3] );
qglBegin( GL_TRIANGLE_STRIP );
for ( i = 0; i < NUM_BEAM_SEGS; i++ )
{
qglVertex3fv( points[i] );
qglVertex3fv( points[i+NUM_BEAM_SEGS] );
qglVertex3fv( points[((i+1)%NUM_BEAM_SEGS)] );
qglVertex3fv( points[((i+1)%NUM_BEAM_SEGS)+NUM_BEAM_SEGS] );
}
qglEnd();
qglEnable( GL_TEXTURE_2D );
qglDisable( GL_BLEND );
qglDepthMask( GL_TRUE );
}
}
void PPL_DrawEnt(entity_t *e, void *parm)
{
qglEnd();
currententity = e;
qglDepthMask(1);
qglDisable(GL_POLYGON_OFFSET_FILL);
R_IBrokeTheArrays();
R_DrawGAliasModel (currententity);
P_FlushRenderer();
qglBegin(GL_QUADS);
}
void PPL_DelayBaseBModelTextures(int count, void **e, void *parm)
{
while(count--)
{
currententity = *e++;
qglDepthFunc ( gldepthfunc );
qglEnable(GL_DEPTH_TEST);
qglDepthMask(1);
PPL_BaseBModelTextures (currententity);
}
}
void PPL_BaseEntTextures(void)
{
extern model_t *currentmodel;
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 (!PPL_ShouldDraw())
continue;
if (currententity->rtype)
continue;
if (currententity->flags & Q2RF_BEAM)
{
R_DrawBeam(currententity);
continue;
}
if (!currententity->model)
continue;
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
{
if (currententity->model->engineflags & MDLF_ENGULPHS)
{
if (gl_part_flame.value)
continue;
}
}
if (currententity->model->engineflags & MDLF_NOTREPLACEMENTS)
{
if (currententity->model->fromgame != fg_quake || currententity->model->type != mod_alias)
if (!ruleset_allow_sensative_texture_replacements.value)
continue;
}
switch (currententity->model->type)
{
//FIXME: We want to depth sort with particles, but we also want depth. :(
//Until then, we have broken model lighting.
case mod_alias:
R_DrawGAliasModel (currententity);
// if (currententity->flags & Q2RF_WEAPONMODEL)
// RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, r_refdef.vieworg);
// else
// RQ_AddDistReorder(PPL_DrawEnt, currententity, NULL, currententity->origin);
break;
case mod_brush:
if (currententity->shaderRGBAf[3] < 1)
RQ_AddDistReorder(PPL_DelayBaseBModelTextures, currententity, NULL, currententity->origin);
else
{
qglDepthFunc ( gldepthfunc );
qglEnable(GL_DEPTH_TEST);
qglDepthMask(1);
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)
{
int vi;
float *v, *stw;
surfvertexarray_t *out;
vec3_t lightdir;
float dist;
shadowlightfaces++;
v = surf->mesh->xyz_array[0];
stw = surf->mesh->st_array[0];
out = &varray_v[0];
for (vi=0 ; vi<surf->mesh->numvertexes ; vi++, v+=3, stw+=2, out++)
{
out->stw[0] = stw[0];
out->stw[1] = stw[1];
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);
out->stl[0] = colour[0]*dist;
out->stl[1] = colour[1]*dist;
out->stl[2] = colour[2]*dist;
out->ncm[0] = DotProduct(lightdir, surf->texinfo->vecs[0]);
out->ncm[1] = -DotProduct(lightdir, surf->texinfo->vecs[1]);
if (surf->flags & SURF_PLANEBACK)
out->ncm[2] = -DotProduct(lightdir, surf->plane->normal);
else
out->ncm[2] = DotProduct(lightdir, surf->plane->normal);
}
}
//flags
enum{
PERMUTATION_GENERIC = 0,
PERMUTATION_BUMPMAP = 1,
PERMUTATION_SPECULAR = 2,
PERMUTATION_BUMP_SPEC = 3,
PERMUTATION_OFFSET = 4,
PERMUTATION_OFFSET_BUMP = 5,
PERMUTATION_OFFSET_SPEC = 6,
PERMUTATION_OFFSET_BUMP_SPEC = 7,
PERMUTATIONS
};
int ppl_light_shader[PERMUTATIONS];
int ppl_light_shader_eyeposition[PERMUTATIONS];
int ppl_light_shader_lightposition[PERMUTATIONS];
int ppl_light_shader_lightcolour[PERMUTATIONS];
int ppl_light_shader_lightradius[PERMUTATIONS];
int ppl_light_shader_offset_scale[PERMUTATIONS];
int ppl_light_shader_offset_bias[PERMUTATIONS];
void PPL_CreateLightTexturesProgram(void)
{
int i;
char *permutation[PERMUTATIONS] = {
"",
"#define BUMP\n",
"#define SPECULAR\n",
"#define SPECULAR\n#define BUMP\n",
"#define USEOFFSETMAPPING\n",
"#define USEOFFSETMAPPING\n#define BUMP\n",
"#define USEOFFSETMAPPING\n#define SPECULAR\n",
"#define USEOFFSETMAPPING\n#define SPECULAR\n#define BUMP\n"
};
char *vert =
"varying vec2 tcbase;\n"
"uniform vec3 texr, texu, texf;\n"
"varying vec3 LightVector;\n"
"uniform vec3 LightPosition;\n"
"#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n"
"uniform vec3 EyePosition;\n"
"varying vec3 EyeVector;\n"
"#endif\n"
"void main (void)\n"
"{\n"
" gl_Position = ftransform();\n"
" tcbase = gl_MultiTexCoord0.xy;\n" //pass the texture coords straight through
" vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
" LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
" LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
" LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
"#if defined(SPECULAR)||defined(USEOFFSETMAPPING)\n"
" vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;\n"
" EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);\n"
" EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);\n"
" EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);\n"
"#endif\n"
"}\n"
;
char *frag =
"uniform sampler2D baset;\n"
"#if defined(BUMP) || defined(SPECULAR) || defined(USEOFFSETMAPPING)\n"
"uniform sampler2D bumpt;\n"
"#endif\n"
"#ifdef SPECULAR\n"
"uniform sampler2D speculart;\n"
"#endif\n"
"varying vec2 tcbase;\n"
"varying vec3 LightVector;\n"
"uniform float lightradius;\n"
"uniform vec3 LightColour;\n"
"#if defined(SPECULAR) || defined(USEOFFSETMAPPING)\n"
"varying vec3 EyeVector;\n"
"#endif\n"
"#ifdef USEOFFSETMAPPING\n"
"uniform float OffsetMapping_Scale;\n"
"uniform float OffsetMapping_Bias;\n"
"#endif\n"
"void main (void)\n"
"{\n"
"#ifdef USEOFFSETMAPPING\n"
" // this is 3 sample because of ATI Radeon 9500-9800/X300 limits\n"
" vec2 OffsetVector = normalize(EyeVector).xy * vec2(-0.333, 0.333);\n"
" vec2 TexCoordOffset = tcbase + OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, tcbase).w);\n"
" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n"
" TexCoordOffset += OffsetVector * (OffsetMapping_Bias + OffsetMapping_Scale * texture2D(bumpt, TexCoordOffset).w);\n"
"#define tcbase TexCoordOffset\n"
"#endif\n"
"#ifdef BUMP\n"
" vec3 bases = vec3(texture2D(baset, tcbase));\n"
"#else\n"
" vec3 diff = vec3(texture2D(baset, tcbase));\n"
"#endif\n"
"#if defined(BUMP) || defined(SPECULAR)\n"
" vec3 bumps = vec3(texture2D(bumpt, tcbase)) * 2.0 - 1.0;\n"
"#endif\n"
"#ifdef SPECULAR\n"
" vec3 specs = vec3(texture2D(speculart, tcbase));\n"
"#endif\n"
" vec3 nl = normalize(LightVector);\n"
" float colorscale = max(1.0 - dot(LightVector, LightVector)/(lightradius*lightradius), 0.0);\n"
"#ifdef BUMP\n"
" vec3 diff;\n"
" diff = bases * max(dot(bumps, nl), 0.0);\n"
"#endif\n"
"#ifdef SPECULAR\n"
" vec3 halfdir = (normalize(EyeVector) + normalize(LightVector))/2.0;\n"
" float dv = dot(halfdir, bumps);\n"
" diff += pow(dv, 8.0) * specs;\n"
"#endif\n"
" gl_FragColor.rgb = diff*colorscale*LightColour;\n"
"}\n"
;
for (i = 0; i < PERMUTATIONS; i++)
{
ppl_light_shader[i] = GLSlang_CreateProgram(permutation[i], vert, frag);
if (ppl_light_shader[i])
{
GLSlang_UseProgram(ppl_light_shader[i]);
qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "baset"), 0);
qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "bumpt"), 1);
qglUniform1iARB(qglGetUniformLocationARB(ppl_light_shader[i], "speculart"), 2);
ppl_light_shader_eyeposition[i] = qglGetUniformLocationARB(ppl_light_shader[i], "EyePosition");
ppl_light_shader_lightposition [i]= qglGetUniformLocationARB(ppl_light_shader[i], "LightPosition");
ppl_light_shader_lightcolour[i] = qglGetUniformLocationARB(ppl_light_shader[i], "LightColour");
ppl_light_shader_lightradius[i] = qglGetUniformLocationARB(ppl_light_shader[i], "lightradius");
ppl_light_shader_offset_scale[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Scale");
ppl_light_shader_offset_bias[i] = qglGetUniformLocationARB(ppl_light_shader[i], "OffsetMapping_Bias");
GLSlang_UseProgram(0);
}
}
};
void PPL_LightTexturesFP_Cached(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour)
{
int i, j;
texture_t *t;
msurface_t *s;
int p, lp=-1;
extern cvar_t gl_specular;
shadowmesh_t *shm = light->worldshadowmesh;
vec3_t relativelightorigin;
vec3_t relativeeyeorigin;
if (qglGetError())
Con_Printf("GL Error before lighttextures\n");
VectorSubtract(light->origin, modelorigin, relativelightorigin);
VectorSubtract(r_refdef.vieworg, modelorigin, relativeeyeorigin);
qglEnable(GL_BLEND);
GL_TexEnv(GL_MODULATE);
qglBlendFunc(GL_ONE, GL_ONE);
qglDisableClientState(GL_COLOR_ARRAY);
if (qglGetError())
Con_Printf("GL Error early in lighttextures\n");
for (j=0 ; j<shm->numsurftextures ; j++)
{
if (!shm->litsurfs[j].count)
continue;
s = shm->litsurfs[j].s[0];
t = s->texinfo->texture;
t = R_TextureAnimation (t);
for (i=0 ; i<shm->litsurfs[j].count ; i++)
{
s = shm->litsurfs[j].s[i];
if (s->visframe != r_framecount)
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;
}
// if ((s->flags & SURF_DRAWTURB) && r_wateralphaval != 1.0)
// continue; // draw translucent water later
p = 0;
if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
p |= PERMUTATION_BUMPMAP;
if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
p |= PERMUTATION_SPECULAR;
if (r_shadow_glsl_offsetmapping.value && t->tn.bump && ppl_light_shader[p|PERMUTATION_OFFSET])
p |= PERMUTATION_OFFSET;
if (p != lp)
{
lp = p;
GLSlang_UseProgram(ppl_light_shader[p]);
if (ppl_light_shader_eyeposition[p] != -1)
qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin);
qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin);
qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour);
qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius);
if (ppl_light_shader_offset_scale[p]!=-1)
qglUniform1fARB(ppl_light_shader_offset_scale[p], r_shadow_glsl_offsetmapping_scale.value);
if (ppl_light_shader_offset_bias[p]!=-1)
qglUniform1fARB(ppl_light_shader_offset_bias[p], r_shadow_glsl_offsetmapping_bias.value);
}
if (p & PERMUTATION_BUMPMAP)
GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
if (p & PERMUTATION_SPECULAR)
GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, s->texinfo->vecs[0][0], s->texinfo->vecs[0][1], s->texinfo->vecs[0][2]);
qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, -s->texinfo->vecs[1][0], -s->texinfo->vecs[1][1], -s->texinfo->vecs[1][2]);
if (s->flags & SURF_PLANEBACK)
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]);
else
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
}
GLSlang_UseProgram(0);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (qglGetError())
Con_Printf("GL Error during lighttextures\n");
}
void PPL_LightTexturesFP(model_t *model, vec3_t modelorigin, dlight_t *light, vec3_t colour)
{
int i;
texture_t *t;
msurface_t *s;
int p, lp=-1;
extern cvar_t gl_specular;
vec3_t relativelightorigin;
vec3_t relativeeyeorigin;
if (qglGetError())
Con_Printf("GL Error before lighttextures\n");
VectorSubtract(light->origin, modelorigin, relativelightorigin);
VectorSubtract(r_refdef.vieworg, modelorigin, relativeeyeorigin);
qglEnable(GL_BLEND);
GL_TexEnv(GL_MODULATE);
qglBlendFunc(GL_ONE, GL_ONE);
qglDisableClientState(GL_COLOR_ARRAY);
if (qglGetError())
Con_Printf("GL Error early in lighttextures\n");
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
t = R_TextureAnimation (t);
p = 0;
if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
p |= PERMUTATION_BUMPMAP;
if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
p |= PERMUTATION_SPECULAR;
if (r_shadow_glsl_offsetmapping.value && t->tn.bump && ppl_light_shader[p|PERMUTATION_OFFSET])
p |= PERMUTATION_OFFSET;
if (p != lp)
{
lp = p;
GLSlang_UseProgram(ppl_light_shader[p]);
if (ppl_light_shader_eyeposition[p] != -1)
qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin);
qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin);
qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour);
qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius);
if (ppl_light_shader_offset_scale[p]!=-1)
qglUniform1fARB(ppl_light_shader_offset_scale[p], r_shadow_glsl_offsetmapping_scale.value);
if (ppl_light_shader_offset_bias[p]!=-1)
qglUniform1fARB(ppl_light_shader_offset_bias[p], r_shadow_glsl_offsetmapping_bias.value);
}
if (p & PERMUTATION_BUMPMAP)
GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
if (p & PERMUTATION_SPECULAR)
GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (; s; s=s->texturechain)
{
if (s->shadowframe != r_shadowframe)
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;
}
qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, s->texinfo->vecs[0][0], s->texinfo->vecs[0][1], s->texinfo->vecs[0][2]);
qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, -s->texinfo->vecs[1][0], -s->texinfo->vecs[1][1], -s->texinfo->vecs[1][2]);
if (s->flags & SURF_PLANEBACK)
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]);
else
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
}
GLSlang_UseProgram(0);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (qglGetError())
Con_Printf("GL Error during lighttextures\n");
}
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;
if (ppl_light_shader[0])
{
if (model == cl.worldmodel && light->worldshadowmesh)
PPL_LightTexturesFP_Cached(model, modelorigin, light, colour);
else
PPL_LightTexturesFP(model, modelorigin, light, colour);
return;
}
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 = R_TextureAnimation (t);
qglEnableClientState(GL_COLOR_ARRAY);
qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
if (t->tn.bump && gl_mtexarbable>3)
{
GL_MBind(GL_TEXTURE0_ARB, t->tn.bump);
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->tn.bump); //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->tn.base);
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 (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);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
varray_ic = 0;
varray_vc = 0;
}
}
}
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_LightBModelTexturesFP(entity_t *e, dlight_t *light, vec3_t colour)
{
int i;
texture_t *t;
msurface_t *s;
model_t *model = e->model;
texture_t *tnum = NULL;
int p, lp = -1;
vec3_t relativelightorigin;
vec3_t relativeeyeorigin;
if (qglGetError())
Con_Printf("GL Error before lighttextures\n");
//Fixme: rotate
VectorSubtract(light->origin, e->origin, relativelightorigin);
VectorSubtract(r_refdef.vieworg, e->origin, relativeeyeorigin);
qglEnable(GL_BLEND);
qglBlendFunc(GL_ONE, GL_ONE);
if (qglGetError())
Con_Printf("GL Error early in lighttextures\n");
for (s = model->surfaces+model->firstmodelsurface,i = 0; i < model->nummodelsurfaces; i++, s++)
{
if (tnum != s->texinfo->texture)
{
tnum = s->texinfo->texture;
t = R_TextureAnimation (tnum);
p = 0;
if (t->tn.bump && ppl_light_shader[p|PERMUTATION_BUMPMAP])
p |= PERMUTATION_BUMPMAP;
if (gl_specular.value && t->tn.specular && ppl_light_shader[p|PERMUTATION_SPECULAR])
p |= PERMUTATION_SPECULAR;
if (p != lp)
{
lp = p;
GLSlang_UseProgram(ppl_light_shader[p]);
if (ppl_light_shader_eyeposition[p] != -1)
qglUniform3fvARB(ppl_light_shader_eyeposition[p], 1, relativeeyeorigin);
qglUniform3fvARB(ppl_light_shader_lightposition[p], 1, relativelightorigin);
qglUniform3fvARB(ppl_light_shader_lightcolour[p], 1, colour);
qglUniform1fARB(ppl_light_shader_lightradius[p], light->radius);
}
GL_MBind(GL_TEXTURE0_ARB, t->tn.base);
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
GL_MBind(GL_TEXTURE1_ARB, t->tn.bump);
GL_MBind(GL_TEXTURE2_ARB, t->tn.specular);
GL_SelectTexture(GL_TEXTURE0_ARB);
}
qglMultiTexCoord3fARB(GL_TEXTURE1_ARB, -s->texinfo->vecs[0][0], -s->texinfo->vecs[0][1], -s->texinfo->vecs[0][2]);
qglMultiTexCoord3fARB(GL_TEXTURE2_ARB, s->texinfo->vecs[1][0], s->texinfo->vecs[1][1], s->texinfo->vecs[1][2]);
if (s->flags & SURF_PLANEBACK)
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, -s->plane->normal[0], -s->plane->normal[1], -s->plane->normal[2]);
else
qglMultiTexCoord3fARB(GL_TEXTURE3_ARB, s->plane->normal[0], s->plane->normal[1], s->plane->normal[2]);
qglTexCoordPointer(2, GL_FLOAT, 0, s->mesh->st_array);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
}
GLSlang_UseProgram(0);
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
if (qglGetError())
Con_Printf("GL Error during lighttextures\n");
}
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);
if (ppl_light_shader[0])
{
PPL_LightBModelTexturesFP(e, light, colour);
qglPopMatrix();
return;
}
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 = R_TextureAnimation (s->texinfo->texture);
qglEnableClientState(GL_COLOR_ARRAY);
qglColorPointer(3, GL_FLOAT, sizeof(surfvertexarray_t), varray_v->stl);
if (t->tn.bump && gl_mtexarbable>3)
{
GL_MBind(GL_TEXTURE0_ARB, t->tn.bump);
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->tn.bump);
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->tn.base);
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);
qglVertexPointer(3, GL_FLOAT, 0, s->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, s->mesh->numindexes, GL_INDEX_TYPE, s->mesh->indexes);
varray_ic = 0;
varray_vc = 0;
}
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 (!PPL_ShouldDraw())
continue;
if (r_inmirror)
{
if (currententity->flags & Q2RF_WEAPONMODEL)
continue;
}
else
{
if (currententity->keynum == (cl.viewentity[r_refdef.currentplayernum]?cl.viewentity[r_refdef.currentplayernum]:(cl.playernum[r_refdef.currentplayernum]+1)))
continue;
// if (cl.viewentity[r_refdef.currentplayernum] && currententity->keynum == cl.viewentity[r_refdef.currentplayernum])
// continue;
if (!Cam_DrawPlayer(0, currententity->keynum-1))
continue;
}
if (currententity->flags & Q2RF_BEAM)
{
continue;
}
if (!currententity->model)
continue;
if (currententity->model->engineflags & MDLF_NOTREPLACEMENTS)
{
if (currententity->model->fromgame != fg_quake || currententity->model->type != mod_alias)
if (!ruleset_allow_sensative_texture_replacements.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);
}
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;
currententity = &r_worldentity;
if (gl_detail.value || (r_fb_bmodels.value && cls.allow_luma))
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->flags & Q2RF_BEAM)
continue;
if (!currententity->model)
continue;
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
{
if (currententity->model->engineflags & MDLF_ENGULPHS)
{
if (gl_part_flame.value)
continue;
}
}
switch (currententity->model->type)
{
case mod_alias:
// R_DrawGAliasModelLighting (currententity);
break;
case mod_brush:
PPL_FullBrightBModelTextures (currententity);
qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
break;
default:
break;
}
}
}
void PPL_SchematicsTextureChain(msurface_t *first)
{
extern int char_texture;
msurface_t *s;
float *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;
int e, en;
if (!cl.worldmodel->surfedges)
return;
qglEnable(GL_ALPHA_TEST);
if (qglPolygonOffset)
qglPolygonOffset(-1, 0);
frow = rand()/(float)RAND_MAX;
frow=frow/2+0.5;
qglColor3f(frow, frow, 0);
//draw the distances
if (gl_schematics.value != 2)
{
qglEnable(GL_POLYGON_OFFSET_FILL);
qglEnable(GL_TEXTURE_2D);
GL_Bind(char_texture);
qglBegin(GL_QUADS);
for (s = first; s ; s=s->texturechain)
{
for (e = s->numedges; e >= 0; e--)
{
en = cl.worldmodel->surfedges[e+s->firstedge];
if (en<0) //backwards
{
en = -en;
v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position;
v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position;
}
else
{
v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position;
v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position;
}
VectorSubtract(v1, v2, dir);
len = Length(dir);
VectorNormalize(dir);
sprintf(str, "%i", (len<1)?1:(int)len);
sl = strlen(str);
VectorMA(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);
if (s->flags & SURF_PLANEBACK)
VectorMA(pos, -8, s->plane->normal, v);
else
VectorMA(pos, 8, s->plane->normal, v);
qglTexCoord2f (fcol, frow);
qglVertex3fv(v);
VectorMA(pos, -8, dir, pos);
if (s->flags & SURF_PLANEBACK)
VectorMA(pos, -8, s->plane->normal, v);
else
VectorMA(pos, 8, s->plane->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 (e = s->numedges; e >= 0; e--)
{
en = cl.worldmodel->surfedges[e+s->firstedge];
if (en<0) //backwards
en = -en;
v1 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[0]].position;
v2 = cl.worldmodel->vertexes[cl.worldmodel->edges[en].v[1]].position;
VectorSubtract(v2, 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)
if (s->flags & SURF_PLANEBACK)
VectorMA(v1, -4, s->plane->normal, pos);
else
VectorMA(v1, 4, s->plane->normal, pos);
VectorMA(pos, 4, dir, v);
if (s->flags & SURF_PLANEBACK)
VectorMA(v, 4, s->plane->normal, v);
else
VectorMA(v, -4, s->plane->normal, v);
qglVertex3fv(v);
qglVertex3fv(pos);
if (s->flags & SURF_PLANEBACK)
VectorMA(v, -8, s->plane->normal, v);
else
VectorMA(v, 8, s->plane->normal, v);
qglVertex3fv(v);
qglVertex3fv(pos);
//the line
qglVertex3fv(pos);
VectorMA(pos, len/2 - sl*4, dir, pos);
qglVertex3fv(pos);
//right hand side.
if (s->flags & SURF_PLANEBACK)
VectorMA(v2, -4, s->plane->normal, pos);
else
VectorMA(v2, 4, s->plane->normal, pos);
VectorMA(pos, -4, dir, v);
if (s->flags & SURF_PLANEBACK)
VectorMA(v, 4, s->plane->normal, v);
else
VectorMA(v, -4, s->plane->normal, v);
qglVertex3fv(v);
qglVertex3fv(pos);
if (s->flags & SURF_PLANEBACK)
VectorMA(v, -8, s->plane->normal, v);
else
VectorMA(v, 8, s->plane->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);
qglEnable(GL_TEXTURE_2D);
}
// :)
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;
}
qboolean PPL_LeafInView(qbyte *lightvis)
{
int i;
int m = (cl.worldmodel->numleafs+7)/8;
mleaf_t *wl = cl.worldmodel->leafs;
unsigned char lv;
for (i = 0; i < m; i++)
{
lv = lightvis[i];
if (lv&1 && wl[(i<<3)+0].visframe == r_visframecount) return true;
if (lv&2 && wl[(i<<3)+1].visframe == r_visframecount) return true;
if (lv&4 && wl[(i<<3)+2].visframe == r_visframecount) return true;
if (lv&8 && wl[(i<<3)+3].visframe == r_visframecount) return true;
if (lv&16 && wl[(i<<3)+4].visframe == r_visframecount) return true;
if (lv&32 && wl[(i<<3)+5].visframe == r_visframecount) return true;
if (lv&64 && wl[(i<<3)+6].visframe == r_visframecount) return true;
if (lv&128 && wl[(i<<3)+7].visframe == r_visframecount) 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;
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;
PPL_Shadow_Cache_Leaf(pleaf);
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;
*/
PPL_Shadow_Cache_Surface(surf);
#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;
}
}
}
shadowsurfcount++;
qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, surf->mesh->numindexes, GL_INDEX_TYPE, surf->mesh->indexes);
//fixme:this only works becuse q1bsps don't have combined meshes yet...
//back (depth precision doesn't matter)
qglBegin(GL_POLYGON);
for (v = surf->mesh->numvertexes-1; v >=0; v--)
{
v1 = surf->mesh->xyz_array[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;
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;
}
}
}
//front face
qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array);
qglDrawElements(GL_TRIANGLES, surf->mesh->numindexes, GL_INDEX_TYPE, surf->mesh->indexes);
//fixme:this only works becuse q1bsps don't have combined meshes yet...
//back (depth precision doesn't matter)
qglBegin(GL_POLYGON);
for (v = surf->mesh->numvertexes-1; v >=0; v--)
{
v1 = surf->mesh->xyz_array[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;
// 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;
}*/
Sys_Error("PPL_RecursiveWorldNodeQ3_r needs work");
/*
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_INDEX_TYPE, 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;
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];
if (dl->worldshadowmesh)
{
qglEnableClientState(GL_VERTEX_ARRAY);
qglVertexPointer(3, GL_FLOAT, 0, dl->worldshadowmesh->verts);
qglDrawRangeElements(GL_TRIANGLES, 0, dl->worldshadowmesh->numverts, dl->worldshadowmesh->numindicies, GL_INDEX_TYPE, dl->worldshadowmesh->indicies);
return;
}
PPL_BeginShadowMesh(dl);
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)
{
qglDrawArrays(GL_QUADS, 0, varray_vc);
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++;
}
qglDrawArrays(GL_QUADS, 0, varray_vc);
if (qglGetError())
Con_Printf("GL Error on entities\n");
varray_vc=0;
firstedge=0;
PPL_FinishShadowMesh(dl);
}
void PPL_DrawBrushModelShadow(dlight_t *dl, entity_t *e)
{
int v;
float *v1, *v2;
vec3_t v3, v4;
int i;
model_t *model;
msurface_t *surf;
RotateLightVector(e->axis, 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;
}
//front face
qglVertexPointer(3, GL_FLOAT, 0, surf->mesh->xyz_array);
qglDrawArrays(GL_POLYGON, 0, surf->mesh->numvertexes);
for (v = 0; v < surf->mesh->numvertexes; v++)
{
//border
v1 = surf->mesh->xyz_array[v];
v2 = surf->mesh->xyz_array[( v+1 )%surf->mesh->numvertexes];
//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 );
qglVertex3fv(v1);
qglVertex3f (v1[0]+v3[0], v1[1]+v3[1], v1[2]+v3[2]);
qglVertex3fv(v2);
qglVertex3f (v2[0]+v4[0], v2[1]+v4[1], v2[2]+v4[2]);
qglEnd();
}
//back
//the same applies as earlier
qglBegin(GL_POLYGON);
for (v = surf->mesh->numvertexes-1; v >=0; v--)
{
v1 = surf->mesh->xyz_array[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 (r_inmirror)
{
if (currententity->flags & Q2RF_WEAPONMODEL)
continue;
}
else
{
if (currententity->keynum == dl->key)
continue;
}
if (currententity->flags & Q2RF_BEAM)
{
R_DrawBeam(currententity);
continue;
}
if (!currententity->model)
continue;
if (cls.allow_anyparticles || currententity->visframe) //allowed or static
{
if (currententity->model->engineflags & MDLF_ENGULPHS)
{
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_DrawBrushModelShadow (dl, currententity);
break;
default:
break;
}
}
}
void PPL_UpdateNodeShadowFrames(qbyte *lvis)
{
int i;
mnode_t *node;
if (!lvis) //using a cached light, we don't need shadowframes
return;
#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;
Matrix4_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;
Matrix4_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
//generates stencil shadows of the world geometry.
//redraws world geometry
qboolean 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 false; //just switch these off.
if (PPL_ScissorForBox(mins, maxs))
return false; //was culled.
if (dl->worldshadowmesh)
{
if (!PPL_LeafInView(dl->worldshadowmesh->litleaves))
return false;
/*
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;
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(dl->worldshadowmesh->litleaves, vvis)) //The two viewing areas do not intersect.
return;
*/
lvis = NULL;
}
else
{
if (cl.worldmodel->fromgame == fg_quake2 || cl.worldmodel->fromgame == fg_quake3)
i = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, r_refdef.vieworg);
else
i = r_viewleaf - cl.worldmodel->leafs;
leaf = cl.worldmodel->funcs.LeafnumForPoint(cl.worldmodel, dl->origin);
lvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb));
vvis = cl.worldmodel->funcs.LeafPVS(cl.worldmodel, i, vvisb, sizeof(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 false;
}
PPL_EnableVertexArrays();
qglDisable(GL_TEXTURE_2D);
qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
qglEnable(GL_SCISSOR_TEST);
if (!((int)r_shadows.value & 4))
{
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)
{
PPL_UpdateNodeShadowFrames(lvis);
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(lvis);
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(lvis);
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_ALWAYS, 0, ~0 );
qglActiveStencilFaceEXT(GL_FRONT);
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);
qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
qglCullFace(GL_FRONT);
#if 0 //draw the stencil stuff to the red channel
/*
{
#pragma comment(lib, "opengl32.lib")
static char buffer[1024*1024*8];
glReadPixels(0, 0, vid.width, vid.height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, buffer);
glDrawPixels(vid.width, vid.height, GL_GREEN, GL_UNSIGNED_BYTE, buffer);
}
*/
qglMatrixMode(GL_PROJECTION);
qglPushMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPushMatrix();
GL_Set2D();
{
extern cvar_t vid_conheight;
qglColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
qglStencilFunc(GL_GREATER, 1, ~0);
Draw_ConsoleBackground(vid_conheight.value);
qglColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
qglStencilFunc(GL_LESS, 1, ~0);
Draw_ConsoleBackground(vid_conheight.value);
qglColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
qglStencilFunc(GL_NEVER, 1, ~0);
Draw_ConsoleBackground(vid_conheight.value);
}
qglMatrixMode(GL_PROJECTION);
qglPopMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPopMatrix();
#endif
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
}
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);
qglDisable(GL_BLEND);
GL_TexEnv(GL_REPLACE);
return true;
}
#endif
void GL_CheckTMUIs0(void);
void PPL_DrawWorld (void)
{
RSpeedLocals();
#if 0
dlight_t *lc, *furthestprev;
float furthest;
#endif
#ifdef PPL
dlight_t *l;
int i;
int numlights;
vec3_t mins, maxs;
#endif
int maxshadowlights = gl_maxshadowlights.value;
if (!r_shadow_realtime_world.value)
r_lightmapintensity = 1;
else
r_lightmapintensity = r_shadow_realtime_world_lightmaps.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_DRAWENTITIES);
// 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
numlights = 0;
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<dlights_running ; i++, l++)
{
if (!l->radius || !(l->flags & LFLAG_ALLOW_PPL))
continue;
if (l->color[0]<0)
continue; //quick check for darklight
if (l->flags & LFLAG_REALTIMEMODE)
{
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))
continue;
#if 1
if (maxshadowlights-- <= 0)
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
TRACE(("dbg: calling PPL_AddLight\n"));
if (PPL_AddLight(l))
numlights++;
}
qglEnable(GL_TEXTURE_2D);
}
qglDisableClientState(GL_COLOR_ARRAY);
}
RSpeedEnd(RSPEED_STENCILSHADOWS);
#endif
// Con_Printf("%i lights\n", numlights);
// 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();
}
void PPL_CreateShaderObjects(void)
{
#ifdef PPL
PPL_CreateLightTexturesProgram();
#endif
PPL_LoadSpecularFragmentProgram();
}
void PPL_FlushShadowMesh(dlight_t *dl)
{
int tn;
shadowmesh_t *sm;
sm = dl->worldshadowmesh;
if (sm)
{
dl->worldshadowmesh = NULL;
for (tn = 0; tn < sm->numsurftextures; tn++)
if (sm->litsurfs[tn].count)
BZ_Free(sm->litsurfs);
BZ_Free(sm->indicies);
BZ_Free(sm->verts);
BZ_Free(sm);
}
}
//okay, so this is a bit of a hack...
qboolean buildingmesh;
void (APIENTRY *realBegin) (GLenum);
void (APIENTRY *realEnd) (void);
void (APIENTRY *realVertex3f) (GLfloat x, GLfloat y, GLfloat z);
void (APIENTRY *realVertex3fv) (const GLfloat *v);
void (APIENTRY *realVertexPointer) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void (APIENTRY *realDrawArrays) (GLenum mode, GLint first, GLsizei count);
void (APIENTRY *realDrawElements) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
#define inc 128
int sh_type;
int sh_index[64*64];
int sh_vertnum; //vertex number (set to 0 at SH_Begin)
int sh_maxverts;
int sh_numverts; //total emitted
int sh_maxindicies;
int sh_numindicies;
const float *sh_vertexpointer;
int sh_vpstride;
shadowmesh_t *sh_shmesh;
void APIENTRY SH_Begin (GLenum e)
{
sh_type = e;
}
void APIENTRY SH_End (void)
{
int i;
int v1, v2;
switch(sh_type)
{
case GL_POLYGON:
i = (sh_numindicies+(sh_vertnum-2)*3+inc+5)&~(inc-1); //and a bit of padding
if (sh_maxindicies != i)
{
sh_maxindicies = i;
sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies));
}
//decompose the poly into a triangle fan.
v1 = sh_index[0];
v2 = sh_index[1];
for (i = 2; i < sh_vertnum; i++)
{
sh_shmesh->indicies[sh_numindicies++] = v1;
sh_shmesh->indicies[sh_numindicies++] = v2;
sh_shmesh->indicies[sh_numindicies++] = v2 = sh_index[i];
}
sh_vertnum = 0;
break;
case GL_TRIANGLES:
i = (sh_numindicies+(sh_vertnum)+inc+5)&~(inc-1); //and a bit of padding
if (sh_maxindicies != i)
{
sh_maxindicies = i;
sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies));
}
//add the extra triangles
for (i = 0; i < sh_vertnum; i+=3)
{
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2];
}
sh_vertnum = 0;
break;
case GL_QUADS:
i = (sh_numindicies+(sh_vertnum/4)*6+inc+5)&~(inc-1); //and a bit of padding
if (sh_maxindicies != i)
{
sh_maxindicies = i;
sh_shmesh->indicies = BZ_Realloc(sh_shmesh->indicies, i * sizeof(*sh_shmesh->indicies));
}
//add the extra triangles
for (i = 0; i < sh_vertnum; i+=4)
{
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+1];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+0];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+2];
sh_shmesh->indicies[sh_numindicies++] = sh_index[i+3];
}
sh_vertnum = 0;
break;
default:
if (sh_vertnum)
Sys_Error("SH_End: verticies were left");
}
}
void APIENTRY SH_Vertex3f (GLfloat x, GLfloat y, GLfloat z)
{
int i;
if (sh_vertnum > sizeof(sh_index)/sizeof(sh_index[0]))
Sys_Error("SH_End: too many verticies");
//add the verts as we go
i = (sh_numverts+inc+5)&~(inc-1); //and a bit of padding
if (sh_maxverts != i)
{
sh_maxverts = i;
sh_shmesh->verts = BZ_Realloc(sh_shmesh->verts, i * sizeof(*sh_shmesh->verts));
}
sh_shmesh->verts[sh_numverts][0] = x;
sh_shmesh->verts[sh_numverts][1] = y;
sh_shmesh->verts[sh_numverts][2] = z;
sh_index[sh_vertnum] = sh_numverts;
sh_vertnum++;
sh_numverts++;
switch(sh_type)
{
case GL_POLYGON:
break;
case GL_TRIANGLES:
if (sh_vertnum == 3)
SH_End();
break;
case GL_QUADS:
if (sh_vertnum == 4)
SH_End();
break;
default:
Sys_Error("SH_Vertex3f: bad type");
}
}
void APIENTRY SH_Vertex3fv (const GLfloat *v)
{
SH_Vertex3f(v[0], v[1], v[2]);
}
void APIENTRY SH_VertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
{
sh_vertexpointer = pointer;
sh_vpstride = stride/4;
if (!sh_vpstride)
sh_vpstride = 3;
}
void APIENTRY SH_DrawArrays (GLenum mode, GLint first, GLsizei count)
{
int i;
SH_Begin(mode);
count+=first;
for (i = first; i < count; i++)
SH_Vertex3fv(sh_vertexpointer + i*sh_vpstride);
SH_End();
}
void APIENTRY SH_DrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
{
int i;
SH_Begin(mode);
for (i = 0; i < count; i++)
SH_Vertex3fv(sh_vertexpointer + (((int*)indices)[i])*sh_vpstride);
SH_End();
}
void PPL_Shadow_Cache_Surface(msurface_t *surf)
{
int i;
if (!buildingmesh)
return;
for (i = 0; i < cl.worldmodel->numtextures; i++)
if (surf->texinfo->texture == cl.worldmodel->textures[i])
break;
sh_shmesh->litsurfs[i].s = BZ_Realloc(sh_shmesh->litsurfs[i].s, sizeof(void*)*(sh_shmesh->litsurfs[i].count+1));
sh_shmesh->litsurfs[i].s[sh_shmesh->litsurfs[i].count] = surf;
sh_shmesh->litsurfs[i].count++;
}
void PPL_Shadow_Cache_Leaf(mleaf_t *leaf)
{
int i;
if (!buildingmesh)
return;
i = leaf - cl.worldmodel->leafs;
sh_shmesh->litleaves[i>>3] = 1<<(i&7);
}
void PPL_BeginShadowMesh(dlight_t *dl)
{
PPL_FlushShadowMesh(dl);
if (buildingmesh)
return;
if (dl->die)
return;
sh_maxverts = 0;
sh_numverts = 0;
sh_vertnum = 0;
sh_maxindicies = 0;
sh_numindicies = 0;
buildingmesh = true;
realBegin = qglBegin;
realEnd = qglEnd;
realVertex3f = qglVertex3f;
realVertex3fv = qglVertex3fv;
realVertexPointer = qglVertexPointer;
realDrawArrays = qglDrawArrays;
realDrawElements = qglDrawElements;
qglBegin = SH_Begin;
qglEnd = SH_End;
qglVertex3f = SH_Vertex3f;
qglVertex3fv = SH_Vertex3fv;
qglVertexPointer = SH_VertexPointer;
qglDrawArrays = SH_DrawArrays;
qglDrawElements = SH_DrawElements;
sh_shmesh = Z_Malloc(sizeof(*sh_shmesh) + (cl.worldmodel->numleafs+7)/8);
sh_shmesh->litsurfs = Z_Malloc(sizeof(shadowmeshsurfs_t)*cl.worldmodel->numtextures);
sh_shmesh->numsurftextures=cl.worldmodel->numtextures;
sh_shmesh->litleaves = (unsigned char*)(sh_shmesh+1);
}
void PPL_FinishShadowMesh(dlight_t *dl)
{
if (!buildingmesh)
return;
qglBegin = realBegin;
qglEnd = realEnd;
qglVertex3f = realVertex3f;
qglVertex3fv = realVertex3fv;
qglVertexPointer = realVertexPointer;
qglDrawArrays = realDrawArrays;
qglDrawElements = realDrawElements;
buildingmesh = false;
dl->worldshadowmesh = sh_shmesh;
sh_shmesh->numindicies = sh_numindicies;
sh_shmesh->numverts = sh_numverts;
sh_shmesh = NULL;
}
#endif //ifdef GLQUAKE
#endif