OSGB format parsing

This paper mainly introduces the analysis of OSGB binary data of tilt photography data. Firstly, it briefly introduces the relevant technologies of OpenSceneGraph, and introduces the organizational structure of tilt photography data, focusing on the analysis of relevant fields of OSGB format. Finally, it analyzes OSGB data byte by byte, visualizes the data through OpenSceneGraph, and optimizes the visualization of tilt photography data.

preface

OpenSceneGraph is an open source, cross platform high-performance 3D graphics toolkit. It is completely written in standard C + + and OpenGL and can be used for 3D simulation. The multithreading technology and PagedLOD technology contained in OSG can easily process the visualization and scheduling of 3D models of big data. OSGB format data is the own format of OpenSceneGraph framework, which is a kind of binary data. Tilt photography data is data in a tree structure organized in OSGB format.

1, OpenSceneGraph

1. Visualization of osgb data

1.1 the results of OSGB data visualization are as follows:

2. OSGB data viewing

2.1 the binary osgb data can be converted into text formats osgt, OSG, etc. through OSG's own data conversion tool osgconv, you can directly open and view osgb data. The number of converted files is as follows:

#Ascii Scene 
#Version 161 
#Generator OpenSceneGraph 3.6.5 
osg::PagedLOD {
  UniqueID 1 
  CenterMode USER_DEFINED_CENTER 
  UserCenter 11406.1 -2410.49 14.3884 34.9388 
  RangeMode PIXEL_SIZE_ON_SCREEN 
  RangeList 2 {
    0 17.4694 
    17.4694 1e+30 
  }
  DatabasePath TRUE "E:\\Desktop\\Data\\Tile_+154_+009/" 
  RangeDataList 2 {
    "" 
    "Tile_+154_+009_L15_0.osgb" 
  }
  PriorityList 2 {
    0 1 
    0 1 
  }
  Children 1 {
    osg::Geode {
      UniqueID 2 
      Drawables 1 {
        osg::Geometry {
          UniqueID 3 
          DataVariance STATIC 
          StateSet TRUE {
            osg::StateSet {
              UniqueID 4 
              DataVariance STATIC 
              AttributeList 1 {
                osg::Material {
                  UniqueID 5 
                  Ambient TRUE Front 1 1 1 1 Back 1 1 1 1 
                  Diffuse TRUE Front 1 1 1 1 Back 1 1 1 1 
                  Specular TRUE Front 0 0 0 1 Back 0 0 0 1 
                  Emission TRUE Front 0 0 0 1 Back 0 0 0 1 
                  Shininess TRUE Front 0 Back 0 
                }
                Value OFF 
              }
              TextureModeList 1 {
                Data 1 {
                  GL_TEXTURE_2D ON 
                }
              }
              TextureAttributeList 1 {
                Data 1 {
                  osg::Texture2D {
                    UniqueID 6 
                    DataVariance STATIC 
                    WRAP_S CLAMP 
                    WRAP_T CLAMP 
                    WRAP_R CLAMP 
                    MIN_FILTER LINEAR_MIPMAP_LINEAR 
                    MAG_FILTER LINEAR 
                    UnRefImageDataAfterApply TRUE 
                    Swizzle RGBA 
                    Image TRUE {
                      ClassName osg::Image 
                      UniqueID 7 
                      FileName "Tile_+154_+009_0.jpg" 
                      WriteHint 2 2 
                      DataVariance STATIC 
                    }
                  }
                  Value OFF 
                }
              }
            }
          }
          PrimitiveSetList 1 {
            osg::DrawElementsUInt {
              UniqueID 8 
              BufferObject TRUE {
                osg::ElementBufferObject {
                  UniqueID 9 
                  Target 34963 
                }
              }
              Mode TRIANGLES 
              vector 249 {
                0 1 2 3 
                4 5 6 7 
                8 9 10 11 
                6 12 7 13 
                14 8 14 7 
                12 13 8 7 
                15 16 17 18 
                14 13 19 20 
                21 14 18 22 
                23 24 22 25 
                26 27 28 29 
                30 31 23 32 
                14 22 33 34 
                25 35 36 37 
                38 39 27 40 
                33 22 24 25 
                27 39 22 32 
                23 26 39 40 
                41 28 30 42 
                43 44 26 25 
                45 25 34 45 
                34 46 45 45 
                47 26 48 49 
                50 51 52 53 
                53 52 54 55 
                56 57 54 58 
                53 59 60 61 
                62 59 61 63 
                62 61 64 65 
                66 67 68 69 
                70 71 72 73 
                74 75 76 77 
                78 78 77 79 
                80 48 50 81 
                82 83 78 84 
                85 86 87 88 
                76 78 85 89 
                90 91 81 92 
                82 93 94 48 
                72 95 96 95 
                97 96 93 98 
                94 72 99 70 
                95 71 100 71 
                95 72 101 102 
                95 97 95 102 
                91 103 104 105 
                102 106 107 108 
                109 110 82 92 
                111 112 113 94 
                98 114 106 101 
                97 101 106 102 
                71 106 97 74 
                73 115 116 73 
                88 117 118 119 
                82 120 83 121 
                108 107 104 122 
                91 71 105 106 
                123 86 88 48 
                80 93 91 90 
                103 116 115 73 
                73 123 88 124 
                119 118 120 82 
                125 
              }
            }
          }
          VertexArray TRUE {
            osg::Vec3Array {
              UniqueID 10 
              BufferObject TRUE {
                osg::VertexBufferObject {
                  UniqueID 11 
                }
              }
              Binding BIND_PER_VERTEX 
              vector 126 {
                11421.4 -2430.02 11.1509 
                11416 -2429.93 12.0398 
                11416.1 -2428.49 11.9536 
                11416.1 -2428.49 11.9536 
                11416.3 -2427.38 9.46918 
                11417 -2431.32 11.2052 
                11416 -2429.93 12.0398 
                11415.2 -2428.63 12.3225 
                11416.1 -2428.49 11.9536 
                11417 -2431.32 11.2052 
                11421.4 -2430.02 11.1509 
                11416.1 -2428.49 11.9536 
                11417 -2431.32 11.2052 
                11417.2 -2428.95 13.4176 
                11416.3 -2427.38 9.46918 
                11416.2 -2430.52 7.36804 
                11416.1 -2430.42 7.60243 
                11416 -2430.16 6.66749 
                11421.4 -2430.02 11.1509 
                11421.4 -2430.02 11.1509 
                11417.2 -2428.95 13.4176 
                11416 -2429.93 12.0398 
                11421.4 -2417.88 10.3103 
                11414 -2415.94 9.09115 
                11414.2 -2416 9.00664 
                11413.7 -2411.71 9.68296 
                11409.8 -2412.62 9.51062 
                11414.2 -2416 9.00664 
                11421.4 -2412.33 10.8725 
                11414.3 -2415.9 8.9807 
                11414.2 -2416 9.00664 
                11409.8 -2412.62 9.51062 
                11421.4 -2412.33 10.8725 
                11414.3 -2415.9 8.9807 
                11421.4 -2412.33 10.8725 
                11414.3 -2415.9 8.9807 
                11416.3 -2427.38 9.46918 
                11414.3 -2415.9 8.9807 
                11413.7 -2411.71 9.68296 
                11416.3 -2427.38 9.46918 
                11414 -2415.94 9.09115 
                11409.8 -2412.62 9.51062 
                11421.4 -2411.74 12.2718 
                11421.4 -2411.62 11.9188 
                11421.4 -2411.76 12.1873 
                11406.3 -2403.12 10.7203 
                11421.4 -2402.07 11.0026 
                11403 -2403.17 11.9259 
                11407.7 -2400.76 20.792 
                11408.6 -2406.5 20.017 
                11421.4 -2405.4 17.8293 
                11408.6 -2406.5 20.017 
                11406.3 -2403.12 10.7203 
                11421.4 -2405.4 17.8293 
                11421.4 -2402.07 11.0026 
                11421.4 -2402.14 14.4776 
                11421.4 -2402.04 14.7014 
                11421.4 -2402.31 14.7539 
                11421.4 -2399.19 11.9584 
                11407.7 -2400.76 20.792 
                11403.3 -2399.47 18.0124 
                11402.6 -2402.11 16.0169 
                11406.3 -2403.12 10.7203 
                11403.5 -2401.78 14.2324 
                11402.6 -2402.11 16.0169 
                11403 -2403.17 11.9259 
                11403.5 -2401.78 14.2324 
                11402.1 -2402.35 10.5813 
                11402 -2402.4 11.4244 
                11401.9 -2402.1 11.4328 
                11406 -2394.56 12.2159 
                11413.6 -2395.24 12.5957 
                11407 -2383.55 10.3011 
                11408.7 -2390.8 17.8375 
                11406 -2394.56 12.2159 
                11398.1 -2392.72 13.3419 
                11406.3 -2403.12 10.7203 
                11403.5 -2401.78 14.2324 
                11403.3 -2399.47 18.0124 
                11403 -2403.17 11.9259 
                11421.4 -2398.48 17.8706 
                11403 -2403.17 11.9259 
                11406 -2394.56 12.2159 
                11403.3 -2399.47 18.0124 
                11407.7 -2400.76 20.792 
                11413.6 -2395.24 12.5957 
                11421.4 -2399.19 11.9584 
                11421.4 -2402.07 11.0026 
                11417.6 -2396.89 10.3681 
                11421.4 -2402.07 11.0026 
                11421.4 -2393.37 11.0167 
                11417.6 -2396.89 10.3681 
                11406.3 -2403.12 10.7203 
                11408.7 -2390.8 17.8375 
                11407.4 -2395.19 18.3994 
                11419.2 -2393.09 11.0517 
                11421.4 -2382.84 9.16199 
                11421.4 -2393.37 11.0167 
                11398.1 -2392.72 13.3419 
                11398.1 -2392.72 13.3419 
                11419 -2393.87 10.3112 
                11419.8 -2394.49 10.5827 
                11419.5 -2394.39 10.7514 
                11419.8 -2394.49 10.5827 
                11419.2 -2393.09 11.0517 
                11417.6 -2396.89 10.3681 
                11419.5 -2394.49 10.9917 
                11413.6 -2395.24 12.5957 
                11419.5 -2394.39 10.7514 
                11419 -2393.87 10.3112 
                11413.6 -2395.24 12.5957 
                11419 -2393.87 10.3112 
                11419.5 -2394.39 10.7514 
                11417.6 -2396.89 10.3681 
                11403.3 -2399.47 18.0124 
                11409.7 -2395.95 16.3532 
                11413.6 -2395.24 12.5957 
                11413.6 -2395.24 12.5957 
                11407.7 -2400.76 20.792 
                11409.7 -2395.95 16.3532 
                11407.4 -2395.19 18.3994 
                11421.4 -2393.37 11.0167 
                11419 -2393.87 10.3112 
                11421.4 -2398.48 17.8706 
                11407.4 -2395.19 18.3994 
                11409.7 -2395.95 16.3532 
              }
            }
          }
          TexCoordArrayList 1 {
            osg::Vec2Array {
              UniqueID 12 
              BufferObject TRUE {
                osg::VertexBufferObject {
                  UniqueID 11 
                }
              }
              Binding BIND_PER_VERTEX 
              vector 126 {
                0.692426 0.855664 
                0.703011 0.856104 
                0.702753 0.861724 
                0.570732 0.609083 
                0.568671 0.599278 
                0.576501 0.605998 
                0.328366 0.857498 
                0.331044 0.855646 
                0.329737 0.852837 
                0.441758 0.855283 
                0.450283 0.850095 
                0.44346 0.866617 
                0.3252 0.858301 
                0.327577 0.854413 
                0.330703 0.845386 
                0.195902 0.353782 
                0.195705 0.354209 
                0.195467 0.355194 
                0.319499 0.845511 
                0.208773 0.844122 
                0.201316 0.85591 
                0.198636 0.849995 
                0.332787 0.808157 
                0.346856 0.815357 
                0.346555 0.815111 
                0.0910442 0.827874 
                0.0927779 0.813587 
                0.0994225 0.828423 
                0.0672952 0.362282 
                0.0812559 0.348427 
                0.0814619 0.34803 
                0.357319 0.814601 
                0.33887 0.79253 
                0.346497 0.814557 
                0.0922966 0.857352 
                0.0992241 0.828762 
                0.0720457 0.599278 
                0.0940807 0.599094 
                0.101988 0.602514 
                0.121655 0.836511 
                0.0993046 0.828032 
                0.0899589 0.361319 
                0.32333 0.364582 
                0.323332 0.36502 
                0.32333 0.36449 
                0.0742107 0.802832 
                0.0722694 0.857707 
                0.074282 0.793042 
                0.0856387 0.56386 
                0.0873095 0.541454 
                0.112424 0.545566 
                0.32318 0.610118 
                0.324436 0.572843 
                0.342956 0.603723 
                0.347425 0.576504 
                0.448395 0.355193 
                0.448395 0.355587 
                0.448393 0.354527 
                0.351276 0.579699 
                0.205769 0.602609 
                0.196975 0.591479 
                0.197885 0.580644 
                0.205193 0.561936 
                0.199157 0.574931 
                0.819516 0.855274 
                0.818829 0.838799 
                0.821246 0.848312 
                0.566881 0.354655 
                0.56682 0.35447 
                0.566539 0.355615 
                0.2075 0.556892 
                0.222176 0.554122 
                0.209448 0.599878 
                0.222347 0.863516 
                0.228093 0.838681 
                0.243193 0.848836 
                0.211664 0.318576 
                0.216188 0.334426 
                0.215268 0.351605 
                0.217788 0.324245 
                0.112475 0.572588 
                0.321275 0.324245 
                0.331548 0.338728 
                0.323795 0.351605 
                0.207751 0.356878 
                0.193749 0.335213 
                0.198898 0.820795 
                0.199349 0.809863 
                0.205922 0.824395 
                0.210728 0.866942 
                0.195963 0.854278 
                0.205604 0.848005 
                0.327399 0.318576 
                0.0876976 0.602792 
                0.0850185 0.585631 
                0.23329 0.56245 
                0.237614 0.60247 
                0.237531 0.561327 
                0.0670734 0.59545 
                0.192073 0.5642 
                0.2328 0.559397 
                0.234342 0.556989 
                0.233846 0.557384 
                0.199434 0.850614 
                0.197591 0.84838 
                0.230092 0.547641 
                0.233775 0.556984 
                0.333479 0.856571 
                0.321888 0.85038 
                0.322974 0.849073 
                0.345314 0.335213 
                0.824279 0.612617 
                0.823928 0.615871 
                0.817834 0.61363 
                0.0771236 0.568969 
                0.221239 0.844325 
                0.213566 0.835886 
                0.453171 0.810441 
                0.459564 0.852859 
                0.451968 0.83147 
                0.333637 0.358427 
                0.318287 0.852249 
                0.199158 0.846992 
                0.198804 0.837991 
                0.449074 0.842425 
                0.337638 0.348894 
              }
            }
          }
        }
      }
    }
  }
}

3.OSG documents

http://dei.isep.ipp.pt/~matos/cadeiras/cgra/OpenSceneGraphReferenceDocs/index.html

2, Tilt photographic data

1. Data organization structure

1.1 as shown in the figure, the Data organization structure is as follows: the Data directory is the Data entry directory, which contains many subdirectories. As shown below, each subdirectory is a root block, and each root block is a tree structure and a LOD hierarchical structure.

1.2 there are many. Osgb files under each root block. The osgb file with the same name as the directory name under the subdirectory is the root file, as follows:

2.OSGB format analysis

2.1 OSGB binary data contains many fields, including non key fields of OpenSceneGraph framework, which are mainly used in OpenSceneGraph framework, as well as key fields, mainly vertex coordinates, normal coordinates, texture data and LOD information of a 3D model. OSGB data contains many different blocks (composed of multiple fields). These blocks have nested relationships in OSGB. OSGB is not like general non nested data, so the OSGB data format is more complex.

The following data reading process is organized according to the reading order structure, which can be combined to read the entire OSGB format data.

2.2 read OSGB file header information
Is the header information of OSGB. The low and high bits are 4 bytes respectively, and each is a 16Bit MD5 code.

		unsigned int headerLow = 0, headerHigh = 0;
		fin.read((char*)&headerLow, INT_SIZE);
		fin.read((char*)&headerHigh, INT_SIZE);

