]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/matlib.cxx
Canvas: fix element mouse hit detection with OSG 3.3.2.
[simgear.git] / simgear / scene / material / matlib.cxx
1 // materialmgr.cxx -- class to handle material properties
2 //
3 // Written by Curtis Olson, started May 1998.
4 //
5 // Copyright (C) 1998  Curtis L. Olson  - http://www.flightgear.org/~curt
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <simgear_config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29 #include <simgear/constants.h>
30 #include <simgear/structure/exception.hxx>
31
32 #include <string.h>
33 #include <string>
34
35 #include <osgDB/Registry>
36
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/misc/sg_path.hxx>
39 #include <simgear/misc/sgstream.hxx>
40 #include <simgear/props/props.hxx>
41 #include <simgear/props/props_io.hxx>
42 #include <simgear/props/condition.hxx>
43 #include <simgear/scene/tgdb/userdata.hxx>
44 #include <simgear/threads/SGThread.hxx>
45 #include <simgear/threads/SGGuard.hxx>
46
47 #include "mat.hxx"
48
49 #include "Effect.hxx"
50 #include "Technique.hxx"
51 #include "matlib.hxx"
52
53 using std::string;
54
55
56 class SGMaterialLib::MatLibPrivate
57 {
58 public:
59     SGMutex mutex;
60 };
61
62 // Constructor
63 SGMaterialLib::SGMaterialLib ( void ) :
64     d(new MatLibPrivate)
65 {
66 }
67
68 // Load a library of material properties
69 bool SGMaterialLib::load( const string &fg_root, const string& mpath,
70         SGPropertyNode *prop_root )
71 {
72     SGPropertyNode materialblocks;
73
74     SG_LOG( SG_INPUT, SG_INFO, "Reading materials from " << mpath );
75     try {
76         readProperties( mpath, &materialblocks );
77     } catch (const sg_exception &ex) {
78         SG_LOG( SG_INPUT, SG_ALERT, "Error reading materials: "
79                 << ex.getMessage() );
80         throw;
81     }
82     osg::ref_ptr<osgDB::Options> options
83         = new osgDB::Options;
84     options->setObjectCacheHint(osgDB::Options::CACHE_ALL);
85     options->setDatabasePath(fg_root);
86
87     simgear::PropertyList blocks = materialblocks.getChildren("region");
88     simgear::PropertyList::const_iterator block_iter = blocks.begin();
89
90     for (; block_iter != blocks.end(); block_iter++) {
91         SGPropertyNode_ptr node = block_iter->get();
92
93                 // Read name node purely for logging purposes
94                 const SGPropertyNode *nameNode = node->getChild("name");
95                 if (nameNode) {
96                         SG_LOG( SG_TERRAIN, SG_INFO, "Loading region "
97                                         << nameNode->getStringValue());
98                 }
99
100                 // Read list of areas
101                 AreaList* arealist = new AreaList;
102
103                 const simgear::PropertyList areas = node->getChildren("area");
104                 simgear::PropertyList::const_iterator area_iter = areas.begin();
105                 for (; area_iter != areas.end(); area_iter++) {
106                         float x1 = area_iter->get()->getFloatValue("lon1", -180.0f);
107                         float x2 = area_iter->get()->getFloatValue("lon2", 180.0);
108                         float y1 = area_iter->get()->getFloatValue("lat1", -90.0f);
109                         float y2 = area_iter->get()->getFloatValue("lat2", 90.0f);
110                         SGRect<float> rect = SGRect<float>(
111                                         std::min<float>(x1, x2),
112                                         std::min<float>(y1, y2),
113                                         fabs(x2 - x1),
114                                         fabs(y2 - y1));
115                         arealist->push_back(rect);
116                         SG_LOG( SG_TERRAIN, SG_INFO, " Area ("
117                                         << rect.x() << ","
118                                         << rect.y() << ") width:"
119                                         << rect.width() << " height:"
120                                         << rect.height());
121                 }
122
123                 // Read conditions node
124                 const SGPropertyNode *conditionNode = node->getChild("condition");
125                 SGSharedPtr<const SGCondition> condition;
126                 if (conditionNode) {
127                         condition = sgReadCondition(prop_root, conditionNode);
128                 }
129
130                 // Now build all the materials for this set of areas and conditions
131
132                 const simgear::PropertyList materials = node->getChildren("material");
133                 simgear::PropertyList::const_iterator materials_iter = materials.begin();
134                 for (; materials_iter != materials.end(); materials_iter++) {
135                         const SGPropertyNode *node = materials_iter->get();
136                         SGSharedPtr<SGMaterial> m =
137                                         new SGMaterial(options.get(), node, prop_root, arealist, condition);
138
139                         std::vector<SGPropertyNode_ptr>names = node->getChildren("name");
140                         for ( unsigned int j = 0; j < names.size(); j++ ) {
141                                 string name = names[j]->getStringValue();
142                                 // cerr << "Material " << name << endl;
143                                 matlib[name].push_back(m);
144                                 m->add_name(name);
145                                 SG_LOG( SG_TERRAIN, SG_DEBUG, "  Loading material "
146                                                 << names[j]->getStringValue() );
147                         }
148                 }
149     }
150
151     return true;
152 }
153
154 // find a material record by material name and tile center
155 SGMaterial *SGMaterialLib::find( const string& material, const SGVec2f center ) const
156 {
157     SGMaterial *result = NULL;
158     const_material_map_iterator it = matlib.find( material );
159     if ( it != end() ) {            
160         // We now have a list of materials that match this
161         // name. Find the first one that matches.
162         // We start at the end of the list, as the materials
163         // list is ordered with the smallest regions at the end.
164         material_list::const_reverse_iterator iter = it->second.rbegin();
165         while (iter != it->second.rend()) {
166             result = *iter;
167             if (result->valid(center)) {
168                 return result;
169             }
170             iter++;
171         }
172     }
173
174     return NULL;
175 }
176
177 // find a material record by material name and tile center
178 SGMaterial *SGMaterialLib::find( const string& material, const SGGeod& center ) const
179 {
180         SGVec2f c = SGVec2f(center.getLongitudeDeg(), center.getLatitudeDeg());
181         return find(material, c);
182 }
183
184 SGMaterialCache *SGMaterialLib::generateMatCache(SGVec2f center)
185 {
186         SGMaterialCache* newCache = new SGMaterialCache();
187     material_map::const_reverse_iterator it = matlib.rbegin();
188     for (; it != matlib.rend(); ++it) {
189         newCache->insert(it->first, find(it->first, center));
190     }
191     
192     return newCache;
193 }
194
195 SGMaterialCache *SGMaterialLib::generateMatCache(SGGeod center)
196 {
197         SGVec2f c = SGVec2f(center.getLongitudeDeg(), center.getLatitudeDeg());
198         return SGMaterialLib::generateMatCache(c);
199 }
200
201
202 // Destructor
203 SGMaterialLib::~SGMaterialLib ( void ) {
204     SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size());
205 }
206
207 const SGMaterial *SGMaterialLib::findMaterial(const osg::Geode* geode)
208 {
209     if (!geode)
210         return 0;
211     const simgear::EffectGeode* effectGeode;
212     effectGeode = dynamic_cast<const simgear::EffectGeode*>(geode);
213     if (!effectGeode)
214         return 0;
215     const simgear::Effect* effect = effectGeode->getEffect();
216     if (!effect)
217         return 0;
218     const SGMaterialUserData* userData;
219     userData = dynamic_cast<const SGMaterialUserData*>(effect->getUserData());
220     if (!userData)
221         return 0;
222     return userData->getMaterial();
223 }
224
225 // Constructor
226 SGMaterialCache::SGMaterialCache ( void )
227 {
228 }
229
230 // Insertion into the material cache
231 void SGMaterialCache::insert(const std::string& name, SGSharedPtr<SGMaterial> material) {
232         cache[name] = material;
233 }
234
235 // Search of the material cache
236 SGMaterial *SGMaterialCache::find(const string& material) const
237 {
238     SGMaterialCache::material_cache::const_iterator it = cache.find(material);
239     if (it == cache.end())
240         return NULL;
241
242     return it->second;
243 }
244
245 // Destructor
246 SGMaterialCache::~SGMaterialCache ( void ) {
247     SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialCache::~SGMaterialCache() size=" << cache.size());
248 }