1 /****************************************************************************
2  * 			xmlparser.cc: a libXML based parser for YafRay scenes
3  *      This is part of the yafray package
4  *      Copyright (C) 2006  Mathias Wein
5  *
6  *      This library is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU Lesser General Public
8  *      License as published by the Free Software Foundation; either
9  *      version 2.1 of the License, or (at your option) any later version.
10  *
11  *      This library is distributed in the hope that it will be useful,
12  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *      Lesser General Public License for more details.
15  *
16  *      You should have received a copy of the GNU Lesser General Public
17  *      License along with this library; if not, write to the Free Software
18  *      Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */
20 
21 #include <yafraycore/xmlparser.h>
22 #include <core_api/logging.h>
23 #include <core_api/environment.h>
24 #include <core_api/scene.h>
25 #include <utilities/math_utils.h>
26 #include <iomanip>
27 
28 #if HAVE_XML
29 #include <libxml/parser.h>
30 #endif
31 #include <cstring>
32 
33 
34 __BEGIN_YAFRAY
35 
36 #if HAVE_XML
37 
setLastElementName(const char * element_name)38 void xmlParser_t::setLastElementName(const char *element_name)
39 {
40 	if(element_name) current->last_element = std::string(element_name);
41 	else current->last_element.clear();
42 }
43 
setLastElementNameAttrs(const char ** element_attrs)44 void xmlParser_t::setLastElementNameAttrs(const char **element_attrs)
45 {
46 	current->last_element_attrs.clear();
47 	if(element_attrs)
48 	{
49 		for(int n=0; element_attrs[n]; ++n)
50 		{
51 			if(n > 0) current->last_element_attrs += " ";
52 			current->last_element_attrs += (std::string(element_attrs[n]));
53 		}
54 	}
55 }
56 
startDocument(void * user_data)57 void startDocument(void *user_data)
58 {
59 	//Empty
60 }
61 
endDocument(void * user_data)62 void endDocument(void *user_data)
63 {
64 	//Empty
65 }
66 
startElement(void * user_data,const xmlChar * name,const xmlChar ** attrs)67 void startElement(void * user_data, const xmlChar * name, const xmlChar **attrs)
68 {
69 	xmlParser_t &parser = *((xmlParser_t *)user_data);
70 	parser.startElement((const char *)name, (const char **)attrs);
71 }
72 
endElement(void * user_data,const xmlChar * name)73 void endElement(void *user_data, const xmlChar *name)
74 {
75 	xmlParser_t &parser = *((xmlParser_t *)user_data);
76 	parser.endElement((const char *)name);
77 }
78 
my_warning(void * user_data,const char * msg,...)79 static void my_warning(void *user_data, const char *msg, ...)
80 {
81 	xmlParser_t &parser = *((xmlParser_t *)user_data);
82     va_list args;
83     va_start(args, msg);
84     const size_t message_size = 1000;
85     char message_buffer[message_size];
86     vsnprintf(message_buffer, message_size, msg, args);
87     Y_WARNING << "XMLParser warning: " << message_buffer;
88     Y_WARNING << " in section '" << parser.getLastSection() << ", level " << parser.currLevel() << yendl;
89     Y_WARNING << " an element previous to the error: '" << parser.getLastElementName() << "', attrs: { " << parser.getLastElementNameAttrs() << " }" << yendl;
90     va_end(args);
91 }
92 
my_error(void * user_data,const char * msg,...)93 static void my_error(void *user_data, const char *msg, ...)
94 {
95 	xmlParser_t &parser = *((xmlParser_t *)user_data);
96     va_list args;
97     va_start(args, msg);
98     const size_t message_size = 1000;
99     char message_buffer[message_size];
100     vsnprintf(message_buffer, message_size, msg, args);
101     Y_ERROR << "XMLParser error: " << message_buffer;
102     Y_ERROR << " in section '" << parser.getLastSection() << ", level " << parser.currLevel() << yendl;
103     Y_ERROR << " an element previous to the error: '" << parser.getLastElementName() << "', attrs: { " << parser.getLastElementNameAttrs() << " }" << yendl;
104     va_end(args);
105 }
106 
my_fatalError(void * user_data,const char * msg,...)107 static void my_fatalError(void *user_data, const char *msg, ...)
108 {
109 	xmlParser_t &parser = *((xmlParser_t *)user_data);
110     va_list args;
111     va_start(args, msg);
112     const size_t message_size = 1000;
113     char message_buffer[message_size];
114     vsnprintf(message_buffer, message_size, msg, args);
115     Y_ERROR << "XMLParser fatal error: " << message_buffer;
116     Y_ERROR << " in section '" << parser.getLastSection() << ", level " << parser.currLevel() << yendl;
117     Y_ERROR << " an element previous to the error: '" << parser.getLastElementName() << "', attrs: { " << parser.getLastElementNameAttrs() << " }" << yendl;
118     va_end(args);
119 }
120 
121 static xmlSAXHandler my_handler =
122 {
123 	nullptr,
124   nullptr,
125   nullptr,
126   nullptr,
127   nullptr,
128   nullptr,
129   nullptr,
130   nullptr,
131   nullptr,
132   nullptr,
133   nullptr,
134   nullptr,
135   startDocument, //  startDocumentSAXFunc startDocument;
136   endDocument, //  endDocumentSAXFunc endDocument;
137   startElement, //  startElementSAXFunc startElement;
138   endElement, //  endElementSAXFunc endElement;
139   nullptr,
140   nullptr, //  charactersSAXFunc characters;
141   nullptr,
142   nullptr,
143   nullptr,
144   my_warning,
145   my_error,
146   my_fatalError
147 };
148 #endif // HAVE_XML
149 
parse_xml_file(const char * filename,scene_t * scene,renderEnvironment_t * env,paraMap_t & render,std::string color_space_string,float input_gamma)150 bool parse_xml_file(const char *filename, scene_t *scene, renderEnvironment_t *env, paraMap_t &render, std::string color_space_string, float input_gamma)
151 {
152 #if HAVE_XML
153 
154 	colorSpaces_t input_color_space = RAW_MANUAL_GAMMA;
155 
156 	if(color_space_string == "sRGB") input_color_space = SRGB;
157 	else if(color_space_string == "XYZ") input_color_space = XYZ_D65;
158 	else if(color_space_string == "LinearRGB") input_color_space = LINEAR_RGB;
159 	//else if(color_space_string == "Raw_Manual_Gamma") input_color_space = RAW_MANUAL_GAMMA; //not available for now
160 	else input_color_space = SRGB;
161 
162 	xmlParser_t parser(env, scene, render, input_color_space, input_gamma);
163 
164 	if (xmlSAXUserParseFile(&my_handler, &parser, filename) < 0)
165 	{
166 		Y_ERROR << "XMLParser: Parsing the file " << filename << yendl;
167 		return false;
168 	}
169 	return true;
170 #else
171 	Y_WARNING << "XMLParser: yafray was compiled without XML support, cannot parse file." << yendl;
172 	return false;
173 #endif
174 }
175 
176 #if HAVE_XML
177 /*=============================================================
178 / parser functions
179 =============================================================*/
180 
xmlParser_t(renderEnvironment_t * renv,scene_t * sc,paraMap_t & r,colorSpaces_t input_color_space,float input_gamma)181 xmlParser_t::xmlParser_t(renderEnvironment_t *renv, scene_t *sc, paraMap_t &r, colorSpaces_t input_color_space, float input_gamma):
182 	env(renv), scene(sc), render(r), current(0), level(0), inputGamma(input_gamma), inputColorSpace(input_color_space)
183 {
184 	cparams = &params;
185 	pushState(startEl_document, endEl_document);
186 }
187 
pushState(startElement_cb start,endElement_cb end,void * userdata)188 void xmlParser_t::pushState(startElement_cb start, endElement_cb end, void *userdata)
189 {
190 	parserState_t state;
191 	state.start = start;
192 	state.end = end;
193 	state.userdata = userdata;
194 	state.level = level;
195 	state_stack.push_back(state);
196 	current = &state_stack.back();
197 }
198 
popState()199 void xmlParser_t::popState()
200 {
201 	state_stack.pop_back();
202 	if(!state_stack.empty()) current = &state_stack.back();
203 	else current = nullptr;
204 }
205 
206 /*=============================================================
207 / utility functions...
208 =============================================================*/
209 
str2bool(const char * s)210 inline bool str2bool(const char *s){ return strcmp(s, "true") ? false : true; }
211 
parsePoint(const char ** attrs,point3d_t & p,point3d_t & op)212 static bool parsePoint(const char **attrs, point3d_t &p, point3d_t &op)
213 {
214 	for( ;attrs && attrs[0]; attrs += 2)
215 	{
216 		if(attrs[0][0] == 'o')
217 		{
218 			if(attrs[0][1] == 0 || attrs[0][2] != 0)
219 			{
220 				Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in orco point (1)" << yendl;
221 				continue; //it is not a single character
222 			}
223 			switch(attrs[0][1])
224 			{
225 				case 'x' : op.x = atof(attrs[1]); break;
226 				case 'y' : op.y = atof(attrs[1]); break;
227 				case 'z' : op.z = atof(attrs[1]); break;
228 				default: Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in orco point (2)" << yendl;
229 			}
230 			continue;
231 		}
232 		else if(attrs[0][1] != 0)
233 		{
234 			Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in point" << yendl;
235 			continue; //it is not a single character
236 		}
237 		switch(attrs[0][0])
238 		{
239 			case 'x' : p.x = atof(attrs[1]); break;
240 			case 'y' : p.y = atof(attrs[1]); break;
241 			case 'z' : p.z = atof(attrs[1]); break;
242 			default: Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in point" << yendl;
243 		}
244 	}
245 
246 	return true;
247 }
248 
parseNormal(const char ** attrs,normal_t & n)249 static bool parseNormal(const char **attrs, normal_t &n)
250 {
251 	int compoRead = 0;
252 	for( ;attrs && attrs[0]; attrs += 2)
253 	{
254 		if(attrs[0][1] != 0)
255 		{
256 			Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in normal" << yendl;
257 			continue; //it is not a single character
258 		}
259 		switch(attrs[0][0])
260 		{
261 			case 'x' : n.x = atof(attrs[1]); compoRead++; break;
262 			case 'y' : n.y = atof(attrs[1]); compoRead++; break;
263 			case 'z' : n.z = atof(attrs[1]); compoRead++; break;
264 			default: Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in normal." << yendl;
265 		}
266 	}
267 
268 	return (compoRead == 3);
269 }
270 
parseParam(const char ** attrs,parameter_t & param,xmlParser_t & parser)271 void parseParam(const char **attrs, parameter_t &param, xmlParser_t &parser)
272 {
273 	if(!attrs[0]) return;
274 	if(!attrs[2]) // only one attribute => bool, integer or float value
275 	{
276 		std::string name(attrs[0]);
277 		if(name == "ival"){ int i = atoi(attrs[1]); param = parameter_t(i); return; }
278 		else if(name == "fval"){ double f = atof(attrs[1]); param = parameter_t(f); return; }
279 		else if(name == "bval"){ bool b = str2bool(attrs[1]); param = parameter_t(b); return; }
280 		else if(name == "sval"){ param = parameter_t(std::string(attrs[1])); return; }
281 	}
282 	colorA_t c(0.f); point3d_t p(0,0,0);
283 	int type=TYPE_NONE;
284 	for(int n=0; attrs[n]; ++n)
285 	{
286 		if(attrs[n][1] != '\0') continue;
287 		switch(attrs[n][0])
288 		{
289 			case 'x': p.x = atof(attrs[n+1]); type = TYPE_POINT; break;
290 			case 'y': p.y = atof(attrs[n+1]); type = TYPE_POINT; break;
291 			case 'z': p.z = atof(attrs[n+1]); type = TYPE_POINT; break;
292 
293 			case 'r': c.R = (float)atof(attrs[n+1]); type = TYPE_COLOR; break;
294 			case 'g': c.G = (float)atof(attrs[n+1]); type = TYPE_COLOR; break;
295 			case 'b': c.B = (float)atof(attrs[n+1]); type = TYPE_COLOR; break;
296 			case 'a': c.A = (float)atof(attrs[n+1]); type = TYPE_COLOR; break;
297 		}
298 	}
299 
300 	switch(type)
301 	{
302 		case TYPE_POINT: param = parameter_t(p); break;
303 		case TYPE_COLOR:
304 			c.linearRGB_from_ColorSpace(parser.getInputColorSpace(), parser.getInputGamma());
305 			param = parameter_t(c);
306 			break;
307 	}
308 }
309 
310 /*=============================================================
311 / start- and endElement callbacks for the different states
312 =============================================================*/
313 
endEl_dummy(xmlParser_t & parser,const char * element)314 void endEl_dummy(xmlParser_t &parser, const char *element)
315 {	parser.popState();	}
316 
startEl_dummy(xmlParser_t & parser,const char * element,const char ** attrs)317 void startEl_dummy(xmlParser_t &parser, const char *element, const char **attrs)
318 {	parser.pushState(startEl_dummy, endEl_dummy);	}
319 
startEl_document(xmlParser_t & parser,const char * element,const char ** attrs)320 void startEl_document(xmlParser_t &parser, const char *element, const char **attrs)
321 {
322 	parser.setLastSection("Document");
323 	parser.setLastElementName(element);
324 	parser.setLastElementNameAttrs(attrs);
325 
326 	if( strcmp(element, "scene") ) Y_WARNING << "XMLParser: skipping <" << element << ">" << yendl; /* parser.error("Expected scene definition"); */
327 	else
328 	{
329 		for( ;attrs && attrs[0]; attrs += 2)
330 		{
331 			if(!strcmp(attrs[0], "type") )
332 			{
333 				std::string val(attrs[1]);
334 				if		(val == "triangle")  parser.scene->setMode(0);
335 				else if	(val == "universal") parser.scene->setMode(1);
336 			}
337 		}
338 		parser.pushState(startEl_scene, endEl_scene);
339 	}
340 }
341 
endEl_document(xmlParser_t & parser,const char * element)342 void endEl_document(xmlParser_t &parser, const char *element)
343 {
344 	Y_VERBOSE << "XMLParser: Finished document" << yendl;
345 }
346 
347 struct mesh_dat_t
348 {
mesh_dat_tmesh_dat_t349 	mesh_dat_t(): has_orco(false), has_uv(false), smooth(false), smooth_angle(0), ID(0), mat(0) {};
350 	bool has_orco, has_uv;
351 	bool smooth;
352 	float smooth_angle;
353 	objID_t ID;
354 	const material_t *mat;
355 };
356 
357 struct curve_dat_t
358 {
curve_dat_tcurve_dat_t359     curve_dat_t(): ID(0), mat(nullptr), strandStart(0), strandEnd(0), strandShape(0) {};
360     objID_t ID;
361     const material_t *mat;
362     float strandStart, strandEnd, strandShape;
363 };
364 
365 // scene-state, i.e. expect only primary elements
366 // such as light, material, texture, object, integrator, render...
367 
startEl_scene(xmlParser_t & parser,const char * element,const char ** attrs)368 void startEl_scene(xmlParser_t &parser, const char *element, const char **attrs)
369 {
370 	parser.setLastSection("Scene");
371 	parser.setLastElementName(element);
372 	parser.setLastElementNameAttrs(attrs);
373 
374 	std::string el(element), *name=0;
375 	if( el == "material" || el == "integrator" || el == "light" || el == "texture" ||
376 		el == "camera" || el == "background" || el == "object" || el == "volumeregion" || el == "render_passes" || el == "logging_badge")
377 	{
378 		if(!attrs[0])
379 		{
380 			Y_ERROR << "XMLParser: No attributes for scene element given!" << yendl;
381 			return;
382 		}
383 		else if(!strcmp(attrs[0], "name")) name = new std::string(attrs[1]);
384 		else
385 		{
386 			Y_ERROR << "XMLParser: Attribute for scene element does not match 'name'!" << yendl;
387 			return;
388 		}
389 		parser.pushState(startEl_parammap, endEl_parammap, name);
390 	}
391 	else if(el == "mesh")
392 	{
393 		mesh_dat_t *md = new mesh_dat_t();
394 		int vertices=0, triangles=0, type=0, id=-1, obj_pass_index=0;
395 		for(int n=0; attrs[n]; ++n)
396 		{
397 			std::string name(attrs[n]);
398 			if(name == "has_orco") md->has_orco = str2bool(attrs[n+1]);
399 			else if(name == "has_uv") md->has_uv = str2bool(attrs[n+1]);
400 			else if(name == "vertices") vertices = atoi(attrs[n+1]);
401 			else if(name == "faces") triangles = atoi(attrs[n+1]);
402 			else if(name == "type")	type = atoi(attrs[n+1]);
403 			else if(name == "id" ) id = atoi(attrs[n+1]);
404 			else if(name == "obj_pass_index" ) obj_pass_index = atoi(attrs[n+1]);
405 		}
406 		parser.pushState(startEl_mesh, endEl_mesh, md);
407 		if(!parser.scene->startGeometry()) Y_ERROR << "XMLParser: Invalid scene state on startGeometry()!" << yendl;
408 
409 		// Get a new object ID if we did not get one
410 		if(id == -1) md->ID = parser.scene->getNextFreeID();
411 		else md->ID = id;
412 
413 		if(!parser.scene->startTriMesh(md->ID, vertices, triangles, md->has_orco, md->has_uv, type, obj_pass_index))
414 		{
415 			Y_ERROR << "XMLParser: Invalid scene state on startTriMesh()!" << yendl;
416 		}
417 	}
418 	else if(el == "smooth")
419 	{
420 		unsigned int ID=0;
421 		float angle=181;
422 		for(int n=0; attrs[n]; ++n)
423 		{
424 			std::string name(attrs[n]);
425 			if(name == "ID") ID = atoi(attrs[n+1]);
426 			else if(name == "angle") angle = atof(attrs[n+1]);
427 		}
428 		//not optimal to take ID blind...
429 		parser.scene->startGeometry();
430 		bool success = parser.scene->smoothMesh(ID, angle);
431 		if(!success) Y_ERROR << "XMLParser: Couldn't smooth mesh ID = " << ID << ", angle = " << angle << yendl;
432 		parser.scene->endGeometry();
433 		parser.pushState(startEl_dummy, endEl_dummy);
434 	}
435 	else if(el == "render")
436 	{
437 		parser.cparams = &parser.render;
438 		parser.pushState(startEl_parammap, endEl_render);
439 	}
440     else if(el == "instance")
441 	{
442 		objID_t * base_object_id = new objID_t();
443         *base_object_id = -1;
444 		for(int n=0; attrs[n]; n++)
445 		{
446 			std::string name(attrs[n]);
447 			if(name == "base_object_id") *base_object_id = atoi(attrs[n+1]);
448 		}
449 		parser.pushState(startEl_instance,endEl_instance, base_object_id);
450 	}
451 	else if(el == "curve")
452     {
453         curve_dat_t *cvd = new curve_dat_t();
454         int vertex = 0, idc = -1;
455         // attribute's loop
456         for(int n=0; attrs[n]; ++n)
457         {
458             std::string name(attrs[n]);
459             if(name == "vertices") vertex = atoi(attrs[n+1]);
460             else if(name == "id" ) idc = atoi(attrs[n+1]);
461         }
462         parser.pushState(startEl_curve, endEl_curve, cvd);
463         if(!parser.scene->startGeometry()) Y_ERROR << "XMLParser: Invalid scene state on startGeometry()!" << yendl;
464 
465         // Get a new object ID if we did not get one
466         if(idc == -1) cvd->ID = parser.scene->getNextFreeID();
467         else cvd->ID = idc;
468 
469         if(!parser.scene->startCurveMesh(cvd->ID, vertex))
470         {
471             Y_ERROR << "XMLParser: Invalid scene state on startCurveMesh()!" << yendl;
472         }
473     }
474 	else Y_WARNING << "XMLParser: Skipping unrecognized scene element" << yendl;
475 }
476 
endEl_scene(xmlParser_t & parser,const char * element)477 void endEl_scene(xmlParser_t &parser, const char *element)
478 {
479 	if(strcmp(element, "scene")) Y_WARNING << "XMLParser: : expected </scene> tag!" << yendl;
480 	else
481 	{
482 		parser.popState();
483 	}
484 }
startEl_curve(xmlParser_t & parser,const char * element,const char ** attrs)485 void startEl_curve(xmlParser_t &parser, const char *element, const char **attrs)
486 {
487 	parser.setLastSection("Curve");
488 	parser.setLastElementName(element);
489 	parser.setLastElementNameAttrs(attrs);
490 
491     std::string el(element);
492     curve_dat_t *dat = (curve_dat_t *)parser.stateData();
493 
494     if(el == "p")
495     {
496         point3d_t p, op;
497         if(!parsePoint(attrs, p, op)) return;
498         parser.scene->addVertex(p);
499     }
500     else if(el == "strand_start")
501     {
502         dat->strandStart = atof(attrs[1]);
503     }
504     else if(el == "strand_end")
505     {
506         dat->strandEnd = atof(attrs[1]);
507     }
508     else if(el == "strand_shape")
509     {
510         dat->strandShape = atof(attrs[1]);
511 
512     }
513     else if(el == "set_material")
514     {
515         std::string mat_name(attrs[1]);
516         dat->mat = parser.env->getMaterial(mat_name);
517         if(!dat->mat) Y_WARNING << "XMLParser: Unknown material!" << yendl;
518     }
519 }
endEl_curve(xmlParser_t & parser,const char * element)520 void endEl_curve(xmlParser_t &parser, const char *element)
521 {
522     if(std::string(element) == "curve")
523     {
524         curve_dat_t *cd = (curve_dat_t *)parser.stateData();
525         if(!parser.scene->endCurveMesh(cd->mat, cd->strandStart, cd->strandEnd, cd->strandShape))
526         {
527             Y_WARNING << "XMLParser: Invalid scene state on endCurveMesh()!" << yendl;
528         }
529         if(!parser.scene->endGeometry())
530         {
531             Y_WARNING << "XMLParser: Invalid scene state on endGeometry()!" << yendl;
532         }
533         delete cd;
534         parser.popState();
535     }
536 }
537 
538 // mesh-state, i.e. expect only points (vertices), faces and material settings
539 // since we're supposed to be inside a mesh block, exit state on "mesh" element
startEl_mesh(xmlParser_t & parser,const char * element,const char ** attrs)540 void startEl_mesh(xmlParser_t &parser, const char *element, const char **attrs)
541 {
542 	parser.setLastSection("Mesh");
543 	parser.setLastElementName(element);
544 	parser.setLastElementNameAttrs(attrs);
545 
546 	std::string el(element);
547 	mesh_dat_t *dat = (mesh_dat_t *)parser.stateData();
548 	if(el == "p")
549 	{
550 		point3d_t p, op;
551 		if(!parsePoint(attrs, p, op)) return;
552 		if(dat->has_orco)	parser.scene->addVertex(p, op);
553 		else 				parser.scene->addVertex(p);
554 	}
555 	else if(el == "n")
556 	{
557 		normal_t n(0.0, 0.0, 0.0);
558 		if(!parseNormal(attrs, n)) return;
559 		parser.scene->addNormal(n);
560 	}
561 	else if(el == "f")
562 	{
563 		int a=0, b=0, c=0, uv_a=0, uv_b=0, uv_c=0;
564 		for( ;attrs && attrs[0]; attrs += 2)
565 		{
566 			if(attrs[0][1]==0) switch(attrs[0][0])
567 			{
568 				case 'a' : a = atoi(attrs[1]); break;
569 				case 'b' : b = atoi(attrs[1]); break;
570 				case 'c' : c = atoi(attrs[1]); break;
571 				default: Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in face" << yendl;
572 			}
573 			else
574 			{
575 				if(!strcmp(attrs[0], "uv_a")) 	   uv_a = atoi(attrs[1]);
576 				else if(!strcmp(attrs[0], "uv_b")) uv_b = atoi(attrs[1]);
577 				else if(!strcmp(attrs[0], "uv_c")) uv_c = atoi(attrs[1]);
578 			}
579 		}
580 		if(dat->has_uv) parser.scene->addTriangle(a, b, c, uv_a, uv_b, uv_c, dat->mat);
581 		else 			parser.scene->addTriangle(a, b, c, dat->mat);
582 	}
583 	else if(el == "uv")
584 	{
585 		float u=0, v=0;
586 		for( ;attrs && attrs[0]; attrs += 2)
587 		{
588 			switch(attrs[0][0])
589 			{
590 				case 'u': u = atof(attrs[1]);
591 					if(!(isValidFloat(u)))
592 					{
593 						Y_WARNING << std::scientific << std::setprecision(6) << "XMLParser: invalid value in \"" << el << "\" xml entry: " << attrs[0]<<"="<<attrs[1]<<". Replacing with 0.0." << yendl;
594 						u = 0.f;
595 					}
596 					break;
597 				case 'v': v = atof(attrs[1]);
598 					if(!(isValidFloat(v)))
599 					{
600 						Y_WARNING << std::scientific << std::setprecision(6) << "XMLParser: invalid value in \"" << el << "\" xml entry: " << attrs[0]<<"="<<attrs[1]<<". Replacing with 0.0." << yendl;
601 						v = 0.f;
602 					}
603 					break;
604 
605 				default: Y_WARNING << "XMLParser: Ignored wrong attribute " << attrs[0] << " in uv" << yendl;
606 			}
607 		}
608 		parser.scene->addUV(u, v);
609 	}
610 	else if(el == "set_material")
611 	{
612 		std::string mat_name(attrs[1]);
613 		dat->mat = parser.env->getMaterial(mat_name);
614 		if(!dat->mat) Y_WARNING << "XMLParser: Unknown material!" << yendl;
615 	}
616 }
617 
endEl_mesh(xmlParser_t & parser,const char * element)618 void endEl_mesh(xmlParser_t &parser, const char *element)
619 {
620 	if(std::string(element) == "mesh")
621 	{
622 		mesh_dat_t *md = (mesh_dat_t *)parser.stateData();
623 		if(!parser.scene->endTriMesh()) Y_ERROR << "XMLParser: Invalid scene state on endTriMesh()!" << yendl;
624 		if(!parser.scene->endGeometry()) Y_ERROR << "XMLParser: Invalid scene state on endGeometry()!" << yendl;
625 		delete md;
626 		parser.popState();
627 	}
628 }
629 
startEl_instance(xmlParser_t & parser,const char * element,const char ** attrs)630 void startEl_instance(xmlParser_t &parser, const char *element, const char **attrs)
631 {
632 	parser.setLastSection("Instance");
633 	parser.setLastElementName(element);
634 	parser.setLastElementNameAttrs(attrs);
635 
636 	std::string el(element);
637 	objID_t boi = *(objID_t *)parser.stateData();
638 	if(el == "transform")
639 	{
640 		float m[4][4];
641 		for(int n=0; attrs[n]; ++n)
642 		{
643 			std::string name(attrs[n]);
644 			if(name ==  "m00") m[0][0] = atof(attrs[n+1]);
645 			else if(name ==  "m01") m[0][1] = atof(attrs[n+1]);
646 			else if(name ==  "m02") m[0][2] = atof(attrs[n+1]);
647 			else if(name ==  "m03") m[0][3] = atof(attrs[n+1]);
648 			else if(name ==  "m10") m[1][0] = atof(attrs[n+1]);
649 			else if(name ==  "m11") m[1][1] = atof(attrs[n+1]);
650 			else if(name ==  "m12") m[1][2] = atof(attrs[n+1]);
651 			else if(name ==  "m13") m[1][3] = atof(attrs[n+1]);
652 			else if(name ==  "m20") m[2][0] = atof(attrs[n+1]);
653 			else if(name ==  "m21") m[2][1] = atof(attrs[n+1]);
654 			else if(name ==  "m22") m[2][2] = atof(attrs[n+1]);
655 			else if(name ==  "m23") m[2][3] = atof(attrs[n+1]);
656 			else if(name ==  "m30") m[3][0] = atof(attrs[n+1]);
657 			else if(name ==  "m31") m[3][1] = atof(attrs[n+1]);
658 			else if(name ==  "m32") m[3][2] = atof(attrs[n+1]);
659 			else if(name ==  "m33") m[3][3] = atof(attrs[n+1]);
660 		}
661 		matrix4x4_t *m4 = new matrix4x4_t(m);
662 		parser.scene->addInstance(boi,*m4);
663 	}
664 }
665 
endEl_instance(xmlParser_t & parser,const char * element)666 void endEl_instance(xmlParser_t &parser, const char *element)
667 {
668 	if(std::string(element) == "instance" )
669 	{
670 		parser.popState();
671 	}
672 }
673 // read a parameter map; take any tag as parameter name
674 // again, exit when end-element is on of the elements that caused to enter state
675 // depending on exit element, create appropriate scene element
676 
startEl_parammap(xmlParser_t & parser,const char * element,const char ** attrs)677 void startEl_parammap(xmlParser_t &parser, const char *element, const char **attrs)
678 {
679 	parser.setLastSection("Params map");
680 	parser.setLastElementName(element);
681 	parser.setLastElementNameAttrs(attrs);
682 	// support for lists of paramMaps
683 	if(std::string(element) == "list_element")
684 	{
685 		parser.eparams.push_back(paraMap_t());
686 		parser.cparams = &parser.eparams.back();
687 		parser.pushState(startEl_paramlist, endEl_paramlist);
688 		return;
689 	}
690 	parameter_t p;
691 	parseParam(attrs, p, parser);
692 	parser.setParam(std::string(element), p);
693 }
694 
endEl_parammap(xmlParser_t & p,const char * element)695 void endEl_parammap(xmlParser_t &p, const char *element)
696 {
697 	bool exit_state= (p.currLevel() == p.stateLevel());
698 	if(exit_state)
699 	{
700 		std::string el(element);
701 		std::string *name = (std::string *)p.stateData();
702 		if(!name) Y_ERROR << "XMLParser: No name for scene element available!" << yendl;
703 		else
704 		{
705 			if(el == "material")
706 			{ p.env->createMaterial(*name, p.params, p.eparams); }
707 			else if(el == "integrator")
708 			{ p.env->createIntegrator(*name, p.params); }
709 			else if(el == "light")
710 			{
711 				light_t *light = p.env->createLight(*name, p.params);
712 				if(light) p.scene->addLight(light);
713 			}
714 			else if(el == "texture")
715 			{ p.env->createTexture(*name, p.params); }
716 			else if(el == "camera")
717 			{ p.env->createCamera(*name, p.params); }
718 			else if(el == "background")
719 			{ p.env->createBackground(*name, p.params); }
720 			else if(el == "object")
721 			{
722 				objID_t id;
723 				object3d_t *obj = p.env->createObject(*name, p.params);
724 				if(obj) p.scene->addObject(obj, id);
725 			}
726 			else if(el == "volumeregion")
727 			{
728 				VolumeRegion* vr = p.env->createVolumeRegion(*name, p.params);
729 				if (vr) p.scene->addVolumeRegion(vr);
730 			}
731 			else if(el == "render_passes")
732 			{
733 				p.env->setupRenderPasses(p.params);
734 			}
735 			else if(el == "logging_badge")
736 			{
737 				p.env->setupLoggingAndBadge(p.params);
738 			}
739 			else Y_WARNING << "XMLParser: Unexpected end-tag of scene element!" << yendl;
740 		}
741 
742 		if(name) delete name;
743 		p.popState(); p.params.clear(); p.eparams.clear();
744 	}
745 }
746 
startEl_paramlist(xmlParser_t & parser,const char * element,const char ** attrs)747 void startEl_paramlist(xmlParser_t &parser, const char *element, const char **attrs)
748 {
749 	parser.setLastSection("Params list");
750 	parser.setLastElementName(element);
751 	parser.setLastElementNameAttrs(attrs);
752 	parameter_t p;
753 	parseParam(attrs, p, parser);
754 	parser.setParam(std::string(element), p);
755 }
756 
endEl_paramlist(xmlParser_t & parser,const char * element)757 void endEl_paramlist(xmlParser_t &parser, const char *element)
758 {
759 	if(std::string(element) == "list_element")
760 	{
761 		parser.popState();
762 		parser.cparams = &parser.params;
763 	}
764 }
765 
endEl_render(xmlParser_t & parser,const char * element)766 void endEl_render(xmlParser_t &parser, const char *element)
767 {
768 	parser.setLastSection("render");
769 	parser.setLastElementName(element);
770 	parser.setLastElementNameAttrs(nullptr);
771 
772 	if(!strcmp(element, "render"))
773 	{
774 		parser.cparams = &parser.params;
775 		parser.popState();
776 	}
777 }
778 
779 #endif // HAVE_XML
780 
781 __END_YAFRAY
782