mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-21 00:41:05 +00:00
GL3: Render Particles, simplify GL3_ShutdownShaders()
* The particles look more fuzzy than in old renderer - I think it looks better this way ;) * Not sure I keep the way they're rendered - instead of calculating and passing the distance in GL3_ShutdownShaders() I could set the player (camera) origin in a UBO and calculate distance (and based on that the size) in the vertex shader. I could also pass the basic point size via UBO, it's the same for all particles.. * Deleting shader programs is a lot shorter now and using a loop and the fact that consecutive fields of the same type in a struct have the same memory layout as an array of that type. Now I can just add a gl3ShaderInfo_t to gl3state, set it up in GL3_InitShaders() and don't have to add anything to GL3_ShutdownShaders() (this is good, I forgot that all the time and didn't notice, as it doesn't cause visible errors)
This commit is contained in:
parent
f3e77e1123
commit
247a81c69b
4 changed files with 200 additions and 33 deletions
|
@ -86,6 +86,7 @@ cvar_t *gl_anisotropic;
|
||||||
cvar_t *gl_texturemode;
|
cvar_t *gl_texturemode;
|
||||||
cvar_t *gl_drawbuffer;
|
cvar_t *gl_drawbuffer;
|
||||||
cvar_t *gl_clear;
|
cvar_t *gl_clear;
|
||||||
|
cvar_t *gl_particle_size;
|
||||||
|
|
||||||
cvar_t *gl_lefthand;
|
cvar_t *gl_lefthand;
|
||||||
cvar_t *gl_farsee;
|
cvar_t *gl_farsee;
|
||||||
|
@ -195,6 +196,7 @@ GL3_Register(void)
|
||||||
gl_mode = ri.Cvar_Get("gl_mode", "4", CVAR_ARCHIVE);
|
gl_mode = ri.Cvar_Get("gl_mode", "4", CVAR_ARCHIVE);
|
||||||
gl_customwidth = ri.Cvar_Get("gl_customwidth", "1024", CVAR_ARCHIVE);
|
gl_customwidth = ri.Cvar_Get("gl_customwidth", "1024", CVAR_ARCHIVE);
|
||||||
gl_customheight = ri.Cvar_Get("gl_customheight", "768", CVAR_ARCHIVE);
|
gl_customheight = ri.Cvar_Get("gl_customheight", "768", CVAR_ARCHIVE);
|
||||||
|
gl_particle_size = ri.Cvar_Get("gl_particle_size", "40", CVAR_ARCHIVE);
|
||||||
|
|
||||||
gl_norefresh = ri.Cvar_Get("gl_norefresh", "0", 0);
|
gl_norefresh = ri.Cvar_Get("gl_norefresh", "0", 0);
|
||||||
gl_drawentities = ri.Cvar_Get("gl_drawentities", "1", 0);
|
gl_drawentities = ri.Cvar_Get("gl_drawentities", "1", 0);
|
||||||
|
@ -247,7 +249,7 @@ GL3_Register(void)
|
||||||
|
|
||||||
gl_particle_min_size = ri.Cvar_Get("gl_particle_min_size", "2", CVAR_ARCHIVE);
|
gl_particle_min_size = ri.Cvar_Get("gl_particle_min_size", "2", CVAR_ARCHIVE);
|
||||||
gl_particle_max_size = ri.Cvar_Get("gl_particle_max_size", "40", CVAR_ARCHIVE);
|
gl_particle_max_size = ri.Cvar_Get("gl_particle_max_size", "40", CVAR_ARCHIVE);
|
||||||
gl_particle_size = ri.Cvar_Get("gl_particle_size", "40", CVAR_ARCHIVE);
|
//gl_particle_size = ri.Cvar_Get("gl_particle_size", "40", CVAR_ARCHIVE);
|
||||||
gl_particle_att_a = ri.Cvar_Get("gl_particle_att_a", "0.01", CVAR_ARCHIVE);
|
gl_particle_att_a = ri.Cvar_Get("gl_particle_att_a", "0.01", CVAR_ARCHIVE);
|
||||||
gl_particle_att_b = ri.Cvar_Get("gl_particle_att_b", "0.0", CVAR_ARCHIVE);
|
gl_particle_att_b = ri.Cvar_Get("gl_particle_att_b", "0.0", CVAR_ARCHIVE);
|
||||||
gl_particle_att_c = ri.Cvar_Get("gl_particle_att_c", "0.01", CVAR_ARCHIVE);
|
gl_particle_att_c = ri.Cvar_Get("gl_particle_att_c", "0.01", CVAR_ARCHIVE);
|
||||||
|
@ -799,6 +801,120 @@ GL3_DrawNullModel(void)
|
||||||
#endif // 0
|
#endif // 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
GL3_PolyBlend(void)
|
||||||
|
{
|
||||||
|
if (!gl_polyblend->value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!v_blend[3])
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glLoadIdentity();
|
||||||
|
|
||||||
|
glRotatef(-90, 1, 0, 0); /* put Z going up */
|
||||||
|
glRotatef(90, 0, 0, 1); /* put Z going up */
|
||||||
|
|
||||||
|
glColor4f( v_blend[0], v_blend[1], v_blend[2], v_blend[3] );
|
||||||
|
|
||||||
|
GLfloat vtx[] = {
|
||||||
|
10, 100, 100,
|
||||||
|
10, -100, 100,
|
||||||
|
10, -100, -100,
|
||||||
|
10, 100, -100
|
||||||
|
};
|
||||||
|
|
||||||
|
glEnableClientState( GL_VERTEX_ARRAY );
|
||||||
|
|
||||||
|
glVertexPointer( 3, GL_FLOAT, 0, vtx );
|
||||||
|
glDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
|
||||||
|
|
||||||
|
glDisableClientState( GL_VERTEX_ARRAY );
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnable(GL_ALPHA_TEST);
|
||||||
|
|
||||||
|
glColor4f(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
#endif // 0
|
||||||
|
|
||||||
|
static void
|
||||||
|
GL3_DrawParticles(void)
|
||||||
|
{
|
||||||
|
// TODO: stereo
|
||||||
|
//qboolean stereo_split_tb = ((gl_state.stereo_mode == STEREO_SPLIT_VERTICAL) && gl_state.camera_separation);
|
||||||
|
//qboolean stereo_split_lr = ((gl_state.stereo_mode == STEREO_SPLIT_HORIZONTAL) && gl_state.camera_separation);
|
||||||
|
|
||||||
|
//if (gl_config.pointparameters && !(stereo_split_tb || stereo_split_lr))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int numParticles = gl3_newrefdef.num_particles;
|
||||||
|
unsigned char color[4];
|
||||||
|
const particle_t *p;
|
||||||
|
// assume the size looks good with window height 600px and scale according to real resolution
|
||||||
|
float pointSize = gl_particle_size->value * (float)gl3_newrefdef.height/600.0f;
|
||||||
|
|
||||||
|
typedef struct part_vtx {
|
||||||
|
GLfloat pos[3];
|
||||||
|
GLfloat size;
|
||||||
|
GLfloat dist;
|
||||||
|
GLfloat color[4];
|
||||||
|
} part_vtx;
|
||||||
|
|
||||||
|
part_vtx buf[numParticles];
|
||||||
|
|
||||||
|
// FIXME: viewOrg could be in UBO
|
||||||
|
vec3_t viewOrg;
|
||||||
|
VectorCopy(gl3_newrefdef.vieworg, viewOrg);
|
||||||
|
|
||||||
|
glDepthMask(GL_FALSE);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||||
|
|
||||||
|
GL3_UseProgram(gl3state.siParticle.shaderProgram);
|
||||||
|
|
||||||
|
for ( i = 0, p = gl3_newrefdef.particles; i < numParticles; i++, p++ )
|
||||||
|
{
|
||||||
|
//*(int *) color = d_8to24table [ p->color & 0xFF ];
|
||||||
|
memcpy(color, &d_8to24table[ p->color & 0xFF ], 4);
|
||||||
|
part_vtx* cur = &buf[i];
|
||||||
|
vec3_t offset; // between viewOrg and particle position
|
||||||
|
VectorSubtract(viewOrg, p->origin, offset);
|
||||||
|
|
||||||
|
VectorCopy(p->origin, cur->pos);
|
||||||
|
cur->size = pointSize;
|
||||||
|
cur->dist = VectorLength(offset);
|
||||||
|
|
||||||
|
for(int j=0; j<3; ++j) cur->color[j] = color[j]/255.0f;
|
||||||
|
|
||||||
|
cur->color[3] = p->alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sizeof(part_vtx)==9*sizeof(float));
|
||||||
|
|
||||||
|
GL3_BindVAO(gl3state.vaoParticle);
|
||||||
|
GL3_BindVBO(gl3state.vboParticle);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(part_vtx)*numParticles, buf, GL_STREAM_DRAW);
|
||||||
|
glDrawArrays(GL_POINTS, 0, numParticles);
|
||||||
|
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDepthMask(GL_TRUE);
|
||||||
|
glDisable(GL_PROGRAM_POINT_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
GL3_DrawEntitiesOnList(void)
|
GL3_DrawEntitiesOnList(void)
|
||||||
{
|
{
|
||||||
|
@ -853,7 +969,6 @@ GL3_DrawEntitiesOnList(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* draw transparent entities
|
/* draw transparent entities
|
||||||
we could sort these if it ever
|
we could sort these if it ever
|
||||||
becomes a problem... */
|
becomes a problem... */
|
||||||
|
@ -901,7 +1016,6 @@ GL3_DrawEntitiesOnList(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
glDepthMask(1); /* back to writing */
|
glDepthMask(1); /* back to writing */
|
||||||
#endif // 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1369,9 +1483,10 @@ GL3_RenderView(refdef_t *fd)
|
||||||
GL3_DrawEntitiesOnList();
|
GL3_DrawEntitiesOnList();
|
||||||
#if 0 // TODO !!
|
#if 0 // TODO !!
|
||||||
GL3_RenderDlights();
|
GL3_RenderDlights();
|
||||||
|
|
||||||
R_DrawParticles();
|
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
|
GL3_DrawParticles();
|
||||||
|
|
||||||
GL3_DrawAlphaSurfaces();
|
GL3_DrawAlphaSurfaces();
|
||||||
#if 0
|
#if 0
|
||||||
R_Flash();
|
R_Flash();
|
||||||
|
|
|
@ -412,6 +412,51 @@ static const char* fragmentSrcAliasColor = MULTILINE_STRING(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static const char* vertexSrcParticles = MULTILINE_STRING(
|
||||||
|
|
||||||
|
// it gets attributes and uniforms from vertexCommon3D
|
||||||
|
|
||||||
|
out vec4 passColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
passColor = vertColor;
|
||||||
|
gl_Position = transProj * transModelView * vec4(position, 1.0);
|
||||||
|
|
||||||
|
// abusing texCoord for pointSize, pointDist for particles
|
||||||
|
float pointDist = texCoord.y*0.1; // with factor 0.1 it looks good.
|
||||||
|
|
||||||
|
// 1.4 to make them a bit bigger, they look smaller due to fading (see fragment shader)
|
||||||
|
gl_PointSize = 1.4*texCoord.x/pointDist;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
static const char* fragmentSrcParticles = MULTILINE_STRING(
|
||||||
|
|
||||||
|
// it gets attributes and uniforms from fragmentCommon3D
|
||||||
|
|
||||||
|
in vec4 passColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 offsetFromCenter = 2.0*(gl_PointCoord - vec2(0.5, 0.5)); // normalize so offset is between 0 and 1 instead 0 and 0.5
|
||||||
|
float distSquared = dot(offsetFromCenter, offsetFromCenter);
|
||||||
|
if(distSquared > 1.0) // this makes sure the particle is round
|
||||||
|
discard;
|
||||||
|
|
||||||
|
vec4 texel = passColor;
|
||||||
|
|
||||||
|
// apply gamma correction and intensity
|
||||||
|
//texel.rgb *= intensity; TODO: intensity? Probably not?
|
||||||
|
outColor.rgb = pow(texel.rgb, vec3(gamma));
|
||||||
|
|
||||||
|
// I want the particles to fade out towards the edge, the following seems to look nice
|
||||||
|
texel.a *= min(1.0, 1.2*(1.0 - distSquared));
|
||||||
|
|
||||||
|
outColor.a = texel.a; // I think alpha shouldn't be modified by gamma and intensity
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
#undef MULTILINE_STRING
|
#undef MULTILINE_STRING
|
||||||
|
|
||||||
|
@ -676,7 +721,11 @@ qboolean GL3_InitShaders(void)
|
||||||
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for rendering flat-colored models!\n");
|
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for rendering flat-colored models!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(!initShader3D(&gl3state.siParticle, vertexSrcParticles, fragmentSrcParticles))
|
||||||
|
{
|
||||||
|
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for rendering particles!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
gl3state.currentShaderProgram = 0;
|
gl3state.currentShaderProgram = 0;
|
||||||
|
|
||||||
|
@ -685,34 +734,15 @@ qboolean GL3_InitShaders(void)
|
||||||
|
|
||||||
void GL3_ShutdownShaders(void)
|
void GL3_ShutdownShaders(void)
|
||||||
{
|
{
|
||||||
if(gl3state.si2D.shaderProgram != 0)
|
const gl3ShaderInfo_t siZero = {0};
|
||||||
glDeleteProgram(gl3state.si2D.shaderProgram);
|
for(gl3ShaderInfo_t* si = &gl3state.si2D; si <= &gl3state.siParticle; ++si)
|
||||||
memset(&gl3state.si2D, 0, sizeof(gl3ShaderInfo_t));
|
{
|
||||||
|
if(si->shaderProgram != 0) glDeleteProgram(si->shaderProgram);
|
||||||
if(gl3state.si2Dcolor.shaderProgram != 0)
|
*si = siZero;
|
||||||
glDeleteProgram(gl3state.si2Dcolor.shaderProgram);
|
}
|
||||||
memset(&gl3state.si2Dcolor, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
if(gl3state.si3D.shaderProgram != 0)
|
|
||||||
glDeleteProgram(gl3state.si3D.shaderProgram);
|
|
||||||
memset(&gl3state.si3D, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
if(gl3state.si3Dflow.shaderProgram != 0)
|
|
||||||
glDeleteProgram(gl3state.si3Dflow.shaderProgram);
|
|
||||||
memset(&gl3state.si3Dflow, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
if(gl3state.si3Dturb.shaderProgram != 0)
|
|
||||||
glDeleteProgram(gl3state.si3Dturb.shaderProgram);
|
|
||||||
memset(&gl3state.si3Dturb, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
if(gl3state.si3Dalias.shaderProgram != 0)
|
|
||||||
glDeleteProgram(gl3state.si3Dalias.shaderProgram);
|
|
||||||
memset(&gl3state.si3Dalias, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
if(gl3state.si3DaliasColor.shaderProgram != 0)
|
|
||||||
glDeleteProgram(gl3state.si3DaliasColor.shaderProgram);
|
|
||||||
memset(&gl3state.si3DaliasColor, 0, sizeof(gl3ShaderInfo_t));
|
|
||||||
|
|
||||||
|
// let's (ab)use the fact that all 3 UBO handles are consecutive fields
|
||||||
|
// of the gl3state struct
|
||||||
glDeleteBuffers(3, &gl3state.uniCommonUBO);
|
glDeleteBuffers(3, &gl3state.uniCommonUBO);
|
||||||
gl3state.uniCommonUBO = gl3state.uni2DUBO = gl3state.uni3DUBO = 0;
|
gl3state.uniCommonUBO = gl3state.uni2DUBO = gl3state.uni3DUBO = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,22 @@ void GL3_SurfInit(void)
|
||||||
|
|
||||||
glEnableVertexAttribArray(GL3_ATTRIB_COLOR);
|
glEnableVertexAttribArray(GL3_ATTRIB_COLOR);
|
||||||
qglVertexAttribPointer(GL3_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 5*sizeof(GLfloat));
|
qglVertexAttribPointer(GL3_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 5*sizeof(GLfloat));
|
||||||
|
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &gl3state.vaoParticle);
|
||||||
|
GL3_BindVAO(gl3state.vaoParticle);
|
||||||
|
|
||||||
|
glGenBuffers(1, &gl3state.vboParticle);
|
||||||
|
GL3_BindVBO(gl3state.vboParticle);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(GL3_ATTRIB_POSITION);
|
||||||
|
qglVertexAttribPointer(GL3_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 0);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(GL3_ATTRIB_TEXCOORD); // it's abused for (point_size, distance) here..
|
||||||
|
qglVertexAttribPointer(GL3_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 3*sizeof(GLfloat));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(GL3_ATTRIB_COLOR);
|
||||||
|
qglVertexAttribPointer(GL3_ATTRIB_COLOR, 4, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), 5*sizeof(GLfloat));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL3_SurfShutdown(void)
|
void GL3_SurfShutdown(void)
|
||||||
|
|
|
@ -162,6 +162,8 @@ typedef struct
|
||||||
GLuint currentVAO;
|
GLuint currentVAO;
|
||||||
GLuint currentVBO;
|
GLuint currentVBO;
|
||||||
GLuint currentShaderProgram;
|
GLuint currentShaderProgram;
|
||||||
|
|
||||||
|
// NOTE: make sure si2D is always the first shaderInfo (or adapt GL3_ShutdownShaders())
|
||||||
gl3ShaderInfo_t si2D; // shader for rendering 2D with textures
|
gl3ShaderInfo_t si2D; // shader for rendering 2D with textures
|
||||||
gl3ShaderInfo_t si2Dcolor; // shader for rendering 2D with flat colors
|
gl3ShaderInfo_t si2Dcolor; // shader for rendering 2D with flat colors
|
||||||
gl3ShaderInfo_t si3D;
|
gl3ShaderInfo_t si3D;
|
||||||
|
@ -170,8 +172,12 @@ typedef struct
|
||||||
gl3ShaderInfo_t si3Dalias; // for models
|
gl3ShaderInfo_t si3Dalias; // for models
|
||||||
gl3ShaderInfo_t si3DaliasColor; // for models w/ flat colors
|
gl3ShaderInfo_t si3DaliasColor; // for models w/ flat colors
|
||||||
|
|
||||||
|
// NOTE: make sure siParticle is always the last shaderInfo (or adapt GL3_ShutdownShaders())
|
||||||
|
gl3ShaderInfo_t siParticle; // for particles. surprising, right?
|
||||||
|
|
||||||
GLuint vao3D, vbo3D; // for brushes etc, using 7 floats as vertex input (x,y,z, s,t, lms,lmt)
|
GLuint vao3D, vbo3D; // for brushes etc, using 7 floats as vertex input (x,y,z, s,t, lms,lmt)
|
||||||
GLuint vaoAlias, vboAlias; // for models, using 9 floats as (x,y,z, s,t, r,g,b,a)
|
GLuint vaoAlias, vboAlias; // for models, using 9 floats as (x,y,z, s,t, r,g,b,a)
|
||||||
|
GLuint vaoParticle, vboParticle; // for particles, using 9 floats (x,y,z, size,distance, r,g,b,a)
|
||||||
|
|
||||||
// UBOs and their data
|
// UBOs and their data
|
||||||
gl3UniCommon_t uniCommonData;
|
gl3UniCommon_t uniCommonData;
|
||||||
|
|
Loading…
Reference in a new issue