#include "RendererSection.hpp"
#include <thread>
const GLfloat vertices[] = {
0, 0, 0,
1, 0, 1,
1, 0, 0,
0, 0, 0,
0, 0, 1,
1, 0, 1,
};
const GLfloat uv_coords[] = {
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
};
const GLuint magicUniqueConstant = 88375;
GLuint RendererSection::VboVertices = magicUniqueConstant;
GLuint RendererSection::VboUvs = magicUniqueConstant;
RendererSection::RendererSection(RendererSectionData data) {
if (VboVertices == magicUniqueConstant) {
glGenBuffers(1, &VboVertices);
glGenBuffers(1, &VboUvs);
//Cube vertices
glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//Cube UVs
glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
glBufferData(GL_ARRAY_BUFFER, sizeof(uv_coords), uv_coords, GL_STATIC_DRAW);
LOG(INFO) << "Created VBOs with vertices (" << VboVertices << ") and UVs (" << VboUvs
<< ") for faces";
}
glGenVertexArrays(1, &Vao);
glGenBuffers(VBOCOUNT, Vbo);
glBindVertexArray(Vao);
{
//Cube vertices
GLuint VertAttribPos = 0;
glBindBuffer(GL_ARRAY_BUFFER, VboVertices);
glVertexAttribPointer(VertAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(VertAttribPos);
//Cube UVs
GLuint UvAttribPos = 2;
glBindBuffer(GL_ARRAY_BUFFER, VboUvs);
glVertexAttribPointer(UvAttribPos, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(UvAttribPos);
//Textures
GLuint textureAttribPos = 7;
glBindBuffer(GL_ARRAY_BUFFER, Vbo[TEXTURES]);
glVertexAttribPointer(textureAttribPos, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(textureAttribPos);
glVertexAttribDivisor(textureAttribPos, 1);
glCheckError();
//Blocks models
GLuint matAttribPos = 8;
size_t sizeOfMat4 = 4 * 4 * sizeof(GLfloat);
glBindBuffer(GL_ARRAY_BUFFER, Vbo[MODELS]);
glVertexAttribPointer(matAttribPos + 0, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, nullptr);
glVertexAttribPointer(matAttribPos + 1, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *)(1 * 4 * sizeof(GLfloat)));
glVertexAttribPointer(matAttribPos + 2, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *)(2 * 4 * sizeof(GLfloat)));
glVertexAttribPointer(matAttribPos + 3, 4, GL_FLOAT, GL_FALSE, sizeOfMat4, (void *)(3 * 4 * sizeof(GLfloat)));
glEnableVertexAttribArray(matAttribPos + 0);
glEnableVertexAttribArray(matAttribPos + 1);
glEnableVertexAttribArray(matAttribPos + 2);
glEnableVertexAttribArray(matAttribPos + 3);
glVertexAttribDivisor(matAttribPos + 0, 1);
glVertexAttribDivisor(matAttribPos + 1, 1);
glVertexAttribDivisor(matAttribPos + 2, 1);
glVertexAttribDivisor(matAttribPos + 3, 1);
//Color
GLuint colorAttribPos = 12;
glBindBuffer(GL_ARRAY_BUFFER, Vbo[COLORS]);
glVertexAttribPointer(colorAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(colorAttribPos);
glVertexAttribDivisor(colorAttribPos, 1);
//Light
GLuint lightAttribPos = 13;
glBindBuffer(GL_ARRAY_BUFFER, Vbo[LIGHTS]);
glVertexAttribPointer(lightAttribPos, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(lightAttribPos);
glVertexAttribDivisor(lightAttribPos, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
glCheckError();
//Upload data to VRAM
glBindBuffer(GL_ARRAY_BUFFER, Vbo[TEXTURES]);
glBufferData(GL_ARRAY_BUFFER, data.textures.size() * sizeof(glm::vec4), data.textures.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, Vbo[MODELS]);
glBufferData(GL_ARRAY_BUFFER, data.models.size() * sizeof(glm::mat4), data.models.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, Vbo[COLORS]);
glBufferData(GL_ARRAY_BUFFER, data.colors.size() * sizeof(glm::vec3), data.colors.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, Vbo[LIGHTS]);
glBufferData(GL_ARRAY_BUFFER, data.lights.size() * sizeof(glm::vec2), data.lights.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
numOfFaces = data.textures.size();
sectionPos = data.sectionPos;
hash = data.hash;
}
RendererSection::RendererSection(RendererSection && other) {
using std::swap;
swap(*this, other);
}
RendererSection::~RendererSection() {
if (Vao != 0)
glDeleteVertexArrays(1, &Vao);
for (int i = 0; i < VBOCOUNT; i++)
if (Vbo[i] != 0) {
glBindBuffer(GL_ARRAY_BUFFER, Vbo[i]);
glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STATIC_DRAW);
}
glDeleteBuffers(VBOCOUNT, Vbo);
}
void swap(RendererSection & lhs, RendererSection & rhs) {
std::swap(lhs.Vbo, rhs.Vbo);
std::swap(lhs.Vao, rhs.Vao);
std::swap(lhs.hash, rhs.hash);
std::swap(lhs.numOfFaces, rhs.numOfFaces);
std::swap(lhs.sectionPos, rhs.sectionPos);
}
void RendererSection::Render(RenderState &renderState) {
renderState.SetActiveVao(Vao);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces);
glCheckError();
}
Vector RendererSection::GetPosition()
{
return sectionPos;
}
size_t RendererSection::GetHash()
{
return hash;
}
RendererSectionData::RendererSectionData(World * world, Vector sectionPosition) {
const std::map<BlockTextureId, glm::vec4> &textureAtlas = AssetManager::Instance().GetTextureAtlasIndexes();
if (!world->GetSection(sectionPosition))
return;
const Section §ion = *world->GetSection(sectionPosition);
hash = section.GetHash();
sectionPos = sectionPosition;
glm::mat4 baseOffset = glm::translate(glm::mat4(), (section.GetPosition() * 16).glm()),transform;
auto sectionsList = world->GetSectionsList();
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
BlockId block = section.GetBlockId(Vector(x, y, z));
if (block.id == 0)
continue;
/*transform = glm::translate(baseOffset, Vector(x, y, z).glm());
const BlockModel* model = AssetManager::Instance().GetBlockModelByBlockId(block);
if (model ) {
this->AddFacesByBlockModel(world, Vector(x,y,z), *model, transform, section.GetBlockLight(Vector(x,y,z)),section.GetBlockSkyLight(Vector(x,y,z)));
} else {
transform = glm::translate(transform, glm::vec3(0, 1, 0));
models.push_back(transform);
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690, 0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(glm::vec3(0, 0, 0));
lights.push_back(glm::vec2(16, 16));
}*/
auto testBlockNonExist = [&](Vector block) -> bool {
Vector offset;
if (block.x == -1) {
offset = Vector(-1, 0, 0);
block.x = 15;
} else if (block.x == 16) {
offset = Vector(1, 0, 0);
block.x = 0;
} else if (block.y == -1) {
offset = Vector(0, -1, 0);
block.y = 15;
} else if (block.y == 16) {
offset = Vector(0, 1, 0);
block.y = 0;
} else if (block.z == -1) {
offset = Vector(0, 0, -1);
block.z = 15;
} else if (block.z == 16) {
offset = Vector(0, 0, 1);
block.z = 0;
}
if (offset != Vector(0, 0, 0)) {
if (std::find(sectionsList.begin(), sectionsList.end(), sectionPosition + offset) == sectionsList.end())
return true;
const Section& blockSection = *world->GetSection(sectionPosition + offset);
return blockSection.GetBlockId(block).id == 0 || blockSection.GetBlockId(block).id == 31 || blockSection.GetBlockId(block).id == 18;
}
return section.GetBlockId(block).id == 0 || section.GetBlockId(block).id == 31 || section.GetBlockId(block).id == 18;
};
unsigned char isVisible = 0;
isVisible |= testBlockNonExist(Vector(x - 1, y, z)) << 0;
isVisible |= testBlockNonExist(Vector(x + 1, y, z)) << 1;
isVisible |= testBlockNonExist(Vector(x, y + 1, z)) << 2;
isVisible |= testBlockNonExist(Vector(x, y - 1, z)) << 3;
isVisible |= testBlockNonExist(Vector(x, y, z - 1)) << 4;
isVisible |= testBlockNonExist(Vector(x, y, z + 1)) << 5;
if (isVisible == 0x00)
continue;
glm::mat4 transform;
transform = glm::translate(transform, glm::vec3(sectionPosition * 16u));
transform = glm::translate(transform, glm::vec3(x, y, z));
glm::vec3 biomeColor(0.275, 0.63, 0.1);
glm::vec3 color(0.0f, 0.0f, 0.0f);
if (block.id == 31 || block.id == 18)
color = biomeColor;
if (block.id == 31) { //X-cross like blocks rendering
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
for (int i = 0; i < 4; i++) {
textures.push_back(texture->second);
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0.15f, 0, 0.15f));
faceTransform = glm::scale(faceTransform, glm::vec3(1.0f, 0.9f, 1.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(45.0f), glm::vec3(1.0f, 0.0f, 0));
for (int i = 0; i < 4; i++) {
models.push_back(faceTransform);
faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, 0.5f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0.0f, 0.0f, -0.5f));
}
continue;
}
if (isVisible >> 0 & 0x1) { //east side of block (X+)
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 2));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
if (isVisible >> 1 & 0x1) { //west side X-
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
if (isVisible >> 2 & 0x1) { //Top side Y+
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 1, 0));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 1));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
if (block.id != 2)
colors.push_back(color);
else
colors.push_back(biomeColor);
lights.push_back(glm::vec2(0, 0));
}
if (isVisible >> 3 & 0x1) { //Bottom side Y-
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0, 0));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 0));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
if (isVisible >> 4 & 0x1) { //south side Z+
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(1, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 3));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
if (isVisible >> 5 & 0x1) { //north side Z-
glm::mat4 faceTransform = glm::translate(transform, glm::vec3(0, 0, 1));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1, 0, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1.0f));
models.push_back(faceTransform);
auto texture = textureAtlas.find(BlockTextureId(block.id, block.state, 4));
if (texture != textureAtlas.end())
textures.push_back(texture->second);
else
textures.push_back(glm::vec4(0.0546875, 0.00442477876106194690,
0.0078125, 0.00442477876106194690)); //Fallback TNT texture
colors.push_back(color);
lights.push_back(glm::vec2(0, 0));
}
}
}
}
textures.shrink_to_fit();
models.shrink_to_fit();
colors.shrink_to_fit();
}
void RendererSectionData::AddFacesByBlockModel(World *world, Vector blockPos, const BlockModel &model, glm::mat4 transform, unsigned char light, unsigned char skyLight) {
glm::mat4 elementTransform, faceTransform;
for (const auto& element : model.Elements) {
VectorF elementSize(VectorF(element.to - element.from) / 16.0f);
VectorF elementOrigin(VectorF(element.from) / 16.0f);
elementTransform = glm::translate(transform, elementOrigin.glm());
elementTransform = glm::scale(elementTransform, elementSize.glm());
for (const auto& face : element.faces) {
if (face.second.cullface != BlockModel::ElementData::FaceDirection::none) {
switch (face.second.cullface) {
case BlockModel::ElementData::FaceDirection::down:
if (TestBlockExists(world, blockPos - Vector(0, -1, 0)))
continue;
break;
case BlockModel::ElementData::FaceDirection::up:
if (TestBlockExists(world, blockPos - Vector(0, +1, 0)))
continue;
break;
case BlockModel::ElementData::FaceDirection::north:
if (TestBlockExists(world, blockPos - Vector(0, 0, -1)))
continue;
break;
case BlockModel::ElementData::FaceDirection::south:
if (TestBlockExists(world, blockPos - Vector(0, 0, +1)))
continue;
break;
case BlockModel::ElementData::FaceDirection::west:
if (TestBlockExists(world, blockPos - Vector(-1, 0, 0)))
continue;
break;
case BlockModel::ElementData::FaceDirection::east:
if (TestBlockExists(world, blockPos - Vector(+1, 0, 0)))
continue;
break;
}
}
switch (face.first) {
case BlockModel::ElementData::FaceDirection::down:
faceTransform = glm::translate(elementTransform, glm::vec3(0, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0, 0));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
break;
case BlockModel::ElementData::FaceDirection::up:
faceTransform = glm::translate(elementTransform, glm::vec3(0.0f, 1.0f, 0.0f));
break;
case BlockModel::ElementData::FaceDirection::north:
faceTransform = glm::translate(elementTransform, glm::vec3(0, 0, 1));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1, 0, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1.0f));
break;
case BlockModel::ElementData::FaceDirection::south:
faceTransform = glm::translate(elementTransform, glm::vec3(1, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(-1.0f, 0.0f, 0.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0.0f, -1.0f, 0.0f));
break;
case BlockModel::ElementData::FaceDirection::west:
faceTransform = glm::translate(elementTransform, glm::vec3(1, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
faceTransform = glm::rotate(faceTransform, glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f));
faceTransform = glm::translate(faceTransform, glm::vec3(0, 0, -1));
break;
case BlockModel::ElementData::FaceDirection::east:
faceTransform = glm::translate(elementTransform, glm::vec3(0, 0, 0));
faceTransform = glm::rotate(faceTransform, glm::radians(90.0f), glm::vec3(0, 0.0f, 1.0f));
break;
}
models.push_back(faceTransform);
std::string textureName = face.second.texture;
while (textureName[0] == '#') {
textureName = model.Textures.find(std::string(textureName.begin()+1,textureName.end()))->second;
}
glm::vec4 texture = AssetManager::Instance().GetTextureByAssetName("minecraft/textures/" + textureName);
textures.push_back(texture);
colors.push_back(glm::vec3(0, 0, 0));
lights.push_back(glm::vec2(light, skyLight));
}
}
}
bool RendererSectionData::TestBlockExists(World *world, Vector blockPos) {
Vector section = sectionPos;
if (blockPos.x == -1) {
section = section - Vector(-1, 0, 0);
blockPos.x = 15;
}
else if (blockPos.x == 16) {
section = section - Vector(+1, 0, 0);
blockPos.x = 0;
}
else if (blockPos.y == -1) {
section = section - Vector(0, -1, 0);
blockPos.y = 15;
}
else if (blockPos.y == 16) {
section = section - Vector(0, +1, 0);
blockPos.y = 0;
}
else if (blockPos.z == -1) {
section = section - Vector(0, 0, -1);
blockPos.z = 15;
}
else if (blockPos.z == 16) {
section = section - Vector(0, 0, +1);
blockPos.z = 0;
}
auto ptr = world->GetSection(sectionPos);
if (!ptr)
return true;
return ptr->GetBlockId(blockPos).id != 0;
}