From ed6726ef7e63b6c37b28e36818030925b370207b Mon Sep 17 00:00:00 2001 From: Prashanth Jonnala Date: Thu, 20 Aug 2015 22:24:32 -0400 Subject: [PATCH 1/2] 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 bfbf0b0bd8..3f417269b2 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 bc60a1846e..035f55921e 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 = std::make_unique(); } 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 5998bf10c7..7299ef9bc0 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 0000000000..4315643ad5 --- /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 0000000000..9526f5e46c --- /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 0000000000..1a91f4190b --- /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 0000000000..540837f4a0 --- /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 0000000000..24ce58b202 --- /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 From c1511db17e62095732e9dbd73c53c3e40cd4fe49 Mon Sep 17 00:00:00 2001 From: Prashanth Jonnala Date: Sat, 22 Aug 2015 19:12:34 -0400 Subject: [PATCH 2/2] renderer: fixed minor issues and added documentation for text renderer --- libopenage/engine.cpp | 6 --- libopenage/renderer/color.cpp | 8 ++-- libopenage/renderer/color.h | 7 +-- libopenage/renderer/text_renderer.cpp | 13 ++---- libopenage/renderer/text_renderer.h | 62 +++++++++++++++++++++++++-- 5 files changed, 69 insertions(+), 27 deletions(-) diff --git a/libopenage/engine.cpp b/libopenage/engine.cpp index 035f55921e..c1efcb2131 100644 --- a/libopenage/engine.cpp +++ b/libopenage/engine.cpp @@ -280,28 +280,22 @@ 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; diff --git a/libopenage/renderer/color.cpp b/libopenage/renderer/color.cpp index 9526f5e46c..0a89d0190a 100644 --- a/libopenage/renderer/color.cpp +++ b/libopenage/renderer/color.cpp @@ -43,12 +43,12 @@ Color &Color::operator=(const Color &other) { 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 Color::operator==(const Color &other) const { + return this->r == other.r && this->g == other.g && this->b == other.b && this->a == other.a; } -bool operator!=(const Color &left, const Color &right) { - return !(left == right); +bool Color::operator!=(const Color &other) const { + return this->r != other.r || this->g != other.g || this->b != other.b || this->a != other.a; } }} // openage::renderer diff --git a/libopenage/renderer/color.h b/libopenage/renderer/color.h index 1a91f4190b..b41f4e5ba2 100644 --- a/libopenage/renderer/color.h +++ b/libopenage/renderer/color.h @@ -18,6 +18,10 @@ class Color { Color &operator=(const Color &other); + bool operator==(const Color &other) const; + + bool operator!=(const Color &other) const; + uint8_t r; uint8_t g; uint8_t b; @@ -25,9 +29,6 @@ class Color { }; -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 index 540837f4a0..ce2986b0da 100644 --- a/libopenage/renderer/text_renderer.cpp +++ b/libopenage/renderer/text_renderer.cpp @@ -58,24 +58,17 @@ void TextRenderer::draw(coord::window position, const std::string &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->render_batches.emplace_back(this->current_font, this->current_color); 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); + this->render_batches.back().passes.emplace_back(x, y, text); } 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 { + [](const text_render_batch &a, const text_render_batch &b) -> bool { return a.font < b.font; }); diff --git a/libopenage/renderer/text_renderer.h b/libopenage/renderer/text_renderer.h index 24ce58b202..39cc1a54c9 100644 --- a/libopenage/renderer/text_renderer.h +++ b/libopenage/renderer/text_renderer.h @@ -22,32 +22,86 @@ class TextRenderer { virtual ~TextRenderer(); + /** + * Set the font to be used for the future text draw calls. + * + * @param font: the font to be used. + */ void set_font(Font *font); + + /** + * Set the color to be used for the future text draw calls. + * + * @param color: the color to be used. + */ void set_color(const Color &color); + /** + * Draw a formatted string at the specified position. + * + * @param position: where the text should be displayed. + * @param format: the text format + */ void draw(coord::window position, const char *format, ...); + + /** + * Draw text at the specified position. + * + * @param position: where the text should be displayed. + * @param text: the text to be displayed. + */ void draw(coord::window position, const std::string &text); + + /** + * Draw text at the specified position. + * + * @param x: the position in x-direction. + * @param y: the position in y-direction. + * @param text: the text to be displayed. + */ void draw(int x, int y, const std::string &text); + /** + * Render all the text draw requests made during the frame. + */ void render(); private: - struct TextRenderBatchPass { + /** + * A single text draw request containing the text and position. + */ + struct text_render_batch_pass { int x; int y; std::string text; + + text_render_batch_pass(int x, int y, const std::string &text) + : + x{x}, + y{y}, + text{text} { + } }; - struct TextRenderBatch { + /** + * The set of text draw requests with the same font and color. + */ + struct text_render_batch { openage::Font *font; Color color; - std::vector passes; + std::vector passes; + + text_render_batch(openage::Font *font, const Color &color) + : + font{font}, + color{color} { + } }; Font *current_font; Color current_color; bool is_dirty; - std::vector render_batches; + std::vector render_batches; };