+void R_RenderTarget_FreeUnused(qboolean force)
+{
+ int i, j, end;
+ end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
+ for (i = 0; i < end; i++)
+ {
+ r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
+ // free resources for rendertargets that have not been used for a while
+ // (note: this check is run after the frame render, so any targets used
+ // this frame will not be affected even at low framerates)
+ if (r && (realtime - r->lastusetime > 0.2 || force))
+ {
+ if (r->fbo)
+ R_Mesh_DestroyFramebufferObject(r->fbo);
+ for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
+ if (r->colortexture[j])
+ R_FreeTexture(r->colortexture[j]);
+ if (r->depthtexture)
+ R_FreeTexture(r->depthtexture);
+ Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
+ }
+ }
+}
+
+static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
+{
+ float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_D3D9:
+ x1 = (x + 0.5f) * iw;
+ x2 = (x + 0.5f + w) * iw;
+ y1 = (y + 0.5f) * ih;
+ y2 = (y + 0.5f + h) * ih;
+ break;
+ default:
+ x1 = x * iw;
+ x2 = (x + w) * iw;
+ y1 = (th - y) * ih;
+ y2 = (th - y - h) * ih;
+ break;
+ }
+ texcoord2f[0] = x1;
+ texcoord2f[2] = x2;
+ texcoord2f[4] = x2;
+ texcoord2f[6] = x1;
+ texcoord2f[1] = y1;
+ texcoord2f[3] = y1;
+ texcoord2f[5] = y2;
+ texcoord2f[7] = y2;
+}
+
+r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
+{
+ int i, j, end;
+ r_rendertarget_t *r = NULL;
+ char vabuf[256];
+ // first try to reuse an existing slot if possible
+ end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
+ for (i = 0; i < end; i++)
+ {
+ r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
+ if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
+ break;
+ }
+ if (i == end)
+ {
+ // no unused exact match found, so we have to make one in the first unused slot
+ r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
+ r->texturewidth = texturewidth;
+ r->textureheight = textureheight;
+ r->colortextype[0] = colortextype0;
+ r->colortextype[1] = colortextype1;
+ r->colortextype[2] = colortextype2;
+ r->colortextype[3] = colortextype3;
+ r->depthtextype = depthtextype;
+ r->depthisrenderbuffer = depthisrenderbuffer;
+ for (j = 0; j < 4; j++)
+ if (r->colortextype[j])
+ r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+ if (r->depthtextype)
+ {
+ if (r->depthisrenderbuffer)
+ r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
+ else
+ r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
+ }
+ r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
+ }
+ r_refdef.stats[r_stat_rendertargets_used]++;
+ r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
+ r->lastusetime = realtime;
+ R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
+ return r;
+}
+