summaryrefslogblamecommitdiffstats
path: root/src/graphics/RenderSection.cpp
blob: ae072d659fe28d1246b4df363a662b02ccd9c12f (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
                                     
                 

                            






                        


                             


                           
 


                           























                                                                                                       















                                                                                                     



                                                                   





                                                                 




                                                                 







                                                           
                                         
                                                           

                                                                                                          

                          
                                       
                                                      








                                                                                                             


                               
                                        

                                                            


















                                                                                                                               



                                                 



                                 
                                     
                                   
                                   
                             

                                                 
 
                                          



                                                 



                                              




                                                                                          


                                                      

                                                                                           


                                                  





                                                                                       

                                                                                                  
                                                                                       
                                        





                                                                                                    
                                 

                                                      

                                                 














































































































                                                                                                                                             


                         
                                     
                                 
 
 
                                                
                               



                                                                                                                     
 


                                                                                                                 
 


                                                                                                                 
 

                                                 
                                
                                                              



                                      
                                                   




                                                          

                                              

                                                      



                                            
                                
 
                                     
                                   
                                   

                             

                                                
                                    


                                    


                                                                          
 
#include <graphics/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 &section = 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;
}