✨ Can draw colored rects.
parent
ae91f57f93
commit
9b4184aa3b
|
@ -0,0 +1,8 @@
|
|||
#version 130
|
||||
|
||||
in vec4 i_color;
|
||||
out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
o_color = i_color;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#version 130
|
||||
|
||||
in vec2 pos;
|
||||
in vec4 color;
|
||||
|
||||
out vec4 i_color;
|
||||
|
||||
uniform mat4 proj;
|
||||
|
||||
void main() {
|
||||
gl_Position = proj * vec4(pos, 0.0, 1.0);
|
||||
i_color = color;
|
||||
}
|
15
meson.build
15
meson.build
|
@ -22,8 +22,23 @@ executable(
|
|||
'bloody-gun',
|
||||
sources: [
|
||||
'src/main.cpp',
|
||||
|
||||
# core
|
||||
'src/Game.cpp',
|
||||
'src/BaseScene.cpp',
|
||||
'src/scenes/World.cpp',
|
||||
|
||||
# gfx
|
||||
'src/Renderer.cpp',
|
||||
'src/Shaders.cpp',
|
||||
'src/Canvas.cpp',
|
||||
|
||||
|
||||
],
|
||||
dependencies: [
|
||||
dependency('glew'),
|
||||
dependency('glm'),
|
||||
dependency('sdl2'),
|
||||
],
|
||||
install: true
|
||||
)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#include "BaseScene.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ BaseScene::BaseScene(Game& game)
|
||||
: m_game { game }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ BaseScene::~BaseScene()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef bg_BASESCENE_HPP
|
||||
#define bg_BASESCENE_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
#include "Renderer.hpp"
|
||||
#include "Game.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
class BaseScene
|
||||
{
|
||||
public:
|
||||
explicit BaseScene(Game& game);
|
||||
virtual ~BaseScene();
|
||||
|
||||
virtual void update(float /*dt*/) {}
|
||||
virtual void draw(Renderer const& /*renderer*/) {}
|
||||
|
||||
private:
|
||||
Game& m_game;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
#include "Canvas.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ Canvas::Canvas()
|
||||
{
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glBindVertexArray(m_vao);
|
||||
|
||||
glGenBuffers(1, &m_vbo);
|
||||
}
|
||||
|
||||
/*virtual*/ Canvas::~Canvas()
|
||||
{
|
||||
glDeleteBuffers(1, &m_vbo);
|
||||
glDeleteVertexArrays(1, &m_vao);
|
||||
}
|
||||
|
||||
void Canvas::use() const
|
||||
{
|
||||
m_shaders->use();
|
||||
glBindVertexArray(m_vao);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
}
|
||||
|
||||
void Canvas::draw(glm::mat4 const& transform) const
|
||||
{
|
||||
use();
|
||||
m_shaders->set_matrix("proj", transform);
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
|
||||
}
|
||||
|
||||
void Canvas::clear()
|
||||
{
|
||||
m_vertices.clear();
|
||||
update();
|
||||
}
|
||||
|
||||
void Canvas::rect(glm::vec2 const& pos,
|
||||
glm::vec2 const& size,
|
||||
glm::vec4 const& color)
|
||||
{
|
||||
// A -- B
|
||||
// | |
|
||||
// D -- C
|
||||
|
||||
Vertex a {pos.x - size.x/2.0f, pos.y - size.y/2.0f,
|
||||
color.x, color.y, color.z, color.w
|
||||
};
|
||||
|
||||
Vertex b {pos.x + size.x/2.0f, pos.y - size.y/2.0f,
|
||||
color.x, color.y, color.z, color.w};
|
||||
|
||||
Vertex c {pos.x + size.x/2.0f, pos.y + size.y/2.0f,
|
||||
color.x, color.y, color.z, color.w};
|
||||
|
||||
Vertex d {pos.x - size.x/2.0f, pos.y + size.y/2.0f,
|
||||
color.x, color.y, color.z, color.w};
|
||||
|
||||
m_vertices.push_back(a);
|
||||
m_vertices.push_back(b);
|
||||
m_vertices.push_back(c);
|
||||
|
||||
m_vertices.push_back(a);
|
||||
m_vertices.push_back(c);
|
||||
m_vertices.push_back(d);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void Canvas::update()
|
||||
{
|
||||
use();
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
m_vertices.size() * sizeof(Vertex),
|
||||
m_vertices.data(),
|
||||
GL_STATIC_DRAW);
|
||||
|
||||
GLint pos = m_shaders->attrib("pos");
|
||||
glEnableVertexAttribArray(pos);
|
||||
glVertexAttribPointer(pos,
|
||||
2,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(Vertex),
|
||||
nullptr);
|
||||
|
||||
GLint color = m_shaders->attrib("color");
|
||||
glEnableVertexAttribArray(color);
|
||||
glVertexAttribPointer(color,
|
||||
4,
|
||||
GL_FLOAT,
|
||||
GL_FALSE,
|
||||
sizeof(Vertex),
|
||||
reinterpret_cast<void*>(offsetof(Vertex, r)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef bg_CANVAS_HPP
|
||||
#define bg_CANVAS_HPP
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include "Shaders.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
struct Vertex
|
||||
{
|
||||
float x; float y;
|
||||
float r; float g; float b; float a;
|
||||
};
|
||||
|
||||
class Canvas
|
||||
{
|
||||
public:
|
||||
explicit Canvas();
|
||||
virtual ~Canvas();
|
||||
|
||||
void use() const;
|
||||
void draw(glm::mat4 const& transform) const;
|
||||
|
||||
// Draw shapes
|
||||
// -----------
|
||||
void clear();
|
||||
|
||||
void rect(glm::vec2 const& pos,
|
||||
glm::vec2 const& size,
|
||||
glm::vec4 const& color =
|
||||
glm::vec4 {0.0f, 0.0f, 0.0f, 1.0f});
|
||||
|
||||
private:
|
||||
std::shared_ptr<Shaders> m_shaders =
|
||||
std::make_shared<Shaders>();
|
||||
|
||||
GLuint m_vao;
|
||||
GLuint m_vbo;
|
||||
std::vector<Vertex> m_vertices;
|
||||
|
||||
void update();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
#include "Game.hpp"
|
||||
#include "BaseScene.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ Game::Game()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Game::~Game()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void Game::init()
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||
{
|
||||
throw game_error {"Cannot initialize SDL 2."};
|
||||
}
|
||||
|
||||
auto title = "Bloody Gun v" + BG_VERSION;
|
||||
|
||||
m_window = SDL_CreateWindow(title.c_str(),
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
1600, 900,
|
||||
SDL_WINDOW_SHOWN
|
||||
| SDL_WINDOW_FULLSCREEN
|
||||
| SDL_WINDOW_OPENGL);
|
||||
|
||||
if (!m_window)
|
||||
{
|
||||
throw game_error {"Cannot open SDL window."};
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
int w;
|
||||
int h;
|
||||
SDL_GetWindowSize(m_window, &w, &h);
|
||||
m_renderer = std::make_unique<Renderer>(w, h);
|
||||
}
|
||||
|
||||
m_context = SDL_GL_CreateContext(m_window);
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
throw game_error {std::string()
|
||||
+ "Cannot create SDL 2 GL context ("
|
||||
+ SDL_GetError()
|
||||
+ ")"};
|
||||
}
|
||||
|
||||
if (glewInit() != GLEW_OK)
|
||||
{
|
||||
throw game_error {"Cannot initialize glew."};
|
||||
}
|
||||
}
|
||||
|
||||
void Game::free()
|
||||
{
|
||||
SDL_GL_DeleteContext(m_context);
|
||||
SDL_DestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
int Game::start()
|
||||
{
|
||||
SDL_Event event;
|
||||
|
||||
m_running = true;
|
||||
float dt = 0.0f;
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
auto loop_start = std::chrono::steady_clock::now();
|
||||
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
if (event.type == SDL_QUIT)
|
||||
{
|
||||
m_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scene_stack.empty() == false)
|
||||
{
|
||||
m_scene_stack.back()->update(dt);
|
||||
}
|
||||
|
||||
glClearColor(1, 1, 1, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (m_scene_stack.empty() == false)
|
||||
{
|
||||
m_scene_stack.back()->draw(*m_renderer);
|
||||
}
|
||||
|
||||
SDL_GL_SwapWindow(m_window);
|
||||
|
||||
for (auto& scene: m_push_queue)
|
||||
{
|
||||
m_scene_stack.push_back(std::move(scene));
|
||||
}
|
||||
|
||||
m_push_queue.clear();
|
||||
|
||||
auto elapsed = std::chrono::steady_clock::now() - loop_start;
|
||||
dt = std::chrono::duration_cast<std::chrono::microseconds>(elapsed)
|
||||
.count() / 1000000.0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Game::queue_push(std::unique_ptr<BaseScene> scene)
|
||||
{
|
||||
m_push_queue.push_back(std::move(scene));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef bg_GAME_HPP
|
||||
#define bg_GAME_HPP
|
||||
|
||||
#include "commons.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "Renderer.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
BG_ERROR(game_error);
|
||||
|
||||
class BaseScene;
|
||||
|
||||
class Game
|
||||
{
|
||||
public:
|
||||
explicit Game();
|
||||
virtual ~Game();
|
||||
|
||||
// Lifecycle management
|
||||
// --------------------
|
||||
void init();
|
||||
void free();
|
||||
int start();
|
||||
|
||||
// Scenes
|
||||
// ------
|
||||
void queue_push(std::unique_ptr<BaseScene> scene);
|
||||
|
||||
private:
|
||||
bool m_running = false;
|
||||
SDL_Window* m_window = nullptr;
|
||||
std::unique_ptr<Renderer> m_renderer;
|
||||
SDL_GLContext m_context = nullptr;
|
||||
std::vector<std::unique_ptr<BaseScene>> m_scene_stack;
|
||||
std::vector<std::unique_ptr<BaseScene>> m_push_queue;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include "Renderer.hpp"
|
||||
#include "Canvas.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ Renderer::Renderer(int width, int height)
|
||||
: m_width { width }
|
||||
, m_height { height }
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ Renderer::~Renderer()
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::draw(Canvas const& canvas) const
|
||||
{
|
||||
glm::mat4 proj = glm::ortho(0.0f,
|
||||
static_cast<float>(m_width),
|
||||
static_cast<float>(m_height),
|
||||
0.0f);
|
||||
canvas.draw(proj);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef bg_RENDERER_HPP
|
||||
#define bg_RENDERER_HPP
|
||||
|
||||
namespace bg
|
||||
{
|
||||
class Canvas;
|
||||
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
explicit Renderer(int width, int height);
|
||||
virtual ~Renderer();
|
||||
|
||||
void draw(Canvas const& canvas) const;
|
||||
|
||||
private:
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,124 @@
|
|||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include "Shaders.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ Shaders::Shaders()
|
||||
{
|
||||
shader(BG_DATADIR / "assets" / "shaders" / "canvas_vertex.glsl",
|
||||
GL_VERTEX_SHADER);
|
||||
|
||||
shader(BG_DATADIR / "assets" / "shaders" / "canvas_fragment.glsl",
|
||||
GL_FRAGMENT_SHADER);
|
||||
|
||||
glLinkProgram(m_program);
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &status);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
size_t const SZ = 512;
|
||||
char msg[SZ];
|
||||
glGetProgramInfoLog(m_program, SZ, nullptr, msg);
|
||||
|
||||
throw shaders_error {std::string() + "Cannot link program.\n" + msg};
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ Shaders::~Shaders()
|
||||
{
|
||||
glDeleteProgram(m_program);
|
||||
}
|
||||
|
||||
void Shaders::use() const
|
||||
{
|
||||
glUseProgram(m_program);
|
||||
}
|
||||
|
||||
GLint Shaders::attrib(std::string const& name) const
|
||||
{
|
||||
use();
|
||||
|
||||
GLint loc = glGetAttribLocation(m_program, name.c_str());
|
||||
|
||||
if (loc < 0)
|
||||
{
|
||||
throw shaders_error {"Cannot find vertex attribute '"+name+"'."};
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
GLint Shaders::matrix(std::string const& name) const
|
||||
{
|
||||
use();
|
||||
|
||||
GLint loc = glGetUniformLocation(m_program, name.c_str());
|
||||
|
||||
if (loc < 0)
|
||||
{
|
||||
throw shaders_error {"Cannot find uniform '"+name+"'."};
|
||||
}
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
void Shaders::set_matrix(std::string const& name, glm::mat4 mat) const
|
||||
{
|
||||
use();
|
||||
glUniformMatrix4fv(matrix(name), 1, GL_FALSE, glm::value_ptr(mat));
|
||||
}
|
||||
|
||||
GLuint Shaders::shader(std::filesystem::path const& path, GLenum type)
|
||||
{
|
||||
if (!std::filesystem::is_regular_file(path))
|
||||
{
|
||||
throw shaders_error {"Shader file '" + path.string() + "' not found."};
|
||||
}
|
||||
|
||||
GLuint myshader = glCreateShader(type);
|
||||
|
||||
std::string source;
|
||||
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::ifstream file { path };
|
||||
|
||||
if (!file)
|
||||
{
|
||||
throw shaders_error {"Cannot open file '" + path.string() + "'"};
|
||||
}
|
||||
|
||||
ss << file.rdbuf();
|
||||
source = ss.str();
|
||||
}
|
||||
|
||||
char const* sources[] = {source.c_str()};
|
||||
|
||||
glShaderSource(myshader, 1, sources, nullptr);
|
||||
glCompileShader(myshader);
|
||||
|
||||
GLint status = GL_FALSE;
|
||||
|
||||
glGetShaderiv(myshader, GL_COMPILE_STATUS, &status);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
size_t const SZ = 512;
|
||||
char msg[SZ];
|
||||
glGetShaderInfoLog(myshader, SZ, nullptr, msg);
|
||||
|
||||
throw shaders_error {"Cannot compile shader '"
|
||||
+ path.string()
|
||||
+ "'\n"
|
||||
+ msg
|
||||
};
|
||||
}
|
||||
|
||||
glAttachShader(m_program, myshader);
|
||||
|
||||
return myshader;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef bg_SHADERS_HPP
|
||||
#define bg_SHADERS_HPP
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include "commons.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
BG_ERROR(shaders_error);
|
||||
|
||||
class Shaders
|
||||
{
|
||||
public:
|
||||
explicit Shaders();
|
||||
virtual ~Shaders();
|
||||
|
||||
void use() const;
|
||||
|
||||
// Attribute and Uniforms
|
||||
// ----------------------
|
||||
GLint attrib(std::string const& name) const;
|
||||
GLint matrix(std::string const& name) const;
|
||||
void set_matrix(std::string const& name, glm::mat4 mat) const;
|
||||
|
||||
private:
|
||||
GLuint m_program = glCreateProgram();
|
||||
|
||||
GLuint shader(std::filesystem::path const& path, GLenum type);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,7 +1,18 @@
|
|||
#ifndef bg_COMMONS_HPP
|
||||
#define bg_COMMONS_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include "conf.hpp"
|
||||
|
||||
|
||||
#define BG_ERROR(NAME) \
|
||||
struct NAME : public std::runtime_error { \
|
||||
explicit NAME (std::string const& what) \
|
||||
: std::runtime_error { what } {} \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
11
src/main.cpp
11
src/main.cpp
|
@ -1,8 +1,15 @@
|
|||
#include <iostream>
|
||||
#include "commons.hpp"
|
||||
#include "Game.hpp"
|
||||
#include "scenes/World.hpp"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
std::cout << "Bloody Gun v" << BG_VERSION << std::endl;
|
||||
return 0;
|
||||
bg::Game game;
|
||||
game.init();
|
||||
|
||||
auto world = std::make_unique<bg::World>(game);
|
||||
game.queue_push(std::move(world));
|
||||
|
||||
return game.start();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#include "World.hpp"
|
||||
#include "../Renderer.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
/*explicit*/ World::World(Game& game)
|
||||
: BaseScene(game)
|
||||
{
|
||||
m_canvas.rect(glm::vec2 {64.0f, 64.0f},
|
||||
glm::vec2 {128.0f, 32.0f},
|
||||
glm::vec4 {0.0f, 0.5f, 0.0f, 1.0f});
|
||||
|
||||
m_canvas.rect(glm::vec2 {512.0f, 512.0f},
|
||||
glm::vec2 {96.0f, 96.0f},
|
||||
glm::vec4 {0.5f, 0.0f, 0.0f, 1.0f});
|
||||
}
|
||||
|
||||
/*virtual*/ World::~World()
|
||||
{
|
||||
}
|
||||
|
||||
void World::update(float) /*override*/
|
||||
{
|
||||
}
|
||||
|
||||
void World::draw(Renderer const& renderer) /*override*/
|
||||
{
|
||||
renderer.draw(m_canvas);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef bg_WORLD_HPP
|
||||
#define bg_WORLD_HPP
|
||||
|
||||
#include "../commons.hpp"
|
||||
#include "../BaseScene.hpp"
|
||||
#include "../Canvas.hpp"
|
||||
|
||||
namespace bg
|
||||
{
|
||||
class World: public BaseScene
|
||||
{
|
||||
public:
|
||||
explicit World(Game& game);
|
||||
virtual ~World();
|
||||
|
||||
void update(float dt) override;
|
||||
void draw(Renderer const& renderer) override;
|
||||
|
||||
private:
|
||||
Canvas m_canvas;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue