#include "RenderSection.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,
};
void RenderState::SetActiveVao(GLuint Vao) {
if (Vao != ActiveVao) {
glBindVertexArray(Vao);
ActiveVao = Vao;
}
}
void RenderState::SetActiveShader(GLuint Shader) {
if (Shader != ActiveShader) {
glUseProgram(Shader);
ActiveShader = Shader;
}
}
const GLuint magicUniqueConstant = 88375;
GLuint RenderSection::VboVertices = magicUniqueConstant;
GLuint RenderSection::VboUvs = magicUniqueConstant;
std::map<GLuint, int> RenderSection::refCounterVbo;
std::map<GLuint, int> RenderSection::refCounterVao;
RenderSection::RenderSection(World *world, Vector position) : sectionPosition(position), world(world) {
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 ordinary blocks";
}
glGenBuffers(1, &VboTextures);
if (refCounterVbo.find(VboTextures) == refCounterVbo.end())
refCounterVbo[VboTextures] = 0;
refCounterVbo[VboTextures]++;
glGenBuffers(1, &VboModels);
if (refCounterVbo.find(VboModels) == refCounterVbo.end())
refCounterVbo[VboModels] = 0;
refCounterVbo[VboModels]++;
glGenBuffers(1, &VboColors);
if (refCounterVbo.find(VboColors) == refCounterVbo.end())
refCounterVbo[VboColors] = 0;
refCounterVbo[VboColors]++;
glGenVertexArrays(1, &Vao);
if (refCounterVao.find(Vao) == refCounterVao.end())
refCounterVao[Vao] = 0;
refCounterVao[Vao]++;
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, VboTextures);
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, VboModels);
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, VboColors);
glVertexAttribPointer(colorAttribPos, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(colorAttribPos);
glVertexAttribDivisor(colorAttribPos, 1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glBindVertexArray(0);
glCheckError();
}
RenderSection::~RenderSection() {
refCounterVbo[VboTextures]--;
refCounterVbo[VboModels]--;
refCounterVbo[VboColors]--;
refCounterVao[Vao]--;
if (refCounterVbo[VboTextures] <= 0)
glDeleteBuffers(1, &VboTextures);
if (refCounterVbo[VboModels] <= 0)
glDeleteBuffers(1, &VboTextures);
if (refCounterVbo[VboColors] <= 0)
glDeleteBuffers(1, &VboColors);
if (refCounterVao[Vao] <= 0)
glDeleteVertexArrays(1, &Vao);
}
void RenderSection::UpdateState(const std::map<BlockTextureId, glm::vec4> &textureAtlas) {
Section §ion = world->GetSection(sectionPosition);
models.clear();
textures.clear();
colors.clear();
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
Vector blockPos = Vector(x, y, z) + (sectionPosition * 16);
Block &block = world->GetBlock(blockPos);
if (block.id == 0)
continue;
auto checkBlockVisibility = [&](Vector block) -> bool {
return section.GetBlock(block).id == 0 ||
section.GetBlock(block).id == 31 ||
section.GetBlock(block).id == 18;
};
unsigned char isVisible = 0;
if (x == 0 || x == 15 || y == 0 || y == 15 || z == 0 || z == 15) {
isVisible = 0b1111'1111; //All faces is visible
} else {
isVisible |= checkBlockVisibility(Vector(x - 1, y, z)) << 0;
isVisible |= checkBlockVisibility(Vector(x + 1, y, z)) << 1;
isVisible |= checkBlockVisibility(Vector(x, y + 1, z)) << 2;
isVisible |= checkBlockVisibility(Vector(x, y - 1, z)) << 3;
isVisible |= checkBlockVisibility(Vector(x, y, z - 1)) << 4;
isVisible |= checkBlockVisibility(Vector(x, y, z + 1)) << 5;
}
if (isVisible == 0x00)
continue;
glm::mat4 transform;
transform = glm::translate(transform, glm::vec3(sectionPosition.GetX() * 16,
sectionPosition.GetY() * 16,
sectionPosition.GetZ() * 16));
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
}
}
}
numOfFaces = textures.size();
hash = section.GetHash();
}
void RenderSection::Render(RenderState &state) {
if (!isEnabled) return;
if (!models.empty()) {
glBindBuffer(GL_ARRAY_BUFFER, VboTextures);
glBufferData(GL_ARRAY_BUFFER, textures.size() * sizeof(glm::vec4), textures.data(), GL_DYNAMIC_DRAW);
textures.clear();
glBindBuffer(GL_ARRAY_BUFFER, VboModels);
glBufferData(GL_ARRAY_BUFFER, models.size() * sizeof(glm::mat4), models.data(), GL_DYNAMIC_DRAW);
models.clear();
glBindBuffer(GL_ARRAY_BUFFER, VboColors);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(glm::vec3), colors.data(), GL_DYNAMIC_DRAW);
colors.clear();
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
state.SetActiveVao(Vao);
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, numOfFaces);
glCheckError();
}
Section *RenderSection::GetSection() {
return &world->GetSection(sectionPosition);
}
RenderSection::RenderSection(const RenderSection &other) {
this->world = other.world;
this->VboModels = other.VboModels;
this->VboTextures = other.VboTextures;
this->VboColors = other.VboColors;
this->sectionPosition = other.sectionPosition;
this->Vao = other.Vao;
this->numOfFaces = other.numOfFaces;
this->models = other.models;
this->textures = other.textures;
this->colors = other.colors;
this->hash = other.hash;
refCounterVbo[VboTextures]++;
refCounterVbo[VboModels]++;
refCounterVbo[VboColors]++;
refCounterVao[Vao]++;
}
void RenderSection::SetEnabled(bool isEnabled) {
this->isEnabled = isEnabled;
}
bool RenderSection::IsNeedUpdate() {
size_t currentHash = world->GetSection(sectionPosition).GetHash();
bool isNeedUpdate = currentHash != hash;
return isNeedUpdate;
}