diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ff24654..72377b13 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Makefile b/Makefile index 58407ceb..898f5623 100644 --- a/Makefile +++ b/Makefile @@ -959,6 +959,7 @@ REFGL1_OBJS_ := \ src/client/refresh/gl1/gl1_surf.o \ src/client/refresh/gl1/gl1_warp.o \ src/client/refresh/gl1/gl1_sdl.o \ + src/client/refresh/gl1/gl1_buffer.o \ src/client/refresh/files/surf.o \ src/client/refresh/files/models.o \ src/client/refresh/files/pcx.o \ diff --git a/src/client/refresh/gl1/gl1_buffer.c b/src/client/refresh/gl1/gl1_buffer.c new file mode 100644 index 00000000..3e591e5e --- /dev/null +++ b/src/client/refresh/gl1/gl1_buffer.c @@ -0,0 +1,171 @@ +/* + * 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; + + if (gl_buf.vtx_ptr == 0 || gl_buf.idx_ptr == 0) + { + return; + } + + // defaults for drawing + vtx_size = 3; + texture = true; + + // choosing features by type + switch (gl_buf.type) + { + case buf_2d: + vtx_size = 2; + break; + default: + break; + } + + glEnableClientState( GL_VERTEX_ARRAY ); + glVertexPointer (vtx_size, GL_FLOAT, 0, gl_buf.vtx); + + if (texture) + { + R_Bind(gl_buf.texture[0]); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, gl_buf.tex[0]); + } + + // 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 (texture) + { + glDisableClientState( GL_TEXTURE_COORD_ARRAY ); + } + + glDisableClientState( GL_VERTEX_ARRAY ); + + 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 ) + { + 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; +} diff --git a/src/client/refresh/gl1/gl1_draw.c b/src/client/refresh/gl1/gl1_draw.c index c8093301..6fe553da 100644 --- a/src/client/refresh/gl1/gl1_draw.c +++ b/src/client/refresh/gl1/gl1_draw.c @@ -77,31 +77,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 * @@ -190,6 +169,14 @@ RDraw_PicScaled(int x, int y, 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[] = { @@ -235,31 +222,10 @@ RDraw_TileClear(int x, int y, int w, int h, 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); } /* @@ -306,6 +272,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); diff --git a/src/client/refresh/gl1/gl1_sdl.c b/src/client/refresh/gl1/gl1_sdl.c index 7623ea32..707b9154 100644 --- a/src/client/refresh/gl1/gl1_sdl.c +++ b/src/client/refresh/gl1/gl1_sdl.c @@ -46,6 +46,7 @@ static qboolean vsyncActive = false; void RI_EndFrame(void) { + R_ApplyGLBuffer(); // to draw buffered 2D text SDL_GL_SwapWindow(window); } diff --git a/src/client/refresh/gl1/header/local.h b/src/client/refresh/gl1/header/local.h index 2740df4a..554b3b4a 100644 --- a/src/client/refresh/gl1/header/local.h +++ b/src/client/refresh/gl1/header/local.h @@ -39,17 +39,18 @@ #define GL_COLOR_INDEX8_EXT GL_COLOR_INDEX #endif -#define TEXNUM_LIGHTMAPS 1024 -#define TEXNUM_SCRAPS 1152 -#define TEXNUM_IMAGES 1153 -#define MAX_GLTEXTURES 1024 +#define MAX_LIGHTMAPS 128 #define MAX_SCRAPS 1 +#define TEXNUM_LIGHTMAPS 1024 +#define TEXNUM_SCRAPS (TEXNUM_LIGHTMAPS + MAX_LIGHTMAPS) +#define TEXNUM_IMAGES (TEXNUM_SCRAPS + MAX_SCRAPS) +#define MAX_GLTEXTURES 1024 #define BLOCK_WIDTH 128 // default values; now defined in glstate_t #define BLOCK_HEIGHT 128 #define REF_VERSION "Yamagi Quake II OpenGL Refresher" #define BACKFACE_EPSILON 0.01 #define LIGHTMAP_BYTES 4 -#define MAX_LIGHTMAPS 128 +#define MAX_TEXTURE_UNITS 2 #define GL_LIGHTMAP_FORMAT GL_RGBA /* up / down */ @@ -106,19 +107,17 @@ typedef enum rserr_unknown } rserr_t; +typedef enum +{ + buf_2d +} buffered_draw_t; + #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_GLTEXTURES]; extern int numgltextures; @@ -287,6 +286,11 @@ void R_TextureAlphaMode(char *string); void R_TextureSolidMode(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); + #ifdef DEBUG void glCheckError_(const char *file, const char *function, int line); // Ideally, the following list should contain all OpenGL calls. @@ -380,7 +384,7 @@ typedef struct int lightmap_textures; - int currenttextures[2]; + int currenttextures[MAX_TEXTURE_UNITS]; int currenttmu; GLenum currenttarget;