From 85843ebeb4ffa8671358839a89133d032406cf51 Mon Sep 17 00:00:00 2001 From: Prashanth Jonnala Date: Thu, 20 Aug 2015 22:24:32 -0400 Subject: [PATCH] renderer: primitive text renderer with support for colors --- libopenage/CMakeLists.txt | 1 + libopenage/engine.cpp | 17 +++- libopenage/engine.h | 8 ++ libopenage/renderer/CMakeLists.txt | 4 + libopenage/renderer/color.cpp | 54 ++++++++++++ libopenage/renderer/color.h | 33 ++++++++ libopenage/renderer/text_renderer.cpp | 114 ++++++++++++++++++++++++++ libopenage/renderer/text_renderer.h | 56 +++++++++++++ 8 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 libopenage/renderer/CMakeLists.txt create mode 100644 libopenage/renderer/color.cpp create mode 100644 libopenage/renderer/color.h create mode 100644 libopenage/renderer/text_renderer.cpp create mode 100644 libopenage/renderer/text_renderer.h diff --git a/libopenage/CMakeLists.txt b/libopenage/CMakeLists.txt index bfbf0b0bd87..3f417269b25 100644 --- a/libopenage/CMakeLists.txt +++ b/libopenage/CMakeLists.txt @@ -50,6 +50,7 @@ add_subdirectory("testing") add_subdirectory("unit") add_subdirectory("util") add_subdirectory("rng") +add_subdirectory("renderer") # run codegen, add files to executable codegen_run() diff --git a/libopenage/engine.cpp b/libopenage/engine.cpp index bc60a1846e6..e8d434f3c35 100644 --- a/libopenage/engine.cpp +++ b/libopenage/engine.cpp @@ -222,6 +222,8 @@ Engine::Engine(util::Dir *data_dir, const char *windowtitle) bind_player_switch(input::action_t::SWITCH_TO_PLAYER_6, 6); bind_player_switch(input::action_t::SWITCH_TO_PLAYER_7, 7); bind_player_switch(input::action_t::SWITCH_TO_PLAYER_8, 8); + + this->text_renderer.reset(new renderer::TextRenderer()); } Engine::~Engine() { @@ -278,22 +280,28 @@ void Engine::end_game() { bool Engine::draw_debug_overlay() { util::col {255, 255, 255, 255}.use(); + this->text_renderer->set_color(renderer::Color{255, 0, 0, 255}); // Draw FPS counter in the lower right corner this->render_text( {this->engine_coord_data->window_size.x - 100, 15}, 20, "%.1f fps", this->fps_counter.fps ); + this->text_renderer->set_color(renderer::Color{0, 255, 0, 255}); // Draw version string in the lower left corner this->render_text( {5, 35}, 20, "openage %s", config::version ); + + this->text_renderer->set_color(renderer::Color{0, 0, 255, 255}); this->render_text( {5, 15}, 12, "%s", config::config_option_string ); + this->text_renderer->set_color(renderer::Color{255, 255, 255, 255}); + this->profiler.show(true); return true; @@ -426,6 +434,8 @@ void Engine::loop() { } } } + + this->text_renderer->render(); } glPopMatrix(); @@ -496,6 +506,10 @@ input::InputManager &Engine::get_input_manager() { return this->input_manager; } +renderer::TextRenderer *Engine::get_text_renderer() { + return this->text_renderer.get(); +} + int64_t Engine::lastframe_duration_nsec() { return this->fps_counter.nsec_lastframe; } @@ -514,7 +528,8 @@ void Engine::render_text(coord::window position, size_t size, const char *format util::vsformat(format, vl, buf); va_end(vl); - font->render_static(position.x, position.y, buf.c_str()); + this->text_renderer->set_font(font); + this->text_renderer->draw(position.x, position.y, buf); } void Engine::move_phys_camera(float x, float y, float amount) { diff --git a/libopenage/engine.h b/libopenage/engine.h index 5998bf10c7b..7299ef9bc01 100644 --- a/libopenage/engine.h +++ b/libopenage/engine.h @@ -26,6 +26,7 @@ #include "util/fps.h" #include "util/profiler.h" #include "screenshot.h" +#include "renderer/text_renderer.h" namespace openage { @@ -213,6 +214,11 @@ class Engine : public ResizeHandler, public options::OptionNode { */ input::InputManager &get_input_manager(); + /** + * return this engine's text renderer. + */ + renderer::TextRenderer *get_text_renderer(); + /** * return the number of nanoseconds that have passed * for rendering the last frame. @@ -358,6 +364,8 @@ class Engine : public ResizeHandler, public options::OptionNode { * the engines profiler */ util::Profiler profiler; + + std::unique_ptr text_renderer; }; } // namespace openage diff --git a/libopenage/renderer/CMakeLists.txt b/libopenage/renderer/CMakeLists.txt new file mode 100644 index 00000000000..4315643ad51 --- /dev/null +++ b/libopenage/renderer/CMakeLists.txt @@ -0,0 +1,4 @@ +add_sources(libopenage + color.cpp + text_renderer.cpp +) diff --git a/libopenage/renderer/color.cpp b/libopenage/renderer/color.cpp new file mode 100644 index 00000000000..9526f5e46c5 --- /dev/null +++ b/libopenage/renderer/color.cpp @@ -0,0 +1,54 @@ +// Copyright 2015-2015 the openage authors. See copying.md for legal info. + +#include "color.h" + +namespace openage { +namespace renderer { + +Color::Color() + : + r{0}, + g{0}, + b{0}, + a{255} { + // Empty +} + +Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) + : + r{r}, + g{g}, + b{b}, + a{a} { + // Empty +} + +Color::Color(const Color &other) + : + r{other.r}, + g{other.g}, + b{other.b}, + a{other.a} { + // Empty +} + +Color &Color::operator=(const Color &other) { + if (this != &other) { + this->r = other.r; + this->g = other.g; + this->b = other.b; + this->a = other.a; + } + + return *this; +} + +bool operator==(const Color &left, const Color &right) { + return left.r == right.r && left.g == right.g && left.b == right.b && left.a == right.a; +} + +bool operator!=(const Color &left, const Color &right) { + return !(left == right); +} + +}} // openage::renderer diff --git a/libopenage/renderer/color.h b/libopenage/renderer/color.h new file mode 100644 index 00000000000..1a91f4190b7 --- /dev/null +++ b/libopenage/renderer/color.h @@ -0,0 +1,33 @@ +// Copyright 2015-2015 the openage authors. See copying.md for legal info. + +#ifndef OPENAGE_RENDERER_COLOR_H_ +#define OPENAGE_RENDERER_COLOR_H_ + +#include + +namespace openage { +namespace renderer { + +class Color { +public: + Color(); + + Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a); + + Color(const Color &other); + + Color &operator=(const Color &other); + + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + +}; + +bool operator==(const Color &left, const Color &right); +bool operator!=(const Color &left, const Color &right); + +}} // openage::renderer + +#endif diff --git a/libopenage/renderer/text_renderer.cpp b/libopenage/renderer/text_renderer.cpp new file mode 100644 index 00000000000..540837f4a00 --- /dev/null +++ b/libopenage/renderer/text_renderer.cpp @@ -0,0 +1,114 @@ +// Copyright 2015-2015 the openage authors. See copying.md for legal info. + +#include "text_renderer.h" + +#include +#include + +#include "../log/log.h" +#include "../util/strings.h" +#include "../font.h" + +namespace openage { +namespace renderer { + +TextRenderer::TextRenderer() + : + current_font{nullptr}, + current_color{255, 255, 255, 255}, + is_dirty{true} { + // Empty +} + +TextRenderer::~TextRenderer() { + // Empty +} + +void TextRenderer::set_font(openage::Font *font) { + if (this->current_font == font) { + return; + } + + this->current_font = font; + this->is_dirty = true; +} + +void TextRenderer::set_color(const Color &color) { + if (this->current_color == color) { + return; + } + + this->current_color = color; + this->is_dirty = true; +} + +void TextRenderer::draw(coord::window position, const char *format, ...) { + std::string text; + va_list vl; + va_start(vl, format); + util::vsformat(format, vl, text); + va_end(vl); + + this->draw(position.x, position.y, text); +} + +void TextRenderer::draw(coord::window position, const std::string &text) { + this->draw(position.x, position.y, text); +} + +void TextRenderer::draw(int x, int y, const std::string &text) { + if (this->is_dirty) { + TextRenderBatch batch; + batch.font = this->current_font; + batch.color = this->current_color; + render_batches.push_back(batch); + this->is_dirty = false; + } + + TextRenderBatchPass batch_pass; + batch_pass.x = x; + batch_pass.y = y; + batch_pass.text = text; + render_batches.back().passes.push_back(batch_pass); +} + +void TextRenderer::render() { + // Sort the batches by font + std::sort(std::begin(this->render_batches), std::end(this->render_batches), + [](const TextRenderBatch &a, const TextRenderBatch &b) -> bool { + return a.font < b.font; + }); + + // Merge consecutive batches if font and color values are same + for (auto current_batch = std::begin(this->render_batches); current_batch != std::end(this->render_batches); ) { + auto next_batch = current_batch; + next_batch++; + if (next_batch != std::end(this->render_batches) && + current_batch->font == next_batch->font && + current_batch->color == next_batch->color) { + // Merge the render passes of current and next batches and remove the next batch + std::move(std::begin(next_batch->passes), + std::end(next_batch->passes), + std::back_inserter(current_batch->passes)); + this->render_batches.erase(next_batch); + } else { + current_batch++; + } + } + + // Render all the batches + for (auto &batch : this->render_batches) { + glColor4f(batch.color.r / 255.f, + batch.color.g / 255.f, + batch.color.b / 255.f, + batch.color.a / 255.f); + for (auto &pass : batch.passes) { + batch.font->render_static(pass.x, pass.y, pass.text.c_str()); + } + } + + // Clear the render batches for next frame + this->render_batches.clear(); +} + +}} // openage::renderer diff --git a/libopenage/renderer/text_renderer.h b/libopenage/renderer/text_renderer.h new file mode 100644 index 00000000000..24ce58b2021 --- /dev/null +++ b/libopenage/renderer/text_renderer.h @@ -0,0 +1,56 @@ +// Copyright 2015-2015 the openage authors. See copying.md for legal info. + +#ifndef OPENAGE_RENDERER_TEXT_RENDERER_H_ +#define OPENAGE_RENDERER_TEXT_RENDERER_H_ + +#include +#include + +#include "../coord/window.h" +#include "color.h" + +namespace openage { + +class Font; + +namespace renderer { + +class TextRenderer { + +public: + TextRenderer(); + + virtual ~TextRenderer(); + + void set_font(Font *font); + void set_color(const Color &color); + + void draw(coord::window position, const char *format, ...); + void draw(coord::window position, const std::string &text); + void draw(int x, int y, const std::string &text); + + void render(); + +private: + struct TextRenderBatchPass { + int x; + int y; + std::string text; + }; + + struct TextRenderBatch { + openage::Font *font; + Color color; + std::vector passes; + }; + + Font *current_font; + Color current_color; + bool is_dirty; + std::vector render_batches; + +}; + +}} // openage::renderer + +#endif