Bubba-3D  0.9.0
Awesome game engine!
TextObject.cpp
1 /*
2  * This file is part of Bubba-3D.
3  *
4  * Bubba-3D is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Bubba-3D 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 Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with Bubba-3D. If not, see http://www.gnu.org/licenses/.
16  */
17 #include <Font.h>
18 #include <Globals.h>
19 #include <GL/glew.h>
20 #include <glutil/glutil.h>
21 #include "TextObject.h"
22 #include <ShaderProgram.h>
23 #include <FontManager.h>
24 #include <ResourceManager.h>
25 
26 TextObject::TextObject(std::string text, Font* font, int width, int height, int x, int y)
27  : text(text), font(font), width(width), height(height), x(x), y(-y) {
28  setText(text);
29 }
30 
31 void TextObject::setText(std::string text) {
32  this->text = text;
33  std::vector<std::string> lines;
34  std::vector<int> linesOffsetX;
35  int numChars =0;
36  getLines(&lines, &linesOffsetX, &numChars);
37 
38  init(lines,linesOffsetX, numChars);
39 
40 }
41 
42 void TextObject::getLines(std::vector<std::string>* lines, std::vector<int>* linesOffsetX, int* numChars){
43  int lineLength = 0;
44  std::string curLine = "";
45  std::string word = "";
46  int wordLength = 0;
47  for(unsigned char c : text){
48  if (c > ' ' && c < 128){ // visible characters
49  wordLength += font->getCharacter(c).advanceX/64;
50  word += c;
51  (*numChars)++;
52  } else if (c == ' '){
53  if (lineLength + wordLength > width){
54  lines->push_back(curLine);
55  linesOffsetX->push_back(getOffsetByLineLength(lineLength));
56  curLine = word;
57  lineLength = wordLength;
58  } else {
59  curLine += " " + word;
60  lineLength += font->getCharacter(' ').advanceX/64 + wordLength;
61  }
62  word = "";
63  wordLength = 0;
64  } else if (c == '\r'){
65  if (lineLength + wordLength > width){
66  lines->push_back(curLine);
67  linesOffsetX->push_back(getOffsetByLineLength(lineLength));
68  curLine = word;
69  lineLength = wordLength;
70  } else {
71  curLine += " " + word;
72  lineLength += font->getCharacter(' ').advanceX/64 + wordLength;
73  }
74  lines->push_back(curLine);
75  linesOffsetX->push_back(getOffsetByLineLength(lineLength));
76  curLine = "";
77  lineLength = 0;
78  word = "";
79  wordLength = 0;
80  }
81  }
82  if (lineLength + wordLength > width){
83  lines->push_back(curLine);
84  linesOffsetX->push_back(getOffsetByLineLength(lineLength));
85  curLine = word;
86  lineLength = wordLength;
87  } else {
88  curLine += " " + word;
89  lineLength += font->getCharacter(' ').advanceX/64 + wordLength;
90  }
91  lines->push_back(curLine);
92  linesOffsetX->push_back(getOffsetByLineLength(lineLength));
93 }
94 
95 int TextObject::getOffsetByLineLength(int lineLength) {
96  return (width-lineLength)/2;
97 }
98 
99 void TextObject::init(std::vector<std::string> lines, std::vector<int> linesOffsetX, int numChars) {
100 
101  int x = -width/2;//this->x;
102  int y = height/2 - font->getPixelSize();
103  std::vector<GLfloat> data;
104  int i = 0;
105  float atlasWidth = Globals::get(Globals::FONT_TEXTURE_WIDTH),
106  atlasHeight = Globals::get(Globals::FONT_TEXTURE_HEIGHT);
107  Font::GlyphData gData;
108  int l = 0;
109  for(std::string line : lines) {
110  int lox = linesOffsetX[l++];
111  for (unsigned char c : line) {
112  if (c >= 32) {
113  gData = font->getCharacter(c);
114  float x2 = x + gData.bitmapLeft + lox;
115  float y2 = -y - gData.bitmapTop;
116  float w = gData.bitmapWidth;
117  float h = gData.bitmapHeight;
118  float ox = gData.offsetX;
119 
120  /* Advance the cursor to the start of the next character */
121  x += gData.advanceX / 64;
122  y += gData.advanceY / 64;
123 
124  /* Skip glyphs that have no pixels */
125  if (!w || !h)
126  continue;
127 
128  // Each vertex: posX,posY,posZ,textureX,textureY
129  addPoints(&data, {x2 + w, -y2 , 0, (ox + w) / atlasWidth, 0});
130  addPoints(&data, {x2 , -y2 , 0, ox / atlasWidth , 0});
131  addPoints(&data, {x2 , -y2 - h, 0, ox / atlasWidth , h / atlasHeight});
132  addPoints(&data, {x2 + w, -y2 , 0, (ox + w) / atlasWidth, 0});
133  addPoints(&data, {x2 , -y2 - h, 0, ox / atlasWidth , h / atlasHeight});
134  addPoints(&data, {x2 + w, -y2 - h, 0, (ox + w) / atlasWidth, h / atlasHeight});
135  i += 6*5;
136  }
137  }
138  y -= font->getPixelSize();
139  x = -width/2;
140  }
141  numVertices = i/5;
142 
143  initAndBindBuffers();
144  glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(), GL_STATIC_DRAW);
145 
146  glEnableVertexAttribArray(0);
147  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), 0);
148 
149  glEnableVertexAttribArray(1);
150  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(GLfloat)));
151 
152  // CLEANUP
153  glBindVertexArray(0);
154  CHECK_GL_ERROR();
155 
156 }
157 
158 void TextObject::addPoints(std::vector<GLfloat> *data, std::initializer_list<float> elems) {
159  for(float elem : elems) {
160  data->push_back(elem);
161  }
162 }
163 
164 void TextObject::initAndBindBuffers() {
165 
166  if (buffersInitiated){
167  glBindVertexArray(vao);
168  glBindBuffer(GL_ARRAY_BUFFER,vbo);
169  } else {
170  glGenVertexArrays(1, &vao);
171  glBindVertexArray(vao);
172 
173  glGenBuffers(1, &vbo);
174  glBindBuffer(GL_ARRAY_BUFFER, vbo);
175  }
176 
177 }
178 
179 void TextObject::render(ShaderProgram *shaderProgram, chag::float4x4 *projectionMatrix) {
180 
181  GLint currentDepthFunc;
182  glGetIntegerv(GL_DEPTH_FUNC, &currentDepthFunc);
183 
184  glDepthFunc(GL_ALWAYS);
185  glEnable(GL_BLEND);
186  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
187 
188  shaderProgram->backupCurrentShaderProgram();
189 
190  shaderProgram->use();
191  glBindVertexArray(vao);
192 
193  shaderProgram->setUniform1i("sprite", 4);
194  shaderProgram->setUniformMatrix4fv("modelMatrix", getModelMatrix());
195  shaderProgram->setUniformMatrix4fv("projectionMatrix",*projectionMatrix);
196  shaderProgram->setUniform1i("isTexture",false);
197  shaderProgram->setUniform1i("isColor",false);
198  shaderProgram->setUniform1i("isFont",true);
199 
200  glActiveTexture(GL_TEXTURE4);
201  glBindTexture(GL_TEXTURE_2D,*FontManager::getInstance()->getTex());
202 
203  glDrawArrays(GL_TRIANGLES, 0, numVertices);
204 
205  CHECK_GL_ERROR();
206 
207  glDepthFunc(currentDepthFunc);
208  glDisable(GL_BLEND);
209 
210  glEnable(GL_CULL_FACE);
211  shaderProgram->restorePreviousShaderProgram();
212 
213 }
214 
215 chag::float4x4 TextObject::getModelMatrix() {
216  chag::float3 originalPosition = chag::make_vector((float)x + width / 2, (float)y - height /2, 0.0f) - center;
217  return chag::make_translation(originalPosition + relativePosition)
218  * chag::make_rotation_z<chag::float4x4>(rotation)
219  * chag::make_scale<chag::float4x4>(scale)
220  * chag::make_translation(center)
221  * chag::make_identity<chag::float4x4>();
222 }
TextObject(std::string text, Font *font, int width, int height, int x, int y)
Definition: TextObject.cpp:26
Definition: Font.h:27
void restorePreviousShaderProgram()
Class for maintaining OpenGL shader programs.
Definition: ShaderProgram.h:39
virtual void setText(std::string text)
Definition: TextObject.cpp:31
static FontManager * getInstance()
Definition: FontManager.cpp:64
virtual void render(ShaderProgram *shaderProgram, chag::float4x4 *projectionMatrix)
Definition: TextObject.cpp:179
void backupCurrentShaderProgram()