mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-03 09:09:47 +02:00
Text rendering
This commit is contained in:
parent
538d0c02f9
commit
2344024f08
@ -28,6 +28,7 @@ class SCMFile;
|
||||
* @brief Stores simple data about Textures such as transparency flags.
|
||||
*
|
||||
* @todo Covert usage to TextureHandles or something for streaming.
|
||||
* @todo Move out of GameData.hpp and into TextureInfo.hpp
|
||||
*/
|
||||
struct TextureInfo
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <render/OpenGLRenderer.hpp>
|
||||
#include "MapRenderer.hpp"
|
||||
#include "TextRenderer.hpp"
|
||||
|
||||
class Model;
|
||||
class ModelFrame;
|
||||
@ -244,6 +245,7 @@ public:
|
||||
}
|
||||
|
||||
MapRenderer map;
|
||||
TextRenderer text;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
/// @todo dont use GLint in the interface.
|
||||
virtual void setProgramBlockBinding(ShaderProgram* p, const std::string& name, GLint point) = 0;
|
||||
virtual void setUniformTexture(ShaderProgram*p, const std::string& name, GLint tex) = 0;
|
||||
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::mat4& m) = 0;
|
||||
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec4& v) = 0;
|
||||
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec3& v) = 0;
|
||||
virtual void setUniform(ShaderProgram*p, const std::string& name, const glm::vec2& v) = 0;
|
||||
@ -89,7 +90,15 @@ public:
|
||||
virtual void draw(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
|
||||
virtual void drawArrays(const glm::mat4& model, DrawBuffer* draw, const DrawParameters& p) = 0;
|
||||
|
||||
void setViewport(const glm::ivec2& vp) { viewport = vp; }
|
||||
const glm::ivec2& getViewport() const { return viewport; }
|
||||
|
||||
glm::mat4 get2DProjection() const;
|
||||
|
||||
virtual void invalidate() = 0;
|
||||
|
||||
private:
|
||||
glm::ivec2 viewport;
|
||||
};
|
||||
|
||||
class OpenGLRenderer : public Renderer
|
||||
@ -127,6 +136,7 @@ public:
|
||||
ShaderProgram* createShader(const std::string &vert, const std::string &frag);
|
||||
void setProgramBlockBinding(ShaderProgram* p, const std::string &name, GLint point);
|
||||
void setUniformTexture(ShaderProgram* p, const std::string &name, GLint tex);
|
||||
void setUniform(ShaderProgram* p, const std::string& name, const glm::mat4& m);
|
||||
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec4& m);
|
||||
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec3& m);
|
||||
void setUniform(ShaderProgram* p, const std::string& name, const glm::vec2& m);
|
||||
|
53
rwengine/include/render/TextRenderer.hpp
Normal file
53
rwengine/include/render/TextRenderer.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include <engine/GameData.hpp>
|
||||
#include "OpenGLRenderer.hpp"
|
||||
|
||||
#define GAME_FONTS 3
|
||||
|
||||
class GameWorld;
|
||||
class GameRenderer;
|
||||
/**
|
||||
* @brief Handles rendering of bitmap font textures.
|
||||
*
|
||||
* In future, strings textures might be cached to improve performance, but
|
||||
* for now, we just render each glyph on it's own quad
|
||||
*/
|
||||
class TextRenderer
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* @todo Can this be merged with the gamestate text entries?
|
||||
*/
|
||||
struct TextInfo
|
||||
{
|
||||
/// Font index @see TextRenderer::setFontTexture
|
||||
int font;
|
||||
/// Message to be displayed (including markup)
|
||||
std::string text;
|
||||
/// On screen position
|
||||
glm::vec2 screenPosition;
|
||||
/// font size
|
||||
float size;
|
||||
/// Base colour
|
||||
glm::vec3 baseColour;
|
||||
|
||||
TextInfo();
|
||||
};
|
||||
|
||||
TextRenderer(GameWorld* engine, GameRenderer* renderer);
|
||||
~TextRenderer();
|
||||
|
||||
void setFontTexture( int index, const std::string& font );
|
||||
|
||||
void renderText( const TextInfo& ti );
|
||||
|
||||
private:
|
||||
std::string fonts[GAME_FONTS];
|
||||
GameWorld* engine;
|
||||
GameRenderer* renderer;
|
||||
Renderer::ShaderProgram* textShader;
|
||||
|
||||
GeometryBuffer gb;
|
||||
DrawBuffer db;
|
||||
};
|
@ -107,6 +107,7 @@ void GameData::load()
|
||||
_knownFiles.insert({"hud.txd", {false, datpath+"/models/hud.txd"}});
|
||||
_knownFiles.insert({"english.gxt", {false, datpath+"/TEXT/english.gxt"}});
|
||||
_knownFiles.insert({"ped.ifp", {false, datpath+"/anim/ped.ifp"}});
|
||||
_knownFiles.insert({"fonts.txd", {false, datpath+"/models/fonts.txd"}});
|
||||
|
||||
_knownFiles.insert({"news.txd", {false, datpath+"/txd/NEWS.TXD"}});
|
||||
_knownFiles.insert({"splash1.txd", {false, datpath+"/txd/SPLASH1.TXD"}});
|
||||
@ -118,6 +119,7 @@ void GameData::load()
|
||||
loadDFF("arrow.dff");
|
||||
loadTXD("particle.txd");
|
||||
loadTXD("hud.txd");
|
||||
loadTXD("fonts.txd");
|
||||
|
||||
loadCarcols(datpath+"/data/carcols.dat");
|
||||
loadWeather(datpath+"/data/timecyc.dat");
|
||||
|
@ -80,7 +80,7 @@ DrawBuffer ssRectDraw;
|
||||
|
||||
GameRenderer::GameRenderer(GameWorld* engine)
|
||||
: engine(engine), renderer(new OpenGLRenderer), _renderAlpha(0.f),
|
||||
map(engine, renderer)
|
||||
map(engine, renderer), text(engine, this)
|
||||
{
|
||||
engine->logInfo("[DRAW] " + renderer->getIDString());
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <render/OpenGLRenderer.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
@ -79,6 +80,22 @@ GLuint compileProgram(const char* vertex, const char* fragment)
|
||||
return prog;
|
||||
}
|
||||
|
||||
glm::mat4 Renderer::get2DProjection() const
|
||||
{
|
||||
glm::vec2 aspect(1.f, 1.f);
|
||||
if( viewport.x > viewport.y )
|
||||
{
|
||||
// Widescreen
|
||||
aspect.x = viewport.x / (float) viewport.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tall-o-vision
|
||||
aspect.y = viewport.y / (float)viewport.x;
|
||||
}
|
||||
return glm::ortho(0.f, 800.f * aspect.x, 600.f * aspect.y, 0.f, -1.f, 1.f);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::useDrawBuffer(DrawBuffer* dbuff)
|
||||
{
|
||||
if( dbuff != currentDbuff )
|
||||
@ -147,6 +164,13 @@ void OpenGLRenderer::setUniformTexture(Renderer::ShaderProgram* p, const std::st
|
||||
glUniform1i(currentProgram->getUniformLocation(name), tex);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::mat4& m)
|
||||
{
|
||||
useProgram(p);
|
||||
|
||||
glUniformMatrix4fv(currentProgram->getUniformLocation(name.c_str()), 1, GL_FALSE, glm::value_ptr(m));
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setUniform(Renderer::ShaderProgram* p, const std::string& name, const glm::vec4& m)
|
||||
{
|
||||
useProgram(p);
|
||||
|
178
rwengine/src/render/TextRenderer.cpp
Normal file
178
rwengine/src/render/TextRenderer.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "render/TextRenderer.hpp"
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
|
||||
const char* TextVertexShader = R"(
|
||||
#version 130
|
||||
#extension GL_ARB_explicit_attrib_location : enable
|
||||
#extension GL_ARB_uniform_buffer_object : enable
|
||||
|
||||
layout(location = 0) in vec2 position;
|
||||
layout(location = 3) in vec2 texcoord;
|
||||
layout(location = 2) in vec3 colour;
|
||||
out vec2 TexCoord;
|
||||
out vec3 Colour;
|
||||
|
||||
uniform mat4 proj;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = proj * vec4(position, 0.0, 1.0);
|
||||
TexCoord = texcoord;
|
||||
Colour = colour;
|
||||
})";
|
||||
|
||||
const char* TextFragmentShader = R"(
|
||||
#version 130
|
||||
in vec2 TexCoord;
|
||||
in vec3 Colour;
|
||||
uniform vec4 colour;
|
||||
uniform sampler2D fontTexture;
|
||||
out vec4 outColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
float a = texture(fontTexture, TexCoord).a;
|
||||
outColour = vec4(Colour, a);
|
||||
})";
|
||||
|
||||
struct TextVertex
|
||||
{
|
||||
glm::vec2 position;
|
||||
glm::vec2 texcoord;
|
||||
glm::vec3 colour;
|
||||
|
||||
static const AttributeList vertex_attributes() {
|
||||
return {
|
||||
{ATRS_Position, 2, sizeof(TextVertex), 0ul},
|
||||
{ATRS_TexCoord, 2, sizeof(TextVertex), 0ul + sizeof(glm::vec2)},
|
||||
{ATRS_Colour, 3, sizeof(TextVertex), 0ul + sizeof(glm::vec2) * 2},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TextRenderer::TextInfo::TextInfo()
|
||||
: font(0), size(1.f), baseColour({1.f, 1.f, 1.f})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
TextRenderer::TextRenderer(GameWorld* engine, GameRenderer* renderer)
|
||||
: fonts({}), engine(engine), renderer(renderer)
|
||||
{
|
||||
textShader = renderer->getRenderer()->createShader(
|
||||
TextVertexShader, TextFragmentShader );
|
||||
}
|
||||
|
||||
TextRenderer::~TextRenderer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TextRenderer::setFontTexture(int index, const std::string& texture)
|
||||
{
|
||||
if( index < GAME_FONTS )
|
||||
{
|
||||
fonts[index] = texture;
|
||||
}
|
||||
}
|
||||
|
||||
/// @todo This is very rough
|
||||
int charToIndex(char g)
|
||||
{
|
||||
if( g >= '0' && g <= '9' )
|
||||
{
|
||||
return 16 + (g - '0');
|
||||
}
|
||||
else if( g >= 'A' && g <= 'Z' )
|
||||
{
|
||||
return 33 + (g - 'A');
|
||||
}
|
||||
else if( g >= 'a' && g <= 'z' )
|
||||
{
|
||||
return 65 + (g - 'a');
|
||||
}
|
||||
switch(g)
|
||||
{
|
||||
default: return 0;
|
||||
case '!': return 1;
|
||||
case '"': return 2;
|
||||
case '#': return 3;
|
||||
case '$': return 4;
|
||||
case '%': return 5;
|
||||
case '&': return 6;
|
||||
case '\'': return 7;
|
||||
case '(': return 8;
|
||||
case ')': return 9;
|
||||
case '*': return 10;
|
||||
case '+': return 11;
|
||||
case ',': return 12;
|
||||
case '-': return 13;
|
||||
case '.': return 14;
|
||||
case '/': return 15;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec4 indexToCoord(int font, int index)
|
||||
{
|
||||
int x = index % 16;
|
||||
int y = index / 16;
|
||||
glm::vec2 gsize( 1.f / 16.f, 1.f / ((font == 0) ? 16.f : 13.f) );
|
||||
return glm::vec4( x, y, x + 1, y + 1 ) *
|
||||
glm::vec4( gsize, gsize ); // + glm::vec4( 0.0001f, 0.0001f,-0.0001f,-0.0001f);
|
||||
}
|
||||
|
||||
void TextRenderer::renderText(const TextRenderer::TextInfo& ti)
|
||||
{
|
||||
renderer->getRenderer()->useProgram(textShader);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
renderer->getRenderer()->setUniform(textShader, "proj", renderer->getRenderer()->get2DProjection());
|
||||
renderer->getRenderer()->setUniformTexture(textShader, "fontTexture", 0);
|
||||
|
||||
glm::vec2 coord = ti.screenPosition;
|
||||
|
||||
Renderer::DrawParameters dp;
|
||||
dp.start = 0;
|
||||
dp.count = gb.getCount();
|
||||
dp.texture = engine->gameData.textures[{fonts[ti.font], ""}].texName;
|
||||
glm::vec2 ss( ti.size );
|
||||
|
||||
glm::vec3 colour = ti.baseColour;
|
||||
|
||||
/// @todo make this less wastefull
|
||||
for( const char& c : ti.text )
|
||||
{
|
||||
// Handle special chars.
|
||||
if( c == '\n' )
|
||||
{
|
||||
coord.x = ti.screenPosition.x;
|
||||
coord.y += ss.y;
|
||||
continue;
|
||||
}
|
||||
|
||||
int glyph = charToIndex(c);
|
||||
auto tex = indexToCoord(ti.font, glyph);
|
||||
|
||||
glm::vec2 p = coord;
|
||||
coord.x += ss.x;
|
||||
|
||||
std::vector<TextVertex> geo = {
|
||||
{ { p.x, p.y + ss.y }, {tex.x, tex.w}, colour },
|
||||
{ { p.x + ss.x, p.y + ss.y }, {tex.z, tex.w}, colour },
|
||||
{ { p.x, p.y }, {tex.x, tex.y}, colour },
|
||||
{ { p.x + ss.x, p.y }, {tex.z, tex.y}, colour },
|
||||
};
|
||||
|
||||
gb.uploadVertices(geo);
|
||||
db.addGeometry(&gb);
|
||||
db.setFaceType(GL_TRIANGLE_STRIP);
|
||||
|
||||
renderer->getRenderer()->drawArrays(glm::mat4(), &db, dp);
|
||||
}
|
||||
}
|
@ -2,17 +2,16 @@
|
||||
#define _GAME_MENUSYSTEM_HPP_
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <SFML/Window.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <functional>
|
||||
|
||||
class Menu
|
||||
{
|
||||
sf::Font font;
|
||||
int font;
|
||||
public:
|
||||
|
||||
Menu(const sf::Font& font)
|
||||
Menu(int font)
|
||||
: font(font), activeEntry(-1) {}
|
||||
|
||||
struct MenuEntry
|
||||
@ -20,19 +19,26 @@ public:
|
||||
std::string name;
|
||||
float _size;
|
||||
|
||||
MenuEntry(const std::string& n, float size = 38.f) : name(n), _size(size) {}
|
||||
MenuEntry(const std::string& n, float size = 30.f) : name(n), _size(size) {}
|
||||
|
||||
float getHeight() { return _size; }
|
||||
|
||||
virtual void draw(const sf::Font& font, sf::RenderWindow& window, glm::vec2& basis)
|
||||
virtual void draw(int font, bool active, GameRenderer* r, glm::vec2& basis)
|
||||
{
|
||||
sf::Text t;
|
||||
t.setFont(font);
|
||||
t.setPosition(basis.x + 6, basis.y + 2);
|
||||
t.setString(name);
|
||||
auto cSize = getHeight() - 10.f;
|
||||
t.setCharacterSize(cSize);
|
||||
window.draw(t);
|
||||
TextRenderer::TextInfo ti;
|
||||
ti.font = font;
|
||||
ti.screenPosition = basis;
|
||||
ti.text = name;
|
||||
ti.size = getHeight();
|
||||
if( ! active )
|
||||
{
|
||||
ti.baseColour = glm::vec3(1.f, 1.f, 1.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
ti.baseColour = glm::vec3(1.f, 1.f, 0.f);
|
||||
}
|
||||
r->text.renderText(ti);
|
||||
basis.y += getHeight();
|
||||
}
|
||||
|
||||
@ -49,7 +55,7 @@ public:
|
||||
void activate(float clickX, float clickY) { callback(); }
|
||||
};
|
||||
|
||||
static std::shared_ptr<MenuEntry> lambda(const std::string& n, std::function<void (void)> callback, float size = 38.f)
|
||||
static std::shared_ptr<MenuEntry> lambda(const std::string& n, std::function<void (void)> callback, float size = 30.f)
|
||||
{
|
||||
return std::shared_ptr<MenuEntry>(new Entry(n, callback, size));
|
||||
}
|
||||
@ -68,20 +74,19 @@ public:
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
void draw(sf::RenderWindow& window)
|
||||
void draw(GameRenderer* r)
|
||||
{
|
||||
glm::vec2 basis(offset);
|
||||
for(size_t i = 0;
|
||||
i < entries.size();
|
||||
++i)
|
||||
{
|
||||
if(activeEntry >= 0 && i == (unsigned) activeEntry) {
|
||||
sf::RectangleShape rs(sf::Vector2f(250.f, entries[i]->getHeight()));
|
||||
rs.setPosition(basis.x, basis.y);
|
||||
rs.setFillColor(sf::Color::Cyan);
|
||||
window.draw(rs);
|
||||
bool active = false;
|
||||
if(activeEntry >= 0 && i == (unsigned) activeEntry)
|
||||
{
|
||||
active = true;
|
||||
}
|
||||
entries[i]->draw(font, window, basis);
|
||||
entries[i]->draw(font, active, r, basis);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <engine/GameObject.hpp>
|
||||
#include <engine/GameState.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <render/DebugDraw.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
@ -19,10 +20,6 @@ RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
||||
: engine(nullptr), inFocus(true),
|
||||
accum(0.f), timescale(1.f)
|
||||
{
|
||||
if(! font.loadFromFile(gamepath + "/DejaVuSansMono.ttf")) {
|
||||
std::cerr << "Failed to load font" << std::endl;
|
||||
}
|
||||
|
||||
size_t w = GAME_WINDOW_WIDTH, h = GAME_WINDOW_HEIGHT;
|
||||
bool fullscreen = false;
|
||||
|
||||
@ -64,6 +61,11 @@ RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
||||
engine->gameData.loadIMG("/models/gta3");
|
||||
engine->gameData.loadIMG("/models/txd");
|
||||
engine->gameData.loadIMG("/anim/cuts");
|
||||
|
||||
// Set up text renderer
|
||||
engine->renderer.text.setFontTexture(0, "pager");
|
||||
engine->renderer.text.setFontTexture(1, "font1");
|
||||
engine->renderer.text.setFontTexture(2, "font2");
|
||||
|
||||
/// @TODO expand this here.
|
||||
engine->load();
|
||||
@ -139,7 +141,7 @@ int RWGame::run()
|
||||
|
||||
render(alpha);
|
||||
|
||||
StateManager::get().draw(window);
|
||||
StateManager::get().draw(&engine->renderer);
|
||||
|
||||
window.display();
|
||||
|
||||
@ -202,6 +204,9 @@ void RWGame::tick(float dt)
|
||||
|
||||
void RWGame::render(float alpha)
|
||||
{
|
||||
auto size = getWindow().getSize();
|
||||
engine->renderer.getRenderer()->setViewport({size.x, size.y});
|
||||
|
||||
ViewCamera viewCam;
|
||||
if( engine->state.currentCutscene != nullptr && engine->state.cutsceneStartTime >= 0.f )
|
||||
{
|
||||
@ -285,8 +290,6 @@ void RWGame::render(float alpha)
|
||||
debug->flush(&engine->renderer);
|
||||
#endif
|
||||
|
||||
window.resetGLStates();
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::setfill('0') << "Time: " << std::setw(2) << engine->getHour()
|
||||
<< ":" << std::setw(2) << engine->getMinute() << " (" << engine->gameTime << "s)\n";
|
||||
@ -302,39 +305,40 @@ void RWGame::render(float alpha)
|
||||
}
|
||||
ss << std::endl;
|
||||
}
|
||||
|
||||
sf::Text text(ss.str(), font, 14);
|
||||
text.setPosition(10, 10);
|
||||
window.draw(text);
|
||||
|
||||
TextRenderer::TextInfo ti;
|
||||
ti.text = ss.str();
|
||||
ti.font = 2;
|
||||
ti.screenPosition = glm::vec2( 10.f, 10.f );
|
||||
ti.size = 20.f;
|
||||
engine->renderer.text.renderText(ti);
|
||||
|
||||
while( engine->log.size() > 0 && engine->log.front().time + 10.f < engine->gameTime ) {
|
||||
engine->log.pop_front();
|
||||
}
|
||||
|
||||
sf::Vector2f tpos(10.f, window.getSize().y - 30.f);
|
||||
text.setCharacterSize(14);
|
||||
ti.screenPosition = glm::vec2( 10.f, 500.f );
|
||||
ti.size = 15.f;
|
||||
for(auto it = engine->log.begin(); it != engine->log.end(); ++it) {
|
||||
text.setString(it->message);
|
||||
ti.text = it->message;
|
||||
switch(it->type) {
|
||||
case GameWorld::LogEntry::Error:
|
||||
text.setColor(sf::Color::Red);
|
||||
ti.baseColour = glm::vec3(1.f, 0.f, 0.f);
|
||||
break;
|
||||
case GameWorld::LogEntry::Warning:
|
||||
text.setColor(sf::Color::Yellow);
|
||||
ti.baseColour = glm::vec3(1.f, 1.f, 0.f);
|
||||
break;
|
||||
default:
|
||||
text.setColor(sf::Color::White);
|
||||
ti.baseColour = glm::vec3(1.f, 1.f, 1.f);
|
||||
break;
|
||||
}
|
||||
|
||||
// Interpolate the color
|
||||
auto c = text.getColor();
|
||||
c.a = (engine->gameTime - it->time > 5.f) ? 255 - (((engine->gameTime - it->time) - 5.f)/5.f) * 255 : 255;
|
||||
text.setColor(c);
|
||||
// c.a = (engine->gameTime - it->time > 5.f) ? 255 - (((engine->gameTime - it->time) - 5.f)/5.f) * 255 : 255;
|
||||
// text.setColor(c);
|
||||
|
||||
text.setPosition(tpos);
|
||||
window.draw(text);
|
||||
tpos.y -= text.getLocalBounds().height;
|
||||
engine->renderer.text.renderText(ti);
|
||||
ti.screenPosition.y -= ti.size;
|
||||
}
|
||||
|
||||
for( int i = 0; i < engine->state.text.size(); )
|
||||
@ -351,77 +355,79 @@ void RWGame::render(float alpha)
|
||||
|
||||
for(OnscreenText& t : engine->state.text)
|
||||
{
|
||||
float fontSize = 15.f;
|
||||
float fontSize = 20.f;
|
||||
switch(t.osTextStyle)
|
||||
{
|
||||
default:
|
||||
fontSize = 15.f;
|
||||
fontSize = 20.f;
|
||||
break;
|
||||
case 1:
|
||||
fontSize = 25.f;
|
||||
fontSize = 40.f;
|
||||
break;
|
||||
case 2:
|
||||
fontSize = 20.f;
|
||||
break;
|
||||
}
|
||||
|
||||
sf::Text messageText(t.osTextString, font, fontSize);
|
||||
auto sz = window.getSize();
|
||||
|
||||
auto b = messageText.getLocalBounds();
|
||||
|
||||
ti.size = fontSize;
|
||||
ti.screenPosition = glm::vec2(0.f);
|
||||
ti.font = 0;
|
||||
if(t.osTextStyle == 1)
|
||||
{
|
||||
messageText.setPosition(sz.x / 2.f - std::round(b.width / 2.f), sz.y / 2.f - std::round(b.height / 2.f));
|
||||
ti.screenPosition = glm::vec2(500.f, 500.f);
|
||||
}
|
||||
else if(t.osTextStyle == 2)
|
||||
{
|
||||
messageText.setPosition(sz.x * 0.9f - std::round(b.width), sz.y * 0.8f - std::round(b.height / 2.f));
|
||||
ti.screenPosition = glm::vec2(500.f, 500.f);
|
||||
}
|
||||
else if(t.osTextStyle == 12)
|
||||
{
|
||||
messageText.setPosition(15.f, 15.f);
|
||||
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);
|
||||
// // 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 = sz.y - sz.y * 0.1f;
|
||||
messageText.setPosition(sz.x / 2.f - std::round(b.width / 2.f), lowerBar - std::round(b.height / 2.f));
|
||||
float lowerBar = 550.f;
|
||||
ti.screenPosition = glm::vec2(300.f, lowerBar);
|
||||
}
|
||||
window.draw(messageText);
|
||||
|
||||
ti.text = t.osTextString;
|
||||
engine->renderer.text.renderText(ti);
|
||||
}
|
||||
|
||||
for(auto& t : engine->state.texts) {
|
||||
/*for(auto& t : engine->state.texts) {
|
||||
sf::Text messageText(t.text, font, 15);
|
||||
|
||||
glm::vec2 scpos(t.position.x, t.position.y);
|
||||
@ -432,7 +438,7 @@ void RWGame::render(float alpha)
|
||||
messageText.setPosition(scpos.x, scpos.y);
|
||||
|
||||
window.draw(messageText);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void RWGame::globalKeyEvent(const sf::Event& event)
|
||||
|
@ -15,8 +15,6 @@ class RWGame
|
||||
|
||||
float accum;
|
||||
float timescale;
|
||||
|
||||
sf::Font font;
|
||||
public:
|
||||
|
||||
RWGame(const std::string& gamepath, int argc, char* argv[]);
|
||||
@ -34,11 +32,6 @@ public:
|
||||
return window;
|
||||
}
|
||||
|
||||
sf::Font& getFont()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
bool hitWorldRay(glm::vec3 &hit, glm::vec3 &normal, GameObject** object = nullptr)
|
||||
{
|
||||
auto vc = nextCam;
|
||||
|
@ -2,7 +2,8 @@
|
||||
#define _GAME_STATE_HPP_
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <SFML/System.hpp>
|
||||
#include <render/ViewCamera.hpp>
|
||||
#include "MenuSystem.hpp"
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
@ -26,10 +27,10 @@ struct State
|
||||
|
||||
virtual void tick(float dt) = 0;
|
||||
|
||||
virtual void draw(sf::RenderWindow& w)
|
||||
virtual void draw(GameRenderer* r)
|
||||
{
|
||||
if(getCurrentMenu()) {
|
||||
getCurrentMenu()->draw(w);
|
||||
getCurrentMenu()->draw(r);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,9 +118,9 @@ struct StateManager
|
||||
states.back()->tick(dt);
|
||||
}
|
||||
|
||||
void draw(sf::RenderWindow& w)
|
||||
void draw(GameRenderer* r)
|
||||
{
|
||||
states.back()->draw(w);
|
||||
states.back()->draw(r);
|
||||
}
|
||||
|
||||
void exit()
|
||||
|
@ -24,8 +24,8 @@ void jumpCharacter(RWGame* game, CharacterController* controller, const glm::vec
|
||||
DebugState::DebugState(RWGame* game, const glm::vec3& vp, const glm::quat& vd)
|
||||
: State(game), _freeLook( false ), _sonicMode( false )
|
||||
{
|
||||
Menu *m = new Menu(game->getFont());
|
||||
m->offset = glm::vec2(50.f, 100.f);
|
||||
Menu *m = new Menu(2);
|
||||
m->offset = glm::vec2(200.f, 200.f);
|
||||
float entryHeight = 24.f;
|
||||
#if 0
|
||||
m->addEntry(Menu::lambda("Random Vehicle", [this] {
|
||||
|
@ -187,14 +187,14 @@ void IngameState::tick(float dt)
|
||||
}
|
||||
}
|
||||
|
||||
void IngameState::draw(sf::RenderWindow& w)
|
||||
void IngameState::draw(GameRenderer* r)
|
||||
{
|
||||
if( !getWorld()->state.isCinematic && getWorld()->isCutsceneDone() )
|
||||
{
|
||||
drawHUD(w);
|
||||
drawHUD(getWindow());
|
||||
}
|
||||
|
||||
State::draw(w);
|
||||
State::draw(r);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
virtual void exit();
|
||||
|
||||
virtual void tick(float dt);
|
||||
virtual void draw(sf::RenderWindow& w);
|
||||
virtual void draw(GameRenderer* r);
|
||||
|
||||
virtual void handleEvent(const sf::Event& event);
|
||||
|
||||
|
@ -47,10 +47,13 @@ void LoadingState::handleEvent(const sf::Event &e)
|
||||
State::handleEvent(e);
|
||||
}
|
||||
|
||||
void LoadingState::draw(sf::RenderWindow &w)
|
||||
void LoadingState::draw(GameRenderer* r)
|
||||
{
|
||||
// Display some manner of loading screen.
|
||||
sf::Text loadingText("Loading...", game->getFont(), 28);
|
||||
loadingText.setPosition({30.f, 20.f});
|
||||
w.draw(loadingText);
|
||||
TextRenderer::TextInfo ti;
|
||||
ti.text = "Loading...";
|
||||
ti.screenPosition = glm::vec2( -1.f, 0.5f );
|
||||
ti.size = 0.1f;
|
||||
ti.font = 2;
|
||||
r->text.renderText(ti);
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public:
|
||||
|
||||
virtual void tick(float dt);
|
||||
|
||||
virtual void draw(sf::RenderWindow &w);
|
||||
virtual void draw(GameRenderer* r);
|
||||
|
||||
virtual void handleEvent(const sf::Event& event);
|
||||
};
|
||||
|
@ -7,8 +7,8 @@
|
||||
MenuState::MenuState(RWGame* game)
|
||||
: State(game)
|
||||
{
|
||||
Menu *m = new Menu(game->getFont());
|
||||
m->offset = glm::vec2(50.f, 100.f);
|
||||
Menu *m = new Menu(2);
|
||||
m->offset = glm::vec2(200.f, 200.f);
|
||||
m->addEntry(Menu::lambda("Start", [=] { StateManager::get().enter(new IngameState(game)); }));
|
||||
m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true)); }));
|
||||
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
||||
|
@ -6,8 +6,8 @@
|
||||
PauseState::PauseState(RWGame* game)
|
||||
: State(game)
|
||||
{
|
||||
Menu *m = new Menu(game->getFont());
|
||||
m->offset = glm::vec2(50.f, 100.f);
|
||||
Menu *m = new Menu(2);
|
||||
m->offset = glm::vec2( 200.f, 200.f );
|
||||
m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); }));
|
||||
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
||||
m->addEntry(Menu::lambda("Exit", [&] { getWindow().close(); }));
|
||||
@ -29,10 +29,12 @@ void PauseState::tick(float dt)
|
||||
|
||||
}
|
||||
|
||||
void PauseState::draw(sf::RenderWindow& w)
|
||||
void PauseState::draw(GameRenderer* r)
|
||||
{
|
||||
MapRenderer::MapInfo map;
|
||||
|
||||
auto& w = getWindow();
|
||||
|
||||
map.scale = 0.25f;
|
||||
map.viewport = glm::vec2(w.getSize().x, w.getSize().y);
|
||||
map.mapSize = map.viewport;
|
||||
@ -44,7 +46,7 @@ void PauseState::draw(sf::RenderWindow& w)
|
||||
}
|
||||
getWorld()->renderer.map.draw(map);
|
||||
|
||||
State::draw(w);
|
||||
State::draw(r);
|
||||
}
|
||||
|
||||
void PauseState::handleEvent(const sf::Event &e)
|
||||
|
@ -13,7 +13,7 @@ public:
|
||||
|
||||
virtual void tick(float dt);
|
||||
|
||||
virtual void draw(sf::RenderWindow& w);
|
||||
virtual void draw(GameRenderer* r);
|
||||
|
||||
virtual void handleEvent(const sf::Event& event);
|
||||
};
|
||||
|
@ -7,8 +7,7 @@ BOOST_AUTO_TEST_SUITE(MenuUnitTests)
|
||||
BOOST_AUTO_TEST_CASE(menu_test_click)
|
||||
{
|
||||
bool clickered = false;
|
||||
sf::Font f;
|
||||
Menu test(f);
|
||||
Menu test(0);
|
||||
test.addEntry(Menu::lambda("Test", [&]{ clickered = true; }));
|
||||
|
||||
BOOST_CHECK(! clickered );
|
||||
@ -32,8 +31,7 @@ BOOST_AUTO_TEST_CASE(menu_test_click)
|
||||
BOOST_AUTO_TEST_CASE(menu_test_click_offset)
|
||||
{
|
||||
bool clickered = false;
|
||||
sf::Font f;
|
||||
Menu test(f);
|
||||
Menu test(0);
|
||||
test.offset = glm::vec2(200.f, 200.f);
|
||||
test.addEntry(Menu::lambda("Test", [&]{ clickered = true; }));
|
||||
|
||||
@ -58,8 +56,7 @@ BOOST_AUTO_TEST_CASE(menu_test_click_offset)
|
||||
BOOST_AUTO_TEST_CASE(menu_test_active_index)
|
||||
{
|
||||
int clickindex = -1;
|
||||
sf::Font f;
|
||||
Menu test(f);
|
||||
Menu test(0);
|
||||
test.addEntry(Menu::lambda("Test1", [&]{ clickindex = 0; }));
|
||||
test.addEntry(Menu::lambda("Test2", [&]{ clickindex = 1; }));
|
||||
|
||||
@ -86,8 +83,7 @@ BOOST_AUTO_TEST_CASE(menu_test_active_index)
|
||||
BOOST_AUTO_TEST_CASE(menu_test_hover_index)
|
||||
{
|
||||
int clickindex = -1;
|
||||
sf::Font f;
|
||||
Menu test(f);
|
||||
Menu test(0);
|
||||
test.addEntry(Menu::lambda("Test1", [&]{ clickindex = 0; }));
|
||||
test.addEntry(Menu::lambda("Test2", [&]{ clickindex = 1; }));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user