Browse Source

sprites

feature/replace-renderer
Martin Dørum 3 years ago
parent
commit
6e0a99a42f
4 changed files with 121 additions and 95 deletions
  1. 26
    14
      libcygnet/include/cygnet/Renderer.h
  2. 78
    76
      libcygnet/src/Renderer.cc
  3. 4
    5
      libcygnet/src/shaders.cc
  4. 13
    0
      src/cygnet-test.cc

+ 26
- 14
libcygnet/include/cygnet/Renderer.h View File

@@ -13,12 +13,13 @@ namespace Cygnet {

struct RendererState;

struct RenderSprite {
struct RenderChunk {
GLuint tex;
};

struct RenderChunk {
struct RenderSprite {
GLuint tex;
SwanCommon::Vec2 scale;
};

struct RenderCamera {
@@ -35,9 +36,9 @@ public:
~Renderer();

void drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos);
void drawSprite(RenderSprite sprite, Mat3gf mat);
void drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos);
void drawSpriteFlipped(RenderSprite chunk, SwanCommon::Vec2 pos);
void drawSprite(RenderSprite sprite, Mat3gf mat, int y = 0);
void drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos, int y = 0);
void drawSpriteFlipped(RenderSprite chunk, SwanCommon::Vec2 pos, int y = 0);

void draw(const RenderCamera &cam);

@@ -49,30 +50,41 @@ public:
void modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id);
void destroyChunk(RenderChunk chunk);

RenderSprite createSprite(uint8_t *rgb, int width, int height);
RenderSprite createSprite(void *data, int width, int height);
void destroySprite(RenderSprite sprite);

private:
struct DrawChunk {
SwanCommon::Vec2 pos;
RenderChunk chunk;
};

struct DrawSprite {
Mat3gf transform;
int y;
RenderSprite sprite;
};

std::unique_ptr<RendererState> state_;

std::vector<std::pair<SwanCommon::Vec2, RenderChunk>> draw_chunks_;
std::vector<std::pair<Mat3gf, RenderSprite>> draw_sprites_;
std::vector<DrawChunk> draw_chunks_;
std::vector<DrawSprite> draw_sprites_;
};

inline void Renderer::drawChunk(RenderChunk chunk, SwanCommon::Vec2 pos) {
draw_chunks_.emplace_back(pos, chunk);
}

