You can now see other players

master
Elias Fleckenstein 2022-04-17 13:35:41 +02:00
parent f931fe22ec
commit 6d60079b8f
No known key found for this signature in database
GPG Key ID: 06927A5199D6C9B2
75 changed files with 914 additions and 476 deletions

View File

@ -1,7 +1,10 @@
name player scale 1 1.8 1 name player scale 1 1.8 1
name head pos 0 0.875 0 scale 0.45 0.25 0.45 cube head name nametag pos 0 1.1 0
name body scale 0.48 0.75 0.36 name neck pos 0 0.75 0 scale 0.45 0.25 0.45
name upper pos 0 1.0 0 scale 1 0.5 1 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 chest pos 0 -0.5 0 cube chest
name shoulders scale 0.5 1 1 name shoulders scale 0.5 1 1
name left pos -1.5 0 0 name left pos -1.5 0 0

19
shaders/3d/entity/fragment.glsl Executable file
View File

@ -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;
}

26
shaders/3d/entity/vertex.glsl Executable file
View File

@ -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;
}

View File

@ -1,6 +1,6 @@
in vec3 fragmentPosition; in vec3 fragmentPosition;
in vec3 fragmentNormal; in vec3 fragmentNormal;
in vec2 fragmentTextureCoords; in vec2 fragmentTextureCoordinates;
in float fragmentTextureIndex; in float fragmentTextureIndex;
in vec3 fragmentColor; in vec3 fragmentColor;
@ -12,7 +12,7 @@ uniform sampler2D textures[MAX_TEXTURE_UNITS];
void main() void main()
{ {
outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoords) * vec4(fragmentColor, 1.0); 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)); outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0));
if (outColor.a == 0.0) if (outColor.a == 0.0)

View File

@ -1,12 +1,12 @@
layout(location = 0) in vec3 vertexPosition; layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec3 vertexNormal; layout(location = 1) in vec3 vertexNormal;
layout(location = 2) in vec2 vertexTextureCoords; layout(location = 2) in vec2 vertexTextureCoordinates;
layout(location = 3) in float vertexTextureIndex; layout(location = 3) in float vertexTextureIndex;
layout(location = 4) in vec3 vertexColor; layout(location = 4) in vec3 vertexColor;
out vec3 fragmentPosition; out vec3 fragmentPosition;
out vec3 fragmentNormal; out vec3 fragmentNormal;
out vec2 fragmentTextureCoords; out vec2 fragmentTextureCoordinates;
out float fragmentTextureIndex; out float fragmentTextureIndex;
out vec3 fragmentColor; out vec3 fragmentColor;
@ -23,7 +23,7 @@ void main()
fragmentPosition = worldSpace.xyz; fragmentPosition = worldSpace.xyz;
fragmentNormal = vertexNormal; fragmentNormal = vertexNormal;
fragmentTextureCoords = vertexTextureCoords; fragmentTextureCoordinates = vertexTextureCoordinates;
fragmentTextureIndex = vertexTextureIndex; fragmentTextureIndex = vertexTextureIndex;
fragmentColor = vertexColor; fragmentColor = vertexColor;

View File

@ -1,4 +1,4 @@
in vec2 fragmentTextureCoords; in vec2 fragmentTextureCoordinates;
out vec4 outColor; out vec4 outColor;
@ -7,5 +7,5 @@ uniform vec4 color;
void main() 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;
} }

View File

@ -1,7 +1,7 @@
layout(location = 0) in vec2 vertexPosition; 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 model;
uniform mat4 projection; uniform mat4 projection;
@ -9,5 +9,5 @@ uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0); gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords; fragmentTextureCoordinates = vertexTextureCoordinates;
} }

View File

@ -1,4 +1,4 @@
in vec2 fragmentTextureCoords; in vec2 fragmentTextureCoordinates;
out vec4 outColor; out vec4 outColor;
@ -6,5 +6,5 @@ uniform sampler2D texture0;
void main() void main()
{ {
outColor = texture(texture0, fragmentTextureCoords); outColor = texture(texture0, fragmentTextureCoordinates);
} }

View File

@ -1,7 +1,7 @@
layout(location = 0) in vec2 vertexPosition; 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 model;
uniform mat4 projection; uniform mat4 projection;
@ -9,5 +9,5 @@ uniform mat4 projection;
void main() void main()
{ {
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0); gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
fragmentTextureCoords = vertexTextureCoords; fragmentTextureCoordinates = vertexTextureCoordinates;
} }

View File

@ -1,4 +1,4 @@
in vec3 fragmentTextureCoords; in vec3 fragmentTextureCoordinates;
out vec4 outColor; out vec4 outColor;
@ -17,13 +17,13 @@ float strengthen(float value, float exponent, float max)
void main() void main()
{ {
float height = normalize(fragmentTextureCoords).y; float height = normalize(fragmentTextureCoordinates).y;
vec4 topColor = texture(texture0, vec3(0.0, 1.0, 0.0)); vec4 topColor = texture(texture0, vec3(0.0, 1.0, 0.0));
vec4 bottomColor = texture(texture0, vec3(1.0, 0.11, 0.5)); vec4 bottomColor = texture(texture0, vec3(1.0, 0.11, 0.5));
vec4 expectedColor = mix(bottomColor, topColor, height); 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))); float cloudFactor = reverseMix(length(dayColor.rg - expectedColor.rg), 0.15, length(vec2(1.0)));

View File

@ -1,6 +1,6 @@
layout(location = 0) in vec3 vertexPosition; layout(location = 0) in vec3 vertexPosition;
out vec3 fragmentTextureCoords; out vec3 fragmentTextureCoordinates;
uniform mat4 VP; uniform mat4 VP;
@ -8,5 +8,5 @@ void main()
{ {
gl_Position = VP * vec4(vertexPosition, 1.0); gl_Position = VP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w; gl_Position.z = gl_Position.w;
fragmentTextureCoords = vertexPosition; fragmentTextureCoordinates = vertexPosition;
} }

View File

@ -1,4 +1,4 @@
in vec3 fragmentTextureCoords; in vec3 fragmentTextureCoordinates;
out vec4 outColor; out vec4 outColor;
@ -10,8 +10,8 @@ void main()
vec4 topColor = texture(textures[0], vec3(0.0, 1.0, 0.0)); 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 bottomColor = texture(textures[0], vec3(1.0, 0.11, 0.5));
vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoords).y); vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoordinates).y);
vec4 nightColor = texture(textures[1], fragmentTextureCoords); vec4 nightColor = texture(textures[1], fragmentTextureCoordinates);
outColor = mix(nightColor, dayColor, daylight); outColor = mix(nightColor, dayColor, daylight);
} }

View File

@ -1,6 +1,6 @@
layout(location = 0) in vec3 vertexPosition; layout(location = 0) in vec3 vertexPosition;
out vec3 fragmentTextureCoords; out vec3 fragmentTextureCoordinates;
uniform mat4 VP; uniform mat4 VP;
@ -8,5 +8,5 @@ void main()
{ {
gl_Position = VP * vec4(vertexPosition, 1.0); gl_Position = VP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w; gl_Position.z = gl_Position.w;
fragmentTextureCoords = vertexPosition; fragmentTextureCoordinates = vertexPosition;
} }

View File

@ -1,4 +1,4 @@
in vec2 fragmentTextureCoords; in vec2 fragmentTextureCoordinates;
out vec4 outColor; out vec4 outColor;
@ -6,5 +6,5 @@ uniform sampler2D texture0;
void main() void main()
{ {
outColor = texture(texture0, fragmentTextureCoords); outColor = texture(texture0, fragmentTextureCoordinates);
} }

View File

@ -1,7 +1,7 @@
layout(location = 0) in vec3 vertexPosition; 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; uniform mat4 MVP;
@ -9,5 +9,5 @@ void main()
{ {
gl_Position = MVP * vec4(vertexPosition, 1.0); gl_Position = MVP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w; gl_Position.z = gl_Position.w;
fragmentTextureCoords = vertexTextureCoords; fragmentTextureCoordinates = vertexTextureCoordinates;
} }

View File

@ -9,7 +9,7 @@ cp -r * .build/
cd .build/ cd .build/
mkdir build mkdir build
cd 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 ../.. cd ../..
rm -rf .build rm -rf .build
exit 1 exit 1

View File

