text3d.cpp 10.3 KB
Newer Older
1 2 3
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
* version 0.1                                                                  *
4
* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg           *
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
*                                                                              *
* This library is free software; you can redistribute it and/or modify it      *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your     *
* option) any later version.                                                   *
*                                                                              *
* This library 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 Lesser General Public License  *
* for more details.                                                            *
*                                                                              *
* You should have received a copy of the GNU Lesser General Public License     *
* along with this library; if not, write to the Free Software Foundation,      *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.           *
*                                                                              *
20
* Web site: http://cgogn.unistra.fr/                                           *
21 22 23
* Contact information: cgogn@unistra.fr                                        *
*                                                                              *
*******************************************************************************/
Sylvain Thery's avatar
Sylvain Thery committed
24
#define CGoGN_UTILS_DLL_EXPORT 1
25
#include "Utils/text3d.h"
Thery Sylvain's avatar
Thery Sylvain committed
26
#include "Utils/vbo_base.h"
27
#include "Utils/svg.h"
Thery Sylvain's avatar
Thery Sylvain committed
28
#include "Utils/gzstream.h"
29

Sylvain Thery's avatar
Sylvain Thery committed
30 31 32
#include <algorithm>


33 34
namespace CGoGN
{
Pierre Kraemer's avatar
Pierre Kraemer committed
35

36 37
namespace Utils
{
38 39 40
#include "text3d.vert"
#include "text3d.frag"

41 42

std::string Strings3D::fragmentShaderText2 =
43
"	if (lum == 0.0) discard;\n FRAG_OUT = color*lum;\n}";
44 45

std::string Strings3D::fragmentShaderText3 =
46
"	FRAG_OUT = mix(backColor,color,lum);\n}";
47

Pierre Kraemer's avatar
Pierre Kraemer committed
48

49
Strings3D* Strings3D::m_instance0 = NULL;
50

Pierre Kraemer's avatar
Pierre Kraemer committed
51

Sylvain's avatar
Sylvain committed
52
Strings3D::Strings3D(bool withBackground, const Geom::Vec3f& bgc, bool with_plane) : m_nbChars(0),m_scale(1.0f)
53
{
54
	if (m_instance0 == NULL)
55
	{
56
		m_instance0 = this;
57
		std::string font_filename = Utils::GLSLShader::findFile("font_cgogn.gz");
58 59 60 61
		igzstream fs(font_filename.c_str(), std::ios::in|std::ios::binary);
		char* buff = new char[WIDTHTEXTURE*HEIGHTTEXTURE];
		fs.read(reinterpret_cast<char*>(buff), WIDTHTEXTURE*HEIGHTTEXTURE );
		fs.close();
62
		
63 64
		glGenTextures(1, &(*m_idTexture));
		glBindTexture(GL_TEXTURE_2D, *m_idTexture);
65
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, WIDTHTEXTURE, HEIGHTTEXTURE, 0, GL_RED,  GL_UNSIGNED_BYTE, (GLvoid*)(buff));
66 67
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
68 69 70
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
71
		delete[] buff;
72
	}
73 74
	else
	{
75
		*m_idTexture = *(m_instance0->m_idTexture);
76
	}
77

78
	std::string glxvert(GLSLShader::defines_gl());
Sylvain's avatar
Sylvain committed
79
	if (with_plane)
Sylvain Thery's avatar
Sylvain Thery committed
80
		glxvert.append("#define WITH_PLANE 1");
81 82
	glxvert.append(vertexShaderText);

83

84
	std::string glxfrag(GLSLShader::defines_gl());
85 86 87
	glxfrag.append(fragmentShaderText1);

	if (!withBackground)
88 89 90 91
	{
		glxfrag.append(fragmentShaderText2);
	}
	else
92 93
	{
		std::stringstream ss;
94
		ss << "    vec4 backColor = vec4(" <<bgc[0] << "," << bgc[1] << "," << bgc[2] << ",color[3]);\n";
95 96
		glxfrag.append(ss.str());
		glxfrag.append(fragmentShaderText3);
97
	}
98

99 100
	std::cout << glxfrag << std::endl;

101
	loadShadersFromMemory(glxvert.c_str(), glxfrag.c_str());
102

103 104 105 106 107 108
	m_vbo1 = new Utils::VBO();
	m_vbo1->setDataSize(4);

	bindVA_VBO("VertexPosition", m_vbo1);

	bind();
109 110 111 112 113
	*m_uniform_position = glGetUniformLocation(program_handler(), "strPos");
	*m_uniform_color = glGetUniformLocation(program_handler(), "color");
	*m_uniform_scale = glGetUniformLocation(program_handler(), "scale");
	*m_uniform_texture = glGetUniformLocation(program_handler(), "FontTexture");
	glUniform1f(*m_uniform_scale, 1.0f);
Sylvain's avatar
Sylvain committed
114 115 116 117 118
	if (with_plane)
	{
		*m_uniform_planeX = glGetUniformLocation(program_handler(), "planeX");
		*m_uniform_planeY = glGetUniformLocation(program_handler(), "planeY");
	}
119
	unbind();
Sylvain Thery's avatar
Sylvain Thery committed
120 121

	m_color = Geom::Vec4f(0.0f,0.0f,0.0f,1.0f);
122
}
123 124 125

void Strings3D::setScale(float scale)
{
126
	bind();
127
	glUniform1f(*m_uniform_scale, scale);
128
	m_scale = scale;
129
	unbind();
130 131
}

Sylvain Thery's avatar
Sylvain Thery committed
132
void Strings3D::setPlane(const Geom::Vec3f& ox, const Geom::Vec3f& oy)
Sylvain's avatar
Sylvain committed
133 134
{
	bind();
Sylvain Thery's avatar
Sylvain Thery committed
135 136
	glUniform3fv(*m_uniform_planeX, 1, ox.data());
	glUniform3fv(*m_uniform_planeY, 1, oy.data());
Sylvain's avatar
Sylvain committed
137 138 139
	unbind();
}

140 141 142 143
Strings3D::~Strings3D()
{
}

144 145 146 147 148 149 150 151
void Strings3D::clear()
{
	m_nbChars=0;
	m_strings.clear();
	m_strTranslate.clear();
	m_strpos.clear();
}

152 153
unsigned int Strings3D::addString(const std::string& str)
{
154
	unsigned int id = uint32(m_strings.size());
155
	m_strings.push_back(str);
156
	m_nbChars += uint32(str.length());
157 158 159 160 161
	return id;
}

unsigned int Strings3D::addString(const std::string& str, const Geom::Vec3f& pos)
{
162
	unsigned int id = uint32(m_strings.size());
163
	m_strings.push_back(str);
164
	m_nbChars += uint32(str.length());
165 166 167 168 169 170
	m_strTranslate.push_back(pos);
	return id;
}

unsigned int Strings3D::sendOneStringToVBO(const std::string& str, float **buffervbo)
{
171
	unsigned int nbc = uint32(str.length());
172

Pierre Kraemer's avatar
Pierre Kraemer committed
173
	float x = 0.0f;
174 175 176

	float* buffer = *buffervbo;

Pierre Kraemer's avatar
Pierre Kraemer committed
177
	for(unsigned int j = 0; j < nbc; ++j)
178 179
	{
		unsigned int ci = str[j]-32;
Pierre Kraemer's avatar
Pierre Kraemer committed
180 181 182 183
		float u  = float(ci % CHARSPERLINE) / float(CHARSPERLINE);
		float v  = float(ci / CHARSPERLINE) / float(CHARSPERCOL) + 1.0f / HEIGHTTEXTURE;
		float u2 = u + float(REALWIDTHFONT) / float(WIDTHTEXTURE);
		float v2 = v + float(WIDTHFONT - 1) / float(HEIGHTTEXTURE);
184

185
		// 0
186 187 188 189 190
		*buffer++ = x;
		*buffer++ = 0;
		*buffer++ = u;
		*buffer++ = v2;

Pierre Kraemer's avatar
Pierre Kraemer committed
191
		float xf = x + float(REALWIDTHFONT) / 25.f;
192

193
		// 1
194 195 196 197 198
		*buffer++ = xf;
		*buffer++ = 0;
		*buffer++ = u2;
		*buffer++ = v2;

199 200 201 202 203 204 205 206 207 208 209 210 211
		// 2
		*buffer++ = xf;
		*buffer++ = float(WIDTHFONT) / 25.f;
		*buffer++ = u2;
		*buffer++ = v;

		// 0
		*buffer++ = x;
		*buffer++ = 0;
		*buffer++ = u;
		*buffer++ = v2;

		// 2
212
		*buffer++ = xf;
Pierre Kraemer's avatar
Pierre Kraemer committed
213
		*buffer++ = float(WIDTHFONT) / 25.f;
214 215 216
		*buffer++ = u2;
		*buffer++ = v;

217
		// 3
218
		*buffer++ = x;
Pierre Kraemer's avatar
Pierre Kraemer committed
219
		*buffer++ = float(WIDTHFONT) / 25.f;
220 221 222 223 224 225 226 227
		*buffer++ = u;
		*buffer++ = v;

		x = xf; // + space ?
	}

	*buffervbo = buffer;

228
	return 6 * nbc;
229 230 231 232 233 234 235
}

void Strings3D::sendToVBO()
{
	// send coord / texcoord of strings

	// alloc buffer
236
	m_vbo1->bind();
237
	glBufferData(GL_ARRAY_BUFFER, m_nbChars * 24 * sizeof(float), 0, GL_STREAM_DRAW);
Pierre Kraemer's avatar
Pierre Kraemer committed
238
	float* buffer = reinterpret_cast<float*>(glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE));
239 240

