1 2 #ifdef HAVE_CONFIG_H 3 # include <simgear_config.h> 4 #endif 5 6 #include "obj.hxx" 7 8 #include <simgear/scene/material/EffectGeode.hxx> 9 #include <simgear/scene/material/matlib.hxx> 10 #include <simgear/scene/material/mat.hxx> 11 12 #include "SGTexturedTriangleBin.hxx" 13 14 using namespace simgear; 15 16 typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap; 17 18 // Class handling the initial BTG loading : should probably be in its own file 19 // it is very closely coupled with SGTexturedTriangleBin.hxx 20 // it was used to load fans, strips, and triangles. 21 // WS2.0 no longer uses fans or strips, but people still use ws1.0, so we need 22 // to keep this functionality. 23 class SGTileGeometryBin : public osg::Referenced { 24 public: 25 SGMaterialTriangleMap materialTriangleMap; 26 SGTileGeometryBin()27 SGTileGeometryBin() {} 28 29 static SGVec2f getTexCoord(const std::vector<SGVec2f> & texCoords,const int_list & tc,const SGVec2f & tcScale,unsigned i)30 getTexCoord(const std::vector<SGVec2f>& texCoords, const int_list& tc, 31 const SGVec2f& tcScale, unsigned i) 32 { 33 if (tc.empty()) 34 return tcScale; 35 else if (tc.size() == 1) 36 return mult(texCoords[tc[0]], tcScale); 37 else 38 return mult(texCoords[tc[i]], tcScale); 39 } 40 getTexCoordScale(const std::string & name,SGMaterialCache * matcache)41 SGVec2f getTexCoordScale(const std::string& name, SGMaterialCache* matcache) 42 { 43 if (!matcache) 44 return SGVec2f(1, 1); 45 SGMaterial* material = matcache->find(name); 46 if (!material) 47 return SGVec2f(1, 1); 48 49 return material->get_tex_coord_scale(); 50 } 51 52 static void addTriangleGeometry(SGTexturedTriangleBin & triangles,const SGBinObject & obj,unsigned grp,const SGVec2f & tc0Scale,const SGVec2f & tc1Scale)53 addTriangleGeometry(SGTexturedTriangleBin& triangles, 54 const SGBinObject& obj, unsigned grp, 55 const SGVec2f& tc0Scale, 56 const SGVec2f& tc1Scale) 57 { 58 const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes()); 59 const std::vector<SGVec3f>& normals(obj.get_normals()); 60 const std::vector<SGVec2f>& texCoords(obj.get_texcoords()); 61 const int_list& tris_v(obj.get_tris_v()[grp]); 62 const int_list& tris_n(obj.get_tris_n()[grp]); 63 const tci_list& tris_tc(obj.get_tris_tcs()[grp]); 64 bool num_norms_is_num_verts = true; 65 66 if (tris_v.size() != tris_n.size()) { 67 // If the normal indices do not match, they should be inmplicitly 68 // the same than the vertex indices. 69 num_norms_is_num_verts = false; 70 } 71 72 if ( !tris_tc[1].empty() ) { 73 triangles.hasSecondaryTexCoord(true); 74 } 75 76 for (unsigned i = 2; i < tris_v.size(); i += 3) { 77 SGVertNormTex v0; 78 v0.SetVertex( toVec3f(vertices[tris_v[i-2]]) ); 79 v0.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-2]] : 80 normals[tris_v[i-2]] ); 81 v0.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-2) ); 82 if (!tris_tc[1].empty()) { 83 v0.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-2) ); 84 } 85 SGVertNormTex v1; 86 v1.SetVertex( toVec3f(vertices[tris_v[i-1]]) ); 87 v1.SetNormal( num_norms_is_num_verts ? normals[tris_n[i-1]] : 88 normals[tris_v[i-1]] ); 89 v1.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i-1) ); 90 if (!tris_tc[1].empty()) { 91 v1.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i-1) ); 92 } 93 SGVertNormTex v2; 94 v2.SetVertex( toVec3f(vertices[tris_v[i]]) ); 95 v2.SetNormal( num_norms_is_num_verts ? normals[tris_n[i]] : 96 normals[tris_v[i]] ); 97 v2.SetTexCoord( 0, getTexCoord(texCoords, tris_tc[0], tc0Scale, i) ); 98 if (!tris_tc[1].empty()) { 99 v2.SetTexCoord( 1, getTexCoord(texCoords, tris_tc[1], tc1Scale, i) ); 100 } 101 102 triangles.insert(v0, v1, v2); 103 } 104 } 105 106 static void addStripGeometry(SGTexturedTriangleBin & triangles,const SGBinObject & obj,unsigned grp,const SGVec2f & tc0Scale,const SGVec2f & tc1Scale)107 addStripGeometry(SGTexturedTriangleBin& triangles, 108 const SGBinObject& obj, unsigned grp, 109 const SGVec2f& tc0Scale, 110 const SGVec2f& tc1Scale) 111 { 112 const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes()); 113 const std::vector<SGVec3f>& normals(obj.get_normals()); 114 const std::vector<SGVec2f>& texCoords(obj.get_texcoords()); 115 const int_list& strips_v(obj.get_strips_v()[grp]); 116 const int_list& strips_n(obj.get_strips_n()[grp]); 117 const tci_list& strips_tc(obj.get_strips_tcs()[grp]); 118 bool num_norms_is_num_verts = true; 119 120 if (strips_v.size() != strips_n.size()) { 121 // If the normal indices do not match, they should be inmplicitly 122 // the same than the vertex indices. 123 num_norms_is_num_verts = false; 124 } 125 126 if ( !strips_tc[1].empty() ) { 127 triangles.hasSecondaryTexCoord(true); 128 } 129 130 for (unsigned i = 2; i < strips_v.size(); ++i) { 131 SGVertNormTex v0; 132 v0.SetVertex( toVec3f(vertices[strips_v[i-2]]) ); 133 v0.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-2]] : 134 normals[strips_v[i-2]] ); 135 v0.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i-2) ); 136 if (!strips_tc[1].empty()) { 137 v0.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-2) ); 138 } 139 SGVertNormTex v1; 140 v1.SetVertex( toVec3f(vertices[strips_v[i-1]]) ); 141 v1.SetNormal( num_norms_is_num_verts ? normals[strips_n[i-1]] : 142 normals[strips_v[i-1]] ); 143 v1.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[1], tc0Scale, i-1) ); 144 if (!strips_tc[1].empty()) { 145 v1.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i-1) ); 146 } 147 SGVertNormTex v2; 148 v2.SetVertex( toVec3f(vertices[strips_v[i]]) ); 149 v2.SetNormal( num_norms_is_num_verts ? normals[strips_n[i]] : 150 normals[strips_v[i]] ); 151 v2.SetTexCoord( 0, getTexCoord(texCoords, strips_tc[0], tc0Scale, i) ); 152 if (!strips_tc[1].empty()) { 153 v2.SetTexCoord( 1, getTexCoord(texCoords, strips_tc[1], tc1Scale, i) ); 154 } 155 if (i%2) 156 triangles.insert(v1, v0, v2); 157 else 158 triangles.insert(v0, v1, v2); 159 } 160 } 161 162 static void addFanGeometry(SGTexturedTriangleBin & triangles,const SGBinObject & obj,unsigned grp,const SGVec2f & tc0Scale,const SGVec2f & tc1Scale)163 addFanGeometry(SGTexturedTriangleBin& triangles, 164 const SGBinObject& obj, unsigned grp, 165 const SGVec2f& tc0Scale, 166 const SGVec2f& tc1Scale) 167 { 168 const std::vector<SGVec3d>& vertices(obj.get_wgs84_nodes()); 169 const std::vector<SGVec3f>& normals(obj.get_normals()); 170 const std::vector<SGVec2f>& texCoords(obj.get_texcoords()); 171 const int_list& fans_v(obj.get_fans_v()[grp]); 172 const int_list& fans_n(obj.get_fans_n()[grp]); 173 const tci_list& fans_tc(obj.get_fans_tcs()[grp]); 174 bool num_norms_is_num_verts = true; 175 176 if (fans_v.size() != fans_n.size()) { 177 // If the normal indices do not match, they should be inmplicitly 178 // the same than the vertex indices. 179 num_norms_is_num_verts = false; 180 } 181 182 if ( !fans_tc[1].empty() ) { 183 triangles.hasSecondaryTexCoord(true); 184 } 185 186 SGVertNormTex v0; 187 v0.SetVertex( toVec3f(vertices[fans_v[0]]) ); 188 v0.SetNormal( num_norms_is_num_verts ? normals[fans_n[0]] : 189 normals[fans_v[0]] ); 190 v0.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 0) ); 191 if (!fans_tc[1].empty()) { 192 v0.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 0) ); 193 } 194 SGVertNormTex v1; 195 v1.SetVertex( toVec3f(vertices[fans_v[1]]) ); 196 v1.SetNormal( num_norms_is_num_verts ? normals[fans_n[1]] : 197 normals[fans_v[1]] ); 198 v1.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, 1) ); 199 if (!fans_tc[1].empty()) { 200 v1.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, 1) ); 201 } 202 for (unsigned i = 2; i < fans_v.size(); ++i) { 203 SGVertNormTex v2; 204 v2.SetVertex( toVec3f(vertices[fans_v[i]]) ); 205 v2.SetNormal( num_norms_is_num_verts ? normals[fans_n[i]] : 206 normals[fans_v[i]] ); 207 v2.SetTexCoord( 0, getTexCoord(texCoords, fans_tc[0], tc0Scale, i) ); 208 if (!fans_tc[1].empty()) { 209 v2.SetTexCoord( 1, getTexCoord(texCoords, fans_tc[1], tc1Scale, i) ); 210 } 211 triangles.insert(v0, v1, v2); 212 v1 = v2; 213 } 214 } 215 216 bool insertSurfaceGeometry(const SGBinObject & obj,SGMaterialCache * matcache)217 insertSurfaceGeometry(const SGBinObject& obj, SGMaterialCache* matcache) 218 { 219 if (obj.get_tris_n().size() < obj.get_tris_v().size() || 220 obj.get_tris_tcs().size() < obj.get_tris_v().size()) { 221 SG_LOG(SG_TERRAIN, SG_ALERT, 222 "Group list sizes for triangles do not match!"); 223 return false; 224 } 225 226 for (unsigned grp = 0; grp < obj.get_tris_v().size(); ++grp) { 227 std::string materialName = obj.get_tri_materials()[grp]; 228 SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); 229 SGVec2f tc1Scale(1.0, 1.0); 230 addTriangleGeometry(materialTriangleMap[materialName], 231 obj, grp, tc0Scale, tc1Scale ); 232 } 233 234 if (obj.get_strips_n().size() < obj.get_strips_v().size() || 235 obj.get_strips_tcs().size() < obj.get_strips_v().size()) { 236 SG_LOG(SG_TERRAIN, SG_ALERT, 237 "Group list sizes for strips do not match!"); 238 return false; 239 } 240 for (unsigned grp = 0; grp < obj.get_strips_v().size(); ++grp) { 241 std::string materialName = obj.get_strip_materials()[grp]; 242 SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); 243 SGVec2f tc1Scale(1.0, 1.0); 244 addStripGeometry(materialTriangleMap[materialName], 245 obj, grp, tc0Scale, tc1Scale); 246 } 247 248 if (obj.get_fans_n().size() < obj.get_fans_v().size() || 249 obj.get_fans_tcs().size() < obj.get_fans_v().size()) { 250 SG_LOG(SG_TERRAIN, SG_ALERT, 251 "Group list sizes for fans do not match!"); 252 return false; 253 } 254 for (unsigned grp = 0; grp < obj.get_fans_v().size(); ++grp) { 255 std::string materialName = obj.get_fan_materials()[grp]; 256 SGVec2f tc0Scale = getTexCoordScale(materialName, matcache); 257 SGVec2f tc1Scale(1.0, 1.0); 258 addFanGeometry(materialTriangleMap[materialName], 259 obj, grp, tc0Scale, tc1Scale ); 260 } 261 return true; 262 } 263 getSurfaceGeometry(SGMaterialCache * matcache,bool useVBOs) const264 osg::Node* getSurfaceGeometry(SGMaterialCache* matcache, bool useVBOs) const 265 { 266 if (materialTriangleMap.empty()) 267 return 0; 268 269 EffectGeode* eg = NULL; 270 osg::Group* group = (materialTriangleMap.size() > 1 ? new osg::Group : NULL); 271 if (group) { 272 group->setName("surfaceGeometryGroup"); 273 } 274 275 //osg::Geode* geode = new osg::Geode; 276 SGMaterialTriangleMap::const_iterator i; 277 for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { 278 osg::Geometry* geometry = i->second.buildGeometry(useVBOs); 279 SGMaterial *mat = NULL; 280 if (matcache) { 281 mat = matcache->find(i->first); 282 } 283 eg = new EffectGeode; 284 eg->setName("EffectGeode"); 285 if (mat) { 286 eg->setMaterial(mat); 287 eg->setEffect(mat->get_one_effect(i->second.getTextureIndex())); 288 } else { 289 eg->setMaterial(NULL); 290 } 291 eg->addDrawable(geometry); 292 eg->runGenerators(geometry); // Generate extra data needed by effect 293 if (group) { 294 group->addChild(eg); 295 } 296 } 297 298 if (group) { 299 return group; 300 } else { 301 return eg; 302 } 303 } 304 }; 305