spingle/source/r_world.c

1224 lines
32 KiB
C
Raw Normal View History

2019-11-24 20:45:15 -08:00
/*
Copyright (C) 1996-2001 Id Software, Inc.
Copyright (C) 2002-2009 John Fitzgibbons and others
Copyright (C) 2007-2008 Kristian Duske
Copyright (C) 2010-2014 QuakeSpasm developers
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// r_world.c: world model rendering
2019-12-02 07:07:37 -08:00
#include "q_defs.h"
2019-11-24 20:45:15 -08:00
extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskyleaf, r_showtris; //johnfitz
2019-11-25 17:40:18 -08:00
extern glpoly_t *lightmap_polys[MAX_LIGHTMAPS];
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
byte *SV_FatPVS(vec3_t org, qmodel_t *worldmodel);
2019-11-24 20:45:15 -08:00
2019-11-25 16:49:58 -08:00
int32_t vis_changed; //if true, force pvs to be refreshed
2019-11-24 20:45:15 -08:00
//==============================================================================
//
// SETUP CHAINS
//
//==============================================================================
/*
================
2019-11-25 13:33:54 -08:00
R_ClearTextureChains -- ericw
2019-11-24 20:45:15 -08:00
clears texture chains for all textures used by the given model, and also
clears the lightmap chains
================
*/
2019-11-25 17:40:18 -08:00
void R_ClearTextureChains(qmodel_t *mod, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 16:49:58 -08:00
int32_t i;
2019-11-24 20:45:15 -08:00
// set all chains to null
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < mod->numtextures ; i++)
if(mod->textures[i])
2019-11-24 20:45:15 -08:00
mod->textures[i]->texturechains[chain] = NULL;
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
// clear lightmap chains
2019-11-25 17:40:18 -08:00
memset(lightmap_polys, 0, sizeof(lightmap_polys));
2019-11-24 20:45:15 -08:00
}
/*
================
R_ChainSurface -- ericw -- adds the given surface to its texture chain
================
*/
2019-11-25 17:40:18 -08:00
void R_ChainSurface(msurface_t *surf, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
surf->texturechain = surf->texinfo->texture->texturechains[chain];
surf->texinfo->texture->texturechains[chain] = surf;
}
/*
===============
R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains
===============
*/
2019-11-25 17:40:18 -08:00
void R_MarkSurfaces(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
byte *vis;
mleaf_t *leaf;
mnode_t *node;
msurface_t *surf, **mark;
int32_t i, j;
bool nearwaterportal;
2019-11-24 20:45:15 -08:00
// clear lightmap chains
2019-11-25 17:40:18 -08:00
memset(lightmap_polys, 0, sizeof(lightmap_polys));
2019-11-24 20:45:15 -08:00
// check this leaf for water portals
// TODO: loop through all water surfs and use distance to leaf cullbox
nearwaterportal = false;
2019-11-25 17:40:18 -08:00
for(i = 0, mark = r_viewleaf->firstmarksurface; i < r_viewleaf->nummarksurfaces; i++, mark++)
if((*mark)->flags & SURF_DRAWTURB)
2019-11-24 20:45:15 -08:00
nearwaterportal = true;
// choose vis data
2019-11-25 17:40:18 -08:00
if(r_novis.value || r_viewleaf->contents == CONTENTS_SOLID || r_viewleaf->contents == CONTENTS_SKY)
vis = Mod_NoVisPVS(cl.worldmodel);
else if(nearwaterportal)
vis = SV_FatPVS(r_origin, cl.worldmodel);
2019-11-24 20:45:15 -08:00
else
2019-11-25 17:40:18 -08:00
vis = Mod_LeafPVS(r_viewleaf, cl.worldmodel);
2019-11-24 20:45:15 -08:00
// if surface chains don't need regenerating, just add static entities and return
2019-11-25 17:40:18 -08:00
if(r_oldviewleaf == r_viewleaf && !vis_changed && !nearwaterportal)
2019-11-24 20:45:15 -08:00
{
leaf = &cl.worldmodel->leafs[1];
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < cl.worldmodel->numleafs ; i++, leaf++)
if(vis[i >> 3] & (1 << (i & 7)))
if(leaf->efrags)
R_StoreEfrags(&leaf->efrags);
2019-11-24 20:45:15 -08:00
return;
}
vis_changed = false;
r_visframecount++;
r_oldviewleaf = r_viewleaf;
// iterate through leaves, marking surfaces
leaf = &cl.worldmodel->leafs[1];
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < cl.worldmodel->numleafs ; i++, leaf++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(vis[i >> 3] & (1 << (i & 7)))
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(r_oldskyleaf.value || leaf->contents != CONTENTS_SKY)
for(j = 0, mark = leaf->firstmarksurface; j < leaf->nummarksurfaces; j++, mark++)
2019-11-24 20:45:15 -08:00
(*mark)->visframe = r_visframecount;
// add static models
2019-11-25 17:40:18 -08:00
if(leaf->efrags)
R_StoreEfrags(&leaf->efrags);
2019-11-24 20:45:15 -08:00
}
}
// set all chains to null
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < cl.worldmodel->numtextures ; i++)
if(cl.worldmodel->textures[i])
2019-11-24 20:45:15 -08:00
cl.worldmodel->textures[i]->texturechains[chain_world] = NULL;
// rebuild chains
//iterate through surfaces one node at a time to rebuild chains
//need to do it this way if we want to work with tyrann's skip removal tool
//becuase his tool doesn't actually remove the surfaces from the bsp surfaces lump
//nor does it remove references to them in each leaf's marksurfaces list
2019-11-25 17:40:18 -08:00
for(i = 0, node = cl.worldmodel->nodes ; i < cl.worldmodel->numnodes ; i++, node++)
for(j = 0, surf = &cl.worldmodel->surfaces[node->firstsurface] ; j < node->numsurfaces ; j++, surf++)
if(surf->visframe == r_visframecount)
2019-11-24 20:45:15 -08:00
{
R_ChainSurface(surf, chain_world);
}
}
/*
================
R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg
================
*/
2019-11-25 17:40:18 -08:00
bool R_BackFaceCull(msurface_t *surf)
2019-11-24 20:45:15 -08:00
{
double dot;
2019-11-25 17:40:18 -08:00
switch(surf->plane->type)
2019-11-24 20:45:15 -08:00
{
case PLANE_X:
dot = r_refdef.vieworg[0] - surf->plane->dist;
break;
case PLANE_Y:
dot = r_refdef.vieworg[1] - surf->plane->dist;
break;
case PLANE_Z:
dot = r_refdef.vieworg[2] - surf->plane->dist;
break;
default:
2019-11-25 17:40:18 -08:00
dot = DotProduct(r_refdef.vieworg, surf->plane->normal) - surf->plane->dist;
2019-11-24 20:45:15 -08:00
break;
}
2019-11-25 17:40:18 -08:00
if((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
2019-11-24 20:45:15 -08:00
return true;
return false;
}
/*
================
R_CullSurfaces -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_CullSurfaces(void)
2019-11-24 20:45:15 -08:00
{
msurface_t *s;
2019-11-25 16:49:58 -08:00
int32_t i;
2019-11-24 20:45:15 -08:00
texture_t *t;
2019-11-25 17:40:18 -08:00
if(!r_drawworld_cheatsafe)
2019-11-24 20:45:15 -08:00
return;
// ericw -- instead of testing (s->visframe == r_visframecount) on all world
// surfaces, use the chained surfaces, which is exactly the same set of sufaces
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < cl.worldmodel->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = cl.worldmodel->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain_world])
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain_world]; s; s = s->texturechain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(R_CullBox(s->mins, s->maxs) || R_BackFaceCull(s))
2019-11-24 20:45:15 -08:00
s->culled = true;
else
{
s->culled = false;
rs_brushpolys++; //count wpolys here
2019-11-25 17:40:18 -08:00
if(s->texinfo->texture->warpimage)
2019-11-24 20:45:15 -08:00
s->texinfo->texture->update_warp = true;
}
}
}
}
/*
================
R_BuildLightmapChains -- johnfitz -- used for r_lightmap 1
2019-11-25 13:33:54 -08:00
ericw -- now always used at the start of R_DrawTextureChains for the
2019-11-24 20:45:15 -08:00
mh dynamic lighting speedup
================
*/
2019-11-25 17:40:18 -08:00
void R_BuildLightmapChains(qmodel_t *model, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
texture_t *t;
msurface_t *s;
2019-11-25 16:49:58 -08:00
int32_t i;
2019-11-24 20:45:15 -08:00
// clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo)
2019-11-25 17:40:18 -08:00
memset(lightmap_polys, 0, sizeof(lightmap_polys));
2019-11-24 20:45:15 -08:00
// now rebuild them
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain])
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
R_RenderDynamicLightmaps(s);
2019-11-24 20:45:15 -08:00
}
}
//==============================================================================
//
// DRAW CHAINS
//
//==============================================================================
/*
=============
R_BeginTransparentDrawing -- ericw
=============
*/
2019-11-25 17:40:18 -08:00
static void R_BeginTransparentDrawing(float entalpha)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(entalpha < 1.0f)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor4f(1, 1, 1, entalpha);
2019-11-24 20:45:15 -08:00
}
}
/*
=============
R_EndTransparentDrawing -- ericw
=============
*/
2019-11-25 17:40:18 -08:00
static void R_EndTransparentDrawing(float entalpha)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(entalpha < 1.0f)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glColor3f(1, 1, 1);
2019-11-24 20:45:15 -08:00
}
}
/*
================
R_DrawTextureChains_ShowTris -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_ShowTris(qmodel_t *model, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
glpoly_t *p;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
if(r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
for(p = s->polys->next; p; p = p->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
DrawGLTriangleFan(p);
2019-11-24 20:45:15 -08:00
}
}
else
{
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
DrawGLTriangleFan(s->polys);
2019-11-24 20:45:15 -08:00
}
}
}
}
/*
================
R_DrawTextureChains_Drawflat -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_Drawflat(qmodel_t *model, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
glpoly_t *p;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t)
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
if(r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
for(p = s->polys->next; p; p = p->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
srand((uint32_t)(uintptr_t) p);
glColor3f(rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0);
DrawGLPoly(p);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
else
{
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
srand((uint32_t)(uintptr_t) s->polys);
glColor3f(rand() % 256 / 255.0, rand() % 256 / 255.0, rand() % 256 / 255.0);
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
}
2019-11-25 17:40:18 -08:00
glColor3f(1, 1, 1);
srand((int32_t)(cl.time * 1000));
2019-11-24 20:45:15 -08:00
}
/*
================
R_DrawTextureChains_Glow -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_Glow(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
gltexture_t *glt;
bool bound;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || !(glt = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_Bind(glt);
2019-11-24 20:45:15 -08:00
bound = true;
}
2019-11-25 17:40:18 -08:00
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
}
//==============================================================================
//
// VBO SUPPORT
//
//==============================================================================
2019-11-25 17:40:18 -08:00
static uint32_t R_NumTriangleIndicesForSurf(msurface_t *s)
2019-11-24 20:45:15 -08:00
{
return 3 * (s->numedges - 2);
}
/*
================
R_TriangleIndicesForSurf
Writes out the triangle indices needed to draw s as a triangle list.
The number of indices it will write is given by R_NumTriangleIndicesForSurf.
================
*/
2019-11-25 17:40:18 -08:00
static void R_TriangleIndicesForSurf(msurface_t *s, uint32_t *dest)
2019-11-24 20:45:15 -08:00
{
2019-11-25 16:49:58 -08:00
int32_t i;
2019-11-25 17:40:18 -08:00
for(i = 2; i < s->numedges; i++)
2019-11-24 20:45:15 -08:00
{
*dest++ = s->vbo_firstvert;
*dest++ = s->vbo_firstvert + i - 1;
*dest++ = s->vbo_firstvert + i;
}
}
#define MAX_BATCH_SIZE 4096
2019-11-25 14:05:12 -08:00
static uint32_t vbo_indices[MAX_BATCH_SIZE];
static uint32_t num_vbo_indices;
2019-11-24 20:45:15 -08:00
/*
================
R_ClearBatch
================
*/
2019-11-25 17:40:18 -08:00
static void R_ClearBatch()
2019-11-24 20:45:15 -08:00
{
num_vbo_indices = 0;
}
/*
================
R_FlushBatch
Draw the current batch if non-empty and clears it, ready for more R_BatchSurface calls.
================
*/
2019-11-25 17:40:18 -08:00
static void R_FlushBatch()
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(num_vbo_indices > 0)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDrawElements(GL_TRIANGLES, num_vbo_indices, GL_UNSIGNED_INT, vbo_indices);
2019-11-24 20:45:15 -08:00
num_vbo_indices = 0;
}
}
/*
================
R_BatchSurface
Add the surface to the current batch, or just draw it immediately if we're not
using VBOs.
================
*/
2019-11-25 17:40:18 -08:00
static void R_BatchSurface(msurface_t *s)
2019-11-24 20:45:15 -08:00
{
2019-11-25 16:49:58 -08:00
int32_t num_surf_indices;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
num_surf_indices = R_NumTriangleIndicesForSurf(s);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(num_vbo_indices + num_surf_indices > MAX_BATCH_SIZE)
2019-11-24 20:45:15 -08:00
R_FlushBatch();
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
R_TriangleIndicesForSurf(s, &vbo_indices[num_vbo_indices]);
2019-11-24 20:45:15 -08:00
num_vbo_indices += num_surf_indices;
}
/*
================
R_DrawTextureChains_Multitexture -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_Multitexture(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i, j;
msurface_t *s;
texture_t *t;
float *v;
bool bound;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_Bind((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(t->texturechains[chain]->flags & SURF_DRAWFENCE)
glEnable(GL_ALPHA_TEST); // Flip alpha test back on
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
GL_EnableMultitexture(); // selects TEXTURE1
bound = true;
}
2019-11-25 17:40:18 -08:00
GL_Bind(lightmap_textures[s->lightmaptexturenum]);
2019-11-24 20:45:15 -08:00
glBegin(GL_POLYGON);
v = s->polys->verts[0];
2019-11-25 17:40:18 -08:00
for(j = 0 ; j < s->polys->numverts ; j++, v += VERTEXSIZE)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_MTexCoord2fFunc(GL_TEXTURE0_ARB, v[3], v[4]);
GL_MTexCoord2fFunc(GL_TEXTURE1_ARB, v[5], v[6]);
glVertex3fv(v);
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
glEnd();
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
GL_DisableMultitexture(); // selects TEXTURE0
2019-11-25 17:40:18 -08:00
if(bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
glDisable(GL_ALPHA_TEST); // Flip alpha test back off
2019-11-24 20:45:15 -08:00
}
}
/*
================
R_DrawTextureChains_NoTexture -- johnfitz
draws surfs whose textures were missing from the BSP
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_NoTexture(qmodel_t *model, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
bool bound;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_NOTEXTURE))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_Bind(t->gltexture);
2019-11-24 20:45:15 -08:00
bound = true;
}
2019-11-25 17:40:18 -08:00
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
}
/*
================
R_DrawTextureChains_TextureOnly -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_TextureOnly(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
bool bound;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_Bind((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(t->texturechains[chain]->flags & SURF_DRAWFENCE)
glEnable(GL_ALPHA_TEST); // Flip alpha test back on
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
bound = true;
}
2019-11-25 17:40:18 -08:00
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
glDisable(GL_ALPHA_TEST); // Flip alpha test back off
2019-11-24 20:45:15 -08:00
}
}
/*
================
GL_WaterAlphaForEntitySurface -- ericw
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
Returns the water alpha to use for the entity and surface combination.
================
*/
2019-11-25 17:40:18 -08:00
float GL_WaterAlphaForEntitySurface(entity_t *ent, msurface_t *s)
2019-11-24 20:45:15 -08:00
{
float entalpha;
2019-11-25 17:40:18 -08:00
if(ent == NULL || ent->alpha == ENTALPHA_DEFAULT)
2019-11-24 20:45:15 -08:00
entalpha = GL_WaterAlphaForSurface(s);
else
entalpha = ENTALPHA_DECODE(ent->alpha);
return entalpha;
}
/*
================
R_DrawTextureChains_Water -- johnfitz
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_Water(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
glpoly_t *p;
bool bound;
2019-11-24 20:45:15 -08:00
float entalpha;
2019-11-25 17:40:18 -08:00
if(r_drawflat_cheatsafe || r_lightmap_cheatsafe) // ericw -- !r_drawworld_cheatsafe check moved to R_DrawWorld_Water ()
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
if(r_oldwater.value)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
entalpha = 1.0f;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
entalpha = GL_WaterAlphaForEntitySurface(ent, s);
R_BeginTransparentDrawing(entalpha);
GL_Bind(t->gltexture);
2019-11-24 20:45:15 -08:00
bound = true;
}
2019-11-25 17:40:18 -08:00
for(p = s->polys->next; p; p = p->next)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
DrawWaterPoly(p);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
2019-11-25 17:40:18 -08:00
R_EndTransparentDrawing(entalpha);
2019-11-24 20:45:15 -08:00
}
}
else
{
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB))
2019-11-24 20:45:15 -08:00
continue;
bound = false;
entalpha = 1.0f;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
entalpha = GL_WaterAlphaForEntitySurface(ent, s);
R_BeginTransparentDrawing(entalpha);
GL_Bind(t->warpimage);
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(model != cl.worldmodel)
2019-11-24 20:45:15 -08:00
{
// ericw -- this is copied from R_DrawSequentialPoly.
// If the poly is not part of the world we have to
// set this flag
t->update_warp = true; // FIXME: one frame too late!
}
bound = true;
}
2019-11-25 17:40:18 -08:00
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
2019-11-25 17:40:18 -08:00
R_EndTransparentDrawing(entalpha);
2019-11-24 20:45:15 -08:00
}
}
}
/*
================
R_DrawTextureChains_White -- johnfitz -- draw sky and water as white polys when r_lightmap is 1
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_White(qmodel_t *model, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
glDisable(GL_TEXTURE_2D);
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTILED))
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
DrawGLPoly(s->polys);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
2019-11-25 17:40:18 -08:00
glEnable(GL_TEXTURE_2D);
2019-11-24 20:45:15 -08:00
}
/*
================
R_DrawLightmapChains -- johnfitz -- R_BlendLightmaps stripped down to almost nothing
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawLightmapChains(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i, j;
glpoly_t *p;
float *v;
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
for(i = 0 ; i < MAX_LIGHTMAPS ; i++)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!lightmap_polys[i])
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
GL_Bind(lightmap_textures[i]);
for(p = lightmap_polys[i]; p; p = p->chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glBegin(GL_POLYGON);
2019-11-24 20:45:15 -08:00
v = p->verts[0];
2019-11-25 17:40:18 -08:00
for(j = 0 ; j < p->numverts ; j++, v += VERTEXSIZE)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glTexCoord2f(v[5], v[6]);
glVertex3fv(v);
2019-11-24 20:45:15 -08:00
}
2019-11-25 17:40:18 -08:00
glEnd();
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
}
}
static GLuint r_world_program;
// uniforms used in vert shader
// uniforms used in frag shader
static GLuint texLoc;
static GLuint LMTexLoc;
static GLuint fullbrightTexLoc;
static GLuint useFullbrightTexLoc;
static GLuint useOverbrightLoc;
static GLuint useAlphaTestLoc;
static GLuint alphaLoc;
#define vertAttrIndex 0
#define texCoordsAttrIndex 1
#define LMCoordsAttrIndex 2
/*
=============
GLWorld_CreateShaders
=============
*/
2019-11-25 17:40:18 -08:00
void GLWorld_CreateShaders(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
const glsl_attrib_binding_t bindings[] =
{
2019-11-24 20:45:15 -08:00
{ "Vert", vertAttrIndex },
{ "TexCoords", texCoordsAttrIndex },
{ "LMCoords", LMCoordsAttrIndex }
};
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
const GLchar *vertSource = \
2019-11-25 17:40:18 -08:00
"#version 110\n"
"\n"
"attribute vec3 Vert;\n"
"attribute vec2 TexCoords;\n"
"attribute vec2 LMCoords;\n"
"\n"
"varying float FogFragCoord;\n"
"\n"
"void main()\n"
"{\n"
" gl_TexCoord[0] = vec4(TexCoords, 0.0, 0.0);\n"
" gl_TexCoord[1] = vec4(LMCoords, 0.0, 0.0);\n"
" gl_Position = gl_ModelViewProjectionMatrix * vec4(Vert, 1.0);\n"
" FogFragCoord = gl_Position.w;\n"
"}\n";
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
const GLchar *fragSource = \
2019-11-25 17:40:18 -08:00
"#version 110\n"
"\n"
"uniform sampler2D Tex;\n"
"uniform sampler2D LMTex;\n"
"uniform sampler2D FullbrightTex;\n"
"uniform bool UseFullbrightTex;\n"
"uniform bool UseOverbright;\n"
"uniform bool UseAlphaTest;\n"
"uniform float Alpha;\n"
"\n"
"varying float FogFragCoord;\n"
"\n"
"void main()\n"
"{\n"
" vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n"
" if (UseAlphaTest && (result.a < 0.666))\n"
" discard;\n"
" result *= texture2D(LMTex, gl_TexCoord[1].xy);\n"
" if (UseOverbright)\n"
" result.rgb *= 2.0;\n"
" if (UseFullbrightTex)\n"
" result += texture2D(FullbrightTex, gl_TexCoord[0].xy);\n"
" result = clamp(result, 0.0, 1.0);\n"
" float fog = exp(-gl_Fog.density * gl_Fog.density * FogFragCoord * FogFragCoord);\n"
" fog = clamp(fog, 0.0, 1.0);\n"
" result = mix(gl_Fog.color, result, fog);\n"
" result.a = Alpha;\n" // FIXME: This will make almost transparent things cut holes though heavy fog
" gl_FragColor = result;\n"
"}\n";
if(!gl_glsl_alias_able)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 13:33:54 -08:00
r_world_program = GL_CreateProgram(vertSource, fragSource, arraysizeof(bindings), bindings);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(r_world_program != 0)
2019-11-24 20:45:15 -08:00
{
// get uniform locations
2019-11-25 17:40:18 -08:00
texLoc = GL_GetUniformLocation(&r_world_program, "Tex");
LMTexLoc = GL_GetUniformLocation(&r_world_program, "LMTex");
fullbrightTexLoc = GL_GetUniformLocation(&r_world_program, "FullbrightTex");
useFullbrightTexLoc = GL_GetUniformLocation(&r_world_program, "UseFullbrightTex");
useOverbrightLoc = GL_GetUniformLocation(&r_world_program, "UseOverbright");
useAlphaTestLoc = GL_GetUniformLocation(&r_world_program, "UseAlphaTest");
alphaLoc = GL_GetUniformLocation(&r_world_program, "Alpha");
2019-11-24 20:45:15 -08:00
}
}
extern GLuint gl_bmodel_vbo;
/*
================
R_DrawTextureChains_GLSL -- ericw
Draw lightmapped surfaces with fulbrights in one pass, using VBO.
Requires 3 TMUs, OpenGL 2.0
================
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains_GLSL(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
int32_t i;
msurface_t *s;
texture_t *t;
bool bound;
int32_t lastlightmap;
gltexture_t *fullbright = NULL;
float entalpha;
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
entalpha = (ent != NULL) ? ENTALPHA_DECODE(ent->alpha) : 1.0f;
// enable blending / disable depth writes
2019-11-25 17:40:18 -08:00
if(entalpha < 1)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
2019-11-24 20:45:15 -08:00
}
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
GL_UseProgramFunc(r_world_program);
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
// Bind the buffers
2019-11-25 17:40:18 -08:00
GL_BindBuffer(GL_ARRAY_BUFFER, gl_bmodel_vbo);
GL_BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // indices come from client memory!
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
GL_EnableVertexAttribArrayFunc(vertAttrIndex);
GL_EnableVertexAttribArrayFunc(texCoordsAttrIndex);
GL_EnableVertexAttribArrayFunc(LMCoordsAttrIndex);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
GL_VertexAttribPointerFunc(vertAttrIndex, 3, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), &((float *)NULL)[0]);
GL_VertexAttribPointerFunc(texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), &((float *)NULL)[3]);
GL_VertexAttribPointerFunc(LMCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), &((float *)NULL)[3 + 2]);
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
// set uniforms
2019-11-25 17:40:18 -08:00
GL_Uniform1iFunc(texLoc, 0);
GL_Uniform1iFunc(LMTexLoc, 1);
GL_Uniform1iFunc(fullbrightTexLoc, 2);
GL_Uniform1iFunc(useFullbrightTexLoc, 0);
GL_Uniform1iFunc(useOverbrightLoc, (int32_t)gl_overbright.value);
GL_Uniform1iFunc(useAlphaTestLoc, 0);
GL_Uniform1fFunc(alphaLoc, entalpha);
for(i = 0 ; i < model->numtextures ; i++)
2019-11-24 20:45:15 -08:00
{
t = model->textures[i];
2019-11-25 17:40:18 -08:00
if(!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE))
2019-11-24 20:45:15 -08:00
continue;
2019-11-25 17:40:18 -08:00
// Enable/disable TMU 2 (fullbrights)
// FIXME: Move below to where we bind GL_TEXTURE0
if(gl_fullbrights.value && (fullbright = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright))
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_SelectTexture(GL_TEXTURE2);
GL_Bind(fullbright);
GL_Uniform1iFunc(useFullbrightTexLoc, 1);
2019-11-24 20:45:15 -08:00
}
else
2019-11-25 17:40:18 -08:00
GL_Uniform1iFunc(useFullbrightTexLoc, 0);
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
R_ClearBatch();
2019-11-24 20:45:15 -08:00
bound = false;
lastlightmap = 0; // avoid compiler warning
2019-11-25 17:40:18 -08:00
for(s = t->texturechains[chain]; s; s = s->texturechain)
if(!s->culled)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!bound) //only bind once we are sure we need this texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_SelectTexture(GL_TEXTURE0);
GL_Bind((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(t->texturechains[chain]->flags & SURF_DRAWFENCE)
GL_Uniform1iFunc(useAlphaTestLoc, 1); // Flip alpha test back on
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
bound = true;
lastlightmap = s->lightmaptexturenum;
}
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(s->lightmaptexturenum != lastlightmap)
R_FlushBatch();
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
GL_SelectTexture(GL_TEXTURE1);
GL_Bind(lightmap_textures[s->lightmaptexturenum]);
2019-11-24 20:45:15 -08:00
lastlightmap = s->lightmaptexturenum;
2019-11-25 17:40:18 -08:00
R_BatchSurface(s);
2019-11-24 20:45:15 -08:00
rs_brushpasses++;
}
2019-11-25 17:40:18 -08:00
R_FlushBatch();
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
GL_Uniform1iFunc(useAlphaTestLoc, 0); // Flip alpha test back off
2019-11-24 20:45:15 -08:00
}
2019-11-25 13:33:54 -08:00
2019-11-24 20:45:15 -08:00
// clean up
2019-11-25 17:40:18 -08:00
GL_DisableVertexAttribArrayFunc(vertAttrIndex);
GL_DisableVertexAttribArrayFunc(texCoordsAttrIndex);
GL_DisableVertexAttribArrayFunc(LMCoordsAttrIndex);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
GL_UseProgramFunc(0);
GL_SelectTexture(GL_TEXTURE0);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(entalpha < 1)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
2019-11-24 20:45:15 -08:00
}
}
/*
=============
R_DrawWorld -- johnfitz -- rewritten
=============
*/
2019-11-25 17:40:18 -08:00
void R_DrawTextureChains(qmodel_t *model, entity_t *ent, texchain_t chain)
2019-11-24 20:45:15 -08:00
{
float entalpha;
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
if(ent != NULL)
2019-11-24 20:45:15 -08:00
entalpha = ENTALPHA_DECODE(ent->alpha);
else
entalpha = 1;
// ericw -- the mh dynamic lightmap speedup: make a first pass through all
// surfaces we are going to draw, and rebuild any lightmaps that need it.
// this also chains surfaces by lightmap which is used by r_lightmap 1.
// the previous implementation of the speedup uploaded lightmaps one frame
// late which was visible under some conditions, this method avoids that.
2019-11-25 17:40:18 -08:00
R_BuildLightmapChains(model, chain);
R_UploadLightmaps();
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
if(r_drawflat_cheatsafe)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDisable(GL_TEXTURE_2D);
R_DrawTextureChains_Drawflat(model, chain);
glEnable(GL_TEXTURE_2D);
2019-11-24 20:45:15 -08:00
return;
}
2019-11-25 17:40:18 -08:00
if(r_fullbright_cheatsafe)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
R_BeginTransparentDrawing(entalpha);
R_DrawTextureChains_TextureOnly(model, ent, chain);
R_EndTransparentDrawing(entalpha);
2019-11-24 20:45:15 -08:00
goto fullbrights;
}
2019-11-25 17:40:18 -08:00
if(r_lightmap_cheatsafe)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!gl_overbright.value)
2019-11-24 20:45:15 -08:00
{
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor3f(0.5, 0.5, 0.5);
}
2019-11-25 17:40:18 -08:00
R_DrawLightmapChains();
if(!gl_overbright.value)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glColor3f(1, 1, 1);
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_White(model, chain);
2019-11-24 20:45:15 -08:00
return;
}
2019-11-25 17:40:18 -08:00
R_BeginTransparentDrawing(entalpha);
2019-11-24 20:45:15 -08:00
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_NoTexture(model, chain);
2019-11-24 20:45:15 -08:00
// OpenGL 2 fast path
2019-11-25 17:40:18 -08:00
if(r_world_program != 0)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
R_EndTransparentDrawing(entalpha);
2019-11-25 13:33:54 -08:00
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_GLSL(model, ent, chain);
2019-11-24 20:45:15 -08:00
return;
}
2019-11-25 17:40:18 -08:00
if(gl_overbright.value)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_EnableMultitexture();
2019-11-24 20:45:15 -08:00
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
2019-11-25 17:40:18 -08:00
GL_DisableMultitexture();
R_DrawTextureChains_Multitexture(model, ent, chain);
GL_EnableMultitexture();
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2019-11-25 17:40:18 -08:00
GL_DisableMultitexture();
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
2019-11-25 17:40:18 -08:00
else if(entalpha < 1) //case 2: can't do multipass if entity has alpha, so just draw the texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_TextureOnly(model, ent, chain);
2019-11-24 20:45:15 -08:00
}
else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass
{
//to make fog work with multipass lightmapping, need to do one pass
//with no fog, one modulate pass with black fog, and one additive
//pass with black geometry and normal fog
2019-11-25 17:40:18 -08:00
Fog_DisableGFog();
R_DrawTextureChains_TextureOnly(model, ent, chain);
Fog_EnableGFog();
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); //2x modulate
Fog_StartAdditive();
R_DrawLightmapChains();
Fog_StopAdditive();
if(Fog_GetDensity() > 0)
2019-11-24 20:45:15 -08:00
{
glBlendFunc(GL_ONE, GL_ONE); //add
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2019-11-25 17:40:18 -08:00
glColor3f(0, 0, 0);
R_DrawTextureChains_TextureOnly(model, ent, chain);
glColor3f(1, 1, 1);
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
2019-11-25 17:40:18 -08:00
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
2019-11-24 20:45:15 -08:00
}
}
else
{
2019-11-25 17:40:18 -08:00
if(gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
GL_EnableMultitexture();
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2019-11-25 17:40:18 -08:00
GL_DisableMultitexture();
R_DrawTextureChains_Multitexture(model, ent, chain);
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
2019-11-25 17:40:18 -08:00
else if(entalpha < 1) //case 5: can't do multipass if entity has alpha, so just draw the texture
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_TextureOnly(model, ent, chain);
2019-11-24 20:45:15 -08:00
}
else //case 6: texture in one pass, lightmap in a second pass, fog in third pass
{
//to make fog work with multipass lightmapping, need to do one pass
//with no fog, one modulate pass with black fog, and one additive
//pass with black geometry and normal fog
2019-11-25 17:40:18 -08:00
Fog_DisableGFog();
R_DrawTextureChains_TextureOnly(model, ent, chain);
Fog_EnableGFog();
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
2019-11-24 20:45:15 -08:00
glBlendFunc(GL_ZERO, GL_SRC_COLOR); //modulate
2019-11-25 17:40:18 -08:00
Fog_StartAdditive();
R_DrawLightmapChains();
Fog_StopAdditive();
if(Fog_GetDensity() > 0)
2019-11-24 20:45:15 -08:00
{
glBlendFunc(GL_ONE, GL_ONE); //add
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
2019-11-25 17:40:18 -08:00
glColor3f(0, 0, 0);
R_DrawTextureChains_TextureOnly(model, ent, chain);
glColor3f(1, 1, 1);
2019-11-24 20:45:15 -08:00
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
}
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2019-11-25 17:40:18 -08:00
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
2019-11-24 20:45:15 -08:00
}
}
2019-11-25 17:40:18 -08:00
R_EndTransparentDrawing(entalpha);
2019-11-24 20:45:15 -08:00
fullbrights:
2019-11-25 17:40:18 -08:00
if(gl_fullbrights.value)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glColor3f(entalpha, entalpha, entalpha);
Fog_StartAdditive();
R_DrawTextureChains_Glow(model, ent, chain);
Fog_StopAdditive();
glColor3f(1, 1, 1);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glDepthMask(GL_TRUE);
2019-11-24 20:45:15 -08:00
}
}
/*
=============
R_DrawWorld -- ericw -- moved from R_DrawTextureChains, which is no longer specific to the world.
=============
*/
2019-11-25 17:40:18 -08:00
void R_DrawWorld(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!r_drawworld_cheatsafe)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
R_DrawTextureChains(cl.worldmodel, NULL, chain_world);
2019-11-24 20:45:15 -08:00
}
/*
=============
R_DrawWorld_Water -- ericw -- moved from R_DrawTextureChains_Water, which is no longer specific to the world.
=============
*/
2019-11-25 17:40:18 -08:00
void R_DrawWorld_Water(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!r_drawworld_cheatsafe)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_Water(cl.worldmodel, NULL, chain_world);
2019-11-24 20:45:15 -08:00
}
/*
=============
R_DrawWorld_ShowTris -- ericw -- moved from R_DrawTextureChains_ShowTris, which is no longer specific to the world.
=============
*/
2019-11-25 17:40:18 -08:00
void R_DrawWorld_ShowTris(void)
2019-11-24 20:45:15 -08:00
{
2019-11-25 17:40:18 -08:00
if(!r_drawworld_cheatsafe)
2019-11-24 20:45:15 -08:00
return;
2019-11-25 17:40:18 -08:00
R_DrawTextureChains_ShowTris(cl.worldmodel, chain_world);
2019-11-24 20:45:15 -08:00
}