
This is my test XML file:
Code: Select all
<scene formatVersion="1.0.0" author="PnP Terrain Creator">
<nodes>
<node>
<position x="10.337000" y="110.991287" z="1009.718018" />
<quaternion qw="1.000000" qx="0.000000" qy="0.000000" qz="0.000000" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="ogrehead" meshfile="ogrehead.mesh" />
<userData>
<property type="BOOL" name="static" data="false" />
<property type="STRING" name="script" data="" />
<property type="STRING" name="name" data="thename" />
</userData>
</node>
<node>
<position x="162.940994" y="92.747040" z="981.447021" />
<quaternion qw="-0.377235" qx="0.000000" qy="-0.926118" qz="0.000000" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="ogrehead" meshfile="ogrehead.mesh" />
<userData>
<property type="BOOL" name="static" data="false" />
<property type="STRING" name="name" data="second head" />
</userData>
</node>
<node>
<position x="57.161037" y="62.299145" z="853.399048" />
<quaternion qw="0.980982" qx="0.194097" qy="0.000000" qz="0.000000" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="cube" meshfile="cube.mesh" />
<userData>
<property type="BOOL" name="static" data="false" />
</userData>
</node>
<node>
<position x="527.401001" y="101.923523" z="835.505005" />
<quaternion qw="-0.941894" qx="0.010783" qy="0.335727" qz="-0.002666" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="tudorhouse" meshfile="tudorhouse.mesh" />
<userData>
<property type="BOOL" name="static" data="true" />
<property type="STRING" name="script" data="tudorhouse.script" />
<property type="STRING" name="name" data="The Tudorhouse" />
</userData>
</node>
<node>
<position x="510.214996" y="46.337009" z="876.419983" />
<quaternion qw="-0.630757" qx="0.000000" qy="-0.775980" qz="0.000000" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="ninja" meshfile="ninja.mesh" />
<userData>
<property type="BOOL" name="static" data="false" />
<property type="STRING" name="script" data="ninja1.script" />
<property type="STRING" name="name" data="FabNinja" />
</userData>
</node>
<node>
<position x="491.822998" y="49.951878" z="886.934021" />
<quaternion qw="1.000000" qx="0.000000" qy="0.000000" qz="0.000000" />
<scale x="0.100000" y="0.100000" z="0.100000" />
<entity name="Barrel" meshfile="Barrel.mesh" />
<userData>
<property type="BOOL" name="static" data="false" />
<property type="STRING" name="script" data="barrel.script" />
<property type="STRING" name="name" data="ninjabarrel" />
</userData>
</node>
</nodes>
</scene>
Code: Select all
package dotproto;
message Vec3f {
optional float x = 1 [default = 0.0];
optional float y = 2 [default = 0.0];
optional float z = 3 [default = 0.0];
}
message Quat4f {
optional float w = 1 [default = 0.0];
optional float x = 2 [default = 0.0];
optional float y = 3 [default = 0.0];
optional float z = 4 [default = 0.0];
}
message Property {
optional string type = 1 [default = ""];
optional string name = 2 [default = ""];
optional string data = 3 [default = ""];
}
message Entity {
optional string name = 1 [default = ""];
optional string meshfile = 2 [default = ""];
}
message Node {
optional string name = 1;
optional Vec3f position = 2;
optional Quat4f quaternion = 3;
optional Vec3f scale = 4;
optional Entity entity = 5;
repeated Property property = 6;
}
message Scene {
repeated Node node = 1;
}
protoc --cpp_out=. dotscene.proto
And it gave me two files: dotscene.pb.cc and dotscene.pb.h.
Now, all I had to do was add those files to a project, link to Google Protocol Buffers and tell the project where the Google PB headers are.
This is a small test application, which loads a scene xml and converts it to a protocol buffer:
Code: Select all
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <google/protobuf/text_format.h>
#include <string>
#include <sstream>
#include "tinyxml/tinyxml.h"
template <class T>
bool from_string(T& t,
const std::string& s,
std::ios_base& (*f)(std::ios_base&))
{
std::istringstream iss(s);
return !(iss >> f >> t).fail();
}
int _tmain(int argc, _TCHAR* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
// a dotproto scene instance
dotproto::Scene scene;
// open xml document
TiXmlDocument xml;
if (!xml.LoadFile("testexport.xml"))
{
return false;
}
// get scene base node
TiXmlElement* pSceneRootNode = xml.FirstChildElement("scene");
if (!pSceneRootNode)
{
return false;
}
// loop through nodes
TiXmlElement* pNodesNode = pSceneRootNode->FirstChildElement("nodes");
for (TiXmlElement* pNode = pNodesNode->FirstChildElement();
pNode != 0; pNode = pNode->NextSiblingElement())
{
// add a node the scene
dotproto::Node* node = scene.add_node();
// read position
TiXmlElement* pPosition = pNode->FirstChildElement("position");
float pos_x, pos_y, pos_z = 0.0f;
from_string<float>(pos_x, pPosition->Attribute("x"), std::dec);
from_string<float>(pos_y, pPosition->Attribute("y"), std::dec);
from_string<float>(pos_z, pPosition->Attribute("z"), std::dec);
// write position
dotproto::Vec3f* pos = node->mutable_position();
pos->set_x(pos_x);
pos->set_y(pos_y);
pos->set_z(pos_z);
// read orientation
TiXmlElement* pQuaternion = pNode->FirstChildElement("quaternion");
float qw, qx, qy, qz = 0.0f;
from_string<float>(qw, pQuaternion->Attribute("qw"), std::dec);
from_string<float>(qx, pQuaternion->Attribute("qx"), std::dec);
from_string<float>(qy, pQuaternion->Attribute("qy"), std::dec);
from_string<float>(qz, pQuaternion->Attribute("qz"), std::dec);
// write orientation
dotproto::Quat4f* quat = node->mutable_quaternion();
quat->set_w(qw);
quat->set_x(qx);
quat->set_y(qy);
quat->set_z(qz);
// read scale
TiXmlElement* pScale = pNode->FirstChildElement("scale");
float sx, sy, sz = 0.0f;
from_string<float>(sx, pScale->Attribute("x"), std::dec);
from_string<float>(sy, pScale->Attribute("y"), std::dec);
from_string<float>(sz, pScale->Attribute("z"), std::dec);
// write scale
dotproto::Vec3f* scale = node->mutable_scale();
scale->set_x(sx);
scale->set_y(sy);
scale->set_z(sz);
// read and write entity
TiXmlElement* pEntity = pNode->FirstChildElement("entity");
dotproto::Entity* ent = node->mutable_entity();
ent->set_name(pEntity->Attribute("name"));
ent->set_meshfile(pEntity->Attribute("meshfile"));
// See if there's any userData
TiXmlElement* pUserdataNode = pNode->FirstChildElement("userData");
if(pUserdataNode)
{
// Loop the properties
for (TiXmlElement* pProperty = pUserdataNode->FirstChildElement();
pProperty != 0; pProperty = pProperty->NextSiblingElement())
{
// read and write property
dotproto::Property* prop1 = node->add_property();
prop1->set_type(pProperty->Attribute("type"));
prop1->set_name(pProperty->Attribute("name"));
prop1->set_data(pProperty->Attribute("data"));
}
}
}
// Are we ready to write a protocul buffer?
if(scene.IsInitialized())
{
// write protocol buffer in standard binary format.
std::string path = "./" + std::string("test.pb");
std::fstream output(path.c_str(), std::ios::out | std::ios::binary );
scene.SerializeToOstream(&output);
// write a protocol buffer in human readable text format.
std::string theproto;
google::protobuf::TextFormat::PrintToString(scene, &theproto);
std::string thepath = "./" + std::string("test.txt");
std::fstream textoutput(thepath.c_str(), std::ios::out | std::ios::binary );
textoutput << theproto;
}
// Open protocol buffer for reading.
std::string inpath = "./" + std::string("test.pb");
std::fstream input(inpath.c_str(), std::ios::in | std::ios::binary );
// Parse it
scene.ParseFromIstream(&input);
// Print the protocol buffer to the screen.
// Loop through nodes in scene
for (int i = 0; i < scene.node_size(); i++)
{
// grab a node
const dotproto::Node& out_node = scene.node(i);
// pretty print node values
std::cout << "Node Position: " << out_node.position().x() << "," << out_node.position().y() << "," << out_node.position().z() << std::endl;
std::cout << "Node Orientation: " << out_node.quaternion().w() << "," << out_node.position().x() << "," << out_node.position().y() << "," << out_node.position().z() << std::endl;
std::cout << "Node Scale: " << out_node.scale().x() << "," << out_node.scale().y() << "," << out_node.scale().z() << std::endl;
std::cout << "Node Entity name: " << out_node.entity().name() << std::endl;
std::cout << "Node Entity meshfile: " << out_node.entity().meshfile() << std::endl;
// Loop through userdata
for (int i = 0; i < out_node.property_size(); i++)
{
// grab a property
const dotproto::Property& out_property = out_node.property(i);
// pretty print property values
std::cout << "Node Userdata type: " << out_property.type() << std::endl;
std::cout << "Node Userdata name: " << out_property.name() << std::endl;
std::cout << "Node Userdata data: " << out_property.data() << std::endl;
}
}
return 0;
}
I think it's a nice alternative to XML.
What do you think?
