add_library(libcygnet SHARED | add_library(libcygnet SHARED | ||||
src/shaders/basic.cc | |||||
src/Context.cc | src/Context.cc | ||||
src/Program.cc | |||||
src/Renderer.cc | |||||
src/Window.cc) | src/Window.cc) | ||||
target_include_directories(libcygnet | target_include_directories(libcygnet | ||||
PUBLIC "include" | PUBLIC "include" |
#pragma once | |||||
#include <stdint.h> | |||||
#include <stdexcept> | |||||
#include "util.h" | |||||
namespace Cygnet { | |||||
struct GlCompileError: public std::exception { | |||||
GlCompileError(std::string message): message(std::move(message)) {} | |||||
const char *what() const noexcept override { return message.c_str(); } | |||||
std::string message; | |||||
}; | |||||
class GlShader { | |||||
public: | |||||
enum class Type { | |||||
VERTEX, | |||||
FRAGMENT, | |||||
}; | |||||
GlShader(Type type, const char *source); | |||||
~GlShader(); | |||||
GlID id() const { return id_; } | |||||
private: | |||||
GlID id_; | |||||
}; | |||||
class GlVxShader: public GlShader { | |||||
public: | |||||
explicit GlVxShader(const char *source): GlShader(Type::VERTEX, source) {} | |||||
}; | |||||
class GlFrShader: public GlShader { | |||||
public: | |||||
explicit GlFrShader(const char *source): GlShader(Type::FRAGMENT, source) {} | |||||
}; | |||||
class GlProgram { | |||||
public: | |||||
template <typename... T> | |||||
GlProgram(const T &... shaders): GlProgram() { (addShader(shaders), ...); link(); } | |||||
GlProgram(); | |||||
~GlProgram(); | |||||
void use(); | |||||
GlID id() const { return id_; } | |||||
protected: | |||||
GlLoc attribLoc(const char *name); | |||||
GlLoc uniformLoc(const char *name); | |||||
private: | |||||
void addShader(const GlShader &shader); | |||||
void link(); | |||||
GlID id_; | |||||
}; | |||||
} |
#pragma once | |||||
#include <memory> | |||||
namespace Cygnet { | |||||
struct RendererState; | |||||
class Renderer { | |||||
public: | |||||
Renderer(); | |||||
~Renderer(); | |||||
void clear(); | |||||
void draw(); | |||||
private: | |||||
std::unique_ptr<RendererState> state_; | |||||
}; | |||||
} |
#pragma once | |||||
namespace Cygnet::Shaders { | |||||
extern const char *texturedQuadVx; | |||||
extern const char *texturedFr; | |||||
extern const char *coloredQuadVx; | |||||
extern const char *coloredFr; | |||||
} |
namespace Cygnet { | namespace Cygnet { | ||||
using GlID = uint32_t; | |||||
using GlLoc = int32_t; | |||||
struct SDLError: public std::exception { | struct SDLError: public std::exception { | ||||
SDLError(std::string msg): message(std::move(msg)) {} | SDLError(std::string msg): message(std::move(msg)) {} | ||||
const char *what() const noexcept override { return message.c_str(); } | |||||
std::string message; | std::string message; | ||||
const char *what() const noexcept override { | |||||
return message.c_str(); | |||||
} | |||||
}; | }; | ||||
struct GLError: public std::exception { | struct GLError: public std::exception { | ||||
GLError(std::string msg): message(std::move(msg)) {} | GLError(std::string msg): message(std::move(msg)) {} | ||||
const char *what() const noexcept override { return message.c_str(); } | |||||
std::string message; | std::string message; | ||||
const char *what() const noexcept override { | |||||
return message.c_str(); | |||||
} | |||||
}; | }; | ||||
inline const char *glErrorString(int err) { | inline const char *glErrorString(int err) { |
#include "Program.h" | |||||
#include <SDL_opengles2.h> | |||||
#include <iostream> | |||||
#include "util.h" | |||||
namespace Cygnet { | |||||
GlShader::GlShader(Type type, const char *source) { | |||||
switch (type) { | |||||
case Type::VERTEX: | |||||
id_ = glCreateShader(GL_VERTEX_SHADER); | |||||
glCheck(); | |||||
std::cerr << "Cygnet: Compiling vertex shader...\n"; | |||||
break; | |||||
case Type::FRAGMENT: | |||||
id_ = glCreateShader(GL_FRAGMENT_SHADER); | |||||
glCheck(); | |||||
std::cerr << "Cygnet: Compiling fragment shader...\n"; | |||||
break; | |||||
} | |||||
glShaderSource(id_, 1, &source, NULL); | |||||
glCheck(); | |||||
glCompileShader(id_); | |||||
glCheck(); | |||||
char log[4096]; | |||||
GLsizei length = 0; | |||||
glGetShaderInfoLog(id_, sizeof(log), &length, log); | |||||
glCheck(); | |||||
if (length != 0) { | |||||
std::cerr << "Cygnet: Shader compile info (" << length << "):\n" << log << '\n'; | |||||
} | |||||
GLint status = 0; | |||||
glGetShaderiv(id_, GL_COMPILE_STATUS, &status); | |||||
glCheck(); | |||||
if (status == GL_FALSE) { | |||||
throw GlCompileError("GL shader compilation failed."); | |||||
} | |||||
} | |||||
GlShader::~GlShader() { | |||||
glDeleteShader(id_); | |||||
glCheck(); | |||||
} | |||||
GlProgram::GlProgram() { | |||||
id_ = glCreateProgram(); | |||||
glCheck(); | |||||
} | |||||
GlProgram::~GlProgram() { | |||||
glDeleteProgram(id_); | |||||
glCheck(); | |||||
} | |||||
void GlProgram::use() { | |||||
glUseProgram(id_); | |||||
glCheck(); | |||||
} | |||||
void GlProgram::addShader(const GlShader &shader) { | |||||
glAttachShader(id_, shader.id()); | |||||
glCheck(); | |||||
} | |||||
GlLoc GlProgram::attribLoc(const char *name) { | |||||
return glGetAttribLocation(id_, name); | |||||
} | |||||
GlLoc GlProgram::uniformLoc(const char *name) { | |||||
return glGetUniformLocation(id_, name); | |||||
} | |||||
void GlProgram::link() { | |||||
std::cout << "Cygnet: Linking...\n"; | |||||
glLinkProgram(id_); | |||||
glCheck(); | |||||
char log[4096]; | |||||
GLsizei length = 0; | |||||
glGetProgramInfoLog(id_, sizeof(log), &length, log); | |||||
glCheck(); | |||||
if (length != 0) { | |||||
std::cerr << "Cygnet: Program link info:\n" << log << '\n'; | |||||
} | |||||
GLint status = 0; | |||||
glGetProgramiv(id_, GL_LINK_STATUS, &status); | |||||
glCheck(); | |||||
if (status == GL_FALSE) { | |||||
throw GlCompileError("GL program link failed."); | |||||
} | |||||
} | |||||
} |
#include "Renderer.h" | |||||
#include "shaders.h" | |||||
#include "Program.h" | |||||
#include "util.h" | |||||
namespace Cygnet { | |||||
struct TexturedQuad: public GlProgram { | |||||
using GlProgram::GlProgram; | |||||
GlLoc position = attribLoc("position"); | |||||
GlLoc texCoord = attribLoc("texCoord"); | |||||
GlLoc tex = uniformLoc("tex"); | |||||
}; | |||||
struct ColoredQuad: public GlProgram { | |||||
using GlProgram::GlProgram; | |||||
GlLoc position = attribLoc("position"); | |||||
GlLoc color = uniformLoc("color"); | |||||
}; | |||||
struct RendererState { | |||||
GlVxShader texturedQuadVx{Shaders::texturedQuadVx}; | |||||
GlFrShader texturedFr{Shaders::texturedFr}; | |||||
GlVxShader coloredQuadVx{Shaders::texturedQuadVx}; | |||||
GlFrShader coloredFr{Shaders::texturedFr}; | |||||
TexturedQuad texturedQuad{texturedQuadVx, texturedFr}; | |||||
ColoredQuad coloredQuad{coloredQuadVx, coloredFr}; | |||||
}; | |||||
Renderer::Renderer(): state_(std::make_unique<RendererState>()) {} | |||||
Renderer::~Renderer() = default; | |||||
} |
onResize(w, h); | onResize(w, h); | ||||
} | } | ||||
Window::~Window() { | |||||
} | |||||
Window::~Window() = default; | |||||
void Window::makeCurrent() { | void Window::makeCurrent() { | ||||
SDL_GL_MakeCurrent(state_->window, state_->glctx); | SDL_GL_MakeCurrent(state_->window, state_->glctx); |
#include "shaders.h" | |||||
namespace Cygnet::Shaders { | |||||
const char *texturedQuadVx = R"glsl( | |||||
uniform mat3 transform; | |||||
attribute vec2 position; | |||||
attribute vec2 texCoord; | |||||
varying vec2 v_texCoord; | |||||
void main() { | |||||
vec3 pos = transform * vec3(position, 0); | |||||
gl_Position = vec4(pos.x, pos.y, 0, 1); | |||||
v_texCoord = texCoord; | |||||
} | |||||
)glsl"; | |||||
const char *texturedFr = R"glsl( | |||||
precision mediump float; | |||||
varying vec2 v_texCoord; | |||||
uniform sampler2D tex; | |||||
void main() { | |||||
gl_FragColor = texture2D(tex, v_texCoord); | |||||
} | |||||
)glsl"; | |||||
const char *coloredQuadVx = R"glsl( | |||||
uniform mat3 transform; | |||||
attribute vec2 position; | |||||
void main() { | |||||
vec3 pos = transform * vec3(position, 0); | |||||
gl_Position = vec4(pos.x, pos.y, 0, 1); | |||||
} | |||||
)glsl"; | |||||
const char *coloredFr = R"glsl( | |||||
precision mediump float; | |||||
uniform vec4 color; | |||||
void main() { | |||||
gl_FragColor = color; | |||||
} | |||||
)glsl"; | |||||
} |
#include <cygnet/Context.h> | #include <cygnet/Context.h> | ||||
#include <cygnet/Window.h> | #include <cygnet/Window.h> | ||||
#include <cygnet/Renderer.h> | |||||
#include <SDL.h> | #include <SDL.h> | ||||
int main() { | int main() { | ||||
Cygnet::Context ctx; | Cygnet::Context ctx; | ||||
Cygnet::Window win("Cygnet Test", 640, 480); | Cygnet::Window win("Cygnet Test", 640, 480); | ||||
Cygnet::Renderer rnd; | |||||
while (true) { | while (true) { | ||||
SDL_Event evt; | SDL_Event evt; |