]> git.lizzy.rs Git - dragonblocks_alpha.git/blob - src/client/scene.c
d2d42ca17706f51b178f09f09c7cfd04650c0a64
[dragonblocks_alpha.git] / src / client / scene.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include "client/camera.h"
4 #include "client/client.h"
5 #include "client/client_config.h"
6 #include "client/frustum.h"
7 #include "client/scene.h"
8 #include "client/shader.h"
9 #include "day.h"
10 #include "util.h"
11
12 struct Scene scene;
13
14 static int bintree_compare_f32(void *v1, void *v2, unused Bintree *tree)
15 {
16         f32 diff = (*(f32 *) v2) - (*(f32 *) v1);
17         return CMPBOUNDS(diff);
18 }
19
20 bool scene_init()
21 {
22         scene.objects = list_create(NULL);
23         scene.transparent_objects = bintree_create(sizeof(f32), &bintree_compare_f32);
24         pthread_mutex_init(&scene.mtx, NULL);
25
26         glGetIntegerv(GL_MAX_TEXTURE_UNITS, &scene.max_texture_units);
27
28         char *shader_defs = format_string(
29                 "#define MAX_TEXTURE_UNITS %d\n"
30                 "#define RENDER_DISTANCE %lf\n",
31                 scene.max_texture_units,
32                 client_config.render_distance
33         );
34
35         if (! shader_program_create(RESSOURCE_PATH "shaders/3d", &scene.prog, shader_defs)) {
36                 fprintf(stderr, "Failed to create 3D shader program\n");
37                 return false;
38         }
39
40         free(shader_defs);
41
42         scene.loc_model = glGetUniformLocation(scene.prog, "model");
43         scene.loc_VP = glGetUniformLocation(scene.prog, "VP");
44         scene.loc_daylight = glGetUniformLocation(scene.prog, "daylight");
45         scene.loc_fogColor = glGetUniformLocation(scene.prog, "fogColor");
46         scene.loc_ambientLight = glGetUniformLocation(scene.prog, "ambientLight");
47         scene.loc_lightDir = glGetUniformLocation(scene.prog, "lightDir");
48         scene.loc_cameraPos = glGetUniformLocation(scene.prog, "cameraPos");
49
50         GLint texture_indices[scene.max_texture_units];
51         for (GLint i = 0; i < scene.max_texture_units; i++)
52                 texture_indices[i] = i;
53
54         glProgramUniform1iv(scene.prog, glGetUniformLocation(scene.prog, "textures"), scene.max_texture_units, texture_indices);
55
56         scene.fov = 86.1f;
57
58         return true;
59 }
60
61 static void list_delete_object(void *key, unused void *value, unused void *arg)
62 {
63         object_delete(key);
64 }
65
66 void scene_deinit()
67 {
68         list_clear_func(&scene.objects, &list_delete_object, NULL);
69         pthread_mutex_destroy(&scene.mtx);
70         glDeleteProgram(scene.prog);
71 }
72
73 void scene_add_object(Object *obj)
74 {
75         pthread_mutex_lock(&scene.mtx);
76         list_put(&scene.objects, obj, NULL);
77         pthread_mutex_unlock(&scene.mtx);
78 }
79
80 static void bintree_render_object(BintreeNode *node, unused void *arg)
81 {
82         object_render(node->value);
83 }
84
85 void scene_render(f64 dtime)
86 {
87         mat4x4_mul(scene.VP, scene.projection, camera.view);
88
89         vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f};
90         vec4 sunlight_dir;
91         mat4x4 sunlight_mat;
92         mat4x4_identity(sunlight_mat);
93
94         mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f);
95         mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir);
96
97         frustum_update(scene.VP);
98
99         f32 daylight = get_daylight();
100         f32 ambient_light = f32_mix(0.3f, 0.7f, daylight);
101         v3f32 fog_color = v3f32_mix((v3f32) {0x03, 0x0A, 0x1A}, (v3f32) {0x87, 0xCE, 0xEB}, daylight);
102
103         glUseProgram(scene.prog);
104         glUniformMatrix4fv(scene.loc_VP, 1, GL_FALSE, scene.VP[0]);
105         glUniform3f(scene.loc_lightDir, sunlight_dir[0], sunlight_dir[1], sunlight_dir[2]);
106         glUniform3f(scene.loc_cameraPos, camera.eye[0], camera.eye[1], camera.eye[2]);
107         glUniform1f(scene.loc_daylight, daylight);
108         glUniform3f(scene.loc_fogColor, fog_color.x / 0xFF * ambient_light, fog_color.y / 0xFF * ambient_light, fog_color.z / 0xFF * ambient_light);
109         glUniform1f(scene.loc_ambientLight, ambient_light);
110
111         for (ListPair **pairptr = &scene.objects.first; *pairptr != NULL; ) {
112                 ListPair *pair = *pairptr;
113                 Object *obj = pair->key;
114                 if (obj->remove) {
115                         pthread_mutex_lock(&scene.mtx);
116                         *pairptr = pair->next;
117                         pthread_mutex_unlock(&scene.mtx);
118                         free(pair);
119                         object_delete(obj);
120                 } else {
121                         f32 distance = sqrt(pow(obj->pos.x - camera.eye[0], 2) + pow(obj->pos.y - camera.eye[1], 2) + pow(obj->pos.z - camera.eye[2], 2));
122                         if (distance < client_config.render_distance && object_before_render(obj, dtime)) {
123                                 if (obj->transparent)
124                                         bintree_insert(&scene.transparent_objects, &distance, obj);
125                                 else
126                                         object_render(obj);
127                         }
128                         pairptr = &pair->next;
129                 }
130         }
131
132         bintree_traverse(&scene.transparent_objects, BTT_INORDER, &bintree_render_object, NULL);
133         bintree_clear(&scene.transparent_objects, NULL, NULL);
134 }
135
136 void scene_on_resize(int width, int height)
137 {
138         mat4x4_perspective(scene.projection, scene.fov / 180.0f * M_PI, (float) width / (float) height, 0.01f, client_config.render_distance + 28.0f);
139 }
140
141 GLuint scene_get_max_texture_units()
142 {
143         return scene.max_texture_units;
144 }