inline void Renderer::drawSprite(RenderSprite sprite, Mat3gf mat) {
draw_sprites_.emplace_back(mat, sprite);
inline void Renderer::drawSprite(RenderSprite sprite, Mat3gf mat, int y) {
draw_sprites_.emplace_back(mat, y, sprite);
}

inline void Renderer::drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos) {
draw_sprites_.emplace_back(Mat3gf{}.translate(pos), sprite);
inline void Renderer::drawSprite(RenderSprite sprite, SwanCommon::Vec2 pos, int y) {
draw_sprites_.emplace_back(Mat3gf{}.translate(pos), y, sprite);
}

inline void Renderer::drawSpriteFlipped(RenderSprite sprite, SwanCommon::Vec2 pos) {
draw_sprites_.emplace_back(Mat3gf{}.translate(pos).scale({ -1, 1 }), sprite);
inline void Renderer::drawSpriteFlipped(RenderSprite sprite, SwanCommon::Vec2 pos, int y) {
draw_sprites_.emplace_back(Mat3gf{}.translate(pos).scale({ -1, 1 }), y, sprite);
}

}

+ 78
- 76
libcygnet/src/Renderer.cc View File

@@ -17,47 +17,44 @@

namespace Cygnet {

struct SpriteProg: public GlProgram {
struct ChunkProg: public GlProgram {
template<typename... T>
SpriteProg(const T &... shaders): GlProgram(shaders...) { init(); }
~SpriteProg() { deinit(); }
ChunkProg(const T &... shaders): GlProgram(shaders...) { init(); }
~ChunkProg() { deinit(); }

GLint camera = uniformLoc("camera");
GLint transform = uniformLoc("transform");
GLint pos = uniformLoc("pos");
GLint vertex = attribLoc("vertex");
GLint texCoord = attribLoc("texCoord");
GLint tex = uniformLoc("tex");
GLint tileAtlas = uniformLoc("tileAtlas");
GLint tileAtlasSize = uniformLoc("tileAtlasSize");
GLint tiles = uniformLoc("tiles");

GLuint vbo;

static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT;
static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH;
static constexpr GLfloat vertexes[] = {
-0.5f, 0.5f, // pos 0: top left
0.0f, 0.0f, // tex 0: top left
-0.5f, -0.5f, // pos 1: bottom left
0.0f, 1.0f, // tex 1: bottom left
0.5f, -0.5f, // pos 2: bottom right
1.0f, 1.0f, // tex 2: bottom right
0.5f, -0.5f, // pos 2: bottom right
1.0f, 1.0f, // tex 2: bottom right
0.5f, 0.5f, // pos 3: top right
1.0f, 0.0f, // tex 3: top right
-0.5f, 0.5f, // pos 0: top left
0.0f, 0.0f, // tex 0: top left
0.0f, 0.0f, // pos 0: top left
0.0f, -ch , // pos 1: bottom left
cw, -ch, // pos 2: bottom right
cw, -ch, // pos 2: bottom right
cw, 0.0f, // pos 3: top right
0.0f, 0.0f, // pos 0: top left
};

void enable() {
glUseProgram(id());
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)0);
glVertexAttribPointer(texCoord, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)(2 * sizeof(GLfloat)));
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
glEnableVertexAttribArray(vertex);
glEnableVertexAttribArray(texCoord);
glCheck();

glUniform1i(tileAtlas, 0);
glUniform1i(tiles, 1);
}

void disable() {
glDisableVertexAttribArray(vertex);
glDisableVertexAttribArray(texCoord);
glCheck();
}

@@ -70,34 +67,30 @@ struct SpriteProg: public GlProgram {
glCheck();
}

void deinit() {
void deinit() {
glDeleteBuffers(1, &vbo);
glCheck();
}
};

struct ChunkProg: public GlProgram {
struct SpriteProg: public GlProgram {
template<typename... T>
ChunkProg(const T &... shaders): GlProgram(shaders...) { init(); }
~ChunkProg() { deinit(); }
SpriteProg(const T &... shaders): GlProgram(shaders...) { init(); }
~SpriteProg() { deinit(); }

GLint camera = uniformLoc("camera");
GLint pos = uniformLoc("pos");
GLint transform = uniformLoc("transform");
GLint vertex = attribLoc("vertex");
GLint tileAtlas = uniformLoc("tileAtlas");
GLint tileAtlasSize = uniformLoc("tileAtlasSize");
GLint tiles = uniformLoc("tiles");
GLint tex = uniformLoc("tex");

GLuint vbo;

static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT;
static constexpr float cw = (float)SwanCommon::CHUNK_WIDTH;
static constexpr GLfloat vertexes[] = {
0.0f, 0.0f, // pos 0: top left
0.0f, -ch , // pos 1: bottom left
cw, -ch, // pos 2: bottom right
cw, -ch, // pos 2: bottom right
cw, 0.0f, // pos 3: top right
0.0f, -1.0f, // pos 1: bottom left
1.0f, -1.0f, // pos 2: bottom right
1.0f, -1.0f, // pos 2: bottom right
1.0f, 0.0f, // pos 3: top right
0.0f, 0.0f, // pos 0: top left
};

@@ -108,8 +101,7 @@ struct ChunkProg: public GlProgram {
glEnableVertexAttribArray(vertex);
glCheck();

glUniform1i(tileAtlas, 0);
glUniform1i(tiles, 1);
glUniform1i(tex, 0);
}

void disable() {
@@ -126,7 +118,7 @@ struct ChunkProg: public GlProgram {
glCheck();
}

void deinit() {
void deinit() {
glDeleteBuffers(1, &vbo);
glCheck();
}
@@ -155,48 +147,51 @@ void Renderer::draw(const RenderCamera &cam) {
camMat.translate(cam.pos.scale(-ratio, 1) * cam.zoom); // TODO: Change something to make this -cam.pos
camMat.scale({ cam.zoom * ratio, cam.zoom });
auto &chunkProg = state_->chunkProg;
auto &spriteProg = state_->spriteProg;

chunkProg.enable();

glUniform2f(chunkProg.tileAtlasSize,
(float)(int)(state_->atlasTex.width() / SwanCommon::TILE_SIZE),
(float)(int)(state_->atlasTex.height() / SwanCommon::TILE_SIZE));
glUniformMatrix3fv(chunkProg.camera, 1, GL_TRUE, camMat.data());
glCheck();

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, state_->atlasTex.id()); // Necessary?
glCheck();
{
chunkProg.enable();
glUniformMatrix3fv(chunkProg.camera, 1, GL_TRUE, camMat.data());
glCheck();

glActiveTexture(GL_TEXTURE1);
for (auto [pos, chunk]: draw_chunks_) {
glUniform2f(chunkProg.pos, pos.x, pos.y);
glBindTexture(GL_TEXTURE_2D, chunk.tex);
glDrawArrays(GL_TRIANGLES, 0, 6);
glUniform2f(chunkProg.tileAtlasSize,
(float)(int)(state_->atlasTex.width() / SwanCommon::TILE_SIZE),
(float)(int)(state_->atlasTex.height() / SwanCommon::TILE_SIZE));
glCheck();
}

draw_chunks_.clear();
chunkProg.disable();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, state_->atlasTex.id());
glCheck();

/*
state_->spriteProg.enable();
glActiveTexture(GL_TEXTURE1);
for (auto [pos, chunk]: draw_chunks_) {
glUniform2f(chunkProg.pos, pos.x, pos.y);
glBindTexture(GL_TEXTURE_2D, chunk.tex);
glDrawArrays(GL_TRIANGLES, 0, 6);
glCheck();
}

state_->camera.translate(-0.00001, 0);
glUniformMatrix3fv(state_->spriteProg.transform, 1, GL_TRUE, Mat3gf::IDENTITY.data());
glUniformMatrix3fv(state_->spriteProg.camera, 1, GL_TRUE, state_->camera.data());
glCheck();
draw_chunks_.clear();
chunkProg.disable();
}

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,state_->atlasTex.id()); // Necessary?
glUniform1i(state_->spriteProg.tex, 0);
glCheck();
{
spriteProg.enable();
glUniformMatrix3fv(spriteProg.camera, 1, GL_TRUE, camMat.data());
glCheck();

glDrawArrays(GL_TRIANGLES, 0, 6);
glCheck();
glActiveTexture(GL_TEXTURE0);
for (auto [mat, y, sprite]: draw_sprites_) {
mat.scale(sprite.scale);
glUniformMatrix3fv(spriteProg.transform, 1, GL_TRUE, mat.data());
glBindTexture(GL_TEXTURE_2D, sprite.tex);
glDrawArrays(GL_TRIANGLES, 0, 6);
glCheck();
}

state_->spriteProg.disable();
*/
draw_sprites_.clear();
spriteProg.disable();
}
}

void Renderer::registerTileTexture(TileID tileId, const void *data, size_t len) {
@@ -255,6 +250,7 @@ RenderChunk Renderer::createChunk(
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf);
}

glCheck();
return chunk;
}

@@ -278,14 +274,20 @@ void Renderer::modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id)
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf);
}