2.3 to read the following blocks, a stack needs to be used to assist in reading each block.

  • Read file type:
    READ_UNKNOWN=0,READ_SCENE=1,READ_IMAGE=2,READ_OBJECT=3, which represents the type supported by osgb. It can be considered that the osgb format of tilt photography is always 1;
  • Read file version number
  • Read properties:
    Determine whether to use in the file_ Is useSchemaData and supported_ SupportBinaryBrackets: all zeros indicate that they are not supported;
  • Set some OSGB parameters according to the attribute information, and then read the information according to the parameter settings;
	//Stack, press "start" when reading
	_fields.push_back("Start");
	//Read file type
	_in->read((char*)&i, osgDB::INT_SIZE);				//unsigned int
	//Read file version number
	_in->read((char*)&i, osgDB::INT_SIZE);				//unsignde int
	//Read attribute value
	_in->read((char*)&attributes, osgDB::INT_SIZE);		//unsignde int

	//Set parameters according to attribute values
	if (attributes & 0x4) 
		_SupportBinaryBrackets = true;
	if (attributes & 0x2) 
		_useSchemaData = true;

	//Read information according to attribute value
	if (attributes & 0x1)
	{
		_in->read((char*)&number, osgDB::INT_SIZE);		//unsignde int
		//According to the number value, the following value is read in a loop
		for(unsigned int i = 0;i<number;++i)
		{
			//Read string
			_in->read((char*)&size, osgDB::INT_SIZE);	//int, read string length
			_in->read((char*)s.c_str(), size);			//char array
			//Read int
			_in->read((char*)&i, osgDB::INT_SIZE);		//int, read string length
			map[s] = i;									//Use collections to store their information, mainly some version information
		}
	}
	//Field out of stack
	_fields.pop_back();

2.4 read the name of the compressor

	//Read the compressor name, generally "0", which indicates the compression format and the compressor name. zib compression can also be used
	_in->read((char*)&size, osgDB::INT_SIZE);			//int, read string length
	_in->read((char*)compressorName .c_str(), size);	//char array

	//Read the compressor name accordingly. In this article, I mainly discuss the case of compressor name = = 0. For zlib, I will briefly introduce it
	if (compressorName != "0")
	{
		//data to be read
		std::string data;
		//Push 
		_fields.push_back("Decompression");
		BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(compressorName);
		if (!compressor)
		{
			throwException("InputStream: Failed to decompress stream, No such compressor.");
			return;
		}
		//The related reading is mainly in the decompress function
		if (!compressor->decompress(*(_in->getStream()), data))
			throwException("InputStream: Failed to decompress stream.");
		if (getException()) return;
		_dataDecompress = new std::stringstream(data);
		_in->setStream(_dataDecompress);
		//Out of stack
		_fields.pop_back();
	}

2.5 basis_ The useSchemaData parameter reads the corresponding information

	if(_useSchemaData)
	{
		//Field stack
		_fields.push_back("SchemaData");
		//Read string
		_in->read((char*)&size, osgDB::INT_SIZE);			//int, read string length
		_in->read((char*)s.c_str(), size);					//char array

		//S string information analysis, and construct an std::istringstream object through s
		//Out of stack
		_fields.pop_back();
	}

2.6 there is a nested relationship later. You need to read the information of the corresponding field according to the value of the currently read string. Each field contains its own reading method. Built to organize each field element into a function.

	//Read string
	_in->read((char*)&size, osgDB::INT_SIZE);				//int
	_in->read((char*)s.c_str(), size);						//char array
	
	//BEGIN_ The bracket operation is used to move the reading position according to the position and size;
	if(_supportBinaryBrackets)
	{
		//Stack current position
		_beginPositions.push_back(_in->tellg());
		if(_in && Version > 148)
		{
			_in->read((char*)&size, osgDB::INT64_SIZE);     //Unsigned long, 8 bytes
			//size stack
			_blockSizes.push_back(size);
		}else{
			_in->read((char*)&size, osgDB::INT_SIZE);       //int
			//size stack
			_blockSizes.push_back(size);
		}
	}

	//PROPERTY operation
	_in->read((char*)&value, osgDB::INT_SIZE);				//int

	//Read ID
	_in->read((char*)&id, osgDB::INT_SIZE);					//unsigned int

	/*explain:
	std::map< unsigned int, osg::ref_ptr<osg::Object> > IdentifierMap;
	IdentifierMap Used to store the object (block) corresponding to ID and ID
	*/
	//Determine whether the block corresponding to the ID exists
	IdentifierMap::iterator it = _identifierMap.find(id);
	if(it != _identifierMap.end())
	{
		
		//Return block
		return it->second;
	}

	//Read the information of the corresponding field according to the string className and id
	osg::ref_ptr<osg::Object> obj = readObjectFields(className, id, existingObj);
	

