From 38185bc1aea210514d6970e3c36a25ad97615e5f Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 1 May 2010 16:48:33 +0000 Subject: [PATCH] overhauled vertex formats, now supports 100% interleaved arrays rendering mode, reworked vertexbuffer management to be a more robust system, added fully vertex buffered rendering options (gl_vbo_dynamicvertex, gl_vbo_dynamicindex) which are off by default (they seem to hurt fps in tests here) centralized handling of "generic" mesh rendering (fixed function stuff) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10109 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_particles.c | 13 +- cl_screen.c | 24 +- client.h | 9 + clvm_cmds.c | 6 +- gl_backend.c | 957 ++++++++++++++---- gl_backend.h | 40 +- gl_draw.c | 119 +-- gl_rmain.c | 2514 ++++++++++++++++++++++++++---------------------- gl_rsurf.c | 70 +- glquake.h | 3 + mathlib.h | 2 + model_shared.c | 190 +++- model_shared.h | 73 +- r_explosion.c | 8 +- r_shadow.c | 126 +-- r_shadow.h | 2 +- render.h | 190 ++-- vid.h | 1 + vid_shared.c | 7 + 19 files changed, 2695 insertions(+), 1659 deletions(-) diff --git a/cl_particles.c b/cl_particles.c index 04bcbfb8..a5b987ea 100644 --- a/cl_particles.c +++ b/cl_particles.c @@ -2270,15 +2270,11 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t particletexture_t *tex; float right[3], up[3], size, ca; float alphascale = (1.0f / 65536.0f) * cl_particles_alpha.value; - float particle_vertex3f[BATCHSIZE*12], particle_texcoord2f[BATCHSIZE*8], particle_color4f[BATCHSIZE*16]; RSurf_ActiveWorldEntity(); r_refdef.stats.drawndecals += numsurfaces; R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(particle_vertex3f, 0, 0); - R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0); - R_Mesh_ColorPointer(particle_color4f, 0, 0); GL_DepthMask(false); GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); @@ -2335,7 +2331,8 @@ void R_DrawDecal_TransparentCallback(const entity_render_t *ent, const rtlight_t // (this assumes they all use one particle font texture!) GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); R_SetupShader_Generic(particletexture[63].texture, NULL, GL_MODULATE, 1); - R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, particle_elements, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); + R_Mesh_Draw(0, numsurfaces * 4, 0, numsurfaces * 2, NULL, NULL, 0, particle_elements, NULL, 0); } void R_DrawDecals (void) @@ -2436,9 +2433,6 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh r_refdef.stats.particles += numsurfaces; R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(particle_vertex3f, 0, 0); - R_Mesh_TexCoordPointer(0, 2, particle_texcoord2f, 0, 0); - R_Mesh_ColorPointer(particle_color4f, 0, 0); GL_DepthMask(false); GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); @@ -2637,6 +2631,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh texture = NULL; batchstart = 0; batchcount = 0; + R_Mesh_PrepareVertices_Generic_Arrays(numsurfaces * 4, particle_vertex3f, particle_color4f, particle_texcoord2f); for (surfacelistindex = 0;surfacelistindex < numsurfaces;) { p = cl.particles + surfacelist[surfacelistindex]; @@ -2674,7 +2669,7 @@ void R_DrawParticle_TransparentCallback(const entity_render_t *ent, const rtligh } batchcount = surfacelistindex - batchstart; - R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, particle_elements, 0, 0); + R_Mesh_Draw(batchstart * 4, batchcount * 4, batchstart * 2, batchcount * 2, NULL, NULL, 0, particle_elements, NULL, 0); } } diff --git a/cl_screen.c b/cl_screen.c index b26ac8fd..9050ab0d 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -765,6 +765,7 @@ void R_TimeReport_EndFrame(void) "%7i lightmap updates (%7i pixels)\n" "%4i lights%4i clears%4i scissored%7i light%7i shadow%7i dynamic\n" "rendered%6i meshes%8i triangles bloompixels%8i copied%8i drawn\n" +"updated%5i indexbuffers%8i bytes%5i vertexbuffers%8i bytes\n" "%s" , loc ? "Location: " : "", loc ? loc->name : "" , r_refdef.stats.renders, r_refdef.view.origin[0], r_refdef.view.origin[1], r_refdef.view.origin[2], r_refdef.view.forward[0], r_refdef.view.forward[1], r_refdef.view.forward[2] @@ -774,6 +775,7 @@ void R_TimeReport_EndFrame(void) , r_refdef.stats.lightmapupdates, r_refdef.stats.lightmapupdatepixels , r_refdef.stats.lights, r_refdef.stats.lights_clears, r_refdef.stats.lights_scissored, r_refdef.stats.lights_lighttriangles, r_refdef.stats.lights_shadowtriangles, r_refdef.stats.lights_dynamicshadowtriangles , r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3, r_refdef.stats.bloom_copypixels, r_refdef.stats.bloom_drawpixels +, r_refdef.stats.indexbufferuploadcount, r_refdef.stats.indexbufferuploadsize, r_refdef.stats.vertexbufferuploadcount, r_refdef.stats.vertexbufferuploadsize , r_speeds_timestring); memset(&r_refdef.stats, 0, sizeof(r_refdef.stats)); @@ -1885,10 +1887,7 @@ static void SCR_DrawLoadingStack(void) GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); GL_DepthTest(false); - R_Mesh_VertexPointer(verts, 0, 0); - R_Mesh_ColorPointer(colors, 0, 0); R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); verts[2] = verts[5] = verts[8] = verts[11] = 0; verts[0] = verts[9] = 0; verts[1] = verts[4] = vid_conheight.integer - scr_loadingscreen_barheight.value; @@ -1906,7 +1905,9 @@ static void SCR_DrawLoadingStack(void) sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[8], &colors[9], &colors[10]); colors[11] = 1; sscanf(scr_loadingscreen_barcolor.string, "%f %f %f", &colors[12], &colors[13], &colors[14]); colors[15] = 1; - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, verts, colors, NULL); + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); // make sure everything is cleared, including the progress indicator if(loadingscreenheight < 8) @@ -1956,25 +1957,20 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear) static void SCR_DrawLoadingScreen (qboolean clear) { // we only need to draw the image if it isn't already there - GL_Color(1,1,1,1); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); GL_DepthTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ResetTextureState(); + GL_Color(1,1,1,1); + R_Mesh_PrepareVertices_Generic_Arrays(4, loadingscreentexture_vertex3f, NULL, loadingscreentexture_texcoord2f); if(loadingscreentexture) { - R_Mesh_VertexPointer(loadingscreentexture_vertex3f, 0, 0); - R_Mesh_ResetTextureState(); R_SetupShader_Generic(loadingscreentexture, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, loadingscreentexture_texcoord2f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } - R_Mesh_VertexPointer(loadingscreenpic_vertex3f, 0, 0); - R_Mesh_ResetTextureState(); R_SetupShader_Generic(loadingscreenpic->tex, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, loadingscreenpic_texcoord2f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); SCR_DrawLoadingStack(); } diff --git a/client.h b/client.h index f9485cc0..e177b76e 100644 --- a/client.h +++ b/client.h @@ -368,6 +368,11 @@ typedef struct entity_render_s float *animcache_normal3f; float *animcache_svector3f; float *animcache_tvector3f; + // interleaved arrays for rendering and dynamic vertex buffers for them + r_vertexposition_t *animcache_vertexposition; + r_meshbuffer_t *animcache_vertexpositionbuffer; + r_vertexmesh_t *animcache_vertexmesh; + r_meshbuffer_t *animcache_vertexmeshbuffer; // current lighting from map (updated ONLY by client code, not renderer) vec3_t modellight_ambient; @@ -1522,6 +1527,10 @@ typedef struct r_refdef_stats_s int bloom; int bloom_copypixels; int bloom_drawpixels; + int indexbufferuploadcount; + int indexbufferuploadsize; + int vertexbufferuploadcount; + int vertexbufferuploadsize; } r_refdef_stats_t; diff --git a/clvm_cmds.c b/clvm_cmds.c index 2c6fb4fe..06d1d648 100644 --- a/clvm_cmds.c +++ b/clvm_cmds.c @@ -2929,9 +2929,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t R_Mesh_ResetTextureState(); R_EntityMatrix(&identitymatrix); GL_CullFace(GL_NONE); - R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0); - R_Mesh_ColorPointer(polys->data_color4f, 0, 0); - R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(polys->num_vertices, polys->data_vertex3f, polys->data_color4f, polys->data_texcoord2f); for (surfacelistindex = 0;surfacelistindex < numsurfaces;) { @@ -2959,7 +2957,7 @@ static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].elements, polys->data_sortedelement3s + 3*numtriangles); numtriangles++; } - R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, polys->data_sortedelement3s, 0, 0); + R_Mesh_Draw(0, polys->num_vertices, 0, numtriangles, NULL, NULL, 0, polys->data_sortedelement3s, NULL, 0); } } diff --git a/gl_backend.c b/gl_backend.c index fd0cff61..8122aa02 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -3,9 +3,9 @@ #include "cl_collision.h" cvar_t gl_mesh_drawrangeelements = {0, "gl_mesh_drawrangeelements", "1", "use glDrawRangeElements function if available instead of glDrawElements (for performance comparisons or bug testing)"}; -cvar_t gl_mesh_testarrayelement = {0, "gl_mesh_testarrayelement", "0", "use glBegin(GL_TRIANGLES);glArrayElement();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"}; cvar_t gl_mesh_testmanualfeeding = {0, "gl_mesh_testmanualfeeding", "0", "use glBegin(GL_TRIANGLES);glTexCoord2f();glVertex3f();glEnd(); primitives instead of glDrawElements (useful to test for driver bugs with glDrawElements)"}; -cvar_t gl_mesh_prefer_short_elements = {0, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"}; +cvar_t gl_mesh_prefer_short_elements = {CVAR_SAVE, "gl_mesh_prefer_short_elements", "1", "use GL_UNSIGNED_SHORT element arrays instead of GL_UNSIGNED_INT"}; +cvar_t gl_mesh_separatearrays = {0, "gl_mesh_separatearrays", "1", "use several separate vertex arrays rather than one combined stream"}; cvar_t gl_paranoid = {0, "gl_paranoid", "0", "enables OpenGL error checking and other tests"}; cvar_t gl_printcheckerror = {0, "gl_printcheckerror", "0", "prints all OpenGL error checks, useful to identify location of driver crashes"}; @@ -15,6 +15,8 @@ cvar_t r_waterwarp = {CVAR_SAVE, "r_waterwarp", "1", "warp view while underwater cvar_t gl_polyblend = {CVAR_SAVE, "gl_polyblend", "1", "tints view while underwater, hurt, etc"}; cvar_t gl_dither = {CVAR_SAVE, "gl_dither", "1", "enables OpenGL dithering (16bit looks bad with this off)"}; cvar_t gl_vbo = {CVAR_SAVE, "gl_vbo", "3", "make use of GL_ARB_vertex_buffer_object extension to store static geometry in video memory for faster rendering, 0 disables VBO allocation or use, 1 enables VBOs for vertex and triangle data, 2 only for vertex data, 3 for vertex data and triangle data of simple meshes (ones with only one surface)"}; +cvar_t gl_vbo_dynamicvertex = {CVAR_SAVE, "gl_vbo_dynamicvertex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"}; +cvar_t gl_vbo_dynamicindex = {CVAR_SAVE, "gl_vbo_dynamicindex", "0", "make use of GL_ARB_vertex_buffer_object extension when rendering dynamic (animated/procedural) geometry such as text and particles"}; cvar_t gl_fbo = {CVAR_SAVE, "gl_fbo", "1", "make use of GL_ARB_framebuffer_object extension to enable shadowmaps and other features using pixel formats different from the framebuffer"}; cvar_t v_flipped = {0, "v_flipped", "0", "mirror the screen (poor man's left handed mode)"}; @@ -91,23 +93,17 @@ void GL_PrintError(int errornumber, char *filename, int linenumber) void SCR_ScreenShot_f (void); -typedef struct gl_bufferobjectinfo_s -{ - int target; - int object; - size_t size; - char name[MAX_QPATH]; -} -gl_bufferobjectinfo_t; - typedef struct gltextureunit_s { - const void *pointer_texcoord; + int pointer_texcoord_components; + int pointer_texcoord_gltype; + size_t pointer_texcoord_stride; + const void *pointer_texcoord_pointer; + const r_meshbuffer_t *pointer_texcoord_vertexbuffer; size_t pointer_texcoord_offset; - int pointer_texcoord_buffer; + int t2d, t3d, tcubemap, trectangle; int arrayenabled; - unsigned int arraycomponents; int rgbscale, alphascale; int combine; int combinergb, combinealpha; @@ -140,14 +136,37 @@ typedef struct gl_state_s int vertexbufferobject; int elementbufferobject; qboolean pointer_color_enabled; - const void *pointer_vertex; - const void *pointer_color; + + int pointer_vertex_components; + int pointer_vertex_gltype; + size_t pointer_vertex_stride; + const void *pointer_vertex_pointer; + const r_meshbuffer_t *pointer_vertex_vertexbuffer; size_t pointer_vertex_offset; + + int pointer_color_components; + int pointer_color_gltype; + size_t pointer_color_stride; + const void *pointer_color_pointer; + const r_meshbuffer_t *pointer_color_vertexbuffer; size_t pointer_color_offset; - int pointer_vertex_buffer; - int pointer_color_buffer; - memexpandablearray_t bufferobjectinfoarray; + void *preparevertices_tempdata; + size_t preparevertices_tempdatamaxsize; + r_meshbuffer_t *preparevertices_dynamicvertexbuffer; + r_vertexposition_t *preparevertices_vertexposition; + r_vertexgeneric_t *preparevertices_vertexgeneric; + r_vertexmesh_t *preparevertices_vertexmesh; + int preparevertices_numvertices; + + r_meshbuffer_t *draw_dynamicindexbuffer; + + qboolean usevbo_staticvertex; + qboolean usevbo_staticindex; + qboolean usevbo_dynamicvertex; + qboolean usevbo_dynamicindex; + + memexpandablearray_t meshbufferarray; qboolean active; } @@ -226,7 +245,11 @@ static void gl_backend_start(void) { memset(&gl_state, 0, sizeof(gl_state)); - Mem_ExpandableArray_NewArray(&gl_state.bufferobjectinfoarray, r_main_mempool, sizeof(gl_bufferobjectinfo_t), 128); + gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo; + gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo; + gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo; + Mem_ExpandableArray_NewArray(&gl_state.meshbufferarray, r_main_mempool, sizeof(r_meshbuffer_t), 128); Con_DPrintf("OpenGL backend started.\n"); @@ -239,7 +262,12 @@ static void gl_backend_shutdown(void) { Con_DPrint("OpenGL Backend shutting down\n"); - Mem_ExpandableArray_FreeArray(&gl_state.bufferobjectinfoarray); + if (gl_state.preparevertices_tempdata) + Mem_Free(gl_state.preparevertices_tempdata); + if (gl_state.preparevertices_dynamicvertexbuffer) + R_Mesh_DestroyMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer); + + Mem_ExpandableArray_FreeArray(&gl_state.meshbufferarray); memset(&gl_state, 0, sizeof(gl_state)); } @@ -281,13 +309,15 @@ void gl_backend_init(void) Cvar_RegisterVariable(&v_flipped); Cvar_RegisterVariable(&gl_dither); Cvar_RegisterVariable(&gl_vbo); + Cvar_RegisterVariable(&gl_vbo_dynamicvertex); + Cvar_RegisterVariable(&gl_vbo_dynamicindex); Cvar_RegisterVariable(&gl_paranoid); Cvar_RegisterVariable(&gl_printcheckerror); Cvar_RegisterVariable(&gl_mesh_drawrangeelements); - Cvar_RegisterVariable(&gl_mesh_testarrayelement); Cvar_RegisterVariable(&gl_mesh_testmanualfeeding); Cvar_RegisterVariable(&gl_mesh_prefer_short_elements); + Cvar_RegisterVariable(&gl_mesh_separatearrays); Cmd_AddCommand("gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them"); @@ -1024,6 +1054,10 @@ void R_Mesh_Start(void) { BACKENDACTIVECHECK CHECKGLERROR + gl_state.usevbo_staticvertex = (vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo; + gl_state.usevbo_staticindex = (vid.support.arb_vertex_buffer_object && (gl_vbo.integer == 1 || gl_vbo.integer == 3)) || vid.forcevbo; + gl_state.usevbo_dynamicvertex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicvertex.integer) || vid.forcevbo; + gl_state.usevbo_dynamicindex = (vid.support.arb_vertex_buffer_object && gl_vbo_dynamicindex.integer) || vid.forcevbo; if (gl_printcheckerror.integer && !gl_paranoid.integer) { Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n"); @@ -1129,46 +1163,84 @@ void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset) // renders triangles using vertices from the active arrays int paranoidblah = 0; -void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s) +void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset) { unsigned int numelements = numtriangles * 3; + int bufferobject3i; + size_t bufferoffset3i; + int bufferobject3s; + size_t bufferoffset3s; if (numvertices < 3 || numtriangles < 1) { if (numvertices < 0 || numtriangles < 0 || developer_extra.integer) - Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %i, %i);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3s, bufferobject3i, bufferobject3s); + Con_DPrintf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %8x, %8p, %8p, %8x);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3i_indexbuffer, (int)element3i_bufferoffset, (void *)element3s, (void *)element3s_indexbuffer, (int)element3s_bufferoffset); + return; + } + if (gl_state.pointer_vertex_pointer == NULL) + { + Con_DPrintf("R_Mesh_Draw with no vertex pointer!\n"); return; } if (!gl_mesh_prefer_short_elements.integer) { if (element3i) element3s = NULL; - if (bufferobject3i) - bufferobject3s = 0; + if (element3i_indexbuffer) + element3i_indexbuffer = NULL; } + // adjust the pointers for firsttriangle if (element3i) element3i += firsttriangle * 3; + if (element3i_indexbuffer) + element3i_bufferoffset += firsttriangle * 3 * sizeof(*element3i); if (element3s) element3s += firsttriangle * 3; - switch (gl_vbo.integer) + if (element3s_indexbuffer) + element3s_bufferoffset += firsttriangle * 3 * sizeof(*element3s); + // check if the user specified to ignore static index buffers + if (!gl_state.usevbo_staticindex || (gl_vbo.integer == 3 && !vid.forcevbo && (element3i_bufferoffset || element3s_bufferoffset))) { - default: - case 0: - case 2: - bufferobject3i = bufferobject3s = 0; - break; - case 1: - break; - case 3: - if (firsttriangle) - bufferobject3i = bufferobject3s = 0; - break; + element3i_indexbuffer = NULL; + element3s_indexbuffer = NULL; } + // upload a dynamic index buffer if needed + if (element3s) + { + if (!element3s_indexbuffer && gl_state.usevbo_dynamicindex) + { + if (gl_state.draw_dynamicindexbuffer) + R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3s, numelements * sizeof(*element3s)); + else + gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3s, numelements * sizeof(*element3s), "temporary", true, true); + element3s_indexbuffer = gl_state.draw_dynamicindexbuffer; + element3s_bufferoffset = 0; + } + } + else if (element3i) + { + if (!element3i_indexbuffer && gl_state.usevbo_dynamicindex) + { + if (gl_state.draw_dynamicindexbuffer) + R_Mesh_UpdateMeshBuffer(gl_state.draw_dynamicindexbuffer, (void *)element3i, numelements * sizeof(*element3i)); + else + gl_state.draw_dynamicindexbuffer = R_Mesh_CreateMeshBuffer((void *)element3i, numelements * sizeof(*element3i), "temporary", true, true); + element3i_indexbuffer = gl_state.draw_dynamicindexbuffer; + element3i_bufferoffset = 0; + } + } + bufferobject3i = element3i_indexbuffer ? element3i_indexbuffer->bufferobject : 0; + bufferoffset3i = element3i_bufferoffset; + bufferobject3s = element3s_indexbuffer ? element3s_indexbuffer->bufferobject : 0; + bufferoffset3s = element3s_bufferoffset; CHECKGLERROR r_refdef.stats.meshes++; r_refdef.stats.meshes_elements += numelements; if (gl_paranoid.integer) { - unsigned int i, j, size; + unsigned int i; + // LordHavoc: disabled this - it needs to be updated to handle components and gltype and stride in each array +#if 0 + unsigned int j, size; const int *p; // note: there's no validation done here on buffer objects because it // is somewhat difficult to get at the data, and gl_paranoid can be @@ -1178,7 +1250,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri if (!qglIsEnabled(GL_VERTEX_ARRAY)) Con_Print("R_Mesh_Draw: vertex array not enabled\n"); CHECKGLERROR - if (gl_state.pointer_vertex) + if (gl_state.pointer_vertex_pointer) for (j = 0, size = numvertices * 3, p = (int *)((float *)gl_state.pointer_vertex + firstvertex * 3);j < size;j++, p++) paranoidblah += *p; if (gl_state.pointer_color_enabled) @@ -1203,6 +1275,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri paranoidblah += *p; } } +#endif if (element3i) { for (i = 0;i < (unsigned int) numtriangles * 3;i++) @@ -1237,83 +1310,119 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri qglBegin(GL_TRIANGLES); for (i = 0;i < (unsigned int) numtriangles * 3;i++) { - element = element3i ? element3i[i] : element3s[i]; + if (element3i) + element = element3i[i]; + else if (element3s) + element = element3s[i]; + else + element = firstvertex + i; for (j = 0;j < vid.texarrayunits;j++) { - if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled) + if (gl_state.units[j].pointer_texcoord_pointer && gl_state.units[j].arrayenabled) { - if (vid.texarrayunits > 1) + if (gl_state.units[j].pointer_texcoord_gltype == GL_FLOAT) { - if (gl_state.units[j].arraycomponents == 4) + p = (const GLfloat *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4; - qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]); - } - else if (gl_state.units[j].arraycomponents == 3) - { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3; - qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]); - } - else if (gl_state.units[j].arraycomponents == 2) - { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2; - qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2], p[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, p[0], p[1], p[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]); + else + qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]); } else { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1; - qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(p[0], p[1], p[2], p[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(p[0], p[1], p[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(p[0], p[1]); + else + qglTexCoord1f(p[0]); } } - else + else if (gl_state.units[j].pointer_texcoord_gltype == GL_SHORT) { - if (gl_state.units[j].arraycomponents == 4) + const GLshort *s = (const GLshort *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4; - qglTexCoord4f(p[0], p[1], p[2], p[3]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2], s[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, s[0], s[1], s[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, s[0], s[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, s[0]); } - else if (gl_state.units[j].arraycomponents == 3) + else { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 3; - qglTexCoord3f(p[0], p[1], p[2]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(s[0], s[1], s[2], s[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(s[0], s[1], s[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(s[0], s[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglTexCoord1f(s[0]); } - else if (gl_state.units[j].arraycomponents == 2) + } + else if (gl_state.units[j].pointer_texcoord_gltype == GL_BYTE) + { + const GLbyte *sb = (const GLbyte *)((const unsigned char *)gl_state.units[j].pointer_texcoord_pointer + element * gl_state.units[j].pointer_texcoord_stride); + if (vid.texarrayunits > 1) { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 2; - qglTexCoord2f(p[0], p[1]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglMultiTexCoord4f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2], sb[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglMultiTexCoord3f(GL_TEXTURE0_ARB + j, sb[0], sb[1], sb[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, sb[0], sb[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, sb[0]); } else { - p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1; - qglTexCoord1f(p[0]); + if (gl_state.units[j].pointer_texcoord_components == 4) + qglTexCoord4f(sb[0], sb[1], sb[2], sb[3]); + else if (gl_state.units[j].pointer_texcoord_components == 3) + qglTexCoord3f(sb[0], sb[1], sb[2]); + else if (gl_state.units[j].pointer_texcoord_components == 2) + qglTexCoord2f(sb[0], sb[1]); + else if (gl_state.units[j].pointer_texcoord_components == 1) + qglTexCoord1f(sb[0]); } } } } - if (gl_state.pointer_color && gl_state.pointer_color_enabled) + if (gl_state.pointer_color_pointer && gl_state.pointer_color_enabled && gl_state.pointer_color_components == 4) { - p = ((const GLfloat *)(gl_state.pointer_color)) + element * 4; - qglColor4f(p[0], p[1], p[2], p[3]); + if (gl_state.pointer_color_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglColor4f(p[0], p[1], p[2], p[3]); + } + else if (gl_state.pointer_color_gltype == GL_UNSIGNED_BYTE) + { + const GLubyte *ub = (const GLubyte *)((const unsigned char *)gl_state.pointer_color_pointer + element * gl_state.pointer_color_stride); + qglColor4ub(ub[0], ub[1], ub[2], ub[3]); + } + } + if (gl_state.pointer_vertex_gltype == GL_FLOAT) + { + p = (const GLfloat *)((const unsigned char *)gl_state.pointer_vertex_pointer + element * gl_state.pointer_vertex_stride); + if (gl_state.pointer_vertex_components == 4) + qglVertex4f(p[0], p[1], p[2], p[3]); + else if (gl_state.pointer_vertex_components == 3) + qglVertex3f(p[0], p[1], p[2]); + else + qglVertex2f(p[0], p[1]); } - p = ((const GLfloat *)(gl_state.pointer_vertex)) + element * 3; - qglVertex3f(p[0], p[1], p[2]); - } - qglEnd(); - CHECKGLERROR - } - else if (gl_mesh_testarrayelement.integer) - { - int i; - qglBegin(GL_TRIANGLES); - if (element3i) - { - for (i = 0;i < numtriangles * 3;i++) - qglArrayElement(element3i[i]); - } - else if (element3s) - { - for (i = 0;i < numtriangles * 3;i++) - qglArrayElement(element3s[i]); } qglEnd(); CHECKGLERROR @@ -1323,7 +1432,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri GL_BindEBO(bufferobject3s); if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) { - qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3]))); + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_SHORT, (void *)bufferoffset3s); CHECKGLERROR } else @@ -1337,7 +1446,7 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri GL_BindEBO(bufferobject3i); if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL) { - qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3]))); + qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices - 1, numelements, GL_UNSIGNED_INT, (void *)bufferoffset3i); CHECKGLERROR } else @@ -1374,6 +1483,11 @@ void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtri CHECKGLERROR } } + else + { + qglDrawArrays(GL_TRIANGLES, firstvertex, numvertices); + CHECKGLERROR + } } } @@ -1382,52 +1496,91 @@ void R_Mesh_Finish(void) { } -int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name) +r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic) { - gl_bufferobjectinfo_t *info; - GLuint bufferobject; - - if (!gl_vbo.integer) - return 0; - - qglGenBuffersARB(1, &bufferobject); - switch(target) + int bufferobject = 0; + void *devicebuffer = NULL; + r_meshbuffer_t *buffer; + if (!(isdynamic ? (isindexbuffer ? gl_state.usevbo_dynamicindex : gl_state.usevbo_dynamicvertex) : (isindexbuffer ? gl_state.usevbo_staticindex : gl_state.usevbo_staticvertex))) + return NULL; + if (isindexbuffer) { - case GL_ELEMENT_ARRAY_BUFFER_ARB: GL_BindEBO(bufferobject);break; - case GL_ARRAY_BUFFER_ARB: GL_BindVBO(bufferobject);break; - default: Sys_Error("R_Mesh_CreateStaticBufferObject: unknown target type %i\n", target);return 0; + r_refdef.stats.indexbufferuploadcount++; + r_refdef.stats.indexbufferuploadsize += size; } - qglBufferDataARB(target, size, data, GL_STATIC_DRAW_ARB); - - info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_AllocRecord(&gl_state.bufferobjectinfoarray); - memset(info, 0, sizeof(*info)); - info->target = target; - info->object = bufferobject; - info->size = size; - strlcpy(info->name, name, sizeof(info->name)); - - return (int)bufferobject; + else + { + r_refdef.stats.vertexbufferuploadcount++; + r_refdef.stats.vertexbufferuploadsize += size; + } + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + qglGenBuffersARB(1, (GLuint *)&bufferobject); + if (isindexbuffer) + GL_BindEBO(bufferobject); + else + GL_BindVBO(bufferobject); + qglBufferDataARB(isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB); + break; + } + buffer = (r_meshbuffer_t *)Mem_ExpandableArray_AllocRecord(&gl_state.meshbufferarray); + memset(buffer, 0, sizeof(*buffer)); + buffer->bufferobject = bufferobject; + buffer->devicebuffer = devicebuffer; + buffer->size = size; + buffer->isindexbuffer = isindexbuffer; + buffer->isdynamic = isdynamic; + strlcpy(buffer->name, name, sizeof(buffer->name)); + return buffer; } -void R_Mesh_DestroyBufferObject(int bufferobject) +void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size) { - int i, endindex; - gl_bufferobjectinfo_t *info; - - qglDeleteBuffersARB(1, (GLuint *)&bufferobject); + if (!buffer || (!buffer->bufferobject && !buffer->devicebuffer)) + return; + if (buffer->isindexbuffer) + { + r_refdef.stats.indexbufferuploadcount++; + r_refdef.stats.indexbufferuploadsize += size; + } + else + { + r_refdef.stats.vertexbufferuploadcount++; + r_refdef.stats.vertexbufferuploadsize += size; + } + switch(vid.renderpath) + { + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (buffer->isindexbuffer) + GL_BindEBO(buffer->bufferobject); + else + GL_BindVBO(buffer->bufferobject); + qglBufferDataARB(buffer->isindexbuffer ? GL_ELEMENT_ARRAY_BUFFER_ARB : GL_ARRAY_BUFFER_ARB, size, data, buffer->isdynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB); + break; + } +} - endindex = Mem_ExpandableArray_IndexRange(&gl_state.bufferobjectinfoarray); - for (i = 0;i < endindex;i++) +void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer) +{ + if (!buffer) + return; + switch(vid.renderpath) { - info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.bufferobjectinfoarray, i); - if (!info) - continue; - if (info->object == bufferobject) - { - Mem_ExpandableArray_FreeRecord(&gl_state.bufferobjectinfoarray, (void *)info); - break; - } + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + qglDeleteBuffersARB(1, (GLuint *)&buffer->bufferobject); + break; } + Mem_ExpandableArray_FreeRecord(&gl_state.meshbufferarray, (void *)buffer); } void GL_Mesh_ListVBOs(qboolean printeach) @@ -1435,47 +1588,45 @@ void GL_Mesh_ListVBOs(qboolean printeach) int i, endindex; size_t ebocount = 0, ebomemory = 0; size_t vbocount = 0, vbomemory = 0; - gl_bufferobjectinfo_t *info; - endindex = Mem_ExpandableArray_IndexRange(&gl_state.bufferobjectinfoarray); + r_meshbuffer_t *buffer; + endindex = Mem_ExpandableArray_IndexRange(&gl_state.meshbufferarray); for (i = 0;i < endindex;i++) { - info = (gl_bufferobjectinfo_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.bufferobjectinfoarray, i); - if (!info) + buffer = (r_meshbuffer_t *) Mem_ExpandableArray_RecordAtIndex(&gl_state.meshbufferarray, i); + if (!buffer) continue; - switch(info->target) - { - case GL_ELEMENT_ARRAY_BUFFER_ARB: ebocount++;ebomemory += info->size;if (printeach) Con_Printf("EBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break; - case GL_ARRAY_BUFFER_ARB: vbocount++;vbomemory += info->size;if (printeach) Con_Printf("VBO #%i %s = %i bytes\n", info->object, info->name, (int)info->size);break; - default: Con_Printf("gl_vbostats: unknown target type %i\n", info->target);break; - } + if (buffer->isindexbuffer) {ebocount++;ebomemory += buffer->size;if (printeach) Con_Printf("indexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");} + else {vbocount++;vbomemory += buffer->size;if (printeach) Con_Printf("vertexbuffer #%i %s = %i bytes%s\n", i, buffer->name, (int)buffer->size, buffer->isdynamic ? " (dynamic)" : " (static)");} } - Con_Printf("vertex buffers: %i element buffers totalling %i bytes (%.3f MB), %i vertex buffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0); + Con_Printf("vertex buffers: %i indexbuffers totalling %i bytes (%.3f MB), %i vertexbuffers totalling %i bytes (%.3f MB), combined %i bytes (%.3fMB)\n", (int)ebocount, (int)ebomemory, ebomemory / 1048576.0, (int)vbocount, (int)vbomemory, vbomemory / 1048576.0, (int)(ebomemory + vbomemory), (ebomemory + vbomemory) / 1048576.0); } -void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset) + + +void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) { - if (!gl_vbo.integer || gl_mesh_testarrayelement.integer) - bufferobject = 0; - if (gl_state.pointer_vertex != vertex3f || gl_state.pointer_vertex_buffer != bufferobject || gl_state.pointer_vertex_offset != bufferoffset) + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; + if (gl_state.pointer_vertex_components != components || gl_state.pointer_vertex_gltype != gltype || gl_state.pointer_vertex_stride != stride || gl_state.pointer_vertex_pointer != pointer || gl_state.pointer_vertex_vertexbuffer != vertexbuffer || gl_state.pointer_vertex_offset != bufferoffset) { - gl_state.pointer_vertex = vertex3f; - gl_state.pointer_vertex_buffer = bufferobject; + gl_state.pointer_vertex_components = components; + gl_state.pointer_vertex_gltype = gltype; + gl_state.pointer_vertex_stride = stride; + gl_state.pointer_vertex_pointer = pointer; + gl_state.pointer_vertex_vertexbuffer = vertexbuffer; gl_state.pointer_vertex_offset = bufferoffset; CHECKGLERROR GL_BindVBO(bufferobject); - qglVertexPointer(3, GL_FLOAT, sizeof(float[3]), bufferobject ? (void *)bufferoffset : vertex3f);CHECKGLERROR + qglVertexPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR } } -void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset) +void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) { - // note: this can not rely on bufferobject to decide whether a color array - // is supplied, because surfmesh_t shares one vbo for all arrays, which - // means that a valid vbo may be supplied even if there is no color array. - if (color4f) + // note: vertexbuffer may be non-NULL even if pointer is NULL, so check + // the pointer only. + if (pointer) { - if (!gl_vbo.integer || gl_mesh_testarrayelement.integer) - bufferobject = 0; + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; // caller wants color array enabled if (!gl_state.pointer_color_enabled) { @@ -1483,14 +1634,17 @@ void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferof CHECKGLERROR qglEnableClientState(GL_COLOR_ARRAY);CHECKGLERROR } - if (gl_state.pointer_color != color4f || gl_state.pointer_color_buffer != bufferobject || gl_state.pointer_color_offset != bufferoffset) + if (gl_state.pointer_color_components != components || gl_state.pointer_color_gltype != gltype || gl_state.pointer_color_stride != stride || gl_state.pointer_color_pointer != pointer || gl_state.pointer_color_vertexbuffer != vertexbuffer || gl_state.pointer_color_offset != bufferoffset) { - gl_state.pointer_color = color4f; - gl_state.pointer_color_buffer = bufferobject; + gl_state.pointer_color_components = components; + gl_state.pointer_color_gltype = gltype; + gl_state.pointer_color_stride = stride; + gl_state.pointer_color_pointer = pointer; + gl_state.pointer_color_vertexbuffer = vertexbuffer; gl_state.pointer_color_offset = bufferoffset; CHECKGLERROR GL_BindVBO(bufferobject); - qglColorPointer(4, GL_FLOAT, sizeof(float[4]), bufferobject ? (void *)bufferoffset : color4f);CHECKGLERROR + qglColorPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR } } else @@ -1507,17 +1661,16 @@ void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferof } } -void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset) +void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) { gltextureunit_t *unit = gl_state.units + unitnum; // update array settings CHECKGLERROR // note: there is no need to check bufferobject here because all cases // that involve a valid bufferobject also supply a texcoord array - if (texcoord) + if (pointer) { - if (!gl_vbo.integer || gl_mesh_testarrayelement.integer) - bufferobject = 0; + int bufferobject = vertexbuffer ? vertexbuffer->bufferobject : 0; // texture array unit is enabled, enable the array if (!unit->arrayenabled) { @@ -1526,15 +1679,17 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, co qglEnableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR } // texcoord array - if (unit->pointer_texcoord != texcoord || unit->pointer_texcoord_buffer != bufferobject || unit->pointer_texcoord_offset != bufferoffset || unit->arraycomponents != numcomponents) + if (unit->pointer_texcoord_components != components || unit->pointer_texcoord_gltype != gltype || unit->pointer_texcoord_stride != stride || unit->pointer_texcoord_pointer != pointer || unit->pointer_texcoord_vertexbuffer != vertexbuffer || unit->pointer_texcoord_offset != bufferoffset) { - unit->pointer_texcoord = texcoord; - unit->pointer_texcoord_buffer = bufferobject; + unit->pointer_texcoord_components = components; + unit->pointer_texcoord_gltype = gltype; + unit->pointer_texcoord_stride = stride; + unit->pointer_texcoord_pointer = pointer; + unit->pointer_texcoord_vertexbuffer = vertexbuffer; unit->pointer_texcoord_offset = bufferoffset; - unit->arraycomponents = numcomponents; GL_ClientActiveTexture(unitnum); GL_BindVBO(bufferobject); - qglTexCoordPointer(unit->arraycomponents, GL_FLOAT, sizeof(float) * unit->arraycomponents, bufferobject ? (void *)bufferoffset : texcoord);CHECKGLERROR + qglTexCoordPointer(components, gltype, stride, bufferobject ? (void *)bufferoffset : pointer);CHECKGLERROR } } else @@ -1919,3 +2074,467 @@ void R_Mesh_ResetTextureState(void) break; } } + + + +r_vertexposition_t *R_Mesh_PrepareVertices_Position_Lock(int numvertices) +{ + size_t size; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + size = sizeof(r_vertexposition_t) * numvertices; + if (gl_state.preparevertices_tempdatamaxsize < size) + { + gl_state.preparevertices_tempdatamaxsize = size; + gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize); + } + gl_state.preparevertices_vertexposition = (r_vertexposition_t *)gl_state.preparevertices_tempdata; + gl_state.preparevertices_numvertices = numvertices; + return gl_state.preparevertices_vertexposition; + default: + Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n"); + return NULL; + } +} + +qboolean R_Mesh_PrepareVertices_Position_Unlock(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + R_Mesh_PrepareVertices_Position(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexposition, NULL); + gl_state.preparevertices_vertexposition = NULL; + gl_state.preparevertices_numvertices = 0; + return true; + default: + Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n"); + return false; + } +} + +void R_Mesh_PrepareVertices_Position_Arrays(int numvertices, const float *vertex3f) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + break; + case RENDERPATH_GL13: + case RENDERPATH_GL11: + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + if (vid.texunits >= 2) + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + if (vid.texunits >= 3) + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + break; + default: + Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n"); + return; + } +} + +void R_Mesh_PrepareVertices_Position(int numvertices, const r_vertexposition_t *vertex, const r_meshbuffer_t *vertexbuffer) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + { + if (gl_state.preparevertices_dynamicvertexbuffer) + R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex)); + else + gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true); + vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer; + } + if (vertexbuffer) + { + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + break; + } + return; + } + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + break; + } +} + + + +r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices) +{ + size_t size; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + size = sizeof(r_vertexgeneric_t) * numvertices; + if (gl_state.preparevertices_tempdatamaxsize < size) + { + gl_state.preparevertices_tempdatamaxsize = size; + gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize); + } + gl_state.preparevertices_vertexgeneric = (r_vertexgeneric_t *)gl_state.preparevertices_tempdata; + gl_state.preparevertices_numvertices = numvertices; + return gl_state.preparevertices_vertexgeneric; + default: + Sys_Error("R_Mesh_PrepareVertices_Generic_Lock: unrecognized vid.renderpath\n"); + return NULL; + } +} + +qboolean R_Mesh_PrepareVertices_Generic_Unlock(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + R_Mesh_PrepareVertices_Generic(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexgeneric, NULL); + gl_state.preparevertices_vertexgeneric = NULL; + gl_state.preparevertices_numvertices = 0; + return true; + default: + Sys_Error("R_Mesh_PrepareVertices_Generic_Lock: unrecognized vid.renderpath\n"); + return false; + } +} + +void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f) +{ + int i; + r_vertexgeneric_t *vertex; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (gl_mesh_separatearrays.integer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + return; + } + break; + case RENDERPATH_GL13: + case RENDERPATH_GL11: + if (gl_mesh_separatearrays.integer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoord2f, NULL, 0); + if (vid.texunits >= 2) + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + if (vid.texunits >= 3) + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + return; + } + break; + default: + Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n"); + return; + } + + // no quick path for this case, convert to vertex structs + vertex = R_Mesh_PrepareVertices_Generic_Lock(numvertices); + for (i = 0;i < numvertices;i++) + VectorCopy(vertex3f + 3*i, vertex[i].vertex3f); + if (color4f) + { + for (i = 0;i < numvertices;i++) + Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub); + } + else + { + float tempcolor4f[4]; + unsigned char tempcolor4ub[4]; + Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f); + tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f); + tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f); + tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f); + tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f); + for (i = 0;i < numvertices;i++) + Vector4Copy(tempcolor4ub, vertex[i].color4ub); + } + if (texcoord2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoord2f + 2*i, vertex[i].texcoord2f); + R_Mesh_PrepareVertices_Generic_Unlock(); + R_Mesh_PrepareVertices_Generic(numvertices, vertex, NULL); +} + +void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + { + if (gl_state.preparevertices_dynamicvertexbuffer) + R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex)); + else + gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true); + vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer; + } + if (vertexbuffer) + { + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , vertexbuffer, (int)((unsigned char *)vertex->color4ub - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , vertexbuffer, (int)((unsigned char *)vertex->texcoord2f - (unsigned char *)vertex)); + break; + } + return; + } + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(3, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoord2f , NULL, 0); + break; + } +} + + + +r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices) +{ + size_t size; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + size = sizeof(r_vertexmesh_t) * numvertices; + if (gl_state.preparevertices_tempdatamaxsize < size) + { + gl_state.preparevertices_tempdatamaxsize = size; + gl_state.preparevertices_tempdata = Mem_Realloc(r_main_mempool, gl_state.preparevertices_tempdata, gl_state.preparevertices_tempdatamaxsize); + } + gl_state.preparevertices_vertexmesh = (r_vertexmesh_t *)gl_state.preparevertices_tempdata; + gl_state.preparevertices_numvertices = numvertices; + return gl_state.preparevertices_vertexmesh; + default: + Sys_Error("R_Mesh_PrepareVertices_Mesh_Lock: unrecognized vid.renderpath\n"); + return NULL; + } +} + +qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void) +{ + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + case RENDERPATH_GL13: + case RENDERPATH_GL11: + R_Mesh_PrepareVertices_Mesh(gl_state.preparevertices_numvertices, gl_state.preparevertices_vertexmesh, NULL); + gl_state.preparevertices_vertexmesh = NULL; + gl_state.preparevertices_numvertices = 0; + return true; + default: + Sys_Error("R_Mesh_PrepareVertices_Mesh_Lock: unrecognized vid.renderpath\n"); + return false; + } +} + +void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f) +{ + int i; + r_vertexmesh_t *vertex; + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + if (gl_mesh_separatearrays.integer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), svector3f, NULL, 0); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), tvector3f, NULL, 0); + R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), normal3f, NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0); + return; + } + break; + case RENDERPATH_GL13: + case RENDERPATH_GL11: + if (gl_mesh_separatearrays.integer) + { + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), vertex3f, NULL, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), color4f, NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), texcoordtexture2f, NULL, 0); + if (vid.texunits >= 2) + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), texcoordlightmap2f, NULL, 0); + if (vid.texunits >= 3) + R_Mesh_TexCoordPointer(2, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); + return; + } + break; + default: + Sys_Error("R_Mesh_PrepareVertices_Position_Lock: unrecognized vid.renderpath\n"); + return; + } + + vertex = R_Mesh_PrepareVertices_Mesh_Lock(numvertices); + for (i = 0;i < numvertices;i++) + VectorCopy(vertex3f + 3*i, vertex[i].vertex3f); + if (svector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(svector3f + 3*i, vertex[i].svector3f); + if (tvector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(tvector3f + 3*i, vertex[i].tvector3f); + if (normal3f) + for (i = 0;i < numvertices;i++) + VectorCopy(normal3f + 3*i, vertex[i].normal3f); + if (color4f) + { + for (i = 0;i < numvertices;i++) + Vector4Scale(color4f + 4*i, 255.0f, vertex[i].color4ub); + } + else + { + float tempcolor4f[4]; + unsigned char tempcolor4ub[4]; + Vector4Scale(gl_state.color4f, 255.0f, tempcolor4f); + tempcolor4ub[0] = (unsigned char)bound(0.0f, tempcolor4f[0], 255.0f); + tempcolor4ub[1] = (unsigned char)bound(0.0f, tempcolor4f[1], 255.0f); + tempcolor4ub[2] = (unsigned char)bound(0.0f, tempcolor4f[2], 255.0f); + tempcolor4ub[3] = (unsigned char)bound(0.0f, tempcolor4f[3], 255.0f); + for (i = 0;i < numvertices;i++) + Vector4Copy(tempcolor4ub, vertex[i].color4ub); + } + if (texcoordtexture2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoordtexture2f + 2*i, vertex[i].texcoordtexture2f); + if (texcoordlightmap2f) + for (i = 0;i < numvertices;i++) + Vector2Copy(texcoordlightmap2f + 2*i, vertex[i].texcoordlightmap2f); + R_Mesh_PrepareVertices_Mesh_Unlock(); + R_Mesh_PrepareVertices_Mesh(numvertices, vertex, NULL); +} + +void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *vertexbuffer) +{ + // upload temporary vertexbuffer for this rendering + if (!gl_state.usevbo_staticvertex) + vertexbuffer = NULL; + if (!vertexbuffer && gl_state.usevbo_dynamicvertex) + { + if (gl_state.preparevertices_dynamicvertexbuffer) + R_Mesh_UpdateMeshBuffer(gl_state.preparevertices_dynamicvertexbuffer, vertex, numvertices * sizeof(*vertex)); + else + gl_state.preparevertices_dynamicvertexbuffer = R_Mesh_CreateMeshBuffer(vertex, numvertices * sizeof(*vertex), "temporary", false, true); + vertexbuffer = gl_state.preparevertices_dynamicvertexbuffer; + } + if (vertexbuffer) + { + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , vertexbuffer, (int)((unsigned char *)vertex->color4ub - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(*vertex), vertex->svector3f , vertexbuffer, (int)((unsigned char *)vertex->svector3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(*vertex), vertex->tvector3f , vertexbuffer, (int)((unsigned char *)vertex->tvector3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(3, 4, GL_FLOAT , sizeof(*vertex), vertex->normal3f , vertexbuffer, (int)((unsigned char *)vertex->normal3f - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex)); + break; + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, vertexbuffer, (int)((unsigned char *)vertex->texcoordlightmap2f - (unsigned char *)vertex)); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , vertexbuffer, (int)((unsigned char *)vertex->vertex3f - (unsigned char *)vertex)); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , vertexbuffer, (int)((unsigned char *)vertex->color4ub - (unsigned char *)vertex)); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , vertexbuffer, (int)((unsigned char *)vertex->texcoordtexture2f - (unsigned char *)vertex)); + break; + } + return; + } + switch(vid.renderpath) + { + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT , sizeof(*vertex), vertex->svector3f , NULL, 0); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT , sizeof(*vertex), vertex->tvector3f , NULL, 0); + R_Mesh_TexCoordPointer(3, 4, GL_FLOAT , sizeof(*vertex), vertex->normal3f , NULL, 0); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0); + break; + case RENDERPATH_GL13: + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordlightmap2f, NULL, 0); + case RENDERPATH_GL11: + R_Mesh_VertexPointer( 3, GL_FLOAT , sizeof(*vertex), vertex->vertex3f , NULL, 0); + R_Mesh_ColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(*vertex), vertex->color4ub , NULL, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT , sizeof(*vertex), vertex->texcoordtexture2f , NULL, 0); + break; + } +} diff --git a/gl_backend.h b/gl_backend.h index cea789ce..2e93c89d 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -59,28 +59,36 @@ 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/element array buffer object -// (storing vertex or element data in video memory) -// target is GL_ELEMENT_ARRAY_BUFFER_ARB (triangle elements) -// or GL_ARRAY_BUFFER_ARB (vertex data) -int R_Mesh_CreateStaticBufferObject(unsigned int target, void *data, size_t size, const char *name); -// frees a vertex/element array buffer object -void R_Mesh_DestroyBufferObject(int bufferobject); + +// vertex buffer and index buffer creation/updating/freeing +r_meshbuffer_t *R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qboolean isindexbuffer, qboolean isdynamic); +void R_Mesh_UpdateMeshBuffer(r_meshbuffer_t *buffer, const void *data, size_t size); +void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer); void GL_Mesh_ListVBOs(qboolean printeach); +r_vertexposition_t *R_Mesh_PrepareVertices_Position_Lock(int numvertices); +qboolean R_Mesh_PrepareVertices_Position_Unlock(void); // if this returns false, you need to prepare the mesh again! +void R_Mesh_PrepareVertices_Position_Arrays(int numvertices, const float *vertex3f); +void R_Mesh_PrepareVertices_Position(int numvertices, const r_vertexposition_t *vertex, const r_meshbuffer_t *buffer); + +r_vertexgeneric_t *R_Mesh_PrepareVertices_Generic_Lock(int numvertices); +qboolean R_Mesh_PrepareVertices_Generic_Unlock(void); +void R_Mesh_PrepareVertices_Generic_Arrays(int numvertices, const float *vertex3f, const float *color4f, const float *texcoord2f); +void R_Mesh_PrepareVertices_Generic(int numvertices, const r_vertexgeneric_t *vertex, const r_meshbuffer_t *vertexbuffer); + +r_vertexmesh_t *R_Mesh_PrepareVertices_Mesh_Lock(int numvertices); +qboolean R_Mesh_PrepareVertices_Mesh_Unlock(void); // if this returns false, you need to prepare the mesh again! +void R_Mesh_PrepareVertices_Mesh_Arrays(int numvertices, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *color4f, const float *texcoordtexture2f, const float *texcoordlightmap2f); +void R_Mesh_PrepareVertices_Mesh(int numvertices, const r_vertexmesh_t *vertex, const r_meshbuffer_t *buffer); + // sets up the requested vertex transform matrix void R_EntityMatrix(const matrix4x4_t *matrix); // sets the vertex array pointer -void R_Mesh_VertexPointer(const float *vertex3f, int bufferobject, size_t bufferoffset); +void R_Mesh_VertexPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); // sets the color array pointer (GL_Color only works when this is NULL) -void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferoffset); +void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); // sets the texcoord array pointer for an array unit -void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset); +void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset); // returns current texture bound to this identifier int R_Mesh_TexBound(unsigned int unitnum, int id); // copies a section of the framebuffer to a 2D texture @@ -95,7 +103,7 @@ void R_Mesh_TexCombine(unsigned int unitnum, int combinergb, int combinealpha, i void R_Mesh_ResetTextureState(void); // renders a mesh -void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int bufferobject3i, int bufferobject3s); +void R_Mesh_Draw(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const r_meshbuffer_t *element3i_indexbuffer, size_t element3i_bufferoffset, const unsigned short *element3s, const r_meshbuffer_t *element3s_indexbuffer, size_t element3s_bufferoffset); // saves a section of the rendered frame to a .tga or .jpg file qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *buffer2, unsigned char *buffer3, int x, int y, int width, int height, qboolean flipx, qboolean flipy, qboolean flipdiagonal, qboolean jpeg, qboolean png, qboolean gammacorrect); diff --git a/gl_draw.c b/gl_draw.c index de8bc085..84dfbd81 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -934,14 +934,19 @@ static void _DrawQ_ProcessDrawFlag(int flags) void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, float red, float green, float blue, float alpha, int flags) { - float floats[20]; + float floats[36]; _DrawQ_ProcessDrawFlag(flags); - GL_Color(red, green, blue, alpha); - R_Mesh_VertexPointer(floats, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; if (pic) { if (width == 0) @@ -949,14 +954,8 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo if (height == 0) height = pic->height; R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0); - -#if 1 - floats[12] = 0.0f;floats[13] = 0.0f; - floats[14] = 1.0f;floats[15] = 0.0f; - floats[16] = 1.0f;floats[17] = 1.0f; - floats[18] = 0.0f;floats[19] = 1.0f; -#else + +#if 0 // AK07: lets be texel correct on the corners { float horz_offset = 0.5f / pic->width; @@ -978,12 +977,13 @@ void DrawQ_Pic(float x, float y, cachepic_t *pic, float width, float height, flo floats[3] = floats[6] = x + width; floats[7] = floats[10] = y + height; - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, float org_x, float org_y, float angle, float red, float green, float blue, float alpha, int flags) { - float floats[20]; + float floats[36]; float af = DEG2RAD(-angle); // forward float ar = DEG2RAD(-angle + 90); // right float sinaf = sin(af); @@ -992,10 +992,7 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, float cosar = cos(ar); _DrawQ_ProcessDrawFlag(flags); - GL_Color(red, green, blue, alpha); - R_Mesh_VertexPointer(floats, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); if (pic) { @@ -1004,12 +1001,6 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, if (height == 0) height = pic->height; R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0); - - floats[12] = 0.0f;floats[13] = 0.0f; - floats[14] = 1.0f;floats[15] = 0.0f; - floats[16] = 1.0f;floats[17] = 1.0f; - floats[18] = 0.0f;floats[19] = 1.0f; } else R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); @@ -1032,18 +1023,25 @@ void DrawQ_RotPic(float x, float y, cachepic_t *pic, float width, float height, floats[9] = x - cosaf*org_x + cosar*(height-org_y); floats[10] = y - sinaf*org_x + sinar*(height-org_y); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } void DrawQ_Fill(float x, float y, float width, float height, float red, float green, float blue, float alpha, int flags) { - float floats[12]; + float floats[36]; _DrawQ_ProcessDrawFlag(flags); - GL_Color(red, green, blue, alpha); - R_Mesh_VertexPointer(floats, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); @@ -1052,8 +1050,17 @@ void DrawQ_Fill(float x, float y, float width, float height, float red, float gr floats[1] = floats[4] = y; floats[3] = floats[6] = x + width; floats[7] = floats[10] = y + height; - - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + floats[12] = 0.0f;floats[13] = 0.0f; + floats[14] = 1.0f;floats[15] = 0.0f; + floats[16] = 1.0f;floats[17] = 1.0f; + floats[18] = 0.0f;floats[19] = 1.0f; + floats[20] = floats[24] = floats[28] = floats[32] = red; + floats[21] = floats[25] = floats[29] = floats[33] = green; + floats[22] = floats[26] = floats[30] = floats[34] = blue; + floats[23] = floats[27] = floats[31] = floats[35] = alpha; + + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } /// color tag printing @@ -1358,12 +1365,9 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma _DrawQ_ProcessDrawFlag(flags); - R_Mesh_ColorPointer(color4f, 0, 0); R_Mesh_ResetTextureState(); if (!fontmap) R_Mesh_TexBind(0, fnt->tex); - R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0); - R_Mesh_VertexPointer(vertex3f, 0, 0); R_SetupShader_Generic(fnt->tex, NULL, GL_MODULATE, 1); ac = color4f; @@ -1493,7 +1497,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma if (batchcount) { // switching from freetype to non-freetype rendering - R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1530,7 +1535,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma batchcount++; if (batchcount >= QUADELEMENTS_MAXQUADS) { - R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1544,7 +1550,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma if (batchcount) { // we need a different character map, render what we currently have: - R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1603,7 +1610,8 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma batchcount++; if (batchcount >= QUADELEMENTS_MAXQUADS) { - R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); batchcount = 0; ac = color4f; at = texcoord2f; @@ -1621,7 +1629,10 @@ float DrawQ_String_Scale(float startx, float starty, const char *text, size_t ma } } if (batchcount > 0) - R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, quadelement3s, 0, 0); + { + R_Mesh_PrepareVertices_Generic_Arrays(batchcount * 4, vertex3f, color4f, texcoord2f); + R_Mesh_Draw(0, batchcount * 4, 0, batchcount * 2, quadelement3i, NULL, 0, quadelement3s, NULL, 0); + } if (outcolor) *outcolor = colorindex; @@ -1696,8 +1707,6 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height _DrawQ_ProcessDrawFlag(flags); - R_Mesh_VertexPointer(floats, 0, 0); - R_Mesh_ColorPointer(floats + 20, 0, 0); R_Mesh_ResetTextureState(); if (pic) { @@ -1706,11 +1715,6 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height if (height == 0) height = pic->height; R_SetupShader_Generic(Draw_GetPicTexture(pic), NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, floats + 12, 0, 0); - floats[12] = s1;floats[13] = t1; - floats[14] = s2;floats[15] = t2; - floats[16] = s4;floats[17] = t4; - floats[18] = s3;floats[19] = t3; } else R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); @@ -1720,25 +1724,28 @@ void DrawQ_SuperPic(float x, float y, cachepic_t *pic, float width, float height floats[1] = floats[4] = y; floats[3] = floats[6] = x + width; floats[7] = floats[10] = y + height; + floats[12] = s1;floats[13] = t1; + floats[14] = s2;floats[15] = t2; + floats[16] = s4;floats[17] = t4; + floats[18] = s3;floats[19] = t3; floats[20] = r1;floats[21] = g1;floats[22] = b1;floats[23] = a1; floats[24] = r2;floats[25] = g2;floats[26] = b2;floats[27] = a2; floats[28] = r4;floats[29] = g4;floats[30] = b4;floats[31] = a4; floats[32] = r3;floats[33] = g3;floats[34] = b3;floats[35] = a3; - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, floats, floats + 20, floats + 12); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } void DrawQ_Mesh (drawqueuemesh_t *mesh, int flags) { _DrawQ_ProcessDrawFlag(flags); - R_Mesh_VertexPointer(mesh->data_vertex3f, 0, 0); - R_Mesh_ColorPointer(mesh->data_color4f, 0, 0); R_Mesh_ResetTextureState(); - R_Mesh_TexCoordPointer(0, 2, mesh->data_texcoord2f, 0, 0); R_SetupShader_Generic(mesh->texture, NULL, GL_MODULATE, 1); - R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, mesh->data_element3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(mesh->num_vertices, mesh->data_vertex3f, mesh->data_color4f, mesh->data_texcoord2f); + R_Mesh_Draw(0, mesh->num_vertices, 0, mesh->num_triangles, mesh->data_element3i, NULL, 0, mesh->data_element3s, NULL, 0); } void DrawQ_LineLoop (drawqueuemesh_t *mesh, int flags) @@ -1824,8 +1831,6 @@ void R_DrawGamma(void) break; } // all the blends ignore depth - R_Mesh_VertexPointer(blendvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); GL_DepthMask(true); @@ -1845,8 +1850,9 @@ void R_DrawGamma(void) GL_BlendFunc(GL_DST_COLOR, GL_ONE); while (c[0] >= 1.01f || c[1] >= 1.01f || c[2] >= 1.01f) { - GL_Color(bound(0, c[0] - 1, 1), bound(0, c[1] - 1, 1), bound(0, c[2] - 1, 1), 1); - R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0); + GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); VectorScale(c, 0.5, c); } } @@ -1861,8 +1867,9 @@ void R_DrawGamma(void) if (c[0] >= 0.01f || c[1] >= 0.01f || c[2] >= 0.01f) { GL_BlendFunc(GL_ONE, GL_ONE); - GL_Color(c[0], c[1], c[2], 1); - R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0); + GL_Color(c[0] - 1, c[1] - 1, c[2] - 1, 1); + R_Mesh_PrepareVertices_Generic_Arrays(3, blendvertex3f, NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } } diff --git a/gl_rmain.c b/gl_rmain.c index 29acd58a..d07ad154 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -168,7 +168,6 @@ cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"}; cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; -cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"}; cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"}; cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"}; cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"}; @@ -655,7 +654,7 @@ static const char *builtinshaderstring = " gl_Position = ModelViewProjectionMatrix * gl_Vertex;\n" " TexCoord1 = gl_MultiTexCoord0.xy;\n" "#ifdef USEBLOOM\n" -" TexCoord2 = gl_MultiTexCoord1.xy;\n" +" TexCoord2 = gl_MultiTexCoord4.xy;\n" "#endif\n" "}\n" "#endif\n" @@ -1908,7 +1907,7 @@ const char *builtincgshaderstring = "float4 gl_Vertex : POSITION,\n" "uniform float4x4 ModelViewProjectionMatrix,\n" "float4 gl_MultiTexCoord0 : TEXCOORD0,\n" -"float4 gl_MultiTexCoord1 : TEXCOORD1,\n" +"float4 gl_MultiTexCoord1 : TEXCOORD4,\n" "out float4 gl_Position : POSITION,\n" "out float2 TexCoord1 : TEXCOORD0,\n" "out float2 TexCoord2 : TEXCOORD1\n" @@ -4547,7 +4546,8 @@ extern rtexture_t *r_shadow_prepassgeometrydepthtexture; extern rtexture_t *r_shadow_prepassgeometrynormalmaptexture; extern rtexture_t *r_shadow_prepasslightingdiffusetexture; extern rtexture_t *r_shadow_prepasslightingspeculartexture; -void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass) +extern cvar_t gl_mesh_separatearrays; +void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist) { // select a permutation of the lighting shader appropriate to this // combination of texture, entity, light source, and fogging, only use the @@ -4568,12 +4568,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, mode = SHADERMODE_GENERIC; permutation |= SHADERPERMUTATION_DIFFUSE; } - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest(false); GL_BlendFunc(GL_ONE, GL_ZERO); } @@ -4600,15 +4594,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, mode = SHADERMODE_DEFERREDGEOMETRY; if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND) permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND; - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest(false); GL_BlendFunc(GL_ONE, GL_ZERO); } @@ -4667,24 +4652,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, } if (rsurface.texture->reflectmasktexture) permutation |= SHADERPERMUTATION_REFLECTCUBE; - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING)) - { - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - } - else - { - R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0); - } - //R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); } @@ -4733,24 +4700,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_REFLECTION; if (rsurface.texture->reflectmasktexture) permutation |= SHADERPERMUTATION_REFLECTCUBE; - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING)) - { - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - } - else - { - R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0); - } - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); } @@ -4807,21 +4756,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP; if (rsurface.texture->reflectmasktexture) permutation |= SHADERPERMUTATION_REFLECTCUBE; - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING)) - { - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - } - else - { - R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0); - } - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); } @@ -4871,21 +4805,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP; if (rsurface.texture->reflectmasktexture) permutation |= SHADERPERMUTATION_REFLECTCUBE; - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING)) - { - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - } - else - { - R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0); - } - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); } @@ -4948,11 +4867,6 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (r_shadow_glossexact.integer) permutation |= SHADERPERMUTATION_EXACTSPECULARMATH; } - R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); } else if (r_glsl_deluxemapping.integer >= 2) { @@ -4965,41 +4879,16 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, if (r_shadow_glossexact.integer) permutation |= SHADERPERMUTATION_EXACTSPECULARMATH; } - R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); } else if (rsurface.uselightmaptexture) { // ordinary lightmapping (q1bsp, q3bsp) mode = SHADERMODE_LIGHTMAP; - R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset); - if (permutation & SHADERPERMUTATION_VERTEXTEXTUREBLEND) - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - else - R_Mesh_ColorPointer(NULL, 0, 0); } else { // ordinary vertex coloring (q3bsp) mode = SHADERMODE_VERTEXCOLOR; - R_Mesh_TexCoordPointer(4, 0, NULL, 0, 0); - R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset); - } - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - if (true || permutation & (SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_OFFSETMAPPING)) - { - R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset); - R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset); - R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset); - } - else - { - R_Mesh_TexCoordPointer(1, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(2, 0, NULL, 0, 0); - R_Mesh_TexCoordPointer(3, 0, NULL, 0, 0); } GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2); @@ -5007,6 +4896,22 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, switch(vid.renderpath) { case RENDERPATH_GL20: + if (gl_mesh_separatearrays.integer) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset); + R_Mesh_TexCoordPointer(3, 4, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + } + else + { + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer); + } R_SetupShader_SetPermutationGLSL(mode, permutation); if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fvARB(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);} if (mode == SHADERMODE_LIGHTSOURCE) @@ -5137,6 +5042,22 @@ void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, break; case RENDERPATH_CGGL: #ifdef SUPPORTCG + if (gl_mesh_separatearrays.integer) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer( 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_Mesh_ColorPointer( 4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset); + R_Mesh_TexCoordPointer(3, 4, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset); + R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); + } + else + { + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0), texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmeshbuffer); + } R_SetupShader_SetPermutationCG(mode, permutation); if (r_cg_permutation->fp_ModelToReflectCube) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);cgGLSetMatrixParameterfc(r_cg_permutation->fp_ModelToReflectCube, m16f);}CHECKCGERROR if (mode == SHADERMODE_LIGHTSOURCE) @@ -6491,7 +6412,6 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&developer_texturelogging); Cvar_RegisterVariable(&gl_lightmaps); Cvar_RegisterVariable(&r_test); - Cvar_RegisterVariable(&r_batchmode); Cvar_RegisterVariable(&r_glsl_saturation); Cvar_RegisterVariable(&r_framedatasize); if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE) @@ -6759,6 +6679,41 @@ void R_AnimCache_ClearCache(void) ent->animcache_normal3f = NULL; ent->animcache_svector3f = NULL; ent->animcache_tvector3f = NULL; + ent->animcache_vertexposition = NULL; + ent->animcache_vertexmesh = NULL; + ent->animcache_vertexpositionbuffer = NULL; + ent->animcache_vertexmeshbuffer = NULL; + } +} + +void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices) +{ + int i; + if (!ent->animcache_vertexmesh && ent->animcache_normal3f) + ent->animcache_vertexmesh = R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices); + if (!ent->animcache_vertexposition) + ent->animcache_vertexposition = R_FrameData_Alloc(sizeof(r_vertexposition_t)*numvertices); + if (ent->animcache_vertexposition) + { + for (i = 0;i < numvertices;i++) + VectorCopy(ent->animcache_vertex3f + 3*i, ent->animcache_vertexposition[i].vertex3f); + // TODO: upload vertex buffer? + } + if (ent->animcache_vertexmesh) + { + memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.vertexmesh, sizeof(r_vertexmesh_t)*numvertices); + for (i = 0;i < numvertices;i++) + VectorCopy(ent->animcache_vertex3f + 3*i, ent->animcache_vertexmesh[i].vertex3f); + if (ent->animcache_svector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(ent->animcache_svector3f + 3*i, ent->animcache_vertexmesh[i].svector3f); + if (ent->animcache_tvector3f) + for (i = 0;i < numvertices;i++) + VectorCopy(ent->animcache_tvector3f + 3*i, ent->animcache_vertexmesh[i].tvector3f); + if (ent->animcache_normal3f) + for (i = 0;i < numvertices;i++) + VectorCopy(ent->animcache_normal3f + 3*i, ent->animcache_vertexmesh[i].normal3f); + // TODO: upload vertex buffer? } } @@ -6769,7 +6724,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool // see if it's already cached this frame if (ent->animcache_vertex3f) { - // add normals/tangents if needed + // add normals/tangents if needed (this only happens with multiple views, reflections, cameras, etc) if (wantnormals || wanttangents) { if (ent->animcache_normal3f) @@ -6787,7 +6742,10 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices); } if (!r_framedata_failed) + { model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL); + R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + } } } } @@ -6807,7 +6765,10 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool ent->animcache_tvector3f = R_FrameData_Alloc(sizeof(float[3])*numvertices); } if (!r_framedata_failed) + { model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f); + R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices); + } } return !r_framedata_failed; } @@ -6815,7 +6776,7 @@ qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qbool void R_AnimCache_CacheVisibleEntities(void) { int i; - qboolean wantnormals = !r_showsurfaces.integer; + qboolean wantnormals = true; qboolean wanttangents = !r_showsurfaces.integer; switch(vid.renderpath) @@ -6829,6 +6790,9 @@ void R_AnimCache_CacheVisibleEntities(void) break; } + if (r_shownormals.integer) + wanttangents = wantnormals = true; + // TODO: thread this // NOTE: R_PrepareRTLights() also caches entities @@ -7853,10 +7817,10 @@ void R_Bloom_CopyBloomTexture(float colorscale) R_SetViewport(&r_bloomstate.viewport); GL_BlendFunc(GL_ONE, GL_ZERO); GL_Color(colorscale, colorscale, colorscale, 1); - // TODO: optimize with multitexture or GLSL - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f); + // TODO: do boxfilter scale-down in shader? R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; // we now have a bloom image in the framebuffer @@ -7879,8 +7843,6 @@ void R_Bloom_MakeTexture(void) r_refdef.stats.bloom++; R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); // we have a bloom image in the framebuffer CHECKGLERROR @@ -7891,10 +7853,10 @@ void R_Bloom_MakeTexture(void) x *= 2; r = bound(0, r_bloom_colorexponent.value / x, 1); GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); - GL_Color(r, r, r, 1); + GL_Color(r,r,r,1); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f); R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; // copy the vertically blurred bloom view to a texture @@ -7910,7 +7872,6 @@ void R_Bloom_MakeTexture(void) if(range >= 1) brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle" R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0); for (dir = 0;dir < 2;dir++) { @@ -7942,7 +7903,8 @@ void R_Bloom_MakeTexture(void) if(range >= 1) r *= (1 - x*x/(float)(range*range)); GL_Color(r, r, r, 1); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.offsettexcoord2f); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; GL_BlendFunc(GL_ONE, GL_ONE); } @@ -7957,18 +7919,18 @@ void R_Bloom_MakeTexture(void) if (r_bloom_colorsubtract.value > 0 && vid.support.ext_blend_subtract) { GL_BlendFunc(GL_ONE, GL_ZERO); + GL_Color(1,1,1,1); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f); R_SetupShader_Generic(r_bloomstate.texture_bloom, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0); - GL_Color(1, 1, 1, 1); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; GL_BlendFunc(GL_ONE, GL_ONE); qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0); GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.bloomtexcoord2f); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; qglBlendEquationEXT(GL_FUNC_ADD_EXT); @@ -8054,8 +8016,6 @@ static void R_BlendView(void) if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); } R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0)) { @@ -8090,9 +8050,9 @@ static void R_BlendView(void) { GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Color(1, 1, 1, cl.motionbluralpha); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_bloomstate.screentexcoord2f); R_SetupShader_Generic(r_bloomstate.texture_screen, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; } } @@ -8108,12 +8068,11 @@ static void R_BlendView(void) { // apply a color tint to the whole view R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); + GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } break; // no screen processing, no bloom, skip it } @@ -8137,12 +8096,9 @@ static void R_BlendView(void) sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]); R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); GL_Color(1, 1, 1, 1); + R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_bloomstate.screentexcoord2f, r_bloomstate.bloomtexcoord2f); GL_BlendFunc(GL_ONE, GL_ZERO); - R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0); - R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0); switch(vid.renderpath) { @@ -8179,7 +8135,7 @@ static void R_BlendView(void) default: break; } - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); r_refdef.stats.bloom_drawpixels += r_refdef.view.viewport.width * r_refdef.view.viewport.height; break; case RENDERPATH_GL13: @@ -8188,12 +8144,11 @@ static void R_BlendView(void) { // apply a color tint to the whole view R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); + GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } break; } @@ -8785,11 +8740,10 @@ void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, floa c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2; } } - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_ColorPointer(color4f, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(8, vertex3f, color4f, NULL); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0); + R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); } static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist) @@ -8935,9 +8889,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST)); GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); memcpy(color4f, nomodelcolor4f, sizeof(float[6*4])); - R_Mesh_ColorPointer(color4f, 0, 0); for (i = 0, c = color4f;i < 6;i++, c += 4) { c[0] *= rsurface.colormod[0]; @@ -8949,7 +8901,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight { for (i = 0, c = color4f;i < 6;i++, c += 4) { - f1 = RSurf_FogVertex(rsurface.vertex3f + 3*i); + f1 = RSurf_FogVertex(nomodelvertex3f + 3*i); f2 = 1 - f1; c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2); c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2); @@ -8957,7 +8909,8 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight } } R_Mesh_ResetTextureState(); - R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, nomodelelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL); + R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0); } void R_DrawNoModel(entity_render_t *ent) @@ -9396,7 +9349,7 @@ texture_t *R_GetCurrentTexture(texture_t *t) } else { - t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white; + t->backgroundbasetexture = r_texture_white; t->backgroundnmaptexture = r_texture_blanknormalmap; t->backgroundglosstexture = r_texture_black; t->backgroundglowtexture = NULL; @@ -9543,24 +9496,51 @@ rsurfacestate_t rsurface; void R_Mesh_ResizeArrays(int newvertices) { - float *base; + unsigned char *base; + size_t size; if (rsurface.array_size >= newvertices) return; - if (rsurface.array_modelvertex3f) - Mem_Free(rsurface.array_modelvertex3f); + if (rsurface.array_base) + Mem_Free(rsurface.array_base); rsurface.array_size = (newvertices + 1023) & ~1023; - base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33])); - rsurface.array_modelvertex3f = base + rsurface.array_size * 0; - rsurface.array_modelsvector3f = base + rsurface.array_size * 3; - rsurface.array_modeltvector3f = base + rsurface.array_size * 6; - rsurface.array_modelnormal3f = base + rsurface.array_size * 9; - rsurface.array_deformedvertex3f = base + rsurface.array_size * 12; - rsurface.array_deformedsvector3f = base + rsurface.array_size * 15; - rsurface.array_deformedtvector3f = base + rsurface.array_size * 18; - rsurface.array_deformednormal3f = base + rsurface.array_size * 21; - rsurface.array_texcoord3f = base + rsurface.array_size * 24; - rsurface.array_color4f = base + rsurface.array_size * 27; - rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31; + size = 0; + size += rsurface.array_size * sizeof(*rsurface.array_modelvertexmesh); + size += rsurface.array_size * sizeof(*rsurface.array_batchvertexmesh); + size += rsurface.array_size * sizeof(*rsurface.array_modelvertexposition); + size += rsurface.array_size * sizeof(*rsurface.array_batchvertexposition); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[3]); + size += rsurface.array_size * sizeof(float[4]); + size += rsurface.array_size * sizeof(float[2]); + size += rsurface.array_size * sizeof(float[2]); + size += rsurface.array_size * sizeof(float[4]); + size += rsurface.array_size * sizeof(int[3]); + size += rsurface.array_size * sizeof(unsigned short[3]); + rsurface.array_base = base = (unsigned char *)Mem_Alloc(r_main_mempool, size); + rsurface.array_modelvertexmesh = (r_vertexmesh_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_modelvertexmesh); + rsurface.array_batchvertexmesh = (r_vertexmesh_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_batchvertexmesh); + rsurface.array_modelvertexposition = (r_vertexposition_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_modelvertexposition); + rsurface.array_batchvertexposition = (r_vertexposition_t *)base;base += rsurface.array_size * sizeof(*rsurface.array_batchvertexposition); + rsurface.array_modelvertex3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_modelsvector3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_modeltvector3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_modelnormal3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_batchvertex3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_batchsvector3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_batchtvector3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_batchnormal3f = (float *)base;base += rsurface.array_size * sizeof(float[3]); + rsurface.array_batchlightmapcolor4f = (float *)base;base += rsurface.array_size * sizeof(float[4]); + rsurface.array_batchtexcoordtexture2f = (float *)base;base += rsurface.array_size * sizeof(float[2]); + rsurface.array_batchtexcoordlightmap2f = (float *)base;base += rsurface.array_size * sizeof(float[2]); + rsurface.array_passcolor4f = (float *)base;base += rsurface.array_size * sizeof(float[4]); + rsurface.array_batchelement3i = (int *)base;base += rsurface.array_size * sizeof(int[3]); + rsurface.array_batchelement3s = (unsigned short *)base;base += rsurface.array_size * sizeof(unsigned short[3]); } void RSurf_ActiveWorldEntity(void) @@ -9601,48 +9581,80 @@ void RSurf_ActiveWorldEntity(void) rsurface.basepolygonfactor = r_refdef.polygonfactor; rsurface.basepolygonoffset = r_refdef.polygonoffset; rsurface.modelvertex3f = model->surfmesh.data_vertex3f; - rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo; + rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; rsurface.modelsvector3f = model->surfmesh.data_svector3f; - rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo; + rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f; rsurface.modeltvector3f = model->surfmesh.data_tvector3f; - rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo; + rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f; rsurface.modelnormal3f = model->surfmesh.data_normal3f; - rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo; + rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f; rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f; - rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo; + rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f; rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f; - rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo; + rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f; rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; - rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo; + rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; rsurface.modelelement3i = model->surfmesh.data_element3i; + rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; + rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; rsurface.modelelement3s = model->surfmesh.data_element3s; - rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i; - rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s; + rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer; + rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset; rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets; - rsurface.modelnum_vertices = model->surfmesh.num_vertices; - rsurface.modelnum_triangles = model->surfmesh.num_triangles; + rsurface.modelnumvertices = model->surfmesh.num_vertices; + rsurface.modelnumtriangles = model->surfmesh.num_triangles; rsurface.modelsurfaces = model->data_surfaces; - rsurface.generatedvertex = false; - rsurface.vertex3f = rsurface.modelvertex3f; - rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject; - rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; - rsurface.svector3f = rsurface.modelsvector3f; - rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject; - rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; - rsurface.tvector3f = rsurface.modeltvector3f; - rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject; - rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; - rsurface.normal3f = rsurface.modelnormal3f; - rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject; - rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; - rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f; + rsurface.modelvertexmesh = model->surfmesh.vertexmesh; + rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer; + rsurface.modelvertexposition = model->surfmesh.vertexposition; + rsurface.modelvertexpositionbuffer = model->surfmesh.vertexpositionbuffer; + rsurface.modelgeneratedvertex = false; + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmeshbuffer = NULL; + rsurface.batchvertexposition = NULL; + rsurface.batchvertexpositionbuffer = NULL; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; } void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass) @@ -9694,6 +9706,10 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL; rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL; rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL; + rsurface.modelvertexmesh = ent->animcache_vertexmesh; + rsurface.modelvertexmeshbuffer = ent->animcache_vertexmeshbuffer; + rsurface.modelvertexposition = ent->animcache_vertexposition; + rsurface.modelvertexpositionbuffer = ent->animcache_vertexpositionbuffer; } else if (wanttangents) { @@ -9702,6 +9718,10 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modeltvector3f = rsurface.array_modeltvector3f; rsurface.modelnormal3f = rsurface.array_modelnormal3f; model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmeshbuffer = NULL; + rsurface.modelvertexposition = NULL; + rsurface.modelvertexpositionbuffer = NULL; } else if (wantnormals) { @@ -9710,6 +9730,10 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modeltvector3f = NULL; rsurface.modelnormal3f = rsurface.array_modelnormal3f; model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmeshbuffer = NULL; + rsurface.modelvertexposition = NULL; + rsurface.modelvertexpositionbuffer = NULL; } else { @@ -9718,77 +9742,115 @@ void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, q rsurface.modeltvector3f = NULL; rsurface.modelnormal3f = NULL; model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.array_modelvertex3f, NULL, NULL, NULL); + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmeshbuffer = NULL; + rsurface.modelvertexposition = NULL; + rsurface.modelvertexpositionbuffer = NULL; } - rsurface.modelvertex3f_bufferobject = 0; + rsurface.modelvertex3f_vertexbuffer = 0; rsurface.modelvertex3f_bufferoffset = 0; - rsurface.modelsvector3f_bufferobject = 0; + rsurface.modelsvector3f_vertexbuffer = 0; rsurface.modelsvector3f_bufferoffset = 0; - rsurface.modeltvector3f_bufferobject = 0; + rsurface.modeltvector3f_vertexbuffer = 0; rsurface.modeltvector3f_bufferoffset = 0; - rsurface.modelnormal3f_bufferobject = 0; + rsurface.modelnormal3f_vertexbuffer = 0; rsurface.modelnormal3f_bufferoffset = 0; - rsurface.generatedvertex = true; + rsurface.modelgeneratedvertex = true; } else { rsurface.modelvertex3f = model->surfmesh.data_vertex3f; - rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo; + rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f; rsurface.modelsvector3f = model->surfmesh.data_svector3f; - rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo; + rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f; rsurface.modeltvector3f = model->surfmesh.data_tvector3f; - rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo; + rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f; rsurface.modelnormal3f = model->surfmesh.data_normal3f; - rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo; + rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f; - rsurface.generatedvertex = false; + rsurface.modelvertexmesh = model->surfmesh.vertexmesh; + rsurface.modelvertexmeshbuffer = model->surfmesh.vertexmeshbuffer; + rsurface.modelvertexposition = model->surfmesh.vertexposition; + rsurface.modelvertexpositionbuffer = model->surfmesh.vertexpositionbuffer; + rsurface.modelgeneratedvertex = false; } rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f; - rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo; + rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f; rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f; - rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo; + rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f; rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f; - rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo; + rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer; rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f; rsurface.modelelement3i = model->surfmesh.data_element3i; + rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer; + rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset; rsurface.modelelement3s = model->surfmesh.data_element3s; - rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i; - rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s; + rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer; + rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset; rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets; - rsurface.modelnum_vertices = model->surfmesh.num_vertices; - rsurface.modelnum_triangles = model->surfmesh.num_triangles; + rsurface.modelnumvertices = model->surfmesh.num_vertices; + rsurface.modelnumtriangles = model->surfmesh.num_triangles; rsurface.modelsurfaces = model->data_surfaces; - rsurface.vertex3f = rsurface.modelvertex3f; - rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject; - rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; - rsurface.svector3f = rsurface.modelsvector3f; - rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject; - rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; - rsurface.tvector3f = rsurface.modeltvector3f; - rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject; - rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; - rsurface.normal3f = rsurface.modelnormal3f; - rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject; - rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; - rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f; + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmeshbuffer = NULL; + rsurface.batchvertexposition = NULL; + rsurface.batchvertexpositionbuffer = NULL; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; } void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents) { + int i; + rsurface.entity = r_refdef.scene.worldentity; rsurface.skeleton = NULL; rsurface.ent_skinnum = 0; rsurface.ent_qwskin = -1; rsurface.ent_shadertime = shadertime; rsurface.ent_flags = entflags; - rsurface.modelnum_vertices = numvertices; - rsurface.modelnum_triangles = numtriangles; - if (rsurface.array_size < rsurface.modelnum_vertices) - R_Mesh_ResizeArrays(rsurface.modelnum_vertices); + rsurface.modelnumvertices = numvertices; + rsurface.modelnumtriangles = numtriangles; + if (rsurface.array_size < rsurface.modelnumvertices) + R_Mesh_ResizeArrays(rsurface.modelnumvertices); rsurface.matrix = *matrix; rsurface.inversematrix = *inversematrix; rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix); @@ -9833,50 +9895,108 @@ void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inve rsurface.modeltvector3f = NULL; rsurface.modelnormal3f = NULL; } - rsurface.modelvertex3f_bufferobject = 0; + rsurface.modelvertexmesh = NULL; + rsurface.modelvertexmeshbuffer = NULL; + rsurface.modelvertexposition = NULL; + rsurface.modelvertexpositionbuffer = NULL; + rsurface.modelvertex3f_vertexbuffer = 0; rsurface.modelvertex3f_bufferoffset = 0; - rsurface.modelsvector3f_bufferobject = 0; + rsurface.modelsvector3f_vertexbuffer = 0; rsurface.modelsvector3f_bufferoffset = 0; - rsurface.modeltvector3f_bufferobject = 0; + rsurface.modeltvector3f_vertexbuffer = 0; rsurface.modeltvector3f_bufferoffset = 0; - rsurface.modelnormal3f_bufferobject = 0; + rsurface.modelnormal3f_vertexbuffer = 0; rsurface.modelnormal3f_bufferoffset = 0; - rsurface.generatedvertex = true; + rsurface.modelgeneratedvertex = true; rsurface.modellightmapcolor4f = color4f; - rsurface.modellightmapcolor4f_bufferobject = 0; + rsurface.modellightmapcolor4f_vertexbuffer = 0; rsurface.modellightmapcolor4f_bufferoffset = 0; rsurface.modeltexcoordtexture2f = texcoord2f; - rsurface.modeltexcoordtexture2f_bufferobject = 0; + rsurface.modeltexcoordtexture2f_vertexbuffer = 0; rsurface.modeltexcoordtexture2f_bufferoffset = 0; rsurface.modeltexcoordlightmap2f = NULL; - rsurface.modeltexcoordlightmap2f_bufferobject = 0; + rsurface.modeltexcoordlightmap2f_vertexbuffer = 0; rsurface.modeltexcoordlightmap2f_bufferoffset = 0; rsurface.modelelement3i = element3i; + rsurface.modelelement3i_indexbuffer = NULL; + rsurface.modelelement3i_bufferoffset = 0; rsurface.modelelement3s = element3s; - rsurface.modelelement3i_bufferobject = 0; - rsurface.modelelement3s_bufferobject = 0; + rsurface.modelelement3s_indexbuffer = NULL; + rsurface.modelelement3s_bufferoffset = 0; rsurface.modellightmapoffsets = NULL; rsurface.modelsurfaces = NULL; - rsurface.vertex3f = rsurface.modelvertex3f; - rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject; - rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; - rsurface.svector3f = rsurface.modelsvector3f; - rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject; - rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; - rsurface.tvector3f = rsurface.modeltvector3f; - rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject; - rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; - rsurface.normal3f = rsurface.modelnormal3f; - rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject; - rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; - rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f; - - if (rsurface.modelnum_vertices && rsurface.modelelement3i) + rsurface.batchgeneratedvertex = false; + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = 0; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = 0; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmeshbuffer = NULL; + rsurface.batchvertexposition = NULL; + rsurface.batchvertexpositionbuffer = NULL; + rsurface.batchelement3i = NULL; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = NULL; + rsurface.passcolor4f_bufferoffset = 0; + + if (rsurface.modelnumvertices && rsurface.modelelement3i) { if ((wantnormals || wanttangents) && !normal3f) - Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0); + { + Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0); + rsurface.modelnormal3f = rsurface.array_modelnormal3f; + } if (wanttangents && !svector3f) - Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0); + { + Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0); + rsurface.modelsvector3f = rsurface.array_modelsvector3f; + rsurface.modeltvector3f = rsurface.array_modeltvector3f; + } + } + + // now convert arrays into vertexmesh structs + for (i = 0;i < numvertices;i++) + { + VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexposition[i].vertex3f); + VectorCopy(rsurface.modelvertex3f + 3*i, rsurface.array_modelvertexmesh[i].vertex3f); + if (rsurface.modelsvector3f) + VectorCopy(rsurface.modelsvector3f + 3*i, rsurface.array_modelvertexmesh[i].svector3f); + if (rsurface.modeltvector3f) + VectorCopy(rsurface.modeltvector3f + 3*i, rsurface.array_modelvertexmesh[i].tvector3f); + if (rsurface.modelnormal3f) + VectorCopy(rsurface.modelnormal3f + 3*i, rsurface.array_modelvertexmesh[i].normal3f); + if (rsurface.modellightmapcolor4f) + Vector4Scale(rsurface.modellightmapcolor4f + 4*i, 255.0f, rsurface.array_modelvertexmesh[i].color4ub); + if (rsurface.modeltexcoordtexture2f) + Vector2Copy(rsurface.modeltexcoordtexture2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordtexture2f); + if (rsurface.modeltexcoordlightmap2f) + Vector2Copy(rsurface.modeltexcoordlightmap2f + 2*i, rsurface.array_modelvertexmesh[i].texcoordlightmap2f); } } @@ -9912,70 +10032,456 @@ float RSurf_FogVertex(const float *v) return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)]; } +void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust) +{ + int i; + for (i = 0;i < numelements;i++) + outelement3i[i] = inelement3i[i] + adjust; +} + static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}}; -void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist) +extern cvar_t gl_vbo; +void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist) { int deformindex; - int texturesurfaceindex; + int firsttriangle; + int numtriangles; + int firstvertex; + int endvertex; + int numvertices; + int surfacefirsttriangle; + int surfacenumtriangles; + int surfacefirstvertex; + int surfaceendvertex; + int surfacenumvertices; + int surfaceadjustvertex; + int needsupdate; int i, j; + qboolean gaps; + qboolean dynamicvertex; float amplitude; float animpos; float scale; - const float *v1, *in_tc; - float *out_tc; float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3]; float waveparms[4]; q3shaderinfo_deform_t *deform; - // if vertices are dynamic (animated models), generate them into the temporary rsurface.array_model* arrays and point rsurface.model* at them instead of the static data from the model itself - if (rsurface.generatedvertex) + const msurface_t *surface, *firstsurface; + r_vertexposition_t *vertexposition; + r_vertexmesh_t *vertexmesh; + if (!texturenumsurfaces) + return; + // find vertex range of this surface batch + gaps = false; + firstsurface = texturesurfacelist[0]; + firsttriangle = firstsurface->num_firsttriangle; + numtriangles = 0; + firstvertex = endvertex = firstsurface->num_firstvertex; + for (i = 0;i < texturenumsurfaces;i++) + { + surface = texturesurfacelist[i]; + if (surface != firstsurface + i) + gaps = true; + surfacefirstvertex = surface->num_firstvertex; + surfaceendvertex = surfacefirstvertex + surface->num_vertices; + surfacenumtriangles = surface->num_triangles; + if (firstvertex > surfacefirstvertex) + firstvertex = surfacefirstvertex; + if (endvertex < surfaceendvertex) + endvertex = surfaceendvertex; + numtriangles += surfacenumtriangles; + } + if (!numtriangles) + return; + + // we now know the vertex range used, and if there are any gaps in it + rsurface.batchfirstvertex = firstvertex; + rsurface.batchnumvertices = endvertex - firstvertex; + rsurface.batchfirsttriangle = firsttriangle; + rsurface.batchnumtriangles = numtriangles; + + // this variable holds flags for which properties have been updated that + // may require regenerating vertexmesh or vertexposition arrays... + needsupdate = 0; + + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) + needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_NOGAPS; + for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++) { - if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT) - generatenormals = true; - for (i = 0;i < Q3MAXDEFORMS;i++) + switch (deform->deform) { - if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE) + default: + case Q3DEFORM_PROJECTIONSHADOW: + case Q3DEFORM_TEXT0: + case Q3DEFORM_TEXT1: + case Q3DEFORM_TEXT2: + case Q3DEFORM_TEXT3: + case Q3DEFORM_TEXT4: + case Q3DEFORM_TEXT5: + case Q3DEFORM_TEXT6: + case Q3DEFORM_TEXT7: + case Q3DEFORM_NONE: + break; + case Q3DEFORM_AUTOSPRITE: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_AUTOSPRITE2: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_NORMAL: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_WAVE: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_BULGE: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR; + break; + case Q3DEFORM_MOVE: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXPOSITION | BATCHNEED_VERTEXMESH_VERTEX; + break; + } + } + switch(rsurface.texture->tcgen.tcgen) + { + default: + case Q3TCGEN_TEXTURE: + break; + case Q3TCGEN_LIGHTMAP: + batchneed |= BATCHNEED_ARRAY_LIGHTMAP | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP; + break; + case Q3TCGEN_VECTOR: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + break; + case Q3TCGEN_ENVIRONMENT: + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + break; + } + if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT) + { + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD; + } + + // check if any dynamic vertex processing must occur + dynamicvertex = false; + + if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) + { + dynamicvertex = true; + batchneed |= BATCHNEED_NOGAPS; + needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)); + } + + if (needsupdate & batchneed & BATCHNEED_VERTEXPOSITION) + { + dynamicvertex = true; + batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS; + needsupdate |= (batchneed & BATCHNEED_VERTEXPOSITION); + } + + if (dynamicvertex || gaps || rsurface.batchfirstvertex) + { + // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set... + if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) batchneed |= BATCHNEED_ARRAY_VERTEX; + if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) batchneed |= BATCHNEED_ARRAY_NORMAL; + if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) batchneed |= BATCHNEED_ARRAY_VECTOR; + if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR; + if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) batchneed |= BATCHNEED_ARRAY_TEXCOORD; + if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) batchneed |= BATCHNEED_ARRAY_LIGHTMAP; + } + + // when the model data has no vertex buffer (dynamic mesh), we need to + // eliminate gaps + if (!rsurface.modelvertexmeshbuffer || (!gl_vbo.integer && !vid.forcevbo)) + batchneed |= BATCHNEED_NOGAPS; + + // if needsupdate, we have to do a dynamic vertex batch for sure + if (needsupdate & batchneed) + dynamicvertex = true; + + // see if we need to build vertexmesh from arrays + if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))) + dynamicvertex = true; + + // see if we need to build vertexposition from arrays + if (!rsurface.modelvertexposition && (batchneed & BATCHNEED_VERTEXPOSITION)) + dynamicvertex = true; + + // if gaps are unacceptable, and there are gaps, it's a dynamic batch... + if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex)) + dynamicvertex = true; + + // if there is a chance of animated vertex colors, it's a dynamic batch + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) + dynamicvertex = true; + + rsurface.batchvertex3f = rsurface.modelvertex3f; + rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer; + rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; + rsurface.batchsvector3f = rsurface.modelsvector3f; + rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer; + rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; + rsurface.batchtvector3f = rsurface.modeltvector3f; + rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer; + rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; + rsurface.batchnormal3f = rsurface.modelnormal3f; + rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer; + rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; + rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f; + rsurface.batchlightmapcolor4f_vertexbuffer = rsurface.modellightmapcolor4f_vertexbuffer; + rsurface.batchlightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = rsurface.modeltexcoordtexture2f_vertexbuffer; + rsurface.batchtexcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset; + rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f; + rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer; + rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset; + rsurface.batchvertexposition = rsurface.modelvertexposition; + rsurface.batchvertexpositionbuffer = rsurface.modelvertexpositionbuffer; + rsurface.batchvertexmesh = rsurface.modelvertexmesh; + rsurface.batchvertexmeshbuffer = rsurface.modelvertexmeshbuffer; + rsurface.batchelement3i = rsurface.modelelement3i; + rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer; + rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset; + rsurface.batchelement3s = rsurface.modelelement3s; + rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer; + rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset; + + // if any dynamic vertex processing has to occur in software, we copy the + // entire surface list together before processing to rebase the vertices + // to start at 0 (otherwise we waste a lot of room in a vertex buffer). + // + // if any gaps exist and we do not have a static vertex buffer, we have to + // copy the surface list together to avoid wasting upload bandwidth on the + // vertices in the gaps. + // + // if gaps exist and we have a static vertex buffer, we still have to + // combine the index buffer ranges into one dynamic index buffer. + // + // in all cases we end up with data that can be drawn in one call. + + if (!dynamicvertex) + { + // static vertex data, just set pointers... + rsurface.batchgeneratedvertex = false; + // if there are gaps, we want to build a combined index buffer, + // otherwise use the original static buffer with an appropriate offset + if (gaps) + { + firsttriangle = 0; + numtriangles = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle; + surfacenumtriangles = texturesurfacelist[i]->num_triangles; + memcpy(rsurface.array_batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3])); + numtriangles += surfacenumtriangles; + } + rsurface.batchelement3i = rsurface.array_batchelement3i; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + if (endvertex <= 65536) + { + rsurface.batchelement3s = rsurface.array_batchelement3s; + for (i = 0;i < numtriangles*3;i++) + rsurface.array_batchelement3s[i] = rsurface.array_batchelement3i[i]; + } + rsurface.batchfirsttriangle = firsttriangle; + rsurface.batchnumtriangles = numtriangles; + } + return; + } + + // something needs software processing, do it for real... + // we only directly handle interleaved array data in this case... + rsurface.batchgeneratedvertex = true; + + // now copy the vertex data into a combined array and make an index array + // (this is what Quake3 does all the time) + //if (gaps || rsurface.batchfirstvertex) + { + rsurface.batchvertexposition = NULL; + rsurface.batchvertexpositionbuffer = NULL; + rsurface.batchvertexmesh = NULL; + rsurface.batchvertexmeshbuffer = NULL; + rsurface.batchvertex3f = NULL; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = NULL; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = NULL; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = NULL; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; + rsurface.batchlightmapcolor4f = NULL; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = NULL; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordlightmap2f = NULL; + rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL; + rsurface.batchtexcoordlightmap2f_bufferoffset = 0; + rsurface.batchelement3i = rsurface.array_batchelement3i; + rsurface.batchelement3i_indexbuffer = NULL; + rsurface.batchelement3i_bufferoffset = 0; + rsurface.batchelement3s = NULL; + rsurface.batchelement3s_indexbuffer = NULL; + rsurface.batchelement3s_bufferoffset = 0; + // we'll only be setting up certain arrays as needed + if (batchneed & BATCHNEED_VERTEXPOSITION) + rsurface.batchvertexposition = rsurface.array_batchvertexposition; + if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) + rsurface.batchvertexmesh = rsurface.array_batchvertexmesh; + if (batchneed & BATCHNEED_ARRAY_VERTEX) + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + if (batchneed & BATCHNEED_ARRAY_NORMAL) + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + if (batchneed & BATCHNEED_ARRAY_VECTOR) + { + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + } + if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) + rsurface.batchlightmapcolor4f = rsurface.array_batchlightmapcolor4f; + if (batchneed & BATCHNEED_ARRAY_TEXCOORD) + rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f; + if (batchneed & BATCHNEED_ARRAY_LIGHTMAP) + rsurface.batchtexcoordlightmap2f = rsurface.array_batchtexcoordlightmap2f; + numvertices = 0; + numtriangles = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surfacefirstvertex = texturesurfacelist[i]->num_firstvertex; + surfacenumvertices = texturesurfacelist[i]->num_vertices; + surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle; + surfaceadjustvertex = numvertices - surfacefirstvertex; + surfacenumtriangles = texturesurfacelist[i]->num_triangles; + // copy only the data requested + if ((batchneed & BATCHNEED_VERTEXPOSITION) && rsurface.modelvertexposition) + memcpy(rsurface.array_batchvertexposition + numvertices, rsurface.modelvertexposition + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexposition[0])); + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh) + memcpy(rsurface.array_batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0])); + if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP)) + { + if (batchneed & BATCHNEED_ARRAY_VERTEX) + memcpy(rsurface.array_batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + if ((batchneed & BATCHNEED_ARRAY_NORMAL) && rsurface.modelnormal3f) + memcpy(rsurface.array_batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + if ((batchneed & BATCHNEED_ARRAY_VECTOR) && rsurface.modelsvector3f) + { + memcpy(rsurface.array_batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + memcpy(rsurface.array_batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3])); + } + if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && rsurface.modellightmapcolor4f) + memcpy(rsurface.array_batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4])); + if ((batchneed & BATCHNEED_ARRAY_TEXCOORD) && rsurface.modeltexcoordtexture2f) + memcpy(rsurface.array_batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2])); + if ((batchneed & BATCHNEED_ARRAY_LIGHTMAP) && rsurface.modeltexcoordlightmap2f) + memcpy(rsurface.array_batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2])); + } + RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.array_batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex); + numvertices += surfacenumvertices; + numtriangles += surfacenumtriangles; + } + + // generate a 16bit index array as well if possible + // (in general, dynamic batches fit) + if (numvertices <= 65536) + { + rsurface.batchelement3s = rsurface.array_batchelement3s; + for (i = 0;i < numtriangles*3;i++) + rsurface.array_batchelement3s[i] = rsurface.array_batchelement3i[i]; + } + + // since we've copied everything, the batch now starts at 0 + rsurface.batchfirstvertex = 0; + rsurface.batchnumvertices = numvertices; + rsurface.batchfirsttriangle = 0; + rsurface.batchnumtriangles = numtriangles; + } + + // q1bsp surfaces rendered in vertex color mode have to have colors + // calculated based on lightstyles + if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo) + { + // generate color arrays for the surfaces in this list + int c[4]; + int scale; + int size3; + const int *offsets; + const unsigned char *lm; + numvertices = 0; + rsurface.batchlightmapcolor4f = rsurface.array_batchlightmapcolor4f; + rsurface.batchlightmapcolor4f_vertexbuffer = NULL; + rsurface.batchlightmapcolor4f_bufferoffset = 0; + for (i = 0;i < texturenumsurfaces;i++) + { + surface = texturesurfacelist[i]; + offsets = rsurface.modellightmapoffsets + surface->num_firstvertex; + surfacenumvertices = surface->num_vertices; + if (surface->lightmapinfo->samples) + { + for (j = 0;j < surfacenumvertices;j++) + { + lm = surface->lightmapinfo->samples + offsets[j]; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]]; + VectorScale(lm, scale, c); + if (surface->lightmapinfo->styles[1] != 255) + { + size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3; + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]]; + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[2] != 255) + { + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]]; + VectorMA(c, scale, lm, c); + if (surface->lightmapinfo->styles[3] != 255) + { + lm += size3; + scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]]; + VectorMA(c, scale, lm, c); + } + } + } + c[0] >>= 15; + c[1] >>= 15; + c[2] >>= 15; + Vector4Set(rsurface.array_batchlightmapcolor4f + 4*numvertices, min(c[0], 255) * (1.0f / 255.0f), min(c[1], 255) * (1.0f / 255.0f), min(c[2], 255) * (1.0f / 255.0f), 1); + numvertices++; + } + } + else { - generatetangents = true; - generatenormals = true; + for (j = 0;j < surfacenumvertices;j++) + { + Vector4Set(rsurface.array_batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1); + numvertices++; + } } - if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE) - generatenormals = true; - } - if (generatenormals && !rsurface.modelnormal3f) - { - rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f; - rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0; - rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0; - Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0); - } - if (generatetangents && !rsurface.modelsvector3f) - { - rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f; - rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0; - rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0; - rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f; - rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0; - rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0; - Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0); - } - } - rsurface.vertex3f = rsurface.modelvertex3f; - rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject; - rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset; - rsurface.svector3f = rsurface.modelsvector3f; - rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject; - rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset; - rsurface.tvector3f = rsurface.modeltvector3f; - rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject; - rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset; - rsurface.normal3f = rsurface.modelnormal3f; - rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject; - rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset; + } + } + // if vertices are deformed (sprite flares and things in maps, possibly - // water waves, bulges and other deformations), generate them into - // rsurface.deform* arrays from whatever the rsurface.* arrays point to - // (may be static model data or generated data for an animated model, or - // the previous deform pass) + // water waves, bulges and other deformations), modify the copied vertices + // in place for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++) { switch (deform->deform) @@ -9999,41 +10505,36 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorNormalize(newforward); VectorNormalize(newright); VectorNormalize(newup); - // make deformed versions of only the model vertices used by the specified surfaces - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + // a single autosprite surface can contain multiple sprites... + for (j = 0;j < rsurface.batchnumvertices - 3;j += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - // a single autosprite surface can contain multiple sprites... - for (j = 0;j < surface->num_vertices - 3;j += 4) + VectorClear(center); + for (i = 0;i < 4;i++) + VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center); + VectorScale(center, 0.25f, center); + VectorCopy(rsurface.batchnormal3f + 3*j, forward); + VectorCopy(rsurface.batchsvector3f + 3*j, right); + VectorCopy(rsurface.batchtvector3f + 3*j, up); + for (i = 0;i < 4;i++) { - VectorClear(center); - for (i = 0;i < 4;i++) - VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); - VectorScale(center, 0.25f, center); - VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward); - VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right); - VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up); - for (i = 0;i < 4;i++) - { - VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v); - VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3); - } + VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v); + VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_batchvertex3f + 3*(j+i)); } - Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0); - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); } - rsurface.vertex3f = rsurface.array_deformedvertex3f; - rsurface.vertex3f_bufferobject = 0; - rsurface.vertex3f_bufferoffset = 0; - rsurface.svector3f = rsurface.array_deformedsvector3f; - rsurface.svector3f_bufferobject = 0; - rsurface.svector3f_bufferoffset = 0; - rsurface.tvector3f = rsurface.array_deformedtvector3f; - rsurface.tvector3f_bufferobject = 0; - rsurface.tvector3f_bufferoffset = 0; - rsurface.normal3f = rsurface.array_deformednormal3f; - rsurface.normal3f_bufferobject = 0; - rsurface.normal3f_bufferoffset = 0; + Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true); + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true); + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; break; case Q3DEFORM_AUTOSPRITE2: Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward); @@ -10042,10 +10543,7 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorNormalize(newforward); VectorNormalize(newright); VectorNormalize(newup); - // make deformed versions of only the model vertices used by the specified surfaces - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; const float *v1, *v2; vec3_t start, end; float f, l; @@ -10058,25 +10556,18 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta shortest[2]; memset(shortest, 0, sizeof(shortest)); // a single autosprite surface can contain multiple sprites... - for (j = 0;j < surface->num_vertices - 3;j += 4) + for (j = 0;j < rsurface.batchnumvertices - 3;j += 4) { VectorClear(center); for (i = 0;i < 4;i++) - VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center); + VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center); VectorScale(center, 0.25f, center); // find the two shortest edges, then use them to define the // axis vectors for rotating around the central axis for (i = 0;i < 6;i++) { - v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]); - v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]); -#if 0 - Debug_PolygonBegin(NULL, 0); - Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1); - Debug_PolygonVertex((v1[0] + v2[0]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, (v1[1] + v2[1]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1], (v1[2] + v2[2]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2], 0, 0, 1, 1, 0, 1); - Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1); - Debug_PolygonEnd(); -#endif + v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]); + v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]); l = VectorDistance2(v1, v2); // this length bias tries to make sense of square polygons, assuming they are meant to be upright if (v1[2] != v2[2]) @@ -10097,13 +10588,6 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta } VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start); VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end); -#if 0 - Debug_PolygonBegin(NULL, 0); - Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1); - Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 4, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 4, 0, 0, 0, 1, 0, 1); - Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1); - Debug_PolygonEnd(); -#endif // this calculates the right vector from the shortest edge // and the up vector from the edge midpoints VectorSubtract(shortest[0].v1, shortest[0].v2, right); @@ -10118,20 +10602,6 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta VectorNormalize(forward); CrossProduct(up, forward, newright); VectorNormalize(newright); -#if 0 - Debug_PolygonBegin(NULL, 0); - Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 8, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 8, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 8, 0, 0, 1, 0, 0, 1); - Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1); - Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1); - Debug_PolygonEnd(); -#endif -#if 0 - Debug_PolygonBegin(NULL, 0); - Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1); - Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1); - Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1); - Debug_PolygonEnd(); -#endif // rotate the quad around the up axis vector, this is made // especially easy by the fact we know the quad is flat, // so we only have to subtract the center position and @@ -10145,54 +10615,49 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta l = DotProduct(right, center); for (i = 0;i < 4;i++) { - v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i); + v1 = rsurface.batchvertex3f + 3*(j+i); f = DotProduct(right, v1) - l; - VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3); + VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_batchvertex3f + 3*(j+i)); } } - Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0); - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); } - rsurface.vertex3f = rsurface.array_deformedvertex3f; - rsurface.vertex3f_bufferobject = 0; - rsurface.vertex3f_bufferoffset = 0; - rsurface.svector3f = rsurface.array_deformedsvector3f; - rsurface.svector3f_bufferobject = 0; - rsurface.svector3f_bufferoffset = 0; - rsurface.tvector3f = rsurface.array_deformedtvector3f; - rsurface.tvector3f_bufferobject = 0; - rsurface.tvector3f_bufferoffset = 0; - rsurface.normal3f = rsurface.array_deformednormal3f; - rsurface.normal3f_bufferobject = 0; - rsurface.normal3f_bufferoffset = 0; + Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true); + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true); + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; break; case Q3DEFORM_NORMAL: // deform the normals to make reflections wavey - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0;j < surface->num_vertices;j++) - { - float vertex[3]; - float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3; - VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex); - VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal); - normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); - normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); - normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); - VectorNormalize(normal); - } - Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0); + float vertex[3]; + float *normal = rsurface.array_batchnormal3f + 3*j; + VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex); + normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); + normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); + normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]); + VectorNormalize(normal); } - rsurface.svector3f = rsurface.array_deformedsvector3f; - rsurface.svector3f_bufferobject = 0; - rsurface.svector3f_bufferoffset = 0; - rsurface.tvector3f = rsurface.array_deformedtvector3f; - rsurface.tvector3f_bufferobject = 0; - rsurface.tvector3f_bufferoffset = 0; - rsurface.normal3f = rsurface.array_deformednormal3f; - rsurface.normal3f_bufferobject = 0; - rsurface.normal3f_bufferoffset = 0; + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true); + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; break; case Q3DEFORM_WAVE: // deform vertex array to make wavey water and flags and such @@ -10203,122 +10668,119 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta // this is how a divisor of vertex influence on deformation animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f; scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms); - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0;j < surface->num_vertices;j++) + // if the wavefunc depends on time, evaluate it per-vertex + if (waveparms[3]) { - float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3; - VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex); - // if the wavefunc depends on time, evaluate it per-vertex - if (waveparms[3]) - { - waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos; - scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms); - } - VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex); + waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos; + scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms); } + VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j); } - rsurface.vertex3f = rsurface.array_deformedvertex3f; - rsurface.vertex3f_bufferobject = 0; - rsurface.vertex3f_bufferoffset = 0; + Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true); + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true); + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; break; case Q3DEFORM_BULGE: // deform vertex array to make the surface have moving bulges - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0;j < surface->num_vertices;j++) - { - scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.scene.time * deform->parms[2])) * deform->parms[1]; - VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j)); - } + scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + r_refdef.scene.time * deform->parms[2]) * deform->parms[1]; + VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.array_batchvertex3f + 3*j); } - rsurface.vertex3f = rsurface.array_deformedvertex3f; - rsurface.vertex3f_bufferobject = 0; - rsurface.vertex3f_bufferoffset = 0; + Mod_BuildNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchnormal3f, true); + Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.array_batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.array_batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.array_batchsvector3f, rsurface.array_batchtvector3f, true); + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; + rsurface.batchsvector3f = rsurface.array_batchsvector3f; + rsurface.batchsvector3f_vertexbuffer = NULL; + rsurface.batchsvector3f_bufferoffset = 0; + rsurface.batchtvector3f = rsurface.array_batchtvector3f; + rsurface.batchtvector3f_vertexbuffer = NULL; + rsurface.batchtvector3f_bufferoffset = 0; + rsurface.batchnormal3f = rsurface.array_batchnormal3f; + rsurface.batchnormal3f_vertexbuffer = NULL; + rsurface.batchnormal3f_bufferoffset = 0; break; case Q3DEFORM_MOVE: // deform vertex array scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms); VectorScale(deform->parms, scale, waveparms); - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0;j < surface->num_vertices;j++) - VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j)); - } - rsurface.vertex3f = rsurface.array_deformedvertex3f; - rsurface.vertex3f_bufferobject = 0; - rsurface.vertex3f_bufferoffset = 0; + for (j = 0;j < rsurface.batchnumvertices;j++) + VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.array_batchvertex3f + 3*j); + rsurface.batchvertex3f = rsurface.array_batchvertex3f; + rsurface.batchvertex3f_vertexbuffer = NULL; + rsurface.batchvertex3f_bufferoffset = 0; break; } } + // generate texcoords based on the chosen texcoord source switch(rsurface.texture->tcgen.tcgen) { default: case Q3TCGEN_TEXTURE: - rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f; - rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject; - rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset; break; case Q3TCGEN_LIGHTMAP: - rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f; - rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject; - rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset; + if (rsurface.batchtexcoordlightmap2f) + memcpy(rsurface.array_batchtexcoordlightmap2f, rsurface.batchtexcoordtexture2f, rsurface.batchnumvertices * sizeof(float[2])); + rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; break; case Q3TCGEN_VECTOR: - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, out_tc += 2) - { - out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms); - out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3); - } + rsurface.array_batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms); + rsurface.array_batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->tcgen.parms + 3); } - rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f; - rsurface.texcoordtexture2f_bufferobject = 0; - rsurface.texcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; break; case Q3TCGEN_ENVIRONMENT: // make environment reflections using a spheremap - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex; - const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex; - float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex; - for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2) - { - // identical to Q3A's method, but executed in worldspace so - // carried models can be shiny too + // identical to Q3A's method, but executed in worldspace so + // carried models can be shiny too - float viewer[3], d, reflected[3], worldreflected[3]; + float viewer[3], d, reflected[3], worldreflected[3]; - VectorSubtract(rsurface.localvieworigin, vertex, viewer); - // VectorNormalize(viewer); + VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer); + // VectorNormalize(viewer); - d = DotProduct(normal, viewer); + d = DotProduct(rsurface.batchnormal3f + 3*j, viewer); - reflected[0] = normal[0]*2*d - viewer[0]; - reflected[1] = normal[1]*2*d - viewer[1]; - reflected[2] = normal[2]*2*d - viewer[2]; - // note: this is proportinal to viewer, so we can normalize later + reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0]; + reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1]; + reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2]; + // note: this is proportinal to viewer, so we can normalize later - Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected); - VectorNormalize(worldreflected); + Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected); + VectorNormalize(worldreflected); - // note: this sphere map only uses world x and z! - // so positive and negative y will LOOK THE SAME. - out_tc[0] = 0.5 + 0.5 * worldreflected[1]; - out_tc[1] = 0.5 - 0.5 * worldreflected[2]; - } + // note: this sphere map only uses world x and z! + // so positive and negative y will LOOK THE SAME. + rsurface.array_batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1]; + rsurface.array_batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2]; } - rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f; - rsurface.texcoordtexture2f_bufferobject = 0; - rsurface.texcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; break; } // the only tcmod that needs software vertex processing is turbulent, so @@ -10330,116 +10792,86 @@ void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generateta { amplitude = rsurface.texture->tcmods[0].parms[1]; animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.scene.time * rsurface.texture->tcmods[0].parms[3]; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (j = 0;j < rsurface.batchnumvertices;j++) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, in_tc = rsurface.texcoordtexture2f + 2 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, in_tc += 2, out_tc += 2) - { - out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2); - out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2); - } + rsurface.array_batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2); + rsurface.array_batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2); } - rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f; - rsurface.texcoordtexture2f_bufferobject = 0; - rsurface.texcoordtexture2f_bufferoffset = 0; + rsurface.batchtexcoordtexture2f = rsurface.array_batchtexcoordtexture2f; + rsurface.batchtexcoordtexture2f_vertexbuffer = NULL; + rsurface.batchtexcoordtexture2f_bufferoffset = 0; } - rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f; - rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject; - rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset; - R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); -} -void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist) -{ - int i, j; - const msurface_t *surface = texturesurfacelist[0]; - const msurface_t *surface2; - int firstvertex; - int endvertex; - int numvertices; - int numtriangles; - // TODO: lock all array ranges before render, rather than on each surface - if (texturenumsurfaces == 1) - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - else if (r_batchmode.integer == 2) + if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) { - #define MAXBATCHTRIANGLES 65536 - int batchtriangles = 0; - static int batchelements[MAXBATCHTRIANGLES*3]; - for (i = 0;i < texturenumsurfaces;i = j) + // convert the modified arrays to vertex structs + rsurface.batchvertexmesh = rsurface.array_batchvertexmesh; + rsurface.batchvertexmeshbuffer = NULL; + if (batchneed & BATCHNEED_VERTEXMESH_VERTEX) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) + VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f); + if (batchneed & BATCHNEED_VERTEXMESH_NORMAL) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) + VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f); + if (batchneed & BATCHNEED_VERTEXMESH_VECTOR) { - surface = texturesurfacelist[i]; - j = i + 1; - if (surface->num_triangles > MAXBATCHTRIANGLES) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) { - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - continue; - } - memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3])); - batchtriangles = surface->num_triangles; - firstvertex = surface->num_firstvertex; - endvertex = surface->num_firstvertex + surface->num_vertices; - for (;j < texturenumsurfaces;j++) - { - surface2 = texturesurfacelist[j]; - if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES) - break; - memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3])); - batchtriangles += surface2->num_triangles; - firstvertex = min(firstvertex, surface2->num_firstvertex); - endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices); + VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f); + VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f); } - surface2 = texturesurfacelist[j-1]; - numvertices = endvertex - firstvertex; - R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0); } + if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) + Vector4Scale(rsurface.batchlightmapcolor4f + 4*j, 255.0f, vertexmesh->color4ub); + if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) + Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f); + if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f) + for (j = 0, vertexmesh = rsurface.array_batchvertexmesh;j < rsurface.batchnumvertices;j++, vertexmesh++) + Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f); } - else if (r_batchmode.integer == 1) - { - for (i = 0;i < texturenumsurfaces;i = j) - { - surface = texturesurfacelist[i]; - for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++) - if (texturesurfacelist[j] != surface2) - break; - surface2 = texturesurfacelist[j-1]; - numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex; - numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle; - R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } - } - else + + if (needsupdate & batchneed & BATCHNEED_VERTEXPOSITION) { - for (i = 0;i < texturenumsurfaces;i++) - { - surface = texturesurfacelist[i]; - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } + // convert the modified arrays to vertex structs + rsurface.batchvertexposition = rsurface.array_batchvertexposition; + rsurface.batchvertexpositionbuffer = NULL; + if (sizeof(r_vertexposition_t) == sizeof(float[3])) + memcpy(rsurface.array_batchvertexposition, rsurface.batchvertex3f, rsurface.batchnumvertices * sizeof(r_vertexposition_t)); + else + for (j = 0, vertexposition = rsurface.array_batchvertexposition;j < rsurface.batchnumvertices;j++, vertexposition++) + VectorCopy(rsurface.batchvertex3f + 3*j, vertexposition->vertex3f); } } -static void RSurf_BindLightmapForSurface(const msurface_t *surface) +void RSurf_DrawBatch(void) +{ + R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset); +} + +static void RSurf_BindLightmapForBatch(void) { switch(vid.renderpath) { case RENDERPATH_CGGL: #ifdef SUPPORTCG - if (r_cg_permutation->fp_Texture_Lightmap ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap , surface->lightmaptexture );CHECKCGERROR - if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, surface->deluxemaptexture);CHECKCGERROR + if (r_cg_permutation->fp_Texture_Lightmap ) CG_BindTexture(r_cg_permutation->fp_Texture_Lightmap , rsurface.lightmaptexture );CHECKCGERROR + if (r_cg_permutation->fp_Texture_Deluxemap) CG_BindTexture(r_cg_permutation->fp_Texture_Deluxemap, rsurface.deluxemaptexture);CHECKCGERROR #endif break; case RENDERPATH_GL20: - if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , surface->lightmaptexture ); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, surface->deluxemaptexture); + if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(GL20TU_LIGHTMAP , rsurface.lightmaptexture ); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(GL20TU_DELUXEMAP, rsurface.deluxemaptexture); break; case RENDERPATH_GL13: case RENDERPATH_GL11: - R_Mesh_TexBind(0, surface->lightmaptexture); + R_Mesh_TexBind(0, rsurface.lightmaptexture); break; } } -static void RSurf_BindReflectionForSurface(const msurface_t *surface) +static void RSurf_BindReflectionForBatch(void) { // pick the closest matching water plane and bind textures int planeindex, vertexindex; @@ -10454,7 +10886,7 @@ static void RSurf_BindReflectionForSurface(const msurface_t *surface) if(p->camera_entity != rsurface.texture->camera_entity) continue; d = 0; - for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3) + for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3) { Matrix4x4_Transform(&rsurface.matrix, v, vert); d += fabs(PlaneDiff(vert, &p->plane)); @@ -10485,376 +10917,170 @@ static void RSurf_BindReflectionForSurface(const msurface_t *surface) } } -static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist) +static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(void) { int i; - const msurface_t *surface; - if (r_waterstate.renderingscene) - return; - for (i = 0;i < texturenumsurfaces;i++) - { - surface = texturesurfacelist[i]; - RSurf_BindLightmapForSurface(surface); - RSurf_BindReflectionForSurface(surface); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } + for (i = 0;i < rsurface.batchnumvertices;i++) + Vector4Set(rsurface.array_passcolor4f + 4*i, 0.5f, 0.5f, 0.5f, 1.0f); + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } -static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, const msurface_t **texturesurfacelist) +static void RSurf_DrawBatch_GL11_ApplyFog(void) { - int i; - int j; - const msurface_t *surface = texturesurfacelist[0]; - const msurface_t *surface2; - int firstvertex; - int endvertex; - int numvertices; - int numtriangles; - if (texturenumsurfaces == 1) - { - RSurf_BindLightmapForSurface(surface); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } - else if (r_batchmode.integer == 2) - { - int batchtriangles = 0; - static int batchelements[MAXBATCHTRIANGLES*3]; - for (i = 0;i < texturenumsurfaces;i = j) - { - surface = texturesurfacelist[i]; - RSurf_BindLightmapForSurface(surface); - j = i + 1; - if (surface->num_triangles > MAXBATCHTRIANGLES) - { - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - continue; - } - memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3])); - batchtriangles = surface->num_triangles; - firstvertex = surface->num_firstvertex; - endvertex = surface->num_firstvertex + surface->num_vertices; - for (;j < texturenumsurfaces;j++) - { - surface2 = texturesurfacelist[j]; - if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES) - break; - memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3])); - batchtriangles += surface2->num_triangles; - firstvertex = min(firstvertex, surface2->num_firstvertex); - endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices); - } - surface2 = texturesurfacelist[j-1]; - numvertices = endvertex - firstvertex; - R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0); - } - } - else if (r_batchmode.integer == 1) - { -#if 0 - Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name); - for (i = 0;i < texturenumsurfaces;i = j) - { - surface = texturesurfacelist[i]; - for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++) - if (texturesurfacelist[j] != surface2) - break; - Con_Printf(" %i", j - i); - } - Con_Printf("\n"); - Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name); -#endif - for (i = 0;i < texturenumsurfaces;i = j) - { - surface = texturesurfacelist[i]; - RSurf_BindLightmapForSurface(surface); - for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++) - if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture) - break; -#if 0 - Con_Printf(" %i", j - i); -#endif - surface2 = texturesurfacelist[j-1]; - numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex; - numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle; - R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } -#if 0 - Con_Printf("\n"); -#endif - } - else - { - for (i = 0;i < texturenumsurfaces;i++) - { - surface = texturesurfacelist[i]; - RSurf_BindLightmapForSurface(surface); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } - } -} - -static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist) -{ - int j; - int texturesurfaceindex; - if (r_showsurfaces.integer == 2) - { - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (j = 0;j < surface->num_triangles;j++) - { - float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_refdef.view.colorscale; - GL_Color(f, f, f, 1); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle + j, 1, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } - } - } - else - { - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - int k = (int)(((size_t)surface) / sizeof(msurface_t)); - GL_Color((k & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, 1); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); - } - } -} - -static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, const msurface_t **texturesurfacelist) -{ - int texturesurfaceindex; - int i; - const float *v; - float *c2; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4) - { - c2[0] = 0.5; - c2[1] = 0.5; - c2[2] = 0.5; - c2[3] = 1; - } - } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; -} - -static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, const msurface_t **texturesurfacelist) -{ - int texturesurfaceindex; int i; float f; const float *v; const float *c; float *c2; - if (rsurface.lightmapcolor4f) + if (rsurface.passcolor4f) { - // generate color arrays for the surfaces in this list - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + // generate color arrays + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4) - { - f = RSurf_FogVertex(v); - c2[0] = c[0] * f; - c2[1] = c[1] * f; - c2[2] = c[2] * f; - c2[3] = c[3]; - } + f = RSurf_FogVertex(v); + c2[0] = c[0] * f; + c2[1] = c[1] * f; + c2[2] = c[2] * f; + c2[3] = c[3]; } } else { - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c2 += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4) - { - f = RSurf_FogVertex(v); - c2[0] = f; - c2[1] = f; - c2[2] = f; - c2[3] = 1; - } + f = RSurf_FogVertex(v); + c2[0] = f; + c2[1] = f; + c2[2] = f; + c2[3] = 1; } } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } -static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, const msurface_t **texturesurfacelist) +static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(void) { - int texturesurfaceindex; int i; float f; const float *v; const float *c; float *c2; - if (!rsurface.lightmapcolor4f) + if (!rsurface.passcolor4f) return; - // generate color arrays for the surfaces in this list - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4, c2 += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4) - { - f = RSurf_FogVertex(v); - c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f); - c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f); - c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f); - c2[3] = c[3]; - } + f = RSurf_FogVertex(v); + c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f); + c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f); + c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f); + c2[3] = c[3]; } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } -static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a) +static void RSurf_DrawBatch_GL11_ApplyColor(float r, float g, float b, float a) { - int texturesurfaceindex; int i; const float *c; float *c2; - if (!rsurface.lightmapcolor4f) + if (!rsurface.passcolor4f) return; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (i = 0, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4) - { - c2[0] = c[0] * r; - c2[1] = c[1] * g; - c2[2] = c[2] * b; - c2[3] = c[3] * a; - } + c2[0] = c[0] * r; + c2[1] = c[1] * g; + c2[2] = c[2] * b; + c2[3] = c[3] * a; } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } -static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, const msurface_t **texturesurfacelist) +static void RSurf_DrawBatch_GL11_ApplyAmbient(void) { - int texturesurfaceindex; int i; const float *c; float *c2; - if (!rsurface.lightmapcolor4f) + if (!rsurface.passcolor4f) return; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + for (i = 0, c = rsurface.passcolor4f + rsurface.batchfirstvertex * 4, c2 = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, c += 4, c2 += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4) - { - c2[0] = c[0] + r_refdef.scene.ambient; - c2[1] = c[1] + r_refdef.scene.ambient; - c2[2] = c[2] + r_refdef.scene.ambient; - c2[3] = c[3]; - } + c2[0] = c[0] + r_refdef.scene.ambient; + c2[1] = c[1] + r_refdef.scene.ambient; + c2[2] = c[2] + r_refdef.scene.ambient; + c2[3] = c[3]; } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } -static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +static void RSurf_DrawBatch_GL11_Lightmap(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) { // TODO: optimize - rsurface.lightmapcolor4f = NULL; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; - if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist); - if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a); - R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); GL_Color(r, g, b, a); - RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist); + RSurf_BindLightmapForBatch(); + RSurf_DrawBatch(); } -static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +static void RSurf_DrawBatch_GL11_Unlit(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) { // TODO: optimize applyfog && applycolor case // just apply fog if necessary, and tint the fog color array if necessary - rsurface.lightmapcolor4f = NULL; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; - if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist); - if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a); - R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); GL_Color(r, g, b, a); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch(); } -static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +static void RSurf_DrawBatch_GL11_VertexColor(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) { - int texturesurfaceindex; - int i; - float *c; // TODO: optimize - if (texturesurfacelist[0]->lightmapinfo) - { - // generate color arrays for the surfaces in this list - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4) - { - if (surface->lightmapinfo->samples) - { - const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i]; - float scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f); - VectorScale(lm, scale, c); - if (surface->lightmapinfo->styles[1] != 255) - { - int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3; - lm += size3; - scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f); - VectorMA(c, scale, lm, c); - if (surface->lightmapinfo->styles[2] != 255) - { - lm += size3; - scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f); - VectorMA(c, scale, lm, c); - if (surface->lightmapinfo->styles[3] != 255) - { - lm += size3; - scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f); - VectorMA(c, scale, lm, c); - } - } - } - } - else - VectorClear(c); - c[3] = 1; - } - } - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; - } - else + rsurface.passcolor4f = rsurface.batchlightmapcolor4f; + rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer; + rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset; + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); + GL_Color(r, g, b, a); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_ClampColor(void) +{ + int i; + const float *c1; + float *c2; + if (!rsurface.passcolor4f) + return; + for (i = 0, c1 = rsurface.passcolor4f + 4*rsurface.batchfirstvertex, c2 = rsurface.array_passcolor4f + 4*rsurface.batchfirstvertex;i < rsurface.batchnumvertices;i++, c1 += 4, c2 += 4) { - rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f; - rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject; - rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; + c2[0] = bound(0.0f, c1[0], 1.0f); + c2[1] = bound(0.0f, c1[1], 1.0f); + c2[2] = bound(0.0f, c1[2], 1.0f); + c2[3] = bound(0.0f, c1[3], 1.0f); } - if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist); - if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a); - R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); - GL_Color(r, g, b, a); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } -static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor) +static void RSurf_DrawBatch_GL11_ApplyVertexShade(float *r, float *g, float *b, float *a, qboolean *applycolor) { - int texturesurfaceindex; int i; float f; float alpha; @@ -10875,33 +11101,24 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, const diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f; diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f; alpha = *a; - if (VectorLength2(diffusecolor) > 0 && rsurface.normal3f) + if (VectorLength2(diffusecolor) > 0) { - // generate color arrays for the surfaces in this list - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + // q3-style directional shading + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, n = rsurface.batchnormal3f + rsurface.batchfirstvertex * 3, c = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, n += 3, c += 4) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - int numverts = surface->num_vertices; - v = rsurface.vertex3f + 3 * surface->num_firstvertex; - n = rsurface.normal3f + 3 * surface->num_firstvertex; - c = rsurface.array_color4f + 4 * surface->num_firstvertex; - // q3-style directional shading - for (i = 0;i < numverts;i++, v += 3, n += 3, c += 4) - { - if ((f = DotProduct(n, lightdir)) > 0) - VectorMA(ambientcolor, f, diffusecolor, c); - else - VectorCopy(ambientcolor, c); - c[3] = alpha; - } + if ((f = DotProduct(n, lightdir)) > 0) + VectorMA(ambientcolor, f, diffusecolor, c); + else + VectorCopy(ambientcolor, c); + c[3] = alpha; } *r = 1; *g = 1; *b = 1; *a = 1; - rsurface.lightmapcolor4f = rsurface.array_color4f; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = rsurface.array_passcolor4f; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; *applycolor = false; } else @@ -10909,20 +11126,36 @@ static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, const *r = ambientcolor[0]; *g = ambientcolor[1]; *b = ambientcolor[2]; - rsurface.lightmapcolor4f = NULL; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; } } -static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, const msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) +static void RSurf_DrawBatch_GL11_VertexShade(float r, float g, float b, float a, qboolean applycolor, qboolean applyfog) { - RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor); - if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist); - if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a); - R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); + RSurf_DrawBatch_GL11_ApplyVertexShade(&r, &g, &b, &a, &applycolor); + if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(); + if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(r, g, b, a); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, rsurface.passcolor4f_vertexbuffer, rsurface.passcolor4f_bufferoffset); GL_Color(r, g, b, a); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch(); +} + +static void RSurf_DrawBatch_GL11_MakeFogColor(float r, float g, float b, float a) +{ + int i; + float f; + const float *v; + float *c; + for (i = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3, c = rsurface.array_passcolor4f + rsurface.batchfirstvertex * 4;i < rsurface.batchnumvertices;i++, v += 3, c += 4) + { + f = 1 - RSurf_FogVertex(v); + c[0] = r; + c[1] = g; + c[2] = b; + c[3] = f * a; + } } void RSurf_SetupDepthAndCulling(void) @@ -10953,8 +11186,6 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_ // level, so don't use it then either. if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis) { - GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); if (skyrendermasked) { @@ -10964,15 +11195,19 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_ // just to make sure that braindead drivers don't draw // anything despite that colormask... GL_BlendFunc(GL_ZERO, GL_ONE); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer); } else { R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); // fog sky GL_BlendFunc(GL_ONE, GL_ZERO); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, texturenumsurfaces, texturesurfacelist); + GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); } - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch(); if (skyrendermasked) GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); } @@ -10986,50 +11221,50 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface { if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))) return; - RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); if (prepass) { // render screenspace normalmap to texture GL_DepthMask(true); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch(); } else if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)) && !r_waterstate.renderingscene) { // render water or distortion background, then blend surface on top GL_DepthMask(true); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND); - RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND, texturenumsurfaces, texturesurfacelist); + RSurf_BindReflectionForBatch(); + if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + RSurf_BindLightmapForBatch(); + RSurf_DrawBatch(); GL_DepthMask(false); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist); if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) - RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist); - else - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_BindLightmapForBatch(); + RSurf_DrawBatch(); } else { // render surface normally GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED)); - R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE); + R_SetupShader_Surface(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION) - RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist); - else if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) - RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist); - else - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_BindReflectionForBatch(); + if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + RSurf_BindLightmapForBatch(); + RSurf_DrawBatch(); } } static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) { // OpenGL 1.3 path - anything not completely ancient - int texturesurfaceindex; qboolean applycolor; qboolean applyfog; int layerindex; const texturelayer_t *layer; - RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++) { @@ -11064,7 +11299,7 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface } layercolor[3] = layer->color[3]; applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1; - R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0); applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED); switch (layer->type) { @@ -11073,27 +11308,27 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, r_texture_white); R_Mesh_TexMatrix(0, NULL); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); R_Mesh_TexBind(1, layer->texture); R_Mesh_TexMatrix(1, &layer->texmatrix); R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); - R_Mesh_TexCoordPointer(1, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) - RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + RSurf_DrawBatch_GL11_VertexShade(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); else if (rsurface.uselightmaptexture) - RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + RSurf_DrawBatch_GL11_Lightmap(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); else - RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + RSurf_DrawBatch_GL11_VertexColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); break; case TEXTURELAYERTYPE_TEXTURE: // singletexture unlit texture with transparency support R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); R_Mesh_TexBind(1, 0); - R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0); - RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); + RSurf_DrawBatch_GL11_Unlit(layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog); break; case TEXTURELAYERTYPE_FOG: // singletexture fogging @@ -11102,34 +11337,19 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, layertexrgbscale, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); } else { R_Mesh_TexBind(0, 0); - R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); } R_Mesh_TexBind(1, 0); - R_Mesh_TexCoordPointer(1, 2, NULL, 0, 0); + R_Mesh_TexCoordPointer(1, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); // generate a color array for the fog pass - R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0); - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - int i; - float f; - const float *v; - float *c; - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4) - { - f = 1 - RSurf_FogVertex(v); - c[0] = layercolor[0]; - c[1] = layercolor[1]; - c[2] = layercolor[2]; - c[3] = f * layercolor[3]; - } - } - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0); + RSurf_DrawBatch_GL11_MakeFogColor(layercolor[0], layercolor[1], layercolor[2], layercolor[3]); + RSurf_DrawBatch(); break; default: Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type); @@ -11146,11 +11366,11 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, const msurface static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) { // OpenGL 1.1 - crusty old voodoo path - int texturesurfaceindex; qboolean applyfog; int layerindex; const texturelayer_t *layer; - RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | ((!rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.modeltexcoordlightmap2f ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++) { @@ -11166,7 +11386,7 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface } GL_DepthMask(layer->depthmask && writedepth); GL_BlendFunc(layer->blendfunc1, layer->blendfunc2); - R_Mesh_ColorPointer(NULL, 0, 0); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), NULL, 0, 0); applyfog = r_refdef.fogenabled && (rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED); switch (layer->type) { @@ -11178,20 +11398,20 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, r_texture_white); R_Mesh_TexMatrix(0, NULL); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) - RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false); + RSurf_DrawBatch_GL11_VertexShade(1, 1, 1, 1, false, false); else if (rsurface.uselightmaptexture) - RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false); + RSurf_DrawBatch_GL11_Lightmap(1, 1, 1, 1, false, false); else - RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false); + RSurf_DrawBatch_GL11_VertexColor(1, 1, 1, 1, false, false); // then apply the texture to it GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR); R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + RSurf_DrawBatch_GL11_Unlit(layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false); } else { @@ -11199,11 +11419,11 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) - RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + RSurf_DrawBatch_GL11_VertexShade(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); else - RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + RSurf_DrawBatch_GL11_VertexColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); } break; case TEXTURELAYERTYPE_TEXTURE: @@ -11211,8 +11431,8 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); - RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); + RSurf_DrawBatch_GL11_Unlit(layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog); break; case TEXTURELAYERTYPE_FOG: // singletexture fogging @@ -11221,32 +11441,17 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface R_Mesh_TexBind(0, layer->texture); R_Mesh_TexMatrix(0, &layer->texmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); } else { R_Mesh_TexBind(0, 0); - R_Mesh_TexCoordPointer(0, 2, NULL, 0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), NULL, 0, 0); } // generate a color array for the fog pass - R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0); - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) - { - int i; - float f; - const float *v; - float *c; - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4) - { - f = 1 - RSurf_FogVertex(v); - c[0] = layer->color[0]; - c[1] = layer->color[1]; - c[2] = layer->color[2]; - c[3] = f * layer->color[3]; - } - } - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0); + RSurf_DrawBatch_GL11_MakeFogColor(layer->color[0], layer->color[1], layer->color[2], layer->color[3]); + RSurf_DrawBatch(); break; default: Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type); @@ -11260,12 +11465,14 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, const msurface } } -static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) +static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth) { + int vi; + int j; + r_vertexgeneric_t *batchvertex; float c[4]; GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); @@ -11323,55 +11530,127 @@ static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, const GL_DepthMask(writedepth); } - rsurface.lightmapcolor4f = NULL; - - if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + if (r_showsurfaces.integer == 3) { - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + rsurface.passcolor4f = NULL; - rsurface.lightmapcolor4f = NULL; - rsurface.lightmapcolor4f_bufferobject = 0; - rsurface.lightmapcolor4f_bufferoffset = 0; - } - else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) - { - qboolean applycolor = true; - float one = 1.0; + if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); - RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist); + rsurface.passcolor4f = NULL; + rsurface.passcolor4f_vertexbuffer = 0; + rsurface.passcolor4f_bufferoffset = 0; + } + else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) + { + qboolean applycolor = true; + float one = 1.0; - r_refdef.lightmapintensity = 1; - RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor); - r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all - } - else - { - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); - rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f; - rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject; - rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset; - } + r_refdef.lightmapintensity = 1; + RSurf_DrawBatch_GL11_ApplyVertexShade(&one, &one, &one, &one, &applycolor); + r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all + } + else + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); - if(!rsurface.lightmapcolor4f) - RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist); + rsurface.passcolor4f = rsurface.batchlightmapcolor4f; + rsurface.passcolor4f_vertexbuffer = rsurface.batchlightmapcolor4f_vertexbuffer; + rsurface.passcolor4f_bufferoffset = rsurface.batchlightmapcolor4f_bufferoffset; + } + + if(!rsurface.passcolor4f) + RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(); - RSurf_DrawBatch_GL11_ApplyAmbient(texturenumsurfaces, texturesurfacelist); - RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, c[0], c[1], c[2], c[3]); - if(r_refdef.fogenabled) - RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(texturenumsurfaces, texturesurfacelist); + RSurf_DrawBatch_GL11_ApplyAmbient(); + RSurf_DrawBatch_GL11_ApplyColor(c[0], c[1], c[2], c[3]); + if(r_refdef.fogenabled) + RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(); + RSurf_DrawBatch_GL11_ClampColor(); - R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.passcolor4f, NULL); + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); + RSurf_DrawBatch(); + } + else if (!r_refdef.view.showdebug) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); + for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++) + { + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Set(batchvertex[vi].color4ub, 0, 0, 0, 255); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } + else if (r_showsurfaces.integer == 4) + { + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices); + for (j = 0, vi = rsurface.batchfirstvertex;j < rsurface.batchnumvertices;j++, vi++) + { + unsigned char c = vi << 3; + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Set(batchvertex[vi].color4ub, c, c, c, 255); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } + else if (r_showsurfaces.integer == 2) + { + const int *e; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles); + for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3) + { + unsigned char c = (j + rsurface.batchfirsttriangle) << 3; + VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f); + VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f); + VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f); + Vector4Set(batchvertex[j*3+0].color4ub, c, c, c, 255); + Vector4Set(batchvertex[j*3+1].color4ub, c, c, c, 255); + Vector4Set(batchvertex[j*3+2].color4ub, c, c, c, 255); + } + R_Mesh_PrepareVertices_Generic_Unlock(); + R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0); + } + else + { + int texturesurfaceindex; + int k; + const msurface_t *surface; + unsigned char surfacecolor4ub[4]; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices); + vi = 0; + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + surface = texturesurfacelist[texturesurfaceindex]; + k = (int)(((size_t)surface) / sizeof(msurface_t)); + Vector4Set(surfacecolor4ub, (k & 0xF) << 4, (k & 0xF0), (k & 0xF00) >> 4, 255); + for (j = 0;j < surface->num_vertices;j++) + { + VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f); + Vector4Copy(surfacecolor4ub, batchvertex[vi].color4ub); + vi++; + } + } + R_Mesh_PrepareVertices_Generic_Unlock(); + RSurf_DrawBatch(); + } } static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass) { CHECKGLERROR RSurf_SetupDepthAndCulling(); - if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)) + if (r_showsurfaces.integer) { - R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth); return; } switch (vid.renderpath) @@ -11394,9 +11673,9 @@ static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface { CHECKGLERROR RSurf_SetupDepthAndCulling(); - if (r_showsurfaces.integer == 3 && !prepass && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)) + if (r_showsurfaces.integer) { - R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth); + R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth); return; } switch (vid.renderpath) @@ -11455,7 +11734,9 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const surface = rsurface.modelsurfaces + surfacelist[i]; texture = surface->texture; rsurface.texture = R_GetCurrentTexture(texture); - rsurface.uselightmaptexture = surface->lightmaptexture != NULL; + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; + rsurface.uselightmaptexture = false; // scan ahead until we find a different texture endsurface = min(i + 1024, numsurfaces); texturenumsurfaces = 0; @@ -11463,7 +11744,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const for (;j < endsurface;j++) { surface = rsurface.modelsurfaces + surfacelist[j]; - if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL)) + if (texture != surface->texture) break; texturesurfacelist[texturenumsurfaces++] = surface; } @@ -11479,13 +11760,13 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_DepthOrShadow(); } RSurf_SetupDepthAndCulling(); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer); + RSurf_DrawBatch(); } if (setup) GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1); @@ -11497,6 +11778,8 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const surface = rsurface.modelsurfaces + surfacelist[i]; texture = surface->texture; rsurface.texture = R_GetCurrentTexture(texture); + rsurface.lightmaptexture = surface->lightmaptexture; + rsurface.deluxemaptexture = surface->deluxemaptexture; rsurface.uselightmaptexture = surface->lightmaptexture != NULL; // scan ahead until we find a different texture endsurface = min(i + MAXBATCH_TRANSPARENTSURFACES, numsurfaces); @@ -11505,7 +11788,7 @@ static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const for (;j < endsurface;j++) { surface = rsurface.modelsurfaces + surfacelist[j]; - if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL)) + if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture) break; texturesurfacelist[texturenumsurfaces++] = surface; } @@ -11542,20 +11825,24 @@ static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const } } +static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist) +{ + if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) + return; + if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) + return; + RSurf_SetupDepthAndCulling(); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer); + RSurf_DrawBatch(); +} + static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass) { const entity_render_t *queueentity = r_refdef.scene.worldentity; CHECKGLERROR if (depthonly) - { - if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) - return; - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) - return; - RSurf_SetupDepthAndCulling(); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); - } + R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist); else if (prepass) { if (!rsurface.texture->currentnumlayers) @@ -11565,34 +11852,7 @@ static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, const msurf else R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); } - else if (r_showsurfaces.integer && !r_refdef.view.showdebug && !prepass) - { - RSurf_SetupDepthAndCulling(); - GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - GL_DepthMask(true); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_Color(0, 0, 0, 1); - GL_DepthTest(writedepth); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); - } - else if (r_showsurfaces.integer && r_showsurfaces.integer != 3 && !prepass) - { - RSurf_SetupDepthAndCulling(); - GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - GL_DepthMask(true); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthTest(true); - RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); - } - else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) + else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && !r_showsurfaces.integer) R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (!rsurface.texture->currentnumlayers) return; @@ -11624,6 +11884,8 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in // use skin 1 instead) texture = surfacelist[i]->texture; rsurface.texture = R_GetCurrentTexture(texture); + rsurface.lightmaptexture = surfacelist[i]->lightmaptexture; + rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture; rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass; if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) { @@ -11633,7 +11895,7 @@ void R_QueueWorldSurfaceList(int numsurfaces, const msurface_t **surfacelist, in continue; } // simply scan ahead until we find a different texture or lightmap state - for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++) ; // render the range of surfaces R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass); @@ -11644,15 +11906,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf { CHECKGLERROR if (depthonly) - { - if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST))) - return; - if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))) - return; - RSurf_SetupDepthAndCulling(); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); - } + R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist); else if (prepass) { if (!rsurface.texture->currentnumlayers) @@ -11662,34 +11916,7 @@ static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurf else R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass); } - else if (r_showsurfaces.integer && !r_refdef.view.showdebug) - { - RSurf_SetupDepthAndCulling(); - GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - GL_DepthMask(true); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_Color(0, 0, 0, 1); - GL_DepthTest(writedepth); - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); - } - else if (r_showsurfaces.integer && r_showsurfaces.integer != 3) - { - RSurf_SetupDepthAndCulling(); - GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); - RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist); - GL_DepthMask(true); - GL_BlendFunc(GL_ONE, GL_ZERO); - GL_DepthTest(true); - RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist); - } - else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) + else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && !r_showsurfaces.integer) R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist); else if (!rsurface.texture->currentnumlayers) return; @@ -11721,6 +11948,8 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa // use skin 1 instead) texture = surfacelist[i]->texture; rsurface.texture = R_GetCurrentTexture(texture); + rsurface.lightmaptexture = surfacelist[i]->lightmaptexture; + rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture; rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL && !depthonly && !prepass; if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)) { @@ -11730,7 +11959,7 @@ void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurfa continue; } // simply scan ahead until we find a different texture or lightmap state - for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++) + for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++) ; // render the range of surfaces R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent, prepass); @@ -11772,10 +12001,7 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in GL_CullFace(GL_NONE); R_EntityMatrix(&identitymatrix); - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); i = surfacelist[0]; GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale, @@ -11798,7 +12024,9 @@ void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, in for (j = 0;j < 3;j++, i++) vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i]; - R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, locboxelements, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL); + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); + R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0); } void R_DrawLocs(void) @@ -12317,12 +12545,12 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) t2f[5] = decal->texcoord2f[2][1]; // update vertex positions for animated models - if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnum_triangles) + if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles) { e = rsurface.modelelement3i + 3*decal->triangleindex; - VectorCopy(rsurface.vertex3f + 3*e[0], v3f); - VectorCopy(rsurface.vertex3f + 3*e[1], v3f + 3); - VectorCopy(rsurface.vertex3f + 3*e[2], v3f + 6); + VectorCopy(rsurface.modelvertexposition[e[0]].vertex3f, v3f); + VectorCopy(rsurface.modelvertexposition[e[1]].vertex3f, v3f + 3); + VectorCopy(rsurface.modelvertexposition[e[2]].vertex3f, v3f + 6); } else { @@ -12355,9 +12583,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) // (this assumes they all use one particle font texture!) RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, rsurface.ent_shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false); R_Mesh_ResetTextureState(); - R_Mesh_VertexPointer(decalsystem->vertex3f, 0, 0); - R_Mesh_TexCoordPointer(0, 2, decalsystem->texcoord2f, 0, 0); - R_Mesh_ColorPointer(decalsystem->color4f, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f); GL_DepthMask(false); GL_DepthRange(0, 1); GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value); @@ -12365,7 +12591,7 @@ static void R_DrawModelDecals_Entity(entity_render_t *ent) GL_CullFace(GL_NONE); GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1); - R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, decalsystem->element3s, 0, 0); + R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0); } } @@ -12416,7 +12642,6 @@ void R_DrawDebugModel(void) flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL; - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); GL_DepthRange(0, 1); @@ -12445,9 +12670,9 @@ void R_DrawDebugModel(void) brush = model->brush.data_brushes + bihleaf->itemindex; if (brush->colbrushf && brush->colbrushf->numtriangles) { - R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0); GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); - R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL); + R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0); } break; case BIH_COLLISIONTRIANGLE: @@ -12455,18 +12680,18 @@ void R_DrawDebugModel(void) VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]); VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]); VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]); - R_Mesh_VertexPointer(vertex3f[0], 0, 0); GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); - R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); break; case BIH_RENDERTRIANGLE: triangleindex = bihleaf->itemindex; VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]); VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]); VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]); - R_Mesh_VertexPointer(vertex3f[0], 0, 0); GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value); - R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL); + R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); break; } } @@ -12493,7 +12718,7 @@ void R_DrawDebugModel(void) rsurface.texture = R_GetCurrentTexture(surface->texture); if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles) { - RSurf_PrepareVerticesForBatch(true, true, 1, &surface); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface); if (r_showtris.value > 0) { if (!rsurface.texture->currentlayers->depthmask) @@ -12502,12 +12727,9 @@ void R_DrawDebugModel(void) GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value); else GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value); - R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - //R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, model->surfmesh.data_element3i, NULL, 0, 0); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject); + RSurf_DrawBatch(); qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); CHECKGLERROR } @@ -12516,25 +12738,25 @@ void R_DrawDebugModel(void) qglBegin(GL_LINES); for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { - VectorCopy(rsurface.vertex3f + l * 3, v); + VectorCopy(rsurface.batchvertex3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 0, 0, 1); qglVertex3f(v[0], v[1], v[2]); - VectorMA(v, -r_shownormals.value, rsurface.svector3f + l * 3, v); + VectorMA(v, -r_shownormals.value, rsurface.batchsvector3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 1, 1, 1); qglVertex3f(v[0], v[1], v[2]); } qglEnd(); CHECKGLERROR } - if (r_shownormals.value > 0) + if (r_shownormals.value > 0 && rsurface.batchsvector3f) { qglBegin(GL_LINES); for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { - VectorCopy(rsurface.vertex3f + l * 3, v); + VectorCopy(rsurface.batchvertex3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 0, 0, 1); qglVertex3f(v[0], v[1], v[2]); - VectorMA(v, r_shownormals.value, rsurface.svector3f + l * 3, v); + VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 1, 1, 1); qglVertex3f(v[0], v[1], v[2]); } @@ -12543,10 +12765,10 @@ void R_DrawDebugModel(void) qglBegin(GL_LINES); for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { - VectorCopy(rsurface.vertex3f + l * 3, v); + VectorCopy(rsurface.batchvertex3f + l * 3, v); GL_Color(0, r_refdef.view.colorscale, 0, 1); qglVertex3f(v[0], v[1], v[2]); - VectorMA(v, r_shownormals.value, rsurface.tvector3f + l * 3, v); + VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 1, 1, 1); qglVertex3f(v[0], v[1], v[2]); } @@ -12555,10 +12777,10 @@ void R_DrawDebugModel(void) qglBegin(GL_LINES); for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++) { - VectorCopy(rsurface.vertex3f + l * 3, v); + VectorCopy(rsurface.batchvertex3f + l * 3, v); GL_Color(0, 0, r_refdef.view.colorscale, 1); qglVertex3f(v[0], v[1], v[2]); - VectorMA(v, r_shownormals.value, rsurface.normal3f + l * 3, v); + VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v); GL_Color(r_refdef.view.colorscale, 1, 1, 1); qglVertex3f(v[0], v[1], v[2]); } @@ -12622,6 +12844,8 @@ void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean dep return; } + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; rsurface.uselightmaptexture = false; rsurface.texture = NULL; rsurface.rtlight = NULL; @@ -12752,6 +12976,8 @@ void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean wr return; } + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; rsurface.uselightmaptexture = false; rsurface.texture = NULL; rsurface.rtlight = NULL; @@ -12821,6 +13047,8 @@ void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, i // now render it rsurface.texture = R_GetCurrentTexture(surface.texture); + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; rsurface.uselightmaptexture = false; R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass); } @@ -12840,6 +13068,8 @@ void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatri // now render it rsurface.texture = R_GetCurrentTexture(surface.texture); + rsurface.lightmaptexture = NULL; + rsurface.deluxemaptexture = NULL; rsurface.uselightmaptexture = false; R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass); } diff --git a/gl_rsurf.c b/gl_rsurf.c index 554fb0fa..374d8587 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -349,10 +349,7 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r numpoints = min(portal->numpoints, POLYGONELEMENTS_MAXPOINTS); - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); isvis = (portal->here->clusterindex >= 0 && portal->past->clusterindex >= 0 && portal->here->clusterindex != portal->past->clusterindex); @@ -363,7 +360,9 @@ static void R_DrawPortal_Callback(const entity_render_t *ent, const rtlight_t *r isvis ? 0.125f : 0.03125f); for (i = 0, v = vertex3f;i < numpoints;i++, v += 3) VectorCopy(portal->points[i].position, v); - R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(numpoints, vertex3f, NULL, NULL); + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); + R_Mesh_Draw(0, numpoints, 0, numpoints - 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); } // LordHavoc: this is just a nice debugging tool, very slow @@ -611,7 +610,6 @@ void R_Q1BSP_DrawDepth(entity_render_t *ent) GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthMask(true); GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_DepthOrShadow(); if (ent == r_refdef.scene.worldentity) @@ -1086,10 +1084,10 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor rsurface.texture = R_GetCurrentTexture(surface->texture); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW) continue; - RSurf_PrepareVerticesForBatch(false, false, 1, &surface); - R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface); + R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.batchvertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs); } - R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.vertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs); + R_Shadow_VolumeFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.batchvertex3f, model->surfmesh.data_element3i, model->surfmesh.data_neighbor3i, relativelightorigin, relativelightdirection, projectdistance, numshadowmark, shadowmarklist, ent->mins, ent->maxs); } if (ent->model->brush.submodel) GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset); @@ -1159,8 +1157,9 @@ void R_Q1BSP_DrawShadowMap(int side, entity_render_t *ent, const vec3_t relative } --modelsurfacelistindex; GL_CullFace(rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE ? GL_NONE : r_refdef.view.cullface_back); - RSurf_PrepareVerticesForBatch(false, false, batchnumsurfaces, batchsurfacelist); - RSurf_DrawBatch_Simple(batchnumsurfaces, batchsurfacelist); + RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXPOSITION, batchnumsurfaces, batchsurfacelist); + R_Mesh_PrepareVertices_Position(rsurface.batchnumvertices, rsurface.batchvertexposition, rsurface.batchvertexpositionbuffer); + RSurf_DrawBatch(); } } @@ -1171,7 +1170,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co int i, j, endsurface; texture_t *t; const msurface_t *surface; - // note: in practice this never actually receives batches), oh well + // note: in practice this never actually receives batches R_Shadow_RenderMode_Begin(); R_Shadow_RenderMode_ActiveLight(rtlight); R_Shadow_RenderMode_Lighting(false, true, false); @@ -1188,8 +1187,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co surface = rsurface.modelsurfaces + surfacelist[j]; if (t != surface->texture) break; - RSurf_PrepareVerticesForBatch(true, true, 1, &surface); - R_Shadow_RenderLighting(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s); + R_Shadow_RenderLighting(1, &surface); } } R_Shadow_RenderMode_End(); @@ -1200,9 +1198,9 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface { dp_model_t *model = ent->model; const msurface_t *surface; - int i, k, kend, l, m, mend, endsurface, batchnumsurfaces, batchnumtriangles, batchfirstvertex, batchlastvertex, batchfirsttriangle; + int i, k, kend, l, endsurface, batchnumsurfaces, texturenumsurfaces; + const msurface_t **texturesurfacelist; const int *element3i; - static int batchelements[BATCHSIZE*3]; texture_t *tex; CHECKGLERROR element3i = rsurface.modelelement3i; @@ -1256,45 +1254,9 @@ void R_Q1BSP_DrawLight(entity_render_t *ent, int numsurfaces, const int *surface } if (r_shadow_usingdeferredprepass) continue; - batchnumtriangles = 0; - batchfirsttriangle = surface->num_firsttriangle; - m = 0; // hush warning - for (l = k;l < kend;l++) - { - surface = batchsurfacelist[l]; - RSurf_PrepareVerticesForBatch(true, true, 1, &surface); - for (m = surface->num_firsttriangle, mend = m + surface->num_triangles;m < mend;m++) - { - if (lighttrispvs && r_test.integer && !CHECKPVSBIT(lighttrispvs, m)) - continue; - if (batchnumtriangles >= BATCHSIZE) - { - r_refdef.stats.lights_lighttriangles += batchnumtriangles; - Mod_VertexRangeFromElements(batchnumtriangles*3, batchelements, &batchfirstvertex, &batchlastvertex); - // use the element buffer if all triangles are consecutive - if (m == batchfirsttriangle + batchnumtriangles) - R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, batchfirsttriangle, batchnumtriangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s); - else - R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, 0, batchnumtriangles, batchelements, NULL, 0, 0); - batchnumtriangles = 0; - batchfirsttriangle = m; - } - batchelements[batchnumtriangles*3+0] = element3i[m*3+0]; - batchelements[batchnumtriangles*3+1] = element3i[m*3+1]; - batchelements[batchnumtriangles*3+2] = element3i[m*3+2]; - batchnumtriangles++; - } - } - if (batchnumtriangles > 0) - { - r_refdef.stats.lights_lighttriangles += batchnumtriangles; - Mod_VertexRangeFromElements(batchnumtriangles*3, batchelements, &batchfirstvertex, &batchlastvertex); - // use the element buffer if all triangles are consecutive - if (m == batchfirsttriangle + batchnumtriangles) - R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, batchfirsttriangle, batchnumtriangles, ent->model->surfmesh.data_element3i, ent->model->surfmesh.data_element3s, ent->model->surfmesh.ebo3i, ent->model->surfmesh.ebo3s); - else - R_Shadow_RenderLighting(batchfirstvertex, batchlastvertex + 1 - batchfirstvertex, 0, batchnumtriangles, batchelements, NULL, 0, 0); - } + texturenumsurfaces = kend - k; + texturesurfacelist = batchsurfacelist + k; + R_Shadow_RenderLighting(texturenumsurfaces, texturesurfacelist); } } } diff --git a/glquake.h b/glquake.h index bd3e133c..4e7ceb8a 100644 --- a/glquake.h +++ b/glquake.h @@ -636,12 +636,14 @@ extern void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean extern void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); extern void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +extern void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count); extern void (GLAPIENTRY *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); extern void (GLAPIENTRY *qglNormalPointer)(GLenum type, GLsizei stride, const GLvoid *ptr); extern void (GLAPIENTRY *qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); extern void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); extern void (GLAPIENTRY *qglArrayElement)(GLint i); +extern void (GLAPIENTRY *qglColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); extern void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); extern void (GLAPIENTRY *qglTexCoord1f)(GLfloat s); extern void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t); @@ -649,6 +651,7 @@ extern void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r); extern void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); extern void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y); extern void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z); +extern void (GLAPIENTRY *qglVertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); extern void (GLAPIENTRY *qglBegin)(GLenum mode); extern void (GLAPIENTRY *qglEnd)(void); diff --git a/mathlib.h b/mathlib.h index 64139365..e7148f40 100644 --- a/mathlib.h +++ b/mathlib.h @@ -83,6 +83,7 @@ unsigned int CeilPowerOf2(unsigned int value); #define Vector2Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define Vector2Negate(a,b) ((b)[0]=-((a)[0]),(b)[1]=-((a)[1])) #define Vector2Set(a,b,c,d,e) ((a)[0]=(b),(a)[1]=(c)) +#define Vector2Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale)) #define Vector2Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct2((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;} #define DotProduct4(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]+(a)[3]*(b)[3]) @@ -94,6 +95,7 @@ unsigned int CeilPowerOf2(unsigned int value); #define Vector4Normalize2(v,dest) {float ilength = (float) sqrt(DotProduct4((v),(v)));if (ilength) ilength = 1.0f / ilength;dest[0] = (v)[0] * ilength;dest[1] = (v)[1] * ilength;dest[2] = (v)[2] * ilength;dest[3] = (v)[3] * ilength;} #define Vector4Subtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) #define Vector4Add(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define Vector4Scale(in, scale, out) ((out)[0] = (in)[0] * (scale),(out)[1] = (in)[1] * (scale),(out)[2] = (in)[2] * (scale),(out)[3] = (in)[3] * (scale)) #define Vector4Multiply(a,b,c) ((c)[0]=(a)[0]*(b)[0],(c)[1]=(a)[1]*(b)[1],(c)[2]=(a)[2]*(b)[2],(c)[3]=(a)[3]*(b)[3]) #define Vector4MA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2],(c)[3] = (a)[3] + (scale) * (b)[3]) diff --git a/model_shared.c b/model_shared.c index 38fc9172..40c49dbf 100644 --- a/model_shared.c +++ b/model_shared.c @@ -194,12 +194,24 @@ void Mod_UnloadModel (dp_model_t *mod) strlcpy(name, mod->name, sizeof(name)); parentmodel = mod->brush.parentmodel; used = mod->used; - if (mod->surfmesh.ebo3i) - R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3i); - if (mod->surfmesh.ebo3s) - R_Mesh_DestroyBufferObject(mod->surfmesh.ebo3s); - if (mod->surfmesh.vbo) - R_Mesh_DestroyBufferObject(mod->surfmesh.vbo); + if (mod->mempool) + { + if (mod->surfmesh.vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexpositionbuffer); + mod->surfmesh.vertexpositionbuffer = NULL; + if (mod->surfmesh.vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vertexmeshbuffer); + mod->surfmesh.vertexmeshbuffer = NULL; + if (mod->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer); + mod->surfmesh.data_element3i_indexbuffer = NULL; + if (mod->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer); + mod->surfmesh.data_element3s_indexbuffer = NULL; + if (mod->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer); + mod->surfmesh.vbo_vertexbuffer = NULL; + } // free textures/memory attached to the model R_FreeTexturePool(&mod->texturepool); Mem_FreePool(&mod->mempool); @@ -1175,26 +1187,60 @@ shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtria static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) { - if (!vid.support.arb_vertex_buffer_object) - return; - if (mesh->vbo) + if (!mesh->numverts) return; - // element buffer is easy because it's just one array - if (mesh->numtriangles) + // build r_vertexmesh_t array + // (compressed interleaved array for faster rendering) + if (!mesh->vertexmesh && mesh->texcoord2f) { - if (mesh->element3s) - mesh->ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3s, mesh->numtriangles * sizeof(unsigned short[3]), "shadowmesh"); - else - mesh->ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh->element3i, mesh->numtriangles * sizeof(unsigned int[3]), "shadowmesh"); + int vertexindex; + int numvertices = mesh->numverts; + r_vertexmesh_t *vertexmesh; + mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexmesh)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + } } + // build r_vertexposition_t array + if (!mesh->vertexposition) + { + int vertexindex; + int numvertices = mesh->numverts; + r_vertexposition_t *vertexposition; + mesh->vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*mesh->vertexposition)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++) + VectorCopy(mesh->vertex3f + 3*vertexindex, vertexposition->vertex3f); + } + + // upload r_vertexmesh_t array as a buffer + if (mesh->vertexmesh && !mesh->vertexmeshbuffer) + mesh->vertexmeshbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexmesh, mesh->numverts * sizeof(*mesh->vertexmesh), loadmodel->name, false, false); + + // upload r_vertexposition_t array as a buffer + if (mesh->vertexposition && !mesh->vertexpositionbuffer) + mesh->vertexpositionbuffer = R_Mesh_CreateMeshBuffer(mesh->vertexposition, mesh->numverts * sizeof(*mesh->vertexposition), loadmodel->name, false, false); + + // upload short indices as a buffer + if (mesh->element3s && !mesh->element3s_indexbuffer) + mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false); + + // upload int indices as a buffer + if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s) + mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false); + // 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) + if (!mesh->vbo_vertexbuffer) { size_t size; unsigned char *mem; @@ -1210,7 +1256,7 @@ static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh) if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3])); if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3])); if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2])); - mesh->vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, "shadowmesh"); + mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false); Mem_Free(mem); } } @@ -1299,12 +1345,16 @@ void Mod_ShadowMesh_Free(shadowmesh_t *mesh) shadowmesh_t *nextmesh; for (;mesh;mesh = nextmesh) { - if (mesh->ebo3i) - R_Mesh_DestroyBufferObject(mesh->ebo3i); - if (mesh->ebo3s) - R_Mesh_DestroyBufferObject(mesh->ebo3s); - if (mesh->vbo) - R_Mesh_DestroyBufferObject(mesh->vbo); + if (mesh->vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vertexpositionbuffer); + if (mesh->vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vertexmeshbuffer); + if (mesh->element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer); + if (mesh->element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer); + if (mesh->vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer); nextmesh = mesh->next; Mem_Free(mesh); } @@ -2610,6 +2660,9 @@ void Mod_MakeSortedSurfaces(dp_model_t *mod) void Mod_BuildVBOs(void) { + if (!loadmodel->surfmesh.num_vertices) + return; + if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i) { int i; @@ -2623,27 +2676,62 @@ void Mod_BuildVBOs(void) } } - if (!vid.support.arb_vertex_buffer_object) - return; - // only build a vbo if one has not already been created (this is important for brush models which load specially) - if (loadmodel->surfmesh.vbo) - return; + // build r_vertexmesh_t array + // (compressed interleaved array for faster rendering) + if (!loadmodel->surfmesh.vertexmesh) + { + int vertexindex; + int numvertices = loadmodel->surfmesh.num_vertices; + r_vertexmesh_t *vertexmesh; + loadmodel->surfmesh.vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexmesh)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++) + { + VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f); + VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f); + VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f); + VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f); + if (loadmodel->surfmesh.data_lightmapcolor4f) + Vector4Scale(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, 255.0f, vertexmesh->color4ub); + Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f); + if (loadmodel->surfmesh.data_texcoordlightmap2f) + Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f); + } + } - // element buffer is easy because it's just one array - if (loadmodel->surfmesh.num_triangles) + // build r_vertexposition_t array + if (!loadmodel->surfmesh.vertexposition) { - if (loadmodel->surfmesh.data_element3s) - loadmodel->surfmesh.ebo3s = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(unsigned short[3]), loadmodel->name); - else - loadmodel->surfmesh.ebo3i = R_Mesh_CreateStaticBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(unsigned int[3]), loadmodel->name); + int vertexindex; + int numvertices = loadmodel->surfmesh.num_vertices; + r_vertexposition_t *vertexposition; + loadmodel->surfmesh.vertexposition = vertexposition = (r_vertexposition_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(*loadmodel->surfmesh.vertexposition)); + for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexposition++) + VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexposition->vertex3f); } + // upload r_vertexmesh_t array as a buffer + if (loadmodel->surfmesh.vertexmesh && !loadmodel->surfmesh.vertexmeshbuffer) + loadmodel->surfmesh.vertexmeshbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexmesh, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexmesh), loadmodel->name, false, false); + + // upload r_vertexposition_t array as a buffer + if (loadmodel->surfmesh.vertexposition && !loadmodel->surfmesh.vertexpositionbuffer) + loadmodel->surfmesh.vertexpositionbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.vertexposition, loadmodel->surfmesh.num_vertices * sizeof(*loadmodel->surfmesh.vertexposition), loadmodel->name, false, false); + + // upload short indices as a buffer + if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer) + loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false); + + // upload int indices as a buffer + if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s) + loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false); + + // only build a vbo if one has not already been created (this is important for brush models which load specially) // 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) + if (!loadmodel->surfmesh.vbo_vertexbuffer) { size_t size; unsigned char *mem; @@ -2663,7 +2751,7 @@ void Mod_BuildVBOs(void) if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2])); if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4])); - loadmodel->surfmesh.vbo = R_Mesh_CreateStaticBufferObject(GL_ARRAY_BUFFER_ARB, mem, size, loadmodel->name); + loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false); Mem_Free(mem); } } @@ -3619,15 +3707,27 @@ static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model) if (model->surfmesh.num_vertices > 65536) model->surfmesh.data_element3s = NULL; - if (model->surfmesh.vbo) - R_Mesh_DestroyBufferObject(model->surfmesh.vbo); - model->surfmesh.vbo = 0; - if (model->surfmesh.ebo3i) - R_Mesh_DestroyBufferObject(model->surfmesh.ebo3i); - model->surfmesh.ebo3i = 0; - if (model->surfmesh.ebo3s) - R_Mesh_DestroyBufferObject(model->surfmesh.ebo3s); - model->surfmesh.ebo3s = 0; + if (model->surfmesh.vertexposition) + Mem_Free(model->surfmesh.vertexposition); + model->surfmesh.vertexposition = NULL; + if (model->surfmesh.vertexmesh) + Mem_Free(model->surfmesh.vertexmesh); + model->surfmesh.vertexmesh = NULL; + if (model->surfmesh.vertexpositionbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexpositionbuffer); + model->surfmesh.vertexpositionbuffer = NULL; + if (model->surfmesh.vertexmeshbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vertexmeshbuffer); + model->surfmesh.vertexmeshbuffer = NULL; + if (model->surfmesh.data_element3i_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer); + model->surfmesh.data_element3i_indexbuffer = NULL; + if (model->surfmesh.data_element3s_indexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer); + model->surfmesh.data_element3s_indexbuffer = NULL; + if (model->surfmesh.vbo_vertexbuffer) + R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer); + model->surfmesh.vbo_vertexbuffer = 0; // convert all triangles to unique vertex data outvertexindex = 0; diff --git a/model_shared.h b/model_shared.h index e02b49e4..eca7ef39 100644 --- a/model_shared.h +++ b/model_shared.h @@ -101,6 +101,46 @@ typedef struct blendweights_s } blendweights_t; +typedef struct r_vertexposition_s +{ + // 12 bytes + float vertex3f[3]; +} +r_vertexposition_t; + +typedef struct r_vertexgeneric_s +{ + // 24 bytes + float vertex3f[3]; + unsigned char color4ub[4]; + float texcoord2f[2]; +} +r_vertexgeneric_t; + +typedef struct r_vertexmesh_s +{ + // 68 bytes + float vertex3f[3]; + unsigned char color4ub[4]; + float texcoordtexture2f[2]; + float texcoordlightmap2f[2]; + float svector3f[3]; + float tvector3f[3]; + float normal3f[3]; +} +r_vertexmesh_t; + +typedef struct r_meshbuffer_s +{ + int bufferobject; // OpenGL + void *devicebuffer; // Direct3D + size_t size; + qboolean isindexbuffer; + qboolean isdynamic; + char name[MAX_QPATH]; +} +r_meshbuffer_t; + // used for mesh lists in q1bsp/q3bsp map models // (the surfaces reference portions of these meshes) typedef struct surfmesh_s @@ -108,11 +148,12 @@ 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 + r_meshbuffer_t *data_element3i_indexbuffer; + size_t data_element3i_bufferoffset; unsigned short *data_element3s; // unsigned short[tris*3] triangles of the mesh in unsigned short format (NULL if num_vertices > 65536) + r_meshbuffer_t *data_element3s_indexbuffer; + size_t data_element3s_bufferoffset; int *data_neighbor3i; // int[tris*3] neighboring triangle on each edge (-1 if none) - // element buffer object (stores triangles in video memory) - int ebo3i; // unsigned int format (only allocated if num_vertices > 65536) - int ebo3s; // unsigned short format (only allocated if num_vertices <= 65536) // vertex data in system memory int num_vertices; // number of vertices in the mesh float *data_vertex3f; // float[verts*3] vertex locations @@ -124,7 +165,7 @@ typedef struct surfmesh_s 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; + r_meshbuffer_t *vbo_vertexbuffer; size_t vbooffset_vertex3f; size_t vbooffset_svector3f; size_t vbooffset_tvector3f; @@ -146,6 +187,12 @@ typedef struct surfmesh_s unsigned short *blends; // set if there is some kind of animation on this model qboolean isanimated; + + // vertex and index buffers for rendering + r_vertexposition_t *vertexposition; + r_vertexmesh_t *vertexmesh; + r_meshbuffer_t *vertexpositionbuffer; + r_meshbuffer_t *vertexmeshbuffer; } surfmesh_t; @@ -176,7 +223,11 @@ typedef struct shadowmesh_s float *texcoord2f; // used always int *element3i; + r_meshbuffer_t *element3i_indexbuffer; + size_t element3i_bufferoffset; unsigned short *element3s; + r_meshbuffer_t *element3s_indexbuffer; + size_t element3s_bufferoffset; // used for shadow mapping cubemap side partitioning int sideoffsets[6], sidetotals[6]; // used for shadow mesh (NULL on light mesh) @@ -184,18 +235,18 @@ 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 ebo3i; - int ebo3s; - // vertex buffer object (stores vertices in video memory) - // (created by Mod_ShadowMesh_Finish if possible) - int vbo; + r_meshbuffer_t *vbo_vertexbuffer; size_t vbooffset_vertex3f; size_t vbooffset_svector3f; size_t vbooffset_tvector3f; size_t vbooffset_normal3f; size_t vbooffset_texcoord2f; + // vertex/index buffers for rendering + // (created by Mod_ShadowMesh_Finish if possible) + r_vertexposition_t *vertexposition; + r_vertexmesh_t *vertexmesh; // usually NULL + r_meshbuffer_t *vertexpositionbuffer; + r_meshbuffer_t *vertexmeshbuffer; // usually NULL } shadowmesh_t; diff --git a/r_explosion.c b/r_explosion.c index 031d6649..5dd1d01f 100644 --- a/r_explosion.c +++ b/r_explosion.c @@ -212,17 +212,15 @@ static void R_DrawExplosion_TransparentCallback(const entity_render_t *ent, cons GL_CullFace(r_refdef.view.cullface_back); R_EntityMatrix(&identitymatrix); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(explosiontexture, NULL, GL_MODULATE, 1); - R_Mesh_TexCoordPointer(0, 2, explosiontexcoord2f[0], 0, 0); for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++) { const explosion_t *e = explosion + surfacelist[surfacelistindex]; - R_Mesh_VertexPointer(e->vert[0], 0, 0); - // FIXME: fixed function path can't properly handle r_refdef.view.colorscale > 1 + // FIXME: this can't properly handle r_refdef.view.colorscale > 1 GL_Color(e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, e->alpha * r_refdef.view.colorscale, 1); - R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, explosiontris[0], 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(numverts, e->vert[0], NULL, explosiontexcoord2f[0]); + R_Mesh_Draw(0, numverts, 0, numtriangles, NULL, NULL, 0, explosiontris[0], NULL, 0); } } diff --git a/r_shadow.c b/r_shadow.c index 33c3005f..406796c4 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1323,8 +1323,8 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES) { tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris); - R_Mesh_VertexPointer(shadowvertex3f, 0, 0); - R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0); + R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); } else { @@ -1338,13 +1338,12 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, r_refdef.stats.lights_dynamicshadowtriangles += tris; r_refdef.stats.lights_shadowtriangles += tris; CHECKGLERROR - R_Mesh_VertexPointer(shadowvertex3f, 0, 0); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) { // increment stencil if frontface is infront of depthbuffer GL_CullFace(r_refdef.view.cullface_front); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR - R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); // decrement stencil if backface is infront of depthbuffer GL_CullFace(r_refdef.view.cullface_back); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR @@ -1354,12 +1353,13 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, // decrement stencil if backface is behind depthbuffer GL_CullFace(r_refdef.view.cullface_front); qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR - R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); // increment stencil if frontface is behind depthbuffer GL_CullFace(r_refdef.view.cullface_back); qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } - R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0); + R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f); + R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0); CHECKGLERROR } } @@ -1895,6 +1895,8 @@ void R_Shadow_ValidateCvars(void) Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0); } +static const r_vertexposition_t resetvertexposition[3]; + void R_Shadow_RenderMode_Begin(void) { #if 0 @@ -1910,8 +1912,8 @@ void R_Shadow_RenderMode_Begin(void) R_Shadow_MakeTextures(); CHECKGLERROR - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); + R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL); GL_BlendFunc(GL_ONE, GL_ZERO); GL_DepthRange(0, 1); GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset); @@ -1990,8 +1992,8 @@ void R_Shadow_RenderMode_Reset(void) #endif R_SetViewport(&r_refdef.view.viewport); GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); + R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL); GL_DepthRange(0, 1); GL_DepthTest(true); GL_DepthMask(false); @@ -2301,7 +2303,7 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qb break; } } - R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0); + //R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0); CHECKGLERROR } @@ -2370,8 +2372,6 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow for (i = 0;i < 8;i++) Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3); CHECKGLERROR - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); GL_ColorMask(1,1,1,1); GL_DepthMask(false); GL_DepthRange(0, 1); @@ -2379,7 +2379,8 @@ void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadow GL_DepthTest(true); qglDepthFunc(GL_GREATER);CHECKGLERROR GL_CullFace(r_refdef.view.cullface_back); - R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0); + R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f); + R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0); } } @@ -2560,11 +2561,12 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) return false; } -static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor) +static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor) { - const float *vertex3f = rsurface.vertex3f + 3 * firstvertex; - const float *normal3f = rsurface.normal3f + 3 * firstvertex; - float *color4f = rsurface.array_color4f + 4 * firstvertex; + int i; + const float *vertex3f; + const float *normal3f; + float *color4f; float dist, dot, distintensity, shadeintensity, v[3], n[3]; switch (r_shadow_rendermode) { @@ -2572,7 +2574,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: if (VectorLength2(diffusecolor) > 0) { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) { Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n); @@ -2594,7 +2596,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu } else { - for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) { VectorCopy(ambientcolor, color4f); if (r_refdef.fogenabled) @@ -2602,7 +2604,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu float f; Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); f = RSurf_FogVertex(vertex3f); - VectorScale(color4f, f, color4f); + VectorScale(color4f + 4*i, f, color4f); } color4f[3] = 1; } @@ -2611,7 +2613,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: if (VectorLength2(diffusecolor) > 0) { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) { Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) @@ -2644,7 +2646,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu } else { - for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) { Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) @@ -2668,7 +2670,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu case R_SHADOW_RENDERMODE_LIGHT_VERTEX: if (VectorLength2(diffusecolor) > 0) { - for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4) { Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) @@ -2702,7 +2704,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu } else { - for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4) + for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4) { Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v); if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)])) @@ -2729,21 +2731,23 @@ static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int nu } } -static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject) +static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist) { // used to display how many times a surface is lit for level design purposes - R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject); + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist); + R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL); + RSurf_DrawBatch(); } -static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale) +static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale) { // ARB2 GLSL shader path (GFFX5200, Radeon 9500) - R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT); + R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) { qglDepthFunc(GL_EQUAL);CHECKGLERROR } - R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject); + RSurf_DrawBatch(); if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) { qglDepthFunc(GL_LEQUAL);CHECKGLERROR @@ -2763,7 +2767,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve float *c; int maxtriangles = 4096; static int newelements[4096*3]; - R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2); + R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2); for (renders = 0;renders < 4;renders++) { stop = true; @@ -2778,7 +2782,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve // renders them at once for (i = 0, e = element3i;i < numtriangles;i++, e += 3) { - if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01) + if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01) { if (newnumtriangles) { @@ -2801,7 +2805,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve newe += 3; if (newnumtriangles >= maxtriangles) { - R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0); + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0); newnumtriangles = 0; newe = newelements; stop = false; @@ -2810,7 +2814,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve } if (newnumtriangles >= 1) { - R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0); + R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0); stop = false; } // if we couldn't find any lit triangles, exit early @@ -2821,7 +2825,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve // handling of negative colors // (some old drivers even have improper handling of >1 color) stop = true; - for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4) + for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4) { if (c[0] > 1 || c[1] > 1 || c[2] > 1) { @@ -2839,7 +2843,7 @@ static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numve } } -static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale) +static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale) { // OpenGL 1.1 path (anything) float ambientcolorbase[3], diffusecolorbase[3]; @@ -2861,29 +2865,32 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2]; ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2]; diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2]; + RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist); + R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); + R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0); + R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset); R_Mesh_TexBind(0, basetexture); R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix); R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset); switch(r_shadow_rendermode) { case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: R_Mesh_TexBind(1, r_shadow_attenuation3dtexture); R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: R_Mesh_TexBind(2, r_shadow_attenuation2dtexture); R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz); R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); + R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); // fall through case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: R_Mesh_TexBind(1, r_shadow_attenuation2dtexture); R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz); R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1); - R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset); + R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX: break; @@ -2891,21 +2898,21 @@ static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertice break; } //R_Mesh_TexBind(0, basetexture); - R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase); if (dopants) { R_Mesh_TexBind(0, pantstexture); - R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants); } if (doshirt) { R_Mesh_TexBind(0, shirttexture); - R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt); + R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt); } } extern cvar_t gl_lightmaps; -void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject) +void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist) { float ambientscale, diffusescale, specularscale; qboolean negated; @@ -2933,16 +2940,16 @@ void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle { case R_SHADOW_RENDERMODE_VISIBLELIGHTING: GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer); - R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject); + R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist); break; case R_SHADOW_RENDERMODE_LIGHT_GLSL: - R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale); + R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale); break; case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN: case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN: case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN: case R_SHADOW_RENDERMODE_LIGHT_VERTEX: - R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale); + R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale); break; default: Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode); @@ -3326,8 +3333,8 @@ void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const if (!mesh->sidetotals[r_shadow_shadowmapside]) continue; r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside]; - R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f); - R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); + R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer); + R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); } CHECKGLERROR } @@ -3359,13 +3366,13 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co for (;mesh;mesh = mesh->next) { r_refdef.stats.lights_shadowtriangles += mesh->numtriangles; - R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f); + R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer); if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL) { // increment stencil if frontface is infront of depthbuffer GL_CullFace(r_refdef.view.cullface_back); qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR - R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); // decrement stencil if backface is infront of depthbuffer GL_CullFace(r_refdef.view.cullface_front); qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR @@ -3375,12 +3382,12 @@ void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, co // decrement stencil if backface is behind depthbuffer GL_CullFace(r_refdef.view.cullface_front); qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR - R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); // increment stencil if frontface is behind depthbuffer GL_CullFace(r_refdef.view.cullface_back); qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR } - R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s); + R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset); } CHECKGLERROR } @@ -3990,7 +3997,6 @@ void R_Shadow_DrawPrepass(void) entity_render_t *ent; GL_AlphaTest(false); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); GL_DepthMask(true); GL_ColorMask(1,1,1,1); @@ -4578,9 +4584,6 @@ void R_DrawModelShadows(void) //R_EntityMatrix(&identitymatrix); //R_Mesh_ResetTextureState(); R_ResetViewRendering2D(); - R_Mesh_VertexPointer(r_screenvertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); - R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); // set up a darkening blend on shadowed areas GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -4597,7 +4600,9 @@ void R_DrawModelShadows(void) qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR // apply the blend to the shadowed areas - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL); + R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); // restore the viewport R_SetViewport(&r_refdef.view.viewport); @@ -4629,14 +4634,14 @@ void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery) qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels); qglDepthFunc(GL_ALWAYS); R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); qglEndQueryARB(GL_SAMPLES_PASSED_ARB); qglDepthFunc(GL_LEQUAL); qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels); R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale); - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0); + R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f); + R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0); qglEndQueryARB(GL_SAMPLES_PASSED_ARB); CHECKGLERROR } @@ -4728,7 +4733,6 @@ void R_Shadow_DrawCoronas(void) GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); GL_DepthTest(true); - R_Mesh_ColorPointer(NULL, 0, 0); R_Mesh_ResetTextureState(); R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1); } diff --git a/r_shadow.h b/r_shadow.h index 5997605e..cf74e268 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -45,7 +45,7 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias); int R_Shadow_CalcSphereSideMask(const vec3_t p1, float radius, float bias); int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals); -void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject); +void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist); void R_Shadow_RenderMode_Begin(void); void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight); void R_Shadow_RenderMode_Reset(void); diff --git a/render.h b/render.h index a6bc2079..753fc92c 100644 --- a/render.h +++ b/render.h @@ -229,19 +229,27 @@ extern mempool_t *r_main_mempool; typedef struct rsurfacestate_s { - // processing buffers - int array_size; - float *array_modelvertex3f; - float *array_modelsvector3f; - float *array_modeltvector3f; - float *array_modelnormal3f; - float *array_deformedvertex3f; - float *array_deformedsvector3f; - float *array_deformedtvector3f; - float *array_deformednormal3f; - float *array_generatedtexcoordtexture2f; - float *array_color4f; - float *array_texcoord3f; + // software processing buffers + int array_size; + unsigned char *array_base; + r_vertexmesh_t *array_modelvertexmesh; + r_vertexmesh_t *array_batchvertexmesh; + r_vertexposition_t *array_modelvertexposition; + r_vertexposition_t *array_batchvertexposition; + float *array_modelvertex3f; + float *array_modelsvector3f; + float *array_modeltvector3f; + float *array_modelnormal3f; + float *array_batchvertex3f; + float *array_batchsvector3f; + float *array_batchtvector3f; + float *array_batchnormal3f; + float *array_batchlightmapcolor4f; + float *array_batchtexcoordtexture2f; + float *array_batchtexcoordlightmap2f; + float *array_passcolor4f; + int *array_batchelement3i; + unsigned short *array_batchelement3s; // current model array pointers // these may point to processing buffers if model is animated, @@ -257,67 +265,89 @@ typedef struct rsurfacestate_s // // this indicates the model* arrays are pointed at array_model* buffers // (in other words, the model has been animated in software) - qboolean generatedvertex; - const float *modelvertex3f; - int modelvertex3f_bufferobject; - size_t modelvertex3f_bufferoffset; - const float *modelsvector3f; - int modelsvector3f_bufferobject; - size_t modelsvector3f_bufferoffset; - const float *modeltvector3f; - int modeltvector3f_bufferobject; - size_t modeltvector3f_bufferoffset; - const float *modelnormal3f; - int modelnormal3f_bufferobject; - size_t modelnormal3f_bufferoffset; - const float *modellightmapcolor4f; - int modellightmapcolor4f_bufferobject; - size_t modellightmapcolor4f_bufferoffset; - const float *modeltexcoordtexture2f; - int modeltexcoordtexture2f_bufferobject; - size_t modeltexcoordtexture2f_bufferoffset; - const float *modeltexcoordlightmap2f; - int modeltexcoordlightmap2f_bufferobject; - size_t modeltexcoordlightmap2f_bufferoffset; - const int *modelelement3i; - const unsigned short *modelelement3s; - int modelelement3i_bufferobject; - int modelelement3s_bufferobject; - const int *modellightmapoffsets; - int modelnum_vertices; - int modelnum_triangles; - const msurface_t *modelsurfaces; + qboolean modelgeneratedvertex; + const float *modelvertex3f; + const r_meshbuffer_t *modelvertex3f_vertexbuffer; + size_t modelvertex3f_bufferoffset; + const float *modelsvector3f; + const r_meshbuffer_t *modelsvector3f_vertexbuffer; + size_t modelsvector3f_bufferoffset; + const float *modeltvector3f; + const r_meshbuffer_t *modeltvector3f_vertexbuffer; + size_t modeltvector3f_bufferoffset; + const float *modelnormal3f; + const r_meshbuffer_t *modelnormal3f_vertexbuffer; + size_t modelnormal3f_bufferoffset; + const float *modellightmapcolor4f; + const r_meshbuffer_t *modellightmapcolor4f_vertexbuffer; + size_t modellightmapcolor4f_bufferoffset; + const float *modeltexcoordtexture2f; + const r_meshbuffer_t *modeltexcoordtexture2f_vertexbuffer; + size_t modeltexcoordtexture2f_bufferoffset; + const float *modeltexcoordlightmap2f; + const r_meshbuffer_t *modeltexcoordlightmap2f_vertexbuffer; + size_t modeltexcoordlightmap2f_bufferoffset; + const r_vertexmesh_t *modelvertexmesh; + const r_meshbuffer_t *modelvertexmeshbuffer; + const r_vertexposition_t *modelvertexposition; + const r_meshbuffer_t *modelvertexpositionbuffer; + const int *modelelement3i; + const r_meshbuffer_t *modelelement3i_indexbuffer; + size_t modelelement3i_bufferoffset; + const unsigned short *modelelement3s; + const r_meshbuffer_t *modelelement3s_indexbuffer; + size_t modelelement3s_bufferoffset; + const int *modellightmapoffsets; + int modelnumvertices; + int modelnumtriangles; + const msurface_t *modelsurfaces; // current rendering array pointers // these may point to any of several different buffers depending on how // much processing was needed to prepare this model for rendering // these usually equal the model* pointers, they only differ if // deformvertexes is used in a q3 shader, and consequently these can // change on a per-surface basis (according to rsurface.texture) - // - // the exception is the color array which is often generated based on - // colormod, alpha fading, and fogging, it may also come from q3bsp vertex - // lighting of certain surfaces - const float *vertex3f; - int vertex3f_bufferobject; - size_t vertex3f_bufferoffset; - const float *svector3f; - int svector3f_bufferobject; - size_t svector3f_bufferoffset; - const float *tvector3f; - int tvector3f_bufferobject; - size_t tvector3f_bufferoffset; - const float *normal3f; - int normal3f_bufferobject; - size_t normal3f_bufferoffset; - const float *lightmapcolor4f; - int lightmapcolor4f_bufferobject; - size_t lightmapcolor4f_bufferoffset; - const float *texcoordtexture2f; - int texcoordtexture2f_bufferobject; - size_t texcoordtexture2f_bufferoffset; - const float *texcoordlightmap2f; - int texcoordlightmap2f_bufferobject; - size_t texcoordlightmap2f_bufferoffset; + qboolean batchgeneratedvertex; + int batchfirstvertex; + int batchnumvertices; + int batchfirsttriangle; + int batchnumtriangles; + const r_vertexmesh_t *batchvertexmesh; + const r_meshbuffer_t *batchvertexmeshbuffer; + const r_vertexposition_t *batchvertexposition; + const r_meshbuffer_t *batchvertexpositionbuffer; + const float *batchvertex3f; + const r_meshbuffer_t *batchvertex3f_vertexbuffer; + size_t batchvertex3f_bufferoffset; + const float *batchsvector3f; + const r_meshbuffer_t *batchsvector3f_vertexbuffer; + size_t batchsvector3f_bufferoffset; + const float *batchtvector3f; + const r_meshbuffer_t *batchtvector3f_vertexbuffer; + size_t batchtvector3f_bufferoffset; + const float *batchnormal3f; + const r_meshbuffer_t *batchnormal3f_vertexbuffer; + size_t batchnormal3f_bufferoffset; + const float *batchlightmapcolor4f; + const r_meshbuffer_t *batchlightmapcolor4f_vertexbuffer; + size_t batchlightmapcolor4f_bufferoffset; + const float *batchtexcoordtexture2f; + const r_meshbuffer_t *batchtexcoordtexture2f_vertexbuffer; + size_t batchtexcoordtexture2f_bufferoffset; + const float *batchtexcoordlightmap2f; + const r_meshbuffer_t *batchtexcoordlightmap2f_vertexbuffer; + size_t batchtexcoordlightmap2f_bufferoffset; + const int *batchelement3i; + const r_meshbuffer_t *batchelement3i_indexbuffer; + size_t batchelement3i_bufferoffset; + const unsigned short *batchelement3s; + const r_meshbuffer_t *batchelement3s_indexbuffer; + size_t batchelement3s_bufferoffset; + // rendering pass processing arrays in GL11 and GL13 paths + const float *passcolor4f; + const r_meshbuffer_t *passcolor4f_vertexbuffer; + size_t passcolor4f_bufferoffset; + // some important fields from the entity int ent_skinnum; int ent_qwskin; @@ -350,8 +380,10 @@ typedef struct rsurfacestate_s // polygon offset data for submodels float basepolygonfactor; float basepolygonoffset; - // current texture in batching code + // current textures in batching code texture_t *texture; + rtexture_t *lightmaptexture; + rtexture_t *deluxemaptexture; // whether lightmapping is active on this batch // (otherwise vertex colored) qboolean uselightmaptexture; @@ -400,8 +432,22 @@ void R_AddWaterPlanes(entity_render_t *ent); void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass); void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass); -void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, const msurface_t **texturesurfacelist); -void RSurf_DrawBatch_Simple(int texturenumsurfaces, const msurface_t **texturesurfacelist); +#define BATCHNEED_VERTEXPOSITION (1<< 0) // set up rsurface.batchvertexposition +#define BATCHNEED_VERTEXMESH_VERTEX (1<< 1) // set up rsurface.batchvertexmesh +#define BATCHNEED_VERTEXMESH_NORMAL (1<< 2) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_VECTOR (1<< 3) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_VERTEXCOLOR (1<< 4) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_TEXCOORD (1<< 5) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_VERTEXMESH_LIGHTMAP (1<< 6) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_VERTEX (1<< 7) // set up rsurface.batchvertex3f and optionally others +#define BATCHNEED_ARRAY_NORMAL (1<< 8) // set up normals in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchnormal3f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_VECTOR (1<< 9) // set up vectors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchsvector3f and rsurface.batchtvector3f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_VERTEXCOLOR (1<<10) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_TEXCOORD (1<<11) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_ARRAY_LIGHTMAP (1<<12) // set up vertex colors in rsurface.batchvertexmesh if BATCHNEED_MESH, set up rsurface.batchlightmapcolor4f if BATCHNEED_ARRAYS +#define BATCHNEED_NOGAPS (1<<13) // force vertex copying (no gaps) +void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist); +void RSurf_DrawBatch(void); void R_DecalSystem_SplatEntities(const vec3_t org, const vec3_t normal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float size); @@ -471,7 +517,7 @@ gl20_texunit; void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale); void R_SetupShader_DepthOrShadow(void); void R_SetupShader_ShowDepth(void); -void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass); +void R_SetupShader_Surface(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist); void R_SetupShader_DeferredLight(const rtlight_t *rtlight); typedef struct r_waterstate_waterplane_s diff --git a/vid.h b/vid.h index 52331ae4..b5ffc050 100644 --- a/vid.h +++ b/vid.h @@ -100,6 +100,7 @@ typedef struct viddef_s void *cgcontext; renderpath_t renderpath; + qboolean forcevbo; // some renderpaths can not operate without it unsigned int texunits; unsigned int teximageunits; diff --git a/vid_shared.c b/vid_shared.c index 4579c143..eb6c56d4 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -147,12 +147,14 @@ void (GLAPIENTRY *qglColorMask)(GLboolean red, GLboolean green, GLboolean blue, void (GLAPIENTRY *qglDrawRangeElements)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); void (GLAPIENTRY *qglDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void (GLAPIENTRY *qglDrawArrays)(GLenum mode, GLint first, GLsizei count); void (GLAPIENTRY *qglVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); void (GLAPIENTRY *qglNormalPointer)(GLenum type, GLsizei stride, const GLvoid *ptr); void (GLAPIENTRY *qglColorPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); void (GLAPIENTRY *qglTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); void (GLAPIENTRY *qglArrayElement)(GLint i); +void (GLAPIENTRY *qglColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); void (GLAPIENTRY *qglColor4f)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); void (GLAPIENTRY *qglTexCoord1f)(GLfloat s); void (GLAPIENTRY *qglTexCoord2f)(GLfloat s, GLfloat t); @@ -160,6 +162,7 @@ void (GLAPIENTRY *qglTexCoord3f)(GLfloat s, GLfloat t, GLfloat r); void (GLAPIENTRY *qglTexCoord4f)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); void (GLAPIENTRY *qglVertex2f)(GLfloat x, GLfloat y); void (GLAPIENTRY *qglVertex3f)(GLfloat x, GLfloat y, GLfloat z); +void (GLAPIENTRY *qglVertex4f)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); void (GLAPIENTRY *qglBegin)(GLenum mode); void (GLAPIENTRY *qglEnd)(void); @@ -488,12 +491,14 @@ static dllfunction_t opengl110funcs[] = {"glDepthMask", (void **) &qglDepthMask}, {"glDepthRange", (void **) &qglDepthRange}, {"glDrawElements", (void **) &qglDrawElements}, + {"glDrawArrays", (void **) &qglDrawArrays}, {"glColorMask", (void **) &qglColorMask}, {"glVertexPointer", (void **) &qglVertexPointer}, {"glNormalPointer", (void **) &qglNormalPointer}, {"glColorPointer", (void **) &qglColorPointer}, {"glTexCoordPointer", (void **) &qglTexCoordPointer}, {"glArrayElement", (void **) &qglArrayElement}, + {"glColor4ub", (void **) &qglColor4ub}, {"glColor4f", (void **) &qglColor4f}, {"glTexCoord1f", (void **) &qglTexCoord1f}, {"glTexCoord2f", (void **) &qglTexCoord2f}, @@ -501,6 +506,7 @@ static dllfunction_t opengl110funcs[] = {"glTexCoord4f", (void **) &qglTexCoord4f}, {"glVertex2f", (void **) &qglVertex2f}, {"glVertex3f", (void **) &qglVertex3f}, + {"glVertex4f", (void **) &qglVertex4f}, {"glBegin", (void **) &qglBegin}, {"glEnd", (void **) &qglEnd}, //[515]: added on 29.07.2005 @@ -798,6 +804,7 @@ void VID_CheckExtensions(void) Con_DPrint("Checking OpenGL extensions...\n"); + vid.forcevbo = false; vid.support.amd_texture_texture4 = GL_CheckExtension("GL_AMD_texture_texture4", NULL, "-notexture4", false); vid.support.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false); vid.support.arb_draw_buffers = GL_CheckExtension("GL_ARB_draw_buffers", drawbuffersfuncs, "-nodrawbuffers", false); -- 2.39.2