From e1cdcf01e9ca9207715154872c4c26f5a5c25dd5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 25 Apr 2021 16:08:48 +0300 Subject: [PATCH] Add files via upload --- res/block.png | Bin 0 -> 13667 bytes res/crosshair.glslf | 7 + res/crosshair.glslv | 7 + res/img.png | Bin 0 -> 342 bytes res/lines.glslf | 8 + res/lines.glslv | 13 ++ res/main.glslf | 14 ++ res/main.glslv | 21 ++ res/screen.glslf | 10 + res/screen.glslv | 10 + src/files/WorldFiles.cpp | 198 +++++++++++++++++ src/files/WorldFiles.h | 38 ++++ src/files/files.cpp | 100 +++++++++ src/files/files.h | 15 ++ src/graphics/LineBatch.cpp | 76 +++++++ src/graphics/LineBatch.h | 32 +++ src/graphics/Mesh.cpp | 45 ++++ src/graphics/Mesh.h | 19 ++ src/graphics/Shader.cpp | 109 +++++++++ src/graphics/Shader.h | 20 ++ src/graphics/Texture.cpp | 31 +++ src/graphics/Texture.h | 21 ++ src/graphics/VoxelRenderer.cpp | 299 +++++++++++++++++++++++++ src/graphics/VoxelRenderer.h | 19 ++ src/lighting/LightSolver.cpp | 122 +++++++++++ src/lighting/LightSolver.h | 29 +++ src/lighting/Lighting.cpp | 246 +++++++++++++++++++++ src/lighting/Lighting.h | 22 ++ src/lighting/Lightmap.cpp | 12 + src/lighting/Lightmap.h | 58 +++++ src/loaders/png_loading.cpp | 125 +++++++++++ src/loaders/png_loading.h | 17 ++ src/voxel_engine.cpp | 276 +++++++++++++++++++++++ src/voxels/Block.cpp | 8 + src/voxels/Block.h | 18 ++ src/voxels/Chunk.cpp | 29 +++ src/voxels/Chunk.h | 24 ++ src/voxels/Chunks.cpp | 388 +++++++++++++++++++++++++++++++++ src/voxels/Chunks.h | 43 ++++ src/voxels/WorldGenerator.cpp | 31 +++ src/voxels/WorldGenerator.h | 11 + src/voxels/voxel.cpp | 2 + src/voxels/voxel.h | 10 + src/window/Camera.cpp | 38 ++++ src/window/Camera.h | 32 +++ src/window/Events.cpp | 105 +++++++++ src/window/Events.h | 32 +++ src/window/Window.cpp | 56 +++++ src/window/Window.h | 20 ++ 49 files changed, 2866 insertions(+) create mode 100644 res/block.png create mode 100644 res/crosshair.glslf create mode 100644 res/crosshair.glslv create mode 100644 res/img.png create mode 100644 res/lines.glslf create mode 100644 res/lines.glslv create mode 100644 res/main.glslf create mode 100644 res/main.glslv create mode 100644 res/screen.glslf create mode 100644 res/screen.glslv create mode 100644 src/files/WorldFiles.cpp create mode 100644 src/files/WorldFiles.h create mode 100644 src/files/files.cpp create mode 100644 src/files/files.h create mode 100644 src/graphics/LineBatch.cpp create mode 100644 src/graphics/LineBatch.h create mode 100644 src/graphics/Mesh.cpp create mode 100644 src/graphics/Mesh.h create mode 100644 src/graphics/Shader.cpp create mode 100644 src/graphics/Shader.h create mode 100644 src/graphics/Texture.cpp create mode 100644 src/graphics/Texture.h create mode 100644 src/graphics/VoxelRenderer.cpp create mode 100644 src/graphics/VoxelRenderer.h create mode 100644 src/lighting/LightSolver.cpp create mode 100644 src/lighting/LightSolver.h create mode 100644 src/lighting/Lighting.cpp create mode 100644 src/lighting/Lighting.h create mode 100644 src/lighting/Lightmap.cpp create mode 100644 src/lighting/Lightmap.h create mode 100644 src/loaders/png_loading.cpp create mode 100644 src/loaders/png_loading.h create mode 100644 src/voxel_engine.cpp create mode 100644 src/voxels/Block.cpp create mode 100644 src/voxels/Block.h create mode 100644 src/voxels/Chunk.cpp create mode 100644 src/voxels/Chunk.h create mode 100644 src/voxels/Chunks.cpp create mode 100644 src/voxels/Chunks.h create mode 100644 src/voxels/WorldGenerator.cpp create mode 100644 src/voxels/WorldGenerator.h create mode 100644 src/voxels/voxel.cpp create mode 100644 src/voxels/voxel.h create mode 100644 src/window/Camera.cpp create mode 100644 src/window/Camera.h create mode 100644 src/window/Events.cpp create mode 100644 src/window/Events.h create mode 100644 src/window/Window.cpp create mode 100644 src/window/Window.h diff --git a/res/block.png b/res/block.png new file mode 100644 index 0000000000000000000000000000000000000000..5f63998d52395084b8452440a2945b61f987051b GIT binary patch literal 13667 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 OTCkq+{f|11asLlgJv(3k literal 0 HcmV?d00001 diff --git a/res/crosshair.glslf b/res/crosshair.glslf new file mode 100644 index 00000000..2cfc3346 --- /dev/null +++ b/res/crosshair.glslf @@ -0,0 +1,7 @@ +#version 330 core + +out vec4 f_color; + +void main(){ + f_color = vec4(1.0); +} diff --git a/res/crosshair.glslv b/res/crosshair.glslv new file mode 100644 index 00000000..5d240912 --- /dev/null +++ b/res/crosshair.glslv @@ -0,0 +1,7 @@ +#version 330 core + +layout (location = 0) in vec2 v_position; + +void main(){ + gl_Position = vec4(v_position, 0.0, 1.0); +} diff --git a/res/img.png b/res/img.png new file mode 100644 index 0000000000000000000000000000000000000000..f7704de173a6d2fcf23f2f9c02851743833aa9ce GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=hEVFv@zmIEGZrNluhVIAHXuLGfwB z|9MjXCvX4wAhdYvSChjhrQF%jmV+C7khzHN(SXLxta>C&eZ`VfgZc{o}-J=PL>BXZIdCV(-VE zaGJG1p~sz%XT=Qe4U9>*n3pshj1=h2VL$W#P)qpX(_ia9o-($J@tMi|g4a#9;bFs) m!`DBEzi8)_lyrxPF)%#!D+}&5S!xRmF9uInKbLh*2~7aubc+7~ literal 0 HcmV?d00001 diff --git a/res/lines.glslf b/res/lines.glslf new file mode 100644 index 00000000..3b42c1ab --- /dev/null +++ b/res/lines.glslf @@ -0,0 +1,8 @@ +#version 330 core + +in vec4 v_color; +out vec4 f_color; + +void main(){ + f_color = v_color; +} diff --git a/res/lines.glslv b/res/lines.glslv new file mode 100644 index 00000000..704a159b --- /dev/null +++ b/res/lines.glslv @@ -0,0 +1,13 @@ +#version 330 core + +layout (location = 0) in vec3 a_position; +layout (location = 1) in vec4 a_color; + +out vec4 v_color; + +uniform mat4 projview; + +void main(){ + v_color = a_color; + gl_Position = projview * vec4(a_position, 1.0); +} diff --git a/res/main.glslf b/res/main.glslf new file mode 100644 index 00000000..42e5d7ae --- /dev/null +++ b/res/main.glslf @@ -0,0 +1,14 @@ +#version 330 core + +in vec4 a_color; +in vec2 a_texCoord; +out vec4 f_color; + +uniform sampler2D u_texture0; + +void main(){ + vec4 tex_color = texture(u_texture0, a_texCoord); + if (tex_color.a < 0.5) + discard; + f_color = a_color * tex_color; +} diff --git a/res/main.glslv b/res/main.glslv new file mode 100644 index 00000000..f2b67588 --- /dev/null +++ b/res/main.glslv @@ -0,0 +1,21 @@ +#version 330 core + +layout (location = 0) in vec3 v_position; +layout (location = 1) in vec2 v_texCoord; +layout (location = 2) in vec4 v_light; + +out vec4 a_color; +out vec2 a_texCoord; + +uniform mat4 model; +uniform mat4 projview; + +void main(){ + vec4 position = projview * model * vec4(v_position, 1.0); + a_color = vec4(v_light.r,v_light.g,v_light.b,1.0f); + a_texCoord = v_texCoord; + a_color.rgb += v_light.a; + a_color.rgb *= 1.0-position.z*0.0025; + //a_color.rgb = pow(a_color.rgb, vec3(1.0/0.7)); + gl_Position = position; +} diff --git a/res/screen.glslf b/res/screen.glslf new file mode 100644 index 00000000..f8db40a1 --- /dev/null +++ b/res/screen.glslf @@ -0,0 +1,10 @@ +#version 330 core + +in vec2 v_coord; +out vec4 f_color; + +uniform sampler2D u_texture; + +void main(){ + f_color = texture(u_texture, v_coord); +} diff --git a/res/screen.glslv b/res/screen.glslv new file mode 100644 index 00000000..391b937e --- /dev/null +++ b/res/screen.glslv @@ -0,0 +1,10 @@ +#version 330 core + +layout (location = 0) in vec2 v_position; + +out vec2 v_coord; + +void main(){ + v_coord = v_position*0.5+0.5; + gl_Position = vec4(v_position, 0.0, 1.0); +} diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp new file mode 100644 index 00000000..d4a8c7e3 --- /dev/null +++ b/src/files/WorldFiles.cpp @@ -0,0 +1,198 @@ +#include "WorldFiles.h" + +#include "files.h" +#include "../voxels/Chunk.h" + +union { + long _key; + int _coords[2]; +} _tempcoords; + +#include +#include +#include +#include +#include + +int bytes2Int(const unsigned char* src, unsigned int offset){ + return (src[offset] << 24) | (src[offset+1] << 16) | (src[offset+2] << 8) | (src[offset+3]); +} + +void int2Bytes(int value, char* dest, unsigned int offset){ + dest[offset] = (char) (value >> 24 & 255); + dest[offset+1] = (char) (value >> 16 & 255); + dest[offset+2] = (char) (value >> 8 & 255); + dest[offset+3] = (char) (value >> 0 & 255); +} + +WorldFiles::WorldFiles(const char* directory, size_t mainBufferCapacity) : directory(directory){ + mainBuffer = new char[mainBufferCapacity]; +} + +WorldFiles::~WorldFiles(){ + delete[] mainBuffer; + std::unordered_map::iterator it; + for (it = regions.begin(); it != regions.end(); it++){ + char** region = it->second; + if (region == nullptr) + continue; + for (unsigned int i = 0; i < REGION_VOL; i++){ + delete[] region[i]; + } + delete[] region; + } + regions.clear(); +} + +void WorldFiles::put(const char* chunkData, int x, int y){ + assert(chunkData != nullptr); + + int regionX = x >> REGION_SIZE_BIT; + int regionY = y >> REGION_SIZE_BIT; + + int localX = x - (regionX << REGION_SIZE_BIT); + int localY = y - (regionY << REGION_SIZE_BIT); + + _tempcoords._coords[0] = regionX; + _tempcoords._coords[1] = regionY; + char** region = regions[_tempcoords._key]; + if (region == nullptr){ + region = new char*[REGION_VOL]; + for (unsigned int i = 0; i < REGION_VOL; i++) + region[i] = nullptr; + regions[_tempcoords._key] = region; + } + char* targetChunk = region[localY * REGION_SIZE + localX]; + if (targetChunk == nullptr){ + targetChunk = new char[CHUNK_VOL]; + region[localY * REGION_SIZE + localX] = targetChunk; + } + for (unsigned int i = 0; i < CHUNK_VOL; i++) + targetChunk[i] = chunkData[i]; +} + +std::string WorldFiles::getRegionFile(int x, int y) { + return directory + std::to_string(x) + "_" + std::to_string(y) + ".bin"; +} + +bool WorldFiles::getChunk(int x, int y, char* out){ + assert(out != nullptr); + + int regionX = x >> REGION_SIZE_BIT; + int regionY = y >> REGION_SIZE_BIT; + + int localX = x - (regionX << REGION_SIZE_BIT); + int localY = y - (regionY << REGION_SIZE_BIT); + int chunkIndex = localY * REGION_SIZE + localX; + assert(chunkIndex >= 0 && chunkIndex < REGION_VOL); + + _tempcoords._coords[0] = regionX; + _tempcoords._coords[1] = regionY; + + char** region = regions[_tempcoords._key]; + if (region == nullptr) + return readChunk(x,y,out); + + char* chunk = region[chunkIndex]; + if (chunk == nullptr) + return readChunk(x,y,out); + for (unsigned int i = 0; i < CHUNK_VOL; i++) + out[i] = chunk[i]; + return true; +} + +bool WorldFiles::readChunk(int x, int y, char* out){ + assert(out != nullptr); + + int regionX = x >> REGION_SIZE_BIT; + int regionY = y >> REGION_SIZE_BIT; + + int localX = x - (regionX << REGION_SIZE_BIT); + int localY = y - (regionY << REGION_SIZE_BIT); + int chunkIndex = localY * REGION_SIZE + localX; + + std::string filename = getRegionFile(regionX, regionY); + + std::ifstream input(filename, std::ios::binary); + if (!input.is_open()){ + return false; + } + + uint32_t offset; + input.seekg(chunkIndex*4); + input.read((char*)(&offset), 4); + // Ordering bytes from big-endian to machine order (any, just reading) + offset = bytes2Int((const unsigned char*)(&offset), 0); + if (offset == 0){ + input.close(); + return false; + } + + input.seekg(offset); + input.read((char*)(&offset), 4); + size_t compressedSize = bytes2Int((const unsigned char*)(&offset), 0); + + input.read(mainBuffer, compressedSize); + input.close(); + + decompressRLE(mainBuffer, compressedSize, out, CHUNK_VOL); + + return true; +} + +void WorldFiles::write(){ + std::unordered_map::iterator it; + for (it = regions.begin(); it != regions.end(); it++){ + if (it->second == nullptr) + continue; + + int x; + int y; + longToCoords(x,y, it->first); + + unsigned int size = writeRegion(mainBuffer, x,y, it->second); + write_binary_file(getRegionFile(x,y), mainBuffer, size); + } +} + +unsigned int WorldFiles::writeRegion(char* out, int x, int y, char** region){ + unsigned int offset = REGION_VOL * 4; + for (unsigned int i = 0; i < offset; i++) + out[i] = 0; + + char* compressed = new char[CHUNK_VOL*2]; + for (int i = 0; i < REGION_VOL; i++){ + char* chunk = region[i]; + if (chunk == nullptr){ + chunk = new char[CHUNK_VOL]; + if (readChunk((i % REGION_SIZE) + x * REGION_SIZE, (i / REGION_SIZE) + y * REGION_SIZE, chunk)){ + region[i] = chunk; + } else { + delete[] chunk; + chunk = nullptr; + } + } + + if (chunk == nullptr){ + int2Bytes(0, out, i*4); + } else { + int2Bytes(offset, out, i*4); + + unsigned int compressedSize = compressRLE(chunk, CHUNK_VOL, compressed); + + int2Bytes(compressedSize, out, offset); + offset += 4; + + for (unsigned int j = 0; j < compressedSize; j++) + out[offset++] = compressed[j]; + } + } + delete[] compressed; + return offset; +} + +void longToCoords(int& x, int& y, long key) { + _tempcoords._key = key; + x = _tempcoords._coords[0]; + y = _tempcoords._coords[1]; +} diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h new file mode 100644 index 00000000..bc816adf --- /dev/null +++ b/src/files/WorldFiles.h @@ -0,0 +1,38 @@ +#ifndef FILES_WORLDFILES_H_ +#define FILES_WORLDFILES_H_ + +#include +#include + +#define REGION_SIZE_BIT 5 +#define REGION_SIZE (1 << (REGION_SIZE_BIT)) +#define REGION_VOL ((REGION_SIZE) * (REGION_SIZE)) + +/* Требование: + * - высота мира = 1 чанк (любых размеров) + * Пример: + * - CHUNK_W = 16, CHUNK_H = 128, CHUNK_D = 16 + * */ +class WorldFiles { +public: + std::unordered_map regions; + std::string directory; + char* mainBuffer; + + WorldFiles(const char* directory, size_t mainBufferCapacity); + ~WorldFiles(); + + void put(const char* chunkData, int x, int y); + + bool readChunk(int x, int y, char* out); + bool getChunk(int x, int y, char* out); + void readRegion(char* fileContent); + unsigned int writeRegion(char* out, int x, int y, char** region); + void write(); + + std::string getRegionFile(int x, int y); +}; + +extern void longToCoords(int& x, int& y, long key); + +#endif /* FILES_WORLDFILES_H_ */ diff --git a/src/files/files.cpp b/src/files/files.cpp new file mode 100644 index 00000000..3b6e8881 --- /dev/null +++ b/src/files/files.cpp @@ -0,0 +1,100 @@ +#include "files.h" + +#include +#include + +bool write_binary_file_part(std::string filename, const char* data, size_t offset, size_t size){ + std::ofstream output(filename, std::ios::out | std::ios::binary | std::ios::in); + if (!output.is_open()) + return false; + output.seekp(offset); + output.write(data, size); + return true; +} + +bool write_binary_file(std::string filename, const char* data, size_t size) { + std::ofstream output(filename, std::ios::binary); + if (!output.is_open()) + return false; + output.write(data, size); + output.close(); + return true; +} + +unsigned int append_binary_file(std::string filename, const char* data, size_t size) { + std::ofstream output(filename, std::ios::binary | std::ios::app); + if (!output.is_open()) + return 0; + unsigned int position = output.tellp(); + output.write(data, size); + output.close(); + return position; +} + +bool read_binary_file(std::string filename, char* data, size_t size) { + std::ifstream output(filename, std::ios::binary); + if (!output.is_open()) + return false; + output.read(data, size); + output.close(); + return true; +} + +bool read_binary_file(std::string filename, char* data, size_t offset, size_t size) { + std::ifstream input(filename, std::ios::binary); + if (!input.is_open()) + return false; + input.seekg(offset); + input.read(data, size); + input.close(); + return true; +} + +// returns decompressed length +unsigned int decompressRLE(const char* src, unsigned int length, char* dst, unsigned int targetLength){ + unsigned int offset = 0; + for (unsigned int i = 0; i < length;){ + unsigned char counter = src[i++]; + char c = src[i++]; + for (unsigned int j = 0; j <= counter; j++){ + dst[offset++] = c; + } + } + return offset; +} + +unsigned int calcRLE(const char* src, unsigned int length) { + unsigned int offset = 0; + unsigned int counter = 1; + char c = src[0]; + for (unsigned int i = 0; i < length; i++){ + char cnext = src[i]; + if (cnext != c || counter == 256){ + offset += 2; + c = cnext; + counter = 0; + } + counter++; + } + return offset + 2; +} + +// max result size = length * 2; returns compressed length +unsigned int compressRLE(const char* src, unsigned int length, char* dst) { + unsigned int offset = 0; + unsigned int counter = 1; + char c = src[0]; + for (unsigned int i = 1; i < length; i++){ + char cnext = src[i]; + if (cnext != c || counter == 256){ + dst[offset++] = counter-1; + dst[offset++] = c; + c = cnext; + counter = 0; + } + counter++; + } + dst[offset++] = counter-1; + dst[offset++] = c; + return offset; +} diff --git a/src/files/files.h b/src/files/files.h new file mode 100644 index 00000000..6e75175a --- /dev/null +++ b/src/files/files.h @@ -0,0 +1,15 @@ +#ifndef FILES_FILES_H_ +#define FILES_FILES_H_ + +#include + +extern bool write_binary_file(std::string filename, const char* data, size_t size); +extern unsigned int append_binary_file(std::string filename, const char* data, size_t size); +extern bool read_binary_file(std::string filename, char* data, size_t size); +extern bool read_binary_file(std::string filename, char* data, size_t offset, size_t size); + +extern unsigned int calcRLE(const char* src, unsigned int length); +extern unsigned int compressRLE(const char* src, unsigned int length, char* dst); +extern unsigned int decompressRLE(const char* src, unsigned int length, char* dst, unsigned int targetLength); + +#endif /* FILES_FILES_H_ */ diff --git a/src/graphics/LineBatch.cpp b/src/graphics/LineBatch.cpp new file mode 100644 index 00000000..eab957d4 --- /dev/null +++ b/src/graphics/LineBatch.cpp @@ -0,0 +1,76 @@ +/* + * LineBatch.cpp + * + * Created on: Jun 25, 2020 + * Author: MihailRis + */ + +#include "LineBatch.h" +#include "Mesh.h" + +#include + +#define LB_VERTEX_SIZE (3+4) + +LineBatch::LineBatch(size_t capacity) : capacity(capacity) { + int attrs[] = {3,4, 0}; + buffer = new float[capacity * LB_VERTEX_SIZE * 2]; + mesh = new Mesh(buffer, 0, attrs); + index = 0; +} + +LineBatch::~LineBatch(){ + delete[] buffer; + delete mesh; +} + +void LineBatch::line(float x1, float y1, float z1, float x2, float y2, float z2, + float r, float g, float b, float a) { + buffer[index] = x1; + buffer[index+1] = y1; + buffer[index+2] = z1; + buffer[index+3] = r; + buffer[index+4] = g; + buffer[index+5] = b; + buffer[index+6] = a; + index += LB_VERTEX_SIZE; + + buffer[index] = x2; + buffer[index+1] = y2; + buffer[index+2] = z2; + buffer[index+3] = r; + buffer[index+4] = g; + buffer[index+5] = b; + buffer[index+6] = a; + index += LB_VERTEX_SIZE; +} + +void LineBatch::box(float x, float y, float z, float w, float h, float d, + float r, float g, float b, float a) { + w *= 0.5f; + h *= 0.5f; + d *= 0.5f; + + line(x-w, y-h, z-d, x+w, y-h, z-d, r,g,b,a); + line(x-w, y+h, z-d, x+w, y+h, z-d, r,g,b,a); + line(x-w, y-h, z+d, x+w, y-h, z+d, r,g,b,a); + line(x-w, y+h, z+d, x+w, y+h, z+d, r,g,b,a); + + line(x-w, y-h, z-d, x-w, y+h, z-d, r,g,b,a); + line(x+w, y-h, z-d, x+w, y+h, z-d, r,g,b,a); + line(x-w, y-h, z+d, x-w, y+h, z+d, r,g,b,a); + line(x+w, y-h, z+d, x+w, y+h, z+d, r,g,b,a); + + line(x-w, y-h, z-d, x-w, y-h, z+d, r,g,b,a); + line(x+w, y-h, z-d, x+w, y-h, z+d, r,g,b,a); + line(x-w, y+h, z-d, x-w, y+h, z+d, r,g,b,a); + line(x+w, y+h, z-d, x+w, y+h, z+d, r,g,b,a); +} + +void LineBatch::render(){ + if (index == 0) + return; + mesh->reload(buffer, index / LB_VERTEX_SIZE); + mesh->draw(GL_LINES); + index = 0; +} diff --git a/src/graphics/LineBatch.h b/src/graphics/LineBatch.h new file mode 100644 index 00000000..99cfaa29 --- /dev/null +++ b/src/graphics/LineBatch.h @@ -0,0 +1,32 @@ +/* + * LineBatch.h + * + * Created on: Jun 25, 2020 + * Author: MihailRis + */ + +#ifndef GRAPHICS_LINEBATCH_H_ +#define GRAPHICS_LINEBATCH_H_ + +#include + +class Mesh; + +class LineBatch { + Mesh* mesh; + float* buffer; + size_t index; + size_t capacity; +public: + LineBatch(size_t capacity); + ~LineBatch(); + + void line(float x1, float y1, float z1, float x2, float y2, float z2, + float r, float g, float b, float a); + void box(float x, float y, float z, float w, float h, float d, + float r, float g, float b, float a); + + void render(); +}; + +#endif /* GRAPHICS_LINEBATCH_H_ */ diff --git a/src/graphics/Mesh.cpp b/src/graphics/Mesh.cpp new file mode 100644 index 00000000..678115f0 --- /dev/null +++ b/src/graphics/Mesh.cpp @@ -0,0 +1,45 @@ +#include "Mesh.h" +#include + +Mesh::Mesh(const float* buffer, size_t vertices, const int* attrs) : vertices(vertices){ + vertexSize = 0; + for (int i = 0; attrs[i]; i++){ + vertexSize += attrs[i]; + } + + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, buffer, GL_STATIC_DRAW); + + // attributes + int offset = 0; + for (int i = 0; attrs[i]; i++){ + int size = attrs[i]; + glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float))); + glEnableVertexAttribArray(i); + offset += size; + } + + glBindVertexArray(0); +} + +Mesh::~Mesh(){ + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vbo); +} + +void Mesh::reload(const float* buffer, size_t vertices){ + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, buffer, GL_STATIC_DRAW); + this->vertices = vertices; +} + +void Mesh::draw(unsigned int primitive){ + glBindVertexArray(vao); + glDrawArrays(primitive, 0, vertices); + glBindVertexArray(0); +} diff --git a/src/graphics/Mesh.h b/src/graphics/Mesh.h new file mode 100644 index 00000000..12c74fc0 --- /dev/null +++ b/src/graphics/Mesh.h @@ -0,0 +1,19 @@ +#ifndef GRAPHICS_MESH_H_ +#define GRAPHICS_MESH_H_ + +#include + +class Mesh { + unsigned int vao; + unsigned int vbo; + size_t vertices; + size_t vertexSize; +public: + Mesh(const float* buffer, size_t vertices, const int* attrs); + ~Mesh(); + + void reload(const float* buffer, size_t vertices); + void draw(unsigned int primitive); +}; + +#endif /* GRAPHICS_MESH_H_ */ diff --git a/src/graphics/Shader.cpp b/src/graphics/Shader.cpp new file mode 100644 index 00000000..34108c55 --- /dev/null +++ b/src/graphics/Shader.cpp @@ -0,0 +1,109 @@ +#include "Shader.h" + +#include +#include +#include +#include + +#include + +#include +#include + +Shader::Shader(unsigned int id) : id(id){ +} + +Shader::~Shader(){ + glDeleteProgram(id); +} + +void Shader::use(){ + glUseProgram(id); +} + +void Shader::uniformMatrix(std::string name, glm::mat4 matrix){ + GLuint transformLoc = glGetUniformLocation(id, name.c_str()); + glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(matrix)); +} + + +Shader* load_shader(std::string vertexFile, std::string fragmentFile) { + // Reading Files + std::string vertexCode; + std::string fragmentCode; + std::ifstream vShaderFile; + std::ifstream fShaderFile; + + vShaderFile.exceptions(std::ifstream::badbit); + fShaderFile.exceptions(std::ifstream::badbit); + try { + vShaderFile.open(vertexFile); + fShaderFile.open(fragmentFile); + std::stringstream vShaderStream, fShaderStream; + + vShaderStream << vShaderFile.rdbuf(); + fShaderStream << fShaderFile.rdbuf(); + + vShaderFile.close(); + fShaderFile.close(); + + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + } + catch(std::ifstream::failure& e) { + std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; + return nullptr; + } + const GLchar* vShaderCode = vertexCode.c_str(); + const GLchar* fShaderCode = fragmentCode.c_str(); + + GLuint vertex, fragment; + GLint success; + GLchar infoLog[512]; + + // Vertex Shader + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vShaderCode, nullptr); + glCompileShader(vertex); + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success){ + glGetShaderInfoLog(vertex, 512, nullptr, infoLog); + std::cerr << "SHADER::VERTEX: compilation failed" << std::endl; + std::cerr << infoLog << std::endl; + return nullptr; + } + + // Fragment Shader + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fShaderCode, nullptr); + glCompileShader(fragment); + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if (!success){ + glGetShaderInfoLog(fragment, 512, nullptr, infoLog); + std::cerr << "SHADER::FRAGMENT: compilation failed" << std::endl; + std::cerr << infoLog << std::endl; + return nullptr; + } + + // Shader Program + GLuint id = glCreateProgram(); + glAttachShader(id, vertex); + glAttachShader(id, fragment); + glLinkProgram(id); + + glGetProgramiv(id, GL_LINK_STATUS, &success); + if (!success){ + glGetProgramInfoLog(id, 512, nullptr, infoLog); + std::cerr << "SHADER::PROGRAM: linking failed" << std::endl; + std::cerr << infoLog << std::endl; + + glDeleteShader(vertex); + glDeleteShader(fragment); + return nullptr; + } + + glDeleteShader(vertex); + glDeleteShader(fragment); + + return new Shader(id); +} diff --git a/src/graphics/Shader.h b/src/graphics/Shader.h new file mode 100644 index 00000000..baed340d --- /dev/null +++ b/src/graphics/Shader.h @@ -0,0 +1,20 @@ +#ifndef GRAPHICS_SHADER_H_ +#define GRAPHICS_SHADER_H_ + +#include +#include + +class Shader { +public: + unsigned int id; + + Shader(unsigned int id); + ~Shader(); + + void use(); + void uniformMatrix(std::string name, glm::mat4 matrix); +}; + +extern Shader* load_shader(std::string vertexFile, std::string fragmentFile); + +#endif /* GRAPHICS_SHADER_H_ */ diff --git a/src/graphics/Texture.cpp b/src/graphics/Texture.cpp new file mode 100644 index 00000000..4516c03a --- /dev/null +++ b/src/graphics/Texture.cpp @@ -0,0 +1,31 @@ +#include "Texture.h" +#include + +Texture::Texture(unsigned int id, int width, int height) : id(id), width(width), height(height) { +} + +Texture::Texture(unsigned char* data, int width, int height) : width(width), height(height) { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); +} + +Texture::~Texture() { + glDeleteTextures(1, &id); +} + +void Texture::bind(){ + glBindTexture(GL_TEXTURE_2D, id); +} + +void Texture::reload(unsigned char* data){ + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data); + glBindTexture(GL_TEXTURE_2D, 0); +} diff --git a/src/graphics/Texture.h b/src/graphics/Texture.h new file mode 100644 index 00000000..0a185aae --- /dev/null +++ b/src/graphics/Texture.h @@ -0,0 +1,21 @@ +#ifndef GRAPHICS_TEXTURE_H_ +#define GRAPHICS_TEXTURE_H_ + +#include + +class Texture { +public: + unsigned int id; + int width; + int height; + Texture(unsigned int id, int width, int height); + Texture(unsigned char* data, int width, int height); + ~Texture(); + + void bind(); + void reload(unsigned char* data); +}; + +extern Texture* load_texture(std::string filename); + +#endif /* GRAPHICS_TEXTURE_H_ */ diff --git a/src/graphics/VoxelRenderer.cpp b/src/graphics/VoxelRenderer.cpp new file mode 100644 index 00000000..6dbf2c9a --- /dev/null +++ b/src/graphics/VoxelRenderer.cpp @@ -0,0 +1,299 @@ +#include "VoxelRenderer.h" +#include "Mesh.h" +#include "../voxels/Chunk.h" +#include "../voxels/voxel.h" +#include "../voxels/Block.h" +#include "../lighting/Lightmap.h" + +#define VERTEX_SIZE (3 + 2 + 4) + +#define CDIV(X,A) (((X) < 0) ? ((X) / (A) - 1) : ((X) / (A))) +#define LOCAL_NEG(X, SIZE) (((X) < 0) ? ((SIZE)+(X)) : (X)) +#define LOCAL(X, SIZE) ((X) >= (SIZE) ? ((X) - (SIZE)) : LOCAL_NEG(X, SIZE)) +#define IS_CHUNK(X,Y,Z) (GET_CHUNK(X,Y,Z) != nullptr) +#define GET_CHUNK(X,Y,Z) (chunks[((CDIV(Y, CHUNK_H)+1) * 3 + CDIV(Z, CHUNK_D) + 1) * 3 + CDIV(X, CHUNK_W) + 1]) + +#define LIGHT(X,Y,Z, CHANNEL) (IS_CHUNK(X,Y,Z) ? GET_CHUNK(X,Y,Z)->lightmap->get(LOCAL(X, CHUNK_W), LOCAL(Y, CHUNK_H), LOCAL(Z, CHUNK_D), (CHANNEL)) : 0) +#define VOXEL(X,Y,Z) (GET_CHUNK(X,Y,Z)->voxels[(LOCAL(Y, CHUNK_H) * CHUNK_D + LOCAL(Z, CHUNK_D)) * CHUNK_W + LOCAL(X, CHUNK_W)]) +#define IS_BLOCKED(X,Y,Z,GROUP) ((!IS_CHUNK(X, Y, Z)) || Block::blocks[VOXEL(X, Y, Z).id]->drawGroup == (GROUP)) + +#define VERTEX(INDEX, X,Y,Z, U,V, R,G,B,S) buffer[INDEX+0] = (X);\ + buffer[INDEX+1] = (Y);\ + buffer[INDEX+2] = (Z);\ + buffer[INDEX+3] = (U);\ + buffer[INDEX+4] = (V);\ + buffer[INDEX+5] = (R);\ + buffer[INDEX+6] = (G);\ + buffer[INDEX+7] = (B);\ + buffer[INDEX+8] = (S);\ + INDEX += VERTEX_SIZE; + + +#define SETUP_UV(INDEX) float u1 = ((INDEX) % 16) * uvsize;\ + float v1 = 1-((1 + (INDEX) / 16) * uvsize);\ + float u2 = u1 + uvsize;\ + float v2 = v1 + uvsize; + +int chunk_attrs[] = {3,2,4, 0}; + +VoxelRenderer::VoxelRenderer(size_t capacity) : capacity(capacity) { + buffer = new float[capacity * VERTEX_SIZE * 6]; +} + +VoxelRenderer::~VoxelRenderer(){ + delete[] buffer; +} + +Mesh* VoxelRenderer::render(Chunk* chunk, const Chunk** chunks){ + size_t index = 0; + for (int y = 0; y < CHUNK_H; y++){ + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + voxel vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x]; + unsigned int id = vox.id; + + if (!id){ + continue; + } + + float l; + float uvsize = 1.0f/16.0f; + + Block* block = Block::blocks[id]; + unsigned char group = block->drawGroup; + + if (!IS_BLOCKED(x,y+1,z,group)){ + l = 1.0f; + + SETUP_UV(block->textureFaces[3]); + + float lr = LIGHT(x,y+1,z, 0) / 15.0f; + float lg = LIGHT(x,y+1,z, 1) / 15.0f; + float lb = LIGHT(x,y+1,z, 2) / 15.0f; + float ls = LIGHT(x,y+1,z, 3) / 15.0f; + + float lr0 = (LIGHT(x-1,y+1,z,0) + lr*30 + LIGHT(x-1,y+1,z-1,0) + LIGHT(x,y+1,z-1,0)) / 5.0f / 15.0f; + float lr1 = (LIGHT(x-1,y+1,z,0) + lr*30 + LIGHT(x-1,y+1,z+1,0) + LIGHT(x,y+1,z+1,0)) / 5.0f / 15.0f; + float lr2 = (LIGHT(x+1,y+1,z,0) + lr*30 + LIGHT(x+1,y+1,z+1,0) + LIGHT(x,y+1,z+1,0)) / 5.0f / 15.0f; + float lr3 = (LIGHT(x+1,y+1,z,0) + lr*30 + LIGHT(x+1,y+1,z-1,0) + LIGHT(x,y+1,z-1,0)) / 5.0f / 15.0f; + + float lg0 = (LIGHT(x-1,y+1,z,1) + lg*30 + LIGHT(x-1,y+1,z-1,1) + LIGHT(x,y+1,z-1,1)) / 5.0f / 15.0f; + float lg1 = (LIGHT(x-1,y+1,z,1) + lg*30 + LIGHT(x-1,y+1,z+1,1) + LIGHT(x,y+1,z+1,1)) / 5.0f / 15.0f; + float lg2 = (LIGHT(x+1,y+1,z,1) + lg*30 + LIGHT(x+1,y+1,z+1,1) + LIGHT(x,y+1,z+1,1)) / 5.0f / 15.0f; + float lg3 = (LIGHT(x+1,y+1,z,1) + lg*30 + LIGHT(x+1,y+1,z-1,1) + LIGHT(x,y+1,z-1,1)) / 5.0f / 15.0f; + + float lb0 = (LIGHT(x-1,y+1,z,2) + lb*30 + LIGHT(x-1,y+1,z-1,2) + LIGHT(x,y+1,z-1,2)) / 5.0f / 15.0f; + float lb1 = (LIGHT(x-1,y+1,z,2) + lb*30 + LIGHT(x-1,y+1,z+1,2) + LIGHT(x,y+1,z+1,2)) / 5.0f / 15.0f; + float lb2 = (LIGHT(x+1,y+1,z,2) + lb*30 + LIGHT(x+1,y+1,z+1,2) + LIGHT(x,y+1,z+1,2)) / 5.0f / 15.0f; + float lb3 = (LIGHT(x+1,y+1,z,2) + lb*30 + LIGHT(x+1,y+1,z-1,2) + LIGHT(x,y+1,z-1,2)) / 5.0f / 15.0f; + + float ls0 = (LIGHT(x-1,y+1,z,3) + ls*30 + LIGHT(x-1,y+1,z-1,3) + LIGHT(x,y+1,z-1,3)) / 5.0f / 15.0f; + float ls1 = (LIGHT(x-1,y+1,z,3) + ls*30 + LIGHT(x-1,y+1,z+1,3) + LIGHT(x,y+1,z+1,3)) / 5.0f / 15.0f; + float ls2 = (LIGHT(x+1,y+1,z,3) + ls*30 + LIGHT(x+1,y+1,z+1,3) + LIGHT(x,y+1,z+1,3)) / 5.0f / 15.0f; + float ls3 = (LIGHT(x+1,y+1,z,3) + ls*30 + LIGHT(x+1,y+1,z-1,3) + LIGHT(x,y+1,z-1,3)) / 5.0f / 15.0f; + + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v1, lr0, lg0, lb0, ls0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, lr1, lg1, lb1, ls1); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, lr2, lg2, lb2, ls2); + + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v1, lr0, lg0, lb0, ls0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, lr2, lg2, lb2, ls2); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v1, lr3, lg3, lb3, ls3); + } + if (!IS_BLOCKED(x,y-1,z,group)){ + l = 0.75f; + + SETUP_UV(block->textureFaces[2]); + + float lr = LIGHT(x,y-1,z, 0) / 15.0f; + float lg = LIGHT(x,y-1,z, 1) / 15.0f; + float lb = LIGHT(x,y-1,z, 2) / 15.0f; + float ls = LIGHT(x,y-1,z, 3) / 15.0f; + + float lr0 = (LIGHT(x-1,y-1,z-1,0) + lr*30 + LIGHT(x-1,y-1,z,0) + LIGHT(x,y-1,z-1,0)) / 5.0f / 15.0f; + float lr1 = (LIGHT(x+1,y-1,z+1,0) + lr*30 + LIGHT(x+1,y-1,z,0) + LIGHT(x,y-1,z+1,0)) / 5.0f / 15.0f; + float lr2 = (LIGHT(x-1,y-1,z+1,0) + lr*30 + LIGHT(x-1,y-1,z,0) + LIGHT(x,y-1,z+1,0)) / 5.0f / 15.0f; + float lr3 = (LIGHT(x+1,y-1,z-1,0) + lr*30 + LIGHT(x+1,y-1,z,0) + LIGHT(x,y-1,z-1,0)) / 5.0f / 15.0f; + + float lg0 = (LIGHT(x-1,y-1,z-1,1) + lg*30 + LIGHT(x-1,y-1,z,1) + LIGHT(x,y-1,z-1,1)) / 5.0f / 15.0f; + float lg1 = (LIGHT(x+1,y-1,z+1,1) + lg*30 + LIGHT(x+1,y-1,z,1) + LIGHT(x,y-1,z+1,1)) / 5.0f / 15.0f; + float lg2 = (LIGHT(x-1,y-1,z+1,1) + lg*30 + LIGHT(x-1,y-1,z,1) + LIGHT(x,y-1,z+1,1)) / 5.0f / 15.0f; + float lg3 = (LIGHT(x+1,y-1,z-1,1) + lg*30 + LIGHT(x+1,y-1,z,1) + LIGHT(x,y-1,z-1,1)) / 5.0f / 15.0f; + + float lb0 = (LIGHT(x-1,y-1,z-1,2) + lb*30 + LIGHT(x-1,y-1,z,2) + LIGHT(x,y-1,z-1,2)) / 5.0f / 15.0f; + float lb1 = (LIGHT(x+1,y-1,z+1,2) + lb*30 + LIGHT(x+1,y-1,z,2) + LIGHT(x,y-1,z+1,2)) / 5.0f / 15.0f; + float lb2 = (LIGHT(x-1,y-1,z+1,2) + lb*30 + LIGHT(x-1,y-1,z,2) + LIGHT(x,y-1,z+1,2)) / 5.0f / 15.0f; + float lb3 = (LIGHT(x+1,y-1,z-1,2) + lb*30 + LIGHT(x+1,y-1,z,2) + LIGHT(x,y-1,z-1,2)) / 5.0f / 15.0f; + + float ls0 = (LIGHT(x-1,y-1,z-1,3) + ls*30 + LIGHT(x-1,y-1,z,3) + LIGHT(x,y-1,z-1,3)) / 5.0f / 15.0f; + float ls1 = (LIGHT(x+1,y-1,z+1,3) + ls*30 + LIGHT(x+1,y-1,z,3) + LIGHT(x,y-1,z+1,3)) / 5.0f / 15.0f; + float ls2 = (LIGHT(x-1,y-1,z+1,3) + ls*30 + LIGHT(x-1,y-1,z,3) + LIGHT(x,y-1,z+1,3)) / 5.0f / 15.0f; + float ls3 = (LIGHT(x+1,y-1,z-1,3) + ls*30 + LIGHT(x+1,y-1,z,3) + LIGHT(x,y-1,z-1,3)) / 5.0f / 15.0f; + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, lr3,lg3,lb3,ls3); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + } + + if (!IS_BLOCKED(x+1,y,z,group)){ + l = 0.95f; + + SETUP_UV(block->textureFaces[1]); + + float lr = LIGHT(x+1,y,z, 0) / 15.0f; + float lg = LIGHT(x+1,y,z, 1) / 15.0f; + float lb = LIGHT(x+1,y,z, 2) / 15.0f; + float ls = LIGHT(x+1,y,z, 3) / 15.0f; + + float lr0 = (LIGHT(x+1,y-1,z-1,0) + lr*30 + LIGHT(x+1,y,z-1,0) + LIGHT(x+1,y-1,z,0)) / 5.0f / 15.0f; + float lr1 = (LIGHT(x+1,y+1,z-1,0) + lr*30 + LIGHT(x+1,y,z-1,0) + LIGHT(x+1,y+1,z,0)) / 5.0f / 15.0f; + float lr2 = (LIGHT(x+1,y+1,z+1,0) + lr*30 + LIGHT(x+1,y,z+1,0) + LIGHT(x+1,y+1,z,0)) / 5.0f / 15.0f; + float lr3 = (LIGHT(x+1,y-1,z+1,0) + lr*30 + LIGHT(x+1,y,z+1,0) + LIGHT(x+1,y-1,z,0)) / 5.0f / 15.0f; + + float lg0 = (LIGHT(x+1,y-1,z-1,1) + lg*30 + LIGHT(x+1,y,z-1,1) + LIGHT(x+1,y-1,z,1)) / 5.0f / 15.0f; + float lg1 = (LIGHT(x+1,y+1,z-1,1) + lg*30 + LIGHT(x+1,y,z-1,1) + LIGHT(x+1,y+1,z,1)) / 5.0f / 15.0f; + float lg2 = (LIGHT(x+1,y+1,z+1,1) + lg*30 + LIGHT(x+1,y,z+1,1) + LIGHT(x+1,y+1,z,1)) / 5.0f / 15.0f; + float lg3 = (LIGHT(x+1,y-1,z+1,1) + lg*30 + LIGHT(x+1,y,z+1,1) + LIGHT(x+1,y-1,z,1)) / 5.0f / 15.0f; + + float lb0 = (LIGHT(x+1,y-1,z-1,2) + lb*30 + LIGHT(x+1,y,z-1,2) + LIGHT(x+1,y-1,z,2)) / 5.0f / 15.0f; + float lb1 = (LIGHT(x+1,y+1,z-1,2) + lb*30 + LIGHT(x+1,y,z-1,2) + LIGHT(x+1,y+1,z,2)) / 5.0f / 15.0f; + float lb2 = (LIGHT(x+1,y+1,z+1,2) + lb*30 + LIGHT(x+1,y,z+1,2) + LIGHT(x+1,y+1,z,2)) / 5.0f / 15.0f; + float lb3 = (LIGHT(x+1,y-1,z+1,2) + lb*30 + LIGHT(x+1,y,z+1,2) + LIGHT(x+1,y-1,z,2)) / 5.0f / 15.0f; + + float ls0 = (LIGHT(x+1,y-1,z-1,3) + ls*30 + LIGHT(x+1,y,z-1,3) + LIGHT(x+1,y-1,z,3)) / 5.0f / 15.0f; + float ls1 = (LIGHT(x+1,y+1,z-1,3) + ls*30 + LIGHT(x+1,y,z-1,3) + LIGHT(x+1,y+1,z,3)) / 5.0f / 15.0f; + float ls2 = (LIGHT(x+1,y+1,z+1,3) + ls*30 + LIGHT(x+1,y,z+1,3) + LIGHT(x+1,y+1,z,3)) / 5.0f / 15.0f; + float ls3 = (LIGHT(x+1,y-1,z+1,3) + ls*30 + LIGHT(x+1,y,z+1,3) + LIGHT(x+1,y-1,z,3)) / 5.0f / 15.0f; + + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, lr2,lg2,lb2,ls2); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u1,v1, lr3,lg3,lb3,ls3); + } + if (!IS_BLOCKED(x-1,y,z,group)){ + l = 0.85f; + + SETUP_UV(block->textureFaces[0]); + + float lr = LIGHT(x-1,y,z, 0) / 15.0f; + float lg = LIGHT(x-1,y,z, 1) / 15.0f; + float lb = LIGHT(x-1,y,z, 2) / 15.0f; + float ls = LIGHT(x-1,y,z, 3) / 15.0f; + + float lr0 = (LIGHT(x-1,y-1,z-1,0) + lr*30 + LIGHT(x-1,y,z-1,0) + LIGHT(x-1,y-1,z,0)) / 5.0f / 15.0f; + float lr1 = (LIGHT(x-1,y+1,z+1,0) + lr*30 + LIGHT(x-1,y,z+1,0) + LIGHT(x-1,y+1,z,0)) / 5.0f / 15.0f; + float lr2 = (LIGHT(x-1,y+1,z-1,0) + lr*30 + LIGHT(x-1,y,z-1,0) + LIGHT(x-1,y+1,z,0)) / 5.0f / 15.0f; + float lr3 = (LIGHT(x-1,y-1,z+1,0) + lr*30 + LIGHT(x-1,y,z+1,0) + LIGHT(x-1,y-1,z,0)) / 5.0f / 15.0f; + + float lg0 = (LIGHT(x-1,y-1,z-1,1) + lg*30 + LIGHT(x-1,y,z-1,1) + LIGHT(x-1,y-1,z,1)) / 5.0f / 15.0f; + float lg1 = (LIGHT(x-1,y+1,z+1,1) + lg*30 + LIGHT(x-1,y,z+1,1) + LIGHT(x-1,y+1,z,1)) / 5.0f / 15.0f; + float lg2 = (LIGHT(x-1,y+1,z-1,1) + lg*30 + LIGHT(x-1,y,z-1,1) + LIGHT(x-1,y+1,z,1)) / 5.0f / 15.0f; + float lg3 = (LIGHT(x-1,y-1,z+1,1) + lg*30 + LIGHT(x-1,y,z+1,1) + LIGHT(x-1,y-1,z,1)) / 5.0f / 15.0f; + + float lb0 = (LIGHT(x-1,y-1,z-1,2) + lb*30 + LIGHT(x-1,y,z-1,2) + LIGHT(x-1,y-1,z,2)) / 5.0f / 15.0f; + float lb1 = (LIGHT(x-1,y+1,z+1,2) + lb*30 + LIGHT(x-1,y,z+1,2) + LIGHT(x-1,y+1,z,2)) / 5.0f / 15.0f; + float lb2 = (LIGHT(x-1,y+1,z-1,2) + lb*30 + LIGHT(x-1,y,z-1,2) + LIGHT(x-1,y+1,z,2)) / 5.0f / 15.0f; + float lb3 = (LIGHT(x-1,y-1,z+1,2) + lb*30 + LIGHT(x-1,y,z+1,2) + LIGHT(x-1,y-1,z,2)) / 5.0f / 15.0f; + + float ls0 = (LIGHT(x-1,y-1,z-1,3) + ls*30 + LIGHT(x-1,y,z-1,3) + LIGHT(x-1,y-1,z,3)) / 5.0f / 15.0f; + float ls1 = (LIGHT(x-1,y+1,z+1,3) + ls*30 + LIGHT(x-1,y,z+1,3) + LIGHT(x-1,y+1,z,3)) / 5.0f / 15.0f; + float ls2 = (LIGHT(x-1,y+1,z-1,3) + ls*30 + LIGHT(x-1,y,z-1,3) + LIGHT(x-1,y+1,z,3)) / 5.0f / 15.0f; + float ls3 = (LIGHT(x-1,y-1,z+1,3) + ls*30 + LIGHT(x-1,y,z+1,3) + LIGHT(x-1,y-1,z,3)) / 5.0f / 15.0f; + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u2,v1, lr3,lg3,lb3,ls3); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + } + + if (!IS_BLOCKED(x,y,z+1,group)){ + l = 0.9f; + + SETUP_UV(block->textureFaces[5]); + + float lr = LIGHT(x,y,z+1, 0) / 15.0f; + float lg = LIGHT(x,y,z+1, 1) / 15.0f; + float lb = LIGHT(x,y,z+1, 2) / 15.0f; + float ls = LIGHT(x,y,z+1, 3) / 15.0f; + + float lr0 = l*(LIGHT(x-1,y-1,z+1,0) + lr*30 + LIGHT(x,y-1,z+1,0) + LIGHT(x-1,y,z+1,0)) / 5.0f / 15.0f; + float lr1 = l*(LIGHT(x+1,y+1,z+1,0) + lr*30 + LIGHT(x,y+1,z+1,0) + LIGHT(x+1,y,z+1,0)) / 5.0f / 15.0f; + float lr2 = l*(LIGHT(x-1,y+1,z+1,0) + lr*30 + LIGHT(x,y+1,z+1,0) + LIGHT(x-1,y,z+1,0)) / 5.0f / 15.0f; + float lr3 = l*(LIGHT(x+1,y-1,z+1,0) + lr*30 + LIGHT(x,y-1,z+1,0) + LIGHT(x+1,y,z+1,0)) / 5.0f / 15.0f; + + float lg0 = l*(LIGHT(x-1,y-1,z+1,1) + lg*30 + LIGHT(x,y-1,z+1,1) + LIGHT(x-1,y,z+1,1)) / 5.0f / 15.0f; + float lg1 = l*(LIGHT(x+1,y+1,z+1,1) + lg*30 + LIGHT(x,y+1,z+1,1) + LIGHT(x+1,y,z+1,1)) / 5.0f / 15.0f; + float lg2 = l*(LIGHT(x-1,y+1,z+1,1) + lg*30 + LIGHT(x,y+1,z+1,1) + LIGHT(x-1,y,z+1,1)) / 5.0f / 15.0f; + float lg3 = l*(LIGHT(x+1,y-1,z+1,1) + lg*30 + LIGHT(x,y-1,z+1,1) + LIGHT(x+1,y,z+1,1)) / 5.0f / 15.0f; + + float lb0 = l*(LIGHT(x-1,y-1,z+1,2) + lb*30 + LIGHT(x,y-1,z+1,2) + LIGHT(x-1,y,z+1,2)) / 5.0f / 15.0f; + float lb1 = l*(LIGHT(x+1,y+1,z+1,2) + lb*30 + LIGHT(x,y+1,z+1,2) + LIGHT(x+1,y,z+1,2)) / 5.0f / 15.0f; + float lb2 = l*(LIGHT(x-1,y+1,z+1,2) + lb*30 + LIGHT(x,y+1,z+1,2) + LIGHT(x-1,y,z+1,2)) / 5.0f / 15.0f; + float lb3 = l*(LIGHT(x+1,y-1,z+1,2) + lb*30 + LIGHT(x,y-1,z+1,2) + LIGHT(x+1,y,z+1,2)) / 5.0f / 15.0f; + + float ls0 = l*(LIGHT(x-1,y-1,z+1,3) + ls*30 + LIGHT(x,y-1,z+1,3) + LIGHT(x-1,y,z+1,3)) / 5.0f / 15.0f; + float ls1 = l*(LIGHT(x+1,y+1,z+1,3) + ls*30 + LIGHT(x,y+1,z+1,3) + LIGHT(x+1,y,z+1,3)) / 5.0f / 15.0f; + float ls2 = l*(LIGHT(x-1,y+1,z+1,3) + ls*30 + LIGHT(x,y+1,z+1,3) + LIGHT(x-1,y,z+1,3)) / 5.0f / 15.0f; + float ls3 = l*(LIGHT(x+1,y-1,z+1,3) + ls*30 + LIGHT(x,y-1,z+1,3) + LIGHT(x+1,y,z+1,3)) / 5.0f / 15.0f; + + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v1, lr3,lg3,lb3,ls3); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u2,v2, lr1,lg1,lb1,ls1); + } + if (!IS_BLOCKED(x,y,z-1,group)){ + l = 0.8f; + + SETUP_UV(block->textureFaces[4]); + + float lr = LIGHT(x,y,z-1, 0) / 15.0f; + float lg = LIGHT(x,y,z-1, 1) / 15.0f; + float lb = LIGHT(x,y,z-1, 2) / 15.0f; + float ls = LIGHT(x,y,z-1, 3) / 15.0f; + + float lr0 = l*(LIGHT(x-1,y-1,z-1,0) + lr*30 + LIGHT(x,y-1,z-1,0) + LIGHT(x-1,y,z-1,0)) / 5.0f / 15.0f; + float lr1 = l*(LIGHT(x-1,y+1,z-1,0) + lr*30 + LIGHT(x,y+1,z-1,0) + LIGHT(x-1,y,z-1,0)) / 5.0f / 15.0f; + float lr2 = l*(LIGHT(x+1,y+1,z-1,0) + lr*30 + LIGHT(x,y+1,z-1,0) + LIGHT(x+1,y,z-1,0)) / 5.0f / 15.0f; + float lr3 = l*(LIGHT(x+1,y-1,z-1,0) + lr*30 + LIGHT(x,y-1,z-1,0) + LIGHT(x+1,y,z-1,0)) / 5.0f / 15.0f; + + float lg0 = l*(LIGHT(x-1,y-1,z-1,1) + lg*30 + LIGHT(x,y-1,z-1,1) + LIGHT(x-1,y,z-1,1)) / 5.0f / 15.0f; + float lg1 = l*(LIGHT(x-1,y+1,z-1,1) + lg*30 + LIGHT(x,y+1,z-1,1) + LIGHT(x-1,y,z-1,1)) / 5.0f / 15.0f; + float lg2 = l*(LIGHT(x+1,y+1,z-1,1) + lg*30 + LIGHT(x,y+1,z-1,1) + LIGHT(x+1,y,z-1,1)) / 5.0f / 15.0f; + float lg3 = l*(LIGHT(x+1,y-1,z-1,1) + lg*30 + LIGHT(x,y-1,z-1,1) + LIGHT(x+1,y,z-1,1)) / 5.0f / 15.0f; + + float lb0 = l*(LIGHT(x-1,y-1,z-1,2) + lb*30 + LIGHT(x,y-1,z-1,2) + LIGHT(x-1,y,z-1,2)) / 5.0f / 15.0f; + float lb1 = l*(LIGHT(x-1,y+1,z-1,2) + lb*30 + LIGHT(x,y+1,z-1,2) + LIGHT(x-1,y,z-1,2)) / 5.0f / 15.0f; + float lb2 = l*(LIGHT(x+1,y+1,z-1,2) + lb*30 + LIGHT(x,y+1,z-1,2) + LIGHT(x+1,y,z-1,2)) / 5.0f / 15.0f; + float lb3 = l*(LIGHT(x+1,y-1,z-1,2) + lb*30 + LIGHT(x,y-1,z-1,2) + LIGHT(x+1,y,z-1,2)) / 5.0f / 15.0f; + + float ls0 = l*(LIGHT(x-1,y-1,z-1,3) + ls*30 + LIGHT(x,y-1,z-1,3) + LIGHT(x-1,y,z-1,3)) / 5.0f / 15.0f; + float ls1 = l*(LIGHT(x-1,y+1,z-1,3) + ls*30 + LIGHT(x,y+1,z-1,3) + LIGHT(x-1,y,z-1,3)) / 5.0f / 15.0f; + float ls2 = l*(LIGHT(x+1,y+1,z-1,3) + ls*30 + LIGHT(x,y+1,z-1,3) + LIGHT(x+1,y,z-1,3)) / 5.0f / 15.0f; + float ls3 = l*(LIGHT(x+1,y-1,z-1,3) + ls*30 + LIGHT(x,y-1,z-1,3) + LIGHT(x+1,y,z-1,3)) / 5.0f / 15.0f; + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v2, lr2,lg2,lb2,ls2); + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u1,v1, lr3,lg3,lb3,ls3); + } + } + } + } + return new Mesh(buffer, index / VERTEX_SIZE, chunk_attrs); +} diff --git a/src/graphics/VoxelRenderer.h b/src/graphics/VoxelRenderer.h new file mode 100644 index 00000000..4b3a6255 --- /dev/null +++ b/src/graphics/VoxelRenderer.h @@ -0,0 +1,19 @@ +#ifndef GRAPHICS_VOXELRENDERER_H_ +#define GRAPHICS_VOXELRENDERER_H_ + +#include + +class Mesh; +class Chunk; + +class VoxelRenderer { + float* buffer; + size_t capacity; +public: + VoxelRenderer(size_t capacity); + ~VoxelRenderer(); + + Mesh* render(Chunk* chunk, const Chunk** chunks); +}; + +#endif /* GRAPHICS_VOXELRENDERER_H_ */ diff --git a/src/lighting/LightSolver.cpp b/src/lighting/LightSolver.cpp new file mode 100644 index 00000000..1ec493a8 --- /dev/null +++ b/src/lighting/LightSolver.cpp @@ -0,0 +1,122 @@ +#include "LightSolver.h" +#include "Lightmap.h" +#include "../voxels/Chunks.h" +#include "../voxels/Chunk.h" +#include "../voxels/voxel.h" +#include "../voxels/Block.h" + +LightSolver::LightSolver(Chunks* chunks, int channel) : chunks(chunks), channel(channel) { +} + +void LightSolver::add(int x, int y, int z, int emission) { + if (emission <= 1) + return; + lightentry entry; + entry.x = x; + entry.y = y; + entry.z = z; + entry.light = emission; + addqueue.push(entry); + + Chunk* chunk = chunks->getChunkByVoxel(entry.x, entry.y, entry.z); + chunk->modified = true; + chunk->lightmap->set(entry.x-chunk->x*CHUNK_W, entry.y-chunk->y*CHUNK_H, entry.z-chunk->z*CHUNK_D, channel, entry.light); +} + +void LightSolver::add(int x, int y, int z) { + add(x,y,z, chunks->getLight(x,y,z, channel)); +} + +void LightSolver::remove(int x, int y, int z) { + Chunk* chunk = chunks->getChunkByVoxel(x, y, z); + if (chunk == nullptr) + return; + + int light = chunk->lightmap->get(x-chunk->x*CHUNK_W, y-chunk->y*CHUNK_H, z-chunk->z*CHUNK_D, channel); + if (light == 0){ + return; + } + + lightentry entry; + entry.x = x; + entry.y = y; + entry.z = z; + entry.light = light; + remqueue.push(entry); + + chunk->lightmap->set(entry.x-chunk->x*CHUNK_W, entry.y-chunk->y*CHUNK_H, entry.z-chunk->z*CHUNK_D, channel, 0); +} + +void LightSolver::solve(){ + const int coords[] = { + 0, 0, 1, + 0, 0,-1, + 0, 1, 0, + 0,-1, 0, + 1, 0, 0, + -1, 0, 0 + }; + + while (!remqueue.empty()){ + lightentry entry = remqueue.front(); + remqueue.pop(); + + for (size_t i = 0; i < 6; i++) { + int x = entry.x+coords[i*3+0]; + int y = entry.y+coords[i*3+1]; + int z = entry.z+coords[i*3+2]; + Chunk* chunk = chunks->getChunkByVoxel(x,y,z); + if (chunk) { + int light = chunks->getLight(x,y,z, channel); + if (light != 0 && light == entry.light-1){ + lightentry nentry; + nentry.x = x; + nentry.y = y; + nentry.z = z; + nentry.light = light; + remqueue.push(nentry); + chunk->lightmap->set(x-chunk->x*CHUNK_W, y-chunk->y*CHUNK_H, z-chunk->z*CHUNK_D, channel, 0); + chunk->modified = true; + } + else if (light >= entry.light){ + lightentry nentry; + nentry.x = x; + nentry.y = y; + nentry.z = z; + nentry.light = light; + addqueue.push(nentry); + } + } + } + } + + while (!addqueue.empty()){ + lightentry entry = addqueue.front(); + addqueue.pop(); + + if (entry.light <= 1) + continue; + + for (size_t i = 0; i < 6; i++) { + int x = entry.x+coords[i*3+0]; + int y = entry.y+coords[i*3+1]; + int z = entry.z+coords[i*3+2]; + Chunk* chunk = chunks->getChunkByVoxel(x,y,z); + if (chunk) { + int light = chunks->getLight(x,y,z, channel); + voxel* v = chunks->get(x,y,z); + Block* block = Block::blocks[v->id]; + if (block->lightPassing && light+2 <= entry.light){ + chunk->lightmap->set(x-chunk->x*CHUNK_W, y-chunk->y*CHUNK_H, z-chunk->z*CHUNK_D, channel, entry.light-1); + chunk->modified = true; + lightentry nentry; + nentry.x = x; + nentry.y = y; + nentry.z = z; + nentry.light = entry.light-1; + addqueue.push(nentry); + } + } + } + } +} diff --git a/src/lighting/LightSolver.h b/src/lighting/LightSolver.h new file mode 100644 index 00000000..4ef8fa3f --- /dev/null +++ b/src/lighting/LightSolver.h @@ -0,0 +1,29 @@ +#ifndef LIGHTING_LIGHTSOLVER_H_ +#define LIGHTING_LIGHTSOLVER_H_ + +#include + +class Chunks; + +struct lightentry { + int x; + int y; + int z; + unsigned char light; +}; + +class LightSolver { + std::queue addqueue; + std::queue remqueue; + Chunks* chunks; + int channel; +public: + LightSolver(Chunks* chunks, int channel); + + void add(int x, int y, int z); + void add(int x, int y, int z, int emission); + void remove(int x, int y, int z); + void solve(); +}; + +#endif /* LIGHTING_LIGHTSOLVER_H_ */ diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp new file mode 100644 index 00000000..d0214df3 --- /dev/null +++ b/src/lighting/Lighting.cpp @@ -0,0 +1,246 @@ +#include "Lighting.h" +#include "LightSolver.h" +#include "Lightmap.h" +#include "../voxels/Chunks.h" +#include "../voxels/Chunk.h" +#include "../voxels/voxel.h" +#include "../voxels/Block.h" + +Chunks* Lighting::chunks = nullptr; +LightSolver* Lighting::solverR = nullptr; +LightSolver* Lighting::solverG = nullptr; +LightSolver* Lighting::solverB = nullptr; +LightSolver* Lighting::solverS = nullptr; + +int Lighting::initialize(Chunks* chunks){ + Lighting::chunks = chunks; + solverR = new LightSolver(chunks, 0); + solverG = new LightSolver(chunks, 1); + solverB = new LightSolver(chunks, 2); + solverS = new LightSolver(chunks, 3); + return 0; +} + +void Lighting::finalize(){ + delete solverR, solverG, solverB, solverS; +} + +void Lighting::clear(){ + for (unsigned int index = 0; index < chunks->volume; index++){ + Chunk* chunk = chunks->chunks[index]; + if (chunk == nullptr) + continue; + Lightmap* lightmap = chunk->lightmap; + for (int i = 0; i < CHUNK_VOL; i++){ + lightmap->map[i] = 0; + } + } +} + +void Lighting::onChunkLoaded(int cx, int cy, int cz){ + Chunk* chunk = chunks->getChunk(cx, cy, cz); + Chunk* chunkUpper = chunks->getChunk(cx, cy+1, cz); + Chunk* chunkLower = chunks->getChunk(cx, cy-1, cz); + if (chunkLower){ + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + int gx = x + cx * CHUNK_W; + int gy = cy * CHUNK_H; + int gz = z + cz * CHUNK_D; + + int light = chunk->lightmap->getS(x,0,z); + int ncy = cy-1; + if (light < 15){ + Chunk* current = chunkLower; + if (chunkLower->lightmap->getS(x,15,z) == 0) + continue; + for (int y = 15;;y--){ + if (y < 0){ + ncy--; + y += CHUNK_H; + } + if (ncy != current->y) + current = chunks->getChunk(cx,ncy,cz); + if (!current) + break; + voxel* vox = &(current->voxels[(y * CHUNK_D + z) * CHUNK_W + x]);//chunks->get(gx,gy+y,gz); + Block* block = Block::blocks[vox->id]; + if (!block->lightPassing) + break; + //current->lightmap->setS(x,y,z, 0); + current->modified = true; + solverS->remove(gx,y+ncy*CHUNK_H,gz); + current->lightmap->setS(x,y,z, 0); + } + } + } + } + } + if (chunkUpper){ + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + int gx = x + cx * CHUNK_W; + int gy = cy * CHUNK_H; + int gz = z + cz * CHUNK_D; + int ncy = cy; + + int light = chunkUpper->lightmap->getS(x,0,z); + + Chunk* current = chunk; + if (light == 15){ + for (int y = CHUNK_H-1;;y--){ + if (y < 0){ + ncy--; + y += CHUNK_H; + } + if (ncy != current->y) + current = chunks->getChunk(cx,ncy,cz); + if (!current) + break; + voxel* vox = &(current->voxels[(y * CHUNK_D + z) * CHUNK_W + x]);//chunks->get(gx,gy+y,gz); + Block* block = Block::blocks[vox->id]; + if (!block->lightPassing) + break; + current->lightmap->setS(x,y,z, 15); + current->modified = true; + solverS->add(gx,y+ncy*CHUNK_H,gz); + } + } else if (light){ + solverS->add(gx,gy+CHUNK_H,gz); + } + } + } + } else { + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + int gx = x + cx * CHUNK_W; + int gz = z + cz * CHUNK_D; + int ncy = cy; + + Chunk* current = chunk; + for (int y = CHUNK_H-1;;y--){ + if (y < 0){ + ncy--; + y += CHUNK_H; + } + if (ncy != current->y) + current = chunks->getChunk(cx,ncy,cz); + if (!current) + break; + voxel* vox = &(current->voxels[(y * CHUNK_D + z) * CHUNK_W + x]);//chunks->get(gx,gy+y,gz); + Block* block = Block::blocks[vox->id]; + if (!block->lightPassing) + break; + current->lightmap->setS(x,y,z, 15); + current->modified = true; + solverS->add(gx,y+ncy*CHUNK_H,gz); + } + } + } + } + //std::cout << "DONE" << std::endl; + for (unsigned int y = 0; y < CHUNK_H; y++){ + for (unsigned int z = 0; z < CHUNK_D; z++){ + for (unsigned int x = 0; x < CHUNK_W; x++){ + voxel vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x]; + Block* block = Block::blocks[vox.id]; + if (block->emission[0] || block->emission[1] || block->emission[2]){ + int gx = x + cx * CHUNK_W; + int gy = y + cy * CHUNK_H; + int gz = z + cz * CHUNK_D; + solverR->add(gx,gy,gz,block->emission[0]); + solverG->add(gx,gy,gz,block->emission[1]); + solverB->add(gx,gy,gz,block->emission[2]); + } + } + } + } + for (int y = -1; y <= CHUNK_H; y++){ + for (int z = -1; z <= CHUNK_D; z++){ + for (int x = -1; x <= CHUNK_W; x++){ + if (!(x == -1 || x == CHUNK_W || y == -1 || y == CHUNK_H || z == -1 || z == CHUNK_D)) + continue; + int gx = x + cx * CHUNK_W; + int gy = y + cy * CHUNK_H; + int gz = z + cz * CHUNK_D; + solverR->add(gx,gy,gz); + solverG->add(gx,gy,gz); + solverB->add(gx,gy,gz); + solverS->add(gx,gy,gz); + } + } + } + + solverR->solve(); + solverG->solve(); + solverB->solve(); + solverS->solve(); + + Chunk* other; + other = chunks->getChunk(cx-1,cy,cz); if (other) other->modified = true; + other = chunks->getChunk(cx+1,cy,cz); if (other) other->modified = true; + other = chunks->getChunk(cx,cy-1,cz); if (other) other->modified = true; + other = chunks->getChunk(cx,cy+1,cz); if (other) other->modified = true; + other = chunks->getChunk(cx,cy,cz-1); if (other) other->modified = true; + other = chunks->getChunk(cx,cy,cz+1); if (other) other->modified = true; +} + +void Lighting::onBlockSet(int x, int y, int z, int id){ + Block* block = Block::blocks[id]; + if (id == 0){ + solverR->remove(x,y,z); + solverG->remove(x,y,z); + solverB->remove(x,y,z); + + solverR->solve(); + solverG->solve(); + solverB->solve(); + + if (chunks->getLight(x,y+1,z, 3) == 0xF){ + for (int i = y; i >= 0; i--){ + voxel* vox = chunks->get(x,i,z); + if (vox == nullptr || vox->id != 0) + break; + solverS->add(x,i,z, 0xF); + } + } + + solverR->add(x,y+1,z); solverG->add(x,y+1,z); solverB->add(x,y+1,z); solverS->add(x,y+1,z); + solverR->add(x,y-1,z); solverG->add(x,y-1,z); solverB->add(x,y-1,z); solverS->add(x,y-1,z); + solverR->add(x+1,y,z); solverG->add(x+1,y,z); solverB->add(x+1,y,z); solverS->add(x+1,y,z); + solverR->add(x-1,y,z); solverG->add(x-1,y,z); solverB->add(x-1,y,z); solverS->add(x-1,y,z); + solverR->add(x,y,z+1); solverG->add(x,y,z+1); solverB->add(x,y,z+1); solverS->add(x,y,z+1); + solverR->add(x,y,z-1); solverG->add(x,y,z-1); solverB->add(x,y,z-1); solverS->add(x,y,z-1); + + solverR->solve(); + solverG->solve(); + solverB->solve(); + solverS->solve(); + } else { + solverR->remove(x,y,z); + solverG->remove(x,y,z); + solverB->remove(x,y,z); + if (!block->lightPassing){ + solverS->remove(x,y,z); + for (int i = y-1; i >= 0; i--){ + solverS->remove(x,i,z); + if (i == 0 || chunks->get(x,i-1,z)->id != 0){ + break; + } + } + solverS->solve(); + } + solverR->solve(); + solverG->solve(); + solverB->solve(); + + if (block->emission[0] || block->emission[1] || block->emission[2]){ + solverR->add(x,y,z,block->emission[0]); + solverG->add(x,y,z,block->emission[1]); + solverB->add(x,y,z,block->emission[2]); + solverR->solve(); + solverG->solve(); + solverB->solve(); + } + } +} diff --git a/src/lighting/Lighting.h b/src/lighting/Lighting.h new file mode 100644 index 00000000..6bd22a2c --- /dev/null +++ b/src/lighting/Lighting.h @@ -0,0 +1,22 @@ +#ifndef LIGHTING_LIGHTING_H_ +#define LIGHTING_LIGHTING_H_ + +class Chunks; +class LightSolver; + +class Lighting { + static Chunks* chunks; + static LightSolver* solverR; + static LightSolver* solverG; + static LightSolver* solverB; + static LightSolver* solverS; +public: + static int initialize(Chunks* chunks); + static void finalize(); + + static void clear(); + static void onChunkLoaded(int cx, int cy, int cz); + static void onBlockSet(int x, int y, int z, int id); +}; + +#endif /* LIGHTING_LIGHTING_H_ */ diff --git a/src/lighting/Lightmap.cpp b/src/lighting/Lightmap.cpp new file mode 100644 index 00000000..7b37ec14 --- /dev/null +++ b/src/lighting/Lightmap.cpp @@ -0,0 +1,12 @@ +#include "Lightmap.h" + +Lightmap::Lightmap(){ + map = new unsigned short[CHUNK_VOL]; + for (unsigned int i = 0; i < CHUNK_VOL; i++){ + map[i] = 0x0000; + } +} + +Lightmap::~Lightmap(){ + delete[] map; +} diff --git a/src/lighting/Lightmap.h b/src/lighting/Lightmap.h new file mode 100644 index 00000000..a2f88ad9 --- /dev/null +++ b/src/lighting/Lightmap.h @@ -0,0 +1,58 @@ +#ifndef LIGHTING_LIGHTMAP_H_ +#define LIGHTING_LIGHTMAP_H_ + +#include "../voxels/Chunk.h" + +class Lightmap { +public: + unsigned short* map; + Lightmap(); + ~Lightmap(); + + inline unsigned char get(int x, int y, int z, int channel){ + return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x] >> (channel << 2)) & 0xF; + } + + inline unsigned char getR(int x, int y, int z){ + return map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x] & 0xF; + } + + inline unsigned char getG(int x, int y, int z){ + return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x] >> 4) & 0xF; + } + + inline unsigned char getB(int x, int y, int z){ + return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x] >> 8) & 0xF; + } + + inline unsigned char getS(int x, int y, int z){ + return (map[y*CHUNK_D*CHUNK_W+z*CHUNK_W+x] >> 12) & 0xF; + } + + inline void setR(int x, int y, int z, int value){ + const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x; + map[index] = (map[index] & 0xFFF0) | value; + } + + inline void setG(int x, int y, int z, int value){ + const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x; + map[index] = (map[index] & 0xFF0F) | (value << 4); + } + + inline void setB(int x, int y, int z, int value){ + const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x; + map[index] = (map[index] & 0xF0FF) | (value << 8); + } + + inline void setS(int x, int y, int z, int value){ + const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x; + map[index] = (map[index] & 0x0FFF) | (value << 12); + } + + inline void set(int x, int y, int z, int channel, int value){ + const int index = y*CHUNK_D*CHUNK_W+z*CHUNK_W+x; + map[index] = (map[index] & (0xFFFF & (~(0xF << (channel*4))))) | (value << (channel << 2)); + } +}; + +#endif /* LIGHTING_LIGHTMAP_H_ */ diff --git a/src/loaders/png_loading.cpp b/src/loaders/png_loading.cpp new file mode 100644 index 00000000..9d69322b --- /dev/null +++ b/src/loaders/png_loading.cpp @@ -0,0 +1,125 @@ +/* + * png_loading.cpp + * + * Created on: Feb 10, 2020 + * Author: MihailRis + */ + +#include "png_loading.h" + +#include +#include +#include +#include "../graphics/Texture.h" + +int _png_load(const char* file, int* width, int* height){ + FILE *f; + int is_png, bit_depth, color_type, row_bytes; + png_infop info_ptr, end_info; + png_uint_32 t_width, t_height; + png_byte header[8], *image_data; + png_bytepp row_pointers; + png_structp png_ptr; + GLuint texture; + int alpha; + + if ( !( f = fopen(file, "r" ) ) ) { + return 0; + } + fread( header, 1, 8, f ); + is_png = !png_sig_cmp( header, 0, 8 ); + if ( !is_png ) { + fclose( f ); + return 0; + } + png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL ); + if ( !png_ptr ) { + fclose( f ); + return 0; + } + info_ptr = png_create_info_struct( png_ptr ); + if ( !info_ptr ) { + png_destroy_read_struct( &png_ptr, (png_infopp) NULL, + (png_infopp) NULL ); + fclose( f ); + return 0; + } + end_info = png_create_info_struct( png_ptr ); + if ( !end_info ) { + png_destroy_read_struct( &png_ptr, (png_infopp) NULL, + (png_infopp) NULL ); + fclose( f ); + return 0; + } + if ( setjmp( png_jmpbuf( png_ptr ) ) ) { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + fclose( f ); + return 0; + } + png_init_io( png_ptr, f ); + png_set_sig_bytes( png_ptr, 8 ); + png_read_info( png_ptr, info_ptr ); + png_get_IHDR( png_ptr, info_ptr, &t_width, &t_height, &bit_depth, + &color_type, NULL, NULL, NULL ); + *width = t_width; + *height = t_height; + png_read_update_info( png_ptr, info_ptr ); + row_bytes = png_get_rowbytes( png_ptr, info_ptr ); + image_data = (png_bytep) malloc( row_bytes * t_height * sizeof(png_byte) ); + if ( !image_data ) { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + fclose( f ); + return 0; + } + row_pointers = (png_bytepp) malloc( t_height * sizeof(png_bytep) ); + if ( !row_pointers ) { + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + free( image_data ); + fclose( f ); + return 0; + } + for (unsigned int i = 0; i < t_height; ++i ) { + row_pointers[t_height - 1 - i] = image_data + i * row_bytes; + } + png_read_image( png_ptr, row_pointers ); + switch ( png_get_color_type( png_ptr, info_ptr ) ) { + case PNG_COLOR_TYPE_RGBA: + alpha = GL_RGBA; + break; + case PNG_COLOR_TYPE_RGB: + alpha = GL_RGB; + break; + default: + printf( "Color type %d not supported!\n", + png_get_color_type( png_ptr, info_ptr ) ); + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + return 0; + } + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, t_width, t_height, 0, + alpha, GL_UNSIGNED_BYTE, (GLvoid *) image_data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); + free( image_data ); + free( row_pointers ); + fclose( f ); + return texture; +} + +Texture* load_texture(std::string filename){ + int width, height; + GLuint texture = _png_load(filename.c_str(), &width, &height); + if (texture == 0){ + std::cerr << "Could not load texture " << filename << std::endl; + return nullptr; + } + return new Texture(texture, width, height); +} diff --git a/src/loaders/png_loading.h b/src/loaders/png_loading.h new file mode 100644 index 00000000..a8f502df --- /dev/null +++ b/src/loaders/png_loading.h @@ -0,0 +1,17 @@ +/* + * png_loading.h + * + * Created on: Feb 10, 2020 + * Author: MihailRis + */ + +#ifndef LOADERS_PNG_LOADING_H_ +#define LOADERS_PNG_LOADING_H_ + +#include + +class Texture; + +extern Texture* load_texture(std::string filename); + +#endif /* LOADERS_PNG_LOADING_H_ */ diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp new file mode 100644 index 00000000..a3fe8c45 --- /dev/null +++ b/src/voxel_engine.cpp @@ -0,0 +1,276 @@ +#include + +#define GLEW_STATIC +#include +#include + +#include + +// GLM +#include +#include +#include + +using namespace glm; + +#include "graphics/Shader.h" +#include "graphics/Texture.h" +#include "graphics/Mesh.h" +#include "graphics/VoxelRenderer.h" +#include "graphics/LineBatch.h" +#include "window/Window.h" +#include "window/Events.h" +#include "window/Camera.h" +#include "loaders/png_loading.h" +#include "voxels/voxel.h" +#include "voxels/Chunk.h" +#include "voxels/Chunks.h" +#include "voxels/Block.h" +#include "voxels/WorldGenerator.h" +#include "files/files.h" +#include "files/WorldFiles.h" +#include "lighting/LightSolver.h" +#include "lighting/Lightmap.h" +#include "lighting/Lighting.h" + +int WIDTH = 1280; +int HEIGHT = 720; + +float vertices[] = { + // x y + -0.01f,-0.01f, + 0.01f, 0.01f, + + -0.01f, 0.01f, + 0.01f,-0.01f, +}; + +int attrs[] = { + 2, 0 //null terminator +}; + +int main() { + Window::initialize(WIDTH, HEIGHT, "Window 2.0"); + Events::initialize(); + + Shader* shader = load_shader("res/main.glslv", "res/main.glslf"); + if (shader == nullptr){ + std::cerr << "failed to load shader" << std::endl; + Window::terminate(); + return 1; + } + + Shader* crosshairShader = load_shader("res/crosshair.glslv", "res/crosshair.glslf"); + if (crosshairShader == nullptr){ + std::cerr << "failed to load crosshair shader" << std::endl; + Window::terminate(); + return 1; + } + + Shader* linesShader = load_shader("res/lines.glslv", "res/lines.glslf"); + if (linesShader == nullptr){ + std::cerr << "failed to load lines shader" << std::endl; + Window::terminate(); + return 1; + } + + Texture* texture = load_texture("res/block.png"); + if (texture == nullptr){ + std::cerr << "failed to load texture" << std::endl; + delete shader; + Window::terminate(); + return 1; + } + + { + // AIR + Block* block = new Block(0,0); + block->drawGroup = 1; + block->lightPassing = true; + Block::blocks[block->id] = block; + + // STONE + block = new Block(1,2); + Block::blocks[block->id] = block; + + // GRASS + block = new Block(2,4); + block->textureFaces[2] = 2; + block->textureFaces[3] = 1; + Block::blocks[block->id] = block; + + // LAMP + block = new Block(3,3); + block->emission[0] = 10; + block->emission[1] = 0; + block->emission[2] = 0; + Block::blocks[block->id] = block; + + // GLASS + block = new Block(4,5); + block->drawGroup = 2; + block->lightPassing = true; + Block::blocks[block->id] = block; + + // PLANKS + block = new Block(5,6); + Block::blocks[block->id] = block; + } + + WorldFiles wfile = WorldFiles("world/", 24*1024*1024); + Chunks* chunks = new Chunks(16*4,1,16*4, 0,0,0); + VoxelRenderer renderer(1024*1024*8); + LineBatch* lineBatch = new LineBatch(4096); + + Lighting::initialize(chunks); + + glClearColor(0.0f,0.0f,0.0f,1); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Mesh* crosshair = new Mesh(vertices, 4, attrs); + Camera* camera = new Camera(vec3(32,32,32), radians(90.0f)); + + float lastTime = glfwGetTime(); + float delta = 0.0f; + + float camX = 0.0f; + float camY = 0.0f; + + float speed = 15; + + int choosenBlock = 1; + + glfwSwapInterval(0); + + while (!Window::isShouldClose()){ + float currentTime = glfwGetTime(); + delta = currentTime - lastTime; + lastTime = currentTime; + + if (Events::jpressed(GLFW_KEY_ESCAPE)){ + Window::setShouldClose(true); + } + if (Events::jpressed(GLFW_KEY_TAB)){ + Events::toogleCursor(); + } + + for (int i = 1; i < 6; i++){ + if (Events::jpressed(GLFW_KEY_0+i)){ + choosenBlock = i; + } + } + + if (Events::pressed(GLFW_KEY_W)){ + camera->position += camera->front * delta * speed; + } + if (Events::pressed(GLFW_KEY_S)){ + camera->position -= camera->front * delta * speed; + } + if (Events::pressed(GLFW_KEY_D)){ + camera->position += camera->right * delta * speed; + } + if (Events::pressed(GLFW_KEY_A)){ + camera->position -= camera->right * delta * speed; + } + + chunks->setCenter(camera->position.x,0,camera->position.z); + chunks->_buildMeshes(&renderer); + chunks->loadVisible(&wfile); + + if (Events::_cursor_locked){ + camY += -Events::deltaY / Window::height * 2; + camX += -Events::deltaX / Window::height * 2; + + if (camY < -radians(89.0f)){ + camY = -radians(89.0f); + } + if (camY > radians(89.0f)){ + camY = radians(89.0f); + } + + camera->rotation = mat4(1.0f); + camera->rotate(camY, camX, 0); + } + + { + vec3 end; + vec3 norm; + vec3 iend; + voxel* vox = chunks->rayCast(camera->position, camera->front, 10.0f, end, norm, iend); + if (vox != nullptr){ + lineBatch->box(iend.x+0.5f, iend.y+0.5f, iend.z+0.5f, 1.005f,1.005f,1.005f, 0,0,0,0.5f); + + if (Events::jclicked(GLFW_MOUSE_BUTTON_1)){ + int x = (int)iend.x; + int y = (int)iend.y; + int z = (int)iend.z; + chunks->set(x,y,z, 0); + Lighting::onBlockSet(x,y,z,0); + } + if (Events::jclicked(GLFW_MOUSE_BUTTON_2)){ + int x = (int)(iend.x)+(int)(norm.x); + int y = (int)(iend.y)+(int)(norm.y); + int z = (int)(iend.z)+(int)(norm.z); + chunks->set(x, y, z, choosenBlock); + Lighting::onBlockSet(x,y,z, choosenBlock); + } + } + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Draw VAO + shader->use(); + shader->uniformMatrix("projview", camera->getProjection()*camera->getView()); + texture->bind(); + mat4 model(1.0f); + for (size_t i = 0; i < chunks->volume; i++){ + Chunk* chunk = chunks->chunks[i]; + if (chunk == nullptr) + continue; + Mesh* mesh = chunks->meshes[i]; + if (mesh == nullptr) + continue; + model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W+0.5f, chunk->y*CHUNK_H+0.5f, chunk->z*CHUNK_D+0.5f)); + shader->uniformMatrix("model", model); + mesh->draw(GL_TRIANGLES); + } + + crosshairShader->use(); + crosshair->draw(GL_LINES); + + linesShader->use(); + linesShader->uniformMatrix("projview", camera->getProjection()*camera->getView()); + glLineWidth(2.0f); + lineBatch->render(); + + Window::swapBuffers(); + Events::pullEvents(); + } + + Lighting::finalize(); + + for (unsigned int i = 0; i < chunks->volume; i++){ + Chunk* chunk = chunks->chunks[i]; + if (chunk == nullptr) + continue; + wfile.put((const char*)chunk->voxels, chunk->x, chunk->z); + } + + wfile.write(); + + delete shader; + delete texture; + delete chunks; + delete crosshair; + delete crosshairShader; + delete linesShader; + delete lineBatch; + + Window::terminate(); + return 0; +} diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp new file mode 100644 index 00000000..49d399c5 --- /dev/null +++ b/src/voxels/Block.cpp @@ -0,0 +1,8 @@ +#include "Block.h" + +Block* Block::blocks[256]; + +Block::Block(unsigned int id, int texture) : id(id), + textureFaces{texture,texture,texture,texture,texture,texture}, + emission{0,0,0}{ +} diff --git a/src/voxels/Block.h b/src/voxels/Block.h new file mode 100644 index 00000000..ce4ec452 --- /dev/null +++ b/src/voxels/Block.h @@ -0,0 +1,18 @@ +#ifndef VOXELS_BLOCK_H_ +#define VOXELS_BLOCK_H_ + +class Block { +public: + static Block* blocks[256]; + + const unsigned int id; + // 0 1 2 3 4 5 + int textureFaces[6]; // -x,x, -y,y, -z,z + unsigned char emission[3]; + unsigned char drawGroup = 0; + bool lightPassing = false; + + Block(unsigned int id, int texture); +}; + +#endif /* VOXELS_BLOCK_H_ */ diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp new file mode 100644 index 00000000..c0d05860 --- /dev/null +++ b/src/voxels/Chunk.cpp @@ -0,0 +1,29 @@ +#include "Chunk.h" +#include "voxel.h" +#include "../lighting/Lightmap.h" + + +Chunk::Chunk(int xpos, int ypos, int zpos) : x(xpos), y(ypos), z(zpos){ + voxels = new voxel[CHUNK_VOL]; + for (unsigned int i = 0; i < CHUNK_VOL; i++) + voxels[i].id = 1; + lightmap = new Lightmap(); +} + +Chunk::~Chunk(){ + delete lightmap; + delete[] voxels; +} + +bool Chunk::isEmpty(){ + int id = -1; + for (int i = 0; i < CHUNK_VOL; i++){ + if (voxels[i].id != id){ + if (id != -1) + return false; + else + id = voxels[i].id; + } + } + return true; +} diff --git a/src/voxels/Chunk.h b/src/voxels/Chunk.h new file mode 100644 index 00000000..8cb3815c --- /dev/null +++ b/src/voxels/Chunk.h @@ -0,0 +1,24 @@ +#ifndef VOXELS_CHUNK_H_ +#define VOXELS_CHUNK_H_ + +#define CHUNK_W 16 +#define CHUNK_H 128 +#define CHUNK_D 16 +#define CHUNK_VOL (CHUNK_W * CHUNK_H * CHUNK_D) + +class voxel; +class Lightmap; + +class Chunk { +public: + int x,y,z; + voxel* voxels; + Lightmap* lightmap; + bool modified = true; + Chunk(int x, int y, int z); + ~Chunk(); + + bool isEmpty(); +}; + +#endif /* VOXELS_CHUNK_H_ */ diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp new file mode 100644 index 00000000..e0ccbc8d --- /dev/null +++ b/src/voxels/Chunks.cpp @@ -0,0 +1,388 @@ +#include "Chunks.h" +#include "Chunk.h" +#include "voxel.h" +#include "WorldGenerator.h" +#include "../lighting/Lightmap.h" +#include "../files/WorldFiles.h" + +#include "../lighting/Lighting.h" +#include "../graphics/VoxelRenderer.h" +#include "../graphics/Mesh.h" + +#include + +using namespace glm; + +#include +#include + +Chunks::Chunks(int w, int h, int d, int ox, int oy, int oz) : w(w), h(h), d(d), ox(ox), oy(oy), oz(oz){ + volume = w*h*d; + chunks = new Chunk*[volume]; + chunksSecond = new Chunk*[volume]; + + meshes = new Mesh*[volume]; + meshesSecond = new Mesh*[volume]; + + for (size_t i = 0; i < volume; i++){ + chunks[i] = nullptr; + meshes[i] = nullptr; + } +} + +Chunks::~Chunks(){ + for (size_t i = 0; i < volume; i++){ + delete chunks[i]; + } + delete[] chunks; +} + +bool Chunks::_buildMeshes(VoxelRenderer* renderer) { + int nearX = 0; + int nearY = 0; + int nearZ = 0; + int minDistance = 1000000000; + for (unsigned int y = 0; y < h; y++){ + for (unsigned int z = 1; z < d-1; z++){ + for (unsigned int x = 1; x < w-1; x++){ + int index = (y * d + z) * w + x; + Chunk* chunk = chunks[index]; + if (chunk == nullptr) + continue; + Mesh* mesh = meshes[index]; + if (mesh != nullptr && !chunk->modified) + continue; + int lx = x - w / 2; + int ly = y - h / 2; + int lz = z - d / 2; + int distance = (lx * lx + ly * ly + lz * lz); + if (distance < minDistance){ + minDistance = distance; + nearX = x; + nearY = y; + nearZ = z; + } + } + } + } + + int index = (nearY * d + nearZ) * w + nearX; + + Chunk* closes[27]; + + Chunk* chunk = chunks[index]; + if (chunk == nullptr) + return false; + Mesh* mesh = meshes[index]; + if (mesh == nullptr || chunk->modified){ + if (mesh != nullptr) + delete mesh; + if (chunk->isEmpty()){ + meshes[index] = nullptr; + return false; + } + chunk->modified = false; + for (int i = 0; i < 27; i++) + closes[i] = nullptr; + for (size_t j = 0; j < volume; j++){ + Chunk* other = chunks[j]; + if (other == nullptr) + continue; + + int ox = other->x - chunk->x; + int oy = other->y - chunk->y; + int oz = other->z - chunk->z; + + if (abs(ox) > 1 || abs(oy) > 1 || abs(oz) > 1) + continue; + + ox += 1; + oy += 1; + oz += 1; + closes[(oy * 3 + oz) * 3 + ox] = other; + } + mesh = renderer->render(chunk, (const Chunk**)closes); + meshes[index] = mesh; + return true; + } + return false; +} + +voxel* Chunks::get(int x, int y, int z){ + x -= ox * CHUNK_W; + y -= oy * CHUNK_H; + z -= oz * CHUNK_D; + int cx = x / CHUNK_W; + int cy = y / CHUNK_H; + int cz = z / CHUNK_D; + if (x < 0) cx--; + if (y < 0) cy--; + if (z < 0) cz--; + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= h || cz >= d) + return nullptr; + Chunk* chunk = chunks[(cy * d + cz) * w + cx]; + if (chunk == nullptr) + return nullptr; + int lx = x - cx * CHUNK_W; + int ly = y - cy * CHUNK_H; + int lz = z - cz * CHUNK_D; + return &chunk->voxels[(ly * CHUNK_D + lz) * CHUNK_W + lx]; +} + +unsigned char Chunks::getLight(int x, int y, int z, int channel){ + x -= ox * CHUNK_W; + y -= oy * CHUNK_H; + z -= oz * CHUNK_D; + int cx = x / CHUNK_W; + int cy = y / CHUNK_H; + int cz = z / CHUNK_D; + if (x < 0) cx--; + if (y < 0) cy--; + if (z < 0) cz--; + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= h || cz >= d) + return 0; + Chunk* chunk = chunks[(cy * d + cz) * w + cx]; + if (chunk == nullptr) + return 0; + int lx = x - cx * CHUNK_W; + int ly = y - cy * CHUNK_H; + int lz = z - cz * CHUNK_D; + return chunk->lightmap->get(lx,ly,lz, channel); +} + +Chunk* Chunks::getChunkByVoxel(int x, int y, int z){ + x -= ox * CHUNK_W; + y -= oy * CHUNK_H; + z -= oz * CHUNK_D; + int cx = x / CHUNK_W; + int cy = y / CHUNK_H; + int cz = z / CHUNK_D; + if (x < 0) cx--; + if (y < 0) cy--; + if (z < 0) cz--; + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= h || cz >= d) + return nullptr; + return chunks[(cy * d + cz) * w + cx]; +} + +Chunk* Chunks::getChunk(int x, int y, int z){ + x -= ox; + y -= oy; + z -= oz; + if (x < 0 || y < 0 || z < 0 || x >= w || y >= h || z >= d) + return nullptr; + return chunks[(y * d + z) * w + x]; +} + +void Chunks::set(int x, int y, int z, int id){ + x -= ox * CHUNK_W; + y -= oy * CHUNK_H; + z -= oz * CHUNK_D; + int cx = x / CHUNK_W; + int cy = y / CHUNK_H; + int cz = z / CHUNK_D; + if (x < 0) cx--; + if (y < 0) cy--; + if (z < 0) cz--; + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= h || cz >= d) + return; + Chunk* chunk = chunks[(cy * d + cz) * w + cx]; + if (chunk == nullptr) + return; + int lx = x - cx * CHUNK_W; + int ly = y - cy * CHUNK_H; + int lz = z - cz * CHUNK_D; + chunk->voxels[(ly * CHUNK_D + lz) * CHUNK_W + lx].id = id; + chunk->modified = true; + + if (lx == 0 && (chunk = getChunk(cx+ox-1, cy+oy, cz+oz))) chunk->modified = true; + if (ly == 0 && (chunk = getChunk(cx+ox, cy+oy-1, cz+oz))) chunk->modified = true; + if (lz == 0 && (chunk = getChunk(cx+ox, cy+oy, cz+oz-1))) chunk->modified = true; + + if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cy+oy, cz+oz))) chunk->modified = true; + if (ly == CHUNK_H-1 && (chunk = getChunk(cx+ox, cy+oy+1, cz+oz))) chunk->modified = true; + if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cy+oy, cz+oz+1))) chunk->modified = true; +} + +voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, vec3& iend) { + float px = a.x; + float py = a.y; + float pz = a.z; + + float dx = dir.x; + float dy = dir.y; + float dz = dir.z; + + float t = 0.0f; + int ix = floor(px); + int iy = floor(py); + int iz = floor(pz); + + float stepx = (dx > 0.0f) ? 1.0f : -1.0f; + float stepy = (dy > 0.0f) ? 1.0f : -1.0f; + float stepz = (dz > 0.0f) ? 1.0f : -1.0f; + + float infinity = std::numeric_limits::infinity(); + + float txDelta = (dx == 0.0f) ? infinity : abs(1.0f / dx); + float tyDelta = (dy == 0.0f) ? infinity : abs(1.0f / dy); + float tzDelta = (dz == 0.0f) ? infinity : abs(1.0f / dz); + + float xdist = (stepx > 0) ? (ix + 1 - px) : (px - ix); + float ydist = (stepy > 0) ? (iy + 1 - py) : (py - iy); + float zdist = (stepz > 0) ? (iz + 1 - pz) : (pz - iz); + + float txMax = (txDelta < infinity) ? txDelta * xdist : infinity; + float tyMax = (tyDelta < infinity) ? tyDelta * ydist : infinity; + float tzMax = (tzDelta < infinity) ? tzDelta * zdist : infinity; + + int steppedIndex = -1; + + while (t <= maxDist){ + voxel* voxel = get(ix, iy, iz); + if (voxel == nullptr || voxel->id){ + end.x = px + t * dx; + end.y = py + t * dy; + end.z = pz + t * dz; + + iend.x = ix; + iend.y = iy; + iend.z = iz; + + norm.x = norm.y = norm.z = 0.0f; + if (steppedIndex == 0) norm.x = -stepx; + if (steppedIndex == 1) norm.y = -stepy; + if (steppedIndex == 2) norm.z = -stepz; + return voxel; + } + if (txMax < tyMax) { + if (txMax < tzMax) { + ix += stepx; + t = txMax; + txMax += txDelta; + steppedIndex = 0; + } else { + iz += stepz; + t = tzMax; + tzMax += tzDelta; + steppedIndex = 2; + } + } else { + if (tyMax < tzMax) { + iy += stepy; + t = tyMax; + tyMax += tyDelta; + steppedIndex = 1; + } else { + iz += stepz; + t = tzMax; + tzMax += tzDelta; + steppedIndex = 2; + } + } + } + iend.x = ix; + iend.y = iy; + iend.z = iz; + + end.x = px + t * dx; + end.y = py + t * dy; + end.z = pz + t * dz; + norm.x = norm.y = norm.z = 0.0f; + return nullptr; +} + +void Chunks::setCenter(int x, int y, int z) { + int cx = x / CHUNK_W; + int cy = y / CHUNK_H; + int cz = z / CHUNK_D; + cx -= ox; + cy -= oy; + cz -= oz; + if (x < 0) cx--; + if (y < 0) cy--; + if (z < 0) cz--; + cx -= w/2; + cy -= h/2; + cz -= d/2; + if (cx != 0 || cy != 0 || cz != 0) + translate(cx,cy,cz); +} + +bool Chunks::loadVisible(WorldFiles* worldFiles){ + int nearX = 0; + int nearY = 0; + int nearZ = 0; + int minDistance = 1000000000; + for (unsigned int y = 0; y < h; y++){ + for (unsigned int z = 1; z < d-1; z++){ + for (unsigned int x = 1; x < w-1; x++){ + int index = (y * d + z) * w + x; + Chunk* chunk = chunks[index]; + if (chunk != nullptr) + continue; + int lx = x - w / 2; + int ly = y - h / 2; + int lz = z - d / 2; + int distance = (lx * lx + ly * ly + lz * lz); + if (distance < minDistance){ + minDistance = distance; + nearX = x; + nearY = y; + nearZ = z; + } + } + } + } + + int index = (nearY * d + nearZ) * w + nearX; + Chunk* chunk = chunks[index]; + if (chunk != nullptr) + return false; + chunk = new Chunk(nearX+ox,nearY+oy,nearZ+oz); + if (!worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels)){ + WorldGenerator::generate(chunk->voxels, chunk->x, chunk->y, chunk->z); + } + + chunks[index] = chunk; + Lighting::onChunkLoaded(ox+nearX, oy+nearY, oz+nearZ); + return true; +} + +void Chunks::translate(int dx, int dy, int dz){ + for (unsigned int i = 0; i < volume; i++){ + chunksSecond[i] = nullptr; + meshesSecond[i] = nullptr; + } + for (unsigned int y = 0; y < h; y++){ + for (unsigned int z = 0; z < d; z++){ + for (unsigned int x = 0; x < w; x++){ + Chunk* chunk = chunks[(y * d + z) * w + x]; + int nx = x - dx; + int ny = y - dy; + int nz = z - dz; + if (chunk == nullptr) + continue; + Mesh* mesh = meshes[(y * d + z) * w + x]; + if (nx < 0 || ny < 0 || nz < 0 || nx >= w || ny >= h || nz >= d){ + delete chunk; + delete mesh; + continue; + } + meshesSecond[(ny * d + nz) * w + nx] = mesh; + chunksSecond[(ny * d + nz) * w + nx] = chunk; + } + } + } + Chunk** ctemp = chunks; + chunks = chunksSecond; + chunksSecond = ctemp; + + Mesh** mtemp = meshes; + meshes = meshesSecond; + meshesSecond = mtemp; + + ox += dx; + oy += dy; + oz += dz; +} diff --git a/src/voxels/Chunks.h b/src/voxels/Chunks.h new file mode 100644 index 00000000..b70e4baf --- /dev/null +++ b/src/voxels/Chunks.h @@ -0,0 +1,43 @@ +#ifndef VOXELS_CHUNKS_H_ +#define VOXELS_CHUNKS_H_ + +#include +#include + +using namespace glm; + +class Mesh; +class VoxelRenderer; + +class Chunk; +class voxel; +class WorldFiles; + +class Chunks { +public: + Chunk** chunks; + Chunk** chunksSecond; + Mesh** meshes; + Mesh** meshesSecond; + size_t volume; + unsigned int w,h,d; + int ox,oy,oz; + + Chunks(int w, int h, int d, int ox, int oy, int oz); + ~Chunks(); + + Chunk* getChunk(int x, int y, int z); + Chunk* getChunkByVoxel(int x, int y, int z); + voxel* get(int x, int y, int z); + unsigned char getLight(int x, int y, int z, int channel); + void set(int x, int y, int z, int id); + voxel* rayCast(vec3 start, vec3 dir, float maxLength, vec3& end, vec3& norm, vec3& iend); + + void setCenter(int x, int y, int z); + void translate(int x, int y, int z); + + bool loadVisible(WorldFiles* worldFiles); + bool _buildMeshes(VoxelRenderer* renderer); +}; + +#endif /* VOXELS_CHUNKS_H_ */ diff --git a/src/voxels/WorldGenerator.cpp b/src/voxels/WorldGenerator.cpp new file mode 100644 index 00000000..663cfae9 --- /dev/null +++ b/src/voxels/WorldGenerator.cpp @@ -0,0 +1,31 @@ +#include "WorldGenerator.h" +#include "voxel.h"; +#include "Chunk.h"; + +#include +#include +#include + +void WorldGenerator::generate(voxel* voxels, int cx, int cy, int cz){ + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + int real_x = x + cx * CHUNK_W; + int real_z = z + cz * CHUNK_D; + float height = glm::perlin(glm::vec3(real_x*0.0125f,real_z*0.0125f, 0.0f)); + height += glm::perlin(glm::vec3(real_x*0.025f,real_z*0.025f, 0.0f))*0.5f; + height *= 0.1f; + height += 0.05f; + for (int y = 0; y < CHUNK_H; y++){ + int real_y = y + cy * CHUNK_H; + float noise = height; + int id = noise / std::fmax(0.01f, real_y*0.1f + 0.1f) > 0.1f; + if (real_y <= 2) + id = 2; + + if (id == 0 && real_y == 14 && height <= 0.01f) + id = 1; + voxels[(y * CHUNK_D + z) * CHUNK_W + x].id = id; + } + } + } +} diff --git a/src/voxels/WorldGenerator.h b/src/voxels/WorldGenerator.h new file mode 100644 index 00000000..c04dbd31 --- /dev/null +++ b/src/voxels/WorldGenerator.h @@ -0,0 +1,11 @@ +#ifndef VOXELS_WORLDGENERATOR_H_ +#define VOXELS_WORLDGENERATOR_H_ + +class voxel; + +class WorldGenerator { +public: + static void generate(voxel* voxels, int x, int y, int z); +}; + +#endif /* VOXELS_WORLDGENERATOR_H_ */ diff --git a/src/voxels/voxel.cpp b/src/voxels/voxel.cpp new file mode 100644 index 00000000..4a391ec7 --- /dev/null +++ b/src/voxels/voxel.cpp @@ -0,0 +1,2 @@ +#include "voxel.h" + diff --git a/src/voxels/voxel.h b/src/voxels/voxel.h new file mode 100644 index 00000000..4e758376 --- /dev/null +++ b/src/voxels/voxel.h @@ -0,0 +1,10 @@ +#ifndef VOXELS_VOXEL_H_ +#define VOXELS_VOXEL_H_ + +#include + +struct voxel { + uint8_t id; +}; + +#endif /* VOXELS_VOXEL_H_ */ diff --git a/src/window/Camera.cpp b/src/window/Camera.cpp new file mode 100644 index 00000000..05bc0361 --- /dev/null +++ b/src/window/Camera.cpp @@ -0,0 +1,38 @@ +/* + * Camera.cpp + * + * Created on: Feb 11, 2020 + * Author: MihailRis + */ + +#include "Camera.h" +#include "Window.h" + +#include + +Camera::Camera(vec3 position, float fov) : position(position), fov(fov), rotation(1.0f) { + updateVectors(); +} + +void Camera::updateVectors(){ + front = vec3(rotation * vec4(0,0,-1,1)); + right = vec3(rotation * vec4(1,0,0,1)); + up = vec3(rotation * vec4(0,1,0,1)); +} + +void Camera::rotate(float x, float y, float z){ + rotation = glm::rotate(rotation, z, vec3(0,0,1)); + rotation = glm::rotate(rotation, y, vec3(0,1,0)); + rotation = glm::rotate(rotation, x, vec3(1,0,0)); + + updateVectors(); +} + +mat4 Camera::getProjection(){ + float aspect = (float)Window::width / (float)Window::height; + return glm::perspective(fov, aspect, 0.1f, 1500.0f); +} + +mat4 Camera::getView(){ + return glm::lookAt(position, position+front, up); +} diff --git a/src/window/Camera.h b/src/window/Camera.h new file mode 100644 index 00000000..c42a0a93 --- /dev/null +++ b/src/window/Camera.h @@ -0,0 +1,32 @@ +/* + * Camera.h + * + * Created on: Feb 11, 2020 + * Author: MihailRis + */ + +#ifndef WINDOW_CAMERA_H_ +#define WINDOW_CAMERA_H_ + +#include +using namespace glm; + +class Camera { + void updateVectors(); +public: + vec3 front; + vec3 up; + vec3 right; + + vec3 position; + float fov; + mat4 rotation; + Camera(vec3 position, float fov); + + void rotate(float x, float y, float z); + + mat4 getProjection(); + mat4 getView(); +}; + +#endif /* WINDOW_CAMERA_H_ */ diff --git a/src/window/Events.cpp b/src/window/Events.cpp new file mode 100644 index 00000000..6e323f1c --- /dev/null +++ b/src/window/Events.cpp @@ -0,0 +1,105 @@ +#include "Events.h" +#include +#include +#include + +bool* Events::_keys; +uint* Events::_frames; +uint Events::_current = 0; +float Events::deltaX = 0.0f; +float Events::deltaY = 0.0f; +float Events::x = 0.0f; +float Events::y = 0.0f; +bool Events::_cursor_locked = false; +bool Events::_cursor_started = false; + +#define _MOUSE_BUTTONS 1024 + +void cursor_position_callback(GLFWwindow* window, double xpos, double ypos){ + if (Events::_cursor_started){ + Events::deltaX += xpos-Events::x; + Events::deltaY += ypos-Events::y; + } + else { + Events::_cursor_started = true; + } + Events::x = xpos; + Events::y = ypos; +} + +void mouse_button_callback(GLFWwindow* window, int button, int action, int mode){ + if (action == GLFW_PRESS){ + Events::_keys[_MOUSE_BUTTONS+button] = true; + Events::_frames[_MOUSE_BUTTONS+button] = Events::_current; + } + else if (action == GLFW_RELEASE){ + Events::_keys[_MOUSE_BUTTONS+button] = false; + Events::_frames[_MOUSE_BUTTONS+button] = Events::_current; + } +} + +void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) { + if (action == GLFW_PRESS){ + Events::_keys[key] = true; + Events::_frames[key] = Events::_current; + } + else if (action == GLFW_RELEASE){ + Events::_keys[key] = false; + Events::_frames[key] = Events::_current; + } +} + +void window_size_callback(GLFWwindow* window, int width, int height){ + glViewport(0,0, width, height); + Window::width = width; + Window::height = height; +} + +int Events::initialize(){ + GLFWwindow* window = Window::window; + _keys = new bool[1032]; + _frames = new uint[1032]; + + memset(_keys, false, 1032*sizeof(bool)); + memset(_frames, 0, 1032*sizeof(uint)); + + glfwSetKeyCallback(window, key_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetWindowSizeCallback(window, window_size_callback); + return 0; +} + +bool Events::pressed(int keycode){ + if (keycode < 0 || keycode >= _MOUSE_BUTTONS) + return false; + return _keys[keycode]; +} + +bool Events::jpressed(int keycode){ + if (keycode < 0 || keycode >= _MOUSE_BUTTONS) + return false; + return _keys[keycode] && _frames[keycode] == _current; +} + +bool Events::clicked(int button){ + int index = _MOUSE_BUTTONS+button; + return _keys[index]; +} + +bool Events::jclicked(int button){ + int index = _MOUSE_BUTTONS+button; + return _keys[index] && _frames[index] == _current; +} + +void Events::toogleCursor(){ + _cursor_locked = !_cursor_locked; + Window::setCursorMode(_cursor_locked ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); +} + +void Events::pullEvents(){ + _current++; + deltaX = 0.0f; + deltaY = 0.0f; + glfwPollEvents(); +} diff --git a/src/window/Events.h b/src/window/Events.h new file mode 100644 index 00000000..414a06bc --- /dev/null +++ b/src/window/Events.h @@ -0,0 +1,32 @@ +#ifndef WINDOW_EVENTS_H_ +#define WINDOW_EVENTS_H_ + +#include "Window.h" + +typedef unsigned int uint; + +class Events { +public: + static bool* _keys; + static uint* _frames; + static uint _current; + static float deltaX; + static float deltaY; + static float x; + static float y; + static bool _cursor_locked; + static bool _cursor_started; + + static int initialize(); + static void pullEvents(); + + static bool pressed(int keycode); + static bool jpressed(int keycode); + + static bool clicked(int button); + static bool jclicked(int button); + + static void toogleCursor(); +}; + +#endif /* WINDOW_EVENTS_H_ */ diff --git a/src/window/Window.cpp b/src/window/Window.cpp new file mode 100644 index 00000000..c3cf644f --- /dev/null +++ b/src/window/Window.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include "Window.h" + +GLFWwindow* Window::window; +int Window::width = 0; +int Window::height = 0; + +int Window::initialize(int width, int height, const char* title){ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); + //glfwWindowHint(GLFW_SAMPLES, 2); + + window = glfwCreateWindow(width, height, title, nullptr, nullptr); + if (window == nullptr){ + std::cerr << "Failed to create GLFW Window" << std::endl; + glfwTerminate(); + return -1; + } + glfwMakeContextCurrent(window); + + glewExperimental = GL_TRUE; + if (glewInit() != GLEW_OK){ + std::cerr << "Failed to initialize GLEW" << std::endl; + return -1; + } + glViewport(0,0, width, height); + + Window::width = width; + Window::height = height; + return 0; +} + +void Window::setCursorMode(int mode){ + glfwSetInputMode(window, GLFW_CURSOR, mode); +} + +void Window::terminate(){ + glfwTerminate(); +} + +bool Window::isShouldClose(){ + return glfwWindowShouldClose(window); +} + +void Window::setShouldClose(bool flag){ + glfwSetWindowShouldClose(window, flag); +} + +void Window::swapBuffers(){ + glfwSwapBuffers(window); +} diff --git a/src/window/Window.h b/src/window/Window.h new file mode 100644 index 00000000..a0575af9 --- /dev/null +++ b/src/window/Window.h @@ -0,0 +1,20 @@ +#ifndef WINDOW_WINDOW_H_ +#define WINDOW_WINDOW_H_ + +class GLFWwindow; + +class Window { +public: + static int width; + static int height; + static GLFWwindow* window; // не лучшее решение делать window публичным + static int initialize(int width, int height, const char* title); + static void terminate(); + + static void setCursorMode(int mode); + static bool isShouldClose(); + static void setShouldClose(bool flag); + static void swapBuffers(); +}; + +#endif /* WINDOW_WINDOW_H_ */