1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2007 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
37 \*---------------------------------------------------------------------------*/
39 #include "OSGOSBCommonElement.h"
40 #include "OSGOSBElementFactory.h"
41 #include "OSGOSBRootElement.h"
43 #include "OSGAttachmentContainer.h"
44 #include "OSGChunkMaterial.h"
47 #include "OSGStateChunk.h"
49 #include "OSGDynFieldContainerInterface.h"
53 /*-------------------------------------------------------------------------*/
54 /* OSBCommonElement */
55 /*-------------------------------------------------------------------------*/
57 /*! \class OSG::OSBCommonElement
58 This element is intended as base class for most (all) other elements and
59 provides functions that simplify implementing these.
60 It itself is abstract and can not handle any types.
63 /*-------------------------------------------------------------------------*/
66 const UInt8
OSBCommonElement::FCPtrUnknown
= 0;
67 const UInt8
OSBCommonElement::FCPtrFieldContainer
= 1;
68 const UInt8
OSBCommonElement::FCPtrNode
= 2;
69 const UInt8
OSBCommonElement::FCPtrNodeCore
= 3;
70 const UInt8
OSBCommonElement::FCPtrAttachment
= 4;
71 const UInt8
OSBCommonElement::FCPtrMaterial
= 5;
72 const UInt8
OSBCommonElement::FCPtrStateChunk
= 6;
74 /*-------------------------------------------------------------------------*/
77 OSBCommonElement::OSBCommonElement(OSBRootElement
*root
, UInt16 version
)
78 : Inherited(root
, version
)
83 /*-------------------------------------------------------------------------*/
86 OSBCommonElement::~OSBCommonElement(void)
91 void OSBCommonElement::postMap(void)
95 /*-------------------------------------------------------------------------*/
99 OSBCommonElement::read(const std::string
&/* typeName */)
105 OSBCommonElement::postRead(void)
110 /*-------------------------------------------------------------------------*/
114 OSBCommonElement::preWrite(FieldContainer
* const /* fc */)
120 OSBCommonElement::write(void)
125 /*-------------------------------------------------------------------------*/
126 /* Reading Helper methods */
128 /*! Reads the common part introducing a FieldContainer and returns
129 the information in \a typeName and \a fcId.
131 \param[out] typeName Type of the next container in the stream or "" if
132 no more data is available.
133 \param[out] fcId Id of the next container - only valid if true is returned.
135 \return If another container is to be read, true is returned,
139 OSBCommonElement::readFieldContainerHeader(
140 std::string
&typeName
,
143 OSG_OSB_LOG(("OSBCommonElement::readFieldContainerHeader\n"));
145 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
147 rh
->getValue(typeName
);
154 OSG_OSB_LOG(("OSBCommonElement::readFieldContainerHeader: [%s] [%u]\n",
155 typeName
.c_str(), fcId
));
160 /*! Reads the common part introducing a Field and returns the information
161 in \a fieldName, \a fieldTypeName, and \a fieldSize.
162 By default reading would stop an a field name of "", by passing a string
163 of type names in \a endMarkers additional stop conditions can be specified.
165 The format of the \a endMarkers string is: "'name1' 'name2' 'name3'", the
166 spaces between the "'" are mandatory.
168 \param[in] endMarkers String of field names on which reading stops.
169 \param[out] fieldName Name of the next field in the stream.
170 \param[out] fieldTypeName Type of the next field in the stream - only valid
172 \param[out] fieldSize Size in bytes of the next field in the stream -
173 only valid if true is returned.
175 \return False, if an endMarker (including the implicit "") is encountered,
178 \sa OSG::OSBCommonElement::readFieldContent
179 \sa OSG::OSBCommonElement::readFieldHeaderContinue
182 OSBCommonElement::readFieldHeader(
183 const std::string
&endMarkers
,
184 std::string
&fieldName
,
185 std::string
&fieldTypeName
,
188 OSG_OSB_LOG(("OSBCommonElement::readFieldHeader\n"));
190 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
192 rh
->getValue(fieldName
);
194 return readFieldHeaderContinue(endMarkers
, fieldName
,
195 fieldTypeName
, fieldSize
);
198 /*! Reads the common part introducing a Field, but after the field name is
199 already consumed from the input stream. This is mainly useful to continue
200 reading after readFields stopped on a non empty endMarkers entry.
201 The information from the field header is returned in \a fieldTypeName and
204 By default reading would stop an a field name of "", by passing a string
205 of type names in \a endMarkers additional stop conditions can be specified.
207 The format of the \a endMarkers string is: "'name1' 'name2' 'name3'", the
208 spaces between the "'" are mandatory.
210 \param[in] endMarkers String of field names on which reading stops.
211 \param[in] fieldName Name of the next field in the stream.
212 \param[out] fieldTypeName Type of the next field in the stream - only valid
214 \param[out] fieldSize Size in bytes of the next field in the stream -
215 only valid if true is returned.
217 \return False, if an endMarker (including the implicit "") is encountered,
220 \sa OSG::OSBCommonElement::readFieldContent
221 \sa OSG::OSBCommonElement::readFieldHeader
224 OSBCommonElement::readFieldHeaderContinue(
225 const std::string
&endMarkers
,
226 const std::string
&fieldName
,
227 std::string
&fieldTypeName
,
230 OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue\n"));
232 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
234 if(fieldName
.empty() ||
235 (!endMarkers
.empty() &&
236 (endMarkers
.find("'" + fieldName
+ "'") != std::string::npos
)))
238 OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue: "
239 "Found field end marker.\n"));
245 rh
->getValue(fieldTypeName
);
246 rh
->getValue(fieldSize
);
248 OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue: "
250 fieldName
.c_str(), fieldTypeName
.c_str(), fieldSize
));
256 /*! Reads the contents of a field from the stream. It is intended to be used
257 in conjunction with readFieldHeader and uses the information obtained
258 by it (\a fieldName, \a fieldTypeName, \a fieldSize ).
260 If a field is not to be read, but skipped instead, its name can be passed
261 in the \a excludeFields argument. The string has the format:
262 "'name1' 'name2' 'name3'", the spaces between the "'" are mandatory.
264 \param[in] fieldName Name of the field.
265 \param[in] fieldTypeName Type of the field.
266 \param[in] fieldSize Size in bytes of the field.
267 \param[in] excludeFields
268 \param[out] ptrFieldIt Iterator that points to the PtrFieldInfo structure
269 that was created, if this is a "pointer field" - only valid if true is
272 \return True, if the field is a "pointer field", i.e. a field holding
273 pointers to other FieldContainers, false otherwise.
276 OSBCommonElement::readFieldContent(
277 const std::string
&fieldName
,
278 const std::string
&fieldTypeName
,
279 const UInt32 fieldSize
,
280 const std::string
&excludeFields
,
281 PtrFieldListIt
&ptrFieldIt
)
283 OSG_OSB_LOG(("OSBCommonElement::readFieldContent: [%s] [%s] [%u]\n",
284 fieldName
.c_str(), fieldTypeName
.c_str(), fieldSize
));
286 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
287 bool isPtrField
= false;
288 FieldDescriptionBase
*fieldDesc
=
289 getContainer()->getFieldDescription(fieldName
.c_str());
291 if((!excludeFields
.empty() ) &&
292 (excludeFields
.find("'" + fieldName
+ "'") != std::string::npos
) )
294 OSG_OSB_LOG(("OSBCommonElement::readFieldContent: "
295 "Skipping excluded field [%s] [%s]\n",
296 fieldName
.c_str(), fieldTypeName
.c_str()));
304 DynFieldContainerInterface
*pIf
=
305 dynamic_cast<DynFieldContainerInterface
*>(getContainer());
309 pIf
->addField(fieldTypeName
.c_str(), fieldName
.c_str());
311 fieldDesc
= getContainer()->getFieldDescription(fieldName
.c_str());
317 FWARNING(("OSBCommonElement::readFieldContent: "
318 "Skipping unknown field [%s] [%s].\n",
319 fieldName
.c_str(), fieldTypeName
.c_str()));
325 const FieldType
&fieldType
= fieldDesc
->getFieldType();
326 UInt32 fieldId
= fieldDesc
->getFieldId ();
327 BitVector fieldMask
= fieldDesc
->getFieldMask();
329 if(fieldType
.getContentType().isDerivedFrom(
330 FieldTraits
<FieldContainer
*>::getMapType()) == true)
332 ptrFieldIt
= readAttachmentMapField(fieldId
, fieldSize
);
335 else if(fieldType
.getContentType().isDerivedFrom(
336 FieldTraits
<FieldContainer
*>::getType()) == true)
338 if(fieldType
.getClass() == FieldType::ParentPtrField
)
345 if(fieldType
.getCardinality() == FieldType::SingleField
)
347 ptrFieldIt
= readPtrSingleField(fieldId
);
350 else if(fieldType
.getCardinality() == FieldType::MultiField
)
352 ptrFieldIt
= readPtrMultiField(fieldId
, fieldSize
);
359 getContainer()->copyFromBin(*rh
, fieldMask
);
366 /*! Reads fields from the stream until an end marker (either a field name of ""
367 or one in \a endMarkers) is encountered, skipping fields in
369 This makes use of readFieldHeader and readFieldContent and also demonstates
370 how these two functions can be used.
372 \param[in] excludeFields Field names that should be skipped in the stream.
373 \param[in] endMarkers Fields names (in additon to "") that will cause
376 \return The last field name that was read, this can be "", if the end of
377 the fields was reached.
380 OSBCommonElement::readFields(const std::string
&excludeFields
,
381 const std::string
&endMarkers
)
383 // BinaryReadHandler *rh = editRoot()->getReadHandler();
384 std::string fieldName
= "";
385 PtrFieldListIt ptrFieldIt
;
389 std::string fieldTypeName
;
392 if(!readFieldHeader(endMarkers
, fieldName
,
393 fieldTypeName
, fieldSize
))
395 OSG_OSB_LOG(("OSBCommonElement::readFields: "
396 "Reading stopped at field: [%s].\n", fieldName
.c_str() ));
400 readFieldContent(fieldName
, fieldTypeName
, fieldSize
,
401 excludeFields
, ptrFieldIt
);
407 /*! Reads fields from the stream until an end marker (either a field name of ""
408 or one in \a endMarkers) is encountered, skipping fields in
410 This function is intended to be used when the next fields name was already
411 consumed from the input stream, e.g. when readFields stopped on a non empty
413 This makes use of readFieldHeader and readFieldContent and also demonstates
414 how these two functions can be used.
416 \param[in] fieldName Name of the next field in the stream.
417 \param[in] excludeFields Field names that should be skipped in the stream.
418 \param[in] endMarkers Fields names (in additon to "") that will cause
421 \return The last field name that was read, this can be "", if the end of
422 the fields was reached.
425 OSBCommonElement::readFieldsContinue(const std::string
&fieldName
,
426 const std::string
&excludeFields
,
427 const std::string
&endMarkers
)
429 PtrFieldListIt ptrFieldIt
;
430 std::string fieldName2
;
431 std::string fieldTypeName
;
434 // Read the first field specially - its name was already consumed
435 if(!readFieldHeaderContinue(endMarkers
, fieldName
,
436 fieldTypeName
, fieldSize
))
438 OSG_OSB_LOG(("OSBCommonElement::readFieldsContinue: "
439 "Reading stopped at field: [%s].\n", fieldName
.c_str() ));
443 readFieldContent(fieldName
, fieldTypeName
, fieldSize
,
444 excludeFields
, ptrFieldIt
);
446 // continue reading normally
449 if(!readFieldHeader(endMarkers
, fieldName2
,
450 fieldTypeName
, fieldSize
))
452 OSG_OSB_LOG(("OSBCommonElement::readFieldsContinue: "
453 "Reading stopped at field: [%s].\n", fieldName2
.c_str() ));
457 readFieldContent(fieldName2
, fieldTypeName
, fieldSize
,
458 excludeFields
, ptrFieldIt
);
464 /*! Skips all fields in the stream, until the field end
465 marker "" is encountered.
468 OSBCommonElement::skipFields(void)
470 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
474 std::string fieldName
;
475 std::string fieldTypeName
;
478 rh
->getValue(fieldName
);
480 if(fieldName
.empty())
482 OSG_OSB_LOG(("OSBCommonElement::skipFields: "
483 "Found field end marker.\n" ));
487 rh
->getValue(fieldTypeName
);
488 rh
->getValue(fieldSize
);
489 rh
->skip (fieldSize
);
491 OSG_OSB_LOG(("OSBCommonElement::skipFields: "
492 "name [%s] type [%s] size [%u]\n",
493 fieldName
.c_str(), fieldTypeName
.c_str(), fieldSize
));
497 /*! Reads a SFFieldContainerPtr (or a more specific pointer type) from the
498 stream. It has the given \a fieldId in the container it belongs to.
500 \param[in] fieldId Id of the field in the container it belongs to.
502 \return Iterator that points to the PtrFieldInfo structure
503 that was created for this field.
505 OSBCommonElement::PtrFieldListIt
506 OSBCommonElement::readPtrSingleField(const UInt32 fieldId
)
508 OSG_OSB_LOG(("OSBCommonElement::readPtrSingleField: "
509 "fieldId: [%u]\n", fieldId
));
511 OSBRootElement
*root
= editRoot();
514 root
->getReadHandler()->getValue(ptrId
);
516 OSG_OSB_LOG(("OSBCommonElement::readPtrSingleField: ptrId [%u]\n", ptrId
));
518 root
->editPtrFieldList().push_back(PtrFieldInfo(getContainer(), fieldId
));
519 root
->editPtrFieldList().back().editIdStore().push_back(ptrId
);
521 return --(root
->editPtrFieldList().end());
524 /*! Reads a MFFieldContainerPtr (or a more specific pointer type) from the
525 stream. It has the given \a fieldId in the container it belongs to.
527 \param[in] fieldId Id of the field in the container it belongs to.
528 \param[in] fieldSize field size
529 \return Iterator that points to the PtrFieldInfo structure
530 that was created for this field.
532 OSBCommonElement::PtrFieldListIt
533 OSBCommonElement::readPtrMultiField(
534 const UInt32 fieldId
, const UInt32 fieldSize
)
536 OSG_OSB_LOG(("OSBCommonElement::readPtrMultiField: "
537 "fieldId: [%u]\n", fieldId
));
541 OSBRootElement
*root
= editRoot();
542 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
544 root
->editPtrFieldList().push_back(PtrFieldInfo(getContainer(), fieldId
));
545 PtrFieldInfo
&pfi
= root
->editPtrFieldList().back();
547 rh
->getValue(numElements
);
549 OSG_OSB_LOG(("OSBCommonElement::readPtrMultiField: ptrIds ["));
551 for(UInt32 i
= 0; i
< numElements
; ++i
)
554 pfi
.editIdStore().push_back(ptrId
);
556 OSG_OSB_PLOG(("%u ", ptrId
));
559 OSG_OSB_PLOG(("]\n"));
561 return --(root
->editPtrFieldList().end());
564 /*! Reads a SFFieldContainerAttachmentPtrMap from the stream. It has the
565 given \a fieldId in the container it belongs to and size \a fieldSize.
567 \param[in] fieldId Id of the field in the container it belongs to.
568 \param[in] fieldSize Size in byte of the field.
570 \return Iterator that points to the PtrFieldInfo structure
571 that was created for this field.
573 OSBCommonElement::PtrFieldListIt
574 OSBCommonElement::readAttachmentMapField(
575 const UInt32 fieldId
, const UInt32 fieldSize
)
577 OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
578 "fieldId: [%u]\n", fieldId
));
580 bool hasBindingInfo
= false;
583 OSBRootElement
*root
= editRoot();
584 BinaryReadHandler
*rh
= editRoot()->getReadHandler();
586 root
->editPtrFieldList().push_back(PtrFieldInfo(getContainer(), fieldId
));
588 PtrFieldInfo
&pfi
= root
->editPtrFieldList().back();
590 rh
->getValue(numElements
);
592 // keep these ordered from highest to lowest version
593 if(root
->getHeaderVersion() >= OSGOSBHeaderVersion200
)
595 if(root
->getHeaderVersion() > OSGOSBHeaderVersion200
)
597 FINFO(("OSBCommonElement::readAttachmentMapField: "
598 "Unknown header version, trying to read as latest.\n"));
601 hasBindingInfo
= true;
603 else if(root
->getHeaderVersion() >= OSGOSBHeaderVersion100
)
605 // distinguish format with or without binding info
606 if(fieldSize
== (sizeof(UInt32
) + numElements
* sizeof(UInt32
)))
608 hasBindingInfo
= false;
612 hasBindingInfo
= true;
616 if(hasBindingInfo
== true)
618 OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
619 "reading [%u] attachments with binding info.\n", numElements
));
621 EditMapFieldHandlePtr sfMapField
=
622 boost::dynamic_pointer_cast
<EditMapFieldHandle
>(
623 getContainer()->editField(fieldId
));
625 if(sfMapField
== NULL
|| sfMapField
->isValid() == false)
626 return --(root
->editPtrFieldList().end());
628 pfi
.setHandledField(sfMapField
->loadFromBin(rh
,
631 pfi
.editBindingStore(),
632 pfi
.editIdStore ()));
634 for(UInt32 i
= 0; i
< numElements
; ++i
)
636 rh
->getValue(binding
);
637 rh
->getValue(ptrId
);
639 OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
640 "attachment [%u], binding [%u], id [%u].\n",
643 pfi
.editBindingStore().push_back(binding
);
644 pfi
.editIdStore ().push_back(ptrId
);
650 OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
651 "reading [%u] attachments without binding info.\n",
654 for(UInt32 i
= 0; i
< numElements
; ++i
)
658 OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
659 "attachment [%u], id [%u].\n", i
, ptrId
));
661 pfi
.editBindingStore().push_back(0 );
662 pfi
.editIdStore ().push_back(ptrId
);
666 return --(root
->editPtrFieldList().end());
669 /*-------------------------------------------------------------------------*/
670 /* Prewriting Helper methods */
672 /*! Visits a SFFieldContainerPtr (or more specific pointer type) during
673 preWrite. It creates an element for the pointed to container and
674 calls preWrite on it. If the pointed to container is not in the
675 root's id set it is added and thus scheduled for writing.
677 \param[in] fieldId Id of the field in the container of this element.
680 OSBCommonElement::preWritePtrSingleField(const UInt32 fieldId
)
682 OSG_OSB_LOG(("OSBCommonElement::preWritePtrSingleField: "
683 "fieldId: [%u]\n", fieldId
));
685 OSBRootElement
*root
= editRoot();
687 FieldContainerPtrSFieldBase::GetHandlePtr sfPtrField
=
688 boost::dynamic_pointer_cast
<FieldContainerPtrSFieldBase::GetHandle
>(
689 getContainer()->getField(fieldId
));
691 if(sfPtrField
== NULL
|| sfPtrField
->isValid() == false)
694 FieldContainer
*refedFC
= (*sfPtrField
)->getValue();
699 UInt32 refedId
= refedFC
->getId ();
700 const std::string
&typeName
= refedFC
->getType().getName();
702 // only schedule a container once
703 if(root
->getIdSet().count(refedId
) == 0)
705 OSBElementBase
*elem
= OSBElementFactory::the()->acquire(
708 root
->editIdSet ().insert (refedId
);
709 root
->editElementList().push_back(elem
);
710 elem
->setContainer(refedFC
);
711 elem
->preWrite (refedFC
);
715 /*! Visits a MFFieldContainerPtr (or more specific pointer type) during
716 preWrite. It creates elements for the pointed to containers and
717 calls preWrite on them. If the pointed to containers are not in the
718 root's id set they are added and thus scheduled for writing.
720 \param[in] fieldId Id of the field in the container of this element.
723 OSBCommonElement::preWritePtrMultiField(const UInt32 fieldId
)
725 OSG_OSB_LOG(("OSBCommonElement::preWritePtrMultiField: "
726 "fieldId: [%u]\n", fieldId
));
728 OSBRootElement
*root
= editRoot();
730 FieldContainerPtrMFieldBase::GetHandlePtr mfPtrField
=
731 boost::dynamic_pointer_cast
<FieldContainerPtrMFieldBase::GetHandle
>(
732 getContainer()->getField(fieldId
));
734 if(mfPtrField
== NULL
|| mfPtrField
->isValid() == false)
737 FieldContainerPtrMFieldBase::const_iterator fieldIt
=
738 (*mfPtrField
)->begin();
740 FieldContainerPtrMFieldBase::const_iterator fieldEnd
=
741 (*mfPtrField
)->end ();
743 for(; fieldIt
!= fieldEnd
; ++fieldIt
)
745 FieldContainer
*refedFC
= *fieldIt
;
750 UInt32 refedId
= refedFC
->getId ();
751 const std::string
&typeName
= refedFC
->getType().getName();
753 // only schedule a container once
754 if(root
->getIdSet().count(refedId
) > 0)
757 OSBElementBase
*elem
= OSBElementFactory::the()->acquire(
760 root
->editIdSet ().insert (refedId
);
761 root
->editElementList().push_back(elem
);
762 elem
->setContainer(refedFC
);
763 elem
->preWrite (refedFC
);
767 /*! Visits a SFFieldContainerAttachmentPtrMap during
768 preWrite. It creates elements for the pointed to containers and
769 calls preWrite on them. If the pointed to containers are not in the
770 root's id set they are added and thus scheduled for writing.
772 \param[in] fieldId Id of the field in the container of this element.
774 void OSBCommonElement::preWriteAttachmentMapField(const UInt32 fieldId
)
776 OSG_OSB_LOG(("OSBCommonElement::preWriteAttachmentMapField: "
777 "fieldId: [%u]\n", fieldId
));
779 GetMapFieldHandlePtr sfMapField
=
780 boost::dynamic_pointer_cast
<GetMapFieldHandle
>(
781 getContainer()->getField(fieldId
));
783 if(sfMapField
== NULL
|| sfMapField
->isValid() == false)
786 sfMapField
->traverse(
787 boost::bind(&OSBCommonElement::handleAttachmentMapElementPreWrite
,
792 /*! Visits a map field (essentially an SF that contains a std::map
793 with a FieldContainer* as value type) for
794 preWrite. It creates elements for the pointed to containers and
795 calls preWrite on them. If the pointed to containers are not in the
796 root's id set they are added and thus scheduled for writing.
798 \param[in] fieldId Id of the field in the container of this element.
800 void OSBCommonElement::preWriteMapField(const UInt32 fieldId
)
802 OSG_OSB_LOG(("OSBCommonElement::preWriteMapField: "
803 "fieldId: [%u]\n", fieldId
));
805 GetMapFieldHandlePtr sfMapField
=
806 boost::dynamic_pointer_cast
<GetMapFieldHandle
>(
807 getContainer()->getField(fieldId
));
809 if(sfMapField
== NULL
|| sfMapField
->isValid() == false)
812 sfMapField
->traverse(
813 boost::bind(&OSBCommonElement::handleMapElementPreWrite
,
818 /*! Visits the given container \a fc during preWrite and creates elements
819 for all containers reachable from this (except for those refered to by
820 fields whose names are in \a excludeFields).
822 The excludeFields string has the format: "'name1' 'name2' 'name3'",
823 the spaces between the "'" are mandatory.
825 \param[in] fc Container this element shall visit.
826 \param[in] excludeFields Field names that are not to be considered when
827 determining reachable containers.
830 OSBCommonElement::preWriteFieldContainer(
831 FieldContainer
*fc
, const std::string
&excludeFields
)
833 OSG_OSB_LOG(("OSBCommonElement::preWriteFieldContainer: >> type [%s] "
834 "excludeFields: [%s]\n",
835 fc
->getType().getName().c_str(),
836 excludeFields
.c_str()));
838 UInt32 fieldCount
= fc
->getType().getNumFieldDescs();
840 // go through all fields and find those refering to other FCs
841 for(UInt32 fieldId
= 1; fieldId
<= fieldCount
; ++fieldId
)
843 const FieldDescriptionBase
*fieldDesc
= fc
->getFieldDescription(fieldId
);
844 const FieldType
&fieldType
= fieldDesc
->getFieldType();
845 const std::string
&fieldName
= fieldDesc
->getName ();
847 OSG_OSB_LOG(("OSBCommonElement::preWriteFieldContainer: "
848 "fieldName: [%s] fieldId: [%u]\n",
849 fieldName
.c_str(), fieldId
));
851 // skip internal fields
852 if(fieldDesc
->isInternal())
854 OSG_OSB_LOG(("OSBCommonElement::preWriteFieldContainer: "
855 "Skipping internal field: [%s]\n",
860 // skip excluded fields
861 if((!excludeFields
.empty() ) &&
862 (excludeFields
.find("'" + fieldName
+ "'") != std::string::npos
) )
864 OSG_OSB_LOG(("OSBCommonElement::preWriteFieldContainer: "
865 "Skipping excluded field: [%s]\n", fieldName
.c_str()));
869 // check if field refers to another FC, i.e. its a field holding
870 // FieldContainerPtr or an FieldContainerAttachmentMap
871 if(fieldType
.getContentType().isDerivedFrom(
872 FieldTraits
<AttachmentMap
>::getType()) == true)
874 preWriteAttachmentMapField(fieldId
);
876 else if(fieldType
.getContentType().isDerivedFrom(
877 FieldTraits
<FieldContainer
*>::getMapType()) == true)
879 preWriteMapField(fieldId
);
881 else if(fieldType
.getContentType().isDerivedFrom(
882 FieldTraits
<FieldContainer
*>::getType()) == true)
884 if(fieldType
.getCardinality() == FieldType::SingleField
)
886 preWritePtrSingleField(fieldId
);
888 else if(fieldType
.getCardinality() == FieldType::MultiField
)
890 preWritePtrMultiField(fieldId
);
895 OSG_OSB_LOG(("OSBCommonElement::preWriteFieldContainer: << type [%s] "
896 "excludeFields: [%s]\n",
897 fc
->getType().getName().c_str(),
898 excludeFields
.c_str()));
901 /*-------------------------------------------------------------------------*/
902 /* Writing Helper methods */
904 /*! Writes the header for the given container \a fc to the stream.
906 \param[in] fc Container to write the header for.
909 OSBCommonElement::writeFieldContainerHeader(FieldContainer
* const fc
)
911 OSG_OSB_LOG(("OSBCommonElement::writeFieldContainerHeader\n"));
913 BinaryWriteHandler
*wh
= editRoot()->getWriteHandler();
914 const std::string
&typeName
= fc
->getType().getName();
915 UInt32 fcId
= fc
->getId ();
917 wh
->putValue(typeName
);
921 /*! Writes the header for a field to the stream.
923 \param[in] fieldName Name of the field.
924 \param[in] fieldTypeName Type of the field.
925 \param[in] fieldSize Size in bytes of the field.
928 OSBCommonElement::writeFieldHeader(
929 const std::string
&fieldName
, const std::string
&fieldTypeName
,
930 const UInt32 fieldSize
)
932 OSG_OSB_LOG(("OSBCommonElement::writeFieldHeader: "
934 fieldName
.c_str(), fieldTypeName
.c_str(), fieldSize
));
936 BinaryWriteHandler
*wh
= editRoot()->getWriteHandler();
938 wh
->putValue(fieldName
);
939 wh
->putValue(fieldTypeName
);
940 wh
->putValue(fieldSize
);
943 /*! Write the contents of the field with the given \a fieldId to the stream.
945 \param[in] fieldId Id of the field to write.
948 OSBCommonElement::writeFieldContent(const UInt32 fieldId
)
950 OSG_OSB_LOG(("OSBCommonElement::writeFieldContent\n"));
952 BinaryWriteHandler
*wh
= editRoot()->getWriteHandler();
953 FieldContainer
*fc
= getContainer();
955 const FieldDescriptionBase
*fieldDesc
= fc
->getFieldDescription(fieldId
);
956 const BitVector fieldMask
= fieldDesc
->getFieldMask( );
958 fc
->copyToBin(*wh
, fieldMask
);
961 /*! Writes all fields to the stream, except for those whose name is in
962 \a excludeFields. Optionally writes an end marker.
964 The excludeFields string has the format: "'name1' 'name2' 'name3'",
965 the spaces between the "'" are mandatory.
967 \param[in] excludeFields String of field names that shall be skipped.
968 \param[in] endMarker Write an end marker to the stream after all fields are
972 OSBCommonElement::writeFields(
973 const std::string
&excludeFields
, const bool endMarker
)
975 OSG_OSB_LOG(("OSBCommonElement::writeFields: "
976 "excludeFields: [%s]\n", excludeFields
.c_str()));
978 FieldContainer
*fc
= getContainer();
979 UInt32 fieldCount
= fc
->getType().getNumFieldDescs();
981 // go through all fields and write them.
982 for(UInt32 fieldId
= 1; fieldId
<= fieldCount
; ++fieldId
)
984 const FieldDescriptionBase
*fieldDesc
=
985 fc
->getFieldDescription(fieldId
);
986 const std::string
&fieldName
= fieldDesc
->getName();
988 // skip internal fields
989 if(fieldDesc
->isInternal())
991 OSG_OSB_LOG(("OSBCommonElement::writeFields: "
992 "Skipping internal field: [%s]\n", fieldName
.c_str()));
996 // skip excluded fields
997 if((!excludeFields
.empty() ) &&
998 (excludeFields
.find("'" + fieldName
+ "'") != std::string::npos
) )
1000 OSG_OSB_LOG(("OSBCommonElement::writeFields: "
1001 "Skipping excluded field: [%s]\n", fieldName
.c_str()));
1005 const FieldType
&fieldType
= fieldDesc
->getFieldType();
1006 const std::string
&fieldTypeName
= fieldType
.getName ();
1007 BitVector fieldMask
= fieldDesc
->getFieldMask();
1008 UInt32 fieldSize
= UInt32(fc
->getBinSize(fieldMask
));
1010 writeFieldHeader (fieldName
, fieldTypeName
, fieldSize
);
1011 writeFieldContent(fieldId
);
1020 /*! Writes an end marker to the stream.
1023 OSBCommonElement::writeEndMarker(void)
1025 OSG_OSB_LOG(("OSBCommonElement::writeEndMarker\n"));
1027 editRoot()->getWriteHandler()->putValue(std::string(""));
1030 /*-------------------------------------------------------------------------*/
1031 /* Map Helper methods */
1033 /*! Callback called for each element in an AttachmentMap (this is used by
1034 preWriteAttachmentMapField).
1036 void OSBCommonElement::handleAttachmentMapElementPreWrite(
1037 FieldContainer
*refedFC
)
1039 OSG_OSB_LOG(("OSBCommonElement::handleAttachmentMapElementPreWrite\n"));
1044 Attachment
*refedAtt
= dynamic_cast<Attachment
*>(refedFC
);
1046 // skip attachments marked as 'internal'
1047 if(refedAtt
== NULL
||
1048 refedAtt
->getSFInternal()->getValue() == true )
1053 OSBRootElement
*root
= editRoot();
1054 UInt32 refedId
= refedAtt
->getId ();
1055 const std::string
&typeName
= refedAtt
->getType().getName();
1057 // only schedule a container once
1058 if(root
->getIdSet().count(refedId
) > 0)
1061 OSBElementBase
*elem
= OSBElementFactory::the()->acquire(typeName
, root
);
1063 root
->editIdSet ().insert (refedId
);
1064 root
->editElementList().push_back(elem
);
1065 elem
->setContainer(refedAtt
);
1066 elem
->preWrite (refedAtt
);
1069 /*! Callback called for each element in a map field (this is used by
1072 void OSBCommonElement::handleMapElementPreWrite(FieldContainer
*refedFC
)
1077 OSBRootElement
*root
= editRoot();
1078 UInt32 refedId
= refedFC
->getId ();
1079 const std::string
&typeName
= refedFC
->getType().getName();
1081 // only schedule a container once
1082 if(root
->getIdSet().count(refedId
) > 0)
1085 OSBElementBase
*elem
= OSBElementFactory::the()->acquire(typeName
, root
);
1087 root
->editIdSet ().insert (refedId
);
1088 root
->editElementList().push_back(elem
);
1089 elem
->setContainer(refedFC
);
1090 elem
->preWrite (refedFC
);
1093 /*-------------------------------------------------------------------------*/
1094 /* Misc Helper methods */
1096 /*! Creates a container that can be used as a replacement for an unavailable
1097 type. The type of the replacement is determined by the \a fcPtrType
1098 which must be one of the constants in this class.
1100 \param[in] fcPtrType One of the constants in this class, descibing what
1101 type of container is to be replaced.
1103 \return A container that can act as replacement for a missing type or
1104 NULL if no such container was found.
1106 FieldContainerTransitPtr
1107 OSBCommonElement::createReplacementFC(const UInt8 fcPtrType
)
1109 FieldContainerTransitPtr
fc(NULL
);
1113 case OSBCommonElement::FCPtrNode
:
1114 fc
= Node::create();
1117 case OSBCommonElement::FCPtrNodeCore
:
1118 fc
= Group::create();
1121 case OSBCommonElement::FCPtrMaterial
:
1122 fc
= ChunkMaterial::create();
1125 case OSBCommonElement::FCPtrStateChunk
:
1129 case OSBCommonElement::FCPtrAttachment
:
1134 fc
= Node::create();
1141 /*! Classifies the given \a container by returning one of the constants in this
1144 \param[in] container Container to classify.
1146 \return One of the constants in this class.
1149 OSBCommonElement::getFCPtrType(FieldContainer
* const container
)
1151 FieldContainerType
&fcType
= container
->getType();
1152 UInt8 ptrType
= OSBCommonElement::FCPtrFieldContainer
;
1156 ptrType
= OSBCommonElement::FCPtrNode
;
1158 else if(fcType
.isNodeCore())
1160 ptrType
= OSBCommonElement::FCPtrNodeCore
;
1162 else if(fcType
.isDerivedFrom(Material::getClassType()))
1164 ptrType
= OSBCommonElement::FCPtrMaterial
;
1166 else if(fcType
.isDerivedFrom(StateChunk::getClassType()))
1168 ptrType
= OSBCommonElement::FCPtrStateChunk
;
1170 else if(fcType
.isAttachment())
1172 ptrType
= OSBCommonElement::FCPtrAttachment
;