diff --git a/.gitignore b/.gitignore index da925adf..30c69d45 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ world .settings .cproject .project +.git +/Default/ \ No newline at end of file diff --git a/Debug/makefile b/Debug/makefile index cbc3aa03..0247a747 100644 --- a/Debug/makefile +++ b/Debug/makefile @@ -8,6 +8,7 @@ RM := rm -rf # All of the sources participating in the build are defined here -include sources.mk +-include src/world/subdir.mk -include src/window/subdir.mk -include src/voxels/subdir.mk -include src/physics/subdir.mk @@ -16,6 +17,7 @@ RM := rm -rf -include src/lighting/subdir.mk -include src/graphics/subdir.mk -include src/files/subdir.mk +-include src/audio/subdir.mk -include src/subdir.mk -include subdir.mk -include objects.mk diff --git a/Debug/objects.mk b/Debug/objects.mk index 471b1bf6..b7d25c5b 100644 --- a/Debug/objects.mk +++ b/Debug/objects.mk @@ -4,5 +4,5 @@ USER_OBJS := -LIBS := -lglfw -lpng -lGL -lGLEW -lstdc++fs +LIBS := -lglfw -lpng -lGL -lGLEW -lstdc++fs -lopenal diff --git a/Debug/res b/Debug/res new file mode 120000 index 00000000..85ee7023 --- /dev/null +++ b/Debug/res @@ -0,0 +1 @@ +../res \ No newline at end of file diff --git a/Debug/sources.mk b/Debug/sources.mk index fb65165d..39d73484 100644 --- a/Debug/sources.mk +++ b/Debug/sources.mk @@ -24,6 +24,7 @@ CPP_DEPS := # Every subdirectory with source files must be described here SUBDIRS := \ src \ +src/audio \ src/files \ src/graphics \ src/lighting \ @@ -32,4 +33,5 @@ src/objects \ src/physics \ src/voxels \ src/window \ +src/world \ diff --git a/Debug/src/audio/subdir.mk b/Debug/src/audio/subdir.mk new file mode 100644 index 00000000..a12515df --- /dev/null +++ b/Debug/src/audio/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/audio/Audio.cpp \ +../src/audio/audioutil.cpp + +OBJS += \ +./src/audio/Audio.o \ +./src/audio/audioutil.o + +CPP_DEPS += \ +./src/audio/Audio.d \ +./src/audio/audioutil.d + + +# Each subdirectory must supply rules for building sources it contributes +src/audio/%.o: ../src/audio/%.cpp src/audio/subdir.mk + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/Debug/src/graphics/subdir.mk b/Debug/src/graphics/subdir.mk index db314574..743d753c 100644 --- a/Debug/src/graphics/subdir.mk +++ b/Debug/src/graphics/subdir.mk @@ -5,26 +5,41 @@ # Add inputs and outputs from these tool invocations to the build variables CPP_SRCS += \ ../src/graphics/Batch2D.cpp \ +../src/graphics/Batch3D.cpp \ +../src/graphics/Font.cpp \ ../src/graphics/LineBatch.cpp \ ../src/graphics/Mesh.cpp \ ../src/graphics/Shader.cpp \ ../src/graphics/Texture.cpp \ +../src/graphics/Sprite.cpp \ +../src/graphics/UVRegion.cpp \ +../src/graphics/Framebuffer.cpp \ ../src/graphics/VoxelRenderer.cpp OBJS += \ ./src/graphics/Batch2D.o \ +./src/graphics/Batch3D.o \ +./src/graphics/Font.o \ ./src/graphics/LineBatch.o \ ./src/graphics/Mesh.o \ ./src/graphics/Shader.o \ ./src/graphics/Texture.o \ +./src/graphics/Sprite.o \ +./src/graphics/UVRegion.o \ +./src/graphics/Framebuffer.o \ ./src/graphics/VoxelRenderer.o CPP_DEPS += \ ./src/graphics/Batch2D.d \ +./src/graphics/Batch3D.d \ +./src/graphics/Font.d \ ./src/graphics/LineBatch.d \ ./src/graphics/Mesh.d \ ./src/graphics/Shader.d \ ./src/graphics/Texture.d \ +./src/graphics/Sprite.d \ +./src/graphics/UVRegion.d \ +./src/graphics/Framebuffer.d \ ./src/graphics/VoxelRenderer.d diff --git a/Debug/src/subdir.mk b/Debug/src/subdir.mk index 5919ac83..60c123c4 100644 --- a/Debug/src/subdir.mk +++ b/Debug/src/subdir.mk @@ -5,14 +5,26 @@ # Add inputs and outputs from these tool invocations to the build variables CPP_SRCS += \ ../src/Assets.cpp \ +../src/player_control.cpp \ +../src/hud_render.cpp \ +../src/world_render.cpp \ +../src/declarations.cpp \ ../src/voxel_engine.cpp OBJS += \ ./src/Assets.o \ +./src/player_control.o \ +./src/hud_render.o \ +./src/world_render.o \ +./src/declarations.o \ ./src/voxel_engine.o CPP_DEPS += \ ./src/Assets.d \ +./src/player_control.d \ +./src/hud_render.d \ +./src/world_render.d \ +./src/declarations.d \ ./src/voxel_engine.d diff --git a/Debug/src/world/subdir.mk b/Debug/src/world/subdir.mk new file mode 100644 index 00000000..0d5d11aa --- /dev/null +++ b/Debug/src/world/subdir.mk @@ -0,0 +1,27 @@ +################################################################################ +# Automatically-generated file. Do not edit! +################################################################################ + +# Add inputs and outputs from these tool invocations to the build variables +CPP_SRCS += \ +../src/world/Level.cpp \ +../src/world/World.cpp + +OBJS += \ +./src/world/Level.o \ +./src/world/World.o + +CPP_DEPS += \ +./src/world/Level.d \ +./src/world/World.d + + +# Each subdirectory must supply rules for building sources it contributes +src/world/%.o: ../src/world/%.cpp src/world/subdir.mk + @echo 'Building file: $<' + @echo 'Invoking: Cross G++ Compiler' + g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$@" -o "$@" "$<" + @echo 'Finished building: $<' + @echo ' ' + + diff --git a/README.md b/README.md index 80e6234f..c42ff866 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,25 @@ -# Run in windows with compiled executable file +# Run in windows with compiled executable file: [EXE for windows](https://drive.google.com/file/d/1lkFc5nyYOs0Yyu1wmOoAAwEp4r9jO1tE/view?usp=sharing)
[MinGW libraries (include & lib) + glew32.dll](https://drive.google.com/file/d/1k1Hnbz2Uhr4-03upt2yHxKws396HQDra/view?usp=sharing) -# Run in linux with +# Run in linux: `$ git clone https://github.com/MihailRis/VoxelEngine-Cpp.git` `$ cd VoxelEngine-Cpp/Debug` -### Debian-based distro: - - $ sudo apt install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev - -### RHEL-based distro: - - $ sudo dnf install glfw-devel glfw glew-devel glm-devel libpng-devel - `$ make` -`$ cd ..` +`$ ./voxel_engine` -`$ ./Debug/voxel_engine` +## Instal libs: +#### Debian-based distro: +`$ sudo apt install libglfw3-dev libglfw3 libglew-dev libglm-dev libpng-dev libopenal-dev` -# Note for MinGW compiling +#### RHEL-based distro: +`$ sudo dnf install glfw-devel glfw glew-devel glm-devel libpng-devel openal-devel` + +# Note for MinGW compiling: To fix problem with `#include ` get headers `mingw.thread.h` and `mingw.invoke.h` from: https://github.com/meganz/mingw-std-threads diff --git a/res/block.png b/res/block.png index 5e2512c7..e7c090d1 100644 Binary files a/res/block.png and b/res/block.png differ diff --git a/res/block (copy).png b/res/block.png.old similarity index 100% rename from res/block (copy).png rename to res/block.png.old diff --git a/res/block_.png b/res/block_.png deleted file mode 100644 index d4941919..00000000 Binary files a/res/block_.png and /dev/null differ diff --git a/res/block_white.png b/res/block_white.png deleted file mode 100644 index cfb6a408..00000000 Binary files a/res/block_white.png and /dev/null differ diff --git a/res/ascii.png b/res/font.png similarity index 100% rename from res/ascii.png rename to res/font.png diff --git a/res/font_0.png b/res/font_0.png new file mode 100644 index 00000000..0f156612 Binary files /dev/null and b/res/font_0.png differ diff --git a/res/font_1.png b/res/font_1.png new file mode 100644 index 00000000..92d7b2b3 Binary files /dev/null and b/res/font_1.png differ diff --git a/res/font_2.png b/res/font_2.png new file mode 100644 index 00000000..984affe8 Binary files /dev/null and b/res/font_2.png differ diff --git a/res/font_3.png b/res/font_3.png new file mode 100644 index 00000000..49b44eec Binary files /dev/null and b/res/font_3.png differ diff --git a/res/font_4.png b/res/font_4.png new file mode 100644 index 00000000..b2c0445c Binary files /dev/null and b/res/font_4.png differ diff --git a/res/img.png b/res/img.png index f7704de1..63e4fba6 100644 Binary files a/res/img.png and b/res/img.png differ diff --git a/res/main.glslf b/res/main.glslf index 1b998767..9127e7ac 100644 --- a/res/main.glslf +++ b/res/main.glslf @@ -7,11 +7,15 @@ out vec4 f_color; uniform sampler2D u_texture0; uniform vec3 u_fogColor; +uniform float u_fogFactor; void main(){ vec4 tex_color = texture(u_texture0, a_texCoord); - //if (tex_color.a < 0.5) - // discard; - float depth = (a_distance/256.0)*(a_distance/256.0)*256.0; - f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, depth/256.0/1.0f)); + float depth = (a_distance/256.0); + float alpha = a_color.a * tex_color.a; + // anyway it's any alpha-test alternative required + if (alpha < 0.1f) + discard; + f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, depth*u_fogFactor)); + f_color.a = alpha; } diff --git a/res/main.glslv b/res/main.glslv index 8f3e237e..98a7acc3 100644 --- a/res/main.glslv +++ b/res/main.glslv @@ -15,12 +15,19 @@ uniform vec3 u_skyLightColor; uniform vec3 u_cameraPos; uniform float u_gamma; +uniform vec3 u_torchlightColor; +uniform float u_torchlightDistance; + void main(){ vec2 pos2d = (u_model * vec4(v_position, 1.0)).xz-u_cameraPos.xz; - vec4 viewmodelpos = u_view * u_model * vec4(v_position+vec3(0,pow(length(pos2d)*0.0, 3.0),0), 1.0); - a_color = vec4(pow(v_light.rgb, vec3(u_gamma)),1.0f); + vec4 modelpos = u_model * vec4(v_position+vec3(0,pow(length(pos2d)*0.0, 3.0),0), 1.0); + vec4 viewmodelpos = u_view * modelpos; + vec3 light = v_light.rgb; + float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz)/u_torchlightDistance); + light += torchlight * u_torchlightColor; + a_color = vec4(pow(light, vec3(u_gamma)),1.0f); a_texCoord = v_texCoord; - a_color.rgb += u_skyLightColor * v_light.a*0.5; - a_distance = length(viewmodelpos); + a_color.rgb += u_skyLightColor * v_light.a; + a_distance = pow(length(viewmodelpos), 1.5); gl_Position = u_proj * viewmodelpos; } diff --git a/res/slot.png b/res/slot.png new file mode 100644 index 00000000..65c5d3ad Binary files /dev/null and b/res/slot.png differ diff --git a/res/ui.glslf b/res/ui.glslf new file mode 100644 index 00000000..ef51d8bf --- /dev/null +++ b/res/ui.glslf @@ -0,0 +1,11 @@ +#version 330 core + +in vec2 a_textureCoord; +in vec4 a_color; +out vec4 f_color; + +uniform sampler2D u_texture; + +void main(){ + f_color = a_color * texture(u_texture, a_textureCoord); +} diff --git a/res/ui.glslv b/res/ui.glslv new file mode 100644 index 00000000..2b65d101 --- /dev/null +++ b/res/ui.glslv @@ -0,0 +1,16 @@ +#version 330 core + +layout (location = 0) in vec2 v_position; +layout (location = 1) in vec2 v_textureCoord; +layout (location = 2) in vec4 v_color; + +out vec2 a_textureCoord; +out vec4 a_color; + +uniform mat4 u_projview; + +void main(){ + a_textureCoord = v_textureCoord; + a_color = v_color; + gl_Position = u_projview * vec4(v_position, 0.5, 1.0); +} diff --git a/src/Assets.cpp b/src/Assets.cpp index fbaaa21e..64f7d6b5 100644 --- a/src/Assets.cpp +++ b/src/Assets.cpp @@ -2,6 +2,7 @@ #include "graphics/Texture.h" #include "graphics/Shader.h" +#include "graphics/Font.h" Assets::~Assets() { for (auto& iter : shaders){ @@ -11,6 +12,10 @@ Assets::~Assets() { for (auto& iter : textures){ delete iter.second; } + + for (auto& iter : fonts){ + delete iter.second; + } } Texture* Assets::getTexture(std::string name){ @@ -29,3 +34,12 @@ Shader* Assets::getShader(std::string name){ void Assets::store(Shader* shader, std::string name){ shaders[name] = shader; } + + +Font* Assets::getFont(std::string name){ + return fonts[name]; +} + +void Assets::store(Font* font, std::string name){ + fonts[name] = font; +} diff --git a/src/Assets.h b/src/Assets.h index daca7d19..3dc9fa5d 100644 --- a/src/Assets.h +++ b/src/Assets.h @@ -6,10 +6,12 @@ class Texture; class Shader; +class Font; class Assets { std::unordered_map textures; std::unordered_map shaders; + std::unordered_map fonts; public: ~Assets(); Texture* getTexture(std::string name); @@ -17,6 +19,9 @@ public: Shader* getShader(std::string name); void store(Shader* shader, std::string name); + + Font* getFont(std::string name); + void store(Font* font, std::string name); }; #endif /* SRC_ASSETS_H_ */ diff --git a/src/audio/Audio.cpp b/src/audio/Audio.cpp new file mode 100644 index 00000000..5562d2e9 --- /dev/null +++ b/src/audio/Audio.cpp @@ -0,0 +1,188 @@ +#include "Audio.h" +#include "audioutil.h" +#include +#include + +#include +#include + +ALCdevice* Audio::device; +ALCcontext* Audio::context; +unsigned Audio::maxSources; +unsigned Audio::maxBuffers = 1024; +std::vector Audio::allsources; +std::vector Audio::freesources; +std::vector Audio::allbuffers; +std::vector Audio::freebuffers; + +bool ALSource::setBuffer(ALBuffer* buffer) { + alSourcei(id, AL_BUFFER, buffer->id); + return alCheck(); +} + +bool ALSource::play(){ + alSourcePlay(id); + return alCheck(); +} + +bool ALSource::isPlaying() { + int state; + alGetSourcei(id, AL_SOURCE_STATE, &state); + return state == AL_PLAYING; +} + +bool ALSource::setPosition(glm::vec3 position) { + alSource3f(id, AL_POSITION, position.x, position.y, position.z); + return alCheck(); +} + +bool ALSource::setVelocity(glm::vec3 velocity) { + alSource3f(id, AL_VELOCITY, velocity.x, velocity.y, velocity.z); + return alCheck(); +} + +bool ALSource::setLoop(bool loop) { + alSourcei(id, AL_LOOPING, AL_TRUE ? loop : AL_FALSE); + return alCheck(); +} + +bool ALSource::setGain(float gain) { + alSourcef(id, AL_GAIN, gain); + return alCheck(); +} + + +bool ALSource::setPitch(float pitch) { + alSourcef(id, AL_PITCH, pitch); + return alCheck(); +} + +bool ALBuffer::load(int format, const char* data, int size, int freq) { + alBufferData(id, format, data, size, freq); + return alCheck(); +} + + +bool Audio::initialize() { + device = alcOpenDevice(nullptr); + if (device == nullptr) + return false; + context = alcCreateContext(device, nullptr); + if (!alcMakeContextCurrent(context)){ + alcCloseDevice(device); + return false; + } + if (!alCheck()) + return false; + + ALCint size; + alcGetIntegerv(device, ALC_ATTRIBUTES_SIZE, 1, &size); + std::vector attrs(size); + alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]); + for(size_t i=0; iisPlaying()){ + alSourceStop(source->id); alCheck(); + } + alDeleteSources(1, &source->id); alCheck(); + } + + for (ALBuffer* buffer : allbuffers){ + alDeleteBuffers(1, &buffer->id); alCheck(); + } + + alcMakeContextCurrent(context); + alcDestroyContext(context); + if (!alcCloseDevice(device)){ + std::cerr << "device not closed!" << std::endl; + } + device = nullptr; + context = nullptr; +} + +ALSource* Audio::getFreeSource(){ + if (!freesources.empty()){ + ALSource* source = freesources.back(); + freesources.pop_back(); + return source; + } + if (allsources.size() == maxSources){ + std::cerr << "attempted to create new source, but limit is " << maxSources << std::endl; + return nullptr; + } + ALuint id; + alGenSources(1, &id); + if (!alCheck()) + return nullptr; + + ALSource* source = new ALSource(id); + allsources.push_back(source); + return source; +} + +ALBuffer* Audio::getFreeBuffer(){ + if (!freebuffers.empty()){ + ALBuffer* buffer = freebuffers.back(); + freebuffers.pop_back(); + return buffer; + } + if (allbuffers.size() == maxBuffers){ + std::cerr << "attempted to create new ALbuffer, but limit is " << maxBuffers << std::endl; + return nullptr; + } + ALuint id; + alGenBuffers(1, &id); + if (!alCheck()) + return nullptr; + + ALBuffer* buffer = new ALBuffer(id); + allbuffers.push_back(buffer); + return buffer; +} + +void Audio::freeSource(ALSource* source){ + freesources.push_back(source); +} + +void Audio::freeBuffer(ALBuffer* buffer){ + freebuffers.push_back(buffer); +} + +bool Audio::get_available_devices(std::vector& devicesVec){ + const ALCchar* devices; + devices = alcGetString(device, ALC_DEVICE_SPECIFIER); + if (!alCheck()) + return false; + + const char* ptr = devices; + + devicesVec.clear(); + + do { + devicesVec.push_back(std::string(ptr)); + ptr += devicesVec.back().size() + 1; + } + while(*(ptr + 1) != '\0'); + + return true; +} + +void Audio::setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up){ + ALfloat listenerOri[] = { at.x, at.y, at.z, up.x, up.y, up.z }; + + alListener3f(AL_POSITION, position.x, position.y, position.z); + alCheck(); + alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); + alCheck(); + alListenerfv(AL_ORIENTATION, listenerOri); + alCheck(); +} diff --git a/src/audio/Audio.h b/src/audio/Audio.h new file mode 100644 index 00000000..af0663f3 --- /dev/null +++ b/src/audio/Audio.h @@ -0,0 +1,62 @@ +#ifndef SRC_AUDIO_AUDIO_H_ +#define SRC_AUDIO_AUDIO_H_ + +#include +#include + +#include +#include + +#include + + +struct ALBuffer; + +struct ALSource { + ALuint id; + ALSource(ALuint id) : id(id) {} + + bool isPlaying(); + bool setPosition(glm::vec3 position); + bool setVelocity(glm::vec3 velocity); + bool setBuffer(ALBuffer* buffer); + bool setLoop(bool loop); + bool setGain(float gain); + bool setPitch(float pitch); + bool play(); +}; + +struct ALBuffer { + ALuint id; + ALBuffer(ALuint id) : id(id) {} + bool load(int format, const char* data, int size, int freq); +}; + +class Audio { + static ALCdevice* device; + static ALCcontext* context; + + static std::vector allsources; + static std::vector freesources; + + static std::vector allbuffers; + static std::vector freebuffers; + + static unsigned maxSources; + static unsigned maxBuffers; + +public: + static ALSource* getFreeSource(); + static ALBuffer* getFreeBuffer(); + static void freeSource(ALSource* source); + static void freeBuffer(ALBuffer* buffer); + + static bool initialize(); + static void finalize(); + static bool get_available_devices(std::vector& devicesVec); + + static void setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up); + +}; + +#endif /* SRC_AUDIO_AUDIO_H_ */ diff --git a/src/audio/audioutil.cpp b/src/audio/audioutil.cpp new file mode 100644 index 00000000..cfedfdec --- /dev/null +++ b/src/audio/audioutil.cpp @@ -0,0 +1,194 @@ +#include "audioutil.h" + +#include +#include +#include +#include +#include +#include + + +bool is_big_endian(void){ + union { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + + return bint.c[0] == 1; +} + +std::int32_t convert_to_int(char* buffer, std::size_t len){ + std::int32_t a = 0; + if(!is_big_endian()) + std::memcpy(&a, buffer, len); + else + for(std::size_t i = 0; i < len; ++i) + reinterpret_cast(&a)[3 - i] = buffer[i]; + return a; +} + +bool check_al_errors(const std::string& filename, const std::uint_fast32_t line){ + ALenum error = alGetError(); + if(error != AL_NO_ERROR){ + std::cerr << "OpenAL ERROR (" << filename << ": " << line << ")\n" ; + switch(error){ + case AL_INVALID_NAME: + std::cerr << "AL_INVALID_NAME: a bad name (ID) was passed to an OpenAL function"; + break; + case AL_INVALID_ENUM: + std::cerr << "AL_INVALID_ENUM: an invalid enum value was passed to an OpenAL function"; + break; + case AL_INVALID_VALUE: + std::cerr << "AL_INVALID_VALUE: an invalid value was passed to an OpenAL function"; + break; + case AL_INVALID_OPERATION: + std::cerr << "AL_INVALID_OPERATION: the requested operation is not valid"; + break; + case AL_OUT_OF_MEMORY: + std::cerr << "AL_OUT_OF_MEMORY: the requested operation resulted in OpenAL running out of memory"; + break; + default: + std::cerr << "UNKNOWN AL ERROR: " << error; + } + std::cerr << std::endl; + return false; + } + return true; +} + +bool load_wav_file_header(std::ifstream& file, + std::uint8_t& channels, + std::int32_t& sampleRate, + std::uint8_t& bitsPerSample, + ALsizei& size){ + char buffer[4]; + if(!file.is_open()) + return false; + + // the RIFF + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read RIFF" << std::endl; + return false; + } + if(std::strncmp(buffer, "RIFF", 4) != 0){ + std::cerr << "ERROR: file is not a valid WAVE file (header doesn't begin with RIFF)" << std::endl; + return false; + } + + // the size of the file + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read size of file" << std::endl; + return false; + } + + // the WAVE + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read WAVE" << std::endl; + return false; + } + if(std::strncmp(buffer, "WAVE", 4) != 0){ + std::cerr << "ERROR: file is not a valid WAVE file (header doesn't contain WAVE)" << std::endl; + return false; + } + + // "fmt/0" + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read fmt/0" << std::endl; + return false; + } + + // this is always 16, the size of the fmt data chunk + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read the 16" << std::endl; + return false; + } + + // PCM should be 1? + if(!file.read(buffer, 2)){ + std::cerr << "ERROR: could not read PCM" << std::endl; + return false; + } + + // the number of channels + if(!file.read(buffer, 2)){ + std::cerr << "ERROR: could not read number of channels" << std::endl; + return false; + } + channels = convert_to_int(buffer, 2); + + // sample rate + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read sample rate" << std::endl; + return false; + } + sampleRate = convert_to_int(buffer, 4); + + // (sampleRate * bitsPerSample * channels) / 8 + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read (sampleRate * bitsPerSample * channels) / 8" << std::endl; + return false; + } + + // ?? dafaq + if(!file.read(buffer, 2)){ + std::cerr << "ERROR: could not read dafaq" << std::endl; + return false; + } + + // bitsPerSample + if(!file.read(buffer, 2)){ + std::cerr << "ERROR: could not read bits per sample" << std::endl; + return false; + } + bitsPerSample = convert_to_int(buffer, 2); + + // data chunk header "data" + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read data chunk header" << std::endl; + return false; + } + if(std::strncmp(buffer, "data", 4) != 0){ + std::cerr << "ERROR: file is not a valid WAVE file (doesn't have 'data' tag)" << std::endl; + return false; + } + + // size of data + if(!file.read(buffer, 4)){ + std::cerr << "ERROR: could not read data size" << std::endl; + return false; + } + size = convert_to_int(buffer, 4); + + /* cannot be at the end of file */ + if(file.eof()){ + std::cerr << "ERROR: reached EOF on the file" << std::endl; + return false; + } + if(file.fail()){ + std::cerr << "ERROR: fail state set on the file" << std::endl; + return false; + } + return true; +} + +char* load_wav(const std::string& filename, + std::uint8_t& channels, + std::int32_t& sampleRate, + std::uint8_t& bitsPerSample, + ALsizei& size){ + std::ifstream in(filename, std::ios::binary); + if(!in.is_open()){ + std::cerr << "ERROR: Could not open \"" << filename << "\"" << std::endl; + return nullptr; + } + if(!load_wav_file_header(in, channels, sampleRate, bitsPerSample, size)){ + std::cerr << "ERROR: Could not load wav header of \"" << filename << "\"" << std::endl; + return nullptr; + } + + char* data = new char[size]; + + in.read(data, size); + + return data; +} diff --git a/src/audio/audioutil.h b/src/audio/audioutil.h new file mode 100644 index 00000000..f62a06cb --- /dev/null +++ b/src/audio/audioutil.h @@ -0,0 +1,44 @@ +#ifndef SRC_AUDIO_AUDIOUTIL_H_ +#define SRC_AUDIO_AUDIOUTIL_H_ + +#include +#include + +#include + +#define alCheck() check_al_errors(__FILE__, __LINE__) + +bool check_al_errors(const std::string& filename, const std::uint_fast32_t line); + +bool load_wav_file_header(std::ifstream& file, + std::uint8_t& channels, + std::int32_t& sampleRate, + std::uint8_t& bitsPerSample, + ALsizei& size); + +char* load_wav(const std::string& filename, + std::uint8_t& channels, + std::int32_t& sampleRate, + std::uint8_t& bitsPerSample, + ALsizei& size); + +static inline ALenum to_al_format(short channels, short samples){ + bool stereo = (channels > 1); + + switch (samples) { + case 16: + if (stereo) + return AL_FORMAT_STEREO16; + else + return AL_FORMAT_MONO16; + case 8: + if (stereo) + return AL_FORMAT_STEREO8; + else + return AL_FORMAT_MONO8; + default: + return -1; + } +} + +#endif /* SRC_AUDIO_AUDIOUTIL_H_ */ diff --git a/src/declarations.cpp b/src/declarations.cpp new file mode 100644 index 00000000..ddb6bd1d --- /dev/null +++ b/src/declarations.cpp @@ -0,0 +1,154 @@ +#include "declarations.h" + +#include "Assets.h" +#include "graphics/Shader.h" +#include "graphics/Texture.h" +#include "graphics/Font.h" +#include "window/Window.h" + +#include "voxels/Block.h" + +// Shaders, textures +bool _load_shader(Assets* assets, std::string vertex_file, std::string fragment_file, std::string name){ + Shader* shader = load_shader(vertex_file, fragment_file); + if (shader == nullptr){ + std::cerr << "failed to load shader '" << name << "'" << std::endl; + return false; + } + assets->store(shader, name); + return true; +} + +bool _load_texture(Assets* assets, std::string filename, std::string name){ + Texture* texture = load_texture(filename); + if (texture == nullptr){ + std::cerr << "failed to load texture '" << name << "'" << std::endl; + return false; + } + assets->store(texture, name); + return true; +} + +bool _load_font(Assets* assets, std::string filename, std::string name){ + std::vector pages; + for (size_t i = 0; i <= 4; i++){ + Texture* texture = load_texture(filename+"_"+std::to_string(i)+".png"); + if (texture == nullptr){ + std::cerr << "failed to load bitmap font '" << name << "' (missing page " << std::to_string(i) << ")" << std::endl; + return false; + } + pages.push_back(texture); + } + Font* font = new Font(pages); + assets->store(font, name); + return true; +} + +int initialize_assets(Assets* assets) { +#define LOAD_SHADER(VERTEX, FRAGMENT, NAME) \ + if (!_load_shader(assets, VERTEX, FRAGMENT, NAME))\ + return 1; +#define LOAD_TEXTURE(FILENAME, NAME) \ + if (!_load_texture(assets, FILENAME, NAME))\ + return 1; +#define LOAD_FONT(FILENAME, NAME) \ + if (!_load_font(assets, FILENAME, NAME))\ + return 1; + + LOAD_SHADER("res/main.glslv", "res/main.glslf", "main"); + LOAD_SHADER("res/crosshair.glslv", "res/crosshair.glslf", "crosshair"); + LOAD_SHADER("res/lines.glslv", "res/lines.glslf", "lines"); + LOAD_SHADER("res/ui.glslv", "res/ui.glslf", "ui"); + + LOAD_TEXTURE("res/block.png", "block"); + LOAD_TEXTURE("res/slot.png", "slot"); + + LOAD_FONT("res/font", "normal"); + return 0; +} + +// All in-game definitions (blocks, items, etc..) +void setup_definitions() { + for (size_t i = 0; i < 256; i++) + Block::blocks[i] = nullptr; + + Block* block = new Block(BLOCK_AIR, 0); + block->drawGroup = 1; + block->lightPassing = true; + block->skyLightPassing = true; + block->obstacle = false; + block->selectable = false; + block->model = 0; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_DIRT, 2); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_GRASS_BLOCK, 4); + block->textureFaces[2] = 2; + block->textureFaces[3] = 1; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_LAMP, 3); + block->emission[0] = 15; + block->emission[1] = 14; + block->emission[2] = 13; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_GLASS,5); + block->drawGroup = 2; + block->lightPassing = true; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_PLANKS, 6); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_WOOD, 7); + block->textureFaces[2] = 8; + block->textureFaces[3] = 8; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_LEAVES, 9); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_STONE, 10); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_WATER, 11); + block->drawGroup = 4; + block->lightPassing = true; + block->skyLightPassing = false; + block->obstacle = false; + block->selectable = false; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_SAND, 12); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_BEDROCK, 13); + block->breakable = false; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_GRASS, 14); + block->drawGroup = 5; + block->lightPassing = true; + block->obstacle = false; + block->model = 2; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_FLOWER, 16); + block->drawGroup = 5; + block->lightPassing = true; + block->obstacle = false; + block->model = 2; + Block::blocks[block->id] = block; + + block = new Block(BLOCK_BRICK, 17); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_METAL, 18); + Block::blocks[block->id] = block; + + block = new Block(BLOCK_RUST, 19); + Block::blocks[block->id] = block; +} diff --git a/src/declarations.h b/src/declarations.h index b49304bf..13ff14be 100644 --- a/src/declarations.h +++ b/src/declarations.h @@ -2,113 +2,29 @@ #define DECLARATIONS_H #include -#include "Assets.h" -#include "graphics/Shader.h" -#include "graphics/Texture.h" -#include "window/Window.h" -#include "voxels/Block.h" +#define BLOCK_AIR 0 +#define BLOCK_DIRT 1 +#define BLOCK_GRASS_BLOCK 2 +#define BLOCK_LAMP 3 +#define BLOCK_GLASS 4 +#define BLOCK_PLANKS 5 +#define BLOCK_WOOD 6 +#define BLOCK_LEAVES 7 +#define BLOCK_STONE 8 +#define BLOCK_WATER 9 +#define BLOCK_SAND 10 +#define BLOCK_BEDROCK 11 +#define BLOCK_GRASS 12 +#define BLOCK_FLOWER 13 +#define BLOCK_BRICK 14 +#define BLOCK_METAL 15 +#define BLOCK_RUST 16 +class Assets; -// Shaders, textures, renderers +int initialize_assets(Assets* assets); +void setup_definitions(); -bool _load_shader(Assets* assets, std::string vertex_file, std::string fragment_file, std::string name){ - Shader* shader = load_shader(vertex_file, fragment_file); - if (shader == nullptr){ - std::cerr << "failed to load shader '" << name << "'" << std::endl; - return false; - } - assets->store(shader, name); - return true; -} - -bool _load_texture(Assets* assets, std::string filename, std::string name){ - Texture* texture = load_texture(filename); - if (texture == nullptr){ - std::cerr << "failed to load texture '" << name << "'" << std::endl; - return false; - } - assets->store(texture, name); - return true; -} - -int initialize_assets(Assets* assets) { -#define LOAD_SHADER(VERTEX, FRAGMENT, NAME) \ - if (!_load_shader(assets, VERTEX, FRAGMENT, NAME))\ - return 1; -#define LOAD_TEXTURE(FILENAME, NAME) \ - if (!_load_texture(assets, FILENAME, NAME))\ - return 1; - - LOAD_SHADER("res/main.glslv", "res/main.glslf", "main"); - LOAD_SHADER("res/crosshair.glslv", "res/crosshair.glslf", "crosshair"); - LOAD_SHADER("res/lines.glslv", "res/lines.glslf", "lines"); - - LOAD_TEXTURE("res/block.png", "block"); - return 0; -} - - -// All in-game definitions (blocks, items, etc..) -void setup_definitions() { - // AIR - Block* block = new Block(0,0); - block->drawGroup = 1; - block->lightPassing = true; - block->skyLightPassing = true; - block->obstacle = false; - block->selectable = false; - 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] = 15; - block->emission[1] = 14; - block->emission[2] = 13; - 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; - - // WOOD - block = new Block(6,7); - block->textureFaces[2] = 8; - block->textureFaces[3] = 8; - Block::blocks[block->id] = block; - - // LEAVES - block = new Block(7,9); - Block::blocks[block->id] = block; - - // ACTUAL STONE - block = new Block(8,10); - Block::blocks[block->id] = block; - - // WATER - block = new Block(9,11); - block->drawGroup = 4; - block->lightPassing = true; - block->skyLightPassing = false; - block->obstacle = false; - block->selectable = false; - Block::blocks[block->id] = block; -} #endif // DECLARATIONS_H diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index 17fee0f0..84388a72 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -19,6 +19,9 @@ union { #define SECTION_POSITION 1 #define SECTION_ROTATION 2 +#define SECTION_FLAGS 3 +#define PLAYER_FLAG_FLIGHT 0x1 +#define PLAYER_FLAG_NOCLIP 0x2 unsigned long WorldFiles::totalCompressed = 0; @@ -33,7 +36,7 @@ void int2Bytes(int value, char* dest, unsigned int offset){ dest[offset+3] = (char) (value >> 0 & 255); } -void float2Bytes(float fvalue, char* dest, unsigned int offset){ +void floatToBytes(float fvalue, char* dest, unsigned int offset){ uint32_t value = *((uint32_t*)&fvalue); dest[offset] = (char) (value >> 24 & 255); dest[offset+1] = (char) (value >> 16 & 255); @@ -50,7 +53,7 @@ float bytes2Float(char* srcs, unsigned int offset){ return *(float*)(&value); } -WorldFiles::WorldFiles(const char* directory, size_t mainBufferCapacity) : directory(directory){ +WorldFiles::WorldFiles(std::string directory, size_t mainBufferCapacity) : directory(directory){ mainBufferIn = new char[CHUNK_VOL*2]; mainBufferOut = new char[mainBufferCapacity]; } @@ -58,15 +61,15 @@ WorldFiles::WorldFiles(const char* directory, size_t mainBufferCapacity) : direc WorldFiles::~WorldFiles(){ delete[] mainBufferIn; delete[] mainBufferOut; - std::unordered_map::iterator it; + std::unordered_map::iterator it; for (it = regions.begin(); it != regions.end(); it++){ - char** region = it->second; - if (region == nullptr) + WorldRegion region = it->second; + if (region.chunksData == nullptr) continue; for (unsigned int i = 0; i < REGION_VOL; i++){ - delete[] region[i]; + delete[] region.chunksData[i]; } - delete[] region; + delete[] region.chunksData; } regions.clear(); } @@ -82,17 +85,17 @@ void WorldFiles::put(const char* chunkData, int x, int y){ _tempcoords._coords[0] = regionX; _tempcoords._coords[1] = regionY; - char** region = regions[_tempcoords._key]; - if (region == nullptr){ - region = new char*[REGION_VOL]; + WorldRegion& region = regions[_tempcoords._key]; + region.unsaved = true; + if (region.chunksData == nullptr){ + region.chunksData = new char*[REGION_VOL]; for (unsigned int i = 0; i < REGION_VOL; i++) - region[i] = nullptr; - regions[_tempcoords._key] = region; + region.chunksData[i] = nullptr; } - char* targetChunk = region[localY * REGION_SIZE + localX]; + char* targetChunk = region.chunksData[localY * REGION_SIZE + localX]; if (targetChunk == nullptr){ targetChunk = new char[CHUNK_VOL]; - region[localY * REGION_SIZE + localX] = targetChunk; + region.chunksData[localY * REGION_SIZE + localX] = targetChunk; totalCompressed += CHUNK_VOL; } for (unsigned int i = 0; i < CHUNK_VOL; i++) @@ -122,11 +125,11 @@ bool WorldFiles::getChunk(int x, int y, char* out){ _tempcoords._coords[0] = regionX; _tempcoords._coords[1] = regionY; - char** region = regions[_tempcoords._key]; - if (region == nullptr) + WorldRegion& region = regions[_tempcoords._key]; + if (region.chunksData == nullptr) return readChunk(x,y,out); - char* chunk = region[chunkIndex]; + char* chunk = region.chunksData[chunkIndex]; if (chunk == nullptr) return readChunk(x,y,out); for (unsigned int i = 0; i < CHUNK_VOL; i++) @@ -174,34 +177,38 @@ bool WorldFiles::readChunk(int x, int y, char* out){ } void WorldFiles::write(){ - std::unordered_map::iterator it; + std::unordered_map::iterator it; for (it = regions.begin(); it != regions.end(); it++){ - if (it->second == nullptr) + if (it->second.chunksData == nullptr || !it->second.unsaved) continue; int x; int y; longToCoords(x,y, it->first); - unsigned int size = writeRegion(mainBufferOut, x,y, it->second); + unsigned int size = writeRegion(mainBufferOut, x,y, it->second.chunksData); write_binary_file(getRegionFile(x,y), mainBufferOut, size); } } void WorldFiles::writePlayer(Player* player){ - char dst[1+3*4 + 1+2*4]; + char dst[1+3*4 + 1+2*4 + 1+1]; glm::vec3 position = player->hitbox->position; size_t offset = 0; dst[offset++] = SECTION_POSITION; - float2Bytes(position.x, dst, offset); offset += 4; - float2Bytes(position.y, dst, offset); offset += 4; - float2Bytes(position.z, dst, offset); offset += 4; + floatToBytes(position.x, dst, offset); offset += 4; + floatToBytes(position.y, dst, offset); offset += 4; + floatToBytes(position.z, dst, offset); offset += 4; dst[offset++] = SECTION_ROTATION; - float2Bytes(player->camX, dst, offset); offset += 4; - float2Bytes(player->camY, dst, offset); offset += 4; + floatToBytes(player->camX, dst, offset); offset += 4; + floatToBytes(player->camY, dst, offset); offset += 4; + + dst[offset++] = SECTION_FLAGS; + dst[offset++] = player->flight * PLAYER_FLAG_FLIGHT | + player->noclip * PLAYER_FLAG_NOCLIP; write_binary_file(getPlayerFile(), (const char*)dst, sizeof(dst)); } @@ -210,7 +217,7 @@ bool WorldFiles::readPlayer(Player* player) { size_t length = 0; char* data = read_binary_file(getPlayerFile(), length); if (data == nullptr){ - std::cerr << "could not to read player.bin" << std::endl; + std::cerr << "could not to read player.bin (ignored)" << std::endl; return false; } glm::vec3 position = player->hitbox->position; @@ -227,6 +234,13 @@ bool WorldFiles::readPlayer(Player* player) { player->camX = bytes2Float(data, offset); offset += 4; player->camY = bytes2Float(data, offset); offset += 4; break; + case SECTION_FLAGS: + { + unsigned char flags = data[offset++]; + player->flight = flags & PLAYER_FLAG_FLIGHT; + player->noclip = flags & PLAYER_FLAG_NOCLIP; + } + break; } } player->hitbox->position = position; diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index e79aed04..93d50db0 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -3,27 +3,29 @@ #include #include - +#ifndef std::string +#include +#endif class Player; #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 - * */ +struct WorldRegion { + char** chunksData; + bool unsaved; +}; + class WorldFiles { public: static unsigned long totalCompressed; - std::unordered_map regions; + std::unordered_map regions; std::string directory; char* mainBufferIn; char* mainBufferOut; - WorldFiles(const char* directory, size_t mainBufferCapacity); + WorldFiles(std::string directory, size_t mainBufferCapacity); ~WorldFiles(); void put(const char* chunkData, int x, int y); diff --git a/src/files/files.cpp b/src/files/files.cpp index 2344128b..783faa2a 100644 --- a/src/files/files.cpp +++ b/src/files/files.cpp @@ -69,16 +69,17 @@ unsigned int decompressRLE(const char* src, unsigned int length, char* dst, unsi unsigned int calcRLE(const char* src, unsigned int length) { unsigned int offset = 0; - unsigned int counter = 1; + unsigned int counter = 0; char c = src[0]; for (unsigned int i = 0; i < length; i++){ char cnext = src[i]; - if (cnext != c || counter == 256){ + if (cnext != c || counter == 255){ offset += 2; c = cnext; counter = 0; + } else { + counter++; } - counter++; } return offset + 2; } @@ -86,19 +87,20 @@ unsigned int calcRLE(const char* src, unsigned int length) { // 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; + unsigned int counter = 0; 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; + if (cnext != c || counter == 255){ + dst[offset++] = counter; dst[offset++] = c; c = cnext; counter = 0; + } else { + counter++; } - counter++; } - dst[offset++] = counter-1; + dst[offset++] = counter; dst[offset++] = c; return offset; } diff --git a/src/files/files.h b/src/files/files.h index 7b53cb16..27cc9c54 100644 --- a/src/files/files.h +++ b/src/files/files.h @@ -1,7 +1,9 @@ #ifndef FILES_FILES_H_ #define FILES_FILES_H_ +#ifndef std::string #include +#endif 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); diff --git a/src/graphics/Batch2D.cpp b/src/graphics/Batch2D.cpp index e6b43770..acb9f2ec 100644 --- a/src/graphics/Batch2D.cpp +++ b/src/graphics/Batch2D.cpp @@ -1,18 +1,281 @@ #include "Batch2D.h" #include "Mesh.h" +#include "Texture.h" +#include "Sprite.h" -Batch2D::Batch2D(size_t capacity) : capacity(capacity), - offset(0), - color(1.0f, 1.0f, 1.0f, 1.0f){ +#include + +#define VERTEX_SIZE 8 + +Batch2D::Batch2D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 1.0f){ const int attrs[] = { 2, 2, 4, 0 //null terminator }; - buffer = new float[capacity]; - mesh = new Mesh(nullptr, 0, attrs); + buffer = new float[capacity * VERTEX_SIZE]; + mesh = new Mesh(buffer, 0, attrs); + index = 0; + + unsigned char pixels[] = { + 255, 255, 255, 255, + }; + blank = new Texture(pixels, 1, 1); + _texture = nullptr; } Batch2D::~Batch2D(){ - delete buffer; + delete blank; + delete[] buffer; delete mesh; } + +void Batch2D::begin(){ + _texture = nullptr; + blank->bind(); +} + +void Batch2D::vertex(float x, float y, + float u, float v, + float r, float g, float b, float a) { + buffer[index++] = x; + buffer[index++] = y; + buffer[index++] = u; + buffer[index++] = v; + buffer[index++] = r; + buffer[index++] = g; + buffer[index++] = b; + buffer[index++] = a; +} +void Batch2D::vertex(vec2 point, + vec2 uvpoint, + float r, float g, float b, float a) { + buffer[index++] = point.x; + buffer[index++] = point.y; + buffer[index++] = uvpoint.x; + buffer[index++] = uvpoint.y; + buffer[index++] = r; + buffer[index++] = g; + buffer[index++] = b; + buffer[index++] = a; +} + +void Batch2D::texture(Texture* new_texture){ + if (_texture == new_texture) + return; + render(); + _texture = new_texture; + if (new_texture == nullptr) + blank->bind(); + else + new_texture->bind(); +} + +void Batch2D::rect(float x, float y, float w, float h){ + const float r = color.r; + const float g = color.g; + const float b = color.b; + const float a = color.a; + if (index + 6*VERTEX_SIZE >= capacity) + render(); + + vertex(x, y, 0, 0, r,g,b,a); + vertex(x+w, y+h, 1, 1, r,g,b,a); + vertex(x, y+h, 0, 1, r,g,b,a); + + vertex(x, y, 0, 0, r,g,b,a); + vertex(x+w, y, 1, 0, r,g,b,a); + vertex(x+w, y+h, 1, 1, r,g,b,a); +} + +void Batch2D::rect( + float x, float y, + float w, float h, + float ox, float oy, + float angle, + UVRegion region, + bool flippedX, + bool flippedY, + vec4 tint) { + if (index + 6*VERTEX_SIZE >= capacity) + render(); + + float centerX = w*ox; + float centerY = h*oy; + float acenterX = w-centerX; + float acenterY = h-centerY; + + float _x1 = -centerX; + float _y1 = -centerY; + + float _x2 = -centerX; + float _y2 = +acenterY; + + float _x3 = +acenterX; + float _y3 = +acenterY; + + float _x4 = +acenterX; + float _y4 = -centerY; + + float x1,y1,x2,y2,x3,y3,x4,y4; + + if (angle != 0) { + float s = sin(angle); + float c = cos(angle); + + x1 = c * _x1 - s * _y1; + y1 = s * _x1 + c * _y1; + + x2 = c * _x2 - s * _y2; + y2 = s * _x2 + c * _y2; + + x3 = c * _x3 - s * _y3; + y3 = s * _x3 + c * _y3; + + x4 = x1 + (x3 - x2); + y4 = y3 - (y2 - y1); + } else { + x1 = _x1; + y1 = _y1; + x2 = _x2; + y2 = _y2; + x3 = _x3; + y3 = _y3; + x4 = _x4; + y4 = _y4; + } + + x1 += x; x2 += x; x3 += x; x4 += x; + y1 += y; y2 += y; y3 += y; y4 += y; + + float u1 = region.u1; + float v1 = region.v1; + float u2 = region.u1; + float v2 = region.v2; + float u3 = region.u2; + float v3 = region.v2; + float u4 = region.u2; + float v4 = region.v1; + + if (flippedX) { + float temp = u1; + u1 = u3; + u4 = temp; + u2 = u3; + u3 = temp; + } + if (flippedY) { + float temp = v1; + v1 = v2; + v4 = v2; + v2 = temp; + v3 = temp; + } + + vertex(x1, y1, u1, v1, tint.r, tint.g, tint.b, tint.a); + vertex(x2, y2, u2, v2, tint.r, tint.g, tint.b, tint.a); + vertex(x3, y3, u3, v3, tint.r, tint.g, tint.b, tint.a); + + /* Right down triangle */ + vertex(x1, y1, u1, v1, tint.r, tint.g, tint.b, tint.a); + vertex(x3, y3, u3, v3, tint.r, tint.g, tint.b, tint.a); + vertex(x4, y4, u4, v4, tint.r, tint.g, tint.b, tint.a); +} + +void Batch2D::sprite(Sprite* sprite) { + vec2 position = sprite->position; + vec2 size = sprite->size; + vec2 origin = sprite->origin; + texture(sprite->texture); + rect( + position.x, position.y, + size.x, size.y, + origin.x, origin.y, + sprite->angle, + sprite->region, + sprite->flippedX, + sprite->flippedY, + sprite->color); +} + +void Batch2D::sprite(float x, float y, float w, float h, int atlasRes, int index, vec4 tint){ + float scale = 1.0f / (float)atlasRes; + float u = (index % atlasRes) * scale; + float v = 1.0f - ((index / atlasRes) * scale) - scale; + rect(x, y, w, h, u, v, scale, scale, tint.r, tint.g, tint.b, tint.a); +} + +void Batch2D::blockSprite(float x, float y, float w, float h, int atlasRes, int index[6], vec4 tint){ + float scale = 1.0f / (float)atlasRes; + float uu = (index[3] % atlasRes) * scale; + float vu = 1.0f - ((index[3] / atlasRes) * scale) - scale; + float uf = (index[0] % atlasRes) * scale; + float vf = 1.0f - ((index[0] / atlasRes) * scale) - scale; + if (this->index + 18*VERTEX_SIZE >= capacity) + render(); + + float ar = 0.88f; + float ox = x + (w * 0.5f); + float sx = w * 0.5f * ar; + vec2 points[7] = {vec2(ox, y+(h*0.5f)), + vec2(ox-sx, y+(h*0.25f)), + vec2(ox, y), + vec2(ox+sx, y+(h*0.25f)), + vec2(ox+sx, y+(h*0.75f)), + vec2(ox, y+h), + vec2(ox-sx, y+(h*0.75f))}; + + vec2 uvpoints[8] = {vec2(uu, vu), + vec2(uu+scale, vu), + vec2(uu+scale, vu+scale), + vec2(uu, vu+scale), + vec2(uf, vf), + vec2(uf+scale, vf), + vec2(uf+scale, vf+scale), + vec2(uf, vf+scale)}; + + vertex(points[0], uvpoints[3], tint.r, tint.g, tint.b, tint.a); + vertex(points[1], uvpoints[0], tint.r, tint.g, tint.b, tint.a); + vertex(points[2], uvpoints[1], tint.r, tint.g, tint.b, tint.a); + + vertex(points[0], uvpoints[3], tint.r, tint.g, tint.b, tint.a); + vertex(points[2], uvpoints[1], tint.r, tint.g, tint.b, tint.a); + vertex(points[3], uvpoints[2], tint.r, tint.g, tint.b, tint.a); + + + vertex(points[0], uvpoints[7], tint.r, tint.g, tint.b, tint.a); + vertex(points[3], uvpoints[6], tint.r, tint.g, tint.b, tint.a); + vertex(points[4], uvpoints[5], tint.r, tint.g, tint.b, tint.a); + + vertex(points[0], uvpoints[7], tint.r, tint.g, tint.b, tint.a); + vertex(points[4], uvpoints[5], tint.r, tint.g, tint.b, tint.a); + vertex(points[5], uvpoints[4], tint.r, tint.g, tint.b, tint.a); + + + vertex(points[0], uvpoints[6], tint.r, tint.g, tint.b, tint.a); + vertex(points[5], uvpoints[5], tint.r, tint.g, tint.b, tint.a); + vertex(points[6], uvpoints[4], tint.r, tint.g, tint.b, tint.a); + + vertex(points[0], uvpoints[6], tint.r, tint.g, tint.b, tint.a); + vertex(points[6], uvpoints[4], tint.r, tint.g, tint.b, tint.a); + vertex(points[1], uvpoints[7], tint.r, tint.g, tint.b, tint.a); +} + +void Batch2D::rect(float x, float y, float w, float h, + float u, float v, float tx, float ty, + float r, float g, float b, float a){ + if (index + 6*VERTEX_SIZE >= capacity) + render(); + vertex(x, y, u, v+ty, r,g,b,a); + vertex(x+w, y+h, u+tx, v, r,g,b,a); + vertex(x, y+h, u, v, r,g,b,a); + + vertex(x, y, u, v+ty, r,g,b,a); + vertex(x+w, y, u+tx, v+ty, r,g,b,a); + vertex(x+w, y+h, u+tx, v, r,g,b,a); +} + +void Batch2D::render() { + mesh->reload(buffer, index / VERTEX_SIZE); + mesh->draw(GL_TRIANGLES); + index = 0; +} diff --git a/src/graphics/Batch2D.h b/src/graphics/Batch2D.h index 7e756eda..0c9b69e8 100644 --- a/src/graphics/Batch2D.h +++ b/src/graphics/Batch2D.h @@ -4,23 +4,53 @@ #include #include +#include "UVRegion.h" + +using namespace glm; + class Mesh; +class Texture; +class Sprite; class Batch2D { float* buffer; size_t capacity; size_t offset; - glm::vec4 color; Mesh* mesh; + size_t index; + + Texture* blank; + Texture* _texture; void vertex(float x, float y, float u, float v, float r, float g, float b, float a); + void vertex(vec2 point, + vec2 uvpoint, + float r, float g, float b, float a); + public: + glm::vec4 color; + Batch2D(size_t capacity); ~Batch2D(); + void begin(); + void texture(Texture* texture); + void sprite(float x, float y, float w, float h, int atlasRes, int index, vec4 tint); + void sprite(Sprite* sprite); + void blockSprite(float x, float y, float w, float h, int atlasRes, int index[6], vec4 tint); + void rect(float x, float y, + float w, float h, + float ox, float oy, + float angle, UVRegion region, + bool flippedX, bool flippedY, + vec4 tint); + void rect(float x, float y, float w, float h); + void rect(float x, float y, float w, float h, + float u, float v, float tx, float ty, + float r, float g, float b, float a); void render(); }; diff --git a/src/graphics/Batch3D.cpp b/src/graphics/Batch3D.cpp new file mode 100644 index 00000000..2531969a --- /dev/null +++ b/src/graphics/Batch3D.cpp @@ -0,0 +1,165 @@ +#include "Batch3D.h" + +#include "Mesh.h" +#include "Texture.h" + +#include + +#define VERTEX_SIZE 9 + +Batch3D::Batch3D(size_t capacity) : capacity(capacity), offset(0), color(1.0f, 1.0f, 1.0f, 0.0f){ + const int attrs[] = { + 3, 2, 4, 0 //null terminator + }; + + buffer = new float[capacity * VERTEX_SIZE]; + mesh = new Mesh(buffer, 0, attrs); + index = 0; + + unsigned char pixels[] = { + 255, 255, 255, 255, + }; + blank = new Texture(pixels, 1, 1); + _texture = nullptr; +} + +Batch3D::~Batch3D(){ + delete blank; + delete[] buffer; + delete mesh; +} + +void Batch3D::begin(){ + _texture = nullptr; + blank->bind(); +} + +void Batch3D::vertex(float x, float y, float z, float u, float v, + float r, float g, float b, float a) { + buffer[index++] = x; + buffer[index++] = y; + buffer[index++] = z; + buffer[index++] = u; + buffer[index++] = v; + buffer[index++] = r; + buffer[index++] = g; + buffer[index++] = b; + buffer[index++] = a; +} +void Batch3D::vertex(vec3 point, + vec2 uvpoint, + float r, float g, float b, float a) { + buffer[index++] = point.x; + buffer[index++] = point.y; + buffer[index++] = point.z; + buffer[index++] = uvpoint.x; + buffer[index++] = uvpoint.y; + buffer[index++] = r; + buffer[index++] = g; + buffer[index++] = b; + buffer[index++] = a; +} + +void Batch3D::texture(Texture* new_texture){ + if (_texture == new_texture) + return; + render(); + _texture = new_texture; + if (new_texture == nullptr) + blank->bind(); + else + new_texture->bind(); +} + +void Batch3D::sprite(vec3 pos, vec3 up, vec3 right, float w, float h){ + const float r = color.r; + const float g = color.g; + const float b = color.b; + const float a = color.a; + if (index + 6*VERTEX_SIZE >= capacity) + render(); + + vertex(pos.x - right.x * w - up.x * h, + pos.y - right.y * w - up.y * h, + pos.z - right.z * w - up.z * h, + 0, 0, + r,g,b,a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y + right.y * w + up.y * h, + pos.z + right.z * w + up.z * h, + 1, 1, + r,g,b,a); + + vertex(pos.x - right.x * w - up.x * h, + pos.y + right.y * w + up.y * h, + pos.z - right.z * w - up.z * h, + 0, 1, + r,g,b,a); + + vertex(pos.x - right.x * w - up.x * h, + pos.y - right.y * w - up.y * h, + pos.z - right.z * w - up.z * h, + 0, 0, + r,g,b,a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y - right.y * w - up.y * h, + pos.z + right.z * w + up.z * h, + 1, 0, + r,g,b,a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y + right.y * w + up.y * h, + pos.z + right.z * w + up.z * h, + 1, 1, + r,g,b,a); +} + +void Batch3D::sprite(vec3 pos, vec3 up, vec3 right, float w, float h, int atlasRes, int index, vec4 tint){ + float scale = 1.0f / (float)atlasRes; + float u = (index % atlasRes) * scale; + float v = 1.0f - ((index / atlasRes) * scale) - scale; + + vertex(pos.x - right.x * w - up.x * h, + pos.y - right.y * w - up.y * h, + pos.z - right.z * w - up.z * h, + u, v, + tint.r,tint.g,tint.b,tint.a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y + right.y * w + up.y * h, + pos.z + right.z * w + up.z * h, + u+scale, v+scale, + tint.r,tint.g,tint.b,tint.a); + + vertex(pos.x - right.x * w - up.x * h, + pos.y + right.y * w + up.y * h, + pos.z - right.z * w - up.z * h, + u, v+scale, + tint.r,tint.g,tint.b,tint.a); + + vertex(pos.x - right.x * w - up.x * h, + pos.y - right.y * w - up.y * h, + pos.z - right.z * w - up.z * h, + u, v, + tint.r,tint.g,tint.b,tint.a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y - right.y * w - up.y * h, + pos.z + right.z * w + up.z * h, + u+scale, v, + tint.r,tint.g,tint.b,tint.a); + + vertex(pos.x + right.x * w + up.x * h, + pos.y + right.y * w + up.y * h, + pos.z + right.z * w + up.z * h, + u+scale, v+scale, + tint.r,tint.g,tint.b,tint.a); +} + +void Batch3D::render() { + mesh->reload(buffer, index / VERTEX_SIZE); + mesh->draw(GL_TRIANGLES); + index = 0; +} diff --git a/src/graphics/Batch3D.h b/src/graphics/Batch3D.h new file mode 100644 index 00000000..a63f7c20 --- /dev/null +++ b/src/graphics/Batch3D.h @@ -0,0 +1,40 @@ +#ifndef GRAPHICS_BATCH3D_H_ +#define GRAPHICS_BATCH3D_H_ + +#include +#include + +using namespace glm; + +class Mesh; +class Texture; + +class Batch3D { + float* buffer; + size_t capacity; + size_t offset; + glm::vec4 color; + Mesh* mesh; + size_t index; + + Texture* blank; + Texture* _texture; + + void vertex(float x, float y, float z, + float u, float v, + float r, float g, float b, float a); + void vertex(vec3 point, vec2 uvpoint, + float r, float g, float b, float a); + +public: + Batch3D(size_t capacity); + ~Batch3D(); + + void begin(); + void texture(Texture* texture); + void sprite(vec3 pos, vec3 up, vec3 right, float w, float h, int atlasRes, int index, vec4 tint); + void sprite(vec3 pos, vec3 up, vec3 right, float w, float h); + void render(); +}; + +#endif /* GRAPHICS_BATCH3D_H_ */ diff --git a/src/graphics/Font.cpp b/src/graphics/Font.cpp new file mode 100644 index 00000000..3e881503 --- /dev/null +++ b/src/graphics/Font.cpp @@ -0,0 +1,90 @@ +#include "Font.h" +#include "Texture.h" +#include "Batch2D.h" + +Font::Font(std::vector pages) : pages(pages) { +} + +Font::~Font(){ + for (Texture* texture : pages) + delete texture; +} + +int Font::getGlyphWidth(char c) { + switch (c){ + case 'l': + case 'i': + case 'j': + case '|': + case '.': + case ',': + case ':': + case ';': return 7; + case 't': return 8; + case ' ': return 7; + } + return 7; +} + + +bool Font::isPrintableChar(int c) { + switch (c){ + case ' ': + case '\t': + case '\n': + case '\f': + case '\r': + return false; + default: + return true; + } +} + +#define RES 16 + +void Font::draw(Batch2D* batch, std::wstring text, int x, int y) { + draw(batch, text, x, y, STYLE_NONE); +} + +void Font::draw(Batch2D* batch, std::wstring text, int x, int y, int style) { + int page = 0; + int next = 10000; + int init_x = x; + do { + for (unsigned c : text){ + if (isPrintableChar(c)){ + int charpage = c >> 8; + if (charpage == page){ + Texture* texture = pages[charpage]; + if (texture == nullptr){ + texture = pages[0]; + } + batch->texture(pages[charpage]); + + switch (style){ + case STYLE_SHADOW: + batch->sprite(x+1, y+1, RES, RES, 16, c, vec4(0.0f, 0.0f, 0.0f, 1.0f)); + break; + case STYLE_OUTLINE: + for (int oy = -1; oy <= 1; oy++){ + for (int ox = -1; ox <= 1; ox++){ + if (ox || oy) + batch->sprite(x+ox, y+oy, RES, RES, 16, c, vec4(0.0f, 0.0f, 0.0f, 1.0f)); + } + } + break; + } + + batch->sprite(x, y, RES, RES, 16, c, batch->color); + } + else if (charpage > page && charpage < next){ + next = charpage; + } + } + x += getGlyphWidth(c); + } + page = next; + next = 10000; + x = init_x; + } while (page < 10000); +} diff --git a/src/graphics/Font.h b/src/graphics/Font.h new file mode 100644 index 00000000..db1fdcda --- /dev/null +++ b/src/graphics/Font.h @@ -0,0 +1,26 @@ +#ifndef GRAPHICS_FONT_H_ +#define GRAPHICS_FONT_H_ + +#include +#include + +class Texture; +class Batch2D; + +#define STYLE_NONE 0 +#define STYLE_SHADOW 1 +#define STYLE_OUTLINE 2 + +class Font { +public: + std::vector pages; + Font(std::vector pages); + ~Font(); + + int getGlyphWidth(char c); + bool isPrintableChar(int c); + void draw(Batch2D* batch, std::wstring text, int x, int y); + void draw(Batch2D* batch, std::wstring text, int x, int y, int style); +}; + +#endif /* GRAPHICS_FONT_H_ */ diff --git a/src/graphics/Framebuffer.cpp b/src/graphics/Framebuffer.cpp new file mode 100644 index 00000000..287be8e5 --- /dev/null +++ b/src/graphics/Framebuffer.cpp @@ -0,0 +1,37 @@ +#include "Framebuffer.h" + +#include +#include "Texture.h" + +Framebuffer::Framebuffer(int width, int height) : width(width), height(height) { + glGenFramebuffers(1, &fbo); + bind(); + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); + texture = new Texture(tex, width, height); + glGenRenderbuffers(1, &depth); + glBindRenderbuffer(GL_RENDERBUFFER, depth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth); + unbind(); +} + +Framebuffer::~Framebuffer() { + delete texture; + glDeleteFramebuffers(1, &fbo); +} + +void Framebuffer::bind() { + glBindFramebuffer(GL_FRAMEBUFFER, fbo); +} + +void Framebuffer::unbind() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} diff --git a/src/graphics/Framebuffer.h b/src/graphics/Framebuffer.h new file mode 100644 index 00000000..3fd889f2 --- /dev/null +++ b/src/graphics/Framebuffer.h @@ -0,0 +1,20 @@ +#ifndef SRC_GRAPHICS_FRAMEBUFFER_H_ +#define SRC_GRAPHICS_FRAMEBUFFER_H_ + +class Texture; + +class Framebuffer { + unsigned int fbo; + unsigned int depth; +public: + int width; + int height; + Texture* texture; + Framebuffer(int width, int height); + ~Framebuffer(); + + void bind(); + void unbind(); +}; + +#endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */ diff --git a/src/graphics/Sprite.cpp b/src/graphics/Sprite.cpp new file mode 100644 index 00000000..3b0ca50f --- /dev/null +++ b/src/graphics/Sprite.cpp @@ -0,0 +1,17 @@ +#include "Sprite.h" + +#include "Texture.h" + +Sprite::Sprite(glm::vec2 position, glm::vec2 size, Texture* texture) + : position(position), + size(size), + origin(0.5f, 0.5f), + color(1.0f, 1.0f, 1.0f, 1.0f), + angle(0.0f), + texture(texture), + region() { +} + +Sprite::~Sprite() { +} + diff --git a/src/graphics/Sprite.h b/src/graphics/Sprite.h new file mode 100644 index 00000000..5d10038e --- /dev/null +++ b/src/graphics/Sprite.h @@ -0,0 +1,29 @@ +#ifndef SRC_GRAPHICS_SPRITE_H_ +#define SRC_GRAPHICS_SPRITE_H_ + +#include +#include "UVRegion.h" + +class Texture; + +class Sprite { +public: + glm::vec2 position; + glm::vec2 size; + glm::vec2 origin; + glm::vec4 color; + float angle; + bool flippedX = false; + bool flippedY = false; + Texture* texture; + UVRegion region; + + Sprite(glm::vec2 position, glm::vec2 size, Texture* texture); + virtual ~Sprite(); + + void setTexture(Texture* texture) { + this->texture = texture; + } +}; + +#endif /* SRC_GRAPHICS_SPRITE_H_ */ diff --git a/src/graphics/UVRegion.cpp b/src/graphics/UVRegion.cpp new file mode 100644 index 00000000..3f421522 --- /dev/null +++ b/src/graphics/UVRegion.cpp @@ -0,0 +1 @@ +#include "UVRegion.h" diff --git a/src/graphics/UVRegion.h b/src/graphics/UVRegion.h new file mode 100644 index 00000000..a59f6c30 --- /dev/null +++ b/src/graphics/UVRegion.h @@ -0,0 +1,17 @@ +#ifndef SRC_GRAPHICS_UVREGION_H_ +#define SRC_GRAPHICS_UVREGION_H_ + +class UVRegion { +public: + float u1; + float v1; + float u2; + float v2; + + UVRegion(float u1, float v1, float u2, float v2) + : u1(u1), v1(v1), u2(u2), v2(v2){} + + UVRegion() : u1(0.0f), v1(0.0f), u2(1.0f), v2(1.0f){} +}; + +#endif /* SRC_GRAPHICS_UVREGION_H_ */ diff --git a/src/graphics/VoxelRenderer.cpp b/src/graphics/VoxelRenderer.cpp index fde67308..7e9ed7fc 100644 --- a/src/graphics/VoxelRenderer.cpp +++ b/src/graphics/VoxelRenderer.cpp @@ -1,32 +1,33 @@ #include "VoxelRenderer.h" + +#include +#include #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 GET_CHUNK(X,Y,Z) (chunks[(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 VERTEX(INDEX, X,Y,Z, U,V, R,G,B,S) buffer.push_back(X);\ + buffer.push_back(Y);\ + buffer.push_back(Z);\ + buffer.push_back(U);\ + buffer.push_back(V);\ + buffer.push_back(R);\ + buffer.push_back(G);\ + buffer.push_back(B);\ + buffer.push_back(S);\ + INDEX += CHUNK_VERTEX_SIZE; #define SETUP_UV(INDEX) float u1 = ((INDEX) % 16) * uvsize;\ @@ -36,21 +37,13 @@ int chunk_attrs[] = {3,2,4, 0}; -VoxelRenderer::VoxelRenderer(size_t capacity) : capacity(capacity) { - buffer = new float[capacity * VERTEX_SIZE * 6]; +VoxelRenderer::VoxelRenderer() { } VoxelRenderer::~VoxelRenderer(){ - delete[] buffer; } -inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunks, voxel vox, size_t& index){ - unsigned int id = vox.id; - - if (!id){ - return; - } - +inline void _renderBlock(std::vector& buffer, int x, int y, int z, const Chunk** chunks, unsigned int id, size_t& index){ float l; float uvsize = 1.0f/16.0f; @@ -62,30 +55,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x,y+1,z, 0) / 15.0f; + const float lg = LIGHT(x,y+1,z, 1) / 15.0f; + const float lb = LIGHT(x,y+1,z, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -100,30 +93,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x,y-1,z, 0) / 15.0f; + const float lg = LIGHT(x,y-1,z, 1) / 15.0f; + const float lb = LIGHT(x,y-1,z, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -139,30 +132,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x+1,y,z, 0) / 15.0f; + const float lg = LIGHT(x+1,y,z, 1) / 15.0f; + const float lb = LIGHT(x+1,y,z, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -177,30 +170,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x-1,y,z, 0) / 15.0f; + const float lg = LIGHT(x-1,y,z, 1) / 15.0f; + const float lb = LIGHT(x-1,y,z, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -216,30 +209,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x,y,z+1, 0) / 15.0f; + const float lg = LIGHT(x,y,z+1, 1) / 15.0f; + const float lb = LIGHT(x,y,z+1, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -254,30 +247,30 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk 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; + const float lr = LIGHT(x,y,z-1, 0) / 15.0f; + const float lg = LIGHT(x,y,z-1, 1) / 15.0f; + const float lb = LIGHT(x,y,z-1, 2) / 15.0f; + const 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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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; + 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)) / 75.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)) / 75.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)) / 75.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)) / 75.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); @@ -289,15 +282,196 @@ inline void _renderBlock(float* buffer, int x, int y, int z, const Chunk** chunk } } -Mesh* VoxelRenderer::render(Chunk* chunk, const Chunk** chunks){ +inline void _renderBlockShadeless(std::vector& buffer, int x, int y, int z, const Chunk** chunks, unsigned int id, size_t& index){ + 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)){ + SETUP_UV(block->textureFaces[3]); + + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v1, 1,1,1,0); + } + if (!IS_BLOCKED(x,y-1,z,group)){ + SETUP_UV(block->textureFaces[2]); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v2, 1,1,1,0); + } + + if (!IS_BLOCKED(x+1,y,z,group)){ + SETUP_UV(block->textureFaces[1]); + + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u1,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u1,v1, 1,1,1,0); + } + if (!IS_BLOCKED(x-1,y,z,group)){ + SETUP_UV(block->textureFaces[0]); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u2,v2, 1,1,1,0); + } + + if (!IS_BLOCKED(x,y,z+1,group)){ + SETUP_UV(block->textureFaces[5]); + + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z+0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x-0.5f, y-0.5f, z+0.5f, u1,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z+0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z+0.5f, u2,v2, 1,1,1,0); + } + if (!IS_BLOCKED(x,y,z-1,group)){ + SETUP_UV(block->textureFaces[4]); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x-0.5f, y+0.5f, z-0.5f, u2,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v2, 1,1,1,0); + + VERTEX(index, x-0.5f, y-0.5f, z-0.5f, u2,v1, 1,1,1,0); + VERTEX(index, x+0.5f, y+0.5f, z-0.5f, u1,v2, 1,1,1,0); + VERTEX(index, x+0.5f, y-0.5f, z-0.5f, u1,v1, 1,1,1,0); + } +} + + +inline void _renderXBlock(std::vector& buffer, int x, int y, int z, const Chunk** chunks, voxel vox, size_t& index){ + Block* block = Block::blocks[vox.id]; + + int rand = ((x * z + y) xor (z * y - x)) * (z + y); + + float xs = (float)(char)rand / 512; + float zs = (float)(char)(rand >> 8) / 512; + + if (block->model != 2){ + return; + } + + float uvsize = 1.0f/16.0f; + + float lr = LIGHT(x,y,z, 0) / 15.0f; + float lg = LIGHT(x,y,z, 1) / 15.0f; + float lb = LIGHT(x,y,z, 2) / 15.0f; + float ls = LIGHT(x,y,z, 3) / 15.0f; + + float lr0 = (LIGHT(x,y-1,z,0) + lr*30) / 45.0f; + float lr1 = (LIGHT(x,y+1,z,0) + lr*30) / 45.0f; + float lr2 = (LIGHT(x,y+1,z,0) + lr*30) / 45.0f; + float lr3 = (LIGHT(x,y-1,z,0) + lr*30) / 45.0f; + float lr4 = (LIGHT(x,y-1,z,0) + lr*30) / 45.0f; + float lr5 = (LIGHT(x,y+1,z,0) + lr*30) / 45.0f; + float lr6 = (LIGHT(x,y+1,z,0) + lr*30) / 45.0f; + float lr7 = (LIGHT(x,y-1,z,0) + lr*30) / 45.0f; + + float lg0 = (LIGHT(x,y-1,z,1) + lg*30) / 45.0f; + float lg1 = (LIGHT(x,y+1,z,1) + lg*30) / 45.0f; + float lg2 = (LIGHT(x,y+1,z,1) + lg*30) / 45.0f; + float lg3 = (LIGHT(x,y-1,z,1) + lg*30) / 45.0f; + float lg4 = (LIGHT(x,y-1,z,1) + lg*30) / 45.0f; + float lg5 = (LIGHT(x,y+1,z,1) + lg*30) / 45.0f; + float lg6 = (LIGHT(x,y+1,z,1) + lg*30) / 45.0f; + float lg7 = (LIGHT(x,y-1,z,1) + lg*30) / 45.0f; + + float lb0 = (LIGHT(x,y-1,z,2) + lb*30) / 45.0f; + float lb1 = (LIGHT(x,y+1,z,2) + lb*30) / 45.0f; + float lb2 = (LIGHT(x,y+1,z,2) + lb*30) / 45.0f; + float lb3 = (LIGHT(x,y-1,z,2) + lb*30) / 45.0f; + float lb4 = (LIGHT(x,y-1,z,2) + lb*30) / 45.0f; + float lb5 = (LIGHT(x,y+1,z,2) + lb*30) / 45.0f; + float lb6 = (LIGHT(x,y+1,z,2) + lb*30) / 45.0f; + float lb7 = (LIGHT(x,y-1,z,2) + lb*30) / 45.0f; + + float ls0 = (LIGHT(x,y-1,z,3) + ls*30) / 45.0f; + float ls1 = (LIGHT(x,y+1,z,3) + ls*30) / 45.0f; + float ls2 = (LIGHT(x,y+1,z,3) + ls*30) / 45.0f; + float ls3 = (LIGHT(x,y-1,z,3) + ls*30) / 45.0f; + float ls4 = (LIGHT(x,y-1,z,3) + ls*30) / 45.0f; + float ls5 = (LIGHT(x,y+1,z,3) + ls*30) / 45.0f; + float ls6 = (LIGHT(x,y+1,z,3) + ls*30) / 45.0f; + float ls7 = (LIGHT(x,y-1,z,3) + ls*30) / 45.0f; + + {SETUP_UV(block->textureFaces[1]); + + VERTEX(index, x-0.5f+xs, y-0.5f, z-0.5f+zs, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x-0.5f+xs, y+0.5f, z-0.5f+zs, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x+0.5f+xs, y+0.5f, z+0.5f+zs, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f+xs, y-0.5f, z-0.5f+zs, u2,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f+xs, y+0.5f, z+0.5f+zs, u1,v2, lr2,lg2,lb2,ls2); + VERTEX(index, x+0.5f+xs, y-0.5f, z+0.5f+zs, u1,v1, lr3,lg3,lb3,ls3);} + + {SETUP_UV(block->textureFaces[0]); + + VERTEX(index, x-0.5f+xs, y-0.5f, z-0.5f+zs, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f+xs, y+0.5f, z+0.5f+zs, u2,v2, lr1,lg1,lb1,ls1); + VERTEX(index, x-0.5f+xs, y+0.5f, z-0.5f+zs, u1,v2, lr2,lg2,lb2,ls2); + + VERTEX(index, x-0.5f+xs, y-0.5f, z-0.5f+zs, u1,v1, lr0,lg0,lb0,ls0); + VERTEX(index, x+0.5f+xs, y-0.5f, z+0.5f+zs, u2,v1, lr3,lg3,lb3,ls3); + VERTEX(index, x+0.5f+xs, y+0.5f, z+0.5f+zs, u2,v2, lr1,lg1,lb1,ls1);} + + {SETUP_UV(block->textureFaces[5]); + + VERTEX(index, x-0.5f+xs, y-0.5f, z+0.5f+zs, u1,v1, lr4,lg4,lb4,ls4); + VERTEX(index, x+0.5f+xs, y+0.5f, z-0.5f+zs, u2,v2, lr5,lg5,lb5,ls5); + VERTEX(index, x-0.5f+xs, y+0.5f, z+0.5f+zs, u1,v2, lr6,lg6,lb6,ls6); + + VERTEX(index, x-0.5f+xs, y-0.5f, z+0.5f+zs, u1,v1, lr4,lg4,lb4,ls4); + VERTEX(index, x+0.5f+xs, y-0.5f, z-0.5f+zs, u2,v1, lr7,lg7,lb7,ls7); + VERTEX(index, x+0.5f+xs, y+0.5f, z-0.5f+zs, u2,v2, lr5,lg5,lb5,ls5);} + + {SETUP_UV(block->textureFaces[4]); + + VERTEX(index, x-0.5f+xs, y-0.5f, z+0.5f+zs, u2,v1, lr4,lg4,lb4,ls4); + VERTEX(index, x-0.5f+xs, y+0.5f, z+0.5f+zs, u2,v2, lr5,lg5,lb5,ls5); + VERTEX(index, x+0.5f+xs, y+0.5f, z-0.5f+zs, u1,v2, lr6,lg6,lb6,ls6); + + VERTEX(index, x-0.5f+xs, y-0.5f, z+0.5f+zs, u2,v1, lr4,lg4,lb4,ls4); + VERTEX(index, x+0.5f+xs, y+0.5f, z-0.5f+zs, u1,v2, lr6,lg6,lb6,ls6); + VERTEX(index, x+0.5f+xs, y-0.5f, z-0.5f+zs, u1,v1, lr7,lg7,lb7,ls7);} +} + +const float* VoxelRenderer::render(Chunk* chunk, const Chunk** chunks, size_t& size){ + buffer.clear(); 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]; - if (vox.id == 9 || vox.id == 4) + if (vox.id == 0) continue; - _renderBlock(buffer, x, y, z, chunks, vox, index); + if (vox.id == 9 || vox.id == 4 || vox.id == 12 || vox.id == 13) + continue; + Block* block = Block::blocks[vox.id]; + if (block->emission[0] || block->emission[1] || block->emission[2]){ + continue; + } + _renderBlock(buffer, x, y, z, chunks, vox.id, index); } } } @@ -306,9 +480,25 @@ Mesh* VoxelRenderer::render(Chunk* chunk, const Chunk** chunks){ 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]; + if (vox.id == 0) + continue; + Block* block = Block::blocks[vox.id]; + if (block->emission[0] || block->emission[1] || block->emission[2]){ + _renderBlockShadeless(buffer, x, y, z, chunks, vox.id, index); + } + } + } + } + + 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]; + if (vox.id == 0) + continue; if (vox.id != 9) continue; - _renderBlock(buffer, x, y, z, chunks, vox, index); + _renderBlock(buffer, x, y, z, chunks, vox.id, index); } } } @@ -317,11 +507,27 @@ Mesh* VoxelRenderer::render(Chunk* chunk, const Chunk** chunks){ 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]; - if (vox.id != 4) + if (vox.id == 0) continue; - _renderBlock(buffer, x, y, z, chunks, vox, index); + if (Block::blocks[vox.id]->model != BLOCK_MODEL_GRASS) + continue; + _renderXBlock(buffer, x, y, z, chunks, vox, index); } } } - return new Mesh(buffer, index / VERTEX_SIZE, chunk_attrs); + + 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]; + if (vox.id == 0) + continue; + if (vox.id != 4) + continue; + _renderBlock(buffer, x, y, z, chunks, vox.id, index); + } + } + } + size = buffer.size(); + return &buffer[0]; } diff --git a/src/graphics/VoxelRenderer.h b/src/graphics/VoxelRenderer.h index 4b3a6255..3e1d545c 100644 --- a/src/graphics/VoxelRenderer.h +++ b/src/graphics/VoxelRenderer.h @@ -2,18 +2,21 @@ #define GRAPHICS_VOXELRENDERER_H_ #include +#include class Mesh; class Chunk; +#define CHUNK_VERTEX_SIZE (3 + 2 + 4) + class VoxelRenderer { - float* buffer; - size_t capacity; public: - VoxelRenderer(size_t capacity); + std::vector buffer; + unsigned char lights[27 * 4]; + VoxelRenderer(); ~VoxelRenderer(); - Mesh* render(Chunk* chunk, const Chunk** chunks); + const float* render(Chunk* chunk, const Chunk** chunks, size_t& size); }; #endif /* GRAPHICS_VOXELRENDERER_H_ */ diff --git a/src/hud_render.cpp b/src/hud_render.cpp new file mode 100644 index 00000000..62894d66 --- /dev/null +++ b/src/hud_render.cpp @@ -0,0 +1,140 @@ +#include "hud_render.h" + +#include +#include +#include "Assets.h" +#include "graphics/Shader.h" +#include "graphics/Batch2D.h" +#include "graphics/Font.h" +#include "graphics/Mesh.h" +#include "window/Camera.h" +#include "window/Window.h" +#include "window/Events.h" +#include "voxels/Chunks.h" +#include "voxels/Block.h" +#include "world/World.h" +#include "world/Level.h" +#include "objects/Player.h" + + +HudRenderer::HudRenderer() { + 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 + }; + crosshair = new Mesh(vertices, 4, attrs); + + batch = new Batch2D(1024); + uicamera = new Camera(glm::vec3(), Window::height / 1.0f); + uicamera->perspective = false; + uicamera->flipped = true; +} + +HudRenderer::~HudRenderer() { + delete crosshair; + delete batch; + delete uicamera; +} + +void HudRenderer::drawDebug(Level* level, Assets* assets, int fps, bool occlusion){ + Chunks* chunks = level->chunks; + Player* player = level->player; + + Font* font = assets->getFont("normal"); + + Shader* uishader = assets->getShader("ui"); + uishader->use(); + uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView()); + batch->color = vec4(1.0f); + batch->begin(); + font->draw(batch, L"chunks: "+std::to_wstring(chunks->chunksCount), 16, 16, STYLE_OUTLINE); + font->draw(batch, std::to_wstring((int)player->camera->position.x), 10, 30, STYLE_OUTLINE); + font->draw(batch, std::to_wstring((int)player->camera->position.y), 50, 30, STYLE_OUTLINE); + font->draw(batch, std::to_wstring((int)player->camera->position.z), 90, 30, STYLE_OUTLINE); + font->draw(batch, L"fps:", 16, 42, STYLE_OUTLINE); + font->draw(batch, std::to_wstring(fps), 44, 42, STYLE_OUTLINE); + font->draw(batch, L"occlusion: "+std::to_wstring(occlusion), 16, 54, STYLE_OUTLINE); + batch->render(); +} + + +void HudRenderer::draw(Level* level, Assets* assets){ + uicamera->fov = Window::height; + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + Shader* uishader = assets->getShader("ui"); + uishader->use(); + uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView()); + + // Chosen block preview + Texture* blocks = assets->getTexture("block"); + Texture* sprite = assets->getTexture("slot"); + + if (!Events::_cursor_locked) { + batch->texture(nullptr); + batch->color = vec4(0.0f, 0.0f, 0.0f, 0.5f); + batch->rect(0, 0, Window::width, Window::height); + } + + batch->color = vec4(1.0f); + batch->texture(sprite); + batch->sprite(16, uicamera->fov - 80, 64, 64, 16, 0, vec4(1.0f)); + + batch->texture(blocks); + Player* player = level->player; + { + Block* cblock = Block::blocks[player->choosenBlock]; + if (cblock->model == BLOCK_MODEL_CUBE){ + batch->blockSprite(24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces, vec4(1.0f)); + } else if (cblock->model == BLOCK_MODEL_GRASS){ + batch->sprite(24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces[3], vec4(1.0f)); + } + } + + if (!Events::_cursor_locked) { + for (unsigned i = 1; i < 256; i++) { + Block* cblock = Block::blocks[i]; + if (cblock == nullptr) + break; + int size = 48; + int step = 70; + int x = 24 + (i-1) * step; + int y = uicamera->fov - 72 - 70; + y -= 72 * (x / (Window::width - step)); + x %= (Window::width - step); + vec4 tint(1.0f); + int mx = Events::x; + int my = Events::y; + if (mx > x && mx < x + size && my > y && my < y + size) { + tint.r *= 2.0f; + tint.g *= 2.0f; + tint.b *= 2.0f; + if (Events::jclicked(GLFW_MOUSE_BUTTON_LEFT)) { + player->choosenBlock = i; + } + } + if (cblock->model == BLOCK_MODEL_CUBE){ + batch->blockSprite(x, y, size, size, 16, cblock->textureFaces, tint); + } else if (cblock->model == BLOCK_MODEL_GRASS){ + batch->sprite(x, y, size, size, 16, cblock->textureFaces[3], tint); + } + } + } + + batch->render(); + + Shader* crosshairShader = assets->getShader("crosshair"); + crosshairShader->use(); + crosshairShader->uniform1f("u_ar", (float)Window::height / (float)Window::width); + crosshairShader->uniform1f("u_scale", 1.0f / ((float)Window::height / 1000.0f)); + crosshair->draw(GL_LINES); +} diff --git a/src/hud_render.h b/src/hud_render.h new file mode 100644 index 00000000..08984627 --- /dev/null +++ b/src/hud_render.h @@ -0,0 +1,21 @@ +#ifndef SRC_HUD_RENDER_H_ +#define SRC_HUD_RENDER_H_ + +class Batch2D; +class Camera; +class Level; +class Assets; +class Mesh; + +class HudRenderer { + Batch2D* batch; + Camera* uicamera; + Mesh* crosshair; +public: + HudRenderer(); + ~HudRenderer(); + void draw(Level* level, Assets* assets); + void drawDebug(Level* level, Assets* assets, int fps, bool occlusion); +}; + +#endif /* SRC_HUD_RENDER_H_ */ diff --git a/src/lighting/LightSolver.cpp b/src/lighting/LightSolver.cpp index b4f22bd6..07070a05 100644 --- a/src/lighting/LightSolver.cpp +++ b/src/lighting/LightSolver.cpp @@ -21,8 +21,8 @@ void LightSolver::add(int x, int y, int z, int 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); + chunk->setModified(true); + chunk->lightmap->set(entry.x-chunk->x*CHUNK_W, entry.y, entry.z-chunk->z*CHUNK_D, channel, entry.light); } void LightSolver::add(int x, int y, int z) { @@ -35,7 +35,7 @@ void LightSolver::remove(int x, int y, int 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); + int light = chunk->lightmap->get(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel); if (light == 0){ return; } @@ -47,7 +47,7 @@ void LightSolver::remove(int x, int y, int 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); + chunk->lightmap->set(entry.x-chunk->x*CHUNK_W, entry.y, entry.z-chunk->z*CHUNK_D, channel, 0); } void LightSolver::solve(){ @@ -78,8 +78,8 @@ void LightSolver::solve(){ 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; + chunk->lightmap->set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, 0); + chunk->setModified(true); } else if (light >= entry.light){ lightentry nentry; @@ -94,7 +94,7 @@ void LightSolver::solve(){ } while (!addqueue.empty()){ - lightentry entry = addqueue.front(); + const lightentry entry = addqueue.front(); addqueue.pop(); if (entry.light <= 1) @@ -110,8 +110,8 @@ void LightSolver::solve(){ 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; + chunk->lightmap->set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, entry.light-1); + chunk->setModified(true); lightentry nentry; nentry.x = x; nentry.y = y; diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index 12bca112..5a036d76 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -6,6 +6,8 @@ #include "../voxels/voxel.h" #include "../voxels/Block.h" +#include + Lighting::Lighting(Chunks* chunks){ this->chunks = chunks; solverR = new LightSolver(chunks, 0); @@ -33,154 +35,94 @@ void Lighting::clear(){ } } -void Lighting::onChunkLoaded(int cx, int cy, int cz, bool sky){ - 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 && sky){ - for (int z = 0; z < CHUNK_D; z++){ - for (int x = 0; x < CHUNK_W; x++){ +void Lighting::prebuildSkyLight(int cx, int cz){ + Chunk* chunk = chunks->getChunk(cx, cz); + int highestPoint = 0; + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + for (int y = CHUNK_H-1;;y--){ + if (y < 0) + break; + voxel* vox = &(chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x]); + Block* block = Block::blocks[vox->id]; + if (!block->skyLightPassing) { + if (highestPoint < y) + highestPoint = y; + break; + } + chunk->lightmap->setS(x,y,z, 15); + } + } + } + if (highestPoint < CHUNK_H-1) + highestPoint++; + chunk->lightmap->highestPoint = highestPoint; +} + +void Lighting::buildSkyLight(int cx, int cz){ + Chunk* chunk = chunks->getChunk(cx, cz); + for (int z = 0; z < CHUNK_D; z++){ + for (int x = 0; x < CHUNK_W; x++){ + for (int y = chunk->lightmap->highestPoint; y >= 0; y--){ int gx = x + cx * CHUNK_W; 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->skyLightPassing) - 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); + while (y > 0 && !Block::blocks[chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x].id]->lightPassing) { + y--; + } + if (chunk->lightmap->getS(x, y, z) != 15) { + solverS->add(gx,y+1,gz); + for (; y >= 0; y--){ + solverS->add(gx+1,y,gz); + solverS->add(gx-1,y,gz); + solverS->add(gx,y,gz+1); + solverS->add(gx,y,gz-1); } } } } } - if (chunkUpper && sky){ - 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; + solverS->solve(); +} - int light = chunkUpper->lightmap->getS(x,0,z); +void Lighting::onChunkLoaded(int cx, int cz){ + const Chunk* chunk = chunks->getChunk(cx, cz); - 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->skyLightPassing) - 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 if (sky){ - 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->skyLightPassing) - 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; - if (chunks->getLight(x,y,z)){ - solverR->add(gx,gy,gz); - solverG->add(gx,gy,gz); - solverB->add(gx,gy,gz); - if (sky) - solverS->add(gx,gy,gz); + if (block->emission[0] || block->emission[1] || block->emission[2]){ + solverR->add(gx,y,gz,block->emission[0]); + solverG->add(gx,y,gz,block->emission[1]); + solverB->add(gx,y,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 || z == -1 || z == CHUNK_D)) + continue; + int gx = x + cx * CHUNK_W; + int gz = z + cz * CHUNK_D; + if (chunks->getLight(x,y,z)){ + solverR->add(gx,y,gz); + solverG->add(gx,y,gz); + solverB->add(gx,y,gz); + solverS->add(gx,y,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){ @@ -189,11 +131,9 @@ void Lighting::onBlockSet(int x, int y, int z, int id){ 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); @@ -202,14 +142,12 @@ void Lighting::onBlockSet(int x, int y, int z, int id){ 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(); diff --git a/src/lighting/Lighting.h b/src/lighting/Lighting.h index ebbb2173..e1caf777 100644 --- a/src/lighting/Lighting.h +++ b/src/lighting/Lighting.h @@ -15,7 +15,9 @@ public: ~Lighting(); void clear(); - void onChunkLoaded(int cx, int cy, int cz, bool sky); + void prebuildSkyLight(int cx, int cz); + void buildSkyLight(int cx, int cz); + void onChunkLoaded(int cx, int cz); void onBlockSet(int x, int y, int z, int id); }; diff --git a/src/lighting/Lightmap.h b/src/lighting/Lightmap.h index bee5c5e7..c0ca007a 100644 --- a/src/lighting/Lightmap.h +++ b/src/lighting/Lightmap.h @@ -6,6 +6,7 @@ class Lightmap { public: unsigned short* map; + int highestPoint = 0; Lightmap(); ~Lightmap(); diff --git a/src/loaders/png_loading.cpp b/src/loaders/png_loading.cpp index 0a02b04a..7757b564 100644 --- a/src/loaders/png_loading.cpp +++ b/src/loaders/png_loading.cpp @@ -102,6 +102,8 @@ int _png_load(const char* file, int* width, int* height){ 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_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); @@ -210,6 +212,8 @@ int _png_load(const char* file, int* pwidth, int* pheight){ alpha, GL_UNSIGNED_BYTE, (GLvoid *) flipped); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBindTexture(GL_TEXTURE_2D, 0); pwidth[0] = ihdr.width; diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index b8e2b37a..997caf06 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -1,5 +1,8 @@ #include "Player.h" #include "../physics/Hitbox.h" +#include "../physics/PhysicsSolver.h" +#include "../voxels/Chunks.h" +#include "../window/Events.h" #include diff --git a/src/objects/Player.h b/src/objects/Player.h index d3e4e081..af7a9fe7 100644 --- a/src/objects/Player.h +++ b/src/objects/Player.h @@ -5,6 +5,8 @@ class Camera; class Hitbox; +class PhysicsSolver; +class Chunks; class Player { public: @@ -12,6 +14,7 @@ public: Camera* camera; Hitbox* hitbox; bool flight = false; + bool noclip = false; int choosenBlock; float camX, camY; float cameraShaking = 0.0f; diff --git a/src/physics/PhysicsSolver.cpp b/src/physics/PhysicsSolver.cpp index bab04f0b..dac915df 100644 --- a/src/physics/PhysicsSolver.cpp +++ b/src/physics/PhysicsSolver.cpp @@ -10,7 +10,9 @@ PhysicsSolver::PhysicsSolver(vec3 gravity) : gravity(gravity) { } -void PhysicsSolver::step(Chunks* chunks, Hitbox* hitbox, float delta, unsigned substeps, bool shifting, float gravityScale) { +void PhysicsSolver::step(Chunks* chunks, Hitbox* hitbox, float delta, unsigned substeps, bool shifting, + float gravityScale, + bool collisions) { hitbox->grounded = false; for (unsigned i = 0; i < substeps; i++){ float dt = delta / (float)substeps; @@ -25,85 +27,87 @@ void PhysicsSolver::step(Chunks* chunks, Hitbox* hitbox, float delta, unsigned s float px = pos.x; float pz = pos.z; - if (vel.x < 0.0){ - for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ - for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ - int x = floor(pos.x-half.x-E); - if (chunks->isObstacle(x,y,z)){ - vel.x *= 0.0; - pos.x = x + 1 + half.x + E; - break; + if (collisions) { + if (vel.x < 0.0){ + for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ + int x = floor(pos.x-half.x-E); + if (chunks->isObstacle(x,y,z)){ + vel.x *= 0.0; + pos.x = x + 1 + half.x + E; + break; + } } } } - } - if (vel.x > 0.0){ - for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ - for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ - int x = floor(pos.x+half.x+E); - if (chunks->isObstacle(x,y,z)){ - vel.x *= 0.0; - pos.x = x - half.x - E; - break; + if (vel.x > 0.0){ + for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ + int x = floor(pos.x+half.x+E); + if (chunks->isObstacle(x,y,z)){ + vel.x *= 0.0; + pos.x = x - half.x - E; + break; + } } } } - } - if (vel.z < 0.0){ - for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + if (vel.z < 0.0){ + for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ + int z = floor(pos.z-half.z-E); + if (chunks->isObstacle(x,y,z)){ + vel.z *= 0.0; + pos.z = z + 1 + half.z + E; + break; + } + } + } + } + + if (vel.z > 0.0){ + for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ + int z = floor(pos.z+half.z+E); + if (chunks->isObstacle(x,y,z)){ + vel.z *= 0.0; + pos.z = z - half.z - E; + break; + } + } + } + } + + if (vel.y < 0.0){ for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ - int z = floor(pos.z-half.z-E); - if (chunks->isObstacle(x,y,z)){ - vel.z *= 0.0; - pos.z = z + 1 + half.z + E; - break; + bool broken = false; + for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ + int y = floor(pos.y-half.y-E); + if (chunks->isObstacle(x,y,z)){ + vel.y *= 0.0; + pos.y = y + 1 + half.y; + int f = DEFAULT_FRICTION; + vel.x *= max(0.0, 1.0 - dt * f); + vel.z *= max(0.0, 1.0 - dt * f); + hitbox->grounded = true; + broken = true; + break; + } } + if (broken) + break; } } - } - - if (vel.z > 0.0){ - for (int y = floor(pos.y-half.y+E); y <= floor(pos.y+half.y-E); y++){ + if (vel.y > 0.0){ for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ - int z = floor(pos.z+half.z+E); - if (chunks->isObstacle(x,y,z)){ - vel.z *= 0.0; - pos.z = z - half.z - E; - break; - } - } - } - } - - if (vel.y < 0.0){ - for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ - bool broken = false; - for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ - int y = floor(pos.y-half.y-E); - if (chunks->isObstacle(x,y,z)){ - vel.y *= 0.0; - pos.y = y + 1 + half.y; - int f = DEFAULT_FRICTION; - vel.x *= max(0.0, 1.0 - dt * f); - vel.z *= max(0.0, 1.0 - dt * f); - hitbox->grounded = true; - broken = true; - break; - } - } - if (broken) - break; - } - } - if (vel.y > 0.0){ - for (int x = floor(pos.x-half.x+E); x <= floor(pos.x+half.x-E); x++){ - for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ - int y = floor(pos.y+half.y+E); - if (chunks->isObstacle(x,y,z)){ - vel.y *= 0.0; - pos.y = y - half.y - E; - break; + for (int z = floor(pos.z-half.z+E); z <= floor(pos.z+half.z-E); z++){ + int y = floor(pos.y+half.y+E); + if (chunks->isObstacle(x,y,z)){ + vel.y *= 0.0; + pos.y = y - half.y - E; + break; + } } } } diff --git a/src/physics/PhysicsSolver.h b/src/physics/PhysicsSolver.h index 469d73a8..f2302b34 100644 --- a/src/physics/PhysicsSolver.h +++ b/src/physics/PhysicsSolver.h @@ -14,7 +14,13 @@ class PhysicsSolver { vec3 gravity; public: PhysicsSolver(vec3 gravity); - void step(Chunks* chunks, Hitbox* hitbox, float delta, unsigned substeps, bool shifting, float gravityScale); + void step(Chunks* chunks, + Hitbox* hitbox, + float delta, + unsigned substeps, + bool shifting, + float gravityScale, + bool collisions); bool isBlockInside(int x, int y, int z, Hitbox* hitbox); }; diff --git a/src/player_control.cpp b/src/player_control.cpp new file mode 100644 index 00000000..59fbe276 --- /dev/null +++ b/src/player_control.cpp @@ -0,0 +1,211 @@ +#include "player_control.h" + +#include "objects/Player.h" +#include "physics/PhysicsSolver.h" +#include "physics/Hitbox.h" +#include "lighting/Lighting.h" +#include "world/Level.h" +#include "voxels/Block.h" +#include "voxels/voxel.h" +#include "voxels/Chunks.h" +#include "window/Camera.h" +#include "window/Events.h" +#include + +#define CROUCH_SPEED_MUL 0.25f +#define CROUCH_SHIFT_Y -0.2f +#define RUN_SPEED_MUL 1.5f +#define CROUCH_ZOOM 0.9f +#define RUN_ZOOM 1.1f +#define C_ZOOM 0.1f +#define ZOOM_SPEED 16.0f +#define DEFAULT_AIR_DAMPING 0.1f +#define PLAYER_NOT_ONGROUND_DAMPING 10.0f +#define CAMERA_SHAKING_OFFSET 0.025f +#define CAMERA_SHAKING_OFFSET_Y 0.031f +#define CAMERA_SHAKING_SPEED 1.6f +#define CAMERA_SHAKING_DELTA_K 10.0f +#define FLIGHT_SPEED_MUL 4.0f +#define CHEAT_SPEED_MUL 5.0f +#define JUMP_FORCE 7.0f + +PlayerController::PlayerController(Level* level) : level(level) { +} + +void PlayerController::update_controls(float delta){ + Player* player = level->player; + + for (int i = 1; i < 10; i++){ + if (Events::jpressed(GLFW_KEY_0+i)){ + player->choosenBlock = i; + } + } + + // Controls + Camera* camera = player->camera; + Hitbox* hitbox = player->hitbox; + bool sprint = Events::pressed(GLFW_KEY_LEFT_CONTROL); + bool shift = Events::pressed(GLFW_KEY_LEFT_SHIFT) && hitbox->grounded && !sprint; + bool zoom = Events::pressed(GLFW_KEY_C); + bool cheat = Events::pressed(GLFW_KEY_R); + + float speed = player->speed; + if (player->flight){ + speed *= FLIGHT_SPEED_MUL; + } + if (cheat){ + speed *= CHEAT_SPEED_MUL; + } + int substeps = (int)(delta * 1000); + substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps)); + level->physics->step(level->chunks, hitbox, delta, substeps, shift, player->flight ? 0.0f : 1.0f, !player->noclip); + camera->position.x = hitbox->position.x; + camera->position.y = hitbox->position.y + 0.7f; + camera->position.z = hitbox->position.z; + + if (player->flight && hitbox->grounded) + player->flight = false; + // Camera shaking + player->interpVel = player->interpVel * (1.0f - delta * 5) + hitbox->velocity * delta * 0.1f; + if (hitbox->grounded && player->interpVel.y < 0.0f){ + player->interpVel.y *= -30.0f; + } + float factor = hitbox->grounded ? length(vec2(hitbox->velocity.x, hitbox->velocity.z)) : 0.0f; + player->cameraShakingTimer += delta * factor * CAMERA_SHAKING_SPEED; + float shakeTimer = player->cameraShakingTimer; + player->cameraShaking = player->cameraShaking * (1.0f - delta * CAMERA_SHAKING_DELTA_K) + factor * delta * CAMERA_SHAKING_DELTA_K; + camera->position += camera->right * sin(shakeTimer) * CAMERA_SHAKING_OFFSET * player->cameraShaking; + camera->position += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking; + camera->position -= min(player->interpVel * 0.05f, 1.0f); + + if ((Events::jpressed(GLFW_KEY_F) && !player->noclip) || + (Events::jpressed(GLFW_KEY_N) && player->flight == player->noclip)){ + player->flight = !player->flight; + if (player->flight){ + hitbox->velocity.y += 1; + hitbox->grounded = false; + } + } + if (Events::jpressed(GLFW_KEY_N)) { + player->noclip = !player->noclip; + } + + // Field of view manipulations + float dt = min(1.0f, delta * ZOOM_SPEED); + float zoomValue = 1.0f; + if (shift){ + speed *= CROUCH_SPEED_MUL; + camera->position.y += CROUCH_SHIFT_Y; + zoomValue = CROUCH_ZOOM; + } else if (sprint){ + speed *= RUN_SPEED_MUL; + zoomValue = RUN_ZOOM; + } + if (zoom) + zoomValue *= C_ZOOM; + camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt); + + if (Events::pressed(GLFW_KEY_SPACE) && hitbox->grounded){ + hitbox->velocity.y = JUMP_FORCE; + } + + vec3 dir(0,0,0); + if (Events::pressed(GLFW_KEY_W)){ + dir.x += camera->dir.x; + dir.z += camera->dir.z; + } + if (Events::pressed(GLFW_KEY_S)){ + dir.x -= camera->dir.x; + dir.z -= camera->dir.z; + } + if (Events::pressed(GLFW_KEY_D)){ + dir.x += camera->right.x; + dir.z += camera->right.z; + } + if (Events::pressed(GLFW_KEY_A)){ + dir.x -= camera->right.x; + dir.z -= camera->right.z; + } + + hitbox->linear_damping = DEFAULT_AIR_DAMPING; + if (player->flight){ + hitbox->linear_damping = PLAYER_NOT_ONGROUND_DAMPING; + hitbox->velocity.y *= 1.0f - delta * 9; + if (Events::pressed(GLFW_KEY_SPACE)){ + hitbox->velocity.y += speed * delta * 9; + } + if (Events::pressed(GLFW_KEY_LEFT_SHIFT)){ + hitbox->velocity.y -= speed * delta * 9; + } + } + if (length(dir) > 0.0f){ + dir = normalize(dir); + + if (!hitbox->grounded) + hitbox->linear_damping = PLAYER_NOT_ONGROUND_DAMPING; + + hitbox->velocity.x += dir.x * speed * delta * 9; + hitbox->velocity.z += dir.z * speed * delta * 9; + } + + if (Events::_cursor_locked){ + player->camY += -Events::deltaY / Window::height * 2; + player->camX += -Events::deltaX / Window::height * 2; + + if (player->camY < -radians(89.0f)){ + player->camY = -radians(89.0f); + } + if (player->camY > radians(89.0f)){ + player->camY = radians(89.0f); + } + + camera->rotation = mat4(1.0f); + camera->rotate(player->camY, player->camX, 0); + } +} + +void PlayerController::update_interaction(){ + Chunks* chunks = level->chunks; + Player* player = level->player; + Lighting* lighting = level->lighting; + Camera* camera = player->camera; + vec3 end; + vec3 norm; + vec3 iend; + voxel* vox = chunks->rayCast(camera->position, camera->front, 10.0f, end, norm, iend); + if (vox != nullptr){ + selectedBlockId = vox->id; + selectedBlockPosition = iend; + + Block* block = Block::blocks[vox->id]; + if (Events::jclicked(GLFW_MOUSE_BUTTON_1) && block->breakable){ + 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); + if (block->model == BLOCK_MODEL_GRASS){ + x = (int)iend.x; + y = (int)iend.y; + z = (int)iend.z; + } + if (!level->physics->isBlockInside(x,y,z, player->hitbox)){ + chunks->set(x, y, z, player->choosenBlock); + lighting->onBlockSet(x,y,z, player->choosenBlock); + } + } + if (Events::jclicked(GLFW_MOUSE_BUTTON_3)){ + int x = (int)iend.x; + int y = (int)iend.y; + int z = (int)iend.z; + player->choosenBlock = chunks->get(x,y,z)->id; + } + } else { + selectedBlockId = -1; + } +} diff --git a/src/player_control.h b/src/player_control.h new file mode 100644 index 00000000..86fbc85b --- /dev/null +++ b/src/player_control.h @@ -0,0 +1,21 @@ +#ifndef PLAYER_CONTROL_H_ +#define PLAYER_CONTROL_H_ + +#include + +class PhysicsSolver; +class Chunks; +class Player; +class Level; + +class PlayerController { + Level* level; +public: + glm::vec3 selectedBlockPosition; + int selectedBlockId = -1; + PlayerController(Level* level); + void update_controls(float delta); + void update_interaction(); +}; + +#endif /* PLAYER_CONTROL_H_ */ diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp index 3cb54bef..99c95676 100644 --- a/src/voxel_engine.cpp +++ b/src/voxel_engine.cpp @@ -2,6 +2,7 @@ // sudo apt install libgl-dev libglew-dev libglfw3-dev libpng-dev libglm-dev #include #include +#include #define GLEW_STATIC #include @@ -22,6 +23,8 @@ using namespace glm; #include "graphics/Mesh.h" #include "graphics/VoxelRenderer.h" #include "graphics/LineBatch.h" +#include "graphics/Batch2D.h" +#include "graphics/Framebuffer.h" #include "window/Window.h" #include "window/Events.h" #include "window/Camera.h" @@ -39,305 +42,163 @@ using namespace glm; #include "lighting/Lighting.h" #include "physics/Hitbox.h" #include "physics/PhysicsSolver.h" +#include "world/World.h" +#include "world/Level.h" +#include "audio/Audio.h" +#include "audio/audioutil.h" #include "Assets.h" #include "objects/Player.h" #include "declarations.h" #include "world_render.h" +#include "hud_render.h" +#include "player_control.h" +int WIDTH = 1280; +int HEIGHT = 720; // Save all world data to files -void write_world(WorldFiles* wfile, Chunks* chunks){ +void write_world(World* world, Level* level){ + WorldFiles* wfile = world->wfile; + Chunks* chunks = level->chunks; + for (unsigned int i = 0; i < chunks->volume; i++){ Chunk* chunk = chunks->chunks[i]; - if (chunk == nullptr) + if (chunk == nullptr || !chunk->isUnsaved()) continue; wfile->put((const char*)chunk->voxels, chunk->x, chunk->z); } wfile->write(); + + world->wfile->writePlayer(level->player); } -// Deleting world data from memory -void close_world(WorldFiles* wfile, Chunks* chunks){ - delete chunks; - delete wfile; +void update_level(World* world, Level* level, float delta, long frame, VoxelRenderer* renderer) { + level->playerController->update_controls(delta); + if (Events::_cursor_locked) + level->playerController->update_interaction(); + + vec3 position = level->player->hitbox->position; + level->chunks->setCenter(world->wfile, position.x, position.z); } -#define CROUCH_SPEED_MUL 0.25f -#define CROUCH_SHIFT_Y -0.2f -#define RUN_SPEED_MUL 1.5f -#define CROUCH_ZOOM 0.9f -#define RUN_ZOOM 1.1f -#define C_ZOOM 0.1f -#define ZOOM_SPEED 16.0f -#define DEFAULT_AIR_DAMPING 0.1f -#define PLAYER_NOT_ONGROUND_DAMPING 10.0f -#define CAMERA_SHAKING_OFFSET 0.025f -#define CAMERA_SHAKING_OFFSET_Y 0.031f -#define CAMERA_SHAKING_SPEED 1.6f -#define CAMERA_SHAKING_DELTA_K 10.0f -#define FLIGHT_SPEED_MUL 5.0f -#define JUMP_FORCE 7.0f +Level* load_level(World* world, Player* player) { + Level* level = new Level(world, player, new Chunks(56, 56, 0, 0), new PhysicsSolver(vec3(0, -19.6f, 0))); + world->wfile->readPlayer(player); -void update_controls(PhysicsSolver* physics, - Chunks* chunks, - Player* player, - float delta){ - - if (Events::jpressed(GLFW_KEY_TAB)){ - Events::toogleCursor(); - } - - for (int i = 1; i < 10; i++){ - if (Events::jpressed(GLFW_KEY_0+i)){ - player->choosenBlock = i; - } - } - - // Controls Camera* camera = player->camera; - Hitbox* hitbox = player->hitbox; - bool sprint = Events::pressed(GLFW_KEY_LEFT_CONTROL); - bool shift = Events::pressed(GLFW_KEY_LEFT_SHIFT) && hitbox->grounded && !sprint; - bool zoom = Events::pressed(GLFW_KEY_C); - - float speed = player->speed; - if (player->flight){ - speed *= FLIGHT_SPEED_MUL; - } - int substeps = (int)(delta * 1000); - substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps)); - physics->step(chunks, hitbox, delta, substeps, shift, player->flight ? 0.0f : 1.0f); - camera->position.x = hitbox->position.x; - camera->position.y = hitbox->position.y + 0.5f; - camera->position.z = hitbox->position.z; - - if (player->flight && hitbox->grounded) - player->flight = false; - // Camera shaking - player->interpVel = player->interpVel * (1.0f - delta * 5) + hitbox->velocity * delta * 0.1f; - if (hitbox->grounded && player->interpVel.y < 0.0f){ - player->interpVel.y *= -30.0f; - } - float factor = hitbox->grounded ? length(vec2(hitbox->velocity.x, hitbox->velocity.z)) : 0.0f; - player->cameraShakingTimer += delta * factor * CAMERA_SHAKING_SPEED; - float shakeTimer = player->cameraShakingTimer; - player->cameraShaking = player->cameraShaking * (1.0f - delta * CAMERA_SHAKING_DELTA_K) + factor * delta * CAMERA_SHAKING_DELTA_K; - camera->position += camera->right * sin(shakeTimer) * CAMERA_SHAKING_OFFSET * player->cameraShaking; - camera->position += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking; - camera->position -= min(player->interpVel * 0.05f, 1.0f); - - if (Events::jpressed(GLFW_KEY_F)){ - player->flight = !player->flight; - if (player->flight){ - hitbox->velocity.y += 1; - hitbox->grounded = false; - } - } - - // Field of view manipulations - float dt = min(1.0f, delta * ZOOM_SPEED); - if (dt > 1.0f) - dt = 1.0f; - float zoomValue = 1.0f; - if (shift){ - speed *= CROUCH_SPEED_MUL; - camera->position.y += CROUCH_SHIFT_Y; - zoomValue = CROUCH_ZOOM; - } else if (sprint){ - speed *= RUN_SPEED_MUL; - zoomValue = RUN_ZOOM; - } - if (zoom) - zoomValue *= C_ZOOM; - camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt); - - if (Events::pressed(GLFW_KEY_SPACE) && hitbox->grounded){ - hitbox->velocity.y = JUMP_FORCE; - } - - vec3 dir(0,0,0); - if (Events::pressed(GLFW_KEY_W)){ - dir.x += camera->dir.x; - dir.z += camera->dir.z; - } - if (Events::pressed(GLFW_KEY_S)){ - dir.x -= camera->dir.x; - dir.z -= camera->dir.z; - } - if (Events::pressed(GLFW_KEY_D)){ - dir.x += camera->right.x; - dir.z += camera->right.z; - } - if (Events::pressed(GLFW_KEY_A)){ - dir.x -= camera->right.x; - dir.z -= camera->right.z; - } - - hitbox->linear_damping = DEFAULT_AIR_DAMPING; - if (player->flight){ - hitbox->linear_damping = PLAYER_NOT_ONGROUND_DAMPING; - hitbox->velocity.y *= 1.0f - delta * 9; - if (Events::pressed(GLFW_KEY_SPACE)){ - hitbox->velocity.y += speed * delta * 9; - } - if (Events::pressed(GLFW_KEY_LEFT_SHIFT)){ - hitbox->velocity.y -= speed * delta * 9; - } - } - if (length(dir) > 0.0f){ - dir = normalize(dir); - - if (!hitbox->grounded) - hitbox->linear_damping = PLAYER_NOT_ONGROUND_DAMPING; - - hitbox->velocity.x += dir.x * speed * delta * 9; - hitbox->velocity.z += dir.z * speed * delta * 9; - } - - if (Events::_cursor_locked){ - player->camY += -Events::deltaY / Window::height * 2; - player->camX += -Events::deltaX / Window::height * 2; - - if (player->camY < -radians(89.0f)){ - player->camY = -radians(89.0f); - } - if (player->camY > radians(89.0f)){ - player->camY = radians(89.0f); - } - - camera->rotation = mat4(1.0f); - camera->rotate(player->camY, player->camX, 0); - } + camera->rotation = mat4(1.0f); + camera->rotate(player->camY, player->camX, 0); + return level; } -void update_interaction(Chunks* chunks, PhysicsSolver* physics, Player* player, Lighting* lighting){ - Camera* camera = player->camera; - 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); - if (!physics->isBlockInside(x,y,z, player->hitbox)){ - chunks->set(x, y, z, player->choosenBlock); - lighting->onBlockSet(x,y,z, player->choosenBlock); - } - } - } -} - -int WIDTH = 1280; -int HEIGHT = 720; - -#define GRAVITY 19.6f -#define DEFAULT_PLAYER_SPEED 4.0f - -vec3 spawnpoint(-320, 255, 32); - - -int main() { - setup_definitions(); - - Window::initialize(WIDTH, HEIGHT, "VoxelEngine Part-11"); +int initialize(Assets*& assets) { + Window::initialize(WIDTH, HEIGHT, "VoxelEngine-Cpp v12"); Events::initialize(); + assets = new Assets(); std::cout << "-- loading assets" << std::endl; - Assets* assets = new Assets(); int result = initialize_assets(assets); if (result){ delete assets; Window::terminate(); return result; } - std::cout << "-- loading world" << std::endl; - - Camera *camera = new Camera(spawnpoint, radians(90.0f)); - WorldFiles *wfile = new WorldFiles("world/", REGION_VOL * (CHUNK_VOL * 2 + 8)); - Chunks *chunks = new Chunks(34,1,34, 0,0,0); - - - Player* player = new Player(vec3(camera->position), DEFAULT_PLAYER_SPEED, camera); - wfile->readPlayer(player); - camera->rotation = mat4(1.0f); - camera->rotate(player->camY, player->camX, 0); + return 0; +} +void mainloop(Level* level, Assets* assets) { + Camera* camera = level->player->camera; std::cout << "-- preparing systems" << std::endl; - - VoxelRenderer renderer(1024*1024); - PhysicsSolver physics(vec3(0,-GRAVITY,0)); - Lighting lighting(chunks); - - init_renderer(); - - ChunksController chunksController(chunks, &lighting); - + World* world = level->world; + WorldRenderer worldRenderer(level, assets); + HudRenderer hud; + long frame = 0; float lastTime = glfwGetTime(); float delta = 0.0f; - - long frame = 0; - - bool occlusion = false; - - glfwSwapInterval(1); - - std::cout << "-- initializing finished" << std::endl; - + bool occlusion = true; + bool devdata = false; + Window::swapInterval(0); while (!Window::isShouldClose()){ frame++; float currentTime = glfwGetTime(); delta = currentTime - lastTime; lastTime = currentTime; - + int fps = 1 / delta; if (Events::jpressed(GLFW_KEY_ESCAPE)){ Window::setShouldClose(true); } - + if (Events::jpressed(GLFW_KEY_TAB)){ + Events::toggleCursor(); + } if (Events::jpressed(GLFW_KEY_O)){ occlusion = !occlusion; } + if (Events::jpressed(GLFW_KEY_F3)){ + devdata = !devdata; + } + if (Events::jpressed(GLFW_KEY_F5)){ + for (unsigned i = 0; i < level->chunks->volume; i++) { + Chunk* chunk = level->chunks->chunks[i]; + if (chunk != nullptr && chunk->isReady()){ + chunk->setModified(true); + } + } + } - update_controls(&physics, chunks, player, delta); - update_interaction(chunks, &physics, player, &lighting); - - chunks->setCenter(wfile, camera->position.x,0,camera->position.z); - chunksController._buildMeshes(&renderer, frame); - - int freeLoaders = chunksController.countFreeLoaders(); + update_level(world, level, delta, frame, worldRenderer.renderer); + int freeLoaders = level->chunksController->countFreeLoaders(); for (int i = 0; i < freeLoaders; i++) - chunksController.loadVisible(wfile); + level->chunksController->_buildMeshes(worldRenderer.renderer, frame); + freeLoaders = level->chunksController->countFreeLoaders(); + for (int i = 0; i < freeLoaders; i++) + level->chunksController->calculateLights(); + freeLoaders = level->chunksController->countFreeLoaders(); + for (int i = 0; i < freeLoaders; i++) + level->chunksController->loadVisible(world->wfile); - draw_world(camera, assets, chunks, occlusion); + worldRenderer.draw(world, camera, occlusion); + hud.draw(level, assets); + if (devdata) { + hud.drawDebug(level, assets, fps, occlusion); + } Window::swapBuffers(); Events::pullEvents(); } - std::cout << "-- saving world" << std::endl; +} - wfile->writePlayer(player); - write_world(wfile, chunks); - close_world(wfile, chunks); +int main() { + setup_definitions(); + + Assets* assets; + int status = initialize(assets); + if (status) return status; + + std::cout << "-- loading world" << std::endl; + vec3 playerPosition = vec3(0,150,-10); + Camera* camera = new Camera(playerPosition, radians(90.0f)); + World* world = new World("world-1", "world/", 42); + Player* player = new Player(playerPosition, 4.0f, camera); + Level* level = load_level(world, player); + + std::cout << "-- initializing finished" << std::endl; + + Audio::initialize(); + mainloop(level, assets); + Audio::finalize(); + + std::cout << "-- saving world" << std::endl; + write_world(world, level); + + delete level; + delete world; std::cout << "-- shutting down" << std::endl; - delete assets; - finalize_renderer(); Events::finalize(); Window::terminate(); return 0; } - diff --git a/src/voxels/Block.h b/src/voxels/Block.h index 58010e70..c57bec3d 100644 --- a/src/voxels/Block.h +++ b/src/voxels/Block.h @@ -1,6 +1,9 @@ #ifndef VOXELS_BLOCK_H_ #define VOXELS_BLOCK_H_ +#define BLOCK_MODEL_CUBE 1 +#define BLOCK_MODEL_GRASS 2 + class Block { public: static Block* blocks[256]; @@ -14,6 +17,8 @@ public: bool skyLightPassing = false; bool obstacle = true; bool selectable = true; + bool breakable = true; + unsigned char model = 1; Block(unsigned int id, int texture); }; diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index a4e645b0..52debffe 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -2,12 +2,12 @@ #include "voxel.h" #include "../lighting/Lightmap.h" - -Chunk::Chunk(int xpos, int ypos, int zpos) : x(xpos), y(ypos), z(zpos){ +Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){ voxels = new voxel[CHUNK_VOL]; for (unsigned int i = 0; i < CHUNK_VOL; i++) voxels[i].id = 1; lightmap = new Lightmap(); + renderData.vertices = nullptr; } Chunk::~Chunk(){ @@ -29,7 +29,7 @@ bool Chunk::isEmpty(){ } Chunk* Chunk::clone() const { - Chunk* other = new Chunk(x,y,z); + Chunk* other = new Chunk(x,z); for (int i = 0; i < CHUNK_VOL; i++) other->voxels[i] = voxels[i]; other->lightmap->set(lightmap); diff --git a/src/voxels/Chunk.h b/src/voxels/Chunk.h index 14d1689c..1ff29b7a 100644 --- a/src/voxels/Chunk.h +++ b/src/voxels/Chunk.h @@ -1,25 +1,42 @@ #ifndef VOXELS_CHUNK_H_ #define VOXELS_CHUNK_H_ +#include + #define CHUNK_W 16 #define CHUNK_H 256 #define CHUNK_D 16 #define CHUNK_VOL (CHUNK_W * CHUNK_H * CHUNK_D) +#define CHUNK_MODIFIED 0x1 +#define CHUNK_READY 0x2 +#define CHUNK_LOADED 0x4 +#define CHUNK_LIGHTED 0x8 +#define CHUNK_UNSAVED 0x10 + class voxel; class Lightmap; +struct RenderData { + float* vertices; + size_t size; +}; + +#define BIT_ON(f,i) do{f|= i;} while(0) +#define BIT_OFF(f,i) do{f&=~(i);} while(0) +#define BITSET(f,i,s) if (s) BIT_ON(f,i); else BIT_OFF(f,i); + class Chunk { public: - int x,y,z; + int x, z; voxel* voxels; Lightmap* lightmap; - bool modified = true; - bool ready = false; - bool loaded = false; + int flags = 0; int surrounding = 0; int references = 1; - Chunk(int x, int y, int z); + RenderData renderData; + + Chunk(int x, int z); ~Chunk(); bool isEmpty(); @@ -27,6 +44,28 @@ public: Chunk* clone() const; void incref(); void decref(); + + // flags getters/setters below + + inline bool isUnsaved() const {return flags & CHUNK_UNSAVED;} + + inline bool isModified() const {return flags & CHUNK_MODIFIED;} + + inline bool isLighted() const {return flags & CHUNK_LIGHTED;} + + inline bool isLoaded() const {return flags & CHUNK_LOADED;} + + inline bool isReady() const {return flags & CHUNK_READY;} + + inline void setUnsaved(bool flag) {BITSET(flags, CHUNK_UNSAVED, flag);} + + inline void setModified(bool flag) {BITSET(flags, CHUNK_MODIFIED, flag);} + + inline void setLoaded(bool flag) {BITSET(flags, CHUNK_LOADED, flag);} + + inline void setLighted(bool flag) {BITSET(flags, CHUNK_LIGHTED, flag);} + + inline void setReady(bool flag) {BITSET(flags, CHUNK_READY, flag);} }; #endif /* VOXELS_CHUNK_H_ */ diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 0591f2f0..b16aecd5 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -11,8 +11,8 @@ #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::Chunks(int w, int d, int ox, int oz) : w(w), d(d), ox(ox), oz(oz){ + volume = w*d; chunks = new Chunk*[volume]; chunksSecond = new Chunk*[volume]; @@ -23,6 +23,7 @@ Chunks::Chunks(int w, int h, int d, int ox, int oy, int oz) : w(w), h(h), d(d), chunks[i] = nullptr; meshes[i] = nullptr; } + chunksCount = 0; } Chunks::~Chunks(){ @@ -35,7 +36,6 @@ Chunks::~Chunks(){ 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; @@ -43,7 +43,7 @@ voxel* Chunks::get(int x, int y, int z){ 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) + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) return nullptr; Chunk* chunk = chunks[(cy * d + cz) * w + cx]; if (chunk == nullptr) @@ -63,7 +63,6 @@ bool Chunks::isObstacle(int x, int y, int z){ 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; @@ -71,7 +70,7 @@ unsigned char Chunks::getLight(int x, int y, int z, int channel){ 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) + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) return 0; Chunk* chunk = chunks[(cy * d + cz) * w + cx]; if (chunk == nullptr) @@ -84,7 +83,6 @@ unsigned char Chunks::getLight(int x, int y, int z, int channel){ unsigned short Chunks::getLight(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; @@ -92,7 +90,7 @@ unsigned short Chunks::getLight(int x, int y, int z){ 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) + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) return 0; Chunk* chunk = chunks[(cy * d + cz) * w + cx]; if (chunk == nullptr) @@ -105,7 +103,6 @@ unsigned short Chunks::getLight(int x, int y, int z){ 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; @@ -113,48 +110,44 @@ Chunk* Chunks::getChunkByVoxel(int x, int y, int z){ 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) + if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) return nullptr; return chunks[(cy * d + cz) * w + cx]; } -Chunk* Chunks::getChunk(int x, int y, int z){ +Chunk* Chunks::getChunk(int x, int z){ x -= ox; - y -= oy; z -= oz; - if (x < 0 || y < 0 || z < 0 || x >= w || y >= h || z >= d) + if (x < 0 || z < 0 || x >= w || z >= d) return nullptr; - return chunks[(y * d + z) * w + x]; + return chunks[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; + if (y < 0 || y >= CHUNK_H) + return; 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) + if (cx < 0 || cz < 0 || cx >= w || cz >= d) return; - Chunk* chunk = chunks[(cy * d + cz) * w + cx]; + Chunk* chunk = chunks[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; + chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx].id = id; + chunk->setUnsaved(true); + chunk->setModified(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 == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) chunk->setModified(true); + if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) chunk->setModified(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; + if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz))) chunk->setModified(true); + if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1))) chunk->setModified(true); } voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, vec3& iend) { @@ -245,47 +238,42 @@ voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, v return nullptr; } -void Chunks::setCenter(WorldFiles* worldFiles, int x, int y, int z) { +void Chunks::setCenter(WorldFiles* worldFiles, int x, 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(worldFiles, cx,cy,cz); + if (cx | cz) { + translate(worldFiles, cx,cz); + } } -void Chunks::translate(WorldFiles* worldFiles, int dx, int dy, int dz){ +void Chunks::translate(WorldFiles* worldFiles, int dx, 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){ - worldFiles->put((const char*)chunk->voxels, chunk->x, chunk->z); - chunk->decref(); - delete mesh; - continue; - } - meshesSecond[(ny * d + nz) * w + nx] = mesh; - chunksSecond[(ny * d + nz) * w + nx] = chunk; + for (int z = 0; z < d; z++){ + for (int x = 0; x < w; x++){ + Chunk* chunk = chunks[z * w + x]; + int nx = x - dx; + int nz = z - dz; + if (chunk == nullptr) + continue; + Mesh* mesh = meshes[z * w + x]; + if (nx < 0 || nz < 0 || nx >= w || nz >= d){ + worldFiles->put((const char*)chunk->voxels, chunk->x, chunk->z); + chunk->decref(); + delete mesh; + chunksCount--; + continue; } + meshesSecond[nz * w + nx] = mesh; + chunksSecond[nz * w + nx] = chunk; } } Chunk** ctemp = chunks; @@ -297,26 +285,23 @@ void Chunks::translate(WorldFiles* worldFiles, int dx, int dy, int dz){ meshesSecond = mtemp; ox += dx; - oy += dy; oz += dz; } -void Chunks::_setOffset(int x, int y, int z){ +void Chunks::_setOffset(int x, int z){ ox = x; - oy = y; oz = z; } bool Chunks::putChunk(Chunk* chunk) { int x = chunk->x; - int y = chunk->y; int z = chunk->z; x -= ox; - y -= oy; z -= oz; - if (x < 0 || y < 0 || z < 0 || x >= w || y >= h || z >= d) + if (x < 0 || z < 0 || x >= w || z >= d) return false; - chunks[(y * d + z) * w + x] = chunk; + chunks[z * w + x] = chunk; + chunksCount++; return true; } @@ -329,4 +314,5 @@ void Chunks::clear(bool freeMemory){ chunks[i] = nullptr; meshes[i] = nullptr; } + chunksCount = 0; } diff --git a/src/voxels/Chunks.h b/src/voxels/Chunks.h index bdd5efbb..5b5f9a3a 100644 --- a/src/voxels/Chunks.h +++ b/src/voxels/Chunks.h @@ -20,15 +20,16 @@ public: Mesh** meshes; Mesh** meshesSecond; size_t volume; - unsigned int w,h,d; - int ox,oy,oz; + size_t chunksCount; + int w,d; + int ox,oz; - Chunks(int w, int h, int d, int ox, int oy, int oz); + Chunks(int w, int d, int ox, int oz); ~Chunks(); bool putChunk(Chunk* chunk); - Chunk* getChunk(int x, int y, int z); + Chunk* getChunk(int x, int z); Chunk* getChunkByVoxel(int x, int y, int z); voxel* get(int x, int y, int z); unsigned short getLight(int x, int y, int z); @@ -39,10 +40,10 @@ public: bool isObstacle(int x, int y, int z); // does not move chunks inside - void _setOffset(int x, int y, int z); + void _setOffset(int x, int z); - void setCenter(WorldFiles* worldFiles, int x, int y, int z); - void translate(WorldFiles* worldFiles, int x, int y, int z); + void setCenter(WorldFiles* worldFiles, int x, int z); + void translate(WorldFiles* worldFiles, int x, int z); void clear(bool freeMemory); }; diff --git a/src/voxels/ChunksController.cpp b/src/voxels/ChunksController.cpp index d64ed858..1ca47b52 100644 --- a/src/voxels/ChunksController.cpp +++ b/src/voxels/ChunksController.cpp @@ -8,6 +8,7 @@ #include "../files/WorldFiles.h" #include "ChunksLoader.h" #include +#include #ifdef _WIN32 #define _WIN32_WINNT 0x0501 @@ -19,13 +20,13 @@ #define MIN_SURROUNDING 9 -ChunksController::ChunksController(Chunks* chunks, Lighting* lighting) : chunks(chunks), lighting(lighting){ - loadersCount = std::thread::hardware_concurrency() - 1; +ChunksController::ChunksController(World* world, Chunks* chunks, Lighting* lighting) : chunks(chunks), lighting(lighting){ + loadersCount = std::thread::hardware_concurrency() * 2 - 1; if (loadersCount <= 0) loadersCount = 1; loaders = new ChunksLoader*[loadersCount]; for (int i = 0; i < loadersCount; i++){ - loaders[i] = new ChunksLoader(); + loaders[i] = new ChunksLoader(world); } std::cout << "created " << loadersCount << " loaders" << std::endl; } @@ -47,50 +48,78 @@ int ChunksController::countFreeLoaders(){ bool ChunksController::loadVisible(WorldFiles* worldFiles){ const int w = chunks->w; - const int h = chunks->h; const int d = chunks->d; const int ox = chunks->ox; - const int oy = chunks->oy; const int oz = chunks->oz; int nearX = 0; - int nearY = 0; int nearZ = 0; int minDistance = (w/2)*(w/2); - for (int y = 0; y < h; y++){ - for (int z = 2; z < d-2; z++){ - for (int x = 2; x < w-2; x++){ - int index = (y * d + z) * w + x; - Chunk* chunk = chunks->chunks[index]; - if (chunk != nullptr){ - int surrounding = 0; - for (int oz = -1; oz <= 1; oz++){ - for (int ox = -1; ox <= 1; ox++){ - Chunk* other = chunks->getChunk(chunk->x+ox, chunk->y, chunk->z+oz); - if (other != nullptr && other->ready) surrounding++; - } + for (int z = 2; z < d-2; z++){ + for (int x = 2; x < w-2; x++){ + int index = z * w + x; + Chunk* chunk = chunks->chunks[index]; + if (chunk != nullptr){ + int surrounding = 0; + for (int oz = -1; oz <= 1; oz++){ + for (int ox = -1; ox <= 1; ox++){ + Chunk* other = chunks->getChunk(chunk->x+ox, chunk->z+oz); + if (other != nullptr && other->isReady()) surrounding++; } - chunk->surrounding = surrounding; - 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; } + chunk->surrounding = surrounding; + continue; + } + int lx = x - w / 2; + int lz = z - d / 2; + int distance = (lx * lx + lz * lz); + if (distance < minDistance){ + minDistance = distance; + nearX = x; + nearZ = z; } } } - int index = (nearY * d + nearZ) * w + nearX; + int index = nearZ * w + nearX; Chunk* chunk = chunks->chunks[index]; if (chunk != nullptr) return false; + ChunksLoader* freeLoader = getFreeLoader(); + if (freeLoader == nullptr) + return false; + + chunk = new Chunk(nearX+ox, nearZ+oz); + if (worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels)) + chunk->setLoaded(true); + + chunks->putChunk(chunk); + + Chunk* closes[9]; + for (int i = 0; i < 9; i++) + closes[i] = nullptr; + for (size_t j = 0; j < chunks->volume; j++){ + Chunk* other = chunks->chunks[j]; + if (other == nullptr) + continue; + if (!other->isReady()) + continue; + + int ox = other->x - chunk->x; + int oz = other->z - chunk->z; + + if (abs(ox) > 1 || abs(oz) > 1) + continue; + + ox += 1; + oz += 1; + closes[oz * 3 + ox] = other; + } + freeLoader->load(chunk, (Chunk**)closes); + return true; +} + +ChunksLoader* ChunksController::getFreeLoader() { ChunksLoader* freeLoader = nullptr; for (int i = 0; i < loadersCount; i++){ ChunksLoader* loader = loaders[i]; @@ -100,116 +129,151 @@ bool ChunksController::loadVisible(WorldFiles* worldFiles){ freeLoader = loader; break; } + return freeLoader; +} + +void ChunksController::calculateLights() { + ChunksLoader* freeLoader = getFreeLoader(); if (freeLoader == nullptr) - return false; - chunk = new Chunk(nearX+ox,nearY+oy,nearZ+oz); - if (worldFiles->getChunk(chunk->x, chunk->z, (char*)chunk->voxels)) - chunk->loaded = true; - - chunks->chunks[index] = chunk; - - Chunk* closes[27]; - for (int i = 0; i < 27; i++) + return; + const int w = chunks->w; + const int d = chunks->d; + int nearX = 0; + int nearZ = 0; + int minDistance = INT_MAX; + for (int z = 1; z < d-1; z++){ + for (int x = 1; x < w-1; x++){ + int index = z * w + x; + Chunk* chunk = chunks->chunks[index]; + if (chunk == nullptr) + continue; + if (chunk->isLighted() || chunk->surrounding < MIN_SURROUNDING){ + continue; + } + int lx = x - w / 2; + int lz = z - d / 2; + int distance = (lx * lx + lz * lz); + if (distance < minDistance){ + minDistance = distance; + nearX = x; + nearZ = z; + } + } + } + int index = nearZ * w + nearX; + Chunk* chunk = chunks->chunks[index]; + if (chunk == nullptr) + return; + Chunk* closes[9]; + for (int i = 0; i < 9; i++) closes[i] = nullptr; for (size_t j = 0; j < chunks->volume; j++){ Chunk* other = chunks->chunks[j]; if (other == nullptr) continue; - if (!other->ready) - 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) + if (abs(ox) > 1|| abs(oz) > 1) continue; ox += 1; - oy += 1; oz += 1; - closes[(oy * 3 + oz) * 3 + ox] = other; + closes[oz * 3 + ox] = other; } - freeLoader->perform(chunk, (Chunk**)closes); - return true; + freeLoader->lights(chunk, (Chunk**)closes); } bool ChunksController::_buildMeshes(VoxelRenderer* renderer, int tick) { const int w = chunks->w; - const int h = chunks->h; const int d = chunks->d; - int nearX = 0; - int nearY = 0; - int nearZ = 0; - int minDistance = 1000000000; - for (int y = 0; y < h; y++){ - for (int z = 1; z < d-1; z++){ - for (int x = 1; x < w-1; x++){ - int index = (y * d + z) * w + x; - Chunk* chunk = chunks->chunks[index]; - if (chunk == nullptr) - continue; - Mesh* mesh = chunks->meshes[index]; - if (mesh != nullptr && !chunk->modified) - continue; - if (!chunk->ready || chunk->surrounding < MIN_SURROUNDING){ - 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; - } + for (int z = 1; z < d-1; z++){ + for (int x = 1; x < w-1; x++){ + int index = z * w + x; + Chunk* chunk = chunks->chunks[index]; + if (chunk == nullptr) + continue; + if (chunk->renderData.vertices > (void*)1){ + const int chunk_attrs[] = {3,2,4, 0}; + Mesh* mesh = new Mesh(chunk->renderData.vertices, chunk->renderData.size / CHUNK_VERTEX_SIZE, chunk_attrs); + if (chunks->meshes[index]) + delete chunks->meshes[index]; + chunks->meshes[index] = mesh; + delete[] chunk->renderData.vertices; + chunk->renderData.vertices = nullptr; } } } + ChunksLoader* freeLoader = getFreeLoader(); + if (freeLoader == nullptr) + return false; - int index = (nearY * d + nearZ) * w + nearX; - - + int nearX = 0; + int nearZ = 0; + int minDistance = INT_MAX; + for (int z = 1; z < d-1; z++){ + for (int x = 1; x < w-1; x++){ + int index = z * w + x; + Chunk* chunk = chunks->chunks[index]; + if (chunk == nullptr) + continue; + Mesh* mesh = chunks->meshes[index]; + if (mesh != nullptr && !chunk->isModified()) + continue; + if (!chunk->isReady() || !chunk->isLighted() || chunk->surrounding < MIN_SURROUNDING){ + continue; + } + int lx = x - w / 2; + int lz = z - d / 2; + int distance = (lx * lx + lz * lz); + if (distance < minDistance){ + minDistance = distance; + nearX = x; + nearZ = z; + } + } + } + int index = nearZ * w + nearX; Chunk* chunk = chunks->chunks[index]; if (chunk == nullptr){ return false; } Mesh* mesh = chunks->meshes[index]; - if (mesh == nullptr || chunk->modified){ - Chunk* closes[27]; - if (mesh != nullptr) - delete mesh; + if (mesh == nullptr || chunk->isModified()){ + if (chunk->renderData.vertices != nullptr) { + return false; + } + Chunk* closes[9]; if (chunk->isEmpty()){ chunks->meshes[index] = nullptr; return false; } - chunk->modified = false; - for (int i = 0; i < 27; i++) + + for (int i = 0; i < 9; i++) closes[i] = nullptr; for (size_t j = 0; j < chunks->volume; j++){ Chunk* other = chunks->chunks[j]; if (other == nullptr) continue; - if (!other->ready) - 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) + if (abs(ox) > 1 || abs(oz) > 1) continue; ox += 1; - oy += 1; oz += 1; - closes[(oy * 3 + oz) * 3 + ox] = other; + if ((!other->isReady() || !other->isLighted()) && other != chunk) + return false; + closes[oz * 3 + ox] = other; } - mesh = renderer->render(chunk, (const Chunk**)closes); - chunks->meshes[index] = mesh; + chunk->setModified(false); + chunk->renderData.vertices = (float*)1; + freeLoader->render(chunk, (Chunk**)closes); + return true; } return false; diff --git a/src/voxels/ChunksController.h b/src/voxels/ChunksController.h index d31d925f..d9315f00 100644 --- a/src/voxels/ChunksController.h +++ b/src/voxels/ChunksController.h @@ -1,6 +1,7 @@ #ifndef VOXELS_CHUNKSCONTROLLER_H_ #define VOXELS_CHUNKSCONTROLLER_H_ +class World; class Chunks; class Lighting; class WorldFiles; @@ -14,11 +15,13 @@ private: ChunksLoader** loaders; int loadersCount; public: - ChunksController(Chunks* chunks, Lighting* lighting); + ChunksController(World* world, Chunks* chunks, Lighting* lighting); ~ChunksController(); + ChunksLoader* getFreeLoader(); int countFreeLoaders(); bool loadVisible(WorldFiles* worldFiles); + void calculateLights(); bool _buildMeshes(VoxelRenderer* renderer, int tick); }; diff --git a/src/voxels/ChunksLoader.cpp b/src/voxels/ChunksLoader.cpp index 89963760..f688a70a 100644 --- a/src/voxels/ChunksLoader.cpp +++ b/src/voxels/ChunksLoader.cpp @@ -3,65 +3,108 @@ #include "Chunk.h" #include "Chunks.h" +#include "Block.h" +#include "voxel.h" +#include "../world/World.h" #include "WorldGenerator.h" #include "../lighting/Lighting.h" +#include "../graphics/VoxelRenderer.h" #include -#define CLOSES_C 27 +#define SURROUNDINGS_C 9 void ChunksLoader::_thread(){ - Chunks chunks(3,3,3, -1,-1,-1); + Chunks chunks(3, 3, -1, -1); Lighting lighting(&chunks); - while (working){ + VoxelRenderer renderer; + while (state != OFF){ if (current == nullptr){ std::this_thread::sleep_for(std::chrono::milliseconds(1)); continue; } Chunk* chunk = current; - chunks._setOffset(chunk->x-1, chunk->y-1, chunk->z-1); - for (size_t i = 0; i < CLOSES_C; i++){ - Chunk* other = closes[i]; + chunks._setOffset(chunk->x-1, chunk->z-1); + for (size_t i = 0; i < SURROUNDINGS_C; i++){ + Chunk* other = surroundings[i]; if (other){ chunks.putChunk(other); } } - if (!chunk->loaded){ - WorldGenerator::generate(chunk->voxels, chunk->x, chunk->y, chunk->z); + if (state == LOAD){ + chunks.putChunk(chunk); + if (!chunk->isLoaded()){ + WorldGenerator::generate(chunk->voxels, chunk->x, chunk->z, world->seed); + chunk->setUnsaved(true); + } + + for (size_t i = 0; i < CHUNK_VOL; i++){ + if (Block::blocks[chunk->voxels[i].id] == nullptr){ + std::cout << "corruped block detected at " << i << " of chunk " << chunk->x << "x" << chunk->z << std::endl; + chunk->voxels[i].id = 11; + } + } + lighting.prebuildSkyLight(chunk->x, chunk->z); + } + else if (state == LIGHTS) { + lighting.buildSkyLight(chunk->x, chunk->z); + lighting.onChunkLoaded(chunk->x, chunk->z); + chunk->setLighted(true); + } + else if (state == RENDER){ + chunk->setModified(false); + size_t size; + renderer.render(chunk, (const Chunk**)(surroundings.load()), size); + float* vertices = new float[size]; + for (size_t i = 0; i < size; i++) + vertices[i] = renderer.buffer[i]; + chunk->renderData.vertices = vertices; + chunk->renderData.size = size; } - chunks.putChunk(chunk); - lighting.onChunkLoaded(chunk->x, chunk->y, chunk->z, true); chunks.clear(false); - for (int i = 0; i < CLOSES_C; i++){ - Chunk* other = closes[i]; + for (int i = 0; i < SURROUNDINGS_C; i++){ + Chunk* other = surroundings[i]; if (other) other->decref(); } - chunk->ready = true; + chunk->setReady(true); current = nullptr; chunk->decref(); } } -void ChunksLoader::perform(Chunk* chunk, Chunk** closes_passed){ +void ChunksLoader::perform(Chunk* chunk, Chunk** surroundings_passed, LoaderMode mode){ if (isBusy()){ std::cerr << "performing while busy" << std::endl; return; } chunk->incref(); - if (closes == nullptr){ - closes = new Chunk*[CLOSES_C]; + if (surroundings == nullptr){ + surroundings = new Chunk*[SURROUNDINGS_C]; } - for (int i = 0; i < CLOSES_C; i++){ - Chunk* other = closes_passed[i]; + for (int i = 0; i < SURROUNDINGS_C; i++){ + Chunk* other = surroundings_passed[i]; if (other == nullptr) - closes[i] = nullptr; + surroundings[i] = nullptr; else { other->incref(); - closes[i] = other; + surroundings[i] = other; } } current = chunk; + state = mode; +} + +void ChunksLoader::load(Chunk* chunk, Chunk** closes_passed){ + perform(chunk, closes_passed, LOAD); +} + +void ChunksLoader::lights(Chunk* chunk, Chunk** closes_passed){ + perform(chunk, closes_passed, LIGHTS); +} + +void ChunksLoader::render(Chunk* chunk, Chunk** closes_passed){ + perform(chunk, closes_passed, RENDER); } diff --git a/src/voxels/ChunksLoader.h b/src/voxels/ChunksLoader.h index aff93ec7..876b0c8c 100644 --- a/src/voxels/ChunksLoader.h +++ b/src/voxels/ChunksLoader.h @@ -11,20 +11,28 @@ #include class Chunk; +class World; + +enum LoaderMode { + OFF, IDLE, LOAD, LIGHTS, RENDER, +}; class ChunksLoader final { private: std::thread loaderThread; void _thread(); std::atomic current {nullptr}; - std::atomic closes {nullptr}; - std::atomic working {true}; + std::atomic surroundings {nullptr}; + std::atomic state {IDLE}; + World* world; + + void perform(Chunk* chunk, Chunk** closes_passed, LoaderMode mode); public: - ChunksLoader() : loaderThread{} { + ChunksLoader(World* world) : loaderThread{}, world(world) { loaderThread = std::thread{&ChunksLoader::_thread, this}; } ~ChunksLoader(){ - working = false; + state = OFF; loaderThread.join(); } @@ -32,10 +40,12 @@ public: return current != nullptr; } - void perform(Chunk* chunk, Chunk** closes_passed); + void load(Chunk* chunk, Chunk** closes_passed); + void lights(Chunk* chunk, Chunk** closes_passed); + void render(Chunk* chunk, Chunk** closes_passed); void stop(){ - working = false; + state = OFF; } }; diff --git a/src/voxels/WorldGenerator.cpp b/src/voxels/WorldGenerator.cpp index 0e27ff3e..1664bbda 100644 --- a/src/voxels/WorldGenerator.cpp +++ b/src/voxels/WorldGenerator.cpp @@ -2,6 +2,7 @@ #include "voxel.h" #include "Chunk.h" +#include #include #include #include @@ -9,54 +10,64 @@ #include "../maths/FastNoiseLite.h" #include +#include "../declarations.h" + class PseudoRandom { - unsigned seed; + unsigned short seed; public: PseudoRandom(){ - seed = (unsigned)time(0); + seed = (unsigned short)time(0); } int rand(){ - seed = (8253729 * seed + 2396403); - return seed % 32768; + seed = (seed + 0x7ed5 + (seed << 6)); + seed = (seed ^ 0xc23c ^ (seed >> 9)); + seed = (seed + 0x1656 + (seed << 3)); + seed = ((seed + 0xa264) ^ (seed << 4)); + seed = (seed + 0xfd70 - (seed << 3)); + seed = (seed ^ 0xba49 ^ (seed >> 8)); + + return (int)seed; } void setSeed(int number){ - seed = (unsigned)number+8253729; + seed = ((unsigned short)number+23729 xor (unsigned short)number+16786); rand(); } }; float calc_height(fnl_state *noise, int real_x, int real_z){ - const float s = 0.2f; - float height = fnlGetNoise3D(noise, real_x*0.0125f*s*32,real_z*0.0125f*s*32, 0.0f); - height += fnlGetNoise3D(noise, real_x*0.025f*s*32,real_z*0.025f*s*32, 0.0f)*0.5f; - height += fnlGetNoise3D(noise, real_x*0.05f*s*32,real_z*0.05f*s*32, 0.0f)*0.25f; - height += fnlGetNoise3D(noise, real_x*0.1f*s*32,real_z*0.1f*s*32, 0.0f)*0.225f; - height += fnlGetNoise3D(noise, real_x*0.2f*s*32,real_z*0.2f*s*32, 0.0f)*0.125f; - height += fnlGetNoise3D(noise, real_x*0.4f*s*32,real_z*0.4f*s*32, 0.0f)*0.125f*0.5F; - height = height * 0.5f + 0.5f; - height *= height; - height *= (140.0f)*0.12f/s; - height += (42)*0.12f/s; + float height = fnlGetNoise3D(noise, real_x*0.0125f*8,real_z*0.0125f*8, 0.0f); + height += fnlGetNoise3D(noise, real_x*0.025f*8,real_z*0.025f*8, 0.0f)*0.5f; + height += fnlGetNoise3D(noise, real_x*0.05f*8,real_z*0.05f*8, 0.0f)*0.25f; + height += fnlGetNoise3D(noise, + real_x*0.2f*8 + fnlGetNoise3D(noise, real_x*0.1f*8,real_z*0.1f*8, 0.0f)*50, + real_z*0.2f*8 + fnlGetNoise3D(noise, real_x*0.1f*8+4363,real_z*0.1f*8, 0.0f)*50, + 0.0f)*0.1f; + height += fnlGetNoise3D(noise, real_x*0.1f*8,real_z*0.1f*8, 0.0f)*0.125f; + height += fnlGetNoise3D(noise, real_x*0.4f*8,real_z*0.4f*8, 0.0f)*0.0625f; + height += fnlGetNoise3D(noise, real_x*8,real_z*8, 0.0f)*0.03f*(fnlGetNoise3D(noise, -real_x*0.0125f*8-1000,real_z*0.0125f*8+2000, 0.0f)/2+0.5f); + height *= fnlGetNoise3D(noise, real_x*0.0125f*8+1000,real_z*0.0125f*8+1000, 0.0f)/2+0.5f; + height += 1.0f; + height *= 64.0f; return height; } float calc_height_faster(fnl_state *noise, int real_x, int real_z){ - const float s = 0.2f; - float height = fnlGetNoise3D(noise, real_x*0.0125f*s*32,real_z*0.0125f*s*32, 0.0f); - height += fnlGetNoise3D(noise, real_x*0.025f*s*32,real_z*0.025f*s*32, 0.0f)*0.5f; - height += fnlGetNoise3D(noise, real_x*0.05f*s*32,real_z*0.05f*s*32, 0.0f)*0.25f; - height += fnlGetNoise3D(noise, real_x*0.1f*s*32,real_z*0.1f*s*32, 0.0f)*0.225f; - height += fnlGetNoise3D(noise, real_x*0.2f*s*32,real_z*0.2f*s*32, 0.0f)*0.125f; - //height += fnlGetNoise3D(noise, real_x*0.4f*s*32,real_z*0.4f*s*32, 0.0f)*0.125f*0.5F; - height = height * 0.5f + 0.5f; - height *= height; - height *= (140.0f)*0.12f/s; - height += (42)*0.12f/s; + float height = fnlGetNoise3D(noise, real_x*0.0125f*8,real_z*0.0125f*8, 0.0f); + height += fnlGetNoise3D(noise, real_x*0.025f*8,real_z*0.025f*8, 0.0f)*0.5f; + height += fnlGetNoise3D(noise, real_x*0.05f*8,real_z*0.05f*8, 0.0f)*0.25f; + height += fnlGetNoise3D(noise, + real_x*0.2f*8 + fnlGetNoise3D(noise, real_x*0.1f*8,real_z*0.1f*8, 0.0f)*50, + real_z*0.2f*8 + fnlGetNoise3D(noise, real_x*0.1f*8+4363,real_z*0.1f*8, 0.0f)*50, + 0.0f)*0.1f; + height += fnlGetNoise3D(noise, real_x*0.1f*8,real_z*0.1f*8, 0.0f)*0.125f; + height *= fnlGetNoise3D(noise, real_x*0.0125f*8+1000,real_z*0.0125f*8+1000, 0.0f)/2+0.5f; + height += 1.0f; + height *= 64.0f; return height; } -#include + int generate_tree(fnl_state *noise, PseudoRandom* random, const float* heights, int real_x, int real_y, int real_z, int tileSize){ const int tileX = floor((double)real_x/(double)tileSize); const int tileY = floor((double)real_z/(double)tileSize); @@ -71,7 +82,7 @@ int generate_tree(fnl_state *noise, PseudoRandom* random, const float* heights, int centerX = tileX * tileSize + tileSize/2 + randomX; int centerY = tileY * tileSize + tileSize/2 + randomZ; int height = (int)calc_height_faster(noise, centerX, centerY); - if (height < 55) + if ((height < 57) || (fnlGetNoise3D(noise, real_x*0.025f,real_z*0.025f, 0.0f)*0.5f > 0.5)) return 0; int lx = real_x - centerX; int radius = random->rand() % 4 + 3; @@ -84,11 +95,11 @@ int generate_tree(fnl_state *noise, PseudoRandom* random, const float* heights, return 0; } -void WorldGenerator::generate(voxel* voxels, int cx, int cy, int cz){ +void WorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){ fnl_state noise = fnlCreateState(); noise.noise_type = FNL_NOISE_OPENSIMPLEX2; - - PseudoRandom random; + noise.seed = seed * 60617077 % 25896307; + PseudoRandom randomtree; float heights[CHUNK_VOL]; @@ -102,34 +113,41 @@ void WorldGenerator::generate(voxel* voxels, int cx, int cy, int cz){ } for (int z = 0; z < CHUNK_D; z++){ + int real_z = z + cz * CHUNK_D; for (int x = 0; x < CHUNK_W; x++){ int real_x = x + cx * CHUNK_W; - int real_z = z + cz * CHUNK_D; float height = heights[z*CHUNK_W+x]; for (int y = 0; y < CHUNK_H; y++){ - int real_y = y + cy * CHUNK_H; - int id = real_y < 55 ? 9 : 0; - if (real_y == (int)height) - id = 2; - else if (real_y < height){ - if (real_y < height-6) - id = 8; - else - id = 1; + int real_y = y; + int id = real_y < 55 ? BLOCK_WATER : BLOCK_AIR; + if ((real_y == (int)height) && (54 < real_y)) { + id = BLOCK_GRASS_BLOCK; + } else if (real_y < (height - 6)){ + id = BLOCK_STONE; + } else if (real_y < height){ + id = BLOCK_DIRT; } else { - int tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 16); - if (tree) + int tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 16); + if (tree) { id = tree; - else if ((tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 19))){ + } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 19))){ id = tree; - }else if ((tree = generate_tree(&noise, &random, heights, real_x, real_y, real_z, 23))){ + } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 23))){ id = tree; } } - + if ( ((height - (1.5 - 0.2 * pow(height - 54, 4))) < real_y) && (real_y < height)){ + id = BLOCK_SAND; + } if (real_y <= 2) - id = 2; + id = BLOCK_BEDROCK; + if ((id == 0) && (real_y > 55) && ((int)height + 1 == real_y) && ((unsigned short)random() > 56000)){ + id = BLOCK_GRASS; + } + if ((id == 0) && (real_y > 55) && ((int)height + 1 == real_y) && ((unsigned short)random() > 64000)){ + id = BLOCK_FLOWER; + } voxels[(y * CHUNK_D + z) * CHUNK_W + x].id = id; } } diff --git a/src/voxels/WorldGenerator.h b/src/voxels/WorldGenerator.h index c04dbd31..0b910441 100644 --- a/src/voxels/WorldGenerator.h +++ b/src/voxels/WorldGenerator.h @@ -5,7 +5,7 @@ class voxel; class WorldGenerator { public: - static void generate(voxel* voxels, int x, int y, int z); + static void generate(voxel* voxels, int x, int z, int seed); }; #endif /* VOXELS_WORLDGENERATOR_H_ */ diff --git a/src/window/Camera.cpp b/src/window/Camera.cpp index 4dfcc2b7..2cebfa35 100644 --- a/src/window/Camera.cpp +++ b/src/window/Camera.cpp @@ -1,10 +1,3 @@ -/* - * Camera.cpp - * - * Created on: Feb 11, 2020 - * Author: MihailRis - */ - #include "Camera.h" #include "Window.h" @@ -36,10 +29,22 @@ void Camera::rotate(float x, float y, float z){ } mat4 Camera::getProjection(){ - float aspect = (float)Window::width / (float)Window::height; - return glm::perspective(fov*zoom, aspect, 0.05f, 1500.0f); + float aspect = this->aspect; + if (aspect == 0.0f){ + aspect = (float)Window::width / (float)Window::height; + } + if (perspective) + return glm::perspective(fov*zoom, aspect, 0.05f, 1500.0f); + else + if (flipped) + return glm::ortho(0.0f, fov*aspect, fov, 0.0f); + else + return glm::ortho(0.0f, fov*aspect, 0.0f, fov); } mat4 Camera::getView(){ - return glm::lookAt(position, position+front, up); + if (perspective) + return glm::lookAt(position, position+front, up); + else + return glm::translate(glm::mat4(1.0f), position); } diff --git a/src/window/Camera.h b/src/window/Camera.h index 91648adb..3e82bac3 100644 --- a/src/window/Camera.h +++ b/src/window/Camera.h @@ -1,10 +1,3 @@ -/* - * Camera.h - * - * Created on: Feb 11, 2020 - * Author: MihailRis - */ - #ifndef WINDOW_CAMERA_H_ #define WINDOW_CAMERA_H_ @@ -23,6 +16,9 @@ public: float fov; float zoom; mat4 rotation; + bool perspective = true; + bool flipped = false; + float aspect = 0.0f; Camera(vec3 position, float fov); void rotate(float x, float y, float z); diff --git a/src/window/Events.cpp b/src/window/Events.cpp index 18d0e0b0..13327b3b 100644 --- a/src/window/Events.cpp +++ b/src/window/Events.cpp @@ -97,7 +97,7 @@ bool Events::jclicked(int button){ return _keys[index] && _frames[index] == _current; } -void Events::toogleCursor(){ +void Events::toggleCursor(){ _cursor_locked = !_cursor_locked; Window::setCursorMode(_cursor_locked ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); } diff --git a/src/window/Events.h b/src/window/Events.h index 996d4a03..d2a92c26 100644 --- a/src/window/Events.h +++ b/src/window/Events.h @@ -27,7 +27,7 @@ public: static bool clicked(int button); static bool jclicked(int button); - static void toogleCursor(); + static void toggleCursor(); }; #endif /* WINDOW_EVENTS_H_ */ diff --git a/src/window/Window.cpp b/src/window/Window.cpp index ef6d48d8..9031edc7 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -41,6 +41,10 @@ int Window::initialize(int width, int height, const char* title){ return 0; } +void Window::viewport(int x, int y, int width, int height){ + glViewport(x, y, width, height); +} + void Window::setCursorMode(int mode){ glfwSetInputMode(window, GLFW_CURSOR, mode); } @@ -57,6 +61,10 @@ void Window::setShouldClose(bool flag){ glfwSetWindowShouldClose(window, flag); } +void Window::swapInterval(int interval){ + glfwSwapInterval(interval); +} + void Window::swapBuffers(){ glfwSwapBuffers(window); } diff --git a/src/window/Window.h b/src/window/Window.h index a0575af9..dfce56b6 100644 --- a/src/window/Window.h +++ b/src/window/Window.h @@ -11,10 +11,12 @@ public: static int initialize(int width, int height, const char* title); static void terminate(); + static void viewport(int x, int y, int width, int height); static void setCursorMode(int mode); static bool isShouldClose(); static void setShouldClose(bool flag); static void swapBuffers(); + static void swapInterval(int interval); }; #endif /* WINDOW_WINDOW_H_ */ diff --git a/src/world/Level.cpp b/src/world/Level.cpp new file mode 100644 index 00000000..d85df92e --- /dev/null +++ b/src/world/Level.cpp @@ -0,0 +1,23 @@ +#include "Level.h" +#include "../lighting/Lighting.h" +#include "../voxels/ChunksController.h" +#include "../player_control.h" + +Level::Level(World* world, Player* player, Chunks* chunks, PhysicsSolver* physics) : + world(world), + player(player), + chunks(chunks), + physics(physics) { + lighting = new Lighting(chunks); + chunksController = new ChunksController(world, chunks, lighting); + playerController = new PlayerController(this); +} + +Level::~Level(){ + delete chunks; + delete physics; + delete player; + delete lighting; + delete chunksController; + delete playerController; +} diff --git a/src/world/Level.h b/src/world/Level.h new file mode 100644 index 00000000..47728e2a --- /dev/null +++ b/src/world/Level.h @@ -0,0 +1,25 @@ +#ifndef WORLD_LEVEL_H_ +#define WORLD_LEVEL_H_ + +class World; +class Player; +class Chunks; +class Lighting; +class PhysicsSolver; +class ChunksController; +class PlayerController; + +class Level { +public: + World* world; + Player* player; + Chunks* chunks; + PhysicsSolver* physics; + Lighting* lighting; + ChunksController* chunksController; + PlayerController* playerController; + Level(World* world, Player* player, Chunks* chunks, PhysicsSolver* physics); + ~Level(); +}; + +#endif /* WORLD_LEVEL_H_ */ diff --git a/src/world/World.cpp b/src/world/World.cpp new file mode 100644 index 00000000..2e336dce --- /dev/null +++ b/src/world/World.cpp @@ -0,0 +1,13 @@ +#include "World.h" + +#include "../files/WorldFiles.h" +#include "../voxels/Chunk.h" +#include "../voxels/Chunks.h" + +World::World(std::string name, std::string directory, int seed) : name(name), seed(seed) { + wfile = new WorldFiles(directory, REGION_VOL * (CHUNK_VOL * 2 + 8)); +} + +World::~World(){ + delete wfile; +} diff --git a/src/world/World.h b/src/world/World.h new file mode 100644 index 00000000..7b51192b --- /dev/null +++ b/src/world/World.h @@ -0,0 +1,19 @@ +#ifndef WORLD_WORLD_H_ +#define WORLD_WORLD_H_ + +#include + +class WorldFiles; +class Chunks; + +class World { +public: + std::string name; + WorldFiles* wfile; + int seed; + + World(std::string name, std::string directory, int seed); + ~World(); +}; + +#endif /* WORLD_WORLD_H_ */ diff --git a/src/world_render.cpp b/src/world_render.cpp new file mode 100644 index 00000000..48209214 --- /dev/null +++ b/src/world_render.cpp @@ -0,0 +1,153 @@ +#include "world_render.h" + +#include +#include "graphics/VoxelRenderer.h" + +#include "window/Window.h" +#include "window/Camera.h" +#include "graphics/Mesh.h" +#include "graphics/Shader.h" +#include "graphics/Texture.h" +#include "graphics/LineBatch.h" +#include "graphics/Batch3D.h" +#include "voxels/Chunks.h" +#include "voxels/Chunk.h" +#include "voxels/Block.h" +#include "world/World.h" +#include "world/Level.h" +#include "objects/Player.h" +#include "Assets.h" +#include "player_control.h" + +float _camera_cx; +float _camera_cz; + +WorldRenderer::WorldRenderer(Level* level, Assets* assets) : assets(assets), level(level) { + lineBatch = new LineBatch(4096); + batch3d = new Batch3D(1024); + renderer = new VoxelRenderer(); +} + +WorldRenderer::~WorldRenderer() { + delete batch3d; + delete lineBatch; + delete renderer; +} + +Chunks* _chunks = nullptr; + +bool chunks_distance_compare(size_t i, size_t j) { + Chunk* a = _chunks->chunks[i]; + Chunk* b = _chunks->chunks[j]; + return ((a->x + 0.5f - _camera_cx)*(a->x + 0.5f - _camera_cx) + (a->z + 0.5f - _camera_cz)*(a->z + 0.5f - _camera_cz) > + (b->x + 0.5f - _camera_cx)*(b->x + 0.5f - _camera_cx) + (b->z + 0.5f - _camera_cz)*(b->z + 0.5f - _camera_cz)); +} + +bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion){ + Chunk* chunk = level->chunks->chunks[index]; + Mesh* mesh = level->chunks->meshes[index]; + if (mesh == nullptr) + return false; + + // Simple frustum culling + if (occlusion){ + float y = camera->position.y+camera->front.y * CHUNK_H * 0.5f; + if (y < 0.0f) + y = 0.0f; + if (y > CHUNK_H) + y = CHUNK_H; + vec3 v = vec3(chunk->x*CHUNK_W, y, chunk->z*CHUNK_D)-camera->position; + if (v.x*v.x+v.z*v.z > (CHUNK_W*3)*(CHUNK_W*3)) { + if (dot(camera->front, v) < 0.0f){ + return true; + } + } + } + + mat4 model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W+0.5f, 0.5f, chunk->z*CHUNK_D+0.5f)); + shader->uniformMatrix("u_model", model); + mesh->draw(GL_TRIANGLES); + return false; +} + + +void WorldRenderer::draw(World* world, Camera* camera, bool occlusion){ + Chunks* chunks = level->chunks; + + vec4 skyColor(0.7f, 0.81f, 1.0f, 1.0f); + glClearColor(skyColor.r, skyColor.g, skyColor.b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + Window::viewport(0, 0, Window::width, Window::height); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + + Texture* texture = assets->getTexture("block"); + Shader* shader = assets->getShader("main"); + Shader* linesShader = assets->getShader("lines"); + shader->use(); + shader->uniformMatrix("u_proj", camera->getProjection()); + shader->uniformMatrix("u_view", camera->getView()); + shader->uniform1f("u_gamma", 1.6f); + shader->uniform3f("u_skyLightColor", 1.1f,1.1f,1.1f); + shader->uniform3f("u_fogColor", skyColor.r,skyColor.g,skyColor.b); + shader->uniform1f("u_fogFactor", 0.025f); + shader->uniform3f("u_cameraPos", camera->position.x,camera->position.y,camera->position.z); + + Block* cblock = Block::blocks[level->player->choosenBlock]; + shader->uniform3f("u_torchlightColor", + cblock->emission[0] / 15.0f, + cblock->emission[1] / 15.0f, + cblock->emission[2] / 15.0f); + shader->uniform1f("u_torchlightDistance", 6.0f); + shader->uniform1f("u_fogFactor", 0.025f); + texture->bind(); + + std::vector indices; + + for (size_t i = 0; i < chunks->volume; i++){ + Chunk* chunk = chunks->chunks[i]; + if (chunk == nullptr) + continue; + if (chunks->meshes[i] != nullptr) + indices.push_back(i); + } + + float px = camera->position.x / (float)CHUNK_W; + float pz = camera->position.z / (float)CHUNK_D; + + _camera_cx = px; + _camera_cz = pz; + _chunks = chunks; + std::sort(indices.begin(), indices.end(), chunks_distance_compare); + + + int occludedChunks = 0; + for (size_t i = 0; i < indices.size(); i++){ + occludedChunks += drawChunk(indices[i], camera, shader, occlusion); + } + + shader->uniformMatrix("u_model", mat4(1.0f)); + batch3d->begin(); + // draw 3D stuff here + batch3d->render(); + + linesShader->use(); + linesShader->uniformMatrix("u_projview", camera->getProjection()*camera->getView()); + glLineWidth(2.0f); + lineBatch->line(camera->position.x, camera->position.y-0.1f, camera->position.z, camera->position.x+0.01f, camera->position.y-0.1f, camera->position.z, 1, 0, 0, 1); + lineBatch->line(camera->position.x, camera->position.y-0.1f, camera->position.z, camera->position.x, camera->position.y-0.1f, camera->position.z+0.01f, 0, 0, 1, 1); + lineBatch->line(camera->position.x, camera->position.y-0.1f, camera->position.z, camera->position.x, camera->position.y-0.1f+0.01f, camera->position.z, 0, 1, 0, 1); + lineBatch->render(); + + if (level->playerController->selectedBlockId != -1){ + Block* selectedBlock = Block::blocks[level->playerController->selectedBlockId]; + vec3 pos = level->playerController->selectedBlockPosition; + if (selectedBlock->model == 1){ + lineBatch->box(pos.x+0.5f, pos.y+0.5f, pos.z+0.5f, 1.005f,1.005f,1.005f, 0,0,0,0.5f); + } else if (selectedBlock->model == 2){ + lineBatch->box(pos.x+0.4f, pos.y+0.3f, pos.z+0.4f, 0.805f,0.805f,0.805f, 0,0,0,0.5f); + } + } +} diff --git a/src/world_render.h b/src/world_render.h index d2909d9a..d237ed29 100644 --- a/src/world_render.h +++ b/src/world_render.h @@ -5,152 +5,40 @@ #include #include +#ifndef std::string +#include +#endif + #include #include #include -#include "window/Window.h" -#include "window/Camera.h" -#include "graphics/Mesh.h" -#include "graphics/Shader.h" -#include "graphics/Texture.h" -#include "graphics/LineBatch.h" -#include "voxels/Chunks.h" -#include "voxels/Chunk.h" +class World; +class Level; +class Camera; +class Assets; +class LineBatch; +class Batch3D; +class VoxelRenderer; +class Shader; +class Texture; +class Framebuffer; -float _camera_cx; -float _camera_cz; -Chunks* _chunks; -Mesh *crosshair; +class WorldRenderer { + Batch3D *batch3d; + Assets* assets; + Level* level; + bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion); +public: + VoxelRenderer *renderer; + LineBatch *lineBatch; -float vertices[] = { - // x y - -0.01f,-0.01f, - 0.01f, 0.01f, + WorldRenderer(Level* level, Assets* assets); + ~WorldRenderer(); - -0.01f, 0.01f, - 0.01f,-0.01f, + void draw(World* world, Camera* camera, bool occlusion); }; -int attrs[] = { - 2, 0 //null terminator -}; - -LineBatch *lineBatch; - -void init_renderer(){ - crosshair = new Mesh(vertices, 4, attrs); - lineBatch = new LineBatch(4096); -} - - -void finalize_renderer(){ - delete crosshair; - delete lineBatch; -} - -void draw_chunk(size_t index, Camera* camera, Shader* shader, bool occlusion){ - Chunk* chunk = _chunks->chunks[index]; - Mesh* mesh = _chunks->meshes[index]; - if (mesh == nullptr) - return; - - // Simple frustum culling (culling chunks behind the camera in 2D - XZ) - if (occlusion){ - const float cameraX = camera->position.x; - const float cameraZ = camera->position.z; - const float camDirX = camera->dir.x; - const float camDirZ = camera->dir.z; - - bool unoccluded = false; - do { - if ((chunk->x*CHUNK_W-cameraX)*camDirX + (chunk->z*CHUNK_D-cameraZ)*camDirZ >= 0.0){ - unoccluded = true; break; - } - if (((chunk->x+1)*CHUNK_W-cameraX)*camDirX + (chunk->z*CHUNK_D-cameraZ)*camDirZ >= 0.0){ - unoccluded = true; break; - } - if (((chunk->x+1)*CHUNK_W-cameraX)*camDirX + ((chunk->z+1)*CHUNK_D-cameraZ)*camDirZ >= 0.0){ - unoccluded = true; break; - } - if ((chunk->x*CHUNK_W-cameraX)*camDirX + ((chunk->z+1)*CHUNK_D-cameraZ)*camDirZ >= 0.0){ - unoccluded = true; break; - } - } while (false); - if (!unoccluded) - return; - } - - mat4 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("u_model", model); - mesh->draw(GL_TRIANGLES); -} - -bool chunks_comparator(size_t i, size_t j) { - Chunk* a = _chunks->chunks[i]; - Chunk* b = _chunks->chunks[j]; - return ((a->x + 0.5f - _camera_cx)*(a->x + 0.5f - _camera_cx) + (a->z + 0.5f - _camera_cz)*(a->z + 0.5f - _camera_cz) - > - (b->x + 0.5f - _camera_cx)*(b->x + 0.5f - _camera_cx) + (b->z + 0.5f - _camera_cz)*(b->z + 0.5f - _camera_cz)); -} - - -void draw_world(Camera* camera, Assets* assets, - Chunks* chunks, bool occlusion){ - glClearColor(0.7f,0.71f,0.73f,1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - _chunks = chunks; - - // Draw VAO - Texture* texture = assets->getTexture("block"); - Shader* shader = assets->getShader("main"); - Shader* crosshairShader = assets->getShader("crosshair"); - Shader* linesShader = assets->getShader("lines"); - shader->use(); - shader->uniformMatrix("u_proj", camera->getProjection()); - shader->uniformMatrix("u_view", camera->getView()); - shader->uniform1f("u_gamma", 1.6f); - shader->uniform3f("u_skyLightColor", 1.8f,1.8f,1.8f); - shader->uniform3f("u_fogColor", 0.7f,0.71f,0.73f); - shader->uniform3f("u_cameraPos", camera->position.x,camera->position.y,camera->position.z); - texture->bind(); - - std::vector indices; - - for (size_t i = 0; i < chunks->volume; i++){ - Chunk* chunk = chunks->chunks[i]; - if (chunk == nullptr) - continue; - if (chunks->meshes[i] != nullptr) - indices.push_back(i); - } - - float px = camera->position.x / (float)CHUNK_W; - float pz = camera->position.z / (float)CHUNK_D; - - _camera_cx = px; - _camera_cz = pz; - - std::sort(indices.begin(), indices.end(), chunks_comparator); - - - for (size_t i = 0; i < indices.size(); i++){ - draw_chunk(indices[i], camera, shader, occlusion); - } - - crosshairShader->use(); - crosshairShader->uniform1f("u_ar", (float)Window::height / (float)Window::width); - crosshairShader->uniform1f("u_scale", 1.0f / ((float)Window::height / 1000.0f)); - crosshair->draw(GL_LINES); - - linesShader->use(); - linesShader->uniformMatrix("u_projview", camera->getProjection()*camera->getView()); - glLineWidth(2.0f); - lineBatch->line(camera->position.x, camera->position.y-0.5f, camera->position.z, camera->position.x+0.1f, camera->position.y-0.5f, camera->position.z, 1, 0, 0, 1); - lineBatch->line(camera->position.x, camera->position.y-0.5f, camera->position.z, camera->position.x, camera->position.y-0.5f, camera->position.z+0.1f, 0, 0, 1, 1); - lineBatch->render(); -} #endif // WORLD_RENDERER_CPP