@ -22,6 +22,10 @@ find_package(Freetype REQUIRED)
# Options # Options
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_compile_definitions("ENABLE_GL_DEBUG")
endif()
add_compile_definitions("USE_DRAGONNET") add_compile_definitions("USE_DRAGONNET")
add_compile_definitions("RESSOURCE_PATH=\"${RESSOURCE_PATH}\"") add_compile_definitions("RESSOURCE_PATH=\"${RESSOURCE_PATH}\"")
@ -38,12 +42,12 @@ include_directories(BEFORE ${CMAKE_SOURCE_DIR})
# System specific options # 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") link_directories("/usr/local/lib")
include_directories("/usr/local/include") include_directories("/usr/local/include")
endif() endif()
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD") if("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
link_directories("/usr/X11R6/lib") link_directories("/usr/X11R6/lib")
include_directories("/usr/X11R6/include") include_directories("/usr/X11R6/include")
endif() endif()
@ -98,8 +102,10 @@ add_executable(dragonblocks
client/font.c client/font.c
client/frustum.c client/frustum.c
client/game.c client/game.c
client/gl_debug.c
client/gui.c client/gui.c
client/input.c client/input.c
client/light.c
client/mesh.c client/mesh.c
client/model.c client/model.c
client/shader.c client/shader.c

View File

@ -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_ToClientEntityAdd ] = (void *) &client_entity_add;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityRemove ] = (void *) &client_entity_remove; 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_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; client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateNametag] = (void *) &client_entity_update_nametag;
flag_ini(&finish); flag_ini(&finish);

View File

@ -1,12 +1,46 @@
#include <asprintf/asprintf.h>
#include <dragonstd/map.h> #include <dragonstd/map.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "client/cube.h"
#include "client/client_config.h"
#include "client/client_entity.h" #include "client/client_entity.h"
#include "client/client_player.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]; 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 Map entities;
static List nametagged;
static pthread_mutex_t mtx_nametagged;
// any thread // any thread
// called when adding, getting or removing an entity from the map // 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) if (entity->type->remove)
entity->type->remove(entity); 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); refcount_drp(&entity->rc);
} }
@ -38,17 +80,78 @@ static void entity_delete(ClientEntity *entity)
free(entity->data.nametag); free(entity->data.nametag);
pthread_rwlock_init(&entity->lock_pos_rot, NULL); 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_nametag, NULL);
pthread_rwlock_init(&entity->lock_box_off, NULL);
free(entity); 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 // main thread
// called on startup // called on startup
void client_entity_init() void client_entity_init()
{ {
map_ini(&entities); map_ini(&entities);
list_ini(&nametagged);
pthread_mutex_init(&mtx_nametagged, NULL);
} }
// main thead // main thead
@ -57,6 +160,58 @@ void client_entity_deinit()
{ {
// forget all entities // forget all entities
map_cnl(&entities, &refcount_drp, NULL, NULL, 0); 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) ClientEntity *client_entity_grab(u64 id)
@ -69,8 +224,8 @@ void client_entity_transform(ClientEntity *entity)
if (!entity->model) if (!entity->model)
return; return;
entity->model->root->pos = (v3f32) {entity->data.pos.x, entity->data.pos.y, entity->data.pos.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 = (v3f32) {entity->data.rot.x, entity->data.rot.y, entity->data.rot.z}; entity->model->root->rot = entity->data.rot;
if (entity->type->transform) if (entity->type->transform)
entity->type->transform(entity); entity->type->transform(entity);
@ -92,14 +247,17 @@ void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEnti
pkt->data.nametag = NULL; pkt->data.nametag = NULL;
entity->model = NULL; entity->model = NULL;
entity->nametag = NULL;
pthread_rwlock_init(&entity->lock_pos_rot, NULL);
pthread_rwlock_init(&entity->lock_box_eye, NULL);
pthread_rwlock_init(&entity->lock_nametag, NULL);
if (entity->type->add) if (entity->type->add)
entity->type->add(entity); 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)) 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); fprintf(stderr, "[warning] failed to add entity %lu\n", entity->data.id);
@ -126,31 +284,13 @@ void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, T
if (entity->type->update_pos_rot) if (entity->type->update_pos_rot)
entity->type->update_pos_rot(entity); entity->type->update_pos_rot(entity);
client_entity_transform(entity);
pthread_rwlock_unlock(&entity->lock_pos_rot); pthread_rwlock_unlock(&entity->lock_pos_rot);
refcount_drp(&entity->rc); 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);
refcount_drp(&entity->rc);
}
void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt) void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt)
{ {
ClientEntity *entity = client_entity_grab(pkt->id); ClientEntity *entity = client_entity_grab(pkt->id);
@ -169,6 +309,7 @@ void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, T
if (entity->type->update_nametag) if (entity->type->update_nametag)
entity->type->update_nametag(entity); entity->type->update_nametag(entity);
update_nametag(entity);
pthread_rwlock_unlock(&entity->lock_nametag); pthread_rwlock_unlock(&entity->lock_nametag);
refcount_drp(&entity->rc); refcount_drp(&entity->rc);

View File

@ -4,6 +4,7 @@
#include <dragonnet/peer.h> #include <dragonnet/peer.h>
#include <dragonstd/refcount.h> #include <dragonstd/refcount.h>
#include <pthread.h> #include <pthread.h>
#include "client/gui.h"
#include "client/model.h" #include "client/model.h"
#include "entity.h" #include "entity.h"
#include "types.h" #include "types.h"
@ -14,27 +15,42 @@ typedef struct {
Refcount rc; Refcount rc;
Model *model; 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_pos_rot;
pthread_rwlock_t lock_box_eye;
pthread_rwlock_t lock_nametag; pthread_rwlock_t lock_nametag;
pthread_rwlock_t lock_box_off;
} ClientEntity; } ClientEntity;
// Entity is pronounced N-Tiddy, hmmmm...
typedef struct ClientEntityType { typedef struct ClientEntityType {
void (*add )(ClientEntity *entity); // called when server sent addition of entity void (*add )(ClientEntity *entity); // called when server sent addition of entity
void (*remove)(ClientEntity *entity); // called when server sent removal of entity void (*remove)(ClientEntity *entity); // called when server sent removal of entity
void (*free )(ClientEntity *entity); // called when entity is garbage collected void (*free )(ClientEntity *entity); // called when entity is garbage collected
void (*update_pos_rot)(ClientEntity *entity); void (*update_pos_rot)(ClientEntity *entity);
void (*update_box_eye)(ClientEntity *entity);
void (*update_nametag)(ClientEntity *entity); void (*update_nametag)(ClientEntity *entity);
void (*transform)(ClientEntity *entity); void (*transform)(ClientEntity *entity);
} ClientEntityType; } ClientEntityType;
extern ClientEntityType client_entity_types[];
extern Mesh client_entity_cube;
extern ModelShader client_entity_shader;
void client_entity_init(); void client_entity_init();
void client_entity_deinit(); 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); ClientEntity *client_entity_grab(u64 id);
void client_entity_drop(ClientEntity *entity); 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_add(DragonnetPeer *peer, ToClientEntityAdd *pkt);
void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt); void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt);
void client_entity_update_pos_rot(DragonnetPeer *peer, ToClientEntityUpdatePosRot *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); void client_entity_update_nametag(DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt);
extern ClientEntityType client_entity_types[];
#endif // _CLIENT_ENTITY_H_ #endif // _CLIENT_ENTITY_H_

View File

