name player scale 1 1.8 1
- name head pos 0 0.875 0 scale 0.45 0.25 0.45 cube head
- name body scale 0.48 0.75 0.36
- name upper pos 0 1.0 0 scale 1 0.5 1
+ name nametag pos 0 1.1 0
+ name neck pos 0 0.75 0 scale 0.45 0.25 0.45
+ name head pos 0 +0.5 0 cube head
+ name eyes pos 0 0 +0.5
+ name body scale 0.48 0.75 0.225
+ name upper pos 0 1.0 0 scale 1 0.5 1
name chest pos 0 -0.5 0 cube chest
name shoulders scale 0.5 1 1
name left pos -1.5 0 0
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+in vec3 fragmentPosition;
+in vec3 fragmentNormal;
+in vec2 fragmentTextureCoordinates;
+in float fragmentTextureIndex;
+in vec3 fragmentColor;
+
+out vec4 outColor;
+
+uniform vec3 fogColor;
+uniform vec3 cameraPos;
+uniform sampler2D textures[MAX_TEXTURE_UNITS];
+
+void main()
+{
+ outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoordinates) * vec4(fragmentColor, 1.0);
+ outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0));
+
+ if (outColor.a == 0.0)
+ discard;
+}
--- /dev/null
+layout(location = 0) in vec3 vertexPosition;
+layout(location = 1) in vec3 vertexNormal;
+layout(location = 2) in vec2 vertexTextureCoordinates;
+layout(location = 3) in float vertexTextureIndex;
+layout(location = 4) in vec3 vertexColor;
+
+out vec3 fragmentPosition;
+out vec3 fragmentNormal;
+out vec2 fragmentTextureCoordinates;
+out float fragmentTextureIndex;
+out vec3 fragmentColor;
+
+uniform mat4 model;
+uniform mat4 VP;
+uniform float daylight;
+uniform float ambientLight;
+uniform vec3 lightDir;
+
+void main()
+{
+ vec4 worldSpace = model * vec4(vertexPosition, 1.0);
+ gl_Position = VP * worldSpace;
+
+ fragmentPosition = worldSpace.xyz;
+ fragmentNormal = vertexNormal;
+ fragmentTextureCoordinates = vertexTextureCoordinates;
+ fragmentTextureIndex = vertexTextureIndex;
+ fragmentColor = vertexColor;
+
+ float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0);
+ float light = ambientLight + diffuseLight;
+
+ fragmentColor *= light;
+}
-in vec2 fragmentTextureCoords;
+in vec2 fragmentTextureCoordinates;
out vec4 outColor;
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;
}
layout(location = 0) in vec2 vertexPosition;
-layout(location = 1) in vec2 vertexTextureCoords;
+layout(location = 1) in vec2 vertexTextureCoordinates;
-out vec2 fragmentTextureCoords;
+out vec2 fragmentTextureCoordinates;
uniform mat4 model;
uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
- fragmentTextureCoords = vertexTextureCoords;
+ fragmentTextureCoordinates = vertexTextureCoordinates;
}
-in vec2 fragmentTextureCoords;
+in vec2 fragmentTextureCoordinates;
out vec4 outColor;
void main()
{
- outColor = texture(texture0, fragmentTextureCoords);
+ outColor = texture(texture0, fragmentTextureCoordinates);
}
layout(location = 0) in vec2 vertexPosition;
-layout(location = 1) in vec2 vertexTextureCoords;
+layout(location = 1) in vec2 vertexTextureCoordinates;
-out vec2 fragmentTextureCoords;
+out vec2 fragmentTextureCoordinates;
uniform mat4 model;
uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
- fragmentTextureCoords = vertexTextureCoords;
+ fragmentTextureCoordinates = vertexTextureCoordinates;
}
-in vec3 fragmentTextureCoords;
+in vec3 fragmentTextureCoordinates;
out vec4 outColor;
void main()
{
- float height = normalize(fragmentTextureCoords).y;
+ float height = normalize(fragmentTextureCoordinates).y;
vec4 topColor = texture(texture0, vec3(0.0, 1.0, 0.0));
vec4 bottomColor = texture(texture0, vec3(1.0, 0.11, 0.5));
vec4 expectedColor = mix(bottomColor, topColor, height);
- vec4 dayColor = texture(texture0, fragmentTextureCoords);
+ vec4 dayColor = texture(texture0, fragmentTextureCoordinates);
float cloudFactor = reverseMix(length(dayColor.rg - expectedColor.rg), 0.15, length(vec2(1.0)));
layout(location = 0) in vec3 vertexPosition;
-out vec3 fragmentTextureCoords;
+out vec3 fragmentTextureCoordinates;
uniform mat4 VP;
{
gl_Position = VP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w;
- fragmentTextureCoords = vertexPosition;
+ fragmentTextureCoordinates = vertexPosition;
}
-in vec3 fragmentTextureCoords;
+in vec3 fragmentTextureCoordinates;
out vec4 outColor;
vec4 topColor = texture(textures[0], vec3(0.0, 1.0, 0.0));
vec4 bottomColor = texture(textures[0], vec3(1.0, 0.11, 0.5));
- vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoords).y);
- vec4 nightColor = texture(textures[1], fragmentTextureCoords);
+ vec4 dayColor = mix(bottomColor, topColor, normalize(fragmentTextureCoordinates).y);
+ vec4 nightColor = texture(textures[1], fragmentTextureCoordinates);
outColor = mix(nightColor, dayColor, daylight);
}
layout(location = 0) in vec3 vertexPosition;
-out vec3 fragmentTextureCoords;
+out vec3 fragmentTextureCoordinates;
uniform mat4 VP;
{
gl_Position = VP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w;
- fragmentTextureCoords = vertexPosition;
+ fragmentTextureCoordinates = vertexPosition;
}
-in vec2 fragmentTextureCoords;
+in vec2 fragmentTextureCoordinates;
out vec4 outColor;
void main()
{
- outColor = texture(texture0, fragmentTextureCoords);
+ outColor = texture(texture0, fragmentTextureCoordinates);
}
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;
{
gl_Position = MVP * vec4(vertexPosition, 1.0);
gl_Position.z = gl_Position.w;
- fragmentTextureCoords = vertexTextureCoords;
+ fragmentTextureCoordinates = vertexTextureCoordinates;
}
+++ /dev/null
-in vec3 fragmentPosition;
-in vec3 fragmentNormal;
-in vec2 fragmentTextureCoords;
-in float fragmentTextureIndex;
-in vec3 fragmentColor;
-
-out vec4 outColor;
-
-uniform vec3 fogColor;
-uniform vec3 cameraPos;
-uniform sampler2D textures[MAX_TEXTURE_UNITS];
-
-void main()
-{
- outColor = texture(textures[int(fragmentTextureIndex + 0.5)], fragmentTextureCoords) * vec4(fragmentColor, 1.0);
- outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0));
-
- if (outColor.a == 0.0)
- discard;
-}
+++ /dev/null
-layout(location = 0) in vec3 vertexPosition;
-layout(location = 1) in vec3 vertexNormal;
-layout(location = 2) in vec2 vertexTextureCoords;
-layout(location = 3) in float vertexTextureIndex;
-layout(location = 4) in vec3 vertexColor;
-
-out vec3 fragmentPosition;
-out vec3 fragmentNormal;
-out vec2 fragmentTextureCoords;
-out float fragmentTextureIndex;
-out vec3 fragmentColor;
-
-uniform mat4 model;
-uniform mat4 VP;
-uniform float daylight;
-uniform float ambientLight;
-uniform vec3 lightDir;
-
-void main()
-{
- vec4 worldSpace = model * vec4(vertexPosition, 1.0);
- gl_Position = VP * worldSpace;
-
- fragmentPosition = worldSpace.xyz;
- fragmentNormal = vertexNormal;
- fragmentTextureCoords = vertexTextureCoords;
- fragmentTextureIndex = vertexTextureIndex;
- fragmentColor = vertexColor;
-
- float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0);
- float light = ambientLight + diffuseLight;
-
- fragmentColor *= light;
-}
cd .build/
mkdir build
cd build
-if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" && make clean && make -j$(nproc)); then
+if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" -DCMAKE_C_FLAGS="-Ofast" && make clean && make -j$(nproc)); then
cd ../..
rm -rf .build
exit 1
# Options
+if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
+ add_compile_definitions("ENABLE_GL_DEBUG")
+endif()
+
add_compile_definitions("USE_DRAGONNET")
add_compile_definitions("RESSOURCE_PATH=\"${RESSOURCE_PATH}\"")
# System specific options
-if ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD" OR "${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
link_directories("/usr/local/lib")
include_directories("/usr/local/include")
endif()
-if ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
link_directories("/usr/X11R6/lib")
include_directories("/usr/X11R6/include")
endif()
client/font.c
client/frustum.c
client/game.c
+ client/gl_debug.c
client/gui.c
client/input.c
+ client/light.c
client/mesh.c
client/model.c
client/shader.c
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityAdd ] = (void *) &client_entity_add;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityRemove ] = (void *) &client_entity_remove;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdatePosRot ] = (void *) &client_entity_update_pos_rot;
- client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateBoxEye ] = (void *) &client_entity_update_box_eye;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateNametag] = (void *) &client_entity_update_nametag;
flag_ini(&finish);
+#include <asprintf/asprintf.h>
#include <dragonstd/map.h>
#include <stdio.h>
#include <stdlib.h>
+#include "client/cube.h"
+#include "client/client_config.h"
#include "client/client_entity.h"
#include "client/client_player.h"
+#include "client/frustum.h"
+#include "client/gl_debug.h"
+#include "client/light.h"
+#include "client/shader.h"
+#include "client/window.h"
ClientEntityType client_entity_types[COUNT_ENTITY];
+ModelShader client_entity_shader;
+typedef struct {
+ v3f32 position;
+ v3f32 normal;
+} __attribute__((packed)) EntityVertex;
+Mesh client_entity_cube = {
+ .layout = &(VertexLayout) {
+ .attributes = (VertexAttribute[]) {
+ {GL_FLOAT, 3, sizeof(v3f32)}, // position
+ {GL_FLOAT, 3, sizeof(v3f32)}, // normal
+ },
+ .count = 2,
+ .size = sizeof(EntityVertex),
+ },
+ .vao = 0,
+ .vbo = 0,
+ .data = NULL,
+ .count = 36,
+ .free_data = false,
+};
+
+static GLuint shader_prog;
+static GLint loc_VP;
+static LightShader light_shader;
static Map entities;
+static List nametagged;
+static pthread_mutex_t mtx_nametagged;
// any thread
// called when adding, getting or removing an entity from the map
if (entity->type->remove)
entity->type->remove(entity);
+ if (entity->nametag) {
+ pthread_mutex_lock(&mtx_nametagged);
+ list_del(&nametagged, &entity->rc, &cmp_ref, &refcount_drp, NULL, NULL);
+ pthread_mutex_unlock(&mtx_nametagged);
+
+ entity->nametag->visible = false;
+ }
+
refcount_drp(&entity->rc);
}
free(entity->data.nametag);
pthread_rwlock_init(&entity->lock_pos_rot, NULL);
- pthread_rwlock_init(&entity->lock_box_eye, NULL);
pthread_rwlock_init(&entity->lock_nametag, NULL);
+ pthread_rwlock_init(&entity->lock_box_off, NULL);
free(entity);
}
+static void update_nametag(ClientEntity *entity)
+{
+ if (entity->nametag) {
+ gui_text(entity->nametag, entity->data.nametag);
+
+ if (!entity->data.nametag)
+ entity->nametag->visible = false;
+ } else if (entity->data.nametag) {
+ entity->nametag = gui_add(NULL, (GUIElementDefinition) {
+ .pos = {-1.0f, -1.0f},
+ .z_index = 0.1f,
+ .offset = {0, 0},
+ .margin = {4, 4},
+ .align = {0.5f, 0.5f},
+ .scale = {1.0f, 1.0f},
+ .scale_type = SCALE_TEXT,
+ .affect_parent_scale = false,
+ .text = entity->data.nametag,
+ .image = NULL,
+ .text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f},
+ .bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.5f},
+ });
+
+ pthread_mutex_lock(&mtx_nametagged);
+ list_apd(&nametagged, refcount_inc(&entity->rc));
+ pthread_mutex_unlock(&mtx_nametagged);
+ }
+}
+
+static void update_nametag_pos(ClientEntity *entity)
+{
+ if (!entity->data.nametag)
+ return;
+
+ pthread_rwlock_rdlock(&entity->lock_pos_rot);
+ pthread_rwlock_rdlock(&entity->lock_box_off);
+
+ mat4x4 mvp;
+ if (entity->nametag_offset)
+ mat4x4_mul(mvp, frustum, *entity->nametag_offset);
+ else
+ mat4x4_dup(mvp, frustum);
+
+ vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
+ mat4x4_mul_vec4(dst, mvp, src);
+
+ dst[0] /= dst[3];
+ dst[1] /= dst[3];
+ dst[2] /= dst[3];
+
+ if ((entity->nametag->visible = dst[2] >= -1.0f && dst[2] <= 1.0f)) {
+ entity->nametag->def.pos = (v2f32) {dst[0] * 0.5f + 0.5f, 1.0f - (dst[1] * 0.5f + 0.5f)};
+ gui_transform(entity->nametag);
+ }
+
+ pthread_rwlock_unlock(&entity->lock_box_off);
+ pthread_rwlock_unlock(&entity->lock_pos_rot);
+}
+
// main thread
// called on startup
void client_entity_init()
{
map_ini(&entities);
+ list_ini(&nametagged);
+ pthread_mutex_init(&mtx_nametagged, NULL);
}
// main thead
{
// forget all entities
map_cnl(&entities, &refcount_drp, NULL, NULL, 0);
+ list_clr(&nametagged, &refcount_drp, NULL, NULL);
+ pthread_mutex_destroy(&mtx_nametagged);
+}
+
+bool client_entity_gfx_init()
+{
+ char *shader_defs;
+ asprintf(&shader_defs, "#define VIEW_DISTANCE %lf\n", client_config.view_distance);
+
+ if (!shader_program_create(RESSOURCE_PATH "shaders/3d/entity", &shader_prog, shader_defs)) {
+ fprintf(stderr, "[error] failed to create entity shader program\n");
+ return false;
+ }
+
+ free(shader_defs);
+
+ loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG
+
+ EntityVertex vertices[6][6];
+ for (int f = 0; f < 6; f++) {
+ for (int v = 0; v < 6; v++) {
+ vertices[f][v].position = cube_vertices[f][v].position;
+ vertices[f][v].normal = cube_vertices[f][v].normal;
+ }
+ }
+
+ client_entity_cube.data = vertices;
+ mesh_upload(&client_entity_cube);
+
+ client_entity_shader.prog = shader_prog;
+ client_entity_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG
+
+ light_shader.prog = shader_prog;
+ light_shader_locate(&light_shader);
+
+ return true;
+}
+
+void client_entity_gfx_deinit()
+{
+ glDeleteProgram(shader_prog); GL_DEBUG
+ mesh_destroy(&client_entity_cube);
+}
+
+void client_entity_gfx_update()
+{
+ glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
+ light_shader_update(&light_shader);
+
+ pthread_mutex_lock(&mtx_nametagged);
+ list_itr(&nametagged, &update_nametag_pos, NULL, &refcount_obj);
+ pthread_mutex_unlock(&mtx_nametagged);
}
ClientEntity *client_entity_grab(u64 id)
if (!entity->model)
return;
- entity->model->root->pos = (v3f32) {entity->data.pos.x, entity->data.pos.y, entity->data.pos.z};
- entity->model->root->rot = (v3f32) {entity->data.rot.x, entity->data.rot.y, entity->data.rot.z};
+ entity->model->root->pos = v3f64_to_f32(entity->data.pos); // ToDo: the render pipeline needs to be updated to handle 64-bit positions
+ entity->model->root->rot = entity->data.rot;
if (entity->type->transform)
entity->type->transform(entity);
pkt->data.nametag = NULL;
entity->model = NULL;
-
- pthread_rwlock_init(&entity->lock_pos_rot, NULL);
- pthread_rwlock_init(&entity->lock_box_eye, NULL);
- pthread_rwlock_init(&entity->lock_nametag, NULL);
+ entity->nametag = NULL;
if (entity->type->add)
entity->type->add(entity);
+ update_nametag(entity);
+
+ pthread_rwlock_init(&entity->lock_pos_rot, NULL);
+ pthread_rwlock_init(&entity->lock_nametag, NULL);
+ pthread_rwlock_init(&entity->lock_box_off, NULL);
+
if (!map_add(&entities, &entity->data.id, &entity->rc, &cmp_entity, &refcount_inc))
fprintf(stderr, "[warning] failed to add entity %lu\n", entity->data.id);
if (entity->type->update_pos_rot)
entity->type->update_pos_rot(entity);
- pthread_rwlock_unlock(&entity->lock_pos_rot);
+ client_entity_transform(entity);
- refcount_drp(&entity->rc);
-}
-
-void client_entity_update_box_eye(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt)
-{
- ClientEntity *entity = client_entity_grab(pkt->id);
-
- if (!entity)
- return;
-
- pthread_rwlock_wrlock(&entity->lock_box_eye);
-
- entity->data.box = pkt->box;
- entity->data.eye = pkt->eye;
-
- if (entity->type->update_box_eye)
- entity->type->update_box_eye(entity);
-
- pthread_rwlock_unlock(&entity->lock_box_eye);
+ pthread_rwlock_unlock(&entity->lock_pos_rot);
refcount_drp(&entity->rc);
}
if (entity->type->update_nametag)
entity->type->update_nametag(entity);
+ update_nametag(entity);
pthread_rwlock_unlock(&entity->lock_nametag);
refcount_drp(&entity->rc);
#include <dragonnet/peer.h>
#include <dragonstd/refcount.h>
#include <pthread.h>
+#include "client/gui.h"
#include "client/model.h"
#include "entity.h"
#include "types.h"
Refcount rc;
Model *model;
+ GUIElement *nametag;
+ void *extra;
+
+ aabb3f32 box_collision;
+ aabb3f32 box_culling; // ToDo
+ mat4x4 *nametag_offset;
pthread_rwlock_t lock_pos_rot;
- pthread_rwlock_t lock_box_eye;
pthread_rwlock_t lock_nametag;
+ pthread_rwlock_t lock_box_off;
} ClientEntity;
+// Entity is pronounced N-Tiddy, hmmmm...
+
typedef struct ClientEntityType {
void (*add )(ClientEntity *entity); // called when server sent addition of entity
void (*remove)(ClientEntity *entity); // called when server sent removal of entity
void (*free )(ClientEntity *entity); // called when entity is garbage collected
void (*update_pos_rot)(ClientEntity *entity);
- void (*update_box_eye)(ClientEntity *entity);
void (*update_nametag)(ClientEntity *entity);
void (*transform)(ClientEntity *entity);
} ClientEntityType;
+extern ClientEntityType client_entity_types[];
+extern Mesh client_entity_cube;
+extern ModelShader client_entity_shader;
+
void client_entity_init();
void client_entity_deinit();
+bool client_entity_gfx_init();
+void client_entity_gfx_deinit();
+void client_entity_gfx_update();
+
ClientEntity *client_entity_grab(u64 id);
void client_entity_drop(ClientEntity *entity);
void client_entity_add(DragonnetPeer *peer, ToClientEntityAdd *pkt);
void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt);
void client_entity_update_pos_rot(DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt);
-void client_entity_update_box_eye(DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt);
void client_entity_update_nametag(DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt);
-extern ClientEntityType client_entity_types[];
-
#endif // _CLIENT_ENTITY_H_
#include "environment.h"
#include "physics.h"
+typedef struct {
+ ModelNode *nametag;
+ ModelNode *neck;
+ ModelNode *eyes;
+ ModelNode *shoulder_left;
+ ModelNode *shoulder_right;
+ ModelNode *hip_left;
+ ModelNode *hip_right;
+} PlayerModelBones;
+
struct ClientPlayer client_player;
static ClientEntity *player_entity;
static pthread_rwlock_t lock_player_entity;
+static Model *player_model;
+
// updat epos/rot box/eye functions
-static void update_eye_pos_camera()
+static void update_camera()
{
- v3f64 pos = player_entity->data.pos;
- v3f32 eye = player_entity->data.eye;
+ vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ PlayerModelBones *bones = player_entity->extra;
- camera_set_position((v3f32) {pos.x + eye.x, pos.y + eye.y, pos.z + eye.z});
+ if (bones->eyes)
+ mat4x4_mul_vec4(dst, bones->eyes->abs, src);
+ else
+ vec4_dup(dst, src);
+
+ camera_set_position((v3f32) {dst[0], dst[1], dst[2]});
}
static void update_pos()
{
- pthread_rwlock_rdlock(&player_entity->lock_box_eye);
- update_eye_pos_camera();
- pthread_rwlock_unlock(&player_entity->lock_box_eye);
-
debug_menu_changed(ENTRY_POS);
debug_menu_changed(ENTRY_HUMIDITY);
debug_menu_changed(ENTRY_TEMPERATURE);
static void update_rot()
{
- camera_set_angle(player_entity->data.rot.x, player_entity->data.rot.y);
+ camera_set_angle(M_PI / 2 - player_entity->data.rot.y, -player_entity->data.rot.x);
debug_menu_changed(ENTRY_YAW);
debug_menu_changed(ENTRY_PITCH);
}
static void update_transform()
{
client_entity_transform(player_entity);
+ update_camera();
}
static void send_pos_rot()
{
+ update_transform();
+
dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) {
.pos = player_entity->data.pos,
.rot = player_entity->data.rot,
});
-
- update_transform();
}
static void recv_pos_rot()
{
+ update_transform();
+
update_pos();
update_rot();
-
- update_transform();
}
// entity callbacks
static void on_add(ClientEntity *entity)
+{
+ entity->model = model_clone(player_model);
+ entity->model->extra = refcount_grb(&entity->rc);
+
+ PlayerModelBones *bones = entity->extra = malloc(sizeof *bones);
+ *bones = (PlayerModelBones) {NULL};
+ model_get_bones(entity->model, (ModelBoneMapping[]) {
+ {"player.nametag", &bones->nametag },
+ {"player.neck", &bones->neck },
+ {"player.neck.head.eyes", &bones->eyes },
+ {"player.body.upper.shoulders.left", &bones->shoulder_left },
+ {"player.body.upper.shoulders.right", &bones->shoulder_right},
+ {"player.body.lower.hips.left", &bones->hip_left },
+ {"player.body.lower.hips.right", &bones->hip_right },
+ }, 7);
+
+ entity->nametag_offset = bones->nametag ? &bones->nametag->abs : NULL;
+ entity->box_collision = (aabb3f32) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.8f, 0.3f}};
+
+ model_scene_add(entity->model);
+ client_entity_transform(entity);
+}
+
+static void on_remove(ClientEntity *entity)
+{
+ entity->model->flags.delete = 1;
+ entity->model = NULL;
+}
+
+static void on_free(ClientEntity *entity)
+{
+ free(entity->extra);
+}
+
+static void on_transform(ClientEntity *entity)
+{
+ PlayerModelBones *bones = entity->extra;
+
+ entity->model->root->rot.x = entity->model->root->rot.z = 0.0f;
+
+ if (bones->neck) {
+ bones->neck->rot.x = entity->data.rot.x;
+ model_node_transform(bones->neck);
+ }
+}
+
+static void local_on_add(ClientEntity *entity)
{
pthread_rwlock_wrlock(&lock_player_entity);
if (player_entity) {
fprintf(stderr, "[error] attempt to re-add localplayer entity\n");
exit(EXIT_FAILURE);
- } else {
- player_entity = refcount_grb(&entity->rc);
- recv_pos_rot();
-
- entity->type->update_nametag(entity);
}
+ on_add(entity);
+
+ player_entity = refcount_grb(&entity->rc);
+ recv_pos_rot();
+
+ entity->type->update_nametag(entity);
+
pthread_rwlock_unlock(&lock_player_entity);
}
-static void on_remove(ClientEntity *entity)
+static void local_on_remove(ClientEntity *entity)
{
pthread_rwlock_wrlock(&lock_player_entity);
refcount_drp(&entity->rc);
player_entity = NULL;
pthread_rwlock_unlock(&lock_player_entity);
-}
-static void on_update_pos_rot(__attribute__((unused)) ClientEntity *entity)
-{
- recv_pos_rot();
+ on_remove(entity);
}
-static void on_update_box_eye(__attribute__((unused)) ClientEntity *entity)
+static void local_on_update_pos_rot(__attribute__((unused)) ClientEntity *entity)
{
- pthread_rwlock_rdlock(&lock_player_entity);
- update_eye_pos_camera();
- pthread_rwlock_unlock(&lock_player_entity);
+ recv_pos_rot();
}
-static void on_update_nametag(ClientEntity *entity)
+static void local_on_update_nametag(ClientEntity *entity)
{
if (entity->data.nametag) {
free(entity->data.nametag);
}
}
-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
.gravity = 0.0f,
};
- client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
+ client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
.add = &on_add,
.remove = &on_remove,
- .free = NULL,
- .update_pos_rot = &on_update_pos_rot,
- .update_box_eye = &on_update_box_eye,
- .update_nametag = &on_update_nametag,
+ .free = &on_free,
+ .update_pos_rot = NULL,
+ .update_nametag = NULL,
.transform = &on_transform,
};
- client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
- .add = NULL,
- .remove = NULL,
- .free = NULL,
- .update_pos_rot = NULL,
- .update_box_eye = NULL,
- .update_nametag = NULL,
+ client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
+ .add = &local_on_add,
+ .remove = &local_on_remove,
+ .free = &on_free,
+ .update_pos_rot = &local_on_update_pos_rot,
+ .update_nametag = &local_on_update_nametag,
.transform = &on_transform,
};
pthread_rwlock_destroy(&lock_player_entity);
}
+void client_player_gfx_init()
+{
+ player_model = model_load(
+ RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player",
+ &client_entity_cube, &client_entity_shader);
+
+ player_model->callbacks.step = &on_model_step;
+ player_model->callbacks.delete = &on_model_delete;
+}
+
+void client_player_gfx_deinit()
+{
+ model_delete(player_model);
+}
+
ClientEntity *client_player_entity()
{
ClientEntity *entity = NULL;
pthread_rwlock_unlock(&lock_player_entity);
}
-/*
-// create mesh object and info hud
-void client_player_add_to_scene()
-{
- client_player.obj = object_create();
- client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6};
- client_player.obj->visible = false;
-
- object_set_texture(client_player.obj, texture_load(RESSOURCE_PATH "textures/player.png", true));
-
- for (int f = 0; f < 6; f++) {
- for (int v = 0; v < 6; v++) {
- Vertex3D vertex = cube_vertices[f][v];
- vertex.position.y += 0.5;
- object_add_vertex(client_player.obj, &vertex);
- }
- }
-
- pthread_rwlock_rdlock(&client_player.rwlock);
- update_pos();
- pthread_rwlock_unlock(&client_player.rwlock);
-
- debug_menu_update_yaw();
- debug_menu_update_pitch();
-}
-*/
-
// jump if possible
void client_player_jump()
{
return;
pthread_rwlock_rdlock(&entity->lock_pos_rot);
- pthread_rwlock_rdlock(&entity->lock_box_eye);
+ pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_ground(
client_terrain,
client_player.movement.collision,
- entity->data.box,
+ entity->box_collision,
&entity->data.pos,
&client_player.velocity
))
client_player.velocity.y += client_player.movement.jump;
- pthread_rwlock_unlock(&entity->lock_box_eye);
+ pthread_rwlock_unlock(&entity->lock_box_off);
pthread_rwlock_unlock(&entity->lock_pos_rot);
refcount_drp(&entity->rc);
pthread_rwlock_rdlock(&client_player.lock_movement);
pthread_rwlock_wrlock(&entity->lock_pos_rot);
- pthread_rwlock_rdlock(&entity->lock_box_eye);
+ pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_step(
client_terrain,
client_player.movement.collision,
- entity->data.box,
+ entity->box_collision,
&entity->data.pos,
&client_player.velocity,
&(v3f64) {
))
client_player_update_pos(entity);
- pthread_rwlock_unlock(&entity->lock_box_eye);
+ pthread_rwlock_unlock(&entity->lock_box_off);
pthread_rwlock_unlock(&entity->lock_pos_rot);
pthread_rwlock_unlock(&client_player.lock_movement);
void client_player_init(); // called on startup
void client_player_deinit(); // called on shutdown
+void client_player_gfx_init();
+void client_player_gfx_deinit();
+
ClientEntity *client_player_entity(); // grab and return client entity
void client_player_jump(); // jump if possible
// mesh generator step
static void meshgen_step()
{
- TerrainChunk *chunk = queue_deq(&meshgen_tasks, (void *) &set_dequeued);
+ TerrainChunk *chunk = queue_deq(&meshgen_tasks, &set_dequeued);
if (chunk)
terrain_gfx_make_chunk_model(chunk);
#include <GL/gl.h>
#include <stdbool.h>
#include <stdio.h>
+#include <stdlib.h>
#include <pthread.h>
#include "client/client_config.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
#include "client/debug_menu.h"
#include "client/game.h"
+#include "client/gl_debug.h"
#include "client/gui.h"
#include "client/window.h"
#include "day.h"
char *str;
switch (entry) {
- case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
- case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break;
- case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break;
- case ENTRY_YAW: asprintf(&str, "yaw = %.1f", rot.x / M_PI * 180.0 ); break;
- case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", rot.y / M_PI * 180.0 ); break;
- case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
- case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break;
- case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break;
- case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break;
- case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break;
- case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break;
- case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break;
- case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break;
- case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break;
- case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break;
- case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); break;
- case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); break;
- case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break;
- case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break;
- case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break;
- case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break;
+ case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
+ case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break;
+ case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break;
+ case ENTRY_YAW: asprintf(&str, "yaw = %.1f", 360.0 - rot.y / M_PI * 180.0 ); break;
+ case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", -rot.x / M_PI * 180.0 ); break;
+ case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
+ case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break;
+ case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break;
+ case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break;
+ case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break;
+ case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break;
+ case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break;
+ case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break;
+ case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break;
+ case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break;
+ case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); GL_DEBUG break;
+ case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); GL_DEBUG break;
+ case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break;
+ case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break;
+ case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break;
+ case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break;
default: break;
}
return str;
.scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT,
.affect_parent_scale = false,
- .text = strdup(""),
+ .text = "",
.image = NULL,
.text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f},
.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f},
pthread_mutex_unlock(&changed_elements_mtx);
for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++)
- if (changed_elements_cpy[i])
- gui_text(gui_elements[i], get_entry_text(i));
+ if (changed_elements_cpy[i]) {
+ char *str = get_entry_text(i);
+ gui_text(gui_elements[i], str);
+ free(str);
+ }
}
void debug_menu_changed(DebugMenuEntry entry)
#include FT_FREETYPE_H
#include "client/client.h"
#include "client/font.h"
+#include "client/gl_debug.h"
#include "client/texture.h"
#define NUM_CHARS 128
return false;
}
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GL_DEBUG
FT_Set_Pixel_Sizes(font_face, 0, 16);
for (unsigned char c = 0; c < NUM_CHARS; c++) {
void font_render(Font *font)
{
for (size_t i = 0; i < font->count; i++) {
- glBindTextureUnit(0, font->textures[i]);
+ glBindTextureUnit(0, font->textures[i]); GL_DEBUG
mesh_render(&font->meshes[i]);
}
}
#include <unistd.h>
#include "client/camera.h"
#include "client/client.h"
+#include "client/client_entity.h"
#include "client/client_node.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
#include "client/debug_menu.h"
#include "client/font.h"
#include "client/frustum.h"
+#include "client/game.h"
+#include "client/gl_debug.h"
#include "client/gui.h"
#include "client/input.h"
#include "client/sky.h"
static void render(f64 dtime)
{
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_ALPHA_TEST);
- glEnable(GL_BLEND);
- glEnable(GL_MULTISAMPLE);
- glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST); GL_DEBUG
+ glEnable(GL_BLEND); GL_DEBUG
+ glEnable(GL_MULTISAMPLE); GL_DEBUG
+ glEnable(GL_CULL_FACE); GL_DEBUG
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glAlphaFunc(GL_GREATER, 0.1f);
- glCullFace(GL_BACK);
- glFrontFace(GL_CCW);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DEBUG
+ glCullFace(GL_BACK); GL_DEBUG
+ glFrontFace(GL_CCW); GL_DEBUG
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GL_DEBUG
frustum_update();
terrain_gfx_update();
+ client_entity_gfx_update();
sky_render();
model_scene_render(dtime);
if (!terrain_gfx_init())
return false;
+ if (!client_entity_gfx_init())
+ return false;
+
+ client_player_gfx_init();
+
client_node_init();
client_terrain_start();
model_deinit();
sky_deinit();
terrain_gfx_deinit();
+ client_entity_gfx_deinit();
+ client_player_gfx_deinit();
return true;
}
{
// renderbuffer for depth & stencil buffer
GLuint rbo;
- glGenRenderbuffers(1, &rbo);
- glBindRenderbuffer(GL_RENDERBUFFER, rbo);
- glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height);
+ glGenRenderbuffers(1, &rbo); GL_DEBUG
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG
// 2 textures, one with AA, one without
GLuint txos[2];
- glGenTextures(2, txos);
+ glGenTextures(2, txos); GL_DEBUG
- glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]);
- glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG
- glBindTexture(GL_TEXTURE_2D, txos[1]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, txos[1]); GL_DEBUG
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); GL_DEBUG
// 2 framebuffers, one with AA, one without
GLuint fbos[2];
- glGenFramebuffers(2, fbos);
+ glGenFramebuffers(2, fbos); GL_DEBUG
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); GL_DEBUG
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG
// render scene
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
render(0.0);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG
// blit AA-buffer into no-AA buffer
- glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
- glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG
// read data
GLubyte data[window.width * window.height * 3];
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]);
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
- glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG
+ glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG
// create filename
char filename[BUFSIZ];
stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
// delete buffers
- glDeleteRenderbuffers(1, &rbo);
- glDeleteTextures(2, txos);
- glDeleteFramebuffers(2, fbos);
+ glDeleteRenderbuffers(1, &rbo); GL_DEBUG
+ glDeleteTextures(2, txos); GL_DEBUG
+ glDeleteFramebuffers(2, fbos); GL_DEBUG
return strdup(filename);
}
--- /dev/null
+#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);
+}
--- /dev/null
+#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
#include <string.h>
#include "client/client.h"
#include "client/cube.h"
+#include "client/gl_debug.h"
#include "client/gui.h"
#include "client/mesh.h"
#include "client/shader.h"
{
if (element->visible) {
if (element->def.bg_color.w > 0.0f) {
- glUseProgram(background_prog);
- glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]);
- glUniform4f(background_loc_color, element->def.bg_color.x, element->def.bg_color.y, element->def.bg_color.z, element->def.bg_color.w);
+ glUseProgram(background_prog); GL_DEBUG
+ glUniformMatrix4fv(background_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
+ glUniform4f(background_loc_color, element->def.bg_color.x, element->def.bg_color.y, element->def.bg_color.z, element->def.bg_color.w); GL_DEBUG
mesh_render(&background_mesh);
}
if (element->def.image) {
- glUseProgram(image_prog);
- glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]);
- glBindTextureUnit(0, element->def.image->txo);
+ glUseProgram(image_prog); GL_DEBUG
+ glUniformMatrix4fv(image_loc_model, 1, GL_FALSE, element->transform[0]); GL_DEBUG
+ glBindTextureUnit(0, element->def.image->txo); GL_DEBUG
mesh_render(&image_mesh);
}
- if (element->text && element->def.text_color.w > 0.0f) {
- glUseProgram(font_prog);
- glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]);
- glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w);
+ if (element->def.text && element->def.text_color.w > 0.0f) {
+ if (!element->text) {
+ element->text = font_create(element->def.text);
+ gui_transform(element);
+ }
+
+ glUseProgram(font_prog); GL_DEBUG
+ glUniformMatrix4fv(font_loc_model, 1, GL_FALSE, element->text_transform[0]); GL_DEBUG
+ glUniform4f(font_loc_color, element->def.text_color.x, element->def.text_color.y, element->def.text_color.z, element->def.text_color.w); GL_DEBUG
font_render(element->text);
}
break;
case SCALE_TEXT:
+ if (!element->text)
+ break;
+
element->scale.x *= element->text->size.x;
element->scale.y *= element->text->size.y;
break;
return false;
}
- background_loc_model = glGetUniformLocation(background_prog, "model");
- background_loc_projection = glGetUniformLocation(background_prog, "projection");
- background_loc_color = glGetUniformLocation(background_prog, "color");
+ background_loc_model = glGetUniformLocation(background_prog, "model"); GL_DEBUG
+ background_loc_projection = glGetUniformLocation(background_prog, "projection"); GL_DEBUG
+ background_loc_color = glGetUniformLocation(background_prog, "color"); GL_DEBUG
// initialize image pipeline
return false;
}
- image_loc_model = glGetUniformLocation(image_prog, "model");
- image_loc_projection = glGetUniformLocation(image_prog, "projection");
+ image_loc_model = glGetUniformLocation(image_prog, "model"); GL_DEBUG
+ image_loc_projection = glGetUniformLocation(image_prog, "projection"); GL_DEBUG
// initialize font pipeline
return false;
}
- font_loc_model = glGetUniformLocation(font_prog, "model");
- font_loc_projection = glGetUniformLocation(font_prog, "projection");
- font_loc_color = glGetUniformLocation(font_prog, "color");
+ font_loc_model = glGetUniformLocation(font_prog, "model"); GL_DEBUG
+ font_loc_projection = glGetUniformLocation(font_prog, "projection"); GL_DEBUG
+ font_loc_color = glGetUniformLocation(font_prog, "color"); GL_DEBUG
// initialize GUI root element
void gui_deinit()
{
- glDeleteProgram(background_prog);
+ glDeleteProgram(background_prog); GL_DEBUG
mesh_destroy(&background_mesh);
- glDeleteProgram(image_prog);
+ glDeleteProgram(image_prog); GL_DEBUG
mesh_destroy(&image_mesh);
- glDeleteProgram(font_prog);
+ glDeleteProgram(font_prog); GL_DEBUG
delete_elements(&root_element.children);
}
void gui_update_projection()
{
mat4x4_ortho(projection, 0, window.width, window.height, 0, -1.0f, 1.0f);
- glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]);
- glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]);
- glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]);
+ glProgramUniformMatrix4fv(background_prog, background_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
+ glProgramUniformMatrix4fv(image_prog, image_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
+ glProgramUniformMatrix4fv(font_prog, font_loc_projection, 1, GL_FALSE, projection[0]); GL_DEBUG
root_element.def.scale.x = window.width;
root_element.def.scale.y = window.height;
void gui_render()
{
- glDisable(GL_CULL_FACE);
- glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE); GL_DEBUG
+ glDisable(GL_DEPTH_TEST); GL_DEBUG
render_elements(&root_element.children);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST); GL_DEBUG
+ glEnable(GL_CULL_FACE); GL_DEBUG
}
GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
element->def = def;
element->visible = true;
element->parent = parent;
+ element->text = NULL;
- if (element->def.text) {
+ if (element->def.text)
element->def.text = strdup(element->def.text);
- element->text = font_create(element->def.text);
- } else {
- element->text = NULL;
- }
- array_ins(&parent->children, &element, (void *) &cmp_element);
+ array_ins(&parent->children, &element, &cmp_element);
array_ini(&element->children, sizeof(GUIElement), 0);
if (element->def.affect_parent_scale)
return element;
}
-void gui_text(GUIElement *element, char *text)
+void gui_text(GUIElement *element, const char *text)
{
if (element->def.text)
free(element->def.text);
- element->def.text = text;
- font_delete(element->text);
- element->text = font_create(text);
- gui_transform(element);
+ if (element->text)
+ font_delete(element->text);
+
+ element->def.text = strdup(text);
+ element->text = NULL;
}
void gui_transform(GUIElement *element)
void gui_update_projection();
void gui_render();
GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def);
-void gui_text(GUIElement *element, char *text);
+void gui_text(GUIElement *element, const char *text);
void gui_transform(GUIElement *element);
#endif // _GUI_H_
#include "client/window.h"
#include "day.h"
+#define SET_STATUS_MESSAGE(args...) { \
+ char *msg; asprintf(&msg, args); \
+ gui_text(status_message, msg); free(msg); \
+ status_message->def.text_color.w = 1.01f; }
+
typedef struct {
int key;
bool state;
return !(listener->state = (glfwGetKey(window.handle, listener->key) == GLFW_PRESS)) && was;
}
-static void set_status_message(char *message)
-{
- gui_text(status_message, message);
- status_message->def.text_color.w = 1.01f;
-}
-
void input_init()
{
pause_menu = gui_add(NULL, (GUIElementDefinition) {
.scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT,
.affect_parent_scale = false,
- .text = strdup(""),
+ .text = "",
.image = NULL,
.text_color = {1.0f, 0.91f, 0.13f, 0.0f},
.bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
pthread_rwlock_wrlock(&client_player.lock_movement);
client_player.movement.flight = !client_player.movement.flight;
- char *msg;
- asprintf(&msg, "Flight %s", client_player.movement.flight ? "Enabled" : "Disabled");
- set_status_message(msg);
+ SET_STATUS_MESSAGE("Flight %s", client_player.movement.flight ? "Enabled" : "Disabled")
debug_menu_changed(ENTRY_FLIGHT);
pthread_rwlock_unlock(&client_player.lock_movement);
pthread_rwlock_wrlock(&client_player.lock_movement);
client_player.movement.collision = !client_player.movement.collision;
- char *msg;
- asprintf(&msg, "Collision %s", client_player.movement.collision ? "Enabled" : "Disabled");
- set_status_message(msg);
+ SET_STATUS_MESSAGE("Collision %s", client_player.movement.collision ? "Enabled" : "Disabled")
debug_menu_changed(ENTRY_COLLISION);
pthread_rwlock_unlock(&client_player.lock_movement);
timelapse = !timelapse;
set_time_of_day(current_time);
- char *msg;
- asprintf(&msg, "Timelapse %s", timelapse ? "Enabled" : "Disabled");
- set_status_message(msg);
+ SET_STATUS_MESSAGE("Timelapse %s", timelapse ? "Enabled" : "Disabled")
debug_menu_changed(ENTRY_TIMELAPSE);
}
if (key_listener(&listener_screenshot)) {
char *screenshot_filename = game_take_screenshot();
- char *msg;
- asprintf(&msg, "Screenshot saved to %s", screenshot_filename);
- set_status_message(msg);
+ SET_STATUS_MESSAGE("Screenshot saved to %s", screenshot_filename)
free(screenshot_filename);
}
}
pthread_rwlock_wrlock(&entity->lock_pos_rot);
- entity->data.rot.x += (f32) delta_x * M_PI / 180.0f / 8.0f;
- entity->data.rot.y -= (f32) delta_y * M_PI / 180.0f / 8.0f;
+ entity->data.rot.y -= (f32) delta_x * M_PI / 180.0f / 8.0f;
+ entity->data.rot.x += (f32) delta_y * M_PI / 180.0f / 8.0f;
- entity->data.rot.x = fmod(entity->data.rot.x + M_PI * 2.0f, M_PI * 2.0f);
- entity->data.rot.y = f32_clamp(entity->data.rot.y, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f);
+ entity->data.rot.y = fmod(entity->data.rot.y + M_PI * 2.0f, M_PI * 2.0f);
+ entity->data.rot.x = f32_clamp(entity->data.rot.x, -M_PI / 2.0f + 0.01f, M_PI / 2.0f - 0.01f);
client_player_update_rot(entity);
pthread_rwlock_unlock(&entity->lock_pos_rot);
--- /dev/null
+#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
+}
--- /dev/null
+#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
#include <stddef.h>
#include <stdlib.h>
+#include "client/gl_debug.h"
#include "client/mesh.h"
// upload data to GPU (only done once)
void mesh_upload(Mesh *mesh)
{
- glGenVertexArrays(1, &mesh->vao);
- glGenBuffers(1, &mesh->vbo);
+ glGenVertexArrays(1, &mesh->vao); GL_DEBUG
+ glGenBuffers(1, &mesh->vbo); GL_DEBUG
- glBindVertexArray(mesh->vao);
- glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
+ glBindVertexArray(mesh->vao); GL_DEBUG
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); GL_DEBUG
glBufferData(GL_ARRAY_BUFFER, mesh->count * mesh->layout->size,
- mesh->data, GL_STATIC_DRAW);
+ mesh->data, GL_STATIC_DRAW); GL_DEBUG
size_t offset = 0;
for (GLuint i = 0; i < mesh->layout->count; i++) {
VertexAttribute *attrib = &mesh->layout->attributes[i];
glVertexAttribPointer(i, attrib->length, attrib->type, GL_FALSE,
- mesh->layout->size, (GLvoid *) offset);
- glEnableVertexAttribArray(i);
+ mesh->layout->size, (GLvoid *) offset); GL_DEBUG
+ glEnableVertexAttribArray(i); GL_DEBUG
offset += attrib->size;
}
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); GL_DEBUG
+ glBindVertexArray(0); GL_DEBUG
if (mesh->free_data)
free(mesh->data);
mesh_upload(mesh);
// render
- glBindVertexArray(mesh->vao);
- glDrawArrays(GL_TRIANGLES, 0, mesh->count);
+ glBindVertexArray(mesh->vao); GL_DEBUG
+ glDrawArrays(GL_TRIANGLES, 0, mesh->count); GL_DEBUG
}
void mesh_destroy(Mesh *mesh)
if (mesh->data && mesh->free_data)
free(mesh->data);
- if (mesh->vao)
- glDeleteVertexArrays(1, &mesh->vao);
+ if (mesh->vao) {
+ glDeleteVertexArrays(1, &mesh->vao); GL_DEBUG
+ }
- if (mesh->vbo)
- glDeleteBuffers(1, &mesh->vbo);
+ if (mesh->vbo) {
+ glDeleteBuffers(1, &mesh->vbo); GL_DEBUG
+ }
mesh->vao = mesh->vbo = 0;
}
#include "client/camera.h"
#include "client/client_config.h"
#include "client/frustum.h"
+#include "client/gl_debug.h"
#include "client/model.h"
typedef struct {
} ModelBatchTexture;
static List scene;
-static pthread_rwlock_t lock_scene;
+static List scene_new;
+static pthread_mutex_t lock_scene_new;
static GLint units;
// fixme: blending issues still occur
for (size_t i = 0; i < node->meshes.siz; i++) {
ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
- glUseProgram(mesh->shader->prog);
- glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]);
+ glUseProgram(mesh->shader->prog); GL_DEBUG
+ glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); GL_DEBUG
// bind textures
- for (GLuint i = 0; i < mesh->num_textures; i++)
- glBindTextureUnit(i, mesh->textures[i]);
+ for (GLuint i = 0; i < mesh->num_textures; i++) {
+ glBindTextureUnit(i, mesh->textures[i]); GL_DEBUG
+ }
mesh_render(mesh->mesh);
}
- list_itr(&node->children, (void *) &render_node, NULL, NULL);
+ list_itr(&node->children, &render_node, NULL, NULL);
}
static void free_node_meshes(ModelNode *node)
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)
if (mesh->textures)
free(mesh->textures);
}
- list_clr(&node->children, (void *) &delete_node, NULL, NULL);
+ list_clr(&node->children, &delete_node, NULL, NULL);
array_clr(&node->meshes);
free(node);
for (size_t i = 0; i < node->meshes.siz; i++)
clone_mesh(&((ModelMesh *) node->meshes.ptr)[i]);
- list_itr(&original->children, (void *) &clone_node, parent, NULL);
+ list_itr(&original->children, &clone_node, node, NULL);
return node;
}
static void render_model(Model *model)
{
- if (model->flags.wireframe)
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ if (model->flags.wireframe) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); GL_DEBUG
+ }
render_node(model->root);
- if (model->flags.wireframe)
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if (model->flags.wireframe) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); GL_DEBUG
+ }
}
// step model help im stuck
void model_init()
{
list_ini(&scene);
- pthread_rwlock_init(&lock_scene, NULL);
- glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units);
+ list_ini(&scene_new);
+
+ pthread_mutex_init(&lock_scene_new, NULL);
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &units); GL_DEBUG
}
// ded
void model_deinit()
{
list_clr(&scene, &model_delete, NULL, NULL);
- pthread_rwlock_destroy(&lock_scene);
+ list_clr(&scene_new, &model_delete, NULL, NULL);
+
+ pthread_mutex_destroy(&lock_scene_new);
}
// Model functions
Model *model = malloc(sizeof *model);
model->root = model_node_create(NULL);
model->extra = NULL;
+ model->replace = NULL;
model->callbacks.step = NULL;
model->callbacks.delete = NULL;
cursor += n;
else
fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count);
- } else if (strcmp(key, "angle") == 0) {
- if (sscanf(cursor, "%f%n", &node->angle, &n) == 1)
- cursor += n;
- else
- fprintf(stderr, "[warning] invalid value for angle in model %s in line %d\n", path, count);
} else if (strcmp(key, "cube") == 0) {
char texture[length + 1];
fclose(file);
array_clr(&stack);
+ transform_node(model->root);
return model;
}
name = cursor = strdup(mappings[i].name);
ModelNode *node = model->root;
- while ((tok = strtok_r(cursor, ".", &saveptr))) {
- node = list_get(&node->children, tok, (void *) &cmp_node, NULL);
+
+ while (node && (tok = strtok_r(cursor, ".", &saveptr))) {
+ node = list_get(&node->children, tok, &cmp_node, NULL);
cursor = NULL;
}
if (node)
*mappings[i].node = node;
else
- fprintf(stderr, "[warning] no such bone: %s\n", name);
+ fprintf(stderr, "[warning] no such bone: %s\n", mappings[i].name);
free(name);
}
node->pos = (v3f32) {0.0f, 0.0f, 0.0f};
node->rot = (v3f32) {0.0f, 0.0f, 0.0f};
node->scale = (v3f32) {1.0f, 1.0f, 1.0f};
- node->angle = 0.0f;
array_ini(&node->meshes, sizeof(ModelMesh), 0);
init_node(node, parent);
return node;
void model_node_transform(ModelNode *node)
{
+ mat4x4_identity(node->rel);
+
mat4x4_translate(node->rel,
node->pos.x,
node->pos.y,
node->pos.z);
- mat4x4_rotate(node->rel, node->rel,
- node->rot.x,
- node->rot.y,
- node->rot.z,
- node->angle);
-
mat4x4_scale_aniso(node->rel, node->rel,
node->scale.x,
node->scale.y,
node->scale.z);
+ mat4x4_rotate_X(node->rel, node->rel, node->rot.x);
+ mat4x4_rotate_Y(node->rel, node->rel, node->rot.y);
+ mat4x4_rotate_Z(node->rel, node->rel, node->rot.z);
+
transform_node(node);
}
void model_scene_add(Model *model)
{
- pthread_rwlock_wrlock(&lock_scene);
- list_apd(&scene, model);
- pthread_rwlock_unlock(&lock_scene);
+ pthread_mutex_lock(&lock_scene_new);
+ list_apd(&scene_new, model);
+ pthread_mutex_unlock(&lock_scene_new);
}
void model_scene_render(f64 dtime)
{
+ pthread_mutex_lock(&lock_scene_new);
+ if (scene_new.fst) {
+ *scene.end = scene_new.fst;
+ scene.end = scene_new.end;
+
+ list_ini(&scene_new);
+ }
+ pthread_mutex_unlock(&lock_scene_new);
+
Tree transparent;
tree_ini(&transparent);
- pthread_rwlock_rdlock(&lock_scene);
for (ListNode **node = &scene.fst; *node != NULL;) {
Model *model = (*node)->dat;
- pthread_rwlock_unlock(&lock_scene);
if (model->flags.delete) {
- model_delete(model);
+ if (model->replace)
+ (*node)->dat = model->replace;
+ else
+ list_nrm(&scene, node);
- pthread_rwlock_wrlock(&lock_scene);
- list_nrm(&scene, node);
- pthread_rwlock_unlock(&lock_scene);
-
- pthread_rwlock_rdlock(&lock_scene);
+ model_delete(model);
} else {
- model_step(model, &transparent, dtime);
-
- pthread_rwlock_rdlock(&lock_scene);
node = &(*node)->nxt;
+ model_step(model, &transparent, dtime);
}
}
- pthread_rwlock_unlock(&lock_scene);
tree_clr(&transparent, &render_model, NULL, NULL, TRAVERSION_INORDER);
}
char *name;
bool visible;
v3f32 pos, rot, scale;
- f32 angle;
mat4x4 abs, rel;
Array meshes;
struct ModelNode *parent;
void *extra;
aabb3f32 box;
f32 distance;
+ struct Model *replace;
struct {
void (*step)(struct Model *model, f64 dtime);
void (*delete)(struct Model *model);
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "client/gl_debug.h"
#include "client/shader.h"
static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *definitions)
fclose(file);
- GLuint id = glCreateShader(type);
+ GLuint id = glCreateShader(type); GL_DEBUG
// Minimum OpenGL version is 4.2.0 (idk some shader feature from that version is required)
const char *version = "#version 420 core\n"; // 420 blaze it
size,
};
- glShaderSource(id, 3, code_list, size_list);
+ glShaderSource(id, 3, code_list, size_list); GL_DEBUG
- glCompileShader(id);
+ glCompileShader(id); GL_DEBUG
GLint success;
- glGetShaderiv(id, GL_COMPILE_STATUS, &success);
+ glGetShaderiv(id, GL_COMPILE_STATUS, &success); GL_DEBUG
if (!success) {
char errbuf[BUFSIZ];
- glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf);
+ glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
fprintf(stderr, "[error] failed to compile %s shader: %s", name, errbuf);
- glDeleteShader(id);
+ glDeleteShader(id); GL_DEBUG
return 0;
}
- glAttachShader(program, id);
+ glAttachShader(program, id); GL_DEBUG
return id;
}
bool shader_program_create(const char *path, GLuint *idptr, const char *definitions)
{
- GLuint id = glCreateProgram();
+ GLuint id = glCreateProgram(); GL_DEBUG
if (!definitions)
definitions = "";
GLuint vert, frag;
if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) {
- glDeleteProgram(id);
+ glDeleteProgram(id); GL_DEBUG
return false;
}
if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) {
- glDeleteShader(vert);
- glDeleteProgram(id);
+ glDeleteShader(vert); GL_DEBUG
+ glDeleteProgram(id); GL_DEBUG
return false;
}
- glLinkProgram(id);
- glDeleteShader(vert);
- glDeleteShader(frag);
+ glLinkProgram(id); GL_DEBUG
+ glDeleteShader(vert); GL_DEBUG
+ glDeleteShader(frag); GL_DEBUG
GLint success;
- glGetProgramiv(id, GL_LINK_STATUS, &success);
+ glGetProgramiv(id, GL_LINK_STATUS, &success); GL_DEBUG
if (!success) {
char errbuf[BUFSIZ];
- glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf);
+ glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
fprintf(stderr, "[error] failed to link shader program: %s\n", errbuf);
- glDeleteProgram(id);
+ glDeleteProgram(id); GL_DEBUG
return false;
}
#include "client/camera.h"
#include "client/client.h"
#include "client/cube.h"
+#include "client/gl_debug.h"
#include "client/mesh.h"
#include "client/shader.h"
#include "client/sky.h"
return false;
}
- glProgramUniform1iv(skybox_prog, glGetUniformLocation(skybox_prog, "textures"), 2, (GLint[]) {0, 1});
+ glProgramUniform1iv(skybox_prog, glGetUniformLocation(skybox_prog, "textures"), 2, (GLint[]) {0, 1}); GL_DEBUG
- skybox_loc_VP = glGetUniformLocation(skybox_prog, "VP");
- skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight");
+ skybox_loc_VP = glGetUniformLocation(skybox_prog, "VP"); GL_DEBUG
+ skybox_loc_daylight = glGetUniformLocation(skybox_prog, "daylight"); GL_DEBUG
skybox_texture_day = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/day")->txo;
skybox_texture_night = texture_load_cubemap(RESSOURCE_PATH "textures/skybox/night")->txo;
skybox_mesh.data = skybox_vertices;
return false;
}
- sun_loc_MVP = glGetUniformLocation(sun_prog, "MVP");
+ sun_loc_MVP = glGetUniformLocation(sun_prog, "MVP"); GL_DEBUG
sun_texture = texture_load(RESSOURCE_PATH "textures/sun.png", false)->txo;
// clouds
return false;
}
- clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP");
- clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight");
+ clouds_loc_VP = glGetUniformLocation(clouds_prog, "VP"); GL_DEBUG
+ clouds_loc_daylight = glGetUniformLocation(clouds_prog, "daylight"); GL_DEBUG
clouds_mesh.data = clouds_vertices;
mesh_upload(&clouds_mesh);
void sky_deinit()
{
- glDeleteProgram(sun_prog);
+ glDeleteProgram(sun_prog); GL_DEBUG
mesh_destroy(&sun_mesh);
- glDeleteProgram(skybox_prog);
+ glDeleteProgram(skybox_prog); GL_DEBUG
mesh_destroy(&skybox_mesh);
- glDeleteProgram(clouds_prog);
+ glDeleteProgram(clouds_prog); GL_DEBUG
mesh_destroy(&clouds_mesh);
}
mat4x4 mvp;
mat4x4_mul(mvp, vp, model);
- glDisable(GL_CULL_FACE);
- glDepthFunc(GL_LEQUAL);
+ glDisable(GL_CULL_FACE); GL_DEBUG
+ glDepthFunc(GL_LEQUAL); GL_DEBUG
- glUseProgram(skybox_prog);
- glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]);
- glUniform1f(skybox_loc_daylight, daylight);
- glBindTextureUnit(0, skybox_texture_day);
- glBindTextureUnit(1, skybox_texture_night);
+ glUseProgram(skybox_prog); GL_DEBUG
+ glUniformMatrix4fv(skybox_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG
+ glUniform1f(skybox_loc_daylight, daylight); GL_DEBUG
+ glBindTextureUnit(0, skybox_texture_day); GL_DEBUG
+ glBindTextureUnit(1, skybox_texture_night); GL_DEBUG
mesh_render(&skybox_mesh);
- glUseProgram(sun_prog);
- glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]);
- glBindTextureUnit(0, sun_texture);
+ glUseProgram(sun_prog); GL_DEBUG
+ glUniformMatrix4fv(sun_loc_MVP, 1, GL_FALSE, mvp[0]); GL_DEBUG
+ glBindTextureUnit(0, sun_texture); GL_DEBUG
mesh_render(&sun_mesh);
- glUseProgram(clouds_prog);
- glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]);
- glUniform1f(clouds_loc_daylight, daylight);
- glBindTextureUnit(0, skybox_texture_day);
+ glUseProgram(clouds_prog); GL_DEBUG
+ glUniformMatrix4fv(clouds_loc_VP, 1, GL_FALSE, vp[0]); GL_DEBUG
+ glUniform1f(clouds_loc_daylight, daylight); GL_DEBUG
+ glBindTextureUnit(0, skybox_texture_day); GL_DEBUG
mesh_render(&clouds_mesh);
- glDepthFunc(GL_LESS);
- glEnable(GL_CULL_FACE);
+ glDepthFunc(GL_LESS); GL_DEBUG
+ glEnable(GL_CULL_FACE); GL_DEBUG
}
#include <linmath.h/linmath.h>
#include <stdio.h>
#include <stdlib.h>
-#include "client/camera.h"
#include "client/client_config.h"
#include "client/client_node.h"
#include "client/client_terrain.h"
#include "client/cube.h"
#include "client/frustum.h"
+#include "client/gl_debug.h"
+#include "client/light.h"
#include "client/shader.h"
#include "client/terrain_gfx.h"
-#include "day.h"
typedef struct {
bool visible;
};
static GLuint shader_prog;
-static GLint loc_model;
static GLint loc_VP;
-static GLint loc_daylight;
-static GLint loc_fogColor;
-static GLint loc_ambientLight;
-static GLint loc_lightDir;
-static GLint loc_cameraPos;
+static LightShader light_shader;
static ModelShader model_shader;
static inline bool cull_face(NodeType self, NodeType nbr)
bool terrain_gfx_init()
{
GLint texture_units;
- glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units);
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); GL_DEBUG
char *shader_defs;
asprintf(&shader_defs,
client_config.view_distance
);
- if (!shader_program_create(RESSOURCE_PATH "shaders/terrain", &shader_prog, shader_defs)) {
+ if (!shader_program_create(RESSOURCE_PATH "shaders/3d/terrain", &shader_prog, shader_defs)) {
fprintf(stderr, "[error] failed to create terrain shader program\n");
return false;
}
free(shader_defs);
- loc_model = glGetUniformLocation(shader_prog, "model");
- loc_VP = glGetUniformLocation(shader_prog, "VP");
- loc_daylight = glGetUniformLocation(shader_prog, "daylight");
- loc_fogColor = glGetUniformLocation(shader_prog, "fogColor");
- loc_ambientLight = glGetUniformLocation(shader_prog, "ambientLight");
- loc_lightDir = glGetUniformLocation(shader_prog, "lightDir");
- loc_cameraPos = glGetUniformLocation(shader_prog, "cameraPos");
+ loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG
GLint texture_indices[texture_units];
for (GLint i = 0; i < texture_units; i++)
texture_indices[i] = i;
- glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices);
+ glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices); GL_DEBUG
model_shader.prog = shader_prog;
- model_shader.loc_transform = loc_model;
+ model_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG
+
+ light_shader.prog = shader_prog;
+ light_shader_locate(&light_shader);
return true;
}
void terrain_gfx_deinit()
{
- glDeleteProgram(shader_prog);
+ glDeleteProgram(shader_prog); GL_DEBUG
}
void terrain_gfx_update()
{
- vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f};
- vec4 sunlight_dir;
- mat4x4 sunlight_mat;
- mat4x4_identity(sunlight_mat);
-
- mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f);
- mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir);
-
- f32 daylight = get_daylight();
- f32 ambient_light = f32_mix(0.3f, 0.7f, daylight);
- v3f32 fog_color = v3f32_mix((v3f32) {0x03, 0x0A, 0x1A}, (v3f32) {0x87, 0xCE, 0xEB}, daylight);
-
- glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]);
- glProgramUniform3f(shader_prog, loc_lightDir, sunlight_dir[0], sunlight_dir[1], sunlight_dir[2]);
- glProgramUniform3f(shader_prog, loc_cameraPos, camera.eye[0], camera.eye[1], camera.eye[2]);
- glProgramUniform1f(shader_prog, loc_daylight, daylight);
- glProgramUniform3f(shader_prog, loc_fogColor, fog_color.x / 0xFF * ambient_light, fog_color.y / 0xFF * ambient_light, fog_color.z / 0xFF * ambient_light);
- glProgramUniform1f(shader_prog, loc_ambientLight, ambient_light);
+ glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
+ light_shader_update(&light_shader);
}
void terrain_gfx_make_chunk_model(TerrainChunk *chunk)
model_node_transform(model->root);
}
+ meta->model->replace = model;
meta->model->flags.delete = 1;
+ } else if (model) {
+ model_scene_add(model);
}
meta->model = model;
-
- if (model)
- model_scene_add(model);
-
pthread_mutex_unlock(&chunk->mtx);
}
#define STB_IMAGE_IMPLEMENTATION
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include <stb/stb_image.h>
+#include <stb/stb_image_resize.h>
#include <stdbool.h>
#include <dragonstd/tree.h>
#include "client/client_config.h"
+#include "client/gl_debug.h"
#include "client/texture.h"
static Tree textures;
TreeNode **node = tree_nfd(&textures, path, &cmp_texture);
if (*node) {
- *texture = &((TextureLookup *) &(*node)->dat)->texture;
+ *texture = &((TextureLookup *) (*node)->dat)->texture;
return true;
}
return texture;
}
+static inline int least_common_multiple(int a, int b)
+{
+ int high, low;
+ if (a > b) {
+ high = a;
+ low = b;
+ } else {
+ high = b;
+ low = a;
+ }
+
+ int lcm = high;
+ while (lcm % low)
+ lcm += high;
+ return lcm;
+}
+
Texture *texture_load_cubemap(char *path)
{
Texture *texture;
if (lookup_texture(path, &texture))
return texture;
- glGenTextures(1, &texture->txo);
- glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo);
+ glGenTextures(1, &texture->txo); GL_DEBUG
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); GL_DEBUG
const char *directions[6] = {
"right",
"back",
};
+ typedef struct {
+ unsigned char *data;
+ int width, height, channels;
+ } CubemapFace;
+
+ CubemapFace faces[6];
+ int size = 1;
+
for (int i = 0; i < 6; i++) {
char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
sprintf(filename, "%s/%s.png", path, directions[i]);
- unsigned char *data = stbi_load(filename,
- &texture->width, &texture->height, &texture->channels, 0);
- if (!data) {
+ if (!(faces[i].data = stbi_load(filename,
+ &faces[i].width, &faces[i].height, &faces[i].channels, 0))) {
fprintf(stderr, "[error] failed to load texture %s\n", filename);
exit(EXIT_FAILURE);
}
+ size = least_common_multiple(size, faces[i].width);
+ size = least_common_multiple(size, faces[i].height);
+ }
+
+ for (int i = 0; i < 6; i++) {
+ unsigned char *data = faces[i].data;
+
+ bool resize = faces[i].width != size || faces[i].height != size;
+ if (resize) {
+ data = malloc(size * size * faces[i].channels);
+
+ stbir_resize_uint8_generic(
+ faces[i].data, faces[i].width, faces[i].height, 0,
+ data, size, size, 0,
+ faces[i].channels, STBIR_ALPHA_CHANNEL_NONE, 0,
+ STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR,
+ NULL);
+ }
+
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,
- texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
- stbi_image_free(data);
+ size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); GL_DEBUG
+
+ stbi_image_free(faces[i].data);
+ if (resize)
+ stbi_image_free(data);
}
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); GL_DEBUG
return texture;
}
void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap)
{
- glGenTextures(1, &texture->txo);
- glBindTexture(GL_TEXTURE_2D, texture->txo);
+ glGenTextures(1, &texture->txo); GL_DEBUG
+ glBindTexture(GL_TEXTURE_2D, texture->txo); GL_DEBUG
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap)
- ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); GL_DEBUG
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); GL_DEBUG
glTexImage2D(GL_TEXTURE_2D, 0, format,
- texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data);
- glGenerateMipmap(GL_TEXTURE_2D);
+ texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); GL_DEBUG
+ glGenerateMipmap(GL_TEXTURE_2D); GL_DEBUG
}
void texture_destroy(Texture *texture)
{
- glDeleteTextures(1, &texture->txo);
+ glDeleteTextures(1, &texture->txo); GL_DEBUG
}
#include "client/client_config.h"
#include "client/debug_menu.h"
#include "client/game.h"
+#include "client/gl_debug.h"
#include "client/gui.h"
#include "client/input.h"
#include "client/window.h"
static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow *handle, int width, int height)
{
- glViewport(0, 0, width, height);
+ glViewport(0, 0, width, height); GL_DEBUG
window.width = width;
window.height = height;
quit
end
end
+break gl_error
"
echo "$COMMON
void schematic_delete(List *schematic)
{
- list_clr(schematic, (void *) &delete_schematic_node, NULL, NULL);
+ list_clr(schematic, &delete_schematic_node, NULL, NULL);
}
// update player's position
static void on_ToServerPosRot(DragonnetPeer *peer, ToServerPosRot *pkt)
{
- ServerPlayer *player = peer->extra;
-
- pthread_rwlock_wrlock(&player->lock_pos);
- player->pos = pkt->pos;
- player->rot = pkt->rot;
-
- // this is recv thread, no lock_auth needed
- database_update_player_pos_rot(player->name, player->pos, player->rot);
- pthread_rwlock_unlock(&player->lock_pos);
+ server_player_move(peer->extra, pkt->pos, pkt->rot);
}
// tell server map manager client requested the chunk
static Map players;
static Map players_named;
+static void send_entity_add(ServerPlayer *player, ServerPlayer *entity)
+{
+ dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) {
+ .type = player == entity ? ENTITY_LOCALPLAYER : ENTITY_PLAYER,
+ .data = {
+ .id = entity->id,
+ .pos = entity->pos,
+ .rot = entity->rot,
+ .nametag = entity->name,
+ },
+ });
+}
+
+static void send_entity_remove(ServerPlayer *player, ServerPlayer *entity)
+{
+ dragonnet_peer_send_ToClientEntityRemove(player->peer, &(ToClientEntityRemove) {
+ .id = entity->id,
+ });
+}
+
+static void send_entity_update_pos_rot(ServerPlayer *player, ServerPlayer *entity)
+{
+ if (player != entity)
+ dragonnet_peer_send_ToClientEntityUpdatePosRot(player->peer, &(ToClientEntityUpdatePosRot) {
+ .id = entity->id,
+ .pos = entity->pos,
+ .rot = entity->rot,
+ });
+}
+
+static void send_entity_add_existing(ServerPlayer *entity, ServerPlayer *player)
+{
+ if (player != entity) {
+ pthread_rwlock_rdlock(&entity->lock_pos);
+ send_entity_add(player, entity);
+ pthread_rwlock_unlock(&entity->lock_pos);
+ }
+}
+
// main thread
// called on server shutdown
static void player_drop(ServerPlayer *player)
.gravity = server_config.movement.gravity,
.jump = server_config.movement.jump,
});
- dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) {
- .type = ENTITY_LOCALPLAYER,
- .data = {
- .id = player->id,
- .pos = player->pos,
- .rot = player->rot,
- .box = {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}},
- .eye = {0.0f, 1.75f, 0.0f},
- .nametag = NULL,
- },
- });
+
+ server_player_iterate(&send_entity_add, player);
+ server_player_iterate(&send_entity_add_existing, player);
}
// any thread
// (we don't want disconnect messages for every player on server shutdown)
if (map_del(&players, &player->id, &cmp_player_id, &refcount_drp, NULL, NULL))
printf("[access] disconnected %s\n", player->name);
- if (player->auth)
- map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL);
+
+ if (player->auth && map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL)) {
+ pthread_rwlock_rdlock(&player->lock_pos);
+ server_player_iterate(&send_entity_remove, player);
+ pthread_rwlock_unlock(&player->lock_pos);
+ }
// peer no longer has a reference to player
refcount_drp(&player->rc);
return success;
}
+// recv thread
+void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot)
+{
+ pthread_rwlock_wrlock(&player->lock_pos);
+ // this is recv thread, no lock_auth needed
+ database_update_player_pos_rot(player->name, player->pos = pos, player->rot = rot);
+ server_player_iterate(&send_entity_update_pos_rot, player);
+ pthread_rwlock_unlock(&player->lock_pos);
+}
+
// any thread
void server_player_disconnect(ServerPlayer *player)
{
bool server_player_auth(ServerPlayer *player, char *name);
void server_player_disconnect(ServerPlayer *player);
+void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot);
void server_player_iterate(void *func, void *arg);
#endif // _SERVER_PLAYER_H_
if (meta->state == CHUNK_CREATED)
return;
- server_player_iterate((void *) &send_chunk, chunk);
+ server_player_iterate(&send_chunk, chunk);
}
// Iterator for sending changed chunks to near clients
meta->state = CHUNK_READY;
pthread_mutex_unlock(&chunk->mtx);
- list_clr(&changed_chunks, (void *) &iterator_send_chunk_to_near, NULL, NULL);
+ list_clr(&changed_chunks, &iterator_send_chunk_to_near, NULL, NULL);
pthread_mutex_lock(&mtx_num_gen_chunks);
num_gen_chunks--;
}
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
void voxelctx_delete(Voxelctx *ctx)
{
- list_clr(&ctx->statestack, (void *) &free, NULL, NULL);
+ list_clr(&ctx->statestack, &free, NULL, NULL);
free(ctx);
}
static void delete_sector(TerrainSector *sector, Terrain *terrain)
{
- tree_clr(§or->chunks, (void *) &delete_chunk, terrain, NULL, 0);
+ tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0);
pthread_rwlock_destroy(§or->lock);
free(sector);
}
void terrain_delete(Terrain *terrain)
{
- tree_clr(&terrain->sectors, (void *) &delete_sector, terrain, NULL, 0);
+ tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0);
pthread_rwlock_destroy(&terrain->lock);
pthread_rwlock_destroy(&terrain->cache_lock);
free(terrain);
u64 id
v3f64 pos
v3f32 rot
- aabb3f32 box
- v3f32 eye
String nametag
; server packets
v3f64 pos
v3f32 rot
-pkt ToClientEntityUpdateBoxEye
- u64 id
- aabb3f32 box
- v3f32 eye
-
pkt ToClientEntityUpdateNametag
u64 id
String nametag
OUTPUT_STRIP_TRAILING_WHITESPACE
)
-if ("${GIT_VERSION}" STREQUAL "")
+if("${GIT_VERSION}" STREQUAL "")
execute_process(COMMAND git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE