]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/EffectBuilder.hxx
wip for effects in models
[simgear.git] / simgear / scene / material / EffectBuilder.hxx
1 // Copyright (C) 2009  Tim Moore timoore@redhat.com
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17 #ifndef SIMGEAR_EFFECTBUILDER_HXX
18 #define SIMGEAR_EFFECTBUILDER_HXX 1
19
20 #include <algorithm>
21 #include <map>
22 #include <string>
23 #include <cstring>
24
25 #include <osgDB/Registry>
26
27 #include <boost/multi_index_container.hpp>
28 #include <boost/multi_index/member.hpp>
29 #include <boost/multi_index/ordered_index.hpp>
30
31 #include <simgear/props/props.hxx>
32 #include <simgear/structure/exception.hxx>
33 #include <simgear/structure/SGSharedPtr.hxx>
34 #include <simgear/structure/Singleton.hxx>
35
36 /**
37  * Support classes for parsing effects.
38  */
39
40 namespace simgear
41 {
42 class Effect;
43
44 /**
45  * Builder that returns an object, probably an OSG object.
46  */
47 template<typename T>
48 class EffectBuilder : public SGReferenced
49 {
50 public:
51     virtual ~EffectBuilder() {}
52     virtual T* build(Effect* effect, const SGPropertyNode*,
53                      const osgDB::ReaderWriter::Options* options) = 0;
54     static T* buildFromType(Effect* effect, const std::string& type,
55                             const SGPropertyNode*props,
56                             const osgDB::ReaderWriter::Options* options)
57     {
58         BuilderMap& builderMap = getMap();
59         typename BuilderMap::iterator iter = builderMap.find(type);
60         if (iter != builderMap.end())
61             return iter->second->build(effect, props, options);
62         else
63             return 0;
64     }
65     struct Registrar;
66     friend struct Registrar;
67     struct Registrar
68     {
69         Registrar(const std::string& type, EffectBuilder* builder)
70         {
71             getMap().insert(std::make_pair(type, builder));
72         }
73     };
74 protected:
75     typedef std::map<std::string, SGSharedPtr<EffectBuilder> > BuilderMap;
76     struct BuilderMapSingleton : public simgear::Singleton<BuilderMapSingleton>
77     {
78         BuilderMap _map;
79     };
80     static BuilderMap& getMap()
81     {
82         return BuilderMapSingleton::instance()->_map;
83     }
84 };
85
86 // Tables of strings and constants. We want to reconstruct the effect
87 // property tree from OSG state sets, so the tables should be bi-directional.
88
89 // two-way map for building StateSets from property descriptions, and
90 // vice versa. Mostly copied from the boost documentation.
91
92 namespace effect
93 {
94 using boost::multi_index_container;
95 using namespace boost::multi_index;
96
97 // tags for accessing both sides of a bidirectional map
98
99 struct from{};
100 struct to{};
101
102 template <typename T>
103 struct EffectNameValue
104 {
105     // Don't use std::pair because we want to use aggregate intialization.
106     const char* first;
107     T second;
108 };
109
110 // The class template bidirectional_map wraps the specification
111 // of a bidirectional map based on multi_index_container.
112
113 template<typename FromType,typename ToType>
114 struct bidirectional_map
115 {
116     typedef std::pair<FromType,ToType> value_type;
117
118     /* A bidirectional map can be simulated as a multi_index_container
119      * of pairs of (FromType,ToType) with two unique indices, one
120      * for each member of the pair.
121      */
122
123     typedef multi_index_container<
124         value_type,
125         indexed_by<
126             ordered_unique<
127                 tag<from>, member<value_type, FromType, &value_type::first> >,
128             ordered_unique<
129                 tag<to>,  member<value_type, ToType, &value_type::second> >
130             >
131         > type;
132 };
133
134 template<typename T>
135 struct EffectPropertyMap
136 {
137     typedef typename bidirectional_map<std::string, T>::type BMap;
138     BMap _map;
139     template<int N>
140     EffectPropertyMap(const EffectNameValue<T> (&attrs)[N]);
141 };
142
143 template<typename T>
144 template<int N>
145 EffectPropertyMap<T>::EffectPropertyMap(const EffectNameValue<T> (&attrs)[N])
146 {
147     for (int i = 0; i < N; ++i)
148         _map.insert(typename BMap::value_type(attrs[i].first, attrs[i].second));
149 }
150
151 }
152
153 template<typename T>
154 bool findAttr(const effect::EffectPropertyMap<T>& pMap,
155               const SGPropertyNode* prop,
156               T& result)
157 {
158     using namespace effect;
159     if (!prop)
160         return false;
161     const char* name = prop->getStringValue();
162     if (!name)
163         return false;
164     typename EffectPropertyMap<T>::BMap::iterator itr
165         = pMap._map.get<from>().find(name);
166     if (itr == pMap._map.end()) {
167         return false;
168     } else {
169         result = itr->second;
170         return true;
171     }
172 }
173
174 template<typename T>
175 std::string findName(const effect::EffectPropertyMap<T>& pMap, T value)
176 {
177     using namespace effect;
178     std::string result;
179     typename EffectPropertyMap<T>::BMap::template index_iterator<to>::type itr
180         = pMap._map.get<to>().find(value);
181     if (itr != pMap._map.get<to>().end())
182         result = itr->first;
183     return result;
184 }
185
186 template<typename T>
187 std::string findName(const effect::EffectPropertyMap<T>& pMap, GLenum value)
188 {
189     return findName(pMap, static_cast<T>(value));
190 }
191
192 /**
193  * Given a property node from a pass, get its value either from it or
194  * from the effect parameters.
195  */
196
197 const SGPropertyNode* getEffectPropertyNode(Effect* effect,
198                                             const SGPropertyNode* prop);
199 /**
200  * Get a named child property from pass parameters or effect
201  * parameters.
202  */
203 const SGPropertyNode* getEffectPropertyChild(Effect* effect,
204                                              const SGPropertyNode* prop,
205                                              const char* name);
206
207 class BuilderException : public sg_exception
208 {
209 public:
210     BuilderException();
211     BuilderException(const char* message, const char* origin = 0);
212     BuilderException(const std::string& message, const std::string& = "");
213     virtual ~BuilderException() throw();
214 };
215 }
216 #endif