Basic font rendering

- added basic font rendering
- minor refactoring & fixes
dev-ui
Piotr Dziwinski 2012-08-03 23:23:13 +02:00
parent 5e637ca028
commit 61bfb22f27
16 changed files with 906 additions and 199 deletions

View File

@ -8,6 +8,7 @@ project(colobot C CXX)
find_package(OpenGL 1.4 REQUIRED)
find_package(SDL 1.2.10 REQUIRED)
find_package(SDL_image 1.2 REQUIRED)
find_package(SDL_ttf 2.0 REQUIRED)
find_package(PNG 1.2 REQUIRED)
# GLEW requirement depends on platform

View File

@ -176,6 +176,7 @@ graphics/opengl/gldevice.cpp
set(LIBS
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${SDLTTF_LIBRARY}
${OPENGL_LIBRARY}
${PNG_LIBRARIES}
${OPTIONAL_LIBS}

View File

@ -122,6 +122,7 @@ bool CApplication::ParseArguments(int argc, char *argv[])
{
waitDataDir = false;
m_dataPath = arg;
continue;
}
if (arg == "-debug")
@ -153,10 +154,6 @@ bool CApplication::Create()
// Temporarily -- only in windowed mode
m_deviceConfig.fullScreen = false;
// Create the 3D engine
m_engine = new Gfx::CEngine(m_iMan, this);
/* // Create the sound instance.
m_sound = new CSound(m_iMan);
@ -224,20 +221,15 @@ bool CApplication::Create()
return false;
}
// Create the 3D engine
m_engine = new Gfx::CEngine(m_iMan, this);
m_engine->SetDevice(m_device);
if (! m_engine->Create() )
{
SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string("Error in CEngine::Create() :\n") +
std::string(m_engine->GetError()) );
m_exitCode = 1;
return false;
}
if (! m_engine->AfterDeviceSetInit() )
{
SystemDialog( SDT_ERROR, "COLOBT - Fatal Error",
std::string("Error in CEngine::AfterDeviceSetInit() :\n") +
std::string("Error in CEngine::Init() :\n") +
std::string(m_engine->GetError()) );
m_exitCode = 1;
return false;
@ -315,8 +307,7 @@ void CApplication::Destroy()
if (m_engine != NULL)
{
if (m_engine->GetWasInit())
m_engine->Destroy();
m_engine->Destroy();
delete m_engine;
m_engine = NULL;
@ -324,8 +315,7 @@ void CApplication::Destroy()
if (m_device != NULL)
{
if (m_device->GetWasInit())
m_device->Destroy();
m_device->Destroy();
delete m_device;
m_device = NULL;
@ -616,21 +606,6 @@ PressState TranslatePressState(unsigned char state)
return STATE_RELEASED;
}
/** Conversion of the position of the mouse from window coords to interface coords:
- x: 0=left, 1=right
- y: 0=down, 1=up */
Math::Point CApplication::WindowToInterfaceCoords(Math::IntPoint pos)
{
return Math::Point( static_cast<float>(pos.x) / static_cast<float>(m_deviceConfig.size.w),
1.0f - static_cast<float>(pos.y) / static_cast<float>(m_deviceConfig.size.h) );
}
Math::IntPoint CApplication::InterfaceToWindowCoords(Math::Point pos)
{
return Math::IntPoint(static_cast<int>(pos.x * m_deviceConfig.size.w),
static_cast<int>((1.0f - pos.y) * m_deviceConfig.size.h));
}
/** The SDL event parsed is stored internally.
If event is not available or is not understood, returned event is of type EVENT_NULL. */
Event CApplication::ParseEvent()
@ -666,14 +641,16 @@ Event CApplication::ParseEvent()
event.mouseButton.button = m_private->currentEvent.button.button;
event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state);
event.mouseButton.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
event.mouseButton.pos = m_engine->WindowToInterfaceCoords(
Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
{
event.type = EVENT_MOUSE_MOVE;
event.mouseMove.state = TranslatePressState(m_private->currentEvent.button.state);
event.mouseMove.pos = WindowToInterfaceCoords(Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
event.mouseMove.pos = m_engine->WindowToInterfaceCoords(
Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
}
else if (m_private->currentEvent.type == SDL_JOYAXISMOTION)
{
@ -792,6 +769,11 @@ void CApplication::StepSimulation(float rTime)
// TODO
}
Gfx::GLDeviceConfig CApplication::GetVideoConfig()
{
return m_deviceConfig;
}
VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntSize> &resolutions,
bool fullScreen, bool resizeable)
{
@ -891,7 +873,7 @@ bool CApplication::GetSystemMouseVisibile()
void CApplication::SetSystemMousePos(Math::Point pos)
{
Math::IntPoint windowPos = InterfaceToWindowCoords(pos);
Math::IntPoint windowPos = m_engine->InterfaceToWindowCoords(pos);
SDL_WarpMouse(windowPos.x, windowPos.y);
m_systemMousePos = pos;
}

View File

@ -25,7 +25,6 @@
#include "graphics/core/device.h"
#include "graphics/engine/engine.h"
#include "graphics/opengl/gldevice.h"
#include "math/intsize.h"
#include <string>
#include <vector>
@ -206,11 +205,6 @@ protected:
//! Closes the joystick device
void CloseJoystick();
//! Converts window coords to interface coords
Math::Point WindowToInterfaceCoords(Math::IntPoint pos);
//! Converts the interface coords to window coords
Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
protected:
//! Instance manager
CInstanceManager* m_iMan;

View File

@ -32,6 +32,7 @@
class CImage;
struct ImageData;
namespace Gfx {
@ -279,8 +280,6 @@ public:
//! Destroys the device, releasing every acquired resource
virtual void Destroy() = 0;
//! Returns whether the device has been initialized
virtual bool GetWasInit() = 0;
//! Returns the last encountered error
virtual std::string GetError() = 0;
@ -317,6 +316,8 @@ public:
//! Creates a texture from image; the image can be safely removed after that
virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params) = 0;
//! Creates a texture from raw image data; image data can be freed after that
virtual Gfx::Texture CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params) = 0;
//! Deletes a given texture, freeing it from video memory
virtual void DestroyTexture(const Gfx::Texture &texture) = 0;
//! Deletes all textures created so far
@ -324,8 +325,10 @@ public:
//! Returns the maximum number of multitexture stages
virtual int GetMaxTextureCount() = 0;
//! Sets the (multi)texture at given index
//! Sets the texture at given texture stage
virtual void SetTexture(int index, const Gfx::Texture &texture) = 0;
//! Sets the texture image by ID at given texture stage
virtual void SetTexture(int index, unsigned int textureId) = 0;
//! Returns the (multi)texture at given index
virtual Gfx::Texture GetTexture(int index) = 0;
//! Enables/disables the given texture stage

View File

@ -25,6 +25,8 @@
#include "common/key.h"
#include "common/logger.h"
#include "graphics/core/device.h"
#include "graphics/engine/lightman.h"
#include "graphics/engine/text.h"
#include "math/geometry.h"
// Initial size of various vectors
@ -44,23 +46,21 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
{
m_iMan = iMan;
m_app = app;
m_device = NULL;
m_wasInit = false;
m_device = nullptr;
m_iMan = iMan;
m_iMan->AddInstance(CLASS_ENGINE, this);
m_app = app;
m_lightMan = NULL;
m_text = NULL;
m_particle = NULL;
m_water = NULL;
m_cloud = NULL;
m_lightning = NULL;
m_planet = NULL;
m_sound = NULL;
m_terrain = NULL;
m_lightMan = nullptr;
m_text = nullptr;
m_particle = nullptr;
m_water = nullptr;
m_cloud = nullptr;
m_lightning = nullptr;
m_planet = nullptr;
m_sound = nullptr;
m_terrain = nullptr;
m_focus = 0.75f;
m_baseTime = 0;
@ -178,17 +178,12 @@ Gfx::CEngine::CEngine(CInstanceManager *iMan, CApplication *app)
Gfx::CEngine::~CEngine()
{
m_iMan = NULL;
m_app = NULL;
m_device = NULL;
m_iMan = nullptr;
m_app = nullptr;
m_device = nullptr;
m_sound = NULL;
m_terrain = NULL;
}
bool Gfx::CEngine::GetWasInit()
{
return m_wasInit;
m_sound = nullptr;
m_terrain = nullptr;
}
std::string Gfx::CEngine::GetError()
@ -196,53 +191,6 @@ std::string Gfx::CEngine::GetError()
return m_error;
}
bool Gfx::CEngine::Create()
{
m_wasInit = true;
/*m_lightMan = new Gfx::CLight(m_iMan, this);
m_text = new Gfx::CText(m_iMan, this);
m_particle = new Gfx::CParticle(m_iMan, this);
m_water = new Gfx::CWater(m_iMan, this);
m_cloud = new Gfx::CCloud(m_iMan, this);
m_lightning = new Gfx::CLightning(m_iMan, this);
m_planet = new Gfx::CPlanet(m_iMan, this);*/
m_matWorldInterface.LoadIdentity();
m_matViewInterface.LoadIdentity();
Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
return true;
}
void Gfx::CEngine::Destroy()
{
// TODO
/*delete m_lightMan;
m_lightMan = NULL;
delete m_text;
m_text = NULL;
delete m_particle;
m_particle = NULL;
delete m_water;
m_water = NULL;
delete m_cloud;
m_cloud = NULL;
delete m_lightning;
m_lightning = NULL;
delete m_planet;
m_planet = NULL;*/
m_wasInit = false;
}
void Gfx::CEngine::SetDevice(Gfx::CDevice *device)
{
m_device = device;
@ -253,8 +201,31 @@ Gfx::CDevice* Gfx::CEngine::GetDevice()
return m_device;
}
bool Gfx::CEngine::AfterDeviceSetInit()
bool Gfx::CEngine::Create()
{
m_size = m_lastSize = m_app->GetVideoConfig().size;
m_lightMan = new Gfx::CLightManager(m_iMan, this);
m_text = new Gfx::CText(m_iMan, this);
/* TODO:
m_particle = new Gfx::CParticle(m_iMan, this);
m_water = new Gfx::CWater(m_iMan, this);
m_cloud = new Gfx::CCloud(m_iMan, this);
m_lightning = new Gfx::CLightning(m_iMan, this);
m_planet = new Gfx::CPlanet(m_iMan, this);*/
m_text->SetDevice(m_device);
if (! m_text->Create())
{
m_error = std::string("Error creating CText: ") + m_text->GetError();
return false;
}
m_matWorldInterface.LoadIdentity();
m_matViewInterface.LoadIdentity();
Math::LoadOrthoProjectionMatrix(m_matProjInterface, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
m_device->SetClearColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
m_device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false);
@ -269,12 +240,38 @@ bool Gfx::CEngine::AfterDeviceSetInit()
return true;
}
void Gfx::CEngine::Destroy()
{
m_text->Destroy();
delete m_lightMan;
m_lightMan = nullptr;
delete m_text;
m_text = nullptr;
/* TODO:
delete m_particle;
m_particle = nullptr;
delete m_water;
m_water = nullptr;
delete m_cloud;
m_cloud = nullptr;
delete m_lightning;
m_lightning = nullptr;
delete m_planet;
m_planet = nullptr;*/
}
void Gfx::CEngine::ResetAfterDeviceChanged()
{
// TODO
}
Gfx::Texture Gfx::CEngine::CreateTexture(const std::string &texName, const Gfx::TextureCreateParams &params)
{
CImage img;
@ -610,9 +607,38 @@ bool Gfx::CEngine::DrawInterface()
DrawMouse();
m_text->DrawString("abcdefghijklmnopqrstuvwxyz ąęśćółńż", Gfx::FONT_COLOBOT, 15.0f, Math::Point(0.25f, 0.2f), 1.0f, 0);
return true;
}
/** Conversion of the position of the mouse from window coords to interface coords:
- x: 0=left, 1=right
- y: 0=down, 1=up */
Math::Point Gfx::CEngine::WindowToInterfaceCoords(Math::IntPoint pos)
{
return Math::Point( static_cast<float>(pos.x) / static_cast<float>(m_size.w),
1.0f - static_cast<float>(pos.y) / static_cast<float>(m_size.h) );
}
Math::IntPoint Gfx::CEngine::InterfaceToWindowCoords(Math::Point pos)
{
return Math::IntPoint(static_cast<int>(pos.x * m_size.w),
static_cast<int>((1.0f - pos.y) * m_size.h));
}
Math::Size Gfx::CEngine::WindowToInterfaceSize(Math::IntSize size)
{
return Math::Size( static_cast<float>(size.w) / static_cast<float>(m_size.w),
static_cast<float>(size.h) / static_cast<float>(m_size.h) );
}
Math::IntSize Gfx::CEngine::InterfaceToWindowSize(Math::Size size)
{
return Math::IntSize(static_cast<int>(size.w * m_size.w),
static_cast<int>(size.h * m_size.h));
}
void Gfx::CEngine::DrawMouse()
{
if (! m_mouseVisible)

View File

@ -29,6 +29,7 @@
#include "math/intsize.h"
#include "math/matrix.h"
#include "math/point.h"
#include "math/size.h"
#include "math/vector.h"
@ -514,23 +515,18 @@ public:
CEngine(CInstanceManager *iMan, CApplication *app);
~CEngine();
//! Returns whether the device was initialized
bool GetWasInit();
//! Returns the last error encountered
std::string GetError();
//! Performs the first initialization, before a device was set
bool Create();
//! Frees all resources before exit
void Destroy();
//! Sets the device to be used
void SetDevice(Gfx::CDevice *device);
//! Returns the current device
Gfx::CDevice* GetDevice();
//! Performs initialization after a device was created and set
bool AfterDeviceSetInit();
//! Performs the initialization; must be called after device was set
bool Create();
//! Frees all resources before exit
void Destroy();
//! Resets some states and flushes textures after device was changed (e.g. resoulution changed)
void ResetAfterDeviceChanged();
@ -544,6 +540,17 @@ public:
bool Render();
//! Converts window coords to interface coords
Math::Point WindowToInterfaceCoords(Math::IntPoint pos);
//! Converts interface coords to window coords
Math::IntPoint InterfaceToWindowCoords(Math::Point pos);
//! Converts window size to interface size
Math::Size WindowToInterfaceSize(Math::IntSize size);
//! Converts interface size to window size
Math::IntSize InterfaceToWindowSize(Math::Size size);
bool WriteProfile();
void SetPause(bool pause);
@ -769,7 +776,8 @@ public:
Math::Vector GetLookatPt();
float GetEyeDirH();
float GetEyeDirV();
Math::Point GetDim();
Math::IntPoint GetViewportSize();
Math::IntPoint GetLastViewportSize();
void UpdateMatProj();
void ApplyChange();
@ -903,8 +911,9 @@ protected:
bool m_render;
bool m_movieLock;
//! Current size of window
//! Current size of viewport
Math::IntSize m_size;
//! Previous size of viewport
Math::IntSize m_lastSize;
std::vector<Gfx::EngineObjLevel1> m_objectTree;

View File

@ -19,5 +19,480 @@
#include "graphics/engine/text.h"
#include "app/app.h"
#include "common/image.h"
#include "common/iman.h"
#include "common/logger.h"
#include "common/stringutils.h"
#include "math/func.h"
// TODO implementation
#include <SDL/SDL.h>
#include <SDL/SDL_ttf.h>
namespace Gfx
{
/**
\struct CachedFont
\brief Base TTF font with UTF-8 char cache */
struct CachedFont
{
TTF_Font* font;
std::map<Gfx::UTF8Char, Gfx::CharTexture> cache;
CachedFont() : font(nullptr) {}
};
};
Gfx::CText::CText(CInstanceManager *iMan, Gfx::CEngine* engine)
{
m_iMan = iMan;
m_iMan->AddInstance(CLASS_TEXT, this);
m_device = nullptr;
m_engine = engine;
m_defaultSize = 12.0f;
m_fontPath = "fonts";
m_lastFontType = Gfx::FONT_COLOBOT;
m_lastFontSize = 0;
m_lastCachedFont = nullptr;
}
Gfx::CText::~CText()
{
m_iMan->DeleteInstance(CLASS_TEXT, this);
m_iMan = nullptr;
m_device = nullptr;
m_engine = nullptr;
}
bool Gfx::CText::Create()
{
if (TTF_Init() != 0)
{
m_error = std::string("TTF_Init error: ") + std::string(TTF_GetError());
return false;
}
m_fonts[Gfx::FONT_COLOBOT] = new MultisizeFont("dvu_sans.ttf");
m_fonts[Gfx::FONT_COLOBOT_BOLD] = new MultisizeFont("dvu_sans_bold.ttf");
m_fonts[Gfx::FONT_COLOBOT_ITALIC] = new MultisizeFont("dvu_sans_italic.ttf");
m_fonts[Gfx::FONT_COURIER] = new MultisizeFont("dvu_sans_mono.ttf");
m_fonts[Gfx::FONT_COURIER_BOLD] = new MultisizeFont("dvu_sans_mono_bold.ttf");
for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
{
Gfx::FontType type = (*it).first;
CachedFont* cf = GetOrOpenFont(type, m_defaultSize);
if (cf == nullptr || cf->font == nullptr)
return false;
}
return true;
}
void Gfx::CText::Destroy()
{
for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
{
MultisizeFont* mf = (*it).second;
for (auto jt = mf->fonts.begin(); jt != mf->fonts.end(); ++jt)
{
CachedFont* cf = (*jt).second;
TTF_CloseFont(cf->font);
cf->font = nullptr;
delete cf;
}
mf->fonts.clear();
delete mf;
}
m_fonts.clear();
m_lastCachedFont = nullptr;
TTF_Quit();
}
void Gfx::CText::SetDevice(Gfx::CDevice* device)
{
m_device = device;
}
std::string Gfx::CText::GetError()
{
return m_error;
}
void Gfx::CText::FlushCache()
{
for (auto it = m_fonts.begin(); it != m_fonts.end(); ++it)
{
MultisizeFont *mf = (*it).second;
for (auto jt = mf->fonts.begin(); jt != mf->fonts.end(); ++jt)
{
CachedFont *f = (*jt).second;
f->cache.clear();
}
}
}
void Gfx::CText::DrawText(const std::string &text, const std::vector<FontMetaChar> &format,
Math::Point pos, float width, Gfx::JustifyType justify, float size,
float stretch, int eol)
{
// TODO
}
void Gfx::CText::DrawText(const std::string &text, Gfx::FontType font,
Math::Point pos, float width, Gfx::JustifyType justify, float size,
float stretch, int eol)
{
// TODO
}
void Gfx::CText::SizeText(const std::string &text, const std::vector<FontMetaChar> &format,
Math::Point pos, Gfx::JustifyType justify, float size,
Math::Point &start, Math::Point &end)
{
// TODO
}
void Gfx::CText::SizeText(const std::string &text, Gfx::FontType font,
Math::Point pos, Gfx::JustifyType justify, float size,
Math::Point &start, Math::Point &end)
{
// TODO
}
float Gfx::CText::GetAscent(Gfx::FontType font, float size)
{
// TODO
return 0.0f;
}
float Gfx::CText::GetDescent(Gfx::FontType font, float size)
{
// TODO
return 0.0f;
}
float Gfx::CText::GetHeight(Gfx::FontType font, float size)
{
// TODO
return 0.0f;
}
float Gfx::CText::GetStringWidth(const std::string &text,
const std::vector<FontMetaChar> &format, float size)
{
// TODO
return 0.0f;
}
float Gfx::CText::GetStringWidth(const std::string &text, Gfx::FontType font, float size)
{
// TODO
return 0.0f;
}
float Gfx::CText::GetCharWidth(int character, Gfx::FontType font, float size, float offset)
{
// TODO
return 0.0f;
}
int Gfx::CText::Justify(const std::string &text, const std::vector<FontMetaChar> &format,
float size, float width)
{
// TODO
return 0;
}
int Gfx::CText::Justify(const std::string &text, Gfx::FontType font, float size, float width)
{
// TODO
return 0;
}
int Gfx::CText::Detect(const std::string &text, const std::vector<FontMetaChar> &format,
float size, float offset)
{
// TODO
return 0;
}
int Gfx::CText::Detect(const std::string &text, Gfx::FontType font, float size, float offset)
{
// TODO
return 0;
}
void Gfx::CText::DrawString(const std::string &text, const std::vector<FontMetaChar> &format,
float size, Math::Point pos, float width, int eol)
{
// TODO
}
void Gfx::CText::DrawString(const std::string &text, Gfx::FontType font,
float size, Math::Point pos, float width, int eol)
{
m_device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true);
m_device->SetTextureEnabled(0, true);
m_device->SetRenderState(Gfx::RENDER_STATE_BLENDING, true);
m_device->SetBlendFunc(Gfx::BLEND_SRC_ALPHA, Gfx::BLEND_INV_SRC_ALPHA);
unsigned int index = 0;
Math::Point screenPos = pos;
while (index < text.length())
{
UTF8Char ch;
int len = StrUtils::Utf8CharSizeAt(text, index);
if (len >= 1)
ch.c1 = text[index];
if (len >= 2)
ch.c2 = text[index+1];
if (len >= 3)
ch.c3 = text[index+2];
index += len;
DrawChar(ch, font, size, screenPos);
}
}
void Gfx::CText::DrawColor(int color, float size, Math::Point pos, float width)
{
// TODO !!!
/*
float h, u1, u2, v1, v2, dp;
int icon;
int icon = -1;
switch (color)
{
case Gfx::FONT_COLOR_LINK:
icon = 9;
break;
case Gfx::FONT_COLOR_TOKEN:
icon = 4;
break;
case Gfx::FONT_COLOR_TYPE:
icon = 5;
break;
}
icon = -1;
if ( color == COLOR_LINK ) icon = 9; // blue
if ( color == COLOR_TOKEN ) icon = 4; // orange
if ( color == COLOR_TYPE ) icon = 5; // green
if ( color == COLOR_CONST ) icon = 8; // red
if ( color == COLOR_REM ) icon = 6; // magenta
if ( color == COLOR_KEY ) icon = 10; // gray
if ( icon == -1 ) return;
if ( color == COLOR_LINK )
{
m_engine->SetState(D3DSTATENORMAL);
}
Math::IntSize vsize = m_engine->GetViewportSize();
if (vsize.h <= 768.0f) // 1024x768 or less?
h = 1.01f / dim.y; // 1 pixel
else // more than 1024x768?
h = 2.0f / dim.y; // 2 pixels
Math::Point p1, p2;
p1.x = pos.x;
p2.x = pos.x + width;
if (color == Gfx::FONT_COLOR_LINK)
{
p1.y = pos.y;
p2.y = pos.y + h; // just emphasized
}
else
{
p1.y = pos.y;
p2.y = pos.y + (16.0f/256.0f)*(size/20.0f);
}
u1 = (16.0f/256.0f)*(icon%16);
v1 = (240.0f/256.0f);
u2 = (16.0f/256.0f)+u1;
v2 = (16.0f/256.0f)+v1;
dp = 0.5f/256.0f;
u1 += dp;
v1 += dp;
u2 -= dp;
v2 -= dp;
Math::Vector n(0.0f, 0.0f, -1.0f); // normal
Gfx::Vertex quad[] =
{
Gfx::Vertex(Math::Vector(p1.x, p1.y, 0.0f), n, Math::Point(u1, v2)),
Gfx::Vertex(Math::Vector(p1.x, p2.y, 0.0f), n, Math::Point(u1, v1)),
Gfx::Vertex(Math::Vector(p2.x, p1.y, 0.0f), n, Math::Point(u2, v2)),
Gfx::Vertex(Math::Vector(p2.x, p2.y, 0.0f), n, Math::Point(u2, v1)),
};
m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
m_engine->AddStatisticTriangle(2);
if (color == Gfx::FONT_COLOR_LINK)
m_engine->SetState(Gfx::ENG_RSTATE_TTEXTURE_WHITE);*/
}
void Gfx::CText::DrawChar(UTF8Char character, Gfx::FontType font, float size, Math::Point &pos)
{
CachedFont* cf = GetOrOpenFont(font, size);
if (cf == nullptr)
return;
auto it = cf->cache.find(character);
CharTexture tex;
if (it != cf->cache.end())
{
tex = (*it).second;
}
else
{
char str[] = { character.c1, character.c2, character.c3, '\0' };
tex = CreateCharTexture(str, cf);
if (tex.id == 0) // invalid
return;
cf->cache[character] = tex;
}
Math::Vector n(0.0f, 0.0f, -1.0f); // normal
Gfx::Vertex quad[4] =
{
Gfx::Vertex(Math::Vector(pos.x, pos.y + tex.charSize.h, 0.0f),
n, Math::Point(0.0f, 0.0f)),
Gfx::Vertex(Math::Vector(pos.x, pos.y + tex.charSize.h - tex.texSize.h, 0.0f),
n, Math::Point(0.0f, 1.0f)),
Gfx::Vertex(Math::Vector(pos.x + tex.texSize.w, pos.y + tex.charSize.h, 0.0f),
n, Math::Point(1.0f, 0.0f)),
Gfx::Vertex(Math::Vector(pos.x + tex.texSize.w, pos.y + tex.charSize.h - tex.texSize.h, 0.0f),
n, Math::Point(1.0f, 1.0f))
};
m_device->SetTexture(0, tex.id);
m_device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4);
pos.x += tex.charSize.w;
}
Gfx::CachedFont* Gfx::CText::GetOrOpenFont(Gfx::FontType font, float size)
{
// TODO: sizing
int pointSize = static_cast<int>(size);
if (m_lastCachedFont != nullptr)
{
if (m_lastFontType == font && m_lastFontSize == pointSize)
return m_lastCachedFont;
}
auto it = m_fonts.find(font);
if (it == m_fonts.end())
{
m_error = std::string("Invalid font type ") + StrUtils::ToString<int>(static_cast<int>(font));
return nullptr;
}
MultisizeFont* mf = (*it).second;
auto jt = mf->fonts.find(pointSize);
if (jt != mf->fonts.end())
{
m_lastCachedFont = (*jt).second;
m_lastFontType = font;
m_lastFontSize = pointSize;
return m_lastCachedFont;
}
std::string path = CApplication::GetInstance().GetDataFilePath(m_fontPath, mf->fileName);
m_lastCachedFont = new CachedFont();
m_lastCachedFont->font = TTF_OpenFont(path.c_str(), pointSize);
if (m_lastCachedFont->font == nullptr)
m_error = std::string("TTF_OpenFont error ") + std::string(TTF_GetError());
mf->fonts[pointSize] = m_lastCachedFont;
return m_lastCachedFont;
}
Gfx::CharTexture Gfx::CText::CreateCharTexture(const char* str, Gfx::CachedFont* font)
{
CharTexture texture;
SDL_Surface* textSurface = nullptr;
SDL_Color white = {255, 255, 255, 0};
textSurface = TTF_RenderUTF8_Blended(font->font, str, white);
if (textSurface == nullptr)
{
m_error = "TTF_Render error";
return texture;
}
int w = Math::NextPowerOfTwo(textSurface->w);
int h = Math::NextPowerOfTwo(textSurface->h);
textSurface->flags = textSurface->flags & (~SDL_SRCALPHA);
SDL_Surface* textureSurface = SDL_CreateRGBSurface(0, w, h, 32, 0x00ff0000, 0x0000ff00,
0x000000ff, 0xff000000);
SDL_BlitSurface(textSurface, NULL, textureSurface, NULL);
ImageData data;
data.surface = textureSurface;
Gfx::TextureCreateParams createParams;
createParams.format = Gfx::TEX_IMG_RGBA;
createParams.minFilter = Gfx::TEX_MIN_FILTER_NEAREST;
createParams.magFilter = Gfx::TEX_MAG_FILTER_NEAREST;
createParams.mipmap = false;
Gfx::Texture tex = m_device->CreateTexture(&data, createParams);
data.surface = nullptr;
SDL_FreeSurface(textSurface);
SDL_FreeSurface(textureSurface);
if (! tex.valid)
{
m_error = "Texture create error";
return texture;
}
texture.id = tex.id;
texture.texSize = m_engine->WindowToInterfaceSize(Math::IntSize(textureSurface->w, textureSurface->h));
texture.charSize = m_engine->WindowToInterfaceSize(Math::IntSize(textSurface->w, textSurface->h));
return texture;
}

View File

@ -19,95 +19,268 @@
#pragma once
#include "graphics/engine/engine.h"
#include "graphics/core/device.h"
#include "math/point.h"
#include "math/size.h"
#include <vector>
#include <map>
class CInstanceManager;
namespace Gfx {
const float SMALLFONT = 10.0f;
const float BIGFONT = 15.0f;
class CEngine;
class CDevice;
const float NORMSTRETCH = 0.8f;
//! Standard small font size
const float FONT_SIZE_SMALL = 10.0f;
//! Standard big font size
const float FONT_SIZE_BIG = 15.0f;
/**
\enum TextAlignType
\brief Type of text alignment */
enum JustifyType
{
TEXT_ALIGN_RIGHT,
TEXT_ALIGN_LEFT,
TEXT_ALIGN_CENTER
};
/* Font meta char constants */
//! Type used for font character metainfo
typedef short FontMetaChar;
/**
\enum FontType
\brief Type of font
Bitmask in lower 4 bits (mask 0x00f) */
enum FontType
{
FONT_COLOBOT = 0,
FONT_COURIER = 1,
FONT_BUTTON = 2,
//! Flag for bold font subtype
FONT_BOLD = 0x04,
//! Flag for italic font subtype
FONT_ITALIC = 0x08,
//! Default colobot font used for interface
FONT_COLOBOT = 0x00,
//! Alias for bold colobot font
FONT_COLOBOT_BOLD = FONT_COLOBOT | FONT_BOLD,
//! Alias for italic colobot font
FONT_COLOBOT_ITALIC = FONT_COLOBOT | FONT_ITALIC,
//! Courier (monospace) font used mainly in code editor (only regular & bold)
FONT_COURIER = 0x01,
//! Alias for bold courier font
FONT_COURIER_BOLD = FONT_COURIER | FONT_BOLD,
// 0x02 left for possible another font
//! Pseudo-font loaded from textures for buttons, icons, etc.
FONT_BUTTON = 0x03,
};
/**
\enum FontTitle
\brief Size of font title
Bitmask in 2 bits left shifted 4 (mask 0x030) */
enum FontTitle
{
TITLE_BIG = 0x04,
TITLE_NORM = 0x08,
TITLE_LITTLE = 0x0c,
FONT_TITLE_BIG = 0x01 << 4,
FONT_TITLE_NORM = 0x02 << 4,
FONT_TITLE_LITTLE = 0x03 << 4,
};
/**
\enum FontColor
\brief Font color type (?)
Bitmask in 3 bits left shifted 6 (mask 0x1c0) */
enum FontColor
{
COLOR_LINK = 0x10,
COLOR_TOKEN = 0x20,
COLOR_TYPE = 0x30,
COLOR_CONST = 0x40,
COLOR_REM = 0x50,
COLOR_KEY = 0x60,
COLOR_TABLE = 0x70,
FONT_COLOR_LINK = 0x01 << 6,
FONT_COLOR_TOKEN = 0x02 << 6,
FONT_COLOR_TYPE = 0x03 << 6,
FONT_COLOR_CONST = 0x04 << 6,
FONT_COLOR_REM = 0x05 << 6,
FONT_COLOR_KEY = 0x06 << 6,
FONT_COLOR_TABLE = 0x07 << 6,
};
const short FONT_MASK = 0x03;
const short TITLE_MASK = 0x0c;
const short COLOR_MASK = 0x70;
const short IMAGE_MASK = 0x80;
/**
\enum FontMask
\brief Masks in FontMetaChar for different attributes */
enum FontMask
{
//! Mask for FontType
FONT_MASK_FONT = 0x00f,
//! Mask for FontTitle
FONT_MASK_TITLE = 0x030,
//! Mask for FontColor
FONT_MASK_COLOR = 0x1c0,
//! Mask for image bit
FONT_MASK_IMAGE = 0x200
};
/**
\struct UTF8Char
\brief UTF-8 character in font cache
class CText {
Only 3-byte chars are supported */
struct UTF8Char
{
char c1, c2, c3;
explicit UTF8Char(char ch1 = '\0', char ch2 = '\0', char ch3 = '\0')
: c1(ch1), c2(ch2), c3(ch3) {}
inline bool operator<(const UTF8Char &other) const
{
if (c1 < other.c1)
return true;
else if (c1 > other.c1)
return false;
if (c2 < other.c2)
return true;
else if (c2 > other.c2)
return false;
return c3 < other.c3;
}
inline bool operator==(const UTF8Char &other) const
{
return c1 == other.c1 && c2 == other.c2 && c3 == other.c3;
}
};
/**
\struct CharTexture
\brief Texture of font character */
struct CharTexture
{
unsigned int id;
Math::Size texSize;
Math::Size charSize;
CharTexture() : id(0) {}
};
// Definition is private - in text.cpp
struct CachedFont;
/**
\struct MultisizeFont
\brief Font with multiple possible sizes */
struct MultisizeFont
{
std::string fileName;
std::map<int, CachedFont*> fonts;
MultisizeFont(const std::string &fn)
: fileName(fn) {}
};
/**
\class CText
\brief Text rendering engine
... */
class CText
{
public:
CText(CInstanceManager *iMan, Gfx::CEngine* engine);
~CText();
//! Sets the device to be used
void SetDevice(Gfx::CDevice *device);
void DrawText(char *string, char *format, int len, Math::Point pos, float width, int justif, float size, float stretch, int eol);
void DrawText(char *string, char *format, Math::Point pos, float width, int justif, float size, float stretch, int eol);
void DrawText(char *string, int len, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol);
void DrawText(char *string, Math::Point pos, float width, int justif, float size, float stretch, FontType font, int eol);
void DimText(char *string, char *format, int len, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end);
void DimText(char *string, char *format, Math::Point pos, int justif, float size, float stretch, Math::Point &start, Math::Point &end);
void DimText(char *string, int len, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end);
void DimText(char *string, Math::Point pos, int justif, float size, float stretch, FontType font, Math::Point &start, Math::Point &end);
//! Returns the last encountered error
std::string GetError();
float RetAscent(float size, FontType font);
float RetDescent(float size, FontType font);
float RetHeight(float size, FontType font);
//! Initializes the font engine; must be called after SetDevice()
bool Create();
//! Frees resources before exit
void Destroy();
float RetStringWidth(char *string, char *format, int len, float size, float stretch);
float RetStringWidth(char *string, int len, float size, float stretch, FontType font);
float RetCharWidth(int character, float offset, float size, float stretch, FontType font);
//! Flushes cached textures
void FlushCache();
int Justif(char *string, char *format, int len, float width, float size, float stretch);
int Justif(char *string, int len, float width, float size, float stretch, FontType font);
int Detect(char *string, char *format, int len, float offset, float size, float stretch);
int Detect(char *string, int len, float offset, float size, float stretch, FontType font);
//! Draws text (multi-format)
void DrawText(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
Math::Point pos, float width, Gfx::JustifyType justify, float size,
float stretch, int eol);
//! Draws text (one font)
void DrawText(const std::string &text, Gfx::FontType font,
Math::Point pos, float width, Gfx::JustifyType justify, float size,
float stretch, int eol);
protected:
void DrawString(char *string, char *format, int len, Math::Point pos, float width, float size, float stretch, int eol);
void DrawString(char *string, int len, Math::Point pos, float width, float size, float stretch, FontType font, int eol);
void DrawColor(Math::Point pos, float size, float width, int color);
void DrawChar(int character, Math::Point pos, float size, float stretch, FontType font);
//! Calculates dimensions for text (multi-format)
void SizeText(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
Math::Point pos, Gfx::JustifyType justify, float size,
Math::Point &start, Math::Point &end);
//! Calculates dimensions for text (one font)
void SizeText(const std::string &text, Gfx::FontType font,
Math::Point pos, Gfx::JustifyType justify, float size,
Math::Point &start, Math::Point &end);
//! Returns the ascent font metric
float GetAscent(Gfx::FontType font, float size);
//! Returns the descent font metric
float GetDescent(Gfx::FontType font, float size);
//! Returns the height font metric
float GetHeight(Gfx::FontType font, float size);
//! Returns width of string (multi-format)
float GetStringWidth(const std::string &text,
const std::vector<Gfx::FontMetaChar> &format, float size);
//! Returns width of string (single font)
float GetStringWidth(const std::string &text, Gfx::FontType font, float size);
//! Returns width of single character
float GetCharWidth(int character, Gfx::FontType font, float size, float offset);
//! Justifies a line of text (multi-format)
int Justify(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
float size, float width);
//! Justifies a line of text (one font)
int Justify(const std::string &text, Gfx::FontType font, float size, float width);
//! Returns the most suitable position to a given offset (multi-format)
int Detect(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
float size, float offset);
//! Returns the most suitable position to a given offset (one font)
int Detect(const std::string &text, Gfx::FontType font, float size, float offset);
public: // for testing!
Gfx::CachedFont* GetOrOpenFont(Gfx::FontType type, float size);
Gfx::CharTexture CreateCharTexture(const char* utf8Char, Gfx::CachedFont* font);
void DrawString(const std::string &text, const std::vector<Gfx::FontMetaChar> &format,
float size, Math::Point pos, float width, int eol);
void DrawString(const std::string &text, Gfx::FontType font,
float size, Math::Point pos, float width, int eol);
void DrawColor(int color, float size, Math::Point pos, float width);
void DrawChar(UTF8Char character, Gfx::FontType font, float size, Math::Point &pos);
protected:
CInstanceManager* m_iMan;
Gfx::CEngine* m_engine;
Gfx::CDevice* m_device;
std::string m_error;
float m_defaultSize;
std::string m_fontPath;
std::map<Gfx::FontType, Gfx::MultisizeFont*> m_fonts;
Gfx::FontType m_lastFontType;
int m_lastFontSize;
Gfx::CachedFont* m_lastCachedFont;
};
}; // namespace Gfx

View File

@ -64,7 +64,6 @@ void Gfx::GLDeviceConfig::LoadDefault()
Gfx::CGLDevice::CGLDevice(const Gfx::GLDeviceConfig &config)
{
m_config = config;
m_wasInit = false;
m_lighting = false;
m_texturing = false;
}
@ -74,11 +73,6 @@ Gfx::CGLDevice::~CGLDevice()
{
}
bool Gfx::CGLDevice::GetWasInit()
{
return m_wasInit;
}
std::string Gfx::CGLDevice::GetError()
{
return m_error;
@ -110,8 +104,6 @@ bool Gfx::CGLDevice::Create()
/* NOTE: when not using GLEW, extension testing is not performed, as it is assumed that
glext.h is up-to-date and the OpenGL shared library has the required functions present. */
m_wasInit = true;
// This is mostly done in all modern hardware by default
// DirectX doesn't even allow the option to turn off perspective correction anymore
// So turn it on permanently
@ -158,8 +150,6 @@ void Gfx::CGLDevice::Destroy()
m_currentTextures.clear();
m_texturesEnabled.clear();
m_textureStageParams.clear();
m_wasInit = false;
}
void Gfx::CGLDevice::ConfigChanged(const Gfx::GLDeviceConfig& newConfig)
@ -385,15 +375,20 @@ bool Gfx::CGLDevice::GetLightEnabled(int index)
This struct must not be deleted in other way than through DeleteTexture() */
Gfx::Texture Gfx::CGLDevice::CreateTexture(CImage *image, const Gfx::TextureCreateParams &params)
{
Gfx::Texture result;
ImageData *data = image->GetData();
if (data == NULL)
{
m_error = "Invalid texture data";
return result; // invalid texture
return Gfx::Texture(); // invalid texture
}
return CreateTexture(data, params);
}
Gfx::Texture Gfx::CGLDevice::CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params)
{
Gfx::Texture result;
result.valid = true;
result.size.w = data->surface->w;
result.size.h = data->surface->h;
@ -531,6 +526,24 @@ void Gfx::CGLDevice::SetTexture(int index, const Gfx::Texture &texture)
glDisable(GL_TEXTURE_2D);
}
void Gfx::CGLDevice::SetTexture(int index, unsigned int textureId)
{
assert(index >= 0);
assert(index < static_cast<int>( m_currentTextures.size() ));
// Enable the given texture stage
glActiveTexture(GL_TEXTURE0 + index);
glEnable(GL_TEXTURE_2D);
m_currentTextures[index].id = textureId;
glBindTexture(GL_TEXTURE_2D, textureId);
// Disable the stage if it is set so
if ( (! m_texturing) || (! m_texturesEnabled[index]) )
glDisable(GL_TEXTURE_2D);
}
/**
Returns the previously assigned texture or invalid texture if the given stage is not enabled. */
Gfx::Texture Gfx::CGLDevice::GetTexture(int index)