@ -10,27 +10,41 @@
#include "environment.h" #include "environment.h"
#include "physics.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; struct ClientPlayer client_player;
static ClientEntity *player_entity; static ClientEntity *player_entity;
static pthread_rwlock_t lock_player_entity; static pthread_rwlock_t lock_player_entity;
static Model *player_model;
// updat epos/rot box/eye functions // updat epos/rot box/eye functions
static void update_eye_pos_camera() static void update_camera()
{ {
v3f64 pos = player_entity->data.pos; vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
v3f32 eye = player_entity->data.eye;
camera_set_position((v3f32) {pos.x + eye.x, pos.y + eye.y, pos.z + eye.z}); PlayerModelBones *bones = player_entity->extra;
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() 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_POS);
debug_menu_changed(ENTRY_HUMIDITY); debug_menu_changed(ENTRY_HUMIDITY);
debug_menu_changed(ENTRY_TEMPERATURE); debug_menu_changed(ENTRY_TEMPERATURE);
@ -38,7 +52,7 @@ static void update_pos()
static void update_rot() 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_YAW);
debug_menu_changed(ENTRY_PITCH); debug_menu_changed(ENTRY_PITCH);
} }
@ -46,66 +60,111 @@ static void update_rot()
static void update_transform() static void update_transform()
{ {
client_entity_transform(player_entity); client_entity_transform(player_entity);
update_camera();
} }
static void send_pos_rot() static void send_pos_rot()
{ {
update_transform();
dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) { dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) {
.pos = player_entity->data.pos, .pos = player_entity->data.pos,
.rot = player_entity->data.rot, .rot = player_entity->data.rot,
}); });
update_transform();
} }
static void recv_pos_rot() static void recv_pos_rot()
{ {
update_transform();
update_pos(); update_pos();
update_rot(); update_rot();
update_transform();
} }
// entity callbacks // entity callbacks
static void on_add(ClientEntity *entity) 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); pthread_rwlock_wrlock(&lock_player_entity);
if (player_entity) { if (player_entity) {
fprintf(stderr, "[error] attempt to re-add localplayer entity\n"); fprintf(stderr, "[error] attempt to re-add localplayer entity\n");
exit(EXIT_FAILURE); 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); 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); pthread_rwlock_wrlock(&lock_player_entity);
refcount_drp(&entity->rc); refcount_drp(&entity->rc);
player_entity = NULL; player_entity = NULL;
pthread_rwlock_unlock(&lock_player_entity); pthread_rwlock_unlock(&lock_player_entity);
on_remove(entity);
} }
static void on_update_pos_rot(__attribute__((unused)) ClientEntity *entity) static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity)
{ {
recv_pos_rot(); recv_pos_rot();
} }
static void on_update_box_eye(__attribute__((unused)) ClientEntity *entity) static void local_on_update_nametag(ClientEntity *entity)
{
pthread_rwlock_rdlock(&lock_player_entity);
update_eye_pos_camera();
pthread_rwlock_unlock(&lock_player_entity);
}
static void on_update_nametag(ClientEntity *entity)
{ {
if (entity->data.nametag) { if (entity->data.nametag) {
free(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 // called on startup
@ -129,23 +195,21 @@ void client_player_init()
.gravity = 0.0f, .gravity = 0.0f,
}; };
client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) { client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
.add = &on_add, .add = &on_add,
.remove = &on_remove, .remove = &on_remove,
.free = NULL, .free = &on_free,
.update_pos_rot = &on_update_pos_rot, .update_pos_rot = NULL,
.update_box_eye = &on_update_box_eye, .update_nametag = NULL,
.update_nametag = &on_update_nametag,
.transform = &on_transform, .transform = &on_transform,
}; };
client_entity_types[ENTITY_PLAYER] = (ClientEntityType) { client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
.add = NULL, .add = &local_on_add,
.remove = NULL, .remove = &local_on_remove,
.free = NULL, .free = &on_free,
.update_pos_rot = NULL, .update_pos_rot = &local_on_update_pos_rot,
.update_box_eye = NULL, .update_nametag = &local_on_update_nametag,
.update_nametag = NULL,
.transform = &on_transform, .transform = &on_transform,
}; };
@ -162,6 +226,21 @@ void client_player_deinit()
pthread_rwlock_destroy(&lock_player_entity); 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 *client_player_entity()
{ {
ClientEntity *entity = NULL; ClientEntity *entity = NULL;
@ -198,33 +277,6 @@ void client_player_update_rot(ClientEntity *entity)
pthread_rwlock_unlock(&lock_player_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 // jump if possible
void client_player_jump() void client_player_jump()
{ {
@ -233,18 +285,18 @@ void client_player_jump()
return; return;
pthread_rwlock_rdlock(&entity->lock_pos_rot); pthread_rwlock_rdlock(&entity->lock_pos_rot);
pthread_rwlock_rdlock(&entity->lock_box_eye); pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_ground( if (physics_ground(
client_terrain, client_terrain,
client_player.movement.collision, client_player.movement.collision,
entity->data.box, entity->box_collision,
&entity->data.pos, &entity->data.pos,
&client_player.velocity &client_player.velocity
)) ))
client_player.velocity.y += client_player.movement.jump; 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); pthread_rwlock_unlock(&entity->lock_pos_rot);
refcount_drp(&entity->rc); refcount_drp(&entity->rc);
@ -259,12 +311,12 @@ void client_player_tick(f64 dtime)
pthread_rwlock_rdlock(&client_player.lock_movement); pthread_rwlock_rdlock(&client_player.lock_movement);
pthread_rwlock_wrlock(&entity->lock_pos_rot); pthread_rwlock_wrlock(&entity->lock_pos_rot);
pthread_rwlock_rdlock(&entity->lock_box_eye); pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_step( if (physics_step(
client_terrain, client_terrain,
client_player.movement.collision, client_player.movement.collision,
entity->data.box, entity->box_collision,
&entity->data.pos, &entity->data.pos,
&client_player.velocity, &client_player.velocity,
&(v3f64) { &(v3f64) {
@ -276,7 +328,7 @@ void client_player_tick(f64 dtime)
)) ))
client_player_update_pos(entity); 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(&entity->lock_pos_rot);
pthread_rwlock_unlock(&client_player.lock_movement); pthread_rwlock_unlock(&client_player.lock_movement);

View File

@ -14,6 +14,9 @@ extern struct ClientPlayer {
void client_player_init(); // called on startup void client_player_init(); // called on startup
void client_player_deinit(); // called on shutdown 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 ClientEntity *client_player_entity(); // grab and return client entity
void client_player_jump(); // jump if possible void client_player_jump(); // jump if possible

View File

@ -39,7 +39,7 @@ static TerrainChunk *set_dequeued(TerrainChunk *chunk)
// mesh generator step // mesh generator step
static void meshgen_step() static void meshgen_step()
{ {
TerrainChunk *chunk = queue_deq(&meshgen_tasks, (void *) &set_dequeued); TerrainChunk *chunk = queue_deq(&meshgen_tasks, &set_dequeued);
if (chunk) if (chunk)
terrain_gfx_make_chunk_model(chunk); terrain_gfx_make_chunk_model(chunk);

View File

@ -3,12 +3,14 @@
#include <GL/gl.h> #include <GL/gl.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <pthread.h> #include <pthread.h>
#include "client/client_config.h" #include "client/client_config.h"
#include "client/client_player.h" #include "client/client_player.h"
#include "client/client_terrain.h" #include "client/client_terrain.h"
#include "client/debug_menu.h" #include "client/debug_menu.h"
#include "client/game.h" #include "client/game.h"
#include "client/gl_debug.h"
#include "client/gui.h" #include "client/gui.h"
#include "client/window.h" #include "client/window.h"
#include "day.h" #include "day.h"
@ -73,27 +75,27 @@ static char *get_entry_text(DebugMenuEntry entry)
char *str; char *str;
switch (entry) { switch (entry) {
case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break; case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); 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_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_YAW: asprintf(&str, "yaw = %.1f", 360.0 - rot.y / M_PI * 180.0 ); break;
case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", 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_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); 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_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_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_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_SEED: asprintf(&str, "seed = %d", seed ); break;
case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); 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_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break;
case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "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_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break;
case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); break; case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); GL_DEBUG break;
case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); 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_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_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_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_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break;
default: break; default: break;
} }
return str; return str;
@ -113,7 +115,7 @@ void debug_menu_init()
.scale = {1.0f, 1.0f}, .scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT, .scale_type = SCALE_TEXT,
.affect_parent_scale = false, .affect_parent_scale = false,
.text = strdup(""), .text = "",
.image = NULL, .image = NULL,
.text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f}, .text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f},
.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.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); pthread_mutex_unlock(&changed_elements_mtx);
for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++) for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++)
if (changed_elements_cpy[i]) if (changed_elements_cpy[i]) {
gui_text(gui_elements[i], get_entry_text(i)); char *str = get_entry_text(i);
gui_text(gui_elements[i], str);
free(str);
}
} }
void debug_menu_changed(DebugMenuEntry entry) void debug_menu_changed(DebugMenuEntry entry)

View File

@ -3,6 +3,7 @@
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include "client/client.h" #include "client/client.h"
#include "client/font.h" #include "client/font.h"
#include "client/gl_debug.h"
#include "client/texture.h" #include "client/texture.h"
#define NUM_CHARS 128 #define NUM_CHARS 128
@ -43,7 +44,7 @@ bool font_init()
return false; return false;
} }
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GL_DEBUG
FT_Set_Pixel_Sizes(font_face, 0, 16); FT_Set_Pixel_Sizes(font_face, 0, 16);
for (unsigned char c = 0; c < NUM_CHARS; c++) { for (unsigned char c = 0; c < NUM_CHARS; c++) {
@ -138,7 +139,7 @@ void font_delete(Font *font)
void font_render(Font *font) void font_render(Font *font)
{ {
for (size_t i = 0; i < font->count; i++) { 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]); mesh_render(&font->meshes[i]);
} }
} }

