rev |
line source |
nuclear@19
|
1 #include <stdio.h>
|
nuclear@19
|
2 #include "goat3d.h"
|
nuclear@19
|
3 #include "goat3d_impl.h"
|
nuclear@19
|
4 #include "tinyxml2.h"
|
nuclear@19
|
5 #include "log.h"
|
nuclear@19
|
6
|
nuclear@47
|
7 using namespace g3dimpl;
|
nuclear@19
|
8 using namespace tinyxml2;
|
nuclear@19
|
9
|
nuclear@19
|
10 static Material *read_material(Scene *scn, XMLElement *xml_mtl);
|
nuclear@19
|
11 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr);
|
nuclear@19
|
12 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh);
|
nuclear@19
|
13 static std::string get_name(XMLElement *node, int idx);
|
nuclear@19
|
14
|
nuclear@19
|
15 bool Scene::loadxml(goat3d_io *io)
|
nuclear@19
|
16 {
|
nuclear@19
|
17 long bytes = io->seek(0, SEEK_END, io->cls);
|
nuclear@19
|
18 io->seek(0, SEEK_SET, io->cls);
|
nuclear@19
|
19
|
nuclear@19
|
20 char *buf = new char[bytes];
|
nuclear@19
|
21 if(io->read(buf, bytes, io->cls) < bytes) {
|
nuclear@19
|
22 logmsg(LOG_ERROR, "failed to read XML scene file\n");
|
nuclear@45
|
23 delete [] buf;
|
nuclear@19
|
24 return false;
|
nuclear@19
|
25 }
|
nuclear@19
|
26
|
nuclear@19
|
27 XMLDocument xml;
|
nuclear@19
|
28 XMLError err = xml.Parse(buf, bytes);
|
nuclear@19
|
29 if(err) {
|
nuclear@19
|
30 logmsg(LOG_ERROR, "failed to parse XML scene file: %s\n%s\n", xml.GetErrorStr1(),
|
nuclear@19
|
31 xml.GetErrorStr2());
|
nuclear@45
|
32 delete [] buf;
|
nuclear@19
|
33 return false;
|
nuclear@19
|
34 }
|
nuclear@19
|
35
|
nuclear@19
|
36 XMLElement *root = xml.RootElement();
|
nuclear@19
|
37 if(strcmp(root->Name(), "scene") != 0) {
|
nuclear@19
|
38 logmsg(LOG_ERROR, "invalid XML file, root node is not <scene>\n");
|
nuclear@45
|
39 delete [] buf;
|
nuclear@19
|
40 return false;
|
nuclear@19
|
41 }
|
nuclear@19
|
42
|
nuclear@19
|
43 XMLElement *elem;
|
nuclear@19
|
44
|
nuclear@19
|
45 // get all materials
|
nuclear@19
|
46 elem = root->FirstChildElement("mtl");
|
nuclear@19
|
47 while(elem) {
|
nuclear@19
|
48 Material *mtl = read_material(this, elem);
|
nuclear@19
|
49 if(mtl) {
|
nuclear@19
|
50 add_material(mtl);
|
nuclear@19
|
51 }
|
nuclear@19
|
52 elem = elem->NextSiblingElement("mtl");
|
nuclear@19
|
53 }
|
nuclear@19
|
54
|
nuclear@19
|
55 // get all meshes
|
nuclear@19
|
56 elem = root->FirstChildElement("mesh");
|
nuclear@19
|
57 while(elem) {
|
nuclear@19
|
58 Mesh *mesh = read_mesh(this, elem);
|
nuclear@19
|
59 if(mesh) {
|
nuclear@19
|
60 add_mesh(mesh);
|
nuclear@19
|
61 }
|
nuclear@19
|
62 elem = elem->NextSiblingElement("mesh");
|
nuclear@19
|
63 }
|
nuclear@19
|
64
|
nuclear@45
|
65 delete [] buf;
|
nuclear@45
|
66 return true;
|
nuclear@19
|
67 }
|
nuclear@19
|
68
|
nuclear@19
|
69
|
nuclear@50
|
70 bool Scene::load_anim_xml(goat3d_io *io)
|
nuclear@50
|
71 {
|
nuclear@50
|
72 return false;
|
nuclear@50
|
73 }
|
nuclear@50
|
74
|
nuclear@50
|
75
|
nuclear@19
|
76 static Material *read_material(Scene *scn, XMLElement *xml_mtl)
|
nuclear@19
|
77 {
|
nuclear@19
|
78 Material *mtl = new Material;
|
nuclear@19
|
79 mtl->name = get_name(xml_mtl, scn->get_material_count());
|
nuclear@19
|
80
|
nuclear@19
|
81 // get all the material attributes in turn
|
nuclear@19
|
82 XMLElement *elem = xml_mtl->FirstChildElement("attr");
|
nuclear@19
|
83 while(elem) {
|
nuclear@19
|
84 MaterialAttrib attr;
|
nuclear@19
|
85 const char *name = read_material_attrib(&attr, elem);
|
nuclear@19
|
86 if(name) {
|
nuclear@19
|
87 (*mtl)[name] = attr;
|
nuclear@19
|
88 }
|
nuclear@19
|
89
|
nuclear@19
|
90 elem = elem->NextSiblingElement("attr");
|
nuclear@19
|
91 }
|
nuclear@19
|
92
|
nuclear@19
|
93 return mtl;
|
nuclear@19
|
94 }
|
nuclear@19
|
95
|
nuclear@19
|
96 static const char *read_material_attrib(MaterialAttrib *attr, XMLElement *xml_attr)
|
nuclear@19
|
97 {
|
nuclear@19
|
98 const char *name;
|
nuclear@19
|
99
|
nuclear@19
|
100 XMLElement *elem;
|
nuclear@19
|
101 if((elem = xml_attr->FirstChildElement("name"))) {
|
nuclear@19
|
102 if(!(name = elem->Attribute("string"))) {
|
nuclear@19
|
103 return 0;
|
nuclear@19
|
104 }
|
nuclear@19
|
105 }
|
nuclear@19
|
106
|
nuclear@19
|
107 if((elem = xml_attr->FirstChildElement("val"))) {
|
nuclear@19
|
108 if(elem->QueryFloatAttribute("float", &attr->value.x) != XML_NO_ERROR) {
|
nuclear@19
|
109 // try a float3
|
nuclear@19
|
110 const char *valstr = elem->Attribute("float3");
|
nuclear@19
|
111 if(!valstr || sscanf(valstr, "%f %f %f", &attr->value.x, &attr->value.y,
|
nuclear@19
|
112 &attr->value.z) != 3) {
|
nuclear@19
|
113 // try a float4
|
nuclear@19
|
114 valstr = elem->Attribute("float4");
|
nuclear@19
|
115 if(!valstr || sscanf(valstr, "%f %f %f %f", &attr->value.x, &attr->value.y,
|
nuclear@19
|
116 &attr->value.z, &attr->value.w) != 4) {
|
nuclear@19
|
117 // no valid val attribute found
|
nuclear@19
|
118 return 0;
|
nuclear@19
|
119 }
|
nuclear@19
|
120 }
|
nuclear@19
|
121 }
|
nuclear@19
|
122 }
|
nuclear@19
|
123
|
nuclear@19
|
124 if((elem = xml_attr->FirstChildElement("map"))) {
|
nuclear@19
|
125 const char *tex = elem->Attribute("string");
|
nuclear@19
|
126 if(tex) {
|
nuclear@19
|
127 attr->map = std::string(tex);
|
nuclear@19
|
128 }
|
nuclear@19
|
129 }
|
nuclear@19
|
130
|
nuclear@19
|
131 return name;
|
nuclear@19
|
132 }
|
nuclear@19
|
133
|
nuclear@19
|
134 static Mesh *read_mesh(Scene *scn, XMLElement *xml_mesh)
|
nuclear@19
|
135 {
|
nuclear@19
|
136 Mesh *mesh = new Mesh;
|
nuclear@19
|
137 mesh->name = get_name(xml_mesh, scn->get_mesh_count());
|
nuclear@19
|
138
|
nuclear@19
|
139 XMLElement *elem;
|
nuclear@19
|
140 if((elem = xml_mesh->FirstChildElement("material"))) {
|
nuclear@19
|
141 int idx;
|
nuclear@19
|
142 if(elem->QueryIntAttribute("int", &idx) == XML_NO_ERROR) {
|
nuclear@19
|
143 mesh->material = scn->get_material(idx);
|
nuclear@19
|
144 } else {
|
nuclear@19
|
145 // try string
|
nuclear@19
|
146 const char *mtlstr = elem->Attribute("string");
|
nuclear@19
|
147 if(mtlstr) {
|
nuclear@19
|
148 mesh->material = scn->get_material(mtlstr);
|
nuclear@19
|
149 }
|
nuclear@19
|
150 }
|
nuclear@19
|
151 }
|
nuclear@19
|
152
|
nuclear@19
|
153 /* reading mesh data from XML is not supported, only MESH_FILE can be used to
|
nuclear@19
|
154 * specify an external mesh file to be loaded
|
nuclear@19
|
155 */
|
nuclear@19
|
156
|
nuclear@19
|
157 if((elem = xml_mesh->FirstChildElement("file"))) {
|
nuclear@19
|
158 const char *fname = elem->Attribute("string");
|
nuclear@19
|
159 if(fname) {
|
nuclear@19
|
160 if(!mesh->load(fname)) {
|
nuclear@19
|
161 delete mesh;
|
nuclear@19
|
162 return 0;
|
nuclear@19
|
163 }
|
nuclear@19
|
164 }
|
nuclear@19
|
165 }
|
nuclear@19
|
166
|
nuclear@19
|
167 return mesh;
|
nuclear@19
|
168 }
|
nuclear@19
|
169
|
nuclear@19
|
170 static std::string get_name(XMLElement *node, int idx)
|
nuclear@19
|
171 {
|
nuclear@19
|
172 char buf[64];
|
nuclear@19
|
173 const char *name = 0;
|
nuclear@19
|
174
|
nuclear@19
|
175 XMLElement *elem;
|
nuclear@19
|
176 if((elem = node->FirstChildElement("name"))) {
|
nuclear@19
|
177 name = elem->Attribute("string");
|
nuclear@19
|
178 }
|
nuclear@19
|
179
|
nuclear@19
|
180 if(!name) {
|
nuclear@19
|
181 sprintf(buf, "mesh%04d", idx);
|
nuclear@19
|
182 name = buf;
|
nuclear@19
|
183 }
|
nuclear@19
|
184
|
nuclear@19
|
185 return std::string(name);
|
nuclear@19
|
186 }
|