1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2014-2015 SuperTuxKart-Team
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 #ifndef STK_TEXT_BILLBOARD_HPP
19 #define STK_TEXT_BILLBOARD_HPP
20 
21 #include "font/font_with_face.hpp"
22 #include "graphics/gl_headers.hpp"
23 #include "graphics/sp/sp_instanced_data.hpp"
24 #include "utils/no_copy.hpp"
25 
26 #include <ISceneNode.h>
27 #include <array>
28 #include <unordered_map>
29 #include <vector>
30 
31 using namespace irr;
32 using namespace scene;
33 
34 class STKTextBillboard : public ISceneNode, public NoCopy,
35                          FontWithFace::FontCharCollector
36 {
37 public:
38     struct GLTB
39     {
40         core::vector3df m_position;
41         video::SColor m_color;
42         short m_uv[2];
43     };
44 
45 private:
46     struct STKTextBillboardChar
47     {
48         video::ITexture* m_texture;
49 
50         core::rect<float> m_dest_rect;
51 
52         core::rect<s32> m_source_rect;
53 
54         // ------------------------------------------------------------------------
STKTextBillboardCharSTKTextBillboard::STKTextBillboardChar55         STKTextBillboardChar(video::ITexture* texture,
56                              const core::rect<float>& dest_rect,
57                              const core::rect<irr::s32>& source_rect,
58                              const video::SColor* const colors)
59         {
60             m_texture = texture;
61             m_dest_rect = dest_rect;
62             m_source_rect = source_rect;
63         }
64     };
65 
66     SP::SPInstancedData m_instanced_data;
67 
68     GLuint m_instanced_array = 0;
69 
70     std::vector<STKTextBillboardChar>* m_chars = NULL;
71 
72     video::SColor m_color_top;
73 
74     video::SColor m_color_bottom;
75 
76     std::unordered_map<video::ITexture*, std::vector<std::array<GLTB, 4> > >
77         m_gl_tbs;
78 
79     std::unordered_map<video::ITexture*, std::pair<GLuint, GLuint> >
80         m_vao_vbos;
81 
82     std::unordered_map<video::ITexture*, IMeshBuffer*> m_gl_mb;
83 
84     core::aabbox3df m_bbox;
85 
86     FontWithFace* m_face;
87 
88     core::stringw m_text;
89 
90     // ------------------------------------------------------------------------
91     float getDefaultScale(FontWithFace* face);
92 public:
93     // ------------------------------------------------------------------------
94     STKTextBillboard(const video::SColor& color_top,
95                      const video::SColor& color_bottom, ISceneNode* parent,
96                      ISceneManager* mgr, s32 id,
97                      const core::vector3df& position,
98                      const core::vector3df& scale = core::vector3df(1, 1, 1));
99     // ------------------------------------------------------------------------
~STKTextBillboard()100     ~STKTextBillboard()
101     {
102         clearBuffer();
103     }
104     // ------------------------------------------------------------------------
clearBuffer()105     void clearBuffer()
106     {
107 #ifndef SERVER_ONLY
108         if (m_instanced_array != 0)
109         {
110             glDeleteBuffers(1, &m_instanced_array);
111         }
112         for (auto& p : m_vao_vbos)
113         {
114             glDeleteVertexArrays(1, &p.second.first);
115             glDeleteBuffers(1, &p.second.second);
116         }
117         m_vao_vbos.clear();
118         for (auto& p : m_gl_mb)
119         {
120             p.second->drop();
121         }
122         m_gl_mb.clear();
123         m_gl_tbs.clear();
124 #endif
125     }
126     // ------------------------------------------------------------------------
127     void reload();
128     // ------------------------------------------------------------------------
129     virtual void collectChar(video::ITexture* texture,
130                              const core::rect<float>& dest_rect,
131                              const core::rect<irr::s32>& source_rect,
132                              const video::SColor* const colors);
133     // ------------------------------------------------------------------------
134     virtual void updateAbsolutePosition();
135     // ------------------------------------------------------------------------
136     virtual void OnRegisterSceneNode();
137     // ------------------------------------------------------------------------
138     virtual void render();
139     // ------------------------------------------------------------------------
getBoundingBox() const140     virtual const core::aabbox3df& getBoundingBox() const    { return m_bbox; }
141     // ------------------------------------------------------------------------
142     void init(const core::stringw& text, FontWithFace* face);
143     // ------------------------------------------------------------------------
144     void initLegacy(const core::stringw& text, FontWithFace* face);
145     // ------------------------------------------------------------------------
draw(video::ITexture * tex) const146     void draw(video::ITexture* tex) const
147     {
148 #ifndef SERVER_ONLY
149         glBindVertexArray(m_vao_vbos.at(tex).first);
150         for (unsigned i = 0; i < m_gl_tbs.at(tex).size(); i++)
151         {
152             glDrawArraysInstanced(GL_TRIANGLE_STRIP, i * 4, 4, 1);
153         }
154 #endif
155     }
156     // ------------------------------------------------------------------------
getAllTBTextures() const157     std::vector<video::ITexture*> getAllTBTextures() const
158     {
159         std::vector<video::ITexture*> ret;
160         for (auto& p : m_vao_vbos)
161         {
162             ret.push_back(p.first);
163         }
164         return ret;
165     }
166     // ------------------------------------------------------------------------
updateGLInstanceData() const167     void updateGLInstanceData() const
168     {
169 #ifndef SERVER_ONLY
170         glBindBuffer(GL_ARRAY_BUFFER, m_instanced_array);
171         glBufferSubData(GL_ARRAY_BUFFER, 0, 36, m_instanced_data.getData());
172         glBindBuffer(GL_ARRAY_BUFFER, 0);
173 #endif
174     }
175     // ------------------------------------------------------------------------
176     static void updateAllTextBillboards();
177 };
178 
179 #endif
180