[Chunk] Working on it.
This commit is contained in:
parent
fad91e840f
commit
0b806a93c6
@ -29,6 +29,8 @@ class Application {
|
||||
Application();
|
||||
~Application();
|
||||
|
||||
void initGL();
|
||||
|
||||
void handleEvents();
|
||||
|
||||
void run();
|
||||
|
59
include/gl/Camera.hpp
Normal file
59
include/gl/Camera.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: Camera.hpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 16/12/2014 12:21:03
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef CAMERA_HPP_
|
||||
#define CAMERA_HPP_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#define RADIANS_PER_DEGREES 0.0174532925199
|
||||
#define M_PI 3.14159265358979323846
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
~Camera();
|
||||
|
||||
void turnH(float angle);
|
||||
void turnV(float angle);
|
||||
|
||||
void move(float direction);
|
||||
|
||||
glm::mat4 processInputs();
|
||||
glm::mat4 update();
|
||||
|
||||
float pointTargetedX() { return m_x + cos(m_angleH * RADIANS_PER_DEGREES) * cos(m_angleV * RADIANS_PER_DEGREES); }
|
||||
float pointTargetedY() { return m_y + sin(m_angleV * RADIANS_PER_DEGREES); }
|
||||
float pointTargetedZ() { return m_z + sin(m_angleH * RADIANS_PER_DEGREES) * cos(m_angleV * RADIANS_PER_DEGREES) - 0.00001; }
|
||||
|
||||
private:
|
||||
glm::mat4 m_viewMatrix;
|
||||
|
||||
float m_x;
|
||||
float m_y;
|
||||
float m_z;
|
||||
|
||||
float m_angleH;
|
||||
float m_angleV;
|
||||
|
||||
float m_vx;
|
||||
float m_vz;
|
||||
};
|
||||
|
||||
#endif // CAMERA_HPP_
|
@ -18,6 +18,10 @@
|
||||
#ifndef SHADER_HPP_
|
||||
#define SHADER_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "OpenGL.hpp"
|
||||
|
||||
class Shader {
|
||||
@ -30,11 +34,14 @@ class Shader {
|
||||
|
||||
void compileShader(GLenum type, GLuint &shader, const char *filename);
|
||||
|
||||
GLint attrib(const char *attribName);
|
||||
GLint uniform(const char *uniformName);
|
||||
GLint attrib(std::string name);
|
||||
GLint uniform(std::string name);
|
||||
|
||||
void enableVertexAttribArray(const char *attribName);
|
||||
void disableVertexAttribArray(const char *attribName);
|
||||
void enableVertexAttribArray(std::string name);
|
||||
void disableVertexAttribArray(std::string name);
|
||||
|
||||
void setUniform(std::string name, int n);
|
||||
void setUniform(std::string name, const glm::mat4 &matrix);
|
||||
|
||||
static void bind(const Shader *shader);
|
||||
|
||||
|
39
include/gl/VertexBuffer.hpp
Normal file
39
include/gl/VertexBuffer.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: VertexBuffer.hpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 15/12/2014 17:09:58
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef VERTEXBUFFER_HPP_
|
||||
#define VERTEXBUFFER_HPP_
|
||||
|
||||
#include "OpenGL.hpp"
|
||||
|
||||
class VertexBuffer {
|
||||
public:
|
||||
VertexBuffer();
|
||||
~VertexBuffer();
|
||||
|
||||
void setData(GLsizeiptr size, const GLvoid *data, GLenum usage);
|
||||
void updateData(GLintptr offset, GLsizeiptr size, const GLvoid *data);
|
||||
|
||||
static void bind(const VertexBuffer *vertexBuffer);
|
||||
|
||||
private:
|
||||
GLuint m_id;
|
||||
|
||||
static VertexBuffer *activeBuffer;
|
||||
};
|
||||
|
||||
#endif // VERTEXBUFFER_HPP_
|
@ -18,9 +18,11 @@
|
||||
#ifndef GAMESTATE_HPP_
|
||||
#define GAMESTATE_HPP_
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "ApplicationState.hpp"
|
||||
#include "OpenGL.hpp"
|
||||
#include "Shader.hpp"
|
||||
#include "Camera.hpp"
|
||||
#include "World.hpp"
|
||||
|
||||
class GameState : public ApplicationState {
|
||||
public:
|
||||
@ -32,9 +34,14 @@ class GameState : public ApplicationState {
|
||||
void draw();
|
||||
|
||||
private:
|
||||
GLuint m_vbo;
|
||||
glm::mat4 m_projectionMatrix;
|
||||
glm::mat4 m_viewMatrix;
|
||||
|
||||
Camera m_camera;
|
||||
|
||||
Shader m_shader;
|
||||
|
||||
World m_world;
|
||||
};
|
||||
|
||||
#endif // GAMESTATE_HPP_
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#define EXCEPTION(args...) (Exception(__LINE__, _FILE, args))
|
||||
|
||||
class Exception : public std::exception {
|
||||
class Exception {
|
||||
public:
|
||||
template<typename... Args>
|
||||
Exception(u16 line, std::string filename, Args... args) throw() {
|
||||
@ -40,8 +40,8 @@ class Exception : public std::exception {
|
||||
~Exception() throw() {
|
||||
}
|
||||
|
||||
virtual const char *what() const throw() {
|
||||
return (Debug::textColor(Debug::TextColor::Red, true) + "at " + m_filename + ":" + std::to_string(m_line) + ": " + Debug::textColor(0, true) + m_errorMsg.c_str() + Debug::textColor()).c_str();
|
||||
virtual std::string what() const throw() {
|
||||
return Debug::textColor(Debug::TextColor::Red, true) + "at " + m_filename + ":" + std::to_string(m_line) + ": " + Debug::textColor(0, true) + m_errorMsg.c_str() + Debug::textColor();
|
||||
}
|
||||
|
||||
private:
|
||||
|
86
include/world/Chunk.hpp
Normal file
86
include/world/Chunk.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: Chunk.hpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 15/12/2014 17:31:17
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef CHUNK_HPP_
|
||||
#define CHUNK_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
|
||||
#include "Shader.hpp"
|
||||
#include "Types.hpp"
|
||||
#include "VertexBuffer.hpp"
|
||||
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk(s32 x, s32 y, s32 z);
|
||||
~Chunk();
|
||||
|
||||
void generate();
|
||||
void update();
|
||||
|
||||
void draw(Shader &shader);
|
||||
|
||||
u8 getBlock(s8 x, s8 y, s8 z);
|
||||
|
||||
static float noise2d(float x, float y, int seed, int octaves, float persistence);
|
||||
static float noise3d_abs(float x, float y, float z, int seed, int octaves, float persistence);
|
||||
|
||||
s32 x() const { return m_x; }
|
||||
s32 y() const { return m_y; }
|
||||
s32 z() const { return m_z; }
|
||||
|
||||
bool initialized() const { return m_initialized; }
|
||||
void setInitialized(bool initialized) { m_initialized = initialized; }
|
||||
|
||||
Chunk *left() const { return m_surroundingChunks[0]; }
|
||||
Chunk *right() const { return m_surroundingChunks[1]; }
|
||||
Chunk *front() const { return m_surroundingChunks[2]; }
|
||||
Chunk *back() const { return m_surroundingChunks[3]; }
|
||||
|
||||
static const u8 width = 16;
|
||||
static const u8 height = 32;
|
||||
static const u8 depth = 16;
|
||||
|
||||
void setLeft(Chunk *left) { m_surroundingChunks[0] = left; }
|
||||
void setRight(Chunk *right) { m_surroundingChunks[1] = right; }
|
||||
void setFront(Chunk *front) { m_surroundingChunks[2] = front; }
|
||||
void setBack(Chunk *back) { m_surroundingChunks[3] = back; }
|
||||
|
||||
private:
|
||||
s32 m_x;
|
||||
s32 m_y;
|
||||
s32 m_z;
|
||||
|
||||
sf::Texture m_texture;
|
||||
|
||||
std::vector<u8> m_data;
|
||||
|
||||
std::vector<float> m_vertices;
|
||||
std::vector<float> m_normals;
|
||||
std::vector<float> m_texCoords;
|
||||
|
||||
VertexBuffer m_vbo;
|
||||
|
||||
Chunk *m_surroundingChunks[4];
|
||||
|
||||
bool m_changed;
|
||||
bool m_initialized;
|
||||
};
|
||||
|
||||
#endif // CHUNK_HPP_
|
41
include/world/World.hpp
Normal file
41
include/world/World.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: World.hpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 16/12/2014 15:28:02
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#ifndef WORLD_HPP_
|
||||
#define WORLD_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Chunk.hpp"
|
||||
|
||||
class World {
|
||||
public:
|
||||
World();
|
||||
~World();
|
||||
|
||||
void draw(Shader &shader, const glm::mat4 &pv);
|
||||
|
||||
Chunk *getChunk(s16 x, s16 z) { return m_chunks[x + z * m_width].get(); }
|
||||
|
||||
private:
|
||||
s32 m_width;
|
||||
s32 m_depth;
|
||||
|
||||
std::vector<std::unique_ptr<Chunk>> m_chunks;
|
||||
};
|
||||
|
||||
#endif // WORLD_HPP_
|
@ -1,6 +1,43 @@
|
||||
#version 120
|
||||
|
||||
varying vec4 v_coord3d;
|
||||
varying vec4 v_normal;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
uniform sampler2D u_tex;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
//vec4 lightSource = vec4(0.0, 48.0, 0.0, 0.0);
|
||||
//float lightIntensity = 1.0;
|
||||
|
||||
//vec4 surfaceToLight = normalize(lightSource - v_coord3d);
|
||||
|
||||
//float brightness = dot(v_normal, surfaceToLight) / (length(surfaceToLight) * length(v_normal));
|
||||
//brightness = clamp(brightness, 0, 1) / 2 + 0.25;
|
||||
|
||||
//gl_FragColor = vec4(brightness * lightIntensity * vec3(1.0, 1.0, 1.0), 1.0);
|
||||
|
||||
vec4 lightPosition = vec4(0.0, 48.0, 0.0, 1.0);
|
||||
vec3 lightColor = vec3(1.0, 1.0, 1.0);
|
||||
vec4 lightDirection = normalize(lightPosition - v_coord3d);
|
||||
|
||||
float ambientIntensity = 0.5;
|
||||
vec4 ambientColor = vec4(lightColor * ambientIntensity, 1.0);
|
||||
|
||||
float diffuseIntensity = 0.5;
|
||||
float diffuseFactor = dot(v_normal, lightDirection);
|
||||
|
||||
vec4 diffuseColor;
|
||||
if(diffuseFactor > 0) {
|
||||
//diffuseColor = vec4(lightColor, 1.0) * diffuseIntensity * diffuseFactor;
|
||||
diffuseColor = vec4(lightColor * diffuseIntensity * diffuseFactor, 1.0);
|
||||
//diffuseColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
} else {
|
||||
diffuseColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec4 surfaceColor = texture2D(u_tex, v_texCoord);
|
||||
|
||||
gl_FragColor = surfaceColor * (ambientColor + diffuseColor);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,22 @@
|
||||
#version 120
|
||||
|
||||
attribute vec2 coord2d;
|
||||
attribute vec3 coord3d;
|
||||
attribute vec3 normal;
|
||||
attribute vec2 texCoord;
|
||||
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_viewMatrix;
|
||||
varying vec4 v_coord3d;
|
||||
varying vec4 v_normal;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
uniform mat4 u_modelMatrix;
|
||||
uniform mat4 u_viewProjectionMatrix;
|
||||
|
||||
void main() {
|
||||
mat4 MVP = u_projectionMatrix * u_viewMatrix;
|
||||
v_coord3d = u_modelMatrix * vec4(coord3d, 1.0);
|
||||
|
||||
gl_Position = MVP * vec4(coord2d, 0.0, 1.0);
|
||||
gl_Position = u_viewProjectionMatrix * v_coord3d;
|
||||
|
||||
v_normal = vec4(normal, 1.0);
|
||||
v_texCoord = texCoord;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include <SFML/Window/Event.hpp>
|
||||
|
||||
#include "Application.hpp"
|
||||
@ -23,13 +26,14 @@
|
||||
#include "OpenGL.hpp"
|
||||
|
||||
Application::Application() {
|
||||
if(glewInit() != GLEW_OK) {
|
||||
EXCEPTION("glew init failed");
|
||||
}
|
||||
srand(time(NULL));
|
||||
|
||||
m_window.create(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT), APP_NAME, sf::Style::Close, sf::ContextSettings(24, 8, 2));
|
||||
m_window.setVerticalSyncEnabled(true);
|
||||
m_defaultView.reset(sf::FloatRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
|
||||
|
||||
initGL();
|
||||
|
||||
//ResourceHandler::getInstance().loadResources();
|
||||
m_applicationStateStack = &ApplicationStateStack::getInstance();
|
||||
}
|
||||
@ -37,6 +41,22 @@ Application::Application() {
|
||||
Application::~Application() {
|
||||
}
|
||||
|
||||
void Application::initGL() {
|
||||
if(glewInit() != GLEW_OK) {
|
||||
throw EXCEPTION("glew init failed");
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
glClearColor(0.196078, 0.6, 0.8, 1.0); // Skyblue
|
||||
}
|
||||
|
||||
void Application::handleEvents() {
|
||||
sf::Event event;
|
||||
while(m_window.pollEvent(event)) {
|
||||
@ -62,9 +82,11 @@ void Application::run() {
|
||||
});
|
||||
|
||||
m_clock.drawGame([&]{
|
||||
m_window.clear();
|
||||
//m_window.clear();
|
||||
m_window.setView(m_defaultView);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_applicationStateStack->top().draw();
|
||||
|
||||
m_window.display();
|
||||
|
125
source/gl/Camera.cpp
Normal file
125
source/gl/Camera.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: Camera.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 16/12/2014 12:21:19
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <SFML/Window/Keyboard.hpp>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "Camera.hpp"
|
||||
|
||||
Camera::Camera() {
|
||||
m_x = 0;
|
||||
m_y = 32;
|
||||
m_z = 0;
|
||||
|
||||
m_angleH = 45.0;
|
||||
m_angleV = -20.0;
|
||||
|
||||
m_vx = 0;
|
||||
m_vz = 0;
|
||||
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
Camera::~Camera() {
|
||||
}
|
||||
|
||||
void Camera::turnH(float angle) {
|
||||
m_angleH += angle;
|
||||
|
||||
while(m_angleH >= 180.0) {
|
||||
m_angleH -= 360.0;
|
||||
}
|
||||
while(m_angleH < -180.0) {
|
||||
m_angleH += 360.0;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::turnV(float angle) {
|
||||
m_angleV += angle;
|
||||
|
||||
if(89.9 < m_angleV) {
|
||||
m_angleV = 89.9;
|
||||
}
|
||||
else if(-89.9 > m_angleV) {
|
||||
m_angleV = -89.9;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::move(float direction) {
|
||||
direction += m_angleH;
|
||||
|
||||
m_vx = 0.04f * cos(direction * M_PI / 180.0);
|
||||
m_vz = 0.04f * sin(direction * M_PI / 180.0);
|
||||
|
||||
m_x += m_vx;
|
||||
m_z += m_vz;
|
||||
|
||||
m_vx = 0;
|
||||
m_vz = 0;
|
||||
}
|
||||
|
||||
glm::mat4 Camera::processInputs() {
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::X)) {
|
||||
turnV(1);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
||||
turnV(-1);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
|
||||
turnH(-0.8);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
|
||||
turnH(0.8);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::BackSpace)) {
|
||||
m_y -= 0.1;
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Return)) {
|
||||
m_y += 0.1;
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
|
||||
move(0.0f);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
|
||||
move(180.0f);
|
||||
m_viewMatrix = update();
|
||||
}
|
||||
|
||||
return m_viewMatrix;
|
||||
}
|
||||
|
||||
glm::mat4 Camera::update() {
|
||||
return glm::lookAt(glm::vec3(m_x, m_y, m_z),
|
||||
glm::vec3(pointTargetedX(), pointTargetedY(), pointTargetedZ()),
|
||||
glm::vec3(0, 1, 0));
|
||||
}
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "Exception.hpp"
|
||||
#include "Shader.hpp"
|
||||
|
||||
@ -107,32 +110,40 @@ void Shader::compileShader(GLenum type, GLuint &shader, const char *filename) {
|
||||
}
|
||||
}
|
||||
|
||||
GLint Shader::attrib(const char *attribName) {
|
||||
GLint attrib = glGetAttribLocation(m_program, attribName);
|
||||
GLint Shader::attrib(std::string name) {
|
||||
GLint attrib = glGetAttribLocation(m_program, name.c_str());
|
||||
|
||||
if(attrib == -1) {
|
||||
throw EXCEPTION("Could not bind attribute:", attribName);
|
||||
throw EXCEPTION("Could not bind attribute:", name);
|
||||
}
|
||||
|
||||
return attrib;
|
||||
}
|
||||
|
||||
GLint Shader::uniform(const char *uniformName) {
|
||||
GLint uniform = glGetUniformLocation(m_program, uniformName);
|
||||
GLint Shader::uniform(std::string name) {
|
||||
GLint uniform = glGetUniformLocation(m_program, name.c_str());
|
||||
|
||||
if(uniform == -1) {
|
||||
throw EXCEPTION("Could not bind uniform:", uniformName);
|
||||
throw EXCEPTION("Could not bind uniform:", name);
|
||||
}
|
||||
|
||||
return uniform;
|
||||
}
|
||||
|
||||
void Shader::enableVertexAttribArray(const char *attribName) {
|
||||
glEnableVertexAttribArray(attrib(attribName));
|
||||
void Shader::enableVertexAttribArray(std::string name) {
|
||||
glEnableVertexAttribArray(attrib(name));
|
||||
}
|
||||
|
||||
void Shader::disableVertexAttribArray(const char *attribName) {
|
||||
glDisableVertexAttribArray(attrib(attribName));
|
||||
void Shader::disableVertexAttribArray(std::string name) {
|
||||
glDisableVertexAttribArray(attrib(name));
|
||||
}
|
||||
|
||||
void Shader::setUniform(std::string name, int n) {
|
||||
glUniform1i(uniform(name), n);
|
||||
}
|
||||
|
||||
void Shader::setUniform(std::string name, const glm::mat4 &matrix) {
|
||||
glUniformMatrix4fv(uniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
||||
}
|
||||
|
||||
void Shader::bind(const Shader *shader) {
|
||||
|
54
source/gl/VertexBuffer.cpp
Normal file
54
source/gl/VertexBuffer.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: VertexBuffer.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 15/12/2014 17:10:16
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include "VertexBuffer.hpp"
|
||||
|
||||
VertexBuffer *VertexBuffer::activeBuffer = nullptr;
|
||||
|
||||
VertexBuffer::VertexBuffer() {
|
||||
glGenBuffers(1, &m_id);
|
||||
}
|
||||
|
||||
VertexBuffer::~VertexBuffer() {
|
||||
}
|
||||
|
||||
void VertexBuffer::setData(GLsizeiptr size, const GLvoid *data, GLenum usage) {
|
||||
if(activeBuffer != this) bind(this);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
|
||||
|
||||
if(activeBuffer != this) bind(nullptr);
|
||||
}
|
||||
|
||||
void VertexBuffer::updateData(GLintptr offset, GLsizeiptr size, const GLvoid *data) {
|
||||
if(activeBuffer != this) bind(this);
|
||||
|
||||
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
|
||||
|
||||
if(activeBuffer != this) bind(nullptr);
|
||||
}
|
||||
|
||||
void VertexBuffer::bind(const VertexBuffer *vertexBuffer) {
|
||||
activeBuffer = const_cast<VertexBuffer*>(vertexBuffer);
|
||||
|
||||
if(vertexBuffer) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->m_id);
|
||||
} else {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
@ -17,67 +17,56 @@
|
||||
*/
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "GameState.hpp"
|
||||
|
||||
GameState::GameState() {
|
||||
m_shader.loadFromFile("shaders/game.v.glsl", "shaders/game.f.glsl");
|
||||
|
||||
glGenBuffers(1, &m_vbo);
|
||||
|
||||
GLfloat vertices[2 * 4] = {
|
||||
0.0, 1.0,
|
||||
1.0, 0.0,
|
||||
0.0, -1.0,
|
||||
-1.0, 0.0
|
||||
};
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
Shader::bind(&m_shader);
|
||||
|
||||
glm::mat4 projectionMatrix = glm::perspective(80.0f, 1.0f, 0.1f, 1000.0f);
|
||||
glUniformMatrix4fv(m_shader.uniform("u_projectionMatrix"), 1, GL_FALSE, glm::value_ptr(projectionMatrix));
|
||||
m_projectionMatrix = glm::perspective(45.0f, 640.0f / 480.0f, 0.1f, 3000.0f);
|
||||
/*glm::mat4 modelviewMatrix = glm::lookAt(glm::vec3(-20.0f, 40.0f, -20.0f),
|
||||
glm::vec3(16.0f, 16.0f, 16.0f),
|
||||
glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
*/
|
||||
m_viewMatrix = m_camera.update();
|
||||
|
||||
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 1.0f, 1.0f),
|
||||
glm::vec3(0.0f, 0.0f, 0.0f),
|
||||
glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glUniformMatrix4fv(m_shader.uniform("u_viewMatrix"), 1, GL_FALSE, glm::value_ptr(viewMatrix));
|
||||
//glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);
|
||||
|
||||
m_shader.setUniform("u_tex", 0);
|
||||
|
||||
Shader::bind(nullptr);
|
||||
}
|
||||
|
||||
GameState::~GameState() {
|
||||
glDeleteBuffers(1, &m_vbo);
|
||||
}
|
||||
|
||||
void GameState::update() {
|
||||
m_viewMatrix = m_camera.processInputs();
|
||||
|
||||
//Shader::bind(&m_shader);
|
||||
//m_shader.setUniform("u_MVP", m_projectionMatrix * m_modelviewMatrix);
|
||||
//Shader::bind(nullptr);
|
||||
}
|
||||
|
||||
void GameState::draw() {
|
||||
Shader::bind(&m_shader);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
m_world.draw(m_shader, m_projectionMatrix * m_viewMatrix);
|
||||
|
||||
glVertexAttribPointer(m_shader.attrib("coord2d"), 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
|
||||
m_shader.enableVertexAttribArray("coord2d");
|
||||
|
||||
GLubyte indices[6] = {
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indices);
|
||||
|
||||
m_shader.disableVertexAttribArray("coord2d");
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
/*glBegin(GL_LINES);
|
||||
glColor3f(1, 1, 1); glVertex3f(0, 0, 0);
|
||||
glColor3f(1, 1, 1); glVertex3f(0, 5, 0);
|
||||
|
||||
glColor3f(1, 0, 1); glVertex3f(0, 0, 0);
|
||||
glColor3f(1, 0, 1); glVertex3f(5, 0, 0);
|
||||
|
||||
glColor3f(1, 1, 0); glVertex3f(0, 0, 0);
|
||||
glColor3f(1, 1, 0); glVertex3f(0, 0, 5);
|
||||
glEnd();*/
|
||||
|
||||
Shader::bind(nullptr);
|
||||
}
|
||||
|
286
source/world/Chunk.cpp
Normal file
286
source/world/Chunk.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: Chunk.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 15/12/2014 17:31:32
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <glm/gtc/noise.hpp>
|
||||
|
||||
#include "Chunk.hpp"
|
||||
|
||||
Chunk::Chunk(s32 x, s32 y, s32 z) {
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
m_z = z;
|
||||
|
||||
m_texture.loadFromFile("textures/cobblestone.bmp");
|
||||
|
||||
sf::Texture::bind(&m_texture);
|
||||
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
sf::Texture::bind(nullptr);
|
||||
|
||||
m_changed = false;
|
||||
m_initialized = false;
|
||||
|
||||
m_surroundingChunks[0] = nullptr;
|
||||
m_surroundingChunks[1] = nullptr;
|
||||
m_surroundingChunks[2] = nullptr;
|
||||
m_surroundingChunks[3] = nullptr;
|
||||
}
|
||||
|
||||
Chunk::~Chunk() {
|
||||
}
|
||||
|
||||
void Chunk::generate() {
|
||||
time_t seed = time(NULL);
|
||||
|
||||
for(u8 z = 0 ; z < depth ; z++) {
|
||||
for(u8 y = 0 ; y < height ; y++) {
|
||||
for(u8 x = 0 ; x < width ; x++) {
|
||||
float n = noise2d((x + m_x * width) / 256.0, (z + m_z * depth) / 256.0, seed, 5, 0.5) * 4;
|
||||
float h = 10 + n * 2;
|
||||
|
||||
/*float n = noise3d_abs((x + m_x * 32) * 0.015, (y + m_y * 32) * 0.015, (z + m_z * 32) * 0.015, seed, 3, 4) / 2;
|
||||
|
||||
if(3 < n && n < 8) {
|
||||
m_data.push_back(1);
|
||||
} else {
|
||||
m_data.push_back(0);
|
||||
}*/
|
||||
|
||||
if(y + m_y * height < h) {
|
||||
//if(y < abs(h)) {
|
||||
m_data.push_back(1);
|
||||
} else {
|
||||
m_data.push_back(0);
|
||||
}
|
||||
|
||||
// Random value used to determine land type
|
||||
/*float r = noise3d_abs((x + m_x * 32) / 16.0, (y + m_y * 32) / 16.0, (z + m_z * CZ) / 16.0, -seed, 2, 1);
|
||||
|
||||
// Sand layer
|
||||
if(n + r * 5 < 4) {
|
||||
//m_blocks[x][y][z] = 7;
|
||||
m_data.push_back(1);
|
||||
}
|
||||
// Dirt layer, but use grass blocks for the top
|
||||
else if(n + r * 5 < 8) {
|
||||
//m_blocks[x][y][z] = (h < 4 || y + m_y * 32 < h - 1) ? 1 : 3;
|
||||
m_data.push_back(1);
|
||||
}
|
||||
// Rock layer
|
||||
else if(r < 1.25) {
|
||||
//m_blocks[x][y][z] = 6;
|
||||
m_data.push_back(1);
|
||||
// Sometimes, ores!
|
||||
} else {
|
||||
//m_blocks[x][y][z] = 11;
|
||||
m_data.push_back(1);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_changed = true;
|
||||
}
|
||||
|
||||
#include "Debug.hpp"
|
||||
#include "GameClock.hpp"
|
||||
|
||||
void Chunk::update() {
|
||||
m_changed = false;
|
||||
|
||||
float cubeCoords[6 * 4 * 3] = {
|
||||
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
|
||||
};
|
||||
|
||||
float texCoords[2 * 4 * 6] = {
|
||||
0.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f
|
||||
};
|
||||
|
||||
for(int i = 1 ; i < 6 ; i++) {
|
||||
memcpy(&texCoords[2 * 4 * i], &texCoords[0], 2 * 4 * sizeof(float));
|
||||
}
|
||||
|
||||
m_vertices.clear();
|
||||
m_normals.clear();
|
||||
m_texCoords.clear();
|
||||
|
||||
//int truc = GameClock::getTicks(true);
|
||||
|
||||
for(u8 z = 0 ; z < depth ; z++) {
|
||||
for(u8 y = 0 ; y < height ; y++) {
|
||||
for(u8 x = 0 ; x < width ; x++) {
|
||||
if(getBlock(x, y, z)) {
|
||||
for(u8 i = 0 ; i < 6 ; i++) {
|
||||
if((x > 0 && getBlock(x - 1, y, z) && i == 0)
|
||||
|| (x < width - 1 && getBlock(x + 1, y, z) && i == 1)
|
||||
|| (y > 0 && getBlock(x, y - 1, z) && i == 2)
|
||||
|| (y < height - 1 && getBlock(x, y + 1, z) && i == 3)
|
||||
|| (z > 0 && getBlock(x, y, z - 1) && i == 5)
|
||||
|| (z < depth - 1 && getBlock(x, y, z + 1) && i == 4)
|
||||
|| (x == 0 && m_surroundingChunks[0] && m_surroundingChunks[0]->getBlock(width - 1, y, z) && i == 0)
|
||||
|| (x == width - 1 && m_surroundingChunks[1] && m_surroundingChunks[1]->getBlock(0, y, z) && i == 1)
|
||||
|| (z == 0 && m_surroundingChunks[2] && m_surroundingChunks[2]->getBlock(x, y, depth - 1) && i == 5)
|
||||
|| (z == depth - 1 && m_surroundingChunks[3] && m_surroundingChunks[3]->getBlock(x, y, 0) && i == 4)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::vec3 u(cubeCoords[i * 12 + 0], cubeCoords[i * 12 + 1], cubeCoords[i * 12 + 2]);
|
||||
glm::vec3 v(cubeCoords[i * 12 + 3], cubeCoords[i * 12 + 4], cubeCoords[i * 12 + 5]);
|
||||
glm::vec3 normal = glm::normalize(glm::cross(u, v));
|
||||
|
||||
for(u8 j = 0 ; j < 4 ; j++) {
|
||||
m_vertices.push_back(x + cubeCoords[i * 12 + j * 3]);
|
||||
m_vertices.push_back(y + cubeCoords[i * 12 + j * 3 + 1]);
|
||||
m_vertices.push_back(z + cubeCoords[i * 12 + j * 3 + 2]);
|
||||
|
||||
m_normals.push_back(normal.x);
|
||||
m_normals.push_back(normal.y);
|
||||
m_normals.push_back(normal.z);
|
||||
|
||||
m_texCoords.push_back(texCoords[i * 8 + j * 2]);
|
||||
m_texCoords.push_back(texCoords[i * 8 + j * 2 + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//DEBUG("Sending vertices:", GameClock::getTicks(true) - truc, "ms");
|
||||
|
||||
VertexBuffer::bind(&m_vbo);
|
||||
|
||||
m_vbo.setData((m_vertices.size() + m_normals.size() + m_texCoords.size()) * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
|
||||
m_vbo.updateData(0, m_vertices.size() * sizeof(float), m_vertices.data());
|
||||
m_vbo.updateData(m_vertices.size() * sizeof(float), m_normals.size() * sizeof(float), m_normals.data());
|
||||
m_vbo.updateData((m_vertices.size() + m_normals.size()) * sizeof(float), m_texCoords.size() * sizeof(float), m_texCoords.data());
|
||||
|
||||
VertexBuffer::bind(nullptr);
|
||||
}
|
||||
|
||||
void Chunk::draw(Shader &shader) {
|
||||
if(m_changed) {
|
||||
int truc = GameClock::getTicks(true);
|
||||
|
||||
//if(m_changed) update();
|
||||
update();
|
||||
|
||||
DEBUG("Chunk", m_x, m_y, m_z, "| Vertices:", m_vertices.size(), "| Update time:", GameClock::getTicks(true) - truc, "ms");
|
||||
}
|
||||
|
||||
if(m_vertices.size() == 0) return;
|
||||
|
||||
VertexBuffer::bind(&m_vbo);
|
||||
|
||||
shader.enableVertexAttribArray("coord3d");
|
||||
shader.enableVertexAttribArray("normal");
|
||||
shader.enableVertexAttribArray("texCoord");
|
||||
|
||||
glVertexAttribPointer(shader.attrib("coord3d"), 3, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glVertexAttribPointer(shader.attrib("normal"), 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(m_vertices.size() * sizeof(float)));
|
||||
glVertexAttribPointer(shader.attrib("texCoord"), 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)((m_vertices.size() + m_normals.size()) * sizeof(float)));
|
||||
|
||||
sf::Texture::bind(&m_texture);
|
||||
|
||||
glDrawArrays(GL_QUADS, 0, m_vertices.size());
|
||||
|
||||
sf::Texture::bind(nullptr);
|
||||
|
||||
shader.disableVertexAttribArray("texCoord");
|
||||
shader.disableVertexAttribArray("normal");
|
||||
shader.disableVertexAttribArray("coord3d");
|
||||
|
||||
VertexBuffer::bind(nullptr);
|
||||
}
|
||||
|
||||
u8 Chunk::getBlock(s8 x, s8 y, s8 z) {
|
||||
u16 i = x + y * width + z * width * height;
|
||||
if(i < m_data.size()) {
|
||||
return m_data[i];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
float Chunk::noise2d(float x, float y, int seed, int octaves, float persistence) {
|
||||
float sum = 0;
|
||||
float strength = 1.0;
|
||||
float scale = 1.0;
|
||||
|
||||
for(int i = 0 ; i < octaves ; i++) {
|
||||
sum += strength * glm::simplex(glm::vec2(x, y) * scale);
|
||||
scale *= 2.0;
|
||||
strength *= persistence;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
float Chunk::noise3d_abs(float x, float y, float z, int seed, int octaves, float persistence) {
|
||||
float sum = 0;
|
||||
float strength = 1.0;
|
||||
float scale = 1.0;
|
||||
|
||||
for(int i = 0 ; i < octaves ; i++) {
|
||||
sum += strength * fabs(glm::simplex(glm::vec3(x, y, z) * scale));
|
||||
scale *= 2.0;
|
||||
strength *= persistence;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
99
source/world/World.cpp
Normal file
99
source/world/World.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* =====================================================================================
|
||||
*
|
||||
* Filename: World.cpp
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Version: 1.0
|
||||
* Created: 16/12/2014 15:28:19
|
||||
* Revision: none
|
||||
* Compiler: gcc
|
||||
*
|
||||
* Author: Quentin BAZIN, <quent42340@gmail.com>
|
||||
* Company:
|
||||
*
|
||||
* =====================================================================================
|
||||
*/
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "World.hpp"
|
||||
|
||||
World::World() {
|
||||
m_width = 4;
|
||||
m_depth = 4;
|
||||
|
||||
//for(s32 z = -m_depth / 2 ; z < m_depth / 2 ; z++) {
|
||||
// for(s32 x = -m_width / 2 ; x < m_width / 2 ; x++) {
|
||||
for(s32 z = 0 ; z < m_depth ; z++) {
|
||||
for(s32 x = 0 ; x < m_width ; x++) {
|
||||
m_chunks.push_back(std::unique_ptr<Chunk>(new Chunk(x, 0, z)));
|
||||
}
|
||||
}
|
||||
|
||||
for(s32 z = 0 ; z < m_depth ; z++) {
|
||||
for(s32 x = 0 ; x < m_width ; x++) {
|
||||
if(x > 0) getChunk(x, z)->setLeft(getChunk(x - 1, z));
|
||||
if(x < m_width - 1) getChunk(x, z)->setRight(getChunk(x + 1, z));
|
||||
if(z > 0) getChunk(x, z)->setFront(getChunk(x, z - 1));
|
||||
if(z < m_depth - 1) getChunk(x, z)->setBack(getChunk(x, z + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
World::~World() {
|
||||
}
|
||||
|
||||
#include "Debug.hpp"
|
||||
|
||||
void World::draw(Shader &shader, const glm::mat4 &pv) {
|
||||
float ud = 0.0;
|
||||
s32 ux = -1;
|
||||
s32 uz = -1;
|
||||
|
||||
for(auto &it : m_chunks) {
|
||||
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(it->x() * Chunk::width, it->y() * Chunk::height, it->z() * Chunk::depth));
|
||||
glm::mat4 mvp = pv * model;
|
||||
|
||||
// Is this chunk on the screen?
|
||||
glm::vec4 center = mvp * glm::vec4(Chunk::width / 2, Chunk::height / 2, Chunk::depth / 2, 1);
|
||||
|
||||
float d = glm::length(center);
|
||||
center.x /= center.w;
|
||||
center.y /= center.w;
|
||||
|
||||
// If it is behind the camera, don't bother drawing it
|
||||
if(center.z < -Chunk::height / 2)
|
||||
continue;
|
||||
|
||||
// It it is outside the screen, don't bother drawing it
|
||||
if(fabsf(center.x) > 1 + fabsf(Chunk::height * 2 / center.w) || fabsf(center.y) > 1 + fabsf(Chunk::height * 2 / center.w))
|
||||
continue;
|
||||
|
||||
if(!it->initialized()) {
|
||||
if(ux < 0 || d < ud) {
|
||||
ud = d;
|
||||
ux = it->x();
|
||||
uz = it->z();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
shader.setUniform("u_modelMatrix", model);
|
||||
shader.setUniform("u_viewProjectionMatrix", pv);
|
||||
|
||||
it->draw(shader);
|
||||
}
|
||||
|
||||
if(ux >= 0) {
|
||||
getChunk(ux, uz)->generate();
|
||||
if(getChunk(ux, uz)->left()) getChunk(ux, uz)->left()->generate();
|
||||
if(getChunk(ux, uz)->right()) getChunk(ux, uz)->right()->generate();
|
||||
if(getChunk(ux, uz)->front()) getChunk(ux, uz)->front()->generate();
|
||||
if(getChunk(ux, uz)->back()) getChunk(ux, uz)->back()->generate();
|
||||
getChunk(ux, uz)->setInitialized(true);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user