gpuray_glsl

diff src/scene_load.cc @ 0:f234630e38ff

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 09 Nov 2014 13:03:36 +0200
parents
children 2ed3da7dc0bc
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/scene_load.cc	Sun Nov 09 13:03:36 2014 +0200
     1.3 @@ -0,0 +1,681 @@
     1.4 +#include <stdio.h>
     1.5 +#include <math.h>
     1.6 +#include <map>
     1.7 +#include "scene.h"
     1.8 +#include "sphere.h"
     1.9 +#include "plane.h"
    1.10 +#include "box.h"
    1.11 +#include "light.h"
    1.12 +#include "camera.h"
    1.13 +#include "texture.h"
    1.14 +
    1.15 +static bool parse_material(char **argv, Material *mtl, std::string *name);
    1.16 +static Object *parse_sphere(char **argv, const std::map<std::string, Material> &materials);
    1.17 +static Object *parse_plane(char **argv, const std::map<std::string, Material> &materials);
    1.18 +static Object *parse_box(char **argv, const std::map<std::string, Material> &materials);
    1.19 +static Light *parse_light(char **argv);
    1.20 +static Camera *parse_camera(char **argv);
    1.21 +static bool parse_env(char **argv, Scene *scn);
    1.22 +static bool parse_xform(char **argv, Scene *scn);
    1.23 +static bool parse_vec(char **argv, Vector3 *vptr);
    1.24 +
    1.25 +static char *strip_space(char *s);
    1.26 +static char **split_args(char *args);
    1.27 +
    1.28 +bool load_scene_file(Scene *scn, const char *fname)
    1.29 +{
    1.30 +	FILE *fp;
    1.31 +	if(!(fp = fopen(fname, "rb"))) {
    1.32 +		fprintf(stderr, "%s: failed to open scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
    1.33 +		return false;
    1.34 +	}
    1.35 +
    1.36 +	char buf[512];
    1.37 +	std::map<std::string, Material> materials;
    1.38 +
    1.39 +	int lineno = 0;
    1.40 +	while(fgets(buf, sizeof buf, fp)) {
    1.41 +		char *line = strip_space(buf);
    1.42 +
    1.43 +		lineno++;
    1.44 +
    1.45 +		if(!*line || *line == '\n' || *line == '#') {
    1.46 +			continue;
    1.47 +		}
    1.48 +
    1.49 +		if(strstr(line, "material") == line) {
    1.50 +			Material mtl;
    1.51 +			std::string name;
    1.52 +
    1.53 +			char *args = strip_space(line + strlen("material"));
    1.54 +			if(!parse_material(split_args(args), &mtl, &name)) {
    1.55 +				goto err;
    1.56 +			}
    1.57 +			materials[name] = mtl;
    1.58 +
    1.59 +		} else if(strstr(line, "sphere") == line) {
    1.60 +			char *args = strip_space(line + strlen("sphere"));
    1.61 +			Object *obj = parse_sphere(split_args(args), materials);
    1.62 +			if(!obj) {
    1.63 +				goto err;
    1.64 +			}
    1.65 +			scn->add_object(obj);
    1.66 +
    1.67 +		} else if(strstr(line, "plane") == line) {
    1.68 +			char *args = strip_space(line + strlen("plane"));
    1.69 +			Object *obj = parse_plane(split_args(args), materials);
    1.70 +			if(!obj) {
    1.71 +				goto err;
    1.72 +			}
    1.73 +			scn->add_object(obj);
    1.74 +
    1.75 +		} else if(strstr(line, "box") == line) {
    1.76 +			char *args = strip_space(line + strlen("box"));
    1.77 +			Object *obj = parse_box(split_args(args), materials);
    1.78 +			if(!obj) {
    1.79 +				goto err;
    1.80 +			}
    1.81 +			scn->add_object(obj);
    1.82 +
    1.83 +		} else if(strstr(line, "light") == line) {
    1.84 +			char *args = strip_space(line + strlen("light"));
    1.85 +			Light *lt = parse_light(split_args(args));
    1.86 +			if(!lt) {
    1.87 +				goto err;
    1.88 +			}
    1.89 +			scn->add_light(lt);
    1.90 +
    1.91 +		} else if(strstr(line, "camera") == line) {
    1.92 +			char *args = strip_space(line + strlen("camera"));
    1.93 +			Camera *cam = parse_camera(split_args(args));
    1.94 +			if(!cam) {
    1.95 +				goto err;
    1.96 +			}
    1.97 +			scn->set_camera(cam);
    1.98 +
    1.99 +		} else if(strstr(line, "environment") == line) {
   1.100 +			char *args = strip_space(line + strlen("environment"));
   1.101 +			if(!parse_env(split_args(args), scn)) {
   1.102 +				goto err;
   1.103 +			}
   1.104 +
   1.105 +		} else if(strstr(line, "xform") == line) {
   1.106 +			char *args = strip_space(line + strlen("xform"));
   1.107 +			if(!parse_xform(split_args(args), scn)) {
   1.108 +				goto err;
   1.109 +			}
   1.110 +
   1.111 +		} else {
   1.112 +			fprintf(stderr, "%s error %s:%d: unknown command: %s\n", __FUNCTION__, fname, lineno, line);
   1.113 +			goto err;
   1.114 +		}
   1.115 +
   1.116 +	}
   1.117 +
   1.118 +	fclose(fp);
   1.119 +	return true;
   1.120 +
   1.121 +err:
   1.122 +	fclose(fp);
   1.123 +	return false;
   1.124 +}
   1.125 +
   1.126 +bool save_scene_file(const Scene *scn, const char *fname)
   1.127 +{
   1.128 +	FILE *fp;
   1.129 +	if(!(fp = fopen(fname, "wb"))) {
   1.130 +		fprintf(stderr, "%s: failed to save scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno));
   1.131 +		return false;
   1.132 +	}
   1.133 +
   1.134 +	for(int i=0; i<scn->get_object_count(); i++) {
   1.135 +		// first write the material
   1.136 +		const Object *obj = scn->get_object(i);
   1.137 +		const Material *mat = &obj->material;
   1.138 +
   1.139 +		char name[128];
   1.140 +		sprintf(name, "mat%d", i);
   1.141 +
   1.142 +		fprintf(fp, "material -name %s", name);
   1.143 +		fprintf(fp, " -diffuse %.3f %.3f %.3f", mat->diffuse.x, mat->diffuse.y, mat->diffuse.z);
   1.144 +		fprintf(fp, " -specular %.3f %.3f %.3f", mat->specular.x, mat->specular.y, mat->specular.z);
   1.145 +		fprintf(fp, " -shininess %.3f", mat->shininess);
   1.146 +		fprintf(fp, " -emission %.3f %.3f %.3f", mat->emission.x, mat->emission.y, mat->emission.z);
   1.147 +		fprintf(fp, " -reflect %.3f", mat->reflectivity);
   1.148 +		fprintf(fp, " -trans %.3f", mat->transparency);
   1.149 +		fprintf(fp, " -ior %.3f", mat->ior);
   1.150 +		if(mat->tex) {
   1.151 +			fprintf(fp, " -texture %s", mat->tex->get_name());
   1.152 +		}
   1.153 +		fputc('\n', fp);
   1.154 +
   1.155 +		// then write the object
   1.156 +		const Sphere *sph;
   1.157 +		const Plane *plane;
   1.158 +		const Box *box;
   1.159 +		if((sph = dynamic_cast<const Sphere*>(obj))) {
   1.160 +			fprintf(fp, "sphere -material %s", name);
   1.161 +			fprintf(fp, " -center %.3f %.3f %.3f", sph->pos.x, sph->pos.y, sph->pos.z);
   1.162 +			fprintf(fp, " -radius %.3f\n", sph->radius);
   1.163 +		} else if((plane = dynamic_cast<const Plane*>(obj))) {
   1.164 +			fprintf(fp, "plane -material %s", name);
   1.165 +			fprintf(fp, " -normal %.3f %.3f %.3f", plane->normal.x, plane->normal.y, plane->normal.z);
   1.166 +			fprintf(fp, " -distance %.3f\n", plane->dist);
   1.167 +		} else if((box = dynamic_cast<const Box*>(obj))) {
   1.168 +			fprintf(fp, "box -material %s", name);
   1.169 +			fprintf(fp, " -min %.3f %.3f %.3f", box->min.x, box->min.y, box->min.z);
   1.170 +			fprintf(fp, " -max %.3f %.3f %.3f\n", box->max.x, box->max.y, box->max.z);
   1.171 +		}
   1.172 +	}
   1.173 +
   1.174 +	for(int i=0; i<scn->get_light_count(); i++) {
   1.175 +		const Light *lt = scn->get_light(i);
   1.176 +
   1.177 +		fprintf(fp, "light -position %.3f %.3f %.3f", lt->pos.x, lt->pos.y, lt->pos.z);
   1.178 +		fprintf(fp, " -color %.3f %.3f %.3f\n", lt->color.x, lt->color.y, lt->color.z);
   1.179 +	}
   1.180 +
   1.181 +	const TargetCamera *tcam = dynamic_cast<const TargetCamera*>(scn->get_camera());
   1.182 +	if(tcam) {
   1.183 +		Vector3 pos = tcam->get_position();
   1.184 +		fprintf(fp, "camera -position %.3f %.3f %.3f", pos.x, pos.y, pos.z);
   1.185 +		Vector3 targ = tcam->get_target();
   1.186 +		fprintf(fp, " -target %.3f %.3f %.3f", targ.x, targ.y, targ.z);
   1.187 +		fprintf(fp, " -fov %.3f\n", tcam->get_fov());
   1.188 +	}
   1.189 +
   1.190 +
   1.191 +	fclose(fp);
   1.192 +	return true;
   1.193 +}
   1.194 +
   1.195 +#define ARGERR(n) \
   1.196 +	do { fprintf(stderr, "failed to parse %s argument\n", (n)); return false; } while(0)
   1.197 +
   1.198 +static bool parse_material(char **argv, Material *mtl, std::string *name)
   1.199 +{
   1.200 +	char *endp;
   1.201 +
   1.202 +	for(int i=0; argv[i]; i++) {
   1.203 +		if(strcmp(argv[i], "-name") == 0) {
   1.204 +			*name = argv[++i];
   1.205 +		} else if(strcmp(argv[i], "-diffuse") == 0) {
   1.206 +			if(!parse_vec(argv + i + 1, &mtl->diffuse)) {
   1.207 +				ARGERR("diffuse");
   1.208 +			}
   1.209 +			argv += 3;
   1.210 +
   1.211 +		} else if(strcmp(argv[i], "-specular") == 0) {
   1.212 +			if(!parse_vec(argv + i + 1, &mtl->specular)) {
   1.213 +				ARGERR("specular");
   1.214 +			}
   1.215 +			argv += 3;
   1.216 +
   1.217 +		} else if(strcmp(argv[i], "-emission") == 0) {
   1.218 +			if(!parse_vec(argv + i + 1, &mtl->emission)) {
   1.219 +				ARGERR("emission");
   1.220 +			}
   1.221 +			argv += 3;
   1.222 +
   1.223 +		} else if(strcmp(argv[i], "-shininess") == 0) {
   1.224 +			mtl->shininess = strtod(argv[++i], &endp);
   1.225 +			if(endp == argv[i]) {
   1.226 +				ARGERR("shininess");
   1.227 +			}
   1.228 +
   1.229 +		} else if(strcmp(argv[i], "-reflect") == 0) {
   1.230 +			mtl->reflectivity = strtod(argv[++i], &endp);
   1.231 +			if(endp == argv[i]) {
   1.232 +				ARGERR("reflect");
   1.233 +			}
   1.234 +
   1.235 +		} else if(strcmp(argv[i], "-trans") == 0) {
   1.236 +			mtl->transparency = strtod(argv[++i], &endp);
   1.237 +			if(endp == argv[i]) {
   1.238 +				ARGERR("trans");
   1.239 +			}
   1.240 +
   1.241 +		} else if(strcmp(argv[i], "-ior") == 0) {
   1.242 +			mtl->ior = strtod(argv[++i], &endp);
   1.243 +			if(endp == argv[i]) {
   1.244 +				ARGERR("ior");
   1.245 +			}
   1.246 +
   1.247 +		} else if(strcmp(argv[i], "-texture") == 0) {
   1.248 +			if(!(mtl->tex = load_texture(argv[++i]))) {
   1.249 +				return false;
   1.250 +			}
   1.251 +
   1.252 +		} else {
   1.253 +			fprintf(stderr, "invalid material option: %s\n", argv[i]);
   1.254 +			return false;
   1.255 +		}
   1.256 +	}
   1.257 +	return true;
   1.258 +}
   1.259 +
   1.260 +static Object *parse_sphere(char **argv, const std::map<std::string, Material> &materials)
   1.261 +{
   1.262 +	char *endp;
   1.263 +	Sphere *sph = new Sphere;
   1.264 +
   1.265 +	for(int i=0; argv[i]; i++) {
   1.266 +		if(strcmp(argv[i], "-name") == 0) {
   1.267 +			sph->set_name(argv[++i]);
   1.268 +
   1.269 +		} else if(strcmp(argv[i], "-center") == 0) {
   1.270 +			if(!parse_vec(argv + i + 1, &sph->pos)) {
   1.271 +				fprintf(stderr, "failed to parse sphere center vector\n");
   1.272 +				return 0;
   1.273 +			}
   1.274 +			argv += 3;
   1.275 +
   1.276 +		} else if(strcmp(argv[i], "-radius") == 0) {
   1.277 +			sph->radius = strtod(argv[++i], &endp);
   1.278 +			if(endp == argv[i]) {
   1.279 +				fprintf(stderr, "failed to parse sphere radius\n");
   1.280 +				return 0;
   1.281 +			}
   1.282 +
   1.283 +		} else if(strcmp(argv[i], "-material") == 0) {
   1.284 +			auto it = materials.find(argv[++i]);
   1.285 +			if(it == materials.end()) {
   1.286 +				fprintf(stderr, "material %s not found\n", argv[i]);
   1.287 +				return 0;
   1.288 +			}
   1.289 +
   1.290 +			sph->material = it->second;
   1.291 +		} else {
   1.292 +			fprintf(stderr, "invalid sphere option: %s\n", argv[i]);
   1.293 +			return 0;
   1.294 +		}
   1.295 +	}
   1.296 +
   1.297 +	return sph;
   1.298 +}
   1.299 +
   1.300 +static Object *parse_plane(char **argv, const std::map<std::string, Material> &materials)
   1.301 +{
   1.302 +	char *endp;
   1.303 +	Plane *plane = new Plane;
   1.304 +
   1.305 +	for(int i=0; argv[i]; i++) {
   1.306 +		if(strcmp(argv[i], "-name") == 0) {
   1.307 +			plane->set_name(argv[++i]);
   1.308 +
   1.309 +		} else if(strcmp(argv[i], "-normal") == 0) {
   1.310 +			if(!parse_vec(argv + i + 1, &plane->normal)) {
   1.311 +				fprintf(stderr, "failed to parse plane normal\n");
   1.312 +				return 0;
   1.313 +			}
   1.314 +			plane->normal.normalize();
   1.315 +			argv += 3;
   1.316 +
   1.317 +		} else if(strcmp(argv[i], "-distance") == 0) {
   1.318 +			plane->dist = strtod(argv[++i], &endp);
   1.319 +			if(endp == argv[i]) {
   1.320 +				fprintf(stderr, "failed to parse plane distance\n");
   1.321 +				return 0;
   1.322 +			}
   1.323 +
   1.324 +		} else if(strcmp(argv[i], "-material") == 0) {
   1.325 +			auto it = materials.find(argv[++i]);
   1.326 +			if(it == materials.end()) {
   1.327 +				fprintf(stderr, "material %s not found\n", argv[i]);
   1.328 +				return 0;
   1.329 +			}
   1.330 +
   1.331 +			plane->material = it->second;
   1.332 +		} else {
   1.333 +			fprintf(stderr, "invalid plane option: %s\n", argv[i]);
   1.334 +			return 0;
   1.335 +		}
   1.336 +	}
   1.337 +
   1.338 +	return plane;
   1.339 +}
   1.340 +
   1.341 +static Object *parse_box(char **argv, const std::map<std::string, Material> &materials)
   1.342 +{
   1.343 +	Box *box = new Box;
   1.344 +
   1.345 +	for(int i=0; argv[i]; i++) {
   1.346 +		if(strcmp(argv[i], "-name") == 0) {
   1.347 +			box->set_name(argv[++i]);
   1.348 +
   1.349 +		} else if(strcmp(argv[i], "-min") == 0) {
   1.350 +			if(!parse_vec(argv + i + 1, &box->min)) {
   1.351 +				fprintf(stderr, "failed to parse box min\n");
   1.352 +				return 0;
   1.353 +			}
   1.354 +			argv += 3;
   1.355 +
   1.356 +		} else if(strcmp(argv[i], "-max") == 0) {
   1.357 +			if(!parse_vec(argv + i + 1, &box->max)) {
   1.358 +				fprintf(stderr, "failed to parse box max\n");
   1.359 +				return 0;
   1.360 +			}
   1.361 +			argv += 3;
   1.362 +
   1.363 +		} else if(strcmp(argv[i], "-material") == 0) {
   1.364 +			auto it = materials.find(argv[++i]);
   1.365 +			if(it == materials.end()) {
   1.366 +				fprintf(stderr, "material %s not found\n", argv[i]);
   1.367 +				return 0;
   1.368 +			}
   1.369 +
   1.370 +			box->material = it->second;
   1.371 +		} else {
   1.372 +			fprintf(stderr, "invalid box option: %s\n", argv[i]);
   1.373 +			return 0;
   1.374 +		}
   1.375 +	}
   1.376 +
   1.377 +	return box;
   1.378 +}
   1.379 +
   1.380 +static Light *parse_light(char **argv)
   1.381 +{
   1.382 +	Light *lt = new Light;
   1.383 +
   1.384 +	for(int i=0; argv[i]; i++) {
   1.385 +		if(strcmp(argv[i], "-position") == 0) {
   1.386 +			if(!parse_vec(argv + i + 1, &lt->pos)) {
   1.387 +				fprintf(stderr, "failed to parse light position\n");
   1.388 +				return 0;
   1.389 +			}
   1.390 +			argv += 3;
   1.391 +
   1.392 +		} else if(strcmp(argv[i], "-color") == 0) {
   1.393 +			if(!parse_vec(argv + i + 1, &lt->color)) {
   1.394 +				fprintf(stderr, "failed to parse light color\n");
   1.395 +				return 0;
   1.396 +			}
   1.397 +			argv += 3;
   1.398 +
   1.399 +		} else {
   1.400 +			fprintf(stderr, "invalid light option: %s\n", argv[i]);
   1.401 +			return 0;
   1.402 +		}
   1.403 +	}
   1.404 +
   1.405 +	return lt;
   1.406 +}
   1.407 +
   1.408 +static Camera *parse_camera(char **argv)
   1.409 +{
   1.410 +	char *endp;
   1.411 +	TargetCamera *cam = new TargetCamera;
   1.412 +
   1.413 +	for(int i=0; argv[i]; i++) {
   1.414 +		if(strcmp(argv[i], "-position") == 0) {
   1.415 +			Vector3 pos;
   1.416 +			if(!parse_vec(argv + i + 1, &pos)) {
   1.417 +				fprintf(stderr, "failed to parse camera position\n");
   1.418 +				return 0;
   1.419 +			}
   1.420 +			argv += 3;
   1.421 +			cam->set_position(pos);
   1.422 +
   1.423 +		} else if(strcmp(argv[i], "-target") == 0) {
   1.424 +			Vector3 targ;
   1.425 +			if(!parse_vec(argv + i + 1, &targ)) {
   1.426 +				fprintf(stderr, "failed to parse camera target\n");
   1.427 +				return 0;
   1.428 +			}
   1.429 +			argv += 3;
   1.430 +			cam->set_target(targ);
   1.431 +
   1.432 +		} else if(strcmp(argv[i], "-fov") == 0) {
   1.433 +			float fov = strtod(argv[++i], &endp);
   1.434 +			if(endp == argv[i]) {
   1.435 +				fprintf(stderr, "failed to parse camera fov\n");
   1.436 +				return 0;
   1.437 +			}
   1.438 +			cam->set_fov(M_PI * fov / 180.0);
   1.439 +
   1.440 +		} else {
   1.441 +			fprintf(stderr, "invalid camera option: %s\n", argv[i]);
   1.442 +			return 0;
   1.443 +		}
   1.444 +	}
   1.445 +
   1.446 +	return cam;
   1.447 +}
   1.448 +
   1.449 +static bool parse_env(char **argv, Scene *scn)
   1.450 +{
   1.451 +	char *endp;
   1.452 +
   1.453 +	TextureCube *env_tex = 0;
   1.454 +	TextureCube *conv_tex = 0;
   1.455 +
   1.456 +	float fog_start = -1;
   1.457 +	float fog_end = -1;
   1.458 +
   1.459 +	for(int i=0; argv[i]; i++) {
   1.460 +		if(strcmp(argv[i], "-color") == 0) {
   1.461 +			Color bgcolor;
   1.462 +			if(!parse_vec(argv + i + 1, &bgcolor)) {
   1.463 +				fprintf(stderr, "failed to parse environment color\n");
   1.464 +				return false;
   1.465 +			}
   1.466 +			i += 3;
   1.467 +			scn->set_background_color(bgcolor);
   1.468 +
   1.469 +		} else if(strcmp(argv[i], "-fog-start") == 0) {
   1.470 +			fog_start = strtod(argv[++i], &endp);
   1.471 +			if(endp == argv[i]) {
   1.472 +				fprintf(stderr, "failed to parse environment fog start\n");
   1.473 +				return false;
   1.474 +			}
   1.475 +
   1.476 +		} else if(strcmp(argv[i], "-fog-end") == 0) {
   1.477 +			fog_end = strtod(argv[++i], &endp);
   1.478 +			if(endp == argv[i]) {
   1.479 +				fprintf(stderr, "failed to parse environment fog end\n");
   1.480 +				return false;
   1.481 +			}
   1.482 +
   1.483 +		} else if(strcmp(argv[i], "-texture") == 0 || strcmp(argv[i], "-texture-conv") == 0) {
   1.484 +			Texture *tex = load_texture(argv[++i]);
   1.485 +			if(!tex || !dynamic_cast<TextureCube*>(tex)) {
   1.486 +				fprintf(stderr, "failed to load environment cubemap: %s\n", argv[i]);
   1.487 +				delete tex;
   1.488 +				return false;
   1.489 +			}
   1.490 +
   1.491 +			if(strstr(argv[i - 1], "-conv")) {
   1.492 +				conv_tex = (TextureCube*)tex;
   1.493 +			} else {
   1.494 +				env_tex = (TextureCube*)tex;
   1.495 +			}
   1.496 +
   1.497 +		} else {
   1.498 +			fprintf(stderr, "invalid environment option: %s\n", argv[i]);
   1.499 +			return false;
   1.500 +		}
   1.501 +	}
   1.502 +
   1.503 +	if(env_tex || conv_tex) {
   1.504 +		scn->set_environment_map(env_tex, conv_tex);
   1.505 +	}
   1.506 +
   1.507 +	if(fog_start > 0.0 && fog_end > 0.0) {
   1.508 +		scn->set_fog(fog_start, fog_end);
   1.509 +	}
   1.510 +
   1.511 +	return true;
   1.512 +}
   1.513 +
   1.514 +static bool parse_xform(char **argv, Scene *scn)
   1.515 +{
   1.516 +	char *endp, *name = 0;
   1.517 +	Vector3 pos, rot_axis, scale;
   1.518 +	float rot_angle = 0;
   1.519 +	long tm = 0;
   1.520 +	Extrap extrap = EXTRAP_REPEAT;
   1.521 +
   1.522 +	bool have_pos = false;
   1.523 +	bool have_rot_axis = false;
   1.524 +	bool have_rot_angle = false;
   1.525 +	bool have_scale = false;
   1.526 +	bool have_extrap = false;
   1.527 +
   1.528 +	for(int i=0; argv[i]; i++) {
   1.529 +		if(strcmp(argv[i], "-name") == 0) {
   1.530 +			name = argv[++i];
   1.531 +
   1.532 +		} else if(strcmp(argv[i], "-pos") == 0) {
   1.533 +			if(!parse_vec(argv + i + 1, &pos)) {
   1.534 +				fprintf(stderr, "failed to parse xform position\n");
   1.535 +				return false;
   1.536 +			}
   1.537 +			have_pos = true;
   1.538 +			i += 3;
   1.539 +
   1.540 +		} else if(strcmp(argv[i], "-rot-axis") == 0) {
   1.541 +			if(!parse_vec(argv + i + 1, &rot_axis)) {
   1.542 +				fprintf(stderr, "failed to parse xform rotation axis\n");
   1.543 +				return false;
   1.544 +			}
   1.545 +			have_rot_axis = true;
   1.546 +			i += 3;
   1.547 +
   1.548 +		} else if(strcmp(argv[i], "-rot-angle") == 0) {
   1.549 +			rot_angle = strtod(argv[++i], &endp);
   1.550 +			if(endp == argv[i]) {
   1.551 +				fprintf(stderr, "failed to parse xform rotation angle\n");
   1.552 +				return false;
   1.553 +			}
   1.554 +			rot_angle = M_PI * rot_angle / 180.0;
   1.555 +			have_rot_angle = true;
   1.556 +
   1.557 +		} else if(strcmp(argv[i], "-scale") == 0) {
   1.558 +			if(!parse_vec(argv + i + 1, &scale)) {
   1.559 +				fprintf(stderr, "failed to parse xform scale\n");
   1.560 +				return false;
   1.561 +			}
   1.562 +			have_scale = true;
   1.563 +			i += 3;
   1.564 +
   1.565 +		} else if(strcmp(argv[i], "-time") == 0) {
   1.566 +			float tm_sec = strtod(argv[++i], &endp);
   1.567 +			if(endp == argv[i]) {
   1.568 +				fprintf(stderr, "failed to parse xform time\n");
   1.569 +				return false;
   1.570 +			}
   1.571 +			tm = (long)(tm_sec * 1000.0f);
   1.572 +
   1.573 +		} else if(strcmp(argv[i], "-extrapolation") == 0) {
   1.574 +			if(strcmp(argv[++i], "extend") == 0) {
   1.575 +				extrap = EXTRAP_EXTEND;
   1.576 +			} else if(strcmp(argv[i], "clamp") == 0) {
   1.577 +				extrap = EXTRAP_CLAMP;
   1.578 +			} else if(strcmp(argv[i], "repeat") == 0) {
   1.579 +				extrap = EXTRAP_REPEAT;
   1.580 +			} else if(strcmp(argv[i], "pingpong") == 0) {
   1.581 +				extrap = EXTRAP_PINGPONG;
   1.582 +			} else {
   1.583 +				fprintf(stderr, "failed to parse xform extrapolation, invalid mode: %s\n", argv[i]);
   1.584 +				return false;
   1.585 +			}
   1.586 +			have_extrap = true;
   1.587 +
   1.588 +		} else {
   1.589 +			fprintf(stderr, "invalid xform option: %s\n", argv[i]);
   1.590 +			return false;
   1.591 +		}
   1.592 +	}
   1.593 +
   1.594 +	if(!name) {
   1.595 +		fprintf(stderr, "invalid xform command, missing -name option\n");
   1.596 +		return false;
   1.597 +	}
   1.598 +	if(have_rot_angle != have_rot_axis) {
   1.599 +		fprintf(stderr, "invalid xform command, must have both -rot-angle and -rot-axis or neither\n");
   1.600 +		return false;
   1.601 +	}
   1.602 +
   1.603 +	Object *obj = 0;
   1.604 +
   1.605 +	int nobj = scn->get_object_count();
   1.606 +	for(int i=0; i<nobj; i++) {
   1.607 +		Object *tmp = scn->get_object(i);
   1.608 +		if(strcmp(tmp->get_name(), name) == 0) {
   1.609 +			obj = tmp;
   1.610 +			break;
   1.611 +		}
   1.612 +	}
   1.613 +
   1.614 +	if(!obj) {
   1.615 +		fprintf(stderr, "invalid xform, refers to nonexistent object: %s\n", name);
   1.616 +		return false;
   1.617 +	}
   1.618 +
   1.619 +	if(have_pos) {
   1.620 +		obj->set_position(pos, tm);
   1.621 +	}
   1.622 +	if(have_rot_angle) {
   1.623 +		obj->set_rotation(Quaternion(rot_axis, rot_angle), tm);
   1.624 +	}
   1.625 +	if(have_scale) {
   1.626 +		obj->set_scaling(scale, tm);
   1.627 +	}
   1.628 +
   1.629 +	if(have_extrap) {
   1.630 +		obj->set_extrapolator(extrap);
   1.631 +	}
   1.632 +	return true;
   1.633 +}
   1.634 +
   1.635 +static bool parse_vec(char **argv, Vector3 *vptr)
   1.636 +{
   1.637 +	char *endp;
   1.638 +
   1.639 +	vptr->x = strtod(argv[0], &endp);
   1.640 +	if(endp == argv[0])
   1.641 +		return false;
   1.642 +	vptr->y = strtod(argv[1], &endp);
   1.643 +	if(endp == argv[1])
   1.644 +		return false;
   1.645 +	vptr->z = strtod(argv[2], &endp);
   1.646 +	if(endp == argv[2])
   1.647 +		return false;
   1.648 +
   1.649 +	return true;
   1.650 +}
   1.651 +
   1.652 +
   1.653 +static char *strip_space(char *s)
   1.654 +{
   1.655 +	while(*s && isspace(*s)) s++;
   1.656 +
   1.657 +	if(!*s)
   1.658 +		return s;
   1.659 +
   1.660 +	char *endp = s + strlen(s) - 1;
   1.661 +	while(isspace(*endp)) endp--;
   1.662 +	endp[1] = 0;
   1.663 +
   1.664 +	if((endp = strrchr(s, '#'))) {
   1.665 +		*endp = 0;
   1.666 +	}
   1.667 +
   1.668 +	return s;
   1.669 +}
   1.670 +
   1.671 +static char **split_args(char *args)
   1.672 +{
   1.673 +	static std::vector<char*> argv;
   1.674 +	char *tok = 0;
   1.675 +
   1.676 +	argv.clear();
   1.677 +
   1.678 +	while((tok = strtok(tok ? 0 : args, " \t\v\n\r"))) {
   1.679 +		argv.push_back(tok);
   1.680 +	}
   1.681 +	argv.push_back(0);
   1.682 +
   1.683 +	return &argv[0];
   1.684 +}