now creates EBOs and VBOs containing static model geometry, map geometry, and compile...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 4 Apr 2007 11:54:05 +0000 (11:54 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Wed, 4 Apr 2007 11:54:05 +0000 (11:54 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@7044 d7cf8633-e32d-0410-b094-e92efae38249

gl_backend.c
gl_backend.h
gl_rsurf.c
model_brush.c
model_shared.c
model_shared.h
todo

index 70af0a4..cb2f2fe 100644 (file)
@@ -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)))
index ba2e646..773a0d1 100644 (file)
@@ -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
index d25f351..8aa3255 100644 (file)
@@ -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)
index 6cc700f..66d4d27 100644 (file)
@@ -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;
index cde3783..4e9b1a2 100644 (file)
@@ -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);
+       }
+}
index c7fc030..14aba98 100644 (file)
@@ -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 d938976..37b09dd 100644 (file)
--- 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)