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_drawbuffer;
|
||||
cvar_t *gl_clear;
|
||||
cvar_t *gl_particle_size;
|
||||
|
||||
cvar_t *gl_lefthand;
|
||||
cvar_t *gl_farsee;
|
||||
|
@ -195,6 +196,7 @@ GL3_Register(void)
|
|||
gl_mode = ri.Cvar_Get("gl_mode", "4", CVAR_ARCHIVE);
|
||||
gl_customwidth = ri.Cvar_Get("gl_customwidth", "1024", 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_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_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_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);
|
||||
|
@ -799,6 +801,120 @@ GL3_DrawNullModel(void)
|
|||
#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
|
||||
GL3_DrawEntitiesOnList(void)
|
||||
{
|
||||
|
@ -853,7 +969,6 @@ GL3_DrawEntitiesOnList(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* draw transparent entities
|
||||
we could sort these if it ever
|
||||
becomes a problem... */
|
||||
|
@ -901,7 +1016,6 @@ GL3_DrawEntitiesOnList(void)
|
|||
}
|
||||
|
||||
glDepthMask(1); /* back to writing */
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1369,9 +1483,10 @@ GL3_RenderView(refdef_t *fd)
|
|||
GL3_DrawEntitiesOnList();
|
||||
#if 0 // TODO !!
|
||||
GL3_RenderDlights();
|
||||
|
||||
R_DrawParticles();
|
||||
#endif // 0
|
||||
|
||||
GL3_DrawParticles();
|
||||
|
||||
GL3_DrawAlphaSurfaces();
|
||||
#if 0
|
||||
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
|
||||
|
||||
|
@ -676,7 +721,11 @@ qboolean GL3_InitShaders(void)
|
|||
R_Printf(PRINT_ALL, "WARNING: Failed to create shader program for rendering flat-colored models!\n");
|
||||
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;
|
||||
|
||||
|
@ -685,34 +734,15 @@ qboolean GL3_InitShaders(void)
|
|||
|
||||
void GL3_ShutdownShaders(void)
|
||||
{
|
||||
if(gl3state.si2D.shaderProgram != 0)
|
||||
glDeleteProgram(gl3state.si2D.shaderProgram);
|
||||
memset(&gl3state.si2D, 0, sizeof(gl3ShaderInfo_t));
|
||||
|
||||
if(gl3state.si2Dcolor.shaderProgram != 0)
|
||||
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));
|
||||
const gl3ShaderInfo_t siZero = {0};
|
||||
for(gl3ShaderInfo_t* si = &gl3state.si2D; si <= &gl3state.siParticle; ++si)
|
||||
{
|
||||
if(si->shaderProgram != 0) glDeleteProgram(si->shaderProgram);
|
||||
*si = siZero;
|
||||
}
|
||||
|
||||
// let's (ab)use the fact that all 3 UBO handles are consecutive fields
|
||||
// of the gl3state struct
|
||||
glDeleteBuffers(3, &gl3state.uniCommonUBO);
|
||||
gl3state.uniCommonUBO = gl3state.uni2DUBO = gl3state.uni3DUBO = 0;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,22 @@ void GL3_SurfInit(void)
|
|||
|
||||
glEnableVertexAttribArray(GL3_ATTRIB_COLOR);
|
||||
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)
|
||||
|
|
|
@ -162,6 +162,8 @@ typedef struct
|
|||
GLuint currentVAO;
|
||||
GLuint currentVBO;
|
||||
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 si2Dcolor; // shader for rendering 2D with flat colors
|
||||
gl3ShaderInfo_t si3D;
|
||||
|
@ -170,8 +172,12 @@ typedef struct
|
|||
gl3ShaderInfo_t si3Dalias; // for models
|
||||
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 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
|
||||
gl3UniCommon_t uniCommonData;
|
||||
|
|
Loading…
Reference in a new issue