+#include "common.h"
+#include "model.h"
+
+#include "shaders/blit.h"
+#include "shaders/standard.h"
+#include "shaders/vblend.h"
+#include "shaders/unlit.h"
+
+static void render_water_texture( m4x3f camera );
+static void render_water_surface( m4x4f pv, m4x3f camera );
+static void render_world( m4x4f projection, m4x3f camera );
+static void shader_link_standard_ub( GLuint shader, int texture_id );
+static void render_world_depth( m4x4f projection, m4x3f camera );
+
#ifndef RENDER_H
#define RENDER_H
-#include "common.h"
-#include "model.h"
+struct framebuffer
+{
+ GLuint fb, colour, rb;
+ int div;
+ GLuint format;
+
+ int allocated;
+};
static struct pipeline
{
struct ub_world_lighting
{
/* v3f (padded) */
- v4f g_directional,
- g_sun_colour,
- g_shadow_colour;
+ v4f g_light_colours[3],
+ g_light_directions[3],
+ g_ambient_colour;
v4f g_water_plane,
g_depth_bounds;
+
float g_water_fog;
+ int g_light_count;
+ int g_light_preview;
}
ub_world_lighting;
+ struct light_widget
+ {
+ int enabled;
+ v2f dir;
+ v3f colour;
+ }
+ widgets[3];
+
+ float shadow_spread, shadow_length;
+
GLuint fb_depthmap, rgb_depthmap;
GLuint ubo_world_lighting,
ubo_world;
-}
-gpipeline;
-static void render_water_texture( m4x3f camera );
-static void render_water_surface( m4x4f pv, m4x3f camera );
-static void render_world( m4x4f projection, m4x3f camera );
-static void render_world_depth( m4x4f projection, m4x3f camera );
+ int ready;
+}
+gpipeline =
+{
+ .widgets =
+ {
+ {
+ .enabled = 1,
+ .colour = { 1.36f, 1.35f, 1.01f },
+ .dir = { 0.63f, -0.08f }
+ },
+ {
+ .enabled = 1,
+ .colour = { 0.33f, 0.56f, 0.64f },
+ .dir = { -2.60f, -0.13f }
+ },
+ {
+ .enabled = 1,
+ .colour = { 0.05f, 0.05f, 0.23f },
+ .dir = { 2.60f, -0.84f }
+ }
+ },
+ .shadow_spread = 0.65f,
+ .shadow_length = 9.50f,
+
+ .ub_world_lighting =
+ {
+ .g_ambient_colour = { 0.09f, 0.03f, 0.07f }
+ }
+};
/*
* Matrix Projections
static void render_update_lighting_ub(void)
{
- glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
+ struct ub_world_lighting *winf = &gpipeline.ub_world_lighting;
+ int c = 0;
- glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
- &gpipeline.ub_world_lighting );
-}
+ for( int i=0; i<3; i++ )
+ {
+ struct light_widget *lw = &gpipeline.widgets[i];
+
+ if( lw->enabled )
+ {
+ float pitch = lw->dir[0],
+ yaw = lw->dir[1],
+ xz = cosf( pitch );
+
+ v3_copy( (v3f){ xz*cosf(yaw), sinf(pitch), xz*sinf(yaw) },
+ winf->g_light_directions[c] );
+ v3_copy( lw->colour, winf->g_light_colours[c] );
+
+ c ++;
+ }
+ }
-static void render_alloc_ub(void)
-{
- glGenBuffers( 1, &gpipeline.ubo_world_lighting );
- glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
- glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
- NULL, GL_DYNAMIC_DRAW );
+ winf->g_light_count = c;
+ winf->g_light_directions[0][3] = gpipeline.shadow_length;
+ winf->g_light_colours[0][3] = gpipeline.shadow_spread;
- render_update_lighting_ub();
- glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
+ glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
+ glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting),
+ &gpipeline.ub_world_lighting );
}
/*
* Framebuffers
*/
-struct framebuffer
-{
- GLuint fb, colour, rb;
- int div;
- GLuint format;
-};
static void fb_use( struct framebuffer *fb )
{
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, fb->rb );
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+
+ VG_CHECK_GL_ERR();
+ fb->allocated = 1;
+}
+
+static void fb_free( struct framebuffer *fb )
+{
+ glDeleteTextures( 1, &fb->colour );
+ glDeleteFramebuffers( 1, &fb->fb );
}
static void fb_bindtex( struct framebuffer *fb, int texture )
static void fb_resize( struct framebuffer *fb )
{
+ if( !fb->allocated )
+ return;
+
i32 ix = vg_window_x / fb->div,
iy = vg_window_y / fb->div;
static void render_fb_resize(void)
{
- 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 );
+ 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 );
+ }
}
-/*
- * Vg
- */
-static void render_init(void)
+/* used for drawing player onto */
+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 );
GL_TEXTURE_2D,
gpipeline.rgb_background, 0);
- /*
- * World depth map, maybe this should be moved to world.h
- * TODO: review
- */
+ VG_CHECK_GL_ERR();
+}
+
+/* used for drawing world depth from the top view, used in our water and
+ * lighting calculations */
+static void render_init_depthmap_buffer(void)
+{
+ vg_info( "[render] Allocate depth map buffer\n" );
+
glGenFramebuffers( 1, &gpipeline.fb_depthmap );
glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap );
GL_TEXTURE_2D,
gpipeline.rgb_depthmap, 0);
+ VG_CHECK_GL_ERR();
+}
+
+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 };
glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
sizeof(float)*2, (void*)0 );
glEnableVertexAttribArray( 0 );
- VG_CHECK_GL();
- render_alloc_ub();
+ VG_CHECK_GL_ERR();
}
-static void render_free(void)
+static void render_init_uniform_buffers(void)
{
- /* TODO: ... */
+ vg_info( "[render] Allocate uniform buffer\n" );
+
+ glGenBuffers( 1, &gpipeline.ubo_world_lighting );
+ glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting );
+ glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
+ NULL, GL_DYNAMIC_DRAW );
+
+ render_update_lighting_ub();
+ glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting );
+
+ VG_CHECK_GL_ERR();
+}
+
+static void render_init(void)
+{
+ shader_blit_register();
+ shader_standard_register();
+ shader_vblend_register();
+ shader_unlit_register();
+
+ vg_acquire_thread_sync();
+ {
+ render_init_temp_buffer();
+ render_init_depthmap_buffer();
+ render_init_fs_quad();
+ render_init_uniform_buffers();
+
+ glBindFramebuffer( GL_FRAMEBUFFER, 0 );
+ gpipeline.ready = 1;
+ }
+
+ vg_release_thread_sync();
+}
+
+static void render_free(void *_)
+{
+ glDeleteBuffers( 1, &gpipeline.ubo_world_lighting );
+
+ glDeleteVertexArrays( 1, &gpipeline.fsquad.vao );
+ glDeleteBuffers( 1, &gpipeline.fsquad.vbo );
+
+ glDeleteFramebuffers( 1, &gpipeline.fb_depthmap );
+ glDeleteTextures( 1, &gpipeline.rgb_depthmap );
+
+ glDeleteFramebuffers( 1, &gpipeline.fb_background );
+ glDeleteTextures( 1, &gpipeline.rgb_background );
}
/*