diff --git a/rwengine/include/engine/GameState.hpp b/rwengine/include/engine/GameState.hpp index a2d254f8..40bd3256 100644 --- a/rwengine/include/engine/GameState.hpp +++ b/rwengine/include/engine/GameState.hpp @@ -28,6 +28,18 @@ struct OnscreenText float osTextStart; float osTextTime; unsigned short osTextStyle; + + enum /*TextStyle*/ + { + /// Used for subtitles + HighPriority = 0, + /// Mission completed message + CenterBig = 1, + /// Right aligned mission names + MissionName = 2, + /// Help text (top left, black background) + Help = 12 + }; }; /** diff --git a/rwengine/include/render/TextRenderer.hpp b/rwengine/include/render/TextRenderer.hpp index 5cb7140e..2059edb6 100644 --- a/rwengine/include/render/TextRenderer.hpp +++ b/rwengine/include/render/TextRenderer.hpp @@ -21,6 +21,13 @@ public: */ struct TextInfo { + enum TextAlignemnt + { + Left = 0, + Right = 1, + Center = 2 + }; + /// Font index @see TextRenderer::setFontTexture int font; /// Message to be displayed (including markup) @@ -31,6 +38,8 @@ public: float size; /// Base colour glm::vec3 baseColour; + /// Horizontal Alignment + TextAlignemnt align; TextInfo(); }; diff --git a/rwengine/src/render/TextRenderer.cpp b/rwengine/src/render/TextRenderer.cpp index 8bb6335b..959c9b56 100644 --- a/rwengine/src/render/TextRenderer.cpp +++ b/rwengine/src/render/TextRenderer.cpp @@ -53,7 +53,7 @@ struct TextVertex TextRenderer::TextInfo::TextInfo() -: font(0), size(1.f), baseColour({1.f, 1.f, 1.f}) +: font(0), size(1.f), baseColour({1.f, 1.f, 1.f}), align(Left) { } @@ -143,6 +143,16 @@ void TextRenderer::renderText(const TextRenderer::TextInfo& ti) dp.texture = engine->gameData.textures[{fonts[ti.font], ""}].texName; glm::vec2 ss( ti.size ); + /// @todo smarter alignment + if ( ti.align == TextInfo::Right ) + { + coord.x -= ss.x * ti.text.length(); + } + else if ( ti.align == TextInfo::Center ) + { + coord.x -= glm::floor(ss.x * ti.text.length() * 0.5f); + } + glm::vec3 colour = ti.baseColour; /// @todo make this less wastefull diff --git a/rwengine/src/script/modules/GameModule.cpp b/rwengine/src/script/modules/GameModule.cpp index 476cd117..254a1ac7 100644 --- a/rwengine/src/script/modules/GameModule.cpp +++ b/rwengine/src/script/modules/GameModule.cpp @@ -24,7 +24,6 @@ #include #include -#include void game_print_big(const ScriptArguments& args) { diff --git a/rwgame/CMakeLists.txt b/rwgame/CMakeLists.txt index bd5518cc..eac73fbc 100644 --- a/rwgame/CMakeLists.txt +++ b/rwgame/CMakeLists.txt @@ -10,6 +10,8 @@ add_executable(rwgame pausestate.cpp menustate.cpp debugstate.cpp + + DrawUI.cpp ) include_directories("${CMAKE_SOURCE_DIR}/rwengine/include" ${BULLET_INCLUDE_DIR}) diff --git a/rwgame/DrawUI.cpp b/rwgame/DrawUI.cpp new file mode 100644 index 00000000..d4d985c7 --- /dev/null +++ b/rwgame/DrawUI.cpp @@ -0,0 +1,146 @@ +#include "DrawUI.hpp" +#include +#include +#include +#include +#include + +void drawMap(PlayerController* player, GameWorld* world, GameRenderer* render) +{ + MapRenderer::MapInfo map; + map.scale = 0.4f; + + glm::quat plyRot; + + if( player ) + { + plyRot = player->getCharacter()->getRotation(); + } + + map.rotation = glm::roll(plyRot); + + const glm::ivec2& vp = render->getRenderer()->getViewport(); + + map.mapScreenTop = glm::vec2(260.f, vp.y - 10.f); + map.mapScreenBottom = glm::vec2(10.f, vp.y - 210.f); + + if( player ) + { + map.center = glm::vec2(player->getCharacter()->getPosition()); + } + + render->map.draw(map); +} + +void drawHUD(PlayerController* player, GameWorld* world, GameRenderer* render) +{ + drawMap(player, world, render); +} + +void drawOnScreenText(GameWorld* world) +{ + const glm::ivec2& vp = world->renderer.getRenderer()->getViewport(); + + TextRenderer::TextInfo ti; + ti.font = 2; + ti.screenPosition = glm::vec2( 10.f, 10.f ); + ti.size = 20.f; + + for(OnscreenText& t : world->state.text) + { + glm::vec2 shadowOffset( 0, 0 ); + + switch(t.osTextStyle) + { + default: + ti.size = 15.f; + ti.font = 0; + ti.align = TextRenderer::TextInfo::Left; + ti.baseColour = glm::vec3(1.f); + ti.screenPosition = vp / 2; + break; + case OnscreenText::HighPriority: + ti.size = 20.f; + ti.font = 2; + ti.baseColour = glm::vec3(1.f); + ti.screenPosition = glm::vec2(vp.x * 0.5f, vp.y - ti.size * 2.f); + ti.align = TextRenderer::TextInfo::Center; + break; + case OnscreenText::CenterBig: + ti.size = 30.f; + ti.font = 1; + ti.baseColour = glm::vec3(82, 114, 128) / 255.f; + ti.align = TextRenderer::TextInfo::Center; + ti.screenPosition = vp / 2; + ti.screenPosition += glm::vec2(0.f, ti.size / 2.f); + shadowOffset = glm::vec2(2.f, 0.f); + break; + case OnscreenText::MissionName: + ti.size = 30.f; + ti.font = 1; + ti.baseColour = glm::vec3(205, 162, 7)/255.f; + ti.screenPosition = glm::vec2(vp.x - 10.f, vp.y * 0.79f); + ti.align = TextRenderer::TextInfo::Right; + shadowOffset = glm::vec2(2.f, 2.f); + break; + case OnscreenText::Help: + ti.screenPosition = glm::vec2(20.f, 20.f); + ti.font = 2; + ti.size = 20.f; + ti.baseColour = glm::vec3(1.f); + ti.align = TextRenderer::TextInfo::Left; + break; + } + + ti.text = t.osTextString; + + if( t.osTextStyle == OnscreenText::Help ) + { + // Insert line breaks into the message string. + auto m = ti.text; + const float boxWidth = 250.f; + int lastSpace = 0; + float lineLength = 0.f, wordLength = 0.f; + for( int c = 0; c < m.length(); ++c ) + { + if(m[c] == ' ') + { + lastSpace = c; + lineLength += wordLength; + wordLength = 0.f; + } + + wordLength += ti.size; + + if( lineLength + wordLength > boxWidth ) + { + m[lastSpace] = '\n'; + lineLength = 0.f; + } + } + ti.text = m; + } + + if( glm::length( shadowOffset ) > 0 ) + { + TextRenderer::TextInfo shadow( ti ); + shadow.baseColour = glm::vec3(0.f); + shadow.screenPosition += shadowOffset; + + world->renderer.text.renderText(shadow); + } + + world->renderer.text.renderText(ti); + } + + for(auto& t : world->state.texts) { + ti.font = 2; + ti.screenPosition = t.position / glm::vec2(640, 480); + ti.screenPosition *= vp; + ti.baseColour = glm::vec3(t.colourFG); + ti.size = 20.f; + ti.text = t.text; + + world->renderer.text.renderText(ti); + } +} diff --git a/rwgame/DrawUI.hpp b/rwgame/DrawUI.hpp new file mode 100644 index 00000000..ce620eca --- /dev/null +++ b/rwgame/DrawUI.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +class PlayerController; + +void drawHUD(PlayerController* player, GameWorld* world, GameRenderer* render); + +void drawOnScreenText(GameWorld* world); \ No newline at end of file diff --git a/rwgame/RWGame.cpp b/rwgame/RWGame.cpp index 416de486..a4e8c9e7 100644 --- a/rwgame/RWGame.cpp +++ b/rwgame/RWGame.cpp @@ -1,6 +1,7 @@ #include "RWGame.hpp" #include "State.hpp" #include "loadingstate.hpp" +#include "DrawUI.hpp" #include #include @@ -290,7 +291,7 @@ void RWGame::render(float alpha) debug->flush(&engine->renderer); #endif - std::stringstream ss; + /*std::stringstream ss; ss << std::setfill('0') << "Time: " << std::setw(2) << engine->getHour() << ":" << std::setw(2) << engine->getMinute() << " (" << engine->gameTime << "s)\n"; ss << "View: " << viewCam.position.x << " " << viewCam.position.y << " " << viewCam.position.z << "\n"; @@ -304,16 +305,16 @@ void RWGame::render(float alpha) ss << "Idle"; } ss << std::endl; - } + }*/ TextRenderer::TextInfo ti; - ti.text = ss.str(); + //ti.text = ss.str(); ti.font = 2; ti.screenPosition = glm::vec2( 10.f, 10.f ); ti.size = 20.f; - engine->renderer.text.renderText(ti); + //engine->renderer.text.renderText(ti); - while( engine->log.size() > 0 && engine->log.front().time + 10.f < engine->gameTime ) { + /*while( engine->log.size() > 0 && engine->log.front().time + 10.f < engine->gameTime ) { engine->log.pop_front(); } @@ -339,7 +340,7 @@ void RWGame::render(float alpha) engine->renderer.text.renderText(ti); ti.screenPosition.y -= ti.size; - } + }*/ for( int i = 0; i < engine->state.text.size(); ) { @@ -352,93 +353,8 @@ void RWGame::render(float alpha) i++; } } - - for(OnscreenText& t : engine->state.text) - { - float fontSize = 20.f; - switch(t.osTextStyle) - { - default: - fontSize = 20.f; - break; - case 1: - fontSize = 40.f; - break; - case 2: - fontSize = 20.f; - break; - } - - ti.size = fontSize; - ti.screenPosition = glm::vec2(0.f); - ti.font = 0; - if(t.osTextStyle == 1) - { - ti.screenPosition = glm::vec2(500.f, 500.f); - } - else if(t.osTextStyle == 2) - { - ti.screenPosition = glm::vec2(500.f, 500.f); - } - else if(t.osTextStyle == 12) - { - ti.screenPosition = glm::vec2(20.f, 20.f); - ti.font = 2; -// messageText.setPosition(15.f, 15.f); - -// // Insert line breaks into the message string. -// auto m = messageText.getString(); -// const float boxWidth = 250.f; -// int lastSpace = 0; -// float lineLength = 0.f, wordLength = 0.f; -// for( int c = 0; c < m.getSize(); ++c ) -// { -// if(m[c] == ' ') -// { -// lastSpace = c; -// lineLength += wordLength; -// wordLength = 0.f; -// } -// -// auto& metrics = font.getGlyph(m[c], fontSize, false); -// wordLength += metrics.bounds.width; -// -// if( lineLength + wordLength > boxWidth ) -// { -// m[lastSpace] = '\n'; -// lineLength = 0.f; -// } -// } -// messageText.setString(m); -// -// auto bds = messageText.getGlobalBounds(); -// sf::RectangleShape bg(sf::Vector2f(bds.width, bds.height) + sf::Vector2f(10.f, 10.f)); -// bg.setFillColor(sf::Color::Black); -// bg.setPosition(sf::Vector2f(bds.left, bds.top) - sf::Vector2f(5.f, 5.f)); -// window.draw(bg); - } - else - { - float lowerBar = 550.f; - ti.screenPosition = glm::vec2(300.f, lowerBar); - } - - ti.text = t.osTextString; - engine->renderer.text.renderText(ti); - } - - /*for(auto& t : engine->state.texts) { - sf::Text messageText(t.text, font, 15); - - glm::vec2 scpos(t.position.x, t.position.y); - auto s = window.getSize(); - scpos /= glm::vec2(640.f, 480.f); - scpos *= glm::vec2(s.x, s.y); - - messageText.setPosition(scpos.x, scpos.y); - - window.draw(messageText); - }*/ + + drawOnScreenText(engine); } void RWGame::globalKeyEvent(const sf::Event& event) diff --git a/rwgame/ingamestate.cpp b/rwgame/ingamestate.cpp index b5745545..6656ff27 100644 --- a/rwgame/ingamestate.cpp +++ b/rwgame/ingamestate.cpp @@ -2,6 +2,7 @@ #include "RWGame.hpp" #include "pausestate.hpp" #include "debugstate.hpp" +#include "DrawUI.hpp" #include #include @@ -191,13 +192,12 @@ void IngameState::draw(GameRenderer* r) { if( !getWorld()->state.isCinematic && getWorld()->isCutsceneDone() ) { - drawHUD(r); + drawHUD(getPlayer(), getWorld(), r); } State::draw(r); } - void IngameState::handleEvent(const sf::Event &event) { auto player = getPlayer(); @@ -299,30 +299,4 @@ const ViewCamera &IngameState::getCamera() return _look; } -void IngameState::drawHUD(GameRenderer* renderer) -{ - MapRenderer::MapInfo map; - map.scale = 0.4f; - - glm::quat plyRot; - - if( getPlayer() ) - { - auto p = getPlayer(); - plyRot = p->getCharacter()->getRotation(); - } - - map.rotation = glm::roll(plyRot); - - const glm::ivec2& vp = renderer->getRenderer()->getViewport(); - - map.mapScreenTop = glm::vec2(260.f, vp.y - 10.f); - map.mapScreenBottom = glm::vec2(10.f, vp.y - 210.f); - - if( getWorld()->state.player ) - { - map.center = glm::vec2(getWorld()->state.player->getCharacter()->getPosition()); - } - getWorld()->renderer.map.draw(map); -} diff --git a/rwgame/ingamestate.hpp b/rwgame/ingamestate.hpp index 5e17786b..39ae35ce 100644 --- a/rwgame/ingamestate.hpp +++ b/rwgame/ingamestate.hpp @@ -29,9 +29,6 @@ public: virtual void handleEvent(const sf::Event& event); const ViewCamera& getCamera(); - -private: - void drawHUD(GameRenderer* r); }; #endif // INGAMESTATE_HPP