#include "common.h"
#include "model.h"
+#include "camera.h"
#include "shaders/blit.h"
+#include "shaders/blitblur.h"
#include "shaders/standard.h"
#include "shaders/vblend.h"
-VG_STATIC void render_water_texture( m4x3f camera );
-VG_STATIC void render_water_surface( m4x4f pv, m4x3f camera );
-VG_STATIC void render_world( m4x4f projection, m4x3f camera );
+VG_STATIC void render_water_texture( camera *cam );
+VG_STATIC void render_water_surface( camera *cam );
+VG_STATIC void render_world( camera *cam );
VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id );
-VG_STATIC void render_world_depth( m4x4f projection, m4x3f camera );
+VG_STATIC void render_world_depth( camera *cam );
#ifndef RENDER_H
#define RENDER_H
-struct framebuffer
-{
- GLuint fb, colour, rb;
- int div;
- GLuint format;
+typedef struct framebuffer framebuffer;
- int allocated;
-};
+/*
+ * All standard buffers used in rendering
+ */
VG_STATIC struct pipeline
{
- float fov;
glmesh fsquad;
- GLuint fb_background,
- rgb_background;
+ framebuffer *fb_main,
+ *fb_heightmap,
+ *fb_water_reflection,
+ *fb_water_beneath;
/* STD140 */
struct ub_world_lighting
float g_water_fog;
int g_light_count;
int g_light_preview;
+ int g_shadow_samples;
}
ub_world_lighting;
widgets[3];
float shadow_spread, shadow_length;
-
- GLuint fb_depthmap, rgb_depthmap;
GLuint ubo_world_lighting,
ubo_world;
}
};
+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;
+
+ /* Runtime */
+ int debug_view;
+ }
+ 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", 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
+ }
+ }
+ }
+};
+
/*
- * Matrix Projections
- */
-/*
- * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
+ * Get the current (automatically scaled or fixed) resolution of framebuffer
*/
-VG_STATIC void plane_clip_projection( m4x4f mat, v4f plane )
+VG_STATIC void render_fb_get_current_res( struct framebuffer *fb,
+ int *x, int *y )
{
- v4f c =
+ if( fb->resolution_div )
{
- (vg_signf(plane[0]) + mat[2][0]) / mat[0][0],
- (vg_signf(plane[1]) + mat[2][1]) / mat[1][1],
- -1.0f,
- (1.0f + mat[2][2]) / mat[3][2]
- };
-
- v4_muls( plane, 2.0f / v4_dot(plane,c), c );
+ *x = vg.window_x / fb->resolution_div;
+ *y = vg.window_y / fb->resolution_div;
+ }
+ else
+ {
+ *x = fb->fixed_w;
+ *y = fb->fixed_h;
+ }
+}
- mat[0][2] = c[0];
- mat[1][2] = c[1];
- mat[2][2] = c[2] + 1.0f;
- mat[3][2] = c[3];
+/*
+ * 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 );
}
-VG_STATIC void pipeline_projection( m4x4f mat, float nearz, float farz )
+/*
+ * Bind framebuffer attachment's texture
+ */
+VG_STATIC void render_fb_bind_texture( framebuffer *fb,
+ int attachment, int slot )
{
- m4x4_projection( mat,
- gpipeline.fov,
- (float)vg.window_x / (float)vg.window_y,
- nearz, farz );
+ 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 );
}
+
/*
* Shaders
*/
GLuint idx = glGetUniformBlockIndex( shader, "ub_world_lighting" );
glUniformBlockBinding( shader, idx, 0 );
- glActiveTexture( GL_TEXTURE0 + texture_id );
- glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap );
+ render_fb_bind_texture( gpipeline.fb_heightmap, 0, texture_id );
glUniform1i( glGetUniformLocation( shader, "g_world_depth" ), texture_id );
}
winf->g_light_directions[0][3] = gpipeline.shadow_length;
winf->g_light_colours[0][3] = gpipeline.shadow_spread;
+ if( vg.quality_profile == k_quality_profile_low )
+ winf->g_shadow_samples = 0;
+ else
+ winf->g_shadow_samples = 8;
+
glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
&gpipeline.ub_world_lighting );
}
+#define FB_FORMAT_STR( E ) { E, #E },
+
/*
- * Framebuffers
+ * Convert OpenGL attachment ID enum to string
*/
+VG_STATIC const char *render_fb_attachment_str( GLenum e )
+{
+ struct { GLenum e; const char *str; }
+ formats[] =
+ {
+ FB_FORMAT_STR(GL_COLOR_ATTACHMENT0)
+ FB_FORMAT_STR(GL_COLOR_ATTACHMENT1)
+ FB_FORMAT_STR(GL_COLOR_ATTACHMENT2)
+ FB_FORMAT_STR(GL_COLOR_ATTACHMENT3)
+ FB_FORMAT_STR(GL_COLOR_ATTACHMENT4)
+ FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT)
+ };
+
+ for( int i=0; i<vg_list_size(formats); i++ )
+ if( formats[i].e == e )
+ return formats[i].str;
+
+ return "UNDEFINED";
+}
-VG_STATIC void fb_use( struct framebuffer *fb )
+/*
+ * Convert OpenGL texture format enums from TexImage2D table 1,2 &
+ * RenderBufferStorage Table 1, into strings
+ */
+VG_STATIC const char *render_fb_format_str( GLenum format )
{
- if( !fb )
+ struct { GLenum e; const char *str; }
+ formats[] =
+ {
+ /* Table 1 */
+ FB_FORMAT_STR(GL_DEPTH_COMPONENT)
+ FB_FORMAT_STR(GL_DEPTH_STENCIL)
+ FB_FORMAT_STR(GL_RED)
+ FB_FORMAT_STR(GL_RG)
+ FB_FORMAT_STR(GL_RGB)
+ FB_FORMAT_STR(GL_RGBA)
+
+ /* Render buffer formats */
+ FB_FORMAT_STR(GL_DEPTH_COMPONENT16)
+ FB_FORMAT_STR(GL_DEPTH_COMPONENT24)
+ FB_FORMAT_STR(GL_DEPTH_COMPONENT32F)
+ FB_FORMAT_STR(GL_DEPTH24_STENCIL8)
+ FB_FORMAT_STR(GL_DEPTH32F_STENCIL8)
+ FB_FORMAT_STR(GL_STENCIL_INDEX8)
+
+ /* Table 2 */
+ FB_FORMAT_STR(GL_R8)
+ FB_FORMAT_STR(GL_R8_SNORM)
+ FB_FORMAT_STR(GL_R16)
+ FB_FORMAT_STR(GL_R16_SNORM)
+ FB_FORMAT_STR(GL_RG8)
+ FB_FORMAT_STR(GL_RG8_SNORM)
+ FB_FORMAT_STR(GL_RG16)
+ FB_FORMAT_STR(GL_RG16_SNORM)
+ FB_FORMAT_STR(GL_R3_G3_B2)
+ FB_FORMAT_STR(GL_RGB4)
+ FB_FORMAT_STR(GL_RGB5)
+ FB_FORMAT_STR(GL_RGB8)
+ FB_FORMAT_STR(GL_RGB8_SNORM)
+ FB_FORMAT_STR(GL_RGB10)
+ FB_FORMAT_STR(GL_RGB12)
+ FB_FORMAT_STR(GL_RGB16_SNORM)
+ FB_FORMAT_STR(GL_RGBA2)
+ FB_FORMAT_STR(GL_RGBA4)
+ FB_FORMAT_STR(GL_RGB5_A1)
+ FB_FORMAT_STR(GL_RGBA8)
+ FB_FORMAT_STR(GL_RGBA8_SNORM)
+ FB_FORMAT_STR(GL_RGB10_A2)
+ FB_FORMAT_STR(GL_RGB10_A2UI)
+ FB_FORMAT_STR(GL_RGBA12)
+ FB_FORMAT_STR(GL_RGBA16)
+ FB_FORMAT_STR(GL_SRGB8)
+ FB_FORMAT_STR(GL_SRGB8_ALPHA8)
+ FB_FORMAT_STR(GL_R16F)
+ FB_FORMAT_STR(GL_RG16F)
+ FB_FORMAT_STR(GL_RGB16F)
+ FB_FORMAT_STR(GL_RGBA16F)
+ FB_FORMAT_STR(GL_R32F)
+ FB_FORMAT_STR(GL_RG32F)
+ FB_FORMAT_STR(GL_RGB32F)
+ FB_FORMAT_STR(GL_RGBA32F)
+ FB_FORMAT_STR(GL_R11F_G11F_B10F)
+ FB_FORMAT_STR(GL_RGB9_E5)
+ FB_FORMAT_STR(GL_R8I)
+ FB_FORMAT_STR(GL_R8UI)
+ FB_FORMAT_STR(GL_R16I)
+ FB_FORMAT_STR(GL_R16UI)
+ FB_FORMAT_STR(GL_R32I)
+ FB_FORMAT_STR(GL_R32UI)
+ FB_FORMAT_STR(GL_RG8I)
+ FB_FORMAT_STR(GL_RG8UI)
+ FB_FORMAT_STR(GL_RG16I)
+ FB_FORMAT_STR(GL_RG16UI)
+ FB_FORMAT_STR(GL_RG32I)
+ FB_FORMAT_STR(GL_RG32UI)
+ FB_FORMAT_STR(GL_RGB8I)
+ FB_FORMAT_STR(GL_RGB8UI)
+ FB_FORMAT_STR(GL_RGB16I)
+ FB_FORMAT_STR(GL_RGB16UI)
+ FB_FORMAT_STR(GL_RGB32I)
+ FB_FORMAT_STR(GL_RGB32UI)
+ FB_FORMAT_STR(GL_RGBA8I)
+ FB_FORMAT_STR(GL_RGBA8UI)
+ FB_FORMAT_STR(GL_RGBA16I)
+ FB_FORMAT_STR(GL_RGBA16UI)
+ FB_FORMAT_STR(GL_RGBA32I)
+ FB_FORMAT_STR(GL_RGBA32UI)
+ };
+
+ for( int i=0; i<vg_list_size(formats); i++ )
+ if( formats[i].e == format )
+ return formats[i].str;
+
+ return "UNDEFINED";
+}
+
+/*
+ * Bind and allocate texture for framebuffer attachment
+ */
+VG_STATIC void render_fb_allocate_texture( struct framebuffer *fb,
+ struct framebuffer_attachment *a )
+{
+ int rx, ry;
+ render_fb_get_current_res( fb, &rx, &ry );
+
+ if( a->purpose == k_framebuffer_attachment_type_renderbuffer )
{
- glBindFramebuffer( GL_FRAMEBUFFER, 0 );
- glViewport( 0, 0, vg.window_x, vg.window_y );
+ glBindRenderbuffer( GL_RENDERBUFFER, a->id );
+ glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, rx, ry );
}
- else
+ else if( a->purpose == k_framebuffer_attachment_type_colour )
{
- glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
- glViewport( 0, 0, vg.window_x / fb->div, vg.window_y / fb->div );
+ glBindTexture( GL_TEXTURE_2D, a->id );
+ glTexImage2D( GL_TEXTURE_2D, 0, a->internalformat, rx, ry,
+ 0, a->format, a->type, NULL );
}
}
-VG_STATIC void fb_init( struct framebuffer *fb )
+/*
+ * Full allocation of a framebuffer
+ */
+VG_STATIC void render_fb_allocate( struct framebuffer *fb )
{
- i32 ix = vg.window_x / fb->div,
- iy = vg.window_y / fb->div;
-
glGenFramebuffers( 1, &fb->fb );
glBindFramebuffer( GL_FRAMEBUFFER, fb->fb );
- glGenTextures( 1, &fb->colour );
- glBindTexture( GL_TEXTURE_2D, fb->colour );
- glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy,
- 0, fb->format, GL_UNSIGNED_BYTE, NULL);
+ int rx, ry;
+ render_fb_get_current_res( fb, &rx, &ry );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, fb->colour, 0);
+ vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry );
+ vg_info( "{\n" );
- glGenRenderbuffers( 1, &fb->rb );
- glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
- glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
+ GLenum colour_attachments[4];
+ u32 colour_count = 0;
- glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, fb->rb );
- glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+ for( int j=0; j<vg_list_size(fb->attachments); j++ )
+ {
+ struct framebuffer_attachment *attachment = &fb->attachments[j];
- VG_CHECK_GL_ERR();
- fb->allocated = 1;
-}
+ if( attachment->purpose == k_framebuffer_attachment_type_none )
+ continue;
-VG_STATIC void fb_free( struct framebuffer *fb )
-{
- glDeleteTextures( 1, &fb->colour );
- glDeleteFramebuffers( 1, &fb->fb );
-}
+ vg_info( " %s: %s\n",
+ render_fb_attachment_str( attachment->attachment ),
+ render_fb_format_str( attachment->internalformat ) );
-VG_STATIC void fb_bindtex( struct framebuffer *fb, int texture )
-{
- glActiveTexture( GL_TEXTURE0 + texture );
- glBindTexture( GL_TEXTURE_2D, fb->colour );
-}
+ if( attachment->purpose == k_framebuffer_attachment_type_renderbuffer )
+ {
+ glGenRenderbuffers( 1, &attachment->id );
+ render_fb_allocate_texture( fb, attachment );
+ glFramebufferRenderbuffer( GL_FRAMEBUFFER,
+ GL_DEPTH_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, attachment->id );
+ }
+ else if( attachment->purpose == k_framebuffer_attachment_type_colour )
+ {
+ glGenTextures( 1, &attachment->id );
+ render_fb_allocate_texture( fb, attachment );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
-VG_STATIC void fb_resize( struct framebuffer *fb )
-{
- if( !fb->allocated )
- return;
+ glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment,
+ GL_TEXTURE_2D, attachment->id, 0 );
- i32 ix = vg.window_x / fb->div,
- iy = vg.window_y / fb->div;
+ colour_attachments[ colour_count ++ ] = attachment->attachment;
+ }
+ }
- glBindTexture( GL_TEXTURE_2D, fb->colour );
- glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, 0,
- fb->format, GL_UNSIGNED_BYTE, NULL );
+ glDrawBuffers( colour_count, colour_attachments );
- glBindRenderbuffer( GL_RENDERBUFFER, fb->rb );
- glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy );
-}
+ /*
+ * Check result
+ */
+ GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER );
-VG_STATIC void render_fb_resize(void)
-{
- if( gpipeline.ready )
+ if( result == GL_FRAMEBUFFER_COMPLETE )
{
- glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg.window_x, vg.window_y, 0,
- GL_RGB, GL_UNSIGNED_BYTE, NULL );
+ /*
+ * Attatch to gpipeline
+ */
+ if( fb->link )
+ *fb->link = fb;
+
+ vg_success( " status: complete\n" );
+ vg_info( "}\n" );
+ }
+ else
+ {
+ if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT )
+ vg_error( " status: Incomplete attachment" );
+ else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT )
+ vg_error( " status: Missing attachment" );
+ else if( result == GL_FRAMEBUFFER_UNSUPPORTED )
+ vg_error( " status: Unsupported framebuffer format" );
+ else
+ vg_error( " status: Generic Error" );
+
+ vg_info( "}\n" );
+ vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" );
}
}
-/* used for drawing player onto */
-VG_STATIC void render_init_temp_buffer(void)
-{
- vg_info( "[render] Allocate temporary framebuffer\n" );
-
- glGenFramebuffers( 1, &gpipeline.fb_background );
- glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background );
-
- glGenTextures( 1, &gpipeline.rgb_background );
- glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg.window_x, vg.window_y,
- 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
-
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- gpipeline.rgb_background, 0);
-
- VG_CHECK_GL_ERR();
-}
-
-/* used for drawing world depth from the top view, used in our water and
- * lighting calculations */
-VG_STATIC void render_init_depthmap_buffer(void)
+/*
+ * Resize/Update all framebuffers(we know about)
+ */
+VG_STATIC void render_fb_resize(void)
{
- vg_info( "[render] Allocate depth map buffer\n" );
-
- glGenFramebuffers( 1, &gpipeline.fb_depthmap );
- glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
-
- glGenTextures( 1, &gpipeline.rgb_depthmap );
- glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0,
- GL_RED, GL_FLOAT, NULL );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- vg_tex2d_clamp();
-
- glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- gpipeline.rgb_depthmap, 0);
+ if( !gpipeline.ready )
+ return;
- VG_CHECK_GL_ERR();
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+ for( int j=0; j<vg_list_size(fb->attachments); j++ )
+ {
+ struct framebuffer_attachment *attachment = &fb->attachments[j];
+ render_fb_allocate_texture( fb, attachment );
+ }
+ }
}
+VG_STATIC int render_framebuffer_control( int argc, char const *argv[] );
+VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] );
VG_STATIC void render_init_fs_quad(void)
{
vg_info( "[render] Allocate quad\n" );
- float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
- 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f };
+ float quad[] =
+ {
+ 0.00f,0.00f, 1.00f,1.00f, 0.00f,1.00f,
+ 0.00f,0.00f, 1.00f,0.00f, 1.00f,1.00f,
+
+ 0.20f,0.00f, 0.80f,1.00f, 0.20f,1.00f,
+ 0.20f,0.00f, 0.80f,0.00f, 0.80f,1.00f,
+
+ /* 9x9 debug grid */
+ /* row0 */
+ 0.00f,0.00f, 0.30f,0.30f, 0.00f,0.30f,
+ 0.00f,0.00f, 0.30f,0.00f, 0.30f,0.30f,
+ 0.30f,0.00f, 0.60f,0.30f, 0.30f,0.30f,
+ 0.30f,0.00f, 0.60f,0.00f, 0.60f,0.30f,
+ 0.60f,0.00f, 0.90f,0.30f, 0.60f,0.30f,
+ 0.60f,0.00f, 0.90f,0.00f, 0.90f,0.30f,
+ /* row1 */
+ 0.00f,0.30f, 0.30f,0.60f, 0.00f,0.60f,
+ 0.00f,0.30f, 0.30f,0.30f, 0.30f,0.60f,
+ 0.30f,0.30f, 0.60f,0.60f, 0.30f,0.60f,
+ 0.30f,0.30f, 0.60f,0.30f, 0.60f,0.60f,
+ 0.60f,0.30f, 0.90f,0.60f, 0.60f,0.60f,
+ 0.60f,0.30f, 0.90f,0.30f, 0.90f,0.60f,
+ /* row2 */
+ 0.00f,0.60f, 0.30f,0.90f, 0.00f,0.90f,
+ 0.00f,0.60f, 0.30f,0.60f, 0.30f,0.90f,
+ 0.30f,0.60f, 0.60f,0.90f, 0.30f,0.90f,
+ 0.30f,0.60f, 0.60f,0.60f, 0.60f,0.90f,
+ 0.60f,0.60f, 0.90f,0.90f, 0.60f,0.90f,
+ 0.60f,0.60f, 0.90f,0.60f, 0.90f,0.90f,
+ };
+
+ vg_function_push( (struct vg_cmd)
+ {
+ .name = "fb",
+ .function = render_framebuffer_control,
+ .poll_suggest = render_framebuffer_poll
+ });
glGenVertexArrays( 1, &gpipeline.fsquad.vao );
glGenBuffers( 1, &gpipeline.fsquad.vbo );
glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
glBindVertexArray( gpipeline.fsquad.vao );
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
- sizeof(float)*2, (void*)0 );
+ sizeof(float)*2, (void*)0 );
glEnableVertexAttribArray( 0 );
VG_CHECK_GL_ERR();
VG_STATIC void render_init(void)
{
shader_blit_register();
+ shader_blitblur_register();
shader_standard_register();
shader_vblend_register();
vg_acquire_thread_sync();
{
- render_init_temp_buffer();
- render_init_depthmap_buffer();
+ /*
+ * Complete Framebuffers
+ */
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+ render_fb_allocate( fb );
+ }
+
render_init_fs_quad();
render_init_uniform_buffers();
glDrawArrays( GL_TRIANGLES, 0, 6 );
}
+VG_STATIC void render_fsquad1(void)
+{
+ glBindVertexArray( gpipeline.fsquad.vao );
+ glDrawArrays( GL_TRIANGLES, 6, 6 );
+}
+
+/*
+ * Call this inside the UI function
+ */
+VG_STATIC void render_view_framebuffer_ui(void)
+{
+ int viewing_count = 0;
+
+ glBindVertexArray( gpipeline.fsquad.vao );
+ shader_blit_use();
+ shader_blit_uTexMain( 0 );
+
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+
+ for( int j=0; j<vg_list_size(fb->attachments); j++ )
+ {
+ struct framebuffer_attachment *at = &fb->attachments[j];
+
+ if( !at->debug_view )
+ continue;
+
+ v2f corner,
+ window = { vg.window_x, vg.window_y };
+
+ corner[0] = viewing_count % 3;
+ corner[1] = 1 + (viewing_count / 3);
+ v2_mul( corner, window, corner );
+ v2_muls( corner, 0.3f, corner );
+ corner[1] = vg.window_y - corner[1];
+
+ ui_text( (ui_rect){ corner[0], corner[1], 0.0f, 0.0f },
+ fb->display_name, 2, k_text_align_left );
+ ui_text( (ui_rect){ corner[0], corner[1] + 32, 0.0f, 0.0f, },
+ at->display_name, 1, k_text_align_left );
+
+ if( at->purpose == k_framebuffer_attachment_type_renderbuffer )
+ {
+ v2f center;
+ v2_muladds( corner, window, 0.15f, center );
+
+ ui_text( (ui_rect){ center[0], center[1], 0.0f, 0.0f },
+ "<hardware texture>", 1, k_text_align_center );
+ }
+ else
+ {
+ render_fb_bind_texture( fb, j, 0 );
+
+ int start = (viewing_count+2) * 6,
+ count = 6;
+ glDrawArrays( GL_TRIANGLES, start, count );
+ }
+
+ viewing_count ++;
+ }
+ }
+}
+
+VG_STATIC void render_framebuffer_show( struct framebuffer *fb,
+ struct framebuffer_attachment *at,
+ int operation )
+{
+ at->debug_view = operation;
+ vg_info( "%s %s:%s\n", (operation?"shown": "hidden"),
+ fb->display_name, at->display_name );
+}
+
+/*
+ * arg0: command "show"/"hide"
+ * arg1: framebuffer name <name>/"all"
+ * arg2: subname <name>/none
+ */
+VG_STATIC int render_framebuffer_control( int argc, char const *argv[] )
+{
+ if( argc < 2 )
+ {
+ vg_error( "Usage: fb \"show/hide\" <name>/\"all\" <name>/none\n" );
+ return 0;
+ }
+
+ int modify_all = 0,
+ operation = 0;
+
+ if( !strcmp( argv[0], "show" ) )
+ operation = 1;
+ else if( !strcmp( argv[0], "hide" ) )
+ operation = 0;
+ else
+ {
+ vg_error( "Unknown framebuffer operation: '%s'\n", argv[0] );
+ return 0;
+ }
+
+ if( !strcmp( argv[1], "all" ) )
+ modify_all = 1;
+
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+
+ for( int j=0; j<vg_list_size(fb->attachments); j++ )
+ {
+ struct framebuffer_attachment *at = &fb->attachments[j];
+
+ if( at->purpose == k_framebuffer_attachment_type_none )
+ continue;
+
+ if( modify_all )
+ {
+ render_framebuffer_show( fb, at, operation );
+ }
+ else
+ {
+ if( !strcmp( fb->display_name, argv[1] ) )
+ {
+ if( argc == 2 )
+ render_framebuffer_show( fb, at, operation );
+ else if( !strcmp( at->display_name, argv[2] ) )
+ render_framebuffer_show( fb, at, operation );
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+VG_STATIC void render_framebuffer_poll( int argc, char const *argv[] )
+{
+ const char *term = argv[argc-1];
+
+ if( argc == 1 )
+ {
+ console_suggest_score_text( "show", term, 0 );
+ console_suggest_score_text( "hide", term, 0 );
+ }
+ else if( argc == 2 )
+ {
+ console_suggest_score_text( "all", term, 0 );
+
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+ console_suggest_score_text( fb->display_name, term, 0 );
+ }
+ }
+ else if( argc == 3 )
+ {
+ int modify_all = 0;
+
+ if( !strcmp( argv[1], "all" ) )
+ modify_all = 1;
+
+ for( int i=0; i<vg_list_size(framebuffers); i++ )
+ {
+ struct framebuffer *fb = &framebuffers[i];
+
+ for( int j=0; j<vg_list_size(fb->attachments); j++ )
+ {
+ struct framebuffer_attachment *at = &fb->attachments[j];
+
+ if( at->purpose == k_framebuffer_attachment_type_none )
+ continue;
+
+ if( modify_all )
+ {
+ console_suggest_score_text( at->display_name, term, 0 );
+ }
+ else if( !strcmp( fb->display_name, argv[1] ) )
+ {
+ console_suggest_score_text( at->display_name, term, 0 );
+ }
+ }
+ }
+ }
+}
+
#endif /* RENDER_H */