+ if (gl_state.lockrange_count)
+ {
+ gl_state.lockrange_count = 0;
+ CHECKGLERROR
+ qglUnlockArraysEXT();
+ CHECKGLERROR
+ }
+ if (count && gl_supportslockarrays && gl_lockarrays.integer && r_render.integer)
+ {
+ gl_state.lockrange_first = first;
+ gl_state.lockrange_count = count;
+ CHECKGLERROR
+ qglLockArraysEXT(first, count);
+ CHECKGLERROR
+ }
+ }
+}
+
+void GL_Scissor (int x, int y, int width, int height)
+{
+ CHECKGLERROR
+ qglScissor(x, vid.height - (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)
+{
+ CHECKGLERROR
+ 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
+ if (gl_printcheckerror.integer && !gl_paranoid.integer)
+ {
+ Con_Printf("WARNING: gl_printcheckerror is on but gl_paranoid is off, turning it on...\n");
+ Cvar_SetValueQuick(&gl_paranoid, 1);
+ }
+ 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[MAX_INPUTLINE];
+ CHECKGLERROR
+
+ programobject = qglCreateProgramObjectARB();CHECKGLERROR
+ if (!programobject)
+ return 0;
+
+ if (developer.integer >= 100)
+ {
+ int i;
+ Con_Printf("Compiling shader:\n");
+ if (vertexstrings_count)
+ {
+ Con_Printf("------ VERTEX SHADER ------\n");
+ for (i = 0;i < vertexstrings_count;i++)
+ Con_Print(vertexstrings_list[i]);
+ Con_Print("\n");
+ }
+ if (fragmentstrings_count)
+ {
+ Con_Printf("------ FRAGMENT SHADER ------\n");
+ for (i = 0;i < fragmentstrings_count;i++)
+ Con_Print(fragmentstrings_list[i]);
+ Con_Print("\n");
+ }
+ }
+
+ if (vertexstrings_count)
+ {
+ vertexshaderobject = qglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);CHECKGLERROR
+ if (!vertexshaderobject)
+ {
+ qglDeleteObjectARB(programobject);
+ CHECKGLERROR
+ return 0;
+ }
+ qglShaderSourceARB(vertexshaderobject, vertexstrings_count, vertexstrings_list, NULL);CHECKGLERROR
+ qglCompileShaderARB(vertexshaderobject);CHECKGLERROR
+ qglGetObjectParameterivARB(vertexshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &vertexshadercompiled);CHECKGLERROR
+ qglGetInfoLogARB(vertexshaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
+ if (compilelog[0])
+ Con_DPrintf("vertex shader compile log:\n%s\n", compilelog);
+ if (!vertexshadercompiled)
+ {
+ qglDeleteObjectARB(programobject);CHECKGLERROR
+ qglDeleteObjectARB(vertexshaderobject);CHECKGLERROR
+ return 0;
+ }
+ qglAttachObjectARB(programobject, vertexshaderobject);CHECKGLERROR
+ qglDeleteObjectARB(vertexshaderobject);CHECKGLERROR
+ }
+
+ if (fragmentstrings_count)
+ {
+ fragmentshaderobject = qglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);CHECKGLERROR
+ if (!fragmentshaderobject)
+ {
+ qglDeleteObjectARB(programobject);CHECKGLERROR
+ return 0;
+ }
+ qglShaderSourceARB(fragmentshaderobject, fragmentstrings_count, fragmentstrings_list, NULL);CHECKGLERROR
+ qglCompileShaderARB(fragmentshaderobject);CHECKGLERROR
+ qglGetObjectParameterivARB(fragmentshaderobject, GL_OBJECT_COMPILE_STATUS_ARB, &fragmentshadercompiled);CHECKGLERROR
+ qglGetInfoLogARB(fragmentshaderobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
+ if (compilelog[0])
+ Con_DPrintf("fragment shader compile log:\n%s\n", compilelog);
+ if (!fragmentshadercompiled)
+ {
+ qglDeleteObjectARB(programobject);CHECKGLERROR
+ qglDeleteObjectARB(fragmentshaderobject);CHECKGLERROR
+ return 0;
+ }
+ qglAttachObjectARB(programobject, fragmentshaderobject);CHECKGLERROR
+ qglDeleteObjectARB(fragmentshaderobject);CHECKGLERROR
+ }
+
+ qglLinkProgramARB(programobject);CHECKGLERROR
+ qglGetObjectParameterivARB(programobject, GL_OBJECT_LINK_STATUS_ARB, &programlinked);CHECKGLERROR
+ qglGetInfoLogARB(programobject, sizeof(compilelog), NULL, compilelog);CHECKGLERROR
+ if (compilelog[0])
+ {
+ Con_DPrintf("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;
+ }
+ if (!programlinked)
+ {
+ qglDeleteObjectARB(programobject);CHECKGLERROR
+ 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
+ r_refdef.stats.meshes++;
+ r_refdef.stats.meshes_elements += 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");
+ CHECKGLERROR
+ 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");
+ CHECKGLERROR
+ 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++)