View File

@ -73,7 +73,6 @@ public:
CGLDevice(const Gfx::GLDeviceConfig &config);
virtual ~CGLDevice();
virtual bool GetWasInit();
virtual std::string GetError();
virtual bool Create();
@ -100,11 +99,13 @@ public:
virtual bool GetLightEnabled(int index);
virtual Gfx::Texture CreateTexture(CImage *image, const Gfx::TextureCreateParams &params);
virtual Gfx::Texture CreateTexture(ImageData *data, const Gfx::TextureCreateParams &params);
virtual void DestroyTexture(const Gfx::Texture &texture);
virtual void DestroyAllTextures();
virtual int GetMaxTextureCount();
virtual void SetTexture(int index, const Gfx::Texture &texture);
virtual void SetTexture(int index, unsigned int textureId);
virtual Gfx::Texture GetTexture(int index);
virtual void SetTextureEnabled(int index, bool enabled);
virtual bool GetTextureEnabled(int index);
@ -163,8 +164,6 @@ private:
private:
//! Current config
Gfx::GLDeviceConfig m_config;
//! Was initialized?
bool m_wasInit;
//! Last encountered error
std::string m_error;

View File

@ -20,6 +20,8 @@
#pragma once
#include <cmath>
// Math module namespace
namespace Math
@ -30,12 +32,12 @@ namespace Math
const float TOLERANCE = 1e-6f;
//! Very small number (used in testing/returning some values)
const float VERY_SMALL = 1e-6f;
const float VERY_SMALL_NUM = 1e-6f;
//! Very big number (used in testing/returning some values)
const float VERY_BIG = 1e6f;
const float VERY_BIG_NUM = 1e6f;
//! Huge number
const float HUGE = 1.0e+38f;
const float HUGE_NUM = 1.0e+38f;
//! PI
const float PI = 3.14159265358979323846f;
@ -45,6 +47,9 @@ const float DEG_TO_RAD = 0.01745329251994329547f;
//! Radians to degrees multiplier
const float RAD_TO_DEG = 57.29577951308232286465f;
//! Natural logarithm of 2
const float LOG_2 = log(2.0f);
/* @} */ // end of group
}; // namespace Math

