Add skybox
|
@ -11,10 +11,9 @@ uniform mat4 MVP;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0);
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0);
|
||||
|
||||
fragmentTextureIndex = vertexTextureIndex;
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
fragmentTextureIndex = vertexTextureIndex;
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
fragmentColor = vertexColor;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,5 +5,5 @@ uniform mat4 projection;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@ uniform mat4 projection;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@ uniform mat4 projection;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
gl_Position = projection * model * vec4(vertexPosition, 0.0, 1.0);
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
in vec3 fragmentTextureCoords;
|
||||
|
||||
out vec4 outColor;
|
||||
|
||||
uniform bool transparency;
|
||||
uniform float daylight;
|
||||
uniform samplerCube textures[2];
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = mix(texture(textures[1], fragmentTextureCoords), texture(textures[0], fragmentTextureCoords), daylight);
|
||||
|
||||
if (transparency) {
|
||||
float f = 0.2;
|
||||
float e = 2.0;
|
||||
|
||||
outColor.a = pow((outColor.r + outColor.g) / 2.0 + f, e) / pow(1.0 + f, e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
layout(location = 0) in vec3 vertexPosition;
|
||||
|
||||
out vec3 fragmentTextureCoords;
|
||||
|
||||
uniform mat4 VP;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = VP * vec4(vertexPosition, 1.0);
|
||||
gl_Position.z = gl_Position.w;
|
||||
fragmentTextureCoords = vertexPosition;
|
||||
}
|
|
@ -7,7 +7,7 @@ uniform mat4 MVP;
|
|||
|
||||
void main()
|
||||
{
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0);
|
||||
gl_Position = MVP * vec4(vertexPosition, 1.0);
|
||||
gl_Position.z = gl_Position.w;
|
||||
fragmentTextureCoords = vertexTextureCoords;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
#define TILES_SIMPLE(path) {.paths = {path, NULL, NULL, NULL, NULL, NULL}, .indices = {0, 0, 0, 0, 0, 0}, .textures = {NULL}}
|
||||
#define TILES_NONE {.paths = {NULL}, .indices = {0}, .textures = {NULL}}
|
||||
|
||||
static f64 clamp(f64 v, f64 min, f64 max)
|
||||
{
|
||||
return v < min ? min : v > max ? max : v;
|
||||
}
|
||||
|
||||
static void render_grass(v3s32 pos, unused MapNode *node, Vertex3D *vertex, unused int f, unused int v)
|
||||
{
|
||||
f32 hum_min, hum_max, temp_max;
|
||||
|
|
|
@ -123,7 +123,7 @@ void debug_menu_update_daylight()
|
|||
void debug_menu_update_sun_angle()
|
||||
{
|
||||
char text[BUFSIZ];
|
||||
sprintf(text, "sun angle = %.1f", get_sun_angle() / M_PI * 180.0);
|
||||
sprintf(text, "sun angle = %.1f", fmod(get_sun_angle() / M_PI * 180.0, 360.0));
|
||||
gui_set_text(gui_elements[DME_SUN_ANGLE], text);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,8 +60,6 @@ static void game_loop(Client *client)
|
|||
|
||||
frames++;
|
||||
|
||||
sky_clear();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
@ -73,8 +71,8 @@ static void game_loop(Client *client)
|
|||
input_tick();
|
||||
client_player_tick(dtime);
|
||||
|
||||
sky_render();
|
||||
scene_render();
|
||||
sky_render();
|
||||
gui_render();
|
||||
|
||||
glfwSwapBuffers(window.handle);
|
||||
|
|
|
@ -32,7 +32,7 @@ bool scene_init()
|
|||
glProgramUniform1iv(scene.prog, glGetUniformLocation(scene.prog, "textures"), scene.max_texture_units, texture_indices);
|
||||
|
||||
scene.fov = 86.1f;
|
||||
scene.render_distance = 1000.0f;
|
||||
scene.render_distance = 255.0f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
139
src/client/sky.c
|
@ -3,6 +3,7 @@
|
|||
#include <GL/gl.h>
|
||||
#include "client/camera.h"
|
||||
#include "client/client.h"
|
||||
#include "client/cube.h"
|
||||
#include "client/mesh.h"
|
||||
#include "client/scene.h"
|
||||
#include "client/shader.h"
|
||||
|
@ -12,6 +13,12 @@
|
|||
|
||||
static struct
|
||||
{
|
||||
GLuint skybox_prog;
|
||||
GLint skybox_loc_VP;
|
||||
GLint skybox_loc_transparency;
|
||||
GLint skybox_loc_daylight;
|
||||
GLuint skybox_textures[2];
|
||||
Mesh *skybox_mesh;
|
||||
GLuint sun_prog;
|
||||
GLint sun_loc_MVP;
|
||||
Texture *sun_texture;
|
||||
|
@ -64,13 +71,77 @@ static VertexSun sun_vertices[6] = {
|
|||
{{-0.5, -0.5, +0.0}, {+0.0, +0.0}},
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GLfloat x, y, z;
|
||||
} __attribute__((packed)) VertexSkyboxPosition;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
VertexSkyboxPosition position;
|
||||
} __attribute__((packed)) VertexSkybox;
|
||||
|
||||
static VertexAttribute skybox_vertex_attributes[2] = {
|
||||
// position
|
||||
{
|
||||
.type = GL_FLOAT,
|
||||
.length = 3,
|
||||
.size = sizeof(VertexSkyboxPosition),
|
||||
},
|
||||
};
|
||||
|
||||
static VertexLayout skybox_vertex_layout = {
|
||||
.attributes = skybox_vertex_attributes,
|
||||
.count = 1,
|
||||
.size = sizeof(VertexSkybox),
|
||||
};
|
||||
|
||||
static VertexSkybox skybox_vertices[6][6];
|
||||
|
||||
bool sky_init()
|
||||
{
|
||||
if (! shader_program_create(RESSOURCEPATH "shaders/sky/skybox", &sky.skybox_prog, NULL)) {
|
||||
fprintf(stderr, "Failed to create skybox shader program\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sky.skybox_loc_VP = glGetUniformLocation(sky.skybox_prog, "VP");
|
||||
sky.skybox_loc_transparency = glGetUniformLocation(sky.skybox_prog, "transparency");
|
||||
sky.skybox_loc_daylight = glGetUniformLocation(sky.skybox_prog, "daylight");
|
||||
|
||||
sky.skybox_textures[0] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/day");
|
||||
sky.skybox_textures[1] = texture_create_cubemap(RESSOURCEPATH "textures/skybox/night");
|
||||
|
||||
GLint texture_indices[2];
|
||||
for (GLint i = 0; i < 2; i++)
|
||||
texture_indices[i] = i;
|
||||
|
||||
glProgramUniform1iv(sky.skybox_prog, glGetUniformLocation(sky.skybox_prog, "textures"), 2, texture_indices);
|
||||
|
||||
for (int f = 0; f < 6; f++) {
|
||||
for (int v = 0; v < 6; v++) {
|
||||
skybox_vertices[f][v].position.x = cube_vertices[f][v].position.x;
|
||||
skybox_vertices[f][v].position.y = cube_vertices[f][v].position.y;
|
||||
skybox_vertices[f][v].position.z = cube_vertices[f][v].position.z;
|
||||
}
|
||||
}
|
||||
|
||||
sky.skybox_mesh = mesh_create();
|
||||
sky.skybox_mesh->textures = sky.skybox_textures;
|
||||
sky.skybox_mesh->textures_count = 2;
|
||||
sky.skybox_mesh->free_textures = false;
|
||||
sky.skybox_mesh->vertices = skybox_vertices;
|
||||
sky.skybox_mesh->vertices_count = 36;
|
||||
sky.skybox_mesh->free_vertices = false;
|
||||
sky.skybox_mesh->layout = &skybox_vertex_layout;
|
||||
|
||||
if (! shader_program_create(RESSOURCEPATH "shaders/sky/sun", &sky.sun_prog, NULL)) {
|
||||
fprintf(stderr, "Failed to create sun shader program\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sky.sun_loc_MVP = glGetUniformLocation(sky.sun_prog, "MVP");
|
||||
|
||||
sky.sun_texture = texture_get(RESSOURCEPATH "textures/sun.png");
|
||||
|
||||
sky.sun_mesh = mesh_create();
|
||||
|
@ -87,17 +158,15 @@ bool sky_init()
|
|||
|
||||
void sky_deinit()
|
||||
{
|
||||
glDeleteProgram(sky.skybox_prog);
|
||||
glDeleteTextures(1, &sky.skybox_textures[0]);
|
||||
glDeleteTextures(1, &sky.skybox_textures[1]);
|
||||
mesh_delete(sky.skybox_mesh);
|
||||
|
||||
glDeleteProgram(sky.sun_prog);
|
||||
mesh_delete(sky.sun_mesh);
|
||||
}
|
||||
|
||||
void sky_clear()
|
||||
{
|
||||
// sky color: #030A1A at night -> #87CEEB at day
|
||||
f64 daylight = get_daylight();
|
||||
glClearColor((daylight * (0x87 - 0x03) + 0x03) / 0xFF, (daylight * (0xCE - 0x0A) + 0x0A) / 0xFF, (daylight * (0xEB - 0x1A) + 0x1A) / 0xFF, 1.0f);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
void sky_render()
|
||||
|
@ -107,46 +176,38 @@ void sky_render()
|
|||
vec3 sun_pos = {0.0f, cos(sun_angle), sin(sun_angle)};
|
||||
vec3_norm(sun_pos, sun_pos);
|
||||
vec3_scale(sun_pos, sun_pos, 5.0f);
|
||||
vec3_add(sun_pos, sun_pos, camera.eye);
|
||||
|
||||
vec3 forward;
|
||||
vec3_sub(forward, camera.eye, sun_pos);
|
||||
vec3_norm(forward, forward);
|
||||
|
||||
vec3 up = {0.0f, 0.0f, 0.0f};
|
||||
if (fabs(forward[0]) == 0.0f && fabs(forward[2]) == 0.0f) {
|
||||
if (forward[2] > 0.0f)
|
||||
up[2] = -1.0f;
|
||||
else
|
||||
up[2] = 1.0f;
|
||||
} else {
|
||||
up[1] = 1.0f;
|
||||
}
|
||||
|
||||
vec3 left;
|
||||
vec3_mul_cross(left, up, forward);
|
||||
vec3_norm(left, left);
|
||||
|
||||
vec3_mul_cross(up, forward, left);
|
||||
|
||||
mat4x4 model = {
|
||||
{left[0], up[0], forward[0], 0.0f},
|
||||
{left[1], up[1], forward[1], 0.0f},
|
||||
{left[2], up[2], forward[2], 0.0f},
|
||||
{sun_pos[0], sun_pos[1], sun_pos[2], 1.0f},
|
||||
};
|
||||
|
||||
mat4x4 model;
|
||||
mat4x4_translate(model, sun_pos[0], sun_pos[1], sun_pos[2]);
|
||||
mat4x4_rotate(model, model, 1.0f, 0.0f, 0.0f, sun_angle + 90);
|
||||
mat4x4_rotate(model, model, 0.0f, 0.0f, 1.0f, M_PI / 4.0f);
|
||||
|
||||
mat4x4 VP, MVP;
|
||||
mat4x4 view;
|
||||
mat4x4_dup(view, camera.view);
|
||||
view[3][0] = 0.0f;
|
||||
view[3][1] = 0.0f;
|
||||
view[3][2] = 0.0f;
|
||||
|
||||
mat4x4_mul(VP, scene.projection, camera.view);
|
||||
mat4x4 VP;
|
||||
mat4x4_mul(VP, scene.projection, view);
|
||||
|
||||
mat4x4 MVP;
|
||||
mat4x4_mul(MVP, VP, model);
|
||||
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
glUseProgram(sky.skybox_prog);
|
||||
glUniformMatrix4fv(sky.skybox_loc_VP, 1, GL_FALSE, VP[0]);
|
||||
glUniform1i(sky.skybox_loc_transparency, 0);
|
||||
glUniform1f(sky.skybox_loc_daylight, get_daylight());
|
||||
mesh_render(sky.skybox_mesh);
|
||||
|
||||
glUseProgram(sky.sun_prog);
|
||||
glUniformMatrix4fv(sky.sun_loc_MVP, 1, GL_FALSE, MVP[0]);
|
||||
glDepthMask(GL_FALSE);
|
||||
mesh_render(sky.sun_mesh);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glUseProgram(sky.skybox_prog);
|
||||
glUniform1i(sky.skybox_loc_transparency, 1);
|
||||
mesh_render(sky.skybox_mesh);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
bool sky_init();
|
||||
void sky_deinit();
|
||||
void sky_clear();
|
||||
void sky_render();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,8 +9,6 @@ static List textures;
|
|||
|
||||
__attribute((constructor(101))) static void textures_init()
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
|
||||
textures = list_create(&list_compare_string);
|
||||
}
|
||||
|
||||
|
@ -47,6 +45,46 @@ Texture *texture_create(unsigned char *data, int width, int height, GLenum forma
|
|||
return texture;
|
||||
}
|
||||
|
||||
GLuint texture_create_cubemap(char *path)
|
||||
{
|
||||
GLuint id;
|
||||
glGenTextures(1, &id);
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
||||
|
||||
const char *directions[6] = {
|
||||
"right",
|
||||
"left",
|
||||
"top",
|
||||
"bottom",
|
||||
"front",
|
||||
"back",
|
||||
};
|
||||
|
||||
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]);
|
||||
|
||||
int width, height, channels;
|
||||
unsigned char *data = stbi_load(filename, &width, &height, &channels, 0);
|
||||
if (! data) {
|
||||
fprintf(stderr, "Failed to load texture %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
stbi_image_free(data);
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void texture_delete(Texture *texture)
|
||||
{
|
||||
glDeleteTextures(1, &texture->id);
|
||||
|
@ -59,7 +97,7 @@ static void *create_image_texture(void *key)
|
|||
|
||||
unsigned char *data = stbi_load(key, &width, &height, &channels, 0);
|
||||
if (! data) {
|
||||
printf("Failed to load texture %s\n", (char *) key);
|
||||
fprintf(stderr, "Failed to load texture %s\n", (char *) key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef struct
|
|||
} Texture;
|
||||
|
||||
Texture *texture_create(unsigned char *data, int width, int height, GLenum format);
|
||||
GLuint texture_create_cubemap(char *path);
|
||||
void texture_delete(Texture *texture);
|
||||
Texture *texture_get(char *path);
|
||||
|
||||
|
|
20
src/day.c
|
@ -9,7 +9,7 @@ f64 get_time_of_day()
|
|||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
|
||||
return fmod((f64) ts.tv_sec - time_of_day_offset + ts.tv_nsec / 1.0e9, MINUTES_PER_DAY);
|
||||
return fmod((f64) ts.tv_sec - time_of_day_offset + ts.tv_nsec / 1.0e9, MINUTES_PER_DAY);
|
||||
}
|
||||
void set_time_of_day(time_t new_time)
|
||||
{
|
||||
|
@ -21,25 +21,9 @@ f64 get_sun_angle()
|
|||
return 2.0 * M_PI * (f64) get_time_of_day() / MINUTES_PER_DAY + M_PI;
|
||||
}
|
||||
|
||||
// workaround for calculating the nth root of a number x, where x may be negative if n is an odd number
|
||||
double root(double x, int n)
|
||||
{
|
||||
double sign = 1.0;
|
||||
|
||||
if (x < 0.0) {
|
||||
if (n % 2 == 0)
|
||||
return 0.0 / 0.0;
|
||||
|
||||
x = -x;
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
return pow(x, 1.0 / (double) n) * sign;
|
||||
}
|
||||
|
||||
f64 get_daylight()
|
||||
{
|
||||
return root(cos(get_sun_angle()), 3) / 2.0 + 0.5;
|
||||
return clamp(cos(get_sun_angle()) * 2.0 + 0.5, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void split_time_of_day(int *hours, int *minutes)
|
||||
|
|
|
@ -114,3 +114,8 @@ bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulatio
|
|||
v3s32 player_block_pos = map_node_to_block_pos((v3s32) {player_pos.x, player_pos.y, player_pos.z}, NULL);
|
||||
return abs(player_block_pos.x - block_pos.x) <= simulation_distance && abs(player_block_pos.y - block_pos.y) <= simulation_distance && abs(player_block_pos.z - block_pos.z) <= simulation_distance;
|
||||
}
|
||||
|
||||
f64 clamp(f64 v, f64 min, f64 max)
|
||||
{
|
||||
return v < min ? min : v > max ? max : v;
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@ v3f32 html_to_v3f32(const char *html); // convert #RRGGBB c
|
|||
void my_compress(const void *uncompressed, size_t uncompressed_size, char **compressed, size_t *compressed_size); // compress data using ZLib and store result(buffer allocated by malloc) in compressed
|
||||
bool my_decompress(const char *compressed, size_t compressed_size, void *decompressed, size_t expected_decompressed_size); // decompress data and put result into decompressed, return false if decompressed size does not match expected_decompressed_size
|
||||
bool within_simulation_distance(v3f64 player_pos, v3s32 block_pos, u32 simulation_distance); // return true if a player is close enough to a block to access it
|
||||
f64 clamp(f64 v, f64 min, f64 max);
|
||||
|
||||
#endif
|
||||
|
|
After Width: | Height: | Size: 203 KiB |
After Width: | Height: | Size: 186 KiB |
After Width: | Height: | Size: 197 KiB |
After Width: | Height: | Size: 205 KiB |
After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 211 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 3.9 KiB |
BIN
textures/sun.png
Before Width: | Height: | Size: 934 B After Width: | Height: | Size: 114 KiB |