GeometryRefPtr buildTerrain(Vec2f Dimensions, UInt32 XSubdivisions, UInt32 YSubdivisions)
{
    GeoUInt8PropertyRefPtr type = GeoUInt8Property::create();        
    type->addValue(GL_TRIANGLES);

    GeoPnt3fPropertyRefPtr  pnts  = GeoPnt3fProperty ::create();
    GeoVec3fPropertyRefPtr  norms = GeoVec3fProperty ::create();
    Real32 ZScale(8.0);
    for(UInt32 i(0) ; i<XSubdivisions ; ++i)
    {
        for(UInt32 j(0) ; j<YSubdivisions ; ++j)
        {
            Real32 Theta(5*3.14159*(static_cast<Real32>(i)/static_cast<Real32>(XSubdivisions))),
                   ThetaNext(5*3.14159*(static_cast<Real32>(i+1)/static_cast<Real32>(XSubdivisions)));
            // the points of the Tris
            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+i*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-j*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(Theta)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));
            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+i*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-(j+1)*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(Theta)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));
            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+(i+1)*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-j*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(ThetaNext)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));

            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+i*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-(j+1)*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(Theta)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));
            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+(i+1)*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-(j+1)*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(ThetaNext)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));
            pnts->addValue(Pnt3f(-Dimensions.x()/2.0+(i+1)*(Dimensions.x()/static_cast<Real32>(XSubdivisions)),  Dimensions.y()/2.0-j*(Dimensions.y()/static_cast<Real32>(YSubdivisions)),  ZScale*osgCos(ThetaNext)));
            norms->addValue(Vec3f( 0.0,0.0,1.0));
        }
    }


    GeoUInt32PropertyUnrecPtr lens = GeoUInt32Property::create();    
    lens->addValue(pnts->size());

    GeometryRefPtr Terrain = Geometry::create();
    Terrain->setTypes    (type);
    Terrain->setLengths  (lens);
    Terrain->setPositions(pnts);
    Terrain->setNormals(norms);

    calcVertexNormals(Terrain);

    return Terrain;
}
void
OgreMeshReader::constructSubMesh(SubMeshInfo        &smInfo,
                                 VertexElementStore &vertexElements)
{
    OSG_OGRE_LOG(("OgreMeshReader::constructSubMesh: meshName '%s'"
                  "matName '%s'\n",
                  smInfo.name.c_str(), smInfo.matName.c_str()));

    if(smInfo.skelAnim == true)
    {
        smInfo.mesh = SkinnedGeometry::create();
    }
    else
    {
        smInfo.mesh = Geometry::create();
    }

    smInfo.meshN = makeNodeFor(smInfo.mesh);
    smInfo.meshN->editSFVolume()->setValue(_rootN->getVolume());

    setName(smInfo.meshN, smInfo.name);

    UInt16 nextIdx = Geometry::TexCoordsIndex;

    for(UInt32 i = 0; i < vertexElements.size(); ++i)
    {
        Int32 usage   = -1;
        Int16 propSlot = -1;

        switch(vertexElements[i].semantic)
        {
        case VES_POSITION:
            usage    = GeoProperty::UsageObjectSpace;
            propSlot = Geometry::PositionsIndex;
            break;

        case VES_BLEND_WEIGHTS:
        case VES_BLEND_INDICES:
        case VES_TEXTURE_COORDINATES:
            usage    = GeoProperty::UsageParameterSpace;
            propSlot = nextIdx++;
            break;

        case VES_BINORMAL:
        case VES_TANGENT:
            usage    = GeoProperty::UsageTangentSpace;
            propSlot = nextIdx++;
            break;

        case VES_NORMAL:
            usage    = GeoProperty::UsageTangentSpace;
            propSlot = Geometry::NormalsIndex;
            break;

        case VES_DIFFUSE:
            usage    = GeoProperty::UsageColorSpace;
            propSlot = Geometry::ColorsIndex;
            break;

        case VES_SPECULAR:
            usage    = GeoProperty::UsageColorSpace;
            propSlot = Geometry::SecondaryColorsIndex;
            break;
        }

        if(usage >= 0)
        {
            vertexElements[i].prop->setUsage(usage);
        }

        if(propSlot >= 0)
        {
            OSG_OGRE_LOG(("OgreMeshReader::constructSubMesh: vertex elem semantic '%s'"
                          " using property '%u'\n",
                          getVertexElementSemanticString(vertexElements[i].semantic).c_str(),
                          propSlot));

            smInfo.mesh->setProperty(vertexElements[i].prop, propSlot);
            smInfo.mesh->setIndex   (smInfo.propIdx,         propSlot);
        }
        else
        {
            SWARNING << "OgreMeshReader::constructSubMesh: no property slot found for "
                     << "vertex elem semantic '"
                     << getVertexElementSemanticString(vertexElements[i].semantic)
                     << "'. Skipping." << std::endl;
        }

        if(vertexElements[i].semantic == VES_BLEND_INDICES)
        {
            SkinnedGeometry* skin =
                dynamic_pointer_cast<SkinnedGeometry>(smInfo.mesh);

            skin->setJointIndexProperty(propSlot);
        }

        if(vertexElements[i].semantic == VES_BLEND_WEIGHTS)
        {
            SkinnedGeometry* skin =
                dynamic_pointer_cast<SkinnedGeometry>(smInfo.mesh);

            skin->setJointWeightProperty(propSlot);
        }
    }

    GeoUInt8PropertyUnrecPtr types = GeoUInt8Property::create();
    switch(smInfo.meshOp)
    {
    case SMO_POINT_LIST:
        types->addValue(GL_POINTS);
        break;

    case SMO_LINE_LIST:
        types->addValue(GL_LINES);
        break;

    case SMO_LINE_STRIP:
        types->addValue(GL_LINE_STRIP);
        break;

    case SMO_TRIANGLE_LIST:
        types->addValue(GL_TRIANGLES);
        break;

    case SMO_TRIANGLE_STRIP:
        types->addValue(GL_TRIANGLE_STRIP);
        break;

    case SMO_TRIANGLE_FAN:
        types->addValue(GL_TRIANGLE_FAN);
        break;
    }

    GeoUInt32PropertyUnrecPtr lengths = GeoUInt32Property::create();
    lengths->addValue(smInfo.propIdx->size());

    smInfo.mesh->setTypes  (types);
    smInfo.mesh->setLengths(lengths);

    constructMaterial(smInfo);

    if(smInfo.skelAnim == true && _skel != NULL)
    {
        SkinnedGeometry* skin = dynamic_pointer_cast<SkinnedGeometry>(smInfo.mesh);

        if(skin != NULL)
        {
            skin->setSkeleton  (_skel);
            skin->setRenderMode(SkinnedGeometry::RMSkeleton);
        }
    }

    _rootN->addChild(smInfo.meshN);
}