00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #ifdef _MSC_VER
00040 # pragma warning (disable: 4786)
00041 #endif
00042
00043 #include "OSGTextVectorGlyph.h"
00044
00045 #include <OSGGLU.h>
00046
00047 #ifdef __sgi
00048 # include <assert.h>
00049 # include <math.h>
00050 #else
00051 # include <cassert>
00052 # include <cmath>
00053 #endif
00054
00055
00056 using namespace std;
00057
00058
00059 OSG_BEGIN_NAMESPACE
00060
00061
00062
00063
00064
00065
00066 TextVectorGlyph::~TextVectorGlyph() {}
00067
00068
00069
00070
00071
00072
00073 Real32 TextVectorGlyph::getWidth() const
00074 { return _width; }
00075
00076
00077
00078
00079
00080
00081 Real32 TextVectorGlyph::getHeight() const
00082 { return _height; }
00083
00084
00085
00086
00087
00088
00089 Real32 TextVectorGlyph::getHoriBearingX() const
00090 { return _horiBearingX; }
00091
00092
00093
00094
00095
00096
00097 Real32 TextVectorGlyph::getHoriBearingY() const
00098 { return _horiBearingY; }
00099
00100
00101
00102
00103
00104
00105 Real32 TextVectorGlyph::getVertBearingX() const
00106 { return _vertBearingX; }
00107
00108
00109
00110
00111
00112
00113 Real32 TextVectorGlyph::getVertBearingY() const
00114 { return _vertBearingY; }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126 static void evalCubicBezierCurve(const Vec2f &pt1, const Vec2f &pt2, const Vec2f &pt3, const Vec2f &pt4,
00127 const UInt32 level, vector<Vec2f> &coords)
00128 {
00129
00130 const UInt32 knotsPerLevel = 3;
00131
00132 const UInt32 steps = knotsPerLevel * (level + 1) - 1;
00133
00134 const Real32 h = 1.0f / steps;
00135 const Real32 hh = h * h;
00136 const Real32 hhh = h * hh;
00137
00138
00139
00140 Vec2f f = pt1;
00141 Vec2f df = (pt2 - pt1) * 3.0f * h;
00142
00143 Vec2f ddf_div_2 = (pt1 - pt2 * 2.0f + pt3) * 3.0f * hh;
00144 Vec2f ddf = ddf_div_2 + ddf_div_2;
00145
00146 const Vec2f dddf_div_2 = ((pt2 - pt3) * 3.0f + pt4 - pt1) * 3.0f * hhh;
00147 const Vec2f dddf = dddf_div_2 + dddf_div_2;
00148 const Vec2f dddf_div_6 = dddf_div_2 * (1.0f / 3.0f);
00149
00150
00151 UInt32 i;
00152 for (i = steps; i > 0; --i)
00153 {
00154 coords.push_back(f);
00155
00156
00157 f += df + ddf_div_2 + dddf_div_6;
00158 df += ddf + dddf_div_2;
00159 ddf += dddf;
00160 ddf_div_2 += dddf_div_2;
00161 }
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 static void evalQuadraticBezierCurve(const Vec2f &pt1, const Vec2f &pt2, const Vec2f &pt3,
00175 const UInt32 level, vector<Vec2f> &coords)
00176 {
00177 const UInt32 knotsPerLevel = 3;
00178
00179 const UInt32 steps = knotsPerLevel * (level + 1) - 1;
00180
00181 const Real32 h = 1.0f / steps;
00182 const Real32 hh = h * h;
00183
00184
00185 Vec2f f = pt1;
00186
00187
00188 Vec2f df = (pt2 - pt1) * 2.f * h;
00189
00190
00191 const Vec2f ddf_div_2 = (pt1 - pt2 * 2.f + pt3) * hh;
00192 const Vec2f ddf = ddf_div_2 + ddf_div_2;
00193
00194
00195 UInt32 i;
00196 for (i = steps; i > 0; --i)
00197 {
00198 coords.push_back(f);
00199
00200 f += df + ddf_div_2;
00201 df += ddf;
00202 }
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 static void evalBezierCurve(const TextVectorGlyph::Contour &contour, UInt32 &index,
00215 const UInt32 level,
00216 vector<Vec2f> &coords)
00217 {
00218 assert(index + 1 < contour.size());
00219 switch (contour[index + 1].type)
00220 {
00221
00222 case TextVectorGlyph::Point::PT_ON:
00223 assert(index < contour.size());
00224 coords.push_back(contour[index].pos);
00225 ++index;
00226 break;
00227
00228 case TextVectorGlyph::Point::PT_QUAD:
00229 assert(index + 2 < contour.size());
00230 evalQuadraticBezierCurve(contour[index].pos, contour[index + 1].pos, contour[index + 2].pos, level, coords);
00231 index += 2;
00232 break;
00233
00234 case TextVectorGlyph::Point::PT_CUBIC:
00235 assert(index + 3 < contour.size());
00236 evalCubicBezierCurve(contour[index].pos, contour[index + 1].pos, contour[index + 2].pos, contour[index + 3].pos, level, coords);
00237 index += 3;
00238 break;
00239 default:
00240 assert(false);
00241 break;
00242 }
00243 }
00244
00245
00246
00247
00248
00249
00250 static void OSG_APIENTRY gluTessBeginDataCB(GLenum type, void *polygonData)
00251 {
00252 TextVectorGlyph::PolygonOutline *outline = reinterpret_cast<TextVectorGlyph::PolygonOutline*>(polygonData);
00253 assert(outline != 0);
00254 outline->types.push_back(TextVectorGlyph::PolygonOutline::TypeIndex(type, 0));
00255 }
00256
00257
00258
00259
00260
00261
00262 static void OSG_APIENTRY gluTessEndDataCB(void *polygonData)
00263 {
00264 TextVectorGlyph::PolygonOutline *outline = reinterpret_cast<TextVectorGlyph::PolygonOutline*>(polygonData);
00265 assert(outline != 0);
00266 assert(outline->types.empty() == false);
00267 outline->types.back().second = outline->indices.size();
00268 }
00269
00270
00271
00272
00273
00274
00275
00276 static void OSG_APIENTRY gluTessVertexDataCB(void *vertexData, void *polygonData)
00277 {
00278 TextVectorGlyph::PolygonOutline *outline = reinterpret_cast<TextVectorGlyph::PolygonOutline*>(polygonData);
00279 #ifdef __sgi
00280
00281 char str[20];
00282 sprintf(str, "%p", vertexData);
00283 UInt64 value;
00284 sscanf(str, "%llx", &value);
00285 UInt32 coordIndex = UInt32(value);
00286 #else
00287 UInt32 coordIndex = (UInt32)vertexData;
00288 #endif
00289 assert(outline != 0);
00290 outline->indices.push_back(coordIndex);
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300 static void OSG_APIENTRY gluTessCombineDataCB(GLdouble coords[3], void *vertexData[4],
00301 GLfloat weight[4], void **outDatab,
00302 void *polygonData)
00303 {
00304 TextVectorGlyph::PolygonOutline *outline = reinterpret_cast<TextVectorGlyph::PolygonOutline*>(polygonData);
00305 assert(outDatab != 0);
00306 *outDatab = reinterpret_cast<void*>(outline->coords.size());
00307 assert(outline != 0);
00308 outline->coords.push_back(Vec2f(coords[0], coords[1]));
00309 }
00310
00311
00312
00313
00314
00315
00316
00317 const TextVectorGlyph::PolygonOutline &TextVectorGlyph::getLines(UInt32 level) const
00318 {
00319
00320
00321 PolygonOutlineMap::const_iterator it = _polygonOutlineMap.find(level);
00322 if (it != _polygonOutlineMap.end())
00323
00324 return it->second;
00325
00326
00327 PolygonOutline &newOutline = _polygonOutlineMap.insert(PolygonOutlineMap::value_type(level, PolygonOutline())).first->second;
00328
00329
00330 Outline::const_iterator oIt;
00331 for (oIt = _outline.begin(); oIt != _outline.end(); ++oIt)
00332 {
00333 UInt32 size = oIt->size();
00334 if (size > 0)
00335 {
00336 size -= 1;
00337 UInt32 index = 0;
00338 while (index < size)
00339 evalBezierCurve(*oIt, index, level, newOutline.coords);
00340 newOutline.contours.push_back(newOutline.coords.size());
00341 }
00342 }
00343
00344
00345
00346
00347 GLUtesselator *tess = gluNewTess();
00348 if (tess == 0)
00349 return newOutline;
00350
00351
00352 gluTessNormal(tess, 0.0, 0.0, 1.0);
00353
00354 gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
00355
00356
00357 gluTessCallback(tess,
00358 GLU_TESS_BEGIN_DATA,
00359 reinterpret_cast<OSGGLUfuncptr>(gluTessBeginDataCB));
00360 gluTessCallback(tess,
00361 GLU_TESS_END_DATA,
00362 reinterpret_cast<OSGGLUfuncptr>(gluTessEndDataCB));
00363 gluTessCallback(tess,
00364 GLU_TESS_COMBINE_DATA,
00365 reinterpret_cast<OSGGLUfuncptr>(gluTessCombineDataCB));
00366 gluTessCallback(tess,
00367 GLU_TESS_VERTEX_DATA,
00368 reinterpret_cast<OSGGLUfuncptr>(gluTessVertexDataCB));
00369
00370
00371 gluTessBeginPolygon(tess, &newOutline);
00372
00373 vector<UInt32>::const_iterator cIt;
00374 UInt32 coordIndex = 0;
00375 for (cIt = newOutline.contours.begin(); cIt != newOutline.contours.end(); ++cIt)
00376 {
00377
00378 gluTessBeginContour(tess);
00379
00380 while (coordIndex < *cIt)
00381 {
00382 GLdouble coords[3];
00383 assert(coordIndex < newOutline.coords.size());
00384 coords[0] = newOutline.coords[coordIndex].x();
00385 coords[1] = newOutline.coords[coordIndex].y();
00386 coords[2] = 0.f;
00387 gluTessVertex(tess, coords, reinterpret_cast<void*>(coordIndex++));
00388 }
00389
00390
00391 gluTessEndContour(tess);
00392 }
00393
00394
00395 gluTessEndPolygon(tess);
00396
00397
00398 gluDeleteTess(tess);
00399
00400 return newOutline;
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410 static Vec2f computeEdgeNormal(const Vec2f &a, const Vec2f &b, bool cw)
00411 {
00412 Vec2f d = b - a;
00413 d.normalize();
00414 return cw == true ? Vec2f(d.y(), -d.x()) : Vec2f(-d.y(), d.x());
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 const TextVectorGlyph::Normals &TextVectorGlyph::getNormals(UInt32 level) const
00426 {
00427
00428
00429 NormalMap::const_iterator it = _normalMap.find(level);
00430 if (it != _normalMap.end())
00431
00432 return it->second;
00433
00434
00435 Normals &normals = _normalMap.insert(NormalMap::value_type(level, Normals())).first->second;
00436
00437
00438
00439 const PolygonOutline &outline = getLines(level);
00440
00441
00442 if (_contourOrientations.empty())
00443 computeContourOrientations();
00444
00445 UInt32 start = 0, end, index = 0;
00446 vector<UInt32>::const_iterator iIt;
00447 vector<Orientation>::const_iterator oriIt = _contourOrientations.begin();
00448 for (iIt = outline.contours.begin(); iIt != outline.contours.end(); ++iIt, ++oriIt)
00449 {
00450 end = *iIt;
00451
00452 assert(end - 1 < outline.coords.size());
00453 assert(start < outline.coords.size());
00454 assert(oriIt != _contourOrientations.end());
00455 Vec2f prevEdgeNormal = computeEdgeNormal(outline.coords[end - 1],
00456 outline.coords[start],
00457 (*oriIt) == CW);
00458 while (index < end)
00459 {
00460 UInt32 nextIndex = index + 1;
00461 if (nextIndex >= end)
00462 nextIndex = start;
00463
00464 assert(index < outline.coords.size());
00465 assert(nextIndex < outline.coords.size());
00466 Vec2f nextEdgeNormal = computeEdgeNormal(outline.coords[index], outline.coords[nextIndex], (*oriIt) == CW);
00467 Vec2f meanEdgeNormal = prevEdgeNormal + nextEdgeNormal;
00468 meanEdgeNormal.normalize();
00469 Real32 edgeAngle = osgacos(osgabs(prevEdgeNormal.dot(nextEdgeNormal)));
00470 normals.push_back(VertexNormal(nextEdgeNormal, meanEdgeNormal, edgeAngle));
00471
00472
00473 prevEdgeNormal = nextEdgeNormal;
00474
00475 ++index;
00476 }
00477
00478 start = end;
00479 }
00480
00481 return normals;
00482 }
00483
00484
00485
00486
00487
00488
00489 const vector<TextVectorGlyph::Orientation> &TextVectorGlyph::getContourOrientations() const
00490 {
00491
00492 if (_contourOrientations.empty())
00493 computeContourOrientations();
00494 return _contourOrientations;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503 static bool isLeft(const Vec2f &a, const Vec2f &b, const Vec2f &point)
00504 {
00505
00506
00507 Vec2f n = computeEdgeNormal(a, b, false);
00508
00509 return n.dot(point - a) > 0.f;
00510 }
00511
00512
00513
00514
00515
00516
00517
00518
00519 static Int32 calcWindingNumber(const vector<Vec2f> &coords, UInt32 start, UInt32 end, const Vec2f &point)
00520 {
00521 Int32 windingNumber = 0;
00522 assert(end - 1 < coords.size());
00523 const Vec2f *prevPoint = &(coords[end - 1]);
00524 UInt32 i;
00525 for (i = start; i < end; ++i)
00526 {
00527 assert(i < coords.size());
00528 const Vec2f *curPoint = &(coords[i]);
00529 if (prevPoint->y() <= point.y())
00530 {
00531
00532 if (curPoint->y() > point.y())
00533 {
00534 if (isLeft(*prevPoint, *curPoint, point) == true)
00535 windingNumber++;
00536 }
00537 }
00538 else
00539 {
00540
00541 if (curPoint->y() < point.y())
00542 {
00543 if (isLeft(*prevPoint, *curPoint, point) == false)
00544 windingNumber--;
00545 }
00546 }
00547 prevPoint = curPoint;
00548 }
00549
00550 return windingNumber;
00551 }
00552
00553
00554
00555
00556
00557
00558 static bool isInteriorPoint(const Vec2f &point, const TextVectorGlyph::PolygonOutline &outline, GLenum windingRule)
00559 {
00560 Int32 totalWindingNumber = 0;
00561 UInt32 start = 0, end;
00562 vector<UInt32>::const_iterator it;
00563 for (it = outline.contours.begin(); it != outline.contours.end(); ++it)
00564 {
00565 end = *it;
00566 totalWindingNumber += calcWindingNumber(outline.coords, start, end, point);
00567 start = end;
00568 }
00569
00570 switch(windingRule)
00571 {
00572 case GLU_TESS_WINDING_NONZERO:
00573 return totalWindingNumber != 0;
00574 case GLU_TESS_WINDING_ODD:
00575 return totalWindingNumber % 2;
00576 default:
00577 return false;
00578 }
00579 }
00580
00581
00582
00583
00584
00585
00586 void TextVectorGlyph::computeContourOrientations() const
00587 {
00588
00589
00590 const PolygonOutline &outline = getLines(0);
00591 UInt32 start = 0, end;
00592 vector<UInt32>::const_iterator it;
00593 for (it = outline.contours.begin(); it != outline.contours.end(); ++it)
00594 {
00595 end = *it;
00596
00597
00598 if (end - start < 3)
00599 _contourOrientations.push_back(CCW);
00600
00601 assert(start + 2 < outline.coords.size());
00602 Vec2f en1 = computeEdgeNormal(outline.coords[start], outline.coords[start + 1], false);
00603 Vec2f en2 = computeEdgeNormal(outline.coords[start + 1], outline.coords[start + 2], false);
00604
00605 Vec2f testNormal = en1 + en2;
00606 testNormal.normalize();
00607
00608 Vec2f testPoint = outline.coords[start + 1] + testNormal * (1000.f * Eps);
00609
00610 if (isInteriorPoint(testPoint, outline, GLU_TESS_WINDING_NONZERO))
00611 _contourOrientations.push_back(CW);
00612 else
00613 _contourOrientations.push_back(CCW);
00614
00615 start = end;
00616 }
00617 }
00618
00619
00620 OSG_END_NAMESPACE
00621
00622
00623
00624
00625
00626 #ifdef OSG_SGI_CC
00627 #pragma set woff 1174
00628 #endif
00629
00630 #ifdef OSG_LINUX_ICC
00631 #pragma warning( disable : 177 )
00632 #endif
00633
00634 namespace
00635 {
00636 static OSG::Char8 cvsid_cpp[] = "@(#)$Id: OSGTextVectorGlyph.cpp,v 1.9 2005/04/25 11:45:24 jbehr Exp $";
00637 static OSG::Char8 cvsid_hpp[] = OSGTEXTVECTORGLYPH_HEADER_CVSID;
00638 static OSG::Char8 cvsid_inl[] = OSGTEXTVECTORGLYPH_INLINE_CVSID;
00639 }
00640
00641 #ifdef __sgi
00642 #pragma reset woff 1174
00643 #endif