View File

@ -7,12 +7,15 @@
#include <unistd.h> #include <unistd.h>
#include "client/camera.h" #include "client/camera.h"
#include "client/client.h" #include "client/client.h"
#include "client/client_entity.h"
#include "client/client_node.h" #include "client/client_node.h"
#include "client/client_player.h" #include "client/client_player.h"
#include "client/client_terrain.h" #include "client/client_terrain.h"
#include "client/debug_menu.h" #include "client/debug_menu.h"
#include "client/font.h" #include "client/font.h"
#include "client/frustum.h" #include "client/frustum.h"
#include "client/game.h"
#include "client/gl_debug.h"
#include "client/gui.h" #include "client/gui.h"
#include "client/input.h" #include "client/input.h"
#include "client/sky.h" #include "client/sky.h"
@ -42,21 +45,20 @@ static void crosshair_init()
static void render(f64 dtime) static void render(f64 dtime)
{ {
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); GL_DEBUG
glEnable(GL_ALPHA_TEST); glEnable(GL_BLEND); GL_DEBUG
glEnable(GL_BLEND); glEnable(GL_MULTISAMPLE); GL_DEBUG
glEnable(GL_MULTISAMPLE); glEnable(GL_CULL_FACE); GL_DEBUG
glEnable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DEBUG
glAlphaFunc(GL_GREATER, 0.1f); glCullFace(GL_BACK); GL_DEBUG
glCullFace(GL_BACK); glFrontFace(GL_CCW); GL_DEBUG
glFrontFace(GL_CCW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GL_DEBUG
frustum_update(); frustum_update();
terrain_gfx_update(); terrain_gfx_update();
client_entity_gfx_update();
sky_render(); sky_render();
model_scene_render(dtime); model_scene_render(dtime);
@ -116,6 +118,11 @@ bool game(Flag *gfx_init)
if (!terrain_gfx_init()) if (!terrain_gfx_init())
return false; return false;
if (!client_entity_gfx_init())
return false;
client_player_gfx_init();
client_node_init(); client_node_init();
client_terrain_start(); client_terrain_start();
@ -139,6 +146,8 @@ bool game(Flag *gfx_init)
model_deinit(); model_deinit();
sky_deinit(); sky_deinit();
terrain_gfx_deinit(); terrain_gfx_deinit();
client_entity_gfx_deinit();
client_player_gfx_deinit();
return true; return true;
} }
@ -147,48 +156,48 @@ char *game_take_screenshot()
{ {
// renderbuffer for depth & stencil buffer // renderbuffer for depth & stencil buffer
GLuint rbo; GLuint rbo;
glGenRenderbuffers(1, &rbo); glGenRenderbuffers(1, &rbo); GL_DEBUG
glBindRenderbuffer(GL_RENDERBUFFER, rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG
// 2 textures, one with AA, one without // 2 textures, one with AA, one without
GLuint txos[2]; GLuint txos[2];
glGenTextures(2, txos); glGenTextures(2, txos); GL_DEBUG
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG
glBindTexture(GL_TEXTURE_2D, txos[1]); 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); 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 // 2 framebuffers, one with AA, one without
GLuint fbos[2]; GLuint fbos[2];
glGenFramebuffers(2, fbos); glGenFramebuffers(2, fbos); GL_DEBUG
glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); 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); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG
glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG
// render scene // render scene
glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
render(0.0); render(0.0);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG
// blit AA-buffer into no-AA buffer // blit AA-buffer into no-AA buffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); 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); glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG
// read data // read data
GLubyte data[window.width * window.height * 3]; GLubyte data[window.width * window.height * 3];
glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG
glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG
// create filename // create filename
char filename[BUFSIZ]; char filename[BUFSIZ];
@ -200,9 +209,9 @@ char *game_take_screenshot()
stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3); stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
// delete buffers // delete buffers
glDeleteRenderbuffers(1, &rbo); glDeleteRenderbuffers(1, &rbo); GL_DEBUG
glDeleteTextures(2, txos); glDeleteTextures(2, txos); GL_DEBUG
glDeleteFramebuffers(2, fbos); glDeleteFramebuffers(2, fbos); GL_DEBUG
return strdup(filename); return strdup(filename);
} }

26
src/client/gl_debug.c Normal file
View File

@ -0,0 +1,26 @@
#include <GL/glew.h>
#include <GL/gl.h>
#include <stdio.h>
#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);
}

12
src/client/gl_debug.h Normal file
View File

@ -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

View File

@ -5,6 +5,7 @@
#include <string.h> #include <string.h>
#include "client/client.h" #include "client/client.h"
#include "client/cube.h" #include "client/cube.h"
#include "client/gl_debug.h"
#include "client/gui.h" #include "client/gui.h"
#include "client/mesh.h" #include "client/mesh.h"
#include "client/shader.h" #include "client/shader.h"
@ -120,23 +121,28 @@ static void render_element(GUIElement *element)
{ {
if (element->visible) { if (element->visible) {
if (element->def.bg_color.w > 0.0f) { if (element->def.bg_color.w > 0.0f) {
glUseProgram(background_prog); glUseProgram(background_prog); GL_DEBUG
glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); 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); 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); mesh_render(&background_mesh);
} }
if (element->def.image) { if (element->def.image) {
glUseProgram(image_prog); glUseProgram(image_prog); GL_DEBUG
glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
glBindTextureUnit(0, element->def.image->txo); glBindTextureUnit(0, element->def.image->txo); GL_DEBUG
mesh_render(&image_mesh); mesh_render(&image_mesh);
} }
if (element->text && element->def.text_color.w > 0.0f) { if (element->def.text && element->def.text_color.w > 0.0f) {
glUseProgram(font_prog); if (!element->text) {
glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); element->text = font_create(element->def.text);
glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w); 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); font_render(element->text);
} }
@ -177,6 +183,9 @@ static void scale_element(GUIElement *element)
break; break;
case SCALE_TEXT: case SCALE_TEXT:
if (!element->text)
break;
element->scale.x *= element->text->size.x; element->scale.x *= element->text->size.x;
element->scale.y *= element->text->size.y; element->scale.y *= element->text->size.y;
break; break;
@ -231,9 +240,9 @@ bool gui_init()
return false; return false;
} }
background_loc_model = glGetUniformLocation(background_prog, "model"); background_loc_model = glGetUniformLocation(background_prog, "model"); GL_DEBUG
background_loc_projection = glGetUniformLocation(background_prog, "projection"); background_loc_projection = glGetUniformLocation(background_prog, "projection"); GL_DEBUG
background_loc_color = glGetUniformLocation(background_prog, "color"); background_loc_color = glGetUniformLocation(background_prog, "color"); GL_DEBUG
// initialize image pipeline // initialize image pipeline
@ -242,8 +251,8 @@ bool gui_init()
return false; return false;
} }
image_loc_model = glGetUniformLocation(image_prog, "model"); image_loc_model = glGetUniformLocation(image_prog, "model"); GL_DEBUG
image_loc_projection = glGetUniformLocation(image_prog, "projection"); image_loc_projection = glGetUniformLocation(image_prog, "projection"); GL_DEBUG
// initialize font pipeline // initialize font pipeline
@ -252,9 +261,9 @@ bool gui_init()
return false; return false;
} }
font_loc_model = glGetUniformLocation(font_prog, "model"); font_loc_model = glGetUniformLocation(font_prog, "model"); GL_DEBUG
font_loc_projection = glGetUniformLocation(font_prog, "projection"); font_loc_projection = glGetUniformLocation(font_prog, "projection"); GL_DEBUG
font_loc_color = glGetUniformLocation(font_prog, "color"); font_loc_color = glGetUniformLocation(font_prog, "color"); GL_DEBUG
// initialize GUI root element // initialize GUI root element
@ -283,13 +292,13 @@ bool gui_init()
void gui_deinit() void gui_deinit()
{ {
glDeleteProgram(background_prog); glDeleteProgram(background_prog); GL_DEBUG
mesh_destroy(&background_mesh); mesh_destroy(&background_mesh);
glDeleteProgram(image_prog); glDeleteProgram(image_prog); GL_DEBUG
mesh_destroy(&image_mesh); mesh_destroy(&image_mesh);
glDeleteProgram(font_prog); glDeleteProgram(font_prog); GL_DEBUG
delete_elements(&root_element.children); delete_elements(&root_element.children);
} }
@ -297,9 +306,9 @@ void gui_deinit()
void gui_update_projection() void gui_update_projection()
{ {
mat4x4_ortho(projection, 0, window.width, window.height, 0, -1.0f, 1.0f); 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(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
root_element.def.scale.x = window.width; root_element.def.scale.x = window.width;
root_element.def.scale.y = window.height; root_element.def.scale.y = window.height;
@ -309,13 +318,13 @@ void gui_update_projection()
void gui_render() void gui_render()
{ {
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE); GL_DEBUG
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST); GL_DEBUG
render_elements(&root_element.children); render_elements(&root_element.children);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); GL_DEBUG
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE); GL_DEBUG
} }
GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def) GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
@ -327,15 +336,12 @@ GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
element->def = def; element->def = def;
element->visible = true; element->visible = true;
element->parent = parent; element->parent = parent;
element->text = NULL;
if (element->def.text) { if (element->def.text)
element->def.text = strdup(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); array_ini(&element->children, sizeof(GUIElement), 0);
if (element->def.affect_parent_scale) if (element->def.affect_parent_scale)
@ -346,15 +352,16 @@ GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
return element; return element;
} }
void gui_text(GUIElement *element, char *text) void gui_text(GUIElement *element, const char *text)
{ {
if (element->def.text) if (element->def.text)
free(element->def.text); free(element->def.text);
element->def.text = text; if (element->text)
font_delete(element->text); font_delete(element->text);
element->text = font_create(text);
gui_transform(element); element->def.text = strdup(text);
element->text = NULL;
} }
void gui_transform(GUIElement *element) void gui_transform(GUIElement *element)