	// fill buffer
Pierre Kraemer's avatar
Pierre Kraemer committed
241
	unsigned int pos = 0; // pos of first index in vbo for current string
242
	unsigned int nbw = uint32(m_strings.size());
Pierre Kraemer's avatar
Pierre Kraemer committed
243
	for (unsigned int i = 0; i < nbw; ++i)
244 245
	{
		unsigned int nb = sendOneStringToVBO(m_strings[i], &buffer);
Pierre Kraemer's avatar
Pierre Kraemer committed
246
		m_strpos.push_back(std::pair<unsigned int, unsigned int>(pos, nb));
247 248 249
		pos += nb;
	}

250
	glUnmapBuffer(GL_ARRAY_BUFFER);
251 252
}

253
void Strings3D::predraw(const Geom::Vec4f& color)
254
{
255
	m_color = color;
256
	bind();
257
	glUniform1i(*m_uniform_texture, 0);
258
	glUniform4fv(*m_uniform_color, 1, color.data());
259

260
	glActiveTexture(GL_TEXTURE0);
261
	glBindTexture(GL_TEXTURE_2D, *m_idTexture);
262 263 264 265
	glEnable(GL_TEXTURE_2D);

	glDisable(GL_LIGHTING);

266
	enableVertexAttribs();
267 268
}

269
void Strings3D::changeColor(const Geom::Vec4f& color)
270
{
271
	m_color = color;
272
	bind();
273 274 275 276 277 278 279 280
	glUniform4fv(*m_uniform_color, 1, color.data());
}

void Strings3D::changeOpacity(float op)
{
	m_color[3] = op;
	bind();
	glUniform4fv(*m_uniform_color, 1, m_color.data());
281 282
}

283 284
void Strings3D::postdraw()
{
285 286
	disableVertexAttribs();
	unbind();
287 288 289 290
}

void Strings3D::draw(unsigned int idSt, const Geom::Vec3f& pos)
{
291
	glUniform3fv(*m_uniform_position, 1, pos.data());
292
	glDrawArrays(GL_TRIANGLES, m_strpos[idSt].first , m_strpos[idSt].second );
293 294
}

