Browse Source

chunk rendering

feature/replace-renderer
Martin Dørum 3 years ago
parent
commit
c1dd15653d
3 changed files with 112 additions and 36 deletions
  1. 26
    1
      libcygnet/include/cygnet/Renderer.h
  2. 74
    35
      libcygnet/src/Renderer.cc
  3. 12
    0
      src/cygnet-test.cc

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

@@ -1,23 +1,48 @@
#pragma once

#include <memory>
#include <vector>
#include <stdint.h>

#include <swan-common/constants.h>
#include <swan-common/Vector2.h>

#include "util.h"

namespace Cygnet {

struct RendererState;

struct RenderChunk {
GLuint tex;
};

class Renderer {
public:
using TileID = uint16_t;

Renderer();
~Renderer();

void drawChunk(SwanCommon::Vec2 pos, RenderChunk chunk);

void draw();

void registerTileTexture(size_t tileId, const void *data, size_t len);
void registerTileTexture(TileID tileId, const void *data, size_t len);
void uploadTileTexture();

RenderChunk createChunk(
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]);
void destroyChunk(RenderChunk chunk);

private:
std::unique_ptr<RendererState> state_;

std::vector<std::pair<SwanCommon::Vec2, RenderChunk>> draw_chunks_;
};

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

}

+ 74
- 35
libcygnet/src/Renderer.cc View File

@@ -6,6 +6,10 @@
#include <swan-common/constants.h>
#include <string.h>

// std::endian was originally in type_traits, was moved to bit
#include <type_traits>
#include <bit>

#include "shaders.h"
#include "GlWrappers.h"
#include "TileAtlas.h"
@@ -84,7 +88,6 @@ struct ChunkProg: public GlProgram {
GLint tileAtlasSize = uniformLoc("tileAtlasSize");
GLint tiles = uniformLoc("tiles");

GLuint tilesTex;
GLuint vbo;

static constexpr float ch = (float)SwanCommon::CHUNK_HEIGHT;
@@ -104,6 +107,9 @@ struct ChunkProg: public GlProgram {
glVertexAttribPointer(vertex, 2, GL_FLOAT, GL_FALSE, 0, (void *)0);
glEnableVertexAttribArray(vertex);
glCheck();

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

void disable() {
@@ -115,16 +121,6 @@ struct ChunkProg: public GlProgram {
glGenBuffers(1, &vbo);
glCheck();

glGenTextures(1, &tilesTex);
glCheck();

glBindTexture(GL_TEXTURE_2D, tilesTex);
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();

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexes), vertexes, GL_STATIC_DRAW);
glCheck();
@@ -132,7 +128,6 @@ struct ChunkProg: public GlProgram {

void deinit() {
glDeleteBuffers(1, &vbo);
glDeleteTextures(1, &tilesTex);
glCheck();
}
};
@@ -157,37 +152,32 @@ Renderer::Renderer(): state_(std::make_unique<RendererState>()) {}
Renderer::~Renderer() = default;

void Renderer::draw() {
state_->chunkProg.enable();
auto &chunkProg = state_->chunkProg;
state_->camera.reset().translate(-0.9, 0.9).scale(0.125, 0.125);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, state_->chunkProg.tilesTex); // Necessary?
glUniform1i(state_->chunkProg.tiles, 1);
uint8_t tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2];
memset(tiles, 0x00, sizeof(tiles));
tiles[1] = 1;
tiles[3] = 2;
tiles[5] = 3;
glTexImage2D(
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tiles);
glCheck();
chunkProg.enable();

glUniform2f(state_->chunkProg.tileAtlasSize,
glUniform2f(chunkProg.tileAtlasSize,
(float)(int)(state_->atlasTex.width() / SwanCommon::TILE_SIZE),
(float)(int)(state_->atlasTex.height() / SwanCommon::TILE_SIZE));

state_->camera.reset().translate(-0.9, 0.9).scale(0.025, 0.025);
glUniformMatrix3fv(state_->chunkProg.camera, 1, GL_TRUE, state_->camera.data());
glUniformMatrix3fv(chunkProg.camera, 1, GL_TRUE, state_->camera.data());
glCheck();

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, state_->atlasTex.id());
glUniform1i(state_->chunkProg.tileAtlas, 0);
glBindTexture(GL_TEXTURE_2D, state_->atlasTex.id()); // Necessary?
glCheck();

glDrawArrays(GL_TRIANGLES, 0, 6);
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);
glCheck();
}

state_->chunkProg.disable();
draw_chunks_.clear();
chunkProg.disable();

/*
state_->spriteProg.enable();
@@ -209,7 +199,7 @@ void Renderer::draw() {
*/
}

void Renderer::registerTileTexture(size_t tileId, const void *data, size_t len) {
void Renderer::registerTileTexture(TileID tileId, const void *data, size_t len) {
state_->atlas.addTile(tileId, data, len);
}

@@ -220,4 +210,53 @@ void Renderer::uploadTileTexture() {
std::cerr << "Uploaded image of size " << w << 'x' << h << '\n';
}

RenderChunk Renderer::createChunk(
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) {
// TODO: Maybe don't do this here? Maybe instead store the buffer and
// upload the texture in the draw method?
// The current approach needs createChunk to be called on the graphics thread.

RenderChunk chunk;
glGenTextures(1, &chunk.tex);
glCheck();
glBindTexture(GL_TEXTURE_2D, chunk.tex);
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);

static_assert(
std::endian::native == std::endian::big ||
std::endian::native == std::endian::little,
"Expected either big or little endian");

if constexpr (std::endian::native == std::endian::little) {
glTexImage2D(
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tiles);
} else if constexpr (std::endian::native == std::endian::big) {
uint8_t buf[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2];
for (size_t y = 0; y < SwanCommon::CHUNK_HEIGHT; ++y) {
for (size_t x = 0; x < SwanCommon::CHUNK_WIDTH; ++x) {
size_t dst = y * SwanCommon::CHUNK_WIDTH * 2 + x * 2;
size_t src = y * SwanCommon::CHUNK_WIDTH + x;
buf[dst + 0] = tiles[src] & 0xff;
buf[dst + 1] = (tiles[src] & 0xff00) >> 8;
}
}

glTexImage2D(
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT,
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf);
}

return chunk;
}

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

}

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

@@ -31,6 +31,16 @@ int main() {
}) addTile(rnd, path);
rnd.uploadTileTexture();

Cygnet::RenderChunk chunk;
{
uint16_t tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT];
memset(tiles, 0, sizeof(tiles));
tiles[0] = 1;
tiles[1] = 2;
tiles[2] = 3;
chunk = rnd.createChunk(tiles);
}

while (true) {
SDL_Event evt;
while (SDL_PollEvent(&evt)) {
@@ -40,6 +50,8 @@ int main() {
}
}

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

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

Loading…
Cancel
Save