Merge pull request #9 from MihailRis/v12

V12
This commit is contained in:
MihailRis 2023-01-26 23:07:29 +03:00 committed by GitHub
commit d535c74f6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 3356 additions and 1176 deletions

2
.gitignore vendored
View File

@ -10,3 +10,5 @@ world
.settings
.cproject
.project
.git
/Default/

View File

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

View File

@ -4,5 +4,5 @@
USER_OBJS :=
LIBS := -lglfw -lpng -lGL -lGLEW -lstdc++fs
LIBS := -lglfw -lpng -lGL -lGLEW -lstdc++fs -lopenal

1
Debug/res Symbolic link
View File

@ -0,0 +1 @@
../res

View File

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

27
Debug/src/audio/subdir.mk Normal file
View File

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

View File

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

View File

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

27
Debug/src/world/subdir.mk Normal file
View File

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

View File

@ -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)<br>
[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 <mingw.thread.h>` get headers `mingw.thread.h` and `mingw.invoke.h` from:
https://github.com/meganz/mingw-std-threads

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
res/font_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
res/font_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
res/font_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
res/font_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
res/font_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 793 B

View File

@ -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;
}

View File

@ -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;
}

BIN
res/slot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 KiB

11
res/ui.glslf Normal file
View File

@ -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);
}

16
res/ui.glslv Normal file
View File

@ -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);
}

View File

@ -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;
}

View File

@ -6,10 +6,12 @@
class Texture;
class Shader;
class Font;
class Assets {
std::unordered_map<std::string, Texture*> textures;
std::unordered_map<std::string, Shader*> shaders;
std::unordered_map<std::string, Font*> 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_ */

188
src/audio/Audio.cpp Normal file
View File

@ -0,0 +1,188 @@
#include "Audio.h"
#include "audioutil.h"
#include <string>
#include <iostream>
#include <AL/al.h>
#include <AL/alc.h>
ALCdevice* Audio::device;
ALCcontext* Audio::context;
unsigned Audio::maxSources;
unsigned Audio::maxBuffers = 1024;
std::vector<ALSource*> Audio::allsources;
std::vector<ALSource*> Audio::freesources;
std::vector<ALBuffer*> Audio::allbuffers;
std::vector<ALBuffer*> 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<ALCint> attrs(size);
alcGetIntegerv(device, ALC_ALL_ATTRIBUTES, size, &attrs[0]);
for(size_t i=0; i<attrs.size(); ++i){
if (attrs[i] == ALC_MONO_SOURCES){
std::cout << "max mono sources: " << attrs[i+1] << std::endl;
maxSources = attrs[i+1];
}
}
return true;
}
void Audio::finalize(){
for (ALSource* source : allsources){
if (source->isPlaying()){
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<std::string>& 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();
}

62
src/audio/Audio.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef SRC_AUDIO_AUDIO_H_
#define SRC_AUDIO_AUDIO_H_
#include <vector>
#include <string>
#include <AL/al.h>
#include <AL/alc.h>
#include <glm/glm.hpp>
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<ALSource*> allsources;
static std::vector<ALSource*> freesources;
static std::vector<ALBuffer*> allbuffers;
static std::vector<ALBuffer*> 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<std::string>& devicesVec);
static void setListener(glm::vec3 position, glm::vec3 velocity, glm::vec3 at, glm::vec3 up);
};
#endif /* SRC_AUDIO_AUDIO_H_ */

194
src/audio/audioutil.cpp Normal file
View File

@ -0,0 +1,194 @@
#include "audioutil.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <type_traits>
#include <AL/al.h>
#include <AL/alc.h>
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<char*>(&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;
}

44
src/audio/audioutil.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef SRC_AUDIO_AUDIOUTIL_H_
#define SRC_AUDIO_AUDIOUTIL_H_
#include <string>
#include <type_traits>
#include <AL/al.h>
#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_ */

154
src/declarations.cpp Normal file
View File

@ -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<Texture*> 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;
}

View File

@ -2,113 +2,29 @@
#define DECLARATIONS_H
#include <iostream>
#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

View File

@ -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<long, char**>::iterator it;
std::unordered_map<long, WorldRegion>::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<long, char**>::iterator it;
std::unordered_map<long, WorldRegion>::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;

View File

@ -3,27 +3,29 @@
#include <map>
#include <unordered_map>
#ifndef std::string
#include <string>
#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<long, char**> regions;
std::unordered_map<long, WorldRegion> 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);

View File

@ -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;
}

View File

@ -1,7 +1,9 @@
#ifndef FILES_FILES_H_
#define FILES_FILES_H_
#ifndef std::string
#include <string>
#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);

View File

@ -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 <GL/glew.h>
#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;
}

View File

@ -4,23 +4,53 @@
#include <stdlib.h>
#include <glm/glm.hpp>
#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();
};

165
src/graphics/Batch3D.cpp Normal file
View File

@ -0,0 +1,165 @@
#include "Batch3D.h"
#include "Mesh.h"
#include "Texture.h"
#include <GL/glew.h>
#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;
}

40
src/graphics/Batch3D.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef GRAPHICS_BATCH3D_H_
#define GRAPHICS_BATCH3D_H_
#include <stdlib.h>
#include <glm/glm.hpp>
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_ */

90
src/graphics/Font.cpp Normal file
View File

@ -0,0 +1,90 @@
#include "Font.h"
#include "Texture.h"
#include "Batch2D.h"
Font::Font(std::vector<Texture*> 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);
}

26
src/graphics/Font.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef GRAPHICS_FONT_H_
#define GRAPHICS_FONT_H_
#include <string>
#include <vector>
class Texture;
class Batch2D;
#define STYLE_NONE 0
#define STYLE_SHADOW 1
#define STYLE_OUTLINE 2
class Font {
public:
std::vector<Texture*> pages;
Font(std::vector<Texture*> 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_ */

View File

@ -0,0 +1,37 @@
#include "Framebuffer.h"
#include <GL/glew.h>
#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);
}

View File

@ -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_ */

17
src/graphics/Sprite.cpp Normal file
View File

@ -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() {
}

29
src/graphics/Sprite.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef SRC_GRAPHICS_SPRITE_H_
#define SRC_GRAPHICS_SPRITE_H_
#include <glm/glm.hpp>
#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_ */

View File

@ -0,0 +1 @@
#include "UVRegion.h"

17
src/graphics/UVRegion.h Normal file
View File

@ -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_ */

View File

@ -1,32 +1,33 @@
#include "VoxelRenderer.h"
#include <iostream>
#include <math.h>
#include "Mesh.h"
#include "../voxels/Chunk.h"
#include "../voxels/voxel.h"
#include "../voxels/Block.h"
#include "../lighting/Lightmap.h"
#define VERTEX_SIZE (3 + 2 + 4)
#define CDIV(X,A) (((X) < 0) ? ((X) / (A) - 1) : ((X) / (A)))
#define LOCAL_NEG(X, SIZE) (((X) < 0) ? ((SIZE)+(X)) : (X))
#define LOCAL(X, SIZE) ((X) >= (SIZE) ? ((X) - (SIZE)) : LOCAL_NEG(X, SIZE))
#define IS_CHUNK(X,Y,Z) (GET_CHUNK(X,Y,Z) != nullptr)
#define GET_CHUNK(X,Y,Z) (chunks[((CDIV(Y, CHUNK_H)+1) * 3 + CDIV(Z, CHUNK_D) + 1) * 3 + CDIV(X, CHUNK_W) + 1])
#define 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<float>& 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<float>& 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<float>& 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];
}

View File

@ -2,18 +2,21 @@
#define GRAPHICS_VOXELRENDERER_H_
#include <stdlib.h>
#include <vector>
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<float> 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_ */

140
src/hud_render.cpp Normal file
View File

@ -0,0 +1,140 @@
#include "hud_render.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#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);
}

21
src/hud_render.h Normal file
View File

@ -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_ */

View File

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

View File

@ -6,6 +6,8 @@
#include "../voxels/voxel.h"
#include "../voxels/Block.h"
#include <iostream>
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();

View File

@ -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);
};

View File

@ -6,6 +6,7 @@
class Lightmap {
public:
unsigned short* map;
int highestPoint = 0;
Lightmap();
~Lightmap();

View File

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

View File

@ -1,5 +1,8 @@
#include "Player.h"
#include "../physics/Hitbox.h"
#include "../physics/PhysicsSolver.h"
#include "../voxels/Chunks.h"
#include "../window/Events.h"
#include <glm/glm.hpp>

View File

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

View File

@ -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;
}
}
}
}

View File

@ -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);
};

211
src/player_control.cpp Normal file
View File

@ -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 <GLFW/glfw3.h>
#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;
}
}

21
src/player_control.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef PLAYER_CONTROL_H_
#define PLAYER_CONTROL_H_
#include <glm/glm.hpp>
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_ */

View File

@ -2,6 +2,7 @@
// sudo apt install libgl-dev libglew-dev libglfw3-dev libpng-dev libglm-dev
#include <iostream>
#include <cmath>
#include <stdint.h>
#define GLEW_STATIC
#include <GL/glew.h>
@ -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;
}

View File

@ -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);
};

View File

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

View File

@ -1,25 +1,42 @@
#ifndef VOXELS_CHUNK_H_
#define VOXELS_CHUNK_H_
#include <stdlib.h>
#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_ */

View File

@ -11,8 +11,8 @@
#include <math.h>
#include <limits.h>
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;
}

View File

@ -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);
};

View File

@ -8,6 +8,7 @@
#include "../files/WorldFiles.h"
#include "ChunksLoader.h"
#include <iostream>
#include <limits.h>
#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;

View File

@ -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);
};

View File

@ -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 <iostream>
#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);
}

View File

@ -11,20 +11,28 @@
#include <atomic>
class Chunk;
class World;
enum LoaderMode {
OFF, IDLE, LOAD, LIGHTS, RENDER,
};
class ChunksLoader final {
private:
std::thread loaderThread;
void _thread();
std::atomic<Chunk*> current {nullptr};
std::atomic<Chunk**> closes {nullptr};
std::atomic<bool> working {true};
std::atomic<Chunk**> surroundings {nullptr};
std::atomic<LoaderMode> 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;
}
};

View File

@ -2,6 +2,7 @@
#include "voxel.h"
#include "Chunk.h"
#include <iostream>
#include <math.h>
#include <glm/glm.hpp>
#include <glm/gtc/noise.hpp>
@ -9,54 +10,64 @@
#include "../maths/FastNoiseLite.h"
#include <time.h>
#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 <iostream>
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;
}
}

View File

@ -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_ */

View File

@ -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);
}

View File

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

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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);
}

View File

@ -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_ */

23
src/world/Level.cpp Normal file
View File

@ -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;
}

25
src/world/Level.h Normal file
View File

@ -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_ */

13
src/world/World.cpp Normal file
View File

@ -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;
}

19
src/world/World.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef WORLD_WORLD_H_
#define WORLD_WORLD_H_
#include <string>
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_ */

153
src/world_render.cpp Normal file
View File

@ -0,0 +1,153 @@
#include "world_render.h"
#include <iostream>
#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<size_t> 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);
}
}
}

View File

@ -5,152 +5,40 @@
#include <algorithm>
#include <GL/glew.h>
#ifndef std::string
#include <string>
#endif
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>
#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<size_t> 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