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

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 fragmentNormal;
in vec2 fragmentTextureCoords;
in vec2 fragmentTextureCoordinates;
in float fragmentTextureIndex;
in vec3 fragmentColor;
@ -12,7 +12,7 @@ uniform sampler2D textures[MAX_TEXTURE_UNITS];
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));
if (outColor.a == 0.0)

View File

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

View File

@ -1,4 +1,4 @@
in vec2 fragmentTextureCoords;
in vec2 fragmentTextureCoordinates;
out vec4 outColor;
@ -7,5 +7,5 @@ uniform vec4 color;
void main()
{
outColor = vec4(1.0, 1.0, 1.0, texture(texture0, fragmentTextureCoords).r) * color;
outColor = vec4(1.0, 1.0, 1.0, texture(texture0, fragmentTextureCoordinates).r) * color;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ cp -r * .build/
cd .build/
mkdir build
cd build
if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" && make clean && make -j$(nproc)); then
if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release -DRESSOURCE_PATH="\"\"" -DCMAKE_C_FLAGS="-Ofast" && make clean && make -j$(nproc)); then
cd ../..
rm -rf .build
exit 1

View File

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

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_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);

View File

@ -1,12 +1,46 @@
#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
@ -22,6 +56,14 @@ static void entity_drop(ClientEntity *entity)
if (entity->type->remove)
entity->type->remove(entity);
if (entity->nametag) {
pthread_mutex_lock(&mtx_nametagged);
list_del(&nametagged, &entity->rc, &cmp_ref, &refcount_drp, NULL, NULL);
pthread_mutex_unlock(&mtx_nametagged);
entity->nametag->visible = false;
}
refcount_drp(&entity->rc);
}
@ -38,17 +80,78 @@ static void entity_delete(ClientEntity *entity)
free(entity->data.nametag);
pthread_rwlock_init(&entity->lock_pos_rot, NULL);
pthread_rwlock_init(&entity->lock_box_eye, NULL);
pthread_rwlock_init(&entity->lock_nametag, NULL);
pthread_rwlock_init(&entity->lock_box_off, NULL);
free(entity);
}
static void update_nametag(ClientEntity *entity)
{
if (entity->nametag) {
gui_text(entity->nametag, entity->data.nametag);
if (!entity->data.nametag)
entity->nametag->visible = false;
} else if (entity->data.nametag) {
entity->nametag = gui_add(NULL, (GUIElementDefinition) {
.pos = {-1.0f, -1.0f},
.z_index = 0.1f,
.offset = {0, 0},
.margin = {4, 4},
.align = {0.5f, 0.5f},
.scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT,
.affect_parent_scale = false,
.text = entity->data.nametag,
.image = NULL,
.text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f},
.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.5f},
});
pthread_mutex_lock(&mtx_nametagged);
list_apd(&nametagged, refcount_inc(&entity->rc));
pthread_mutex_unlock(&mtx_nametagged);
}
}
static void update_nametag_pos(ClientEntity *entity)
{
if (!entity->data.nametag)
return;
pthread_rwlock_rdlock(&entity->lock_pos_rot);
pthread_rwlock_rdlock(&entity->lock_box_off);
mat4x4 mvp;
if (entity->nametag_offset)
mat4x4_mul(mvp, frustum, *entity->nametag_offset);
else
mat4x4_dup(mvp, frustum);
vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
mat4x4_mul_vec4(dst, mvp, src);
dst[0] /= dst[3];
dst[1] /= dst[3];
dst[2] /= dst[3];
if ((entity->nametag->visible = dst[2] >= -1.0f && dst[2] <= 1.0f)) {
entity->nametag->def.pos = (v2f32) {dst[0] * 0.5f + 0.5f, 1.0f - (dst[1] * 0.5f + 0.5f)};
gui_transform(entity->nametag);
}
pthread_rwlock_unlock(&entity->lock_box_off);
pthread_rwlock_unlock(&entity->lock_pos_rot);
}
// main thread
// called on startup
void client_entity_init()
{
map_ini(&entities);
list_ini(&nametagged);
pthread_mutex_init(&mtx_nametagged, NULL);
}
// main thead
@ -57,6 +160,58 @@ void client_entity_deinit()
{
// forget all entities
map_cnl(&entities, &refcount_drp, NULL, NULL, 0);
list_clr(&nametagged, &refcount_drp, NULL, NULL);
pthread_mutex_destroy(&mtx_nametagged);
}
bool client_entity_gfx_init()
{
char *shader_defs;
asprintf(&shader_defs, "#define VIEW_DISTANCE %lf\n", client_config.view_distance);
if (!shader_program_create(RESSOURCE_PATH "shaders/3d/entity", &shader_prog, shader_defs)) {
fprintf(stderr, "[error] failed to create entity shader program\n");
return false;
}
free(shader_defs);
loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG
EntityVertex vertices[6][6];
for (int f = 0; f < 6; f++) {
for (int v = 0; v < 6; v++) {
vertices[f][v].position = cube_vertices[f][v].position;
vertices[f][v].normal = cube_vertices[f][v].normal;
}
}
client_entity_cube.data = vertices;
mesh_upload(&client_entity_cube);
client_entity_shader.prog = shader_prog;
client_entity_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG
light_shader.prog = shader_prog;
light_shader_locate(&light_shader);
return true;
}
void client_entity_gfx_deinit()
{
glDeleteProgram(shader_prog); GL_DEBUG
mesh_destroy(&client_entity_cube);
}
void client_entity_gfx_update()
{
glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
light_shader_update(&light_shader);
pthread_mutex_lock(&mtx_nametagged);
list_itr(&nametagged, &update_nametag_pos, NULL, &refcount_obj);
pthread_mutex_unlock(&mtx_nametagged);
}
ClientEntity *client_entity_grab(u64 id)
@ -69,8 +224,8 @@ void client_entity_transform(ClientEntity *entity)
if (!entity->model)
return;
entity->model->root->pos = (v3f32) {entity->data.pos.x, entity->data.pos.y, entity->data.pos.z};
entity->model->root->rot = (v3f32) {entity->data.rot.x, entity->data.rot.y, entity->data.rot.z};
entity->model->root->pos = v3f64_to_f32(entity->data.pos); // ToDo: the render pipeline needs to be updated to handle 64-bit positions
entity->model->root->rot = entity->data.rot;
if (entity->type->transform)
entity->type->transform(entity);
@ -92,14 +247,17 @@ void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEnti
pkt->data.nametag = NULL;
entity->model = NULL;
pthread_rwlock_init(&entity->lock_pos_rot, NULL);
pthread_rwlock_init(&entity->lock_box_eye, NULL);
pthread_rwlock_init(&entity->lock_nametag, NULL);
entity->nametag = NULL;
if (entity->type->add)
entity->type->add(entity);
update_nametag(entity);
pthread_rwlock_init(&entity->lock_pos_rot, NULL);
pthread_rwlock_init(&entity->lock_nametag, NULL);
pthread_rwlock_init(&entity->lock_box_off, NULL);
if (!map_add(&entities, &entity->data.id, &entity->rc, &cmp_entity, &refcount_inc))
fprintf(stderr, "[warning] failed to add entity %lu\n", entity->data.id);
@ -126,31 +284,13 @@ void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, T
if (entity->type->update_pos_rot)
entity->type->update_pos_rot(entity);
client_entity_transform(entity);
pthread_rwlock_unlock(&entity->lock_pos_rot);
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)
{
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)
entity->type->update_nametag(entity);
update_nametag(entity);
pthread_rwlock_unlock(&entity->lock_nametag);
refcount_drp(&entity->rc);

