mirror of
https://github.com/Shpoike/Quakespasm.git
synced 2024-11-10 07:21:58 +00:00
Alias model VBO renderer: restructure so each model is stored in a separate VBO and load them in Mod_LoadAliasModel, rather than R_NewMap.
Initially I thought that we would never need to draw an alias model that hadn't been precached when R_NewMap runs, but this assumption turned out to be incorrect. This fixes the issue where progs/bolt.mdl wasn't rendering in the Scourge Done Slick demos. git-svn-id: svn://svn.code.sf.net/p/quakespasm/code/trunk/quakespasm@1253 af15c1b1-3010-417e-b628-4374ebc0bcbd
This commit is contained in:
parent
b2465a4c82
commit
e007116a5d
9 changed files with 170 additions and 130 deletions
233
Quake/gl_mesh.c
233
Quake/gl_mesh.c
|
@ -287,7 +287,8 @@ void BuildTris (void)
|
|||
alltris += pheader->numtris;
|
||||
}
|
||||
|
||||
void GL_MakeAliasModelDisplayLists_VBO (void);
|
||||
static void GL_MakeAliasModelDisplayLists_VBO (void);
|
||||
static void GLMesh_LoadVertexBuffer (qmodel_t *m, const aliashdr_t *hdr);
|
||||
|
||||
/*
|
||||
================
|
||||
|
@ -436,144 +437,178 @@ void GL_MakeAliasModelDisplayLists_VBO (void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// upload immediately
|
||||
GLMesh_LoadVertexBuffer (aliasmodel, pheader);
|
||||
}
|
||||
|
||||
#define NUMVERTEXNORMALS 162
|
||||
extern float r_avertexnormals[NUMVERTEXNORMALS][3];
|
||||
|
||||
GLuint r_meshvbo = 0;
|
||||
GLuint r_meshindexesvbo = 0;
|
||||
|
||||
/*
|
||||
================
|
||||
GLMesh_LoadVertexBuffers
|
||||
GLMesh_LoadVertexBuffer
|
||||
|
||||
Loop over all precached alias models, and upload them into one big VBO plus
|
||||
an GL_ELEMENT_ARRAY_BUFFER for the vertex indices.
|
||||
Upload the given alias model's mesh to a VBO
|
||||
|
||||
Original code by MH from RMQEngine
|
||||
================
|
||||
*/
|
||||
void GLMesh_LoadVertexBuffers (void)
|
||||
static void GLMesh_LoadVertexBuffer (qmodel_t *m, const aliashdr_t *hdr)
|
||||
{
|
||||
int j;
|
||||
qmodel_t *m;
|
||||
int totalindexes = 0;
|
||||
int totalvbosize = 0;
|
||||
const aliasmesh_t *desc;
|
||||
const short *indexes;
|
||||
const trivertx_t *trivertexes;
|
||||
byte *vbodata;
|
||||
int f;
|
||||
|
||||
if (!gl_glsl_alias_able)
|
||||
return;
|
||||
|
||||
// count the sizes we need
|
||||
|
||||
// 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 = 0;
|
||||
|
||||
m->vboxyzofs = 0;
|
||||
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 (!hdr->numindexes) return;
|
||||
if (!totalvbosize) return;
|
||||
|
||||
// grab the pointers to data in the extradata
|
||||
|
||||
// pass 1 - count the sizes we need
|
||||
for (j = 1; j < MAX_MODELS; j++)
|
||||
desc = (aliasmesh_t *) ((byte *) hdr + hdr->meshdesc);
|
||||
indexes = (short *) ((byte *) hdr + hdr->indexes);
|
||||
trivertexes = (trivertx_t *) ((byte *)hdr + hdr->vertexes);
|
||||
|
||||
// upload indices buffer
|
||||
|
||||
GL_DeleteBuffersFunc (1, &m->meshindexesvbo);
|
||||
GL_GenBuffersFunc (1, &m->meshindexesvbo);
|
||||
GL_BindBufferFunc (GL_ELEMENT_ARRAY_BUFFER, m->meshindexesvbo);
|
||||
GL_BufferDataFunc (GL_ELEMENT_ARRAY_BUFFER, hdr->numindexes * sizeof (unsigned short), indexes, GL_STATIC_DRAW);
|
||||
|
||||
// create the vertex buffer (empty)
|
||||
|
||||
vbodata = (byte *) malloc(totalvbosize);
|
||||
memset(vbodata, 0, totalvbosize);
|
||||
|
||||
// fill in the vertices at the start of the buffer
|
||||
for (f = 0; f < hdr->numposes; f++) // ericw -- what RMQEngine called nummeshframes is called numposes in QuakeSpasm
|
||||
{
|
||||
aliashdr_t *hdr;
|
||||
int v;
|
||||
meshxyz_t *xyz = (meshxyz_t *) (vbodata + (f * hdr->numverts_vbo * sizeof (meshxyz_t)));
|
||||
const trivertx_t *tv = trivertexes + (hdr->numverts * f);
|
||||
|
||||
if (!(m = cl.model_precache[j])) break;
|
||||
if (m->type != mod_alias) continue;
|
||||
for (v = 0; v < hdr->numverts_vbo; v++)
|
||||
{
|
||||
trivertx_t trivert = tv[desc[v].vertindex];
|
||||
|
||||
hdr = (aliashdr_t *) Mod_Extradata (m);
|
||||
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
|
||||
|
||||
// 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));
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
if (!totalindexes) return;
|
||||
if (!totalvbosize) return;
|
||||
|
||||
// pass 2 - create the buffers
|
||||
GL_DeleteBuffersFunc (1, &r_meshindexesvbo);
|
||||
GL_GenBuffersFunc (1, &r_meshindexesvbo);
|
||||
GL_BindBufferFunc (GL_ELEMENT_ARRAY_BUFFER, r_meshindexesvbo);
|
||||
GL_BufferDataFunc (GL_ELEMENT_ARRAY_BUFFER, totalindexes * sizeof (unsigned short), NULL, GL_STATIC_DRAW);
|
||||
|
||||
GL_DeleteBuffersFunc (1, &r_meshvbo);
|
||||
GL_GenBuffersFunc (1, &r_meshvbo);
|
||||
GL_BindBufferFunc (GL_ARRAY_BUFFER, r_meshvbo);
|
||||
GL_BufferDataFunc (GL_ARRAY_BUFFER, totalvbosize, NULL, GL_STATIC_DRAW);
|
||||
|
||||
// pass 3 - fill in the buffers
|
||||
for (j = 1; j < MAX_MODELS; j++)
|
||||
// fill in the ST coords at the end of the buffer
|
||||
{
|
||||
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 = (aliashdr_t *) 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
|
||||
|
||||
GL_BufferSubDataFunc (GL_ELEMENT_ARRAY_BUFFER,
|
||||
m->vboindexofs,
|
||||
hdr->numindexes * sizeof (unsigned short),
|
||||
((byte *) hdr + hdr->indexes));
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
GL_BufferSubDataFunc (GL_ARRAY_BUFFER,
|
||||
m->vboxyzofs + (f * hdr->numverts_vbo * sizeof (meshxyz_t)),
|
||||
hdr->numverts_vbo * sizeof (meshxyz_t),
|
||||
xyz);
|
||||
|
||||
free (xyz);
|
||||
}
|
||||
|
||||
st = (meshst_t *) malloc (hdr->numverts_vbo * sizeof (meshst_t));
|
||||
|
||||
st = (meshst_t *) (vbodata + m->vbostofs);
|
||||
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;
|
||||
}
|
||||
|
||||
GL_BufferSubDataFunc (GL_ARRAY_BUFFER,
|
||||
m->vbostofs,
|
||||
hdr->numverts_vbo * sizeof (meshst_t),
|
||||
st);
|
||||
|
||||
free (st);
|
||||
}
|
||||
|
||||
// upload vertexes buffer
|
||||
GL_DeleteBuffersFunc (1, &m->meshvbo);
|
||||
GL_GenBuffersFunc (1, &m->meshvbo);
|
||||
GL_BindBufferFunc (GL_ARRAY_BUFFER, m->meshvbo);
|
||||
GL_BufferDataFunc (GL_ARRAY_BUFFER, totalvbosize, vbodata, GL_STATIC_DRAW);
|
||||
|
||||
free (vbodata);
|
||||
|
||||
// invalidate the cached bindings
|
||||
GL_ClearBufferBindings ();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
GLMesh_LoadVertexBuffers
|
||||
|
||||
Loop over all precached alias models, and upload each one to a VBO.
|
||||
================
|
||||
*/
|
||||
void GLMesh_LoadVertexBuffers (void)
|
||||
{
|
||||
int j;
|
||||
qmodel_t *m;
|
||||
const aliashdr_t *hdr;
|
||||
|
||||
if (!gl_glsl_alias_able)
|
||||
return;
|
||||
|
||||
for (j = 1; j < MAX_MODELS; j++)
|
||||
{
|
||||
if (!(m = cl.model_precache[j])) break;
|
||||
if (m->type != mod_alias) continue;
|
||||
|
||||
hdr = (const aliashdr_t *) Mod_Extradata (m);
|
||||
|
||||
GLMesh_LoadVertexBuffer (m, hdr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
GLMesh_DeleteVertexBuffers
|
||||
|
||||
Delete VBOs for all loaded alias models
|
||||
================
|
||||
*/
|
||||
void GLMesh_DeleteVertexBuffers (void)
|
||||
{
|
||||
int j;
|
||||
qmodel_t *m;
|
||||
|
||||
if (!gl_glsl_alias_able)
|
||||
return;
|
||||
|
||||
for (j = 1; j < MAX_MODELS; j++)
|
||||
{
|
||||
if (!(m = cl.model_precache[j])) break;
|
||||
if (m->type != mod_alias) continue;
|
||||
|
||||
GL_DeleteBuffersFunc (1, &m->meshvbo);
|
||||
m->meshvbo = 0;
|
||||
|
||||
GL_DeleteBuffersFunc (1, &m->meshindexesvbo);
|
||||
m->meshindexesvbo = 0;
|
||||
}
|
||||
|
||||
GL_ClearBufferBindings ();
|
||||
}
|
||||
|
|
|
@ -200,6 +200,9 @@ void Mod_ResetAll (void)
|
|||
int i;
|
||||
qmodel_t *mod;
|
||||
|
||||
//ericw -- free alias model VBOs
|
||||
GLMesh_DeleteVertexBuffers ();
|
||||
|
||||
for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
|
||||
{
|
||||
if (!mod->needload) //otherwise Mod_ClearAll() did it already
|
||||
|
|
|
@ -485,6 +485,8 @@ typedef struct qmodel_s
|
|||
// alias model
|
||||
//
|
||||
|
||||
GLuint meshvbo;
|
||||
GLuint meshindexesvbo;
|
||||
int vboindexofs; // offset in vbo of the hdr->numindexes unsigned shorts
|
||||
int vboxyzofs; // offset in vbo of hdr->numposes*hdr->numverts_vbo meshxyz_t
|
||||
int vbostofs; // offset in vbo of hdr->numverts_vbo meshst_t
|
||||
|
|
|
@ -397,9 +397,9 @@ void R_NewMap (void)
|
|||
R_ClearParticles ();
|
||||
|
||||
GL_BuildLightmaps ();
|
||||
GL_BuildVBOs ();
|
||||
GLMesh_LoadVertexBuffers ();
|
||||
|
||||
GL_BuildBModelVertexBuffer ();
|
||||
//ericw -- no longer load alias models into a VBO here, it's done in Mod_LoadAliasModel
|
||||
|
||||
r_framecount = 0; //johnfitz -- paranoid?
|
||||
r_visframecount = 0; //johnfitz -- paranoid?
|
||||
|
||||
|
|
|
@ -737,14 +737,18 @@ static void VID_Restart (void)
|
|||
return;
|
||||
}
|
||||
|
||||
// ericw -- depending on platform / SDL version, after a video mode change we
|
||||
// can have a new context (all textures are already freed) or the same context
|
||||
// as before, in which case we need to delete the old textures to avoid a
|
||||
// memory leak.
|
||||
// ericw -- OS X, SDL1: textures, VBO's invalid after mode change
|
||||
// OS X, SDL2: still valid after mode change
|
||||
// To handle both cases, delete all GL objects (textures, VBO, GLSL) now.
|
||||
// We must not interleave deleting the old objects with creating new ones, because
|
||||
// one of the new objects could be given the same ID as an invalid handle
|
||||
// which is later deleted.
|
||||
|
||||
TexMgr_DeleteTextureObjects ();
|
||||
GLSLGamma_DeleteTexture ();
|
||||
R_DeleteShaders ();
|
||||
GL_DeleteBModelVertexBuffer ();
|
||||
GLMesh_DeleteVertexBuffers ();
|
||||
|
||||
//
|
||||
// set new mode
|
||||
|
@ -753,7 +757,7 @@ static void VID_Restart (void)
|
|||
|
||||
GL_Init ();
|
||||
TexMgr_ReloadImages ();
|
||||
GL_BuildVBOs ();
|
||||
GL_BuildBModelVertexBuffer ();
|
||||
GLMesh_LoadVertexBuffers ();
|
||||
GL_SetupState ();
|
||||
|
||||
|
|
|
@ -343,8 +343,10 @@ 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 GL_DeleteBModelVertexBuffer (void);
|
||||
void GL_BuildBModelVertexBuffer (void);
|
||||
void GLMesh_LoadVertexBuffers (void);
|
||||
void GLMesh_DeleteVertexBuffers (void);
|
||||
void R_RebuildAllLightmaps (void);
|
||||
|
||||
int R_LightPoint (vec3_t p);
|
||||
|
|
|
@ -85,9 +85,6 @@ static const GLint pose2VertexAttrIndex = 2;
|
|||
static const GLint pose2NormalAttrIndex = 3;
|
||||
static const GLint texCoordsAttrIndex = 4;
|
||||
|
||||
extern GLuint r_meshvbo;
|
||||
extern GLuint r_meshindexesvbo;
|
||||
|
||||
/*
|
||||
=============
|
||||
GLARB_GetXYZOffset
|
||||
|
@ -237,8 +234,8 @@ void GL_DrawAliasFrame_GLSL (aliashdr_t *paliashdr, lerpdata_t lerpdata, gltextu
|
|||
|
||||
GL_UseProgramFunc (r_alias_program);
|
||||
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, r_meshvbo);
|
||||
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, r_meshindexesvbo);
|
||||
GL_BindBuffer (GL_ARRAY_BUFFER, currententity->model->meshvbo);
|
||||
GL_BindBuffer (GL_ELEMENT_ARRAY_BUFFER, currententity->model->meshindexesvbo);
|
||||
|
||||
GL_EnableVertexAttribArrayFunc (texCoordsAttrIndex);
|
||||
GL_EnableVertexAttribArrayFunc (pose1VertexAttrIndex);
|
||||
|
|
|
@ -961,15 +961,26 @@ void GL_BuildLightmaps (void)
|
|||
|
||||
GLuint gl_bmodel_vbo = 0;
|
||||
|
||||
void GL_DeleteBModelVertexBuffer (void)
|
||||
{
|
||||
if (!(gl_vbo_able && gl_mtexable && gl_max_texture_units >= 3))
|
||||
return;
|
||||
|
||||
GL_DeleteBuffersFunc (1, &gl_bmodel_vbo);
|
||||
gl_bmodel_vbo = 0;
|
||||
|
||||
GL_ClearBufferBindings ();
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
GL_BuildVBOs
|
||||
GL_BuildBModelVertexBuffer
|
||||
|
||||
Deletes gl_bmodel_vbo if it already exists, then rebuilds it with all
|
||||
surfaces from world + all brush models
|
||||
==================
|
||||
*/
|
||||
void GL_BuildVBOs (void)
|
||||
void GL_BuildBModelVertexBuffer (void)
|
||||
{
|
||||
unsigned int numverts, varray_bytes, varray_index;
|
||||
int i, j;
|
||||
|
|
16
Quake/zone.c
16
Quake/zone.c
|
@ -804,20 +804,6 @@ void Cache_Flush (void)
|
|||
Cache_Free ( cache_head.next->user, true); // reclaim the space //johnfitz -- added second argument
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cache_FlushReload
|
||||
|
||||
ericw -- "flush" command is used by modders to view modified mdl files. need to
|
||||
call GLMesh_LoadVertexBuffers to keep that use case working with GLSL renderer.
|
||||
============
|
||||
*/
|
||||
static void Cache_FlushReload (void)
|
||||
{
|
||||
Cache_Flush ();
|
||||
GLMesh_LoadVertexBuffers ();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cache_Print
|
||||
|
@ -856,7 +842,7 @@ void Cache_Init (void)
|
|||
cache_head.next = cache_head.prev = &cache_head;
|
||||
cache_head.lru_next = cache_head.lru_prev = &cache_head;
|
||||
|
||||
Cmd_AddCommand ("flush", Cache_FlushReload);
|
||||
Cmd_AddCommand ("flush", Cache_Flush);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue