Port billboard text

This commit is contained in:
Benau 2017-12-30 15:28:04 +08:00
parent ec59e3f573
commit cce8abe6f3
11 changed files with 472 additions and 186 deletions

View File

@ -0,0 +1,15 @@
in vec2 uv;
in vec4 color;
out vec4 o_diffuse_color;
uniform sampler2D font_texture;
void main()
{
vec4 col = texture(font_texture, uv);
if (col.a < 0.5)
{
discard;
}
o_diffuse_color = vec4(col.xyz * color.xyz, 1.0);
}

View File

@ -25,6 +25,8 @@
#include "graphics/lod_node.hpp"
#include "graphics/shaders.hpp"
#include "graphics/stk_particle.hpp"
#include "graphics/stk_text_billboard.hpp"
#include "graphics/text_billboard_drawer.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_mesh_node.hpp"
#include "tracks/track.hpp"
@ -155,7 +157,7 @@ void DrawCalls::parseSceneManager(core::list<scene::ISceneNode*> &List,
if (!(*I)->isVisible())
continue;
if (STKParticle *node = dynamic_cast<STKParticle *>(*I))
if (STKParticle *node = dynamic_cast<STKParticle*>(*I))
{
if (!isCulledPrecise(cam, *I, irr_driver->getBoundingBoxesViz()) ||
SP::sp_first_frame)
@ -164,13 +166,22 @@ void DrawCalls::parseSceneManager(core::list<scene::ISceneNode*> &List,
}
if (scene::IBillboardSceneNode *node =
dynamic_cast<scene::IBillboardSceneNode *>(*I))
dynamic_cast<scene::IBillboardSceneNode*>(*I))
{
if (!isCulledPrecise(cam, *I) || SP::sp_first_frame)
CPUParticleManager::getInstance()->addBillboardNode(node);
continue;
}
if (STKTextBillboard *tb =
dynamic_cast<STKTextBillboard*>(*I))
{
if (!isCulledPrecise(cam, *I, irr_driver->getBoundingBoxesViz()) ||
SP::sp_first_frame)
TextBillboardDrawer::addTextBillboard(tb);
continue;
}
SP::SPMeshNode* node = dynamic_cast<SP::SPMeshNode*>(*I);
if (node)
{
@ -199,6 +210,7 @@ DrawCalls::~DrawCalls()
void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
{
CPUParticleManager::getInstance()->reset();
TextBillboardDrawer::reset();
PROFILER_PUSH_CPU_MARKER("- culling", 0xFF, 0xFF, 0x0);
SP::prepareDrawCalls();
parseSceneManager(
@ -246,8 +258,10 @@ void DrawCalls::prepareDrawCalls(scene::ICameraSceneNode *camnode)
break;
}*/
PROFILER_PUSH_CPU_MARKER("- cpu particle upload", 0x3F, 0x03, 0x61);
PROFILER_PUSH_CPU_MARKER("- particle and text billboard upload", 0x3F,
0x03, 0x61);
CPUParticleManager::getInstance()->uploadAll();
TextBillboardDrawer::updateAll();
PROFILER_POP_CPU_MARKER();
PROFILER_PUSH_CPU_MARKER("- SP::upload instance and skinning matrices",

View File

@ -36,6 +36,7 @@
#include "graphics/spherical_harmonics.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/sp/sp_shader.hpp"
#include "graphics/text_billboard_drawer.hpp"
#include "items/item_manager.hpp"
#include "items/powerup_manager.hpp"
#include "modes/world.hpp"
@ -392,11 +393,13 @@ void ShaderBasedRenderer::renderSceneDeferred(scene::ICameraSceneNode * const ca
PROFILER_POP_CPU_MARKER();
}
// Render particles
// Render particles and text billboard
{
PROFILER_PUSH_CPU_MARKER("- Particles", 0xFF, 0xFF, 0x00);
PROFILER_PUSH_CPU_MARKER("- Particles and text billboard", 0xFF, 0xFF,
0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_PARTICLES));
CPUParticleManager::getInstance()->drawAll();
TextBillboardDrawer::drawAll();
PROFILER_POP_CPU_MARKER();
}
@ -494,20 +497,6 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
PROFILER_POP_CPU_MARKER();
}
const Track * const track = Track::getCurrentTrack();
// Render discrete lights scattering
if (CVS->isDefferedEnabled() && track && track->isFogEnabled())
{
PROFILER_PUSH_CPU_MARKER("- PointLight Scatter", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_FOG));
m_lighting_passes.renderLightsScatter(m_rtts->getDepthStencilTexture(),
m_rtts->getFBO(FBO_HALF1),
m_rtts->getFBO(FBO_HALF2),
m_rtts->getFBO(FBO_COLORS),
m_post_processing);
PROFILER_POP_CPU_MARKER();
}
// Render transparent
{
PROFILER_PUSH_CPU_MARKER("- Transparent Pass", 0xFF, 0x00, 0x00);
@ -517,11 +506,13 @@ void ShaderBasedRenderer::renderScene(scene::ICameraSceneNode * const camnode,
PROFILER_POP_CPU_MARKER();
}
// Render particles
// Render particles and text billboard
{
PROFILER_PUSH_CPU_MARKER("- Particles", 0xFF, 0xFF, 0x00);
PROFILER_PUSH_CPU_MARKER("- Particles and text billboard", 0xFF, 0xFF,
0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_PARTICLES));
CPUParticleManager::getInstance()->drawAll();
TextBillboardDrawer::drawAll();
PROFILER_POP_CPU_MARKER();
}

View File

@ -77,6 +77,8 @@ public:
short hue_packed = short(core::clamp(int(hue * 100.0f), 0, 100));
memcpy(m_data + 30, &hue_packed, 2);
}
// ------------------------------------------------------------------------
const void* getData() const { return m_data; }
};