2.7 select the corresponding field to read according to the value of string className.

  • Read osg::Object field
	//Read string
	_in->read((char*)&size, osgDB::INT_SIZE);					//int
	_in->read((char*)s.c_str(), size);
	
	_in->read((char*)&i, osgDB::INT_SIZE);					    //int
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
  • osg::Node field
	//Bool, usually read a char and set the bool value according to the char
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read(&c, osgDB::CHAR_SIZE);							//bool
	_in->read((char*)&i, osgDB::INT_SIZE);						//unsignde int
	_in->read(&c, osgDB::CHAR_SIZE);							//bool

	//Note: according to the previous bool value, if it is true, you need to read the relevant information immediately
  • osg::LOD field
	_in->read((char*)&i, osgDB::INT_SIZE);						//int
	//If bool value is false, return true
	_in->read(&c, osgDB::CHAR_SIZE);							//bool

	//Read center point and radius
	_in->read((char*)&d, osgDB::DOUBLE_SIZE);					//double
	_in->read((char*)&d, osgDB::DOUBLE_SIZE);					//double
	_in->read((char*)&d, osgDB::DOUBLE_SIZE);					//double

	_in->read((char*)&d, osgDB::DOUBLE_SIZE);					//double

	_in->read((char*)&i, osgDB::INT_SIZE);						//int

	//RangList information reading
	_in->read(&c, osgDB::CHAR_SIZE);							//bool,false returns true

	_in->read((char*)&size, osgDB::INT_SIZE);					//unsignde  int
	
	//BEGIN_BRACKET operation, omitted here, see above
	...

	//Cyclic reading according to size
	for(int i = 0;i<size;++i)
	{
		_in->read((char*)&min, osgDB::FLOAT_SIZE);				//float
		_in->read((char*)&max, osgDB::FLOAT_SIZE);				//float
		
		//osg::LOD& node 
		node.setRange(i,min,max);
	}

	//END_ Brake operation
	if (_supportBinaryBrackets)
	{
		//If the stack is not empty, get out of the stack
		_beginPositions.pop_back();
		_blockSizes.pop_back();
	}
  • osg::PagedLOD subfield
	_in->read(&c, osgDB::CHAR_SIZE);							//bool,false return true
	_in->read(&havePath, osgDB::CHAR_SIZE);						//bool

	//If havePath is true, you need to read string
	_in->read((char*)&size, osgDB::INT_SIZE);					//int
	_in->read((char*)s.c_str(), size);							//string
  • osg::PagedLOD combined field
    Reading osg::PagedLOD requires reading four fields.

    • osg::Object
    • osg::Node
    • osg::LOD
    • osg::PagedLOD subfield
  • osg::Geode combination field

    • osg::Object
    • osg::Node
    • osg::Geode subfield
  • osg::Geometry combined field

    • osg::Object
    • osg::Drawable
    • osg::Geometry
  • osg::stateSet

    • osg::Object
    • osg::stateSet
  • osg::Material

    • osg::Object
    • osg::stateAttribute
    • osg::material
  • osg::Texture2D

    • osg::Object
    • osg::stateAttribute
    • osg::Texture
    • osg::Texture2D
  • osg::Object

    • osg::Object
  • osg::Group

    • osg::Object
    • osg::Node
    • osg::Group
  • osg::DrawElementsUint

    • osg::Object
    • osg::PrimitiveSet
    • osg::DrawElementsUint
  • osg::Vec3Array

    • osg::Object
    • osg::Array
    • osg::Vec3Array
  • osg::Vec2Array

    • osg::Object
    • osg::Array
    • osg::Vec2Array
  • osg::Node

    • osg::Object
    • osg::Node
  • osg::MatrixTransform

    • osg::Object
    • osg::Node
    • osg::Group
    • osg::Transform
    • osg::MatrixTransform
  • osg::TexMat

    • osg::Object
    • osg::StateAttribute
    • osg::TexMat
  • osg::DefaultUserData combination field

    • osg::Object
    • osg::UserDataContainer
    • osg::DefaultUserDataContainer
  • OSG:: drawelementsusshort combined field

    • osg::Object
    • osg::PrimitiveSet
    • osg::DrawElementsUshort

2.8 complete source code interpretation
You can analyze the composition of OSGB format through the key part of the source code. The comment part is an excerpt of the source code, which is used to assist in the analysis of the current source code.

  • Binary OSGB write class definition:
class BinaryOutputIterator : public osgDB::OutputIterator
{
public:
	BinaryOutputIterator(std::ostream* ostream) { _out = ostream; }
	virtual ~BinaryOutputIterator() {}
	virtual bool isBinary() const { return true; }
	virtual void writeBool(bool b)
	{
		char c = b ? 1 : 0; _out->write(&c, osgDB::CHAR_SIZE);
	}
	virtual void writeChar(char c)
	{
		_out->write(&c, osgDB::CHAR_SIZE);
	}
	virtual void writeUChar(unsigned char c)
	{
		_out->write((char*)&c, osgDB::CHAR_SIZE);
	}
	virtual void writeShort(short s)
	{
		_out->write((char*)&s, osgDB::SHORT_SIZE);
	}
	virtual void writeUShort(unsigned short s)
	{
		_out->write((char*)&s, osgDB::SHORT_SIZE);
	}
	virtual void writeInt(int i)
	{
		_out->write((char*)&i, osgDB::INT_SIZE);
	}
	virtual void writeUInt(unsigned int i)
	{
		_out->write((char*)&i, osgDB::INT_SIZE);
	}
	virtual void writeLong(long l)
	{
		// On 64-bit systems a long may not be the same size as the file value
		int32_t value = (int32_t)l;
		_out->write((char*)&value, osgDB::LONG_SIZE);
	}
	virtual void writeULong(unsigned long l)
	{
		// On 64-bit systems a long may not be the same size as the file value
		uint32_t value = (int32_t)l;
		_out->write((char*)&value, osgDB::LONG_SIZE);
	}
	virtual void writeInt64(int64_t ll)
	{
		_out->write((char*)&ll, osgDB::INT64_SIZE);
	}
	virtual void writeUInt64(uint64_t ull)
	{
		_out->write((char*)&ull, osgDB::INT64_SIZE);
	}
	virtual void writeInt(long long ll)
	{
		_out->write((char*)&ll, osgDB::INT64_SIZE);
	}
	virtual void writeUInt(unsigned long long ull)
	{
		_out->write((char*)&ull, osgDB::INT64_SIZE);
	}
	virtual void writeFloat(float f)
	{
		_out->write((char*)&f, osgDB::FLOAT_SIZE);
	}
	virtual void writeDouble(double d)
	{
		_out->write((char*)&d, osgDB::DOUBLE_SIZE);
	}
	virtual void writeString(const std::string& s)
	{
		int size = s.size();
		_out->write((char*)&size, osgDB::INT_SIZE);
		_out->write(s.c_str(), s.size());
	}
	virtual void writeStream(std::ostream& (* /*fn*/)(std::ostream&)) {}
	virtual void writeBase(std::ios_base& (* /*fn*/)(std::ios_base&)) {}
	virtual void writeGLenum(const osgDB::ObjectGLenum& value)
	{
		GLenum e = value.get(); _out->write((char*)&e, osgDB::GLENUM_SIZE);
	}
	virtual void writeProperty(const osgDB::ObjectProperty& prop)
	{
		if (prop._mapProperty) _out->write((char*)&(prop._value), osgDB::INT_SIZE);
	}
	virtual void writeMark(const osgDB::ObjectMark& mark)
	{
		if (_supportBinaryBrackets)
		{
			if (getOutputStream() && getOutputStream()->getFileVersion() > 148)
			{
				if (mark._name == "{")
				{
					uint64_t size = 0;
					_beginPositions.push_back(_out->tellp());
					_out->write((char*)&size, osgDB::INT64_SIZE);
				}
				else if (mark._name == "}" && _beginPositions.size() > 0)
				{
					std::streampos pos = _out->tellp(), beginPos = _beginPositions.back();
					_beginPositions.pop_back();
					_out->seekp(beginPos);
					std::streampos size64 = pos - beginPos;
					uint64_t size = (uint64_t)size64;
					_out->write((char*)&size, osgDB::INT64_SIZE);
					_out->seekp(pos);
				}
			}
			else
			{
				if (mark._name == "{")
				{
					int size = 0;
					_beginPositions.push_back(_out->tellp());
					_out->write((char*)&size, osgDB::INT_SIZE);
				}
				else if (mark._name == "}" && _beginPositions.size() > 0)
				{
					std::streampos pos = _out->tellp(), beginPos = _beginPositions.back();
					_beginPositions.pop_back();
					_out->seekp(beginPos);
					std::streampos size64 = pos - beginPos;
					int size = (int)size64;
					_out->write((char*)&size, osgDB::INT_SIZE);
					_out->seekp(pos);
				}
			}
		}
	}
	virtual void writeCharArray(const char* s, unsigned int size)
	{
		if (size > 0) _out->write(s, size);
	}
	virtual void writeWrappedString(const std::string& str)
	{
		writeString(str);
	}
protected:
	std::vector<std::streampos> _beginPositions;
};
  • Binary OSGB read class definition