View File

@ -127,6 +127,14 @@ inline float Rand()
return static_cast<float>(rand()) / static_cast<float>(RAND_MAX);
}
//! Returns the next nearest power of two to \a x
inline int NextPowerOfTwo(int x)
{
double logbase2 = log(static_cast<float>(x)) / Math::LOG_2;
return static_cast<int>(pow(2, ceil(logbase2)) + 0.5);
}
//! Returns a normalized angle, that is in other words between 0 and 2 * PI
inline float NormAngle(float angle)
{

View File

@ -45,9 +45,9 @@ inline float MidPoint(const Math::Point &a, const Math::Point &b, float px)
if (IsEqual(a.x, b.x))
{
if (a.y < b.y)
return HUGE;
return Math::HUGE_NUM;
else
return -HUGE;
return -Math::HUGE_NUM;
}
return (b.y-a.y) * (px-a.x) / (b.x-a.x) + a.y;
}

View File

@ -20,6 +20,9 @@
#pragma once
#include "math/intpoint.h"
// Math module namespace
namespace Math
{
@ -31,9 +34,9 @@ namespace Math
struct IntSize
{
//! Width
int w;
long w;
//! Height
int h;
long h;
//! Constructs a zero size: (0,0)
inline IntSize()
@ -42,7 +45,7 @@ struct IntSize
}
//! Constructs a size from given dimensions: (w,h)
inline explicit IntSize(int w, int h)
inline explicit IntSize(long w, long h)
{
this->w = w;
this->h = h;
@ -53,6 +56,12 @@ struct IntSize
{
w = h = 0;
}
//! Converts Point to Size
inline static Math::IntSize FromIntPoint(Math::IntPoint p)
{
return Math::IntSize(p.x, p.y);
}
}; // struct Size

View File

@ -20,6 +20,9 @@
#pragma once
#include "math/point.h"
// Math module namespace
namespace Math
{
@ -58,6 +61,12 @@ struct Size
{
w = h = 0.0f;
}
//! Converts Point to Size
inline static Math::Size FromPoint(Math::Point p)
{
return Math::Size(p.x, p.y);
}
}; // struct Size