OpenMiner/source/chunk.cpp

310 lines
11 KiB
C++
Raw Normal View History

2013-03-02 00:11:18 +01:00
/*---------------------------------------------------------------------------------
KubKraft
Copyright (C) 2012 Quent42340 <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>
2013-03-02 00:11:18 +01:00
#include <cmath>
#include <SDL/SDL.h>
#include <GL/glew.h>
2013-03-02 00:11:18 +01:00
#include "types.h"
2013-03-02 06:06:07 +01:00
#include "config.h"
2013-03-02 00:11:18 +01:00
#include "player.h"
#include "cube.h"
#include "chunk.h"
2013-03-02 06:06:07 +01:00
#include "map.h"
2013-03-02 04:54:21 +01:00
#include "game.h"
2013-03-02 00:11:18 +01:00
using namespace std;
2013-04-29 15:29:22 +02:00
Chunk::Chunk(int x, int y, int z) {
2013-03-02 00:11:18 +01:00
srand(time(NULL));
m_x = x;
m_y = y;
m_z = z;
m_surroundingChunks = new Chunk*[6];
for (int i = 0; i < 6; 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;
2013-03-02 00:11:18 +01:00
}
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;
2013-03-02 00:11:18 +01:00
}
m_cubes.clear();
delete[] m_surroundingChunks;
2013-03-02 00:11:18 +01:00
}
2013-03-09 03:23:13 +01:00
void Chunk::setSurroundingChunk(unsigned char face, Chunk* chunk) {
if ((face >= 0) && (face < 6)) {
m_surroundingChunks[face] = chunk;
}
}
2013-03-02 00:11:18 +01:00
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()) {
2013-03-02 00:11:18 +01:00
if(cube->selected()) {
2013-03-02 06:06:07 +01:00
Game::map->map()[MAP_POS(cube->x(), cube->y(), cube->z())] = 0;
2013-03-02 00:11:18 +01:00
m_cubes.erase(it);
2013-03-10 16:15:24 +01:00
refreshVBO();
if((cube->x() - 1 <= m_x) && (m_surroundingChunks[0] != NULL)) m_surroundingChunks[0]->refreshVBO();
if((cube->x() + 1 >= m_x + CHUNK_WIDTH - 1) && (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() + 1 >= m_y + CHUNK_DEPTH - 1) && (m_surroundingChunks[3] != NULL)) m_surroundingChunks[3]->refreshVBO();
if((cube->z() + 1 >= m_z + CHUNK_HEIGHT - 1) && (m_surroundingChunks[4] != NULL)) m_surroundingChunks[4]->refreshVBO();
if((cube->z() - 1 <= m_z) && (m_surroundingChunks[5] != NULL)) m_surroundingChunks[5]->refreshVBO();
delete cube;
2013-03-02 00:11:18 +01:00
break;
}
}
}
}
void Chunk::addCube(Cube *selectedCube, int type) {
int x = selectedCube->x();
int y = selectedCube->y();
int z = selectedCube->z();
2013-04-29 15:29:22 +02:00
/*if(x == 0) {
m_surroundingChunks[0]->addCube(m_surroundingChunks[0]->getCube(CHUNK_WIDTH - 1, y, z), type);
return;
}*/
if((selectedCube == NULL) || (selectedCube->selectedFace() == -1)) {
m_cubes[CUBE_POS(x, y, z)] = selectedCube;
2013-03-09 15:20:18 +01:00
return;
2013-03-02 07:10:06 +01:00
}
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;
m_cubes[CUBE_POS(x, y + 1, z)] = new Cube(x, y + 1, z, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
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;
m_cubes[CUBE_POS(x + 1, y, z)] = new Cube(x + 1, y, z, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
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;
m_cubes[CUBE_POS(x - 1, y, z)] = new Cube(x - 1, y, z, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
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;
m_cubes[CUBE_POS(x, y - 1, z)] = new Cube(x, y - 1, z, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
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;
m_cubes[CUBE_POS(x, y, z + 1)] = new Cube(x, y, z + 1, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
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;
m_cubes[CUBE_POS(x, y, z - 1)] = new Cube(x, y, z - 1, type);
2013-03-09 15:20:18 +01:00
}
2013-03-02 00:11:18 +01:00
}
2013-03-11 02:05:34 +01:00
refreshVBO();
2013-03-11 02:05:34 +01:00
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();
if((selectedCube->z() == m_z + CHUNK_HEIGHT - 1) && (m_surroundingChunks[4] != NULL)) m_surroundingChunks[4]->refreshVBO();
if((selectedCube->z() == m_z) && (m_surroundingChunks[5] != NULL)) m_surroundingChunks[5]->refreshVBO();
2013-03-02 00:11:18 +01:00
}
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];
2013-03-11 23:14:43 +01:00
if(cube == NULL) {
m_cubes.erase(coords);
2013-03-11 02:05:34 +01:00
return NULL;
}
2013-03-11 18:56:48 +01:00
else return cube;
}
2013-04-29 23:53:31 +02:00
float Chunk::getTexOffsetU(int type, int i, Cube *cube) {
if((type == 2) && (cube != NULL)) {
Cube *higherCube = NULL;
// Little bug with this way: Dirt blocks at chunk borders are grassed too...
if(cube->z() < m_z + CHUNK_HEIGHT - 1) higherCube = getCube(cube->x() - m_x, cube->y() - m_y, cube->z() - m_z + 1);
else {
if(m_surroundingChunks[4] != NULL) higherCube = m_surroundingChunks[4]->getCube(cube->x() - m_x, cube->y() - m_y, 0);
2013-04-29 15:58:15 +02:00
}
2013-04-29 23:53:31 +02:00
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;
}
2013-04-29 15:58:15 +02:00
} else {
return (type - 1) * 0.125;
}
2013-04-29 23:53:31 +02:00
} else {
return (type - 1) * 0.125;
2013-04-29 15:58:15 +02:00
}
}
2013-04-29 23:53:31 +02:00
float Chunk::getTexOffsetV(int type) {
if(type > 8) {
type <<= 3; // Here 8 ( remember x * 8 == x << 3 ) is the texture image width
return 1 - type * 0.125;
}
return 0.875;
}
void Chunk::refreshVBO() {
m_vboVertexCount = 0;
2013-03-09 03:23:13 +01:00
2013-03-11 23:14:43 +01:00
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>();
2013-03-11 23:14:43 +01:00
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;
2013-03-11 23:14:43 +01:00
Cube *qe = getCube(x, y, z);
if (qe == NULL) continue;
2013-03-11 23:14:43 +01:00
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
};
2013-03-11 23:14:43 +01:00
for(int i = 0 ; i < 6 ; i++) {
cube = getCube(coords[i*3], coords[i*3 + 1], coords[i*3 + 2]);
2013-03-11 02:05:34 +01:00
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]);
}
2013-03-11 02:05:34 +01:00
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 ((coords[i*3 + 2] >= CHUNK_HEIGHT) && (m_surroundingChunks[4] != NULL)) {
cube = m_surroundingChunks[4]->getCube(coords[i*3], coords[i*3 + 1], coords[i*3 + 2] - CHUNK_HEIGHT);
}
else if ((coords[i*3 + 2] < 0) && (m_surroundingChunks[5] != NULL)) {
cube = m_surroundingChunks[5]->getCube(coords[i*3], coords[i*3 + 1], coords[i*3 + 2] + CHUNK_HEIGHT);
}
2013-03-09 03:23:13 +01:00
if ((cube == NULL) || (cube->type() == 0)) {
2013-03-11 02:05:34 +01:00
for(int j = 0 ; j < 4 ; j++) {
vertices.push_back(x + cubeCoords[(i * 12) + (j * 3)]);
vertices.push_back(y + cubeCoords[(i * 12) + (j * 3) + 1]);
vertices.push_back(z + cubeCoords[(i * 12) + (j * 3) + 2]);
2013-04-29 23:53:31 +02:00
texCoords.push_back(getTexOffsetU(qe->type(), i, qe) + (cubeCoords[48 + (j * 3)] * 0.125));
2013-03-10 16:15:24 +01:00
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);
}