inline void swapBytes( char* in, unsigned int size )
{
    char* start = in;
    char* end = start+size-1;
    while (start<end)
    {
        std::swap(*start++,*end--);
    }
}
class BinaryInputIterator : public osgDB::InputIterator
{
public:
	BinaryInputIterator(std::istream* istream, int byteSwap)
	{
		_in = istream;
		setByteSwap(byteSwap);
	}
	virtual ~BinaryInputIterator() {}
	virtual bool isBinary() const { return true; }
	virtual void readBool(bool& b)
	{
		char c = 0;
		_in->read(&c, osgDB::CHAR_SIZE);
		b = (c != 0);
	}
	virtual void readChar(char& c)
	{
		_in->read(&c, osgDB::CHAR_SIZE);
	}
	virtual void readSChar(signed char& c)
	{
		_in->read((char*)&c, osgDB::CHAR_SIZE);
	}
	virtual void readUChar(unsigned char& c)
	{
		_in->read((char*)&c, osgDB::CHAR_SIZE);
	}
	virtual void readShort(short& s)
	{
		_in->read((char*)&s, osgDB::SHORT_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&s, osgDB::SHORT_SIZE);
	}
	virtual void readUShort(unsigned short& s)
	{
		_in->read((char*)&s, osgDB::SHORT_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&s, osgDB::SHORT_SIZE);
	}
	virtual void readInt(int& i)
	{
		_in->read((char*)&i, osgDB::INT_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&i, osgDB::INT_SIZE);
	}
	virtual void readUInt(unsigned int& i)
	{
		_in->read((char*)&i, osgDB::INT_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&i, osgDB::INT_SIZE);
	}
	virtual void readLong(long& l)
	{
		// On 64-bit systems a long may not be the same size as the file value
		int32_t value;
		_in->read((char*)&value, osgDB::LONG_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&value, osgDB::LONG_SIZE);
		l = (long)value;
	}
	virtual void readULong(unsigned long& l)
	{
		uint32_t value;
		_in->read((char*)&value, osgDB::LONG_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&value, osgDB::LONG_SIZE);
		l = (unsigned long)value;
	}
	virtual void readFloat(float& f)
	{
		_in->read((char*)&f, osgDB::FLOAT_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&f, osgDB::FLOAT_SIZE);
	}
	virtual void readDouble(double& d)
	{
		_in->read((char*)&d, osgDB::DOUBLE_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&d, osgDB::DOUBLE_SIZE);
	}
	virtual void readString(std::string& s)
	{
		int size = 0;
		readInt(size);
		if (size > 0)
		{
			s.resize(size);
			_in->read((char*)s.c_str(), size);
		}
		else if (size < 0)
		{
			throwException("InputStream::readString() error, negative string size read.");
		}
	}
	virtual void readStream(std::istream& (* /*fn*/)(std::istream&)) {}
	virtual void readBase(std::ios_base& (* /*fn*/)(std::ios_base&)) {}
	virtual void readGLenum(osgDB::ObjectGLenum& value)
	{
		GLenum e = 0;
		_in->read((char*)&e, osgDB::GLENUM_SIZE);
		if (_byteSwap) osg::swapBytes((char*)&e, osgDB::GLENUM_SIZE);
		value.set(e);
	}
	virtual void readProperty(osgDB::ObjectProperty& prop)
	{
		int value = 0;
		if (prop._mapProperty)
		{
			_in->read((char*)&value, osgDB::INT_SIZE);
			if (_byteSwap) osg::swapBytes((char*)&value, osgDB::INT_SIZE);
		}
		prop.set(value);
	}
	virtual void readMark(osgDB::ObjectMark& mark)
	{
		if (_supportBinaryBrackets)
		{
			if (mark._name == "{")
			{
				_beginPositions.push_back(_in->tellg());
				// since version 149 (osg version > 3.5.6) size is expressed 
				// on 8 bytes rather than 4 bytes, 
				// to accommodate any block size.
				if (getInputStream() && getInputStream()->getFileVersion() > 148)
				{
					uint64_t size = 0;
					_in->read((char*)&size, osgDB::INT64_SIZE);
					if (_byteSwap) osg::swapBytes((char*)&size, osgDB::INT64_SIZE);
					_blockSizes.push_back(size);
				}
				else
				{
					int size = 0;
					_in->read((char*)&size, osgDB::INT_SIZE);
					if (_byteSwap) osg::swapBytes((char*)&size, osgDB::INT_SIZE);
					_blockSizes.push_back(size);
				}
			}
			else if (mark._name == "}" && _beginPositions.size() > 0)
			{
				_beginPositions.pop_back();
				_blockSizes.pop_back();
			}
		}
	}
	virtual void readCharArray(char* s, unsigned int size)
	{
		if (size > 0) _in->read(s, size);
	}
	virtual void readWrappedString(std::string& str)
	{
		readString(str);
	}
	virtual void advanceToCurrentEndBracket()
	{
		if (_supportBinaryBrackets && _beginPositions.size() > 0)
		{
			std::streampos position(_beginPositions.back());
			position += _blockSizes.back();
			_in->seekg(position);
			_beginPositions.pop_back();
			_blockSizes.pop_back();
		}
	}
protected:
	std::vector<std::streampos> _beginPositions;
	std::vector<std::streampos> _blockSizes;
};
  • Read header file: load the corresponding read plug-in through the tilt photography suffix
InputIterator* readInputIterator(std::istream& fin, const Options* options)
{
	bool extensionIsAscii = false, extensionIsXML = false;
	if (options)
	{
		const std::string& optionString = options->getPluginStringData("fileType");
		if (optionString == "Ascii") extensionIsAscii = true;
		else if (optionString == "XML") extensionIsXML = true;
	}
	if (!extensionIsAscii && !extensionIsXML)
	{
		unsigned int headerLow = 0, headerHigh = 0;
		fin.read((char*)&headerLow, INT_SIZE);
		fin.read((char*)&headerHigh, INT_SIZE);
		// OSG Header (MD5, 16Bit), the excerpt part, defines the MD5 code of header information
		//#define OSG_HEADER_LOW  0x6C910EA1
		//#define OSG_HEADER_HIGH 0x1AFB4545
		if (headerLow == OSG_HEADER_LOW && headerHigh == OSG_HEADER_HIGH)
		{
			OSG_INFO << "Reading OpenSceneGraph binary file with the same endian as this computer." << std::endl;
			return new BinaryInputIterator(&fin, 0); // endian the same so no byte swap required
		}
		//#define OSG_ Reverse (value) (((value & 0x000000ff) < < 24) | ((value & 0x0000ff00) < < 8) | ((value & 0x00ff0000) > > 8) | ((value & 0xff000000) > > 24)), excerpt, which is used to assist in analyzing the source code
		else if (headerLow == OSG_REVERSE(OSG_HEADER_LOW) && headerHigh == OSG_REVERSE(OSG_HEADER_HIGH))
		{
			OSG_INFO << "Reading OpenSceneGraph binary file with the different endian to this computer, doing byte swap." << std::endl;
			return new BinaryInputIterator(&fin, 1); // endian different so byte swap required
		}
		fin.seekg(0, std::ios::beg);
	}
	if (!extensionIsXML)
	{
		std::string header; fin >> header;
		if (header == "#Ascii")
		{
			return new AsciiInputIterator(&fin);
		}
		fin.seekg(0, std::ios::beg);
	}
	if (1)
	{
		std::string header; std::getline(fin, header);
		if (!header.compare(0, 5, "<?xml"))
		{
			return new XmlInputIterator(&fin);
		}
		fin.seekg(0, std::ios::beg);
	}
	return NULL;
}
  • Read attribute information
