fixed: gcc8 compile issues
[opensg.git] / Source / System / Text / OSGTextVectorFace.cpp
blobe46d6026914e419f9419473130a065f6c6fc5868
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
39 #ifdef _MSC_VER
40 # pragma warning (disable: 4786)
41 #endif
43 #include "OSGTextVectorFace.h"
44 #include "OSGTextVectorGlyph.h"
45 #include "OSGTextLayoutResult.h"
46 #include "OSGTextFaceFactory.h"
47 #include "OSGTypedGeoIntegralProperty.h"
48 #include "OSGTypedGeoVectorProperty.h"
50 OSG_BEGIN_NAMESPACE
52 //----------------------------------------------------------------------
53 // Static Class Variable implementations:
54 // Author: pdaehne
55 //----------------------------------------------------------------------
56 TextVectorGlyph TextVectorFace::_emptyGlyph;
59 //----------------------------------------------------------------------
60 // Destructor
61 // Author: pdaehne
62 //----------------------------------------------------------------------
63 TextVectorFace::~TextVectorFace(void)
65 // Delete all glyphs in the glyph cache
66 GlyphMap::iterator it;
67 for (it = _glyphMap.begin(); it != _glyphMap.end(); ++it)
69 OSG_ASSERT(it->second != 0);
70 delete it->second;
75 //----------------------------------------------------------------------
76 // Returns information about a glyph.
77 // Author: pdaehne
78 //----------------------------------------------------------------------
79 const TextGlyph &TextVectorFace::getGlyph(TextGlyph::Index glyphIndex)
81 return getVectorGlyph(glyphIndex);
85 //----------------------------------------------------------------------
86 // Returns information about a glyph.
87 // Author: pdaehne
88 //----------------------------------------------------------------------
89 const TextVectorGlyph &TextVectorFace::getVectorGlyph(TextGlyph::Index glyphIndex)
91 if (glyphIndex == TextGlyph::INVALID_INDEX)
92 return _emptyGlyph;
94 // Try to find the glyph in the map of glyphs
95 GlyphMap::const_iterator it = _glyphMap.find(glyphIndex);
96 if (it != _glyphMap.end())
98 OSG_ASSERT(it->second != 0);
99 return *(it->second);
102 // We did not find the glyph, so we have to create it
103 unique_ptr<TextVectorGlyph> glyph = createGlyph(glyphIndex);
105 // We could not create the glyph, return 0
106 if (glyph.get() == 0)
107 return _emptyGlyph;
109 // Put the glyph into the glyph cache
110 _glyphMap.insert(GlyphMap::value_type(glyphIndex, glyph.get()));
112 // Return the glyph
113 return *(glyph.release());
117 //----------------------------------------------------------------------
118 // Fills a geometry with a new text
119 // Author: afischle, pdaehne
120 //----------------------------------------------------------------------
121 void TextVectorFace::fillGeo(Geometry *geoPtr, const TextLayoutResult &layoutResult,
122 Real32 scale, Real32 depth, UInt32 level,
123 Real32 creaseAngle)
125 // cast the field containers down to the needed type and create them
126 // when they have the wrong type
127 GeoPnt3fPropertyUnrecPtr posPtr =
128 dynamic_cast<GeoPnt3fProperty *>(geoPtr->getPositions());
130 if (posPtr == NULL)
132 posPtr = GeoPnt3fProperty::create();
133 geoPtr->setPositions(posPtr);
135 else
136 posPtr->clear();
137 GeoVec3fPropertyUnrecPtr normalsPtr =
138 dynamic_cast<GeoVec3fProperty *>(geoPtr->getNormals());
140 if (normalsPtr == NULL)
142 normalsPtr = GeoVec3fProperty::create();
143 geoPtr->setNormals(normalsPtr);
145 else
146 normalsPtr->clear();
148 GeoVec2fPropertyUnrecPtr texPtr =
149 dynamic_cast<GeoVec2fProperty *>(geoPtr->getTexCoords());
151 if (texPtr == NULL)
153 texPtr = GeoVec2fProperty::create();
154 geoPtr->setTexCoords(texPtr);
156 else
157 texPtr->clear();
159 GeoUInt32PropertyUnrecPtr lensPtr =
160 dynamic_cast<GeoUInt32Property *>(geoPtr->getLengths());
162 if (lensPtr == NULL)
164 lensPtr = GeoUInt32Property::create();
165 geoPtr->setLengths(lensPtr);
167 else
168 lensPtr->clear();
170 GeoUInt32PropertyUnrecPtr posIndicesPtr =
171 dynamic_cast<GeoUInt32Property *>(
172 geoPtr->getIndex(Geometry::PositionsIndex));
174 if (posIndicesPtr == NULL)
176 posIndicesPtr = GeoUInt32Property::create();
177 geoPtr->setIndex(posIndicesPtr, Geometry::PositionsIndex);
179 else
180 posIndicesPtr->clear();
182 GeoUInt32PropertyUnrecPtr normalIndicesPtr =
183 dynamic_cast<GeoUInt32Property *>(
184 geoPtr->getIndex(Geometry::NormalsIndex));
186 if (normalIndicesPtr == NULL)
188 normalIndicesPtr = GeoUInt32Property::create();
189 geoPtr->setIndex(normalIndicesPtr, Geometry::NormalsIndex);
191 else
192 normalIndicesPtr->clear();
194 GeoUInt32PropertyUnrecPtr texCoordIndicesPtr =
195 dynamic_cast<GeoUInt32Property *>(
196 geoPtr->getIndex(Geometry::TexCoordsIndex));
198 if (texCoordIndicesPtr == NULL)
200 texCoordIndicesPtr = GeoUInt32Property::create();
201 geoPtr->setIndex(texCoordIndicesPtr, Geometry::TexCoordsIndex);
203 else
204 texCoordIndicesPtr->clear();
206 GeoUInt8PropertyUnrecPtr typesPtr =
207 dynamic_cast<GeoUInt8Property *>(geoPtr->getTypes());
209 if (typesPtr == NULL)
211 typesPtr = GeoUInt8Property::create();
212 geoPtr->setTypes(typesPtr);
214 else
215 typesPtr->clear();
217 geoPtr->setColors(NULL);
218 geoPtr->setSecondaryColors(NULL);
219 geoPtr->setTexCoords1(NULL);
220 geoPtr->setTexCoords2(NULL);
221 geoPtr->setTexCoords3(NULL);
223 UInt32 numGlyphs = layoutResult.getNumGlyphs();
224 if (numGlyphs == 0)
226 return;
229 // the interleaved multi-index blocks have the layout
230 // Position | Normal | TexCoord
232 geoPtr->getIndexMapping().push_back(Geometry::MapPosition);
233 geoPtr->getIndexMapping().push_back(Geometry::MapNormal);
234 geoPtr->getIndexMapping().push_back(Geometry::MapTexCoords);
237 // store the normal for the front face
238 normalsPtr->push_back(Vec3f(0.f, 0.f, 1.f));
239 if (depth > 0.f)
240 // store the normal for the back face
241 normalsPtr->push_back(Vec3f(0.f, 0.f, -1.f));
243 UInt32 i;
244 for (i = 0; i < numGlyphs; ++i)
246 const TextVectorGlyph &glyph = getVectorGlyph(layoutResult.indices[i]);
247 const TextVectorGlyph::PolygonOutline &outline = glyph.getLines(level);
248 const Vec2f &pos = layoutResult.positions[i];
250 // add the front face to the geometry
252 // store positions and texture coordinates
253 UInt32 coordOffset = posPtr->size32();
254 UInt32 texCoordOffset = texPtr->size32();
255 Real32 coordZ = 0.5f * depth;
256 vector<Vec2f>::const_iterator cIt;
257 for (cIt = outline.coords.begin(); cIt != outline.coords.end(); ++cIt)
259 Vec2f coord = *cIt + pos;
260 Vec2f texCoord = coord;
261 coord *= scale;
262 posPtr->push_back(Vec3f(coord.x(), coord.y(), coordZ));
263 texCoord -= layoutResult.positions.front();
264 texPtr->push_back(texCoord);
267 // Store types, lengths and indices
268 vector<TextVectorGlyph::PolygonOutline::TypeIndex>::const_iterator tIt;
269 UInt32 indexBegin = 0, indexEnd;
270 for (tIt = outline.types.begin(); tIt != outline.types.end(); ++tIt)
272 typesPtr->push_back(tIt->first);
273 indexEnd = tIt->second;
274 OSG_ASSERT(indexEnd >= indexBegin);
275 lensPtr->push_back(indexEnd - indexBegin);
276 UInt32 j;
277 for (j = indexBegin; j < indexEnd; ++j)
279 // the interleaved multi-index blocks have the layout
280 // Position | Normal | TexCoord
281 OSG_ASSERT(j < outline.indices.size());
282 UInt32 index = outline.indices[j];
283 OSG_ASSERT(coordOffset + index < posPtr->size());
284 posIndicesPtr->push_back(coordOffset + index);
285 normalIndicesPtr->push_back(0);
286 OSG_ASSERT(texCoordOffset + index < texPtr->size());
287 texCoordIndicesPtr->push_back(texCoordOffset + index);
289 indexBegin = indexEnd;
292 // add the back and side faces only if depth > 0
293 if (depth > 0.f)
295 // add the back face to the geometry
297 // store positions
298 // No need to store texture coordinates - we reuse the
299 // texture coordinates from the front side
300 UInt32 backCoordOffset = posPtr->size32();
301 coordZ = -0.5f * depth;
302 for (cIt = outline.coords.begin(); cIt != outline.coords.end(); ++cIt)
304 Vec2f coord = *cIt + pos;
305 coord *= scale;
306 posPtr->push_back(Vec3f(coord.x(), coord.y(), coordZ));
309 // Store types, lengths and indices
310 // We have to flip all triangles to enable correct backface culling.
311 // For GL_TRIANGLES, we simply flip the vertices.
312 // For GL_TRIANGLE_FANs, we leave the first vertex at its place and flip the
313 // remaining vertices.
314 // For GL_TRIANGLE_STRIPs, things are more complicated. When the number of
315 // vertices is uneven, we simply flip the vertices. When the number of
316 // vertices is even, we have to add an additional vertex before we flip the
317 // vertices.
318 // UInt32 indexBegin = 0, indexEnd;
319 for (tIt = outline.types.begin(); tIt != outline.types.end(); ++tIt)
321 typesPtr->push_back(tIt->first);
322 indexEnd = tIt->second;
323 OSG_ASSERT(indexEnd >= indexBegin);
324 UInt32 len = indexEnd - indexBegin;
325 UInt32 j = indexEnd;
326 if (tIt->first == GL_TRIANGLE_FAN)
328 j = indexBegin;
329 ++indexBegin;
331 if ((tIt->first == GL_TRIANGLE_STRIP) && ((len & 1) == 0))
333 OSG_ASSERT((indexEnd >= 2) && (indexEnd - 2 >= indexBegin));
334 j = indexEnd - 2;
335 ++len;
337 if (j != indexEnd)
339 // the interleaved multi-index blocks have the layout
340 // Position | Normal | TexCoord
341 OSG_ASSERT(j < outline.indices.size());
342 UInt32 index = outline.indices[j];
343 OSG_ASSERT(backCoordOffset + index < posPtr->size());
344 posIndicesPtr->push_back(backCoordOffset + index);
345 normalIndicesPtr->push_back(1);
346 OSG_ASSERT(texCoordOffset + index < texPtr->size());
347 texCoordIndicesPtr->push_back(texCoordOffset + index);
348 j = indexEnd;
350 lensPtr->push_back(len);
351 while (true)
353 if (j <= indexBegin)
354 break;
355 --j;
357 // the interleaved multi-index blocks have the layout
358 // Position | Normal | TexCoord
359 OSG_ASSERT(j < outline.indices.size());
360 UInt32 index = outline.indices[j];
361 OSG_ASSERT(backCoordOffset + index < posPtr->size());
362 posIndicesPtr->push_back(backCoordOffset + index);
363 normalIndicesPtr->push_back(1);
364 OSG_ASSERT(texCoordOffset + index < texPtr->size());
365 texCoordIndicesPtr->push_back(texCoordOffset + index);
367 indexBegin = indexEnd;
370 // Add the side faces to the geometry
371 const TextVectorGlyph::Normals &normals = glyph.getNormals(level);
373 // construct the multi index
374 UInt32 start = 0, end, index = 0;
375 vector<UInt32>::const_iterator iIt;
376 vector<TextVectorGlyph::Orientation>::const_iterator oriIt = glyph.getContourOrientations().begin();
377 for (iIt = outline.contours.begin(); iIt != outline.contours.end(); ++iIt, ++oriIt)
379 OSG_ASSERT(oriIt != glyph.getContourOrientations().end());
380 UInt32 contourCoordOffset, contourBackCoordOffset;
381 if (*oriIt == TextVectorGlyph::CCW)
383 contourCoordOffset = coordOffset;
384 contourBackCoordOffset = backCoordOffset;
386 else
388 contourCoordOffset = backCoordOffset;
389 contourBackCoordOffset = coordOffset;
392 end = *iIt;
394 // the side faces are stored as quads
395 GLenum mode = GL_QUAD_STRIP;
396 UInt32 len = 0;
398 UInt32 coordIndex, backCoordIndex;
399 UInt32 normalOffset, startNormalOffset = normalsPtr->size32();
400 for (index = start; index < end; ++index)
402 normalOffset = normalsPtr->size32() - 1;
403 OSG_ASSERT(index < normals.size());
404 if (normals[index].edgeAngle > creaseAngle)
406 // We have an edge with two normals, so we need to
407 // add the vertices twice, but with different normals
408 // - but only when this is not the start index
409 if (index > start)
411 if ((mode == GL_QUAD_STRIP) && (len > 2))
413 typesPtr->push_back(GL_QUAD_STRIP);
414 OSG_ASSERT(((len + 2) & 1) == 0);
415 lensPtr->push_back(len + 2);
416 len = 0;
417 coordIndex = contourCoordOffset + index;
418 backCoordIndex = contourBackCoordOffset + index;
420 else
422 mode = GL_QUADS;
423 len += 2;
424 coordIndex = contourBackCoordOffset + index;
425 backCoordIndex = contourCoordOffset + index;
428 // back
429 OSG_ASSERT(backCoordIndex < posPtr->size());
430 posIndicesPtr->push_back(backCoordIndex);
431 OSG_ASSERT(normalOffset < normalsPtr->size());
432 normalIndicesPtr->push_back(normalOffset);
433 OSG_ASSERT(texCoordOffset + index < texPtr->size());
434 texCoordIndicesPtr->push_back(texCoordOffset + index);
435 // front
436 OSG_ASSERT(coordIndex < posPtr->size());
437 posIndicesPtr->push_back(coordIndex);
438 OSG_ASSERT(normalOffset < normalsPtr->size());
439 normalIndicesPtr->push_back(normalOffset);
440 OSG_ASSERT(texCoordOffset + index < texPtr->size());
441 texCoordIndicesPtr->push_back(texCoordOffset + index);
444 const Vec2f &normal = normals[index].nextEdgeNormal;
445 normalsPtr->push_back(Vec3f(normal.x(), normal.y(), 0.f));
447 else
449 if (mode == GL_QUADS)
451 typesPtr->push_back(GL_QUADS);
452 mode = GL_QUAD_STRIP;
453 OSG_ASSERT(len >= 6);
454 OSG_ASSERT(((len - 2) & 3) == 0);
455 lensPtr->push_back(len - 2);
456 len = 2;
459 const Vec2f &normal = normals[index].meanEdgeNormal;
460 normalsPtr->push_back(Vec3f(normal.x(), normal.y(), 0.f));
462 ++normalOffset;
464 // back
465 OSG_ASSERT(contourBackCoordOffset + index < posPtr->size());
466 posIndicesPtr->push_back(contourBackCoordOffset + index);
467 OSG_ASSERT(normalOffset < normalsPtr->size());
468 normalIndicesPtr->push_back(normalOffset);
469 OSG_ASSERT(texCoordOffset + index < texPtr->size());
470 texCoordIndicesPtr->push_back(texCoordOffset + index);
471 // front
472 OSG_ASSERT(contourCoordOffset + index < posPtr->size());
473 posIndicesPtr->push_back(contourCoordOffset + index);
474 OSG_ASSERT(normalOffset < normalsPtr->size());
475 normalIndicesPtr->push_back(normalOffset);
476 OSG_ASSERT(texCoordOffset + index < texPtr->size());
477 texCoordIndicesPtr->push_back(texCoordOffset + index);
479 len += 2;
482 // We have to close the strip, so add the start vertices again
483 if (normals[start].edgeAngle <= creaseAngle)
484 normalOffset = startNormalOffset;
485 if (mode == GL_QUAD_STRIP)
487 coordIndex = contourCoordOffset + start;
488 backCoordIndex = contourBackCoordOffset + start;
490 else
492 coordIndex = contourBackCoordOffset + start;
493 backCoordIndex = contourCoordOffset + start;
496 // back
497 OSG_ASSERT(backCoordIndex < posPtr->size());
498 posIndicesPtr->push_back(backCoordIndex);
499 OSG_ASSERT(normalOffset < normalsPtr->size());
500 normalIndicesPtr->push_back(normalOffset);
501 OSG_ASSERT(texCoordOffset + start < texPtr->size());
502 texCoordIndicesPtr->push_back(texCoordOffset + start);
503 // front
504 OSG_ASSERT(coordIndex < posPtr->size());
505 posIndicesPtr->push_back(coordIndex);
506 OSG_ASSERT(normalOffset < normalsPtr->size());
507 normalIndicesPtr->push_back(normalOffset);
508 OSG_ASSERT(texCoordOffset + start < texPtr->size());
509 texCoordIndicesPtr->push_back(texCoordOffset + start);
511 len += 2;
513 // store the number of multi index blocks
514 typesPtr->push_back(mode);
515 OSG_ASSERT((mode != GL_QUADS) || ((len & 3) == 0));
516 OSG_ASSERT((mode != GL_QUAD_STRIP) || ((len & 1) == 0));
517 lensPtr->push_back(len);
519 start = end;
526 //----------------------------------------------------------------------
527 // Creates a new text geometry
528 // Author: pdaehne
529 //----------------------------------------------------------------------
530 GeometryTransitPtr TextVectorFace::makeGeo(const TextLayoutResult &layoutResult, Real32 scale,
531 Real32 depth, UInt32 level, Real32 creaseAngle)
533 GeometryTransitPtr geo = Geometry::create();
534 fillGeo(geo.get(), layoutResult, scale, depth, level, creaseAngle);
535 return geo;
539 //----------------------------------------------------------------------
540 // Creates a new node with a text geometry
541 // Author: pdaehne
542 //----------------------------------------------------------------------
543 NodeTransitPtr TextVectorFace::makeNode(const TextLayoutResult &layoutResult, Real32 scale,
544 Real32 depth, UInt32 level, Real32 creaseAngle)
546 GeometryTransitPtr geo = makeGeo(layoutResult, scale, depth, level, creaseAngle);
547 NodeTransitPtr node = Node::create();
549 node->setCore(geo);
551 return node;
555 //----------------------------------------------------------------------
556 // Tries to create a vector face
557 // Author: pdaehne
558 //----------------------------------------------------------------------
559 TextVectorFaceTransitPtr TextVectorFace::create(
560 const std::string &family, Style style)
562 return TextFaceFactory::the()->createVectorFace(family, style);
565 OSG_END_NAMESPACE