View File

@ -48,7 +48,7 @@ void gui_deinit();
void gui_update_projection(); void gui_update_projection();
void gui_render(); void gui_render();
GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def); 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); void gui_transform(GUIElement *element);
#endif // _GUI_H_ #endif // _GUI_H_

View File

@ -12,6 +12,11 @@
#include "client/window.h" #include "client/window.h"
#include "day.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 { typedef struct {
int key; int key;
bool state; bool state;
@ -65,12 +70,6 @@ static bool key_listener(KeyListener *listener)
return !(listener->state = (glfwGetKey(window.handle, listener->key) == GLFW_PRESS)) && was; 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() void input_init()
{ {
pause_menu = gui_add(NULL, (GUIElementDefinition) { pause_menu = gui_add(NULL, (GUIElementDefinition) {
@ -97,7 +96,7 @@ void input_init()
.scale = {1.0f, 1.0f}, .scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT, .scale_type = SCALE_TEXT,
.affect_parent_scale = false, .affect_parent_scale = false,
.text = strdup(""), .text = "",
.image = NULL, .image = NULL,
.text_color = {1.0f, 0.91f, 0.13f, 0.0f}, .text_color = {1.0f, 0.91f, 0.13f, 0.0f},
.bg_color = {0.0f, 0.0f, 0.0f, 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); pthread_rwlock_wrlock(&client_player.lock_movement);
client_player.movement.flight = !client_player.movement.flight; client_player.movement.flight = !client_player.movement.flight;
char *msg; SET_STATUS_MESSAGE("Flight %s", client_player.movement.flight ? "Enabled" : "Disabled")
asprintf(&msg, "Flight %s", client_player.movement.flight ? "Enabled" : "Disabled");
set_status_message(msg);
debug_menu_changed(ENTRY_FLIGHT); debug_menu_changed(ENTRY_FLIGHT);
pthread_rwlock_unlock(&client_player.lock_movement); pthread_rwlock_unlock(&client_player.lock_movement);
@ -149,9 +146,7 @@ void input_tick(f64 dtime)
pthread_rwlock_wrlock(&client_player.lock_movement); pthread_rwlock_wrlock(&client_player.lock_movement);
client_player.movement.collision = !client_player.movement.collision; client_player.movement.collision = !client_player.movement.collision;
char *msg; SET_STATUS_MESSAGE("Collision %s", client_player.movement.collision ? "Enabled" : "Disabled")
asprintf(&msg, "Collision %s", client_player.movement.collision ? "Enabled" : "Disabled");
set_status_message(msg);
debug_menu_changed(ENTRY_COLLISION); debug_menu_changed(ENTRY_COLLISION);
pthread_rwlock_unlock(&client_player.lock_movement); pthread_rwlock_unlock(&client_player.lock_movement);
@ -162,9 +157,7 @@ void input_tick(f64 dtime)
timelapse = !timelapse; timelapse = !timelapse;
set_time_of_day(current_time); set_time_of_day(current_time);
char *msg; SET_STATUS_MESSAGE("Timelapse %s", timelapse ? "Enabled" : "Disabled")
asprintf(&msg, "Timelapse %s", timelapse ? "Enabled" : "Disabled");
set_status_message(msg);
debug_menu_changed(ENTRY_TIMELAPSE); debug_menu_changed(ENTRY_TIMELAPSE);
} }
@ -173,9 +166,7 @@ void input_tick(f64 dtime)
if (key_listener(&listener_screenshot)) { if (key_listener(&listener_screenshot)) {
char *screenshot_filename = game_take_screenshot(); char *screenshot_filename = game_take_screenshot();
char *msg; SET_STATUS_MESSAGE("Screenshot saved to %s", screenshot_filename)
asprintf(&msg, "Screenshot saved to %s", screenshot_filename);
set_status_message(msg);
free(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); 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_x * M_PI / 180.0f / 8.0f;
entity->data.rot.y -= (f32) delta_y * 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 = fmod(entity->data.rot.y + 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.x = f32_clamp(entity->data.rot.x, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f);
client_player_update_rot(entity); client_player_update_rot(entity);
pthread_rwlock_unlock(&entity->lock_pos_rot); pthread_rwlock_unlock(&entity->lock_pos_rot);

35
src/client/light.c Normal file
View File

@ -0,0 +1,35 @@
#include <linmath.h/linmath.h>
#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
}

19
src/client/light.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _LIGHT_H_
#define _LIGHT_H_
#include <GL/glew.h>
#include <GL/gl.h>
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

View File

@ -1,32 +1,33 @@
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include "client/gl_debug.h"
#include "client/mesh.h" #include "client/mesh.h"
// upload data to GPU (only done once) // upload data to GPU (only done once)
void mesh_upload(Mesh *mesh) void mesh_upload(Mesh *mesh)
{ {
glGenVertexArrays(1, &mesh->vao); glGenVertexArrays(1, &mesh->vao); GL_DEBUG
glGenBuffers(1, &mesh->vbo); glGenBuffers(1, &mesh->vbo); GL_DEBUG
glBindVertexArray(mesh->vao); glBindVertexArray(mesh->vao); GL_DEBUG
glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); GL_DEBUG
glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->layout->size, 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; size_t offset = 0;
for (GLuint i = 0; i < mesh->layout->count; i++) { for (GLuint i = 0; i < mesh->layout->count; i++) {
VertexAttribute *attrib = &mesh->layout->attributes[i]; VertexAttribute *attrib = &mesh->layout->attributes[i];
glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE, glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE,
mesh->layout->size, (GLvoid *) offset); mesh->layout->size, (GLvoid *) offset); GL_DEBUG
glEnableVertexAttribArray(i); glEnableVertexAttribArray(i); GL_DEBUG
offset += attrib->size; offset += attrib->size;
} }
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); GL_DEBUG
glBindVertexArray(0); glBindVertexArray(0); GL_DEBUG
if (mesh->free_data) if (mesh->free_data)
free(mesh->data); free(mesh->data);
@ -40,8 +41,8 @@ void mesh_render(Mesh *mesh)
mesh_upload(mesh); mesh_upload(mesh);
// render // render
glBindVertexArray(mesh->vao); glBindVertexArray(mesh->vao); GL_DEBUG
glDrawArrays(GL_TRIANGLES, 0, mesh->count); glDrawArrays(GL_TRIANGLES, 0, mesh->count); GL_DEBUG
} }
void mesh_destroy(Mesh *mesh) void mesh_destroy(Mesh *mesh)
@ -49,11 +50,13 @@ void mesh_destroy(Mesh *mesh)
if (mesh->data && mesh->free_data) if (mesh->data && mesh->free_data)
free(mesh->data); free(mesh->data);
if (mesh->vao) if (mesh->vao) {
glDeleteVertexArrays(1, &mesh->vao); glDeleteVertexArrays(1, &mesh->vao); GL_DEBUG
}
if (mesh->vbo) if (mesh->vbo) {
glDeleteBuffers(1, &mesh->vbo); glDeleteBuffers(1, &mesh->vbo); GL_DEBUG
}
mesh->vao = mesh->vbo = 0; mesh->vao = mesh->vbo = 0;
} }