InputStream::ReadType InputStream::start(InputIterator* inIterator)
{
	_fields.clear();
	_fields.push_back("Start");
	ReadType type = READ_UNKNOWN;
	_in = inIterator;
	if (!_in)
		throwException("InputStream: Null stream specified.");
	if (getException()) return type;
	_in->setInputStream(this);
	// Check OSG header information
	unsigned int version = 0;
	if (isBinary())
	{
		unsigned int typeValue;
		*this >> typeValue >> version;
		type = static_cast<ReadType>(typeValue);
		unsigned int attributes; *this >> attributes;
		if (attributes & 0x4) inIterator->setSupportBinaryBrackets(true);
		if (attributes & 0x2) _useSchemaData = true;
		// Record custom domains
		if (attributes & 0x1)
		{
			unsigned int numDomains; *this >> numDomains;
			for (unsigned int i = 0; i < numDomains; ++i)
			{
				std::string domainName; *this >> domainName;
				int domainVersion; *this >> domainVersion;
				_domainVersionMap[domainName] = domainVersion;
			}
		}
	}
	if (!isBinary())
	{
		std::string typeString; *this >> typeString;
		if (typeString == "Scene") type = READ_SCENE;
		else if (typeString == "Image") type = READ_IMAGE;
		else if (typeString == "Object") type = READ_OBJECT;
		std::string osgName, osgVersion;
		*this >> PROPERTY("#Version") >> version;
		*this >> PROPERTY("#Generator") >> osgName >> osgVersion;
		while (matchString("#CustomDomain"))
		{
			std::string domainName; *this >> domainName;
			int domainVersion; *this >> domainVersion;
			_domainVersionMap[domainName] = domainVersion;
		}
	}
	// Record file version for back-compatibility checking of wrappers
	_fileVersion = version;
	_fields.pop_back();
	return type;
}
  • Read compressor
    Generally, the compressor name is 0;
void InputStream::decompress()
{
	if (!isBinary()) return;
	_fields.clear();
	std::string compressorName; *this >> compressorName;
	if (compressorName != "0")
	{
		//When the compressor is zlib or other non-0 compressor, the decompress function of the corresponding compressor will be called;
		std::string data;
		_fields.push_back("Decompression");
		//Find the object wrapper through the packaging manager and read the information of the object;
		BaseCompressor* compressor = Registry::instance()->getObjectWrapperManager()->findCompressor(compressorName);
		if (!compressor)
		{
			throwException("InputStream: Failed to decompress stream, No such compressor.");
			return;
		}
		if (!compressor->decompress(*(_in->getStream()), data))
			throwException("InputStream: Failed to decompress stream.");
		if (getException()) return;
		_dataDecompress = new std::stringstream(data);
		_in->setStream(_dataDecompress);
		_fields.pop_back();
	}
	if (_useSchemaData)
	{
		_fields.push_back("SchemaData");
		std::string schemaSource; *this >> schemaSource;
		std::istringstream iss(schemaSource);
		readSchema(iss);
		_fields.pop_back();
	}
}

The decompress function of null and zlib compressor is defined as follows:

class NullCompressor : public BaseCompressor
{
public:
    NullCompressor() {}
    virtual bool compress( std::ostream& fout, const std::string& src )
    {
        int size = src.size();
        fout.write( (char*)&size, INT_SIZE );
        fout.write( src.c_str(), src.size() );
        return true;
    }
    virtual bool decompress( std::istream& fin, std::string& target )
    {
        int size = 0; fin.read( (char*)&size, INT_SIZE );
        if ( size )
        {
            target.resize( size );
            fin.read( (char*)target.c_str(), size );
        }
        return true;
    }
};
REGISTER_COMPRESSOR( "null", NullCompressor )
#ifdef USE_ZLIB
#include <zlib.h>
#define CHUNK 32768
// ZLib compressor
class ZLibCompressor : public BaseCompressor
{
public:
    ZLibCompressor() {}
    virtual bool compress( std::ostream& fout, const std::string& src )
    {
        int ret, flush = Z_FINISH;
        unsigned have;
        z_stream strm;
        unsigned char out[CHUNK];
        int level = 6;
        int stategy = Z_DEFAULT_STRATEGY;
        /* allocate deflate state */
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        ret = deflateInit2( &strm, level, Z_DEFLATED, 15+16, // +16 to use gzip encoding
                           8, // default
                           stategy );
        if ( ret != Z_OK ) return false;
        strm.avail_in = src.size();
        strm.next_in = (Bytef*)( &(*src.begin()) );
        /* run deflate() on input until output buffer not full, finish
           compression if all of source has been read in */
        do
        {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = deflate(&strm, flush);    /* no bad return value */
            if ( ret == Z_STREAM_ERROR )
            {
                OSG_NOTICE << "Z_STREAM_ERROR" << std::endl;
                return false;
            }
            have = CHUNK - strm.avail_out;
            if ( have>0 ) fout.write( (const char*)out, have );
            if ( fout.fail() )
            {
                (void)deflateEnd( &strm );
                return false;
            }
        } while ( strm.avail_out==0 );
        /* clean up and return */
        (void)deflateEnd( &strm );
        return true;
    }
    virtual bool decompress( std::istream& fin, std::string& target )
    {
        int ret;
        unsigned have;
        z_stream strm;
        unsigned char in[CHUNK];
        unsigned char out[CHUNK];
        /* allocate inflate state */
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        strm.avail_in = 0;
        strm.next_in = Z_NULL;
        ret = inflateInit2( &strm,15 + 32 ); // autodected zlib or gzip header
        if ( ret!=Z_OK )
        {
            OSG_INFO << "failed to init" << std::endl;
            return ret!=0;
        }
        /* decompress until deflate stream ends or end of file */
        do
        {
            fin.read( (char *)in, CHUNK );
            strm.avail_in = fin.gcount();
            if (strm.avail_in==0 ) break;
            /* run inflate() on input until output buffer not full */
            strm.next_in = in;
            do
            {
                strm.avail_out = CHUNK;
                strm.next_out = out;
                ret = inflate( &strm, Z_NO_FLUSH );
                switch (ret)
                {
                case Z_NEED_DICT:
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
                    (void)inflateEnd( &strm );
                    return false;
                }
                have = CHUNK - strm.avail_out;
                target.append( (char*)out, have );
            } while ( strm.avail_out==0 );
            /* done when inflate() says it's done */
        } while ( ret!=Z_STREAM_END );
        /* clean up and return */
        (void)inflateEnd( &strm );
        return ret==Z_STREAM_END ? true : false;
    }
};
REGISTER_COMPRESSOR( "zlib", ZLibCompressor )
#endif
  • Read each object
    Read the children of each composite object according to its name.
