+ CHECKGLERROR
+ qglScissor(x, vid.realheight - (y + height),width,height);
+ CHECKGLERROR
+}
+
+void GL_ScissorTest(int state)
+{
+ if(gl_state.scissortest == state)
+ return;
+
+ CHECKGLERROR
+ if((gl_state.scissortest = state))
+ qglEnable(GL_SCISSOR_TEST);
+ else
+ qglDisable(GL_SCISSOR_TEST);
+ CHECKGLERROR
+}
+
+void GL_Clear(int mask)
+{
+ if (r_showtrispass)
+ return;
+ qglClear(mask);CHECKGLERROR
+}
+
+void GL_TransformToScreen(const vec4_t in, vec4_t out)
+{
+ vec4_t temp;
+ float iw;
+ Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
+ Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
+ iw = 1.0f / out[3];
+ out[0] = r_view_x + (out[0] * iw + 1.0f) * r_view_width * 0.5f;
+ out[1] = r_view_y + (out[1] * iw + 1.0f) * r_view_height * 0.5f;
+ out[2] = r_view_z + (out[2] * iw + 1.0f) * r_view_depth * 0.5f;
+}
+
+// called at beginning of frame
+void R_Mesh_Start(void)
+{
+ BACKENDACTIVECHECK
+ CHECKGLERROR
+ GL_Backend_ResetState();
+}
+
+unsigned int GL_Backend_CompileProgram(int vertexstrings_count, const char **vertexstrings_list, int fragmentstrings_count, const char **fragmentstrings_list)
+{
+ GLint vertexshadercompiled, fragmentshadercompiled, programlinked;
+ GLuint vertexshaderobject, fragmentshaderobject, programobject = 0;
+ char compilelog[4096];
+ CHECKGLERROR
+
+ programobject = qglCreateProgramObjectARB();
+ CHECKGLERROR
+ if (!programobject)
+ return 0;
+
+ if (vertexstrings_count)
+ {
+ CHECKGLERROR
+ vertexshaderobject = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+ if (!vertexshaderobject)
+ {
+ qglDeleteObjectARB(programobject);
+ CHECKGLERROR
+ return 0;
+ }
+ qglShaderSourceARB(vertexshaderobject, vertexstrings_count, vertexstrings_list, NULL);
+ qglCompileShaderARB(vertexshaderobject);
+ CHECKGLERROR
+ qglGetObjectParameterivARB(vertexshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &vertexshadercompiled);
+ qglGetInfoLogARB(vertexshaderobject, sizeof(compilelog), NULL, compilelog);
+ if (compilelog[0])
+ Con_Printf("vertex shader compile log:\n%s\n", compilelog);
+ if (!vertexshadercompiled)
+ {
+ qglDeleteObjectARB(programobject);
+ qglDeleteObjectARB(vertexshaderobject);
+ CHECKGLERROR
+ return 0;
+ }
+ qglAttachObjectARB(programobject, vertexshaderobject);
+ qglDeleteObjectARB(vertexshaderobject);
+ CHECKGLERROR
+ }
+
+ if (fragmentstrings_count)
+ {
+ CHECKGLERROR
+ fragmentshaderobject = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+ if (!fragmentshaderobject)
+ {
+ qglDeleteObjectARB(programobject);
+ CHECKGLERROR
+ return 0;
+ }
+ qglShaderSourceARB(fragmentshaderobject, fragmentstrings_count, fragmentstrings_list, NULL);
+ qglCompileShaderARB(fragmentshaderobject);
+ CHECKGLERROR
+ qglGetObjectParameterivARB(fragmentshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentshadercompiled);
+ qglGetInfoLogARB(fragmentshaderobject, sizeof(compilelog), NULL, compilelog);
+ if (compilelog[0])
+ Con_Printf("fragment shader compile log:\n%s\n", compilelog);
+ if (!fragmentshadercompiled)
+ {
+ qglDeleteObjectARB(programobject);
+ qglDeleteObjectARB(fragmentshaderobject);
+ CHECKGLERROR
+ return 0;
+ }
+ qglAttachObjectARB(programobject, fragmentshaderobject);
+ qglDeleteObjectARB(fragmentshaderobject);
+ CHECKGLERROR
+ }
+
+ qglLinkProgramARB(programobject);
+ CHECKGLERROR
+ qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);
+ qglGetInfoLogARB(programobject, sizeof(compilelog), NULL, compilelog);
+ if (compilelog[0])
+ {
+ Con_Printf("program link log:\n%s\n", compilelog);
+ // software vertex shader is ok but software fragment shader is WAY
+ // too slow, fail program if so.
+ // NOTE: this string might be ATI specific, but that's ok because the
+ // ATI R300 chip (Radeon 9500-9800/X300) is the most likely to use a
+ // software fragment shader due to low instruction and dependent
+ // texture limits.
+ if (strstr(compilelog, "fragment shader will run in software"))
+ programlinked = false;
+ }
+ CHECKGLERROR
+ if (!programlinked)
+ {
+ qglDeleteObjectARB(programobject);
+ return 0;
+ }
+ CHECKGLERROR
+ return programobject;
+}
+
+void GL_Backend_FreeProgram(unsigned int prog)
+{
+ CHECKGLERROR
+ qglDeleteObjectARB(prog);
+ CHECKGLERROR
+}
+
+int gl_backend_rebindtextures;
+
+void GL_Backend_RenumberElements(int *out, int count, const int *in, int offset)
+{
+ int i;
+ 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 numtriangles, const int *elements)
+{
+ unsigned int numelements = numtriangles * 3;
+ if (numvertices < 3 || numtriangles < 1)
+ {
+ Con_Printf("R_Mesh_Draw(%d, %d, %d, %08p);\n", firstvertex, numvertices, numtriangles, elements);
+ return;
+ }
+ //CHECKGLERROR
+ if (r_showtrispass)
+ {
+ R_Mesh_Draw_ShowTris(firstvertex, numvertices, numtriangles, elements);
+ return;
+ }
+ c_meshs++;
+ c_meshelements += numelements;
+ if (gl_paranoid.integer)
+ {
+ unsigned int i, j, size;
+ const int *p;
+ if (!qglIsEnabled(GL_VERTEX_ARRAY))
+ Con_Print("R_Mesh_Draw: vertex array not enabled\n");
+ 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)
+ {
+ if (!qglIsEnabled(GL_COLOR_ARRAY))
+ Con_Print("R_Mesh_Draw: color array set but not enabled\n");
+ 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");
+ 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;
+ }
+ }
+ for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+ {
+ if (elements[i] < firstvertex || elements[i] >= firstvertex + numvertices)
+ {
+ Con_Printf("R_Mesh_Draw: invalid vertex index %i (outside range %i - %i) in elements list\n", elements[i], firstvertex, firstvertex + numvertices);
+ return;
+ }
+ }
+ CHECKGLERROR
+ }
+ if (r_render.integer)
+ {
+ CHECKGLERROR
+ if (gl_mesh_testmanualfeeding.integer)
+ {
+ unsigned int i, j;
+ const GLfloat *p;
+ qglBegin(GL_TRIANGLES);
+ for (i = 0;i < (unsigned int) numtriangles * 3;i++)
+ {
+ for (j = 0;j < backendarrayunits;j++)
+ {
+ if (gl_state.units[j].pointer_texcoord)
+ {
+ if (backendarrayunits > 1)
+ {
+ if (gl_state.units[j].arraycomponents == 4)
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 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)) + elements[i] * 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)) + elements[i] * 2;
+ qglMultiTexCoord2f(GL_TEXTURE0_ARB + j, p[0], p[1]);
+ }
+ else
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 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)) + elements[i] * 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)) + elements[i] * 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)) + elements[i] * 2;
+ qglTexCoord2f(p[0], p[1]);
+ }
+ else
+ {
+ p = ((const GLfloat *)(gl_state.units[j].pointer_texcoord)) + elements[i] * 1;
+ qglTexCoord1f(p[0]);
+ }
+ }
+ }
+ }
+ if (gl_state.pointer_color)
+ {
+ p = ((const GLfloat *)(gl_state.pointer_color)) + elements[i] * 4;
+ qglColor4f(p[0], p[1], p[2], p[3]);
+ }
+ p = ((const GLfloat *)(gl_state.pointer_vertex)) + elements[i] * 3;
+ qglVertex3f(p[0], p[1], p[2]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ else if (gl_mesh_testarrayelement.integer)
+ {
+ int i;
+ qglBegin(GL_TRIANGLES);
+ for (i = 0;i < numtriangles * 3;i++)
+ {
+ qglArrayElement(elements[i]);
+ }
+ qglEnd();
+ CHECKGLERROR
+ }
+ else if (gl_mesh_drawrangeelements.integer && qglDrawRangeElements != NULL)
+ {
+ qglDrawRangeElements(GL_TRIANGLES, firstvertex, firstvertex + numvertices, numelements, GL_UNSIGNED_INT, elements);
+ CHECKGLERROR
+ }
+ else
+ {
+ qglDrawElements(GL_TRIANGLES, numelements, GL_UNSIGNED_INT, elements);
+ CHECKGLERROR
+ }
+ }
+}
+
+// restores backend state, used when done with 3D rendering
+void R_Mesh_Finish(void)
+{
+ unsigned int i;
+ BACKENDACTIVECHECK
+ CHECKGLERROR
+ GL_LockArrays(0, 0);
+ CHECKGLERROR
+
+ for (i = 0;i < backendimageunits;i++)
+ {
+ GL_ActiveTexture(i);
+ qglBindTexture(GL_TEXTURE_1D, 0);CHECKGLERROR
+ qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR
+ if (gl_texture3d)
+ {
+ qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR
+ }
+ if (gl_texturecubemap)
+ {
+ qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
+ }
+ }
+ for (i = 0;i < backendarrayunits;i++)
+ {
+ GL_ActiveTexture(backendarrayunits - 1 - i);
+ qglDisableClientState(GL_TEXTURE_COORD_ARRAY);CHECKGLERROR
+ }
+ for (i = 0;i < backendunits;i++)
+ {
+ GL_ActiveTexture(backendunits - 1 - i);
+ qglDisable(GL_TEXTURE_1D);CHECKGLERROR
+ qglDisable(GL_TEXTURE_2D);CHECKGLERROR
+ if (gl_texture3d)
+ {
+ qglDisable(GL_TEXTURE_3D);CHECKGLERROR
+ }
+ if (gl_texturecubemap)
+ {
+ qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+ }
+ qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
+ if (gl_combine.integer)
+ {
+ qglTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1);CHECKGLERROR
+ qglTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);CHECKGLERROR
+ }
+ }
+ qglDisableClientState(GL_COLOR_ARRAY);CHECKGLERROR
+ qglDisableClientState(GL_VERTEX_ARRAY);CHECKGLERROR