implement proper lerping

This commit is contained in:
Eric Wasylishen 2014-10-25 15:06:00 -06:00
parent 37bc1a7d0d
commit 9b729cdac9
6 changed files with 77 additions and 412 deletions

View file

@ -373,9 +373,6 @@ void GL_MakeAliasModelDisplayLists_VBO (void)
unsigned short *indexes;
aliasmesh_t *desc;
if (!GLAlias_SupportsShaders())
return;
// first, copy the verts onto the hunk
verts = (trivertx_t *) Hunk_Alloc (paliashdr->numposes * paliashdr->numverts * sizeof(trivertx_t));
paliashdr->vertexes = (byte *)verts - (byte *)paliashdr;
@ -437,131 +434,3 @@ void GL_MakeAliasModelDisplayLists_VBO (void)
}
}
}
#define NUMVERTEXNORMALS 162
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
GLuint r_meshvbo = 0;
GLuint r_meshindexesvbo = 0;
char *r_meshdata;
/*
================
GLMesh_LoadVertexBuffers
Loop over all precached alias models, and upload them into one big VBO plus
an GL_ELEMENT_ARRAY_BUFFER for the vertex indices.
Original code by MH from RMQEngine
================
*/
void GLMesh_LoadVertexBuffers (void)
{
int j;
qmodel_t *m;
int totalindexes = 0;
int totalvbosize = 0;
if (!GLAlias_SupportsShaders())
return;
// pass 1 - count the sizes we need
for (j = 1; j < MAX_MODELS; j++)
{
aliashdr_t *hdr;
if (!(m = cl.model_precache[j])) break;
if (m->type != mod_alias) continue;
hdr = Mod_Extradata (m);
// ericw -- RMQEngine stored these vbo*ofs values in aliashdr_t, but we must not
// mutate Mod_Extradata since it might be reloaded from disk, so I moved them to qmodel_t
// (test case: roman1.bsp from arwop, 64mb heap)
m->vboindexofs = (totalindexes * sizeof (unsigned short));
totalindexes += hdr->numindexes;
m->vboxyzofs = totalvbosize;
totalvbosize += (hdr->numposes * hdr->numverts_vbo * sizeof (meshxyz_t)); // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
m->vbostofs = totalvbosize;
totalvbosize += (hdr->numverts_vbo * sizeof (meshst_t));
}
if (!totalindexes) return;
if (!totalvbosize) return;
// pass 2 - create the buffers
if (r_meshdata != NULL)
free(r_meshdata);
r_meshdata = malloc(totalvbosize);
// pass 3 - fill in the buffers
for (j = 1; j < MAX_MODELS; j++)
{
int f;
aliashdr_t *hdr;
aliasmesh_t *desc;
meshst_t *st;
float hscale, vscale;
if (!(m = cl.model_precache[j])) break;
if (m->type != mod_alias) continue;
hdr = Mod_Extradata (m);
desc = (aliasmesh_t *) ((byte *) hdr + hdr->meshdesc);
//johnfitz -- padded skins
hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth);
vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight);
//johnfitz
for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
{
int v;
meshxyz_t *xyz = (meshxyz_t *) malloc (hdr->numverts_vbo * sizeof (meshxyz_t));
trivertx_t *tv = (trivertx_t *) ((byte *) hdr + hdr->vertexes + (hdr->numverts * sizeof(trivertx_t) * f));
for (v = 0; v < hdr->numverts_vbo; v++)
{
trivertx_t trivert = tv[desc[v].vertindex];
xyz[v].xyz[0] = trivert.v[0];
xyz[v].xyz[1] = trivert.v[1];
xyz[v].xyz[2] = trivert.v[2];
//xyz[v].xyz[3] = 1; // need w 1 for 4 byte vertex compression
// map the normal coordinates in [-1..1] to [-127..127] and store in an unsigned char.
// this introduces some error (less than 0.004), but the normals were very coarse
// to begin with
xyz[v].normal[0] = /*127 **/ r_avertexnormals[trivert.lightnormalindex][0];
xyz[v].normal[1] = /*127 **/ r_avertexnormals[trivert.lightnormalindex][1];
xyz[v].normal[2] = /*127 **/ r_avertexnormals[trivert.lightnormalindex][2];
//xyz[v].normal[3] = 0; // unused; for 4-byte alignment
}
memcpy (r_meshdata + m->vboxyzofs + (f * hdr->numverts_vbo * sizeof (meshxyz_t)),
xyz,
hdr->numverts_vbo * sizeof (meshxyz_t));
free (xyz);
}
st = (meshst_t *) malloc (hdr->numverts_vbo * sizeof (meshst_t));
for (f = 0; f < hdr->numverts_vbo; f++)
{
st[f].st[0] = hscale * ((float) desc[f].st[0] + 0.5f) / (float) hdr->skinwidth;
st[f].st[1] = vscale * ((float) desc[f].st[1] + 0.5f) / (float) hdr->skinheight;
}
memcpy (r_meshdata + m->vbostofs,
st,
hdr->numverts_vbo * sizeof (meshst_t));
free (st);
}
}