osg::ref_ptr<osg::Object> InputStream::readObject(osg::Object* existingObj)
{
	std::string className;
	unsigned int id = 0;
	*this >> className;
	if (className == "NULL")
	{
		return 0;
	}
	*this >> BEGIN_BRACKET >> PROPERTY("UniqueID") >> id;
	if (getException()) return 0;
	//Each object corresponds to an id and name. According to the id, you can judge whether the id already exists;
	IdentifierMap::iterator itr = _identifierMap.find(id);
	if (itr != _identifierMap.end())
	{
		advanceToCurrentEndBracket();
		return itr->second;
	}
	std::cout << "className = " << className << std::endl;
	osg::ref_ptr<osg::Object> obj = readObjectFields(className, id, existingObj);
	advanceToCurrentEndBracket();
	return obj;
}
  • BEGIN_ Break and end_ Brake operation
    BEGIN_BRACKET ,END_ Brake is an ObjectMark class object. Different objects set different initial values.
    • Class definition
	class ObjectMark
	{
	public:
		ObjectMark() : _indentDelta(0) {}
		ObjectMark(const ObjectMark& copy)
			: _name(copy._name), _indentDelta(copy._indentDelta) {}
		void set(const char* name, int delta = 0)
		{
			_name = name; _indentDelta = delta;
		}
		std::string _name;
		int _indentDelta;
	};
  • BEGIN_ Brake operation
    BEGIN_ Brake is an ObjectMark object, which sets the initial value of the object: "{"
	virtual void readMark(osgDB::ObjectMark& mark)
	{
		if (_supportBinaryBrackets)
		{
			if (mark._name == "{")
			{
				_beginPositions.push_back(_in->tellg());
				// since version 149 (osg version > 3.5.6) size is expressed 
				// on 8 bytes rather than 4 bytes, 
				// to accommodate any block size.
				if (getInputStream() && getInputStream()->getFileVersion() > 148)
				{
					uint64_t size = 0;
					_in->read((char*)&size, osgDB::INT64_SIZE);
					if (_byteSwap) osg::swapBytes((char*)&size, osgDB::INT64_SIZE);
					_blockSizes.push_back(size);
				}
				else
				{
					int size = 0;
					_in->read((char*)&size, osgDB::INT_SIZE);
					if (_byteSwap) osg::swapBytes((char*)&size, osgDB::INT_SIZE);
					_blockSizes.push_back(size);
				}
			}
			else if (mark._name == "}" && _beginPositions.size() > 0)
			{
				_beginPositions.pop_back();
				_blockSizes.pop_back();
			}
		}
	}
  • PROPERTY operation
    • Class definition
	class ObjectProperty
	{
	public:
		ObjectProperty() : _value(0), _mapProperty(false) {}
		ObjectProperty(const char* name, int value = 0, bool useMap = false)
			: _name(name), _value(value), _mapProperty(useMap) {}
		ObjectProperty(const ObjectProperty& copy)
			: _name(copy._name), _value(copy._value), _mapProperty(copy._mapProperty) {}
		ObjectProperty& operator()(const char* name)
		{
			_name = name; return *this;
		}
		void set(int v) { _value = v; }
		int get() const { return _value; }
		std::string _name;
		int _value;
		bool _mapProperty;
	};
  • read operation
	virtual void readProperty(osgDB::ObjectProperty& prop)
	{
		int value = 0;
		if (prop._mapProperty)
		{
			_in->read((char*)&value, osgDB::INT_SIZE);
			if (_byteSwap) osg::swapBytes((char*)&value, osgDB::INT_SIZE);
		}
		prop.set(value);
	}
  • Subfield read
    In the code, getobjectwrappermanager () - > findwrapper (classname) finds the wrapper of the object, encapsulates its sub fields in each wrapper, obtains the sub fields of the wrapper through getAssociates(), and then reads them one by one.
osg::ref_ptr<osg::Object> InputStream::readObjectFields(const std::string& className, unsigned int id, osg::Object* existingObj)
{
	ObjectWrapper* wrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(className);
	if (!wrapper)
	{
		OSG_WARN << "InputStream::readObject(): Unsupported wrapper class "
			<< className << std::endl;
		return NULL;
	}
	int inputVersion = getFileVersion(wrapper->getDomain());
	osg::ref_ptr<osg::Object> obj = existingObj ? existingObj : wrapper->createInstance();
	_identifierMap[id] = obj;
	if (obj.valid())
	{
		const ObjectWrapper::RevisionAssociateList& associates = wrapper->getAssociates();
		for (ObjectWrapper::RevisionAssociateList::const_iterator itr = associates.begin(); itr != associates.end(); ++itr)
		{
			if (itr->_firstVersion <= inputVersion &&
				inputVersion <= itr->_lastVersion)
			{
				ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(itr->_name);
				if (!assocWrapper)
				{
					OSG_WARN << "InputStream::readObject(): Unsupported associated class "
						<< itr->_name << std::endl;
					continue;
				}
				_fields.push_back(assocWrapper->getName());
				std::cout << "_fileds add : " << assocWrapper->getName() << std::endl;
				assocWrapper->read(*this, *obj);
				if (getException()) return NULL;
				_fields.pop_back();
			}
			else
			{
				/* OSG_INFO << "InputStream::readObject():"<<className<<" Ignoring associated class due to version mismatch"
				          << itr->_name<<"["<<itr->_firstVersion <<","<<itr->_lastVersion <<"]for version "<<inputVersion<< std::endl;*/
			}
		}
	}
	return obj;
}

The function to find the wrapper is as follows:

ObjectWrapper* ObjectWrapperManager::findWrapper( const std::string& name )
{
    OpenThreads::ScopedLock<OpenThreads::ReentrantMutex> lock(_wrapperMutex);
    WrapperMap::iterator itr = _wrappers.find( name );
    if ( itr!=_wrappers.end() ) return itr->second.get();
    // Load external libraries
    std::string::size_type posDoubleColon = name.rfind("::");
    if ( posDoubleColon!=std::string::npos )
    {
        std::string libName = std::string( name, 0, posDoubleColon );
        ObjectWrapper* found=0;
        std::string nodeKitLib = osgDB::Registry::instance()->createLibraryNameForNodeKit(libName);
        if ( osgDB::Registry::instance()->loadLibrary(nodeKitLib)==osgDB::Registry::LOADED )
            found= findWrapper(name);
        std::string pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(std::string("serializers_")+libName);
        if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED )
            found= findWrapper(name);
        pluginLib = osgDB::Registry::instance()->createLibraryNameForExtension(libName);
        if ( osgDB::Registry::instance()->loadLibrary(pluginLib)==osgDB::Registry::LOADED )
            found= findWrapper(name);
        if (found) found->setupAssociatesRevisionsInheritanceIfRequired();
        return found;
    }
    return NULL;
}

The wrapper subfield reading function is as follows: read the corresponding information through the corresponding serialization function, which is responsible for reading the information,

bool ObjectWrapper::read( InputStream& is, osg::Object& obj )
{
    bool readOK = true;
    int inputVersion = is.getFileVersion(_domain);
    for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr )
    {
        BaseSerializer* serializer = itr->get();
        if ( serializer->_firstVersion <= inputVersion && inputVersion <= serializer->_lastVersion && serializer->supportsReadWrite())
        {
            if ( !serializer->read(is, obj) )
            {
                OSG_WARN << "ObjectWrapper::read(): Error reading property "<< _name << "::" << (*itr)->getName() << std::endl;
                readOK = false;
            }
        }
        else
        {
            // OSG_NOTICE<<"Ignoring serializer due to version mismatch"<<std::endl;
        }
    }
    for ( FinishedObjectReadCallbackList::iterator itr=_finishedObjectReadCallbacks.begin();itr!=_finishedObjectReadCallbacks.end();++itr )
     {
         (*itr)->objectRead(is, obj);
     }
    return readOK;
}

