+ Cmd_AddCommand(CF_CLIENT, "gl_vbostats", GL_VBOStats_f, "prints a list of all buffer objects (vertex data and triangle elements) and total video memory used by them");
+
+ R_RegisterModule("GL_Backend", gl_backend_start, gl_backend_shutdown, gl_backend_newmap, gl_backend_devicelost, gl_backend_devicerestored);
+}
+
+void GL_SetMirrorState(qbool state);
+
+void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
+{
+ vec4_t temp;
+ float iw;
+ Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
+ Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
+ iw = 1.0f / out[3];
+ out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
+
+ // for an odd reason, inverting this is wrong for R_Shadow_ScissorForBBox (we then get badly scissored lights)
+ //out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
+ out[1] = v->y + (out[1] * iw + 1.0f) * v->height * 0.5f;
+
+ out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
+}
+
+void GL_Finish(void)
+{
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL32:
+ case RENDERPATH_GLES2:
+ CHECKGLERROR
+ qglFinish();CHECKGLERROR
+ break;
+ }
+}
+
+static int bboxedges[12][2] =
+{
+ // top
+ {0, 1}, // +X
+ {0, 2}, // +Y
+ {1, 3}, // Y, +X
+ {2, 3}, // X, +Y
+ // bottom
+ {4, 5}, // +X
+ {4, 6}, // +Y
+ {5, 7}, // Y, +X
+ {6, 7}, // X, +Y
+ // verticals
+ {0, 4}, // +Z
+ {1, 5}, // X, +Z
+ {2, 6}, // Y, +Z
+ {3, 7}, // XY, +Z
+};
+
+qbool R_ScissorForBBox(const float *mins, const float *maxs, int *scissor)
+{
+ int i, ix1, iy1, ix2, iy2;
+ float x1, y1, x2, y2;
+ vec4_t v, v2;
+ float vertex[20][3];
+ int j, k;
+ vec4_t plane4f;
+ int numvertices;
+ float corner[8][4];
+ float dist[8];
+ int sign[8];
+ float f;
+
+ scissor[0] = r_refdef.view.viewport.x;
+ scissor[1] = r_refdef.view.viewport.y;
+ scissor[2] = r_refdef.view.viewport.width;
+ scissor[3] = r_refdef.view.viewport.height;
+
+ // if view is inside the box, just say yes it's visible
+ if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
+ return false;
+
+ // transform all corners that are infront of the nearclip plane
+ VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
+ plane4f[3] = r_refdef.view.frustum[4].dist;
+ numvertices = 0;
+ for (i = 0;i < 8;i++)
+ {
+ Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
+ dist[i] = DotProduct4(corner[i], plane4f);
+ sign[i] = dist[i] > 0;
+ if (!sign[i])
+ {
+ VectorCopy(corner[i], vertex[numvertices]);
+ numvertices++;
+ }
+ }
+ // if some points are behind the nearclip, add clipped edge points to make
+ // sure that the scissor boundary is complete
+ if (numvertices > 0 && numvertices < 8)
+ {
+ // add clipped edge points
+ for (i = 0;i < 12;i++)
+ {
+ j = bboxedges[i][0];
+ k = bboxedges[i][1];
+ if (sign[j] != sign[k])
+ {
+ f = dist[j] / (dist[j] - dist[k]);
+ VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
+ numvertices++;
+ }
+ }
+ }
+
+ // if we have no points to check, it is behind the view plane
+ if (!numvertices)
+ return true;
+
+ // if we have some points to transform, check what screen area is covered
+ x1 = y1 = x2 = y2 = 0;
+ v[3] = 1.0f;
+ //Con_Printf("%i vertices to transform...\n", numvertices);
+ for (i = 0;i < numvertices;i++)
+ {
+ VectorCopy(vertex[i], v);
+ R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
+ //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
+ if (i)
+ {
+ if (x1 > v2[0]) x1 = v2[0];
+ if (x2 < v2[0]) x2 = v2[0];
+ if (y1 > v2[1]) y1 = v2[1];
+ if (y2 < v2[1]) y2 = v2[1];
+ }
+ else
+ {
+ x1 = x2 = v2[0];
+ y1 = y2 = v2[1];
+ }
+ }
+
+ // now convert the scissor rectangle to integer screen coordinates
+ ix1 = (int)(x1 - 1.0f);
+ //iy1 = vid.height - (int)(y2 - 1.0f);
+ //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
+ iy1 = (int)(y1 - 1.0f);
+ ix2 = (int)(x2 + 1.0f);
+ //iy2 = vid.height - (int)(y1 + 1.0f);
+ //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
+ iy2 = (int)(y2 + 1.0f);
+ //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);