View file

@ -290,16 +290,13 @@ typedef struct aliasmesh_s
unsigned short vertindex;
} aliasmesh_t;
typedef struct meshxyz_s
typedef struct meshvert_t
{
float xyz[3];
float normal[3];
} meshxyz_t;
typedef struct meshst_s
{
float color[4];
float st[2];
} meshst_t;
} meshvert_t;
//--
typedef struct

View file

@ -274,7 +274,6 @@ void R_NewMap (void)
GL_BuildLightmaps ();
GL_BuildVBOs ();
GLMesh_LoadVertexBuffers ();
r_framecount = 0; //johnfitz -- paranoid?
r_visframecount = 0; //johnfitz -- paranoid?
@ -321,91 +320,3 @@ void R_TimeRefresh_f (void)
void D_FlushCaches (void)
{
}
static GLuint gl_programs[16];
static int gl_num_programs;
/*
====================
GL_CreateVertexShader
Compiles an GLSL vertex shader. Returns the program.
====================
*/
GLuint GL_CreateVertexShader (const GLchar *source)
{
GLuint program, shader;
GLint status;
if (!GLAlias_SupportsShaders())
return 0;
shader = GL_CreateShaderFunc (GL_VERTEX_SHADER);
GL_ShaderSourceFunc (shader, 1, &source, NULL);
GL_CompileShaderFunc (shader);
GL_GetShaderivFunc (shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
char infolog[1024];
memset(infolog, 0, sizeof(infolog));
GL_GetShaderInfoLogFunc (shader, sizeof(infolog), NULL, infolog);
GL_DeleteShaderFunc (shader);
Con_Warning ("GLSL program failed to compile: %s", infolog);
return 0;
}
program = GL_CreateProgramFunc ();
GL_AttachShaderFunc (program, shader);
GL_DeleteShaderFunc (shader);
GL_LinkProgramFunc (program);
GL_GetProgramivFunc (program, GL_LINK_STATUS, &status);
if (status != GL_TRUE)
{
char infolog[1024];
memset(infolog, 0, sizeof(infolog));
GL_GetProgramInfoLogFunc (program, sizeof(infolog), NULL, infolog);
GL_DeleteProgramFunc (program);
Con_Warning ("GLSL program failed to link: %s", infolog);
return 0;
}
else
{
if (gl_num_programs == (sizeof(gl_programs)/sizeof(GLuint)))
Host_Error ("gl_programs overflow");
gl_programs[gl_num_programs] = program;
gl_num_programs++;
return program;
}
}
/*
====================
R_DeleteShaders
Deletes any GLSL programs that have been created.
====================
*/
void R_DeleteShaders (void)
{
int i;
if (!GLAlias_SupportsShaders())
return;
for (i = 0; i < gl_num_programs; i++)
{
GL_DeleteProgramFunc (gl_programs[i]);
gl_programs[i] = 0;
}
gl_num_programs = 0;
}

View file

