#include "common.hpp" #include #include static sf::RectangleShape wot_rect; static sf::Font font; void interface::state_t::render_to(render::state_t *render) { if (select.selecting) render->render_hlrect(select.rect, sf::Color(200, 100, 50)); } namespace render { state_t::state_t(sf::RenderWindow *window_) { window = window_; font.loadFromFile("assets/LiberationMono-Regular.ttf"); } // FIXME: rename static sf::Texture *tiles[256] = {0}; void register_tile(uint8_t type, const char *path) { printf("load %s\n", path); tiles[type] = new sf::Texture; tiles[type]->loadFromFile(path); } void state_t::begin_frame(double now_, double dt_) { now = now_; dt = dt_; window->clear(); } void state_t::end_frame(void) { window->display(); } void state_t::drender_text(rectf_t rect, std::string str) { sf::Text text(str, font, 20); sf::FloatRect text_rect; v2f_t text_size, x; text.setScale(0.006f, 0.006f); text_rect = text.getGlobalBounds(); text_size = v2f_t(text_rect.width, text_rect.height); x = rect.center() - text_size / 2; text.setPosition(x + v2f_t(0.01f, 0.01f)); text.setFillColor(sf::Color::Black); window->draw(text); text.setPosition(x); text.setFillColor(sf::Color::White); window->draw(text); } void state_t::drender_entity(world::entity_t *ent) { std::stringstream ss; render_hlrect(ent->render_bounds, sf::Color::Red); render_hlrect(ent->cmodel.bounds, sf::Color::Yellow); ss << (void*)ent << "\n"; ss << "CF=" << ent->cmodel.cflags; drender_text(ent->render_bounds, ss.str()); } void state_t::render_sector(world::sector_t *sector) { for (ssize_t y = 0; y < SECTOR_SIZE; y++) for (ssize_t x = 0; x < SECTOR_SIZE; x++) { 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(); } wot_rect.setTexture(texture, true); wot_rect.setSize(sf::Vector2f(1.0f, 1.0f)); wot_rect.setPosition(tx); wot_rect.setFillColor(sf::Color::White); wot_rect.setOutlineColor(sf::Color::Transparent); window->draw(wot_rect); wot_rect.setTexture(NULL); if (debug_draw_tile_coords) { world::tile_index_t local(x, y); std::stringstream ss; ss << "L=" << local; sf::Text text(ss.str(), font, 20); text.setPosition(tx); text.setScale(0.005, 0.005); window->draw(text); } } } void state_t::render(game::state_t *game) { sf::Vector2u size = window->getSize(); v2f_t A, B, C, D; rectf_t bbox; std::list ents; 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]}); for (world::sector_t *sector : game->world.get_sectors(bbox)) render_sector(sector); ents = game->world.get_render_entities(bbox); ents.sort( [](const world::entity_t *x, const world::entity_t *y) -> bool { 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]; }); for (world::entity_t *ent : ents) { ent->render_to(this); if (debug_draw_cmodels) drender_entity(ent); } } void state_t::render(animated_texture_t *anim, rectf_t bounds, bool mirror){ size_t frame; if (!anim) return; if (!anim->frame_count) return; frame = floor(fmod(now * 20.0, anim->frame_count)); wot_rect.setTexture(anim->frames + frame, true); wot_rect.setFillColor(sf::Color::White); if (!mirror) { wot_rect.setPosition(bounds[0]); wot_rect.setSize(bounds[1] - bounds[0]); } else { float dx = bounds[1][0] - bounds[0][0]; wot_rect.setPosition(bounds[0] + v2f_t(dx, 0)); wot_rect.setSize(bounds[1] - bounds[0]); wot_rect.setScale(v2f_t(-1, 1)); } window->draw(wot_rect); wot_rect.setTexture(NULL); wot_rect.setScale(v2f_t(1, 1)); } void state_t::render(oriented_sprite_t *sprite, rectf_t bounds, float angle) { size_t index; bool mirror; index = sprite->select_index(angle, &mirror); render(sprite->textures + index, bounds, mirror); } void state_t::render_text(v2f_t x, float height, const wchar_t *wstr, text_align_t align, sf::Color color) { sf::Text text(wstr, font, 20); sf::FloatRect rect; float scale; v2f_t offset; rect = text.getGlobalBounds(); scale = height / 20.0f; switch (align) { case ALIGN_CENTER_BOTTOM: offset[0] = -rect.width / 2; offset[1] = -rect.height; break; } offset *= scale; text.setScale(scale, scale); text.setPosition(x + offset); text.setFillColor(color); window->draw(text); } void state_t::render_hlrect(rectf_t rect, sf::Color color) { sf::Color fill; fill = sf::Color(color.r, color.g, color.b, 50); wot_rect.setSize(rect.dims()); wot_rect.setPosition(rect[0]); wot_rect.setFillColor(fill); wot_rect.setOutlineThickness(0.01); wot_rect.setOutlineColor(color); window->draw(wot_rect); wot_rect.setOutlineColor(sf::Color::Transparent); } void state_t::render_arrow(v2f_t x0, v2f_t x1, sf::Color color) { sf::Vertex line[2] = { sf::Vertex(x0, color), sf::Vertex(x1, color) }; window->draw(line, 2, sf::Lines); } void state_t::debug_path(std::list *path) { bool first = true; sf::Vertex line[2]; for (v2f_t &point : *path) { line[1] = line[0]; line[0] = sf::Vertex(point, sf::Color::Blue); if (first) { first = false; continue; } window->draw(line, 2, sf::Lines); } } animated_texture_t::~animated_texture_t(void) { delete[] frames; } bool animated_texture_t::load(std::string prefix, size_t frame_count_) { frame_count = frame_count_; frames = new sf::Texture[frame_count]; for (size_t i = 0; i < frame_count; i++) { std::string path; path = prefix + std::to_string(i) + ".png"; std::cout << "load " << path << "\n"; if (!frames[i].loadFromFile(path)) { delete[] frames; frames = NULL; frame_count = 0; return false; } } return true; } oriented_sprite_t::~oriented_sprite_t(void) { delete[] textures; } float normalize_angle(float angle) { float t; t = angle / (2 * M_PI); t -= floor(t); return t * 2 * M_PI; } size_t oriented_sprite_4M_t::select_index(float angle, bool *mirror) { angle = normalize_angle(angle); if (angle < 0.25f * M_PI) { select_x: *mirror = false; return 0; } else if (angle < 0.75f * M_PI) { *mirror = false; return 1; } else if (angle < 1.25f * M_PI) { *mirror = true; return 0; } else if (angle < 1.75f * M_PI) { *mirror = false; return 2; } else goto select_x; } void oriented_sprite_4M_t::load(std::string prefix, size_t xc, size_t yc, size_t nyc) { textures = new animated_texture_t[3]; textures[0].load(prefix + "_x_", xc); textures[1].load(prefix + "_y_", yc); textures[2].load(prefix + "_ny_", nyc); } size_t oriented_sprite_4M2_t::select_index(float angle, bool *mirror) { angle = normalize_angle(angle + 0.01f); if (angle < 0.25f * M_PI) { select_x: *mirror = false; return 0; } else if (angle < 0.75f * M_PI) { *mirror = false; return 1; } else if (angle < 1.25f * M_PI) { *mirror = true; return 0; } else if (angle < 1.75f * M_PI) { *mirror = false; return 1; } else goto select_x; } void oriented_sprite_4M2_t::load(std::string prefix, size_t xc, size_t yc) { textures = new animated_texture_t[2]; textures[0].load(prefix + "_x_", xc); textures[1].load(prefix + "_y_", yc); } } // namespace render