My take on the Marisa bombs. Also blur shaders, minor fixes, etc.
This commit is contained in:
parent
c06a333726
commit
4e9ec77c91
24 changed files with 243 additions and 63 deletions
4
resources/shader/blur13.frag.glsl
Normal file
4
resources/shader/blur13.frag.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
#version 330 core
|
||||
|
||||
#define BLUR_KERNEL_SIZE 13
|
||||
#include "lib/blur.frag.glslh"
|
1
resources/shader/blur13.prog
Normal file
1
resources/shader/blur13.prog
Normal file
|
@ -0,0 +1 @@
|
|||
glsl_objects = blur13.frag standardnotex.vert
|
4
resources/shader/blur25.frag.glsl
Normal file
4
resources/shader/blur25.frag.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
#version 330 core
|
||||
|
||||
#define BLUR_KERNEL_SIZE 25
|
||||
#include "lib/blur.frag.glslh"
|
1
resources/shader/blur25.prog
Normal file
1
resources/shader/blur25.prog
Normal file
|
@ -0,0 +1 @@
|
|||
glsl_objects = blur25.frag standardnotex.vert
|
4
resources/shader/blur5.frag.glsl
Normal file
4
resources/shader/blur5.frag.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
#version 330 core
|
||||
|
||||
#define BLUR_KERNEL_SIZE 5
|
||||
#include "lib/blur.frag.glslh"
|
1
resources/shader/blur5.prog
Normal file
1
resources/shader/blur5.prog
Normal file
|
@ -0,0 +1 @@
|
|||
glsl_objects = blur5.frag standardnotex.vert
|
4
resources/shader/blur9.frag.glsl
Normal file
4
resources/shader/blur9.frag.glsl
Normal file
|
@ -0,0 +1,4 @@
|
|||
#version 330 core
|
||||
|
||||
#define BLUR_KERNEL_SIZE 9
|
||||
#include "lib/blur.frag.glslh"
|
1
resources/shader/blur9.prog
Normal file
1
resources/shader/blur9.prog
Normal file
|
@ -0,0 +1 @@
|
|||
glsl_objects = blur9.frag standardnotex.vert
|
24
resources/shader/lib/blur.frag.glslh
Normal file
24
resources/shader/lib/blur.frag.glslh
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
#ifndef BLUR_KERNEL_SIZE
|
||||
#error BLUR_KERNEL_SIZE not defined
|
||||
#endif
|
||||
|
||||
#include "../interface/standard.glslh"
|
||||
|
||||
UNIFORM(1) vec2 blur_resolution;
|
||||
UNIFORM(2) vec2 blur_direction;
|
||||
|
||||
// must have the highest location index
|
||||
UNIFORM(3) float blur_kernel[BLUR_KERNEL_SIZE];
|
||||
|
||||
void main(void) {
|
||||
const int kernel_half_size = (BLUR_KERNEL_SIZE - 1) / 2;
|
||||
vec4 color = vec4(0.0);
|
||||
vec2 dir = blur_direction / blur_resolution;
|
||||
|
||||
for(int i = -kernel_half_size; i <= kernel_half_size; ++i) {
|
||||
color += blur_kernel[kernel_half_size + i] * texture(tex, texCoord + dir * float(i));
|
||||
}
|
||||
|
||||
fragColor = color;
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
#include "interface/standard.glslh"
|
||||
|
||||
UNIFORM(1) float t;
|
||||
UNIFORM(2) vec3 tint;
|
||||
|
||||
float smootherstep(float x, float width) {
|
||||
// step function with a very slow decay towards zero
|
||||
|
@ -15,21 +14,25 @@ float smootherstep(float x, float width) {
|
|||
void main(void) {
|
||||
vec2 r = vec2(texCoord.x - 0.5, 1.0 - texCoord.y);
|
||||
|
||||
// globally distort the coordinate system a little bit for a more interesting/dynamic shape
|
||||
r.x -= 0.005 * sin(r.y * 13.32 - t * 0.53);
|
||||
|
||||
// this is > 0 in the basic core region of the spark. to make the shape more interesting, it is modulated with additional terms later.
|
||||
//
|
||||
//
|
||||
// The terms after abs(r.x) diverge to -∞ (= invisible later) assuring that
|
||||
// there are no hard edges. This is necessary because I use this debil
|
||||
// smootherstep function which never actually is zero for finite x. But it looks
|
||||
// better, mate. Glow!
|
||||
float coreRegion = 0.4 * pow(r.y, 0.3) - abs(r.x) - pow(0.1/(0.5 - abs(r.x))+0.1*abs(r.x)/r.y, 2);
|
||||
float coreRegion = 0.4 * pow(r.y, 0.25) - pow(abs(r.x), 1.0)*1.0 - pow(0.1/(0.5 - abs(r.x))+0.1*pow(abs(r.x), 1.5)/r.y, 2);
|
||||
|
||||
// smootherstep(coreRegion, 0) would be a mask for the bare cone shape of the spark. By adding extra terms it is distorted.
|
||||
// sin adds a wavy edge, the fraction with t takes care of fading in/out
|
||||
|
||||
float colorRegion = coreRegion - 0.01 * sin(r.y * 30 - t * 0.7) * (1-1/(t+1)) - 0.05;
|
||||
|
||||
float whiteRegion = coreRegion - 0.15 - 0.2 / (1 + t * 0.1);
|
||||
float whiteRegion = coreRegion - 0.15 * pow(r.y, 0.5) - 0.2 / (1 + t * 0.1);
|
||||
|
||||
fragColor = vec4(tint, 0) * smootherstep(colorRegion, 0.05)
|
||||
+ vec4(1, 1, 1, 0) * smootherstep(whiteRegion, 0.02);
|
||||
vec3 tint = hsv2rgb(vec3(t / 100.0 - pow(r.y, 0.25), 1.0, 1.0));
|
||||
|
||||
fragColor = mix(vec4(tint, 0) * smootherstep(colorRegion, 0.05), vec4(vec3(1), 0), 0.5 * smootherstep(whiteRegion, 0.02));
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ glsl_files = files(
|
|||
# @begin glsl
|
||||
'alpha_depth.frag.glsl',
|
||||
'bloom.frag.glsl',
|
||||
'blur13.frag.glsl',
|
||||
'blur25.frag.glsl',
|
||||
'blur5.frag.glsl',
|
||||
'blur9.frag.glsl',
|
||||
'boss_zoom.frag.glsl',
|
||||
'copy_depth.frag.glsl',
|
||||
'fxaa.frag.glsl',
|
||||
|
|
|
@ -101,7 +101,7 @@ Enemy *create_enemy_p(EnemyList *enemies, complex pos, float hp, EnemyVisualRule
|
|||
void* _delete_enemy(ListAnchor *enemies, List* enemy, void *arg) {
|
||||
Enemy *e = (Enemy*)enemy;
|
||||
|
||||
if(e->hp <= 0 && e->hp != ENEMY_IMMUNE) {
|
||||
if(e->hp <= 0 && e->hp != ENEMY_IMMUNE && e->hp != ENEMY_BOMB) {
|
||||
play_sound("enemydeath");
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "global.h"
|
||||
#include "plrmodes.h"
|
||||
#include "marisa.h"
|
||||
#include "stagedraw.h"
|
||||
|
||||
PlayerCharacter character_marisa = {
|
||||
.id = PLR_CHAR_MARISA,
|
||||
|
@ -83,11 +84,76 @@ void marisa_common_slave_visual(Enemy *e, int t, bool render) {
|
|||
});
|
||||
}
|
||||
|
||||
void marisa_common_masterspark_draw(int t, Color *tint) {
|
||||
ShaderProgram *prog_saved = r_shader_current();
|
||||
r_shader("masterspark");
|
||||
r_uniform_vec3("tint", tint->r, tint->g, tint->b);
|
||||
r_uniform_float("t", t);
|
||||
r_draw_quad();
|
||||
r_shader_ptr(prog_saved);
|
||||
static void draw_masterspark_ring(int t, float width) {
|
||||
float sy = sqrt(t / 500.0) * 6;
|
||||
float sx = sy * width / 800;
|
||||
|
||||
if(sx == 0 || sy == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
r_draw_sprite(&(SpriteParams) {
|
||||
.sprite = "masterspark_ring",
|
||||
.shader = "sprite_default",
|
||||
.pos = { 0, -t*t*0.4 + 2 },
|
||||
.color = RGBA(0.5, 0.5, 0.5, 0.0),
|
||||
.scale = { .x = sx, .y = sy * sy * 1.5 },
|
||||
});
|
||||
}
|
||||
|
||||
static void draw_masterspark_beam(complex origin, complex size, float angle, int t, float alpha) {
|
||||
r_mat_push();
|
||||
r_mat_translate(creal(origin), cimag(origin), 0);
|
||||
r_mat_rotate(angle, 0, 0, 1);
|
||||
|
||||
r_shader("masterspark");
|
||||
r_uniform_float("t", t);
|
||||
|
||||
r_mat_push();
|
||||
r_mat_translate(0, cimag(size) * -0.5, 0);
|
||||
r_mat_scale(alpha * creal(size), cimag(size), 1);
|
||||
r_draw_quad();
|
||||
r_mat_pop();
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
draw_masterspark_ring(t % 20 + 10 * i, alpha * creal(size));
|
||||
}
|
||||
|
||||
r_mat_pop();
|
||||
}
|
||||
|
||||
void marisa_common_masterspark_draw(complex origin, complex size, float angle, int t, float alpha) {
|
||||
r_state_push();
|
||||
|
||||
float blur = 1.0 - alpha;
|
||||
|
||||
if(blur == 0) {
|
||||
draw_masterspark_beam(origin, size, angle, t, alpha);
|
||||
} else {
|
||||
Framebuffer *main_fb = r_framebuffer_current();
|
||||
FBPair *aux = stage_get_fbpair(FBPAIR_FG_AUX);
|
||||
|
||||
r_framebuffer(aux->back);
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_clear(CLEAR_COLOR);
|
||||
|
||||
draw_masterspark_beam(origin, size, angle, t, alpha);
|
||||
|
||||
r_shader("blur25");
|
||||
r_uniform_vec2("blur_resolution", VIEWPORT_W, VIEWPORT_H);
|
||||
r_uniform_vec2("blur_direction", blur, 0);
|
||||
|
||||
fbpair_swap(aux);
|
||||
r_framebuffer(aux->back);
|
||||
r_clear(CLEAR_COLOR);
|
||||
draw_framebuffer_tex(aux->front, VIEWPORT_W, VIEWPORT_H);
|
||||
|
||||
r_uniform_vec2("blur_direction", 0, blur);
|
||||
|
||||
fbpair_swap(aux);
|
||||
r_framebuffer(main_fb);
|
||||
draw_framebuffer_tex(aux->front, VIEWPORT_W, VIEWPORT_H);
|
||||
}
|
||||
|
||||
r_state_pop();
|
||||
}
|
||||
|
|
|
@ -20,4 +20,4 @@ extern PlayerCharacter character_marisa;
|
|||
double marisa_common_property(Player *plr, PlrProperty prop);
|
||||
void marisa_common_shot(Player *plr, float dmg);
|
||||
void marisa_common_slave_visual(Enemy *e, int t, bool render);
|
||||
void marisa_common_masterspark_draw(int t, Color *tint);
|
||||
void marisa_common_masterspark_draw(complex origin, complex size, float angle, int t, float alpha);
|
||||
|
|
|
@ -401,27 +401,18 @@ static void masterspark_visual(Enemy *e, int t2, bool render) {
|
|||
|
||||
float t = player_get_bomb_progress(&global.plr, NULL);
|
||||
float fade = 1;
|
||||
complex diroffset = e->args[0];
|
||||
|
||||
if(t < 1./6) {
|
||||
fade = t*6;
|
||||
fade = sqrt(fade);
|
||||
fade = pow(fade, 1.0/3.0);
|
||||
}
|
||||
|
||||
if(t > 3./4) {
|
||||
fade = 1-t*4 + 3;
|
||||
fade *= fade;
|
||||
if(t > 4./5) {
|
||||
fade = 1-t*5 + 4;
|
||||
fade = pow(fade, 5);
|
||||
}
|
||||
|
||||
r_mat_push();
|
||||
r_mat_translate(creal(global.plr.pos), cimag(global.plr.pos), 0);
|
||||
r_mat_rotate(carg(diroffset), 0, 0, 1);
|
||||
r_mat_translate(0, - 40 - VIEWPORT_H/2, 0);
|
||||
|
||||
Color color = *HSL(t2/100., 1, 0.5);
|
||||
r_mat_scale(fade * 800, VIEWPORT_H, 1);
|
||||
marisa_common_masterspark_draw(t * global.plr.bombtotaltime, &color);
|
||||
r_mat_pop();
|
||||
marisa_common_masterspark_draw(global.plr.pos - 30 * I, 800 + I * VIEWPORT_H * 1.25, carg(e->args[0]), t2, fade);
|
||||
}
|
||||
|
||||
static int masterspark_star(Projectile *p, int t) {
|
||||
|
@ -434,30 +425,37 @@ static int masterspark_star(Projectile *p, int t) {
|
|||
}
|
||||
|
||||
static int masterspark(Enemy *e, int t2) {
|
||||
// FIXME: This may interact badly with other view shake effects...
|
||||
// We need a proper system for this stuff.
|
||||
|
||||
if(t2 == EVENT_BIRTH) {
|
||||
global.shake_view = 8;
|
||||
return 1;
|
||||
} else if(t2 == EVENT_DEATH) {
|
||||
global.shake_view=0;
|
||||
global.shake_view = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(t2 < 0)
|
||||
return 1;
|
||||
e->args[0] *= cexp(I*0.005*creal(global.plr.velocity));
|
||||
|
||||
e->args[0] *= cexp(I*(0.005*creal(global.plr.velocity) + nfrand() * 0.005));
|
||||
complex diroffset = e->args[0];
|
||||
|
||||
float t = player_get_bomb_progress(&global.plr, NULL);
|
||||
if(t2%2==0 && t < 3./4) {
|
||||
complex dir = -cexp(1.2*I*nfrand())*I;
|
||||
Color *c = HSLA(-t,1,0.5,0);
|
||||
|
||||
if(t >= 3.0/4.0) {
|
||||
global.shake_view = 8 * (1 - t * 4 + 3);
|
||||
} else if(t2 % 2 == 0) {
|
||||
complex dir = -cexp(1.5*I*sin(t2*M_PI*1.12))*I;
|
||||
Color *c = HSLA(-t*5.321,1,0.5,0.5*frand());
|
||||
PARTICLE(
|
||||
.sprite = "maristar_orbit",
|
||||
.pos = global.plr.pos+40*dir,
|
||||
.color = c,
|
||||
.rule = masterspark_star,
|
||||
.timeout = 50,
|
||||
.args= { (10 * dir - 10*I)*diroffset, 6 },
|
||||
.args= { (10 * dir - 10*I)*diroffset, 4 },
|
||||
.angle = nfrand(),
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
|
@ -468,7 +466,7 @@ static int masterspark(Enemy *e, int t2) {
|
|||
.color = c,
|
||||
.rule = masterspark_star,
|
||||
.timeout = 50,
|
||||
.args = { (10 * dir - 10*I)*diroffset, 6 },
|
||||
.args = { (10 * dir - 10*I)*diroffset, 4 },
|
||||
.angle = nfrand(),
|
||||
.draw_rule = GrowFade
|
||||
);
|
||||
|
@ -512,7 +510,8 @@ static void marisa_laser_bombbg(Player *plr) {
|
|||
|
||||
static void marisa_laser_bomb(Player *plr) {
|
||||
play_sound("bomb_marisa_a");
|
||||
create_enemy_p(&plr->slaves, 40.0*I, ENEMY_BOMB, masterspark_visual, masterspark, 1,0,0,0);
|
||||
Enemy *e = create_enemy_p(&plr->slaves, 0.0*I, ENEMY_BOMB, masterspark_visual, masterspark, 1,0,0,0);
|
||||
e->ent.draw_layer = LAYER_PLAYER_FOCUS - 1;
|
||||
}
|
||||
|
||||
static Enemy* marisa_laser_spawn_slave(Player *plr, complex pos, complex a0, complex a1, complex a2, complex a3) {
|
||||
|
@ -609,6 +608,7 @@ static void marisa_laser_preload(void) {
|
|||
"proj/marisa",
|
||||
"part/maristar_orbit",
|
||||
"hakkero",
|
||||
"masterspark_ring",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
|
|
|
@ -201,16 +201,10 @@ static void marisa_star_orbit_visual(Enemy *e, int t, bool render) {
|
|||
|
||||
color_mul_scalar(&color, fade);
|
||||
|
||||
marisa_common_masterspark_draw(e->pos, 250*fade + VIEWPORT_H*1.5*I, carg(e->pos - global.plr.pos) + M_PI/2, global.plr.bombtotaltime * tb, fade);
|
||||
|
||||
r_mat_push();
|
||||
r_mat_translate(creal(e->pos),cimag(e->pos),0);
|
||||
r_mat_push();
|
||||
r_mat_rotate_deg(carg(e->pos-global.plr.pos)*180/M_PI+90,0,0,1);
|
||||
|
||||
r_mat_scale(250*fade,VIEWPORT_H*1.5,1);
|
||||
r_mat_translate(0,-0.5,0);
|
||||
marisa_common_masterspark_draw(global.plr.bombtotaltime*tb, &color);
|
||||
|
||||
r_mat_pop();
|
||||
color.a = 0;
|
||||
r_color(&color);
|
||||
r_mat_rotate_deg(t*10,0,0,1);
|
||||
|
@ -226,7 +220,8 @@ static void marisa_star_bomb(Player *plr) {
|
|||
int count = 5; // might as well be hard coded. We are talking marisa here.
|
||||
for(int i = 0; i < 5; i++) {
|
||||
complex dir = cexp(2*I*M_PI/count*i);
|
||||
create_enemy2c(plr->pos,ENEMY_IMMUNE,marisa_star_orbit_visual,marisa_star_orbit,i,dir);
|
||||
Enemy *e = create_enemy2c(plr->pos, ENEMY_BOMB, marisa_star_orbit_visual, marisa_star_orbit, i ,dir);
|
||||
e->ent.draw_layer = LAYER_PLAYER_FOCUS - 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,6 +317,7 @@ static void marisa_star_preload(void) {
|
|||
"proj/maristar",
|
||||
"part/maristar_orbit",
|
||||
"hakkero",
|
||||
"masterspark_ring",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "common/models.h"
|
||||
#include "common/state.h"
|
||||
#include "util/glm.h"
|
||||
#include "util/graphics.h"
|
||||
|
||||
#define B _r_backend.funcs
|
||||
|
||||
|
@ -29,6 +30,12 @@ void r_init(void) {
|
|||
_r_backend_init();
|
||||
}
|
||||
|
||||
typedef struct BlurInfo {
|
||||
const char *progname;
|
||||
int kernel_size;
|
||||
float sigma;
|
||||
} BlurInfo;
|
||||
|
||||
void r_post_init(void) {
|
||||
_r_state_init();
|
||||
B.post_init();
|
||||
|
@ -43,6 +50,21 @@ void r_post_init(void) {
|
|||
"standardnotex",
|
||||
NULL);
|
||||
|
||||
BlurInfo blurs[] = {
|
||||
// { "blur5", 5, 1.25, },
|
||||
// { "blur9", 9, 1.85, },
|
||||
// { "blur13", 13, 2.45, },
|
||||
{ "blur25", 25, 4.25, },
|
||||
};
|
||||
|
||||
for(int i = 0; i < sizeof(blurs)/sizeof(*blurs); ++i) {
|
||||
preload_resource(RES_SHADER_PROGRAM, blurs[i].progname, RESF_PERMANENT);
|
||||
}
|
||||
|
||||
for(int i = 0; i < sizeof(blurs)/sizeof(*blurs); ++i) {
|
||||
init_blur_shader(r_shader_get(blurs[i].progname), blurs[i].kernel_size, blurs[i].sigma);
|
||||
}
|
||||
|
||||
R.progs.standard = r_shader_get("standard");
|
||||
R.progs.standardnotex = r_shader_get("standardnotex");
|
||||
|
||||
|
|
|
@ -67,7 +67,17 @@ static bool stage1_draw_predicate(EntityInterface *ent) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(ent->type == ENT_BOSS || ent->type == ENT_ENEMY) {
|
||||
if(ent->type == ENT_BOSS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(ent->type == ENT_ENEMY) {
|
||||
Enemy *e = ENT_CAST(ent, Enemy);
|
||||
|
||||
if(e->hp == ENEMY_BOMB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,41 +30,43 @@ static void fbpair_resize_fb(Framebuffer *fb, FramebufferAttachment attachment,
|
|||
void fbpair_create(FBPair *pair, uint num_attachments, FBAttachmentConfig attachments[num_attachments]) {
|
||||
assert(num_attachments > 0 && num_attachments <= FRAMEBUFFER_MAX_ATTACHMENTS);
|
||||
memset(pair, 0, sizeof(*pair));
|
||||
fbpair_create_fb(*(void**)&pair->front = pair->framebuffers + 0, num_attachments, attachments);
|
||||
fbpair_create_fb(*(void**)&pair->back = pair->framebuffers + 1, num_attachments, attachments);
|
||||
fbpair_create_fb(pair->front = calloc(1, sizeof(Framebuffer)), num_attachments, attachments);
|
||||
fbpair_create_fb(pair->back = calloc(1, sizeof(Framebuffer)), num_attachments, attachments);
|
||||
}
|
||||
|
||||
void fbpair_destroy(FBPair *pair) {
|
||||
fbpair_destroy_fb(pair->framebuffers + 0);
|
||||
fbpair_destroy_fb(pair->framebuffers + 1);
|
||||
fbpair_destroy_fb(pair->front);
|
||||
fbpair_destroy_fb(pair->back);
|
||||
free(pair->front);
|
||||
free(pair->back);
|
||||
}
|
||||
|
||||
void fbpair_swap(FBPair *pair) {
|
||||
void *tmp = pair->front;
|
||||
*(void**)&pair->front = pair->back;
|
||||
*(void**)&pair->back = tmp;
|
||||
pair->front = pair->back;
|
||||
pair->back = tmp;
|
||||
}
|
||||
|
||||
static void fbpair_clear(FBPair *pair) {
|
||||
r_state_push();
|
||||
r_clear_color4(0, 0, 0, 0);
|
||||
r_framebuffer(pair->framebuffers + 0);
|
||||
r_framebuffer(pair->front);
|
||||
r_clear(CLEAR_ALL);
|
||||
r_framebuffer(pair->framebuffers + 1);
|
||||
r_framebuffer(pair->back);
|
||||
r_clear(CLEAR_ALL);
|
||||
r_state_pop();
|
||||
}
|
||||
|
||||
void fbpair_resize(FBPair *pair, FramebufferAttachment attachment, uint width, uint height) {
|
||||
fbpair_resize_fb(pair->framebuffers + 0, attachment, width, height);
|
||||
fbpair_resize_fb(pair->framebuffers + 1, attachment, width, height);
|
||||
fbpair_resize_fb(pair->front, attachment, width, height);
|
||||
fbpair_resize_fb(pair->back, attachment, width, height);
|
||||
fbpair_clear(pair);
|
||||
}
|
||||
|
||||
void fbpair_resize_all(FBPair *pair, uint width, uint height) {
|
||||
for(uint i = 0; i < FRAMEBUFFER_MAX_ATTACHMENTS; ++i) {
|
||||
fbpair_resize_fb(pair->framebuffers + 0, i, width, height);
|
||||
fbpair_resize_fb(pair->framebuffers + 1, i, width, height);
|
||||
fbpair_resize_fb(pair->front, i, width, height);
|
||||
fbpair_resize_fb(pair->back, i, width, height);
|
||||
}
|
||||
|
||||
fbpair_clear(pair);
|
||||
|
|
|
@ -20,10 +20,8 @@ typedef struct FBPair {
|
|||
* 4. Rinse, repeat.
|
||||
*/
|
||||
|
||||
Framebuffer *const front;
|
||||
Framebuffer *const back;
|
||||
|
||||
Framebuffer framebuffers[2];
|
||||
Framebuffer *front;
|
||||
Framebuffer *back;
|
||||
} FBPair;
|
||||
|
||||
typedef struct FBAttachmentConfig {
|
||||
|
|
|
@ -157,3 +157,9 @@ void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment,
|
|||
r_texture_create(tex, ¶ms);
|
||||
r_framebuffer_attach(fb, tex, 0, attachment);
|
||||
}
|
||||
|
||||
void init_blur_shader(ShaderProgram *prog, size_t kernel_size, float sigma) {
|
||||
float kernel[kernel_size];
|
||||
gaussian_kernel_1d(kernel_size, sigma, kernel);
|
||||
r_uniform_ptr(r_shader_uniform(prog, "blur_kernel[0]"), kernel_size, kernel);
|
||||
}
|
||||
|
|
|
@ -21,3 +21,5 @@ void draw_framebuffer_attachment(Framebuffer *fb, double width, double height, F
|
|||
void fbutil_create_attachments(Framebuffer *fb, uint num_attachments, FBAttachmentConfig attachments[num_attachments]);
|
||||
void fbutil_destroy_attachments(Framebuffer *fb);
|
||||
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height);
|
||||
|
||||
void init_blur_shader(ShaderProgram *prog, size_t kernel_size, float sigma);
|
||||
|
|
|
@ -106,3 +106,28 @@ float smoothreclamp(float x, float old_min, float old_max, float new_min, float
|
|||
float sanitize_scale(float scale) {
|
||||
return max(0.1, scale);
|
||||
}
|
||||
|
||||
float normpdf(float x, float sigma) {
|
||||
return 0.39894 * exp(-0.5 * pow(x, 2) / pow(sigma, 2)) / sigma;
|
||||
}
|
||||
|
||||
void gaussian_kernel_1d(size_t size, float sigma, float kernel[size]) {
|
||||
assert(size & 1);
|
||||
|
||||
double sum = 0.0;
|
||||
size_t halfsize = size / 2;
|
||||
|
||||
kernel[halfsize] = normpdf(0, sigma);
|
||||
sum += kernel[halfsize];
|
||||
|
||||
for(size_t i = 1; i <= halfsize; ++i) {
|
||||
float k = normpdf(i, sigma);
|
||||
kernel[halfsize + i] = kernel[halfsize - i] = k;
|
||||
sum += k * 2;
|
||||
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < size; ++i) {
|
||||
kernel[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ float ftopow2(float x) attr_const;
|
|||
float smooth(float x) attr_const;
|
||||
float smoothreclamp(float x, float old_min, float old_max, float new_min, float new_max) attr_const;
|
||||
float sanitize_scale(float scale) attr_const;
|
||||
float normpdf(float x, float sigma) attr_const;
|
||||
void gaussian_kernel_1d(size_t size, float sigma, float kernel[size]) attr_nonnull(3);
|
||||
|
||||
#define topow2(x) (_Generic((x), \
|
||||
uint32_t: topow2_u32, \
|
||||
|
|
Loading…
Reference in a new issue