2.8 serialization mechanism

Each object corresponds to a serialization mechanism. The serialization mechanism is described below through PagedLOD.

#include <osg/PagedLOD>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>
#include <osgDB/Options>
// _databasePath
static bool checkDatabasePath( const osg::PagedLOD& node )
{
    return true;
}
static bool readDatabasePath( osgDB::InputStream& is, osg::PagedLOD& node )
{
    bool hasPath; is >> hasPath;
    if ( !hasPath )
    {
        if ( is.getOptions() && !is.getOptions()->getDatabasePathList().empty() )
        {
            const std::string& optionPath = is.getOptions()->getDatabasePathList().front();
            if ( !optionPath.empty() ) node.setDatabasePath( optionPath );
        }
    }
    else
    {
        std::string path; is.readWrappedString( path );
        node.setDatabasePath( path );
    }
    return true;
}
static bool writeDatabasePath( osgDB::OutputStream& os, const osg::PagedLOD& node )
{
    os << (!node.getDatabasePath().empty());
    if ( !node.getDatabasePath().empty() )
        os.writeWrappedString( node.getDatabasePath() );
    os << std::endl;
    return true;
}
// _perRangeDataList
static bool checkRangeDataList( const osg::PagedLOD& node )
{
    return node.getNumFileNames()>0;
}
static bool readRangeDataList( osgDB::InputStream& is, osg::PagedLOD& node )
{
    unsigned int size = 0; is >> size >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        std::string name; is.readWrappedString( name );
        node.setFileName( i, name );
    }
    is >> is.END_BRACKET;
    size = 0; is >> is.PROPERTY("PriorityList") >> size >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        float offset, scale;
        is >> offset >> scale;
        node.setPriorityOffset( i, offset );
        node.setPriorityScale( i, scale );
    }
    is >> is.END_BRACKET;
    return true;
}
static bool writeRangeDataList( osgDB::OutputStream& os, const osg::PagedLOD& node )
{
    unsigned int size = node.getNumFileNames();
    os << size << os.BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<size; ++i )
    {
        os.writeWrappedString( node.getFileName(i) );
        os << std::endl;
    }
    os << os.END_BRACKET << std::endl;
    size = node.getNumPriorityOffsets();
    os << os.PROPERTY("PriorityList") << size << os.BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<size; ++i )
    {
        os << node.getPriorityOffset(i) << node.getPriorityScale(i) << std::endl;
    }
    os << os.END_BRACKET << std::endl;
    return true;
}
// _children
static bool checkChildren( const osg::PagedLOD& node )
{
    return node.getNumChildren()>0;
}
static bool readChildren( osgDB::InputStream& is, osg::PagedLOD& node )
{
    unsigned int size = 0; is >> size;
    if (size > 0)
    {
        is >> is.BEGIN_BRACKET;
        for ( unsigned int i=0; i<size; ++i )
        {
            osg::ref_ptr<osg::Node> child = is.readObjectOfType<osg::Node>();
            if ( child ) node.addChild( child );
        }
        is >> is.END_BRACKET;
    }
    return true;
}
static bool writeChildren( osgDB::OutputStream& os, const osg::PagedLOD& node )
{
    unsigned int size=node.getNumFileNames(), dynamicLoadedSize=0;
    for ( unsigned int i=0; i<size; ++i )
    {
        if ( !node.getFileName(i).empty() )
            dynamicLoadedSize++;
    }
    unsigned int realSize = size-dynamicLoadedSize; os << realSize;
    if ( realSize>0 )
    {
        os << os.BEGIN_BRACKET << std::endl;
        for ( unsigned int i=0; i<size; ++i )
        {
            if ( !node.getFileName(i).empty() ) continue;
            if ( i<node.getNumChildren() )
                os << node.getChild(i);
        }
        os << os.END_BRACKET;
    }
    os << std::endl;
    return true;
}
//Encapsulates the corresponding subfield name
REGISTER_OBJECT_WRAPPER( PagedLOD,
                         new osg::PagedLOD,
                         osg::PagedLOD,
                         "osg::Object osg::Node osg::LOD osg::PagedLOD" )
{
    // Note: osg::Group is not in the list to prevent recording dynamic loaded children
    ADD_USER_SERIALIZER( DatabasePath );  // _databasePath
    ADD_UINT_SERIALIZER( FrameNumberOfLastTraversal, 0 );  // _frameNumberOfLastTraversal, note, not required, removed from soversion 70 onwwards, see below
    ADD_UINT_SERIALIZER( NumChildrenThatCannotBeExpired, 0 );  // _numChildrenThatCannotBeExpired
    ADD_BOOL_SERIALIZER( DisableExternalChildrenPaging, false );  // _disableExternalChildrenPaging
    ADD_USER_SERIALIZER( RangeDataList );  // _perRangeDataList
    ADD_USER_SERIALIZER( Children );  // _children (which are not loaded from external)
    {
        UPDATE_TO_VERSION_SCOPED( 70 )
        REMOVE_SERIALIZER( FrameNumberOfLastTraversal );
    }
}

So far, I have a basic understanding of the osgb format, but I need to be able to parse its data and analyze the serialization mechanism of other objects. Because it involves the compatibility of iterative versions, I can directly extract the read-write source code from the OSG source code as a part of the project, which can well solve the problem of version compatibility.

3. Visual scheduling optimization of tilt photography data

3.1 load a single osgb file and display it

	osg::Group* root = new osg::Group;
	//read file
	osg::ref_ptr<osg::Node> n = osgDB::readNodeFile("E:/Desktop/Data/Tile_+157_+009/Tile_+157_+009.osgb");
	root->addChild(n);
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setSceneData(root);
	viewer->setUpViewInWindow(20, 20, 1400, 700);
	//Corresponding common keyboard key functions
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::WindowSizeHandler);
	viewer->addEventHandler(new osgViewer::StatsHandler);
	viewer->realize();
	return viewer->run();

To respond to common keyboard keys, you need to select an American keyboard to respond.

  • s: Display model statistics, including frame rate, model vertex data, etc;
  • w: Display the triangular mesh of the model;
  • f: Zoom in and out of the window;
  • b: Model occlusion (back) elimination;
  • l: Lighting control;

3.2 visualization of large data sets for tilt photography
Data preprocessing is required, mainly using:

  • Multiple root nodes can be merged for multiple times (multiple levels) and finally merged into one root node;
  • Control the size of merged nodes;
  • LOD generation: various strategies can be adopted, including model simplification, model reconstruction, etc;

4. Multi thread debugging method

4.1 during multi-threaded program debugging, multiple sub threads will switch alternately, and the program will be interrupted at the same breakpoint. Therefore, the debugging program becomes complex and is not easy to debug. There are two methods for debugging:

  • Use one-way to debug the program;
  • Specify a specific sub process and debug it: you can write a specific sub process interrupt statement (add a breakpoint in the relevant statement), or locate a specific sub process through the breakpoint. When you locate a specific sub process and cancel the breakpoint, you can try the sub process sentence by sentence;

summary

The learning of related technologies of OSG open source framework mainly focuses on the analysis, visualization and scheduling of OSGB tilt photography data.

Keywords: C++ Big Data data structure

Added by wwwapu on Sat, 23 Oct 2021 18:18:35 +0300