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