techkaczynski.dev / code

summaryrefslogtreecommitdiff
path: root/env.c
blob: f00b669e27b2f5b172882c41147353346f85b74b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
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);
}