Merge remote-tracking branch 'yquake2/master'

This commit is contained in:
Denis Pauk 2024-07-21 18:07:00 +03:00
commit 6c16fe1e8e
14 changed files with 684 additions and 571 deletions

View file

@ -83,7 +83,6 @@ Quake II 8.30 to 8.40:
`gl1_multitexture`, enabled by default. (by protocultor)
- Optimize dynamic lights and texture allocation in the OpenGL 1.4
renderer. (by protocultor)
- Support big lightmaps in the OpenGL 1.4 renderer. (by protocultor)
- Implement gyro tightening for gamepads and joysticks. (by protocultor)
- Support long player skin names. (by 0lvin)
- Add a very simple download filter. Files ending in .dll, .dylib and
@ -91,6 +90,8 @@ Quake II 8.30 to 8.40:
- Don't load OpenAL and cURL libraries if thy are configured with a full
or relative path.
- Work around naggy help icons. (by BjossiAlfreds)
- Group draw call in GL1. This yields huge performance gains on slow
GPUs. (by protocultor)
Quake II 8.20 to 8.30:
- Use the same image loading code in all renderers. (by 0lvin)

View file

@ -590,6 +590,7 @@ set(GL1-Source
${REF_SRC_DIR}/gl1/gl1_surf.c
${REF_SRC_DIR}/gl1/gl1_warp.c
${REF_SRC_DIR}/gl1/gl1_sdl.c
${REF_SRC_DIR}/gl1/gl1_buffer.c
${REF_SRC_DIR}/files/models.c
${REF_SRC_DIR}/files/pcx.c
${REF_SRC_DIR}/files/stb.c

View file

@ -1096,6 +1096,7 @@ REFGL1_OBJS_ := \
src/client/refresh/gl1/gl1_sdl.o \
src/client/refresh/files/mesh.o \
src/client/refresh/files/light.o \
src/client/refresh/gl1/gl1_buffer.o \
src/client/refresh/files/surf.o \
src/client/refresh/files/maps.o \
src/client/refresh/files/models.o \

View file

@ -495,10 +495,6 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable`
## Graphics (OpenGL 1.4 only)
* **gl1_biglightmaps**: Enables lightmaps and scrap to use a bigger
texture size, which means fewer texture switches, improving
performance. Default is `1` (enabled). Requires a `vid_restart`.
* **gl1_intensity**: Sets the color intensity. Must be a floating point
value, at least `1.0` - default is `2.0`. Applied when textures are
loaded, so it needs a `vid_restart`.

View file

@ -0,0 +1,449 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2024 Jaime Moreira
*
* 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.
*
* =======================================================================
*
* Drawing buffer: sort of a "Q3A shader" handler, allows to join multiple
* draw calls into one, by grouping those which share the same
* characteristics (mostly the same texture).
*
* =======================================================================
*/
#include "header/local.h"
#define MAX_VERTICES 16384
#define MAX_INDICES (MAX_VERTICES * 4)
typedef struct // 832k aprox.
{
buffered_draw_t type;
GLfloat
vtx[MAX_VERTICES * 3], // vertexes
tex[MAX_TEXTURE_UNITS][MAX_VERTICES * 2], // texture coords
clr[MAX_VERTICES * 4]; // color components
GLushort
idx[MAX_INDICES], // indices
vtx_ptr, idx_ptr; // pointers for array positions
int texture[MAX_TEXTURE_UNITS];
int flags; // entity flags
float alpha;
} glbuffer_t;
glbuffer_t gl_buf;
GLuint vt, tx, cl; // indices for arrays in gl_buf
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
void
R_ApplyGLBuffer(void)
{
// Properties of batched draws here
GLint vtx_size;
qboolean texture, mtex, alpha, color, alias, texenv_set;
float fovy, dist;
if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0)
{
return;
}
// defaults for drawing (mostly buf_singletex features)
vtx_size = 3;
texture = true;
mtex = alpha = color = alias = texenv_set = false;
// choosing features by type
switch (gl_buf.type)
{
case buf_2d:
vtx_size = 2;
break;
case buf_mtex:
mtex = true;
break;
case buf_alpha:
alpha = true;
break;
case buf_alias:
alias = color = true;
break;
case buf_flash:
color = true;
case buf_shadow:
texture = false;
break;
default:
break;
}
R_EnableMultitexture(mtex);
if (alias)
{
if (gl_buf.flags & RF_DEPTHHACK)
{
// hack the depth range to prevent view model from poking into walls
glDepthRange(gldepthmin, gldepthmin + 0.3 * (gldepthmax - gldepthmin));
}
if (gl_buf.flags & RF_WEAPONMODEL)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
if (gl_lefthand->value == 1.0f)
{
glScalef(-1, 1, 1);
}
fovy = (r_gunfov->value < 0) ? r_newrefdef.fov_y : r_gunfov->value;
dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f;
R_MYgluPerspective(fovy, (float)r_newrefdef.width / r_newrefdef.height, 4, dist);
glMatrixMode(GL_MODELVIEW);
if (gl_lefthand->value == 1.0f)
{
glCullFace(GL_BACK);
}
}
glShadeModel(GL_SMOOTH);
R_TexEnv(GL_MODULATE);
if (gl_buf.flags & RF_TRANSLUCENT)
{
glEnable(GL_BLEND);
}
if (gl_buf.flags & (RF_SHELL_RED | RF_SHELL_GREEN |
RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM))
{
texture = false;
glDisable(GL_TEXTURE_2D);
}
}
if (alpha)
{
// the textures are prescaled up for a better
// lighting range, so scale it back down
glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity,
gl_state.inverse_intensity, gl_buf.alpha);
}
else if (gl_buf.flags & SURF_DRAWTURB)
{
texenv_set = true;
// This is a hack ontop of a hack. Warping surfaces like those generated
// by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore
// negated the global intensity on those surfaces, because otherwise they
// would show up much too bright. When we implemented overbright bits this
// hack modified the global GL state in an incompatible way. So implement
// a new hack, based on overbright bits... Depending on the value set to
// gl1_overbrightbits the result is different:
// 0: Old behaviour.
// 1: No overbright bits on the global scene but correct lighting on
// warping surfaces.
// 2,4: Overbright bits on the global scene but not on warping surfaces.
// They oversaturate otherwise.
if (gl1_overbrightbits->value)
{
R_TexEnv(GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
}
else
{
R_TexEnv(GL_MODULATE);
glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity,
gl_state.inverse_intensity, 1.0f);
}
}
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx);
if (texture)
{
if (mtex)
{
// TMU 1: Lightmap texture
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + gl_buf.texture[1]);
if (gl1_overbrightbits->value)
{
R_TexEnv(GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value);
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, gl_buf.tex[1]);
// TMU 0: Color texture
R_MBind(GL_TEXTURE0, gl_buf.texture[0]);
}
else
{
R_Bind(gl_buf.texture[0]);
}
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, gl_buf.tex[0]);
}
if (color)
{
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, gl_buf.clr);
}
// All set, we can finally draw
glDrawElements(GL_TRIANGLES, gl_buf.idx_ptr, GL_UNSIGNED_SHORT, gl_buf.idx);
// ... and now, turn back everything as it was
if (color)
{
glDisableClientState(GL_COLOR_ARRAY);
}
if (texture)
{
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
}
glDisableClientState( GL_VERTEX_ARRAY );
if (texenv_set)
{
R_TexEnv(GL_REPLACE);
}
if (alias)
{
if (gl_buf.flags & (RF_SHELL_RED | RF_SHELL_GREEN |
RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM))
{
glEnable(GL_TEXTURE_2D);
}
if (gl_buf.flags & RF_TRANSLUCENT)
{
glDisable(GL_BLEND);
}
R_TexEnv(GL_REPLACE);
glShadeModel(GL_FLAT);
if (gl_buf.flags & RF_WEAPONMODEL)
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
if (gl_lefthand->value == 1.0F)
{
glCullFace(GL_FRONT);
}
}
if (gl_buf.flags & RF_DEPTHHACK)
{
glDepthRange(gldepthmin, gldepthmax);
}
}
gl_buf.vtx_ptr = gl_buf.idx_ptr = 0;
}
void
R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha)
{
if ( gl_buf.type != type || gl_buf.texture[0] != colortex ||
(gl_config.multitexture && type == buf_mtex && gl_buf.texture[1] != lighttex) ||
((type == buf_singletex || type == buf_alias) && gl_buf.flags != flags) ||
(type == buf_alpha && gl_buf.alpha != alpha))
{
R_ApplyGLBuffer();
gl_buf.type = type;
gl_buf.texture[0] = colortex;
gl_buf.texture[1] = lighttex;
gl_buf.flags = flags;
gl_buf.alpha = alpha;
}
}
void
R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty)
{
static const GLushort idx_max = MAX_INDICES - 7;
static const GLushort vtx_max = MAX_VERTICES - 5;
unsigned int i;
if (gl_buf.idx_ptr > idx_max || gl_buf.vtx_ptr > vtx_max)
{
R_ApplyGLBuffer();
}
i = gl_buf.vtx_ptr * 2; // vertex index
// "Quad" = 2-triangle GL_TRIANGLE_FAN
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+3;
// up left corner coords
gl_buf.vtx[i] = ul_vx;
gl_buf.vtx[i+1] = ul_vy;
// up right
gl_buf.vtx[i+2] = dr_vx;
gl_buf.vtx[i+3] = ul_vy;
// down right
gl_buf.vtx[i+4] = dr_vx;
gl_buf.vtx[i+5] = dr_vy;
// and finally, down left
gl_buf.vtx[i+6] = ul_vx;
gl_buf.vtx[i+7] = dr_vy;
gl_buf.tex[0][i] = ul_tx;
gl_buf.tex[0][i+1] = ul_ty;
gl_buf.tex[0][i+2] = dr_tx;
gl_buf.tex[0][i+3] = ul_ty;
gl_buf.tex[0][i+4] = dr_tx;
gl_buf.tex[0][i+5] = dr_ty;
gl_buf.tex[0][i+6] = ul_tx;
gl_buf.tex[0][i+7] = dr_ty;
gl_buf.vtx_ptr += 4;
}
/*
* Set up indices with the proper shape for the next buffered vertices
*/
void
R_SetBufferIndices(GLenum type, GLuint vertices_num)
{
int i;
if ( gl_buf.vtx_ptr + vertices_num >= MAX_VERTICES ||
gl_buf.idx_ptr + ( (vertices_num - 2) * 3 ) >= MAX_INDICES )
{
R_ApplyGLBuffer();
}
switch (type)
{
case GL_TRIANGLE_FAN:
for (i = 0; i < vertices_num-2; i++)
{
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2;
}
break;
case GL_TRIANGLE_STRIP:
for (i = 0; i < vertices_num-2; i++)
{
if (i % 2 == 0)
{
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2;
}
else // backwards order
{
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+2;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i+1;
gl_buf.idx[gl_buf.idx_ptr++] = gl_buf.vtx_ptr+i;
}
}
break;
default:
R_Printf(PRINT_DEVELOPER, "R_SetBufferIndices: no such type %d\n", type);
return;
}
// These affect the functions that follow in this file
vt = gl_buf.vtx_ptr * 3; // vertex index
tx = gl_buf.vtx_ptr * 2; // texcoord index
cl = gl_buf.vtx_ptr * 4; // color index
// R_BufferVertex() must be called as many times as vertices_num
gl_buf.vtx_ptr += vertices_num;
}
/*
* Adds a single vertex to buffer
*/
void
R_BufferVertex(GLfloat x, GLfloat y, GLfloat z)
{
gl_buf.vtx[vt++] = x;
gl_buf.vtx[vt++] = y;
gl_buf.vtx[vt++] = z;
}
/*
* Adds texture coordinates for color texture (no lightmap coords)
*/
void
R_BufferSingleTex(GLfloat s, GLfloat t)
{
// tx should be set before this is called, by R_SetBufferIndices
gl_buf.tex[0][tx++] = s;
gl_buf.tex[0][tx++] = t;
}
/*
* Adds texture coordinates for color and lightmap
*/
void
R_BufferMultiTex(GLfloat cs, GLfloat ct, GLfloat ls, GLfloat lt)
{
gl_buf.tex[0][tx] = cs;
gl_buf.tex[0][tx+1] = ct;
gl_buf.tex[1][tx] = ls;
gl_buf.tex[1][tx+1] = lt;
tx += 2;
}
/*
* Adds color components of vertex
*/
void
R_BufferColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
gl_buf.clr[cl++] = r;
gl_buf.clr[cl++] = g;
gl_buf.clr[cl++] = b;
gl_buf.clr[cl++] = a;
}

View file

@ -90,31 +90,10 @@ RDraw_CharScaled(int x, int y, int num, float scale)
scaledSize = 8*scale;
R_Bind(draw_chars->texnum);
R_UpdateGLBuffer(buf_2d, draw_chars->texnum, 0, 0, 1);
GLfloat vtx[] = {
x, y,
x + scaledSize, y,
x + scaledSize, y + scaledSize,
x, y + scaledSize
};
GLfloat tex[] = {
fcol, frow,
fcol + size, frow,
fcol + size, frow + size,
fcol, frow + size
};
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, vtx );
glTexCoordPointer( 2, GL_FLOAT, 0, tex );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
R_Buffer2DQuad(x, y, x + scaledSize, y + scaledSize,
fcol, frow, fcol + size, frow + size);
}
image_t *
@ -203,6 +182,14 @@ RDraw_PicScaled(int x, int y, const char *pic, float factor)
Scrap_Upload();
}
if (gl->texnum == TEXNUM_SCRAPS)
{
R_UpdateGLBuffer(buf_2d, TEXNUM_SCRAPS, 0, 0, 1);
R_Buffer2DQuad(x, y, x + gl->width * factor, y + gl->height * factor,
gl->sl, gl->tl, gl->sh, gl->th);
return;
}
R_Bind(gl->texnum);
GLfloat vtx[] = {
@ -248,31 +235,10 @@ RDraw_TileClear(int x, int y, int w, int h, const char *pic)
return;
}
R_Bind(image->texnum);
R_UpdateGLBuffer(buf_2d, image->texnum, 0, 0, 1);
GLfloat vtx[] = {
x, y,
x + w, y,
x + w, y + h,
x, y + h
};
GLfloat tex[] = {
x / 64.0, y / 64.0,
( x + w ) / 64.0, y / 64.0,
( x + w ) / 64.0, ( y + h ) / 64.0,
x / 64.0, ( y + h ) / 64.0
};
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glVertexPointer( 2, GL_FLOAT, 0, vtx );
glTexCoordPointer( 2, GL_FLOAT, 0, tex );
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
R_Buffer2DQuad(x, y, x + w, y + h, x / 64.0, y / 64.0,
( x + w ) / 64.0, ( y + h ) / 64.0);
}
/*
@ -319,6 +285,7 @@ RDraw_Fill(int x, int y, int w, int h, int c)
void
RDraw_FadeScreen(void)
{
R_ApplyGLBuffer(); // draw what needs to be hidden
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glColor4f(0, 0, 0, 0.8);

View file

@ -147,21 +147,12 @@ R_SetTexturePalette(const unsigned palette[256])
void
R_SelectTexture(GLenum texture)
{
int tmu;
if (!gl_config.multitexture)
if (!gl_config.multitexture || gl_state.currenttarget == texture)
{
return;
}
tmu = texture - GL_TEXTURE0;
if (tmu == gl_state.currenttmu)
{
return;
}
gl_state.currenttmu = tmu;
gl_state.currenttmu = texture - GL_TEXTURE0;
gl_state.currenttarget = texture;
qglActiveTexture(texture);
@ -180,7 +171,7 @@ R_TexEnv(GLenum mode)
}
}
void
qboolean
R_Bind(int texnum)
{
extern image_t *draw_chars;
@ -192,11 +183,12 @@ R_Bind(int texnum)
if (gl_state.currenttextures[gl_state.currenttmu] == texnum)
{
return;
return false;
}
gl_state.currenttextures[gl_state.currenttmu] = texnum;
glBindTexture(GL_TEXTURE_2D, texnum);
return true;
}
void
@ -308,7 +300,11 @@ R_TextureMode(const char *string)
nolerp = true;
}
R_Bind(glt->texnum);
if ( !R_Bind(glt->texnum) )
{
continue; // don't bother changing anything if texture was already set
}
if ((glt->type != it_pic) && (glt->type != it_sky)) /* mipmapped texture */
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);

View file

@ -32,54 +32,36 @@ vec3_t lightspot;
static void
R_RenderDlight(dlight_t *light)
{
const float rad = light->intensity * 0.35;
int i, j;
float rad;
float vtx[3];
rad = light->intensity * 0.35;
GLfloat vtx[3*18];
GLfloat clr[4*18];
unsigned int index_vtx = 3;
unsigned int index_clr = 0;
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
clr[index_clr++] = light->color [ 0 ] * 0.2;
clr[index_clr++] = light->color [ 1 ] * 0.2;
clr[index_clr++] = light->color [ 2 ] * 0.2;
clr[index_clr++] = 1;
R_SetBufferIndices(GL_TRIANGLE_FAN, 18);
for ( i = 0; i < 3; i++ )
{
vtx [ i ] = light->origin [ i ] - vpn [ i ] * rad;
}
R_BufferVertex( vtx[0], vtx[1], vtx[2] );
R_BufferColor( light->color[0] * 0.2, light->color[1] * 0.2,
light->color[2] * 0.2, 1 );
for ( i = 16; i >= 0; i-- )
{
float a;
clr[index_clr++] = 0;
clr[index_clr++] = 0;
clr[index_clr++] = 0;
clr[index_clr++] = 1;
a = i / 16.0 * M_PI * 2;
for ( j = 0; j < 3; j++ )
{
vtx[index_vtx++] = light->origin [ j ] + vright [ j ] * cos( a ) * rad
vtx[ j ] = light->origin [ j ] + vright [ j ] * cos( a ) * rad
+ vup [ j ] * sin( a ) * rad;
}
R_BufferVertex( vtx[0], vtx[1], vtx[2] );
R_BufferColor( 0, 0, 0, 1 );
}
glVertexPointer( 3, GL_FLOAT, 0, vtx );
glColorPointer( 4, GL_FLOAT, 0, clr );
glDrawArrays( GL_TRIANGLE_FAN, 0, 18 );
glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );
}
void
@ -92,6 +74,7 @@ R_RenderDlights(void)
{
return;
}
R_UpdateGLBuffer(buf_flash, 0, 0, 0, 1);
/* because the count hasn't advanced yet for this frame */
r_dlightframecount = r_framecount + 1;
@ -108,6 +91,7 @@ R_RenderDlights(void)
{
R_RenderDlight(l);
}
R_ApplyGLBuffer();
glColor4f(1, 1, 1, 1);
glDisable(GL_BLEND);

View file

@ -92,7 +92,6 @@ cvar_t *gl1_particle_square;
cvar_t *gl1_palettedtexture;
cvar_t *gl1_pointparameters;
cvar_t *gl1_multitexture;
cvar_t *gl1_biglightmaps;
cvar_t *gl_drawbuffer;
cvar_t *gl_lightmap;
@ -1171,6 +1170,7 @@ R_SetLightLevel(const entity_t *currententity)
static void
RI_RenderFrame(refdef_t *fd)
{
R_ApplyGLBuffer(); // menu rendering when needed
R_RenderView(fd);
R_SetLightLevel(NULL);
R_SetGL2D();
@ -1234,7 +1234,6 @@ R_Register(void)
gl1_palettedtexture = ri.Cvar_Get("r_palettedtextures", "0", CVAR_ARCHIVE);
gl1_pointparameters = ri.Cvar_Get("gl1_pointparameters", "1", CVAR_ARCHIVE);
gl1_multitexture = ri.Cvar_Get("gl1_multitexture", "1", CVAR_ARCHIVE);
gl1_biglightmaps = ri.Cvar_Get("gl1_biglightmaps", "1", CVAR_ARCHIVE);
gl_drawbuffer = ri.Cvar_Get("gl_drawbuffer", "GL_BACK", 0);
r_vsync = ri.Cvar_Get("r_vsync", "1", CVAR_ARCHIVE);
@ -1415,7 +1414,7 @@ R_SetMode(void)
qboolean
RI_Init(void)
{
int j, max_tex_size;
int j;
extern float r_turbsin[256];
Swap_Init();
@ -1633,35 +1632,17 @@ RI_Init(void)
// ----
/* Big lightmaps */
R_Printf(PRINT_ALL, " - Big lightmaps: ");
/* Big lightmaps: this used to be fast, but after the implementation of the "GL Buffer", it
* became too evident that the bigger the texture, the slower the call to glTexSubImage2D() is.
* Original logic remains, but it's preferable not to make it visible to the user.
* Let's see if something changes in the future.
*/
gl_state.block_width = BLOCK_WIDTH;
gl_state.block_height = BLOCK_HEIGHT;
gl_state.max_lightmaps = MAX_LIGHTMAPS;
gl_state.scrap_width = BLOCK_WIDTH;
gl_state.scrap_height = BLOCK_HEIGHT;
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_size);
if (max_tex_size > BLOCK_WIDTH)
{
if (gl1_biglightmaps->value)
{
gl_state.block_width = gl_state.block_height = Q_min(max_tex_size, 512);
gl_state.max_lightmaps = (BLOCK_WIDTH * BLOCK_HEIGHT * MAX_LIGHTMAPS)
/ (gl_state.block_width * gl_state.block_height);
gl_state.scrap_width = gl_state.scrap_height =
(gl_config.npottextures)? Q_min(max_tex_size, 384) : Q_min(max_tex_size, 256);
R_Printf(PRINT_ALL, "Okay\n");
}
else
{
R_Printf(PRINT_ALL, "Disabled\n");
}
}
else
{
R_Printf(PRINT_ALL, "Failed, detected texture size = %d\n", max_tex_size);
}
gl_state.scrap_width = BLOCK_WIDTH * 2;
gl_state.scrap_height = BLOCK_HEIGHT * 2;
// ----

View file

@ -31,31 +31,8 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
float alpha, dxtrivertx_t *verts, vec4_t *s_lerped, const float *shadelight,
const float *shadevector)
{
#ifdef _MSC_VER // workaround for lack of VLAs (=> our workaround uses alloca() which is bad in loops)
int maxCount = 0;
const int* tmpOrder = order;
while (1)
{
int c = *tmpOrder++;
if (!c)
break;
if ( c < 0 )
c = -c;
if ( c > maxCount )
maxCount = c;
tmpOrder += 3 * c;
}
YQ2_VLA( GLfloat, vtx, 3 * maxCount );
YQ2_VLA( GLfloat, tex, 2 * maxCount );
YQ2_VLA( GLfloat, clr, 4 * maxCount );
#endif
while (1)
{
unsigned short total;
GLenum type;
int count;
/* get the vertex count and primitive type */
@ -69,28 +46,16 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
if (count < 0)
{
count = -count;
type = GL_TRIANGLE_FAN;
R_SetBufferIndices(GL_TRIANGLE_FAN, count);
}
else
{
type = GL_TRIANGLE_STRIP;
R_SetBufferIndices(GL_TRIANGLE_STRIP, count);
}
total = count;
#ifndef _MSC_VER // we have real VLAs, so it's safe to use one in this loop
YQ2_VLA(GLfloat, vtx, 3*total);
YQ2_VLA(GLfloat, tex, 2*total);
YQ2_VLA(GLfloat, clr, 4*total);
#endif
if (currententity->flags &
(RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE))
{
unsigned int index_vtx = 0;
unsigned int index_clr = 0;
do
{
int index_xyz;
@ -98,32 +63,25 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
index_xyz = order[2];
order += 3;
clr[index_clr++] = shadelight[0];
clr[index_clr++] = shadelight[1];
clr[index_clr++] = shadelight[2];
clr[index_clr++] = alpha;
R_BufferVertex(s_lerped[index_xyz][0],
s_lerped[index_xyz][1], s_lerped[index_xyz][2]);
vtx[index_vtx++] = s_lerped[index_xyz][0];
vtx[index_vtx++] = s_lerped[index_xyz][1];
vtx[index_vtx++] = s_lerped[index_xyz][2];
R_BufferColor(shadelight[0], shadelight[1],
shadelight[2], alpha);
}
while (--count);
}
else
{
unsigned int index_vtx = 0;
unsigned int index_tex = 0;
unsigned int index_clr = 0;
do
{
int i, index_xyz;
vec3_t normal;
float l;
float l, tex[2];
/* texture coordinates come from the draw list */
tex[index_tex++] = ((float *) order)[0];
tex[index_tex++] = ((float *) order)[1];
tex[0] = ((float *)order)[0];
tex[1] = ((float *)order)[1];
index_xyz = order[2];
order += 3;
@ -138,35 +96,17 @@ R_DrawAliasDrawCommands(const entity_t *currententity, int *order, const int *or
/* shadevector is set above according to rotation (around Z axis I think) */
l = DotProduct(normal, shadevector) + 1;
clr[index_clr++] = l * shadelight[0];
clr[index_clr++] = l * shadelight[1];
clr[index_clr++] = l * shadelight[2];
clr[index_clr++] = alpha;
R_BufferVertex(s_lerped[index_xyz][0],
s_lerped[index_xyz][1], s_lerped[index_xyz][2]);
vtx[index_vtx++] = s_lerped[index_xyz][0];
vtx[index_vtx++] = s_lerped[index_xyz][1];
vtx[index_vtx++] = s_lerped[index_xyz][2];
R_BufferSingleTex(tex[0], tex[1]);
R_BufferColor(l * shadelight[0], l * shadelight[1],
l * shadelight[2], alpha);
}
while (--count);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vtx);
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glColorPointer(4, GL_FLOAT, 0, clr);
glDrawArrays(type, 0, total);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
YQ2_VLAFREE( vtx );
YQ2_VLAFREE( tex );
YQ2_VLAFREE( clr );
}
/*
@ -211,11 +151,6 @@ R_DrawAliasFrameLerp(entity_t *currententity, dmdx_t *paliashdr, float backlerp,
alpha = 1.0;
}
if (colorOnly)
{
glDisable(GL_TEXTURE_2D);
}
frontlerp = 1.0 - backlerp;
/* move should be the delta back to the previous frame * backlerp */
@ -252,41 +187,15 @@ R_DrawAliasFrameLerp(entity_t *currententity, dmdx_t *paliashdr, float backlerp,
mesh_nodes[i].ofs_glcmds + mesh_nodes[i].num_glcmds),
alpha, verts, s_lerped, shadelight, shadevector);
}
if (colorOnly)
{
glEnable(GL_TEXTURE_2D);
}
}
static void
R_DrawAliasShadowCommand(const entity_t *currententity, int *order, const int *order_end,
float height, float lheight, vec4_t *s_lerped, const float *shadevector)
{
unsigned short total;
vec3_t point;
GLenum type;
int count;
#ifdef _MSC_VER // workaround for lack of VLAs (=> our workaround uses alloca() which is bad in loops)
int maxCount = 0;
const int* tmpOrder = order;
while (1)
{
int c = *tmpOrder++;
if (!c)
break;
if (c < 0)
c = -c;
if (c > maxCount)
maxCount = c;
tmpOrder += 3 * c;
}
YQ2_VLA(GLfloat, vtx, 3 * maxCount);
#endif
while (1)
{
/* get the vertex count and primitive type */
@ -300,21 +209,13 @@ R_DrawAliasShadowCommand(const entity_t *currententity, int *order, const int *o
if (count < 0)
{
count = -count;
type = GL_TRIANGLE_FAN;
R_SetBufferIndices(GL_TRIANGLE_FAN, count);
}
else
{
type = GL_TRIANGLE_STRIP;
R_SetBufferIndices(GL_TRIANGLE_STRIP, count);
}
total = count;
#ifndef _MSC_VER // we have real VLAs, so it's safe to use one in this loop
YQ2_VLA(GLfloat, vtx, 3*total);
#endif
unsigned int index_vtx = 0;
do
{
/* normals and vertexes come from the frame list */
@ -324,22 +225,12 @@ R_DrawAliasShadowCommand(const entity_t *currententity, int *order, const int *o
point[1] -= shadevector[1] * (point[2] + lheight);
point[2] = height;
vtx[index_vtx++] = point[0];
vtx[index_vtx++] = point[1];
vtx[index_vtx++] = point[2];
R_BufferVertex( point[0], point[1], point[2] );
order += 3;
}
while (--count);
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, vtx );
glDrawArrays( type, 0, total );
glDisableClientState( GL_VERTEX_ARRAY );
}
YQ2_VLAFREE(vtx);
}
static void
@ -354,6 +245,8 @@ R_DrawAliasShadow(entity_t *currententity, dmdx_t *paliashdr, int posenum,
order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
height = -lheight + 0.1f;
R_UpdateGLBuffer(buf_shadow, 0, 0, 0, 1);
/* stencilbuffer shadows */
if (gl_state.stencil && gl1_stencilshadow->value)
{
@ -374,6 +267,8 @@ R_DrawAliasShadow(entity_t *currententity, dmdx_t *paliashdr, int posenum,
height, lheight, s_lerped, shadevector);
}
R_ApplyGLBuffer();
/* stencilbuffer shadows */
if (gl_state.stencil && gl1_stencilshadow->value)
{
@ -439,7 +334,6 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
}
}
R_EnableMultitexture(false);
paliashdr = (dmdx_t *)currentmodel->extradata;
/* get lighting information */
@ -593,45 +487,6 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
/* locate the proper data */
c_alias_polys += paliashdr->num_tris;
/* draw all the triangles */
if (currententity->flags & RF_DEPTHHACK)
{
/* hack the depth range to prevent view model from poking into walls */
glDepthRange(gldepthmin, gldepthmin + 0.3 * (gldepthmax - gldepthmin));
}
if (currententity->flags & RF_WEAPONMODEL)
{
extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
if (gl_lefthand->value == 1.0F)
{
glScalef(-1, 1, 1);
}
float dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f;
if (r_gunfov->value < 0)
{
R_MYgluPerspective(r_newrefdef.fov_y, (float)r_newrefdef.width / r_newrefdef.height, 4, dist);
}
else
{
R_MYgluPerspective(r_gunfov->value, (float)r_newrefdef.width / r_newrefdef.height, 4, dist);
}
glMatrixMode(GL_MODELVIEW);
if (gl_lefthand->value == 1.0F)
{
glCullFace(GL_BACK);
}
}
glPushMatrix();
currententity->angles[PITCH] = -currententity->angles[PITCH];
R_RotateForEntity(currententity);
@ -660,18 +515,6 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
skin = r_notexture; /* fallback... */
}
R_Bind(skin->texnum);
/* draw it */
glShadeModel(GL_SMOOTH);
R_TexEnv(GL_MODULATE);
if (currententity->flags & RF_TRANSLUCENT)
{
glEnable(GL_BLEND);
}
if ((currententity->frame >= paliashdr->num_frames) ||
(currententity->frame < 0))
{
@ -698,8 +541,10 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
/* buffer for scalled vert from frame */
s_lerped = R_VertBufferRealloc(paliashdr->num_xyz);
R_UpdateGLBuffer(buf_alias, skin->texnum, 0, currententity->flags, 1);
R_DrawAliasFrameLerp(currententity, paliashdr, currententity->backlerp,
s_lerped, shadelight, shadevector);
R_ApplyGLBuffer();
R_TexEnv(GL_REPLACE);
glShadeModel(GL_FLAT);
@ -722,25 +567,6 @@ R_DrawAliasModel(entity_t *currententity, const model_t *currentmodel)
glEnable(GL_CULL_FACE);
}
if (currententity->flags & RF_WEAPONMODEL)
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
if (gl_lefthand->value == 1.0F)
glCullFace(GL_FRONT);
}
if (currententity->flags & RF_TRANSLUCENT)
{
glDisable(GL_BLEND);
}
if (currententity->flags & RF_DEPTHHACK)
{
glDepthRange(gldepthmin, gldepthmax);
}
if (gl_shadows->value &&
!(currententity->flags & (RF_TRANSLUCENT | RF_WEAPONMODEL | RF_NOSHADOW)))
{

View file

@ -46,6 +46,7 @@ static qboolean vsyncActive = false;
void
RI_EndFrame(void)
{
R_ApplyGLBuffer(); // to draw buffered 2D text
SDL_GL_SwapWindow(window);
}

View file

@ -40,55 +40,24 @@ void LM_UploadBlock(qboolean dynamic);
qboolean LM_AllocBlock(int w, int h, int *x, int *y);
static void
R_DrawGLPoly(mpoly_t *p)
R_DrawGLPoly(msurface_t *fa)
{
mvtx_t* vert = p->verts;
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(mvtx_t), vert->pos);
glTexCoordPointer(2, GL_FLOAT, sizeof(mvtx_t), vert->texCoord);
glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
static void
R_DrawGLFlowingPoly(msurface_t *fa)
{
int i;
mvtx_t* vert;
mpoly_t *p;
int i, nv;
mvtx_t *v;
float sscroll, tscroll;
p = fa->polys;
v = fa->polys->verts;
nv = fa->polys->numverts;
R_FlowingScroll(&r_newrefdef, fa->texinfo->flags, &sscroll, &tscroll);
YQ2_VLA(GLfloat, tex, 2 * p->numverts);
unsigned int index_tex = 0;
R_SetBufferIndices(GL_TRIANGLE_FAN, nv);
vert = p->verts;
for ( i = 0; i < p->numverts; i++, vert++)
for ( i = 0; i < nv; i++, v ++)
{
tex[index_tex++] = vert->texCoord[0] + sscroll;
tex[index_tex++] = vert->texCoord[1] + tscroll;
R_BufferVertex(v->pos[0], v->pos[1], v->pos[2]);
R_BufferSingleTex(v->texCoord[0] + sscroll, v->texCoord[1] + tscroll);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(mvtx_t), p->verts->pos);
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
YQ2_VLAFREE(tex);
}
static void
@ -410,47 +379,11 @@ R_RenderBrushPoly(const entity_t *currententity, msurface_t *fa)
if (fa->flags & SURF_DRAWTURB)
{
/* This is a hack ontop of a hack. Warping surfaces like those generated
by R_EmitWaterPolys() don't have a lightmap. Original Quake II therefore
negated the global intensity on those surfaces, because otherwise they
would show up much too bright. When we implemented overbright bits this
hack modified the global GL state in an incompatible way. So implement
a new hack, based on overbright bits... Depending on the value set to
gl1_overbrightbits the result is different:
0: Old behaviour.
1: No overbright bits on the global scene but correct lighting on
warping surfaces.
2: Overbright bits on the global scene but not on warping surfaces.
They oversaturate otherwise. */
if (gl1_overbrightbits->value)
{
R_TexEnv(GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
}
else
{
R_TexEnv(GL_MODULATE);
glColor4f(gl_state.inverse_intensity, gl_state.inverse_intensity,
gl_state.inverse_intensity, 1.0f);
}
R_EmitWaterPolys(fa);
R_TexEnv(GL_REPLACE);
return;
}
R_TexEnv(GL_REPLACE);
if (fa->texinfo->flags & SURF_SCROLL)
{
R_DrawGLFlowingPoly(fa);
}
else
{
R_DrawGLPoly(fa->polys);
}
R_DrawGLPoly(fa);
if (gl_config.multitexture)
{
@ -532,7 +465,7 @@ void
R_DrawAlphaSurfaces(void)
{
msurface_t *s;
float intens;
float alpha;
/* go back to the world matrix */
glLoadMatrixf(r_world_matrix);
@ -540,41 +473,35 @@ R_DrawAlphaSurfaces(void)
glEnable(GL_BLEND);
R_TexEnv(GL_MODULATE);
/* the textures are prescaled up for a better
lighting range, so scale it back down */
intens = gl_state.inverse_intensity;
for (s = r_alpha_surfaces; s; s = s->texturechain)
{
R_Bind(s->texinfo->image->texnum);
c_brush_polys++;
if (s->texinfo->flags & SURF_TRANS33)
{
glColor4f(intens, intens, intens, 0.33);
alpha = 0.33f;
}
else if (s->texinfo->flags & SURF_TRANS66)
{
glColor4f(intens, intens, intens, 0.66);
alpha = 0.66f;
}
else
{
glColor4f(intens, intens, intens, 1);
alpha = 1.0f;
}
R_UpdateGLBuffer(buf_alpha, s->texinfo->image->texnum, 0, 0, alpha);
if (s->flags & SURF_DRAWTURB)
{
R_EmitWaterPolys(s);
}
else if (s->texinfo->flags & SURF_SCROLL)
{
R_DrawGLFlowingPoly(s);
}
else
{
R_DrawGLPoly(s->polys);
R_DrawGLPoly(s);
}
}
R_ApplyGLBuffer(); // Flush the last batched array
R_TexEnv(GL_REPLACE);
glColor4f(1, 1, 1, 1);
@ -635,104 +562,21 @@ R_RenderLightmappedPoly(const entity_t *currententity, msurface_t *surf)
int i;
int nv = surf->polys->numverts;
mvtx_t* vert;
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + surf->lightmaptexturenum);
// Apply overbrightbits to TMU 1 (lightmap)
if (gl1_overbrightbits->value)
{
R_TexEnv(GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, gl1_overbrightbits->value);
}
float sscroll, tscroll;
c_brush_polys++;
vert = surf->polys->verts;
if (surf->texinfo->flags & SURF_FLOWING)
R_FlowingScroll(&r_newrefdef, surf->texinfo->flags, &sscroll, &tscroll);
R_SetBufferIndices(GL_TRIANGLE_FAN, nv);
for (i = 0; i < nv; i++, vert++)
{
float sscroll, tscroll;
R_FlowingScroll(&r_newrefdef, surf->texinfo->flags, &sscroll, &tscroll);
YQ2_VLA(GLfloat, tex, 4 * nv);
unsigned int index_tex = 0;
for (i = 0; i < nv; i++, vert++)
{
tex[index_tex++] = vert->texCoord[0] + sscroll;
tex[index_tex++] = vert->texCoord[1] + tscroll;
tex[index_tex++] = vert->lmTexCoord[0];
tex[index_tex++] = vert->lmTexCoord[1];
}
// Polygon
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(mvtx_t), surf->polys->verts->pos);
// Texture
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), tex);
// Lightmap
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglClientActiveTexture(GL_TEXTURE1);
glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(GLfloat), tex + 2);
// Draw the thing
glDrawArrays(GL_TRIANGLE_FAN, 0, nv);
YQ2_VLAFREE(tex);
R_BufferVertex( vert->pos[0], vert->pos[1], vert->pos[2] );
R_BufferMultiTex( vert->texCoord[0] + sscroll, vert->texCoord[1] + tscroll,
vert->lmTexCoord[0], vert->lmTexCoord[1] );
}
else
{
// Polygon
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(mvtx_t), vert->pos);
// Texture
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, GL_FLOAT, sizeof(mvtx_t), vert->texCoord);
// Lightmap
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
qglClientActiveTexture(GL_TEXTURE1);
glTexCoordPointer(2, GL_FLOAT, sizeof(mvtx_t), vert->lmTexCoord);
// Draw it
glDrawArrays(GL_TRIANGLE_FAN, 0, nv);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
static void
R_UploadDynamicLights(msurface_t *surf)
{
int map, smax, tmax, size;
byte *temp;
if ( !gl_config.multitexture || !R_HasDynamicLights(surf, &map) )
{
return;
}
smax = (surf->extents[0] >> surf->lmshift) + 1;
tmax = (surf->extents[1] >> surf->lmshift) + 1;
size = smax * tmax * LIGHTMAP_BYTES;
temp = R_GetTemporaryLMBuffer(size);
R_BuildLightMap(surf, (void *) temp, smax * LIGHTMAP_BYTES,
&r_newrefdef, r_modulate->value, r_framecount);
R_UpdateSurfCache(surf, map);
R_Bind(gl_state.lightmap_textures + surf->lightmaptexturenum);
glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax,
tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp);
YQ2_VLAFREE(temp);
}
/* Upload dynamic lights to each lightmap texture (multitexture path only) */
@ -859,17 +703,16 @@ R_DrawTextureChains(const entity_t *currententity)
for ( ; s; s = s->texturechain)
{
R_Bind(image->texnum); // may reset because of dynamic lighting in R_RenderBrushPoly
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1);
R_RenderBrushPoly(currententity, s);
}
image->texturechain = NULL;
}
R_ApplyGLBuffer(); // Flush the last batched array
}
else // multitexture
{
R_EnableMultitexture(true);
for (i = 0, image = gltextures; i < numgltextures; i++, image++)
{
if (!image->registration_sequence || !image->texturechain)
@ -877,19 +720,20 @@ R_DrawTextureChains(const entity_t *currententity)
continue;
}
R_MBind(GL_TEXTURE0, image->texnum); // setting it only once
c_visible_textures++;
for (s = image->texturechain; s; s = s->texturechain)
{
if (!(s->flags & SURF_DRAWTURB))
{
R_UpdateGLBuffer(buf_mtex, image->texnum, s->lightmaptexturenum, 0, 1);
R_RenderLightmappedPoly(currententity, s);
}
}
}
R_ApplyGLBuffer();
R_EnableMultitexture(false);
R_EnableMultitexture(false); // force disabling, SURF_DRAWTURB surfaces may not exist
for (i = 0, image = gltextures; i < numgltextures; i++, image++)
{
@ -902,13 +746,14 @@ R_DrawTextureChains(const entity_t *currententity)
{
if (s->flags & SURF_DRAWTURB)
{
R_Bind(image->texnum);
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, s->flags, 1);
R_RenderBrushPoly(currententity, s);
}
}
image->texturechain = NULL;
}
R_ApplyGLBuffer();
}
}
@ -920,7 +765,7 @@ R_DrawInlineBModel(const entity_t *currententity, const model_t *currentmodel)
image_t *image;
/* calculate dynamic lighting for bmodel */
if (!r_flashblend->value)
if (!gl_config.multitexture && !r_flashblend->value)
{
R_PushDlights(&r_newrefdef, currentmodel->nodes + currentmodel->firstnode,
r_dlightframecount, currentmodel->surfaces);
@ -962,20 +807,19 @@ R_DrawInlineBModel(const entity_t *currententity, const model_t *currentmodel)
if (gl_config.multitexture && !(psurf->flags & SURF_DRAWTURB))
{
R_UploadDynamicLights(psurf);
R_EnableMultitexture(true);
R_MBind(GL_TEXTURE0, image->texnum);
// Dynamic lighting already generated in R_GetBrushesLighting()
R_UpdateGLBuffer(buf_mtex, image->texnum, psurf->lightmaptexturenum, 0, 1);
R_RenderLightmappedPoly(currententity, psurf);
}
else
{
R_EnableMultitexture(false);
R_Bind(image->texnum);
R_UpdateGLBuffer(buf_singletex, image->texnum, 0, psurf->flags, 1);
R_RenderBrushPoly(currententity, psurf);
}
}
}
}
R_ApplyGLBuffer();
if (!(currententity->flags & RF_TRANSLUCENT))
{
@ -1212,6 +1056,89 @@ R_RecursiveWorldNode(entity_t *currententity, mnode_t *node)
R_RecursiveWorldNode(currententity, node->children[!side]);
}
/*
* This is for the RegenAllLightmaps() function to be able to regenerate
* lighting not only for the world, but also for the brushes in the entity list.
* Logic extracted from R_DrawBrushModel() & R_DrawInlineBModel().
*/
static void
R_GetBrushesLighting(void)
{
int i, k;
vec3_t mins, maxs;
msurface_t *surf;
cplane_t *pplane;
float dot;
if (!gl_config.multitexture || !r_drawentities->value || r_flashblend->value)
{
return;
}
for (i = 0; i < r_newrefdef.num_entities; i++)
{
entity_t *currententity = &r_newrefdef.entities[i];
if (currententity->flags & RF_BEAM)
{
continue;
}
const model_t *currentmodel = currententity->model;
if (!currentmodel || currentmodel->type != mod_brush || currentmodel->nummodelsurfaces == 0)
{
continue;
}
// from R_DrawBrushModel()
if (currententity->angles[0] || currententity->angles[1] || currententity->angles[2])
{
for (k = 0; k < 3; k++)
{
mins[k] = currententity->origin[k] - currentmodel->radius;
maxs[k] = currententity->origin[k] + currentmodel->radius;
}
}
else
{
VectorAdd(currententity->origin, currentmodel->mins, mins);
VectorAdd(currententity->origin, currentmodel->maxs, maxs);
}
if (r_cull->value && R_CullBox(mins, maxs, frustum))
{
continue;
}
// from R_DrawInlineBModel()
R_PushDlights(&r_newrefdef, currentmodel->nodes + currentmodel->firstnode,
r_dlightframecount, currentmodel->surfaces);
surf = &currentmodel->surfaces[currentmodel->firstmodelsurface];
for (k = 0; k < currentmodel->nummodelsurfaces; k++, surf++)
{
if (surf->texinfo->flags & (SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)
|| surf->flags & SURF_DRAWTURB)
{
continue;
}
// find which side of the node we are on
pplane = surf->plane;
dot = DotProduct(modelorg, pplane->normal) - pplane->dist;
if (((surf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
(!(surf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
{
surf->lightmapchain = gl_lms.lightmap_surfaces[surf->lightmaptexturenum];
gl_lms.lightmap_surfaces[surf->lightmaptexturenum] = surf;
}
}
}
}
void
R_DrawWorld(void)
{
@ -1240,6 +1167,7 @@ R_DrawWorld(void)
RE_ClearSkyBox();
R_RecursiveWorldNode(&ent, r_worldmodel->nodes);
R_GetBrushesLighting();
R_RegenAllLightmaps();
R_DrawTextureChains(&ent);
R_BlendLightmaps(r_worldmodel);

View file

@ -68,60 +68,30 @@ R_EmitWaterPolys(msurface_t *fa)
{
mpoly_t *p, *bp;
mvtx_t *v;
int i;
int i, nv;
float s, t, os, ot;
float sscroll, tscroll;
R_FlowingScroll(&r_newrefdef, fa->texinfo->flags, &sscroll, &tscroll);
// workaround for lack of VLAs (=> our workaround uses alloca() which is bad in loops)
#ifdef _MSC_VER
int maxNumVerts = 0;
for ( mpoly_t* tmp = fa->polys; tmp; tmp = tmp->next )
{
if (tmp->numverts > maxNumVerts)
maxNumVerts = tmp->numverts;
}
YQ2_VLA( GLfloat, tex, 2 * maxNumVerts );
#endif
for (bp = fa->polys; bp; bp = bp->next)
{
p = bp;
#ifndef _MSC_VER // we have real VLAs, so it's safe to use one in this loop
YQ2_VLA(GLfloat, tex, 2 * p->numverts);
#endif
unsigned int index_tex = 0;
nv = p->numverts;
R_SetBufferIndices(GL_TRIANGLE_FAN, nv);
for ( i = 0, v = p->verts; i < p->numverts; i++, v++)
{
os = v->texCoord[0];
ot = v->texCoord[1];
s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ];
s += sscroll;
tex[index_tex++] = s * ( 1.0 / 64 );
s = os + r_turbsin [ (int) ( ( ot * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + sscroll;
t = ot + r_turbsin [ (int) ( ( os * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ] + tscroll;
t = ot + r_turbsin [ (int) ( ( os * 0.125 + r_newrefdef.time ) * TURBSCALE ) & 255 ];
t += tscroll;
tex[index_tex++] = t * ( 1.0 / 64 );
R_BufferVertex( v->pos[0], v->pos[1], v->pos[2] );
R_BufferSingleTex( s * ( 1.0 / 64 ), t * ( 1.0 / 64 ) );
}
v = p->verts;
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(mvtx_t), v->pos);
glTexCoordPointer(2, GL_FLOAT, 0, tex);
glDrawArrays(GL_TRIANGLE_FAN, 0, p->numverts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
YQ2_VLAFREE( tex );
}
void

View file

@ -39,14 +39,15 @@
#define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX
#endif
#define TEXNUM_LIGHTMAPS 1024
#define TEXNUM_SCRAPS 1152
#define TEXNUM_IMAGES 1153
#define MAX_LIGHTMAPS 256
#define MAX_SCRAPS 1
#define TEXNUM_LIGHTMAPS 1024
#define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS)
#define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS)
#define BLOCK_WIDTH 256 // default values; now defined in glstate_t
#define BLOCK_HEIGHT 256
#define REF_VERSION "Yamagi Quake II OpenGL Refresher"
#define MAX_LIGHTMAPS 256
#define MAX_TEXTURE_UNITS 2
#define GL_LIGHTMAP_FORMAT GL_RGBA
extern viddef_t vid;
@ -85,22 +86,23 @@ typedef struct image_s
qboolean paletted;
} image_t;
#include "model.h"
typedef enum
{
buf_2d,
buf_singletex,
buf_mtex,
buf_alpha,
buf_alias,
buf_flash,
buf_shadow
} buffered_draw_t;
void GL_BeginRendering(int *x, int *y, int *width, int *height);
void GL_EndRendering(void);
#include "model.h"
void R_SetDefaultState(void);
extern float gldepthmin, gldepthmax;
typedef struct
{
float x, y, z;
float s, t;
float r, g, b;
} glvert_t;
extern image_t gltextures[MAX_TEXTURES];
extern int numgltextures;
@ -144,7 +146,6 @@ extern cvar_t *gl1_overbrightbits;
extern cvar_t *gl1_palettedtexture;
extern cvar_t *gl1_pointparameters;
extern cvar_t *gl1_multitexture;
extern cvar_t *gl1_biglightmaps;
extern cvar_t *gl1_particle_min_size;
extern cvar_t *gl1_particle_max_size;
@ -211,7 +212,7 @@ extern int c_visible_textures;
extern float r_world_matrix[16];
void R_TranslatePlayerSkin(int playernum);
void R_Bind(int texnum);
qboolean R_Bind(int texnum);
void R_TexEnv(GLenum value);
void R_SelectTexture(GLenum);
@ -265,12 +266,23 @@ void R_TextureAlphaMode(const char *string);
void R_TextureSolidMode(const char *string);
int Scrap_AllocBlock(int w, int h, int *x, int *y);
void R_ApplyGLBuffer(void);
void R_UpdateGLBuffer(buffered_draw_t type, int colortex, int lighttex, int flags, float alpha);
void R_Buffer2DQuad(GLfloat ul_vx, GLfloat ul_vy, GLfloat dr_vx, GLfloat dr_vy,
GLfloat ul_tx, GLfloat ul_ty, GLfloat dr_tx, GLfloat dr_ty);
void R_SetBufferIndices(GLenum type, GLuint vertices_num);
void R_BufferVertex(GLfloat x, GLfloat y, GLfloat z);
void R_BufferSingleTex(GLfloat s, GLfloat t);
void R_BufferMultiTex(GLfloat cs, GLfloat ct, GLfloat ls, GLfloat lt);
void R_BufferColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
#ifdef DEBUG
void glCheckError_(const char *file, const char *function, int line);
// Ideally, the following list should contain all OpenGL calls.
// Either way, errors are caught, since error flags are persisted until the next glGetError() call.
// So they show, even if the location of the error is inaccurate.
#define glDrawArrays(...) glDrawArrays(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
#define glDrawElements(...) glDrawElements(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
#define glTexImage2D(...) glTexImage2D(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
#define glTexSubImage2D(...) glTexSubImage2D(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
#define glTexEnvf(...) glTexEnvf(__VA_ARGS__); glCheckError_(__FILE__, __func__, __LINE__)
@ -352,7 +364,7 @@ typedef struct
int lightmap_textures;
int currenttextures[2];
int currenttextures[MAX_TEXTURE_UNITS];
int currenttmu;
GLenum currenttarget;