View File

@ -5,6 +5,7 @@
#include "client/camera.h" #include "client/camera.h"
#include "client/client_config.h" #include "client/client_config.h"
#include "client/frustum.h" #include "client/frustum.h"
#include "client/gl_debug.h"
#include "client/model.h" #include "client/model.h"
typedef struct { typedef struct {
@ -13,7 +14,8 @@ typedef struct {
} ModelBatchTexture; } ModelBatchTexture;
static List scene; static List scene;
static pthread_rwlock_t lock_scene; static List scene_new;
static pthread_mutex_t lock_scene_new;
static GLint units; static GLint units;
// fixme: blending issues still occur // 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++) { for (size_t i = 0; i < node->meshes.siz; i++) {
ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i]; ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
glUseProgram(mesh->shader->prog); glUseProgram(mesh->shader->prog); GL_DEBUG
glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); GL_DEBUG
// bind textures // bind textures
for (GLuint i = 0; i < mesh->num_textures; i++) for (GLuint i = 0; i < mesh->num_textures; i++) {
glBindTextureUnit(i, mesh->textures[i]); glBindTextureUnit(i, mesh->textures[i]); GL_DEBUG
}
mesh_render(mesh->mesh); 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) static void free_node_meshes(ModelNode *node)
@ -79,7 +82,7 @@ static void free_node_meshes(ModelNode *node)
free(mesh->mesh); 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) static void delete_node(ModelNode *node)
@ -90,7 +93,7 @@ static void delete_node(ModelNode *node)
if (mesh->textures) if (mesh->textures)
free(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); array_clr(&node->meshes);
free(node); free(node);
@ -121,7 +124,7 @@ static ModelNode *clone_node(ModelNode *original, ModelNode *parent)
for (size_t i = 0; i < node->meshes.siz; i++) for (size_t i = 0; i < node->meshes.siz; i++)
clone_mesh(&((ModelMesh *) node->meshes.ptr)[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; return node;
} }
@ -132,13 +135,15 @@ static int cmp_model(const Model *model, const f32 *distance)
static void render_model(Model *model) static void render_model(Model *model)
{ {
if (model->flags.wireframe) if (model->flags.wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); GL_DEBUG
}
render_node(model->root); render_node(model->root);
if (model->flags.wireframe) if (model->flags.wireframe) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); GL_DEBUG
}
} }
// step model help im stuck // step model help im stuck
@ -172,15 +177,19 @@ static void model_step(Model *model, Tree *transparent, f64 dtime)
void model_init() void model_init()
{ {
list_ini(&scene); list_ini(&scene);
pthread_rwlock_init(&lock_scene, NULL); list_ini(&scene_new);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
pthread_mutex_init(&lock_scene_new, NULL);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units); GL_DEBUG
} }
// ded // ded
void model_deinit() void model_deinit()
{ {
list_clr(&scene, &model_delete, NULL, NULL); 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 // Model functions
@ -190,6 +199,7 @@ Model *model_create()
Model *model = malloc(sizeof *model); Model *model = malloc(sizeof *model);
model->root = model_node_create(NULL); model->root = model_node_create(NULL);
model->extra = NULL; model->extra = NULL;
model->replace = NULL;
model->callbacks.step = NULL; model->callbacks.step = NULL;
model->callbacks.delete = NULL; model->callbacks.delete = NULL;
@ -272,11 +282,6 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model
cursor += n; cursor += n;
else else
fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count); 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) { } else if (strcmp(key, "cube") == 0) {
char texture[length + 1]; char texture[length + 1];
@ -313,6 +318,7 @@ Model *model_load(const char *path, const char *textures_path, Mesh *cube, Model
fclose(file); fclose(file);
array_clr(&stack); array_clr(&stack);
transform_node(model->root);
return model; return model;
} }
@ -346,15 +352,16 @@ void model_get_bones(Model *model, ModelBoneMapping *mappings, size_t num_mappin
name = cursor = strdup(mappings[i].name); name = cursor = strdup(mappings[i].name);
ModelNode *node = model->root; 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; cursor = NULL;
} }
if (node) if (node)
*mappings[i].node = node; *mappings[i].node = node;
else else
fprintf(stderr, "[warning] no such bone: %s\n", name); fprintf(stderr, "[warning] no such bone: %s\n", mappings[i].name);
free(name); free(name);
} }
@ -370,7 +377,6 @@ ModelNode *model_node_create(ModelNode *parent)
node->pos = (v3f32) {0.0f, 0.0f, 0.0f}; node->pos = (v3f32) {0.0f, 0.0f, 0.0f};
node->rot = (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->scale = (v3f32) {1.0f, 1.0f, 1.0f};
node->angle = 0.0f;
array_ini(&node->meshes, sizeof(ModelMesh), 0); array_ini(&node->meshes, sizeof(ModelMesh), 0);
init_node(node, parent); init_node(node, parent);
return node; return node;
@ -378,22 +384,22 @@ ModelNode *model_node_create(ModelNode *parent)
void model_node_transform(ModelNode *node) void model_node_transform(ModelNode *node)
{ {
mat4x4_identity(node->rel);
mat4x4_translate(node->rel, mat4x4_translate(node->rel,
node->pos.x, node->pos.x,
node->pos.y, node->pos.y,
node->pos.z); 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, mat4x4_scale_aniso(node->rel, node->rel,
node->scale.x, node->scale.x,
node->scale.y, node->scale.y,
node->scale.z); 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); 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) void model_scene_add(Model *model)
{ {
pthread_rwlock_wrlock(&lock_scene); pthread_mutex_lock(&lock_scene_new);
list_apd(&scene, model); list_apd(&scene_new, model);
pthread_rwlock_unlock(&lock_scene); pthread_mutex_unlock(&lock_scene_new);
} }
void model_scene_render(f64 dtime) 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 transparent;
tree_ini(&transparent); tree_ini(&transparent);
pthread_rwlock_rdlock(&lock_scene);
for (ListNode **node = &scene.fst; *node != NULL;) { for (ListNode **node = &scene.fst; *node != NULL;) {
Model *model = (*node)->dat; Model *model = (*node)->dat;
pthread_rwlock_unlock(&lock_scene);
if (model->flags.delete) { if (model->flags.delete) {
if (model->replace)
(*node)->dat = model->replace;
else
list_nrm(&scene, node);
model_delete(model); model_delete(model);
pthread_rwlock_wrlock(&lock_scene);
list_nrm(&scene, node);
pthread_rwlock_unlock(&lock_scene);
pthread_rwlock_rdlock(&lock_scene);
} else { } else {
model_step(model, &transparent, dtime);
pthread_rwlock_rdlock(&lock_scene);
node = &(*node)->nxt; node = &(*node)->nxt;
model_step(model, &transparent, dtime);
} }
} }
pthread_rwlock_unlock(&lock_scene);
tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER); tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER);
} }

View File

@ -28,7 +28,6 @@ typedef struct ModelNode {
char *name; char *name;
bool visible; bool visible;
v3f32 pos, rot, scale; v3f32 pos, rot, scale;
f32 angle;
mat4x4 abs, rel; mat4x4 abs, rel;
Array meshes; Array meshes;
struct ModelNode *parent; struct ModelNode *parent;
@ -52,6 +51,7 @@ typedef struct Model {
void *extra; void *extra;
aabb3f32 box; aabb3f32 box;
f32 distance; f32 distance;
struct Model *replace;
struct { struct {
void (*step)(struct Model *model, f64 dtime); void (*step)(struct Model *model, f64 dtime);
void (*delete)(struct Model *model); void (*delete)(struct Model *model);

View File

@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "client/gl_debug.h"
#include "client/shader.h" #include "client/shader.h"
static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *definitions) 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); 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) // 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 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, 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; GLint success;
glGetShaderiv(id, GL_COMPILE_STATUS, &success); glGetShaderiv(id, GL_COMPILE_STATUS, &success); GL_DEBUG
if (!success) { if (!success) {
char errbuf[BUFSIZ]; 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); fprintf(stderr, "[error] failed to compile %s shader: %s", name, errbuf);
glDeleteShader(id); glDeleteShader(id); GL_DEBUG
return 0; return 0;
} }
glAttachShader(program, id); glAttachShader(program, id); GL_DEBUG
return id; return id;
} }
bool shader_program_create(const char *path, GLuint *idptr, const char *definitions) bool shader_program_create(const char *path, GLuint *idptr, const char *definitions)
{ {
GLuint id = glCreateProgram(); GLuint id = glCreateProgram(); GL_DEBUG
if (!definitions) if (!definitions)
definitions = ""; definitions = "";
@ -91,27 +92,27 @@ bool shader_program_create(const char *path, GLuint *idptr, const char *definiti
GLuint vert, frag; GLuint vert, frag;
if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) { if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) {
glDeleteProgram(id); glDeleteProgram(id); GL_DEBUG
return false; return false;
} }
if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) { if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) {
glDeleteShader(vert); glDeleteShader(vert); GL_DEBUG
glDeleteProgram(id); glDeleteProgram(id); GL_DEBUG
return false; return false;
} }
glLinkProgram(id); glLinkProgram(id); GL_DEBUG
glDeleteShader(vert); glDeleteShader(vert); GL_DEBUG
glDeleteShader(frag); glDeleteShader(frag); GL_DEBUG
GLint success; GLint success;
glGetProgramiv(id, GL_LINK_STATUS, &success); glGetProgramiv(id, GL_LINK_STATUS, &success); GL_DEBUG
if (!success) { if (!success) {
char errbuf[BUFSIZ]; 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); fprintf(stderr, "[error] failed to link shader program: %s\n", errbuf);
glDeleteProgram(id); glDeleteProgram(id); GL_DEBUG
return false; return false;
} }

