From: Elias Fleckenstein Date: Sun, 17 Apr 2022 11:35:41 +0000 (+0200) Subject: You can now see other players X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=6d60079b8f06b9701c4e823d33ac11a843814183;p=dragonblocks_alpha.git You can now see other players --- diff --git a/models/player.txt b/models/player.txt index 0fe8485..ee482f8 100644 --- a/models/player.txt +++ b/models/player.txt @@ -1,7 +1,10 @@ name player scale 1 1.8 1 - name head pos 0 0.875 0 scale 0.45 0.25 0.45 cube head - name body scale 0.48 0.75 0.36 - name upper pos 0 1.0 0 scale 1 0.5 1 + name nametag pos 0 1.1 0 + name neck pos 0 0.75 0 scale 0.45 0.25 0.45 + name head pos 0 +0.5 0 cube head + name eyes pos 0 0 +0.5 + name body scale 0.48 0.75 0.225 + name upper pos 0 1.0 0 scale 1 0.5 1 name chest pos 0 -0.5 0 cube chest name shoulders scale 0.5 1 1 name left pos -1.5 0 0 diff --git a/shaders/3d/entity/fragment.glsl b/shaders/3d/entity/fragment.glsl new file mode 100755 index 0000000..2cd4768 --- /dev/null +++ b/shaders/3d/entity/fragment.glsl @@ -0,0 +1,19 @@ +in vec3 fragmentPosition; +in vec3 fragmentNormal; +in vec3 fragmentTextureCoordinates; +in float fragmentLight; + +out vec4 outColor; + +uniform vec3 fogColor; +uniform vec3 cameraPos; +uniform samplerCube texture0; + +void main() +{ + outColor = texture(texture0, fragmentTextureCoordinates) * vec4(vec3(fragmentLight), 1.0); + outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0)); + + if (outColor.a == 0.0) + discard; +} diff --git a/shaders/3d/entity/vertex.glsl b/shaders/3d/entity/vertex.glsl new file mode 100755 index 0000000..ca8684a --- /dev/null +++ b/shaders/3d/entity/vertex.glsl @@ -0,0 +1,26 @@ +layout(location = 0) in vec3 vertexPosition; +layout(location = 1) in vec3 vertexNormal; + +out vec3 fragmentPosition; +out vec3 fragmentNormal; +out vec3 fragmentTextureCoordinates; +out float fragmentLight; + +uniform mat4 model; +uniform mat4 VP; +uniform float daylight; +uniform float ambientLight; +uniform vec3 lightDir; + +void main() +{ + vec4 worldSpace = model * vec4(vertexPosition, 1.0); + gl_Position = VP * worldSpace; + + fragmentPosition = worldSpace.xyz; + fragmentNormal = vertexNormal; + fragmentTextureCoordinates = vertexPosition; + + float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0); + fragmentLight = ambientLight + diffuseLight; +} diff --git a/shaders/3d/terrain/fragment.glsl b/shaders/3d/terrain/fragment.glsl new file mode 100755 index 0000000..62ee89b --- /dev/null +++ b/shaders/3d/terrain/fragment.glsl @@ -0,0 +1,20 @@ +in vec3 fragmentPosition; +in vec3 fragmentNormal; +in vec2 fragmentTextureCoordinates; +in float fragmentTextureIndex; +in vec3 fragmentColor; + +out vec4 outColor; + +uniform vec3 fogColor; +uniform vec3 cameraPos; +uniform sampler2D textures[MAX_TEXTURE_UNITS]; + +void main() +{ + outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoordinates) * vec4(fragmentColor, 1.0); + outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0)); + + if (outColor.a == 0.0) + discard; +} diff --git a/shaders/3d/terrain/vertex.glsl b/shaders/3d/terrain/vertex.glsl new file mode 100755 index 0000000..abef047 --- /dev/null +++ b/shaders/3d/terrain/vertex.glsl @@ -0,0 +1,34 @@ +layout(location = 0) in vec3 vertexPosition; +layout(location = 1) in vec3 vertexNormal; +layout(location = 2) in vec2 vertexTextureCoordinates; +layout(location = 3) in float vertexTextureIndex; +layout(location = 4) in vec3 vertexColor; + +out vec3 fragmentPosition; +out vec3 fragmentNormal; +out vec2 fragmentTextureCoordinates; +out float fragmentTextureIndex; +out vec3 fragmentColor; + +uniform mat4 model; +uniform mat4 VP; +uniform float daylight; +uniform float ambientLight; +uniform vec3 lightDir; + +void main() +{ + vec4 worldSpace = model * vec4(vertexPosition, 1.0); + gl_Position = VP * worldSpace; + + fragmentPosition = worldSpace.xyz; + fragmentNormal = vertexNormal; + fragmentTextureCoordinates = vertexTextureCoordinates; + fragmentTextureIndex = vertexTextureIndex; + fragmentColor = vertexColor; + + float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0); + float light = ambientLight + diffuseLight; + + fragmentColor *= light; +} diff --git a/shaders/gui/font/fragment.glsl b/shaders/gui/font/fragment.glsl index 02f9186..883a012 100755 --- a/shaders/gui/font/fragment.glsl +++ b/shaders/gui/font/fragment.glsl @@ -1,4 +1,4 @@ -in vec2 fragmentTextureCoords; +in vec2 fragmentTextureCoordinates; out vec4 outColor; @@ -7,5 +7,5 @@ uniform vec4 color; void main() { - outColor = vec4(1.0, 1.0, 1.0, texture(texture0, fragmentTextureCoords).r) * color; + outColor = vec4(1.0, 1.0, 1.0, texture(texture0, fragmentTextureCoordinates).r) * color; } diff --git a/shaders/gui/font/vertex.glsl b/shaders/gui/font/vertex.glsl index 3072c1b..50bcd6e 100644 --- a/shaders/gui/font/vertex.glsl +++ b/shaders/gui/font/vertex.glsl @@ -1,7 +1,7 @@ layout(location = 0) in vec2 vertexPosition; -layout(location = 1) in vec2 vertexTextureCoords; +layout(location = 1) in vec2 vertexTextureCoordinates; -out vec2 fragmentTextureCoords; +out vec2 fragmentTextureCoordinates; uniform mat4 model; uniform mat4 projection; @@ -9,5 +9,5 @@ uniform mat4 projection; void main() { gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0); - fragmentTextureCoords = vertexTextureCoords; + fragmentTextureCoordinates = vertexTextureCoordinates; } diff --git a/shaders/gui/image/fragment.glsl b/shaders/gui/image/fragment.glsl index 3cb7c7e..bc8e428 100755 --- a/shaders/gui/image/fragment.glsl +++ b/shaders/gui/image/fragment.glsl @@ -1,4 +1,4 @@ -in vec2 fragmentTextureCoords; +in vec2 fragmentTextureCoordinates; out vec4 outColor; @@ -6,5 +6,5 @@ uniform sampler2D texture0; void main() { - outColor = texture(texture0, fragmentTextureCoords); + outColor = texture(texture0, fragmentTextureCoordinates); } diff --git a/shaders/gui/image/vertex.glsl b/shaders/gui/image/vertex.glsl index 3072c1b..50bcd6e 100755 --- a/shaders/gui/image/vertex.glsl +++ b/shaders/gui/image/vertex.glsl @@ -1,7 +1,7 @@ layout(location = 0) in vec2 vertexPosition; -layout(location = 1) in vec2 vertexTextureCoords; +layout(location = 1) in vec2 vertexTextureCoordinates; -out vec2 fragmentTextureCoords; +out vec2 fragmentTextureCoordinates; uniform mat4 model; uniform mat4 projection; @@ -9,5 +9,5 @@ uniform mat4 projection; void main() { gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0); - fragmentTextureCoords = vertexTextureCoords; + fragmentTextureCoordinates = vertexTextureCoordinates; } diff --git a/shaders/sky/clouds/fragment.glsl b/shaders/sky/clouds/fragment.glsl index f22dc67..32fc25b 100755 --- a/shaders/sky/clouds/fragment.glsl +++ b/shaders/sky/clouds/fragment.glsl @@ -1,4 +1,4 @@ -in vec3 fragmentTextureCoords; +in vec3 fragmentTextureCoordinates; out vec4 outColor; @@ -17,13 +17,13 @@ float strengthen(float value, float exponent, float max) void main() { - float height = normalize(fragmentTextureCoords).y; + float height = normalize(fragmentTextureCoordinates).y; vec4 topColor = texture(texture0, vec3(0.0, 1.0, 0.0)); vec4 bottomColor = texture(texture0, vec3(1.0, 0.11, 0.5)); vec4 expectedColor = mix(bottomColor, topColor, height); - vec4 dayColor = texture(texture0, fragmentTextureCoords); + vec4 dayColor = texture(texture0, fragmentTextureCoordinates); float cloudFactor = reverseMix(length(dayColor.rg - expectedColor.rg), 0.15, length(vec2(1.0))); diff --git a/shaders/sky/clouds/vertex.glsl b/shaders/sky/clouds/vertex.glsl index 6aab041..1b361b7 100755 --- a/shaders/sky/clouds/vertex.glsl +++ b/shaders/sky/clouds/vertex.glsl @@ -1,6 +1,6 @@ layout(location = 0) in vec3 vertexPosition; -out vec3 fragmentTextureCoords; +out vec3 fragmentTextureCoordinates; uniform mat4 VP; @@ -8,5 +8,5 @@ void main() { gl_Position = VP * vec4(vertexPosition, 1.0); gl_Position.z = gl_Position.w; - fragmentTextureCoords = vertexPosition; + fragmentTextureCoordinates = vertexPosition; } diff --git a/shaders/sky/skybox/fragment.glsl b/shaders/sky/skybox/fragment.glsl index ce1bac4..e6c61b4 100755 --- a/shaders/sky/skybox/fragment.glsl +++ b/shaders/sky/skybox/fragment.glsl @@ -1,4 +1,4 @@ -in vec3 fragmentTextureCoords; +in vec3 fragmentTextureCoordinates; out vec4 outColor; @@ -10,8 +10,8 @@ void main() vec4 topColor = texture(textures[0], vec3(0.0, 1.0, 0.0)); vec4 bottomColor = texture(textures[0], vec3(1.0, 0.11, 0.5)); - vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoords).y); - vec4 nightColor = texture(textures[1], fragmentTextureCoords); + vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoordinates).y); + vec4 nightColor = texture(textures[1], fragmentTextureCoordinates); outColor = mix(nightColor, dayColor, daylight); } diff --git a/shaders/sky/skybox/vertex.glsl b/shaders/sky/skybox/vertex.glsl index 6aab041..1b361b7 100755 --- a/shaders/sky/skybox/vertex.glsl +++ b/shaders/sky/skybox/vertex.glsl @@ -1,6 +1,6 @@ layout(location = 0) in vec3 vertexPosition; -out vec3 fragmentTextureCoords; +out vec3 fragmentTextureCoordinates; uniform mat4 VP; @@ -8,5 +8,5 @@ void main() { gl_Position = VP * vec4(vertexPosition, 1.0); gl_Position.z = gl_Position.w; - fragmentTextureCoords = vertexPosition; + fragmentTextureCoordinates = vertexPosition; } diff --git a/shaders/sky/sun/fragment.glsl b/shaders/sky/sun/fragment.glsl index 3cb7c7e..bc8e428 100755 --- a/shaders/sky/sun/fragment.glsl +++ b/shaders/sky/sun/fragment.glsl @@ -1,4 +1,4 @@ -in vec2 fragmentTextureCoords; +in vec2 fragmentTextureCoordinates; out vec4 outColor; @@ -6,5 +6,5 @@ uniform sampler2D texture0; void main() { - outColor = texture(texture0, fragmentTextureCoords); + outColor = texture(texture0, fragmentTextureCoordinates); } diff --git a/shaders/sky/sun/vertex.glsl b/shaders/sky/sun/vertex.glsl index f6bf7ce..243d17f 100755 --- a/shaders/sky/sun/vertex.glsl +++ b/shaders/sky/sun/vertex.glsl @@ -1,7 +1,7 @@ layout(location = 0) in vec3 vertexPosition; -layout(location = 1) in vec2 vertexTextureCoords; +layout(location = 1) in vec2 vertexTextureCoordinates; -out vec2 fragmentTextureCoords; +out vec2 fragmentTextureCoordinates; uniform mat4 MVP; @@ -9,5 +9,5 @@ void main() { gl_Position = MVP * vec4(vertexPosition, 1.0); gl_Position.z = gl_Position.w; - fragmentTextureCoords = vertexTextureCoords; + fragmentTextureCoordinates = vertexTextureCoordinates; } diff --git a/shaders/terrain/fragment.glsl b/shaders/terrain/fragment.glsl deleted file mode 100755 index 533c91c..0000000 --- a/shaders/terrain/fragment.glsl +++ /dev/null @@ -1,20 +0,0 @@ -in vec3 fragmentPosition; -in vec3 fragmentNormal; -in vec2 fragmentTextureCoords; -in float fragmentTextureIndex; -in vec3 fragmentColor; - -out vec4 outColor; - -uniform vec3 fogColor; -uniform vec3 cameraPos; -uniform sampler2D textures[MAX_TEXTURE_UNITS]; - -void main() -{ - outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoords) * vec4(fragmentColor, 1.0); - outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0)); - - if (outColor.a == 0.0) - discard; -} diff --git a/shaders/terrain/vertex.glsl b/shaders/terrain/vertex.glsl deleted file mode 100755 index 7104497..0000000 --- a/shaders/terrain/vertex.glsl +++ /dev/null @@ -1,34 +0,0 @@ -layout(location = 0) in vec3 vertexPosition; -layout(location = 1) in vec3 vertexNormal; -layout(location = 2) in vec2 vertexTextureCoords; -layout(location = 3) in float vertexTextureIndex; -layout(location = 4) in vec3 vertexColor; - -out vec3 fragmentPosition; -out vec3 fragmentNormal; -out vec2 fragmentTextureCoords; -out float fragmentTextureIndex; -out vec3 fragmentColor; - -uniform mat4 model; -uniform mat4 VP; -uniform float daylight; -uniform float ambientLight; -uniform vec3 lightDir; - -void main() -{ - vec4 worldSpace = model * vec4(vertexPosition, 1.0); - gl_Position = VP * worldSpace; - - fragmentPosition = worldSpace.xyz; - fragmentNormal = vertexNormal; - fragmentTextureCoords = vertexTextureCoords; - fragmentTextureIndex = vertexTextureIndex; - fragmentColor = vertexColor; - - float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0); - float light = ambientLight + diffuseLight; - - fragmentColor *= light; -} diff --git a/snapshot.sh b/snapshot.sh index 66b6882..9c1098f 100755 --- a/snapshot.sh +++ b/snapshot.sh @@ -9,7 +9,7 @@ cp -r * .build/ cd .build/ mkdir build cd build -if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" && make clean && make -j$(nproc)); then +if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" -DCMAKE_C_FLAGS="-Ofast" && make clean && make -j$(nproc)); then cd ../.. rm -rf .build exit 1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a9c496..e8d1b54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,10 @@ find_package(Freetype REQUIRED) # Options +if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_compile_definitions("ENABLE_GL_DEBUG") +endif() + add_compile_definitions("USE_DRAGONNET") add_compile_definitions("RESSOURCE_PATH=\"${RESSOURCE_PATH}\"") @@ -38,12 +42,12 @@ include_directories(BEFORE ${CMAKE_SOURCE_DIR}) # System specific options -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") +if("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") link_directories("/usr/local/lib") include_directories("/usr/local/include") endif() -if ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") +if("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") link_directories("/usr/X11R6/lib") include_directories("/usr/X11R6/include") endif() @@ -98,8 +102,10 @@ add_executable(dragonblocks client/font.c client/frustum.c client/game.c + client/gl_debug.c client/gui.c client/input.c + client/light.c client/mesh.c client/model.c client/shader.c diff --git a/src/client/client.c b/src/client/client.c index 0dd8626..c0160d0 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -144,7 +144,6 @@ int main(int argc, char **argv) client->on_recv_type[DRAGONNET_TYPE_ToClientEntityAdd ] = (void *) &client_entity_add; client->on_recv_type[DRAGONNET_TYPE_ToClientEntityRemove ] = (void *) &client_entity_remove; client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdatePosRot ] = (void *) &client_entity_update_pos_rot; - client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateBoxEye ] = (void *) &client_entity_update_box_eye; client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateNametag] = (void *) &client_entity_update_nametag; flag_ini(&finish); diff --git a/src/client/client_entity.c b/src/client/client_entity.c index 2c34b68..97173e8 100644 --- a/src/client/client_entity.c +++ b/src/client/client_entity.c @@ -1,12 +1,46 @@ +#include #include #include #include +#include "client/cube.h" +#include "client/client_config.h" #include "client/client_entity.h" #include "client/client_player.h" +#include "client/frustum.h" +#include "client/gl_debug.h" +#include "client/light.h" +#include "client/shader.h" +#include "client/window.h" ClientEntityType client_entity_types[COUNT_ENTITY]; +ModelShader client_entity_shader; +typedef struct { + v3f32 position; + v3f32 normal; +} __attribute__((packed)) EntityVertex; +Mesh client_entity_cube = { + .layout = &(VertexLayout) { + .attributes = (VertexAttribute[]) { + {GL_FLOAT, 3, sizeof(v3f32)}, // position + {GL_FLOAT, 3, sizeof(v3f32)}, // normal + }, + .count = 2, + .size = sizeof(EntityVertex), + }, + .vao = 0, + .vbo = 0, + .data = NULL, + .count = 36, + .free_data = false, +}; + +static GLuint shader_prog; +static GLint loc_VP; +static LightShader light_shader; static Map entities; +static List nametagged; +static pthread_mutex_t mtx_nametagged; // any thread // called when adding, getting or removing an entity from the map @@ -22,6 +56,14 @@ static void entity_drop(ClientEntity *entity) if (entity->type->remove) entity->type->remove(entity); + if (entity->nametag) { + pthread_mutex_lock(&mtx_nametagged); + list_del(&nametagged, &entity->rc, &cmp_ref, &refcount_drp, NULL, NULL); + pthread_mutex_unlock(&mtx_nametagged); + + entity->nametag->visible = false; + } + refcount_drp(&entity->rc); } @@ -38,17 +80,78 @@ static void entity_delete(ClientEntity *entity) free(entity->data.nametag); pthread_rwlock_init(&entity->lock_pos_rot, NULL); - pthread_rwlock_init(&entity->lock_box_eye, NULL); pthread_rwlock_init(&entity->lock_nametag, NULL); + pthread_rwlock_init(&entity->lock_box_off, NULL); free(entity); } +static void update_nametag(ClientEntity *entity) +{ + if (entity->nametag) { + gui_text(entity->nametag, entity->data.nametag); + + if (!entity->data.nametag) + entity->nametag->visible = false; + } else if (entity->data.nametag) { + entity->nametag = gui_add(NULL, (GUIElementDefinition) { + .pos = {-1.0f, -1.0f}, + .z_index = 0.1f, + .offset = {0, 0}, + .margin = {4, 4}, + .align = {0.5f, 0.5f}, + .scale = {1.0f, 1.0f}, + .scale_type = SCALE_TEXT, + .affect_parent_scale = false, + .text = entity->data.nametag, + .image = NULL, + .text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f}, + .bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.5f}, + }); + + pthread_mutex_lock(&mtx_nametagged); + list_apd(&nametagged, refcount_inc(&entity->rc)); + pthread_mutex_unlock(&mtx_nametagged); + } +} + +static void update_nametag_pos(ClientEntity *entity) +{ + if (!entity->data.nametag) + return; + + pthread_rwlock_rdlock(&entity->lock_pos_rot); + pthread_rwlock_rdlock(&entity->lock_box_off); + + mat4x4 mvp; + if (entity->nametag_offset) + mat4x4_mul(mvp, frustum, *entity->nametag_offset); + else + mat4x4_dup(mvp, frustum); + + vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f}; + mat4x4_mul_vec4(dst, mvp, src); + + dst[0] /= dst[3]; + dst[1] /= dst[3]; + dst[2] /= dst[3]; + + if ((entity->nametag->visible = dst[2] >= -1.0f && dst[2] <= 1.0f)) { + entity->nametag->def.pos = (v2f32) {dst[0] * 0.5f + 0.5f, 1.0f - (dst[1] * 0.5f + 0.5f)}; + gui_transform(entity->nametag); + } + + pthread_rwlock_unlock(&entity->lock_box_off); + pthread_rwlock_unlock(&entity->lock_pos_rot); +} + // main thread // called on startup void client_entity_init() { map_ini(&entities); + list_ini(&nametagged); + pthread_mutex_init(&mtx_nametagged, NULL); } // main thead @@ -57,6 +160,58 @@ void client_entity_deinit() { // forget all entities map_cnl(&entities, &refcount_drp, NULL, NULL, 0); + list_clr(&nametagged, &refcount_drp, NULL, NULL); + pthread_mutex_destroy(&mtx_nametagged); +} + +bool client_entity_gfx_init() +{ + char *shader_defs; + asprintf(&shader_defs, "#define VIEW_DISTANCE %lf\n", client_config.view_distance); + + if (!shader_program_create(RESSOURCE_PATH "shaders/3d/entity", &shader_prog, shader_defs)) { + fprintf(stderr, "[error] failed to create entity shader program\n"); + return false; + } + + free(shader_defs); + + loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG + + EntityVertex vertices[6][6]; + for (int f = 0; f < 6; f++) { + for (int v = 0; v < 6; v++) { + vertices[f][v].position = cube_vertices[f][v].position; + vertices[f][v].normal = cube_vertices[f][v].normal; + } + } + + client_entity_cube.data = vertices; + mesh_upload(&client_entity_cube); + + client_entity_shader.prog = shader_prog; + client_entity_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG + + light_shader.prog = shader_prog; + light_shader_locate(&light_shader); + + return true; +} + +void client_entity_gfx_deinit() +{ + glDeleteProgram(shader_prog); GL_DEBUG + mesh_destroy(&client_entity_cube); +} + +void client_entity_gfx_update() +{ + glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG + light_shader_update(&light_shader); + + pthread_mutex_lock(&mtx_nametagged); + list_itr(&nametagged, &update_nametag_pos, NULL, &refcount_obj); + pthread_mutex_unlock(&mtx_nametagged); } ClientEntity *client_entity_grab(u64 id) @@ -69,8 +224,8 @@ void client_entity_transform(ClientEntity *entity) if (!entity->model) return; - entity->model->root->pos = (v3f32) {entity->data.pos.x, entity->data.pos.y, entity->data.pos.z}; - entity->model->root->rot = (v3f32) {entity->data.rot.x, entity->data.rot.y, entity->data.rot.z}; + entity->model->root->pos = v3f64_to_f32(entity->data.pos); // ToDo: the render pipeline needs to be updated to handle 64-bit positions + entity->model->root->rot = entity->data.rot; if (entity->type->transform) entity->type->transform(entity); @@ -92,14 +247,17 @@ void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEnti pkt->data.nametag = NULL; entity->model = NULL; - - pthread_rwlock_init(&entity->lock_pos_rot, NULL); - pthread_rwlock_init(&entity->lock_box_eye, NULL); - pthread_rwlock_init(&entity->lock_nametag, NULL); + entity->nametag = NULL; if (entity->type->add) entity->type->add(entity); + update_nametag(entity); + + pthread_rwlock_init(&entity->lock_pos_rot, NULL); + pthread_rwlock_init(&entity->lock_nametag, NULL); + pthread_rwlock_init(&entity->lock_box_off, NULL); + if (!map_add(&entities, &entity->data.id, &entity->rc, &cmp_entity, &refcount_inc)) fprintf(stderr, "[warning] failed to add entity %lu\n", entity->data.id); @@ -126,27 +284,9 @@ void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, T if (entity->type->update_pos_rot) entity->type->update_pos_rot(entity); - pthread_rwlock_unlock(&entity->lock_pos_rot); + client_entity_transform(entity); - refcount_drp(&entity->rc); -} - -void client_entity_update_box_eye(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt) -{ - ClientEntity *entity = client_entity_grab(pkt->id); - - if (!entity) - return; - - pthread_rwlock_wrlock(&entity->lock_box_eye); - - entity->data.box = pkt->box; - entity->data.eye = pkt->eye; - - if (entity->type->update_box_eye) - entity->type->update_box_eye(entity); - - pthread_rwlock_unlock(&entity->lock_box_eye); + pthread_rwlock_unlock(&entity->lock_pos_rot); refcount_drp(&entity->rc); } @@ -169,6 +309,7 @@ void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, T if (entity->type->update_nametag) entity->type->update_nametag(entity); + update_nametag(entity); pthread_rwlock_unlock(&entity->lock_nametag); refcount_drp(&entity->rc); diff --git a/src/client/client_entity.h b/src/client/client_entity.h index 05651c4..53125db 100644 --- a/src/client/client_entity.h +++ b/src/client/client_entity.h @@ -4,6 +4,7 @@ #include #include #include +#include "client/gui.h" #include "client/model.h" #include "entity.h" #include "types.h" @@ -14,27 +15,42 @@ typedef struct { Refcount rc; Model *model; + GUIElement *nametag; + void *extra; + + aabb3f32 box_collision; + aabb3f32 box_culling; // ToDo + mat4x4 *nametag_offset; pthread_rwlock_t lock_pos_rot; - pthread_rwlock_t lock_box_eye; pthread_rwlock_t lock_nametag; + pthread_rwlock_t lock_box_off; } ClientEntity; +// Entity is pronounced N-Tiddy, hmmmm... + typedef struct ClientEntityType { void (*add )(ClientEntity *entity); // called when server sent addition of entity void (*remove)(ClientEntity *entity); // called when server sent removal of entity void (*free )(ClientEntity *entity); // called when entity is garbage collected void (*update_pos_rot)(ClientEntity *entity); - void (*update_box_eye)(ClientEntity *entity); void (*update_nametag)(ClientEntity *entity); void (*transform)(ClientEntity *entity); } ClientEntityType; +extern ClientEntityType client_entity_types[]; +extern Mesh client_entity_cube; +extern ModelShader client_entity_shader; + void client_entity_init(); void client_entity_deinit(); +bool client_entity_gfx_init(); +void client_entity_gfx_deinit(); +void client_entity_gfx_update(); + ClientEntity *client_entity_grab(u64 id); void client_entity_drop(ClientEntity *entity); @@ -43,9 +59,6 @@ void client_entity_transform(ClientEntity *entity); void client_entity_add(DragonnetPeer *peer, ToClientEntityAdd *pkt); void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt); void client_entity_update_pos_rot(DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt); -void client_entity_update_box_eye(DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt); void client_entity_update_nametag(DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt); -extern ClientEntityType client_entity_types[]; - #endif // _CLIENT_ENTITY_H_ diff --git a/src/client/client_player.c b/src/client/client_player.c index 08b9adb..3bc1b46 100644 --- a/src/client/client_player.c +++ b/src/client/client_player.c @@ -10,27 +10,41 @@ #include "environment.h" #include "physics.h" +typedef struct { + ModelNode *nametag; + ModelNode *neck; + ModelNode *eyes; + ModelNode *shoulder_left; + ModelNode *shoulder_right; + ModelNode *hip_left; + ModelNode *hip_right; +} PlayerModelBones; + struct ClientPlayer client_player; static ClientEntity *player_entity; static pthread_rwlock_t lock_player_entity; +static Model *player_model; + // updat epos/rot box/eye functions -static void update_eye_pos_camera() +static void update_camera() { - v3f64 pos = player_entity->data.pos; - v3f32 eye = player_entity->data.eye; + vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f}; + + PlayerModelBones *bones = player_entity->extra; - camera_set_position((v3f32) {pos.x + eye.x, pos.y + eye.y, pos.z + eye.z}); + if (bones->eyes) + mat4x4_mul_vec4(dst, bones->eyes->abs, src); + else + vec4_dup(dst, src); + + camera_set_position((v3f32) {dst[0], dst[1], dst[2]}); } static void update_pos() { - pthread_rwlock_rdlock(&player_entity->lock_box_eye); - update_eye_pos_camera(); - pthread_rwlock_unlock(&player_entity->lock_box_eye); - debug_menu_changed(ENTRY_POS); debug_menu_changed(ENTRY_HUMIDITY); debug_menu_changed(ENTRY_TEMPERATURE); @@ -38,7 +52,7 @@ static void update_pos() static void update_rot() { - camera_set_angle(player_entity->data.rot.x, player_entity->data.rot.y); + camera_set_angle(M_PI / 2 - player_entity->data.rot.y, -player_entity->data.rot.x); debug_menu_changed(ENTRY_YAW); debug_menu_changed(ENTRY_PITCH); } @@ -46,66 +60,111 @@ static void update_rot() static void update_transform() { client_entity_transform(player_entity); + update_camera(); } static void send_pos_rot() { + update_transform(); + dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) { .pos = player_entity->data.pos, .rot = player_entity->data.rot, }); - - update_transform(); } static void recv_pos_rot() { + update_transform(); + update_pos(); update_rot(); - - update_transform(); } // entity callbacks static void on_add(ClientEntity *entity) +{ + entity->model = model_clone(player_model); + entity->model->extra = refcount_grb(&entity->rc); + + PlayerModelBones *bones = entity->extra = malloc(sizeof *bones); + *bones = (PlayerModelBones) {NULL}; + model_get_bones(entity->model, (ModelBoneMapping[]) { + {"player.nametag", &bones->nametag }, + {"player.neck", &bones->neck }, + {"player.neck.head.eyes", &bones->eyes }, + {"player.body.upper.shoulders.left", &bones->shoulder_left }, + {"player.body.upper.shoulders.right", &bones->shoulder_right}, + {"player.body.lower.hips.left", &bones->hip_left }, + {"player.body.lower.hips.right", &bones->hip_right }, + }, 7); + + entity->nametag_offset = bones->nametag ? &bones->nametag->abs : NULL; + entity->box_collision = (aabb3f32) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.8f, 0.3f}}; + + model_scene_add(entity->model); + client_entity_transform(entity); +} + +static void on_remove(ClientEntity *entity) +{ + entity->model->flags.delete = 1; + entity->model = NULL; +} + +static void on_free(ClientEntity *entity) +{ + free(entity->extra); +} + +static void on_transform(ClientEntity *entity) +{ + PlayerModelBones *bones = entity->extra; + + entity->model->root->rot.x = entity->model->root->rot.z = 0.0f; + + if (bones->neck) { + bones->neck->rot.x = entity->data.rot.x; + model_node_transform(bones->neck); + } +} + +static void local_on_add(ClientEntity *entity) { pthread_rwlock_wrlock(&lock_player_entity); if (player_entity) { fprintf(stderr, "[error] attempt to re-add localplayer entity\n"); exit(EXIT_FAILURE); - } else { - player_entity = refcount_grb(&entity->rc); - recv_pos_rot(); - - entity->type->update_nametag(entity); } + on_add(entity); + + player_entity = refcount_grb(&entity->rc); + recv_pos_rot(); + + entity->type->update_nametag(entity); + pthread_rwlock_unlock(&lock_player_entity); } -static void on_remove(ClientEntity *entity) +static void local_on_remove(ClientEntity *entity) { pthread_rwlock_wrlock(&lock_player_entity); refcount_drp(&entity->rc); player_entity = NULL; pthread_rwlock_unlock(&lock_player_entity); -} -static void on_update_pos_rot(__attribute__((unused)) ClientEntity *entity) -{ - recv_pos_rot(); + on_remove(entity); } -static void on_update_box_eye(__attribute__((unused)) ClientEntity *entity) +static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity) { - pthread_rwlock_rdlock(&lock_player_entity); - update_eye_pos_camera(); - pthread_rwlock_unlock(&lock_player_entity); + recv_pos_rot(); } -static void on_update_nametag(ClientEntity *entity) +static void local_on_update_nametag(ClientEntity *entity) { if (entity->data.nametag) { free(entity->data.nametag); @@ -113,9 +172,16 @@ static void on_update_nametag(ClientEntity *entity) } } -static void on_transform(ClientEntity *entity) +static void __attribute__((unused)) on_model_step(Model *model, __attribute__((unused)) f64 dtime) { - entity->model->root->rot.y = entity->model->root->rot.z = 0.0f; + PlayerModelBones *bones = ((ClientEntity *) model->extra)->extra; + (void) bones; +} + +static void on_model_delete(Model *model) +{ + if (model->extra) + refcount_drp(&((ClientEntity *) model->extra)->rc); } // called on startup @@ -129,23 +195,21 @@ void client_player_init() .gravity = 0.0f, }; - client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) { + client_entity_types[ENTITY_PLAYER] = (ClientEntityType) { .add = &on_add, .remove = &on_remove, - .free = NULL, - .update_pos_rot = &on_update_pos_rot, - .update_box_eye = &on_update_box_eye, - .update_nametag = &on_update_nametag, + .free = &on_free, + .update_pos_rot = NULL, + .update_nametag = NULL, .transform = &on_transform, }; - client_entity_types[ENTITY_PLAYER] = (ClientEntityType) { - .add = NULL, - .remove = NULL, - .free = NULL, - .update_pos_rot = NULL, - .update_box_eye = NULL, - .update_nametag = NULL, + client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) { + .add = &local_on_add, + .remove = &local_on_remove, + .free = &on_free, + .update_pos_rot = &local_on_update_pos_rot, + .update_nametag = &local_on_update_nametag, .transform = &on_transform, }; @@ -162,6 +226,21 @@ void client_player_deinit() pthread_rwlock_destroy(&lock_player_entity); } +void client_player_gfx_init() +{ + player_model = model_load( + RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player", + &client_entity_cube, &client_entity_shader); + + player_model->callbacks.step = &on_model_step; + player_model->callbacks.delete = &on_model_delete; +} + +void client_player_gfx_deinit() +{ + model_delete(player_model); +} + ClientEntity *client_player_entity() { ClientEntity *entity = NULL; @@ -198,33 +277,6 @@ void client_player_update_rot(ClientEntity *entity) pthread_rwlock_unlock(&lock_player_entity); } -/* -// create mesh object and info hud -void client_player_add_to_scene() -{ - client_player.obj = object_create(); - client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6}; - client_player.obj->visible = false; - - object_set_texture(client_player.obj, texture_load(RESSOURCE_PATH "textures/player.png", true)); - - for (int f = 0; f < 6; f++) { - for (int v = 0; v < 6; v++) { - Vertex3D vertex = cube_vertices[f][v]; - vertex.position.y += 0.5; - object_add_vertex(client_player.obj, &vertex); - } - } - - pthread_rwlock_rdlock(&client_player.rwlock); - update_pos(); - pthread_rwlock_unlock(&client_player.rwlock); - - debug_menu_update_yaw(); - debug_menu_update_pitch(); -} -*/ - // jump if possible void client_player_jump() { @@ -233,18 +285,18 @@ void client_player_jump() return; pthread_rwlock_rdlock(&entity->lock_pos_rot); - pthread_rwlock_rdlock(&entity->lock_box_eye); + pthread_rwlock_rdlock(&entity->lock_box_off); if (physics_ground( client_terrain, client_player.movement.collision, - entity->data.box, + entity->box_collision, &entity->data.pos, &client_player.velocity )) client_player.velocity.y += client_player.movement.jump; - pthread_rwlock_unlock(&entity->lock_box_eye); + pthread_rwlock_unlock(&entity->lock_box_off); pthread_rwlock_unlock(&entity->lock_pos_rot); refcount_drp(&entity->rc); @@ -259,12 +311,12 @@ void client_player_tick(f64 dtime) pthread_rwlock_rdlock(&client_player.lock_movement); pthread_rwlock_wrlock(&entity->lock_pos_rot); - pthread_rwlock_rdlock(&entity->lock_box_eye); + pthread_rwlock_rdlock(&entity->lock_box_off); if (physics_step( client_terrain, client_player.movement.collision, - entity->data.box, + entity->box_collision, &entity->data.pos, &client_player.velocity, &(v3f64) { @@ -276,7 +328,7 @@ void client_player_tick(f64 dtime) )) client_player_update_pos(entity); - pthread_rwlock_unlock(&entity->lock_box_eye); + pthread_rwlock_unlock(&entity->lock_box_off); pthread_rwlock_unlock(&entity->lock_pos_rot); pthread_rwlock_unlock(&client_player.lock_movement); diff --git a/src/client/client_player.h b/src/client/client_player.h index f2ea0e4..5ddefa0 100644 --- a/src/client/client_player.h +++ b/src/client/client_player.h @@ -14,6 +14,9 @@ extern struct ClientPlayer { void client_player_init(); // called on startup void client_player_deinit(); // called on shutdown +void client_player_gfx_init(); +void client_player_gfx_deinit(); + ClientEntity *client_player_entity(); // grab and return client entity void client_player_jump(); // jump if possible diff --git a/src/client/client_terrain.c b/src/client/client_terrain.c index f60dbb1..c9c0ff1 100644 --- a/src/client/client_terrain.c +++ b/src/client/client_terrain.c @@ -39,7 +39,7 @@ static TerrainChunk *set_dequeued(TerrainChunk *chunk) // mesh generator step static void meshgen_step() { - TerrainChunk *chunk = queue_deq(&meshgen_tasks, (void *) &set_dequeued); + TerrainChunk *chunk = queue_deq(&meshgen_tasks, &set_dequeued); if (chunk) terrain_gfx_make_chunk_model(chunk); diff --git a/src/client/debug_menu.c b/src/client/debug_menu.c index 8385707..8e60bdb 100644 --- a/src/client/debug_menu.c +++ b/src/client/debug_menu.c @@ -3,12 +3,14 @@ #include #include #include +#include #include #include "client/client_config.h" #include "client/client_player.h" #include "client/client_terrain.h" #include "client/debug_menu.h" #include "client/game.h" +#include "client/gl_debug.h" #include "client/gui.h" #include "client/window.h" #include "day.h" @@ -73,27 +75,27 @@ static char *get_entry_text(DebugMenuEntry entry) char *str; switch (entry) { - case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break; - case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break; - case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break; - case ENTRY_YAW: asprintf(&str, "yaw = %.1f", rot.x / M_PI * 180.0 ); break; - case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", rot.y / M_PI * 180.0 ); break; - case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break; - case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break; - case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break; - case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break; - case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break; - case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break; - case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break; - case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break; - case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break; - case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break; - case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); break; - case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); break; - case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break; - case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break; - case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break; - case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break; + case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break; + case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break; + case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break; + case ENTRY_YAW: asprintf(&str, "yaw = %.1f", 360.0 - rot.y / M_PI * 180.0 ); break; + case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", -rot.x / M_PI * 180.0 ); break; + case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break; + case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break; + case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break; + case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break; + case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break; + case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break; + case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break; + case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break; + case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break; + case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break; + case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); GL_DEBUG break; + case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); GL_DEBUG break; + case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break; + case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break; + case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break; + case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break; default: break; } return str; @@ -113,7 +115,7 @@ void debug_menu_init() .scale = {1.0f, 1.0f}, .scale_type = SCALE_TEXT, .affect_parent_scale = false, - .text = strdup(""), + .text = "", .image = NULL, .text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f}, .bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f}, @@ -153,8 +155,11 @@ void debug_menu_update() pthread_mutex_unlock(&changed_elements_mtx); for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++) - if (changed_elements_cpy[i]) - gui_text(gui_elements[i], get_entry_text(i)); + if (changed_elements_cpy[i]) { + char *str = get_entry_text(i); + gui_text(gui_elements[i], str); + free(str); + } } void debug_menu_changed(DebugMenuEntry entry) diff --git a/src/client/font.c b/src/client/font.c index 15e432a..2370480 100644 --- a/src/client/font.c +++ b/src/client/font.c @@ -3,6 +3,7 @@ #include FT_FREETYPE_H #include "client/client.h" #include "client/font.h" +#include "client/gl_debug.h" #include "client/texture.h" #define NUM_CHARS 128 @@ -43,7 +44,7 @@ bool font_init() return false; } - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GL_DEBUG FT_Set_Pixel_Sizes(font_face, 0, 16); for (unsigned char c = 0; c < NUM_CHARS; c++) { @@ -138,7 +139,7 @@ void font_delete(Font *font) void font_render(Font *font) { for (size_t i = 0; i < font->count; i++) { - glBindTextureUnit(0, font->textures[i]); + glBindTextureUnit(0, font->textures[i]); GL_DEBUG mesh_render(&font->meshes[i]); } } diff --git a/src/client/game.c b/src/client/game.c index 99da578..8cd2b74 100644 --- a/src/client/game.c +++ b/src/client/game.c @@ -7,12 +7,15 @@ #include #include "client/camera.h" #include "client/client.h" +#include "client/client_entity.h" #include "client/client_node.h" #include "client/client_player.h" #include "client/client_terrain.h" #include "client/debug_menu.h" #include "client/font.h" #include "client/frustum.h" +#include "client/game.h" +#include "client/gl_debug.h" #include "client/gui.h" #include "client/input.h" #include "client/sky.h" @@ -42,21 +45,20 @@ static void crosshair_init() static void render(f64 dtime) { - glEnable(GL_DEPTH_TEST); - glEnable(GL_ALPHA_TEST); - glEnable(GL_BLEND); - glEnable(GL_MULTISAMPLE); - glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); GL_DEBUG + glEnable(GL_BLEND); GL_DEBUG + glEnable(GL_MULTISAMPLE); GL_DEBUG + glEnable(GL_CULL_FACE); GL_DEBUG - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glAlphaFunc(GL_GREATER, 0.1f); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DEBUG + glCullFace(GL_BACK); GL_DEBUG + glFrontFace(GL_CCW); GL_DEBUG - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GL_DEBUG frustum_update(); terrain_gfx_update(); + client_entity_gfx_update(); sky_render(); model_scene_render(dtime); @@ -116,6 +118,11 @@ bool game(Flag *gfx_init) if (!terrain_gfx_init()) return false; + if (!client_entity_gfx_init()) + return false; + + client_player_gfx_init(); + client_node_init(); client_terrain_start(); @@ -139,6 +146,8 @@ bool game(Flag *gfx_init) model_deinit(); sky_deinit(); terrain_gfx_deinit(); + client_entity_gfx_deinit(); + client_player_gfx_deinit(); return true; } @@ -147,48 +156,48 @@ char *game_take_screenshot() { // renderbuffer for depth & stencil buffer GLuint rbo; - glGenRenderbuffers(1, &rbo); - glBindRenderbuffer(GL_RENDERBUFFER, rbo); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); + glGenRenderbuffers(1, &rbo); GL_DEBUG + glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG // 2 textures, one with AA, one without GLuint txos[2]; - glGenTextures(2, txos); + glGenTextures(2, txos); GL_DEBUG - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG - glBindTexture(GL_TEXTURE_2D, txos[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glBindTexture(GL_TEXTURE_2D, txos[1]); GL_DEBUG + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); GL_DEBUG // 2 framebuffers, one with AA, one without GLuint fbos[2]; - glGenFramebuffers(2, fbos); + glGenFramebuffers(2, fbos); GL_DEBUG - glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); GL_DEBUG + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG - glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); + glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG // render scene - glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); + glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG render(0.0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG // blit AA-buffer into no-AA buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); - glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); GL_DEBUG + glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG // read data GLubyte data[window.width * window.height * 3]; - glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); + glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG + glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG + glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG // create filename char filename[BUFSIZ]; @@ -200,9 +209,9 @@ char *game_take_screenshot() stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3); // delete buffers - glDeleteRenderbuffers(1, &rbo); - glDeleteTextures(2, txos); - glDeleteFramebuffers(2, fbos); + glDeleteRenderbuffers(1, &rbo); GL_DEBUG + glDeleteTextures(2, txos); GL_DEBUG + glDeleteFramebuffers(2, fbos); GL_DEBUG return strdup(filename); } diff --git a/src/client/gl_debug.c b/src/client/gl_debug.c new file mode 100644 index 0000000..cc75d24 --- /dev/null +++ b/src/client/gl_debug.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include "client/gl_debug.h" + +// put this into seperate function to make it easy to trace stack using external debugger +static void gl_error(GLenum err, const char *file, int line) +{ + switch (err) { + case GL_INVALID_ENUM: printf("INVALID_ENUM %s:%d\n", file, line); break; + case GL_INVALID_VALUE: printf("INVALID_VALUE %s:%d\n", file, line); break; + case GL_INVALID_OPERATION: printf("INVALID_OPERATION %s:%d\n", file, line); break; + case GL_STACK_OVERFLOW: printf("STACK_OVERFLOW %s:%d\n", file, line); break; + case GL_STACK_UNDERFLOW: printf("STACK_UNDERFLOW %s:%d\n", file, line); break; + case GL_OUT_OF_MEMORY: printf("OUT_OF_MEMORY %s:%d\n", file, line); break; + case GL_INVALID_FRAMEBUFFER_OPERATION: printf("INVALID_FRAMEBUFFER_OPERATION %s:%d\n", file, line); break; + default: break; + } +} +void gl_debug(const char *file, int line) +{ + GLenum err = glGetError(); + + if (err != GL_NO_ERROR) + gl_error(err, file, line); +} diff --git a/src/client/gl_debug.h b/src/client/gl_debug.h new file mode 100644 index 0000000..f65f080 --- /dev/null +++ b/src/client/gl_debug.h @@ -0,0 +1,12 @@ +#ifndef _GL_DEBUG_H_ +#define _GL_DEBUG_H_ + +#ifdef ENABLE_GL_DEBUG +#define GL_DEBUG gl_debug(__FILE__, __LINE__); +#else +#define GL_DEBUG +#endif + +void gl_debug(const char *file, int line); + +#endif diff --git a/src/client/gui.c b/src/client/gui.c index 29f6b91..4aecb48 100644 --- a/src/client/gui.c +++ b/src/client/gui.c @@ -5,6 +5,7 @@ #include #include "client/client.h" #include "client/cube.h" +#include "client/gl_debug.h" #include "client/gui.h" #include "client/mesh.h" #include "client/shader.h" @@ -120,23 +121,28 @@ static void render_element(GUIElement *element) { if (element->visible) { if (element->def.bg_color.w > 0.0f) { - glUseProgram(background_prog); - glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); - glUniform4f(background_loc_color, element->def.bg_color.x, element->def.bg_color.y, element->def.bg_color.z, element->def.bg_color.w); + glUseProgram(background_prog); GL_DEBUG + glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG + glUniform4f(background_loc_color, element->def.bg_color.x, element->def.bg_color.y, element->def.bg_color.z, element->def.bg_color.w); GL_DEBUG mesh_render(&background_mesh); } if (element->def.image) { - glUseProgram(image_prog); - glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); - glBindTextureUnit(0, element->def.image->txo); + glUseProgram(image_prog); GL_DEBUG + glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG + glBindTextureUnit(0, element->def.image->txo); GL_DEBUG mesh_render(&image_mesh); } - if (element->text && element->def.text_color.w > 0.0f) { - glUseProgram(font_prog); - glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); - glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w); + if (element->def.text && element->def.text_color.w > 0.0f) { + if (!element->text) { + element->text = font_create(element->def.text); + gui_transform(element); + } + + glUseProgram(font_prog); GL_DEBUG + glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); GL_DEBUG + glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w); GL_DEBUG font_render(element->text); } @@ -177,6 +183,9 @@ static void scale_element(GUIElement *element) break; case SCALE_TEXT: + if (!element->text) + break; + element->scale.x *= element->text->size.x; element->scale.y *= element->text->size.y; break; @@ -231,9 +240,9 @@ bool gui_init() return false; } - background_loc_model = glGetUniformLocation(background_prog, "model"); - background_loc_projection = glGetUniformLocation(background_prog, "projection"); - background_loc_color = glGetUniformLocation(background_prog, "color"); + background_loc_model = glGetUniformLocation(background_prog, "model"); GL_DEBUG + background_loc_projection = glGetUniformLocation(background_prog, "projection"); GL_DEBUG + background_loc_color = glGetUniformLocation(background_prog, "color"); GL_DEBUG // initialize image pipeline @@ -242,8 +251,8 @@ bool gui_init() return false; } - image_loc_model = glGetUniformLocation(image_prog, "model"); - image_loc_projection = glGetUniformLocation(image_prog, "projection"); + image_loc_model = glGetUniformLocation(image_prog, "model"); GL_DEBUG + image_loc_projection = glGetUniformLocation(image_prog, "projection"); GL_DEBUG // initialize font pipeline @@ -252,9 +261,9 @@ bool gui_init() return false; } - font_loc_model = glGetUniformLocation(font_prog, "model"); - font_loc_projection = glGetUniformLocation(font_prog, "projection"); - font_loc_color = glGetUniformLocation(font_prog, "color"); + font_loc_model = glGetUniformLocation(font_prog, "model"); GL_DEBUG + font_loc_projection = glGetUniformLocation(font_prog, "projection"); GL_DEBUG + font_loc_color = glGetUniformLocation(font_prog, "color"); GL_DEBUG // initialize GUI root element @@ -283,13 +292,13 @@ bool gui_init() void gui_deinit() { - glDeleteProgram(background_prog); + glDeleteProgram(background_prog); GL_DEBUG mesh_destroy(&background_mesh); - glDeleteProgram(image_prog); + glDeleteProgram(image_prog); GL_DEBUG mesh_destroy(&image_mesh); - glDeleteProgram(font_prog); + glDeleteProgram(font_prog); GL_DEBUG delete_elements(&root_element.children); } @@ -297,9 +306,9 @@ void gui_deinit() void gui_update_projection() { mat4x4_ortho(projection, 0, window.width, window.height, 0, -1.0f, 1.0f); - glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); - glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); - glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); + glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG + glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG + glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG root_element.def.scale.x = window.width; root_element.def.scale.y = window.height; @@ -309,13 +318,13 @@ void gui_update_projection() void gui_render() { - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); GL_DEBUG + glDisable(GL_DEPTH_TEST); GL_DEBUG render_elements(&root_element.children); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); GL_DEBUG + glEnable(GL_CULL_FACE); GL_DEBUG } GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def) @@ -327,15 +336,12 @@ GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def) element->def = def; element->visible = true; element->parent = parent; + element->text = NULL; - if (element->def.text) { + if (element->def.text) element->def.text = strdup(element->def.text); - element->text = font_create(element->def.text); - } else { - element->text = NULL; - } - array_ins(&parent->children, &element, (void *) &cmp_element); + array_ins(&parent->children, &element, &cmp_element); array_ini(&element->children, sizeof(GUIElement), 0); if (element->def.affect_parent_scale) @@ -346,15 +352,16 @@ GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def) return element; } -void gui_text(GUIElement *element, char *text) +void gui_text(GUIElement *element, const char *text) { if (element->def.text) free(element->def.text); - element->def.text = text; - font_delete(element->text); - element->text = font_create(text); - gui_transform(element); + if (element->text) + font_delete(element->text); + + element->def.text = strdup(text); + element->text = NULL; } void gui_transform(GUIElement *element) diff --git a/src/client/gui.h b/src/client/gui.h index 7f4c0d2..ea4b15e 100644 --- a/src/client/gui.h +++ b/src/client/gui.h @@ -48,7 +48,7 @@ void gui_deinit(); void gui_update_projection(); void gui_render(); GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def); -void gui_text(GUIElement *element, char *text); +void gui_text(GUIElement *element, const char *text); void gui_transform(GUIElement *element); #endif // _GUI_H_ diff --git a/src/client/input.c b/src/client/input.c index e9b154c..19dc81c 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -12,6 +12,11 @@ #include "client/window.h" #include "day.h" +#define SET_STATUS_MESSAGE(args...) { \ + char *msg; asprintf(&msg, args); \ + gui_text(status_message, msg); free(msg); \ + status_message->def.text_color.w = 1.01f; } + typedef struct { int key; bool state; @@ -65,12 +70,6 @@ static bool key_listener(KeyListener *listener) return !(listener->state = (glfwGetKey(window.handle, listener->key) == GLFW_PRESS)) && was; } -static void set_status_message(char *message) -{ - gui_text(status_message, message); - status_message->def.text_color.w = 1.01f; -} - void input_init() { pause_menu = gui_add(NULL, (GUIElementDefinition) { @@ -97,7 +96,7 @@ void input_init() .scale = {1.0f, 1.0f}, .scale_type = SCALE_TEXT, .affect_parent_scale = false, - .text = strdup(""), + .text = "", .image = NULL, .text_color = {1.0f, 0.91f, 0.13f, 0.0f}, .bg_color = {0.0f, 0.0f, 0.0f, 0.0f}, @@ -137,9 +136,7 @@ void input_tick(f64 dtime) pthread_rwlock_wrlock(&client_player.lock_movement); client_player.movement.flight = !client_player.movement.flight; - char *msg; - asprintf(&msg, "Flight %s", client_player.movement.flight ? "Enabled" : "Disabled"); - set_status_message(msg); + SET_STATUS_MESSAGE("Flight %s", client_player.movement.flight ? "Enabled" : "Disabled") debug_menu_changed(ENTRY_FLIGHT); pthread_rwlock_unlock(&client_player.lock_movement); @@ -149,9 +146,7 @@ void input_tick(f64 dtime) pthread_rwlock_wrlock(&client_player.lock_movement); client_player.movement.collision = !client_player.movement.collision; - char *msg; - asprintf(&msg, "Collision %s", client_player.movement.collision ? "Enabled" : "Disabled"); - set_status_message(msg); + SET_STATUS_MESSAGE("Collision %s", client_player.movement.collision ? "Enabled" : "Disabled") debug_menu_changed(ENTRY_COLLISION); pthread_rwlock_unlock(&client_player.lock_movement); @@ -162,9 +157,7 @@ void input_tick(f64 dtime) timelapse = !timelapse; set_time_of_day(current_time); - char *msg; - asprintf(&msg, "Timelapse %s", timelapse ? "Enabled" : "Disabled"); - set_status_message(msg); + SET_STATUS_MESSAGE("Timelapse %s", timelapse ? "Enabled" : "Disabled") debug_menu_changed(ENTRY_TIMELAPSE); } @@ -173,9 +166,7 @@ void input_tick(f64 dtime) if (key_listener(&listener_screenshot)) { char *screenshot_filename = game_take_screenshot(); - char *msg; - asprintf(&msg, "Screenshot saved to %s", screenshot_filename); - set_status_message(msg); + SET_STATUS_MESSAGE("Screenshot saved to %s", screenshot_filename) free(screenshot_filename); } } @@ -217,11 +208,11 @@ void input_cursor(double current_x, double current_y) pthread_rwlock_wrlock(&entity->lock_pos_rot); - entity->data.rot.x += (f32) delta_x * M_PI / 180.0f / 8.0f; - entity->data.rot.y -= (f32) delta_y * M_PI / 180.0f / 8.0f; + entity->data.rot.y -= (f32) delta_x * M_PI / 180.0f / 8.0f; + entity->data.rot.x += (f32) delta_y * M_PI / 180.0f / 8.0f; - entity->data.rot.x = fmod(entity->data.rot.x + M_PI * 2.0f, M_PI * 2.0f); - entity->data.rot.y = f32_clamp(entity->data.rot.y, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f); + entity->data.rot.y = fmod(entity->data.rot.y + M_PI * 2.0f, M_PI * 2.0f); + entity->data.rot.x = f32_clamp(entity->data.rot.x, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f); client_player_update_rot(entity); pthread_rwlock_unlock(&entity->lock_pos_rot); diff --git a/src/client/light.c b/src/client/light.c new file mode 100644 index 0000000..9ba99d0 --- /dev/null +++ b/src/client/light.c @@ -0,0 +1,35 @@ +#include +#include "client/camera.h" +#include "client/gl_debug.h" +#include "client/light.h" +#include "day.h" + +void light_shader_locate(LightShader *shader) +{ + shader->loc_daylight = glGetUniformLocation(shader->prog, "daylight"); GL_DEBUG + shader->loc_fogColor = glGetUniformLocation(shader->prog, "fogColor"); GL_DEBUG + shader->loc_ambientLight = glGetUniformLocation(shader->prog, "ambientLight"); GL_DEBUG + shader->loc_lightDir = glGetUniformLocation(shader->prog, "lightDir"); GL_DEBUG + shader->loc_cameraPos = glGetUniformLocation(shader->prog, "cameraPos"); GL_DEBUG +} + +void light_shader_update(LightShader *shader) +{ + vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f}; + vec4 sunlight_dir; + mat4x4 sunlight_mat; + mat4x4_identity(sunlight_mat); + + mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f); + mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir); + + f32 daylight = get_daylight(); + f32 ambient_light = f32_mix(0.3f, 0.7f, daylight); + v3f32 fog_color = v3f32_mix((v3f32) {0x03, 0x0A, 0x1A}, (v3f32) {0x87, 0xCE, 0xEB}, daylight); + + glProgramUniform1f(shader->prog, shader->loc_daylight, daylight); GL_DEBUG + glProgramUniform3f(shader->prog, shader->loc_fogColor, fog_color.x / 0xFF * ambient_light, fog_color.y / 0xFF * ambient_light, fog_color.z / 0xFF * ambient_light); GL_DEBUG + glProgramUniform1f(shader->prog, shader->loc_ambientLight, ambient_light); GL_DEBUG + glProgramUniform3f(shader->prog, shader->loc_lightDir, sunlight_dir[0], sunlight_dir[1], sunlight_dir[2]); GL_DEBUG + glProgramUniform3f(shader->prog, shader->loc_cameraPos, camera.eye[0], camera.eye[1], camera.eye[2]); GL_DEBUG +} diff --git a/src/client/light.h b/src/client/light.h new file mode 100644 index 0000000..10e7775 --- /dev/null +++ b/src/client/light.h @@ -0,0 +1,19 @@ +#ifndef _LIGHT_H_ +#define _LIGHT_H_ + +#include +#include + +typedef struct { + GLuint prog; + GLint loc_daylight; + GLint loc_fogColor; + GLint loc_ambientLight; + GLint loc_lightDir; + GLint loc_cameraPos; +} LightShader; + +void light_shader_locate(LightShader *shader); +void light_shader_update(LightShader *shader); + +#endif diff --git a/src/client/mesh.c b/src/client/mesh.c index f2ded84..49df506 100644 --- a/src/client/mesh.c +++ b/src/client/mesh.c @@ -1,32 +1,33 @@ #include #include +#include "client/gl_debug.h" #include "client/mesh.h" // upload data to GPU (only done once) void mesh_upload(Mesh *mesh) { - glGenVertexArrays(1, &mesh->vao); - glGenBuffers(1, &mesh->vbo); + glGenVertexArrays(1, &mesh->vao); GL_DEBUG + glGenBuffers(1, &mesh->vbo); GL_DEBUG - glBindVertexArray(mesh->vao); - glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBindVertexArray(mesh->vao); GL_DEBUG + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); GL_DEBUG glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->layout->size, - mesh->data, GL_STATIC_DRAW); + mesh->data, GL_STATIC_DRAW); GL_DEBUG size_t offset = 0; for (GLuint i = 0; i < mesh->layout->count; i++) { VertexAttribute *attrib = &mesh->layout->attributes[i]; glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE, - mesh->layout->size, (GLvoid *) offset); - glEnableVertexAttribArray(i); + mesh->layout->size, (GLvoid *) offset); GL_DEBUG + glEnableVertexAttribArray(i); GL_DEBUG offset += attrib->size; } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); GL_DEBUG + glBindVertexArray(0); GL_DEBUG if (mesh->free_data) free(mesh->data); @@ -40,8 +41,8 @@ void mesh_render(Mesh *mesh) mesh_upload(mesh); // render - glBindVertexArray(mesh->vao); - glDrawArrays(GL_TRIANGLES, 0, mesh->count); + glBindVertexArray(mesh->vao); GL_DEBUG + glDrawArrays(GL_TRIANGLES, 0, mesh->count); GL_DEBUG } void mesh_destroy(Mesh *mesh) @@ -49,11 +50,13 @@ void mesh_destroy(Mesh *mesh) if (mesh->data && mesh->free_data) free(mesh->data); - if (mesh->vao) - glDeleteVertexArrays(1, &mesh->vao); + if (mesh->vao) { + glDeleteVertexArrays(1, &mesh->vao); GL_DEBUG + } - if (mesh->vbo) - glDeleteBuffers(1, &mesh->vbo); + if (mesh->vbo) { + glDeleteBuffers(1, &mesh->vbo); GL_DEBUG + } mesh->vao = mesh->vbo = 0; } diff --git a/src/client/model.c b/src/client/model.c index 1d163c7..c770d1c 100644 --- a/src/client/model.c +++ b/src/client/model.c @@ -5,6 +5,7 @@ #include "client/camera.h" #include "client/client_config.h" #include "client/frustum.h" +#include "client/gl_debug.h" #include "client/model.h" typedef struct { @@ -13,7 +14,8 @@ typedef struct { } ModelBatchTexture; static List scene; -static pthread_rwlock_t lock_scene; +static List scene_new; +static pthread_mutex_t lock_scene_new; static GLint units; // fixme: blending issues still occur @@ -57,17 +59,18 @@ static void render_node(ModelNode *node) for (size_t i = 0; i < node->meshes.siz; i++) { ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i]; - glUseProgram(mesh->shader->prog); - glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); + glUseProgram(mesh->shader->prog); GL_DEBUG + glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); GL_DEBUG // bind textures - for (GLuint i = 0; i < mesh->num_textures; i++) - glBindTextureUnit(i, mesh->textures[i]); + for (GLuint i = 0; i < mesh->num_textures; i++) { + glBindTextureUnit(i, mesh->textures[i]); GL_DEBUG + } mesh_render(mesh->mesh); } - list_itr(&node->children, (void *) &render_node, NULL, NULL); + list_itr(&node->children, &render_node, NULL, NULL); } static void free_node_meshes(ModelNode *node) @@ -79,7 +82,7 @@ static void free_node_meshes(ModelNode *node) free(mesh->mesh); } - list_clr(&node->children, (void *) &free_node_meshes, NULL, NULL); + list_clr(&node->children, &free_node_meshes, NULL, NULL); } static void delete_node(ModelNode *node) @@ -90,7 +93,7 @@ static void delete_node(ModelNode *node) if (mesh->textures) free(mesh->textures); } - list_clr(&node->children, (void *) &delete_node, NULL, NULL); + list_clr(&node->children, &delete_node, NULL, NULL); array_clr(&node->meshes); free(node); @@ -121,7 +124,7 @@ static ModelNode *clone_node(ModelNode *original, ModelNode *parent) for (size_t i = 0; i < node->meshes.siz; i++) clone_mesh(&((ModelMesh *) node->meshes.ptr)[i]); - list_itr(&original->children, (void *) &clone_node, parent, NULL); + list_itr(&original->children, &clone_node, node, NULL); return node; } @@ -132,13 +135,15 @@ static int cmp_model(const Model *model, const f32 *distance) static void render_model(Model *model) { - if (model->flags.wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + if (model->flags.wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); GL_DEBUG + } render_node(model->root); - if (model->flags.wireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if (model->flags.wireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); GL_DEBUG + } } // step model help im stuck @@ -172,15 +177,19 @@ static void model_step(Model *model, Tree *transparent, f64 dtime) void model_init() { list_ini(&scene); - pthread_rwlock_init(&lock_scene, NULL); - glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units); + list_ini(&scene_new); + + pthread_mutex_init(&lock_scene_new, NULL); + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units); GL_DEBUG } // ded void model_deinit() { list_clr(&scene, &model_delete, NULL, NULL); - pthread_rwlock_destroy(&lock_scene); + list_clr(&scene_new, &model_delete, NULL, NULL); + + pthread_mutex_destroy(&lock_scene_new); } // Model functions @@ -190,6 +199,7 @@ Model *model_create() Model *model = malloc(sizeof *model); model->root = model_node_create(NULL); model->extra = NULL; + model->replace = NULL; model->callbacks.step = NULL; model->callbacks.delete = NULL; @@ -272,11 +282,6 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model cursor += n; else fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count); - } else if (strcmp(key, "angle") == 0) { - if (sscanf(cursor, "%f%n", &node->angle, &n) == 1) - cursor += n; - else - fprintf(stderr, "[warning] invalid value for angle in model %s in line %d\n", path, count); } else if (strcmp(key, "cube") == 0) { char texture[length + 1]; @@ -313,6 +318,7 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model fclose(file); array_clr(&stack); + transform_node(model->root); return model; } @@ -346,15 +352,16 @@ void model_get_bones(Model *model, ModelBoneMapping *mappings, size_t num_mappin name = cursor = strdup(mappings[i].name); ModelNode *node = model->root; - while ((tok = strtok_r(cursor, ".", &saveptr))) { - node = list_get(&node->children, tok, (void *) &cmp_node, NULL); + + while (node && (tok = strtok_r(cursor, ".", &saveptr))) { + node = list_get(&node->children, tok, &cmp_node, NULL); cursor = NULL; } if (node) *mappings[i].node = node; else - fprintf(stderr, "[warning] no such bone: %s\n", name); + fprintf(stderr, "[warning] no such bone: %s\n", mappings[i].name); free(name); } @@ -370,7 +377,6 @@ ModelNode *model_node_create(ModelNode *parent) node->pos = (v3f32) {0.0f, 0.0f, 0.0f}; node->rot = (v3f32) {0.0f, 0.0f, 0.0f}; node->scale = (v3f32) {1.0f, 1.0f, 1.0f}; - node->angle = 0.0f; array_ini(&node->meshes, sizeof(ModelMesh), 0); init_node(node, parent); return node; @@ -378,22 +384,22 @@ ModelNode *model_node_create(ModelNode *parent) void model_node_transform(ModelNode *node) { + mat4x4_identity(node->rel); + mat4x4_translate(node->rel, node->pos.x, node->pos.y, node->pos.z); - mat4x4_rotate(node->rel, node->rel, - node->rot.x, - node->rot.y, - node->rot.z, - node->angle); - mat4x4_scale_aniso(node->rel, node->rel, node->scale.x, node->scale.y, node->scale.z); + mat4x4_rotate_X(node->rel, node->rel, node->rot.x); + mat4x4_rotate_Y(node->rel, node->rel, node->rot.y); + mat4x4_rotate_Z(node->rel, node->rel, node->rot.z); + transform_node(node); } @@ -506,37 +512,40 @@ void model_batch_add_vertex(ModelBatch *batch, GLuint texture, const void *verte void model_scene_add(Model *model) { - pthread_rwlock_wrlock(&lock_scene); - list_apd(&scene, model); - pthread_rwlock_unlock(&lock_scene); + pthread_mutex_lock(&lock_scene_new); + list_apd(&scene_new, model); + pthread_mutex_unlock(&lock_scene_new); } void model_scene_render(f64 dtime) { + pthread_mutex_lock(&lock_scene_new); + if (scene_new.fst) { + *scene.end = scene_new.fst; + scene.end = scene_new.end; + + list_ini(&scene_new); + } + pthread_mutex_unlock(&lock_scene_new); + Tree transparent; tree_ini(&transparent); - pthread_rwlock_rdlock(&lock_scene); for (ListNode **node = &scene.fst; *node != NULL;) { Model *model = (*node)->dat; - pthread_rwlock_unlock(&lock_scene); if (model->flags.delete) { - model_delete(model); + if (model->replace) + (*node)->dat = model->replace; + else + list_nrm(&scene, node); - pthread_rwlock_wrlock(&lock_scene); - list_nrm(&scene, node); - pthread_rwlock_unlock(&lock_scene); - - pthread_rwlock_rdlock(&lock_scene); + model_delete(model); } else { - model_step(model, &transparent, dtime); - - pthread_rwlock_rdlock(&lock_scene); node = &(*node)->nxt; + model_step(model, &transparent, dtime); } } - pthread_rwlock_unlock(&lock_scene); tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER); } diff --git a/src/client/model.h b/src/client/model.h index 663df77..977dbc6 100644 --- a/src/client/model.h +++ b/src/client/model.h @@ -28,7 +28,6 @@ typedef struct ModelNode { char *name; bool visible; v3f32 pos, rot, scale; - f32 angle; mat4x4 abs, rel; Array meshes; struct ModelNode *parent; @@ -52,6 +51,7 @@ typedef struct Model { void *extra; aabb3f32 box; f32 distance; + struct Model *replace; struct { void (*step)(struct Model *model, f64 dtime); void (*delete)(struct Model *model); diff --git a/src/client/shader.c b/src/client/shader.c index f4f050f..fcf358a 100644 --- a/src/client/shader.c +++ b/src/client/shader.c @@ -2,6 +2,7 @@ #include #include #include +#include "client/gl_debug.h" #include "client/shader.h" static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *definitions) @@ -45,7 +46,7 @@ static GLuint compile_shader(GLenum type, const char *path, const char *name, GL fclose(file); - GLuint id = glCreateShader(type); + GLuint id = glCreateShader(type); GL_DEBUG // Minimum OpenGL version is 4.2.0 (idk some shader feature from that version is required) const char *version = "#version 420 core\n"; // 420 blaze it @@ -62,28 +63,28 @@ static GLuint compile_shader(GLenum type, const char *path, const char *name, GL size, }; - glShaderSource(id, 3, code_list, size_list); + glShaderSource(id, 3, code_list, size_list); GL_DEBUG - glCompileShader(id); + glCompileShader(id); GL_DEBUG GLint success; - glGetShaderiv(id, GL_COMPILE_STATUS, &success); + glGetShaderiv(id, GL_COMPILE_STATUS, &success); GL_DEBUG if (!success) { char errbuf[BUFSIZ]; - glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf); + glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG fprintf(stderr, "[error] failed to compile %s shader: %s", name, errbuf); - glDeleteShader(id); + glDeleteShader(id); GL_DEBUG return 0; } - glAttachShader(program, id); + glAttachShader(program, id); GL_DEBUG return id; } bool shader_program_create(const char *path, GLuint *idptr, const char *definitions) { - GLuint id = glCreateProgram(); + GLuint id = glCreateProgram(); GL_DEBUG if (!definitions) definitions = ""; @@ -91,27 +92,27 @@ bool shader_program_create(const char *path, GLuint *idptr, const char *definiti GLuint vert, frag; if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) { - glDeleteProgram(id); + glDeleteProgram(id); GL_DEBUG return false; } if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) { - glDeleteShader(vert); - glDeleteProgram(id); + glDeleteShader(vert); GL_DEBUG + glDeleteProgram(id); GL_DEBUG return false; } - glLinkProgram(id); - glDeleteShader(vert); - glDeleteShader(frag); + glLinkProgram(id); GL_DEBUG + glDeleteShader(vert); GL_DEBUG + glDeleteShader(frag); GL_DEBUG GLint success; - glGetProgramiv(id, GL_LINK_STATUS, &success); + glGetProgramiv(id, GL_LINK_STATUS, &success); GL_DEBUG if (!success) { char errbuf[BUFSIZ]; - glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf); + glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG fprintf(stderr, "[error] failed to link shader program: %s\n", errbuf); - glDeleteProgram(id); + glDeleteProgram(id); GL_DEBUG return false; } diff --git a/src/client/sky.c b/src/client/sky.c index 45b7836..e648d8d 100644 --- a/src/client/sky.c +++ b/src/client/sky.c @@ -4,6 +4,7 @@ #include "client/camera.h" #include "client/client.h" #include "client/cube.h" +#include "client/gl_debug.h" #include "client/mesh.h" #include "client/shader.h" #include "client/sky.h" @@ -90,10 +91,10 @@ bool sky_init() return false; } - glProgramUniform1iv(skybox_prog, glGetUniformLocation(skybox_prog, "textures"), 2, (GLint[]) {0, 1}); + glProgramUniform1iv(skybox_prog, glGetUniformLocation(skybox_prog, "textures"), 2, (GLint[]) {0, 1}); GL_DEBUG - skybox_loc_VP = glGetUniformLocation(skybox_prog, "VP"); - skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight"); + skybox_loc_VP = glGetUniformLocation(skybox_prog, "VP"); GL_DEBUG + skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight"); GL_DEBUG skybox_texture_day = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/day")->txo; skybox_texture_night = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/night")->txo; skybox_mesh.data = skybox_vertices; @@ -106,7 +107,7 @@ bool sky_init() return false; } - sun_loc_MVP = glGetUniformLocation(sun_prog, "MVP"); + sun_loc_MVP = glGetUniformLocation(sun_prog, "MVP"); GL_DEBUG sun_texture = texture_load(RESSOURCE_PATH "textures/sun.png", false)->txo; // clouds @@ -116,8 +117,8 @@ bool sky_init() return false; } - clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP"); - clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight"); + clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP"); GL_DEBUG + clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight"); GL_DEBUG clouds_mesh.data = clouds_vertices; mesh_upload(&clouds_mesh); @@ -126,13 +127,13 @@ bool sky_init() void sky_deinit() { - glDeleteProgram(sun_prog); + glDeleteProgram(sun_prog); GL_DEBUG mesh_destroy(&sun_mesh); - glDeleteProgram(skybox_prog); + glDeleteProgram(skybox_prog); GL_DEBUG mesh_destroy(&skybox_mesh); - glDeleteProgram(clouds_prog); + glDeleteProgram(clouds_prog); GL_DEBUG mesh_destroy(&clouds_mesh); } @@ -161,27 +162,27 @@ void sky_render() mat4x4 mvp; mat4x4_mul(mvp, vp, model); - glDisable(GL_CULL_FACE); - glDepthFunc(GL_LEQUAL); + glDisable(GL_CULL_FACE); GL_DEBUG + glDepthFunc(GL_LEQUAL); GL_DEBUG - glUseProgram(skybox_prog); - glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]); - glUniform1f(skybox_loc_daylight, daylight); - glBindTextureUnit(0, skybox_texture_day); - glBindTextureUnit(1, skybox_texture_night); + glUseProgram(skybox_prog); GL_DEBUG + glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG + glUniform1f(skybox_loc_daylight, daylight); GL_DEBUG + glBindTextureUnit(0, skybox_texture_day); GL_DEBUG + glBindTextureUnit(1, skybox_texture_night); GL_DEBUG mesh_render(&skybox_mesh); - glUseProgram(sun_prog); - glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]); - glBindTextureUnit(0, sun_texture); + glUseProgram(sun_prog); GL_DEBUG + glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]); GL_DEBUG + glBindTextureUnit(0, sun_texture); GL_DEBUG mesh_render(&sun_mesh); - glUseProgram(clouds_prog); - glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]); - glUniform1f(clouds_loc_daylight, daylight); - glBindTextureUnit(0, skybox_texture_day); + glUseProgram(clouds_prog); GL_DEBUG + glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG + glUniform1f(clouds_loc_daylight, daylight); GL_DEBUG + glBindTextureUnit(0, skybox_texture_day); GL_DEBUG mesh_render(&clouds_mesh); - glDepthFunc(GL_LESS); - glEnable(GL_CULL_FACE); + glDepthFunc(GL_LESS); GL_DEBUG + glEnable(GL_CULL_FACE); GL_DEBUG } diff --git a/src/client/terrain_gfx.c b/src/client/terrain_gfx.c index 38c7799..a855221 100644 --- a/src/client/terrain_gfx.c +++ b/src/client/terrain_gfx.c @@ -2,15 +2,15 @@ #include #include #include -#include "client/camera.h" #include "client/client_config.h" #include "client/client_node.h" #include "client/client_terrain.h" #include "client/cube.h" #include "client/frustum.h" +#include "client/gl_debug.h" +#include "client/light.h" #include "client/shader.h" #include "client/terrain_gfx.h" -#include "day.h" typedef struct { bool visible; @@ -51,14 +51,9 @@ static v3f32 center_offset = { }; static GLuint shader_prog; -static GLint loc_model; static GLint loc_VP; -static GLint loc_daylight; -static GLint loc_fogColor; -static GLint loc_ambientLight; -static GLint loc_lightDir; -static GLint loc_cameraPos; +static LightShader light_shader; static ModelShader model_shader; static inline bool cull_face(NodeType self, NodeType nbr) @@ -202,7 +197,7 @@ static Model *create_chunk_model(TerrainChunk *chunk, bool animate) bool terrain_gfx_init() { GLint texture_units; - glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); + glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); GL_DEBUG char *shader_defs; asprintf(&shader_defs, @@ -212,58 +207,39 @@ bool terrain_gfx_init() client_config.view_distance ); - if (!shader_program_create(RESSOURCE_PATH "shaders/terrain", &shader_prog, shader_defs)) { + if (!shader_program_create(RESSOURCE_PATH "shaders/3d/terrain", &shader_prog, shader_defs)) { fprintf(stderr, "[error] failed to create terrain shader program\n"); return false; } free(shader_defs); - loc_model = glGetUniformLocation(shader_prog, "model"); - loc_VP = glGetUniformLocation(shader_prog, "VP"); - loc_daylight = glGetUniformLocation(shader_prog, "daylight"); - loc_fogColor = glGetUniformLocation(shader_prog, "fogColor"); - loc_ambientLight = glGetUniformLocation(shader_prog, "ambientLight"); - loc_lightDir = glGetUniformLocation(shader_prog, "lightDir"); - loc_cameraPos = glGetUniformLocation(shader_prog, "cameraPos"); + loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG GLint texture_indices[texture_units]; for (GLint i = 0; i < texture_units; i++) texture_indices[i] = i; - glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices); + glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices); GL_DEBUG model_shader.prog = shader_prog; - model_shader.loc_transform = loc_model; + model_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG + + light_shader.prog = shader_prog; + light_shader_locate(&light_shader); return true; } void terrain_gfx_deinit() { - glDeleteProgram(shader_prog); + glDeleteProgram(shader_prog); GL_DEBUG } void terrain_gfx_update() { - vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f}; - vec4 sunlight_dir; - mat4x4 sunlight_mat; - mat4x4_identity(sunlight_mat); - - mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f); - mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir); - - f32 daylight = get_daylight(); - f32 ambient_light = f32_mix(0.3f, 0.7f, daylight); - v3f32 fog_color = v3f32_mix((v3f32) {0x03, 0x0A, 0x1A}, (v3f32) {0x87, 0xCE, 0xEB}, daylight); - - glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); - glProgramUniform3f(shader_prog, loc_lightDir, sunlight_dir[0], sunlight_dir[1], sunlight_dir[2]); - glProgramUniform3f(shader_prog, loc_cameraPos, camera.eye[0], camera.eye[1], camera.eye[2]); - glProgramUniform1f(shader_prog, loc_daylight, daylight); - glProgramUniform3f(shader_prog, loc_fogColor, fog_color.x / 0xFF * ambient_light, fog_color.y / 0xFF * ambient_light, fog_color.z / 0xFF * ambient_light); - glProgramUniform1f(shader_prog, loc_ambientLight, ambient_light); + glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG + light_shader_update(&light_shader); } void terrain_gfx_make_chunk_model(TerrainChunk *chunk) @@ -288,13 +264,12 @@ void terrain_gfx_make_chunk_model(TerrainChunk *chunk) model_node_transform(model->root); } + meta->model->replace = model; meta->model->flags.delete = 1; + } else if (model) { + model_scene_add(model); } meta->model = model; - - if (model) - model_scene_add(model); - pthread_mutex_unlock(&chunk->mtx); } diff --git a/src/client/texture.c b/src/client/texture.c index 9f4f7ec..a80738f 100644 --- a/src/client/texture.c +++ b/src/client/texture.c @@ -1,8 +1,11 @@ #define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_RESIZE_IMPLEMENTATION #include +#include #include #include #include "client/client_config.h" +#include "client/gl_debug.h" #include "client/texture.h" static Tree textures; @@ -22,7 +25,7 @@ static bool lookup_texture(char *path, Texture **texture) TreeNode **node = tree_nfd(&textures, path, &cmp_texture); if (*node) { - *texture = &((TextureLookup *) &(*node)->dat)->texture; + *texture = &((TextureLookup *) (*node)->dat)->texture; return true; } @@ -70,14 +73,31 @@ Texture *texture_load(char *path, bool mipmap) return texture; } +static inline int least_common_multiple(int a, int b) +{ + int high, low; + if (a > b) { + high = a; + low = b; + } else { + high = b; + low = a; + } + + int lcm = high; + while (lcm % low) + lcm += high; + return lcm; +} + Texture *texture_load_cubemap(char *path) { Texture *texture; if (lookup_texture(path, &texture)) return texture; - glGenTextures(1, &texture->txo); - glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); + glGenTextures(1, &texture->txo); GL_DEBUG + glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); GL_DEBUG const char *directions[6] = { "right", @@ -88,48 +108,77 @@ Texture *texture_load_cubemap(char *path) "back", }; + typedef struct { + unsigned char *data; + int width, height, channels; + } CubemapFace; + + CubemapFace faces[6]; + int size = 1; + for (int i = 0; i < 6; i++) { char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1]; sprintf(filename, "%s/%s.png", path, directions[i]); - unsigned char *data = stbi_load(filename, - &texture->width, &texture->height, &texture->channels, 0); - if (!data) { + if (!(faces[i].data = stbi_load(filename, + &faces[i].width, &faces[i].height, &faces[i].channels, 0))) { fprintf(stderr, "[error] failed to load texture %s\n", filename); exit(EXIT_FAILURE); } + size = least_common_multiple(size, faces[i].width); + size = least_common_multiple(size, faces[i].height); + } + + for (int i = 0; i < 6; i++) { + unsigned char *data = faces[i].data; + + bool resize = faces[i].width != size || faces[i].height != size; + if (resize) { + data = malloc(size * size * faces[i].channels); + + stbir_resize_uint8_generic( + faces[i].data, faces[i].width, faces[i].height, 0, + data, size, size, 0, + faces[i].channels, STBIR_ALPHA_CHANNEL_NONE, 0, + STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, + NULL); + } + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, - texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - stbi_image_free(data); + size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); GL_DEBUG + + stbi_image_free(faces[i].data); + if (resize) + stbi_image_free(data); } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GL_DEBUG + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_DEBUG + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_DEBUG + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); GL_DEBUG return texture; } void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap) { - glGenTextures(1, &texture->txo); - glBindTexture(GL_TEXTURE_2D, texture->txo); + glGenTextures(1, &texture->txo); GL_DEBUG + glBindTexture(GL_TEXTURE_2D, texture->txo); GL_DEBUG glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap) - ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); GL_DEBUG + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); GL_DEBUG + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); GL_DEBUG glTexImage2D(GL_TEXTURE_2D, 0, format, - texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); + texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); GL_DEBUG + glGenerateMipmap(GL_TEXTURE_2D); GL_DEBUG } void texture_destroy(Texture *texture) { - glDeleteTextures(1, &texture->txo); + glDeleteTextures(1, &texture->txo); GL_DEBUG } diff --git a/src/client/window.c b/src/client/window.c index 63dc81f..b9460eb 100644 --- a/src/client/window.c +++ b/src/client/window.c @@ -4,6 +4,7 @@ #include "client/client_config.h" #include "client/debug_menu.h" #include "client/game.h" +#include "client/gl_debug.h" #include "client/gui.h" #include "client/input.h" #include "client/window.h" @@ -22,7 +23,7 @@ static void update_projection() static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow *handle, int width, int height) { - glViewport(0, 0, width, height); + glViewport(0, 0, width, height); GL_DEBUG window.width = width; window.height = height; diff --git a/src/debug.sh b/src/debug.sh index 7f80044..5dc2bac 100755 --- a/src/debug.sh +++ b/src/debug.sh @@ -19,6 +19,7 @@ define hook-stop quit end end +break gl_error " echo "$COMMON diff --git a/src/server/schematic.c b/src/server/schematic.c index 5a754e8..0f18ebb 100644 --- a/src/server/schematic.c +++ b/src/server/schematic.c @@ -90,5 +90,5 @@ static void delete_schematic_node(SchematicNode *node) void schematic_delete(List *schematic) { - list_clr(schematic, (void *) &delete_schematic_node, NULL, NULL); + list_clr(schematic, &delete_schematic_node, NULL, NULL); } diff --git a/src/server/server.c b/src/server/server.c index f4bfaa1..aaaba08 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -34,15 +34,7 @@ static void on_ToServerSetnode(__attribute__((unused)) DragonnetPeer *peer, ToSe // update player's position static void on_ToServerPosRot(DragonnetPeer *peer, ToServerPosRot *pkt) { - ServerPlayer *player = peer->extra; - - pthread_rwlock_wrlock(&player->lock_pos); - player->pos = pkt->pos; - player->rot = pkt->rot; - - // this is recv thread, no lock_auth needed - database_update_player_pos_rot(player->name, player->pos, player->rot); - pthread_rwlock_unlock(&player->lock_pos); + server_player_move(peer->extra, pkt->pos, pkt->rot); } // tell server map manager client requested the chunk diff --git a/src/server/server_player.c b/src/server/server_player.c index 1f464f9..530e9ef 100644 --- a/src/server/server_player.c +++ b/src/server/server_player.c @@ -14,6 +14,45 @@ static Map players; static Map players_named; +static void send_entity_add(ServerPlayer *player, ServerPlayer *entity) +{ + dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) { + .type = player == entity ? ENTITY_LOCALPLAYER : ENTITY_PLAYER, + .data = { + .id = entity->id, + .pos = entity->pos, + .rot = entity->rot, + .nametag = entity->name, + }, + }); +} + +static void send_entity_remove(ServerPlayer *player, ServerPlayer *entity) +{ + dragonnet_peer_send_ToClientEntityRemove(player->peer, &(ToClientEntityRemove) { + .id = entity->id, + }); +} + +static void send_entity_update_pos_rot(ServerPlayer *player, ServerPlayer *entity) +{ + if (player != entity) + dragonnet_peer_send_ToClientEntityUpdatePosRot(player->peer, &(ToClientEntityUpdatePosRot) { + .id = entity->id, + .pos = entity->pos, + .rot = entity->rot, + }); +} + +static void send_entity_add_existing(ServerPlayer *entity, ServerPlayer *player) +{ + if (player != entity) { + pthread_rwlock_rdlock(&entity->lock_pos); + send_entity_add(player, entity); + pthread_rwlock_unlock(&entity->lock_pos); + } +} + // main thread // called on server shutdown static void player_drop(ServerPlayer *player) @@ -71,17 +110,9 @@ static void player_spawn(ServerPlayer *player) .gravity = server_config.movement.gravity, .jump = server_config.movement.jump, }); - dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) { - .type = ENTITY_LOCALPLAYER, - .data = { - .id = player->id, - .pos = player->pos, - .rot = player->rot, - .box = {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}}, - .eye = {0.0f, 1.75f, 0.0f}, - .nametag = NULL, - }, - }); + + server_player_iterate(&send_entity_add, player); + server_player_iterate(&send_entity_add_existing, player); } // any thread @@ -169,8 +200,12 @@ void server_player_remove(DragonnetPeer *peer) // (we don't want disconnect messages for every player on server shutdown) if (map_del(&players, &player->id, &cmp_player_id, &refcount_drp, NULL, NULL)) printf("[access] disconnected %s\n", player->name); - if (player->auth) - map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL); + + if (player->auth && map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL)) { + pthread_rwlock_rdlock(&player->lock_pos); + server_player_iterate(&send_entity_remove, player); + pthread_rwlock_unlock(&player->lock_pos); + } // peer no longer has a reference to player refcount_drp(&player->rc); @@ -224,6 +259,16 @@ bool server_player_auth(ServerPlayer *player, char *name) return success; } +// recv thread +void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot) +{ + pthread_rwlock_wrlock(&player->lock_pos); + // this is recv thread, no lock_auth needed + database_update_player_pos_rot(player->name, player->pos = pos, player->rot = rot); + server_player_iterate(&send_entity_update_pos_rot, player); + pthread_rwlock_unlock(&player->lock_pos); +} + // any thread void server_player_disconnect(ServerPlayer *player) { diff --git a/src/server/server_player.h b/src/server/server_player.h index 71d0916..1d20a5d 100644 --- a/src/server/server_player.h +++ b/src/server/server_player.h @@ -34,6 +34,7 @@ ServerPlayer *server_player_grab_named(char *name); bool server_player_auth(ServerPlayer *player, char *name); void server_player_disconnect(ServerPlayer *player); +void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot); void server_player_iterate(void *func, void *arg); #endif // _SERVER_PLAYER_H_ diff --git a/src/server/server_terrain.c b/src/server/server_terrain.c index a4aa91e..f6a22da 100644 --- a/src/server/server_terrain.c +++ b/src/server/server_terrain.c @@ -72,7 +72,7 @@ static void send_chunk_to_near(TerrainChunk *chunk) if (meta->state == CHUNK_CREATED) return; - server_player_iterate((void *) &send_chunk, chunk); + server_player_iterate(&send_chunk, chunk); } // Iterator for sending changed chunks to near clients @@ -104,7 +104,7 @@ static void terrain_gen_step() meta->state = CHUNK_READY; pthread_mutex_unlock(&chunk->mtx); - list_clr(&changed_chunks, (void *) &iterator_send_chunk_to_near, NULL, NULL); + list_clr(&changed_chunks, &iterator_send_chunk_to_near, NULL, NULL); pthread_mutex_lock(&mtx_num_gen_chunks); num_gen_chunks--; @@ -276,7 +276,7 @@ static void generate_spawn_hut() } Blob_free(&wood_color); - list_clr(&changed_chunks, (void *) iterator_send_chunk_to_near, NULL, NULL); + list_clr(&changed_chunks, &iterator_send_chunk_to_near, NULL, NULL); } // public functions diff --git a/src/server/voxelctx.c b/src/server/voxelctx.c index bea87fd..7148102 100644 --- a/src/server/voxelctx.c +++ b/src/server/voxelctx.c @@ -46,7 +46,7 @@ Voxelctx *voxelctx_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos) void voxelctx_delete(Voxelctx *ctx) { - list_clr(&ctx->statestack, (void *) &free, NULL, NULL); + list_clr(&ctx->statestack, &free, NULL, NULL); free(ctx); } diff --git a/src/terrain.c b/src/terrain.c index 5b6d48a..2e8eec8 100644 --- a/src/terrain.c +++ b/src/terrain.c @@ -15,7 +15,7 @@ static void delete_chunk(TerrainChunk *chunk, Terrain *terrain) static void delete_sector(TerrainSector *sector, Terrain *terrain) { - tree_clr(§or->chunks, (void *) &delete_chunk, terrain, NULL, 0); + tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0); pthread_rwlock_destroy(§or->lock); free(sector); } @@ -32,7 +32,7 @@ Terrain *terrain_create() void terrain_delete(Terrain *terrain) { - tree_clr(&terrain->sectors, (void *) &delete_sector, terrain, NULL, 0); + tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0); pthread_rwlock_destroy(&terrain->lock); pthread_rwlock_destroy(&terrain->cache_lock); free(terrain); diff --git a/src/types.def b/src/types.def index 9aa6aa7..48c572b 100644 --- a/src/types.def +++ b/src/types.def @@ -23,8 +23,6 @@ EntityData u64 id v3f64 pos v3f32 rot - aabb3f32 box - v3f32 eye String nametag ; server packets @@ -82,11 +80,6 @@ pkt ToClientEntityUpdatePosRot v3f64 pos v3f32 rot -pkt ToClientEntityUpdateBoxEye - u64 id - aabb3f32 box - v3f32 eye - pkt ToClientEntityUpdateNametag u64 id String nametag diff --git a/src/version.cmake b/src/version.cmake index 25e2782..f6e2306 100644 --- a/src/version.cmake +++ b/src/version.cmake @@ -3,7 +3,7 @@ execute_process(COMMAND git tag --points-at HEAD OUTPUT_STRIP_TRAILING_WHITESPACE ) -if ("${GIT_VERSION}" STREQUAL "") +if("${GIT_VERSION}" STREQUAL "") execute_process(COMMAND git rev-parse --short HEAD OUTPUT_VARIABLE GIT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE diff --git a/textures/models/player/arm/back.png b/textures/models/player/arm/back.png index 6b98546..69ffff3 100644 Binary files a/textures/models/player/arm/back.png and b/textures/models/player/arm/back.png differ diff --git a/textures/models/player/arm/bottom.png b/textures/models/player/arm/bottom.png index ceaa6aa..fda334e 100644 Binary files a/textures/models/player/arm/bottom.png and b/textures/models/player/arm/bottom.png differ diff --git a/textures/models/player/arm/front.png b/textures/models/player/arm/front.png index f62ee88..ce19461 100644 Binary files a/textures/models/player/arm/front.png and b/textures/models/player/arm/front.png differ diff --git a/textures/models/player/arm/left.png b/textures/models/player/arm/left.png index 558391a..c2b2325 100644 Binary files a/textures/models/player/arm/left.png and b/textures/models/player/arm/left.png differ diff --git a/textures/models/player/arm/right.png b/textures/models/player/arm/right.png index b1b7b9f..9ae2e41 100644 Binary files a/textures/models/player/arm/right.png and b/textures/models/player/arm/right.png differ diff --git a/textures/models/player/arm/top.png b/textures/models/player/arm/top.png index 45567ca..e12765d 100644 Binary files a/textures/models/player/arm/top.png and b/textures/models/player/arm/top.png differ diff --git a/textures/models/player/chest/back.png b/textures/models/player/chest/back.png index 0a0a862..5eca9ec 100644 Binary files a/textures/models/player/chest/back.png and b/textures/models/player/chest/back.png differ diff --git a/textures/models/player/chest/bottom.png b/textures/models/player/chest/bottom.png index e51749a..131d33d 100644 Binary files a/textures/models/player/chest/bottom.png and b/textures/models/player/chest/bottom.png differ diff --git a/textures/models/player/chest/front.png b/textures/models/player/chest/front.png index 6ec46e1..d44fd42 100644 Binary files a/textures/models/player/chest/front.png and b/textures/models/player/chest/front.png differ diff --git a/textures/models/player/chest/left.png b/textures/models/player/chest/left.png index c04fb71..995ad5f 100644 Binary files a/textures/models/player/chest/left.png and b/textures/models/player/chest/left.png differ diff --git a/textures/models/player/chest/right.png b/textures/models/player/chest/right.png index 60329f4..e48eb66 100644 Binary files a/textures/models/player/chest/right.png and b/textures/models/player/chest/right.png differ diff --git a/textures/models/player/chest/top.png b/textures/models/player/chest/top.png index 2711dd1..df84083 100644 Binary files a/textures/models/player/chest/top.png and b/textures/models/player/chest/top.png differ diff --git a/textures/models/player/head/back.png b/textures/models/player/head/back.png index 6b98546..935a2b9 100644 Binary files a/textures/models/player/head/back.png and b/textures/models/player/head/back.png differ diff --git a/textures/models/player/head/bottom.png b/textures/models/player/head/bottom.png index ceaa6aa..1fdae43 100644 Binary files a/textures/models/player/head/bottom.png and b/textures/models/player/head/bottom.png differ diff --git a/textures/models/player/head/front.png b/textures/models/player/head/front.png index f62ee88..805fec0 100644 Binary files a/textures/models/player/head/front.png and b/textures/models/player/head/front.png differ diff --git a/textures/models/player/head/left.png b/textures/models/player/head/left.png index 558391a..7dc2a81 100644 Binary files a/textures/models/player/head/left.png and b/textures/models/player/head/left.png differ diff --git a/textures/models/player/head/right.png b/textures/models/player/head/right.png index b1b7b9f..47436ba 100644 Binary files a/textures/models/player/head/right.png and b/textures/models/player/head/right.png differ diff --git a/textures/models/player/head/top.png b/textures/models/player/head/top.png index 45567ca..916ea2b 100644 Binary files a/textures/models/player/head/top.png and b/textures/models/player/head/top.png differ diff --git a/textures/models/player/leg/back.png b/textures/models/player/leg/back.png index 6b98546..48b93ce 100644 Binary files a/textures/models/player/leg/back.png and b/textures/models/player/leg/back.png differ diff --git a/textures/models/player/leg/bottom.png b/textures/models/player/leg/bottom.png index ceaa6aa..0c942fb 100644 Binary files a/textures/models/player/leg/bottom.png and b/textures/models/player/leg/bottom.png differ diff --git a/textures/models/player/leg/front.png b/textures/models/player/leg/front.png index f62ee88..13b1016 100644 Binary files a/textures/models/player/leg/front.png and b/textures/models/player/leg/front.png differ diff --git a/textures/models/player/leg/left.png b/textures/models/player/leg/left.png index 558391a..104c6e7 100644 Binary files a/textures/models/player/leg/left.png and b/textures/models/player/leg/left.png differ diff --git a/textures/models/player/leg/right.png b/textures/models/player/leg/right.png index b1b7b9f..a97a13a 100644 Binary files a/textures/models/player/leg/right.png and b/textures/models/player/leg/right.png differ diff --git a/textures/models/player/leg/top.png b/textures/models/player/leg/top.png index 45567ca..d575dc7 100644 Binary files a/textures/models/player/leg/top.png and b/textures/models/player/leg/top.png differ