@@ -1,9 +1,10 @@ | |||
add_library(libcygnet SHARED | |||
src/Context.cc | |||
src/Program.cc | |||
src/GlWrappers.cc | |||
src/Renderer.cc | |||
src/shaders.cc | |||
src/TileAtlas.cc | |||
src/util.cc | |||
src/Window.cc) | |||
target_include_directories(libcygnet | |||
PUBLIC "include" |
@@ -23,10 +23,10 @@ public: | |||
GlShader(Type type, const char *source); | |||
~GlShader(); | |||
GlID id() const { return id_; } | |||
GLuint id() const { return id_; } | |||
private: | |||
GlID id_; | |||
GLuint id_; | |||
}; | |||
class GlVxShader: public GlShader { | |||
@@ -47,18 +47,35 @@ public: | |||
~GlProgram(); | |||
void use(); | |||
GlID id() const { return id_; } | |||
GLuint id() const { return id_; } | |||
protected: | |||
GlLoc attribLoc(const char *name); | |||
GlLoc uniformLoc(const char *name); | |||
GLint attribLoc(const char *name); | |||
GLint uniformLoc(const char *name); | |||
private: | |||
void addShader(const GlShader &shader); | |||
void link(); | |||
GlID id_; | |||
GLuint id_; | |||
}; | |||
class GlTexture { | |||
public: | |||
GlTexture(); | |||
void bind(); | |||
void upload(GLsizei width, GLsizei height, void *data, | |||
GLenum format, GLenum type); | |||
GLuint id() { return id_; } | |||
int width() { return w_; } | |||
int height() { return h_; } | |||
private: | |||
GLuint id_; | |||
int w_; | |||
int h_; | |||
}; | |||
} |
@@ -11,9 +11,11 @@ public: | |||
Renderer(); | |||
~Renderer(); | |||
void clear(); | |||
void draw(); | |||
void registerTileTexture(size_t tileId, const void *data, size_t len); | |||
void uploadTileTexture(); | |||
private: | |||
std::unique_ptr<RendererState> state_; | |||
}; |
@@ -12,6 +12,7 @@ public: | |||
~TileAtlas(); | |||
void addTile(size_t tileId, const void *data, size_t len); | |||
const unsigned char *getImage(size_t *w, size_t *h); | |||
private: | |||
std::unique_ptr<AtlasState> state_; |
@@ -1,13 +1,16 @@ | |||
#pragma once | |||
#include <stdexcept> | |||
#include <SDL_opengles2.h> | |||
#include <stdint.h> | |||
#include <SDL.h> | |||
namespace Cygnet { | |||
using GlID = uint32_t; | |||
using GlLoc = int32_t; | |||
// I don't want every use of Cygnet to drag in OpenGL headers. | |||
using GLint = int32_t; | |||
using GLuint = uint32_t; | |||
using GLsizei = int32_t; | |||
using GLenum = uint32_t; | |||
struct SDLError: public std::exception { | |||
SDLError(std::string msg): message(std::move(msg)) {} | |||
@@ -15,37 +18,13 @@ struct SDLError: public std::exception { | |||
std::string message; | |||
}; | |||
struct GLError: public std::exception { | |||
GLError(std::string msg): message(std::move(msg)) {} | |||
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; | |||
}; | |||
inline const char *glErrorString(int err) { | |||
#define errcase(x) case x: return #x | |||
switch (err) { | |||
errcase(GL_NO_ERROR); | |||
errcase(GL_INVALID_ENUM); | |||
errcase(GL_INVALID_VALUE); | |||
errcase(GL_INVALID_OPERATION); | |||
errcase(GL_INVALID_FRAMEBUFFER_OPERATION); | |||
errcase(GL_OUT_OF_MEMORY); | |||
default: return "(unknown)"; | |||
} | |||
#undef errcase | |||
} | |||
inline void sdlCheck(bool ok) { | |||
if (!ok) { | |||
throw SDLError(SDL_GetError()); | |||
} | |||
} | |||
inline void glCheck() { | |||
GLenum err = glGetError(); | |||
if (err != GL_NO_ERROR) { | |||
throw GLError(glErrorString(err)); | |||
} | |||
} | |||
void sdlCheck(bool ok); | |||
void glCheck(); | |||
} |
@@ -1,4 +1,4 @@ | |||
#include "Program.h" | |||
#include "GlWrappers.h" | |||
#include <SDL_opengles2.h> | |||
#include <iostream> | |||
@@ -68,11 +68,11 @@ void GlProgram::addShader(const GlShader &shader) { | |||
glCheck(); | |||
} | |||
GlLoc GlProgram::attribLoc(const char *name) { | |||
GLint GlProgram::attribLoc(const char *name) { | |||
return glGetAttribLocation(id_, name); | |||
} | |||
GlLoc GlProgram::uniformLoc(const char *name) { | |||
GLint GlProgram::uniformLoc(const char *name) { | |||
return glGetUniformLocation(id_, name); | |||
} | |||
@@ -97,4 +97,27 @@ void GlProgram::link() { | |||
} | |||
} | |||
GlTexture::GlTexture() { | |||
glGenTextures(1, &id_); | |||
glCheck(); | |||
} | |||
void GlTexture::bind() { | |||
glActiveTexture(GL_TEXTURE0); | |||
glBindTexture(GL_TEXTURE_2D, id_); | |||
} | |||
void GlTexture::upload(GLsizei width, GLsizei height, void *data, | |||
GLenum format, GLenum type) { | |||
w_ = width; | |||
h_ = height; | |||
bind(); | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, type, data); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |||
glCheck(); | |||
} | |||
} |
@@ -1,7 +1,9 @@ | |||
#include "Renderer.h" | |||
#include <SDL_opengles2.h> | |||
#include "shaders.h" | |||
#include "Program.h" | |||
#include "GlWrappers.h" | |||
#include "TileAtlas.h" | |||
#include "util.h" | |||
@@ -10,16 +12,16 @@ namespace Cygnet { | |||
struct TexturedProg: public GlProgram { | |||
using GlProgram::GlProgram; | |||
GlLoc position = attribLoc("position"); | |||
GlLoc texCoord = attribLoc("texCoord"); | |||
GlLoc tex = uniformLoc("tex"); | |||
GLint position = attribLoc("position"); | |||
GLint texCoord = attribLoc("texCoord"); | |||
GLint tex = uniformLoc("tex"); | |||
}; | |||
struct SolidColorProg: public GlProgram { | |||
using GlProgram::GlProgram; | |||
GlLoc position = attribLoc("position"); | |||
GlLoc color = uniformLoc("color"); | |||
GLint position = attribLoc("position"); | |||
GLint color = uniformLoc("color"); | |||
}; | |||
struct RendererState { | |||
@@ -32,10 +34,25 @@ struct RendererState { | |||
SolidColorProg solidColorProg{basicVx, solidColorFr}; | |||
TileAtlas atlas; | |||
GlTexture atlasTex; | |||
}; | |||
Renderer::Renderer(): state_(std::make_unique<RendererState>()) {} | |||
Renderer::~Renderer() = default; | |||
void Renderer::draw() { | |||
state_->texturedProg.use(); | |||
} | |||
void Renderer::registerTileTexture(size_t tileId, const void *data, size_t len) { | |||
state_->atlas.addTile(tileId, data, len); | |||
} | |||
void Renderer::uploadTileTexture() { | |||
size_t w, h; | |||
const unsigned char *data = state_->atlas.getImage(&w, &h); | |||
state_->atlasTex.upload(w, h, (void *)data, GL_RGBA, GL_UNSIGNED_BYTE); | |||
} | |||
} |
@@ -56,4 +56,10 @@ void TileAtlas::addTile(size_t tileId, const void *data, size_t len) { | |||
} | |||
} | |||
const unsigned char *TileAtlas::getImage(size_t *w, size_t *h) { | |||
*w = state_->width * SwanCommon::TILE_SIZE; | |||
*h = state_->height * SwanCommon::TILE_SIZE; | |||
return state_->data.data(); | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
#include "util.h" | |||
#include <SDL_opengles2.h> | |||
namespace Cygnet { | |||
inline const char *glErrorString(int err) { | |||
#define errcase(x) case x: return #x | |||
switch (err) { | |||
errcase(GL_NO_ERROR); | |||
errcase(GL_INVALID_ENUM); | |||
errcase(GL_INVALID_VALUE); | |||
errcase(GL_INVALID_OPERATION); | |||
errcase(GL_INVALID_FRAMEBUFFER_OPERATION); | |||
errcase(GL_OUT_OF_MEMORY); | |||
default: return "(unknown)"; | |||
} | |||
#undef errcase | |||
} | |||
void sdlCheck(bool ok) { | |||
if (!ok) { | |||
throw SDLError(SDL_GetError()); | |||
} | |||
} | |||
void glCheck() { | |||
GLenum err = glGetError(); | |||
if (err != GL_NO_ERROR) { | |||
throw GlError(glErrorString(err)); | |||
} | |||
} | |||
} |
@@ -1,7 +1,9 @@ | |||
#include <cygnet/Context.h> | |||
#include <cygnet/Window.h> | |||
#include <cygnet/Renderer.h> | |||
#include <swan-common/constants.h> | |||
#include <stdint.h> | |||
#include <SDL.h> | |||
int main() { | |||
@@ -9,6 +11,13 @@ int main() { | |||
Cygnet::Window win("Cygnet Test", 640, 480); | |||
Cygnet::Renderer rnd; | |||
uint32_t img[SwanCommon::TILE_SIZE * SwanCommon::TILE_SIZE]; | |||
for (size_t i = 0; i < sizeof(img) / sizeof(*img); ++i) { | |||
img[i] = 0xff00aaff; | |||
} | |||
rnd.registerTileTexture(0, img, sizeof(img)); | |||
rnd.uploadTileTexture(); | |||
while (true) { | |||
SDL_Event evt; | |||
while (SDL_PollEvent(&evt)) { | |||
@@ -18,6 +27,8 @@ int main() { | |||
} | |||
} | |||
win.clear(); | |||
rnd.draw(); | |||
win.flip(); | |||
} | |||