View File

@ -4,6 +4,7 @@
#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"
@ -14,27 +15,42 @@ typedef struct {
Refcount rc;
Model *model;
GUIElement *nametag;
void *extra;
aabb3f32 box_collision;
aabb3f32 box_culling; // ToDo
mat4x4 *nametag_offset;
pthread_rwlock_t lock_pos_rot;
pthread_rwlock_t lock_box_eye;
pthread_rwlock_t lock_nametag;
pthread_rwlock_t lock_box_off;
} ClientEntity;
// Entity is pronounced N-Tiddy, hmmmm...
typedef struct ClientEntityType {
void (*add )(ClientEntity *entity); // called when server sent addition of entity
void (*remove)(ClientEntity *entity); // called when server sent removal of entity
void (*free )(ClientEntity *entity); // called when entity is garbage collected
void (*update_pos_rot)(ClientEntity *entity);
void (*update_box_eye)(ClientEntity *entity);
void (*update_nametag)(ClientEntity *entity);
void (*transform)(ClientEntity *entity);
} ClientEntityType;
extern ClientEntityType client_entity_types[];
extern Mesh client_entity_cube;
extern ModelShader client_entity_shader;
void client_entity_init();
void client_entity_deinit();
bool client_entity_gfx_init();
void client_entity_gfx_deinit();
void client_entity_gfx_update();
ClientEntity *client_entity_grab(u64 id);
void client_entity_drop(ClientEntity *entity);
@ -43,9 +59,6 @@ void client_entity_transform(ClientEntity *entity);
void client_entity_add(DragonnetPeer *peer, ToClientEntityAdd *pkt);
void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt);
void client_entity_update_pos_rot(DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt);
void client_entity_update_box_eye(DragonnetPeer *peer, ToClientEntityUpdateBoxEye *pkt);
void client_entity_update_nametag(DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt);
extern ClientEntityType client_entity_types[];
#endif // _CLIENT_ENTITY_H_

View File

@ -10,27 +10,41 @@
#include "environment.h"
#include "physics.h"
typedef struct {
ModelNode *nametag;
ModelNode *neck;
ModelNode *eyes;
ModelNode *shoulder_left;
ModelNode *shoulder_right;
ModelNode *hip_left;
ModelNode *hip_right;
} PlayerModelBones;
struct ClientPlayer client_player;
static ClientEntity *player_entity;
static pthread_rwlock_t lock_player_entity;
static Model *player_model;
// updat epos/rot box/eye functions
static void update_eye_pos_camera()
static void update_camera()
{
v3f64 pos = player_entity->data.pos;
v3f32 eye = player_entity->data.eye;
vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
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()
{
pthread_rwlock_rdlock(&player_entity->lock_box_eye);
update_eye_pos_camera();
pthread_rwlock_unlock(&player_entity->lock_box_eye);
debug_menu_changed(ENTRY_POS);
debug_menu_changed(ENTRY_HUMIDITY);
debug_menu_changed(ENTRY_TEMPERATURE);
@ -38,7 +52,7 @@ static void update_pos()
static void update_rot()
{
camera_set_angle(player_entity->data.rot.x, player_entity->data.rot.y);
camera_set_angle(M_PI / 2 - player_entity->data.rot.y, -player_entity->data.rot.x);
debug_menu_changed(ENTRY_YAW);
debug_menu_changed(ENTRY_PITCH);
}
@ -46,66 +60,111 @@ static void update_rot()
static void update_transform()
{
client_entity_transform(player_entity);
update_camera();
}
static void send_pos_rot()
{
update_transform();
dragonnet_peer_send_ToServerPosRot(client, &(ToServerPosRot) {
.pos = player_entity->data.pos,
.rot = player_entity->data.rot,
});
update_transform();
}
static void recv_pos_rot()
{
update_transform();
update_pos();
update_rot();
update_transform();
}
// entity callbacks
static void on_add(ClientEntity *entity)
{
entity->model = model_clone(player_model);
entity->model->extra = refcount_grb(&entity->rc);
PlayerModelBones *bones = entity->extra = malloc(sizeof *bones);
*bones = (PlayerModelBones) {NULL};
model_get_bones(entity->model, (ModelBoneMapping[]) {
{"player.nametag", &bones->nametag },
{"player.neck", &bones->neck },
{"player.neck.head.eyes", &bones->eyes },
{"player.body.upper.shoulders.left", &bones->shoulder_left },
{"player.body.upper.shoulders.right", &bones->shoulder_right},
{"player.body.lower.hips.left", &bones->hip_left },
{"player.body.lower.hips.right", &bones->hip_right },
}, 7);
entity->nametag_offset = bones->nametag ? &bones->nametag->abs : NULL;
entity->box_collision = (aabb3f32) {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.8f, 0.3f}};
model_scene_add(entity->model);
client_entity_transform(entity);
}
static void on_remove(ClientEntity *entity)
{
entity->model->flags.delete = 1;
entity->model = NULL;
}
static void on_free(ClientEntity *entity)
{
free(entity->extra);
}
static void on_transform(ClientEntity *entity)
{
PlayerModelBones *bones = entity->extra;
entity->model->root->rot.x = entity->model->root->rot.z = 0.0f;
if (bones->neck) {
bones->neck->rot.x = entity->data.rot.x;
model_node_transform(bones->neck);
}
}
static void local_on_add(ClientEntity *entity)
{
pthread_rwlock_wrlock(&lock_player_entity);
if (player_entity) {
fprintf(stderr, "[error] attempt to re-add localplayer entity\n");
exit(EXIT_FAILURE);
} else {
player_entity = refcount_grb(&entity->rc);
recv_pos_rot();
entity->type->update_nametag(entity);
}
on_add(entity);
player_entity = refcount_grb(&entity->rc);
recv_pos_rot();
entity->type->update_nametag(entity);
pthread_rwlock_unlock(&lock_player_entity);
}
static void on_remove(ClientEntity *entity)
static void local_on_remove(ClientEntity *entity)
{
pthread_rwlock_wrlock(&lock_player_entity);
refcount_drp(&entity->rc);
player_entity = NULL;
pthread_rwlock_unlock(&lock_player_entity);
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();
}
static void on_update_box_eye(__attribute__((unused)) 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)
static void local_on_update_nametag(ClientEntity *entity)
{
if (entity->data.nametag) {
free(entity->data.nametag);
@ -113,9 +172,16 @@ static void on_update_nametag(ClientEntity *entity)
}
}
static void on_transform(ClientEntity *entity)
static void __attribute__((unused)) on_model_step(Model *model, __attribute__((unused)) f64 dtime)
{
entity->model->root->rot.y = entity->model->root->rot.z = 0.0f;
PlayerModelBones *bones = ((ClientEntity *) model->extra)->extra;
(void) bones;
}
static void on_model_delete(Model *model)
{
if (model->extra)
refcount_drp(&((ClientEntity *) model->extra)->rc);
}
// called on startup
@ -129,23 +195,21 @@ void client_player_init()
.gravity = 0.0f,
};
client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
.add = &on_add,
.remove = &on_remove,
.free = NULL,
.update_pos_rot = &on_update_pos_rot,
.update_box_eye = &on_update_box_eye,
.update_nametag = &on_update_nametag,
.free = &on_free,
.update_pos_rot = NULL,
.update_nametag = NULL,
.transform = &on_transform,
};
client_entity_types[ENTITY_PLAYER] = (ClientEntityType) {
.add = NULL,
.remove = NULL,
.free = NULL,
.update_pos_rot = NULL,
.update_box_eye = NULL,
.update_nametag = NULL,
client_entity_types[ENTITY_LOCALPLAYER] = (ClientEntityType) {
.add = &local_on_add,
.remove = &local_on_remove,
.free = &on_free,
.update_pos_rot = &local_on_update_pos_rot,
.update_nametag = &local_on_update_nametag,
.transform = &on_transform,
};
@ -162,6 +226,21 @@ void client_player_deinit()
pthread_rwlock_destroy(&lock_player_entity);
}
void client_player_gfx_init()
{
player_model = model_load(
RESSOURCE_PATH "models/player.txt", RESSOURCE_PATH "textures/models/player",
&client_entity_cube, &client_entity_shader);
player_model->callbacks.step = &on_model_step;
player_model->callbacks.delete = &on_model_delete;
}
void client_player_gfx_deinit()
{
model_delete(player_model);
}
ClientEntity *client_player_entity()
{
ClientEntity *entity = NULL;
@ -198,33 +277,6 @@ void client_player_update_rot(ClientEntity *entity)
pthread_rwlock_unlock(&lock_player_entity);
}
/*
// create mesh object and info hud
void client_player_add_to_scene()
{
client_player.obj = object_create();
client_player.obj->scale = (v3f32) {0.6, 1.75, 0.6};
client_player.obj->visible = false;
object_set_texture(client_player.obj, texture_load(RESSOURCE_PATH "textures/player.png", true));
for (int f = 0; f < 6; f++) {
for (int v = 0; v < 6; v++) {
Vertex3D vertex = cube_vertices[f][v];
vertex.position.y += 0.5;
object_add_vertex(client_player.obj, &vertex);
}
}
pthread_rwlock_rdlock(&client_player.rwlock);
update_pos();
pthread_rwlock_unlock(&client_player.rwlock);
debug_menu_update_yaw();
debug_menu_update_pitch();
}
*/
// jump if possible
void client_player_jump()
{
@ -233,18 +285,18 @@ void client_player_jump()
return;
pthread_rwlock_rdlock(&entity->lock_pos_rot);
pthread_rwlock_rdlock(&entity->lock_box_eye);
pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_ground(
client_terrain,
client_player.movement.collision,
entity->data.box,
entity->box_collision,
&entity->data.pos,
&client_player.velocity
))
client_player.velocity.y += client_player.movement.jump;
pthread_rwlock_unlock(&entity->lock_box_eye);
pthread_rwlock_unlock(&entity->lock_box_off);
pthread_rwlock_unlock(&entity->lock_pos_rot);
refcount_drp(&entity->rc);
@ -259,12 +311,12 @@ void client_player_tick(f64 dtime)
pthread_rwlock_rdlock(&client_player.lock_movement);
pthread_rwlock_wrlock(&entity->lock_pos_rot);
pthread_rwlock_rdlock(&entity->lock_box_eye);
pthread_rwlock_rdlock(&entity->lock_box_off);
if (physics_step(
client_terrain,
client_player.movement.collision,
entity->data.box,
entity->box_collision,
&entity->data.pos,
&client_player.velocity,
&(v3f64) {
@ -276,7 +328,7 @@ void client_player_tick(f64 dtime)
))
client_player_update_pos(entity);
pthread_rwlock_unlock(&entity->lock_box_eye);
pthread_rwlock_unlock(&entity->lock_box_off);
pthread_rwlock_unlock(&entity->lock_pos_rot);
pthread_rwlock_unlock(&client_player.lock_movement);

View File

@ -14,6 +14,9 @@ extern struct ClientPlayer {
void client_player_init(); // called on startup
void client_player_deinit(); // called on shutdown
void client_player_gfx_init();
void client_player_gfx_deinit();
ClientEntity *client_player_entity(); // grab and return client entity
void client_player_jump(); // jump if possible

View File

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

View File

@ -3,12 +3,14 @@
#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"
@ -73,27 +75,27 @@ static char *get_entry_text(DebugMenuEntry entry)
char *str;
switch (entry) {
case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break;
case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break;
case ENTRY_YAW: asprintf(&str, "yaw = %.1f", rot.x / M_PI * 180.0 ); break;
case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", rot.y / M_PI * 180.0 ); break;
case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break;
case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break;
case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break;
case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break;
case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break;
case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break;
case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break;
case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break;
case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break;
case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); break;
case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); break;
case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break;
case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break;
case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break;
case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break;
case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break;
case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break;
case ENTRY_YAW: asprintf(&str, "yaw = %.1f", 360.0 - rot.y / M_PI * 180.0 ); break;
case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", -rot.x / M_PI * 180.0 ); break;
case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
case ENTRY_DAYLIGHT: asprintf(&str, "daylight = %.2f", get_daylight() ); break;
case ENTRY_SUN_ANGLE: asprintf(&str, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0) ); break;
case ENTRY_HUMIDITY: asprintf(&str, "humidity = %.2f", get_humidity((v3s32) {pos.x, pos.y, pos.z}) ); break;
case ENTRY_TEMPERATURE: asprintf(&str, "temperature = %.2f", get_temperature((v3s32) {pos.x, pos.y, pos.z})); break;
case ENTRY_SEED: asprintf(&str, "seed = %d", seed ); break;
case ENTRY_FLIGHT: asprintf(&str, "flight: %s", flight ? "enabled" : "disabled" ); break;
case ENTRY_COLLISION: asprintf(&str, "collision: %s", collision ? "enabled" : "disabled" ); break;
case ENTRY_TIMELAPSE: asprintf(&str, "timelapse: %s", timelapse ? "enabled" : "disabled" ); break;
case ENTRY_FULLSCREEN: asprintf(&str, "fullscreen: %s", window.fullscreen ? "enabled" : "disabled" ); break;
case ENTRY_OPENGL: asprintf(&str, "OpenGL %s", glGetString(GL_VERSION) ); GL_DEBUG break;
case ENTRY_GPU: asprintf(&str, "%s", glGetString(GL_RENDERER) ); GL_DEBUG break;
case ENTRY_ANTIALIASING: asprintf(&str, "antialiasing: %u samples", client_config.antialiasing ); break;
case ENTRY_MIPMAP: asprintf(&str, "mipmap: %s", client_config.mipmap ? "enabled" : "disabled" ); break;
case ENTRY_VIEW_DISTANCE: asprintf(&str, "view distance: %.1lf", client_config.view_distance ); break;
case ENTRY_LOAD_DISTANCE: asprintf(&str, "load distance: %u", client_terrain_get_load_distance() ); break;
default: break;
}
return str;
@ -113,7 +115,7 @@ void debug_menu_init()
.scale = {1.0f, 1.0f},
.scale_type = SCALE_TEXT,
.affect_parent_scale = false,
.text = strdup(""),
.text = "",
.image = NULL,
.text_color = (v4f32) {1.0f, 1.0f, 1.0f, 1.0f},
.bg_color = (v4f32) {0.0f, 0.0f, 0.0f, 0.0f},
@ -153,8 +155,11 @@ void debug_menu_update()
pthread_mutex_unlock(&changed_elements_mtx);
for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++)
if (changed_elements_cpy[i])
gui_text(gui_elements[i], get_entry_text(i));
if (changed_elements_cpy[i]) {
char *str = get_entry_text(i);
gui_text(gui_elements[i], str);
free(str);
}
}
void debug_menu_changed(DebugMenuEntry entry)

View File

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

View File

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

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

View File

@ -48,7 +48,7 @@ void gui_deinit();
void gui_update_projection();
void gui_render();
GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def);
void gui_text(GUIElement *element, char *text);
void gui_text(GUIElement *element, const char *text);
void gui_transform(GUIElement *element);
#endif // _GUI_H_

View File

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

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 <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);
@ -40,8 +41,8 @@ void mesh_render(Mesh *mesh)
mesh_upload(mesh);
// render
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->count);
glBindVertexArray(mesh->vao); GL_DEBUG
glDrawArrays(GL_TRIANGLES, 0, mesh->count); GL_DEBUG
}
void mesh_destroy(Mesh *mesh)
@ -49,11 +50,13 @@ void mesh_destroy(Mesh *mesh)
if (mesh->data && mesh->free_data)
free(mesh->data);
if (mesh->vao)
glDeleteVertexArrays(1, &mesh->vao);
if (mesh->vao) {
glDeleteVertexArrays(1, &mesh->vao); GL_DEBUG
}
if (mesh->vbo)
glDeleteBuffers(1, &mesh->vbo);
if (mesh->vbo) {
glDeleteBuffers(1, &mesh->vbo); GL_DEBUG
}
mesh->vao = mesh->vbo = 0;
}

View File

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

View File

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

View File

@ -2,6 +2,7 @@
#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)
@ -45,7 +46,7 @@ static GLuint compile_shader(GLenum type, const char *path, const char *name, GL
fclose(file);
GLuint id = glCreateShader(type);
GLuint id = glCreateShader(type); GL_DEBUG
// Minimum OpenGL version is 4.2.0 (idk some shader feature from that version is required)
const char *version = "#version 420 core\n"; // 420 blaze it
@ -62,28 +63,28 @@ static GLuint compile_shader(GLenum type, const char *path, const char *name, GL
size,
};
glShaderSource(id, 3, code_list, size_list);
glShaderSource(id, 3, code_list, size_list); GL_DEBUG
glCompileShader(id);
glCompileShader(id); GL_DEBUG
GLint success;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
glGetShaderiv(id, GL_COMPILE_STATUS, &success); GL_DEBUG
if (!success) {
char errbuf[BUFSIZ];
glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf);
glGetShaderInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
fprintf(stderr, "[error] failed to compile %s shader: %s", name, errbuf);
glDeleteShader(id);
glDeleteShader(id); GL_DEBUG
return 0;
}
glAttachShader(program, id);
glAttachShader(program, id); GL_DEBUG
return id;
}
bool shader_program_create(const char *path, GLuint *idptr, const char *definitions)
{
GLuint id = glCreateProgram();
GLuint id = glCreateProgram(); GL_DEBUG
if (!definitions)
definitions = "";
@ -91,27 +92,27 @@ bool shader_program_create(const char *path, GLuint *idptr, const char *definiti
GLuint vert, frag;
if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) {
glDeleteProgram(id);
glDeleteProgram(id); GL_DEBUG
return false;
}
if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) {
glDeleteShader(vert);
glDeleteProgram(id);
glDeleteShader(vert); GL_DEBUG
glDeleteProgram(id); GL_DEBUG
return false;
}
glLinkProgram(id);
glDeleteShader(vert);
glDeleteShader(frag);
glLinkProgram(id); GL_DEBUG
glDeleteShader(vert); GL_DEBUG
glDeleteShader(frag); GL_DEBUG
GLint success;
glGetProgramiv(id, GL_LINK_STATUS, &success);
glGetProgramiv(id, GL_LINK_STATUS, &success); GL_DEBUG
if (!success) {
char errbuf[BUFSIZ];
glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf);
glGetProgramInfoLog(id, BUFSIZ, NULL, errbuf); GL_DEBUG
fprintf(stderr, "[error] failed to link shader program: %s\n", errbuf);
glDeleteProgram(id);
glDeleteProgram(id); GL_DEBUG
return false;
}

View File

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

View File

@ -2,15 +2,15 @@
#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;
@ -51,14 +51,9 @@ static v3f32 center_offset = {
};
static GLuint shader_prog;
static GLint loc_model;
static GLint loc_VP;
static GLint loc_daylight;
static GLint loc_fogColor;
static GLint loc_ambientLight;
static GLint loc_lightDir;
static GLint loc_cameraPos;
static LightShader light_shader;
static ModelShader model_shader;
static inline bool cull_face(NodeType self, NodeType nbr)
@ -202,7 +197,7 @@ static Model *create_chunk_model(TerrainChunk *chunk, bool animate)
bool terrain_gfx_init()
{
GLint texture_units;
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units);
glGetIntegerv(GL_MAX_TEXTURE_UNITS, &texture_units); GL_DEBUG
char *shader_defs;
asprintf(&shader_defs,
@ -212,58 +207,39 @@ bool terrain_gfx_init()
client_config.view_distance
);
if (!shader_program_create(RESSOURCE_PATH "shaders/terrain", &shader_prog, shader_defs)) {
if (!shader_program_create(RESSOURCE_PATH "shaders/3d/terrain", &shader_prog, shader_defs)) {
fprintf(stderr, "[error] failed to create terrain shader program\n");
return false;
}
free(shader_defs);
loc_model = glGetUniformLocation(shader_prog, "model");
loc_VP = glGetUniformLocation(shader_prog, "VP");
loc_daylight = glGetUniformLocation(shader_prog, "daylight");
loc_fogColor = glGetUniformLocation(shader_prog, "fogColor");
loc_ambientLight = glGetUniformLocation(shader_prog, "ambientLight");
loc_lightDir = glGetUniformLocation(shader_prog, "lightDir");
loc_cameraPos = glGetUniformLocation(shader_prog, "cameraPos");
loc_VP = glGetUniformLocation(shader_prog, "VP"); GL_DEBUG
GLint texture_indices[texture_units];
for (GLint i = 0; i < texture_units; i++)
texture_indices[i] = i;
glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices);
glProgramUniform1iv(shader_prog, glGetUniformLocation(shader_prog, "textures"), texture_units, texture_indices); GL_DEBUG
model_shader.prog = shader_prog;
model_shader.loc_transform = loc_model;
model_shader.loc_transform = glGetUniformLocation(shader_prog, "model"); GL_DEBUG
light_shader.prog = shader_prog;
light_shader_locate(&light_shader);
return true;
}
void terrain_gfx_deinit()
{
glDeleteProgram(shader_prog);
glDeleteProgram(shader_prog); GL_DEBUG
}
void terrain_gfx_update()
{
vec4 base_sunlight_dir = {0.0f, 0.0f, -1.0f, 1.0f};
vec4 sunlight_dir;
mat4x4 sunlight_mat;
mat4x4_identity(sunlight_mat);
mat4x4_rotate(sunlight_mat, sunlight_mat, 1.0f, 0.0f, 0.0f, get_sun_angle() + M_PI / 2.0f);
mat4x4_mul_vec4(sunlight_dir, sunlight_mat, base_sunlight_dir);
f32 daylight = get_daylight();
f32 ambient_light = f32_mix(0.3f, 0.7f, daylight);
v3f32 fog_color = v3f32_mix((v3f32) {0x03, 0x0A, 0x1A}, (v3f32) {0x87, 0xCE, 0xEB}, daylight);
glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]);
glProgramUniform3f(shader_prog, loc_lightDir, sunlight_dir[0], sunlight_dir[1], sunlight_dir[2]);
glProgramUniform3f(shader_prog, loc_cameraPos, camera.eye[0], camera.eye[1], camera.eye[2]);
glProgramUniform1f(shader_prog, loc_daylight, daylight);
glProgramUniform3f(shader_prog, loc_fogColor, fog_color.x / 0xFF * ambient_light, fog_color.y / 0xFF * ambient_light, fog_color.z / 0xFF * ambient_light);
glProgramUniform1f(shader_prog, loc_ambientLight, ambient_light);
glProgramUniformMatrix4fv(shader_prog, loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
light_shader_update(&light_shader);
}
void terrain_gfx_make_chunk_model(TerrainChunk *chunk)
@ -288,13 +264,12 @@ void terrain_gfx_make_chunk_model(TerrainChunk *chunk)
model_node_transform(model->root);
}
meta->model->replace = model;
meta->model->flags.delete = 1;
} else if (model) {
model_scene_add(model);
}
meta->model = model;
if (model)
model_scene_add(model);
pthread_mutex_unlock(&chunk->mtx);
}

View File

@ -1,8 +1,11 @@
#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;
@ -22,7 +25,7 @@ static bool lookup_texture(char *path, Texture **texture)
TreeNode **node = tree_nfd(&textures, path, &cmp_texture);
if (*node) {
*texture = &((TextureLookup *) &(*node)->dat)->texture;
*texture = &((TextureLookup *) (*node)->dat)->texture;
return true;
}
@ -70,14 +73,31 @@ Texture *texture_load(char *path, bool mipmap)
return texture;
}
static inline int least_common_multiple(int a, int b)
{
int high, low;
if (a > b) {
high = a;
low = b;
} else {
high = b;
low = a;
}
int lcm = high;
while (lcm % low)
lcm += high;
return lcm;
}
Texture *texture_load_cubemap(char *path)
{
Texture *texture;
if (lookup_texture(path, &texture))
return texture;
glGenTextures(1, &texture->txo);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo);
glGenTextures(1, &texture->txo); GL_DEBUG
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); GL_DEBUG
const char *directions[6] = {
"right",
@ -88,48 +108,77 @@ Texture *texture_load_cubemap(char *path)
"back",
};
typedef struct {
unsigned char *data;
int width, height, channels;
} CubemapFace;
CubemapFace faces[6];
int size = 1;
for (int i = 0; i < 6; i++) {
char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
sprintf(filename, "%s/%s.png", path, directions[i]);
unsigned char *data = stbi_load(filename,
&texture->width, &texture->height, &texture->channels, 0);
if (!data) {
if (!(faces[i].data = stbi_load(filename,
&faces[i].width, &faces[i].height, &faces[i].channels, 0))) {
fprintf(stderr, "[error] failed to load texture %s\n", filename);
exit(EXIT_FAILURE);
}
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 = least_common_multiple(size, faces[i].width);
size = least_common_multiple(size, faces[i].height);
}
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);
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,
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;
}
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
}

View File

@ -4,6 +4,7 @@
#include "client/client_config.h"
#include "client/debug_menu.h"
#include "client/game.h"
#include "client/gl_debug.h"
#include "client/gui.h"
#include "client/input.h"
#include "client/window.h"
@ -22,7 +23,7 @@ static void update_projection()
static void framebuffer_size_callback(__attribute__((unused)) GLFWwindow *handle, int width, int height)
{
glViewport(0, 0, width, height);
glViewport(0, 0, width, height); GL_DEBUG
window.width = width;
window.height = height;

View File

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

View File

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

View File

@ -34,15 +34,7 @@ static void on_ToServerSetnode(__attribute__((unused)) DragonnetPeer *peer, ToSe
// update player's position
static void on_ToServerPosRot(DragonnetPeer *peer, ToServerPosRot *pkt)
{
ServerPlayer *player = peer->extra;
pthread_rwlock_wrlock(&player->lock_pos);
player->pos = pkt->pos;
player->rot = pkt->rot;
// this is recv thread, no lock_auth needed
database_update_player_pos_rot(player->name, player->pos, player->rot);
pthread_rwlock_unlock(&player->lock_pos);
server_player_move(peer->extra, pkt->pos, pkt->rot);
}
// tell server map manager client requested the chunk

View File

@ -14,6 +14,45 @@
static Map players;
static Map players_named;
static void send_entity_add(ServerPlayer *player, ServerPlayer *entity)
{
dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) {
.type = player == entity ? ENTITY_LOCALPLAYER : ENTITY_PLAYER,
.data = {
.id = entity->id,
.pos = entity->pos,
.rot = entity->rot,
.nametag = entity->name,
},
});
}
static void send_entity_remove(ServerPlayer *player, ServerPlayer *entity)
{
dragonnet_peer_send_ToClientEntityRemove(player->peer, &(ToClientEntityRemove) {
.id = entity->id,
});
}
static void send_entity_update_pos_rot(ServerPlayer *player, ServerPlayer *entity)
{
if (player != entity)
dragonnet_peer_send_ToClientEntityUpdatePosRot(player->peer, &(ToClientEntityUpdatePosRot) {
.id = entity->id,
.pos = entity->pos,
.rot = entity->rot,
});
}
static void send_entity_add_existing(ServerPlayer *entity, ServerPlayer *player)
{
if (player != entity) {
pthread_rwlock_rdlock(&entity->lock_pos);
send_entity_add(player, entity);
pthread_rwlock_unlock(&entity->lock_pos);
}
}
// main thread
// called on server shutdown
static void player_drop(ServerPlayer *player)
@ -71,17 +110,9 @@ static void player_spawn(ServerPlayer *player)
.gravity = server_config.movement.gravity,
.jump = server_config.movement.jump,
});
dragonnet_peer_send_ToClientEntityAdd(player->peer, &(ToClientEntityAdd) {
.type = ENTITY_LOCALPLAYER,
.data = {
.id = player->id,
.pos = player->pos,
.rot = player->rot,
.box = {{-0.3f, 0.0f, -0.3f}, {0.3f, 1.75f, 0.3f}},
.eye = {0.0f, 1.75f, 0.0f},
.nametag = NULL,
},
});
server_player_iterate(&send_entity_add, player);
server_player_iterate(&send_entity_add_existing, player);
}
// any thread
@ -169,8 +200,12 @@ void server_player_remove(DragonnetPeer *peer)
// (we don't want disconnect messages for every player on server shutdown)
if (map_del(&players, &player->id, &cmp_player_id, &refcount_drp, NULL, NULL))
printf("[access] disconnected %s\n", player->name);
if (player->auth)
map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL);
if (player->auth && map_del(&players_named, player->name, &cmp_player_name, &refcount_drp, NULL, NULL)) {
pthread_rwlock_rdlock(&player->lock_pos);
server_player_iterate(&send_entity_remove, player);
pthread_rwlock_unlock(&player->lock_pos);
}
// peer no longer has a reference to player
refcount_drp(&player->rc);
@ -224,6 +259,16 @@ bool server_player_auth(ServerPlayer *player, char *name)
return success;
}
// recv thread
void server_player_move(ServerPlayer *player, v3f64 pos, v3f32 rot)
{
pthread_rwlock_wrlock(&player->lock_pos);
// this is recv thread, no lock_auth needed
database_update_player_pos_rot(player->name, player->pos = pos, player->rot = rot);
server_player_iterate(&send_entity_update_pos_rot, player);
pthread_rwlock_unlock(&player->lock_pos);
}
// any thread
void server_player_disconnect(ServerPlayer *player)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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