stage4: update background

* Add parallax mapping for pebbles
* Optimize meshes
* Add bevels to bridge and stone path
* Misc shading adjustments
* Enable anisotropic filtering
* Revamp corridor lighting + add torches
* Improve water
This commit is contained in:
Andrei Alexeyev 2021-09-18 18:43:46 +03:00
parent 0f8975d4be
commit 417471b784
No known key found for this signature in database
GPG key ID: 72D26128040B9690
41 changed files with 392 additions and 83 deletions

View file

@ -1 +1 @@
linearize = true
anisotropy = 16

View file

@ -1 +1 @@
linearize = true
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -3,3 +3,6 @@ ambient_map = stage4/ground_ambient
diffuse_map = stage4/ground_diffuse
normal_map = stage4/ground_normal
roughness_map = stage4/ground_roughness
depth_map = stage4/ground_depth
depth_scale = 0.005

View file

@ -1 +1 @@
linearize = True
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -1 +1 @@
linearize = true
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -3,3 +3,4 @@ ambient_map = stage4/mansion_ambient
diffuse_map = stage4/mansion_diffuse
normal_map = stage4/mansion_normal
roughness_map = stage4/mansion_roughness

View file

@ -1 +1 @@
linearize = True
anisotropy = 16

View file

@ -1 +1 @@
linearize = true
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -0,0 +1 @@
anisotropy = 16

View file

@ -0,0 +1,14 @@
#version 330 core
#include "lib/defs.glslh"
#include "interface/particle_emitter.glslh"
void main(void) {
vec4 c = color * texture(sprite_tex, tex_coord.xy);
if(all(lessThan(c, vec4(1.0/256.0)))) {
discard;
}
fragColor = c;
}

View file

@ -0,0 +1 @@
objects = fireparticles.vert fireparticles.frag

View file

@ -0,0 +1,65 @@
#version 330 core
#include "lib/defs.glslh"
#include "lib/util.glslh"
#include "lib/render_context.glslh"
#include "lib/hash.glslh"
#include "interface/particle_emitter.glslh"
const float min_scale = 0.8;
const float max_scale = 1.0;
const float min_shrink = 0.2;
const float min_lift = 0.9;
const float max_lift = 1.2;
const float min_ofs = 0.02;
const float max_ofs = 0.2;
const float lift_scale = 3;
const vec3 v_forward = vec3(0, 0, 1);
const vec3 v_right = vec3(1, 0, 0);
const vec3 v_up = vec3(0, -1, 0);
void main(void) {
// instance seed is used to seed the time offset of this instance
vec3 instance_seed = vec3(seed, float(gl_InstanceID));
float t = hash13(instance_seed) + time;
// particle seed is used to seed the random properties of this particle
vec4 particle_seed = vec4(instance_seed, floor(t));
vec4 rand = hash44(particle_seed);
float state = fract(t);
float nstate = 1.0 - state;
float nstate2 = nstate * nstate;
float nstate4 = nstate2 * nstate2;
float nstate6 = nstate4 * nstate2;
float ph = (seed.y - seed.x + t) * (21 + 0.1 * rand.z);
float d = 0.2 * nstate2;
vec3 up = v_up + d * vec3(sin(ph + seed.y), 0, cos(ph - seed.x));
float a = rand.x * tau;
float sin_a = sin(a);
float cos_a = cos(a);
vec3 p = mat3(mat2(cos_a, sin_a, -sin_a, cos_a)) * position;
p *= mix(min_scale, max_scale, rand.y) * mix(min_shrink, 1, nstate2);
p += (mix(min_lift, max_lift, rand.z) * lift_scale * state) * up;
p += mix(min_ofs, max_ofs, rand.w) * (v_forward * sin_a + v_right * cos_a);
gl_Position = r_projectionMatrix * r_modelViewMatrix * vec4(p, 1.0);
tex_coord.xy = uv_to_region(sprite_tex_region, texCoordRawIn);
tex_coord.zw = texCoordRawIn;
color.rgb = color_base + color_nstate * nstate + color_nstate2 * nstate2;
color.rgb *= nstate6;
color.a = smoothstep(0.1, 0.5, state);
color.a *= color.a;
color.a *= color.a;
float f = 0.075;
color *= smoothstep(0, f, state) * nstate2;
color *= tint;
}

View file

