1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
40 # pragma warning (disable: 4786)
43 #include "OSGTextVectorFace.h"
44 #include "OSGTextVectorGlyph.h"
45 #include "OSGTextLayoutResult.h"
46 #include "OSGTextFaceFactory.h"
47 #include "OSGTypedGeoIntegralProperty.h"
48 #include "OSGTypedGeoVectorProperty.h"
52 //----------------------------------------------------------------------
53 // Static Class Variable implementations:
55 //----------------------------------------------------------------------
56 TextVectorGlyph
TextVectorFace::_emptyGlyph
;
59 //----------------------------------------------------------------------
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);
75 //----------------------------------------------------------------------
76 // Returns information about a glyph.
78 //----------------------------------------------------------------------
79 const TextGlyph
&TextVectorFace::getGlyph(TextGlyph::Index glyphIndex
)
81 return getVectorGlyph(glyphIndex
);
85 //----------------------------------------------------------------------
86 // Returns information about a glyph.
88 //----------------------------------------------------------------------
89 const TextVectorGlyph
&TextVectorFace::getVectorGlyph(TextGlyph::Index glyphIndex
)
91 if (glyphIndex
== TextGlyph::INVALID_INDEX
)
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);
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)
109 // Put the glyph into the glyph cache
110 _glyphMap
.insert(GlyphMap::value_type(glyphIndex
, glyph
.get()));
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
,
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());
132 posPtr
= GeoPnt3fProperty::create();
133 geoPtr
->setPositions(posPtr
);
137 GeoVec3fPropertyUnrecPtr normalsPtr
=
138 dynamic_cast<GeoVec3fProperty
*>(geoPtr
->getNormals());
140 if (normalsPtr
== NULL
)
142 normalsPtr
= GeoVec3fProperty::create();
143 geoPtr
->setNormals(normalsPtr
);
148 GeoVec2fPropertyUnrecPtr texPtr
=
149 dynamic_cast<GeoVec2fProperty
*>(geoPtr
->getTexCoords());
153 texPtr
= GeoVec2fProperty::create();
154 geoPtr
->setTexCoords(texPtr
);
159 GeoUInt32PropertyUnrecPtr lensPtr
=
160 dynamic_cast<GeoUInt32Property
*>(geoPtr
->getLengths());
164 lensPtr
= GeoUInt32Property::create();
165 geoPtr
->setLengths(lensPtr
);
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
);
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
);
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
);
204 texCoordIndicesPtr
->clear();
206 GeoUInt8PropertyUnrecPtr typesPtr
=
207 dynamic_cast<GeoUInt8Property
*>(geoPtr
->getTypes());
209 if (typesPtr
== NULL
)
211 typesPtr
= GeoUInt8Property::create();
212 geoPtr
->setTypes(typesPtr
);
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();
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
));
240 // store the normal for the back face
241 normalsPtr
->push_back(Vec3f(0.f
, 0.f
, -1.f
));
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
;
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
);
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
295 // add the back face to the geometry
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
;
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
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
;
326 if (tIt
->first
== GL_TRIANGLE_FAN
)
331 if ((tIt
->first
== GL_TRIANGLE_STRIP
) && ((len
& 1) == 0))
333 OSG_ASSERT((indexEnd
>= 2) && (indexEnd
- 2 >= indexBegin
));
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
);
350 lensPtr
->push_back(len
);
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
;
388 contourCoordOffset
= backCoordOffset
;
389 contourBackCoordOffset
= coordOffset
;
394 // the side faces are stored as quads
395 GLenum mode
= GL_QUAD_STRIP
;
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
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);
417 coordIndex
= contourCoordOffset
+ index
;
418 backCoordIndex
= contourBackCoordOffset
+ index
;
424 coordIndex
= contourBackCoordOffset
+ index
;
425 backCoordIndex
= contourCoordOffset
+ index
;
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
);
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
));
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);
459 const Vec2f
&normal
= normals
[index
].meanEdgeNormal
;
460 normalsPtr
->push_back(Vec3f(normal
.x(), normal
.y(), 0.f
));
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
);
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
);
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
;
492 coordIndex
= contourBackCoordOffset
+ start
;
493 backCoordIndex
= contourCoordOffset
+ start
;
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
);
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
);
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
);
526 //----------------------------------------------------------------------
527 // Creates a new text geometry
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
);
539 //----------------------------------------------------------------------
540 // Creates a new node with a text geometry
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();
555 //----------------------------------------------------------------------
556 // Tries to create a vector face
558 //----------------------------------------------------------------------
559 TextVectorFaceTransitPtr
TextVectorFace::create(
560 const std::string
&family
, Style style
)
562 return TextFaceFactory::the()->createVectorFace(family
, style
);