295
void Strings3D::drawAll(const Geom::Vec4f& color)
296
{
297
	m_color = color;
298
	unsigned int nb = uint32(m_strpos.size());
Sylvain's avatar
Sylvain committed
299 300 301 302
	//  nothing to do if no string !
	if (nb == 0)
		return;

303 304 305
	predraw(color);
	if (m_strpos.size() != m_strTranslate.size())
	{
306
		CGoGNerr << "Strings3D: for drawAll use exclusively addString with position"<< CGoGNendl;
307 308
		return;
	}
Sylvain's avatar
Sylvain committed
309
		
310 311
	for (unsigned int idSt=0; idSt<nb; ++idSt)
	{
312
		glUniform3fv(*m_uniform_position, 1, m_strTranslate[idSt].data());
313
		glDrawArrays(GL_TRIANGLES, m_strpos[idSt].first , m_strpos[idSt].second );
314 315 316 317
	}
	postdraw();
}

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
void Strings3D::updateString(unsigned int idSt, const std::string& str)
{
	unsigned int firstIndex = m_strpos[idSt].first;
	unsigned int nbIndices = m_strpos[idSt].second;

	unsigned int nbc = std::min((unsigned int)(str.length()), nbIndices/4);


	m_vbo1->bind();
	float* buffer = reinterpret_cast<float*>(glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE));

	buffer += firstIndex*4;
	float x = 0.0f;
	for(unsigned int j = 0; j < nbc; ++j)
	{
		unsigned int ci = str[j]-32;
		float u  = float(ci % CHARSPERLINE) / float(CHARSPERLINE);
		float v  = float(ci / CHARSPERLINE) / float(CHARSPERCOL) + 1.0f / HEIGHTTEXTURE;
		float u2 = u + float(REALWIDTHFONT) / float(WIDTHTEXTURE);
		float v2 = v + float(WIDTHFONT - 1) / float(HEIGHTTEXTURE);

339
		// 0
340 341 342 343 344 345
		*buffer++ = x;
		*buffer++ = 0;
		*buffer++ = u;
		*buffer++ = v2;

		float xf = x + float(REALWIDTHFONT) / 25.f;
346
		// 1
347 348 349 350 351
		*buffer++ = xf;
		*buffer++ = 0;
		*buffer++ = u2;
		*buffer++ = v2;

352 353 354 355 356 357 358 359 360 361 362 363 364
		// 2
		*buffer++ = xf;
		*buffer++ = float(WIDTHFONT) / 25.f;
		*buffer++ = u2;
		*buffer++ = v;

		// 0
		*buffer++ = x;
		*buffer++ = 0;
		*buffer++ = u;
		*buffer++ = v2;

		// 2
365 366 367 368 369
		*buffer++ = xf;
		*buffer++ = float(WIDTHFONT) / 25.f;
		*buffer++ = u2;
		*buffer++ = v;

370
		// 3
371 372 373 374 375 376 377 378 379 380 381 382
		*buffer++ = x;
		*buffer++ = float(WIDTHFONT) / 25.f;
		*buffer++ = u;
		*buffer++ = v;

		x = xf; // + space ?
	}
	glUnmapBuffer(GL_ARRAY_BUFFER);
}



383 384
void Strings3D::toSVG(Utils::SVG::SVGOut& svg)
{
385 386
	Utils::SVG::SvgGroup* svg1 = new Utils::SVG::SvgGroup("strings3D", svg.m_model, svg.m_proj);
	svg1->beginStrings(m_scale);
387
	unsigned int nb = uint32(m_strings.size());
388
	for(unsigned int i=0; i<nb; ++i)
389 390 391 392
		svg1->addString(m_strTranslate[i],m_strings[i]);
	svg1->endStrings();

	svg.addGroup(svg1);
393 394
}

Pierre Kraemer's avatar
Pierre Kraemer committed
395
} // namespace Utils
396

Pierre Kraemer's avatar
Pierre Kraemer committed
397
} // namespace CGoGN