소스 검색

add the ability to compress chunks

opengl-renderer-broken
Martin Dørum 4 년 전
부모
커밋
294a3528b9

+ 4
- 4
core.mod/src/WGDefault.cc 파일 보기

@@ -10,13 +10,13 @@ void WGDefault::genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) {
chunk.pos_.x_ * Swan::CHUNK_WIDTH, chunk.pos_.y_ * Swan::CHUNK_HEIGHT);

if (tpos.y_ == height)
chunk.tiles_[cx][cy] = tGrass_;
chunk.setTileID(Swan::TilePos(cx, cy), tGrass_);
else if (tpos.y_ > height && tpos.y_ <= depth)
chunk.tiles_[cx][cy] = tDirt_;
chunk.setTileID(Swan::TilePos(cx, cy), tDirt_);
else if (tpos.y_ > depth)
chunk.tiles_[cx][cy] = tStone_;
chunk.setTileID(Swan::TilePos(cx, cy), tStone_);
else
chunk.tiles_[cx][cy] = tAir_;
chunk.setTileID(Swan::TilePos(cx, cy), tAir_);
}
}
}

+ 1
- 1
core.mod/src/entities/EntPlayer.h 파일 보기

@@ -22,7 +22,7 @@ private:
static constexpr float FORCE = 3000;
static constexpr float JUMP_FORCE = 10;
static constexpr float MASS = 80;
static constexpr Swan::Vec2 FRICTION = Swan::Vec2(400, 25);
static constexpr Swan::Vec2 FRICTION = Swan::Vec2(400, 50);
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.6, 1.9);

enum class State {

+ 28
- 12
libswan/include/swan/Chunk.h 파일 보기

@@ -2,6 +2,8 @@

#include <SFML/Graphics/Texture.hpp>
#include <string.h>
#include <stdint.h>
#include <memory>

#include "common.h"
#include "Tile.h"
@@ -9,32 +11,46 @@
namespace Swan {

class World;
class Game;

class Chunk {
public:
using RelPos = TilePos;

Chunk(ChunkPos pos): pos_(pos) {
texture_.create(CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE);
sprite_ = sf::Sprite(texture_);
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]);
visuals_.reset(new Visuals());
visuals_->tex_.create(CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE);
visuals_->sprite_ = sf::Sprite(visuals_->tex_);
visuals_->dirty_ = false;
}

void setTileID(World &world, RelPos pos, Tile::ID id);
Tile &getTile(World &world, RelPos pos);
Tile::ID *getTileData();
Tile::ID getTileID(RelPos pos);
void setTileID(RelPos pos, Tile::ID id);
void drawBlock(RelPos pos, const Tile &t);

void compress();
void decompress();
void render(World &world);
void draw(Win &win);
void draw(Game &game, Win &win);

ChunkPos pos_;
Tile::ID tiles_[CHUNK_WIDTH][CHUNK_HEIGHT];

private:
static sf::Uint8 *imgbuf;
static sf::Uint8 *renderbuf;

void drawBlock(RelPos pos, const Tile &t);
void drawBlock(World &world, RelPos pos, Tile::ID id);
bool dirty_ = false;
sf::Texture texture_;
sf::Sprite sprite_;
std::unique_ptr<uint8_t[]> data_;

int compressed_size_ = -1; // -1 if not compressed, a positive number if compressed
bool need_render_ = false;

struct Visuals {
sf::Texture tex_;
sf::Sprite sprite_;
bool dirty_;
};
std::unique_ptr<Visuals> visuals_;
};

}

+ 3
- 1
libswan/include/swan/World.h 파일 보기

@@ -14,6 +14,8 @@