@ -678,7 +678,6 @@ static void VID_Restart (void)
GL_Init ();
TexMgr_ReloadImages ();
GL_BuildVBOs ();
GLMesh_LoadVertexBuffers ();
GL_SetupState ();
//warpimages needs to be recalculated
@ -1139,9 +1138,6 @@ static void GL_Init (void)
Cbuf_AddText ("gl_clear 1");
}
//johnfitz
R_DeleteShaders ();
GLAlias_CreateShaders ();
}
/*

View file

@ -327,7 +327,6 @@ void R_DrawTextureChains_Water (qmodel_t *model, entity_t *ent, texchain_t chain
void R_RenderDlights (void);
void GL_BuildLightmaps (void);
void GL_BuildVBOs (void);
void GLMesh_LoadVertexBuffers (void);
void R_RebuildAllLightmaps (void);
int R_LightPoint (vec3_t p);
@ -345,8 +344,6 @@ void R_DrawParticles_ShowTris (void);
GLuint GL_CreateVertexShader (const GLchar *source);
void R_DeleteShaders (void);
qboolean GLAlias_SupportsShaders (void);
void GLAlias_CreateShaders (void);
void GL_DrawAliasShadow (entity_t *e);
void DrawGLTriangleFan (glpoly_t *p);
void DrawGLPoly (glpoly_t *p);

View file

@ -67,129 +67,50 @@ typedef struct {
} lerpdata_t;
//johnfitz
static GLuint r_alias_vertex_program;
static GLuint blendLoc;
static GLuint shadevectorLoc;
static GLuint lightColorLoc;
static GLint pose1VertexAttrIndex;
static GLint pose1NormalAttrIndex;
static GLint pose2VertexAttrIndex;
static GLint pose2NormalAttrIndex;
extern GLuint r_meshvbo;
extern GLuint r_meshindexesvbo;
extern char *r_meshdata;
void *GLARB_GetXYZOffset (aliashdr_t *hdr, int pose)
void fillverts(unsigned short *indices, meshvert_t *verts, aliashdr_t *hdr, float blend, lerpdata_t lerpdata)
{
meshxyz_t dummy;
int xyzoffs = ((char*)&dummy.xyz - (char*)&dummy);
return (void *) (r_meshdata + currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + xyzoffs);
}
aliasmesh_t *desc;
float hscale, vscale;
void *GLARB_GetNormalOffset (aliashdr_t *hdr, int pose)
{
meshxyz_t dummy;
int normaloffs = ((char*)&dummy.normal - (char*)&dummy);
return (void *)(r_meshdata + currententity->model->vboxyzofs + (hdr->numverts_vbo * pose * sizeof (meshxyz_t)) + normaloffs);
}
float iblend;
iblend = 1 - blend;
qboolean GLAlias_SupportsShaders (void)
{
return gl_glsl_able && gl_vbo_able && gl_max_texture_units >= 3;
}
desc = (aliasmesh_t *) ((byte *) hdr + hdr->meshdesc);
static GLint GLAlias_GetUniformLocation (const char *name)
{
GLint location;
location = GL_GetUniformLocationFunc(r_alias_vertex_program, name);
if (location == -1)
//johnfitz -- padded skins
hscale = (float)hdr->skinwidth/(float)TexMgr_PadConditional(hdr->skinwidth);
vscale = (float)hdr->skinheight/(float)TexMgr_PadConditional(hdr->skinheight);
//johnfitz
int v;
trivertx_t *tv1 = (trivertx_t *) ((byte *) hdr + hdr->vertexes + (hdr->numverts * sizeof(trivertx_t) * lerpdata.pose1));
trivertx_t *tv2 = (trivertx_t *) ((byte *) hdr + hdr->vertexes + (hdr->numverts * sizeof(trivertx_t) * lerpdata.pose2));
for (v = 0; v < hdr->numverts_vbo; v++)
{
Con_Warning("GL_GetUniformLocationFunc %s failed", name);
r_alias_vertex_program = 0;
}
return location;
}
trivertx_t trivert1 = tv1[desc[v].vertindex];
trivertx_t trivert2 = tv2[desc[v].vertindex];
/*
=============
GLAlias_CreateShaders
=============
*/
void GLAlias_CreateShaders (void)
{
const GLchar *source = \
"#version 110\n"
"\n"
"uniform float Blend;\n"
"uniform vec3 ShadeVector;\n"
"uniform vec4 LightColor;\n"
"attribute vec4 Pose1Vert;\n"
"attribute vec3 Pose1Normal;\n"
"attribute vec4 Pose2Vert;\n"
"attribute vec3 Pose2Normal;\n"
"float r_avertexnormal_dot(vec3 vertexnormal) // from MH \n"
"{\n"
" float dot = dot(vertexnormal, ShadeVector);\n"
" // wtf - this reproduces anorm_dots within as reasonable a degree of tolerance as the >= 0 case\n"
" if (dot < 0.0)\n"
" return 1.0 + dot * (13.0 / 44.0);\n"
" else\n"
" return 1.0 + dot;\n"
"}\n"
"void main()\n"
"{\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" gl_TexCoord[1] = gl_MultiTexCoord0;\n"
" vec4 lerpedVert = mix(Pose1Vert, Pose2Vert, Blend);\n"
" gl_Position = gl_ModelViewProjectionMatrix * lerpedVert;\n"
" float dot1 = r_avertexnormal_dot(Pose1Normal);\n"
" float dot2 = r_avertexnormal_dot(Pose2Normal);\n"
" gl_FrontColor = LightColor * vec4(vec3(mix(dot1, dot2, Blend)), 1.0);\n"
" // fog\n"
" vec3 ecPosition = vec3(gl_ModelViewMatrix * lerpedVert);\n"
" gl_FogFragCoord = abs(ecPosition.z);\n"
"}\n";
verts[v].xyz[0] = iblend*trivert1.v[0] + blend*trivert2.v[0];
verts[v].xyz[1] = iblend*trivert1.v[1] + blend*trivert2.v[1];
verts[v].xyz[2] = iblend*trivert1.v[2] + blend*trivert2.v[2];
if (!GLAlias_SupportsShaders())
return;
float brightness = shadedots[trivert1.lightnormalindex]*iblend + shadedots[trivert2.lightnormalindex]*blend;
r_alias_vertex_program = GL_CreateVertexShader (source);
verts[v].color[0] = brightness * lightcolor[0];
verts[v].color[1] = brightness * lightcolor[1];
verts[v].color[2] = brightness * lightcolor[2];
verts[v].color[3] = entalpha;
if (r_alias_vertex_program != 0)
{
// get uniform locations
blendLoc = GLAlias_GetUniformLocation ("Blend");
shadevectorLoc = GLAlias_GetUniformLocation ("ShadeVector");
lightColorLoc = GLAlias_GetUniformLocation ("LightColor");
// get attributes
pose1VertexAttrIndex = GL_GetAttribLocationFunc (r_alias_vertex_program, "Pose1Vert");
pose1NormalAttrIndex = GL_GetAttribLocationFunc (r_alias_vertex_program, "Pose1Normal");
pose2VertexAttrIndex = GL_GetAttribLocationFunc (r_alias_vertex_program, "Pose2Vert");
pose2NormalAttrIndex = GL_GetAttribLocationFunc (r_alias_vertex_program, "Pose2Normal");
verts[v].st[0] = hscale * ((float) desc[v].st[0] + 0.5f) / (float) hdr->skinwidth;
verts[v].st[1] = vscale * ((float) desc[v].st[1] + 0.5f) / (float) hdr->skinheight;
}
}
/*
=============
GL_DrawAliasFrame_GLSL -- ericw
Optimized alias model drawing codepath.
Compared to the original GL_DrawAliasFrame, this makes 1 draw call,
no vertex data is uploaded (it's already in the r_meshvbo and r_meshindexesvbo
static VBOs), and lerping and lighting is done in the vertex shader.
Based on code by MH from RMQEngine
=============
*/
void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata)
void GLAlias_ArrayDraw (aliashdr_t *paliashdr, lerpdata_t lerpdata)
{
float blend;
aliashdr_t *hdr = paliashdr;
if (lerpdata.pose1 != lerpdata.pose2)
{
@ -200,83 +121,57 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata)
blend = 0;
}
// setup array
unsigned short *indices = (unsigned short *) malloc (sizeof (unsigned short) * hdr->numindexes);
meshvert_t *verts = (meshvert_t *) malloc (sizeof (meshvert_t) * hdr->numverts_vbo);
fillverts(indices, verts, hdr, blend, lerpdata);
// bind
GL_BindBufferFunc (GL_ARRAY_BUFFER, 0);
glVertexPointer(3, GL_FLOAT, sizeof(meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose1));
glNormalPointer(GL_FLOAT, sizeof(meshxyz_t), GLARB_GetNormalOffset(paliashdr, lerpdata.pose1));
glVertexPointer(3, GL_FLOAT, sizeof(meshvert_t), &(verts[0].xyz));
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glColorPointer(4, GL_FLOAT, sizeof(meshvert_t), &(verts[0].color));
glEnableClientState(GL_COLOR_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB);
glTexCoordPointer (2, GL_FLOAT, 0, r_meshdata + currententity->model->vbostofs);
glTexCoordPointer (2, GL_FLOAT, sizeof(meshvert_t), &(verts[0].st));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB);
glTexCoordPointer (2, GL_FLOAT, sizeof(meshvert_t), &(verts[0].st));
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
// draw
glDrawElements (GL_TRIANGLES, hdr->numindexes, GL_UNSIGNED_SHORT, ((char*)hdr) + hdr->indexes);
// clean up
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
//
// GL_UseProgramFunc (r_alias_vertex_program);
//
// GL_BindBufferFunc (GL_ARRAY_BUFFER, r_meshvbo);
// GL_BindBufferFunc (GL_ELEMENT_ARRAY_BUFFER, r_meshindexesvbo);
//
// GL_VertexAttribPointerFunc (pose1VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), );
// GL_EnableVertexAttribArrayFunc (pose1VertexAttrIndex);
//
// GL_VertexAttribPointerFunc (pose2VertexAttrIndex, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof (meshxyz_t), GLARB_GetXYZOffset (paliashdr, lerpdata.pose2));
// GL_EnableVertexAttribArrayFunc (pose2VertexAttrIndex);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB);
// glTexCoordPointer (2, GL_FLOAT, 0, (void *)(intptr_t)currententity->model->vbostofs);
// glEnableClientState (GL_TEXTURE_COORD_ARRAY);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB);
// glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB);
// glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
//// GL_TRUE to normalize the signed bytes to [-1 .. 1]
// GL_VertexAttribPointerFunc (pose1NormalAttrIndex, 3, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose1));
// GL_EnableVertexAttribArrayFunc (pose1NormalAttrIndex);
//
// GL_VertexAttribPointerFunc (pose2NormalAttrIndex, 3, GL_BYTE, GL_TRUE, sizeof (meshxyz_t), GLARB_GetNormalOffset (paliashdr, lerpdata.pose2));
// GL_EnableVertexAttribArrayFunc (pose2NormalAttrIndex);
//
//// set uniforms
// GL_Uniform1fFunc (blendLoc, blend);
// GL_Uniform3fFunc (shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]);
// GL_Uniform4fFunc (lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha);
// draw
glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, ((char*)paliashdr) + paliashdr->indexes);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// clean up
// GL_DisableVertexAttribArrayFunc (pose1VertexAttrIndex);
// GL_DisableVertexAttribArrayFunc (pose2VertexAttrIndex);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE0_ARB);
// glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE1_ARB);
// glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
// GL_ClientActiveTextureFunc (GL_TEXTURE2_ARB);
// glDisableClientState (GL_TEXTURE_COORD_ARRAY);
//
// GL_DisableVertexAttribArrayFunc (pose1NormalAttrIndex);
// GL_DisableVertexAttribArrayFunc (pose2NormalAttrIndex);
//
// GL_UseProgramFunc (0);
free(indices);
free(verts);
// stats
rs_aliaspasses += paliashdr->numtris;
}
@ -297,9 +192,9 @@ void GL_DrawAliasFrame (aliashdr_t *paliashdr, lerpdata_t lerpdata)
// call fast path if possible. if the shader compliation failed for some reason,
// r_alias_vertex_program will be 0.
if (GLAlias_SupportsShaders() && (r_alias_vertex_program != 0) && !r_drawflat_cheatsafe && shading)
if (!r_drawflat_cheatsafe && shading)
{
GL_DrawAliasFrame_GLSL (paliashdr, lerpdata);
GLAlias_ArrayDraw (paliashdr, lerpdata);
return;
}