View File

@ -4,6 +4,7 @@
#include "client/camera.h" #include "client/camera.h"
#include "client/client.h" #include "client/client.h"
#include "client/cube.h" #include "client/cube.h"
#include "client/gl_debug.h"
#include "client/mesh.h" #include "client/mesh.h"
#include "client/shader.h" #include "client/shader.h"
#include "client/sky.h" #include "client/sky.h"
@ -90,10 +91,10 @@ bool sky_init()
return false; 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_VP = glGetUniformLocation(skybox_prog, "VP"); GL_DEBUG
skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight"); skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight"); GL_DEBUG
skybox_texture_day = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/day")->txo; 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_texture_night = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/night")->txo;
skybox_mesh.data = skybox_vertices; skybox_mesh.data = skybox_vertices;
@ -106,7 +107,7 @@ bool sky_init()
return false; 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; sun_texture = texture_load(RESSOURCE_PATH "textures/sun.png", false)->txo;
// clouds // clouds
@ -116,8 +117,8 @@ bool sky_init()
return false; return false;
} }
clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP"); clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP"); GL_DEBUG
clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight"); clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight"); GL_DEBUG
clouds_mesh.data = clouds_vertices; clouds_mesh.data = clouds_vertices;
mesh_upload(&clouds_mesh); mesh_upload(&clouds_mesh);
@ -126,13 +127,13 @@ bool sky_init()
void sky_deinit() void sky_deinit()
{ {
glDeleteProgram(sun_prog); glDeleteProgram(sun_prog); GL_DEBUG
mesh_destroy(&sun_mesh); mesh_destroy(&sun_mesh);
glDeleteProgram(skybox_prog); glDeleteProgram(skybox_prog); GL_DEBUG
mesh_destroy(&skybox_mesh); mesh_destroy(&skybox_mesh);
glDeleteProgram(clouds_prog); glDeleteProgram(clouds_prog); GL_DEBUG
mesh_destroy(&clouds_mesh); mesh_destroy(&clouds_mesh);
} }
@ -161,27 +162,27 @@ void sky_render()
mat4x4 mvp; mat4x4 mvp;
mat4x4_mul(mvp, vp, model); mat4x4_mul(mvp, vp, model);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE); GL_DEBUG
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL); GL_DEBUG
glUseProgram(skybox_prog); glUseProgram(skybox_prog); GL_DEBUG
glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]); glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG
glUniform1f(skybox_loc_daylight, daylight); glUniform1f(skybox_loc_daylight, daylight); GL_DEBUG
glBindTextureUnit(0, skybox_texture_day); glBindTextureUnit(0, skybox_texture_day); GL_DEBUG
glBindTextureUnit(1, skybox_texture_night); glBindTextureUnit(1, skybox_texture_night); GL_DEBUG
mesh_render(&skybox_mesh); mesh_render(&skybox_mesh);
glUseProgram(sun_prog); glUseProgram(sun_prog); GL_DEBUG
glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]); glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]); GL_DEBUG
glBindTextureUnit(0, sun_texture); glBindTextureUnit(0, sun_texture); GL_DEBUG
mesh_render(&sun_mesh); mesh_render(&sun_mesh);
glUseProgram(clouds_prog); glUseProgram(clouds_prog); GL_DEBUG
glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]); glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG
glUniform1f(clouds_loc_daylight, daylight); glUniform1f(clouds_loc_daylight, daylight); GL_DEBUG
glBindTextureUnit(0, skybox_texture_day); glBindTextureUnit(0, skybox_texture_day); GL_DEBUG
mesh_render(&clouds_mesh); mesh_render(&clouds_mesh);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS); GL_DEBUG
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE); GL_DEBUG
} }

View File

@ -2,15 +2,15 @@
#include <linmath.h/linmath.h> #include <linmath.h/linmath.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "client/camera.h"
#include "client/client_config.h" #include "client/client_config.h"
#include "client/client_node.h" #include "client/client_node.h"
#include "client/client_terrain.h" #include "client/client_terrain.h"
#include "client/cube.h" #include "client/cube.h"
#include "client/frustum.h" #include "client/frustum.h"
#include "client/gl_debug.h"
#include "client/light.h"
#include "client/shader.h" #include "client/shader.h"
#include "client/terrain_gfx.h" #include "client/terrain_gfx.h"
#include "day.h"
typedef struct { typedef struct {
bool visible; bool visible;
@ -51,14 +51,9 @@ static v3f32 center_offset = {
}; };
static GLuint shader_prog; static GLuint shader_prog;
static GLint loc_model;
static GLint loc_VP; 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 ModelShader model_shader;
static inline bool cull_face(NodeType self, NodeType nbr) 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() bool terrain_gfx_init()
{ {
GLint texture_units; GLint texture_units;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); GL_DEBUG
char *shader_defs; char *shader_defs;
asprintf(&shader_defs, asprintf(&shader_defs,
@ -212,58 +207,39 @@ bool terrain_gfx_init()
client_config.view_distance 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"); fprintf(stderr, "[error] failed to create terrain shader program\n");
return false; return false;
} }
free(shader_defs); free(shader_defs);
loc_model = glGetUniformLocation(shader_prog, "model"); loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG
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");
GLint texture_indices[texture_units]; GLint texture_indices[texture_units];
for (GLint i = 0; i < texture_units; i++) for (GLint i = 0; i < texture_units; i++)
texture_indices[i] = 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.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; return true;
} }
void terrain_gfx_deinit() void terrain_gfx_deinit()
{ {
glDeleteProgram(shader_prog); glDeleteProgram(shader_prog); GL_DEBUG
} }
void terrain_gfx_update() void terrain_gfx_update()
{ {
vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f}; glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
vec4 sunlight_dir; light_shader_update(&light_shader);
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);
} }
void terrain_gfx_make_chunk_model(TerrainChunk *chunk) 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); model_node_transform(model->root);
} }
meta->model->replace = model;
meta->model->flags.delete = 1; meta->model->flags.delete = 1;
} else if (model) {
model_scene_add(model);
} }
meta->model = model; meta->model = model;
if (model)
model_scene_add(model);
pthread_mutex_unlock(&chunk->mtx); pthread_mutex_unlock(&chunk->mtx);
} }

View File

