+ qglBindBufferARB(GL_UNIFORM_BUFFER, bufferobject);CHECKGLERROR
+#endif
+ }
+}
+
+static const GLuint drawbuffers[4] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3};
+int R_Mesh_CreateFramebufferObject(rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
+{
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES2:
+ if (vid.support.arb_framebuffer_object)
+ {
+ int temp;
+ GLuint status;
+ qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
+ R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
+ // GL_ARB_framebuffer_object (GL3-class hardware) - depth stencil attachment
+#ifdef USE_GLES2
+ // FIXME: separate stencil attachment on GLES
+ if (depthtexture && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+ if (depthtexture && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+#else
+ if (depthtexture && depthtexture->texnum )
+ {
+ qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+ if (depthtexture->glisdepthstencil) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+ }
+ if (depthtexture && depthtexture->renderbuffernum )
+ {
+ qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+ if (depthtexture->glisdepthstencil) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+ }
+#endif
+ if (colortexture && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR
+ if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR
+ if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR
+ if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR
+ if (colortexture && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR
+ if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR
+ if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR
+ if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR
+
+#ifndef USE_GLES2
+ if (colortexture4 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture3 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture2 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture && qglDrawBuffer)
+ {
+ qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+ qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+ }
+ else if (qglDrawBuffer)
+ {
+ qglDrawBuffer(GL_NONE);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+#endif
+ status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
+ gl_state.framebufferobject = 0; // GL unbinds it for us
+ qglDeleteFramebuffers(1, (GLuint*)&temp);
+ temp = 0;
+ }
+ return temp;
+ }
+ else if (vid.support.ext_framebuffer_object)
+ {
+ int temp;
+ GLuint status;
+ qglGenFramebuffers(1, (GLuint*)&temp);CHECKGLERROR
+ R_Mesh_SetRenderTargets(temp, NULL, NULL, NULL, NULL, NULL);
+ // GL_EXT_framebuffer_object (GL2-class hardware) - no depth stencil attachment, let it break stencil
+ if (depthtexture && depthtexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , depthtexture->gltexturetypeenum , depthtexture->texnum , 0);CHECKGLERROR
+ if (depthtexture && depthtexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, depthtexture->renderbuffernum );CHECKGLERROR
+ if (colortexture && colortexture->texnum ) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , colortexture->gltexturetypeenum , colortexture->texnum , 0);CHECKGLERROR
+ if (colortexture2 && colortexture2->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , colortexture2->gltexturetypeenum, colortexture2->texnum, 0);CHECKGLERROR
+ if (colortexture3 && colortexture3->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , colortexture3->gltexturetypeenum, colortexture3->texnum, 0);CHECKGLERROR
+ if (colortexture4 && colortexture4->texnum) qglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , colortexture4->gltexturetypeenum, colortexture4->texnum, 0);CHECKGLERROR
+ if (colortexture && colortexture->renderbuffernum ) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_RENDERBUFFER, colortexture->renderbuffernum );CHECKGLERROR
+ if (colortexture2 && colortexture2->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_RENDERBUFFER, colortexture2->renderbuffernum);CHECKGLERROR
+ if (colortexture3 && colortexture3->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_RENDERBUFFER, colortexture3->renderbuffernum);CHECKGLERROR
+ if (colortexture4 && colortexture4->renderbuffernum) qglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_RENDERBUFFER, colortexture4->renderbuffernum);CHECKGLERROR
+
+#ifndef USE_GLES2
+ if (colortexture4 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(4, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture3 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(3, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture2 && qglDrawBuffersARB)
+ {
+ qglDrawBuffersARB(2, drawbuffers);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+ else if (colortexture && qglDrawBuffer)
+ {
+ qglDrawBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+ qglReadBuffer(GL_COLOR_ATTACHMENT0);CHECKGLERROR
+ }
+ else if (qglDrawBuffer)
+ {
+ qglDrawBuffer(GL_NONE);CHECKGLERROR
+ qglReadBuffer(GL_NONE);CHECKGLERROR
+ }
+#endif
+ status = qglCheckFramebufferStatus(GL_FRAMEBUFFER);CHECKGLERROR
+ if (status != GL_FRAMEBUFFER_COMPLETE)
+ {
+ Con_Printf("R_Mesh_CreateFramebufferObject: glCheckFramebufferStatus returned %i\n", status);
+ gl_state.framebufferobject = 0; // GL unbinds it for us
+ qglDeleteFramebuffers(1, (GLuint*)&temp);
+ temp = 0;
+ }
+ return temp;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+void R_Mesh_DestroyFramebufferObject(int fbo)
+{
+ switch(vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES2:
+ if (fbo)
+ {
+ // GL clears the binding if we delete something bound
+ if (gl_state.framebufferobject == fbo)
+ gl_state.framebufferobject = 0;
+ qglDeleteFramebuffers(1, (GLuint*)&fbo);
+ }
+ break;
+ }
+}
+
+void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, rtexture_t *colortexture2, rtexture_t *colortexture3, rtexture_t *colortexture4)
+{
+ unsigned int i;
+ unsigned int j;
+ rtexture_t *textures[5];
+ Vector4Set(textures, colortexture, colortexture2, colortexture3, colortexture4);
+ textures[4] = depthtexture;
+ // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target
+ for (j = 0;j < 5;j++)
+ if (textures[j])
+ for (i = 0;i < vid.teximageunits;i++)
+ if (gl_state.units[i].texture == textures[j])
+ R_Mesh_TexBind(i, NULL);
+ // set up framebuffer object or render targets for the active rendering API
+ switch (vid.renderpath)
+ {
+ case RENDERPATH_GL20:
+ case RENDERPATH_GLES2:
+ if (gl_state.framebufferobject != fbo)
+ {
+ gl_state.framebufferobject = fbo;
+ qglBindFramebuffer(GL_FRAMEBUFFER, gl_state.framebufferobject ? gl_state.framebufferobject : gl_state.defaultframebufferobject);
+ }
+ break;