1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 18:32:44 +01:00
openrw/rwgame/HUDDrawer.cpp

332 lines
12 KiB
C++
Raw Normal View History

2018-10-29 14:52:18 +01:00
#include "HUDDrawer.hpp"
2018-12-09 22:43:42 +01:00
#include <ai/PlayerController.hpp>
#include <data/WeaponData.hpp>
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
2018-12-09 22:43:42 +01:00
#include <engine/GameWorld.hpp>
#include <objects/CharacterObject.hpp>
2016-09-09 22:13:20 +02:00
#include <render/GameRenderer.hpp>
2016-08-16 18:53:35 +02:00
#include <glm/gtc/constants.hpp>
2018-12-10 01:51:05 +01:00
#include <glm/gtc/quaternion.hpp>
2016-04-10 06:53:49 +02:00
#include <iomanip>
2018-02-10 16:59:07 +01:00
#include <sstream>
2016-04-10 06:53:49 +02:00
2018-12-01 18:57:06 +01:00
void HUDDrawer::drawScriptTimer(GameWorld* world, GameRenderer& render) {
if (world->state->scriptTimerVariable) {
2018-08-30 02:02:02 +02:00
float scriptTimerTextX = static_cast<float>(
2018-12-01 18:57:06 +01:00
render.getRenderer().getViewport().x - hudParameters.uiOuterMargin);
2018-10-29 14:52:18 +01:00
float scriptTimerTextY = hudParameters.uiScriptTimerHeight;
TextRenderer::TextInfo ti;
ti.font = FONT_PRICEDOWN;
2018-10-29 14:52:18 +01:00
ti.size = hudParameters.uiTextSize;
ti.align = TextRenderer::TextInfo::TextAlignment::Right;
{
int32_t seconds = *world->state->scriptTimerVariable / 1000;
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << seconds / 60
<< std::setw(0) << ":" << std::setw(2) << seconds % 60;
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
}
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
ti.screenPosition =
glm::vec2(scriptTimerTextX + 1.f, scriptTimerTextY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiScriptTimerColour;
ti.screenPosition = glm::vec2(scriptTimerTextX, scriptTimerTextY);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
}
}
2018-12-10 01:51:05 +01:00
void HUDDrawer::drawMap(ViewCamera& currentView, ai::PlayerController* player,
2018-12-01 18:57:06 +01:00
GameWorld* world, GameRenderer& render) {
2016-09-09 22:13:20 +02:00
MapRenderer::MapInfo map;
if (world->state->hudFlash != HudFlash::FlashRadar ||
std::fmod(world->getGameTime(), 0.5f) >= .25f) {
2018-01-21 16:44:34 +01:00
glm::quat camRot = currentView.rotation;
2016-04-10 06:53:49 +02:00
2018-01-21 16:44:34 +01:00
map.rotation = glm::roll(camRot) - glm::half_pi<float>();
2018-10-29 14:52:18 +01:00
map.worldSize = hudParameters.uiWorldSizeMin;
map.worldSize = hudParameters.uiWorldSizeMax;
2018-01-21 16:44:34 +01:00
if (player) {
map.worldCenter = glm::vec2(player->getCharacter()->getPosition());
}
2016-04-10 06:53:49 +02:00
2018-12-01 18:57:06 +01:00
const glm::ivec2& vp = render.getRenderer().getViewport();
2016-04-10 06:53:49 +02:00
2018-01-21 16:44:34 +01:00
glm::vec2 mapTop =
2018-10-29 14:52:18 +01:00
glm::vec2(hudParameters.uiOuterMargin, vp.y - (hudParameters.uiOuterMargin + hudParameters.uiMapSize));
2018-01-21 16:44:34 +01:00
glm::vec2 mapBottom =
2018-10-29 14:52:18 +01:00
glm::vec2(hudParameters.uiOuterMargin + hudParameters.uiMapSize, vp.y - hudParameters.uiOuterMargin);
2018-01-21 16:44:34 +01:00
map.screenPosition = (mapTop + mapBottom) / 2.f;
2018-10-29 14:52:18 +01:00
map.screenSize = hudParameters.uiMapSize * 0.95f;
2016-04-10 06:53:49 +02:00
2018-12-01 18:57:06 +01:00
render.map.draw(world, map);
2018-01-21 16:44:34 +01:00
}
2016-09-09 22:13:20 +02:00
}
2018-12-10 01:51:05 +01:00
void HUDDrawer::drawPlayerInfo(ai::PlayerController* player, GameWorld* world,
2018-12-01 18:57:06 +01:00
GameRenderer& render) {
float infoTextX = static_cast<float>(render.getRenderer().getViewport().x -
2018-10-29 14:52:18 +01:00
(hudParameters.uiOuterMargin + hudParameters.uiWeaponSize + hudParameters.uiInfoMargin));
float infoTextY = 0.f + hudParameters.uiOuterMargin;
2018-12-01 18:57:06 +01:00
float iconX = static_cast<float>(render.getRenderer().getViewport().x -
2018-10-29 14:52:18 +01:00
(hudParameters.uiOuterMargin + hudParameters.uiWeaponSize));
float iconY = hudParameters.uiOuterMargin;
2018-12-01 18:57:06 +01:00
float wantedX = static_cast<float>(render.getRenderer().getViewport().x - hudParameters.uiOuterMargin);
2018-10-29 14:52:18 +01:00
float wantedY = hudParameters.uiWantedLevelHeight;
2016-09-09 22:13:20 +02:00
TextRenderer::TextInfo ti;
ti.font = FONT_PRICEDOWN;
2018-10-29 14:52:18 +01:00
ti.size = hudParameters.uiTextSize;
ti.align = TextRenderer::TextInfo::TextAlignment::Right;
2016-09-09 22:13:20 +02:00
{
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << world->getHour()
<< std::setw(0) << ":" << std::setw(2) << world->getMinute();
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
2016-09-09 22:13:20 +02:00
}
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiTimeColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(infoTextX, infoTextY);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
infoTextY += hudParameters.uiTextHeight;
2016-09-09 22:13:20 +02:00
{
std::stringstream ss;
ss << std::setw(8) << std::setfill('0')
<< world->state->playerInfo.displayedMoney;
ti.text = GameSymbols::Money + GameStringUtil::fromString(ss.str(), ti.font);
2016-09-09 22:13:20 +02:00
}
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiMoneyColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(infoTextX, infoTextY);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
infoTextY += hudParameters.uiTextHeight;
2016-09-09 22:13:20 +02:00
if ((world->state->hudFlash != HudFlash::FlashHealth &&
2018-10-29 14:52:18 +01:00
player->getCharacter()->getCurrentState().health > hudParameters.uiLowHealth) ||
std::fmod(world->getGameTime(), 0.5f) >=
.25f) { // UI: Blinking health indicator if health is low
2016-09-09 22:13:20 +02:00
std::stringstream ss;
ss << std::setw(3) << std::setfill('0')
2018-07-27 22:53:35 +02:00
<< static_cast<int>(
player->getCharacter()->getCurrentState().health);
ti.text = GameSymbols::Heart + GameStringUtil::fromString(ss.str(), ti.font);
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiHealthColour;
ti.screenPosition = glm::vec2(infoTextX, infoTextY);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
}
2016-09-09 22:13:20 +02:00
if (player->getCharacter()->getCurrentState().armour > 0) {
std::stringstream ss;
ss << std::setw(3) << std::setfill('0')
2018-07-27 22:53:35 +02:00
<< static_cast<int>(
player->getCharacter()->getCurrentState().armour);
ti.text = GameSymbols::Armour + GameStringUtil::fromString(ss.str(), ti.font);
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition =
2018-10-29 14:52:18 +01:00
glm::vec2(infoTextX + 1.f - hudParameters.uiArmourOffset, infoTextY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiArmourColour;
ti.screenPosition = glm::vec2(infoTextX - hudParameters.uiArmourOffset, infoTextY);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
}
GameString s;
2018-10-29 14:52:18 +01:00
for (size_t i = 0; i < hudParameters.uiMaxWantedLevel; ++i) {
2016-09-09 22:13:20 +02:00
s += GameSymbols::Star;
}
ti.text = s;
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(wantedX + 1.f, wantedY + 1.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
#if 0 // Useful for debugging
ti.text = "ABCDEFGHIJKLMANOQRTSWXYZ\nM0123456789";
ti.size = 30;
ti.align = TextRenderer::TextInfo::Left;
ti.baseColour = glm::vec3(0.f, 0.f, 0.f);
ti.screenPosition = glm::vec2(101.f, 202.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
ti.baseColour = glm::vec3(1.f, 1.f, 1.f);
ti.screenPosition = glm::vec2(100.f, 200.f);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
#endif
auto item = player->getCharacter()->getActiveItem();
const auto& weapon = world->data->weaponData[item];
2016-09-09 22:13:20 +02:00
std::string itemTextureName = "fist";
if (weapon.modelID > 0) {
auto model =
world->data->findModelInfo<SimpleModelInfo>(weapon.modelID);
if (model != nullptr) {
itemTextureName = model->name;
2016-09-09 22:13:20 +02:00
}
}
// Urgh
if (itemTextureName == "colt45") {
itemTextureName = "pistol";
} else if (itemTextureName == "bomb") {
itemTextureName = "detonator";
2016-09-09 22:13:20 +02:00
}
2019-01-18 03:46:59 +01:00
auto itemTexturePtr =
2018-12-01 18:57:06 +01:00
render.getData().findSlotTexture("hud", itemTextureName);
2019-01-18 03:46:59 +01:00
RW_CHECK(itemTexturePtr != nullptr, "Item has 0 texture");
if (itemTexturePtr != nullptr) {
RW_CHECK(itemTexturePtr->getName() != 0, "Item has 0 texture");
render.drawTexture(itemTexturePtr,
2018-12-01 18:57:06 +01:00
glm::vec4(iconX, iconY, hudParameters.uiWeaponSize,
hudParameters.uiWeaponSize));
2016-09-09 22:13:20 +02:00
}
if (weapon.fireType != WeaponData::MELEE) {
const CharacterState& cs = player->getCharacter()->getCurrentState();
const CharacterWeaponSlot& slotInfo = cs.weapons[cs.currentWeapon];
2017-02-19 06:13:31 +01:00
// In weapon.dat clip size of 0 or 1000+ indicates no reload
// Clip size of 1 is being visually omitted as well
bool noClip = weapon.clipSize < 2 || weapon.clipSize > 999;
2017-02-19 06:13:31 +01:00
uint32_t displayBulletsTotal = slotInfo.bulletsTotal;
if (noClip) {
2017-02-19 06:13:31 +01:00
// The clip is actually there, but it holds just one shot/charge
displayBulletsTotal += slotInfo.bulletsClip;
ti.text =
GameStringUtil::fromString(std::to_string(displayBulletsTotal), ti.font);
} else {
2017-02-19 06:13:31 +01:00
// Limit the maximal displayed length for the total bullet count
if (slotInfo.bulletsTotal > 9999) {
displayBulletsTotal = 9999;
}
ti.text = GameStringUtil::fromString(
2017-02-19 06:13:31 +01:00
std::to_string(displayBulletsTotal) + "-" +
std::to_string(slotInfo.bulletsClip), ti.font);
}
2018-10-29 14:52:18 +01:00
ti.baseColour = hudParameters.uiShadowColour;
ti.font = FONT_ARIAL;
2018-10-29 14:52:18 +01:00
ti.size = hudParameters.uiAmmoSize;
ti.align = TextRenderer::TextInfo::TextAlignment::Center;
2018-10-29 14:52:18 +01:00
ti.screenPosition = glm::vec2(iconX + hudParameters.uiWeaponSize / 2.f,
iconY + hudParameters.uiWeaponSize - hudParameters.uiAmmoHeight);
2018-12-01 18:57:06 +01:00
render.text.renderText(ti);
2016-09-09 22:13:20 +02:00
}
2016-04-10 06:53:49 +02:00
}
2018-12-10 01:51:05 +01:00
void HUDDrawer::drawHUD(ViewCamera& currentView, ai::PlayerController* player,
2018-12-01 18:57:06 +01:00
GameWorld* world, GameRenderer& render) {
2016-09-09 22:13:20 +02:00
if (player && player->getCharacter()) {
drawMap(currentView, player, world, render);
drawPlayerInfo(player, world, render);
drawScriptTimer(world, render);
2016-09-09 22:13:20 +02:00
}
}
2018-12-01 18:57:06 +01:00
void HUDDrawer::drawOnScreenText(GameWorld* world, GameRenderer& renderer) {
const auto vp = glm::vec2(renderer.getRenderer().getViewport());
2016-09-09 22:13:20 +02:00
TextRenderer::TextInfo ti;
ti.font = FONT_ARIAL;
2016-09-09 22:13:20 +02:00
ti.screenPosition = glm::vec2(10.f, 10.f);
ti.size = 20.f;
auto& alltext = world->state->text.getAllText();
for (auto& l : alltext) {
for (auto& t : l) {
2018-10-29 14:52:18 +01:00
ti.size = static_cast<float>(t.size * hudParameters.hudScale);
2016-09-09 22:13:20 +02:00
ti.font = t.font;
ti.text = t.text;
ti.wrapX = t.wrapX;
ti.screenPosition = (t.position / glm::vec2(640.f, 480.f)) * vp;
switch (t.alignment) {
case 0:
ti.align = TextRenderer::TextInfo::TextAlignment::Left;
2016-09-09 22:13:20 +02:00
break;
case 1:
ti.align = TextRenderer::TextInfo::TextAlignment::Center;
2016-09-09 22:13:20 +02:00
break;
case 2:
ti.align = TextRenderer::TextInfo::TextAlignment::Right;
2016-09-09 22:13:20 +02:00
break;
}
// Check for the background type
if (t.colourBG.a == 0) {
2018-07-27 22:53:35 +02:00
glm::vec2 shadowPosition(static_cast<int8_t>(t.colourBG.x),
static_cast<int8_t>(t.colourBG.y));
2016-09-09 22:13:20 +02:00
ti.baseColour = glm::vec3(0.f);
ti.screenPosition += shadowPosition;
ti.backgroundColour = {0, 0, 0, 0};
2018-12-01 18:57:06 +01:00
renderer.text.renderText(ti, true);
2016-09-09 22:13:20 +02:00
ti.screenPosition -= shadowPosition;
} else if (t.colourBG.a > 0) {
ti.backgroundColour = t.colourBG;
}
ti.baseColour = t.colourFG;
2018-12-01 18:57:06 +01:00
renderer.text.renderText(ti);
2016-09-09 22:13:20 +02:00
}
}
}
2018-10-26 22:04:09 +02:00
2018-10-29 16:54:13 +01:00
void HUDDrawer::applyHUDScale(float scale) {
hudParameters.hudScale = scale;
2018-10-29 14:52:18 +01:00
hudParameters.uiTextSize *= scale;
hudParameters.uiTextHeight *= scale;
hudParameters.uiElementMargin *= scale;
hudParameters.uiOuterMargin *= scale;
hudParameters.uiInfoMargin *= scale;
hudParameters.uiWeaponSize *= scale;
hudParameters.uiAmmoSize *= scale;
hudParameters.uiAmmoHeight *= scale;
hudParameters.uiWantedLevelHeight *= scale;
hudParameters.uiScriptTimerHeight *= scale;
hudParameters.uiArmourOffset *= scale;
hudParameters.uiMapSize *= scale;
}
2018-10-29 14:52:18 +01:00
HUDDrawer::HUDParameters HUDDrawer::getHUDParameters() {
2018-10-29 16:54:13 +01:00
return hudParameters;
2018-10-26 22:04:09 +02:00
}