View File

@ -203,8 +203,7 @@ void SPMeshBuffer::uploadGLMesh()
offset += 4;
video::SColor vc = m_vertices[i].m_color;
if (CVS->isDefferedEnabled() ||
CVS->isARBSRGBFramebufferUsable())
if (CVS->isDefferedEnabled())
{
video::SColorf tmp(vc);
vc.setRed(srgbToLinear(tmp.r));

View File

@ -18,35 +18,41 @@
#ifndef SERVER_ONLY
#include "graphics/stk_text_billboard.hpp"
#include "graphics/shaders.hpp"
#include "graphics/sp/sp_base.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/stk_mesh_scene_node.hpp"
#include "graphics/stk_tex_manager.hpp"
#include <SMesh.h>
#include <SMeshBuffer.h>
#include <ISceneManager.h>
#include <ICameraSceneNode.h>
#include "graphics/graphics_restrictions.hpp"
using namespace irr;
STKTextBillboard::STKTextBillboard(core::stringw text, FontWithFace* font,
const video::SColor& color_top, const video::SColor& color_bottom,
irr::scene::ISceneNode* parent,
irr::scene::ISceneManager* mgr, irr::s32 id,
const irr::core::vector3df& position, const irr::core::vector3df& size) :
STKMeshSceneNode(new scene::SMesh(),
parent, irr_driver->getSceneManager(), -1, "text_billboard",
position, core::vector3df(0.0f, 0.0f, 0.0f), size, false)
// ----------------------------------------------------------------------------
STKTextBillboard::STKTextBillboard(const video::SColor& color_top,
const video::SColor& color_bottom,
ISceneNode* parent, ISceneManager* mgr,
s32 id,
const core::vector3df& position,
const core::vector3df& size)
: ISceneNode(parent, mgr, id, position,
core::vector3df(0.0f, 0.0f, 0.0f), size)
{
m_color_top = color_top;
if (CVS->isDefferedEnabled())
{
video::SColorf tmp(m_color_top);
m_color_top.setRed(SP::srgbToLinear(tmp.r));
m_color_top.setGreen(SP::srgbToLinear(tmp.g));
m_color_top.setBlue(SP::srgbToLinear(tmp.b));
}
m_color_bottom = color_bottom;
getTextMesh(text, font);
createGLMeshes();
Mesh->drop();
//setAutomaticCulling(0);
updateAbsolutePosition();
}
if (CVS->isDefferedEnabled())
{
video::SColorf tmp(m_color_bottom);
m_color_bottom.setRed(SP::srgbToLinear(tmp.r));
m_color_bottom.setGreen(SP::srgbToLinear(tmp.g));
m_color_bottom.setBlue(SP::srgbToLinear(tmp.b));
}
static_assert(sizeof(GLTB) == 20, "Wrong compiler padding");
} // STKTextBillboard
// ----------------------------------------------------------------------------
void STKTextBillboard::updateAbsolutePosition()
{
// Make billboard always face the camera
@ -71,126 +77,193 @@ void STKTextBillboard::updateAbsolutePosition()
core::matrix4 m;
m.setScale(RelativeScale);
AbsoluteTransformation *= m;
}
m_instanced_data = SP::SPInstancedData(AbsoluteTransformation, 0, 0, 0, 0);
scene::IMesh* STKTextBillboard::getTextMesh(core::stringw text, FontWithFace* font)
} // updateAbsolutePosition
// ----------------------------------------------------------------------------
void STKTextBillboard::init(core::stringw text, FontWithFace* face)
{
core::dimension2du size = font->getDimension(text.c_str());
font->render(text, core::rect<s32>(0, 0, size.Width, size.Height), video::SColor(255,255,255,255),
false, false, NULL, NULL, this);
m_chars = new std::vector<STKTextBillboardChar>();
core::dimension2du size = face->getDimension(text.c_str());
face->render(text, core::rect<s32>(0, 0, size.Width, size.Height),
video::SColor(255,255,255,255), false, false, NULL, NULL, this);
const float scale = 0.02f;
//scene::SMesh* mesh = new scene::SMesh();
std::map<video::ITexture*, scene::SMeshBuffer*> buffers;
float max_x = 0;
float min_y = 0;
float max_y = 0;
for (unsigned int i = 0; i < m_chars.size(); i++)
for (unsigned int i = 0; i < m_chars->size(); i++)
{
float char_x = m_chars[i].m_destRect.LowerRightCorner.X;
float char_x = (*m_chars)[i].m_dest_rect.LowerRightCorner.X;
if (char_x > max_x)
{
max_x = char_x;
}
float char_min_y = m_chars[i].m_destRect.UpperLeftCorner.Y;
float char_max_y = m_chars[i].m_destRect.LowerRightCorner.Y;
float char_min_y = (*m_chars)[i].m_dest_rect.UpperLeftCorner.Y;
float char_max_y = (*m_chars)[i].m_dest_rect.LowerRightCorner.Y;
if (char_min_y < min_y)
{
min_y = char_min_y;
}
if (char_max_y > min_y)
{
max_y = char_max_y;
}
}
float scaled_center_x = (max_x / 2.0f) * scale;
float scaled_y = (max_y / 2.0f) * scale; // -max_y * scale;
float scaled_y = (max_y / 2.0f) * scale;
for (unsigned int i = 0; i < m_chars.size(); i++)
for (unsigned int i = 0; i < m_chars->size(); i++)
{
core::vector3df char_pos(m_chars[i].m_destRect.UpperLeftCorner.X,
m_chars[i].m_destRect.UpperLeftCorner.Y, 0);
core::vector3df char_pos((*m_chars)[i].m_dest_rect.UpperLeftCorner.X,
(*m_chars)[i].m_dest_rect.UpperLeftCorner.Y, 0);
char_pos *= scale;
core::vector3df char_pos2(m_chars[i].m_destRect.LowerRightCorner.X,
m_chars[i].m_destRect.LowerRightCorner.Y, 0);
core::vector3df char_pos2((*m_chars)[i].m_dest_rect.LowerRightCorner.X,
(*m_chars)[i].m_dest_rect.LowerRightCorner.Y, 0);
char_pos2 *= scale;
//core::dimension2di char_size_i = m_chars[i].m_destRect.getSize();
//core::dimension2df char_size(char_size_i.Width*scale, char_size_i.Height*scale);
std::map<video::ITexture*, scene::SMeshBuffer*>::iterator map_itr = buffers.find(m_chars[i].m_texture);
scene::SMeshBuffer* buffer;
if (map_itr == buffers.end())
{
buffer = new scene::SMeshBuffer();
buffer->getMaterial().setTexture(0, m_chars[i].m_texture);
buffer->getMaterial().setTexture(1, STKTexManager::getInstance()->getUnicolorTexture(video::SColor(0, 0, 0, 0)));
buffer->getMaterial().setTexture(2, STKTexManager::getInstance()->getUnicolorTexture(video::SColor(0, 0, 0, 0)));
buffer->getMaterial().MaterialType = Shaders::getShader(ES_OBJECT_UNLIT);
buffers[m_chars[i].m_texture] = buffer;
}
else
{
buffer = map_itr->second;
}
float tex_width = (float) m_chars[i].m_texture->getSize().Width;
float tex_height = (float)m_chars[i].m_texture->getSize().Height;
video::S3DVertex vertices[] =
{
video::S3DVertex(char_pos.X - scaled_center_x, char_pos.Y - scaled_y, 0.0f,
0.0f, 0.0f, 1.0f,
float tex_width = (float)(*m_chars)[i].m_texture->getSize().Width;
float tex_height = (float)(*m_chars)[i].m_texture->getSize().Height;
using namespace MiniGLM;
std::array<GLTB, 4> triangle_strip =
{{
{
core::vector3df
(char_pos.X - scaled_center_x, char_pos.Y - scaled_y, 0),
m_color_bottom,
m_chars[i].m_sourceRect.UpperLeftCorner.X / tex_width,
m_chars[i].m_sourceRect.LowerRightCorner.Y / tex_height),
{
toFloat16((*m_chars)
[i].m_source_rect.UpperLeftCorner.X / tex_width),
toFloat16((*m_chars)
[i].m_source_rect.LowerRightCorner.Y / tex_height)
}
},
video::S3DVertex(char_pos2.X - scaled_center_x, char_pos.Y - scaled_y, 0.0f,
0.0f, 0.0f, 1.0f,
{
core::vector3df
(char_pos.X - scaled_center_x, char_pos2.Y - scaled_y, 0),
m_color_top,
{
toFloat16((*m_chars)
[i].m_source_rect.UpperLeftCorner.X / tex_width),
toFloat16((*m_chars)
[i].m_source_rect.UpperLeftCorner.Y / tex_height)
}
},
{
core::vector3df
(char_pos2.X - scaled_center_x, char_pos.Y - scaled_y, 0),
m_color_bottom,
m_chars[i].m_sourceRect.LowerRightCorner.X / tex_width,
m_chars[i].m_sourceRect.LowerRightCorner.Y / tex_height),
{
toFloat16((*m_chars)
[i].m_source_rect.LowerRightCorner.X / tex_width),
toFloat16((*m_chars)
[i].m_source_rect.LowerRightCorner.Y / tex_height)
}
},
video::S3DVertex(char_pos2.X - scaled_center_x, char_pos2.Y - scaled_y, 0.0f,
0.0f, 0.0f, 1.0f,
{
core::vector3df
(char_pos2.X - scaled_center_x, char_pos2.Y - scaled_y, 0),
m_color_top,
m_chars[i].m_sourceRect.LowerRightCorner.X / tex_width,
m_chars[i].m_sourceRect.UpperLeftCorner.Y / tex_height),
video::S3DVertex(char_pos.X - scaled_center_x, char_pos2.Y - scaled_y, 0.0f,
0.0f, 0.0f, 1.0f,
m_color_top,
m_chars[i].m_sourceRect.UpperLeftCorner.X / tex_width,
m_chars[i].m_sourceRect.UpperLeftCorner.Y / tex_height)
};
irr::u16 indices[] = { 2, 1, 0, 3, 2, 0 };
buffer->append(vertices, 4, indices, 6);
{
toFloat16((*m_chars)
[i].m_source_rect.LowerRightCorner.X / tex_width),
toFloat16((*m_chars)
[i].m_source_rect.UpperLeftCorner.Y / tex_height)
}
}
}};
m_gl_tbs[(*m_chars)[i].m_texture].push_back(triangle_strip);
}
for (std::map<video::ITexture*, scene::SMeshBuffer*>::iterator map_itr = buffers.begin();
map_itr != buffers.end(); map_itr++)
glGenBuffers(1, &m_instanced_array);
glBindBuffer(GL_ARRAY_BUFFER, m_instanced_array);
glBufferData(GL_ARRAY_BUFFER,
12 /*position*/ + 4/*quaternion*/ + 8 /*scale*/, NULL,
GL_DYNAMIC_DRAW);
for (auto& p : m_gl_tbs)
{
((scene::SMesh*)Mesh)->addMeshBuffer(map_itr->second);
glGenVertexArrays(1, &m_vao_vbos[p.first].first);
glGenBuffers(1, &m_vao_vbos[p.first].second);
glBindBuffer(GL_ARRAY_BUFFER, m_vao_vbos.at(p.first).second);
glBufferData(GL_ARRAY_BUFFER, m_gl_tbs.at(p.first).size() * 4 * 20,
m_gl_tbs.at(p.first).data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(m_vao_vbos.at(p.first).first);
glBindBuffer(GL_ARRAY_BUFFER, m_vao_vbos.at(p.first).second);
map_itr->second->recalculateBoundingBox();
Mesh->setBoundingBox(map_itr->second->getBoundingBox()); // TODO: wrong if several buffers
// Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 20, (void*)0);
map_itr->second->drop();
// Vertex color
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, 20,
(void*)12);
// 1st texture coordinates
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 2, GL_HALF_FLOAT, GL_FALSE, 20, (void*)16);
glBindBuffer(GL_ARRAY_BUFFER, m_instanced_array);
// Origin
glEnableVertexAttribArray(8);
glVertexAttribPointer(8, 3, GL_FLOAT, GL_FALSE, 24, (void*)0);
glVertexAttribDivisorARB(8, 1);
// Rotation (quaternion .xyz)
glEnableVertexAttribArray(9);
glVertexAttribPointer(9, 4, GL_INT_2_10_10_10_REV,
GraphicsRestrictions::isDisabled
(GraphicsRestrictions::GR_10BIT_VECTOR) ? GL_FALSE : GL_TRUE, 24,
(void*)12);
glVertexAttribDivisorARB(9, 1);
// Scale (3 half floats and .w for quaternion .w)
glEnableVertexAttribArray(10);
glVertexAttribPointer(10, 4, GL_HALF_FLOAT, GL_FALSE, 24, (void*)16);
glVertexAttribDivisorARB(10, 1);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
getMaterial(0).MaterialType = Shaders::getShader(ES_OBJECT_UNLIT);
Vec3 min = Vec3( 999999.9f);
Vec3 max = Vec3(-999999.9f);
for (auto& p : m_gl_tbs)
{
for (auto& q : p.second)
{
for (auto& r : q)
{
Vec3 c(r.m_position.X, r.m_position.Y, r.m_position.Z);
min.min(c);
max.max(c);
}
}
}
m_bbox.MinEdge = min.toIrrVector();
m_bbox.MaxEdge = max.toIrrVector();
return Mesh;
}
delete m_chars;
updateAbsolutePosition();
} // init
// ----------------------------------------------------------------------------
void STKTextBillboard::collectChar(video::ITexture* texture,
const core::rect<float>& destRect,
const core::rect<s32>& sourceRect,
const video::SColor* const colors)
const core::rect<float>& dest_rect,
const core::rect<s32>& source_rect,
const video::SColor* const colors)
{
m_chars.push_back(STKTextBillboardChar(texture, destRect, sourceRect, colors));
}
assert(m_chars != NULL);
m_chars->push_back(STKTextBillboardChar(texture, dest_rect, source_rect,
colors));
} // collectChar
#endif // !SERVER_ONLY

View File

@ -18,73 +18,134 @@
#ifndef STK_TEXT_BILLBOARD_HPP
#define STK_TEXT_BILLBOARD_HPP
#include "graphics/stk_mesh_scene_node.hpp"
#include "font/font_with_face.hpp"
#include "utils/cpp2011.hpp"
#include "graphics/gl_headers.hpp"
#include "graphics/sp/sp_instanced_data.hpp"
#include "utils/no_copy.hpp"
#include "../lib/irrlicht/source/Irrlicht/CBillboardSceneNode.h"
#include <IBillboardSceneNode.h>
#include <irrTypes.h>
#include <IMesh.h>
#include <ISceneNode.h>
#include <array>
#include <unordered_map>
#include <vector>
class STKTextBillboardChar
using namespace irr;
using namespace scene;
class STKTextBillboard : public ISceneNode, public NoCopy,
FontWithFace::FontCharCollector
{
public:
irr::video::ITexture* m_texture;
irr::core::rect<float> m_destRect;
irr::core::rect<irr::s32> m_sourceRect;
//irr::video::SColor m_colors[4];
STKTextBillboardChar(irr::video::ITexture* texture,
const irr::core::rect<float>& destRect,
const irr::core::rect<irr::s32>& sourceRect,
const irr::video::SColor* const colors)
private:
struct STKTextBillboardChar
{
m_texture = texture;
m_destRect = destRect;
m_sourceRect = sourceRect;
//if (colors == NULL)
//{
// m_colors[0] = m_colors[1] = m_colors[2] = m_colors[3] = NULL;
//}
//else
//{
// m_colors[0] = colors[0];
// m_colors[1] = colors[1];
// m_colors[2] = colors[2];
// m_colors[3] = colors[3];
//}
}
};
video::ITexture* m_texture;
class STKTextBillboard : public STKMeshSceneNode, FontWithFace::FontCharCollector
{
std::vector<STKTextBillboardChar> m_chars;
irr::video::SColor m_color_top;
irr::video::SColor m_color_bottom;
core::rect<float> m_dest_rect;
irr::scene::IMesh* getTextMesh(irr::core::stringw text, FontWithFace* font);
core::rect<s32> m_source_rect;
// ------------------------------------------------------------------------
STKTextBillboardChar(video::ITexture* texture,
const core::rect<float>& dest_rect,
const core::rect<irr::s32>& source_rect,
const video::SColor* const colors)
{
m_texture = texture;
m_dest_rect = dest_rect;
m_source_rect = source_rect;
}
};
struct GLTB
{
core::vector3df m_position;
video::SColor m_color;
short m_uv[2];
};
SP::SPInstancedData m_instanced_data;
GLuint m_instanced_array = 0;
std::vector<STKTextBillboardChar>* m_chars = NULL;
video::SColor m_color_top;
video::SColor m_color_bottom;
std::unordered_map<video::ITexture*, std::vector<std::array<GLTB, 4> > >
m_gl_tbs;
std::unordered_map<video::ITexture*, std::pair<GLuint, GLuint> >
m_vao_vbos;
core::aabbox3df m_bbox;
public:
STKTextBillboard(irr::core::stringw text, FontWithFace* font,
const irr::video::SColor& color_top,
const irr::video::SColor& color_bottom,
irr::scene::ISceneNode* parent,
irr::scene::ISceneManager* mgr, irr::s32 id,
const irr::core::vector3df& position,
const irr::core::vector3df& size);
virtual scene::ESCENE_NODE_TYPE getType() const OVERRIDE
// ------------------------------------------------------------------------
STKTextBillboard(const video::SColor& color_top,
const video::SColor& color_bottom, ISceneNode* parent,
ISceneManager* mgr, s32 id,
const core::vector3df& position,
const core::vector3df& size);
// ------------------------------------------------------------------------
~STKTextBillboard()
{
return scene::ESNT_TEXT;
#ifndef SERVER_ONLY
if (m_instanced_array != 0)
{
glDeleteBuffers(1, &m_instanced_array);
}
for (auto& p : m_vao_vbos)
{
glDeleteVertexArrays(1, &p.second.first);
glDeleteBuffers(1, &p.second.second);
}
m_vao_vbos.clear();
#endif
}
// ------------------------------------------------------------------------
virtual void collectChar(video::ITexture* texture,
const core::rect<float>& dest_rect,
const core::rect<irr::s32>& source_rect,
const video::SColor* const colors);
// ------------------------------------------------------------------------
virtual void updateAbsolutePosition();
// ------------------------------------------------------------------------
virtual void render() {}
// ------------------------------------------------------------------------
virtual const core::aabbox3df& getBoundingBox() const { return m_bbox; }
// ------------------------------------------------------------------------
void init(core::stringw text, FontWithFace* face);
// ------------------------------------------------------------------------
void draw(video::ITexture* tex) const
{
#ifndef SERVER_ONLY
glBindVertexArray(m_vao_vbos.at(tex).first);
for (unsigned i = 0; i < m_gl_tbs.at(tex).size(); i++)
{
glDrawArraysInstanced(GL_TRIANGLE_STRIP, i * 4, 4, 1);
}
#endif
}
// ------------------------------------------------------------------------
std::vector<video::ITexture*> getAllTBTextures() const
{
std::vector<video::ITexture*> ret;
for (auto& p : m_vao_vbos)
{
ret.push_back(p.first);
}
return ret;
}
// ------------------------------------------------------------------------
void updateGLInstanceData() const
{
#ifndef SERVER_ONLY
glBindBuffer(GL_ARRAY_BUFFER, m_instanced_array);
glBufferSubData(GL_ARRAY_BUFFER, 0, 24, m_instanced_data.getData());
glBindBuffer(GL_ARRAY_BUFFER, 0);
#endif
}
virtual void collectChar(irr::video::ITexture* texture,
const irr::core::rect<float>& destRect,
const irr::core::rect<irr::s32>& sourceRect,
const irr::video::SColor* const colors) OVERRIDE;
virtual void updateAbsolutePosition() OVERRIDE;
};
#endif

View File

@ -0,0 +1,96 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef SERVER_ONLY
#include "graphics/stk_text_billboard.hpp"
#include "graphics/texture_shader.hpp"
#include <unordered_set>
namespace TextBillboardDrawer
{
// ----------------------------------------------------------------------------
std::unordered_map<video::ITexture*, std::vector<STKTextBillboard*> > g_tbs;
// ----------------------------------------------------------------------------
std::unordered_set<STKTextBillboard*> g_tbs_update;
// ============================================================================
/** A Shader to render text billboard.
*/
class TBRenderer : public TextureShader<TBRenderer, 1>
{
public:
TBRenderer()
{
loadProgram(PARTICLES_RENDERING,
GL_VERTEX_SHADER, "sp_pass.vert",
GL_FRAGMENT_SHADER, "sp_text_billboard.frag");
assignUniforms();
assignSamplerNames(0, "font_texture",
ST_TRILINEAR_ANISOTROPIC_FILTERED);
} // TBRenderer
}; // TBRenderer
// ============================================================================
void addTextBillboard(STKTextBillboard* tb)
{
g_tbs_update.insert(tb);
const auto& tex = tb->getAllTBTextures();
for (video::ITexture* t : tex)
{
g_tbs[t].push_back(tb);
}
} // addTextBillboard
// ----------------------------------------------------------------------------
void drawAll()
{
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
TBRenderer::getInstance()->use();
for (auto& p : g_tbs)
{
TBRenderer::getInstance()
->setTextureUnits(p.first->getOpenGLTextureName());
for (auto* q : p.second)
{
q->draw(p.first);
}
}
} // drawAll
// ----------------------------------------------------------------------------
void reset()
{
g_tbs.clear();
g_tbs_update.clear();
} // reset
// ----------------------------------------------------------------------------
void updateAll()
{
for (STKTextBillboard* tb : g_tbs_update)
{
tb->updateGLInstanceData();
}
} // updateAll
}
#endif

