diff options
-rw-r--r-- | inc/common/bsp.h | 6 | ||||
-rw-r--r-- | inc/shared/shared.h | 2 | ||||
-rw-r--r-- | src/common/bsp.c | 4 | ||||
-rw-r--r-- | src/refresh/gl/draw.c | 13 | ||||
-rw-r--r-- | src/refresh/gl/gl.h | 289 | ||||
-rw-r--r-- | src/refresh/gl/images.c | 60 | ||||
-rw-r--r-- | src/refresh/gl/main.c | 92 | ||||
-rw-r--r-- | src/refresh/gl/mesh.c | 119 | ||||
-rw-r--r-- | src/refresh/gl/models.c | 15 | ||||
-rw-r--r-- | src/refresh/gl/sky.c | 11 | ||||
-rw-r--r-- | src/refresh/gl/state.c | 427 | ||||
-rw-r--r-- | src/refresh/gl/surf.c | 502 | ||||
-rw-r--r-- | src/refresh/gl/tess.c | 398 | ||||
-rw-r--r-- | src/refresh/gl/world.c | 179 |
14 files changed, 1145 insertions, 972 deletions
diff --git a/inc/common/bsp.h b/inc/common/bsp.h index ca0dba2..47c7797 100644 --- a/inc/common/bsp.h +++ b/inc/common/bsp.h @@ -69,8 +69,9 @@ typedef struct { int vert; } msurfedge_t; -#define SURF_NOLM_MASK \ - (SURF_SKY | SURF_WARP | SURF_FLOWING | SURF_TRANS33 | SURF_TRANS66) +#define SURF_TRANS_MASK (SURF_TRANS33 | SURF_TRANS66) +#define SURF_COLOR_MASK (SURF_TRANS_MASK | SURF_WARP) +#define SURF_NOLM_MASK (SURF_COLOR_MASK | SURF_FLOWING | SURF_SKY) #define DSURF_PLANEBACK 1 @@ -95,6 +96,7 @@ typedef struct mface_s { #if USE_REF == REF_GL int texnum[2]; + int statebits; int firstvert; int light_s, light_t; float stylecache[MAX_LIGHTMAPS]; diff --git a/inc/shared/shared.h b/inc/shared/shared.h index ba3b87d..372c792 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -695,6 +695,8 @@ COLLISION DETECTION #define SURF_FLOWING 0x40 // scroll towards angle #define SURF_NODRAW 0x80 // don't bother referencing the texture +#define SURF_ALPHATEST 0x02000000 // used by kmquake2 + // content masks diff --git a/src/common/bsp.c b/src/common/bsp.c index aa3a045..804b98a 100644 --- a/src/common/bsp.c +++ b/src/common/bsp.c @@ -388,6 +388,10 @@ LOAD(Faces) DEBUG("bad surfedges"); return Q_ERR_TOO_FEW; } + if (numedges > 4096) { + DEBUG("bad surfedges"); + return Q_ERR_TOO_MANY; + } if (lastedge < firstedge || lastedge > bsp->numsurfedges) { DEBUG("bad surfedges"); return Q_ERR_BAD_INDEX; diff --git a/src/refresh/gl/draw.c b/src/refresh/gl/draw.c index 344cf57..cd54d1a 100644 --- a/src/refresh/gl/draw.c +++ b/src/refresh/gl/draw.c @@ -27,7 +27,7 @@ static inline void _GL_StretchPic( { vec_t *dst_vert; uint32_t *dst_color; - int *dst_indices; + QGL_INDEX_TYPE *dst_indices; if (tess.numverts + 4 > TESS_MAX_VERTICES || tess.numindices + 6 > TESS_MAX_INDICES || @@ -181,10 +181,7 @@ void R_SetScale(float *scale) GL_Flush2D(); - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity(); - - qglOrtho(0, Q_rint(r_config.width * f), + GL_Ortho(0, Q_rint(r_config.width * f), Q_rint(r_config.height * f), 0, -1, 1); draw.scale = f; @@ -339,9 +336,9 @@ void Draw_Stats(void) } if (c.batchesDrawn) { Draw_Stringf(x, y, "Batches drawn: %i", c.batchesDrawn); y += 10; - Draw_Stringf(x, y, "Faces / batch: %i", c.facesDrawn / c.batchesDrawn); + Draw_Stringf(x, y, "Faces / batch: %.1f", (float)c.facesDrawn / c.batchesDrawn); y += 10; - Draw_Stringf(x, y, "Tris / batch : %i", c.trisDrawn / c.batchesDrawn); + Draw_Stringf(x, y, "Tris / batch : %.1f", (float)c.facesTris / c.batchesDrawn); y += 10; } Draw_Stringf(x, y, "2D batches : %i", c.batchesDrawn2D); y += 10; @@ -355,7 +352,7 @@ void Draw_Lightmaps(void) x = i & 1; y = i >> 1; _GL_StretchPic(256 * x, 256 * y, 256, 256, - 0, 0, 1, 1, U32_WHITE, TEXNUM_LIGHTMAP + i, 0); + 0, 0, 1, 1, U32_WHITE, lm.texnums[i], 0); } } diff --git a/src/refresh/gl/gl.h b/src/refresh/gl/gl.h index bd7fe77..e412ecd 100644 --- a/src/refresh/gl/gl.h +++ b/src/refresh/gl/gl.h @@ -36,47 +36,60 @@ with this program; if not, write to the Free Software Foundation, Inc., * */ +#if 0 +#define QGL_INDEX_TYPE GLushort +#define QGL_INDEX_ENUM GL_UNSIGNED_SHORT +#else +#define QGL_INDEX_TYPE GLuint +#define QGL_INDEX_ENUM GL_UNSIGNED_INT +#endif + #define MAX_TMUS 2 +#define TAB_SIN(x) gl_static.sintab[(x) & 255] +#define TAB_COS(x) gl_static.sintab[((x) + 64) & 255] + +#define NUM_TEXNUMS 6 + typedef struct { - qboolean registering; + qboolean registering; struct { - bsp_t *cache; - memhunk_t hunk; - vec_t *vertices; - GLuint bufnum; - float add, modulate, scale; - vec_t size; + bsp_t *cache; + memhunk_t hunk; + vec_t *vertices; + GLuint bufnum; + vec_t size; } world; - GLuint prognum_warp; - GLbitfield stencil_buffer_bit; - float entity_modulate; - float inverse_intensity; - float sintab[256]; -#define TAB_SIN(x) gl_static.sintab[(x) & 255] -#define TAB_COS(x) gl_static.sintab[((x) + 64) & 255] - byte latlngtab[NUMVERTEXNORMALS][2]; - byte lightstylemap[MAX_LIGHTSTYLES]; + GLuint prognum_warp; + GLuint texnums[NUM_TEXNUMS]; + GLbitfield stencil_buffer_bit; + float entity_modulate; + uint32_t inverse_intensity_33; + uint32_t inverse_intensity_66; + uint32_t inverse_intensity_100; + float sintab[256]; + byte latlngtab[NUMVERTEXNORMALS][2]; + byte lightstylemap[MAX_LIGHTSTYLES]; } glStatic_t; typedef struct { - refdef_t fd; - vec3_t viewaxis[3]; - GLfloat viewmatrix[16]; - int visframe; - int drawframe; + refdef_t fd; + vec3_t viewaxis[3]; + GLfloat viewmatrix[16]; + int visframe; + int drawframe; #if USE_DLIGHTS - int dlightframe; + int dlightframe; #endif - int viewcluster1; - int viewcluster2; - cplane_t frustumPlanes[4]; - entity_t *ent; - qboolean entrotated; - vec3_t entaxis[3]; - GLfloat entmatrix[16]; - lightpoint_t lightpoint; - int num_beams; + int viewcluster1; + int viewcluster2; + cplane_t frustumPlanes[4]; + entity_t *ent; + qboolean entrotated; + vec3_t entaxis[3]; + GLfloat entmatrix[16]; + lightpoint_t lightpoint; + int num_beams; } glRefdef_t; typedef struct { @@ -107,6 +120,7 @@ typedef struct { int leavesDrawn; int facesMarked; int facesDrawn; + int facesTris; int texSwitches; int texUploads; int trisDrawn; @@ -155,6 +169,7 @@ extern cvar_t *gl_novis; extern cvar_t *gl_lockpvs; extern cvar_t *gl_lightmap; extern cvar_t *gl_fullbright; +extern cvar_t *gl_vertexlight; typedef enum { CULL_OUT, @@ -183,35 +198,35 @@ qboolean GL_ShowErrors(const char *func); */ typedef struct maliastc_s { - float st[2]; + float st[2]; } maliastc_t; -typedef struct maliasvert_s { - short pos[3]; - byte norm[2]; // lat, lng +typedef struct masliasvert_s { + short pos[3]; + byte norm[2]; // lat, lng } maliasvert_t; typedef struct maliasframe_s { - vec3_t scale; - vec3_t translate; - vec3_t bounds[2]; - vec_t radius; + vec3_t scale; + vec3_t translate; + vec3_t bounds[2]; + vec_t radius; } maliasframe_t; typedef struct maliasmesh_s { - int numverts; - int numtris; - int numindices; - uint32_t *indices; - maliasvert_t *verts; - maliastc_t *tcoords; - image_t *skins[MAX_ALIAS_SKINS]; - int numskins; + int numverts; + int numtris; + int numindices; + QGL_INDEX_TYPE *indices; + maliasvert_t *verts; + maliastc_t *tcoords; + image_t *skins[MAX_ALIAS_SKINS]; + int numskins; } maliasmesh_t; -// xyz[3] + st[2] + lmst[2] -// xyz[3] + color[4] -#define VERTEX_SIZE 7 +// xyz[3] | color[1] | st[2] | lmst[2] +// xyz[3] | unused[1] | color[4] +#define VERTEX_SIZE 8 /* * gl_surf.c @@ -227,72 +242,141 @@ typedef struct maliasmesh_s { #define LM_BLOCK_HEIGHT 256 typedef struct { - int inuse[LM_BLOCK_WIDTH]; - byte buffer[LM_BLOCK_WIDTH * LM_BLOCK_HEIGHT * 4]; - qboolean dirty; - int comp; - int nummaps; - int highwater; + int inuse[LM_BLOCK_WIDTH]; + byte buffer[LM_BLOCK_WIDTH * LM_BLOCK_HEIGHT * 4]; + qboolean dirty; + int comp; + float add, modulate, scale; + int nummaps; + GLuint texnums[LM_MAX_LIGHTMAPS]; } lightmap_builder_t; extern lightmap_builder_t lm; void GL_AdjustColor(vec3_t color); -void GL_BeginLights(void); -void GL_EndLights(void); void GL_PushLights(mface_t *surf); -void LM_RebuildSurfaces(void); - -void GL_LoadWorld(const char *name); +void GL_RebuildLighting(void); void GL_FreeWorld(void); +void GL_LoadWorld(const char *name); /* * gl_state.c * */ typedef enum { - GLS_CULL_DISABLE, - GLS_CULL_FRONT, - GLS_CULL_BACK -} glCullFace_t; - -typedef enum { GLS_DEFAULT = 0, GLS_DEPTHMASK_FALSE = (1 << 0), GLS_DEPTHTEST_DISABLE = (1 << 1), GLS_BLEND_BLEND = (1 << 2), GLS_BLEND_ADD = (1 << 3), GLS_BLEND_MODULATE = (1 << 4), - GLS_ALPHATEST_ENABLE = (1 << 5) + GLS_ALPHATEST_ENABLE = (1 << 5), + GLS_TEXTURE_REPLACE = (1 << 6), + GLS_FLOW_ENABLE = (1 << 7), + GLS_LIGHTMAP_ENABLE = (1 << 8), + GLS_WARP_ENABLE = (1 << 9), + GLS_CULL_DISABLE = (1 << 10), + GLS_SHADE_SMOOTH = (1 << 11) } glStateBits_t; #define GLS_BLEND_MASK (GLS_BLEND_BLEND | GLS_BLEND_ADD | GLS_BLEND_MODULATE) +typedef enum { + GLA_NONE = 0, + GLA_VERTEX = (1 << 0), + GLA_TC = (1 << 1), + GLA_LMTC = (1 << 2), + GLA_COLOR = (1 << 3), +} glArrayBits_t; + typedef struct { - int tmu; - int texnum[MAX_TMUS]; - GLenum texenv[MAX_TMUS]; - glStateBits_t bits; - glCullFace_t cull; - qboolean fp_enabled; + GLuint client_tmu; + GLuint server_tmu; + GLuint texnums[MAX_TMUS]; + glStateBits_t state_bits; + glArrayBits_t array_bits; + const GLfloat *currentmatrix; } glState_t; extern glState_t gls; -void GL_BindTexture(int texnum); -void GL_SelectTMU(int tmu); -void GL_TexEnv(GLenum texenv); -void GL_CullFace(glCullFace_t cull); -void GL_Bits(glStateBits_t bits); +static inline void GL_ActiveTexture(GLuint tmu) +{ + if (gls.server_tmu != tmu) { + qglActiveTextureARB(GL_TEXTURE0_ARB + tmu); + gls.server_tmu = tmu; + } +} + +static inline void GL_ClientActiveTexture(GLuint tmu) +{ + if (gls.client_tmu != tmu) { + qglClientActiveTextureARB(GL_TEXTURE0_ARB + tmu); + gls.client_tmu = tmu; + } +} + +static inline void GL_VertexPointer(GLint size, GLsizei stride, const GLfloat *pointer) +{ + qglVertexPointer(size, GL_FLOAT, sizeof(GLfloat) * stride, pointer); +} + +static inline void GL_TexCoordPointer(GLint size, GLsizei stride, const GLfloat *pointer) +{ + GL_ClientActiveTexture(0); + qglTexCoordPointer(size, GL_FLOAT, sizeof(GLfloat) * stride, pointer); +} + +static inline void GL_LightCoordPointer(GLint size, GLsizei stride, const GLfloat *pointer) +{ + GL_ClientActiveTexture(1); + qglTexCoordPointer(size, GL_FLOAT, sizeof(GLfloat) * stride, pointer); +} + +static inline void GL_ColorBytePointer(GLint size, GLsizei stride, const GLubyte *pointer) +{ + qglColorPointer(size, GL_UNSIGNED_BYTE, sizeof(GLfloat) * stride, pointer); +} + +static inline void GL_ColorFloatPointer(GLint size, GLsizei stride, const GLfloat *pointer) +{ + qglColorPointer(size, GL_FLOAT, sizeof(GLfloat) * stride, pointer); +} + +static inline void GL_LockArrays(GLsizei count) +{ + if (qglLockArraysEXT) { + qglLockArraysEXT(0, count); + } +} + +static inline void GL_UnlockArrays(void) +{ + if (qglUnlockArraysEXT) { + qglUnlockArraysEXT(); + } +} + +static inline void GL_LoadMatrix(const GLfloat *matrix) +{ + if (gls.currentmatrix != matrix) { + qglLoadMatrixf(matrix); + gls.currentmatrix = matrix; + } +} + +void GL_ForceTexture(GLuint tmu, GLuint texnum); +void GL_BindTexture(GLuint tmu, GLuint texnum); +void GL_StateBits(glStateBits_t bits); +void GL_ArrayBits(glArrayBits_t bits); +void GL_LoadMatrix(const GLfloat *matrix); +void GL_Ortho(GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat znear, GLfloat zfar); void GL_Setup2D(void); void GL_Setup3D(void); - void GL_SetDefaultState(void); void GL_InitPrograms(void); void GL_ShutdownPrograms(void); -void GL_EnableWarp(void); -void GL_DisableWarp(void); void GL_EnableOutlines(void); void GL_DisableOutlines(void); @@ -302,8 +386,8 @@ void GL_DisableOutlines(void); */ typedef struct { color_t colors[2]; // 0 - actual color, 1 - transparency (for text drawing) - int flags; - float scale; + int flags; + float scale; } drawStatic_t; extern drawStatic_t draw; @@ -324,17 +408,12 @@ void GL_Blend(void); */ // auto textures -enum { - TEXNUM_DEFAULT = MAX_RIMAGES, - TEXNUM_SCRAP, - TEXNUM_PARTICLE, - TEXNUM_BEAM, - TEXNUM_WHITE, - TEXNUM_BLACK, - TEXNUM_LIGHTMAP // must be the last one -}; - -#define NUM_TEXNUMS (TEXNUM_LIGHTMAP + LM_MAX_LIGHTMAPS - TEXNUM_DEFAULT) +#define TEXNUM_DEFAULT gl_static.texnums[0] +#define TEXNUM_SCRAP gl_static.texnums[1] +#define TEXNUM_PARTICLE gl_static.texnums[2] +#define TEXNUM_BEAM gl_static.texnums[3] +#define TEXNUM_WHITE gl_static.texnums[4] +#define TEXNUM_BLACK gl_static.texnums[5] extern mtexinfo_t *upload_texinfo; @@ -353,13 +432,13 @@ void GL_ShutdownImages(void); #define TESS_MAX_INDICES (3 * TESS_MAX_VERTICES) typedef struct { - vec_t vertices[VERTEX_SIZE*TESS_MAX_VERTICES]; - int indices[TESS_MAX_INDICES]; - byte colors[4 * TESS_MAX_VERTICES]; - int texnum[MAX_TMUS]; - int numverts; - int numindices; - int flags; + GLfloat vertices[VERTEX_SIZE * TESS_MAX_VERTICES]; + QGL_INDEX_TYPE indices[TESS_MAX_INDICES]; + GLubyte colors[4 * TESS_MAX_VERTICES]; + GLuint texnum[MAX_TMUS]; + int numverts; + int numindices; + int flags; } tesselator_t; extern tesselator_t tess; @@ -368,10 +447,15 @@ void GL_Flush2D(void); void GL_DrawParticles(void); void GL_DrawBeams(void); +void GL_BindArrays(void); +void GL_Flush3D(void); +void GL_DrawFace(mface_t *surf); + void GL_AddAlphaFace(mface_t *face); void GL_AddSolidFace(mface_t *face); void GL_DrawAlphaFaces(void); void GL_DrawSolidFaces(void); +void GL_ClearSolidFaces(void); /* * gl_world.c @@ -379,6 +463,7 @@ void GL_DrawSolidFaces(void); */ void GL_DrawBspModel(mmodel_t *model); void GL_DrawWorld(void); +void GL_SampleLightPoint(vec3_t color); void GL_LightPoint(vec3_t origin, vec3_t color); /* diff --git a/src/refresh/gl/images.c b/src/refresh/gl/images.c index a6baf8a..5124277 100644 --- a/src/refresh/gl/images.c +++ b/src/refresh/gl/images.c @@ -88,7 +88,7 @@ static void gl_texturemode_changed(cvar_t *self) // change all the existing mipmap texture objects for (i = 0, image = r_images; i < r_numImages; i++, image++) { if (image->type == IT_WALL || image->type == IT_SKIN) { - GL_BindTexture(image->texnum); + GL_ForceTexture(0, image->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, @@ -123,7 +123,7 @@ static void gl_anisotropy_changed(cvar_t *self) // change all the existing mipmap texture objects for (i = 0, image = r_images; i < r_numImages; i++, image++) { if (image->type == IT_WALL || image->type == IT_SKIN) { - GL_BindTexture(image->texnum); + GL_ForceTexture(0, image->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, gl_filter_anisotropy); } @@ -139,7 +139,7 @@ static void gl_bilerp_chars_changed(cvar_t *self) // change all the existing charset texture objects for (i = 0, image = r_images; i < r_numImages; i++, image++) { if (image->type == IT_FONT) { - GL_BindTexture(image->texnum); + GL_ForceTexture(0, image->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param); } @@ -155,7 +155,7 @@ static void gl_bilerp_pics_changed(cvar_t *self) // change all the existing pic texture objects for (i = 0, image = r_images; i < r_numImages; i++, image++) { if (image->type == IT_PIC) { - GL_BindTexture(image->texnum); + GL_ForceTexture(0, image->texnum); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param); } @@ -164,7 +164,7 @@ static void gl_bilerp_pics_changed(cvar_t *self) // change scrap texture object if (!gl_noscrap->integer) { param = self->integer > 1 ? GL_LINEAR : GL_NEAREST; - GL_BindTexture(TEXNUM_SCRAP); + GL_ForceTexture(0, TEXNUM_SCRAP); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param); } @@ -229,7 +229,8 @@ void Scrap_Upload(void) if (!scrap_dirty) { return; } - GL_BindTexture(TEXNUM_SCRAP); + + GL_ForceTexture(0, TEXNUM_SCRAP); GL_Upload8(scrap_data, SCRAP_BLOCK_WIDTH, SCRAP_BLOCK_HEIGHT, qfalse); scrap_dirty = qfalse; } @@ -398,7 +399,7 @@ static void GL_ColorInvertTexture(byte *in, int inwidth, int inheight) // (useful for small images in scarp, charsets, etc) static inline qboolean is_nearest(void) { - if (gls.texnum[gls.tmu] == TEXNUM_SCRAP && gl_bilerp_pics->integer <= 1) { + if (gls.texnums[0] == TEXNUM_SCRAP && gl_bilerp_pics->integer <= 1) { return qtrue; // hack for scrap texture } if (!upload_image) { @@ -443,7 +444,7 @@ static inline qboolean is_downsample(void) static inline qboolean is_clamp(void) { - if (gls.texnum[gls.tmu] == TEXNUM_SCRAP) { + if (gls.texnums[0] == TEXNUM_SCRAP) { return qtrue; // hack for scrap texture } if (!upload_image) { @@ -735,8 +736,8 @@ void IMG_Load(image_t *image, byte *pic, int width, int height) R_FloodFillSkin(pic, width, height); mipmap = (image->type == IT_WALL || image->type == IT_SKIN); - image->texnum = (image - r_images); - GL_BindTexture(image->texnum); + qglGenTextures(1, &image->texnum); + GL_ForceTexture(0, image->texnum); if (image->flags & IF_PALETTED) { transparent = GL_Upload8(pic, width, height, mipmap); } else { @@ -757,9 +758,9 @@ void IMG_Load(image_t *image, byte *pic, int width, int height) void IMG_Unload(image_t *image) { - if (image->texnum > 0 && image->texnum < MAX_RIMAGES) { - if (gls.texnum[gls.tmu] == image->texnum) - gls.texnum[gls.tmu] = 0; + if (image->texnum && !(image->flags & IF_SCRAP)) { + if (gls.texnums[0] == image->texnum) + gls.texnums[0] = 0; qglDeleteTextures(1, &image->texnum); image->texnum = 0; } @@ -771,7 +772,6 @@ static void GL_BuildIntensityTable(void) float f; f = Cvar_ClampValue(gl_intensity, 1, 5); - gl_static.inverse_intensity = 1 / f; for (i = 0; i < 256; i++) { j = i * f; if (j > 255) { @@ -779,6 +779,11 @@ static void GL_BuildIntensityTable(void) } intensitytable[i] = j; } + + j = 255.0f / f; + gl_static.inverse_intensity_33 = MakeColor(j, j, j, 85); + gl_static.inverse_intensity_66 = MakeColor(j, j, j, 170); + gl_static.inverse_intensity_100 = MakeColor(j, j, j, 255); } static void GL_BuildGammaTables(void) @@ -838,7 +843,7 @@ static void GL_InitDefaultTexture(void) } } - GL_BindTexture(TEXNUM_DEFAULT); + GL_ForceTexture(0, TEXNUM_DEFAULT); GL_Upload32(pixels, 8, 8, qtrue); // fill in notexture image @@ -876,7 +881,7 @@ static void GL_InitParticleTexture(void) } } - GL_BindTexture(TEXNUM_PARTICLE); + GL_ForceTexture(0, TEXNUM_PARTICLE); GL_Upload32(pixels, 16, 16, qfalse); if (gl_config.version_major == 1 && gl_config.version_minor == 1) { qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); @@ -892,13 +897,13 @@ static void GL_InitWhiteImage(void) uint32_t pixel; pixel = U32_WHITE; - GL_BindTexture(TEXNUM_WHITE); + GL_ForceTexture(0, TEXNUM_WHITE); GL_Upload32((byte *)&pixel, 1, 1, qfalse); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); pixel = U32_BLACK; - GL_BindTexture(TEXNUM_BLACK); + GL_ForceTexture(0, TEXNUM_BLACK); GL_Upload32((byte *)&pixel, 1, 1, qfalse); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -924,7 +929,7 @@ static void GL_InitBeamTexture(void) } } - GL_BindTexture(TEXNUM_BEAM); + GL_ForceTexture(0, TEXNUM_BEAM); GL_Upload32(pixels, 16, 16, qfalse); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -989,12 +994,17 @@ void GL_InitImages(void) upload_image = NULL; upload_texinfo = NULL; + qglGenTextures(NUM_TEXNUMS, gl_static.texnums); + qglGenTextures(LM_MAX_LIGHTMAPS, lm.texnums); + Scrap_Init(); GL_InitDefaultTexture(); GL_InitParticleTexture(); GL_InitWhiteImage(); GL_InitBeamTexture(); + + GL_ShowErrors(__func__); } #ifdef _DEBUG @@ -1008,9 +1018,6 @@ GL_ShutdownImages */ void GL_ShutdownImages(void) { - GLuint texnums[NUM_TEXNUMS]; - int i, j; - gl_bilerp_chars->changed = NULL; gl_bilerp_pics->changed = NULL; gl_texturemode->changed = NULL; @@ -1019,13 +1026,8 @@ void GL_ShutdownImages(void) gl_gamma->changed = NULL; // delete auto textures - j = TEXNUM_LIGHTMAP + lm.highwater - TEXNUM_DEFAULT; - for (i = 0; i < j; i++) { - texnums[i] = TEXNUM_DEFAULT + i; - } - qglDeleteTextures(j, texnums); - - lm.highwater = 0; + qglDeleteTextures(NUM_TEXNUMS, gl_static.texnums); + qglDeleteTextures(LM_MAX_LIGHTMAPS, lm.texnums); #ifdef _DEBUG r_charset = NULL; diff --git a/src/refresh/gl/main.c b/src/refresh/gl/main.c index 2d02de5..95cbb95 100644 --- a/src/refresh/gl/main.c +++ b/src/refresh/gl/main.c @@ -78,6 +78,7 @@ cvar_t *gl_novis; cvar_t *gl_lockpvs; cvar_t *gl_lightmap; cvar_t *gl_fullbright; +cvar_t *gl_vertexlight; cvar_t *gl_polyblend; cvar_t *gl_showerrors; @@ -328,6 +329,9 @@ void GL_RotateForEntity(vec3_t origin) GL_MultMatrix(glr.entmatrix, glr.viewmatrix, matrix); qglLoadMatrixf(glr.entmatrix); + + // forced matrix upload + gls.currentmatrix = glr.entmatrix; } static void GL_DrawSpriteModel(model_t *model) @@ -353,9 +357,10 @@ static void GL_DrawSpriteModel(model_t *model) bits |= GLS_BLEND_BLEND; } - GL_TexEnv(GL_MODULATE); - GL_Bits(bits); - GL_BindTexture(image->texnum); + GL_LoadMatrix(glr.viewmatrix); + GL_BindTexture(0, image->texnum); + GL_StateBits(bits); + GL_ArrayBits(GLA_VERTEX | GLA_TC); qglColor4f(1, 1, 1, alpha); VectorScale(glr.viewaxis[1], frame->origin_x, left); @@ -368,8 +373,8 @@ static void GL_DrawSpriteModel(model_t *model) VectorAdd3(e->origin, down, right, points[2]); VectorAdd3(e->origin, up, right, points[3]); - qglTexCoordPointer(2, GL_FLOAT, 0, tcoords); - qglVertexPointer(3, GL_FLOAT, 0, points); + GL_TexCoordPointer(2, 0, tcoords); + GL_VertexPointer(3, 0, &points[0][0]); qglDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -391,19 +396,13 @@ static void GL_DrawNullModel(void) VectorMA(e->origin, 16, glr.entaxis[1], points[3]); VectorMA(e->origin, 16, glr.entaxis[2], points[5]); - qglDisable(GL_TEXTURE_2D); - //qglDisable(GL_DEPTH_TEST); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - qglEnableClientState(GL_COLOR_ARRAY); - - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, colors); - qglVertexPointer(3, GL_FLOAT, 0, points); + GL_LoadMatrix(glr.viewmatrix); + GL_BindTexture(0, TEXNUM_WHITE); + GL_StateBits(GLS_DEFAULT); + GL_ArrayBits(GLA_VERTEX | GLA_COLOR); + GL_ColorBytePointer(4, 0, (GLubyte *)colors); + GL_VertexPointer(3, 0, &points[0][0]); qglDrawArrays(GL_LINES, 0, 6); - - qglDisableClientState(GL_COLOR_ARRAY); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - //qglEnable(GL_DEPTH_TEST); - qglEnable(GL_TEXTURE_2D); } static void GL_DrawEntities(int mask) @@ -485,39 +484,17 @@ static void GL_DrawEntities(int mask) static void GL_DrawTearing(void) { - vec2_t points[4]; static int i; // alternate colors to make tearing obvious i++; if (i & 1) { qglClearColor(1, 1, 1, 1); - qglColor4f(1, 1, 1, 1); } else { qglClearColor(1, 0, 0, 0); - qglColor4f(1, 0, 0, 1); } - points[0][0] = 0; - points[0][1] = r_config.height; - points[1][0] = 0; - points[1][1] = 0; - points[2][0] = r_config.width; - points[2][1] = r_config.height; - points[3][0] = r_config.width; - points[3][1] = 0; - qglClear(GL_COLOR_BUFFER_BIT); - - qglDisable(GL_TEXTURE_2D); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - - qglVertexPointer(2, GL_FLOAT, 0, points); - qglDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglEnable(GL_TEXTURE_2D); - qglClearColor(0, 0, 0, 1); } @@ -580,13 +557,13 @@ void R_RenderFrame(refdef_t *fd) glr.num_beams = 0; #if USE_DLIGHTS - if (gl_dynamic->integer != 1) { + if (gl_dynamic->integer != 1 || gl_vertexlight->integer) { glr.fd.num_dlights = 0; } #endif if (lm.dirty) { - LM_RebuildSurfaces(); + GL_RebuildLighting(); lm.dirty = qfalse; } @@ -710,14 +687,20 @@ static size_t GL_ViewCluster_m(char *buffer, size_t size) return Q_scnprintf(buffer, size, "%d", glr.viewcluster1); } +static void gl_lightmap_changed(cvar_t *self) +{ + lm.scale = Cvar_ClampValue(gl_coloredlightmaps, 0, 1); + lm.comp = lm.scale ? GL_RGB : GL_LUMINANCE; + lm.add = 255 * Cvar_ClampValue(gl_brightness, -1, 1); + lm.modulate = gl_modulate->value * gl_modulate_world->value; + lm.dirty = qtrue; // rebuild all lightmaps next frame +} + static void gl_modulate_entities_changed(cvar_t *self) { gl_static.entity_modulate = gl_modulate->value * gl_modulate_entities->value; } -// this one is defined in gl_surf.c -extern void gl_lightmap_changed(cvar_t *self); - static void gl_modulate_changed(cvar_t *self) { gl_lightmap_changed(self); @@ -791,10 +774,14 @@ static void GL_Register(void) gl_lockpvs = Cvar_Get("gl_lockpvs", "0", CVAR_CHEAT); gl_lightmap = Cvar_Get("gl_lightmap", "0", CVAR_CHEAT); gl_fullbright = Cvar_Get("r_fullbright", "0", CVAR_CHEAT); + gl_fullbright->changed = gl_lightmap_changed; + gl_vertexlight = Cvar_Get("gl_vertexlight", "0", 0); + gl_vertexlight->changed = gl_lightmap_changed; gl_polyblend = Cvar_Get("gl_polyblend", "1", 0); gl_showerrors = Cvar_Get("gl_showerrors", "1", 0); - gl_modulate_entities_changed(gl_modulate_entities); + gl_lightmap_changed(NULL); + gl_modulate_entities_changed(NULL); Cmd_AddCommand("strings", GL_Strings_f); Cmd_AddMacro("gl_viewcluster", GL_ViewCluster_m); @@ -838,14 +825,8 @@ static qboolean GL_SetupConfig(void) return qfalse; } - // get extensions string + // get and parse extension string extensions = (const char *)qglGetString(GL_EXTENSIONS); - if (!extensions || !*extensions) { - Com_EPrintf("No OpenGL extensions found, check your drivers\n"); - return qfalse; - } - - // parse extension string gl_config.ext_supported = QGL_ParseExtensionString(extensions); gl_config.ext_enabled = 0; @@ -892,12 +873,6 @@ static qboolean GL_SetupConfig(void) QGL_InitExtensions(gl_config.ext_enabled); - // lack of multitexture support is a show stopper - if (!qglActiveTextureARB) { - Com_EPrintf("Required GL_ARB_multitexture extension is missing\n"); - return qfalse; - } - qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &integer); if (integer < 256) { Com_EPrintf("OpenGL reports invalid maximum texture size\n"); @@ -928,6 +903,7 @@ static qboolean GL_SetupConfig(void) qglGetIntegerv(GL_STENCIL_BITS, &integer); gl_config.stencilbits = integer; + GL_ShowErrors(__func__); return qtrue; } diff --git a/src/refresh/gl/mesh.c b/src/refresh/gl/mesh.c index e1650c3..e469339 100644 --- a/src/refresh/gl/mesh.c +++ b/src/refresh/gl/mesh.c @@ -127,10 +127,10 @@ static void tess_static_shade(const maliasmesh_t *mesh) dst_vert[0] = src_vert->pos[0] * newscale[0] + translate[0]; dst_vert[1] = src_vert->pos[1] * newscale[1] + translate[1]; dst_vert[2] = src_vert->pos[2] * newscale[2] + translate[2]; - dst_vert[3] = shadelight[0] * d; - dst_vert[4] = shadelight[1] * d; - dst_vert[5] = shadelight[2] * d; - dst_vert[6] = shadelight[3]; + dst_vert[4] = shadelight[0] * d; + dst_vert[5] = shadelight[1] * d; + dst_vert[6] = shadelight[2] * d; + dst_vert[7] = shadelight[3]; dst_vert += VERTEX_SIZE; src_vert++; @@ -220,10 +220,10 @@ static void tess_lerped_shade(const maliasmesh_t *mesh) dst_vert[2] = src_oldvert->pos[2] * oldscale[2] + src_newvert->pos[2] * newscale[2] + translate[2]; - dst_vert[3] = shadelight[0] * d; - dst_vert[4] = shadelight[1] * d; - dst_vert[5] = shadelight[2] * d; - dst_vert[6] = shadelight[3]; + dst_vert[4] = shadelight[0] * d; + dst_vert[5] = shadelight[1] * d; + dst_vert[6] = shadelight[2] * d; + dst_vert[7] = shadelight[3]; dst_vert += VERTEX_SIZE; src_oldvert++; @@ -424,29 +424,19 @@ static void draw_celshading(maliasmesh_t *mesh) if (celscale < 0.01f || celscale > 1) return; - GL_Bits(GLS_BLEND_BLEND); - qglDisable(GL_TEXTURE_2D); + GL_BindTexture(0, TEXNUM_BLACK); + GL_StateBits(GLS_BLEND_BLEND); + GL_ArrayBits(GLA_VERTEX); + qglLineWidth(gl_celshading->value * celscale); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); qglCullFace(GL_FRONT); - - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - if (shadelight) - qglDisableClientState(GL_COLOR_ARRAY); - qglColor4f(0, 0, 0, color[3] * celscale); - qglDrawElements(GL_TRIANGLES, mesh->numindices, GL_UNSIGNED_INT, + qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, mesh->indices); - qglColor4fv(color); - - if (shadelight) - qglEnableClientState(GL_COLOR_ARRAY); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglCullFace(GL_BACK); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); qglLineWidth(1); - qglEnable(GL_TEXTURE_2D); } static void setup_shadow(void) @@ -530,7 +520,7 @@ static void draw_shadow(maliasmesh_t *mesh) return; // load shadow projection matrix - qglLoadMatrixf(shadowmatrix); + GL_LoadMatrix(shadowmatrix); // eliminate z-fighting by utilizing stencil buffer, if available if (gl_config.stencilbits) { @@ -539,26 +529,17 @@ static void draw_shadow(maliasmesh_t *mesh) qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); } - GL_Bits(GLS_BLEND_BLEND); - GL_TexEnv(GL_MODULATE); - GL_BindTexture(TEXNUM_WHITE); - - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - if (shadelight) - qglDisableClientState(GL_COLOR_ARRAY); + GL_StateBits(GLS_BLEND_BLEND); + GL_BindTexture(0, TEXNUM_WHITE); + GL_ArrayBits(GLA_VERTEX); qglEnable(GL_POLYGON_OFFSET_FILL); qglPolygonOffset(-1.0f, -2.0f); qglColor4f(0, 0, 0, color[3] * 0.5f); - qglDrawElements(GL_TRIANGLES, mesh->numindices, GL_UNSIGNED_INT, + qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, mesh->indices); - qglColor4fv(color); qglDisable(GL_POLYGON_OFFSET_FILL); - if (shadelight) - qglEnableClientState(GL_COLOR_ARRAY); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - // once we have drawn something to stencil buffer, continue to clear it for // the lifetime of OpenGL context. leaving stencil buffer "dirty" and // clearing just depth is slower (verified for Nvidia and ATI drivers). @@ -566,9 +547,6 @@ static void draw_shadow(maliasmesh_t *mesh) qglDisable(GL_STENCIL_TEST); gl_static.stencil_buffer_bit |= GL_STENCIL_BUFFER_BIT; } - - // fall back to entity matrix - qglLoadMatrixf(glr.entmatrix); } static int texnum_for_mesh(maliasmesh_t *mesh) @@ -597,30 +575,46 @@ static int texnum_for_mesh(maliasmesh_t *mesh) static void draw_alias_mesh(maliasmesh_t *mesh) { + glStateBits_t state = GLS_DEFAULT; + + // fall back to entity matrix + GL_LoadMatrix(glr.entmatrix); + + if (shadelight) + state |= GLS_SHADE_SMOOTH; + if (glr.ent->flags & RF_TRANSLUCENT) - GL_Bits(GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE); - else - GL_Bits(GLS_DEFAULT); + state |= GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE; + + GL_StateBits(state); - GL_TexEnv(GL_MODULATE); - GL_BindTexture(texnum_for_mesh(mesh)); + GL_BindTexture(0, texnum_for_mesh(mesh)); (*tessfunc)(mesh); c.trisDrawn += mesh->numverts; - qglTexCoordPointer(2, GL_FLOAT, 0, mesh->tcoords); + if (shadelight) { + GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); + GL_VertexPointer(3, VERTEX_SIZE, tess.vertices); + GL_ColorFloatPointer(4, VERTEX_SIZE, tess.vertices + 4); + } else { + GL_ArrayBits(GLA_VERTEX | GLA_TC); + GL_VertexPointer(3, 4, tess.vertices); + qglColor4fv(color); + } - if (qglLockArraysEXT) - qglLockArraysEXT(0, mesh->numverts); + GL_TexCoordPointer(2, 0, (GLfloat *)mesh->tcoords); - qglDrawElements(GL_TRIANGLES, mesh->numindices, GL_UNSIGNED_INT, + GL_LockArrays(mesh->numverts); + + qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, mesh->indices); draw_celshading(mesh); if (gl_showtris->integer) { GL_EnableOutlines(); - qglDrawElements(GL_TRIANGLES, mesh->numindices, GL_UNSIGNED_INT, + qglDrawElements(GL_TRIANGLES, mesh->numindices, QGL_INDEX_ENUM, mesh->indices); GL_DisableOutlines(); } @@ -628,15 +622,14 @@ static void draw_alias_mesh(maliasmesh_t *mesh) // FIXME: unlock arrays before changing matrix? draw_shadow(mesh); - if (qglUnlockArraysEXT) - qglUnlockArraysEXT(); + GL_UnlockArrays(); } void GL_DrawAliasModel(model_t *model) { entity_t *ent = glr.ent; glCullResult_t cull; - maliasmesh_t *mesh, *last; + int i; newframenum = ent->frame; if (newframenum < 0 || newframenum >= model->numframes) { @@ -692,7 +685,6 @@ void GL_DrawAliasModel(model_t *model) tess_static_plain : tess_lerped_plain; } - qglPushMatrix(); GL_RotateForEntity(origin); if ((ent->flags & (RF_WEAPONMODEL | RF_LEFTHAND)) == @@ -706,22 +698,9 @@ void GL_DrawAliasModel(model_t *model) if (ent->flags & RF_DEPTHHACK) qglDepthRange(0, 0.25f); - if (shadelight) { - qglVertexPointer(3, GL_FLOAT, 4 * VERTEX_SIZE, tess.vertices); - qglColorPointer(4, GL_FLOAT, 4 * VERTEX_SIZE, tess.vertices + 3); - qglEnableClientState(GL_COLOR_ARRAY); - } else { - qglVertexPointer(3, GL_FLOAT, 4 * 4, tess.vertices); - qglColor4fv(color); - } - // draw all the meshes - last = model->meshes + model->nummeshes; - for (mesh = model->meshes; mesh != last; mesh++) - draw_alias_mesh(mesh); - - if (shadelight) - qglDisableClientState(GL_COLOR_ARRAY); + for (i = 0; i < model->nummeshes; i++) + draw_alias_mesh(&model->meshes[i]); if (ent->flags & RF_DEPTHHACK) qglDepthRange(0, 1); @@ -733,7 +712,5 @@ void GL_DrawAliasModel(model_t *model) qglMatrixMode(GL_MODELVIEW); qglFrontFace(GL_CW); } - - qglPopMatrix(); } diff --git a/src/refresh/gl/models.c b/src/refresh/gl/models.c index cb1aa46..64524c5 100644 --- a/src/refresh/gl/models.c +++ b/src/refresh/gl/models.c @@ -31,7 +31,7 @@ qerror_t MOD_LoadMD2(model_t *model, const void *rawdata, size_t length) maliasframe_t *dst_frame; maliasvert_t *dst_vert; maliasmesh_t *dst_mesh; - uint32_t *finalIndices; + QGL_INDEX_TYPE *finalIndices; maliastc_t *dst_tc; int i, j, k; uint16_t remap[MD2_MAX_TRIANGLES * 3]; @@ -229,7 +229,8 @@ qerror_t MOD_LoadMD3(model_t *model, const void *rawdata, size_t length) maliasmesh_t *dst_mesh; maliasvert_t *dst_vert; maliastc_t *dst_tc; - uint32_t *dst_idx; + QGL_INDEX_TYPE *dst_idx; + uint32_t index; uint32_t numverts, numtris, numskins; uint32_t totalVerts; char skinname[MAX_QPATH]; @@ -387,15 +388,13 @@ qerror_t MOD_LoadMD3(model_t *model, const void *rawdata, size_t length) goto fail; } dst_idx = dst_mesh->indices; - for (j = 0; j < numtris; j++) { - dst_idx[0] = LittleLong(src_idx[0]); - dst_idx[1] = LittleLong(src_idx[1]); - dst_idx[2] = LittleLong(src_idx[2]); - if (dst_idx[0] >= numverts || dst_idx[1] >= numverts || dst_idx[2] >= numverts) { + for (j = 0; j < numtris * 3; j++) { + index = LittleLong(*src_idx++); + if (index >= numverts) { ret = Q_ERR_BAD_INDEX; goto fail; } - src_idx += 3; dst_idx += 3; + *dst_idx++ = index; } offset = LittleLong(src_mesh->meshsize); diff --git a/src/refresh/gl/sky.c b/src/refresh/gl/sky.c index d0e7807..beee1d4 100644 --- a/src/refresh/gl/sky.c +++ b/src/refresh/gl/sky.c @@ -369,18 +369,17 @@ void R_DrawSkyBox(void) SkyRotate(); } - GL_TexEnv(GL_REPLACE); - GL_Bits(GLS_DEFAULT); - - qglVertexPointer(3, GL_FLOAT, 5 * 4, &verts[0][0]); - qglTexCoordPointer(2, GL_FLOAT, 5 * 4, &verts[0][3]); + GL_StateBits(GLS_TEXTURE_REPLACE); + GL_ArrayBits(GLA_VERTEX | GLA_TC); + GL_VertexPointer(3, 5, &verts[0][0]); + GL_TexCoordPointer(2, 5, &verts[0][3]); for (i = 0; i < 6; i++) { if (!SKY_VISIBLE(i)) { continue; } - GL_BindTexture(sky_images[skytexorder[i]]); + GL_BindTexture(0, sky_images[skytexorder[i]]); MakeSkyVec(skymaxs[0][i], skymins[1][i], i, verts[0]); MakeSkyVec(skymins[0][i], skymins[1][i], i, verts[1]); diff --git a/src/refresh/gl/state.c b/src/refresh/gl/state.c index 732c103..3d8c6b4 100644 --- a/src/refresh/gl/state.c +++ b/src/refresh/gl/state.c @@ -21,89 +21,45 @@ with this program; if not, write to the Free Software Foundation, Inc., glState_t gls; -void GL_BindTexture(int texnum) +// for uploading +void GL_ForceTexture(GLuint tmu, GLuint texnum) { -#ifdef _DEBUG - if (gl_nobind->integer && !gls.tmu) { - texnum = TEXNUM_DEFAULT; - } -#endif + GL_ActiveTexture(tmu); - if (gls.texnum[gls.tmu] == texnum) { + if (gls.texnums[tmu] == texnum) { return; } qglBindTexture(GL_TEXTURE_2D, texnum); - gls.texnum[gls.tmu] = texnum; + gls.texnums[tmu] = texnum; c.texSwitches++; } -void GL_SelectTMU(int tmu) +// for drawing +void GL_BindTexture(GLuint tmu, GLuint texnum) { - if (gls.tmu == tmu) { - return; - } - - if (tmu < 0 || tmu >= gl_config.numTextureUnits) { - Com_Error(ERR_FATAL, "GL_SelectTMU: bad tmu %d", tmu); +#ifdef _DEBUG + if (gl_nobind->integer && !tmu) { + texnum = TEXNUM_DEFAULT; } +#endif - qglActiveTextureARB(GL_TEXTURE0_ARB + tmu); - qglClientActiveTextureARB(GL_TEXTURE0_ARB + tmu); - - gls.tmu = tmu; -} - -void GL_TexEnv(GLenum texenv) -{ - if (gls.texenv[gls.tmu] == texenv) { + if (gls.texnums[tmu] == texnum) { return; } - switch (texenv) { - case GL_REPLACE: - case GL_MODULATE: - case GL_BLEND: - case GL_ADD: - qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texenv); - break; - default: - Com_Error(ERR_FATAL, "GL_TexEnv: bad texenv"); - break; - } - - gls.texenv[gls.tmu] = texenv; -} + GL_ActiveTexture(tmu); -void GL_CullFace(glCullFace_t cull) -{ - if (gls.cull == cull) { - return; - } - switch (cull) { - case GLS_CULL_DISABLE: - qglDisable(GL_CULL_FACE); - break; - case GLS_CULL_FRONT: - qglEnable(GL_CULL_FACE); - qglCullFace(GL_FRONT); - break; - case GLS_CULL_BACK: - qglEnable(GL_CULL_FACE); - qglCullFace(GL_BACK); - break; - default: - Com_Error(ERR_FATAL, "GL_CullFace: bad cull"); - break; - } + qglBindTexture(GL_TEXTURE_2D, texnum); + gls.texnums[tmu] = texnum; - gls.cull = cull; + c.texSwitches++; } -void GL_Bits(glStateBits_t bits) +void GL_StateBits(glStateBits_t bits) { - glStateBits_t diff = bits ^ gls.bits; + glStateBits_t diff = bits ^ gls.state_bits; if (!diff) { return; @@ -148,17 +104,165 @@ void GL_Bits(glStateBits_t bits) } } - gls.bits = bits; + if (diff & GLS_TEXTURE_REPLACE) { + GL_ActiveTexture(0); + if (bits & GLS_TEXTURE_REPLACE) { + qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } else { + qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + + if (diff & GLS_FLOW_ENABLE) { + GL_ActiveTexture(0); + qglMatrixMode(GL_TEXTURE); + + if (bits & GLS_FLOW_ENABLE) { + float scaled, scroll; + + if (bits & GLS_WARP_ENABLE) { + scaled = glr.fd.time * 0.5f; + scroll = -scaled; + } else { + scaled = glr.fd.time / 40; + scroll = -64 * (scaled - (int)scaled); + } + + qglTranslatef(scroll, 0, 0); + } else { + qglLoadIdentity(); + } + + qglMatrixMode(GL_MODELVIEW); + } + + if (diff & GLS_LIGHTMAP_ENABLE) { + GL_ActiveTexture(1); + if (bits & GLS_LIGHTMAP_ENABLE) { + qglEnable(GL_TEXTURE_2D); + } else { + qglDisable(GL_TEXTURE_2D); + } + } + + if ((diff & GLS_WARP_ENABLE) && gl_static.prognum_warp) { + if (bits & GLS_WARP_ENABLE) { + vec4_t param; + + qglEnable(GL_FRAGMENT_PROGRAM_ARB); + qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, gl_static.prognum_warp); + param[0] = glr.fd.time; + param[1] = glr.fd.time; + param[2] = param[3] = 0; + qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, param); + } else { + qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + qglDisable(GL_FRAGMENT_PROGRAM_ARB); + } + } + + if (diff & GLS_CULL_DISABLE) { + if (bits & GLS_CULL_DISABLE) { + qglDisable(GL_CULL_FACE); + } else { + qglEnable(GL_CULL_FACE); + } + } + + if (diff & GLS_SHADE_SMOOTH) { + if (bits & GLS_SHADE_SMOOTH) { + qglShadeModel(GL_SMOOTH); + } else { + qglShadeModel(GL_FLAT); + } + } + + gls.state_bits = bits; } -void GL_Setup2D(void) +void GL_ArrayBits(glArrayBits_t bits) { - qglViewport(0, 0, r_config.width, r_config.height); + glArrayBits_t diff = bits ^ gls.array_bits; + + if (!diff) { + return; + } + + if (diff & GLA_VERTEX) { + if (bits & GLA_VERTEX) { + qglEnableClientState(GL_VERTEX_ARRAY); + } else { + qglDisableClientState(GL_VERTEX_ARRAY); + } + } + + if (diff & GLA_TC) { + GL_ClientActiveTexture(0); + if (bits & GLA_TC) { + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + } else { + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } + + if (diff & GLA_LMTC) { + GL_ClientActiveTexture(1); + if (bits & GLA_LMTC) { + qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + } else { + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + } + + if (diff & GLA_COLOR) { + if (bits & GLA_COLOR) { + qglEnableClientState(GL_COLOR_ARRAY); + } else { + qglDisableClientState(GL_COLOR_ARRAY); + } + } + + gls.array_bits = bits; +} + +void GL_Ortho(GLfloat xmin, GLfloat xmax, GLfloat ymin, GLfloat ymax, GLfloat znear, GLfloat zfar) +{ + GLfloat width, height, depth; + GLfloat matrix[16]; + + width = xmax - xmin; + height = ymax - ymin; + depth = zfar - znear; + + matrix[0] = 2 / width; + matrix[4] = 0; + matrix[8] = 0; + matrix[12] = -(xmax + xmin) / width; + + matrix[1] = 0; + matrix[5] = 2 / height; + matrix[9] = 0; + matrix[13] = -(ymax + ymin) / height; + + matrix[2] = 0; + matrix[6] = 0; + matrix[10] = -2 / depth; + matrix[14] = -(zfar + znear) / depth; + + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = 0; + matrix[15] = 1; qglMatrixMode(GL_PROJECTION); - qglLoadIdentity(); + qglLoadMatrixf(matrix); +} - qglOrtho(0, r_config.width, r_config.height, 0, -1, 1); +void GL_Setup2D(void) +{ + qglViewport(0, 0, r_config.width, r_config.height); + + GL_Ortho(0, r_config.width, r_config.height, 0, -1, 1); draw.scale = 1; draw.colors[0].u32 = U32_WHITE; @@ -172,63 +276,99 @@ void GL_Setup2D(void) qglMatrixMode(GL_MODELVIEW); qglLoadIdentity(); - - GL_Bits(GLS_DEPTHTEST_DISABLE); - GL_CullFace(GLS_CULL_DISABLE); } -void GL_Setup3D(void) +static void GL_Frustum(void) { - GLdouble xmin, xmax, ymin, ymax, zfar; - int yb = glr.fd.y + glr.fd.height; + GLfloat xmin, xmax, ymin, ymax, zfar, znear; + GLfloat width, height, depth; + GLfloat matrix[16]; - qglViewport(glr.fd.x, r_config.height - yb, - glr.fd.width, glr.fd.height); + znear = gl_znear->value; - qglMatrixMode(GL_PROJECTION); - qglLoadIdentity(); + if (glr.fd.rdflags & RDF_NOWORLDMODEL) + zfar = 2048; + else + zfar = gl_static.world.size * 2; - ymax = gl_znear->value * tan(glr.fd.fov_y * M_PI / 360.0); + ymax = znear * tan(glr.fd.fov_y * M_PI / 360.0); ymin = -ymax; - xmax = gl_znear->value * tan(glr.fd.fov_x * M_PI / 360.0); + xmax = znear * tan(glr.fd.fov_x * M_PI / 360.0); xmin = -xmax; - if (glr.fd.rdflags & RDF_NOWORLDMODEL) - zfar = 2048; - else - zfar = gl_static.world.size * 2; + width = xmax - xmin; + height = ymax - ymin; + depth = zfar - znear; - qglFrustum(xmin, xmax, ymin, ymax, gl_znear->value, zfar); + matrix[0] = 2 * znear / width; + matrix[4] = 0; + matrix[8] = (xmax + xmin) / width; + matrix[12] = 0; - qglMatrixMode(GL_MODELVIEW); + matrix[1] = 0; + matrix[5] = 2 * znear / height; + matrix[9] = (ymax + ymin) / height; + matrix[13] = 0; + + matrix[2] = 0; + matrix[6] = 0; + matrix[10] = -(zfar + znear) / depth; + matrix[14] = -2 * zfar * znear / depth; + + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = -1; + matrix[15] = 0; + + qglMatrixMode(GL_PROJECTION); + qglLoadMatrixf(matrix); +} + +static void GL_RotateForViewer(void) +{ + GLfloat *matrix = glr.viewmatrix; AnglesToAxis(glr.fd.viewangles, glr.viewaxis); - glr.viewmatrix[0] = -glr.viewaxis[1][0]; - glr.viewmatrix[4] = -glr.viewaxis[1][1]; - glr.viewmatrix[8] = -glr.viewaxis[1][2]; - glr.viewmatrix[12] = DotProduct(glr.viewaxis[1], glr.fd.vieworg); + matrix[0] = -glr.viewaxis[1][0]; + matrix[4] = -glr.viewaxis[1][1]; + matrix[8] = -glr.viewaxis[1][2]; + matrix[12] = DotProduct(glr.viewaxis[1], glr.fd.vieworg); - glr.viewmatrix[1] = glr.viewaxis[2][0]; - glr.viewmatrix[5] = glr.viewaxis[2][1]; - glr.viewmatrix[9] = glr.viewaxis[2][2]; - glr.viewmatrix[13] = -DotProduct(glr.viewaxis[2], glr.fd.vieworg); + matrix[1] = glr.viewaxis[2][0]; + matrix[5] = glr.viewaxis[2][1]; + matrix[9] = glr.viewaxis[2][2]; + matrix[13] = -DotProduct(glr.viewaxis[2], glr.fd.vieworg); - glr.viewmatrix[2] = -glr.viewaxis[0][0]; - glr.viewmatrix[6] = -glr.viewaxis[0][1]; - glr.viewmatrix[10] = -glr.viewaxis[0][2]; - glr.viewmatrix[14] = DotProduct(glr.viewaxis[0], glr.fd.vieworg); + matrix[2] = -glr.viewaxis[0][0]; + matrix[6] = -glr.viewaxis[0][1]; + matrix[10] = -glr.viewaxis[0][2]; + matrix[14] = DotProduct(glr.viewaxis[0], glr.fd.vieworg); - glr.viewmatrix[3] = 0; - glr.viewmatrix[7] = 0; - glr.viewmatrix[11] = 0; - glr.viewmatrix[15] = 1; + matrix[3] = 0; + matrix[7] = 0; + matrix[11] = 0; + matrix[15] = 1; - qglLoadMatrixf(glr.viewmatrix); + qglMatrixMode(GL_MODELVIEW); + qglLoadMatrixf(matrix); - GL_Bits(GLS_DEFAULT); - GL_CullFace(GLS_CULL_BACK); + // forced matrix upload + gls.currentmatrix = matrix; +} + +void GL_Setup3D(void) +{ + qglViewport(glr.fd.x, r_config.height - (glr.fd.y + glr.fd.height), + glr.fd.width, glr.fd.height); + + GL_Frustum(); + + GL_RotateForViewer(); + + // enable depth writes before clearing + GL_StateBits(GLS_DEFAULT); qglClear(GL_DEPTH_BUFFER_BIT | gl_static.stencil_buffer_bit); } @@ -246,22 +386,35 @@ void GL_SetDefaultState(void) qglDisable(GL_BLEND); qglDisable(GL_ALPHA_TEST); qglAlphaFunc(GL_GREATER, 0.666f); - qglFrontFace(GL_CW); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + qglFrontFace(GL_CW); + qglCullFace(GL_BACK); + qglEnable(GL_CULL_FACE); + qglShadeModel(GL_FLAT); + + if (qglActiveTextureARB && qglClientActiveTextureARB) { + qglActiveTextureARB(GL_TEXTURE1_ARB); + qglBindTexture(GL_TEXTURE_2D, 0); + qglDisable(GL_TEXTURE_2D); + qglClientActiveTextureARB(GL_TEXTURE1_ARB); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + + qglActiveTextureARB(GL_TEXTURE0_ARB); + qglBindTexture(GL_TEXTURE_2D, 0); + qglEnable(GL_TEXTURE_2D); + qglClientActiveTextureARB(GL_TEXTURE0_ARB); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + } else { + qglBindTexture(GL_TEXTURE_2D, 0); + qglEnable(GL_TEXTURE_2D); + qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + } - qglActiveTextureARB(GL_TEXTURE1_ARB); - qglClientActiveTextureARB(GL_TEXTURE1_ARB); - qglBindTexture(GL_TEXTURE_2D, 0); - qglDisable(GL_TEXTURE_2D); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - - qglActiveTextureARB(GL_TEXTURE0_ARB); - qglClientActiveTextureARB(GL_TEXTURE0_ARB); - qglBindTexture(GL_TEXTURE_2D, 0); - qglEnable(GL_TEXTURE_2D); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); + qglMatrixMode(GL_TEXTURE); + qglLoadIdentity(); + qglMatrixMode(GL_MODELVIEW); - qglEnableClientState(GL_VERTEX_ARRAY); + qglDisableClientState(GL_VERTEX_ARRAY); qglDisableClientState(GL_COLOR_ARRAY); qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | gl_static.stencil_buffer_bit); @@ -287,45 +440,19 @@ byte *IMG_ReadPixels(qboolean reverse, int *width, int *height) void GL_EnableOutlines(void) { - if (gls.fp_enabled) { - qglDisable(GL_FRAGMENT_PROGRAM_ARB); - } - qglDisable(GL_TEXTURE_2D); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); + GL_BindTexture(0, TEXNUM_WHITE); + GL_StateBits(GLS_DEFAULT); + GL_ArrayBits(GLA_VERTEX); + qglColor4f(1, 1, 1, 1); + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); qglDepthRange(0, 0); - qglColor4f(1, 1, 1, 1); } void GL_DisableOutlines(void) { qglDepthRange(0, 1); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglEnable(GL_TEXTURE_2D); - if (gls.fp_enabled) { - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - } -} - -void GL_EnableWarp(void) -{ - vec4_t param; - - qglEnable(GL_FRAGMENT_PROGRAM_ARB); - qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, gl_static.prognum_warp); - param[0] = glr.fd.time; - param[1] = glr.fd.time; - param[2] = param[3] = 0; - qglProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, param); - gls.fp_enabled = qtrue; -} - -void GL_DisableWarp(void) -{ - qglBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); - qglDisable(GL_FRAGMENT_PROGRAM_ARB); - gls.fp_enabled = qfalse; } void GL_InitPrograms(void) @@ -345,7 +472,8 @@ void GL_InitPrograms(void) Cvar_Set("gl_fragment_program", "0"); } - if (!qglProgramStringARB) { + if (!qglGenProgramsARB || !qglBindProgramARB || + !qglProgramStringARB || !qglDeleteProgramsARB) { return; } @@ -379,4 +507,3 @@ void GL_ShutdownPrograms(void) QGL_ShutdownExtensions(QGL_ARB_fragment_program); gl_config.ext_enabled &= ~QGL_ARB_fragment_program; } - diff --git a/src/refresh/gl/surf.c b/src/refresh/gl/surf.c index 7fd44b8..cb86462 100644 --- a/src/refresh/gl/surf.c +++ b/src/refresh/gl/surf.c @@ -38,9 +38,9 @@ adjust_color_f(vec_t *out, const vec_t *in, float modulate) float r, g, b, y, max; // add & modulate - r = (in[0] + gl_static.world.add) * modulate; - g = (in[1] + gl_static.world.add) * modulate; - b = (in[2] + gl_static.world.add) * modulate; + r = (in[0] + lm.add) * modulate; + g = (in[1] + lm.add) * modulate; + b = (in[2] + lm.add) * modulate; // catch negative lights if (r < 0) r = 0; @@ -67,11 +67,11 @@ adjust_color_f(vec_t *out, const vec_t *in, float modulate) // transform to grayscale by replacing color components with // overall pixel luminance computed from weighted color sum - if (gl_static.world.scale != 1) { + if (lm.scale != 1) { y = LUMINANCE(r, g, b); - r = y + (r - y) * gl_static.world.scale; - g = y + (g - y) * gl_static.world.scale; - b = y + (b - y) * gl_static.world.scale; + r = y + (r - y) * lm.scale; + g = y + (g - y) * lm.scale; + b = y + (b - y) * lm.scale; } out[0] = r; @@ -84,7 +84,7 @@ adjust_color_ub(byte *out, const vec_t *in) { vec3_t tmp; - adjust_color_f(tmp, in, gl_static.world.modulate); + adjust_color_f(tmp, in, lm.modulate); out[0] = (byte)tmp[0]; out[1] = (byte)tmp[1]; out[2] = (byte)tmp[2]; @@ -263,7 +263,7 @@ static void update_dynamic_lightmap(mface_t *surf) } // upload lightmap subimage - GL_BindTexture(surf->texnum[1]); + GL_ForceTexture(1, surf->texnum[1]); qglTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax, tmax, GL_RGBA, GL_UNSIGNED_BYTE, temp); @@ -271,23 +271,21 @@ static void update_dynamic_lightmap(mface_t *surf) c.texUploads++; } -void GL_BeginLights(void) -{ - qglActiveTextureARB(GL_TEXTURE1_ARB); - gls.tmu = 1; -} - -void GL_EndLights(void) -{ - qglActiveTextureARB(GL_TEXTURE0_ARB); - gls.tmu = 0; -} - void GL_PushLights(mface_t *surf) { lightstyle_t *style; int i; + if (!surf->lightmap) { + return; + } + if (surf->drawflags & SURF_NOLM_MASK) { + return; + } + if (!surf->texnum[1]) { + return; + } + #if USE_DLIGHTS // dynamic this frame or dynamic previously if (surf->dlightframe) { @@ -334,16 +332,11 @@ static void LM_UploadBlock(void) return; } - // bypassing our state tracker here, be careful to reset TMU1 afterwards! - qglBindTexture(GL_TEXTURE_2D, TEXNUM_LIGHTMAP + lm.nummaps); + GL_ForceTexture(1, lm.texnums[lm.nummaps++]); qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - if (lm.highwater < ++lm.nummaps) { - lm.highwater = lm.nummaps; - } } static void build_style_map(int dynamic) @@ -377,7 +370,10 @@ static void build_style_map(int dynamic) static void LM_BeginBuilding(void) { - qglActiveTextureARB(GL_TEXTURE1_ARB); + // lightmap textures are not deleted from memory when changing maps, + // they are merely reused + lm.nummaps = 0; + LM_InitBlock(); // start up with fullbright styles @@ -390,21 +386,14 @@ static void LM_EndBuilding(void) LM_UploadBlock(); LM_InitBlock(); - qglActiveTextureARB(GL_TEXTURE0_ARB); - - // because LM_UploadBlock doesn't use our state tracker functions, - // their idea of what is bound to TMU1 needs to be reset - gls.texnum[1] = 0; + // vertex lighting implies fullbright styles + if (gl_fullbright->integer || gl_vertexlight->integer) + return; // now build the real lightstyle map build_style_map(gl_dynamic->integer); -} -static void LM_FreeLightmaps(void) -{ - // lightmap textures are not deleted from memory when changing maps, - // they are merely reused - lm.nummaps = 0; + Com_DPrintf("%s: %d lightmaps built\n", __func__, lm.nummaps); } static void build_primary_lightmap(mface_t *surf) @@ -438,48 +427,24 @@ static void build_primary_lightmap(mface_t *surf) } } -static qboolean LM_BuildSurface(mface_t *surf, vec_t *vbo) +static void LM_BuildSurface(mface_t *surf, vec_t *vbo) { - int smax, tmax, size, s, t, i; - byte *src, *ptr; - bsp_t *bsp; + int smax, tmax, s, t; - // validate extents - if (surf->extents[0] < 0 || surf->extents[0] > MAX_SURFACE_EXTENTS || - surf->extents[1] < 0 || surf->extents[1] > MAX_SURFACE_EXTENTS) { - Com_EPrintf("%s: bad surface extents\n", __func__); - return qfalse; - } - - // validate blocklights size smax = S_MAX(surf); tmax = T_MAX(surf); - size = smax * tmax; - if (size > MAX_BLOCKLIGHTS) { - Com_EPrintf("%s: MAX_BLOCKLIGHTS exceeded\n", __func__); - return qfalse; - } - - // validate lightmap bounds - bsp = gl_static.world.cache; - src = surf->lightmap + surf->numstyles * size * 3; - ptr = bsp->lightmap + bsp->numlightmapbytes; - if (src > ptr) { - Com_EPrintf("%s: bad surface lightmap\n", __func__); - return qfalse; - } if (!LM_AllocBlock(smax, tmax, &s, &t)) { LM_UploadBlock(); if (lm.nummaps == LM_MAX_LIGHTMAPS) { Com_EPrintf("%s: LM_MAX_LIGHTMAPS exceeded\n", __func__); - return qfalse; + return; } LM_InitBlock(); if (!LM_AllocBlock(smax, tmax, &s, &t)) { Com_EPrintf("%s: LM_AllocBlock(%d, %d) failed\n", __func__, smax, tmax); - return qfalse; + return; } } @@ -488,49 +453,26 @@ static qboolean LM_BuildSurface(mface_t *surf, vec_t *vbo) // store the surface lightmap parameters surf->light_s = s; surf->light_t = t; - surf->texnum[1] = TEXNUM_LIGHTMAP + lm.nummaps; + surf->texnum[1] = lm.texnums[lm.nummaps]; // build the primary lightmap build_primary_lightmap(surf); - - // normalize and store lmtc in vertices - s = (s << 4) + 8; - t = (t << 4) + 8; - - s -= surf->texturemins[0]; - t -= surf->texturemins[1]; - - for (i = 0; i < surf->numsurfedges; i++) { - vbo[5] += s; - vbo[6] += t; - vbo[5] /= LM_BLOCK_WIDTH * 16; - vbo[6] /= LM_BLOCK_HEIGHT * 16; - vbo += VERTEX_SIZE; - } - - return qtrue; } -// called from the main loop whenever lightmap parameters change -void LM_RebuildSurfaces(void) +static void LM_RebuildSurfaces(void) { bsp_t *bsp = gl_static.world.cache; mface_t *surf; int i, texnum; - if (!bsp) { - return; - } - build_style_map(gl_dynamic->integer); if (!lm.nummaps) { return; } - qglActiveTextureARB(GL_TEXTURE1_ARB); - qglBindTexture(GL_TEXTURE_2D, TEXNUM_LIGHTMAP); - texnum = TEXNUM_LIGHTMAP; + GL_ForceTexture(1, lm.texnums[0]); + texnum = lm.texnums[0]; for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { if (!surf->lightmap) { @@ -548,7 +490,7 @@ void LM_RebuildSurfaces(void) qglTexImage2D(GL_TEXTURE_2D, 0, lm.comp, LM_BLOCK_WIDTH, LM_BLOCK_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); - qglBindTexture(GL_TEXTURE_2D, surf->texnum[1]); + GL_ForceTexture(1, surf->texnum[1]); texnum = surf->texnum[1]; c.texUploads++; @@ -563,9 +505,6 @@ void LM_RebuildSurfaces(void) GL_RGBA, GL_UNSIGNED_BYTE, lm.buffer); c.texUploads++; - - qglActiveTextureARB(GL_TEXTURE0_ARB); - gls.texnum[1] = 0; } @@ -577,19 +516,55 @@ POLYGONS BUILDING ============================================================================= */ +static uint32_t color_for_surface(mface_t *surf) +{ + if (surf->drawflags & SURF_TRANS33) + return gl_static.inverse_intensity_33; + + if (surf->drawflags & SURF_TRANS66) + return gl_static.inverse_intensity_66; + + if (surf->drawflags & SURF_WARP) + return gl_static.inverse_intensity_100; + + return U32_WHITE; +} + static void build_surface_poly(mface_t *surf, vec_t *vbo) { msurfedge_t *src_surfedge; mvertex_t *src_vert; medge_t *src_edge; mtexinfo_t *texinfo = surf->texinfo; - int i; vec2_t scale, tc, mins, maxs; - int bmins[2], bmaxs[2]; + int i, bmins[2], bmaxs[2]; + uint32_t color; surf->texnum[0] = texinfo->image->texnum; surf->texnum[1] = 0; + color = color_for_surface(surf); + + // convert surface flags to state bits + surf->statebits = GLS_DEFAULT; + if (!(surf->drawflags & SURF_COLOR_MASK)) { + surf->statebits |= GLS_TEXTURE_REPLACE; + } + + if (surf->drawflags & SURF_WARP) { + surf->statebits |= GLS_WARP_ENABLE; + } + + if (surf->drawflags & SURF_TRANS_MASK) { + surf->statebits |= GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE; + } else if (surf->drawflags & SURF_ALPHATEST) { + surf->statebits |= GLS_ALPHATEST_ENABLE; + } + + if (surf->drawflags & SURF_FLOWING) { + surf->statebits |= GLS_FLOW_ENABLE; + } + // normalize texture coordinates scale[0] = 1.0f / texinfo->image->width; scale[1] = 1.0f / texinfo->image->height; @@ -606,6 +581,9 @@ static void build_surface_poly(mface_t *surf, vec_t *vbo) // vertex coordinates VectorCopy(src_vert->point, vbo); + // vertex color + memcpy(vbo + 3, &color, sizeof(color)); + // texture0 coordinates tc[0] = DotProduct(vbo, texinfo->axis[0]) + texinfo->offset[0]; tc[1] = DotProduct(vbo, texinfo->axis[1]) + texinfo->offset[1]; @@ -616,12 +594,12 @@ static void build_surface_poly(mface_t *surf, vec_t *vbo) if (mins[1] > tc[1]) mins[1] = tc[1]; if (maxs[1] < tc[1]) maxs[1] = tc[1]; - vbo[3] = tc[0] * scale[0]; - vbo[4] = tc[1] * scale[1]; + vbo[4] = tc[0] * scale[0]; + vbo[5] = tc[1] * scale[1]; // texture1 coordinates - vbo[5] = tc[0]; - vbo[6] = tc[1]; + vbo[6] = tc[0]; + vbo[7] = tc[1]; vbo += VERTEX_SIZE; } @@ -639,37 +617,109 @@ static void build_surface_poly(mface_t *surf, vec_t *vbo) surf->extents[1] = (bmaxs[1] - bmins[1]) << 4; } -// duplicates normalized texture0 coordinates for non-lit surfaces in texture1 -// to make them render properly when gl_lightmap hack is used -static void duplicate_surface_lmtc(mface_t *surf, vec_t *vbo) +// vertex lighting approximation +static void sample_surface_verts(mface_t *surf, vec_t *vbo) { - int i; + int i; + vec3_t color; + + glr.lightpoint.surf = surf; for (i = 0; i < surf->numsurfedges; i++) { - vbo[5] = vbo[3]; - vbo[6] = vbo[4]; + glr.lightpoint.s = (int)vbo[6] - surf->texturemins[0]; + glr.lightpoint.t = (int)vbo[7] - surf->texturemins[1]; + + GL_SampleLightPoint(color); + adjust_color_ub((byte *)(vbo + 3), color); vbo += VERTEX_SIZE; } + + surf->statebits &= ~GLS_TEXTURE_REPLACE; + surf->statebits |= GLS_SHADE_SMOOTH; } -void GL_FreeWorld(void) +// validates and processes surface lightmap +static void build_surface_light(mface_t *surf, vec_t *vbo) { - if (!gl_static.world.cache) { + int smax, tmax, size; + byte *src, *ptr; + bsp_t *bsp; + + if (gl_fullbright->integer) + return; + + if (!surf->lightmap) + return; + + if (surf->drawflags & SURF_NOLM_MASK) + return; + + // validate extents + if (surf->extents[0] < 0 || surf->extents[0] > MAX_SURFACE_EXTENTS || + surf->extents[1] < 0 || surf->extents[1] > MAX_SURFACE_EXTENTS) { + Com_EPrintf("%s: bad surface extents\n", __func__); + surf->lightmap = NULL; // don't use this lightmap return; } - BSP_Free(gl_static.world.cache); + // validate blocklights size + smax = S_MAX(surf); + tmax = T_MAX(surf); + size = smax * tmax; + if (size > MAX_BLOCKLIGHTS) { + Com_EPrintf("%s: MAX_BLOCKLIGHTS exceeded\n", __func__); + surf->lightmap = NULL; // don't use this lightmap + return; + } - if (gl_static.world.vertices) { - Hunk_Free(&gl_static.world.hunk); - } else if (qglDeleteBuffersARB) { - qglDeleteBuffersARB(1, &gl_static.world.bufnum); + // validate lightmap bounds + bsp = gl_static.world.cache; + src = surf->lightmap + surf->numstyles * size * 3; + ptr = bsp->lightmap + bsp->numlightmapbytes; + if (src > ptr) { + Com_EPrintf("%s: bad surface lightmap\n", __func__); + surf->lightmap = NULL; // don't use this lightmap + return; } - LM_FreeLightmaps(); + if (gl_vertexlight->integer) + sample_surface_verts(surf, vbo); + else + LM_BuildSurface(surf, vbo); +} - memset(&gl_static.world, 0, sizeof(gl_static.world)); +// normalizes and stores lightmap texture coordinates in vertices +static void normalize_surface_lmtc(mface_t *surf, vec_t *vbo) +{ + float s, t; + int i; + + s = ((surf->light_s << 4) + 8) - surf->texturemins[0]; + t = ((surf->light_t << 4) + 8) - surf->texturemins[1]; + + for (i = 0; i < surf->numsurfedges; i++) { + vbo[6] += s; + vbo[7] += t; + vbo[6] *= 1.0f / (LM_BLOCK_WIDTH * 16); + vbo[7] *= 1.0f / (LM_BLOCK_HEIGHT * 16); + + vbo += VERTEX_SIZE; + } +} + +// duplicates normalized texture0 coordinates for non-lit surfaces in texture1 +// to make them render properly when gl_lightmap hack is used +static void duplicate_surface_lmtc(mface_t *surf, vec_t *vbo) +{ + int i; + + for (i = 0; i < surf->numsurfedges; i++) { + vbo[6] = vbo[4]; + vbo[7] = vbo[5]; + + vbo += VERTEX_SIZE; + } } static qboolean create_surface_vbo(size_t size) @@ -704,40 +754,137 @@ static void upload_surface_vbo(int lastvert) GLintptrARB offset = lastvert * VERTEX_SIZE * sizeof(vec_t); GLsizeiptrARB size = tess.numverts * VERTEX_SIZE * sizeof(vec_t); - Com_DDPrintf("%s: %"PRIz" bytes\n", __func__, size); + Com_DDPrintf("%s: %"PRIz" bytes at %"PRIz"\n", __func__, size, offset); qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, offset, size, tess.vertices); tess.numverts = 0; } -// silence GCC warning -extern void gl_lightmap_changed(cvar_t *self); +static void upload_world_surfaces(void) +{ + bsp_t *bsp = gl_static.world.cache; + vec_t *vbo; + mface_t *surf; + int i, currvert, lastvert; + + // force vertex lighting if multitexture is not supported + if (!qglActiveTextureARB || !qglClientActiveTextureARB) + Cvar_Set("gl_vertexlight", "1"); + + if (!gl_static.world.vertices) + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, gl_static.world.bufnum); + + currvert = 0; + lastvert = 0; + for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { + if (surf->drawflags & SURF_SKY) + continue; + + if (gl_static.world.vertices) { + vbo = gl_static.world.vertices + currvert * VERTEX_SIZE; + } else { + // upload VBO chunk if needed + if (tess.numverts + surf->numsurfedges > TESS_MAX_VERTICES) { + upload_surface_vbo(lastvert); + lastvert = currvert; + } + + vbo = tess.vertices + tess.numverts * VERTEX_SIZE; + tess.numverts += surf->numsurfedges; + } + + surf->firstvert = currvert; + build_surface_poly(surf, vbo); + build_surface_light(surf, vbo); -void gl_lightmap_changed(cvar_t *self) + if (surf->texnum[1]) + normalize_surface_lmtc(surf, vbo); + else + duplicate_surface_lmtc(surf, vbo); + + currvert += surf->numsurfedges; + } + + // upload the last VBO chunk + if (!gl_static.world.vertices) { + upload_surface_vbo(lastvert); + qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } + + gl_fullbright->modified = qfalse; + gl_vertexlight->modified = qfalse; +} + +static void set_world_size(void) +{ + mnode_t *node = gl_static.world.cache->nodes; + vec_t size, temp; + int i; + + for (i = 0, size = 0; i < 3; i++) { + temp = node->maxs[i] - node->mins[i]; + if (temp > size) + size = temp; + } + + if (size > 4096) + gl_static.world.size = 8192; + else if (size > 2048) + gl_static.world.size = 4096; + else + gl_static.world.size = 2048; +} + +// called from the main loop whenever lighting parameters change +void GL_RebuildLighting(void) { - gl_static.world.scale = Cvar_ClampValue(gl_coloredlightmaps, 0, 1); - lm.comp = gl_static.world.scale ? GL_RGB : GL_LUMINANCE; + if (!gl_static.world.cache) + return; - // FIXME: the name 'brightness' is misleading in this context - gl_static.world.add = 255 * Cvar_ClampValue(gl_brightness, -1, 1); + // if doing vertex lighting, rebuild all surfaces + if (gl_fullbright->integer || gl_vertexlight->integer) { + upload_world_surfaces(); + return; + } - gl_static.world.modulate = gl_modulate->value * gl_modulate_world->value; + // if did vertex lighting previously, rebuild all surfaces and lightmaps + if (gl_fullbright->modified || gl_vertexlight->modified) { + LM_BeginBuilding(); + upload_world_surfaces(); + LM_EndBuilding(); + return; + } - // rebuild all lightmaps next frame - lm.dirty = qtrue; + // rebuild all lightmaps + LM_RebuildSurfaces(); +} + +void GL_FreeWorld(void) +{ + if (!gl_static.world.cache) { + return; + } + + BSP_Free(gl_static.world.cache); + + if (gl_static.world.vertices) { + Hunk_Free(&gl_static.world.hunk); + } else if (qglDeleteBuffersARB) { + qglDeleteBuffersARB(1, &gl_static.world.bufnum); + } + + memset(&gl_static.world, 0, sizeof(gl_static.world)); } void GL_LoadWorld(const char *name) { char buffer[MAX_QPATH]; - mface_t *surf; - int i, count, lastvert; size_t size; - vec_t s, t; - vec_t *vbo; bsp_t *bsp; mtexinfo_t *info; + mface_t *surf; qerror_t ret; + int i; ret = BSP_Load(name, &bsp); if (!bsp) { @@ -764,25 +911,10 @@ void GL_LoadWorld(const char *name) // free previous model, if any GL_FreeWorld(); - gl_lightmap_changed(NULL); - gl_static.world.cache = bsp; // calculate world size for far clip plane and sky box - for (i = 0, s = 0; i < 3; i++) { - t = bsp->nodes[0].maxs[i] - bsp->nodes[0].mins[i]; - if (t > s) - s = t; - } - - if (s > 4096) - gl_static.world.size = 8192; - else if (s > 2048) - gl_static.world.size = 4096; - else - gl_static.world.size = 2048; - - Com_DPrintf("%s: world size %.f (%.f)\n", __func__, gl_static.world.size, s); + set_world_size(); // register all texinfo for (i = 0, info = bsp->texinfo; i < bsp->numtexinfo; i++, info++) { @@ -794,82 +926,38 @@ void GL_LoadWorld(const char *name) } // calculate vertex buffer size in bytes - count = 0; + size = 0; for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { - if (!(surf->texinfo->c.flags & SURF_SKY)) { - count += surf->numsurfedges; - } + // hack surface flags into drawflags for faster access + surf->drawflags |= surf->texinfo->c.flags & ~DSURF_PLANEBACK; + + // don't count sky surfaces + if (surf->drawflags & SURF_SKY) + continue; + + size += surf->numsurfedges * VERTEX_SIZE * sizeof(vec_t); } - size = count * VERTEX_SIZE * sizeof(vec_t); // try VBO first, then allocate on hunk if (create_surface_vbo(size)) { Com_DPrintf("%s: %"PRIz" bytes of vertex data as VBO\n", __func__, size); } else { Hunk_Begin(&gl_static.world.hunk, size); - vbo = Hunk_Alloc(&gl_static.world.hunk, size); + gl_static.world.vertices = Hunk_Alloc(&gl_static.world.hunk, size); Hunk_End(&gl_static.world.hunk); Com_DPrintf("%s: %"PRIz" bytes of vertex data on hunk\n", __func__, size); - gl_static.world.vertices = vbo; } // begin building lightmaps LM_BeginBuilding(); // post process all surfaces - count = 0; - lastvert = 0; - for (i = 0, surf = bsp->faces; i < bsp->numfaces; i++, surf++) { - // hack surface flags into drawflags for faster access - surf->drawflags |= surf->texinfo->c.flags & ~DSURF_PLANEBACK; - - if (surf->drawflags & SURF_SKY) { - continue; - } - - if (gl_static.world.vertices) { - vbo = gl_static.world.vertices + count * VERTEX_SIZE; - } else { - if (surf->numsurfedges > TESS_MAX_VERTICES) { - Com_EPrintf("%s: too many verts\n", __func__); - continue; - } - - // upload VBO chunk if needed - if (tess.numverts + surf->numsurfedges > TESS_MAX_VERTICES) { - upload_surface_vbo(lastvert); - lastvert = count; - } - - vbo = tess.vertices + tess.numverts * VERTEX_SIZE; - tess.numverts += surf->numsurfedges; - } - - surf->firstvert = count; - build_surface_poly(surf, vbo); - - if (gl_fullbright->integer || (surf->drawflags & SURF_NOLM_MASK)) { - surf->lightmap = NULL; - } else if (surf->lightmap && !LM_BuildSurface(surf, vbo)) { - surf->lightmap = NULL; - } - - if (!surf->lightmap) { - duplicate_surface_lmtc(surf, vbo); - } - - count += surf->numsurfedges; - } - - // upload the last VBO chunk - if (!gl_static.world.vertices) { - upload_surface_vbo(lastvert); - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - } + upload_world_surfaces(); // end building lightmaps LM_EndBuilding(); - Com_DPrintf("%s: %d lightmaps built\n", __func__, lm.nummaps); + + GL_ShowErrors(__func__); } diff --git a/src/refresh/gl/tess.c b/src/refresh/gl/tess.c index 3a671a3..0571ef4 100644 --- a/src/refresh/gl/tess.c +++ b/src/refresh/gl/tess.c @@ -21,15 +21,12 @@ with this program; if not, write to the Free Software Foundation, Inc., tesselator_t tess; #define FACE_HASH_BITS 5 -#define FACE_HASH_SIZE (1<<FACE_HASH_BITS) -#define FACE_HASH_MASK (FACE_HASH_SIZE-1) +#define FACE_HASH_SIZE (1 << FACE_HASH_BITS) +#define FACE_HASH_MASK (FACE_HASH_SIZE - 1) -// assumes a < 1024 (texture), b > 1024 (lightmap) -#define FACE_HASH(a,b) \ - (((a)^((a)>>FACE_HASH_BITS)^((b)>>FACE_HASH_BITS*2))&FACE_HASH_MASK) - -static mface_t *faces_alpha, *faces_warp, *faces_alpha_warp; -static mface_t *faces_hash[FACE_HASH_SIZE]; +static mface_t *faces_head[FACE_HASH_SIZE]; +static mface_t **faces_next[FACE_HASH_SIZE]; +static mface_t *faces_alpha; void GL_Flush2D(void) { @@ -39,40 +36,32 @@ void GL_Flush2D(void) return; } - bits = GLS_DEPTHTEST_DISABLE; + bits = GLS_DEPTHTEST_DISABLE | GLS_DEPTHMASK_FALSE | GLS_CULL_DISABLE; if (tess.flags & 2) { bits |= GLS_BLEND_BLEND; } else if (tess.flags & 1) { bits |= GLS_ALPHATEST_ENABLE; } - GL_BindTexture(tess.texnum[0]); - GL_TexEnv(GL_MODULATE); - GL_Bits(bits); - - qglEnableClientState(GL_COLOR_ARRAY); + GL_BindTexture(0, tess.texnum[0]); + GL_StateBits(bits); + GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.colors); - qglTexCoordPointer(2, GL_FLOAT, 16, tess.vertices + 2); - qglVertexPointer(2, GL_FLOAT, 16, tess.vertices); + GL_VertexPointer(2, 4, tess.vertices); + GL_TexCoordPointer(2, 4, tess.vertices + 2); + GL_ColorBytePointer(4, 0, tess.colors); - if (qglLockArraysEXT) { - qglLockArraysEXT(0, tess.numverts); - } + GL_LockArrays(tess.numverts); - qglDrawElements(GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices); + qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); - if (gl_showtris->integer) { + if (gl_showtris->integer > 1) { GL_EnableOutlines(); - qglDrawElements(GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices); + qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); GL_DisableOutlines(); } - if (qglUnlockArraysEXT) { - qglUnlockArraysEXT(); - } - - qglDisableClientState(GL_COLOR_ARRAY); + GL_UnlockArrays(); c.batchesDrawn2D++; @@ -82,10 +71,13 @@ void GL_Flush2D(void) tess.flags = 0; } +#define PARTICLE_SIZE (1 + M_SQRT1_2) +#define PARTICLE_SCALE (1 / (2 * PARTICLE_SIZE)) + void GL_DrawParticles(void) { particle_t *p; - int i; + int total, count; vec3_t transformed; vec_t scale, dist; color_t color; @@ -94,82 +86,76 @@ void GL_DrawParticles(void) uint32_t *dst_color; int blend; - if (!glr.fd.num_particles) { + if (!glr.fd.num_particles) return; - } if (gl_partstyle->integer) blend = GLS_BLEND_ADD; else blend = GLS_BLEND_BLEND; - GL_BindTexture(TEXNUM_PARTICLE); - GL_TexEnv(GL_MODULATE); - GL_Bits(blend | GLS_DEPTHMASK_FALSE); + GL_LoadMatrix(glr.viewmatrix); - qglEnableClientState(GL_COLOR_ARRAY); - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.colors); - qglTexCoordPointer(2, GL_FLOAT, 20, tess.vertices + 3); - qglVertexPointer(3, GL_FLOAT, 20, tess.vertices); + GL_VertexPointer(3, 5, tess.vertices); + GL_TexCoordPointer(2, 5, tess.vertices + 3); + GL_ColorBytePointer(4, 0, tess.colors); -#define PARTICLE_SIZE (1+M_SQRT1_2) -#define PARTICLE_SCALE (1/(2*PARTICLE_SIZE)) + p = glr.fd.particles; + total = glr.fd.num_particles; + do { + GL_BindTexture(0, TEXNUM_PARTICLE); + GL_StateBits(blend | GLS_DEPTHMASK_FALSE); + GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); - numverts = 0; - for (i = 0, p = glr.fd.particles; i < glr.fd.num_particles; i++, p++) { - VectorSubtract(p->origin, glr.fd.vieworg, transformed); - dist = DotProduct(transformed, glr.viewaxis[0]); + count = total; + if (count > TESS_MAX_VERTICES / 3) + count = TESS_MAX_VERTICES / 3; - scale = gl_partscale->value; - if (dist > 20) { - scale += dist * 0.01f; - } + total -= count; - if (p->color == -1) { - color.u32 = p->rgba.u32; - } else { - color.u32 = d_8to24table[p->color & 0xff]; - color.u8[3] = 255 * p->alpha; - } + numverts = 0; + do { + VectorSubtract(p->origin, glr.fd.vieworg, transformed); + dist = DotProduct(transformed, glr.viewaxis[0]); - if (numverts + 3 > TESS_MAX_VERTICES) { - qglDrawArrays(GL_TRIANGLES, 0, numverts); - if (gl_showtris->integer) { - qglDisableClientState(GL_COLOR_ARRAY); - GL_EnableOutlines(); - qglDrawArrays(GL_TRIANGLES, 0, numverts); - GL_DisableOutlines(); - qglEnableClientState(GL_COLOR_ARRAY); - } - numverts = 0; - } + scale = gl_partscale->value; + if (dist > 20) + scale += dist * 0.01f; - dst_vert = tess.vertices + numverts * 5; - VectorMA(p->origin, scale * PARTICLE_SCALE, glr.viewaxis[1], dst_vert); - VectorMA(dst_vert, -scale * PARTICLE_SCALE, glr.viewaxis[2], dst_vert); - VectorMA(dst_vert, scale, glr.viewaxis[2], dst_vert + 5); - VectorMA(dst_vert, -scale, glr.viewaxis[1], dst_vert + 10); + if (p->color == -1) { + color.u32 = p->rgba.u32; + } else { + color.u32 = d_8to24table[p->color & 0xff]; + color.u8[3] = 255 * p->alpha; + } - dst_vert[ 3] = 0; dst_vert[ 4] = 0; - dst_vert[ 8] = 0; dst_vert[ 9] = PARTICLE_SIZE; - dst_vert[13] = PARTICLE_SIZE; dst_vert[14] = 0; + dst_vert = tess.vertices + numverts * 5; + VectorMA(p->origin, scale * PARTICLE_SCALE, glr.viewaxis[1], dst_vert); + VectorMA(dst_vert, -scale * PARTICLE_SCALE, glr.viewaxis[2], dst_vert); + VectorMA(dst_vert, scale, glr.viewaxis[2], dst_vert + 5); + VectorMA(dst_vert, -scale, glr.viewaxis[1], dst_vert + 10); - dst_color = (uint32_t *)tess.colors + numverts; - dst_color[0] = color.u32; - dst_color[1] = color.u32; - dst_color[2] = color.u32; + dst_vert[ 3] = 0; dst_vert[ 4] = 0; + dst_vert[ 8] = 0; dst_vert[ 9] = PARTICLE_SIZE; + dst_vert[13] = PARTICLE_SIZE; dst_vert[14] = 0; - numverts += 3; - } + dst_color = (uint32_t *)tess.colors + numverts; + dst_color[0] = color.u32; + dst_color[1] = color.u32; + dst_color[2] = color.u32; - qglDrawArrays(GL_TRIANGLES, 0, numverts); - qglDisableClientState(GL_COLOR_ARRAY); + p++; + numverts += 3; + } while (--count); - if (gl_showtris->integer) { - GL_EnableOutlines(); qglDrawArrays(GL_TRIANGLES, 0, numverts); - GL_DisableOutlines(); - } + + if (gl_showtris->integer) { + GL_EnableOutlines(); + qglDrawArrays(GL_TRIANGLES, 0, numverts); + GL_DisableOutlines(); + } + } while (total); } /* all things serve the Beam */ @@ -180,7 +166,7 @@ void GL_DrawBeams(void) color_t color; vec_t *dst_vert; uint32_t *dst_color; - int *dst_indices; + QGL_INDEX_TYPE *dst_indices; vec_t length; int numverts; int numindices; @@ -191,14 +177,14 @@ void GL_DrawBeams(void) return; } - GL_BindTexture(TEXNUM_BEAM); - GL_TexEnv(GL_MODULATE); - GL_Bits(GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE); + GL_LoadMatrix(glr.viewmatrix); + GL_BindTexture(0, TEXNUM_BEAM); + GL_StateBits(GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE); + GL_ArrayBits(GLA_VERTEX | GLA_TC | GLA_COLOR); - qglEnableClientState(GL_COLOR_ARRAY); - qglColorPointer(4, GL_UNSIGNED_BYTE, 0, tess.colors); - qglTexCoordPointer(2, GL_FLOAT, 20, tess.vertices + 3); - qglVertexPointer(3, GL_FLOAT, 20, tess.vertices); + GL_VertexPointer(3, 5, tess.vertices); + GL_TexCoordPointer(2, 5, tess.vertices + 3); + GL_ColorBytePointer(4, 0, tess.colors); numverts = numindices = 0; for (i = 0, ent = glr.fd.entities; i < glr.fd.num_entities; i++, ent++) { @@ -227,7 +213,7 @@ void GL_DrawBeams(void) if (numverts + 4 > TESS_MAX_VERTICES || numindices + 6 > TESS_MAX_INDICES) { qglDrawElements(GL_TRIANGLES, numindices, - GL_UNSIGNED_INT, tess.indices); + QGL_INDEX_ENUM, tess.indices); numverts = numindices = 0; } @@ -261,11 +247,10 @@ void GL_DrawBeams(void) } qglDrawElements(GL_TRIANGLES, numindices, - GL_UNSIGNED_INT, tess.indices); - qglDisableClientState(GL_COLOR_ARRAY); + QGL_INDEX_ENUM, tess.indices); } -static void GL_BindArrays(void) +void GL_BindArrays(void) { vec_t *ptr; @@ -276,97 +261,64 @@ static void GL_BindArrays(void) qglBindBufferARB(GL_ARRAY_BUFFER_ARB, gl_static.world.bufnum); } - qglVertexPointer(3, GL_FLOAT, 4 * VERTEX_SIZE, ptr + 0); - qglTexCoordPointer(2, GL_FLOAT, 4 * VERTEX_SIZE, - gl_lightmap->integer ? ptr + 5 : ptr + 3); + GL_VertexPointer(3, VERTEX_SIZE, ptr + 0); - qglClientActiveTextureARB(GL_TEXTURE1_ARB); - qglEnableClientState(GL_TEXTURE_COORD_ARRAY); - qglTexCoordPointer(2, GL_FLOAT, 4 * VERTEX_SIZE, ptr + 5); - qglClientActiveTextureARB(GL_TEXTURE0_ARB); -} + if (gl_lightmap->integer) { + GL_TexCoordPointer(2, VERTEX_SIZE, ptr + 6); + } else { + GL_TexCoordPointer(2, VERTEX_SIZE, ptr + 4); + if (lm.nummaps) { + GL_LightCoordPointer(2, VERTEX_SIZE, ptr + 6); + } + } + + GL_ColorBytePointer(4, VERTEX_SIZE, (GLubyte *)(ptr + 3)); -static void GL_UnbindArrays(void) -{ if (!gl_static.world.vertices) { qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); } - qglClientActiveTextureARB(GL_TEXTURE1_ARB); - qglDisableClientState(GL_TEXTURE_COORD_ARRAY); - qglClientActiveTextureARB(GL_TEXTURE0_ARB); } -static void GL_Flush3D(void) +void GL_Flush3D(void) { + glStateBits_t state = tess.flags; + glArrayBits_t array = GLA_VERTEX | GLA_TC; + if (!tess.numindices) { return; } - if (tess.flags & (SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)) { - float f = gl_static.inverse_intensity; - - if (tess.flags & SURF_TRANS33) { - qglColor4f(f, f, f, 0.33f); - } else if (tess.flags & SURF_TRANS66) { - qglColor4f(f, f, f, 0.66f); - } else { - qglColor4f(f, f, f, 1.0f); - } - - GL_TexEnv(GL_MODULATE); - } else { - GL_TexEnv(GL_REPLACE); + if (q_likely(tess.texnum[1])) { + state |= GLS_LIGHTMAP_ENABLE; + array |= GLA_LMTC; } - GL_BindTexture(tess.texnum[0]); - - if (tess.flags & SURF_FLOWING) { - float scaled, scroll; - - if (tess.flags & SURF_WARP) { - scaled = glr.fd.time * 0.5f; - scroll = -scaled; - } else { - scaled = glr.fd.time / 40; - scroll = -64 * (scaled - (int)scaled); - } - - qglMatrixMode(GL_TEXTURE); - qglPushMatrix(); - qglTranslatef(scroll, 0, 0); + if (!(state & GLS_TEXTURE_REPLACE)) { + array |= GLA_COLOR; } - if (tess.texnum[1]) { - GL_SelectTMU(1); - qglEnable(GL_TEXTURE_2D); - GL_TexEnv(GL_MODULATE); - GL_BindTexture(tess.texnum[1]); - } + GL_StateBits(state); + GL_ArrayBits(array); - if (gl_static.world.vertices && qglLockArraysEXT) { - qglLockArraysEXT(0, tess.numverts); + GL_BindTexture(0, tess.texnum[0]); + if (q_likely(tess.texnum[1])) { + GL_BindTexture(1, tess.texnum[1]); } - qglDrawElements(GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices); - - if (tess.texnum[1]) { - qglDisable(GL_TEXTURE_2D); - GL_SelectTMU(0); + if (gl_static.world.vertices) { + GL_LockArrays(tess.numverts); } + qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); + if (gl_showtris->integer) { GL_EnableOutlines(); - qglDrawElements(GL_TRIANGLES, tess.numindices, GL_UNSIGNED_INT, tess.indices); + qglDrawElements(GL_TRIANGLES, tess.numindices, QGL_INDEX_ENUM, tess.indices); GL_DisableOutlines(); } - if (gl_static.world.vertices && qglUnlockArraysEXT) { - qglUnlockArraysEXT(); - } - - if (tess.flags & SURF_FLOWING) { - qglPopMatrix(); - qglMatrixMode(GL_MODELVIEW); + if (gl_static.world.vertices) { + GL_UnlockArrays(); } c.batchesDrawn++; @@ -399,31 +351,26 @@ static int GL_TextureAnimation(mtexinfo_t *tex) { int c; - if (!tex->next) - return tex->image->texnum; - - c = glr.ent->frame % tex->numframes; - while (c) { - tex = tex->next; - c--; + if (q_unlikely(tex->next)) { + c = glr.ent->frame % tex->numframes; + while (c) { + tex = tex->next; + c--; + } } return tex->image->texnum; } -#define SURF_FLUSH_MASK \ - (SURF_TRANS33|SURF_TRANS66|SURF_WARP|SURF_FLOWING) - -static void GL_DrawFace(mface_t *surf) +void GL_DrawFace(mface_t *surf) { int numtris = surf->numsurfedges - 2; int numindices = numtris * 3; - int diff = surf->drawflags ^ tess.flags; - int texnum[2]; - int *dst_indices; + GLuint texnum[2]; + QGL_INDEX_TYPE *dst_indices; int i, j; - if (gl_lightmap->integer) { + if (q_unlikely(gl_lightmap->integer)) { texnum[0] = surf->texnum[1]; if (!texnum[0]) texnum[0] = GL_TextureAnimation(surf->texinfo); @@ -435,16 +382,16 @@ static void GL_DrawFace(mface_t *surf) if (tess.texnum[0] != texnum[0] || tess.texnum[1] != texnum[1] || - (diff & SURF_FLUSH_MASK) || + tess.flags != surf->statebits || tess.numindices + numindices > TESS_MAX_INDICES) { GL_Flush3D(); } tess.texnum[0] = texnum[0]; tess.texnum[1] = texnum[1]; - tess.flags = surf->drawflags; + tess.flags = surf->statebits; - if (gl_static.world.vertices) { + if (q_unlikely(gl_static.world.vertices)) { j = GL_CopyVerts(surf); } else { j = surf->firstvert; @@ -460,6 +407,8 @@ static void GL_DrawFace(mface_t *surf) tess.numindices += numindices; c.trisDrawn += numtris; + c.facesTris += numtris; + c.facesDrawn++; } static inline void GL_DrawChain(mface_t **head) @@ -469,96 +418,63 @@ static inline void GL_DrawChain(mface_t **head) for (face = *head; face; face = face->next) { GL_DrawFace(face); } + *head = NULL; } -void GL_DrawSolidFaces(void) +void GL_ClearSolidFaces(void) { int i; - GL_BindArrays(); - - GL_Bits(GLS_DEFAULT); - - if (faces_warp) { - GL_EnableWarp(); - GL_DrawChain(&faces_warp); - GL_Flush3D(); - GL_DisableWarp(); + for (i = 0; i < FACE_HASH_SIZE; i++) { + faces_next[i] = &faces_head[i]; } +} - if (gl_hash_faces->integer) { - for (i = 0; i < FACE_HASH_SIZE; i++) { - GL_DrawChain(&faces_hash[i]); - } - } else { - GL_DrawChain(&faces_hash[0]); - faces_hash[1] = NULL; - } +void GL_DrawSolidFaces(void) +{ + int i; - GL_Flush3D(); - GL_UnbindArrays(); + for (i = 0; i < FACE_HASH_SIZE; i++) { + GL_DrawChain(&faces_head[i]); + } } void GL_DrawAlphaFaces(void) { - glr.ent = &gl_world; + if (!faces_alpha) { + return; + } - GL_BindArrays(); + glr.ent = &gl_world; - GL_Bits(GLS_BLEND_BLEND | GLS_DEPTHMASK_FALSE); + GL_LoadMatrix(glr.viewmatrix); - if (faces_alpha_warp) { - GL_EnableWarp(); - GL_DrawChain(&faces_alpha_warp); - GL_Flush3D(); - GL_DisableWarp(); - } + GL_BindArrays(); GL_DrawChain(&faces_alpha); GL_Flush3D(); - GL_UnbindArrays(); } void GL_AddSolidFace(mface_t *face) { - if ((face->drawflags & SURF_WARP) && gl_static.prognum_warp) { - face->next = faces_warp; - faces_warp = face; - } else { - if (gl_hash_faces->integer && !gl_lightmap->integer) { - unsigned i = FACE_HASH(face->texnum[0], face->texnum[1]); - face->next = faces_hash[i]; - faces_hash[i] = face; - } else { - // preserve front-to-back ordering - face->next = NULL; - if (faces_hash[1]) - faces_hash[1]->next = face; - else - faces_hash[0] = face; - faces_hash[1] = face; - } + unsigned hash; - if (face->lightmap && !(face->drawflags & SURF_NOLM_MASK) && gl_dynamic->integer) { - GL_PushLights(face); - } - } + hash = face->texnum[0] ^ face->texnum[1] ^ face->statebits; + hash ^= hash >> FACE_HASH_BITS; + hash &= FACE_HASH_MASK; - c.facesDrawn++; + // preserve front-to-back ordering + face->next = NULL; + *faces_next[hash] = face; + faces_next[hash] = &face->next; } void GL_AddAlphaFace(mface_t *face) { - if ((face->drawflags & SURF_WARP) && gl_static.prognum_warp) { - face->next = faces_alpha_warp; - faces_alpha_warp = face; - } else { - face->next = faces_alpha; - faces_alpha = face; - } - - c.facesDrawn++; + // draw back-to-front + face->next = faces_alpha; + faces_alpha = face; } diff --git a/src/refresh/gl/world.c b/src/refresh/gl/world.c index 8c0a1b4..e7d3091 100644 --- a/src/refresh/gl/world.c +++ b/src/refresh/gl/world.c @@ -18,11 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gl.h" -static qboolean GL_SmoothLightPoint(vec3_t start, vec3_t color) +void GL_SampleLightPoint(vec3_t color) { - bsp_t *bsp; mface_t *surf; - int s, t, i, index; + int s, t, i; byte *lightmap; byte *b1, *b2, *b3, *b4; int fracu, fracv; @@ -30,6 +29,53 @@ static qboolean GL_SmoothLightPoint(vec3_t start, vec3_t color) byte temp[3]; int smax, tmax, size; lightstyle_t *style; + + fracu = glr.lightpoint.s & 15; + fracv = glr.lightpoint.t & 15; + + // compute weights of lightmap blocks + w1 = (16 - fracu) * (16 - fracv); + w2 = fracu * (16 - fracv); + w3 = fracu * fracv; + w4 = (16 - fracu) * fracv; + + s = glr.lightpoint.s >> 4; + t = glr.lightpoint.t >> 4; + + surf = glr.lightpoint.surf; + + smax = S_MAX(surf); + tmax = T_MAX(surf); + size = smax * tmax * 3; + + VectorClear(color); + + // add all the lightmaps with bilinear filtering + lightmap = surf->lightmap; + for (i = 0; i < surf->numstyles; i++) { + b1 = &lightmap[3 * ((t + 0) * smax + (s + 0))]; + b2 = &lightmap[3 * ((t + 0) * smax + (s + 1))]; + b3 = &lightmap[3 * ((t + 1) * smax + (s + 1))]; + b4 = &lightmap[3 * ((t + 1) * smax + (s + 0))]; + + temp[0] = (w1 * b1[0] + w2 * b2[0] + w3 * b3[0] + w4 * b4[0]) >> 8; + temp[1] = (w1 * b1[1] + w2 * b2[1] + w3 * b3[1] + w4 * b4[1]) >> 8; + temp[2] = (w1 * b1[2] + w2 * b2[2] + w3 * b3[2] + w4 * b4[2]) >> 8; + + style = LIGHT_STYLE(surf, i); + + color[0] += temp[0] * style->rgb[0]; + color[1] += temp[1] * style->rgb[1]; + color[2] += temp[2] * style->rgb[2]; + + lightmap += size; + } +} + +static qboolean _GL_LightPoint(vec3_t start, vec3_t color) +{ + bsp_t *bsp; + int i, index; lightpoint_t pt; vec3_t end, mins, maxs; entity_t *ent; @@ -86,48 +132,10 @@ static qboolean GL_SmoothLightPoint(vec3_t start, vec3_t color) glr.lightpoint = pt; } - surf = glr.lightpoint.surf; - if (!surf) + if (!glr.lightpoint.surf) return qfalse; - fracu = glr.lightpoint.s & 15; - fracv = glr.lightpoint.t & 15; - - // compute weights of lightmap blocks - w1 = (16 - fracu) * (16 - fracv); - w2 = fracu * (16 - fracv); - w3 = fracu * fracv; - w4 = (16 - fracu) * fracv; - - s = glr.lightpoint.s >> 4; - t = glr.lightpoint.t >> 4; - - smax = S_MAX(surf); - tmax = T_MAX(surf); - size = smax * tmax * 3; - - VectorClear(color); - - // add all the lightmaps with bilinear filtering - lightmap = surf->lightmap; - for (i = 0; i < surf->numstyles; i++) { - b1 = &lightmap[3 * ((t + 0) * smax + (s + 0))]; - b2 = &lightmap[3 * ((t + 0) * smax + (s + 1))]; - b3 = &lightmap[3 * ((t + 1) * smax + (s + 1))]; - b4 = &lightmap[3 * ((t + 1) * smax + (s + 0))]; - - temp[0] = (w1 * b1[0] + w2 * b2[0] + w3 * b3[0] + w4 * b4[0]) >> 8; - temp[1] = (w1 * b1[1] + w2 * b2[1] + w3 * b3[1] + w4 * b4[1]) >> 8; - temp[2] = (w1 * b1[2] + w2 * b2[2] + w3 * b3[2] + w4 * b4[2]) >> 8; - - style = LIGHT_STYLE(surf, i); - - color[0] += temp[0] * style->rgb[0]; - color[1] += temp[1] * style->rgb[1]; - color[2] += temp[2] * style->rgb[2]; - - lightmap += size; - } + GL_SampleLightPoint(color); GL_AdjustColor(color); @@ -168,7 +176,6 @@ static void GL_MarkLights_r(mnode_t *node, dlight_t *light, int lightbit) } GL_MarkLights_r(node->children[0], light, lightbit); - node = node->children[1]; } } @@ -178,6 +185,8 @@ static void GL_MarkLights(void) int i; dlight_t *light; + glr.dlightframe++; + for (i = 0, light = glr.fd.dlights; i < glr.fd.num_dlights; i++, light++) { VectorCopy(light->origin, light->transformed); GL_MarkLights_r(gl_static.world.cache->nodes, light, 1 << i); @@ -190,9 +199,7 @@ static void GL_TransformLights(mmodel_t *model) dlight_t *light; vec3_t temp; - if (!model->headnode) { - return; - } + glr.dlightframe++; for (i = 0, light = glr.fd.dlights; i < glr.fd.num_dlights; i++, light++) { VectorSubtract(light->origin, glr.ent->origin, temp); @@ -219,6 +226,10 @@ static void GL_AddLights(vec3_t origin, vec3_t color) } } } +#else +#define GL_MarkLights() (void)0 +#define GL_TransformLights() (void)0 +#define GL_AddLights(origin, color) (void)0 #endif void GL_LightPoint(vec3_t origin, vec3_t color) @@ -229,16 +240,12 @@ void GL_LightPoint(vec3_t origin, vec3_t color) } // get lighting from world - if (!GL_SmoothLightPoint(origin, color)) { + if (!_GL_LightPoint(origin, color)) { VectorSet(color, 1, 1, 1); } -#if USE_DLIGHTS - if (gl_dynamic->integer == 1) { - // add dynamic lights - GL_AddLights(origin, color); - } -#endif + // add dynamic lights + GL_AddLights(origin, color); if (gl_doublelight_entities->integer) { // apply modulate twice to mimic original ref_gl behavior @@ -344,7 +351,7 @@ finish: } -#define BACKFACE_EPSILON 0.001f +#define BACKFACE_EPSILON 0.01f #define BSP_CullFace(face, dot) \ (((dot) < -BACKFACE_EPSILON && !((face)->drawflags & DSURF_PLANEBACK)) || \ @@ -392,7 +399,7 @@ void GL_DrawBspModel(mmodel_t *model) } VectorSubtract(glr.fd.vieworg, ent->origin, transformed); if (VectorEmpty(ent->origin) && model->drawframe != glr.drawframe) { - mask = SURF_TRANS33 | SURF_TRANS66; + mask = SURF_TRANS_MASK; } } @@ -400,20 +407,12 @@ void GL_DrawBspModel(mmodel_t *model) // with alpha faces is referenced by multiple entities model->drawframe = glr.drawframe; -#if USE_DLIGHTS - glr.dlightframe++; - if (gl_dynamic->integer == 1) { - GL_TransformLights(model); - } -#endif - - if (gl_dynamic->integer) { - GL_BeginLights(); - } + GL_TransformLights(model); - qglPushMatrix(); GL_RotateForEntity(ent->origin); + GL_BindArrays(); + // draw visible faces // FIXME: go by headnode instead? face = model->firstface; @@ -427,18 +426,15 @@ void GL_DrawBspModel(mmodel_t *model) // on rotated or translated inline models GL_AddAlphaFace(face); } else { - GL_AddSolidFace(face); + if (gl_dynamic->integer) { + GL_PushLights(face); + } + GL_DrawFace(face); } face++; } - if (gl_dynamic->integer) { - GL_EndLights(); - } - - GL_DrawSolidFaces(); - - qglPopMatrix(); + GL_Flush3D(); } #define NODE_CLIPPED 0 @@ -504,12 +500,20 @@ static inline void GL_DrawNode(mnode_t *node) continue; } - if (face->drawflags & (SURF_TRANS33 | SURF_TRANS66)) { + if (face->drawflags & SURF_TRANS_MASK) { GL_AddAlphaFace(face); continue; } - GL_AddSolidFace(face); + if (gl_dynamic->integer) { + GL_PushLights(face); + } + + if (gl_hash_faces->integer) { + GL_AddSolidFace(face); + } else { + GL_DrawFace(face); + } } c.nodesDrawn++; @@ -551,28 +555,23 @@ void GL_DrawWorld(void) GL_MarkLeaves(); -#if USE_DLIGHTS - glr.dlightframe++; - if (gl_dynamic->integer == 1) { - GL_MarkLights(); - } -#endif + GL_MarkLights(); R_ClearSkyBox(); - if (gl_dynamic->integer) { - GL_BeginLights(); - } + GL_LoadMatrix(glr.viewmatrix); + + GL_BindArrays(); + + GL_ClearSolidFaces(); GL_WorldNode_r(gl_static.world.cache->nodes, gl_cull_nodes->integer ? NODE_CLIPPED : NODE_UNCLIPPED); - if (gl_dynamic->integer) { - GL_EndLights(); - } - GL_DrawSolidFaces(); + GL_Flush3D(); + R_DrawSkyBox(); } |