summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2017-12-19 19:27:06 +0100
committerPaweł Redman <pawel.redman@gmail.com>2017-12-19 19:27:06 +0100
commit297524c8ec41b585c4812494791772406653e479 (patch)
tree40e91994daeb073051e7b3f40465f76b9f54ed36
parentbbed2cb38638e51bc19a50464ec818ea96524c2c (diff)
Introduce tall tiles.
Some features are still missing but the commit is large enough as it is. TODO: render layers and fix minor artifacts.
-rw-r--r--assets/tiles/stone_side.pngbin0 -> 1644 bytes
-rw-r--r--src/common.hpp21
-rw-r--r--src/game/assets.cpp6
-rw-r--r--src/render.cpp221
-rw-r--r--src/world.cpp56
5 files changed, 204 insertions, 100 deletions
diff --git a/assets/tiles/stone_side.png b/assets/tiles/stone_side.png
new file mode 100644
index 0000000..0c9ad1f
--- /dev/null
+++ b/assets/tiles/stone_side.png
Binary files differ
diff --git a/src/common.hpp b/src/common.hpp
index a253da5..71bc695 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -70,13 +70,18 @@ namespace world {
class entity_t;
+ typedef enum {
+ SECTOR_EMPTY,
+ SECTOR_PARTIAL,
+ SECTOR_FULL
+ } sector_level_t;
+
class sector_t {
public:
sector_index_t index;
rectf_t bounds;
std::unordered_set<entity_t*> ents;
-
- bool empty = true;
+ sector_level_t level;
tile_t tiles[SECTOR_SIZE * SECTOR_SIZE];
};
@@ -101,7 +106,7 @@ namespace world {
std::map<sector_index_t, sector_t> sectors;
void generate_tile(tile_t *tile, tile_index_t index);
- void generate(sector_t *sector, sector_index_t index, bool partial);
+ void generate(sector_t *sector, sector_index_t index, sector_level_t level);
protected:
friend render::state_t;
@@ -115,13 +120,13 @@ namespace world {
world_t(void);
- sector_t *get_sector(sector_index_t index, bool partial = false);
- tile_t *get_tile(tile_index_t index, bool partial = false);
+ sector_t *get_sector(sector_index_t index, sector_level_t level);
+ tile_t *get_tile(tile_index_t index, sector_level_t level);
bool find_path(v2f_t src, v2f_t dst, cmodel_t *cmodel, entity_t *ignore, std::list<v2f_t> *path);
// FIXME: iterators instead of returning std::lists
- std::list<sector_t*> get_sectors(rectf_t rect);
+ std::list<sector_t*> get_sectors(rectf_t rect, sector_level_t level);
std::list<entity_t*> get_entities(rectf_t rect, cflags_t cflags);
std::list<entity_t*> get_render_entities(rectf_t rect);
@@ -313,12 +318,12 @@ namespace render {
ALIGN_CENTER_BOTTOM
} text_align_t;
- void register_tile(uint8_t type, const char *path);
+ void register_tile(uint8_t type, const char *top, const char *side, float height);
class state_t {
sf::RenderWindow *window;
- void render_sector(world::world_t *world, world::sector_t *sector);
+ void render_tile(world::world_t *world, v2f_t tx, world::tile_t *tile);
void drender_text(rectf_t rect, std::string str);
void drender_entity(world::entity_t *ent);
public:
diff --git a/src/game/assets.cpp b/src/game/assets.cpp
index 1bc8948..046934b 100644
--- a/src/game/assets.cpp
+++ b/src/game/assets.cpp
@@ -38,11 +38,11 @@ void load(void)
unit_selected.load("assets/units/selected_", 1);
world::register_tile(TILE_DIRT, 0);
- render::register_tile(TILE_DIRT, "assets/tiles/dirt.png");
+ render::register_tile(TILE_DIRT, "assets/tiles/dirt.png", NULL, 0.0f);
world::register_tile(TILE_STONE, CF_SOLID);
- render::register_tile(TILE_STONE, "assets/tiles/stone.png");
+ render::register_tile(TILE_STONE, "assets/tiles/stone.png", "assets/tiles/stone_side.png", 1.0f);
world::register_tile(TILE_WATER, CF_WATER);
- render::register_tile(TILE_WATER, "assets/tiles/water.png");
+ render::register_tile(TILE_WATER, "assets/tiles/water.png", NULL, 0.0f);
}
} // namespace game::assets
diff --git a/src/render.cpp b/src/render.cpp
index 76701b6..6c47ab7 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -1,4 +1,5 @@
#include "common.hpp"
+#include <iomanip>
static sf::RectangleShape wot_rect;
static sf::Font font;
@@ -12,17 +13,31 @@ state_t::state_t(sf::RenderWindow *window_)
font.loadFromFile("assets/FanwoodText.otf");
}
-// FIXME: rename
-static sf::Texture *tiles[256] = {0};
+typedef struct {
+ sf::Texture *top, *side;
+ float height;
+} tiledata_t;
+static tiledata_t tiledata[256] = {0};
-void register_tile(uint8_t type, const char *path)
+void register_tile(uint8_t type, const char *top, const char *side, float height)
{
- printf("load %s\n", path);
- tiles[type] = new sf::Texture;
- tiles[type]->loadFromFile(path);
- tiles[type]->setRepeated(true);
+ tiledata_t *tile = tiledata + type;
+
+ printf("load %s\n", top);
+ tile->top = new sf::Texture;
+ tile->top->loadFromFile(top);
+ tile->top->setRepeated(true);
+
+ if (height > 0.0f) {
+ tile->height = height;
+ printf("load %s\n", side);
+ tile->side = new sf::Texture;
+ tile->side->loadFromFile(side);
+ tile->side->setRepeated(true);
+ }
}
+
void state_t::begin_frame(double now_, double dt_)
{
now = now_;
@@ -71,17 +86,17 @@ void state_t::drender_entity(world::entity_t *ent)
drender_text(ent->render_bounds, ss.str());
}
-static const v2f_t tile_base[8] ={
- {1.0f, 0.5f}, {1.0f, 1.0f}, {0.5f, 1.0f}, {0.0f, 1.0f},
- {0.0f, 0.5f}, {0.0f, 0.0f}, {0.5f, 0.0f}, {1.0f, 0.0f}
-};
-
static void generate_tile_verts(sf::Vertex *verts, v2f_t tx, procgen::perlin_noise_t *perlin)
{
+ static const v2f_t local_base[8] ={
+ {1.0f, 0.5f}, {1.0f, 1.0f}, {0.5f, 1.0f}, {0.0f, 1.0f},
+ {0.0f, 0.5f}, {0.0f, 0.0f}, {0.5f, 0.0f}, {1.0f, 0.0f}
+ };
+
for (size_t i = 0; i < 8; i++) {
v2f_t base, turb;
- base = tile_base[i] + tx;
+ base = local_base[i] + tx;
turb[0] = perlin->get(base, 1.0f) * 0.5f;
turb[1] = perlin->get(base, 2.0f) * 0.5f;
@@ -92,89 +107,173 @@ static void generate_tile_verts(sf::Vertex *verts, v2f_t tx, procgen::perlin_noi
}
}
-void state_t::render_sector(world::world_t *world, world::sector_t *sector)
+void state_t::render_tile(world::world_t *world, v2f_t tx, world::tile_t *tile)
{
- for (ssize_t y = 0; y < SECTOR_SIZE; y++)
- for (ssize_t x = 0; x < SECTOR_SIZE; x++) {
- sf::Vertex verts[8];
- sf::Texture *texture;
- v2f_t tx;
- world::tile_t *tile;
-
- tx = sector->bounds.v[0] + v2f_t(x, y);
- tile = sector->tiles + y * SECTOR_SIZE + x;
-
- texture = tiles[tile->type];
- if (!texture) {
- printf("draw_tile: tile %i not registered\n", tile->type);
- abort();
- }
+ static const size_t side_order[6] = {4, 0, 7, 3, 2, 1};
+ static const size_t side_tests[8] = {1, 4, 4, 16, 16, 64, 64, 1};
- sf::RenderStates states(texture);
- generate_tile_verts(verts, tx, &world->perlin);
- window->draw(verts, 8, sf::TrianglesFan, states);
+ sf::Vertex verts[8];
+ tiledata_t *data;
- if (debug_draw_tile_coords) {
- world::tile_index_t local(x, y);
- std::stringstream ss;
+ data = tiledata + tile->type;
- ss << "L=" << local;
- sf::Text text(ss.str(), font, 20);
- text.setPosition(tx);
- text.setScale(0.005, 0.005);
- window->draw(text);
+ generate_tile_verts(verts, tx, &world->perlin);
+
+ if (data->height) {
+ sf::RenderStates states(data->side);
+
+ for (size_t i = 0; i < 6; i++) {
+ size_t j = side_order[i];
+ size_t k = (j + 1) % 8;
+ sf::Vertex quad[4];
+
+ if (tile->neighbors & side_tests[j])
+ continue;
+
+ quad[0] = verts[j];
+ quad[0].texCoords.y = 0;
+ quad[1] = verts[k];
+ quad[1].texCoords.y = 0;
+ quad[2] = quad[1];
+ quad[3] = quad[0];
+
+ quad[2].position.y -= data->height;
+ quad[2].texCoords.y -= data->height * 32;
+ quad[3].position.y -= data->height;
+ quad[3].texCoords.y -= data->height * 32;
+
+ window->draw(quad, 4, sf::TrianglesFan, states);
}
- stats.tiles++;
+ for (size_t i = 0; i < 8; i++)
+ verts[i].position.y -= data->height;
}
- stats.sectors++;
+ sf::RenderStates states(data->top);
+ window->draw(verts, 8, sf::TrianglesFan, states);
+ stats.tiles++;
}
-void state_t::render(game::state_t *game)
+static rectf_t window_bounds(sf::RenderWindow *window)
{
+ const v2f_t margin(1.5f, 1.5f);
+
sf::Vector2u size = window->getSize();
v2f_t A, B, C, D;
- const v2f_t margin(1.0f, 1.0f);
- rectf_t bbox;
- std::list<world::entity_t*> ents;
+ rectf_t bounds;
A = window->mapPixelToCoords(sf::Vector2i(0, 0));
B = window->mapPixelToCoords(sf::Vector2i(size.x, 0));
C = window->mapPixelToCoords(sf::Vector2i(0, size.y));
D = window->mapPixelToCoords(sf::Vector2i(size.x, size.y));
- bbox[0][0] = std::min({A[0], B[0], C[0], D[0]});
- bbox[0][1] = std::min({A[1], B[1], C[1], D[1]});
- bbox[1][0] = std::max({A[0], B[0], C[0], D[0]});
- bbox[1][1] = std::max({A[1], B[1], C[1], D[1]});
+ bounds[0][0] = std::min({A[0], B[0], C[0], D[0]});
+ bounds[0][1] = std::min({A[1], B[1], C[1], D[1]});
+ bounds[1][0] = std::max({A[0], B[0], C[0], D[0]});
+ bounds[1][1] = std::max({A[1], B[1], C[1], D[1]});
+ bounds[0] -= margin;
+ bounds[1] += margin;
+
+ return bounds;
+}
- bbox[0] -= margin;
- bbox[1] += margin;
+void state_t::render(game::state_t *game)
+{
+ rectf_t bounds;
+ std::list<world::entity_t*> ents;
+ std::list<world::entity_t*>::iterator ent;
+ rect_t<world::coord_t, 2> sectors;
- for (world::sector_t *sector : game->world.get_sectors(bbox))
- render_sector(&game->world, sector);
+ bounds = window_bounds(window);
+ sectors[0] = world::sector_index_at(bounds[0]);
+ sectors[1] = world::sector_index_at(bounds[1]);
- ents = game->world.get_render_entities(bbox);
+ ents = game->world.get_render_entities(bounds);
ents.sort(
[](const world::entity_t *x, const world::entity_t *y) -> bool
{
+ return x->render_bounds[1][1] < y->render_bounds[1][1];
+ // FIXME: bring render layers back
+ /*
if (x->render_layer < y->render_layer)
return true;
else if (x->render_layer > y->render_layer)
return false;
else
- return x->render_bounds[1][1] < y->render_bounds[1][1];
+ return x->render_bounds[1][1] < y->render_bounds[1][1];*/
});
- for (world::entity_t *ent : ents) {
- ent->render_to(this);
+ ent = ents.begin();
- if (debug_draw_cmodels)
- drender_entity(ent);
+ for (world::coord_t sy = sectors[0][1]; sy <= sectors[1][1]; sy++)
+ for (world::coord_t ty = 0; ty < SECTOR_SIZE; ty++)
+ for (world::coord_t sx = sectors[0][0]; sx <= sectors[1][0]; sx++) {
+ world::sector_index_t sector_index(sx, sy);
+ world::sector_t *sector;
+
+ sector = game->world.get_sector(sector_index, world::SECTOR_FULL);
+
+ while (ent != ents.end() &&
+ (*ent)->render_bounds[1][1] < sy * SECTOR_SIZE + ty) {
+ (*ent)->render_to(this);
+ stats.entities++;
+ ent++;
+ }
+
+ for (world::coord_t tx = 0; tx < SECTOR_SIZE; tx++) {
+ world::tile_index_t index;
+ world::tile_t *tile;
- stats.entities++;
+ index = sector_index * SECTOR_SIZE +
+ world::tile_index_t(tx, ty);
+ tile = sector->tiles + ty * SECTOR_SIZE + tx;
+
+ render_tile(&game->world, index, tile);
+ }
+
+ stats.sectors++;
}
+
+ // Every sector is iterated SECTOR_SIZE times.
+ stats.sectors /= SECTOR_SIZE;
+
+ if (debug_draw_tile_coords) {
+ for (world::sector_t *sector : game->world.get_sectors(bounds, world::SECTOR_FULL))
+ for (world::coord_t ty = 0; ty < SECTOR_SIZE; ty++)
+ for (world::coord_t tx = 0; tx < SECTOR_SIZE; tx++) {
+ std::stringstream ss;
+ world::tile_index_t local, index;
+ world::tile_t *tile;
+ int neighbors;
+
+ local = world::tile_index_t(tx, ty);
+ index = sector->index * SECTOR_SIZE + local;
+ tile = sector->tiles + ty * SECTOR_SIZE + tx;
+
+ ss << "SI: " << sector->index << "\n";
+ ss << "GI: " << index << "\n";
+ ss << "LI: " << local << "\n";
+ ss << "T: " << tile->type << "\n";
+ ss << "N: ";
+
+ neighbors = tile->neighbors;
+ for (size_t i = 0; i < 8; i++) {
+ ss << ((neighbors & 1) ? 'P' : 'A');
+ neighbors >>= 1;
+ }
+
+ ss << " (" << tile->neighbors << ")";
+
+ sf::Text text(ss.str(), font, 20);
+ text.setPosition(index);
+ text.setScale(0.005, 0.005);
+ window->draw(text);
+ }
+ }
+
+ if (debug_draw_cmodels)
+ for (world::entity_t *ent : ents)
+ drender_entity(ent);
}
void state_t::render(double phase, animated_texture_t *anim, rectf_t bounds, sf::Color color, bool mirror){
diff --git a/src/world.cpp b/src/world.cpp
index 5c2d7b3..6a0ba97 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -27,50 +27,50 @@ void register_tile(uint8_t type, cflags_t cflags)
tiles[type] = cflags;
}
-void world_t::generate(sector_t *sector, sector_index_t index, bool partial)
+void world_t::generate(sector_t *sector, sector_index_t index, sector_level_t level)
{
bool gen_tiles = false, gen_decos = false;
sector->index = index;
-
sector->bounds.v[0] = (v2f_t)index * SECTOR_SIZE;
sector->bounds.v[1] = sector->bounds.v[0] + v2f_t(SECTOR_SIZE, SECTOR_SIZE);
- if (sector->empty) {
- if (partial)
+ if (sector->level == SECTOR_EMPTY) {
+ if (level == SECTOR_PARTIAL)
gen_tiles = true;
- else
+ else if (level == SECTOR_FULL)
gen_tiles = gen_decos = true;
- } else
+ } else if (sector->level == SECTOR_PARTIAL)
gen_decos = true;
- sector->empty = false;
+ sector->level = level;
generator(this, index, sector, gen_tiles, gen_decos, generator_data);
stats.sectors++;
stats.tiles += SECTOR_SIZE * SECTOR_SIZE;
- // Unused, for now.
- /*
- for (coord_t ly = 0; ly < SECTOR_SIZE; ly++)
- for (coord_t lx = 0; lx < SECTOR_SIZE; lx++) {
+ if (sector->level < SECTOR_FULL)
+ return;
+
+ for (coord_t ty = 0; ty < SECTOR_SIZE; ty++)
+ for (coord_t tx = 0; tx < SECTOR_SIZE; tx++) {
tile_t *tile;
+ tile_index_t local(tx, ty);
- tile = sector->tiles + ly * SECTOR_SIZE + lx;
+ tile = sector->tiles + ty * SECTOR_SIZE + tx;
tile->neighbors = 0;
for (size_t i = 0; i < 8; i++) {
tile_index_t neighbor_index;
tile_t *neighbor;
- neighbor_index = index * SECTOR_SIZE + tile_index_t(lx, ly) + neighbor_offsets[i];
- neighbor = get_tile(neighbor_index, true);
+ neighbor_index = index * SECTOR_SIZE + local + neighbor_offsets[i];
+ neighbor = get_tile(neighbor_index, SECTOR_PARTIAL);
if (neighbor->type == tile->type)
tile->neighbors |= (1 << i);
}
}
- */
}
bool world_t::find_path(v2f_t src, v2f_t dst, cmodel_t *cmodel, entity_t *ignore,
@@ -91,7 +91,7 @@ bool world_t::find_path(v2f_t src, v2f_t dst, cmodel_t *cmodel, entity_t *ignore
index = finder.base + tile_index_t(x, y);
- if (!(tiles[get_tile(index)->type] & cmodel->cflags))
+ if (!(tiles[get_tile(index, SECTOR_FULL)->type] & cmodel->cflags))
continue;
combined[0] = v2f_t(index) - cmodel_dims / 2;
@@ -129,19 +129,19 @@ bool world_t::find_path(v2f_t src, v2f_t dst, cmodel_t *cmodel, entity_t *ignore
return true;
}
-sector_t *world_t::get_sector(sector_index_t index, bool partial)
+sector_t *world_t::get_sector(sector_index_t index, sector_level_t level)
{
sector_t *sector;
sector = &sectors[index];
- if (sector->empty)
- generate(sector, index, partial);
+ if (sector->level < level)
+ generate(sector, index, level);
return sector;
}
-tile_t *world_t::get_tile(tile_index_t index, bool partial)
+tile_t *world_t::get_tile(tile_index_t index, sector_level_t level)
{
sector_index_t sector_index;
sector_t *sector;
@@ -149,12 +149,12 @@ tile_t *world_t::get_tile(tile_index_t index, bool partial)
sector_index[0] = divide_rmi(index[0], (int64_t)SECTOR_SIZE, &tx);
sector_index[1] = divide_rmi(index[1], (int64_t)SECTOR_SIZE, &ty);
- sector = get_sector(sector_index, partial);
+ sector = get_sector(sector_index, level);
return sector->tiles + ty * SECTOR_SIZE + tx;
}
-std::list<sector_t*> world_t::get_sectors(rectf_t rect)
+std::list<sector_t*> world_t::get_sectors(rectf_t rect, sector_level_t level)
{
sector_index_t base, upper;
std::list<sector_t*> list;
@@ -165,7 +165,7 @@ std::list<sector_t*> world_t::get_sectors(rectf_t rect)
for (int64_t y = base[1]; y <= upper[1]; y++)
for (int64_t x = base[0]; x <= upper[0]; x++) {
sector_index_t index(x, y);
- list.push_back(get_sector(index));
+ list.push_back(get_sector(index, level));
}
return list;
@@ -179,7 +179,7 @@ std::list<entity_t*> world_t::get_entities(rectf_t rect, cflags_t cflags)
cookie++;
- for (sector_t *sector : get_sectors(rect))
+ for (sector_t *sector : get_sectors(rect, SECTOR_FULL))
for (entity_t *ent : sector->ents) {
if (ent->cookie == cookie)
continue;
@@ -204,7 +204,7 @@ std::list<entity_t*> world_t::get_render_entities(rectf_t rect)
cookie++;
- for (sector_t *sector : get_sectors(rect))
+ for (sector_t *sector : get_sectors(rect, SECTOR_FULL))
for (entity_t *ent : sector->ents) {
if (ent->cookie == cookie)
continue;
@@ -224,7 +224,7 @@ bool world_t::test_rect(const cmodel_t *cmodel, const entity_t *ignore)
{
cookie++;
- for (sector_t *sector : get_sectors(cmodel->bounds)) {
+ for (sector_t *sector : get_sectors(cmodel->bounds, SECTOR_FULL)) {
rect_t<coord_t, 2> bounds;
tile_index_t index;
@@ -338,7 +338,7 @@ trace_t world_t::trace(v2f_t start, v2f_t end, cflags_t cflags)
index = (tile_index_t(x.floor()) ^ transforms_index[quad]) +
offsets_index[quad];
- if (tiles[get_tile(index, false)->type] & cflags) {
+ if (tiles[get_tile(index, SECTOR_FULL)->type] & cflags) {
res.hit = true;
res.end = x ^ transforms[quad];
res.frac = (x - start).len() / (end - start).len();
@@ -423,7 +423,7 @@ void entity_t::link(world_t *world_)
sector_index_t index = base + sector_index_t(x, y);
sector_t *sector;
- sector = world->get_sector(index);
+ sector = world->get_sector(index, SECTOR_FULL);
link_to_sector(sector);
}