]> git.mxchange.org Git - simgear.git/blob - simgear/hla/RTIObjectInstance.hxx
Add an initial implementation of a rti/hla dispatcher.
[simgear.git] / simgear / hla / RTIObjectInstance.hxx
1 // Copyright (C) 2009 - 2010  Mathias Froehlich - Mathias.Froehlich@web.de
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
18 #ifndef RTIObjectInstance_hxx
19 #define RTIObjectInstance_hxx
20
21 #include <list>
22 #include <map>
23 #include <string>
24 #include <vector>
25 #include "simgear/debug/logstream.hxx"
26 #include "simgear/structure/SGReferenced.hxx"
27 #include "simgear/structure/SGWeakPtr.hxx"
28 #include "simgear/timing/timestamp.hxx"
29 #include "RTIData.hxx"
30 #include "RTIObjectClass.hxx"
31 #include "HLADataElement.hxx"
32
33 class SGTimeStamp;
34
35 namespace simgear {
36
37 class RTIObjectClass;
38 class HLAObjectInstance;
39
40 class RTIObjectInstance : public SGReferenced {
41 public:
42     RTIObjectInstance(HLAObjectInstance* hlaObjectInstance);
43     virtual ~RTIObjectInstance();
44
45     virtual const RTIObjectClass* getObjectClass() const = 0;
46
47     virtual std::string getName() const = 0;
48
49     unsigned getNumAttributes() const;
50     unsigned getAttributeIndex(const std::string& name) const;
51     std::string getAttributeName(unsigned index) const;
52
53     // FIXME: factor out an ambassador base
54     virtual void addToRequestQueue() = 0;
55
56     virtual void deleteObjectInstance(const RTIData& tag) = 0;
57     virtual void deleteObjectInstance(const SGTimeStamp& timeStamp, const RTIData& tag) = 0;
58     virtual void localDeleteObjectInstance() = 0;
59
60     virtual void requestObjectAttributeValueUpdate() = 0;
61
62     virtual void updateAttributeValues(const RTIData& tag) = 0;
63     virtual void updateAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag) = 0;
64
65     void removeInstance(const RTIData& tag);
66     // Call this if you want to roll up the queued timestamed updates
67     // and reflect that into the attached data elements.
68     void reflectQueuedAttributeValues(const SGTimeStamp& timeStamp)
69     {
70         // replay all updates up to the given timestamp
71         UpdateListMap::iterator last = _updateListMap.upper_bound(timeStamp);
72         for (UpdateListMap::iterator i = _updateListMap.begin(); i != last; ++i) {
73             for (UpdateList::iterator j = i->second.begin(); j != i->second.end(); ++j) {
74                 // FIXME have a variant that takes the timestamp?
75                 reflectAttributeValues(j->_indexDataPairList, j->_tag);
76             }
77             putUpdateToPool(i->second);
78         }
79     }
80     void reflectAttributeValues(const RTIIndexDataPairList& dataPairList, const RTIData& tag);
81     void reflectAttributeValues(const RTIIndexDataPairList& dataPairList, const SGTimeStamp& timeStamp, const RTIData& tag);
82     void reflectAttributeValue(unsigned i, const RTIData& data)
83     {
84         if (_attributeData.size() <= i)
85             return;
86         HLADataElement* dataElement = _attributeData[i]._dataElement.get();
87         if (!dataElement)
88             return;
89         HLADecodeStream stream(data);
90         dataElement->decode(stream);
91     }
92
93     const HLADataType* getAttributeDataType(unsigned i) const
94     {
95         return getObjectClass()->getAttributeDataType(i);
96     }
97     HLAUpdateType getAttributeUpdateType(unsigned i) const
98     {
99         return getObjectClass()->getAttributeUpdateType(i);
100     }
101     bool getAttributeSubscribed(unsigned i) const
102     {
103         return getObjectClass()->getAttributeSubscribed(i);
104     }
105     bool getAttributePublished(unsigned i) const
106     {
107         return getObjectClass()->getAttributePublished(i);
108     }
109
110     HLADataElement* getDataElement(unsigned i)
111     {
112         if (_attributeData.size() <= i)
113             return 0;
114         return _attributeData[i]._dataElement.get();
115     }
116     const HLADataElement* getDataElement(unsigned i) const
117     {
118         if (_attributeData.size() <= i)
119             return 0;
120         return _attributeData[i]._dataElement.get();
121     }
122     void setDataElement(unsigned i, HLADataElement* dataElement)
123     {
124         if (_attributeData.size() <= i)
125             return;
126         _attributeData[i]._dataElement = dataElement;
127     }
128
129     void updateAttributesFromClass(bool owned)
130     {
131         // FIXME: rethink that!!!
132         unsigned numAttributes = getNumAttributes();
133         unsigned i = 0;
134         for (; i < _attributeData.size(); ++i) {
135             if (getAttributePublished(i)) {
136             } else {
137                 _attributeData[i].setUpdateEnabled(false);
138                 _attributeData[i].setOwned(false);
139             }
140         }
141         _attributeData.resize(numAttributes);
142         for (; i < numAttributes; ++i) {
143             if (getAttributePublished(i)) {
144                 _attributeData[i].setUpdateEnabled(true);
145                 _attributeData[i].setOwned(owned);
146             } else {
147                 _attributeData[i].setUpdateEnabled(false);
148                 _attributeData[i].setOwned(false);
149             }
150         }
151     }
152
153     void setAttributeForceUpdate(unsigned i)
154     {
155         if (_attributeData.size() <= i)
156             return;
157         _attributeData[i].setForceUpdate(true);
158     }
159     void setAttributeInScope(unsigned i, bool inScope)
160     {
161         if (_attributeData.size() <= i)
162             return;
163         _attributeData[i].setInScope(inScope);
164     }
165     void setAttributeUpdateEnabled(unsigned i, bool enabled)
166     {
167         if (_attributeData.size() <= i)
168             return;
169         _attributeData[i].setUpdateEnabled(enabled);
170     }
171     void setAttributeUpdated(unsigned i)
172     {
173         if (_attributeData.size() <= i)
174             return;
175         _attributeData[i].setForceUpdate(false);
176     }
177     bool getAttributeEffectiveUpdateEnabled(unsigned i)
178     {
179         if (_attributeData.size() <= i)
180             return false;
181         if (!getAttributePublished(i))
182             return false;
183         if (!_attributeData[i]._updateEnabled)
184             return false;
185         if (!_attributeData[i]._inScope)
186             return false;
187         if (_attributeData[i]._forceUpdate)
188             return true;
189         switch (getAttributeUpdateType(i)) {
190         case HLAPeriodicUpdate:
191             return true;
192         case HLAConditionalUpdate:
193             return true; // FIXME
194         case HLAStaticUpdate:
195             return false;
196         default:
197             return false;
198         }
199     }
200     void setRequestAttributeUpdate(bool request)
201     {
202         for (unsigned i = 0; i < getNumAttributes(); ++i) {
203             if (getAttributeUpdateType(i) == HLAPeriodicUpdate)
204                 continue;
205             setRequestAttributeUpdate(i, request);
206         }
207     }
208     void setRequestAttributeUpdate(unsigned i, bool request)
209     {
210         if (_attributeData.size() <= i)
211             return;
212         _attributeData[i].setRequestUpdate(request);
213         if (request) {
214             if (!_pendingAttributeUpdateRequest) {
215                 _pendingAttributeUpdateRequest = true;
216                 addToRequestQueue();
217             }
218         }
219     }
220     bool getRequestAttributeUpdate(unsigned i) const
221     {
222         if (_attributeData.size() <= i)
223             return false;
224         return _attributeData[i]._requestUpdate;
225     }
226
227     void flushPendingRequests()
228     {
229         if (_pendingAttributeUpdateRequest) {
230             requestObjectAttributeValueUpdate();
231             _pendingAttributeUpdateRequest = false;
232         }
233     }
234
235 protected:
236     // The backward reference to the user visible object
237     SGWeakPtr<HLAObjectInstance> _hlaObjectInstance;
238
239     // Is true if we should emit a requestattr
240     bool _pendingAttributeUpdateRequest;
241
242     // Contains a full update as it came in from the RTI
243     struct Update {
244         RTIIndexDataPairList _indexDataPairList;
245         RTIData _tag;
246     };
247     // A bunch of updates for the same timestamp
248     typedef std::list<Update> UpdateList;
249     // The timestamp sorted list of updates
250     typedef std::map<SGTimeStamp, UpdateList> UpdateListMap;
251
252     // The timestamped updates sorted by timestamp
253     UpdateListMap _updateListMap;
254
255     // The pool of unused updates so that we do not need to malloc/free each time
256     UpdateList _updateList;
257
258     void getUpdateFromPool(UpdateList& updateList)
259     {
260         if (_updateList.empty())
261             updateList.push_back(Update());
262         else
263             updateList.splice(updateList.end(), _updateList, _updateList.begin());
264     }
265     void putUpdateToPool(UpdateList& updateList)
266     {
267         for (UpdateList::iterator i = updateList.begin(); i != updateList.end(); ++i)
268             putDataToPool(i->_indexDataPairList);
269         _updateList.splice(_updateList.end(), updateList);
270     }
271
272     // Appends the updates in the list to the given timestamps updates
273     void scheduleUpdates(const SGTimeStamp& timeStamp, UpdateList& updateList)
274     {
275         UpdateListMap::iterator i = _updateListMap.find(timeStamp);
276         if (i == _updateListMap.end())
277             i = _updateListMap.insert(UpdateListMap::value_type(timeStamp, UpdateList())).first;
278         i->second.splice(i->second.end(), updateList);
279     }
280
281     // This adds raw storage for attribute index i to the end of the dataPairList.
282     void getDataFromPool(unsigned i, RTIIndexDataPairList& dataPairList)
283     {
284         if (_attributeData.size() <= i) {
285             SG_LOG(SG_NETWORK, SG_WARN, "RTI: Invalid object attribute index!");
286             return;
287         }
288
289         // Nothing left in the pool - so allocate something
290         if (_attributeData[i]._indexDataPairList.empty()) {
291             dataPairList.push_back(RTIIndexDataPairList::value_type());
292             dataPairList.back().first = i;
293             return;
294         }
295
296         // Take one from the pool
297         dataPairList.splice(dataPairList.end(),
298                             _attributeData[i]._indexDataPairList,
299                             _attributeData[i]._indexDataPairList.begin());
300     }
301
302     void putDataToPool(RTIIndexDataPairList& dataPairList)
303     {
304         while (!dataPairList.empty()) {
305             // Put back into the pool
306             unsigned i = dataPairList.front().first;
307             if (_attributeData.size() <= i) {
308                 // should not happen!!!
309                 SG_LOG(SG_NETWORK, SG_WARN, "RTI: Invalid object attribute index!");
310                 dataPairList.pop_front();
311             } else {
312                 _attributeData[i]._indexDataPairList.splice(_attributeData[i]._indexDataPairList.begin(),
313                                                             dataPairList, dataPairList.begin());
314             }
315         }
316     }
317
318     struct AttributeData {
319         AttributeData() : _owned(false), _inScope(true), _updateEnabled(true), _forceUpdate(false), _requestUpdate(false)
320         { }
321
322         // The hla level data element with tha actual local program
323         // accessible data.
324         SGSharedPtr<HLADataElement> _dataElement;
325         // SGSharedPtr<HLADataElement::TimeStamp> _timeStamp;
326
327         // Pool of already allocated raw data used for reflection of updates
328         RTIIndexDataPairList _indexDataPairList;
329
330         void setOwned(bool owned)
331         { _owned = owned; }
332         void setInScope(bool inScope)
333         { _inScope = inScope; }
334         void setUpdateEnabled(bool updateEnabled)
335         { _updateEnabled = updateEnabled; }
336         void setForceUpdate(bool forceUpdate)
337         { _forceUpdate = forceUpdate; }
338         void setRequestUpdate(bool requestUpdate)
339         { _requestUpdate = requestUpdate; }
340
341         bool _owned;
342         bool _inScope;
343         bool _updateEnabled;
344         bool _forceUpdate;
345         bool _requestUpdate;
346     };
347     std::vector<AttributeData> _attributeData;
348
349     friend class HLAObjectInstance;
350 };
351
352 }
353
354 #endif