1 // Copyright (C) 2009 - 2010 Mathias Froehlich - Mathias.Froehlich@web.de
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.
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.
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.
18 #ifndef RTIObjectInstance_hxx
19 #define RTIObjectInstance_hxx
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"
38 class HLAObjectInstance;
40 class RTIObjectInstance : public SGReferenced {
42 RTIObjectInstance(HLAObjectInstance* hlaObjectInstance);
43 virtual ~RTIObjectInstance();
45 virtual const RTIObjectClass* getObjectClass() const = 0;
47 virtual std::string getName() const = 0;
49 unsigned getNumAttributes() const;
50 unsigned getAttributeIndex(const std::string& name) const;
51 std::string getAttributeName(unsigned index) const;
53 // FIXME: factor out an ambassador base
54 virtual void addToRequestQueue() = 0;
56 virtual void deleteObjectInstance(const RTIData& tag) = 0;
57 virtual void deleteObjectInstance(const SGTimeStamp& timeStamp, const RTIData& tag) = 0;
58 virtual void localDeleteObjectInstance() = 0;
60 virtual void requestObjectAttributeValueUpdate() = 0;
62 virtual void updateAttributeValues(const RTIData& tag) = 0;
63 virtual void updateAttributeValues(const SGTimeStamp& timeStamp, const RTIData& tag) = 0;
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)
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);
77 putUpdateToPool(i->second);
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)
84 if (_attributeData.size() <= i)
86 HLADataElement* dataElement = _attributeData[i]._dataElement.get();
89 HLADecodeStream stream(data);
90 dataElement->decode(stream);
93 const HLADataType* getAttributeDataType(unsigned i) const
95 return getObjectClass()->getAttributeDataType(i);
97 HLAUpdateType getAttributeUpdateType(unsigned i) const
99 return getObjectClass()->getAttributeUpdateType(i);
101 bool getAttributeSubscribed(unsigned i) const
103 return getObjectClass()->getAttributeSubscribed(i);
105 bool getAttributePublished(unsigned i) const
107 return getObjectClass()->getAttributePublished(i);
110 HLADataElement* getDataElement(unsigned i)
112 if (_attributeData.size() <= i)
114 return _attributeData[i]._dataElement.get();
116 const HLADataElement* getDataElement(unsigned i) const
118 if (_attributeData.size() <= i)
120 return _attributeData[i]._dataElement.get();
122 void setDataElement(unsigned i, HLADataElement* dataElement)
124 if (_attributeData.size() <= i)
126 _attributeData[i]._dataElement = dataElement;
129 void updateAttributesFromClass(bool owned)
131 // FIXME: rethink that!!!
132 unsigned numAttributes = getNumAttributes();
134 for (; i < _attributeData.size(); ++i) {
135 if (getAttributePublished(i)) {
137 _attributeData[i].setUpdateEnabled(false);
138 _attributeData[i].setOwned(false);
141 _attributeData.resize(numAttributes);
142 for (; i < numAttributes; ++i) {
143 if (getAttributePublished(i)) {
144 _attributeData[i].setUpdateEnabled(true);
145 _attributeData[i].setOwned(owned);
147 _attributeData[i].setUpdateEnabled(false);
148 _attributeData[i].setOwned(false);
153 void setAttributeForceUpdate(unsigned i)
155 if (_attributeData.size() <= i)
157 _attributeData[i].setForceUpdate(true);
159 void setAttributeInScope(unsigned i, bool inScope)
161 if (_attributeData.size() <= i)
163 _attributeData[i].setInScope(inScope);
165 void setAttributeUpdateEnabled(unsigned i, bool enabled)
167 if (_attributeData.size() <= i)
169 _attributeData[i].setUpdateEnabled(enabled);
171 void setAttributeUpdated(unsigned i)
173 if (_attributeData.size() <= i)
175 _attributeData[i].setForceUpdate(false);
177 bool getAttributeEffectiveUpdateEnabled(unsigned i)
179 if (_attributeData.size() <= i)
181 if (!getAttributePublished(i))
183 if (!_attributeData[i]._updateEnabled)
185 if (!_attributeData[i]._inScope)
187 if (_attributeData[i]._forceUpdate)
189 switch (getAttributeUpdateType(i)) {
190 case HLAPeriodicUpdate:
192 case HLAConditionalUpdate:
193 return true; // FIXME
194 case HLAStaticUpdate:
200 void setRequestAttributeUpdate(bool request)
202 for (unsigned i = 0; i < getNumAttributes(); ++i) {
203 if (getAttributeUpdateType(i) == HLAPeriodicUpdate)
205 setRequestAttributeUpdate(i, request);
208 void setRequestAttributeUpdate(unsigned i, bool request)
210 if (_attributeData.size() <= i)
212 _attributeData[i].setRequestUpdate(request);
214 if (!_pendingAttributeUpdateRequest) {
215 _pendingAttributeUpdateRequest = true;
220 bool getRequestAttributeUpdate(unsigned i) const
222 if (_attributeData.size() <= i)
224 return _attributeData[i]._requestUpdate;
227 void flushPendingRequests()
229 if (_pendingAttributeUpdateRequest) {
230 requestObjectAttributeValueUpdate();
231 _pendingAttributeUpdateRequest = false;
236 // The backward reference to the user visible object
237 SGWeakPtr<HLAObjectInstance> _hlaObjectInstance;
239 // Is true if we should emit a requestattr
240 bool _pendingAttributeUpdateRequest;
242 // Contains a full update as it came in from the RTI
244 RTIIndexDataPairList _indexDataPairList;
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;
252 // The timestamped updates sorted by timestamp
253 UpdateListMap _updateListMap;
255 // The pool of unused updates so that we do not need to malloc/free each time
256 UpdateList _updateList;
258 void getUpdateFromPool(UpdateList& updateList)
260 if (_updateList.empty())
261 updateList.push_back(Update());
263 updateList.splice(updateList.end(), _updateList, _updateList.begin());
265 void putUpdateToPool(UpdateList& updateList)
267 for (UpdateList::iterator i = updateList.begin(); i != updateList.end(); ++i)
268 putDataToPool(i->_indexDataPairList);
269 _updateList.splice(_updateList.end(), updateList);
272 // Appends the updates in the list to the given timestamps updates
273 void scheduleUpdates(const SGTimeStamp& timeStamp, UpdateList& updateList)
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);
281 // This adds raw storage for attribute index i to the end of the dataPairList.
282 void getDataFromPool(unsigned i, RTIIndexDataPairList& dataPairList)
284 if (_attributeData.size() <= i) {
285 SG_LOG(SG_NETWORK, SG_WARN, "RTI: Invalid object attribute index!");
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;
296 // Take one from the pool
297 dataPairList.splice(dataPairList.end(),
298 _attributeData[i]._indexDataPairList,
299 _attributeData[i]._indexDataPairList.begin());
302 void putDataToPool(RTIIndexDataPairList& dataPairList)
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();
312 _attributeData[i]._indexDataPairList.splice(_attributeData[i]._indexDataPairList.begin(),
313 dataPairList, dataPairList.begin());
318 struct AttributeData {
319 AttributeData() : _owned(false), _inScope(true), _updateEnabled(true), _forceUpdate(false), _requestUpdate(false)
322 // The hla level data element with tha actual local program
324 SGSharedPtr<HLADataElement> _dataElement;
325 // SGSharedPtr<HLADataElement::TimeStamp> _timeStamp;
327 // Pool of already allocated raw data used for reflection of updates
328 RTIIndexDataPairList _indexDataPairList;
330 void setOwned(bool 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; }
347 std::vector<AttributeData> _attributeData;
349 friend class HLAObjectInstance;