@ -0,0 +1,26 @@
#ifndef I_PARTICLE_EMITTER_H
#define I_PARTICLE_EMITTER_H
#ifdef VERT_STAGE
ATTRIBUTE(0) vec3 position;
ATTRIBUTE(1) vec2 texCoordRawIn;
#endif
#ifdef FRAG_STAGE
OUT(0) vec4 fragColor;
#endif
UNIFORM(0) sampler2D sprite_tex;
UNIFORM(1) vec4 sprite_tex_region;
UNIFORM(2) float time;
UNIFORM(3) vec2 seed;
UNIFORM(4) vec4 tint;
UNIFORM(6) vec3 color_base;
UNIFORM(7) vec3 color_nstate;
UNIFORM(8) vec3 color_nstate2;
VARYING(0) vec4 tex_coord;
VARYING(1) vec4 color;
#endif

View file

@ -26,6 +26,8 @@ glsl_files = files(
'extra_tower_apply_mask.frag.glsl',
'extra_tower_mask.frag.glsl',
'extra_tower_mask.vert.glsl',
'fireparticles.frag.glsl',
'fireparticles.vert.glsl',
'fxaa.frag.glsl',
'fxaa.vert.glsl',
'glitch.frag.glsl',

View file

@ -6,8 +6,9 @@
#include "lib/water.glslh"
#include "lib/frag_util.glslh"
const int steps = 10;
UNIFORM(5) float wave_height;
const int steps = 10;
// way to optimize: do projection matrix in the vertex shader
vec3 pos_to_texcoord(vec3 pos) {
@ -15,27 +16,18 @@ vec3 pos_to_texcoord(vec3 pos) {
return 0.5*tmp.xyz/tmp.w + vec3(0.5);
}
void main(void) {
vec2 uv = flip_native_to_bottomleft(texCoord - wave_offset);
float height = 0.01*warpedNoise(uv * 4, time);
vec2 dheightduv = dFduv(height, uv);
mat3 tbn = mat3(normalize(tangent), normalize(bitangent), normalize(normal));
vec3 n = normalize(tbn*vec3(-dheightduv, 1));
vec3 trace_screenspace_reflection(vec3 pos, vec3 n, sampler2D screen_depth, sampler2D screen_color) {
vec3 reflected_ray = reflect(pos, n);
reflected_ray /= length(reflected_ray.xy);
float step_size = 15./steps;
const float step_size = 15.0 / steps;
fragColor = r_color;
vec3 color = vec3(0);
int ihit = 0;
for(int i = 1; i < steps; i++) {
vec3 raypos = pos + i * step_size * reflected_ray;
vec3 raycoord = pos_to_texcoord(raypos);
float bgdepth = texture(depth, raycoord.xy).r;
float bgdepth = texture(screen_depth, raycoord.xy).r;
if(bgdepth < raycoord.z) {
ihit = i;
break; // sorry gpu
@ -43,15 +35,30 @@ void main(void) {
}
if(ihit == 0) {
return;
return color;
}
for(int j = 0; j < steps; j++) {
vec3 raypos = pos + (ihit-1+j*1.0/(steps-1)) * step_size * reflected_ray;
vec3 raycoord = pos_to_texcoord(raypos);
float bgdepth = texture(depth, raycoord.xy).r;
float bgdepth = texture(screen_depth, raycoord.xy).r;
if(bgdepth < raycoord.z) {
fragColor += 0.8 * texture(tex, raycoord.xy);
color += 0.8 * texture(screen_color, raycoord.xy).rgb;
break; // sorry gpu
}
}
return color;
}
void main(void) {
vec2 uv = flip_native_to_bottomleft(texCoord - wave_offset);
float height = wave_height * warpedNoise(uv * 4, time);
vec2 dheightduv = dFduv(height, uv);
mat3 tbn = mat3(normalize(tangent), normalize(bitangent), normalize(normal));
vec3 n = normalize(tbn*vec3(-dheightduv, 1));
fragColor = r_color;
fragColor.rgb *= trace_screenspace_reflection(pos, n, depth, tex);
}

View file

@ -23,7 +23,6 @@ TASK(update_stage_3d) {
TASK(animate_bg_fullstage) {
Camera3D *cam = &stage_3d_context.cam;
cam->far = 300;
cam->pos[2] = -1.8;
cam->pos[1] = -30;
@ -44,36 +43,66 @@ TASK(animate_bg_fullstage) {
INVOKE_TASK(common_easing_animate,&cam->vel[1], 0.06, 200, glm_ease_quad_in);
}
void stage4_bg_init_fullstage() {
static void stage4_bg_init_common(void) {
Stage4DrawData *draw_data = stage4_get_draw_data();
draw_data->ambient_color = *RGB(0.3, 0.3, 0.3);
stage_3d_context.cam.far = 300;
glm_vec3_copy((vec3) { 0.8f, 0.4f, 0.2f }, draw_data->corridor.torch_light.base);
draw_data->corridor.torch_light.r_factor = 0.1;
draw_data->corridor.torch_light.g_factor = 0.05;
// nstate goes from 1 to 0 linearly as the particle evolves
// particle color = color_base + (nstate * color_nstate) + (nstate^2 * color_nstate2)
glm_vec3_copy((vec3) { 10.0f, 0.0f, 0.0f }, draw_data->corridor.torch_particles.c_base);
glm_vec3_copy((vec3) { 0.0f, 0.0f, 0.8f }, draw_data->corridor.torch_particles.c_nstate);
glm_vec3_copy((vec3) { 0.0f, 3.2f, 0.0f }, draw_data->corridor.torch_particles.c_nstate2);
}
void stage4_bg_init_fullstage(void) {
stage4_bg_init_common();
INVOKE_TASK(update_stage_3d);
INVOKE_TASK(animate_bg_fullstage);
}
void stage4_bg_init_spellpractice(void) {
stage_3d_context.cam.far = 300;
stage4_bg_init_common();
stage_3d_context.cam.pos[2] = 4;
stage_3d_context.cam.pos[1] = 200;
stage_3d_context.cam.rot.v[0] = 80;
stage_3d_context.cam.vel[1] = 0.06;
stage_3d_context.cam.vel[1] = 0.05;
stage4_bg_redden_corridor();
INVOKE_TASK(update_stage_3d);
}
TASK(redden_corridor) {
Stage4DrawData *draw_data = stage4_get_draw_data();
int t = 100;
for(int i = 0; i < t; i++) {
color_approach(&draw_data->ambient_color, RGB(1, 0, 0), 1.0f / t);
YIELD;
}
// INVOKE_TASK_DELAYED(60, common_call_func, stage4_bg_redden_corridor);
}
void stage4_bg_redden_corridor(void) {
INVOKE_TASK(redden_corridor);
// TODO: maybe a nicer transition effect based on proximity of the lights
Stage4DrawData *draw_data = stage4_get_draw_data();
INVOKE_TASK(common_easing_animate_vec3,
&draw_data->corridor.torch_light.base,
{ 0.8f, 0.1f, 0.2f },
60,
glm_ease_quad_out
);
INVOKE_TASK(common_easing_animate_vec3,
&draw_data->corridor.torch_particles.c_base,
{ 10.0f, 0.0, 0.0f },
60,
glm_ease_quad_out
);
INVOKE_TASK(common_easing_animate_vec3,
&draw_data->corridor.torch_particles.c_nstate,
{ 10.0f, 0.2f, 0.3f },
80,
glm_ease_quad_out
);
INVOKE_TASK(common_easing_animate_vec3,
&draw_data->corridor.torch_particles.c_nstate2,
{ 10.0f, 0.2f, 0.2f },
56,
glm_ease_quad_out
);
}

View file

@ -13,6 +13,10 @@
#include "global.h"
#include "util/glm.h"
#define LIGHT_OFS { 2.7f, 4.86f, 0.3f }
#define CORRIDOR_POS { 0.0f, 25.0f, 3.0f }
#define TORCHLIGHT_CLOCK (global.frames / 30.0f)
static Stage4DrawData *stage4_draw_data;
Stage4DrawData *stage4_get_draw_data(void) {
@ -20,17 +24,34 @@ Stage4DrawData *stage4_get_draw_data(void) {
}
static bool stage4_fog(Framebuffer *fb) {
float f = 0;
r_state_push();
r_blend(BLEND_NONE);
// NOTE: this is applied in linear HDR space, before tonemapping
Color c = *RGBA(0.05, 0.0, 0.01, 1.0);
r_shader("zbuf_fog");
r_uniform_sampler("depth", r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
r_uniform_vec4("fog_color", 9.0*f+0.1, 0.0, 0.1-f, 1.0);
r_uniform_vec4_rgba("fog_color", &c);
r_uniform_float("start", 0.4);
r_uniform_float("end", 1);
r_uniform_float("exponent", 50.0);
r_uniform_float("exponent", 20.0);
r_uniform_float("curvature", 0);
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
r_shader_standard();
r_state_pop();
return true;
}
static bool stage4_tonemap(Framebuffer *fb) {
r_state_push();
r_blend(BLEND_NONE);
r_shader("tonemap");
r_uniform_vec3("exposure", 1, 1, 1);
draw_framebuffer_tex(fb, VIEWPORT_W, VIEWPORT_H);
r_state_pop();
return true;
}
@ -52,14 +73,18 @@ static bool stage4_water(Framebuffer *fb) {
r_mat_mv_translate(0, 3, -0.6);
r_enable(RCAP_DEPTH_TEST);
r_mat_mv_scale(20,-20,10);
r_mat_mv_scale(15, -10, 1);
r_shader("ssr_water");
r_uniform_sampler("depth", r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_DEPTH));
r_uniform_sampler("tex", r_framebuffer_get_attachment(fb, FRAMEBUFFER_ATTACH_COLOR0));
r_uniform_float("time", global.frames * 0.002);
r_uniform_vec2("wave_offset", -global.frames * 0.0005, 0);
r_color4(0, 0.01, 0.01, 1);
r_uniform_float("wave_height", 0.005);
r_color4(0.8, 0.9, 1.0, 1);
r_mat_tex_push();
r_mat_tex_scale(3, 3, 3);
r_draw_quad();
r_mat_tex_pop();
r_mat_mv_pop();
r_state_pop();
@ -73,17 +98,40 @@ static bool stage4_water_composite(Framebuffer *reflections) {
return false;
}
r_shader("alpha_discard");
r_state_push();
// NOTE: Ideally, we should copy depth from the previous framebuffer here,
// otherwise the fog shader will destroy parts of the water that were composed
// over the void. We can get away without a proper copy in this case by simply
// enabling unconditional depth writes. This way, fragments that were not
// rejected by the alpha threshold test will get a depth value of 0.5 from the
// screen-space quad. This effectively makes the water fragments completely
// exempt from the fog effect, which is not 100% correct, but the error is not
// noticeable with our camera and fog settings.
// Perhaps a more delcarative post-processing system would be nice, so that we
// could specify which passes consume and/or update depth, and have the depth
// buffer copied automatically when needed.
r_enable(RCAP_DEPTH_TEST);
r_depth_func(DEPTH_ALWAYS);
r_blend(BLEND_NONE);
r_shader("alpha_discard");
r_uniform_float("threshold", 1);
draw_framebuffer_tex(reflections, VIEWPORT_W, VIEWPORT_H);
r_state_pop();
return true;
}
static void torchlight(float t, PointLight3D *light);
static void stage4_bg_setup_pbr_lighting_outdoors(Camera3D *cam) {
PointLight3D lights[] = {
{ { 0, 0, 0 }, { 3, 4, 5 } },
{ { 0, 25, 3 }, { 4, 20, 22 } },
{ { 0, 25, 3 }, { 4*0, 20*0, 22*0} },
};
vec3 r;
@ -97,33 +145,54 @@ static void stage4_bg_setup_pbr_lighting_outdoors(Camera3D *cam) {
static void stage4_bg_setup_pbr_env_outdoors(Camera3D *cam, PBREnvironment *env) {
stage4_bg_setup_pbr_lighting_outdoors(cam);
glm_vec3_broadcast(1.0f, env->ambient_color);
env->disable_tonemap = true;
}
static void torchlight(float t, PointLight3D *light) {
uint32_t prng = float_to_bits(light->pos[0]) ^ float_to_bits(light->pos[1]);
float t_ofs = (float)(splitmix32(&prng) / (double)UINT32_MAX);
t += 32.124 * t_ofs;
float o0 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float o1 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float o2 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float o3 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float o4 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float o5 = (float)(splitmix32(&prng) / (double)UINT32_MAX);
float r = powf(psinf(2*t+o0), 2) + powf(pcosf(4.43*t+o1), 4) + powf(psinf(5*t+o2), 21);
float g = powf(psinf(1.65*t+o3), 2) + powf(pcosf(5.21*t+o4), 3) + powf(psinf(-3*t+o5), 12);
r = fmaxf(r, g);
r = powf(tanh(r), 5);
g = powf(tanh(g), 5);
vec3 c;
vec3 rg = {
r * stage4_draw_data->corridor.torch_light.r_factor,
g * stage4_draw_data->corridor.torch_light.g_factor,
0.0f
};
glm_vec3_add(stage4_draw_data->corridor.torch_light.base, rg, c);
glm_vec3_scale(c, 20 + sinf(t) + cosf(2*t), light->radiance);
}
static void stage4_bg_setup_pbr_lighting_indoors(Camera3D *cam, vec3 pos) {
float xoff = 3.0f;
float zoff = 1.3f;
vec3 off = LIGHT_OFS;
PointLight3D lights[] = {
{ { -xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1], pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]-10, pos[2]+zoff }, { 1, 20, 20 } },
{ { -xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
{ { xoff, pos[1]+10, pos[2]+zoff }, { 1, 20, 20 } },
{ { -off[0], off[1]+pos[1], pos[2]+off[2] } },
{ { off[0], off[1]+pos[1], pos[2]+off[2] } },
{ { -off[0], off[1]+pos[1]-10, pos[2]+off[2] } },
{ { off[0], off[1]+pos[1]-10, pos[2]+off[2] } },
{ { -off[0], off[1]+pos[1]+10, pos[2]+off[2] } },
{ { off[0], off[1]+pos[1]+10, pos[2]+off[2] } },
};
float t = TORCHLIGHT_CLOCK;
for(int i = 0; i < ARRAY_SIZE(lights); i++) {
float t = global.frames * 0.02f;
float mod1 = cosf(13095434.0f * lights[i].pos[1]);
float mod2 = sinf(1242435.0f * lights[i].pos[0] * lights[i].pos[1]);
float f = (
sinf((1.0f + mod1) * t) +
sinf((2.35f + mod2) * t + mod1) +
sinf((3.1257f + mod1 * mod2) * t + mod2)
) / 3.0f;
glm_vec3_scale(lights[i].radiance, 0.6f + 0.4f * f, lights[i].radiance);
torchlight(t, lights + i);
}
camera3d_set_point_light_uniforms(cam, ARRAY_SIZE(lights), lights);
@ -131,13 +200,13 @@ static void stage4_bg_setup_pbr_lighting_indoors(Camera3D *cam, vec3 pos) {
static void stage4_bg_setup_pbr_env_indoors(Camera3D *cam, vec3 pos, PBREnvironment *env) {
stage4_bg_setup_pbr_lighting_indoors(cam, pos);
glm_vec3_copy(&stage4_draw_data->ambient_color.r, env->ambient_color);
log_debug("%0.2f %0.2f %0.2f", env->ambient_color[0], env->ambient_color[1], env->ambient_color[2]);
glm_vec3_copy(stage4_draw_data->ambient_color.rgb, env->ambient_color);
env->disable_tonemap = true;
}
static uint stage4_lake_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 0, 0};
return single3dpos(s3d, pos, maxrange, p);
static uint stage4_lake_pos(Stage3D *s3d, vec3 cam, float maxrange) {
vec3 orig = {0, 0, 0};
return stage3d_pos_single(s3d, cam, orig, 35);
}
static void stage4_lake_draw(vec3 pos) {
@ -157,19 +226,16 @@ static void stage4_lake_draw(vec3 pos) {
r_state_pop();
}
static uint stage4_corridor_pos(Stage3D *s3d, vec3 pos, float maxrange) {
vec3 p = {0, 25, 3};
static uint stage4_corridor_pos(Stage3D *s3d, vec3 cam, float maxrange) {
vec3 p = CORRIDOR_POS;
vec3 r = {0, 10, 0};
return stage3d_pos_ray_nearfirst(s3d, cam, p, r, maxrange, 0);
}
uint num = linear3dpos(s3d, pos, maxrange, p, r);
for(uint i = 0; i < num; ++i) {
if(s3d->pos_buffer[i][1] < p[1]) {
s3d->pos_buffer[i][1] = -9000;
}
}
return num;
static uint stage4_flames_pos(Stage3D *s3d, vec3 cam, float maxrange) {
vec3 p = CORRIDOR_POS;
vec3 r = {0, 10, 0};
return stage3d_pos_ray_farfirst(s3d, cam, p, r, maxrange, 0);
}
static void stage4_corridor_draw(vec3 pos) {
@ -188,13 +254,78 @@ static void stage4_corridor_draw(vec3 pos) {
r_state_pop();
}
static void stage4_flames_draw(vec3 pos) {
r_state_push();
r_mat_mv_push();
Camera3D *cam = &stage_3d_context.cam;
float dist = pos[1] - cam->pos[1];
float dmin = 8;
float dmax = 128;
float lod = 1.0f - clamp((dist - dmin) / (dmax - dmin), 0.0f, 1.0f);
uint imin = 16;
uint imax = 256;
uint instances = lerpf(imin, imax, lod * lod * lod * lod);
float al = fminf(1.0f, 64.0f / instances);
r_blend(BLEND_PREMUL_ALPHA);
r_disable(RCAP_DEPTH_WRITE);
const Model *quad = r_model_get_quad();
Sprite *spr = res_sprite("part/stain");
r_shader("fireparticles");
r_uniform_sampler("sprite_tex", spr->tex);
r_uniform_vec3_vec("color_base", stage4_draw_data->corridor.torch_particles.c_base);
r_uniform_vec3_vec("color_nstate", stage4_draw_data->corridor.torch_particles.c_nstate);
r_uniform_vec3_vec("color_nstate2", stage4_draw_data->corridor.torch_particles.c_nstate2);
r_uniform_vec4("tint", al, al, al, al);
r_uniform_vec4("sprite_tex_region",
spr->tex_area.x,
spr->tex_area.y,
spr->tex_area.w,
spr->tex_area.h
);
r_uniform_float("time", global.frames / 120.0f);
vec3 ofs = LIGHT_OFS;
vec3 p;
mat4 *mv;
glm_vec3_add(pos, ofs, p);
r_uniform_vec2_vec("seed", p);
r_mat_mv_push();
r_mat_mv_translate_v(p);
mv = r_mat_mv_current_ptr();
glm_mul(*mv, stage4_draw_data->fire_emitter_transform, *mv);
r_draw_model_ptr(quad, instances, 0);
r_mat_mv_pop();
ofs[0] *= -1.0f;
glm_vec3_add(pos, ofs, p);
r_uniform_vec2_vec("seed", p);
r_mat_mv_push();
r_mat_mv_translate_v(p);
mv = r_mat_mv_current_ptr();
glm_mul(*mv, stage4_draw_data->fire_emitter_transform, *mv);
r_draw_model_ptr(quad, instances, 0);
r_mat_mv_pop();
r_mat_mv_pop();
r_state_pop();
}
void stage4_draw(void) {
Stage3DSegment segs[] = {
{ stage4_lake_draw, stage4_lake_pos },
{ stage4_corridor_draw, stage4_corridor_pos },
{ stage4_flames_draw, stage4_flames_pos },
};
stage3d_draw(&stage_3d_context, 400, ARRAY_SIZE(segs), segs);
stage3d_draw(&stage_3d_context, 240, ARRAY_SIZE(segs), segs);
}
void stage4_drawsys_init(void) {
@ -204,6 +335,12 @@ void stage4_drawsys_init(void) {
pbr_load_model(&stage4_draw_data->models.corridor, "stage4/corridor", "stage4/corridor");
pbr_load_model(&stage4_draw_data->models.ground, "stage4/ground", "stage4/ground");
pbr_load_model(&stage4_draw_data->models.mansion, "stage4/mansion", "stage4/mansion");
mat4 *m = &stage4_draw_data->fire_emitter_transform;
glm_mat4_identity(*m);
glm_rotate_x(*m, -M_PI/2, *m);
float s = 0.6f;
glm_scale_to(*m, (vec3) { 0.5f * s, s, s }, *m);
}
void stage4_drawsys_shutdown(void) {
@ -216,5 +353,6 @@ ShaderRule stage4_bg_effects[] = {
stage4_water,
stage4_water_composite,
stage4_fog,
stage4_tonemap,
NULL,
};

View file

@ -22,6 +22,22 @@ typedef struct Stage4DrawData {
PBRModel ground;
PBRModel mansion;
} models;
struct {
struct {
vec3 c_base;
vec3 c_nstate;
vec3 c_nstate2;
} torch_particles;
struct {
vec3 base;
float r_factor;
float g_factor;
} torch_light;
} corridor;
mat4 fire_emitter_transform;
} Stage4DrawData;
void stage4_drawsys_init(void);