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
00280
00281 UInt64 coordIndexHelp = (UInt64)vertexData;
00282 UInt32 coordIndex = static_cast<UInt32>(coordIndexHelp);
00283
00284 assert(outline != 0);
00285 outline->indices.push_back(coordIndex);
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295 static void OSG_APIENTRY gluTessCombineDataCB(GLdouble coords[3], void *vertexData[4],
00296 GLfloat weight[4], void **outDatab,
00297 void *polygonData)
00298 {
00299 TextVectorGlyph::PolygonOutline *outline = reinterpret_cast<TextVectorGlyph::PolygonOutline*>(polygonData);
00300 assert(outDatab != 0);
00301 *outDatab = reinterpret_cast<void*>(outline->coords.size());
00302 assert(outline != 0);
00303 outline->coords.push_back(Vec2f(coords[0], coords[1]));
00304 }
00305
00306
00307
00308
00309
00310
00311
00312 const TextVectorGlyph::PolygonOutline &TextVectorGlyph::getLines(UInt32 level) const
00313 {
00314
00315
00316 PolygonOutlineMap::const_iterator it = _polygonOutlineMap.find(level);
00317 if (it != _polygonOutlineMap.end())
00318
00319 return it->second;
00320
00321
00322 PolygonOutline &newOutline = _polygonOutlineMap.insert(PolygonOutlineMap::value_type(level, PolygonOutline())).first->second;
00323
00324
00325 Outline::const_iterator oIt;
00326 for (oIt = _outline.begin(); oIt != _outline.end(); ++oIt)
00327 {
00328 UInt32 size = oIt->size();
00329 if (size > 0)
00330 {
00331 size -= 1;
00332 UInt32 index = 0;
00333 while (index < size)
00334 evalBezierCurve(*oIt, index, level, newOutline.coords);
00335 newOutline.contours.push_back(newOutline.coords.size());
00336 }
00337 }
00338
00339
00340
00341
00342 GLUtesselator *tess = gluNewTess();
00343 if (tess == 0)
00344 return newOutline;
00345
00346
00347 gluTessNormal(tess, 0.0, 0.0, 1.0);
00348
00349 gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
00350
00351
00352 gluTessCallback(tess,
00353 GLU_TESS_BEGIN_DATA,
00354 reinterpret_cast<OSGGLUfuncptr>(gluTessBeginDataCB));
00355 gluTessCallback(tess,
00356 GLU_TESS_END_DATA,
00357 reinterpret_cast<OSGGLUfuncptr>(gluTessEndDataCB));
00358 gluTessCallback(tess,
00359 GLU_TESS_COMBINE_DATA,
00360 reinterpret_cast<OSGGLUfuncptr>(gluTessCombineDataCB));
00361 gluTessCallback(tess,
00362 GLU_TESS_VERTEX_DATA,
00363 reinterpret_cast<OSGGLUfuncptr>(gluTessVertexDataCB));
00364
00365
00366 gluTessBeginPolygon(tess, &newOutline);
00367
00368 vector<UInt32>::const_iterator cIt;
00369 UInt32 coordIndex = 0;
00370 for (cIt = newOutline.contours.begin(); cIt != newOutline.contours.end(); ++cIt)
00371 {
00372
00373 gluTessBeginContour(tess);
00374
00375 while (coordIndex < *cIt)
00376 {
00377 GLdouble coords[3];
00378 assert(coordIndex < newOutline.coords.size());
00379 coords[0] = newOutline.coords[coordIndex].x();
00380 coords[1] = newOutline.coords[coordIndex].y();
00381 coords[2] = 0.f;
00382 gluTessVertex(tess, coords, reinterpret_cast<void*>(coordIndex++));
00383 }
00384
00385
00386 gluTessEndContour(tess);
00387 }
00388
00389
00390 gluTessEndPolygon(tess);
00391
00392
00393 gluDeleteTess(tess);
00394
00395 return newOutline;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405 static Vec2f computeEdgeNormal(const Vec2f &a, const Vec2f &b, bool cw)
00406 {
00407 Vec2f d = b - a;
00408 d.normalize();
00409 return cw == true ? Vec2f(d.y(), -d.x()) : Vec2f(-d.y(), d.x());
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420 const TextVectorGlyph::Normals &TextVectorGlyph::getNormals(UInt32 level) const
00421 {
00422
00423
00424 NormalMap::const_iterator it = _normalMap.find(level);
00425 if (it != _normalMap.end())
00426
00427 return it->second;
00428
00429
00430 Normals &normals = _normalMap.insert(NormalMap::value_type(level, Normals())).first->second;
00431
00432
00433
00434 const PolygonOutline &outline = getLines(level);
00435
00436
00437 if (_contourOrientations.empty())
00438 computeContourOrientations();
00439
00440 UInt32 start = 0, end, index = 0;
00441 vector<UInt32>::const_iterator iIt;
00442 vector<Orientation>::const_iterator oriIt = _contourOrientations.begin();
00443 for (iIt = outline.contours.begin(); iIt != outline.contours.end(); ++iIt, ++oriIt)
00444 {
00445 end = *iIt;
00446
00447 assert(end - 1 < outline.coords.size());
00448 assert(start < outline.coords.size());
00449 assert(oriIt != _contourOrientations.end());
00450 Vec2f prevEdgeNormal = computeEdgeNormal(outline.coords[end - 1],
00451 outline.coords[start],
00452 (*oriIt) == CW);
00453 while (index < end)
00454 {
00455 UInt32 nextIndex = index + 1;
00456 if (nextIndex >= end)
00457 nextIndex = start;
00458
00459 assert(index < outline.coords.size());
00460 assert(nextIndex < outline.coords.size());
00461 Vec2f nextEdgeNormal = computeEdgeNormal(outline.coords[index], outline.coords[nextIndex], (*oriIt) == CW);
00462 Vec2f meanEdgeNormal = prevEdgeNormal + nextEdgeNormal;
00463 meanEdgeNormal.normalize();
00464 Real32 edgeAngle = osgacos(osgabs(prevEdgeNormal.dot(nextEdgeNormal)));
00465 normals.push_back(VertexNormal(nextEdgeNormal, meanEdgeNormal, edgeAngle));
00466
00467
00468 prevEdgeNormal = nextEdgeNormal;
00469
00470 ++index;
00471 }
00472
00473 start = end;
00474 }
00475
00476 return normals;
00477 }
00478
00479
00480
00481
00482
00483
00484 const vector<TextVectorGlyph::Orientation> &TextVectorGlyph::getContourOrientations() const
00485 {
00486
00487 if (_contourOrientations.empty())
00488 computeContourOrientations();
00489 return _contourOrientations;
00490 }
00491
00492
00493
00494
00495
00496
00497
00498 static bool isLeft(const Vec2f &a, const Vec2f &b, const Vec2f &point)
00499 {
00500
00501
00502 Vec2f n = computeEdgeNormal(a, b, false);
00503
00504 return n.dot(point - a) > 0.f;
00505 }
00506
00507
00508
00509
00510
00511
00512
00513
00514 static Int32 calcWindingNumber(const vector<Vec2f> &coords, UInt32 start, UInt32 end, const Vec2f &point)
00515 {
00516 Int32 windingNumber = 0;
00517 assert(end - 1 < coords.size());
00518 const Vec2f *prevPoint = &(coords[end - 1]);
00519 UInt32 i;
00520 for (i = start; i < end; ++i)
00521 {
00522 assert(i < coords.size());
00523 const Vec2f *curPoint = &(coords[i]);
00524 if (prevPoint->y() <= point.y())
00525 {
00526
00527 if (curPoint->y() > point.y())
00528 {
00529 if (isLeft(*prevPoint, *curPoint, point) == true)
00530 windingNumber++;
00531 }
00532 }
00533 else
00534 {
00535
00536 if (curPoint->y() < point.y())
00537 {
00538 if (isLeft(*prevPoint, *curPoint, point) == false)
00539 windingNumber--;
00540 }
00541 }
00542 prevPoint = curPoint;
00543 }
00544
00545 return windingNumber;
00546 }
00547
00548
00549
00550
00551
00552
00553 static bool isInteriorPoint(const Vec2f &point, const TextVectorGlyph::PolygonOutline &outline, GLenum windingRule)
00554 {
00555 Int32 totalWindingNumber = 0;
00556 UInt32 start = 0, end;
00557 vector<UInt32>::const_iterator it;
00558 for (it = outline.contours.begin(); it != outline.contours.end(); ++it)
00559 {
00560 end = *it;
00561 totalWindingNumber += calcWindingNumber(outline.coords, start, end, point);
00562 start = end;
00563 }
00564
00565 switch(windingRule)
00566 {
00567 case GLU_TESS_WINDING_NONZERO:
00568 return totalWindingNumber != 0;
00569 case GLU_TESS_WINDING_ODD:
00570 return totalWindingNumber % 2;
00571 default:
00572 return false;
00573 }
00574 }
00575
00576
00577
00578
00579
00580
00581 void TextVectorGlyph::computeContourOrientations() const
00582 {
00583
00584
00585 const PolygonOutline &outline = getLines(0);
00586 UInt32 start = 0, end;
00587 vector<UInt32>::const_iterator it;
00588 for (it = outline.contours.begin(); it != outline.contours.end(); ++it)
00589 {
00590 end = *it;
00591
00592
00593 if (end - start < 3)
00594 _contourOrientations.push_back(CCW);
00595
00596 assert(start + 2 < outline.coords.size());
00597 Vec2f en1 = computeEdgeNormal(outline.coords[start], outline.coords[start + 1], false);
00598 Vec2f en2 = computeEdgeNormal(outline.coords[start + 1], outline.coords[start + 2], false);
00599
00600 Vec2f testNormal = en1 + en2;
00601 testNormal.normalize();
00602
00603 Vec2f testPoint = outline.coords[start + 1] + testNormal * (1000.f * Eps);
00604
00605 if (isInteriorPoint(testPoint, outline, GLU_TESS_WINDING_NONZERO))
00606 _contourOrientations.push_back(CW);
00607 else
00608 _contourOrientations.push_back(CCW);
00609
00610 start = end;
00611 }
00612 }
00613
00614
00615 OSG_END_NAMESPACE
00616
00617
00618
00619
00620
00621 #ifdef OSG_SGI_CC
00622 #pragma set woff 1174
00623 #endif
00624
00625 #ifdef OSG_LINUX_ICC
00626 #pragma warning( disable : 177 )
00627 #endif
00628
00629 namespace
00630 {
00631 static OSG::Char8 cvsid_cpp[] = "@(#)$Id: OSGTextVectorGlyph.cpp,v 1.11 2005/11/09 22:26:28 dirk Exp $";
00632 static OSG::Char8 cvsid_hpp[] = OSGTEXTVECTORGLYPH_HEADER_CVSID;
00633 static OSG::Char8 cvsid_inl[] = OSGTEXTVECTORGLYPH_INLINE_CVSID;
00634 }
00635
00636 #ifdef __sgi
00637 #pragma reset woff 1174
00638 #endif