From 71443d1c9abb0ef3aa5b1ac5ed32c0624c958c50 Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 8 May 2012 09:47:42 +0100 Subject: [PATCH] Phase 1 - single geometry per material --- simgear/scene/tgdb/apt_signs.cxx | 258 +++++++++++++++---------------- simgear/scene/tgdb/apt_signs.hxx | 4 +- 2 files changed, 129 insertions(+), 133 deletions(-) diff --git a/simgear/scene/tgdb/apt_signs.cxx b/simgear/scene/tgdb/apt_signs.cxx index 6c54c626..83410051 100644 --- a/simgear/scene/tgdb/apt_signs.cxx +++ b/simgear/scene/tgdb/apt_signs.cxx @@ -25,6 +25,7 @@ #endif #include +#include #include #include @@ -66,6 +67,9 @@ struct element_info { typedef std::vector ElementVec; + + + const double HT[5] = {0.460, 0.610, 0.760, 1.220, 0.760}; // standard panel height sizes const double grounddist = 0.2; // hard-code sign distance from surface for now const double thick = 0.1; // half the thickness of the 3D sign @@ -91,73 +95,115 @@ struct pair { {0, 0}, }; -void SGMakeSignFace(osg::Group* object, const ElementVec& elements, double hpos, bool isBackside) +struct GlyphGeometry { - std::map geodesByEffect; - - for (unsigned int i = 0; i < elements.size(); i++) { - element_info *element = elements[i]; - - double xoffset = element->glyph->get_left(); - double height = element->height; - double width = element->glyph->get_width(); - - osg::Vec3Array* vl = new osg::Vec3Array; - osg::Vec2Array* tl = new osg::Vec2Array; - - // vertices - vl->push_back(osg::Vec3(thick, hpos, grounddist)); - vl->push_back(osg::Vec3(thick, hpos + element->abswidth, grounddist)); - vl->push_back(osg::Vec3(thick, hpos, grounddist + height)); - vl->push_back(osg::Vec3(thick, hpos + element->abswidth, grounddist + height)); - - // texture coordinates - tl->push_back(osg::Vec2(xoffset, 0)); - tl->push_back(osg::Vec2(xoffset + width, 0)); - tl->push_back(osg::Vec2(xoffset, 1)); - tl->push_back(osg::Vec2(xoffset + width, 1)); - - // normals - osg::Vec3Array* nl = new osg::Vec3Array; - nl->push_back(osg::Vec3(0, -1, 0)); - - // colors - osg::Vec4Array* cl = new osg::Vec4Array; - cl->push_back(osg::Vec4(1, 1, 1, 1)); - - osg::Geometry* geometry = new osg::Geometry; - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_OVERALL); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - geometry->setTexCoordArray(0, tl); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size())); - - EffectGeode* geode = geodesByEffect[element->state]; - if (!geode) { - geode = new EffectGeode(); - geode->setEffect(element->state); - geodesByEffect[element->state] = geode; - } - - geode->addDrawable(geometry); + osg::DrawArrays* quads; + osg::Vec2Array* uvs; + osg::Vec3Array* vertices; + osg::Vec3Array* normals; + + void addGlyph(SGMaterialGlyph* glyph, double x, double y, double width, double height, const osg::Matrix& xform) + { + + vertices->push_back(xform.preMult(osg::Vec3(thick, x, y))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x + width, y))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x + width, y + height))); + vertices->push_back(xform.preMult(osg::Vec3(thick, x, y + height))); + + // texture coordinates + double xoffset = glyph->get_left(); + double texWidth = glyph->get_width(); + + uvs->push_back(osg::Vec2(xoffset, 0)); + uvs->push_back(osg::Vec2(xoffset + texWidth, 0)); + uvs->push_back(osg::Vec2(xoffset + texWidth, 1)); + uvs->push_back(osg::Vec2(xoffset, 1)); + + // normals + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(0, -1, 0))); + + quads->setCount(vertices->size()); + } + + void addSignCase(double caseWidth, double caseHeight, const osg::Matrix& xform) + { + vertices->push_back(osg::Vec3(-thick, -caseWidth, grounddist)); + vertices->push_back(osg::Vec3(thick, -caseWidth, grounddist)); + vertices->push_back(osg::Vec3(thick, -caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(-thick, -caseWidth, grounddist + caseHeight)); + + + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(-1, 0.0, 0))); + + vertices->push_back(osg::Vec3(-thick, -caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, -caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist + caseHeight)); + + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(0, 0, 1))); + + vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist + caseHeight)); + vertices->push_back(osg::Vec3(thick, caseWidth, grounddist)); + vertices->push_back(osg::Vec3(-thick, caseWidth, grounddist)); + + for (int i=0; i<4; ++i) + normals->push_back(xform.preMult(osg::Vec3(1, 0.0, 0))); + + for (int i = 0; i < 3; ++i) { + uvs->push_back(osg::Vec2(1, 1)); + uvs->push_back(osg::Vec2(0.75, 1)); + uvs->push_back(osg::Vec2(0.75, 0)); + uvs->push_back(osg::Vec2(1, 0)); + } + + quads->setCount(vertices->size()); + } +}; - if (isBackside) { - osg::MatrixTransform* transform = new osg::MatrixTransform(); - const double angle = 180; - const osg::Vec3d axis(0, 0, 1); - transform->setMatrix(osg::Matrix::rotate( osg::DegreesToRadians(angle), axis)); - transform->addChild(geode); - object->addChild(transform); - } else - object->addChild(geode); +typedef std::map EffectGeometryMap; +void SGMakeSignFace(EffectGeometryMap& glyphs, const ElementVec& elements, double hpos, const osg::Matrix& xform) +{ + BOOST_FOREACH(element_info* element, elements) { + GlyphGeometry* gg = glyphs[element->state]; + gg->addGlyph(element->glyph, hpos, grounddist, element->abswidth, element->height, xform); hpos += element->abswidth; delete element; } } +GlyphGeometry* makeGeometry(Effect* eff, osg::Group* group) +{ + GlyphGeometry* gg = new GlyphGeometry; + + EffectGeode* geode = new EffectGeode; + geode->setEffect(eff); + + gg->vertices = new osg::Vec3Array; + gg->normals = new osg::Vec3Array; + gg->uvs = new osg::Vec2Array; + + osg::Vec4Array* cl = new osg::Vec4Array; + cl->push_back(osg::Vec4(1, 1, 1, 1)); + + osg::Geometry* geometry = new osg::Geometry; + geometry->setVertexArray(gg->vertices); + geometry->setNormalArray(gg->normals); + geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + geometry->setColorArray(cl); + geometry->setColorBinding(osg::Geometry::BIND_OVERALL); + geometry->setTexCoordArray(0, gg->uvs); + + gg->quads = new osg::DrawArrays(GL_QUADS, 0, gg->vertices->size()); + geometry->addPrimitiveSet(gg->quads); + geode->addDrawable(geometry); + group->addChild(geode); + return gg; +} // see $FG_ROOT/Docs/README.scenery // @@ -176,6 +222,8 @@ SGMakeSign(SGMaterialLib *matlib, const string& content) int size = -1; char oldtype = 0, newtype = 0; + EffectGeometryMap geoms; + osg::Group* object = new osg::Group; object->setName(content); @@ -298,6 +346,10 @@ SGMakeSign(SGMaterialLib *matlib, const string& content) // in managed mode push frame stop and frame start first Effect *state = material->get_effect(); + if (geoms[state] == NULL) { + geoms[state] = makeGeometry(state, object); + } + element_info *e1; element_info *e2; if (!isBackside) { @@ -361,92 +413,38 @@ SGMakeSign(SGMaterialLib *matlib, const string& content) } - // Part II: typeset - double hpos = -total_width1 / 2; - double boxwidth = total_width1 > total_width2 ? total_width1/2 : total_width2/2; - + // Part II: typeset + double boxwidth = std::max(total_width1, total_width2) * 0.5; + double hpos = -boxwidth; + SGMaterial *mat = matlib->find("signcase"); + geoms[mat->get_effect()] = makeGeometry(mat->get_effect(), object); + + double coverSize = fabs(total_width1 - total_width2) * 0.5; + if (total_width1 < total_width2) { - double ssize = (total_width2 - total_width1)/2; - SGMaterial *mat = matlib->find("signcase"); if (mat) { - element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, ssize); - element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, ssize); + element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize); + element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize); elements1.insert(elements1.begin(), s1); elements1.push_back(s2); } - hpos = -total_width2 / 2; } else if (total_width2 < total_width1) { - double ssize = (total_width1 - total_width2)/2; - SGMaterial *mat = matlib->find("signcase"); if (mat) { - element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, ssize); - element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, ssize); + element_info* s1 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize); + element_info* s2 = new element_info(mat, mat->get_effect(), mat->get_glyph("cover"), sign_height, coverSize); elements2.insert(elements2.begin(), s1); elements2.push_back(s2); } - hpos = -total_width1 / 2; } // Create front side - SGMakeSignFace(object, elements1, hpos, false); + SGMakeSignFace(geoms, elements1, hpos, osg::Matrix::identity()); // Create back side - SGMakeSignFace(object, elements2, hpos, true); - - - // Add 3D case for signs - osg::Vec3Array* vl = new osg::Vec3Array; - osg::Vec2Array* tl = new osg::Vec2Array; - osg::Vec3Array* nl = new osg::Vec3Array; - - //left side - vl->push_back(osg::Vec3(-thick, -boxwidth, grounddist)); - vl->push_back(osg::Vec3(thick, -boxwidth, grounddist)); - vl->push_back(osg::Vec3(-thick, -boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(thick, -boxwidth, grounddist + sign_height)); - - nl->push_back(osg::Vec3(-1, 0, 0)); - - //top - vl->push_back(osg::Vec3(-thick, -boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(thick, -boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(-thick, boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(thick, boxwidth, grounddist + sign_height)); - - nl->push_back(osg::Vec3(0, 0, 1)); - - //right side - vl->push_back(osg::Vec3(-thick, boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(thick, boxwidth, grounddist + sign_height)); - vl->push_back(osg::Vec3(-thick, boxwidth, grounddist)); - vl->push_back(osg::Vec3(thick, boxwidth, grounddist)); - - for (int i = 0; i < 4; ++i) { - tl->push_back(osg::Vec2(1, 1)); - tl->push_back(osg::Vec2(0.75, 1)); - tl->push_back(osg::Vec2(1, 0)); - tl->push_back(osg::Vec2(0.75, 0)); - } - - nl->push_back(osg::Vec3(1, 0, 0)); - - osg::Vec4Array* cl = new osg::Vec4Array; - cl->push_back(osg::Vec4(1.0, 1.0, 1.0, 1.0)); - osg::Geometry* geometry = new osg::Geometry; - geometry->setVertexArray(vl); - geometry->setNormalArray(nl); - geometry->setNormalBinding(osg::Geometry::BIND_OVERALL); - geometry->setTexCoordArray(0, tl); - geometry->setColorArray(cl); - geometry->setColorBinding(osg::Geometry::BIND_OVERALL); - geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, vl->size())); - EffectGeode* geode = new EffectGeode; - geode->addDrawable(geometry); - SGMaterial *mat = matlib->find("signcase"); - if (mat) - geode->setEffect(mat->get_effect()); - object->addChild(geode); - + const osg::Vec3d axis(0, 0, 1); + SGMakeSignFace(geoms, elements2, hpos, osg::Matrix::rotate( M_PI, axis)); + geoms[mat->get_effect()]->addSignCase(boxwidth, sign_height, osg::Matrix::identity()); + return object; } diff --git a/simgear/scene/tgdb/apt_signs.hxx b/simgear/scene/tgdb/apt_signs.hxx index 17e91d7a..01339401 100644 --- a/simgear/scene/tgdb/apt_signs.hxx +++ b/simgear/scene/tgdb/apt_signs.hxx @@ -38,11 +38,9 @@ class SGMaterialLib; // forward declaration -using std::string; - // Generate a generic sign -osg::Node* SGMakeSign( SGMaterialLib *matlib, const string& content ); +osg::Node* SGMakeSign( SGMaterialLib *matlib, const std::string& content ); #endif // _SG_APT_SIGNS_HXX -- 2.39.5