@ -16,6 +16,8 @@
# include "blit_vertex_shader.h"
# include "blit_fragment_shader.h"
# include "blit_div_vertex_shader.h"
# include "blit_div_fragment_shader.h"
# include "common_vertex_shader.h"
# include "advect_shader.h"
# include "divergence_shader.h"
@ -24,6 +26,7 @@
# include "multigrid_correct_shader.h"
# include "subtract_pressure_shader.h"
# include "splat_shader.h"
# include "blit_residue_fragment_shader.h"
void * memcpy ( void * dst , void * src , unsigned long n )
{
@ -50,7 +53,7 @@ float fabs(float x)
return ( x > 0 ? x : - x ) ;
}
# define PI 3.14159
# define PI 3.14159265359
# define EULER 2.71828
# define SQRT2 1.41421
@ -133,6 +136,16 @@ typedef struct jacobi_program
} jacobi_program ;
typedef struct blit_residue_program
{
GLuint prog ;
GLint pos ;
GLint mvp ;
GLint xTex ;
GLint bTex ;
} blit_residue_program ;
typedef struct multigrid_restrict_residual_program
{
GLuint prog ;
@ -169,6 +182,7 @@ typedef struct blit_program
GLint pos ;
GLint mvp ;
GLint gridSize ;
GLint tex ;
} blit_program ;
@ -183,6 +197,7 @@ typedef struct splat_program
GLint radius ;
GLint additive ;
GLint blending ;
GLint randomize ;
} splat_program ;
@ -201,7 +216,8 @@ multigrid_correct_program multigridCorrectProgram;
subtract_program subtractProgram ;
splat_program splatProgram ;
blit_program blitProgram ;
blit_program blitDivProgram ;
blit_residue_program blitResidueProgram ;
frame_buffer colorBuffer ;
frame_buffer velocityBuffer ;
@ -302,6 +318,7 @@ void init_splat(splat_program* program)
program - > radius = glGetUniformLocation ( program - > prog , " radius " ) ;
program - > additive = glGetUniformLocation ( program - > prog , " additive " ) ;
program - > blending = glGetUniformLocation ( program - > prog , " blending " ) ;
program - > randomize = glGetUniformLocation ( program - > prog , " randomize " ) ;
}
void init_blit ( blit_program * program )
@ -311,8 +328,29 @@ void init_blit(blit_program* program)
program - > pos = glGetAttribLocation ( program - > prog , " pos " ) ;
program - > mvp = glGetUniformLocation ( program - > prog , " mvp " ) ;
program - > tex = glGetUniformLocation ( program - > prog , " tex " ) ;
program - > gridSize = glGetUniformLocation ( program - > prog , " gridSize " ) ;
}
void init_blit_div ( blit_program * program )
{
console_log_fmt ( " compiling blit div... " ) ;
program - > prog = compile_shader ( blit_div_vertex_shader_src , blit_div_fragment_shader_src ) ;
program - > pos = glGetAttribLocation ( program - > prog , " pos " ) ;
program - > mvp = glGetUniformLocation ( program - > prog , " mvp " ) ;
program - > tex = glGetUniformLocation ( program - > prog , " tex " ) ;
}
void init_blit_residue ( blit_residue_program * program )
{
console_log_fmt ( " compiling blit residue... " ) ;
program - > prog = compile_shader ( blit_div_vertex_shader_src , blit_residue_fragment_shader_src ) ;
program - > pos = glGetAttribLocation ( program - > prog , " pos " ) ;
program - > mvp = glGetUniformLocation ( program - > prog , " mvp " ) ;
program - > xTex = glGetUniformLocation ( program - > prog , " xTex " ) ;
program - > bTex = glGetUniformLocation ( program - > prog , " bTex " ) ;
}
GLuint create_texture ( int width , int height , GLenum internalFormat , GLenum format , GLenum type , char * initData )
{
GLuint texture ;
@ -323,7 +361,6 @@ GLuint create_texture(int width, int height, GLenum internalFormat, GLenum forma
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 ) ;
return ( texture ) ;
}
@ -334,7 +371,6 @@ GLuint create_fbo(GLuint texture)
glBindFramebuffer ( GL_FRAMEBUFFER , fbo ) ;
glBindTexture ( GL_TEXTURE_2D , texture ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , texture , 0 ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
return ( fbo ) ;
}
@ -373,10 +409,7 @@ void frame_buffer_swap(frame_buffer* buffer)
//----------------------------------------------------------------
//NOTE(martin): entry point
//----------------------------------------------------------------
/*
# define texWidth 512
# define texHeight 512
*/
# define texWidth (256)
# define texHeight (256)
@ -397,8 +430,11 @@ void reset_texture(GLuint texture, float width, float height, char* initData)
glTexImage2D ( GL_TEXTURE_2D , 0 , TEX_INTERNAL_FORMAT , width , height , 0 , TEX_FORMAT , TEX_TYPE , initData ) ;
}
//static bool resetCmd = false;
void reset ( )
{
// resetCmd = true;
console_log_fmt ( " reset " ) ;
reset_texture ( colorBuffer . textures [ 0 ] , texWidth , texHeight , ( char * ) colorInitData ) ;
@ -476,6 +512,7 @@ void init_velocity_vortex()
float y = 2 * i / ( float ) texWidth - 1 ;
velocityInitData [ i ] [ j ] [ 0 ] = sinf ( 2 * PI * y ) ;
velocityInitData [ i ] [ j ] [ 1 ] = sinf ( 2 * PI * x ) ;
}
}
}
@ -490,22 +527,27 @@ int init(float canvasSize)
WAJS_SetupCanvas ( canvasSize , canvasSize ) ;
// init_color_checker();
// init_velocity_vortex();
// init programs
init_advect ( & advectProgram ) ;
init_div ( & divProgram ) ;
init_jacobi ( & jacobiProgram ) ;
init_multigrid_restrict_residual ( & multigridRestrictResidualProgram ) ;
init_multigrid_correct ( & multigridCorrectProgram ) ;
init_blit_residue ( & blitResidueProgram ) ;
init_subtract ( & subtractProgram ) ;
init_splat ( & splatProgram ) ;
init_blit ( & blitProgram ) ;
init_blit_div ( & blitDivProgram ) ;
// init frame buffers
console_log_fmt ( " create color buffer " ) ;
init_frame_buffer ( & colorBuffer , texWidth , texHeight , TEX_INTERNAL_FORMAT , TEX_FORMAT , TEX_TYPE , 0 ) ;
init_frame_buffer ( & colorBuffer , texWidth , texHeight , TEX_INTERNAL_FORMAT , TEX_FORMAT , TEX_TYPE , ( char * ) colorInitData ) ;
console_log_fmt ( " create velocity buffer " ) ;
init_frame_buffer ( & velocityBuffer , texWidth , texHeight , TEX_INTERNAL_FORMAT , TEX_FORMAT , TEX_TYPE , 0 ) ;
init_frame_buffer ( & velocityBuffer , texWidth , texHeight , TEX_INTERNAL_FORMAT , TEX_FORMAT , TEX_TYPE , ( char * ) velocityInitData ) ;
int gridFactor = 1 ;
for ( int i = 0 ; i < MULTIGRID_COUNT ; i + + )
@ -547,10 +589,19 @@ int init(float canvasSize)
return ( 0 ) ;
}
void apply_splat ( float splatPosX , float splatPosY , float splatVelX , float splatVelY , float r , float g , float b )
void apply_splat ( float splatPosX , float splatPosY , float radius , float splatVelX , float splatVelY , float r , float g , float b , bool randomize )
{
glUseProgram ( splatProgram . prog ) ;
if ( randomize )
{
glUniform1f ( splatProgram . randomize , 1. ) ;
}
else
{
glUniform1f ( splatProgram . randomize , 0. ) ;
}
// force
glBindFramebuffer ( GL_FRAMEBUFFER , velocityBuffer . fbos [ 1 ] ) ;
@ -563,7 +614,7 @@ void apply_splat(float splatPosX, float splatPosY, float splatVelX, float splatV
glUniform1f ( splatProgram . additive , 1 ) ;
glUniform1f ( splatProgram . blending , 0 ) ;
glUniform1f ( splatProgram . radius , 0.01 ) ;
glUniform1f ( splatProgram . radius , radius ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
@ -580,7 +631,7 @@ void apply_splat(float splatPosX, float splatPosY, float splatVelX, float splatV
glUniform3f ( splatProgram . splatColor , r , g , b ) ;
glUniform1f ( splatProgram . additive , 0 ) ;
glUniform1f ( splatProgram . blending , 1 ) ;
glUniform1f ( splatProgram . radius , 0.01 ) ;
glUniform1f ( splatProgram . radius , radius ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
@ -588,7 +639,7 @@ void apply_splat(float splatPosX, float splatPosY, float splatVelX, float splatV
}
void multigrid_smooth ( frame_buffer * x , frame_buffer * b , float invGridSize , int iterationCount )
void jacobi_solve ( frame_buffer * x , frame_buffer * b , float invGridSize , int iterationCount )
{
glUseProgram ( jacobiProgram . prog ) ;
@ -656,6 +707,40 @@ void multigrid_clear(frame_buffer* error)
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
void input_splat ( float t )
{
//NOTE: apply force and dye
if ( mouseInput . down & & ( mouseInput . deltaX | | mouseInput . deltaY ) )
{
// account for margin
float margin = 32 ;
float canvasWidth = canvas_width ( ) ;
float canvasHeight = canvas_height ( ) ;
float offset = margin / texWidth ;
float ratio = 1 - 2 * margin / texWidth ;
float splatPosX = ( mouseInput . x / canvasWidth ) * ratio + offset ;
float splatPosY = ( 1 - mouseInput . y / canvasHeight ) * ratio + offset ;
float splatVelX = ( 10000. * DELTA * mouseInput . deltaX / canvasWidth ) * ratio ;
float splatVelY = ( - 10000. * DELTA * mouseInput . deltaY / canvasWidth ) * ratio ;
float intensity = 100 * sqrtf ( square ( ratio * mouseInput . deltaX / canvasWidth ) + square ( ratio * mouseInput . deltaY / canvasHeight ) ) ;
float r = intensity * ( sinf ( 2 * PI * 0.1 * t ) + 1 ) ;
float g = 0.5 * intensity * ( cosf ( 2 * PI * 0.1 / EULER * t + 654 ) + 1 ) ;
float b = intensity * ( sinf ( 2 * PI * 0.1 / SQRT2 * t + 937 ) + 1 ) ;
float radius = 0.005 ;
apply_splat ( splatPosX , splatPosY , radius , splatVelX , splatVelY , r , g , b , false ) ;
mouseInput . deltaX = 0 ;
mouseInput . deltaY = 0 ;
}
}
// This function is called by loader.js every frame
void WAFNDraw ( )
{
@ -686,39 +771,60 @@ void WAFNDraw()
frame_buffer_swap ( & velocityBuffer ) ;
//NOTE: apply force and dye
if ( mouseInput . down & & ( mouseInput . deltaX | | mouseInput . deltaY ) )
{
float canvasWidth = canvas_width ( ) ;
float canvasHeight = canvas_height ( ) ;
float splatPosX = mouseInput . x / canvasWidth ;
float splatPosY = 1 - mouseInput . y / canvasHeight ;
float splatVelX = 10000. * DELTA * mouseInput . deltaX / canvasWidth ;
float splatVelY = - 10000. * DELTA * mouseInput . deltaY / canvasWidth ;
float intensity = 100 * sqrtf ( square ( mouseInput . deltaX / canvasWidth ) + square ( mouseInput . deltaY / canvasHeight ) ) ;
/*
//DEBUG
static bool splatTrig = false ;
static bool splat = false ;
static float splatStart = 0 ;
static int splatDir = 0 ;
float r = intensity * ( sinf ( 2 * PI * 0.1 * t ) + 1 ) ;
float g = intensity * ( cosf ( 2 * PI * 0.1 / EULER * t + 654 ) + 1 ) ;
float b = intensity * ( sinf ( 2 * PI * 0.1 / SQRT2 * t + 937 ) + 1 ) ;
static int frameCount = 0 ;
apply_splat ( splatPosX , splatPosY , splatVelX , splatVelY , r , g , b ) ;
if ( resetCmd )
{
frameCount = 0 ;
splat = true ;
splatStart = frameT ;
}
mouseInput . deltaX = 0 ;
mouseInput . deltaY = 0 ;
if ( splat )
{
if ( frameT - splatStart > = 0.5 )
{
splat = false ;
splatDir + + ;
splatDir = splatDir % 3 ;
}
float dirX = 0 ;
float dirY = 0 ;
if ( splatDir = = 0 )
{
dirX = 0 ;
dirY = 0.3 ;
}
if ( splatDir = = 1 )
{
dirX = 0.3 ;
dirY = 0 ;
}
if ( splatDir = = 2 )
{
dirX = 0.2121 ;
dirY = 0.2121 ;
}
apply_splat ( 0.5 , 0.5 , dirX , dirY , 1.5 , 1. , 0.1 , false ) ;
}
resetCmd = false ;
//DEBUG
//*
if ( ( int ) ( frameT * 3 / 2. ) % 6 = = 0 )
if ( frameCount > 20 )
{
float dirX = 0.2 * cosf ( 2 * 3.141516 * frameT * 7.26 ) ;
float dirY = 0.3 + 0.1 * sinf ( frameT ) ;
apply_splat ( 0.5 , 0.1 , dirX , dirY , 1.5 , 1. , 0.1 ) ;
return ;
}
//*/
frameCount + + ;
*/
input_splat ( t ) ;
//NOTE: compute divergence of advected velocity
glUseProgram ( divProgram . prog ) ;
@ -733,48 +839,37 @@ void WAFNDraw()
frame_buffer_swap ( & divBuffer [ 0 ] ) ;
//NOTE: compute pressure
glBindFramebuffer ( GL_FRAMEBUFFER , pressureBuffer [ 0 ] . fbos [ 1 ] ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
#if 0
multigrid_clear ( & pressureBuffer [ 0 ] ) ;
multigrid_smooth ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 500 ) ;
jacobi_solve ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , texWidth * texHeight ) ;
# else
//*
multigrid_clear ( & pressureBuffer [ 0 ] ) ;
for ( int i = 0 ; i < 4 ; i + + )
for ( int i = 0 ; i < 1 ; i + + )
{
multigrid_smooth ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 2 ) ;
//*
jacobi_solve ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 2 ) ;
multigrid_coarsen_residual ( & divBuffer [ 1 ] , & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE ) ;
multigrid_clear ( & pressureBuffer [ 1 ] ) ;
multigrid_smooth ( & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE , 2 ) ;
jacobi_solve ( & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE , 2 ) ;
multigrid_coarsen_residual ( & divBuffer [ 2 ] , & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE ) ;
multigrid_clear ( & pressureBuffer [ 2 ] ) ;
multigrid_smooth ( & pressureBuffer [ 2 ] , & divBuffer [ 2 ] , 4 * INV_GRID_SIZE , 6 0) ;
jacobi_solve ( & pressureBuffer [ 2 ] , & divBuffer [ 2 ] , 4 * INV_GRID_SIZE , 3 0) ;
multigrid_prolongate_and_correct ( & pressureBuffer [ 1 ] , & pressureBuffer [ 2 ] , 2 * INV_GRID_SIZE ) ;
multigrid_smooth ( & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE , 8 ) ;
jacobi_solve ( & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE , 8 ) ;
multigrid_prolongate_and_correct ( & pressureBuffer [ 0 ] , & pressureBuffer [ 1 ] , INV_GRID_SIZE ) ;
//*/
multigrid_smooth ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 4 ) ;
jacobi_solve ( & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 4 ) ;
}
/*/
multigrid_clear ( & pressureBuffer [ 0 ] ) ;
multigrid_smooth ( & pressureBuffer [ 0 ] , & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 10 ) ;
multigrid_coarsen_residual ( & divBuffer [ 1 ] , & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE ) ;
# endif
multigrid_clear ( & pressureBuffer [ 1 ] ) ;
multigrid_smooth ( & pressureBuffer [ 1 ] , & pressureBuffer [ 1 ] , & divBuffer [ 1 ] , 2 * INV_GRID_SIZE , 400 ) ;
multigrid_prolongate_and_correct ( & pressureBuffer [ 0 ] , & pressureBuffer [ 0 ] , & pressureBuffer [ 1 ] , INV_GRID_SIZE ) ;
multigrid_smooth ( & pressureBuffer [ 0 ] , & pressureBuffer [ 0 ] , & divBuffer [ 0 ] , INV_GRID_SIZE , 10 ) ;
//*/
# endif
//NOTE: subtract pressure gradient to advected velocity
glUseProgram ( subtractProgram . prog ) ;
@ -808,23 +903,40 @@ void WAFNDraw()
glUniform1f ( advectProgram . delta , DELTA ) ;
glUniform1f ( advectProgram . dissipation , 0.5 ) ;
glUniform1f ( advectProgram . dissipation , 0.001 ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
frame_buffer_swap ( & colorBuffer ) ;
//*
//NOTE: Blit color texture to screen
//NOTE: blit residue to screen
glViewport ( 0 , 0 , canvas_width ( ) , canvas_height ( ) ) ;
float displayMatrix [ 16 ] = {
1 / aspectRatio , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 1 , 0 ,
0 , 0 , 0 , 1 } ;
glViewport ( 0 , 0 , canvas_width ( ) , canvas_height ( ) ) ;
/*
glUseProgram ( blitResidueProgram . prog ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , pressureBuffer [ 0 ] . textures [ 0 ] ) ;
glUniform1i ( blitResidueProgram . xTex , 0 ) ;
glActiveTexture ( GL_TEXTURE1 ) ;
glBindTexture ( GL_TEXTURE_2D , divBuffer [ 0 ] . textures [ 0 ] ) ;
glUniform1i ( blitResidueProgram . bTex , 1 ) ;
glUniformMatrix4fv ( blitResidueProgram . mvp , 1 , GL_FALSE , displayMatrix ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
//*/
//*
glUseProgram ( blitProgram . prog ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
@ -832,21 +944,37 @@ void WAFNDraw()
glBindTexture ( GL_TEXTURE_2D , colorBuffer . textures [ 0 ] ) ;
glUniform1i ( blitProgram . tex , 0 ) ;
glUniform2i ( blitProgram . gridSize , texWidth , texHeight ) ;
glUniformMatrix4fv ( blitProgram . mvp , 1 , GL_FALSE , displayMatrix ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
/*/
//NOTE: Blit velocity to screen
glViewport ( 0 , 0 , window_width ( ) , window_height ( ) ) ;
glUseProgram ( blit Program. prog ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
//NOTE: recompute divergence of (corrected) velocity
glUseProgram ( div Program. prog ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , divBuffer [ 0 ] . fbos [ 1 ] ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , velocityBuffer . textures [ 0 ] ) ;
glUniform1i ( blitProgram . tex , 0 ) ;
glUniform1i ( divProgram . src , 0 ) ;
glUniformMatrix4fv ( blitProgram . mvp , 1 , GL_FALSE , displayMatrix ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
frame_buffer_swap ( & divBuffer [ 0 ] ) ;
//NOTE: Blit divergence to screen
glViewport ( 0 , 0 , canvas_width ( ) , canvas_height ( ) ) ;
glUseProgram ( blitDivProgram . prog ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
glBindTexture ( GL_TEXTURE_2D , divBuffer [ 0 ] . textures [ 0 ] ) ;
glUniform1i ( blitDivProgram . tex , 0 ) ;
glUniformMatrix4fv ( blitDivProgram . mvp , 1 , GL_FALSE , displayMatrix ) ;
glDrawArrays ( GL_TRIANGLES , 0 , 6 ) ;
//*/
}