Created
December 31, 2017 17:03
-
-
Save MagicRB/b8658bb1cd29018336e8c1db266cd87e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* main.cpp | |
* | |
* Created on: Dec 30, 2017 | |
* Author: Magic_RB | |
*/ | |
#include <iostream> | |
#include <vector> | |
#include <experimental/random> | |
#include <fstream> | |
#include <GL/glew.h> | |
#include <GLFW/glfw3.h> | |
#include <glm/ext.hpp> | |
#include "bmpread.h" | |
struct vertex { | |
glm::vec2 pos, uv; | |
}; | |
struct tile { | |
bool bomb = false; | |
bool revealed = true ; | |
bool flag = false; | |
short unsigned int number = 0; | |
GLuint vertexbuffer; | |
}; | |
tile safe_tile_at(std::vector<std::vector<tile>> vector, short unsigned int x, short unsigned int y) | |
{ | |
try { | |
return vector.at(x).at(y); | |
} catch(const std::exception& e) { | |
return tile(); | |
} | |
} | |
void delete_vbo_for_tiles(std::vector<std::vector<tile>>* mine_field) | |
{ | |
for (short unsigned int x = 0; x < mine_field->size(); x++) { | |
for (short unsigned int y = 0; y < mine_field->at(x).size(); y++) { | |
glDeleteBuffers(1, &mine_field->at(x).at(y).vertexbuffer); | |
} | |
} | |
} | |
void clear_mine_field(std::vector<std::vector<tile>>* mine_field) | |
{ | |
delete_vbo_for_tiles(mine_field); | |
for (short unsigned int x = 0; x < mine_field->size(); x++) { | |
for (short unsigned int y = 0; y < mine_field->at(x).size(); y++) { | |
mine_field->at(x).at(y) = tile(); | |
} | |
} | |
} | |
unsigned char* ReadBMP(char* filename) | |
{ | |
int i; | |
FILE* f = fopen(filename, "rb"); | |
unsigned char info[54]; | |
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header | |
// extract image height and width from header | |
int width = *(int*)&info[18]; | |
int height = *(int*)&info[22]; | |
int size = 3 * width * height; | |
unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel | |
fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once | |
fclose(f); | |
for(i = 0; i < size; i += 3) | |
{ | |
unsigned char tmp = data[i]; | |
data[i] = data[i+2]; | |
data[i+2] = tmp; | |
} | |
return data; | |
} | |
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){ | |
// Create the shaders | |
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER); | |
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); | |
// Read the Vertex Shader code from the file | |
std::string VertexShaderCode; | |
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in); | |
if(VertexShaderStream.is_open()){ | |
std::string Line = ""; | |
while(getline(VertexShaderStream, Line)) | |
VertexShaderCode += "\n" + Line; | |
VertexShaderStream.close(); | |
}else{ | |
printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path); | |
getchar(); | |
return 0; | |
} | |
// Read the Fragment Shader code from the file | |
std::string FragmentShaderCode; | |
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in); | |
if(FragmentShaderStream.is_open()){ | |
std::string Line = ""; | |
while(getline(FragmentShaderStream, Line)) | |
FragmentShaderCode += "\n" + Line; | |
FragmentShaderStream.close(); | |
} | |
GLint Result = GL_FALSE; | |
int InfoLogLength; | |
// Compile Vertex Shader | |
printf("Compiling shader : %s\n", vertex_file_path); | |
char const * VertexSourcePointer = VertexShaderCode.c_str(); | |
glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL); | |
glCompileShader(VertexShaderID); | |
// Check Vertex Shader | |
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> VertexShaderErrorMessage(InfoLogLength+1); | |
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]); | |
printf("%s\n", &VertexShaderErrorMessage[0]); | |
} | |
// Compile Fragment Shader | |
printf("Compiling shader : %s\n", fragment_file_path); | |
char const * FragmentSourcePointer = FragmentShaderCode.c_str(); | |
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL); | |
glCompileShader(FragmentShaderID); | |
// Check Fragment Shader | |
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result); | |
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1); | |
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]); | |
printf("%s\n", &FragmentShaderErrorMessage[0]); | |
} | |
// Link the program | |
printf("Linking program\n"); | |
GLuint ProgramID = glCreateProgram(); | |
glAttachShader(ProgramID, VertexShaderID); | |
glAttachShader(ProgramID, FragmentShaderID); | |
glLinkProgram(ProgramID); | |
// Check the program | |
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result); | |
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength); | |
if ( InfoLogLength > 0 ){ | |
std::vector<char> ProgramErrorMessage(InfoLogLength+1); | |
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]); | |
printf("%s\n", &ProgramErrorMessage[0]); | |
} | |
glDetachShader(ProgramID, VertexShaderID); | |
glDetachShader(ProgramID, FragmentShaderID); | |
glDeleteShader(VertexShaderID); | |
glDeleteShader(FragmentShaderID); | |
return ProgramID; | |
} | |
void populate_mine_field(std::vector<std::vector<tile>>* mine_field, short unsigned int number_of_bombs, short unsigned int number_of_collums, short unsigned int number_of_rows) | |
{ | |
clear_mine_field(mine_field); | |
mine_field->resize(number_of_collums, std::vector<tile>(number_of_rows, tile())); | |
for (short unsigned int i = 0; i < number_of_bombs; i++) { | |
int x = std::experimental::randint(0, number_of_collums - 1); | |
int y = std::experimental::randint(0, number_of_rows - 1); | |
while (mine_field->at(x).at(y).bomb == true) { | |
x = std::experimental::randint(0, number_of_collums - 1); | |
y = std::experimental::randint(0, number_of_rows - 1); | |
} | |
mine_field->at(x).at(y).bomb = true; | |
} | |
for (short unsigned int x = 0; x < mine_field->size(); x++) { | |
for (short unsigned int y = 0; y < mine_field->at(x).size(); y++) { | |
short unsigned int b = 0; | |
if (safe_tile_at(*mine_field, x - 1, y - 1).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x , y - 1).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x + 1, y - 1).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x - 1, y ).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x + 1, y ).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x - 1, y + 1).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x , y + 1).bomb == true) { b++; } | |
if (safe_tile_at(*mine_field, x + 1, y + 1).bomb == true) { b++; } | |
mine_field->at(x).at(y).number = b; | |
} | |
} | |
} | |
void reveal_mine_field(std::vector<std::vector<tile>>* mine_field) | |
{ | |
for (short unsigned int x = 0; x < mine_field->size(); x++) { | |
for (short unsigned int y = 0; y < mine_field->at(x).size(); y++) { | |
mine_field->at(x).at(y).revealed = true; | |
} | |
} | |
} | |
std::vector<std::vector<tile>> tile_matrix; | |
short unsigned int number_of_bombs = 15; | |
short unsigned int number_of_rows = 10; | |
short unsigned int number_of_collums = 10; | |
short unsigned int revealed_tiles = 0; | |
std::vector<vertex> tile_vector = { | |
{ { 0, 0 }, { 0, 0 } }, | |
{ { 32, 0 }, { 1, 0 } }, | |
{ { 0, 32 }, { 0, 1 } }, | |
{ { 0, 32 }, { 0, 1 } }, | |
{ { 32, 0 }, { 1, 0 } }, | |
{ { 32, 32 }, { 1, 1 } }, | |
}; | |
std::vector<vertex> translate_vector(const std::vector<vertex>& tile, const glm::vec2& pos) | |
{ | |
std::vector<vertex> res; | |
res.reserve(tile.size()); | |
for (const auto& v : tile) | |
{ | |
vertex nv = { v.pos + pos, v.uv }; | |
res.push_back(nv); | |
} | |
return res; | |
} | |
void generate_vbo_for_tiles(std::vector<std::vector<tile>>* mine_field) | |
{ | |
for (short unsigned int x = 0; x < mine_field->size(); x++) { | |
for (short unsigned int y = 0; y < mine_field->at(x).size(); y++) { | |
glGenBuffers(1, &mine_field->at(x)[y].vertexbuffer); | |
glBindBuffer(GL_ARRAY_BUFFER, mine_field->at(x)[y].vertexbuffer); | |
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * translate_vector(tile_vector, glm::vec2(x*32, y*32)).size(), translate_vector(tile_vector, glm::vec2(x*32, y*32)).data(), GL_STATIC_DRAW); | |
} | |
} | |
} | |
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) | |
{ | |
if (action == GLFW_PRESS && key == GLFW_KEY_Q) { | |
glfwSetWindowShouldClose(window, GLFW_TRUE); | |
} else if (action == GLFW_PRESS && key == GLFW_KEY_R) { | |
populate_mine_field(&tile_matrix, number_of_bombs, number_of_collums, number_of_rows); | |
generate_vbo_for_tiles(&tile_matrix); | |
} else if (action == GLFW_PRESS && key == GLFW_KEY_X) { | |
reveal_mine_field(&tile_matrix); | |
} | |
} | |
inline float layer2coord(int capacity, int layer) | |
{ | |
return std::max(0.0f, std::min(float(capacity - 1), std::floor(float(layer) + 0.5f))); | |
} | |
int main() | |
{ | |
GLuint VertexArrayID; | |
if (!glfwInit()) | |
{ | |
return -1; | |
} | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); | |
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
GLFWwindow* window = glfwCreateWindow(32*number_of_collums, 32*number_of_rows, "Mine Sweeper", NULL, NULL); | |
if (!window) { | |
return -1; | |
} | |
glfwMakeContextCurrent(window); | |
glewExperimental = true; | |
if (glewInit() != GLEW_OK) { | |
return -1; | |
} | |
glGenVertexArrays(1, &VertexArrayID); | |
glBindVertexArray(VertexArrayID); | |
populate_mine_field(&tile_matrix, number_of_bombs, number_of_collums, number_of_rows); | |
generate_vbo_for_tiles(&tile_matrix); | |
glfwSetKeyCallback(window, key_callback); | |
glm::mat4 projectionMatrix = glm::ortho(0.0f, (float)32*number_of_collums,(float)32*number_of_rows,0.0f, -0.1f, 100.0f); // glm::ortho(0.0f, (float)1024/*32*number_of_collums*/, 0.0f, (float)768/*32*number_of_rows*/, -1.0f, 1.0f); | |
// Create and compile our GLSL program from the shaders | |
GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" ); | |
glUseProgram(programID); | |
GLuint texture_array; | |
glGenTextures(1, &texture_array); | |
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_array); | |
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 32, 32, 12, GL_FALSE, GL_RGB, GL_UNSIGNED_BYTE, nullptr); | |
for (short unsigned int i = 0; i < 12; i++) { | |
bmpread_t bitmap; | |
bmpread((std::string("Textures/") + std::to_string(i) + std::string(".bmp")).c_str(), 0, &bitmap); | |
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, bitmap.width, bitmap.height, 1, GL_RGB, GL_UNSIGNED_BYTE, bitmap.rgb_data); | |
bmpread_free(&bitmap); | |
} | |
GLint projectionLoc = glGetUniformLocation(programID, "projectionMatrix" ); | |
GLint texLoc = glGetUniformLocation(programID, "tex"); | |
GLint layerLoc = glGetUniformLocation(programID, "layer"); | |
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); | |
while (!glfwWindowShouldClose(window)) { | |
glfwPollEvents(); | |
glClear(GL_COLOR_BUFFER_BIT); | |
for (short unsigned int x = 0; x < tile_matrix.size(); x++) { | |
for (short unsigned int y = 0; y < tile_matrix.at(x).size(); y++) { | |
if (tile_matrix[x][y].flag && !tile_matrix[x][y].revealed) { | |
// Set texture to flag | |
} else if (tile_matrix[x][y].bomb && tile_matrix[x][y].revealed) { | |
glUniform1f(layerLoc, layer2coord(12, 0)); | |
glEnableVertexAttribArray(0); | |
glBindBuffer(GL_ARRAY_BUFFER, tile_matrix[x][y].vertexbuffer); | |
glVertexAttribPointer( | |
0, // attribute 0. No particular reason for 0, but must match the layout in the shader. | |
2, // size | |
GL_FLOAT, // type | |
GL_FALSE, // normalized? | |
sizeof(vertex), // stride | |
(void*)offsetof(vertex, pos) // array buffer offset | |
); | |
glVertexAttribPointer( | |
1, // attribute 0. No particular reason for 0, but must match the layout in the shader. | |
2, // size | |
GL_FLOAT, // type | |
GL_FALSE, // normalized? | |
sizeof(vertex), // stride | |
(void*)offsetof(vertex, uv) // array buffer offset | |
); | |
// Draw the triangle ! | |
glDrawArrays(GL_TRIANGLES, 0, 6); // Starting from vertex 0; 3 vertices total -> 1 triangle | |
glDisableVertexAttribArray(0); | |
} else if (tile_matrix[x][y].revealed) { | |
if (tile_matrix[x][y].number == 0) { | |
} else if (tile_matrix[x][y].number == 1) { | |
} else if (tile_matrix[x][y].number == 2) { | |
} else if (tile_matrix[x][y].number == 3) { | |
} else if (tile_matrix[x][y].number == 4) { | |
} else if (tile_matrix[x][y].number == 5) { | |
} else if (tile_matrix[x][y].number == 6) { | |
} else if (tile_matrix[x][y].number == 7) { | |
} else if (tile_matrix[x][y].number == 8) { | |
} | |
} else { | |
} | |
} | |
} | |
glfwSwapBuffers(window); | |
} | |
delete_vbo_for_tiles(&tile_matrix); | |
glfwDestroyWindow(window); | |
glfwTerminate(); | |
} | |
// else if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { | |
// if (left_mouse_pressed == false) { | |
// if (tile_matrix[event.mouseButton.x / 32][event.mouseButton.y / 32].revealed == false) { | |
// tile_matrix[event.mouseButton.x / 32][event.mouseButton.y / 32].revealed = true; | |
// revealed_tiles++; | |
// text_revealed_tiles.setString(std::to_string(revealed_tiles)); | |
// } | |
// left_mouse_pressed = true; | |
// if (tile_matrix[event.mouseButton.x / 32][event.mouseButton.y / 32].bomb == true) reveal_mine_field(&tile_matrix); | |
// } | |
// } else if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) { | |
// left_mouse_pressed = false; | |
// } else if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Right) { | |
// if (right_mouse_pressed == false) { | |
// tile_matrix[event.mouseButton.x / 32][event.mouseButton.y / 32].flag = !tile_matrix[event.mouseButton.x / 32][event.mouseButton.y / 32].flag; | |
// right_mouse_pressed = true; | |
// } | |
// } else if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Right) { | |
// right_mouse_pressed = false; | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment