+#include "common.h"
+#include "model.h"
+
+static void water_register(void);
+static void water_init(void);
+static void water_fb_resize(void);
+static void water_set_surface( glmesh *surf, float height );
+static float water_height(void);
+
#ifndef WATER_H
#define WATER_H
-#define VG_3D
-#include "vg/vg.h"
-
-#include "model.h"
+#include "world.h"
#include "render.h"
#include "shaders/water.h"
#include "scene.h"
static struct
{
- GLuint fb, rgb, rb;
+ struct framebuffer fbreflect, fbdepth;
glmesh mdl;
- GLuint depthmap;
boxf depthbounds;
int depth_computed;
float height;
+ int enabled;
+ v4f plane;
+}
+wrender =
+{
+ .fbreflect = { .format = GL_RGB, .div = 3 },
+ .fbdepth = { .format = GL_RGBA, .div = 4 }
+};
+
+static float water_height(void)
+{
+ return wrender.height;
}
-wrender;
static void water_register(void)
{
static void water_init(void)
{
- create_renderbuffer_std( &wrender.fb, &wrender.rgb, &wrender.rb );
+ /* TODO: probably dont do this every time */
+ wrender.enabled = 1;
+
+ fb_init( &wrender.fbreflect );
+ fb_init( &wrender.fbdepth );
}
-static int ray_world( v3f pos, v3f dir, ray_hit *hit );
+static void water_fb_resize(void)
+{
+ if( !wrender.enabled )
+ return;
+
+ fb_resize( &wrender.fbreflect );
+ fb_resize( &wrender.fbdepth );
+}
+
+#if 0
static void water_compute_depth( boxf bounds )
{
+ if( !wrender.enabled )
+ return;
+
#ifdef VG_RELEASE
int const kres = 512;
#else
- int const kres = 64;
+ int const kres = 1024;
#endif
vg_info( "Computing depth map\n" );
- u8 *img = malloc( kres*kres );
+ float *img = malloc( kres*kres*sizeof(float) );
+
+ boxf interior;
+ v3_add(bounds[0],(v3f){1.0f,1.0f,1.0f},interior[0]);
+ v3_sub(bounds[1],(v3f){1.0f,1.0f,1.0f},interior[1]);
v3f volume;
- v3_sub( bounds[1], bounds[0], volume );
- box_copy( bounds, wrender.depthbounds );
+ v3_sub( interior[1], interior[0], volume );
+ box_copy( interior, wrender.depthbounds );
for( int y=0; y<kres; y++ )
{
for( int x=0; x<kres; x++ )
{
- v3f pos = { x, 0, y };
- v3_divs( pos, kres, pos );
- v3_muladd( bounds[0], pos, volume, pos );
- pos[1] = wrender.height;
+ v3f pos = { x, 0.0f, y };
+ pos[0] += 0.5f;
+ pos[2] += 0.5f;
+ v3_divs( pos, kres+1, pos );
+ v3_muladd( interior[0], pos, volume, pos );
+ pos[1] = 2000.0f;
ray_hit hit;
hit.dist = INFINITY;
- u8 *dst = &img[ y*kres+x ];
+ float *dst = &img[ y*kres+x ];
if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
{
- float h = wrender.height - hit.pos[1];
- h *= 1.0f/15.0f;
- h = vg_clampf( h, 0.0f, 1.0f );
- *dst = (u8)(h*255.0f);
+ *dst = hit.pos[1];
}
else
- *dst = 0;
+ {
+ *dst = 0.0f;
+ }
}
}
glGenTextures( 1, &wrender.depthmap );
glBindTexture( GL_TEXTURE_2D, wrender.depthmap );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, kres, kres, 0,
- GL_RED, GL_UNSIGNED_BYTE, img );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, kres, kres, 0,
+ GL_RED, GL_FLOAT, img );
vg_tex2d_mipmap();
vg_tex2d_linear_mipmap();
free( img );
vg_success( "Done.\n" );
}
+#endif
static void water_set_surface( glmesh *surf, float height )
{
wrender.mdl = *surf;
wrender.height = height;
-}
-static void water_fb_resize(void)
-{
- resize_renderbuffer_std( &wrender.fb, &wrender.rgb, &wrender.rb );
+ v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, wrender.plane );
}
static void render_water_texture( m4x3f camera )
{
+ if( !wrender.enabled )
+ return;
+
/* Draw reflection buffa */
- glBindFramebuffer( GL_FRAMEBUFFER, wrender.fb );
- glClearColor( 0.11f, 0.35f, 0.37f, 1.0f );
+ fb_use( &wrender.fbreflect );
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
m4x3f new_cam, inverse;
glCullFace( GL_FRONT );
render_world( projection, new_cam );
glCullFace( GL_BACK );
+
+
+ /* Draw beneath texture */
+ fb_use( &wrender.fbdepth );
+ glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
+
+ m4x3_invert_affine( camera, inverse );
+ m4x3_expand( inverse, view );
+
+ float bias = -(camera[3][1]-wrender.height)*0.1f;
+ v4f clippb = { 0.0f, -1.0f, 0.0f, -(wrender.height) + bias };
+ m4x3_mulp( inverse, clippb, clippb );
+ clippb[3] *= -1.0f;
+
+ m4x4_projection( projection,
+ gpipeline.fov,
+ (float)vg_window_x / (float)vg_window_y,
+ 0.1f, 900.0f );
+
+ plane_clip_projection( projection, clippb );
+ m4x4_mul( projection, view, projection );
+ render_world_depth( projection, camera );
+
+ glViewport( 0, 0, vg_window_x, vg_window_y );
}
-static void render_water_surface( m4x4f pv )
+static void render_water_surface( m4x4f pv, m4x3f camera )
{
+ if( !wrender.enabled )
+ return;
+
/* Draw surface */
shader_water_use();
- glActiveTexture( GL_TEXTURE0 );
- glBindTexture( GL_TEXTURE_2D, wrender.rgb );
+ fb_bindtex( &wrender.fbreflect, 0 );
shader_water_uTexMain( 0 );
vg_tex2d_bind( &tex_water_surf, 1 );
1.0f / (float)vg_window_x,
1.0f / (float)vg_window_y });
- glActiveTexture( GL_TEXTURE2 );
- glBindTexture( GL_TEXTURE_2D, wrender.depthmap );
- shader_water_uTexDepth( 2 );
- shader_water_uDepthBounds( (v4f){
- wrender.depthbounds[0][0],
- wrender.depthbounds[0][2],
- 1.0f/ (wrender.depthbounds[1][0]-wrender.depthbounds[0][0]),
- 1.0f/ (wrender.depthbounds[1][2]-wrender.depthbounds[0][2])} );
+ shader_link_standard_ub( _shader_water.id, 2 );
+ fb_bindtex( &wrender.fbdepth, 3 );
+ shader_water_uTexBack( 3 );
shader_water_uTime( vg_time );
+ shader_water_uCamera( camera[3] );
+ shader_water_uSurfaceY( wrender.height );
+
shader_water_uPv( pv );
m4x3f full;