techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/env.c
diff options
context:
space:
mode:
Diffstat (limited to 'env.c')
-rw-r--r--env.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/env.c b/env.c
new file mode 100644
index 0000000..f00b669
--- /dev/null
+++ b/env.c
@@ -0,0 +1,384 @@
+#include "env.h"
+
+Environment env = {0};
+
+static const Color SKY_NIGHT_HORIZON = { 14, 11, 28, 255 };
+static const Color SKY_NIGHT_ZENITH = { 1, 2, 6, 255 };
+static const Color SKY_DAY_HORIZON = { 158, 199, 235, 255 };
+static const Color SKY_DAY_ZENITH = { 20, 71, 158, 255 };
+
+static f32
+sky_smoothstep(f32 edge_0, f32 edge_1, f32 value) {
+ f32 amount = (value - edge_0) / (edge_1 - edge_0);
+
+ if (amount < 0.0f) {
+ amount = 0.0f;
+ } else if (amount > 1.0f) {
+ amount = 1.0f;
+ }
+
+ return amount * amount * (3.0f - 2.0f * amount);
+}
+
+static Vec3
+sky_get_sun_direction(f32 cycle) {
+ f32 angle = cycle * 2.0f * PI - PI * 0.5f;
+
+ Vec3 dir = (Vec3) {
+ cosf(angle),
+ sinf(angle),
+ 0.0f
+ };
+
+ return Vector3Normalize(dir);
+}
+
+static Vec3
+sky_get_moon_direction(Vec3 sun_dir) {
+ return Vector3Negate(sun_dir);
+}
+
+static void
+sky_draw_symbol(Texture tex, Vec3 dir, Camera3D cam, f32 angular_diameter,
+ Color tint, f32 visibility) {
+ if (tex.id == 0 || visibility <= 0.0f) {
+ return;
+ }
+
+ Vec3 cam_fwd = Vector3Normalize(
+ Vector3Subtract(cam.target, cam.position));
+
+ f32 fwd_facing = Vector3DotProduct(cam_fwd, dir);
+
+ // don't draw if behind the camera
+ if (fwd_facing <= 0.0f) {
+ return;
+ }
+
+ // distance is arbitrary. Only the direction matters because result is
+ // projected into screen space.
+ Vec3 world_pos = Vector3Add(cam.position, Vector3Scale(dir, 1000.0f));
+ Vec2 scr_pos = GetWorldToScreen(world_pos, cam);
+
+ // Convert the requested angular diameter into pixels. This makes the
+ // symbols respond correctly when camera FOV changes.
+ f32 vfov = cam.fovy * DEG2RAD;
+
+ f32 diameter =
+ (f32)GetScreenHeight() *
+ tanf(angular_diameter * DEG2RAD * 0.5f) /
+ tanf(vfov * 0.5f);
+
+ if (diameter < 1.0f) {
+ return;
+ }
+
+ tint.a = (u8)((f32)tint.a * visibility);
+
+ Rect src = (Rect) { 0, 0, (f32)tex.width, (f32)tex.height };
+ Rect dst = (Rect) { scr_pos.x, scr_pos.y, diameter, diameter };
+ Vec2 origin = (Vec2) { diameter * 0.5f, diameter * 0.5f };
+
+ DrawTexturePro(tex, src, dst, origin, 0, tint);
+}
+
+static Color
+color_lerp(Color a, Color b, f32 t) {
+ t = Clamp(t, 0.0f, 1.0f);
+
+ return (Color) {
+ (u8)Lerp(a.r, b.r, t),
+ (u8)Lerp(a.g, b.g, t),
+ (u8)Lerp(a.b, b.b, t),
+ (u8)Lerp(a.a, b.a, t),
+ };
+}
+
+static Vec3
+color_to_vec3(Color col) {
+ return (Vec3) {
+ (f32)col.r / 255.0f,
+ (f32)col.g / 255.0f,
+ (f32)col.b / 255.0f,
+ };
+}
+
+static void
+sky_update_lighting(void) {
+ Vec3 sun_dir = sky_get_sun_direction(env.cycle);
+ Vec3 moon_dir = sky_get_moon_direction(sun_dir);
+
+ f32 day_amount = sky_smoothstep(-0.08f, 0.15f, sun_dir.y);
+ f32 night_amount = 1.0f - day_amount;
+
+ // Strongest when the sun is close to the horizon.
+ f32 twilight_amount = 1.0f - sky_smoothstep(
+ 0.02f,
+ 0.28f,
+ fabsf(sun_dir.y)
+ );
+
+ Color horizon_col = color_lerp(
+ SKY_NIGHT_HORIZON,
+ SKY_DAY_HORIZON,
+ day_amount
+ );
+
+ Color zenith_col = color_lerp(
+ SKY_NIGHT_ZENITH,
+ SKY_DAY_ZENITH,
+ day_amount
+ );
+
+ Color night_ambient = { 18, 22, 42, 255 };
+ Color day_ambient = { 145, 165, 185, 255 };
+ Color twilight_ambient = { 185, 90, 55, 255 };
+
+ Color ambient_col = color_lerp(
+ night_ambient,
+ day_ambient,
+ day_amount
+ );
+
+ ambient_col = color_lerp(
+ ambient_col,
+ twilight_ambient,
+ twilight_amount * 0.45f
+ );
+
+ Color sun_col = color_lerp(
+ (Color){ 255, 155, 95, 255 },
+ (Color){ 255, 244, 215, 255 },
+ day_amount
+ );
+
+ Color moon_col = { 135, 155, 205, 255 };
+
+ env.sun_dir = sun_dir;
+ env.moon_dir = moon_dir;
+
+ env.sun_col = sun_col;
+ env.moon_col = moon_col;
+ env.ambient_col = ambient_col;
+
+ env.horizon_col = horizon_col;
+ env.zenith_col = zenith_col;
+
+ env.day_amount = day_amount;
+ env.twilight_amount = twilight_amount;
+
+ env.sun_intensity = day_amount;
+ env.moon_intensity = night_amount * 0.12f;
+ env.ambient_intensity = Lerp(0.18f, 0.55f, day_amount);
+}
+
+static void
+env_update_mdl_shader(void) {
+ Vec3 sun_col = color_to_vec3(env.sun_col);
+ Vec3 moon_col = color_to_vec3(env.moon_col);
+ Vec3 ambient_col = color_to_vec3(env.ambient_col);
+
+ Shader sdr = shader_get("model")->sdr;
+ SetTraceLogLevel(LOG_DEBUG);
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "sun_direction"),
+ &env.sun_dir,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "sun_colour"),
+ &sun_col,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "sun_intensity"),
+ &env.sun_intensity,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "moon_direction"),
+ &env.moon_dir,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "moon_colour"),
+ &moon_col,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "moon_intensity"),
+ &env.moon_intensity,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "ambient_colour"),
+ &ambient_col,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ sdr,
+ fun_shader_uniform("model", "ambient_intensity"),
+ &env.ambient_intensity,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ SetTraceLogLevel(LOG_WARNING);
+}
+
+void
+env_init(void) {
+ env.sky_sdr_key = "sky";
+ env.sun_tex_key = "res/tex/sun.png";
+ env.moon_tex_key = "res/tex/moon.png";
+ env.cycle = 0.2;
+ env.day_len = 240; // 600s = 5 min day/night cycle
+ env.sun_sz = 14;
+ env.moon_sz = 4;
+ env.sun_tint = WHITE;
+ env.moon_tint = GRAY;
+
+ sky_update_lighting();
+}
+
+void
+env_exit(void) {
+}
+
+void
+env_update(void) {
+ // if (env.day_len > 0.0f) {
+ // env.cycle += GetFrameTime() / env.day_len;
+ // env.cycle -= floorf(env.cycle);
+ // }
+ sky_update_lighting();
+ env_update_mdl_shader();
+}
+
+
+void
+env_draw_sky(Camera cam) {
+ int scr_w = GetScreenWidth();
+ int scr_h = GetScreenHeight();
+
+ if (scr_w <= 0 || scr_h <= 0) {
+ return;
+ }
+
+ Vec3 cam_fwd =
+ Vector3Normalize(Vector3Subtract(cam.target, cam.position));
+
+ Vec3 cam_right =
+ Vector3Normalize(Vector3CrossProduct(cam_fwd, cam.up));
+
+ Vec3 cam_up =
+ Vector3Normalize(Vector3CrossProduct(cam_right, cam_fwd));
+
+ Vec3 sun_dir = env.sun_dir;
+ Vec3 moon_dir = env.moon_dir;
+
+ f32 scr_res[2] = { (f32)scr_w, (f32)scr_h };
+ f32 aspect = scr_res[0] / scr_res[1];
+ f32 tan_half_fovy = tanf(cam.fovy * DEG2RAD * 0.5f);
+
+ Vec3 horizon_col = color_to_vec3(env.horizon_col);
+ Vec3 zenith_col = color_to_vec3(env.zenith_col);
+
+ FunShader *shader = shader_get(env.sky_sdr_key);
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "resolution"),
+ scr_res,
+ SHADER_UNIFORM_VEC2
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "camera_forward"),
+ &cam_fwd,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "camera_right"),
+ &cam_right,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "camera_up"),
+ &cam_up,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "sun_direction"),
+ &env.sun_dir,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "horizon_colour"),
+ &horizon_col,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "zenith_colour"),
+ &zenith_col,
+ SHADER_UNIFORM_VEC3
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "day_amount"),
+ &env.day_amount,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "twilight_amount"),
+ &env.twilight_amount,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ SetShaderValue(
+ shader->sdr,
+ fun_shader_uniform(env.sky_sdr_key, "tan_half_fovy"),
+ &tan_half_fovy,
+ SHADER_UNIFORM_FLOAT
+ );
+
+ BeginShaderMode(shader->sdr);
+ DrawRectangle(0, 0, scr_w, scr_h, WHITE);
+ EndShaderMode();
+
+ f32 sun_vis = sky_smoothstep(-0.05f, 0.25f, sun_dir.y);
+ f32 moon_vis = sky_smoothstep(-0.05f, 0.8f, moon_dir.y);
+
+ sky_draw_symbol(asset_get(env.sun_tex_key)->tex, sun_dir, cam,
+ env.sun_sz, env.sun_tint, sun_vis);
+
+ sky_draw_symbol(asset_get(env.moon_tex_key)->tex, moon_dir, cam,
+ env.moon_sz, env.moon_tint, moon_vis);
+}