@@ -1,5 +1,8 @@ | |||
add_library(libcygnet SHARED | |||
src/shaders/basic.cc | |||
src/Context.cc | |||
src/Program.cc | |||
src/Renderer.cc | |||
src/Window.cc) | |||
target_include_directories(libcygnet | |||
PUBLIC "include" |
@@ -0,0 +1,64 @@ | |||
#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_; | |||
}; | |||
} |
@@ -0,0 +1,21 @@ | |||
#pragma once | |||
#include <memory> | |||
namespace Cygnet { | |||
struct RendererState; | |||
class Renderer { | |||
public: | |||
Renderer(); | |||
~Renderer(); | |||
void clear(); | |||
void draw(); | |||
private: | |||
std::unique_ptr<RendererState> state_; | |||
}; | |||
} |
@@ -0,0 +1,11 @@ | |||
#pragma once | |||
namespace Cygnet::Shaders { | |||
extern const char *texturedQuadVx; | |||
extern const char *texturedFr; | |||
extern const char *coloredQuadVx; | |||
extern const char *coloredFr; | |||
} |
@@ -6,22 +6,19 @@ | |||
namespace Cygnet { | |||
using GlID = uint32_t; | |||
using GlLoc = int32_t; | |||
struct SDLError: public std::exception { | |||
SDLError(std::string msg): message(std::move(msg)) {} | |||
const char *what() const noexcept override { return message.c_str(); } | |||
std::string message; | |||
const char *what() const noexcept override { | |||
return message.c_str(); | |||
} | |||
}; | |||
struct GLError: public std::exception { | |||
GLError(std::string msg): message(std::move(msg)) {} | |||
const char *what() const noexcept override { return message.c_str(); } | |||
std::string message; | |||
const char *what() const noexcept override { | |||
return message.c_str(); | |||
} | |||
}; | |||
inline const char *glErrorString(int err) { |
@@ -0,0 +1,100 @@ | |||
#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."); | |||
} | |||
} | |||
} |
@@ -0,0 +1,38 @@ | |||
#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; | |||
} |
@@ -31,8 +31,7 @@ Window::Window(const char *name, int w, int h): | |||
onResize(w, h); | |||
} | |||
Window::~Window() { | |||
} | |||
Window::~Window() = default; | |||
void Window::makeCurrent() { | |||
SDL_GL_MakeCurrent(state_->window, state_->glctx); |
@@ -0,0 +1,43 @@ | |||
#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"; | |||
} |
@@ -1,11 +1,13 @@ | |||
#include <cygnet/Context.h> | |||
#include <cygnet/Window.h> | |||
#include <cygnet/Renderer.h> | |||
#include <SDL.h> | |||
int main() { | |||
Cygnet::Context ctx; | |||
Cygnet::Window win("Cygnet Test", 640, 480); | |||
Cygnet::Renderer rnd; | |||
while (true) { | |||
SDL_Event evt; |