View File

@ -0,0 +1,31 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2018 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef TEXT_BILLBOARD_DRAWER_HPP
#define TEXT_BILLBOARD_DRAWER_HPP
class STKTextBillboard;
namespace TextBillboardDrawer
{
void addTextBillboard(STKTextBillboard* tb);
void drawAll();
void reset();
void updateAll();
}
#endif

View File

@ -31,6 +31,7 @@
#include "graphics/central_settings.hpp"
#include "graphics/explosion.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/particle_emitter.hpp"
#include "graphics/particle_kind_manager.hpp"
@ -2971,13 +2972,14 @@ void Kart::setOnScreenText(const wchar_t *text)
if (CVS->isGLSL())
{
scene::ISceneNode* tb =
new STKTextBillboard(text, bold_face,
STKTextBillboard* tb =
new STKTextBillboard(
GUIEngine::getSkin()->getColor("font::bottom"),
GUIEngine::getSkin()->getColor("font::top"),
getNode(), irr_driver->getSceneManager(), -1,
core::vector3df(0.0f, 1.5f, 0.0f),
core::vector3df(1.0f, 1.0f, 1.0f));
tb->init(text, bold_face);
tb->drop();
}
else

View File

@ -22,6 +22,7 @@
#include "font/digit_face.hpp"
#include "font/font_manager.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/stk_text_billboard.hpp"
#include "guiengine/scalable_font.hpp"
#include "input/device_manager.hpp"
@ -98,12 +99,13 @@ namespace Scripting
#ifndef SERVER_ONLY
if (CVS->isGLSL())
{
STKTextBillboard* tb = new STKTextBillboard(wtext.c_str(), digit_face,
STKTextBillboard* tb = new STKTextBillboard(
GUIEngine::getSkin()->getColor("font::bottom"),
GUIEngine::getSkin()->getColor("font::top"),
irr_driver->getSceneManager()->getRootSceneNode(),
irr_driver->getSceneManager(), -1, xyz,
core::vector3df(1.5f, 1.5f, 1.5f));
tb->init(wtext.c_str(), digit_face);
::Track::getCurrentTrack()->addNode(tb);
tb->drop();