2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 1996-2001 Id Software, Inc.
|
|
|
|
Copyright (C) 2002-2009 John Fitzgibbons and others
|
|
|
|
Copyright (C) 2007-2008 Kristian Duske
|
2014-09-22 08:55:46 +00:00
|
|
|
Copyright (C) 2010-2014 QuakeSpasm developers
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
// r_world.c: world model rendering
|
|
|
|
|
|
|
|
#include "quakedef.h"
|
|
|
|
|
|
|
|
extern cvar_t gl_fullbrights, r_drawflat, gl_overbright, r_oldwater, r_oldskyleaf, r_showtris; //johnfitz
|
|
|
|
|
2012-05-30 08:56:06 +00:00
|
|
|
byte *SV_FatPVS (vec3_t org, qmodel_t *worldmodel);
|
2017-07-26 04:27:16 +00:00
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
int vis_changed; //if true, force pvs to be refreshed
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// SETUP CHAINS
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_ClearTextureChains -- ericw
|
|
|
|
|
|
|
|
clears texture chains for all textures used by the given model, and also
|
|
|
|
clears the lightmap chains
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void R_ClearTextureChains (qmodel_t *mod, texchain_t chain)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// set all chains to null
|
|
|
|
for (i=0 ; i<mod->numtextures ; i++)
|
|
|
|
if (mod->textures[i])
|
|
|
|
mod->textures[i]->texturechains[chain] = NULL;
|
|
|
|
|
|
|
|
// clear lightmap chains
|
2019-09-12 06:49:35 +00:00
|
|
|
for (i=0 ; i<lightmap_count ; i++)
|
|
|
|
lightmap[i].polys = NULL;
|
2014-08-29 08:27:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_ChainSurface -- ericw -- adds the given surface to its texture chain
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void R_ChainSurface (msurface_t *surf, texchain_t chain)
|
|
|
|
{
|
|
|
|
surf->texturechain = surf->texinfo->texture->texturechains[chain];
|
|
|
|
surf->texinfo->texture->texturechains[chain] = surf;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
R_MarkSurfaces -- johnfitz -- mark surfaces based on PVS and rebuild texture chains
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void R_MarkSurfaces (void)
|
|
|
|
{
|
|
|
|
byte *vis;
|
|
|
|
mleaf_t *leaf;
|
|
|
|
mnode_t *node;
|
|
|
|
msurface_t *surf, **mark;
|
|
|
|
int i, j;
|
|
|
|
qboolean nearwaterportal;
|
|
|
|
|
|
|
|
// clear lightmap chains
|
2019-09-12 06:49:35 +00:00
|
|
|
for (i=0 ; i<lightmap_count ; i++)
|
|
|
|
lightmap[i].polys = NULL;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
// check this leaf for water portals
|
|
|
|
// TODO: loop through all water surfs and use distance to leaf cullbox
|
|
|
|
nearwaterportal = false;
|
|
|
|
for (i=0, mark = r_viewleaf->firstmarksurface; i < r_viewleaf->nummarksurfaces; i++, mark++)
|
|
|
|
if ((*mark)->flags & SURF_DRAWTURB)
|
|
|
|
nearwaterportal = true;
|
|
|
|
|
|
|
|
// choose vis data
|
|
|
|
if (r_novis.value || r_viewleaf->contents == CONTENTS_SOLID || r_viewleaf->contents == CONTENTS_SKY)
|
2017-07-26 04:27:16 +00:00
|
|
|
vis = Mod_NoVisPVS (cl.worldmodel);
|
2010-02-15 23:26:55 +00:00
|
|
|
else if (nearwaterportal)
|
|
|
|
vis = SV_FatPVS (r_origin, cl.worldmodel);
|
|
|
|
else
|
|
|
|
vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
|
|
|
|
|
|
|
|
// if surface chains don't need regenerating, just add static entities and return
|
|
|
|
if (r_oldviewleaf == r_viewleaf && !vis_changed && !nearwaterportal)
|
|
|
|
{
|
|
|
|
leaf = &cl.worldmodel->leafs[1];
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
|
|
if (vis[i>>3] & (1<<(i&7)))
|
|
|
|
if (leaf->efrags)
|
|
|
|
R_StoreEfrags (&leaf->efrags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-18 20:51:35 +00:00
|
|
|
vis_changed = false;
|
2010-02-15 23:26:55 +00:00
|
|
|
r_visframecount++;
|
|
|
|
r_oldviewleaf = r_viewleaf;
|
|
|
|
|
|
|
|
// iterate through leaves, marking surfaces
|
|
|
|
leaf = &cl.worldmodel->leafs[1];
|
|
|
|
for (i=0 ; i<cl.worldmodel->numleafs ; i++, leaf++)
|
|
|
|
{
|
|
|
|
if (vis[i>>3] & (1<<(i&7)))
|
|
|
|
{
|
|
|
|
if (r_oldskyleaf.value || leaf->contents != CONTENTS_SKY)
|
|
|
|
for (j=0, mark = leaf->firstmarksurface; j<leaf->nummarksurfaces; j++, mark++)
|
|
|
|
(*mark)->visframe = r_visframecount;
|
|
|
|
|
|
|
|
// add static models
|
|
|
|
if (leaf->efrags)
|
|
|
|
R_StoreEfrags (&leaf->efrags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// set all chains to null
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
|
|
|
if (cl.worldmodel->textures[i])
|
2014-08-29 08:27:22 +00:00
|
|
|
cl.worldmodel->textures[i]->texturechains[chain_world] = NULL;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
// rebuild chains
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
//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
|
|
|
|
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)
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
R_ChainSurface(surf, chain_world);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
//the old way
|
|
|
|
surf = &cl.worldmodel->surfaces[cl.worldmodel->firstmodelsurface];
|
|
|
|
for (i=0 ; i<cl.worldmodel->nummodelsurfaces ; i++, surf++)
|
|
|
|
{
|
|
|
|
if (surf->visframe == r_visframecount)
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
R_ChainSurface(surf, chain_world);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_BackFaceCull -- johnfitz -- returns true if the surface is facing away from vieworg
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
qboolean R_BackFaceCull (msurface_t *surf)
|
|
|
|
{
|
|
|
|
double dot;
|
|
|
|
|
|
|
|
switch (surf->plane->type)
|
|
|
|
{
|
|
|
|
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:
|
|
|
|
dot = DotProduct (r_refdef.vieworg, surf->plane->normal) - surf->plane->dist;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((dot < 0) ^ !!(surf->flags & SURF_PLANEBACK))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_CullSurfaces -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void R_CullSurfaces (void)
|
|
|
|
{
|
|
|
|
msurface_t *s;
|
|
|
|
int i;
|
2014-09-08 04:31:26 +00:00
|
|
|
texture_t *t;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
if (!r_drawworld_cheatsafe)
|
|
|
|
return;
|
|
|
|
|
2014-09-08 04:31:26 +00:00
|
|
|
// ericw -- instead of testing (s->visframe == r_visframecount) on all world
|
|
|
|
// surfaces, use the chained surfaces, which is exactly the same set of sufaces
|
|
|
|
for (i=0 ; i<cl.worldmodel->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-09-08 04:31:26 +00:00
|
|
|
t = cl.worldmodel->textures[i];
|
|
|
|
|
|
|
|
if (!t || !t->texturechains[chain_world])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (s = t->texturechains[chain_world]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
if (R_CullBox(s->mins, s->maxs) || R_BackFaceCull (s))
|
|
|
|
s->culled = true;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
s->culled = false;
|
|
|
|
rs_brushpolys++; //count wpolys here
|
|
|
|
if (s->texinfo->texture->warpimage)
|
|
|
|
s->texinfo->texture->update_warp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_BuildLightmapChains -- johnfitz -- used for r_lightmap 1
|
2014-10-21 19:27:42 +00:00
|
|
|
|
|
|
|
ericw -- now always used at the start of R_DrawTextureChains for the
|
|
|
|
mh dynamic lighting speedup
|
2010-02-15 23:26:55 +00:00
|
|
|
================
|
|
|
|
*/
|
2014-10-21 19:27:42 +00:00
|
|
|
void R_BuildLightmapChains (qmodel_t *model, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-10-21 19:27:42 +00:00
|
|
|
texture_t *t;
|
2010-02-15 23:26:55 +00:00
|
|
|
msurface_t *s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// clear lightmap chains (already done in r_marksurfaces, but clearing them here to be safe becuase of r_stereo)
|
2019-09-12 06:49:35 +00:00
|
|
|
for (i=0 ; i<lightmap_count ; i++)
|
|
|
|
lightmap[i].polys = NULL;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
|
|
|
// now rebuild them
|
2014-10-21 19:27:42 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
|
|
|
{
|
|
|
|
t = model->textures[i];
|
|
|
|
|
|
|
|
if (!t || !t->texturechains[chain])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
|
|
|
if (!s->culled)
|
|
|
|
R_RenderDynamicLightmaps (s);
|
|
|
|
}
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// DRAW CHAINS
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_BeginTransparentDrawing -- ericw
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static void R_BeginTransparentDrawing (float entalpha)
|
|
|
|
{
|
|
|
|
if (entalpha < 1.0f)
|
|
|
|
{
|
|
|
|
glDepthMask (GL_FALSE);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glColor4f (1,1,1,entalpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_EndTransparentDrawing -- ericw
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static void R_EndTransparentDrawing (float entalpha)
|
|
|
|
{
|
|
|
|
if (entalpha < 1.0f)
|
|
|
|
{
|
|
|
|
glDepthMask (GL_TRUE);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_ShowTris -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_ShowTris (qmodel_t *model, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
glpoly_t *p;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!t)
|
|
|
|
continue;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
for (p = s->polys->next; p; p = p->next)
|
|
|
|
{
|
|
|
|
DrawGLTriangleFan (p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
DrawGLTriangleFan (s->polys);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_Drawflat -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_Drawflat (qmodel_t *model, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
glpoly_t *p;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!t)
|
|
|
|
continue;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (r_oldwater.value && t->texturechains[chain] && (t->texturechains[chain]->flags & SURF_DRAWTURB))
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
for (p = s->polys->next; p; p = p->next)
|
|
|
|
{
|
2011-04-01 14:55:45 +00:00
|
|
|
srand((unsigned int) (uintptr_t) p);
|
2010-02-15 23:26:55 +00:00
|
|
|
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
|
|
|
DrawGLPoly (p);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
2011-04-01 14:55:45 +00:00
|
|
|
srand((unsigned int) (uintptr_t) s->polys);
|
2010-02-15 23:26:55 +00:00
|
|
|
glColor3f (rand()%256/255.0, rand()%256/255.0, rand()%256/255.0);
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glColor3f (1,1,1);
|
|
|
|
srand ((int) (cl.time * 1000));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_Glow -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_Glow (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
gltexture_t *glt;
|
|
|
|
qboolean bound;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain] || !(glt = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bound = false;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
|
|
|
GL_Bind (glt);
|
|
|
|
bound = true;
|
|
|
|
}
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
|
|
|
//==============================================================================
|
|
|
|
//
|
|
|
|
// VBO SUPPORT
|
|
|
|
//
|
|
|
|
//==============================================================================
|
|
|
|
|
|
|
|
static unsigned int R_NumTriangleIndicesForSurf (msurface_t *s)
|
|
|
|
{
|
|
|
|
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.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
static void R_TriangleIndicesForSurf (msurface_t *s, unsigned int *dest)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i=2; i<s->numedges; i++)
|
|
|
|
{
|
|
|
|
*dest++ = s->vbo_firstvert;
|
|
|
|
*dest++ = s->vbo_firstvert + i - 1;
|
|
|
|
*dest++ = s->vbo_firstvert + i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_BATCH_SIZE 4096
|
|
|
|
|
|
|
|
static unsigned int vbo_indices[MAX_BATCH_SIZE];
|
|
|
|
static unsigned int num_vbo_indices;
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_ClearBatch
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
static void R_ClearBatch ()
|
|
|
|
{
|
|
|
|
num_vbo_indices = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_FlushBatch
|
|
|
|
|
|
|
|
Draw the current batch if non-empty and clears it, ready for more R_BatchSurface calls.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
static void R_FlushBatch ()
|
|
|
|
{
|
|
|
|
if (num_vbo_indices > 0)
|
|
|
|
{
|
|
|
|
glDrawElements (GL_TRIANGLES, num_vbo_indices, GL_UNSIGNED_INT, vbo_indices);
|
|
|
|
num_vbo_indices = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_BatchSurface
|
|
|
|
|
|
|
|
Add the surface to the current batch, or just draw it immediately if we're not
|
|
|
|
using VBOs.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
static void R_BatchSurface (msurface_t *s)
|
|
|
|
{
|
|
|
|
int num_surf_indices;
|
2014-09-20 01:08:13 +00:00
|
|
|
|
Load world and brush models into a VBO, and draw it in batches in R_DrawTextureChains_Multitexture. Uses the same immediate mode code as before if VBOs are not available, or if "-novbo" used at the command line. I only touched R_DrawTextureChains_Multitexture because it's usually the main bottleneck aside from alias model rendering.
This seems to help fps a fair bit on maps with a lot of world polys like jam2_tronyn. Tried on a few computers with intel and nvidia gpus, windows, mac os, linux, and there's always at least some fps improvement. Best case was 70fps -> 96fps on jam2_tronyn, on OS X + nvidia 650gt.
Interested to hear how this works for amd gpu's, just do a timedemo with and without "-novbo".
Only downside is I had to disable the fast path in Vid_Toggle_f() because at least with SDL1, the vbo no longer works after a toggle. So as a result, fullscreen toggles with alt-enter are slightly slower.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1018 af15c1b1-3010-417e-b628-4374ebc0bcbd
2014-09-11 04:55:16 +00:00
|
|
|
num_surf_indices = R_NumTriangleIndicesForSurf (s);
|
|
|
|
|
|
|
|
if (num_vbo_indices + num_surf_indices > MAX_BATCH_SIZE)
|
|
|
|
R_FlushBatch();
|
|
|
|
|
|
|
|
R_TriangleIndicesForSurf (s, &vbo_indices[num_vbo_indices]);
|
|
|
|
num_vbo_indices += num_surf_indices;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_Multitexture -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_Multitexture (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-09-20 01:08:13 +00:00
|
|
|
int i, j;
|
2010-02-15 23:26:55 +00:00
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
2014-09-20 01:08:13 +00:00
|
|
|
float *v;
|
2010-02-15 23:26:55 +00:00
|
|
|
qboolean bound;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bound = false;
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
|
2014-08-22 01:10:58 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2014-08-22 01:10:58 +00:00
|
|
|
glEnable (GL_ALPHA_TEST); // Flip alpha test back on
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
GL_EnableMultitexture(); // selects TEXTURE1
|
|
|
|
bound = true;
|
|
|
|
}
|
2019-09-12 06:49:35 +00:00
|
|
|
GL_Bind (lightmap[s->lightmaptexturenum].texture);
|
2014-09-20 01:08:13 +00:00
|
|
|
glBegin(GL_POLYGON);
|
|
|
|
v = s->polys->verts[0];
|
|
|
|
for (j=0 ; j<s->polys->numverts ; j++, v+= VERTEXSIZE)
|
|
|
|
{
|
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE0_ARB, v[3], v[4]);
|
|
|
|
GL_MTexCoord2fFunc (GL_TEXTURE1_ARB, v[5], v[6]);
|
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
glEnd ();
|
2010-02-15 23:26:55 +00:00
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
GL_DisableMultitexture(); // selects TEXTURE0
|
2014-08-30 08:00:34 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2014-08-22 01:10:58 +00:00
|
|
|
glDisable (GL_ALPHA_TEST); // Flip alpha test back off
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_NoTexture -- johnfitz
|
|
|
|
|
|
|
|
draws surfs whose textures were missing from the BSP
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_NoTexture (qmodel_t *model, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
qboolean bound;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_NOTEXTURE))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bound = false;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
|
|
|
GL_Bind (t->gltexture);
|
|
|
|
bound = true;
|
|
|
|
}
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_TextureOnly -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_TextureOnly (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
qboolean bound;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTURB | SURF_DRAWSKY))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
bound = false;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
|
2014-08-22 01:10:58 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2014-08-22 01:10:58 +00:00
|
|
|
glEnable (GL_ALPHA_TEST); // Flip alpha test back on
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
bound = true;
|
|
|
|
}
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
2014-08-22 01:10:58 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2014-08-22 01:10:58 +00:00
|
|
|
glDisable (GL_ALPHA_TEST); // Flip alpha test back off
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
GL_WaterAlphaForEntitySurface -- ericw
|
|
|
|
|
|
|
|
Returns the water alpha to use for the entity and surface combination.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
float GL_WaterAlphaForEntitySurface (entity_t *ent, msurface_t *s)
|
|
|
|
{
|
|
|
|
float entalpha;
|
|
|
|
if (ent == NULL || ent->alpha == ENTALPHA_DEFAULT)
|
|
|
|
entalpha = GL_WaterAlphaForSurface(s);
|
|
|
|
else
|
|
|
|
entalpha = ENTALPHA_DECODE(ent->alpha);
|
|
|
|
return entalpha;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_Water -- johnfitz
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
glpoly_t *p;
|
|
|
|
qboolean bound;
|
2014-08-29 08:27:22 +00:00
|
|
|
float entalpha;
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (r_drawflat_cheatsafe || r_lightmap_cheatsafe) // ericw -- !r_drawworld_cheatsafe check moved to R_DrawWorld_Water ()
|
2010-02-15 23:26:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (r_oldwater.value)
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
|
|
|
if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
bound = false;
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
entalpha = 1.0f;
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
entalpha = GL_WaterAlphaForEntitySurface (ent, s);
|
|
|
|
R_BeginTransparentDrawing (entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
GL_Bind (t->gltexture);
|
|
|
|
bound = true;
|
|
|
|
}
|
|
|
|
for (p = s->polys->next; p; p = p->next)
|
|
|
|
{
|
|
|
|
DrawWaterPoly (p);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
R_EndTransparentDrawing (entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
|
|
|
if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTURB))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
bound = false;
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
entalpha = 1.0f;
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
entalpha = GL_WaterAlphaForEntitySurface (ent, s);
|
|
|
|
R_BeginTransparentDrawing (entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
GL_Bind (t->warpimage);
|
2014-08-29 08:27:22 +00:00
|
|
|
|
|
|
|
if (model != cl.worldmodel)
|
|
|
|
{
|
|
|
|
// 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!
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
bound = true;
|
|
|
|
}
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
new cvars: r_lavaalpha, r_slimealpha, r_telealpha for fine-tuning specific liquid opacities (from DirectQ, RMQEngine)
new worldspawn keys: _wateralpha, _lavaalpha, _slimealpha, _telealpha, _skyfog (unique to Quakespasm)
The lava/slime/telealpha cvars are non-archived, and default to 0, which means to use the value of r_wateralpha, so they have no effect by default.
The worldspawn keys allow custom maps to set these values in a way that only applies while the map is loaded, and doesn't change the cvar value. (similar to the behaviour of the "fog" worldspawn key.) They are accepted with or without the underscore, like "fog".
see also:
http://forums.insideqc.com/viewtopic.php?f=3&t=5532
http://celephais.net/board/view_thread.php?id=60452&start=937
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1238 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-07-26 21:51:25 +00:00
|
|
|
R_EndTransparentDrawing (entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawTextureChains_White -- johnfitz -- draw sky and water as white polys when r_lightmap is 1
|
|
|
|
================
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains_White (qmodel_t *model, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
2014-08-29 08:27:22 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
t = model->textures[i];
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
if (!t || !t->texturechains[chain] || !(t->texturechains[chain]->flags & SURF_DRAWTILED))
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
2010-02-15 23:26:55 +00:00
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
DrawGLPoly (s->polys);
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
R_DrawLightmapChains -- johnfitz -- R_BlendLightmaps stripped down to almost nothing
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void R_DrawLightmapChains (void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
glpoly_t *p;
|
|
|
|
float *v;
|
|
|
|
|
2019-09-12 06:49:35 +00:00
|
|
|
for (i=0 ; i<lightmap_count ; i++)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2019-09-12 06:49:35 +00:00
|
|
|
if (!lightmap[i].polys)
|
2010-02-15 23:26:55 +00:00
|
|
|
continue;
|
|
|
|
|
2019-09-12 06:49:35 +00:00
|
|
|
GL_Bind (lightmap[i].texture);
|
|
|
|
for (p = lightmap[i].polys; p; p=p->chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
glBegin (GL_POLYGON);
|
|
|
|
v = p->verts[0];
|
|
|
|
for (j=0 ; j<p->numverts ; j++, v+= VERTEXSIZE)
|
|
|
|
{
|
|
|
|
glTexCoord2f (v[5], v[6]);
|
|
|
|
glVertex3fv (v);
|
|
|
|
}
|
|
|
|
glEnd ();
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
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
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void GLWorld_CreateShaders (void)
|
|
|
|
{
|
|
|
|
const glsl_attrib_binding_t bindings[] = {
|
|
|
|
{ "Vert", vertAttrIndex },
|
|
|
|
{ "TexCoords", texCoordsAttrIndex },
|
|
|
|
{ "LMCoords", LMCoordsAttrIndex }
|
|
|
|
};
|
|
|
|
|
|
|
|
const GLchar *vertSource = \
|
|
|
|
"#version 110\n"
|
|
|
|
"\n"
|
|
|
|
"attribute vec3 Vert;\n"
|
|
|
|
"attribute vec2 TexCoords;\n"
|
|
|
|
"attribute vec2 LMCoords;\n"
|
|
|
|
"\n"
|
2017-12-24 18:59:44 +00:00
|
|
|
"varying float FogFragCoord;\n"
|
2017-12-20 03:04:39 +00:00
|
|
|
"\n"
|
2017-11-01 04:01:02 +00:00
|
|
|
"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"
|
2017-12-24 18:59:44 +00:00
|
|
|
" FogFragCoord = gl_Position.w;\n"
|
2017-11-01 04:01:02 +00:00
|
|
|
"}\n";
|
|
|
|
|
|
|
|
const GLchar *fragSource = \
|
|
|
|
"#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"
|
2017-12-20 03:04:39 +00:00
|
|
|
"\n"
|
2017-12-24 18:59:44 +00:00
|
|
|
"varying float FogFragCoord;\n"
|
2017-12-20 03:04:39 +00:00
|
|
|
"\n"
|
2017-11-01 04:01:02 +00:00
|
|
|
"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"
|
2017-12-24 18:59:44 +00:00
|
|
|
" float fog = exp(-gl_Fog.density * gl_Fog.density * FogFragCoord * FogFragCoord);\n"
|
2017-11-01 04:01:02 +00:00
|
|
|
" fog = clamp(fog, 0.0, 1.0);\n"
|
|
|
|
" result = mix(gl_Fog.color, result, fog);\n"
|
2017-12-24 18:59:44 +00:00
|
|
|
" result.a = Alpha;\n" // FIXME: This will make almost transparent things cut holes though heavy fog
|
2017-11-01 04:01:02 +00:00
|
|
|
" gl_FragColor = result;\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
if (!gl_glsl_alias_able)
|
|
|
|
return;
|
|
|
|
|
|
|
|
r_world_program = GL_CreateProgram (vertSource, fragSource, sizeof(bindings)/sizeof(bindings[0]), bindings);
|
|
|
|
|
|
|
|
if (r_world_program != 0)
|
|
|
|
{
|
|
|
|
// get uniform locations
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
extern GLuint gl_bmodel_vbo;
|
|
|
|
|
2014-09-20 01:08:13 +00:00
|
|
|
/*
|
|
|
|
================
|
2017-11-01 04:01:02 +00:00
|
|
|
R_DrawTextureChains_GLSL -- ericw
|
2014-09-20 01:08:13 +00:00
|
|
|
|
|
|
|
Draw lightmapped surfaces with fulbrights in one pass, using VBO.
|
2017-11-01 04:01:02 +00:00
|
|
|
Requires 3 TMUs, OpenGL 2.0
|
2014-09-20 01:08:13 +00:00
|
|
|
================
|
|
|
|
*/
|
2017-11-01 04:01:02 +00:00
|
|
|
void R_DrawTextureChains_GLSL (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2014-09-20 01:08:13 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
msurface_t *s;
|
|
|
|
texture_t *t;
|
|
|
|
qboolean bound;
|
|
|
|
int lastlightmap;
|
|
|
|
gltexture_t *fullbright = NULL;
|
2017-11-01 04:01:02 +00:00
|
|
|
float entalpha;
|
|
|
|
|
|
|
|
entalpha = (ent != NULL) ? ENTALPHA_DECODE(ent->alpha) : 1.0f;
|
|
|
|
|
|
|
|
// enable blending / disable depth writes
|
|
|
|
if (entalpha < 1)
|
|
|
|
{
|
|
|
|
glDepthMask (GL_FALSE);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
}
|
|
|
|
|
|
|
|
GL_UseProgramFunc (r_world_program);
|
2014-09-20 01:08:13 +00:00
|
|
|
|
Alias model rendering fast-path using OpenGL 2.
In GL_MakeAliasModelDisplayLists, after saving the standerd triangle strips and fans onto the hunk, if the system is GL2 capable, we also save a second version of the mdl on the hunk designed to be loaded into a VBO (GL_MakeAliasModelDisplayLists_VBO). In R_NewMap, and on video mode changes, we call GLMesh_LoadVertexBuffers which loops over all precached mdl's and loads the data into a pair of VBO's (vertices and vertex indices).
Finally, in R_DrawAliasModel, assuming no rendering options are disabling the fast-path (r_drawflat 1, r_lightmap 1, or r_fullbright 1 would disable it), we call GL_DrawAliasFrame_GLSL, which sets up all of the bindings and draws the (possibly lerped) mdl in one glDrawElements call.
Special thanks to MH for some of the code from RMQEngine and the general concept.
git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1151 af15c1b1-3010-417e-b628-4374ebc0bcbd
2015-01-20 18:59:15 +00:00
|
|
|
// Bind the buffers
|
|
|
|
GL_BindBuffer (GL_ARRAY_BUFFER, gl_bmodel_vbo);
|
|
|
|
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, 0); // indices come from client memory!
|
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_EnableVertexAttribArrayFunc (vertAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (texCoordsAttrIndex);
|
|
|
|
GL_EnableVertexAttribArrayFunc (LMCoordsAttrIndex);
|
|
|
|
|
|
|
|
GL_VertexAttribPointerFunc (vertAttrIndex, 3, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0));
|
|
|
|
GL_VertexAttribPointerFunc (texCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0) + 3);
|
|
|
|
GL_VertexAttribPointerFunc (LMCoordsAttrIndex, 2, GL_FLOAT, GL_FALSE, VERTEXSIZE * sizeof(float), ((float *)0) + 5);
|
|
|
|
|
|
|
|
// set uniforms
|
|
|
|
GL_Uniform1iFunc (texLoc, 0);
|
|
|
|
GL_Uniform1iFunc (LMTexLoc, 1);
|
|
|
|
GL_Uniform1iFunc (fullbrightTexLoc, 2);
|
|
|
|
GL_Uniform1iFunc (useFullbrightTexLoc, 0);
|
|
|
|
GL_Uniform1iFunc (useOverbrightLoc, (int)gl_overbright.value);
|
|
|
|
GL_Uniform1iFunc (useAlphaTestLoc, 0);
|
|
|
|
GL_Uniform1fFunc (alphaLoc, entalpha);
|
|
|
|
|
2014-09-20 01:08:13 +00:00
|
|
|
for (i=0 ; i<model->numtextures ; i++)
|
|
|
|
{
|
|
|
|
t = model->textures[i];
|
|
|
|
|
|
|
|
if (!t || !t->texturechains[chain] || t->texturechains[chain]->flags & (SURF_DRAWTILED | SURF_NOTEXTURE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Enable/disable TMU 2 (fullbrights)
|
2017-11-01 04:01:02 +00:00
|
|
|
// FIXME: Move below to where we bind GL_TEXTURE0
|
2014-09-20 01:08:13 +00:00
|
|
|
if (gl_fullbrights.value && (fullbright = R_TextureAnimation(t, ent != NULL ? ent->frame : 0)->fullbright))
|
|
|
|
{
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_SelectTexture (GL_TEXTURE2);
|
2014-09-20 01:08:13 +00:00
|
|
|
GL_Bind (fullbright);
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_Uniform1iFunc (useFullbrightTexLoc, 1);
|
2014-09-20 01:08:13 +00:00
|
|
|
}
|
|
|
|
else
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_Uniform1iFunc (useFullbrightTexLoc, 0);
|
2014-09-20 01:08:13 +00:00
|
|
|
|
|
|
|
R_ClearBatch ();
|
|
|
|
|
|
|
|
bound = false;
|
|
|
|
lastlightmap = 0; // avoid compiler warning
|
|
|
|
for (s = t->texturechains[chain]; s; s = s->texturechain)
|
|
|
|
if (!s->culled)
|
|
|
|
{
|
|
|
|
if (!bound) //only bind once we are sure we need this texture
|
|
|
|
{
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_SelectTexture (GL_TEXTURE0);
|
2014-09-20 01:08:13 +00:00
|
|
|
GL_Bind ((R_TextureAnimation(t, ent != NULL ? ent->frame : 0))->gltexture);
|
|
|
|
|
|
|
|
if (t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_Uniform1iFunc (useAlphaTestLoc, 1); // Flip alpha test back on
|
2014-09-20 01:08:13 +00:00
|
|
|
|
|
|
|
bound = true;
|
|
|
|
lastlightmap = s->lightmaptexturenum;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->lightmaptexturenum != lastlightmap)
|
|
|
|
R_FlushBatch ();
|
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_SelectTexture (GL_TEXTURE1);
|
2019-09-12 06:49:35 +00:00
|
|
|
GL_Bind (lightmap[s->lightmaptexturenum].texture);
|
2014-09-20 01:08:13 +00:00
|
|
|
lastlightmap = s->lightmaptexturenum;
|
|
|
|
R_BatchSurface (s);
|
|
|
|
|
|
|
|
rs_brushpasses++;
|
|
|
|
}
|
|
|
|
|
|
|
|
R_FlushBatch ();
|
|
|
|
|
|
|
|
if (bound && t->texturechains[chain]->flags & SURF_DRAWFENCE)
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_Uniform1iFunc (useAlphaTestLoc, 0); // Flip alpha test back off
|
2014-09-20 01:08:13 +00:00
|
|
|
}
|
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
// clean up
|
|
|
|
GL_DisableVertexAttribArrayFunc (vertAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (texCoordsAttrIndex);
|
|
|
|
GL_DisableVertexAttribArrayFunc (LMCoordsAttrIndex);
|
2014-09-20 01:08:13 +00:00
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
GL_UseProgramFunc (0);
|
|
|
|
GL_SelectTexture (GL_TEXTURE0);
|
|
|
|
|
|
|
|
if (entalpha < 1)
|
|
|
|
{
|
|
|
|
glDepthMask (GL_TRUE);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
}
|
2014-09-20 01:08:13 +00:00
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_DrawWorld -- johnfitz -- rewritten
|
|
|
|
=============
|
|
|
|
*/
|
2014-08-29 08:27:22 +00:00
|
|
|
void R_DrawTextureChains (qmodel_t *model, entity_t *ent, texchain_t chain)
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
float entalpha;
|
|
|
|
|
|
|
|
if (ent != NULL)
|
|
|
|
entalpha = ENTALPHA_DECODE(ent->alpha);
|
|
|
|
else
|
|
|
|
entalpha = 1;
|
2014-07-12 07:50:57 +00:00
|
|
|
|
2014-10-21 19:27:42 +00:00
|
|
|
// 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.
|
|
|
|
R_BuildLightmapChains (model, chain);
|
|
|
|
R_UploadLightmaps ();
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
if (r_drawflat_cheatsafe)
|
|
|
|
{
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_Drawflat (model, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
glEnable (GL_TEXTURE_2D);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_fullbright_cheatsafe)
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
R_BeginTransparentDrawing (entalpha);
|
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
|
|
|
R_EndTransparentDrawing (entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
goto fullbrights;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r_lightmap_cheatsafe)
|
|
|
|
{
|
|
|
|
if (!gl_overbright.value)
|
|
|
|
{
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glColor3f(0.5, 0.5, 0.5);
|
|
|
|
}
|
|
|
|
R_DrawLightmapChains ();
|
|
|
|
if (!gl_overbright.value)
|
|
|
|
{
|
|
|
|
glColor3f(1,1,1);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_White (model, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
R_BeginTransparentDrawing (entalpha);
|
|
|
|
|
|
|
|
R_DrawTextureChains_NoTexture (model, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
|
2017-11-01 04:01:02 +00:00
|
|
|
// OpenGL 2 fast path
|
|
|
|
if (r_world_program != 0)
|
2014-09-20 01:08:13 +00:00
|
|
|
{
|
|
|
|
R_EndTransparentDrawing (entalpha);
|
2017-11-01 04:01:02 +00:00
|
|
|
|
|
|
|
R_DrawTextureChains_GLSL (model, ent, chain);
|
2014-09-20 01:08:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
if (gl_overbright.value)
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
if (gl_texture_env_combine && gl_mtexable) //case 1: texture and lightmap in one pass, overbright using texture combiners
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
GL_EnableMultitexture ();
|
|
|
|
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);
|
|
|
|
GL_DisableMultitexture ();
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_Multitexture (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
GL_EnableMultitexture ();
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_DisableMultitexture ();
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
2014-08-29 08:27:22 +00:00
|
|
|
else if (entalpha < 1) //case 2: can't do multipass if entity has alpha, so just draw the texture
|
|
|
|
{
|
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
|
|
|
}
|
|
|
|
else //case 3: texture in one pass, lightmap in second pass using 2x modulation blend func, fog in third pass
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
//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
|
|
|
|
Fog_DisableGFog ();
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE); //add
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glColor3f(0,0,0);
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-29 08:27:22 +00:00
|
|
|
if (gl_mtexable) //case 4: texture and lightmap in one pass, regular modulation
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
GL_EnableMultitexture ();
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
GL_DisableMultitexture ();
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_Multitexture (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
}
|
2014-08-29 08:27:22 +00:00
|
|
|
else if (entalpha < 1) //case 5: can't do multipass if entity has alpha, so just draw the texture
|
|
|
|
{
|
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
|
|
|
}
|
|
|
|
else //case 6: texture in one pass, lightmap in a second pass, fog in third pass
|
2010-02-15 23:26:55 +00:00
|
|
|
{
|
|
|
|
//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
|
|
|
|
Fog_DisableGFog ();
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
Fog_EnableGFog ();
|
|
|
|
glDepthMask (GL_FALSE);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glBlendFunc(GL_ZERO, GL_SRC_COLOR); //modulate
|
|
|
|
Fog_StartAdditive ();
|
|
|
|
R_DrawLightmapChains ();
|
|
|
|
Fog_StopAdditive ();
|
|
|
|
if (Fog_GetDensity() > 0)
|
|
|
|
{
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE); //add
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glColor3f(0,0,0);
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_TextureOnly (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-29 08:27:22 +00:00
|
|
|
R_EndTransparentDrawing (entalpha);
|
|
|
|
|
2010-02-15 23:26:55 +00:00
|
|
|
fullbrights:
|
|
|
|
if (gl_fullbrights.value)
|
|
|
|
{
|
|
|
|
glDepthMask (GL_FALSE);
|
|
|
|
glEnable (GL_BLEND);
|
|
|
|
glBlendFunc (GL_ONE, GL_ONE);
|
2014-08-29 08:27:22 +00:00
|
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
glColor3f (entalpha, entalpha, entalpha);
|
2010-02-15 23:26:55 +00:00
|
|
|
Fog_StartAdditive ();
|
2014-08-29 08:27:22 +00:00
|
|
|
R_DrawTextureChains_Glow (model, ent, chain);
|
2010-02-15 23:26:55 +00:00
|
|
|
Fog_StopAdditive ();
|
2014-08-29 08:27:22 +00:00
|
|
|
glColor3f (1, 1, 1);
|
|
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
2010-02-15 23:26:55 +00:00
|
|
|
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
glDepthMask (GL_TRUE);
|
|
|
|
}
|
2010-02-16 12:24:38 +00:00
|
|
|
}
|
2014-08-29 08:27:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_DrawWorld -- ericw -- moved from R_DrawTextureChains, which is no longer specific to the world.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void R_DrawWorld (void)
|
|
|
|
{
|
|
|
|
if (!r_drawworld_cheatsafe)
|
|
|
|
return;
|
|
|
|
|
|
|
|
R_DrawTextureChains (cl.worldmodel, NULL, chain_world);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_DrawWorld_Water -- ericw -- moved from R_DrawTextureChains_Water, which is no longer specific to the world.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void R_DrawWorld_Water (void)
|
|
|
|
{
|
|
|
|
if (!r_drawworld_cheatsafe)
|
|
|
|
return;
|
|
|
|
|
|
|
|
R_DrawTextureChains_Water (cl.worldmodel, NULL, chain_world);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
R_DrawWorld_ShowTris -- ericw -- moved from R_DrawTextureChains_ShowTris, which is no longer specific to the world.
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void R_DrawWorld_ShowTris (void)
|
|
|
|
{
|
|
|
|
if (!r_drawworld_cheatsafe)
|
|
|
|
return;
|
|
|
|
|
|
|
|
R_DrawTextureChains_ShowTris (cl.worldmodel, chain_world);
|
|
|
|
}
|