@ -1,8 +1,11 @@
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb/stb_image.h> #include <stb/stb_image.h>
#include <stb/stb_image_resize.h>
#include <stdbool.h> #include <stdbool.h>
#include <dragonstd/tree.h> #include <dragonstd/tree.h>
#include "client/client_config.h" #include "client/client_config.h"
#include "client/gl_debug.h"
#include "client/texture.h" #include "client/texture.h"
static Tree textures; static Tree textures;
@ -22,7 +25,7 @@ static bool lookup_texture(char *path, Texture **texture)
TreeNode **node = tree_nfd(&textures, path, &cmp_texture); TreeNode **node = tree_nfd(&textures, path, &cmp_texture);
if (*node) { if (*node) {
*texture = &((TextureLookup *) &(*node)->dat)->texture; *texture = &((TextureLookup *) (*node)->dat)->texture;
return true; return true;
} }
@ -70,14 +73,31 @@ Texture *texture_load(char *path, bool mipmap)
return texture; 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_load_cubemap(char *path)
{ {
Texture *texture; Texture *texture;
if (lookup_texture(path, &texture)) if (lookup_texture(path, &texture))
return texture; return texture;
glGenTextures(1, &texture->txo); glGenTextures(1, &texture->txo); GL_DEBUG
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); GL_DEBUG
const char *directions[6] = { const char *directions[6] = {
"right", "right",
@ -88,48 +108,77 @@ Texture *texture_load_cubemap(char *path)
"back", "back",
}; };
typedef struct {
unsigned char *data;
int width, height, channels;
} CubemapFace;
CubemapFace faces[6];
int size = 1;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1]; char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
sprintf(filename, "%s/%s.png", path, directions[i]); sprintf(filename, "%s/%s.png", path, directions[i]);
unsigned char *data = stbi_load(filename, if (!(faces[i].data = stbi_load(filename,
&texture->width, &texture->height, &texture->channels, 0); &faces[i].width, &faces[i].height, &faces[i].channels, 0))) {
if (!data) {
fprintf(stderr, "[error] failed to load texture %s\n", filename); fprintf(stderr, "[error] failed to load texture %s\n", filename);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, size = least_common_multiple(size, faces[i].width);
texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); size = least_common_multiple(size, faces[i].height);
stbi_image_free(data);
} }
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); for (int i = 0; i < 6; i++) {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); unsigned char *data = faces[i].data;
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); bool resize = faces[i].width != size || faces[i].height != size;
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 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,
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_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; return texture;
} }
void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap) void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap)
{ {
glGenTextures(1, &texture->txo); glGenTextures(1, &texture->txo); GL_DEBUG
glBindTexture(GL_TEXTURE_2D, texture->txo); glBindTexture(GL_TEXTURE_2D, texture->txo); GL_DEBUG
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap)
? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); GL_DEBUG
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); GL_DEBUG
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); GL_DEBUG
glTexImage2D(GL_TEXTURE_2D, 0, format, glTexImage2D(GL_TEXTURE_2D, 0, format,
texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); GL_DEBUG
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D); GL_DEBUG
} }
void texture_destroy(Texture *texture) void texture_destroy(Texture *texture)
{ {
glDeleteTextures(1, &texture->txo); glDeleteTextures(1, &texture->txo); GL_DEBUG
} }

View File

@ -4,6 +4,7 @@
#include "client/client_config.h" #include "client/client_config.h"
#include "client/debug_menu.h" #include "client/debug_menu.h"
#include "client/game.h" #include "client/game.h"
#include "client/gl_debug.h"
#include "client/gui.h" #include "client/gui.h"
#include "client/input.h" #include "client/input.h"
#include "client/window.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) 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.width = width;
window.height = height; window.height = height;

View File

@ -19,6 +19,7 @@ define hook-stop
quit quit
end end
end end
break gl_error
" "
echo "$COMMON echo "$COMMON

View File

@ -90,5 +90,5 @@ static void delete_schematic_node(SchematicNode *node)
void schematic_delete(List *schematic) void schematic_delete(List *schematic)
{ {
list_clr(schematic, (void *) &delete_schematic_node, NULL, NULL); list_clr(schematic, &delete_schematic_node, NULL, NULL);
} }

View File

@ -34,15 +34,7 @@ static void on_ToServerSetnode(__attribute__((unused)) DragonnetPeer *peer, ToSe
// update player's position // update player's position
static void on_ToServerPosRot(DragonnetPeer *peer, ToServerPosRot *pkt) static void on_ToServerPosRot(DragonnetPeer *peer, ToServerPosRot *pkt)
{ {
ServerPlayer *player = peer->extra; server_player_move(peer->extra, pkt->pos, pkt->rot);
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);
} }
// tell server map manager client requested the chunk // tell server map manager client requested the chunk

View File

@ -14,6 +14,45 @@
static Map players; static Map players;
static Map players_named; 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 // main thread
// called on server shutdown // called on server shutdown
static void player_drop(ServerPlayer *player) static void player_drop(ServerPlayer *player)
@ -71,17 +110,9 @@ static void player_spawn(ServerPlayer *player)
.gravity = server_config.movement.gravity, .gravity = server_config.movement.gravity,
.jump = server_config.movement.jump, .jump = server_config.movement.jump,
}); });
dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) {
.type = ENTITY_LOCALPLAYER, server_player_iterate(&send_entity_add, player);
.data = { server_player_iterate(&send_entity_add_existing, player);
.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,
},
});
} }
// any thread // any thread
@ -169,8 +200,12 @@ void server_player_remove(DragonnetPeer *peer)
// (we don't want disconnect messages for every player on server shutdown) // (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)) if (map_del(&players, &player->id, &cmp_player_id, &refcount_drp, NULL, NULL))
printf("[access] disconnected %s\n", player->name); 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 // peer no longer has a reference to player
refcount_drp(&player->rc); refcount_drp(&player->rc);
@ -224,6 +259,16 @@ bool server_player_auth(ServerPlayer *player, char *name)
return success; 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 // any thread
void server_player_disconnect(ServerPlayer *player) void server_player_disconnect(ServerPlayer *player)
{ {

View File

@ -34,6 +34,7 @@ ServerPlayer *server_player_grab_named(char *name);
bool server_player_auth(ServerPlayer *player, char *name); bool server_player_auth(ServerPlayer *player, char *name);
void server_player_disconnect(ServerPlayer *player); void server_player_disconnect(ServerPlayer *player);
void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot);
void server_player_iterate(void *func, void *arg); void server_player_iterate(void *func, void *arg);
#endif // _SERVER_PLAYER_H_ #endif // _SERVER_PLAYER_H_

View File

@ -72,7 +72,7 @@ static void send_chunk_to_near(TerrainChunk *chunk)
if (meta->state == CHUNK_CREATED) if (meta->state == CHUNK_CREATED)
return; return;
server_player_iterate((void *) &send_chunk, chunk); server_player_iterate(&send_chunk, chunk);
} }
// Iterator for sending changed chunks to near clients // Iterator for sending changed chunks to near clients
@ -104,7 +104,7 @@ static void terrain_gen_step()
meta->state = CHUNK_READY; meta->state = CHUNK_READY;
pthread_mutex_unlock(&chunk->mtx); 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); pthread_mutex_lock(&mtx_num_gen_chunks);
num_gen_chunks--; num_gen_chunks--;
@ -276,7 +276,7 @@ static void generate_spawn_hut()
} }
Blob_free(&wood_color); 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 // public functions

View File

@ -46,7 +46,7 @@ Voxelctx *voxelctx_create(List *changed_chunks, TerrainGenStage tgs, v3s32 pos)
void voxelctx_delete(Voxelctx *ctx) void voxelctx_delete(Voxelctx *ctx)
{ {
list_clr(&ctx->statestack, (void *) &free, NULL, NULL); list_clr(&ctx->statestack, &free, NULL, NULL);
free(ctx); free(ctx);
} }

View File

@ -15,7 +15,7 @@ static void delete_chunk(TerrainChunk *chunk, Terrain *terrain)
static void delete_sector(TerrainSector *sector, Terrain *terrain) static void delete_sector(TerrainSector *sector, Terrain *terrain)
{ {
tree_clr(&sector->chunks, (void *) &delete_chunk, terrain, NULL, 0); tree_clr(&sector->chunks, &delete_chunk, terrain, NULL, 0);
pthread_rwlock_destroy(&sector->lock); pthread_rwlock_destroy(&sector->lock);
free(sector); free(sector);
} }
@ -32,7 +32,7 @@ Terrain *terrain_create()
void terrain_delete(Terrain *terrain) 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->lock);
pthread_rwlock_destroy(&terrain->cache_lock); pthread_rwlock_destroy(&terrain->cache_lock);
free(terrain); free(terrain);

View File

@ -23,8 +23,6 @@ EntityData
u64 id u64 id
v3f64 pos v3f64 pos
v3f32 rot v3f32 rot
aabb3f32 box
v3f32 eye
String nametag String nametag
; server packets ; server packets
@ -82,11 +80,6 @@ pkt ToClientEntityUpdatePosRot
v3f64 pos v3f64 pos
v3f32 rot v3f32 rot
pkt ToClientEntityUpdateBoxEye
u64 id
aabb3f32 box
v3f32 eye
pkt ToClientEntityUpdateNametag pkt ToClientEntityUpdateNametag
u64 id u64 id
String nametag String nametag

View File

@ -3,7 +3,7 @@ execute_process(COMMAND git tag --points-at HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
if ("${GIT_VERSION}" STREQUAL "") if("${GIT_VERSION}" STREQUAL "")
execute_process(COMMAND git rev-parse --short HEAD execute_process(COMMAND git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_VERSION OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB