You can now see other players
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ define hook-stop
|
|||
quit
|
||||
end
|
||||
end
|
||||
break gl_error
|
||||
"
|
||||
|
||||
echo "$COMMON
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ static void delete_chunk(TerrainChunk *chunk, Terrain *terrain)
|
|||
|
||||
static void delete_sector(TerrainSector *sector, Terrain *terrain)
|
||||
{
|
||||
tree_clr(§or->chunks, (void *) &delete_chunk, terrain, NULL, 0);
|
||||
tree_clr(§or->chunks, &delete_chunk, terrain, NULL, 0);
|
||||
pthread_rwlock_destroy(§or->lock);
|
||||
free(sector);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ Terrain *terrain_create()
|
|||
|
||||
void terrain_delete(Terrain *terrain)
|
||||
{
|
||||
tree_clr(&terrain->sectors, (void *) &delete_sector, terrain, NULL, 0);
|
||||
tree_clr(&terrain->sectors, &delete_sector, terrain, NULL, 0);
|
||||
pthread_rwlock_destroy(&terrain->lock);
|
||||
pthread_rwlock_destroy(&terrain->cache_lock);
|
||||
free(terrain);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 203 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 205 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 4.7 KiB |