+ if (offset)
+ {
+ for (i = 0;i < count;i++)
+ *out++ = *in++ + offset;
+ }
+ else
+ memcpy(out, in, sizeof(*out) * count);
+}
+
+// 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)
+{
+ unsigned int numelements = numtriangles * 3;
+ if (numvertices < 3 || numtriangles < 1)
+ {
+ if (numvertices < 0 || numtriangles < 0 || developer.integer >= 100)
+ Con_Printf("R_Mesh_Draw(%d, %d, %d, %d, %8p, %8p, %i, %i);\n", firstvertex, numvertices, firsttriangle, numtriangles, (void *)element3i, (void *)element3s, bufferobject3i, bufferobject3s);
+ return;
+ }
+ if (!gl_mesh_prefer_short_elements.integer)
+ {
+ if (element3i)
+ element3s = NULL;
+ if (bufferobject3i)
+ bufferobject3s = 0;
+ }
+ if (element3i)
+ element3i += firsttriangle * 3;
+ if (element3s)
+ element3s += firsttriangle * 3;
+ switch (gl_vbo.integer)
+ {
+ default:
+ case 0:
+ case 2:
+ bufferobject3i = bufferobject3s = 0;
+ break;
+ case 1:
+ break;
+ case 3:
+ if (firsttriangle)
+ bufferobject3i = bufferobject3s = 0;
+ break;
+ }
+ CHECKGLERROR
+ r_refdef.stats.meshes++;
+ r_refdef.stats.meshes_elements += numelements;
+ if (gl_paranoid.integer)
+ {
+ unsigned int i, 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
+ // used without buffer objects if the need arises
+ // (the data could be gotten using glMapBuffer but it would be very
+ // slow due to uncachable video memory reads)
+ if (!qglIsEnabled(GL_VERTEX_ARRAY))
+ Con_Print("R_Mesh_Draw: vertex array not enabled\n");
+ CHECKGLERROR
+ if (gl_state.pointer_vertex)
+ 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)
+ {
+ if (!qglIsEnabled(GL_COLOR_ARRAY))
+ Con_Print("R_Mesh_Draw: color array set but not enabled\n");
+ CHECKGLERROR
+ if (gl_state.pointer_color && gl_state.pointer_color_enabled)
+ for (j = 0, size = numvertices * 4, p = (int *)((float *)gl_state.pointer_color + firstvertex * 4);j < size;j++, p++)
+ paranoidblah += *p;
+ }
+ for (i = 0;i < backendarrayunits;i++)
+ {
+ if (gl_state.units[i].arrayenabled)
+ {
+ GL_ClientActiveTexture(i);
+ if (!qglIsEnabled(GL_TEXTURE_COORD_ARRAY))
+ Con_Print("R_Mesh_Draw: texcoord array set but not enabled\n");
+ CHECKGLERROR
+ if (gl_state.units[i].pointer_texcoord && gl_state.units[i].arrayenabled)
+ for (j = 0, size = numvertices * gl_state.units[i].arraycomponents, p = (int *)((float *)gl_state.units[i].pointer_texcoord + firstvertex * gl_state.units[i].arraycomponents);j < size;j++, p++)
+ paranoidblah += *p;
+ }
+ }
+ if (element3i)
+ {
+ for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+ {
+ if (element3i[i] < firstvertex || element3i[i] >= firstvertex + numvertices)
+ {
+ Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3i array\n", element3i[i], firstvertex, firstvertex + numvertices);
+ return;
+ }
+ }
+ }
+ if (element3s)
+ {
+ for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+ {
+ if (element3s[i] < firstvertex || element3s[i] >= firstvertex + numvertices)
+ {
+ Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in element3s array\n", element3s[i], firstvertex, firstvertex + numvertices);
+ return;
+ }
+ }
+ }
+ CHECKGLERROR
+ }
+ if (r_render.integer)
+ {
+ CHECKGLERROR
+ if (gl_mesh_testmanualfeeding.integer)
+ {
+ unsigned int i, j, element;
+ const GLfloat *p;
+ qglBegin(GL_TRIANGLES);
+ for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+ {
+ element = element3i ? element3i[i] : element3s[i];
+ for (j = 0;j < backendarrayunits;j++)
+ {
+ if (gl_state.units[j].pointer_texcoord && gl_state.units[j].arrayenabled)
+ {
+ if (backendarrayunits > 1)
+ {
+ if (gl_state.units[j].arraycomponents == 4)
+ {
+ 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]);
+ }
+ else
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
+ qglMultiTexCoord1f(GL_TEXTURE0_ARB + j, p[0]);
+ }
+ }
+ else
+ {
+ if (gl_state.units[j].arraycomponents == 4)
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 4;
+ qglTexCoord4f(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;
+ qglTexCoord3f(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;
+ qglTexCoord2f(p[0], p[1]);
+ }
+ else
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + element * 1;
+ qglTexCoord1f(p[0]);
+ }
+ }
+ }
+ }
+ if (gl_state.pointer_color && gl_state.pointer_color_enabled)
+ {
+ p = ((const GLfloat *)(gl_state.pointer_color)) + element * 4;
+ qglColor4f(p[0], p[1], p[2], p[3]);
+ }
+ 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
+ }
+ else if (bufferobject3s)
+ {
+ GL_BindEBO(bufferobject3s);
+ if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+ {
+ qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
+ CHECKGLERROR
+ }
+ else
+ {
+ qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, (void *)(firsttriangle * sizeof(unsigned short[3])));
+ CHECKGLERROR
+ }
+ }
+ else if (bufferobject3i)
+ {
+ GL_BindEBO(bufferobject3i);
+ if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+ {
+ qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
+ CHECKGLERROR
+ }
+ else
+ {
+ qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, (void *)(firsttriangle * sizeof(unsigned int[3])));
+ CHECKGLERROR
+ }
+ }
+ else if (element3s)
+ {
+ GL_BindEBO(0);
+ if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+ {
+ qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_SHORT, element3s);
+ CHECKGLERROR
+ }
+ else
+ {
+ qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_SHORT, element3s);
+ CHECKGLERROR
+ }
+ }
+ else if (element3i)
+ {
+ GL_BindEBO(0);
+ if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+ {
+ qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, element3i);
+ CHECKGLERROR
+ }
+ else
+ {
+ qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, element3i);
+ CHECKGLERROR
+ }
+ }
+ }
+}
+
+// restores backend state, used when done with 3D rendering
+void R_Mesh_Finish(void)
+{
+ unsigned int i;