glCheck();
}

void Renderer::destroyChunk(RenderChunk chunk) {
glDeleteTextures(1, &chunk.tex);
glCheck();
}

RenderSprite createSprite(uint8_t *rgb, int width, int height) {
RenderSprite Renderer::createSprite(void *data, int width, int height) {
RenderSprite sprite;
sprite.scale = {
(float)width / SwanCommon::TILE_SIZE,
(float)height / SwanCommon::TILE_SIZE };
glGenTextures(1, &sprite.tex);
glCheck();

@@ -298,9 +300,9 @@ RenderSprite createSprite(uint8_t *rgb, int width, int height) {
glCheck();

glTexImage2D(
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, rgb);
GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glCheck();

return sprite;
}

+ 4
- 5
libcygnet/src/shaders.cc View File

@@ -6,13 +6,12 @@ const char *spriteVx = R"glsl(
uniform mat3 camera;
uniform mat3 transform;
attribute vec2 vertex;
attribute vec2 texCoord;
varying vec2 v_texCoord;

void main() {
vec3 pos = camera * transform * vec3(vertex, 1);
gl_Position = vec4(pos.xy, 0, 1);
v_texCoord = texCoord;
v_texCoord = vec2(vertex.x, -vertex.y);
}
)glsl";

@@ -35,7 +34,7 @@ const char *chunkVx = R"glsl(
void main() {
vec3 pos = camera * vec3(pos + vertex, 1);
gl_Position = vec4(pos.xy, 0, 1);
v_tileCoord = vertex;
v_tileCoord = vec2(vertex.x, -vertex.y);
}
)glsl";

@@ -51,13 +50,13 @@ const char *chunkFr = R"glsl(
uniform sampler2D tiles;

void main() {
vec2 tilePos = floor(vec2(v_tileCoord.x, -v_tileCoord.y));
vec2 tilePos = floor(vec2(v_tileCoord.x, v_tileCoord.y));
vec4 tileColor = texture2D(tiles, tilePos / vec2(CHUNK_WIDTH, CHUNK_HEIGHT));
float tileID = floor((tileColor.r * 256.0 + tileColor.a) * 256.0);

vec2 atlasPos = vec2(
tileID + v_tileCoord.x - tilePos.x,
floor(tileID / tileAtlasSize.x) - v_tileCoord.y - tilePos.y);
floor(tileID / tileAtlasSize.x) + v_tileCoord.y - tilePos.y);

gl_FragColor = texture2D(tileAtlas, fract(atlasPos / tileAtlasSize));
}

+ 13
- 0
src/cygnet-test.cc View File

@@ -22,6 +22,13 @@ void addTile(Cygnet::Renderer &rnd, const char *path) {
SDL_FreeSurface(surf);
}

Cygnet::RenderSprite loadSprite(Cygnet::Renderer &rnd, const char *path) {
SDL_Surface *surf = IMG_Load(path);
auto sprite = rnd.createSprite(surf->pixels, surf->w, surf->h);
SDL_FreeSurface(surf);
return sprite;
}

int main() {
Cygnet::Context ctx;
IMG_Init(IMG_INIT_PNG);
@@ -38,6 +45,8 @@ int main() {
}) addTile(rnd, path);
rnd.uploadTileTexture();

Cygnet::RenderSprite playerSprite = loadSprite(rnd, "core.mod/assets/entity/player-running.png");

Cygnet::RenderChunk chunk;
{
uint16_t tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT];
@@ -61,6 +70,7 @@ int main() {
double acc = 0;
double prevTime = getTime() - 1/60.0;
int frames = 0;
float x = 0;

while (true) {
double currTime = getTime();
@@ -124,6 +134,9 @@ int main() {

rnd.drawChunk(chunk, { 0, 0 });

x += dt;
rnd.drawSprite(playerSprite, { x, 0 });

win.clear();
rnd.draw(cam);
win.flip();

Loading…
Cancel
Save