X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=render.h;h=0bb4c3330bd42a878940e26feae5f9fb5213422a;hb=c88172d6968a02a4e643b74cc419c0ac8168d92a;hp=58c88311d76af42a6a6c7860af46f2224db3a9f8;hpb=f7db507815e2822d971031c30f25e02b45e9c914;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/render.h b/render.h index 58c8831..0bb4c33 100644 --- a/render.h +++ b/render.h @@ -20,29 +20,20 @@ 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 { -#if 0 - float fov; -#endif glmesh fsquad; - GLuint fb_background, - rgb_background, - mv_background, - rb_background; + framebuffer *fb_main, + *fb_heightmap, + *fb_water_reflection, + *fb_water_beneath; /* STD140 */ struct ub_world_lighting @@ -71,8 +62,6 @@ VG_STATIC struct pipeline widgets[3]; float shadow_spread, shadow_length; - - GLuint fb_depthmap, rgb_depthmap; GLuint ubo_world_lighting, ubo_world; @@ -107,6 +96,201 @@ gpipeline = } }; +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 ); +} + + /* * Shaders */ @@ -115,8 +299,7 @@ VG_STATIC void shader_link_standard_ub( GLuint shader, int texture_id ) 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 ); } @@ -157,181 +340,252 @@ VG_STATIC void render_update_lighting_ub(void) &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; ipurpose == k_framebuffer_attachment_type_renderbuffer ) { - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); - 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); - - 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); - - glGenRenderbuffers( 1, &fb->rb ); - glBindRenderbuffer( GL_RENDERBUFFER, fb->rb ); - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy ); - - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, fb->rb ); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + int rx, ry; + render_fb_get_current_res( fb, &rx, &ry ); - VG_CHECK_GL_ERR(); - fb->allocated = 1; -} + vg_info( "allocate_framebuffer( %s, %dx%d )\n", fb->display_name, rx, ry ); + vg_info( "{\n" ); -VG_STATIC void fb_free( struct framebuffer *fb ) -{ - glDeleteTextures( 1, &fb->colour ); - glDeleteFramebuffers( 1, &fb->fb ); -} + GLenum colour_attachments[4]; + u32 colour_count = 0; -VG_STATIC void fb_bindtex( struct framebuffer *fb, int texture ) -{ - glActiveTexture( GL_TEXTURE0 + texture ); - glBindTexture( GL_TEXTURE_2D, fb->colour ); -} - -VG_STATIC void fb_resize( struct framebuffer *fb ) -{ - if( !fb->allocated ) - return; + for( int j=0; jattachments); j++ ) + { + struct framebuffer_attachment *attachment = &fb->attachments[j]; - i32 ix = vg.window_x / fb->div, - iy = vg.window_y / fb->div; + if( attachment->purpose == k_framebuffer_attachment_type_none ) + continue; - glBindTexture( GL_TEXTURE_2D, fb->colour ); - glTexImage2D( GL_TEXTURE_2D, 0, fb->format, ix, iy, 0, - fb->format, GL_UNSIGNED_BYTE, NULL ); + vg_info( " %s: %s\n", + render_fb_attachment_str( attachment->attachment ), + render_fb_format_str( attachment->internalformat ) ); - glBindRenderbuffer( GL_RENDERBUFFER, fb->rb ); - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, ix, iy ); -} + 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 render_fb_resize(void) -{ - if( gpipeline.ready ) - { - 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 ); + glFramebufferTexture2D( GL_FRAMEBUFFER, attachment->attachment, + GL_TEXTURE_2D, attachment->id, 0 ); - /* FIXME: Resizeother textures and rb */ + colour_attachments[ colour_count ++ ] = attachment->attachment; + } } -} -VG_STATIC void render_init_temp_buffer(void) -{ - vg_info( "[render] Allocate 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 ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - gpipeline.rgb_background, 0 ); - - glGenTextures( 1, &gpipeline.mv_background ); - glBindTexture( GL_TEXTURE_2D, gpipeline.mv_background ); -#if 0 - glTexImage2D( GL_TEXTURE_2D, 0, GL_RG, vg.window_x, vg.window_y, - 0, GL_RG, GL_FLOAT, NULL); -#endif - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F, vg.window_x, vg.window_y, - 0, GL_RGBA, GL_FLOAT, NULL); - - 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 ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, - gpipeline.mv_background, 0 ); - - /* render buffer */ - glGenRenderbuffers( 1, &gpipeline.rb_background ); - glBindRenderbuffer( GL_RENDERBUFFER, gpipeline.rb_background ); - glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, - vg.window_x, vg.window_y ); - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, gpipeline.rb_background ); - - GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers( 2, attachments ); + glDrawBuffers( colour_count, colour_attachments ); + /* + * Check result + */ GLenum result = glCheckFramebufferStatus( GL_FRAMEBUFFER ); - if( result != GL_FRAMEBUFFER_COMPLETE ) + if( result == GL_FRAMEBUFFER_COMPLETE ) + { + /* + * 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_fatal_exit_loop( "Main RT: Incomplete attachment" ); + vg_error( " status: Incomplete attachment" ); else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT ) - vg_fatal_exit_loop( "Main RT: Missing attachment" ); + vg_error( " status: Missing attachment" ); else if( result == GL_FRAMEBUFFER_UNSUPPORTED ) - vg_fatal_exit_loop( "Main RT: Unsupported framebuffer format" ); + vg_error( " status: Unsupported framebuffer format" ); else - vg_fatal_exit_loop( "Main RT: Generic Error" ); - } + vg_error( " status: Generic Error" ); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - VG_CHECK_GL_ERR(); + vg_info( "}\n" ); + vg_fatal_exit_loop( "Incomplete framebuffer (see logs)" ); + } } -/* 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; iattachments); j++ ) + { + struct framebuffer_attachment *attachment = &fb->attachments[j]; + render_fb_allocate_texture( fb, attachment ); + } + } } VG_STATIC void render_init_fs_quad(void) @@ -381,8 +635,15 @@ VG_STATIC void render_init(void) vg_acquire_thread_sync(); { - render_init_temp_buffer(); - render_init_depthmap_buffer(); + /* + * Complete Framebuffers + */ + for( int i=0; i