+struct framebuffer
+{
+ const char *display_name;
+ int resolution_div,
+ fixed_w,
+ fixed_h;
+
+ struct framebuffer_attachment
+ {
+ const char *display_name;
+
+ enum framebuffer_attachment_type
+ {
+ k_framebuffer_attachment_type_none,
+ k_framebuffer_attachment_type_colour,
+ k_framebuffer_attachment_type_renderbuffer
+ }
+ purpose;
+
+ enum framebuffer_quality_profile
+ {
+ k_framebuffer_quality_all,
+ k_framebuffer_quality_high_only
+ }
+ quality;
+
+ GLenum internalformat,
+ format,
+ type,
+ attachment;
+
+ GLuint id;
+ }
+ attachments[5];
+ GLuint fb;
+ framebuffer **link;
+}
+framebuffers[] =
+{
+ {
+ /*
+ * The primary draw target
+ */
+ "Main",
+ .link = &gpipeline.fb_main,
+ .resolution_div = 1,
+ .attachments =
+ {
+ {
+ "Colour", k_framebuffer_attachment_type_colour,
+
+ .internalformat = GL_RGB,
+ .format = GL_RGB,
+ .type = GL_UNSIGNED_BYTE,
+ .attachment = GL_COLOR_ATTACHMENT0
+ },
+ {
+ "Motion Vectors", k_framebuffer_attachment_type_colour,
+
+ .quality = k_framebuffer_quality_high_only,
+ .internalformat = GL_RG16F,
+ .format = GL_RG,
+ .type = GL_FLOAT,
+ .attachment = GL_COLOR_ATTACHMENT1
+ },
+ {
+ "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+
+ .internalformat = GL_DEPTH24_STENCIL8,
+ .attachment = GL_DEPTH_STENCIL_ATTACHMENT
+ }
+ }
+ },
+ {
+ /*
+ * A ortho projection of the world, used for shadows and ocean colouring.
+ * Note: it does not have a render buffer attachement because it's
+ * intended to be drawn to in a MAX blending mode
+ */
+ "Heightmap",
+ .link = &gpipeline.fb_heightmap,
+ .fixed_w = 1024,
+ .fixed_h = 1024,
+
+ .attachments =
+ {
+ {
+ "Depth", k_framebuffer_attachment_type_colour,
+
+ .internalformat = GL_R32F,
+ .format = GL_RED,
+ .type = GL_FLOAT,
+ .attachment = GL_COLOR_ATTACHMENT0
+ }
+ }
+ },
+ {
+ /*
+ * Second rendered view from the perspective of the water reflection
+ */
+ "Water reflection",
+ .link = &gpipeline.fb_water_reflection,
+ .resolution_div = 3,
+ .attachments =
+ {
+ {
+ "Colour", k_framebuffer_attachment_type_colour,
+ .internalformat = GL_RGB,
+ .format = GL_RGB,
+ .type = GL_UNSIGNED_BYTE,
+ .attachment = GL_COLOR_ATTACHMENT0
+ },
+ {
+ "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+
+ .internalformat = GL_DEPTH24_STENCIL8,
+ .attachment = GL_DEPTH_STENCIL_ATTACHMENT
+ }
+ }
+ },
+ {
+ /*
+ * Thid rendered view from the perspective of the camera, but just
+ * captures stuff thats under the water
+ */
+ "Water Beneath",
+ .link = &gpipeline.fb_water_beneath,
+ .resolution_div = 4,
+ .attachments =
+ {
+ {
+ "Colour", k_framebuffer_attachment_type_colour,
+ .internalformat = GL_RGBA,
+ .format = GL_RGBA,
+ .type = GL_UNSIGNED_BYTE,
+ .attachment = GL_COLOR_ATTACHMENT0
+ },
+ {
+ "Depth/Stencil", k_framebuffer_attachment_type_renderbuffer,
+
+ .internalformat = GL_DEPTH24_STENCIL8,
+ .attachment = GL_DEPTH_STENCIL_ATTACHMENT
+ }
+ }
+ }
+};
+
+/*
+ * Get the current (automatically scaled or fixed) resolution of framebuffer
+ */
+VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
+ int *x, int *y )
+{
+ if( fb->resolution_div )
+ {
+ *x = vg.window_x / fb->resolution_div;
+ *y = vg.window_y / fb->resolution_div;
+ }
+ else
+ {
+ *x = fb->fixed_w;
+ *y = fb->fixed_h;
+ }
+}
+
+/*
+ * Bind framebuffer for drawing to
+ */
+VG_STATIC void render_fb_bind( framebuffer *fb )
+{
+ int x, y;
+ render_fb_get_current_res( fb, &x, &y );
+ glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
+ glViewport( 0, 0, x, y );
+}
+
+/*
+ * Bind framebuffer attachment's texture
+ */
+VG_STATIC void render_fb_bind_texture( framebuffer *fb,
+ int attachment, int slot )
+{
+ struct framebuffer_attachment *at = &fb->attachments[attachment];
+
+ if( at->purpose != k_framebuffer_attachment_type_colour )
+ {
+ vg_fatal_exit_loop( "illegal operation: bind non-colour framebuffer"
+ " attachment to texture slot" );
+ }
+
+ glActiveTexture( GL_TEXTURE0 + slot );
+ glBindTexture( GL_TEXTURE_2D, fb->attachments[attachment].id );
+}
+
+