// Create the metrics NodePtr createMetrics(TextFace *face, Real32 scale, const TextLayoutParam &layoutParam, const TextLayoutResult &layoutResult) { GeometryPtr geoPtr = Geometry::create(); beginEditCP(geoPtr); { GeoPTypesUI8Ptr typesPtr = GeoPTypesUI8::create(); geoPtr->setTypes(typesPtr); GeoPLengthsUI32Ptr lensPtr = GeoPLengthsUI32::create(); geoPtr->setLengths(lensPtr); GeoPositions3fPtr posPtr = GeoPositions3f::create(); geoPtr->setPositions(posPtr); GeoColors3fPtr colorsPtr = GeoColors3f::create(); colorsPtr->push_back(Color3f(0.f, 0.f, 1.f)); colorsPtr->push_back(Color3f(1.f, 0.f, 0.f)); colorsPtr->push_back(Color3f(0.f, 1.f, 0.f)); colorsPtr->push_back(Color3f(1.f, 1.f, 0.f)); geoPtr->setColors(colorsPtr); GeoIndicesUI32Ptr indicesPtr = GeoIndicesUI32::create(); geoPtr->setIndices(indicesPtr); UInt32 i, numGlyphs = layoutResult.getNumGlyphs(); for (i = 0; i < numGlyphs; ++i) { const TextGlyph &glyph = face->getGlyph(layoutResult.indices[i]); typesPtr->push_back(GL_LINE_LOOP); lensPtr->push_back(4); const Vec2f &pos = layoutResult.positions[i]; Real32 left = pos.x() * scale; Real32 right = (pos.x() + glyph.getWidth()) * scale; Real32 top = pos.y() * scale; Real32 bottom = (pos.y() - glyph.getHeight()) * scale; UInt32 posOffset = posPtr->size(); posPtr->push_back(Vec3f(left, bottom, 0.f)); posPtr->push_back(Vec3f(right, bottom, 0.f)); posPtr->push_back(Vec3f(right, top, 0.f)); posPtr->push_back(Vec3f(left, top, 0.f)); indicesPtr->push_back(posOffset); indicesPtr->push_back(0); indicesPtr->push_back(posOffset + 1); indicesPtr->push_back(0); indicesPtr->push_back(posOffset + 2); indicesPtr->push_back(0); indicesPtr->push_back(posOffset + 3); indicesPtr->push_back(0); } // Bounding box Vec2f lowerLeft, upperRight; face->calculateBoundingBox(layoutResult, lowerLeft, upperRight); typesPtr->push_back(GL_LINE_LOOP); lensPtr->push_back(4); Real32 left = lowerLeft.x() * scale; Real32 right = upperRight.x() * scale; Real32 top = upperRight.y() * scale; Real32 bottom = lowerLeft.y() * scale; UInt32 posOffset = posPtr->size(); posPtr->push_back(Vec3f(left, bottom, 0.f)); posPtr->push_back(Vec3f(right, bottom, 0.f)); posPtr->push_back(Vec3f(right, top, 0.f)); posPtr->push_back(Vec3f(left, top, 0.f)); indicesPtr->push_back(posOffset); indicesPtr->push_back(1); indicesPtr->push_back(posOffset + 1); indicesPtr->push_back(1); indicesPtr->push_back(posOffset + 2); indicesPtr->push_back(1); indicesPtr->push_back(posOffset + 3); indicesPtr->push_back(1); // Text bounds & Line bounds Vec2f pos, textPos, offset; if (layoutParam.horizontal == true) { Real32 lineHeight = face->getHoriAscent() - face->getHoriDescent(); Real32 spacing = layoutParam.spacing * lineHeight; if (layoutParam.topToBottom == true) { switch (layoutParam.minorAlignment) { case TextLayoutParam::ALIGN_BEGIN: break; case TextLayoutParam::ALIGN_FIRST: pos[1] = textPos[1] = face->getHoriAscent(); break; case TextLayoutParam::ALIGN_MIDDLE: pos[1] = textPos[1] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f; break; case TextLayoutParam::ALIGN_END: pos[1] = textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + lineHeight; break; } offset.setValues(0.f, -spacing); } else { switch (layoutParam.minorAlignment) { case TextLayoutParam::ALIGN_BEGIN: pos[1] = lineHeight; textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + lineHeight; break; case TextLayoutParam::ALIGN_FIRST: pos[1] = face->getHoriAscent(); textPos[1] = spacing * (layoutResult.lineBounds.size() - 1) + face->getHoriAscent(); break; case TextLayoutParam::ALIGN_MIDDLE: pos[1] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f + lineHeight; textPos[1] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f; break; case TextLayoutParam::ALIGN_END: pos[1] = -spacing * (layoutResult.lineBounds.size() - 1); break; } offset.setValues(0.f, spacing); } } else { Real32 lineHeight = face->getVertDescent() - face->getVertAscent(); Real32 spacing = layoutParam.spacing * lineHeight; if (layoutParam.leftToRight == true) { switch (layoutParam.minorAlignment) { case TextLayoutParam::ALIGN_BEGIN: break; case TextLayoutParam::ALIGN_FIRST: pos[0] = textPos[0] = face->getVertAscent(); break; case TextLayoutParam::ALIGN_MIDDLE: pos[0] = textPos[0] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f; break; case TextLayoutParam::ALIGN_END: pos[0] = textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) - lineHeight; break; } offset.setValues(spacing, 0.f); } else { switch (layoutParam.minorAlignment) { case TextLayoutParam::ALIGN_BEGIN: pos[0] = -lineHeight; textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) - lineHeight; break; case TextLayoutParam::ALIGN_FIRST: pos[0] = -face->getVertDescent(); textPos[0] = -spacing * (layoutResult.lineBounds.size() - 1) -face->getVertDescent(); break; case TextLayoutParam::ALIGN_MIDDLE: pos[0] = (spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f - lineHeight; textPos[0] = -(spacing * (layoutResult.lineBounds.size() - 1) + lineHeight) / 2.f; break; case TextLayoutParam::ALIGN_END: pos[0] = spacing * (layoutResult.lineBounds.size() - 1); break; } offset.setValues(-spacing, 0.f); } } typesPtr->push_back(GL_LINE_LOOP); lensPtr->push_back(4); left = textPos.x(); top = textPos.y(); if (layoutParam.horizontal == true) if (layoutParam.leftToRight == true) switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: break; case TextLayoutParam::ALIGN_MIDDLE: left -= layoutResult.textBounds.x() / 2.f; break; case TextLayoutParam::ALIGN_END: left -= layoutResult.textBounds.x(); break; } else switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: left -= layoutResult.textBounds.x(); break; case TextLayoutParam::ALIGN_MIDDLE: left -= layoutResult.textBounds.x() / 2.f; break; case TextLayoutParam::ALIGN_END: break; } else if (layoutParam.topToBottom == true) switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: break; case TextLayoutParam::ALIGN_MIDDLE: top += layoutResult.textBounds.y() / 2.f; break; case TextLayoutParam::ALIGN_END: top += layoutResult.textBounds.y(); break; } else switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: top += layoutResult.textBounds.y(); break; case TextLayoutParam::ALIGN_MIDDLE: top += layoutResult.textBounds.y() / 2.f; break; case TextLayoutParam::ALIGN_END: break; } left *= scale; right = left + layoutResult.textBounds.x() * scale; top *= scale; bottom = top - layoutResult.textBounds.y() * scale; posOffset = posPtr->size(); posPtr->push_back(Vec3f(left, bottom, 0.f)); posPtr->push_back(Vec3f(right, bottom, 0.f)); posPtr->push_back(Vec3f(right, top, 0.f)); posPtr->push_back(Vec3f(left, top, 0.f)); indicesPtr->push_back(posOffset); indicesPtr->push_back(3); indicesPtr->push_back(posOffset + 1); indicesPtr->push_back(3); indicesPtr->push_back(posOffset + 2); indicesPtr->push_back(3); indicesPtr->push_back(posOffset + 3); indicesPtr->push_back(3); vector<Vec2f>::const_iterator lbIt; for (lbIt = layoutResult.lineBounds.begin(); lbIt != layoutResult.lineBounds.end(); ++lbIt) { typesPtr->push_back(GL_LINE_LOOP); lensPtr->push_back(4); Real32 left = pos.x(); Real32 top = pos.y(); if (layoutParam.horizontal == true) if (layoutParam.leftToRight == true) switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: break; case TextLayoutParam::ALIGN_MIDDLE: left -= lbIt->x() / 2.f; break; case TextLayoutParam::ALIGN_END: left -= lbIt->x(); break; } else switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: left -= lbIt->x(); break; case TextLayoutParam::ALIGN_MIDDLE: left -= lbIt->x() / 2.f; break; case TextLayoutParam::ALIGN_END: break; } else if (layoutParam.topToBottom == true) switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: break; case TextLayoutParam::ALIGN_MIDDLE: top += lbIt->y() / 2.f; break; case TextLayoutParam::ALIGN_END: top += lbIt->y(); break; } else switch (layoutParam.majorAlignment) { case TextLayoutParam::ALIGN_BEGIN: case TextLayoutParam::ALIGN_FIRST: top += lbIt->y(); break; case TextLayoutParam::ALIGN_MIDDLE: top += lbIt->y() / 2.f; break; case TextLayoutParam::ALIGN_END: break; } left *= scale; Real32 right = left + lbIt->x() * scale; top *= scale; Real32 bottom = top - lbIt->y() * scale; UInt32 posOffset = posPtr->size(); posPtr->push_back(Vec3f(left, bottom, 0.f)); posPtr->push_back(Vec3f(right, bottom, 0.f)); posPtr->push_back(Vec3f(right, top, 0.f)); posPtr->push_back(Vec3f(left, top, 0.f)); indicesPtr->push_back(posOffset); indicesPtr->push_back(2); indicesPtr->push_back(posOffset + 1); indicesPtr->push_back(2); indicesPtr->push_back(posOffset + 2); indicesPtr->push_back(2); indicesPtr->push_back(posOffset + 3); indicesPtr->push_back(2); typesPtr->push_back(GL_LINE_STRIP); lensPtr->push_back(2); posOffset = posPtr->size(); if (layoutParam.horizontal == true) { Real32 base = top - face->getHoriAscent() * scale; posPtr->push_back(Vec3f(left, base, 0.f)); posPtr->push_back(Vec3f(right, base, 0.f)); } else { Real32 base = left - face->getVertAscent() * scale; posPtr->push_back(Vec3f(base, top, 0.f)); posPtr->push_back(Vec3f(base, bottom, 0.f)); } indicesPtr->push_back(posOffset); indicesPtr->push_back(2); indicesPtr->push_back(posOffset + 1); indicesPtr->push_back(2); pos += offset; } geoPtr->editMFIndexMapping()->clear(); geoPtr->editMFIndexMapping()->push_back(Geometry::MapPosition); geoPtr->editMFIndexMapping()->push_back(Geometry::MapColor); SimpleMaterialPtr matPtr = SimpleMaterial::create(); geoPtr->setMaterial(matPtr); } endEditCP(geoPtr); NodePtr nodePtr = Node::create(); beginEditCP(nodePtr, Node::CoreFieldMask); { nodePtr->setCore(geoPtr); } endEditCP(nodePtr, Node::CoreFieldMask); return nodePtr; }
// Create the coordinate cross NodePtr createCoordinateCross() { GeometryPtr geoPtr = Geometry::create(); beginEditCP(geoPtr); { GeoPTypesUI8Ptr typesPtr = GeoPTypesUI8::create(); typesPtr->push_back(GL_LINES); geoPtr->setTypes(typesPtr); GeoPLengthsUI32Ptr lensPtr = GeoPLengthsUI32::create(); lensPtr->push_back(6); geoPtr->setLengths(lensPtr); GeoPositions3fPtr posPtr = GeoPositions3f::create(); posPtr->push_back(Vec3f(-0.1f, 0.f, 0.f)); posPtr->push_back(Vec3f(1.f, 0.f, 0.f)); posPtr->push_back(Vec3f(0.f, -0.1f, 0.f)); posPtr->push_back(Vec3f(0.f, 1.f, 0.f)); posPtr->push_back(Vec3f(0.f, 0.f, -0.1f)); posPtr->push_back(Vec3f(0.f, 0.f, 1.f)); geoPtr->setPositions(posPtr); GeoColors3fPtr colorsPtr = GeoColors3f::create(); colorsPtr->push_back(Color3f(1.f, 0.f, 0.f)); colorsPtr->push_back(Color3f(0.f, 1.f, 0.f)); colorsPtr->push_back(Color3f(0.f, 0.f, 1.f)); geoPtr->setColors(colorsPtr); GeoIndicesUI32Ptr indicesPtr = GeoIndicesUI32::create(); // X Axis indicesPtr->push_back(0); indicesPtr->push_back(0); indicesPtr->push_back(1); indicesPtr->push_back(0); // Y Axis indicesPtr->push_back(2); indicesPtr->push_back(1); indicesPtr->push_back(3); indicesPtr->push_back(1); // Z Axis indicesPtr->push_back(4); indicesPtr->push_back(2); indicesPtr->push_back(5); indicesPtr->push_back(2); geoPtr->setIndices(indicesPtr); geoPtr->editMFIndexMapping()->clear(); geoPtr->editMFIndexMapping()->push_back(Geometry::MapPosition); geoPtr->editMFIndexMapping()->push_back(Geometry::MapColor); SimpleMaterialPtr matPtr = SimpleMaterial::create(); geoPtr->setMaterial(matPtr); } endEditCP(geoPtr); NodePtr nodePtr = Node::create(); beginEditCP(nodePtr, Node::CoreFieldMask); { nodePtr->setCore(geoPtr); } endEditCP(nodePtr, Node::CoreFieldMask); return nodePtr; }
// Initialize GLUT & OpenSG and set up the scene int main(int argc, char **argv) { // OSG init osgInit(argc,argv); // GLUT init int winid = setupGLUT(&argc, argv); // the connection between GLUT and OpenSG GLUTWindowPtr gwin= GLUTWindow::create(); gwin->setId(winid); gwin->init(); // create the scene /* In the previous example, the colors and positions used the same indices. That might not always be the preferred way, and it might not make sense for other properties, e.g. normals. It is possible to assign a different index for every property. See the indices section below for details. */ /* The initial setup is the same as in the single indexed geometry... */ GeoPTypesPtr type = GeoPTypesUI8::create(); beginEditCP(type, GeoPTypesUI8::GeoPropDataFieldMask); { type->push_back(GL_POLYGON ); type->push_back(GL_TRIANGLES); type->push_back(GL_QUADS ); } endEditCP (type, GeoPTypesUI8::GeoPropDataFieldMask); GeoPLengthsPtr lens = GeoPLengthsUI32::create(); beginEditCP(lens, GeoPLengthsUI32::GeoPropDataFieldMask); { lens->push_back(4); lens->push_back(6); lens->push_back(8); } endEditCP (lens, GeoPLengthsUI32::GeoPropDataFieldMask); GeoPositions3fPtr pnts = GeoPositions3f::create(); beginEditCP(pnts, GeoPositions3f::GeoPropDataFieldMask); { // the base pnts->push_back(Pnt3f(-1, -1, -1)); pnts->push_back(Pnt3f(-1, -1, 1)); pnts->push_back(Pnt3f( 1, -1, 1)); pnts->push_back(Pnt3f( 1, -1, -1)); // the roof base pnts->push_back(Pnt3f(-1, 0, -1)); pnts->push_back(Pnt3f(-1, 0, 1)); pnts->push_back(Pnt3f( 1, 0, 1)); pnts->push_back(Pnt3f( 1, 0, -1)); // the gable pnts->push_back(Pnt3f( 0, 1, -1)); pnts->push_back(Pnt3f( 0, 1, 1)); } endEditCP (pnts, GeoPositions3f::GeoPropDataFieldMask); GeoColors3fPtr colors = GeoColors3f::create(); beginEditCP(colors, GeoColors3f::GeoPropDataFieldMask); { colors->push_back(Color3f(1, 1, 0)); colors->push_back(Color3f(1, 0, 0)); colors->push_back(Color3f(1, 0, 0)); colors->push_back(Color3f(1, 1, 0)); colors->push_back(Color3f(0, 1, 1)); colors->push_back(Color3f(1, 0, 1)); } endEditCP (colors, GeoPositions3f::GeoPropDataFieldMask); /* A new property: normals. They are used for lighting calculations and have to point away from the surface. Normals are standard vectors. */ GeoNormals3fPtr norms = GeoNormals3f::create(); beginEditCP(norms, GeoNormals3f::GeoPropDataFieldMask); { norms->push_back(Vec3f(-1, 0, 0)); norms->push_back(Vec3f( 1, 0, 0)); norms->push_back(Vec3f( 0, -1, 0)); norms->push_back(Vec3f( 0, 1, 0)); norms->push_back(Vec3f( 0, 0, -1)); norms->push_back(Vec3f( 0, 0, 1)); } endEditCP (norms, GeoNormals3f::GeoPropDataFieldMask); /* To use different indices for different attributes they have to be specified. This is done within the single index property, by using more than one index per vertex. In this case every vertex reads multiple indices from the Indices property. The meaning of every index is defined by the indexMapping given below. */ GeoIndicesUI32Ptr indices = GeoIndicesUI32::create(); beginEditCP(indices, GeoIndicesUI32::GeoPropDataFieldMask); { // indices for the polygon indices->push_back(0); // position index indices->push_back(3); // color/normal index indices->push_back(1); // position index indices->push_back(3); // color/normal index indices->push_back(2); // position index indices->push_back(3); // color/normal index indices->push_back(3); // position index indices->push_back(3); // color/normal index // indices for the triangles indices->push_back(7); // position index indices->push_back(4); // color/normal index indices->push_back(4); // position index indices->push_back(4); // color/normal index indices->push_back(8); // position index indices->push_back(4); // color/normal index indices->push_back(5); // position index indices->push_back(5); // color/normal index indices->push_back(6); // position index indices->push_back(5); // color/normal index indices->push_back(9); // position index indices->push_back(5); // color/normal index // indices for the quads indices->push_back(1); // position index indices->push_back(5); // color/normal index indices->push_back(2); // position index indices->push_back(5); // color/normal index indices->push_back(6); // position index indices->push_back(5); // color/normal index indices->push_back(5); // position index indices->push_back(5); // color/normal index indices->push_back(3); // position index indices->push_back(4); // color/normal index indices->push_back(0); // position index indices->push_back(4); // color/normal index indices->push_back(4); // position index indices->push_back(4); // color/normal index indices->push_back(7); // position index indices->push_back(4); // color/normal index } endEditCP (indices, GeoIndicesUI32::GeoPropDataFieldMask); /* Put it all together into a Geometry NodeCore. */ GeometryPtr geo=Geometry::create(); beginEditCP(geo, Geometry::TypesFieldMask | Geometry::LengthsFieldMask | Geometry::IndicesFieldMask | Geometry::IndexMappingFieldMask | Geometry::PositionsFieldMask | Geometry::NormalsFieldMask | Geometry::ColorsFieldMask | Geometry::MaterialFieldMask ); { geo->setTypes (type); geo->setLengths (lens); geo->setIndices (indices); /* The meaning of the different indices is given by the indexMapping field. If contains an entry that defines which index for a vertex selects which attribute. In this example the first index selects the positions, the second is used for colors and normals. The number of elements in the indexMapping field defines the number of indices used for every vertex. */ geo->editMFIndexMapping()->push_back(Geometry::MapPosition ); geo->editMFIndexMapping()->push_back(Geometry::MapColor | Geometry::MapNormal ); geo->setPositions(pnts ); geo->setColors (colors); geo->setNormals (norms ); /* Use a lit material this time, to show the effect of the normals. */ geo->setMaterial (getDefaultMaterial()); } endEditCP (geo, Geometry::TypesFieldMask | Geometry::LengthsFieldMask | Geometry::IndicesFieldMask | Geometry::IndexMappingFieldMask | Geometry::PositionsFieldMask | Geometry::NormalsFieldMask | Geometry::ColorsFieldMask | Geometry::MaterialFieldMask ); // put the geometry core into a node NodePtr n = Node::create(); beginEditCP(n, Node::CoreFieldMask); { n->setCore(geo); } endEditCP (n, Node::CoreFieldMask); // add a transformation to make it move NodePtr scene = Node::create(); trans = Transform::create(); beginEditCP(scene, Node::CoreFieldMask | Node::ChildrenFieldMask ); { scene->setCore(trans); scene->addChild(n); } endEditCP (scene, Node::CoreFieldMask | Node::ChildrenFieldMask ); // create the SimpleSceneManager helper mgr = new SimpleSceneManager; // tell the manager what to manage mgr->setWindow(gwin ); mgr->setRoot (scene); // show the whole scene mgr->showAll(); // GLUT main loop glutMainLoop(); return 0; }