From 6be576a5bdfccd4467e87edcbb13ff81740bb79c Mon Sep 17 00:00:00 2001 From: havoc Date: Wed, 4 Apr 2007 11:54:05 +0000 Subject: [PATCH] now creates EBOs and VBOs containing static model geometry, map geometry, and compiled shadows git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7044 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_backend.c | 28 ++++++++++++++++ gl_backend.h | 11 ++++++ gl_rsurf.c | 2 +- model_brush.c | 4 +-- model_shared.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++- model_shared.h | 26 ++++++++++++++- todo | 1 + 7 files changed, 157 insertions(+), 5 deletions(-) diff --git a/gl_backend.c b/gl_backend.c index 70af0a43..cb2f2fea 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -1081,6 +1081,34 @@ void R_Mesh_Finish(void) qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);CHECKGLERROR } +int R_Mesh_CreateStaticEBO(void *data, size_t size) +{ + GLuint bufferobject; + qglGenBuffersARB(1, &bufferobject); + GL_BindEBO(bufferobject); + qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB); + return (int)bufferobject; +} + +void R_Mesh_DestroyEBO(int bufferobject) +{ + qglDeleteBuffersARB(1, (GLuint *)&bufferobject); +} + +int R_Mesh_CreateStaticVBO(void *data, size_t size) +{ + GLuint bufferobject; + qglGenBuffersARB(1, &bufferobject); + GL_BindVBO(bufferobject); + qglBufferDataARB(GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB); + return (int)bufferobject; +} + +void R_Mesh_DestroyVBO(int bufferobject) +{ + qglDeleteBuffersARB(1, (GLuint *)&bufferobject); +} + void R_Mesh_Matrix(const matrix4x4_t *matrix) { if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t))) diff --git a/gl_backend.h b/gl_backend.h index ba2e646a..773a0d1b 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -69,6 +69,17 @@ void R_Mesh_Start(void); // (only valid after R_Mesh_Start) void R_Mesh_Finish(void); +// allocates a static element array buffer object +// (storing triangle data in video memory) +int R_Mesh_CreateStaticEBO(void *data, size_t size); +// frees an element array buffer object +void R_Mesh_DestroyEBO(int bufferobject); +// allocates a static vertex array buffer object +// (storing vertex data in video memory) +int R_Mesh_CreateStaticVBO(void *data, size_t size); +// frees a vertex array buffer object +void R_Mesh_DestroyVBO(int bufferobject); + // sets up the requested vertex transform matrix void R_Mesh_Matrix(const matrix4x4_t *matrix); // sets the vertex array pointer diff --git a/gl_rsurf.c b/gl_rsurf.c index d25f3513..8aa32558 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -900,7 +900,7 @@ void R_Q1BSP_CompileShadowVolume(entity_render_t *ent, vec3_t relativelightorigi R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, r_shadow_compilingrtlight->cullmins, r_shadow_compilingrtlight->cullmaxs, surface->mins, surface->maxs); } R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist); - r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false); + r_shadow_compilingrtlight->static_meshchain_shadow = Mod_ShadowMesh_Finish(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow, false, false, true); } void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs) diff --git a/model_brush.c b/model_brush.c index 6cc700f1..66d4d27d 100644 --- a/model_brush.c +++ b/model_brush.c @@ -3437,7 +3437,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend) loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true); for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++) Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); - loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true); + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true, false); Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles); if (loadmodel->brush.numsubmodels) @@ -6001,7 +6001,7 @@ void Mod_Q3BSP_Load(model_t *mod, void *buffer, void *bufferend) for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++) if (surface->num_triangles > 0) Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); - loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true); + loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true, false); Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles); loadmodel->brush.num_leafs = 0; diff --git a/model_shared.c b/model_shared.c index cde3783b..4e9b1a26 100644 --- a/model_shared.c +++ b/model_shared.c @@ -97,6 +97,7 @@ Mod_Init */ static void Mod_Print(void); static void Mod_Precache (void); +static void Mod_BuildVBOs(void); void Mod_Init (void) { Mod_BrushInit(); @@ -121,6 +122,10 @@ void Mod_UnloadModel (model_t *mod) strlcpy(name, mod->name, sizeof(name)); isworldmodel = mod->isworldmodel; used = mod->used; + if (mod->surfmesh.ebo) + R_Mesh_DestroyEBO(mod->surfmesh.ebo); + if (mod->surfmesh.vbo) + R_Mesh_DestroyVBO(mod->surfmesh.vbo); // free textures/memory attached to the model R_FreeTexturePool(&mod->texturepool); Mem_FreePool(&mod->mempool); @@ -234,6 +239,9 @@ model_t *Mod_LoadModel(model_t *mod, qboolean crash, qboolean checkdisk, qboolea else if (num == BSPVERSION || num == 30) Mod_Q1BSP_Load(mod, buf, bufend); else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name); Mem_Free(buf); + + Mod_BuildVBOs(); + // no fatal errors occurred, so this model is ready to use. mod->loaded = true; } @@ -905,7 +913,42 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtria return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable); } -shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, int light, int neighbors) +static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) +{ + if (!gl_support_arb_vertex_buffer_object) + return; + + // element buffer is easy because it's just one array + if (mesh->numtriangles) + mesh->ebo = R_Mesh_CreateStaticEBO(mesh->element3i, mesh->numtriangles * sizeof(int[3])); + + // vertex buffer is several arrays and we put them in the same buffer + // + // is this wise? the texcoordtexture2f array is used with dynamic + // vertex/svector/tvector/normal when rendering animated models, on the + // other hand animated models don't use a lot of vertices anyway... + if (mesh->numverts) + { + size_t size; + unsigned char *data, *mem; + size = 0; + mesh->vbooffset_vertex3f = size;if (mesh->vertex3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_svector3f = size;if (mesh->svector3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_tvector3f = size;if (mesh->tvector3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_normal3f = size;if (mesh->normal3f ) size += mesh->numverts * sizeof(float[3]); + mesh->vbooffset_texcoord2f = size;if (mesh->texcoord2f ) size += mesh->numverts * sizeof(float[2]); + data = mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (mesh->vertex3f ) {memcpy(data, mesh->vertex3f , mesh->numverts * sizeof(float[3]));data += mesh->numverts * sizeof(float[3]);} + if (mesh->svector3f ) {memcpy(data, mesh->svector3f , mesh->numverts * sizeof(float[3]));data += mesh->numverts * sizeof(float[3]);} + if (mesh->tvector3f ) {memcpy(data, mesh->tvector3f , mesh->numverts * sizeof(float[3]));data += mesh->numverts * sizeof(float[3]);} + if (mesh->normal3f ) {memcpy(data, mesh->normal3f , mesh->numverts * sizeof(float[3]));data += mesh->numverts * sizeof(float[3]);} + if (mesh->texcoord2f ) {memcpy(data, mesh->texcoord2f , mesh->numverts * sizeof(float[2]));data += mesh->numverts * sizeof(float[2]);} + mesh->vbo = R_Mesh_CreateStaticVBO(mem, size); + Mem_Free(mem); + } +} + +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo) { shadowmesh_t *mesh, *newmesh, *nextmesh; // reallocate meshs to conserve space @@ -917,6 +960,8 @@ shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light, neighbors); newmesh->next = firstmesh; firstmesh = newmesh; + if (createvbo) + Mod_ShadowMesh_CreateVBOs(newmesh); } Mem_Free(mesh); } @@ -977,6 +1022,10 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) shadowmesh_t *nextmesh; for (;mesh;mesh = nextmesh) { + if (mesh->ebo) + R_Mesh_DestroyEBO(mesh->ebo); + if (mesh->vbo) + R_Mesh_DestroyVBO(mesh->vbo); nextmesh = mesh->next; Mem_Free(mesh); } @@ -1379,3 +1428,42 @@ void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firs if (lastvertexpointer) *lastvertexpointer = lastvertex; } + +static void Mod_BuildVBOs(void) +{ + if (!gl_support_arb_vertex_buffer_object) + return; + + // element buffer is easy because it's just one array + if (loadmodel->surfmesh.num_triangles) + loadmodel->surfmesh.ebo = R_Mesh_CreateStaticEBO(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3])); + + // vertex buffer is several arrays and we put them in the same buffer + // + // is this wise? the texcoordtexture2f array is used with dynamic + // vertex/svector/tvector/normal when rendering animated models, on the + // other hand animated models don't use a lot of vertices anyway... + if (loadmodel->surfmesh.num_vertices) + { + size_t size; + unsigned char *data, *mem; + size = 0; + loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_normal3f = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]); + loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]); + loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]); + data = mem = (unsigned char *)Mem_Alloc(tempmempool, size); + if (loadmodel->surfmesh.data_vertex3f ) {memcpy(data, loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);} + if (loadmodel->surfmesh.data_svector3f ) {memcpy(data, loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);} + if (loadmodel->surfmesh.data_tvector3f ) {memcpy(data, loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);} + if (loadmodel->surfmesh.data_normal3f ) {memcpy(data, loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));data += loadmodel->surfmesh.num_vertices * sizeof(float[3]);} + if (loadmodel->surfmesh.data_texcoordtexture2f ) {memcpy(data, loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);} + if (loadmodel->surfmesh.data_texcoordlightmap2f) {memcpy(data, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));data += loadmodel->surfmesh.num_vertices * sizeof(float[2]);} + if (loadmodel->surfmesh.data_lightmapcolor4f ) {memcpy(data, loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));data += loadmodel->surfmesh.num_vertices * sizeof(float[4]);} + loadmodel->surfmesh.vbo = R_Mesh_CreateStaticVBO(mem, size); + Mem_Free(mem); + } +} diff --git a/model_shared.h b/model_shared.h index c7fc0306..14aba985 100644 --- a/model_shared.h +++ b/model_shared.h @@ -79,9 +79,13 @@ struct trivertex_s; // (the surfaces reference portions of these meshes) typedef struct surfmesh_s { + // triangle data in system memory int num_triangles; // number of triangles in the mesh int *data_element3i; // int[tris*3] triangles of the mesh, 3 indices into vertex arrays for each int *data_neighbor3i; // int[tris*3] neighboring triangle on each edge (-1 if none) + // element buffer object (stores triangles in video memory) + int ebo; + // vertex data in system memory int num_vertices; // number of vertices in the mesh float *data_vertex3f; // float[verts*3] vertex locations float *data_svector3f; // float[verts*3] direction of 'S' (right) texture axis for each vertex @@ -91,6 +95,15 @@ typedef struct surfmesh_s float *data_texcoordlightmap2f; // float[verts*2] texcoords for lightmap texture float *data_lightmapcolor4f; int *data_lightmapoffsets; // index into surface's lightmap samples for vertex lighting + // vertex buffer object (stores geometry in video memory) + int vbo; + size_t vbooffset_vertex3f; + size_t vbooffset_svector3f; + size_t vbooffset_tvector3f; + size_t vbooffset_normal3f; + size_t vbooffset_texcoordtexture2f; + size_t vbooffset_texcoordlightmap2f; + size_t vbooffset_lightmapcolor4f; // morph blending, these are zero if model is skeletal or static int num_morphframes; struct md3vertex_s *data_morphmd3vertex; @@ -138,6 +151,17 @@ typedef struct shadowmesh_s // these are NULL after Mod_ShadowMesh_Finish is performed, only used // while building meshes shadowmeshvertexhash_t **vertexhashtable, *vertexhashentries; + // element buffer object (stores triangles in video memory) + // (created by Mod_ShadowMesh_Finish if possible) + int ebo; + // vertex buffer object (stores vertices in video memory) + // (created by Mod_ShadowMesh_Finish if possible) + int vbo; + size_t vbooffset_vertex3f; + size_t vbooffset_svector3f; + size_t vbooffset_tvector3f; + size_t vbooffset_normal3f; + size_t vbooffset_texcoord2f; } shadowmesh_t; @@ -650,7 +674,7 @@ int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f); void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f); void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i); shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable); -shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, int light, int neighbors); +shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo); void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius); void Mod_ShadowMesh_Free(shadowmesh_t *mesh); diff --git a/todo b/todo index d938976d..37b09dd6 100644 --- a/todo +++ b/todo @@ -1,4 +1,5 @@ - todo: difficulty ratings are: 0 = trivial, 1 = easy, 2 = easy-moderate, 3 = moderate, 4 = moderate-hard, 5 = hard, 6 = hard++, 7 = nightmare, d = done, -d = done but have not notified the people who asked for it, f = failed, -f = failed but have not notified the people who asked for it +0 bug darkplaces memory: memstats doesn't account for memory used by VBO/EBO buffers in models 0 bug darkplaces client: can't move mouse around in nexuiz menu if vid_mouse is 0 0 bug darkplaces client: decals are not sticking to submodels 0 bug darkplaces client: if you press 1 during the demo loop when quake starts, escape doesn't do anything until you hit some other key (daemon) -- 2.39.2