namespace Swan {

class Game;

class World {
public:
WorldPlane &addPlane(std::string gen);
@@ -32,7 +34,7 @@ public:
Tile &getTileByID(Tile::ID id);
Tile &getTile(const std::string &name);

void draw(Win &win);
void draw(Game &game, Win &win);
void update(Game &game, float dt);
void tick();


+ 3
- 2
libswan/include/swan/WorldPlane.h 파일 보기

@@ -13,6 +13,7 @@
namespace Swan {

class World;
class Game;

class WorldPlane {
public:
@@ -31,7 +32,7 @@ public:

Entity &spawnPlayer();

void draw(Win &win);
void draw(Game &game, Win &win);
void update(Game &game, float dt);
void tick();

@@ -42,7 +43,7 @@ public:
std::shared_ptr<WorldGen> gen_;

private:
std::map<std::pair<int, int>, std::unique_ptr<Chunk>> chunks_;
std::map<std::pair<int, int>, Chunk> chunks_;
std::vector<std::unique_ptr<Entity>> entities_;
std::vector<TilePos> debug_boxes_;
};

+ 2
- 2
libswan/include/swan/common.h 파일 보기

@@ -9,8 +9,8 @@ namespace Swan {

static constexpr int TILE_SIZE = 32;
static constexpr int TICK_RATE = 20;
static constexpr int CHUNK_HEIGHT = 16;
static constexpr int CHUNK_WIDTH = 24;
static constexpr int CHUNK_HEIGHT = 32;
static constexpr int CHUNK_WIDTH = 32;

using TilePos = Vec2i;
using ChunkPos = Vec2i;

+ 92
- 18
libswan/src/Chunk.cc 파일 보기

@@ -1,27 +1,92 @@
#include "Chunk.h"

#include <SFML/System/Clock.hpp>
#include <zlib.h>

#include "World.h"
#include "Game.h"

namespace Swan {

sf::Uint8 *Chunk::imgbuf = new sf::Uint8[CHUNK_WIDTH * TILE_SIZE * CHUNK_HEIGHT * TILE_SIZE * 4];
sf::Uint8 *Chunk::renderbuf = new sf::Uint8[CHUNK_WIDTH * TILE_SIZE * CHUNK_HEIGHT * TILE_SIZE * 4];

Tile::ID *Chunk::getTileData() {
if (compressed_size_ != -1)
decompress();

void Chunk::setTileID(World &world, RelPos pos, Tile::ID id) {
tiles_[pos.x_][pos.y_] = id;
drawBlock(world, pos, id);
return (Tile::ID *)data_.get();
}

Tile &Chunk::getTile(World &world, RelPos pos) {
return world.getTileByID(tiles_[pos.x_][pos.y_]);
Tile::ID Chunk::getTileID(RelPos pos) {
return getTileData()[pos.y_ * CHUNK_WIDTH + pos.x_];
}

void Chunk::setTileID(RelPos pos, Tile::ID id) {
getTileData()[pos.y_ * CHUNK_WIDTH + pos.x_] = id;
}

void Chunk::drawBlock(RelPos pos, const Tile &t) {
texture_.update(t.image_, pos.x_ * TILE_SIZE, pos.y_ * TILE_SIZE);
dirty_ = true;
if (compressed_size_ != -1)
decompress();

visuals_->tex_.update(t.image_, pos.x_ * TILE_SIZE, pos.y_ * TILE_SIZE);
visuals_->dirty_ = true;
}

void Chunk::compress() {
if (compressed_size_ != -1)
return;

sf::Clock clock;

// We only need a fixed-length temp buffer;
// if the compressed data gets too big, there's no point in compressing
uint8_t dest[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)];

uLongf destlen = sizeof(dest);
int ret = compress2(
(Bytef *)dest, &destlen,
(Bytef *)data_.get(), CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID),
Z_BEST_COMPRESSION);

if (ret == Z_OK) {
data_.reset(new uint8_t[destlen]);
memcpy(data_.get(), dest, destlen);

visuals_.reset();
compressed_size_ = destlen;

fprintf(stderr, "Compressed chunk %i,%i from %lu bytes to %lu bytes in %.3fs.\n",
pos_.x_, pos_.y_, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID), destlen,
clock.getElapsedTime().asSeconds());
} else if (ret == Z_BUF_ERROR) {
fprintf(stderr, "Didn't compress chunk %i,%i because compressing it would've made it bigger.\n",
pos_.x_, pos_.y_);
} else {
fprintf(stderr, "Chunk compression error: %i (Out of memory?)\n", ret);
}
}

void Chunk::drawBlock(World &world, RelPos pos, Tile::ID id) {
drawBlock(pos, world.getTileByID(id));
void Chunk::decompress() {
uint8_t *dest = new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)];
uLongf destlen = CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID);
int ret = uncompress(
dest, &destlen,
(Bytef *)data_.get(), compressed_size_);

if (ret != Z_OK) {
fprintf(stderr, "Decompressing chunk failed: %i\n", ret);
delete[] dest;
abort();
}

data_.reset(dest);
visuals_.reset(new Visuals());
visuals_->tex_.create(CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE);
visuals_->sprite_ = sf::Sprite();
visuals_->dirty_ = true;
need_render_ = true;
compressed_size_ = -1;
}

void Chunk::render(World &world) {
@@ -30,7 +95,7 @@ void Chunk::render(World &world) {

for (int x = 0; x < CHUNK_WIDTH; ++x) {
for (int y = 0; y < CHUNK_HEIGHT; ++y) {
Tile::ID id = tiles_[x][y];
Tile::ID id = getTileID(RelPos(x, y));
if (id != prevID) {
prevID = id;
tile = world.getTileByID(id);
@@ -40,7 +105,7 @@ void Chunk::render(World &world) {
for (int imgy = 0; imgy < TILE_SIZE; ++imgy) {
int pixx = x * TILE_SIZE;
int pixy = y * TILE_SIZE + imgy;
sf::Uint8 *pix = imgbuf +
sf::Uint8 *pix = renderbuf +
pixy * CHUNK_WIDTH * TILE_SIZE * 4 +
pixx * 4;
memcpy(pix, imgptr + imgy * TILE_SIZE * 4, TILE_SIZE * 4);
@@ -48,17 +113,26 @@ void Chunk::render(World &world) {
}
}

texture_.update(imgbuf, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE, 0, 0);
visuals_->tex_.update(renderbuf, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE, 0, 0);
visuals_->dirty_ = true;
}

void Chunk::draw(Win &win) {
if (dirty_) {
sprite_.setTexture(texture_);
dirty_ = false;
void Chunk::draw(Game &game, Win &win) {
if (compressed_size_ != -1)
decompress();

if (need_render_) {
render(*game.world_);
need_render_ = false;
}

if (visuals_->dirty_) {
visuals_->sprite_.setTexture(visuals_->tex_);
visuals_->dirty_ = false;
}

win.setPos(pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT));
win.draw(sprite_);
win.draw(visuals_->sprite_);
}

}

+ 1
- 1
libswan/src/Game.cc 파일 보기

@@ -61,7 +61,7 @@ bool Game::isMousePressed() {
}

void Game::draw() {
world_->draw(win_);
world_->draw(*this, win_);
}

void Game::update(float dt) {

+ 5
- 3
libswan/src/World.cc 파일 보기

@@ -2,6 +2,8 @@

#include <SFML/System/Clock.hpp>

#include "Game.h"

namespace Swan {

static bool chunkLine(int l, sf::Clock &clock, WorldPlane &plane, ChunkPos &abspos, const Vec2i &dir) {
@@ -24,7 +26,7 @@ void World::ChunkRenderer::tick(WorldPlane &plane, ChunkPos abspos) {
sf::Clock clock;
int l = 0;

for (int i = 0; i < 8; ++i) {
for (int i = 0; i < 4; ++i) {
if (chunkLine(l, clock, plane, abspos, Vec2i(0, -1))) break;
if (chunkLine(l, clock, plane, abspos, Vec2i(1, 0))) break;
l += 1;
@@ -116,9 +118,9 @@ WorldPlane &World::addPlane(std::string gen) {
return planes_[id];
}

void World::draw(Win &win) {
void World::draw(Game &game, Win &win) {
win.cam_ = player_->getPos() - (win.getSize() / 2) + 0.5;
planes_[current_plane_].draw(win);
planes_[current_plane_].draw(game, win);
}

void World::update(Game &game, float dt) {

+ 15
- 10
libswan/src/WorldPlane.cc 파일 보기

@@ -1,8 +1,10 @@
#include "WorldPlane.h"

#include <math.h>
#include <SFML/System/Clock.hpp>

#include "World.h"
#include "Game.h"
#include "Timer.h"

namespace Swan {
@@ -44,16 +46,19 @@ Chunk &WorldPlane::getChunk(ChunkPos pos) {
auto iter = chunks_.find(pos);

if (iter == chunks_.end()) {
iter = chunks_.emplace(pos, new Chunk(pos)).first;
gen_->genChunk(*this, *iter->second);
iter->second->render(*world_);
iter = chunks_.emplace(pos, Chunk(pos)).first;
gen_->genChunk(*this, iter->second);
iter->second.render(*world_);
}

return *iter->second;
return iter->second;
}

void WorldPlane::setTileID(TilePos pos, Tile::ID id) {
getChunk(chunkPos(pos)).setTileID(*world_, relPos(pos), id);
Chunk &chunk = getChunk(chunkPos(pos));
Chunk::RelPos rp = relPos(pos);
chunk.setTileID(rp, id);
chunk.drawBlock(rp, world_->getTileByID(id));
}

void WorldPlane::setTile(TilePos pos, const std::string &name) {
@@ -61,14 +66,16 @@ void WorldPlane::setTile(TilePos pos, const std::string &name) {
}

Tile &WorldPlane::getTile(TilePos pos) {
return getChunk(chunkPos(pos)).getTile(*world_, relPos(pos));
Chunk &chunk = getChunk(chunkPos(pos));
Tile::ID id = chunk.getTileID(relPos(pos));
return world_->getTileByID(id);
}

Entity &WorldPlane::spawnPlayer() {
return gen_->spawnPlayer(*this);
}

void WorldPlane::draw(Win &win) {
void WorldPlane::draw(Game &game, Win &win) {
const Vec2 &ppos = world_->player_->getPos();
ChunkPos pcpos = ChunkPos(
(int)floor(ppos.x_ / CHUNK_WIDTH),
@@ -78,12 +85,10 @@ void WorldPlane::draw(Win &win) {
for (int y = -1; y <= 1; ++y) {
auto chunk = chunks_.find(pcpos + ChunkPos(x, y));
if (chunk != chunks_.end())
chunk->second->draw(win);
chunk->second.draw(game, win);
}
}

//for (auto &ch: chunks_)
// ch.second->draw(win);
for (auto &ent: entities_)
ent->draw(win);


Loading…
취소
저장