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