MinecraftConsoles/Minecraft.Client/LivingEntityRenderer.cpp
Langtanium fd2fd65908 Added code for more DLC skin geometry
Added code to DLCSkinFile.cpp to store skin box scale value. Added code to HumanoidModel.cpp and HumanoidModel.h to handle skin boxes added to the armor layer of skin. Added another float value to SkinBox.h
2026-04-09 17:59:13 -07:00

704 lines
20 KiB
C++

#include "stdafx.h"
#include "LivingEntityRenderer.h"
#include "Lighting.h"
#include "Cube.h"
#include "ModelPart.h"
#include "EntityRenderDispatcher.h"
#include "MultiPlayerLocalPlayer.h"
#include "..\Minecraft.World\Arrow.h"
#include "..\Minecraft.World\Mth.h"
#include "..\Minecraft.World\Player.h"
ResourceLocation LivingEntityRenderer::ENCHANT_GLINT_LOCATION = ResourceLocation(TN__BLUR__MISC_GLINT);
int LivingEntityRenderer::MAX_ARMOR_LAYERS = 4;
LivingEntityRenderer::LivingEntityRenderer(Model *model, float shadow)
{
this->model = model;
shadowRadius = shadow;
armor = nullptr;
}
LivingEntityRenderer::LivingEntityRenderer(Model *model, float shadow, bool is64x64)
{
this->model = model;
if (is64x64)
{
this->modelClassic = new HumanoidModel(0, 0, 64, 64, false);
this->modelSlim = new HumanoidModel(0, 0, 64, 64, true);
}
shadowRadius = shadow;
armor = nullptr;
}
void LivingEntityRenderer::setArmor(Model *armor)
{
this->armor = armor;
}
float LivingEntityRenderer::rotlerp(float from, float to, float a)
{
float diff = to - from;
while (diff < -180)
diff += 360;
while (diff >= 180)
diff -= 360;
return from + a * diff;
}
void LivingEntityRenderer::render(shared_ptr<Entity> _mob, double x, double y, double z, float rot, float a)
{
if (_mob == nullptr)
{
return;
}
shared_ptr<LivingEntity> mob = dynamic_pointer_cast<LivingEntity>(_mob);
shared_ptr<Player> player = dynamic_pointer_cast<Player>(_mob);
Model *resModel;
if (mob == nullptr)
{
return;
}
glPushMatrix();
glDisable(GL_CULL_FACE);
if (player != nullptr && modelClassic != nullptr && (player->getCustomSkin() == 18 || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_ClassicModel))) resModel = modelClassic;
else if (player != nullptr && modelSlim != nullptr && ((player->getCustomSkin() >= 8 && player->getCustomSkin() <= 17) || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_SlimModel))) resModel = modelSlim;
else resModel = model;
resModel->attackTime = getAttackAnim(mob, a);
if (armor != nullptr) armor->attackTime = resModel->attackTime;
resModel->riding = mob->isRiding();
if (armor != nullptr) armor->riding = resModel->riding;
resModel->young = mob->isBaby();
if (armor != nullptr) armor->young = resModel->young;
/*try*/
{
float bodyRot = rotlerp(mob->yBodyRotO, mob->yBodyRot, a);
float headRot = rotlerp(mob->yHeadRotO, mob->yHeadRot, a);
if (mob->isRiding() && mob->riding->instanceof(eTYPE_LIVINGENTITY))
{
shared_ptr<LivingEntity> riding = dynamic_pointer_cast<LivingEntity>(mob->riding);
bodyRot = rotlerp(riding->yBodyRotO, riding->yBodyRot, a);
float headDiff = Mth::wrapDegrees(headRot - bodyRot);
if (headDiff < -85) headDiff = -85;
if (headDiff >= 85) headDiff = +85;
bodyRot = headRot - headDiff;
if (headDiff * headDiff > 50 * 50)
{
bodyRot += headDiff * 0.2f;
}
}
float headRotx = (mob->xRotO + (mob->xRot - mob->xRotO) * a);
setupPosition(mob, x, y, z);
float bob = getBob(mob, a);
setupRotations(mob, bob, bodyRot, a);
float fScale = 1 / 16.0f;
glEnable(GL_RESCALE_NORMAL);
glScalef(-1, -1, 1);
scale(mob, a);
glTranslatef(0, -24 * fScale - 0.125f / 16.0f, 0);
float ws = mob->walkAnimSpeedO + (mob->walkAnimSpeed - mob->walkAnimSpeedO) * a;
float wp = mob->walkAnimPos - mob->walkAnimSpeed * (1 - a);
if (mob->isBaby())
{
wp *= 3.0f;
}
if (ws > 1) ws = 1;
glEnable(GL_ALPHA_TEST);
resModel->prepareMobModel(mob, wp, ws, a);
renderModel(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale);
for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
{
int armorType = prepareArmor(mob, i, a);
if (armorType > 0)
{
armor->prepareMobModel(mob, wp, ws, a);
armor->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, true);
if ((armorType & 0xf0) == 16)
{
prepareSecondPassArmor(mob, i, a);
armor->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, true);
}
// 4J - added condition here for rendering player as part of the gui. Avoiding rendering the glint here as it involves using its own blending, and for gui rendering
// we are globally blending to be able to offer user configurable gui opacity. Note that I really don't know why GL_BLEND is turned off at the end of the first
// armour layer anyway, or why alpha testing is turned on... but we definitely don't want to be turning blending off during the gui render.
if( !entityRenderDispatcher->isGuiRender )
{
if ((armorType & 0xf) == 0xf)
{
float time = mob->tickCount + a;
bindTexture(&ENCHANT_GLINT_LOCATION);
glEnable(GL_BLEND);
float br = 0.5f;
glColor4f(br, br, br, 1);
glDepthFunc(GL_EQUAL);
glDepthMask(false);
for (int j = 0; j < 2; j++)
{
glDisable(GL_LIGHTING);
float brr = 0.76f;
glColor4f(0.5f * brr, 0.25f * brr, 0.8f * brr, 1);
glBlendFunc(GL_SRC_COLOR, GL_ONE);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
float uo = time * (0.001f + j * 0.003f) * 20;
float ss = 1 / 3.0f;
glScalef(ss, ss, ss);
glRotatef(30 - (j) * 60.0f, 0, 0, 1);
glTranslatef(0, uo, 0);
glMatrixMode(GL_MODELVIEW);
armor->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, false);
}
glColor4f(1, 1, 1, 1);
glMatrixMode(GL_TEXTURE);
glDepthMask(true);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL);
}
glDisable(GL_BLEND);
}
glEnable(GL_ALPHA_TEST);
}
}
glDepthMask(true);
additionalRendering(mob, a);
float br = mob->getBrightness(a);
int overlayColor = getOverlayColor(mob, br, a);
glActiveTexture(GL_TEXTURE1);
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
if (((overlayColor >> 24) & 0xff) > 0 || mob->hurtTime > 0 || mob->deathTime > 0)
{
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthFunc(GL_EQUAL);
// 4J - changed these renders to not use the compiled version of their models, because otherwise the render states set
// about (in particular the depth & alpha test) don't work with our command buffer versions
if (mob->hurtTime > 0 || mob->deathTime > 0)
{
glColor4f(br, 0, 0, 0.4f);
resModel->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, false);
for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
{
if (prepareArmorOverlay(mob, i, a) >= 0)
{
glColor4f(br, 0, 0, 0.4f);
armor->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, false);
}
}
}
if (((overlayColor >> 24) & 0xff) > 0)
{
float r = ((overlayColor >> 16) & 0xff) / 255.0f;
float g = ((overlayColor >> 8) & 0xff) / 255.0f;
float b = ((overlayColor) & 0xff) / 255.0f;
float aa = ((overlayColor >> 24) & 0xff) / 255.0f;
glColor4f(r, g, b, aa);
resModel->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, false);
for (int i = 0; i < MAX_ARMOR_LAYERS; i++)
{
if (prepareArmorOverlay(mob, i, a) >= 0)
{
glColor4f(r, g, b, aa);
armor->render(mob, wp, ws, bob, headRot - bodyRot, headRotx, fScale, false);
}
}
}
glDepthFunc(GL_LEQUAL);
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST);
glEnable(GL_TEXTURE_2D);
}
glDisable(GL_RESCALE_NORMAL);
}
/* catch (Exception e)
{
e.printStackTrace();
}*/
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_CULL_FACE);
glPopMatrix();
MemSect(31);
renderName(mob, x, y, z);
MemSect(0);
}
void LivingEntityRenderer::renderModel(shared_ptr<LivingEntity> mob, float wp, float ws, float bob, float headRotMinusBodyRot, float headRotx, float scale)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(mob);
Model *resModel;
if (player != nullptr && modelClassic != nullptr && (player->getCustomSkin() == 18 || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_ClassicModel))) resModel = modelClassic;
else if (player != nullptr && modelSlim != nullptr && ((player->getCustomSkin() >= 8 && player->getCustomSkin() <= 17) || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_SlimModel))) resModel = modelSlim;
else resModel = model;
bindTexture(mob);
if (!mob->isInvisible())
{
resModel->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true);
}
else if(!mob->isInvisibleTo(dynamic_pointer_cast<Player>(Minecraft::GetInstance()->player)))
{
glPushMatrix();
glColor4f(1, 1, 1, 0.15f);
glDepthMask(false);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glAlphaFunc(GL_GREATER, 1.0f / 255.0f);
resModel->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true);
glDisable(GL_BLEND);
glAlphaFunc(GL_GREATER, .1f);
glPopMatrix();
glDepthMask(true);
}
else
{
resModel->setupAnim(wp, ws, bob, headRotMinusBodyRot, headRotx, scale, mob);
}
}
void LivingEntityRenderer::setupPosition(shared_ptr<LivingEntity> mob, double x, double y, double z)
{
glTranslatef(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
}
void LivingEntityRenderer::setupRotations(shared_ptr<LivingEntity> mob, float bob, float bodyRot, float a)
{
glRotatef(180 - bodyRot, 0, 1, 0);
if (mob->deathTime > 0)
{
float fall = (mob->deathTime + a - 1) / 20.0f * 1.6f;
fall = sqrt(fall);
if (fall > 1) fall = 1;
glRotatef(fall * getFlipDegrees(mob), 0, 0, 1);
}
else
{
wstring name = mob->getAName();
if (name == L"Dinnerbone" || name == L"Grumm" || mob->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_Dinnerbone))
{
if ( !mob->instanceof(eTYPE_PLAYER) || !dynamic_pointer_cast<Player>(mob)->isCapeHidden() )
{
glTranslatef(0, mob->bbHeight + 0.1f, 0);
glRotatef(180, 0, 0, 1);
}
}
}
}
float LivingEntityRenderer::getAttackAnim(shared_ptr<LivingEntity> mob, float a)
{
return mob->getAttackAnim(a);
}
float LivingEntityRenderer::getBob(shared_ptr<LivingEntity> mob, float a)
{
return (mob->tickCount + a);
}
void LivingEntityRenderer::additionalRendering(shared_ptr<LivingEntity> mob, float a)
{
}
void LivingEntityRenderer::renderArrows(shared_ptr<LivingEntity> mob, float a)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(mob);
Model *resModel;
if (player != nullptr && modelClassic != nullptr && (player->getCustomSkin() == 18 || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_ClassicModel))) resModel = modelClassic;
else if (player != nullptr && modelSlim != nullptr && ((player->getCustomSkin() >= 8 && player->getCustomSkin() <= 17) || player->getAnimOverrideBitmask()&(1<<HumanoidModel::eAnim_SlimModel))) resModel = modelSlim;
else resModel = model;
int arrowCount = mob->getArrowCount();
if (arrowCount > 0)
{
shared_ptr<Entity> arrow = std::make_shared<Arrow>(mob->level, mob->x, mob->y, mob->z);
Random random = Random(mob->entityId);
Lighting::turnOff();
for (int i = 0; i < arrowCount; i++)
{
glPushMatrix();
ModelPart *modelPart;
modelPart = resModel->getRandomModelPart(random);
Cube *cube = modelPart->cubes[random.nextInt(modelPart->cubes.size())];
modelPart->translateTo(1 / 16.0f);
float xd = random.nextFloat();
float yd = random.nextFloat();
float zd = random.nextFloat();
float xo = (cube->x0 + (cube->x1 - cube->x0) * xd) / 16.0f;
float yo = (cube->y0 + (cube->y1 - cube->y0) * yd) / 16.0f;
float zo = (cube->z0 + (cube->z1 - cube->z0) * zd) / 16.0f;
glTranslatef(xo, yo, zo);
xd = xd * 2 - 1;
yd = yd * 2 - 1;
zd = zd * 2 - 1;
if (true)
{
xd *= -1;
yd *= -1;
zd *= -1;
}
float sd = (float) sqrt(xd * xd + zd * zd);
arrow->yRotO = arrow->yRot = (float) (atan2(xd, zd) * 180 / PI);
arrow->xRotO = arrow->xRot = (float) (atan2(yd, sd) * 180 / PI);
double x = 0;
double y = 0;
double z = 0;
float yRot = 0;
entityRenderDispatcher->render(arrow, x, y, z, yRot, a);
glPopMatrix();
}
Lighting::turnOn();
}
}
int LivingEntityRenderer::prepareArmorOverlay(shared_ptr<LivingEntity> mob, int layer, float a)
{
return prepareArmor(mob, layer, a);
}
int LivingEntityRenderer::prepareArmor(shared_ptr<LivingEntity> mob, int layer, float a)
{
return -1;
}
void LivingEntityRenderer::prepareSecondPassArmor(shared_ptr<LivingEntity> mob, int layer, float a)
{
}
float LivingEntityRenderer::getFlipDegrees(shared_ptr<LivingEntity> mob)
{
return 90;
}
int LivingEntityRenderer::getOverlayColor(shared_ptr<LivingEntity> mob, float br, float a)
{
return 0;
}
void LivingEntityRenderer::scale(shared_ptr<LivingEntity> mob, float a)
{
}
void LivingEntityRenderer::renderName(shared_ptr<LivingEntity> mob, double x, double y, double z)
{
if (shouldShowName(mob) || Minecraft::renderDebug())
{
float size = 1.60f;
float s = 1 / 60.0f * size;
double dist = mob->distanceToSqr(entityRenderDispatcher->cameraEntity);
float maxDist = mob->isSneaking() ? 32 : 64;
if (dist < maxDist * maxDist)
{
wstring msg = mob->getDisplayName();
if (!msg.empty())
{
if (mob->isSneaking())
{
if ( app.GetGameSettings(eGameSetting_DisplayHUD)==0 )
{
// 4J-PB - turn off gamertag render
return;
}
if(app.GetGameHostOption(eGameHostOption_Gamertags)==0)
{
// turn off gamertags if the host has set them off
return;
}
Font *font = getFont();
glPushMatrix();
glTranslatef(static_cast<float>(x) + 0, static_cast<float>(y) + mob->bbHeight + 0.5f, static_cast<float>(z));
glNormal3f(0, 1, 0);
glRotatef(-entityRenderDispatcher->playerRotY, 0, 1, 0);
glRotatef(entityRenderDispatcher->playerRotX, 1, 0, 0);
glScalef(-s, -s, s);
glDisable(GL_LIGHTING);
glTranslatef(0, 0.25f / s, 0);
glDepthMask(false);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Tesselator *t = Tesselator::getInstance();
glDisable(GL_TEXTURE_2D);
t->begin();
int w = font->width(msg) / 2;
t->color(0.f, 0.f, 0.f, 0.25f);
t->vertex(-w - 1, -1, 0);
t->vertex(-w - 1, +8, 0);
t->vertex(+w + 1, +8, 0);
t->vertex(+w + 1, -1, 0);
t->end();
glEnable(GL_TEXTURE_2D);
glDepthMask(true);
font->draw(msg, -font->width(msg) / 2, 0, 0x20ffffff);
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
glColor4f(1, 1, 1, 1);
glPopMatrix();
}
else
{
renderNameTags(mob, x, y, z, msg, s, dist);
}
}
}
}
}
bool LivingEntityRenderer::shouldShowName(shared_ptr<LivingEntity> mob)
{
return Minecraft::renderNames() && mob != entityRenderDispatcher->cameraEntity && !mob->isInvisibleTo(Minecraft::GetInstance()->player) && mob->rider.lock() == nullptr;
}
void LivingEntityRenderer::renderNameTags(shared_ptr<LivingEntity> mob, double x, double y, double z, const wstring &msg, float scale, double dist)
{
if (mob->isSleeping())
{
renderNameTag(mob, msg, x, y - 1.5f, z, 64);
}
else
{
renderNameTag(mob, msg, x, y, z, 64);
}
}
// 4J Added parameter for color here so that we can colour players names
void LivingEntityRenderer::renderNameTag(shared_ptr<LivingEntity> mob, const wstring &name, double x, double y, double z, int maxDist, int color /*= 0xff000000*/)
{
if ( app.GetGameSettings(eGameSetting_DisplayHUD)==0 )
{
// 4J-PB - turn off gamertag render
return;
}
if(app.GetGameHostOption(eGameHostOption_Gamertags)==0)
{
// turn off gamertags if the host has set them off
return;
}
float dist = mob->distanceTo(entityRenderDispatcher->cameraEntity);
if (dist > maxDist )
{
return;
}
Font *font = getFont();
constexpr float size = 1.60f;
constexpr float s = 1 / 60.0f * size;
glPushMatrix();
glTranslatef(static_cast<float>(x) + 0, static_cast<float>(y) + mob->bbHeight + 0.5f, static_cast<float>(z));
glNormal3f(0, 1, 0);
glRotatef(-this->entityRenderDispatcher->playerRotY, 0, 1, 0);
glRotatef(this->entityRenderDispatcher->playerRotX, 1, 0, 0);
glScalef(-s, -s, s);
glDisable(GL_LIGHTING);
// 4J Stu - If it's beyond readable distance, then just render a coloured box
int readableDist = PLAYER_NAME_READABLE_FULLSCREEN;
if( !RenderManager.IsHiDef() )
{
readableDist = PLAYER_NAME_READABLE_DISTANCE_SD;
}
else if ( app.GetLocalPlayerCount() > 2 )
{
readableDist = PLAYER_NAME_READABLE_DISTANCE_SPLITSCREEN;
}
float textOpacity = 1.0f;
if( dist >= readableDist )
{
int diff = dist - readableDist;
textOpacity /= (diff/2);
if( diff > readableDist ) textOpacity = 0.0f;
}
if( textOpacity < 0.0f ) textOpacity = 0.0f;
if( textOpacity > 1.0f ) textOpacity = 1.0f;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Tesselator *t = Tesselator::getInstance();
int offs = 0;
wstring playerName;
WCHAR wchName[2];
if(mob->instanceof(eTYPE_PLAYER))
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(mob);
if(app.isXuidDeadmau5( player->getXuid() ) ) offs = -10;
#if defined(__PS3__) || defined(__ORBIS__)
// Check we have all the font characters for this player name
switch(player->GetPlayerNameValidState())
{
case Player::ePlayerNameValid_NotSet:
if(font->AllCharactersValid(name))
{
playerName=name;
player->SetPlayerNameValidState(true);
}
else
{
memset(wchName,0,sizeof(WCHAR)*2);
swprintf(wchName, 2, L"%d",player->getPlayerIndex()+1);
playerName=wchName;
player->SetPlayerNameValidState(false);
}
break;
case Player::ePlayerNameValid_True:
playerName=name;
break;
case Player::ePlayerNameValid_False:
memset(wchName,0,sizeof(WCHAR)*2);
swprintf(wchName, 2, L"%d",player->getPlayerIndex()+1);
playerName=wchName;
break;
}
#else
playerName = name;
#endif
}
else
{
playerName = name;
}
if( textOpacity > 0.0f )
{
glColor4f(1.0f,1.0f,1.0f,textOpacity);
glDepthMask(false);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
t->begin();
int w = font->width(playerName) / 2;
if( textOpacity < 1.0f )
{
t->color(color, 255 * textOpacity);
}
else
{
t->color(0.0f, 0.0f, 0.0f, 0.25f);
}
t->vertex(static_cast<float>(-w - 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(-w - 1), static_cast<float>(+8 + offs + 1), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(+8 + offs + 1), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->end();
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glDepthFunc(GL_ALWAYS);
glLineWidth(2.0f);
t->begin(GL_LINE_STRIP);
t->color(color, 255 * textOpacity);
t->vertex(static_cast<float>(-w - 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(-w - 1), static_cast<float>(+8 + offs + 1), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(+8 + offs + 1), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(-w - 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->end();
glDepthFunc(GL_LEQUAL);
glDepthMask(false);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
font->draw(playerName, -font->width(playerName) / 2, offs, 0x20ffffff);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
}
if( textOpacity < 1.0f )
{
glColor4f(1.0f,1.0f,1.0f,1.0f);
glDisable(GL_TEXTURE_2D);
glDepthFunc(GL_ALWAYS);
t->begin();
int w = font->width(playerName) / 2;
t->color(color, 255);
t->vertex(static_cast<float>(-w - 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(-w - 1), static_cast<float>(+8 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(+8 + offs), static_cast<float>(0));
t->vertex(static_cast<float>(+w + 1), static_cast<float>(-1 + offs), static_cast<float>(0));
t->end();
glDepthFunc(GL_LEQUAL);
glEnable(GL_TEXTURE_2D);
glTranslatef(0.0f, 0.0f, -0.04f);
}
if( textOpacity > 0.0f )
{
int textColor = ( ( static_cast<int>(textOpacity * 255) << 24 ) | 0xffffff );
font->draw(playerName, -font->width(playerName) / 2, offs, textColor);
}
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
glColor4f(1, 1, 1, 1);
glPopMatrix();
}