OpenMiner/source/chunk.cpp

290 lines
11 KiB
C++

/*---------------------------------------------------------------------------------
KubKraft
Copyright (C) 2013 Quentin Bazin <quent42340@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
---------------------------------------------------------------------------------*/
#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath>
#include <SDL/SDL.h>
#include <GL/glew.h>
#include "types.h"
#include "config.h"
#include "player.h"
#include "cube.h"
#include "chunk.h"
#include "map.h"
#include "game.h"
using namespace std;
Chunk::Chunk(int x, int y) {
srand(time(NULL));
m_x = x;
m_y = y;
m_loaded = false;
m_surroundingChunks = new Chunk*[8];
for (int i = 0; i < 8; i++) m_surroundingChunks[i] = NULL;
m_vboVertices = 0; glGenBuffers(1, &m_vboVertices);
m_vboTexCoords = 0; glGenBuffers(1, &m_vboTexCoords);
m_vboColors = 0; glGenBuffers(1, &m_vboColors);
m_vboVertexCount = 0;
}
Chunk::~Chunk() {
glDeleteBuffers(1, &m_vboVertices);
glDeleteBuffers(1, &m_vboTexCoords);
glDeleteBuffers(1, &m_vboColors);
for(std::unordered_map<int, Cube*>::iterator it = m_cubes.begin() ; it != m_cubes.end() ; it++) {
delete it->second;
}
m_cubes.clear();
delete[] m_surroundingChunks;
}
void Chunk::setSurroundingChunk(unsigned char face, Chunk* chunk) {
if ((face >= 0) && (face < 8)) {
m_surroundingChunks[face] = chunk;
}
}
void Chunk::deleteCube(Cube *cube) {
for(std::unordered_map<int, Cube*>::iterator it = m_cubes.begin(); it != m_cubes.end() ; it++) {
if(it->second == NULL) continue;
if(it->second->x() == cube->x() && it->second->y() == cube->y() && it->second->z() == cube->z()) {
if(cube->selected()) {
Game::map->map()[MAP_POS(cube->x(), cube->y(), cube->z())] = 0;
m_cubes.erase(it);
refreshVBO();
if((cube->x() - 1 <= m_x) && (m_surroundingChunks[0] != NULL)) m_surroundingChunks[0]->refreshVBO();
if((cube->x() >= m_x + CHUNK_WIDTH) && (m_surroundingChunks[1] != NULL)) m_surroundingChunks[1]->refreshVBO();
if((cube->y() - 1 <= m_y) && (m_surroundingChunks[2] != NULL)) m_surroundingChunks[2]->refreshVBO();
if((cube->y() >= m_y + CHUNK_DEPTH) && (m_surroundingChunks[3] != NULL)) m_surroundingChunks[3]->refreshVBO();
//if((cube->y() >= m_y + CHUNK_DEPTH && cube->x() >= m_x + CHUNK_WIDTH) && (m_surroundingChunks[4] != NULL)) m_surroundingChunks[4]->refreshVBO();
//if((cube->y() - 1 <= m_y && cube->x() >= m_x + CHUNK_WIDTH) && (m_surroundingChunks[5] != NULL)) m_surroundingChunks[5]->refreshVBO();
//if((cube->y() >= m_y + CHUNK_DEPTH && cube->x() - 1 <= m_x) && (m_surroundingChunks[6] != NULL)) m_surroundingChunks[6]->refreshVBO();
//if((cube->y() - 1 <= m_y && cube->x() - 1 <= m_x ) && (m_surroundingChunks[7] != NULL)) m_surroundingChunks[7]->refreshVBO();
delete cube;
break;
}
}
}
}
void Chunk::addCube(Cube *selectedCube, int type) {
int x = selectedCube->x();
int y = selectedCube->y();
int z = selectedCube->z();
if(selectedCube->selectedFace() == -1) {
m_cubes[CUBE_POS(x, y, z)] = selectedCube;
return;
}
else if(selectedCube->selectedFace() == 0) {
if((MAP_POS(x, y + 1, z) >= 0) && (MAP_POS(x, y + 1, z) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x, y + 1, z)] = type;
if(y + 1 - m_y < CHUNK_DEPTH) m_cubes[CUBE_POS(x, y + 1, z)] = new Cube(x, y + 1, z, type);
else if(m_surroundingChunks[3] != NULL) m_surroundingChunks[3]->putCube(x, y + 1, z, type);
}
}
else if(selectedCube->selectedFace() == 1) {
if((MAP_POS(x + 1, y, z) >= 0) && (MAP_POS(x + 1, y, z) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x + 1, y, z)] = type;
if(x + 1 - m_x < CHUNK_WIDTH) m_cubes[CUBE_POS(x + 1, y, z)] = new Cube(x + 1, y, z, type);
else if(m_surroundingChunks[1] != NULL) m_surroundingChunks[1]->putCube(x + 1, y, z, type);
}
}
else if(selectedCube->selectedFace() == 2) {
if((MAP_POS(x - 1, y, z) >= 0) && (MAP_POS(x - 1, y, z) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x - 1, y, z)] = type;
if(x - 1 - m_x >= 0) m_cubes[CUBE_POS(x - 1, y, z)] = new Cube(x - 1, y, z, type);
else if(m_surroundingChunks[0] != NULL) m_surroundingChunks[0]->putCube(x - 1, y, z, type);
}
}
else if(selectedCube->selectedFace() == 3) {
if((MAP_POS(x, y - 1, z) >= 0) && (MAP_POS(x, y - 1, z) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x, y - 1, z)] = type;
if(y - 1 - m_y >= 0) m_cubes[CUBE_POS(x, y - 1, z)] = new Cube(x, y - 1, z, type);
else if(m_surroundingChunks[2] != NULL) m_surroundingChunks[2]->putCube(x, y - 1, z, type);
}
}
/*else if(selectedCube->selectedFace() == 4) {
if((MAP_POS(x, y, z + 1) >= 0) && (MAP_POS(x, y, z + 1) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x, y, z + 1)] = type;
if(z + 1 - m_z < CHUNK_HEIGHT) m_cubes[CUBE_POS(x, y, z + 1)] = new Cube(x, y, z + 1, type);
else if(m_surroundingChunks[4] != NULL) m_surroundingChunks[4]->putCube(x, y, z + 1, type);
}
}
else if(selectedCube->selectedFace() == 5) {
if((MAP_POS(x, y, z - 1) >= 0) && (MAP_POS(x, y, z - 1) < Game::map->width() * Game::map->depth() * Game::map->height())) {
Game::map->map()[MAP_POS(x, y, z - 1)] = type;
if(z - 1 - m_z >= 0) m_cubes[CUBE_POS(x, y, z - 1)] = new Cube(x, y, z - 1, type);
else if(m_surroundingChunks[5] != NULL) m_surroundingChunks[5]->putCube(x, y, z - 1, type);
}
}*/
refreshVBO();
if((selectedCube->x() == m_x) && (m_surroundingChunks[0] != NULL)) m_surroundingChunks[0]->refreshVBO();
if((selectedCube->x() == m_x + CHUNK_WIDTH - 1) && (m_surroundingChunks[1] != NULL)) m_surroundingChunks[1]->refreshVBO();
if((selectedCube->y() == m_y) && (m_surroundingChunks[2] != NULL)) m_surroundingChunks[2]->refreshVBO();
if((selectedCube->y() == m_y + CHUNK_DEPTH - 1) && (m_surroundingChunks[3] != NULL)) m_surroundingChunks[3]->refreshVBO();
}
Cube* Chunk::getCube(int x, int y, int z) {
if ((x < 0) || (x >= CHUNK_WIDTH) || (y < 0) || (y >= CHUNK_DEPTH) || (z < 0) || (z >= CHUNK_HEIGHT)) {
return NULL;
}
int coords = x + (y * CHUNK_WIDTH) + (z * CHUNK_WIDTH * CHUNK_DEPTH);
Cube *cube = m_cubes[coords];
if(cube == NULL) {
m_cubes.erase(coords);
return NULL;
}
else return cube;
}
float Chunk::getTexOffsetU(int type, int i, Cube *cube) {
if((type == 2) && (cube != NULL)) {
Cube *higherCube = getCube(cube->x() - m_x, cube->y() - m_y, cube->z() + 1);
if((higherCube == NULL) || (higherCube->type() == 0)) {
if((i == 0) || (i == 1) || (i == 2) || (i == 3))
return type * 0.125;
else if(i == 4) return (type + 1) * 0.125;
else return (type - 1) * 0.125;
} else return (type - 1) * 0.125;
} else return (type - 1) * 0.125;
}
float Chunk::getTexOffsetV(int type) {
return 1 - ((type >> 3) + 1) * 0.125;
}
void Chunk::refreshVBO() {
m_loaded = true;
m_vboVertexCount = 0;
if(m_cubes.size() == 0) return;
float cubeCoords[6 * 12] = {
0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1,
1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1,
0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1,
1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0
};
unsigned char grey[6] = {159, 191, 127, 223, 255, 95};
std::vector<float> vertices = std::vector<float>();
std::vector<float> texCoords = std::vector<float>();
std::vector<unsigned char> colors = std::vector<unsigned char>();
for(int qc = 0 ; qc < CHUNK_WIDTH * CHUNK_DEPTH * CHUNK_HEIGHT ; qc++) {
int x = qc % CHUNK_WIDTH;
int y = (qc / CHUNK_WIDTH) % CHUNK_DEPTH;
int z = (qc / CHUNK_WIDTH) / CHUNK_DEPTH;
Cube *qe = getCube(x, y, z);
if (qe == NULL) continue;
Cube *cube = NULL;
int coords[6 * 3] = {
x-1, y, z,
x+1, y, z,
x, y-1, z,
x, y+1, z,
x, y, z+1,
x, y, z-1
};
for(int i = 0 ; i < 6 ; i++) {
cube = getCube(coords[i*3], coords[i*3 + 1], coords[i*3 + 2]);
if ((coords[i*3] < 0) && (m_surroundingChunks[0] != NULL)) {
cube = m_surroundingChunks[0]->getCube(coords[i*3] + CHUNK_WIDTH, coords[i*3 + 1], coords[i*3 + 2]);
}
else if ((coords[i*3] >= CHUNK_WIDTH) && (m_surroundingChunks[1] != NULL)) {
cube = m_surroundingChunks[1]->getCube(coords[i*3] - CHUNK_WIDTH, coords[i*3 + 1], coords[i*3 + 2]);
}
if ((coords[i*3 + 1] < 0) && (m_surroundingChunks[2] != NULL)) {
cube = m_surroundingChunks[2]->getCube(coords[i*3], coords[i*3 + 1] + CHUNK_DEPTH, coords[i*3 + 2]);
}
else if ((coords[i*3 + 1] >= CHUNK_DEPTH) && (m_surroundingChunks[3] != NULL)) {
cube = m_surroundingChunks[3]->getCube(coords[i*3], coords[i*3 + 1] - CHUNK_DEPTH, coords[i*3 + 2]);
}
if ((cube == NULL) || (cube->type() == 0)) {
for(int j = 0 ; j < 4 ; j++) {
vertices.push_back(m_x + x + cubeCoords[(i * 12) + (j * 3)]);
vertices.push_back(m_y + y + cubeCoords[(i * 12) + (j * 3) + 1]);
vertices.push_back(z + cubeCoords[(i * 12) + (j * 3) + 2]);
texCoords.push_back(getTexOffsetU(qe->type(), i, qe) + (cubeCoords[48 + (j * 3)] * 0.125));
texCoords.push_back(getTexOffsetV(qe->type()) + (cubeCoords[48 + (j * 3) + 1] * 0.125));
colors.push_back(grey[i]);
colors.push_back(grey[i]);
colors.push_back(grey[i]);
colors.push_back(255);
m_vboVertexCount++;
}
}
}
}
glBindBuffer(GL_ARRAY_BUFFER, m_vboVertices);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboTexCoords);
glBufferData(GL_ARRAY_BUFFER, texCoords.size() * sizeof(float), texCoords.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_vboColors);
glBufferData(GL_ARRAY_BUFFER, colors.size() * sizeof(unsigned char), colors.data(), GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
vertices.clear();
texCoords.clear();
colors.clear();
}
void Chunk::render() {
if(m_vboVertexCount == 0) return;
glBindBuffer(GL_ARRAY_BUFFER, m_vboVertices);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboTexCoords);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboColors);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
glDrawArrays(GL_QUADS, 0, m_vboVertexCount);
}