923 lines
26 KiB
C
923 lines
26 KiB
C
/************************************************************/ /**
|
|
*
|
|
* @file: main.cpp
|
|
* @author: Martin Fouilleul
|
|
* @date: 27/02/2022
|
|
* @revision:
|
|
*
|
|
*****************************************************************/
|
|
|
|
#include "glsl_shaders.h"
|
|
#include "math.h"
|
|
#include "orca.h"
|
|
|
|
//----------------------------------------------------------------
|
|
//NOTE(martin): GL vertex struct and identifiers
|
|
//----------------------------------------------------------------
|
|
typedef struct Vertex
|
|
{
|
|
float x, y;
|
|
} Vertex;
|
|
|
|
typedef struct advect_program
|
|
{
|
|
GLuint prog;
|
|
|
|
GLint pos;
|
|
GLint src;
|
|
GLint velocity;
|
|
GLint delta;
|
|
GLint dissipation;
|
|
|
|
} advect_program;
|
|
|
|
typedef struct div_program
|
|
{
|
|
GLuint prog;
|
|
GLint pos;
|
|
GLint src;
|
|
|
|
} div_program;
|
|
|
|
typedef struct jacobi_program
|
|
{
|
|
GLuint prog;
|
|
GLint pos;
|
|
GLint xTex;
|
|
GLint bTex;
|
|
|
|
} 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;
|
|
GLint pos;
|
|
GLint xTex;
|
|
GLint bTex;
|
|
|
|
} multigrid_restrict_residual_program;
|
|
|
|
typedef struct multigrid_correct_program
|
|
{
|
|
GLuint prog;
|
|
GLint pos;
|
|
GLint src;
|
|
GLint error;
|
|
GLint invGridSize;
|
|
|
|
} multigrid_correct_program;
|
|
|
|
typedef struct subtract_program
|
|
{
|
|
GLuint prog;
|
|
|
|
GLint pos;
|
|
GLint src;
|
|
GLint pressure;
|
|
GLint invGridSize;
|
|
|
|
} subtract_program;
|
|
|
|
typedef struct blit_program
|
|
{
|
|
GLuint prog;
|
|
|
|
GLint pos;
|
|
GLint mvp;
|
|
GLint gridSize;
|
|
GLint tex;
|
|
} blit_program;
|
|
|
|
typedef struct splat_program
|
|
{
|
|
GLuint prog;
|
|
|
|
GLint pos;
|
|
GLint src;
|
|
GLint splatPos;
|
|
GLint splatColor;
|
|
GLint radius;
|
|
GLint additive;
|
|
GLint blending;
|
|
GLint randomize;
|
|
|
|
} splat_program;
|
|
|
|
typedef struct frame_buffer
|
|
{
|
|
GLuint textures[2];
|
|
GLuint fbos[2];
|
|
} frame_buffer;
|
|
|
|
advect_program advectProgram;
|
|
div_program divProgram;
|
|
jacobi_program jacobiProgram;
|
|
multigrid_restrict_residual_program multigridRestrictResidualProgram;
|
|
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;
|
|
|
|
const int MULTIGRID_COUNT = 4;
|
|
frame_buffer pressureBuffer[4];
|
|
frame_buffer divBuffer[4];
|
|
|
|
GLuint vertexBuffer;
|
|
|
|
//----------------------------------------------------------------
|
|
//NOTE(martin): initialization
|
|
//----------------------------------------------------------------
|
|
|
|
GLuint compile_shader(const char* vs, const char* fs)
|
|
{
|
|
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vertexShader, 1, &vs, 0);
|
|
glCompileShader(vertexShader);
|
|
|
|
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragmentShader, 1, &fs, 0);
|
|
glCompileShader(fragmentShader);
|
|
|
|
GLuint prog = glCreateProgram();
|
|
glAttachShader(prog, vertexShader);
|
|
glAttachShader(prog, fragmentShader);
|
|
glLinkProgram(prog);
|
|
|
|
//TODO errors
|
|
int status = 0;
|
|
glGetProgramiv(prog, GL_LINK_STATUS, &status);
|
|
if(status != GL_TRUE)
|
|
{
|
|
oc_log_error("program failed to link: ");
|
|
int logSize = 0;
|
|
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logSize);
|
|
|
|
oc_arena_scope scratch = oc_scratch_begin();
|
|
char* log = oc_arena_push(scratch.arena, logSize);
|
|
|
|
glGetProgramInfoLog(prog, logSize, 0, log);
|
|
oc_log_error("%s\n", log);
|
|
|
|
oc_scratch_end(scratch);
|
|
}
|
|
|
|
int err = glGetError();
|
|
if(err)
|
|
{
|
|
oc_log_error("gl error %i\n", err);
|
|
}
|
|
|
|
return (prog);
|
|
}
|
|
|
|
void init_advect(advect_program* program)
|
|
{
|
|
oc_log_info("compiling advect...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_advect);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->src = glGetUniformLocation(program->prog, "src");
|
|
program->velocity = glGetUniformLocation(program->prog, "velocity");
|
|
program->delta = glGetUniformLocation(program->prog, "delta");
|
|
program->dissipation = glGetUniformLocation(program->prog, "dissipation");
|
|
}
|
|
|
|
void init_div(div_program* program)
|
|
{
|
|
oc_log_info("compiling div...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_divergence);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->src = glGetUniformLocation(program->prog, "src");
|
|
}
|
|
|
|
void init_jacobi(jacobi_program* program)
|
|
{
|
|
oc_log_info("compiling jacobi...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_jacobi_step);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->xTex = glGetUniformLocation(program->prog, "xTex");
|
|
program->bTex = glGetUniformLocation(program->prog, "bTex");
|
|
}
|
|
|
|
void init_multigrid_restrict_residual(multigrid_restrict_residual_program* program)
|
|
{
|
|
oc_log_info("compiling multigrid restrict residual...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_restrict_residual);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->xTex = glGetUniformLocation(program->prog, "xTex");
|
|
program->bTex = glGetUniformLocation(program->prog, "bTex");
|
|
}
|
|
|
|
void init_multigrid_correct(multigrid_correct_program* program)
|
|
{
|
|
oc_log_info("compiling multigrid correct...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_multigrid_correct);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->src = glGetUniformLocation(program->prog, "src");
|
|
program->error = glGetUniformLocation(program->prog, "error");
|
|
program->invGridSize = glGetUniformLocation(program->prog, "invGridSize");
|
|
}
|
|
|
|
void init_subtract(subtract_program* program)
|
|
{
|
|
oc_log_info("compiling subtract...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_subtract_pressure);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->src = glGetUniformLocation(program->prog, "src");
|
|
program->pressure = glGetUniformLocation(program->prog, "pressure");
|
|
program->invGridSize = glGetUniformLocation(program->prog, "invGridSize");
|
|
}
|
|
|
|
void init_splat(splat_program* program)
|
|
{
|
|
oc_log_info("compiling splat...");
|
|
program->prog = compile_shader(glsl_common_vertex, glsl_splat);
|
|
program->pos = glGetAttribLocation(program->prog, "pos");
|
|
program->src = glGetUniformLocation(program->prog, "src");
|
|
program->splatPos = glGetUniformLocation(program->prog, "splatPos");
|
|
program->splatColor = glGetUniformLocation(program->prog, "splatColor");
|
|
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)
|
|
{
|
|
oc_log_info("compiling blit...");
|
|
program->prog = compile_shader(glsl_blit_vertex, glsl_blit_fragment);
|
|
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)
|
|
{
|
|
oc_log_info("compiling blit div...");
|
|
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_div_fragment);
|
|
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)
|
|
{
|
|
oc_log_info("compiling blit residue...");
|
|
program->prog = compile_shader(glsl_blit_div_vertex, glsl_blit_residue_fragment);
|
|
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;
|
|
glGenTextures(1, &texture);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, initData);
|
|
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);
|
|
return (texture);
|
|
}
|
|
|
|
GLuint create_fbo(GLuint texture)
|
|
{
|
|
GLuint fbo;
|
|
glGenFramebuffers(1, &fbo);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
|
|
return (fbo);
|
|
}
|
|
|
|
void init_frame_buffer(frame_buffer* framebuffer,
|
|
int width,
|
|
int height,
|
|
GLenum internalFormat,
|
|
GLenum format,
|
|
GLenum type,
|
|
char* initData)
|
|
{
|
|
for(int i = 0; i < 2; i++)
|
|
{
|
|
framebuffer->textures[i] = create_texture(width, height, internalFormat, format, type, initData);
|
|
framebuffer->fbos[i] = create_fbo(framebuffer->textures[i]);
|
|
}
|
|
|
|
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
|
if(err != GL_FRAMEBUFFER_COMPLETE)
|
|
{
|
|
oc_log_info("Frame buffer incomplete, %i", err);
|
|
}
|
|
}
|
|
|
|
void frame_buffer_swap(frame_buffer* buffer)
|
|
{
|
|
GLuint tmp = buffer->fbos[0];
|
|
buffer->fbos[0] = buffer->fbos[1];
|
|
buffer->fbos[1] = tmp;
|
|
|
|
tmp = buffer->textures[0];
|
|
buffer->textures[0] = buffer->textures[1];
|
|
buffer->textures[1] = tmp;
|
|
}
|
|
|
|
//----------------------------------------------------------------
|
|
//NOTE(martin): entry point
|
|
//----------------------------------------------------------------
|
|
|
|
#define texWidth (256)
|
|
#define texHeight (256)
|
|
|
|
float colorInitData[texWidth][texHeight][4] = { 0 };
|
|
float velocityInitData[texWidth][texHeight][4] = { 0 };
|
|
|
|
const float EPSILON = 1.,
|
|
INV_GRID_SIZE = 1. / (float)texWidth,
|
|
DELTA = 1. / 120.;
|
|
|
|
const GLenum TEX_INTERNAL_FORMAT = GL_RGBA32F;
|
|
const GLenum TEX_FORMAT = GL_RGBA;
|
|
const GLenum TEX_TYPE = GL_FLOAT;
|
|
|
|
#define square(x) ((x) * (x))
|
|
|
|
/*
|
|
void reset_texture(GLuint texture, float width, float height, char* initData)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, TEX_INTERNAL_FORMAT, width, height, 0, TEX_FORMAT, TEX_TYPE, initData);
|
|
}
|
|
|
|
static bool resetCmd = false;
|
|
|
|
void reset()
|
|
{
|
|
// resetCmd = true;
|
|
oc_log_info("reset");
|
|
|
|
reset_texture(colorBuffer.textures[0], texWidth, texHeight, (char*)colorInitData);
|
|
reset_texture(colorBuffer.textures[1], texWidth, texHeight, (char*)colorInitData);
|
|
reset_texture(velocityBuffer.textures[0], texWidth, texHeight, (char*)velocityInitData);
|
|
reset_texture(velocityBuffer.textures[1], texWidth, texHeight, (char*)velocityInitData);
|
|
|
|
int gridFactor = 1;
|
|
for(int i=0; i<MULTIGRID_COUNT; i++)
|
|
{
|
|
reset_texture(pressureBuffer[i].textures[0], texWidth/gridFactor, texHeight/gridFactor, 0);
|
|
reset_texture(pressureBuffer[i].textures[1], texWidth/gridFactor, texHeight/gridFactor, 0);
|
|
|
|
gridFactor *= 2;
|
|
}
|
|
}
|
|
|
|
*/
|
|
|
|
typedef struct mouse_input
|
|
{
|
|
float x;
|
|
float y;
|
|
float deltaX;
|
|
float deltaY;
|
|
bool down;
|
|
|
|
} mouse_input;
|
|
|
|
mouse_input mouseInput = { 0 };
|
|
|
|
int frameWidth = 800;
|
|
int frameHeight = 600;
|
|
|
|
ORCA_EXPORT void oc_on_mouse_down(int button)
|
|
{
|
|
mouseInput.down = true;
|
|
}
|
|
|
|
ORCA_EXPORT void oc_on_mouse_up(int button)
|
|
{
|
|
mouseInput.down = false;
|
|
}
|
|
|
|
ORCA_EXPORT void oc_on_mouse_move(float x, float y, float dx, float dy)
|
|
{
|
|
mouseInput.x = x * 2;
|
|
mouseInput.y = y * 2;
|
|
mouseInput.deltaX = dx * 2;
|
|
mouseInput.deltaY = dy * 2;
|
|
}
|
|
|
|
void init_color_checker()
|
|
{
|
|
for(int i = 0; i < texHeight; i++)
|
|
{
|
|
for(int j = 0; j < texWidth; j++)
|
|
{
|
|
float u = j / (float)texWidth;
|
|
float v = i / (float)texWidth;
|
|
float value = ((int)(u * 10) % 2) == ((int)(v * 10) % 2) ? 1. : 0.;
|
|
|
|
for(int k = 0; k < 3; k++)
|
|
{
|
|
colorInitData[i][j][k] = value;
|
|
}
|
|
colorInitData[i][j][3] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void init_velocity_vortex()
|
|
{
|
|
for(int i = 0; i < texHeight; i++)
|
|
{
|
|
for(int j = 0; j < texWidth; j++)
|
|
{
|
|
float x = 2 * j / (float)texWidth - 1;
|
|
float y = 2 * i / (float)texWidth - 1;
|
|
velocityInitData[i][j][0] = sinf(2 * M_PI * y);
|
|
velocityInitData[i][j][1] = sinf(2 * M_PI * x);
|
|
}
|
|
}
|
|
}
|
|
|
|
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]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(splatProgram.src, 0);
|
|
|
|
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY);
|
|
glUniform3f(splatProgram.splatColor, splatVelX, splatVelY, 0);
|
|
glUniform1f(splatProgram.additive, 1);
|
|
glUniform1f(splatProgram.blending, 0);
|
|
|
|
glUniform1f(splatProgram.radius, radius);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(&velocityBuffer);
|
|
|
|
// dye
|
|
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]);
|
|
glUniform1i(splatProgram.src, 0);
|
|
|
|
glUniform2f(splatProgram.splatPos, splatPosX, splatPosY);
|
|
glUniform3f(splatProgram.splatColor, r, g, b);
|
|
glUniform1f(splatProgram.additive, 0);
|
|
glUniform1f(splatProgram.blending, 1);
|
|
glUniform1f(splatProgram.radius, radius);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(&colorBuffer);
|
|
}
|
|
|
|
void jacobi_solve(frame_buffer* x, frame_buffer* b, float invGridSize, int iterationCount)
|
|
{
|
|
glUseProgram(jacobiProgram.prog);
|
|
|
|
for(int i = 0; i < iterationCount; i++)
|
|
{
|
|
glBindFramebuffer(GL_FRAMEBUFFER, x->fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
|
|
glUniform1i(jacobiProgram.xTex, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, b->textures[0]);
|
|
glUniform1i(jacobiProgram.bTex, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(x);
|
|
}
|
|
}
|
|
|
|
void multigrid_coarsen_residual(frame_buffer* output, frame_buffer* x, frame_buffer* b, float invFineGridSize)
|
|
{
|
|
//NOTE: compute residual and downsample to coarser grid, put result in coarser buffer
|
|
glUseProgram(multigridRestrictResidualProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, output->fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
|
|
glUniform1i(multigridRestrictResidualProgram.xTex, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, b->textures[0]);
|
|
glUniform1i(multigridRestrictResidualProgram.bTex, 1);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(output);
|
|
}
|
|
|
|
void multigrid_prolongate_and_correct(frame_buffer* x, frame_buffer* error, float invFineGridSize)
|
|
{
|
|
//NOTE: correct finer pressure
|
|
glUseProgram(multigridCorrectProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, x->fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, x->textures[0]);
|
|
glUniform1i(multigridCorrectProgram.src, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, error->textures[0]);
|
|
glUniform1i(multigridCorrectProgram.error, 1);
|
|
|
|
glUniform1f(multigridCorrectProgram.invGridSize, invFineGridSize);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(x);
|
|
}
|
|
|
|
void multigrid_clear(frame_buffer* error)
|
|
{
|
|
glBindFramebuffer(GL_FRAMEBUFFER, error->fbos[0]);
|
|
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 offset = margin / texWidth;
|
|
float ratio = 1 - 2 * margin / texWidth;
|
|
|
|
float splatPosX = (mouseInput.x / frameWidth) * ratio + offset;
|
|
float splatPosY = (1 - mouseInput.y / frameHeight) * ratio + offset;
|
|
|
|
float splatVelX = (10000. * DELTA * mouseInput.deltaX / frameWidth) * ratio;
|
|
float splatVelY = (-10000. * DELTA * mouseInput.deltaY / frameWidth) * ratio;
|
|
|
|
float intensity = 100 * sqrtf(square(ratio * mouseInput.deltaX / frameWidth) + square(ratio * mouseInput.deltaY / frameHeight));
|
|
|
|
float r = intensity * (sinf(2 * M_PI * 0.1 * t) + 1);
|
|
float g = 0.5 * intensity * (cosf(2 * M_PI * 0.1 / M_E * t + 654) + 1);
|
|
float b = intensity * (sinf(2 * M_PI * 0.1 / M_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;
|
|
}
|
|
}
|
|
|
|
float testDiv[texWidth / 2][texWidth / 2][4];
|
|
|
|
oc_surface surface;
|
|
|
|
ORCA_EXPORT void oc_on_init()
|
|
{
|
|
oc_log_info("Hello, world (from C)");
|
|
|
|
surface = oc_surface_gles();
|
|
oc_surface_select(surface);
|
|
|
|
// 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
|
|
oc_log_info("create color buffer");
|
|
init_frame_buffer(&colorBuffer, texWidth, texHeight, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, (char*)colorInitData);
|
|
oc_log_info("create velocity buffer");
|
|
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++)
|
|
{
|
|
oc_log_info("create div buffer %i", i);
|
|
init_frame_buffer(&divBuffer[i], texWidth / gridFactor, texHeight / gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
|
|
oc_log_info("create pressure buffer %i", i);
|
|
init_frame_buffer(&pressureBuffer[i], texWidth / gridFactor, texHeight / gridFactor, TEX_INTERNAL_FORMAT, TEX_FORMAT, TEX_TYPE, 0);
|
|
gridFactor *= 2;
|
|
}
|
|
|
|
// init vertex buffer
|
|
static Vertex vertices[6] = {
|
|
{ -1, -1 },
|
|
{ 1, -1 },
|
|
{ 1, 1 },
|
|
{ -1, -1 },
|
|
{ 1, 1 },
|
|
{ -1, 1 }
|
|
};
|
|
|
|
//WARN: we assume blitProgram.pos == advectProgram.pos, is there a situation where it wouldn't be true??
|
|
GLuint vertexBuffer = 0;
|
|
glGenBuffers(1, &vertexBuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
|
|
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(Vertex), vertices, GL_STATIC_DRAW);
|
|
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(blitProgram.pos, 2, GL_FLOAT, GL_FALSE, 0, 0);
|
|
|
|
for(int i = 0; i < texWidth / 2; i++)
|
|
{
|
|
for(int j = 0; j < texHeight / 2; j++)
|
|
{
|
|
testDiv[i][j][0] = 0.5 + 0.5 * cosf(j / 100. * 3.14159 + i / 100. * 1.2139);
|
|
}
|
|
}
|
|
}
|
|
|
|
ORCA_EXPORT void oc_on_resize(u32 width, u32 height)
|
|
{
|
|
frameWidth = width * 2;
|
|
frameHeight = height * 2;
|
|
}
|
|
|
|
ORCA_EXPORT void oc_on_frame_refresh()
|
|
{
|
|
float aspectRatio = texWidth / texHeight; //TODO replace with actual aspect ratio?
|
|
|
|
static float t = 0;
|
|
t += 1. / 60.;
|
|
|
|
oc_surface_select(surface);
|
|
|
|
glViewport(0, 0, texWidth, texHeight);
|
|
|
|
//NOTE: advect velocity thru itself
|
|
glUseProgram(advectProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(advectProgram.src, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(advectProgram.velocity, 1);
|
|
|
|
glUniform1f(advectProgram.delta, DELTA);
|
|
glUniform1f(advectProgram.dissipation, 0.01);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(&velocityBuffer);
|
|
|
|
/*
|
|
//DEBUG
|
|
static bool splatTrig = false;
|
|
static bool splat = false;
|
|
static float splatStart = 0;
|
|
static int splatDir = 0;
|
|
|
|
static int frameCount = 0;
|
|
|
|
if(resetCmd)
|
|
{
|
|
frameCount = 0;
|
|
splat = true;
|
|
splatStart = frameT;
|
|
}
|
|
|
|
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;
|
|
|
|
if(frameCount>20)
|
|
{
|
|
return;
|
|
}
|
|
frameCount++;
|
|
*/
|
|
|
|
input_splat(t);
|
|
|
|
//NOTE: compute divergence of advected velocity
|
|
glUseProgram(divProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(divProgram.src, 0);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
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]);
|
|
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, texWidth*texHeight);
|
|
#else
|
|
multigrid_clear(&pressureBuffer[0]);
|
|
|
|
for(int i = 0; i < 1; i++)
|
|
{
|
|
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]);
|
|
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]);
|
|
jacobi_solve(&pressureBuffer[2], &divBuffer[2], 4 * INV_GRID_SIZE, 30);
|
|
|
|
multigrid_prolongate_and_correct(&pressureBuffer[1], &pressureBuffer[2], 2 * INV_GRID_SIZE);
|
|
jacobi_solve(&pressureBuffer[1], &divBuffer[1], 2 * INV_GRID_SIZE, 8);
|
|
|
|
multigrid_prolongate_and_correct(&pressureBuffer[0], &pressureBuffer[1], INV_GRID_SIZE);
|
|
jacobi_solve(&pressureBuffer[0], &divBuffer[0], INV_GRID_SIZE, 4);
|
|
}
|
|
#endif
|
|
|
|
//NOTE: subtract pressure gradient to advected velocity
|
|
glUseProgram(subtractProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, velocityBuffer.fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(subtractProgram.src, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, pressureBuffer[0].textures[0]);
|
|
glUniform1i(subtractProgram.pressure, 1);
|
|
|
|
glUniform1f(subtractProgram.invGridSize, INV_GRID_SIZE);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
|
|
|
frame_buffer_swap(&velocityBuffer);
|
|
|
|
//NOTE: Advect color through corrected velocity field
|
|
glUseProgram(advectProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, colorBuffer.fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, colorBuffer.textures[0]);
|
|
glUniform1i(advectProgram.src, 0);
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(advectProgram.velocity, 1);
|
|
|
|
glUniform1f(advectProgram.delta, DELTA);
|
|
|
|
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, frameWidth, frameHeight);
|
|
|
|
float displayMatrix[16] = {
|
|
1 / aspectRatio, 0, 0, 0,
|
|
0, 1, 0, 0,
|
|
0, 0, 1, 0,
|
|
0, 0, 0, 1
|
|
};
|
|
|
|
/*
|
|
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);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
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: recompute divergence of (corrected) velocity
|
|
glUseProgram(divProgram.prog);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, divBuffer[0].fbos[1]);
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, velocityBuffer.textures[0]);
|
|
glUniform1i(divProgram.src, 0);
|
|
|
|
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);
|
|
|
|
//*/
|
|
|
|
oc_surface_present(surface);
|
|
}
|