nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "scene.h" nuclear@0: #include "sphere.h" nuclear@0: #include "plane.h" nuclear@0: #include "box.h" nuclear@4: #include "cone.h" nuclear@0: #include "light.h" nuclear@0: #include "camera.h" nuclear@0: #include "texture.h" nuclear@0: nuclear@0: static bool parse_material(char **argv, Material *mtl, std::string *name); nuclear@0: static Object *parse_sphere(char **argv, const std::map &materials); nuclear@0: static Object *parse_plane(char **argv, const std::map &materials); nuclear@0: static Object *parse_box(char **argv, const std::map &materials); nuclear@4: static Object *parse_cone(char **argv, const std::map &materials); nuclear@0: static Light *parse_light(char **argv); nuclear@0: static Camera *parse_camera(char **argv); nuclear@0: static bool parse_env(char **argv, Scene *scn); nuclear@0: static bool parse_xform(char **argv, Scene *scn); nuclear@0: static bool parse_vec(char **argv, Vector3 *vptr); nuclear@0: nuclear@0: static char *strip_space(char *s); nuclear@0: static char **split_args(char *args); nuclear@0: nuclear@0: bool load_scene_file(Scene *scn, const char *fname) nuclear@0: { nuclear@0: FILE *fp; nuclear@0: if(!(fp = fopen(fname, "rb"))) { nuclear@0: fprintf(stderr, "%s: failed to open scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno)); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: char buf[512]; nuclear@0: std::map materials; nuclear@0: nuclear@0: int lineno = 0; nuclear@0: while(fgets(buf, sizeof buf, fp)) { nuclear@0: char *line = strip_space(buf); nuclear@0: nuclear@0: lineno++; nuclear@0: nuclear@0: if(!*line || *line == '\n' || *line == '#') { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: if(strstr(line, "material") == line) { nuclear@0: Material mtl; nuclear@0: std::string name; nuclear@0: nuclear@0: char *args = strip_space(line + strlen("material")); nuclear@0: if(!parse_material(split_args(args), &mtl, &name)) { nuclear@0: goto err; nuclear@0: } nuclear@0: materials[name] = mtl; nuclear@0: nuclear@0: } else if(strstr(line, "sphere") == line) { nuclear@0: char *args = strip_space(line + strlen("sphere")); nuclear@0: Object *obj = parse_sphere(split_args(args), materials); nuclear@0: if(!obj) { nuclear@0: goto err; nuclear@0: } nuclear@0: scn->add_object(obj); nuclear@0: nuclear@0: } else if(strstr(line, "plane") == line) { nuclear@0: char *args = strip_space(line + strlen("plane")); nuclear@0: Object *obj = parse_plane(split_args(args), materials); nuclear@0: if(!obj) { nuclear@0: goto err; nuclear@0: } nuclear@0: scn->add_object(obj); nuclear@0: nuclear@0: } else if(strstr(line, "box") == line) { nuclear@0: char *args = strip_space(line + strlen("box")); nuclear@0: Object *obj = parse_box(split_args(args), materials); nuclear@0: if(!obj) { nuclear@0: goto err; nuclear@0: } nuclear@0: scn->add_object(obj); nuclear@0: nuclear@4: } else if(strstr(line, "cone") == line) { nuclear@4: char *args = strip_space(line + strlen("cone")); nuclear@4: Object *obj = parse_cone(split_args(args), materials); nuclear@4: if(!obj) { nuclear@4: goto err; nuclear@4: } nuclear@4: scn->add_object(obj); nuclear@4: nuclear@0: } else if(strstr(line, "light") == line) { nuclear@0: char *args = strip_space(line + strlen("light")); nuclear@0: Light *lt = parse_light(split_args(args)); nuclear@0: if(!lt) { nuclear@0: goto err; nuclear@0: } nuclear@0: scn->add_light(lt); nuclear@0: nuclear@0: } else if(strstr(line, "camera") == line) { nuclear@0: char *args = strip_space(line + strlen("camera")); nuclear@0: Camera *cam = parse_camera(split_args(args)); nuclear@0: if(!cam) { nuclear@0: goto err; nuclear@0: } nuclear@0: scn->set_camera(cam); nuclear@0: nuclear@0: } else if(strstr(line, "environment") == line) { nuclear@0: char *args = strip_space(line + strlen("environment")); nuclear@0: if(!parse_env(split_args(args), scn)) { nuclear@0: goto err; nuclear@0: } nuclear@0: nuclear@0: } else if(strstr(line, "xform") == line) { nuclear@0: char *args = strip_space(line + strlen("xform")); nuclear@0: if(!parse_xform(split_args(args), scn)) { nuclear@0: goto err; nuclear@0: } nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "%s error %s:%d: unknown command: %s\n", __FUNCTION__, fname, lineno, line); nuclear@0: goto err; nuclear@0: } nuclear@0: nuclear@0: } nuclear@0: nuclear@0: fclose(fp); nuclear@0: return true; nuclear@0: nuclear@0: err: nuclear@0: fclose(fp); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: bool save_scene_file(const Scene *scn, const char *fname) nuclear@0: { nuclear@0: FILE *fp; nuclear@0: if(!(fp = fopen(fname, "wb"))) { nuclear@0: fprintf(stderr, "%s: failed to save scene file: %s: %s\n", __FUNCTION__, fname, strerror(errno)); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: for(int i=0; iget_object_count(); i++) { nuclear@0: // first write the material nuclear@0: const Object *obj = scn->get_object(i); nuclear@0: const Material *mat = &obj->material; nuclear@0: nuclear@0: char name[128]; nuclear@0: sprintf(name, "mat%d", i); nuclear@0: nuclear@0: fprintf(fp, "material -name %s", name); nuclear@0: fprintf(fp, " -diffuse %.3f %.3f %.3f", mat->diffuse.x, mat->diffuse.y, mat->diffuse.z); nuclear@0: fprintf(fp, " -specular %.3f %.3f %.3f", mat->specular.x, mat->specular.y, mat->specular.z); nuclear@0: fprintf(fp, " -shininess %.3f", mat->shininess); nuclear@0: fprintf(fp, " -emission %.3f %.3f %.3f", mat->emission.x, mat->emission.y, mat->emission.z); nuclear@0: fprintf(fp, " -reflect %.3f", mat->reflectivity); nuclear@0: fprintf(fp, " -trans %.3f", mat->transparency); nuclear@0: fprintf(fp, " -ior %.3f", mat->ior); nuclear@0: if(mat->tex) { nuclear@0: fprintf(fp, " -texture %s", mat->tex->get_name()); nuclear@0: } nuclear@0: fputc('\n', fp); nuclear@0: nuclear@0: // then write the object nuclear@0: const Sphere *sph; nuclear@0: const Plane *plane; nuclear@0: const Box *box; nuclear@4: const Cone *cone; nuclear@0: if((sph = dynamic_cast(obj))) { nuclear@0: fprintf(fp, "sphere -material %s", name); nuclear@0: fprintf(fp, " -center %.3f %.3f %.3f", sph->pos.x, sph->pos.y, sph->pos.z); nuclear@0: fprintf(fp, " -radius %.3f\n", sph->radius); nuclear@0: } else if((plane = dynamic_cast(obj))) { nuclear@0: fprintf(fp, "plane -material %s", name); nuclear@0: fprintf(fp, " -normal %.3f %.3f %.3f", plane->normal.x, plane->normal.y, plane->normal.z); nuclear@0: fprintf(fp, " -distance %.3f\n", plane->dist); nuclear@0: } else if((box = dynamic_cast(obj))) { nuclear@0: fprintf(fp, "box -material %s", name); nuclear@0: fprintf(fp, " -min %.3f %.3f %.3f", box->min.x, box->min.y, box->min.z); nuclear@0: fprintf(fp, " -max %.3f %.3f %.3f\n", box->max.x, box->max.y, box->max.z); nuclear@4: } else if((cone = dynamic_cast(obj))) { nuclear@4: fprintf(fp, "cone -material %s", name); nuclear@4: fprintf(fp, " -angle %g", RAD_TO_DEG(cone->angle)); nuclear@4: fprintf(fp, " -start %g -end %g\n", cone->ymin, cone->ymax); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: for(int i=0; iget_light_count(); i++) { nuclear@0: const Light *lt = scn->get_light(i); nuclear@0: nuclear@0: fprintf(fp, "light -position %.3f %.3f %.3f", lt->pos.x, lt->pos.y, lt->pos.z); nuclear@0: fprintf(fp, " -color %.3f %.3f %.3f\n", lt->color.x, lt->color.y, lt->color.z); nuclear@0: } nuclear@0: nuclear@0: const TargetCamera *tcam = dynamic_cast(scn->get_camera()); nuclear@0: if(tcam) { nuclear@0: Vector3 pos = tcam->get_position(); nuclear@0: fprintf(fp, "camera -position %.3f %.3f %.3f", pos.x, pos.y, pos.z); nuclear@0: Vector3 targ = tcam->get_target(); nuclear@0: fprintf(fp, " -target %.3f %.3f %.3f", targ.x, targ.y, targ.z); nuclear@0: fprintf(fp, " -fov %.3f\n", tcam->get_fov()); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: fclose(fp); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: #define ARGERR(n) \ nuclear@0: do { fprintf(stderr, "failed to parse %s argument\n", (n)); return false; } while(0) nuclear@0: nuclear@0: static bool parse_material(char **argv, Material *mtl, std::string *name) nuclear@0: { nuclear@0: char *endp; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-name") == 0) { nuclear@0: *name = argv[++i]; nuclear@0: } else if(strcmp(argv[i], "-diffuse") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &mtl->diffuse)) { nuclear@0: ARGERR("diffuse"); nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-specular") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &mtl->specular)) { nuclear@0: ARGERR("specular"); nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-emission") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &mtl->emission)) { nuclear@0: ARGERR("emission"); nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-shininess") == 0) { nuclear@0: mtl->shininess = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: ARGERR("shininess"); nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-reflect") == 0) { nuclear@0: mtl->reflectivity = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: ARGERR("reflect"); nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-trans") == 0) { nuclear@0: mtl->transparency = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: ARGERR("trans"); nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-ior") == 0) { nuclear@0: mtl->ior = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: ARGERR("ior"); nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-texture") == 0) { nuclear@0: if(!(mtl->tex = load_texture(argv[++i]))) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid material option: %s\n", argv[i]); nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static Object *parse_sphere(char **argv, const std::map &materials) nuclear@0: { nuclear@0: char *endp; nuclear@0: Sphere *sph = new Sphere; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-name") == 0) { nuclear@0: sph->set_name(argv[++i]); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-center") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &sph->pos)) { nuclear@0: fprintf(stderr, "failed to parse sphere center vector\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-radius") == 0) { nuclear@0: sph->radius = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse sphere radius\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-material") == 0) { nuclear@0: auto it = materials.find(argv[++i]); nuclear@0: if(it == materials.end()) { nuclear@0: fprintf(stderr, "material %s not found\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: sph->material = it->second; nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid sphere option: %s\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return sph; nuclear@0: } nuclear@0: nuclear@0: static Object *parse_plane(char **argv, const std::map &materials) nuclear@0: { nuclear@0: char *endp; nuclear@0: Plane *plane = new Plane; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-name") == 0) { nuclear@0: plane->set_name(argv[++i]); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-normal") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &plane->normal)) { nuclear@0: fprintf(stderr, "failed to parse plane normal\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: plane->normal.normalize(); nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-distance") == 0) { nuclear@0: plane->dist = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse plane distance\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-material") == 0) { nuclear@0: auto it = materials.find(argv[++i]); nuclear@0: if(it == materials.end()) { nuclear@0: fprintf(stderr, "material %s not found\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: plane->material = it->second; nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid plane option: %s\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return plane; nuclear@0: } nuclear@0: nuclear@0: static Object *parse_box(char **argv, const std::map &materials) nuclear@0: { nuclear@0: Box *box = new Box; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-name") == 0) { nuclear@0: box->set_name(argv[++i]); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-min") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &box->min)) { nuclear@0: fprintf(stderr, "failed to parse box min\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-max") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &box->max)) { nuclear@0: fprintf(stderr, "failed to parse box max\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-material") == 0) { nuclear@0: auto it = materials.find(argv[++i]); nuclear@0: if(it == materials.end()) { nuclear@0: fprintf(stderr, "material %s not found\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: box->material = it->second; nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid box option: %s\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return box; nuclear@0: } nuclear@0: nuclear@4: static Object *parse_cone(char **argv, const std::map &materials) nuclear@4: { nuclear@4: char *endp; nuclear@4: Cone *cone = new Cone; nuclear@4: nuclear@4: for(int i=0; argv[i]; i++) { nuclear@4: if(strcmp(argv[i], "-name") == 0) { nuclear@4: cone->set_name(argv[++i]); nuclear@4: nuclear@4: } else if(strcmp(argv[i], "-angle") == 0) { nuclear@4: cone->angle = DEG_TO_RAD(strtod(argv[++i], &endp)); nuclear@4: if(endp == argv[i]) { nuclear@4: fprintf(stderr, "failed to parse cone angle\n"); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: } else if(strcmp(argv[i], "-start") == 0) { nuclear@4: cone->ymin = strtod(argv[++i], &endp); nuclear@4: if(endp == argv[i]) { nuclear@4: fprintf(stderr, "failed to parse cone start\n"); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: } else if(strcmp(argv[i], "-end") == 0) { nuclear@4: cone->ymax = strtod(argv[++i], &endp); nuclear@4: if(endp == argv[i]) { nuclear@4: fprintf(stderr, "failed to parse cone end\n"); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: } else if(strcmp(argv[i], "-material") == 0) { nuclear@4: auto it = materials.find(argv[++i]); nuclear@4: if(it == materials.end()) { nuclear@4: fprintf(stderr, "material %s not found\n", argv[i]); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: cone->material = it->second; nuclear@4: } else { nuclear@4: fprintf(stderr, "invalid box option: %s\n", argv[i]); nuclear@4: return 0; nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: return cone; nuclear@4: } nuclear@4: nuclear@0: static Light *parse_light(char **argv) nuclear@0: { nuclear@0: Light *lt = new Light; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-position") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, <->pos)) { nuclear@0: fprintf(stderr, "failed to parse light position\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-color") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, <->color)) { nuclear@0: fprintf(stderr, "failed to parse light color\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid light option: %s\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return lt; nuclear@0: } nuclear@0: nuclear@0: static Camera *parse_camera(char **argv) nuclear@0: { nuclear@0: char *endp; nuclear@0: TargetCamera *cam = new TargetCamera; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-position") == 0) { nuclear@0: Vector3 pos; nuclear@0: if(!parse_vec(argv + i + 1, &pos)) { nuclear@0: fprintf(stderr, "failed to parse camera position\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: cam->set_position(pos); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-target") == 0) { nuclear@0: Vector3 targ; nuclear@0: if(!parse_vec(argv + i + 1, &targ)) { nuclear@0: fprintf(stderr, "failed to parse camera target\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: argv += 3; nuclear@0: cam->set_target(targ); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-fov") == 0) { nuclear@0: float fov = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse camera fov\n"); nuclear@0: return 0; nuclear@0: } nuclear@0: cam->set_fov(M_PI * fov / 180.0); nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid camera option: %s\n", argv[i]); nuclear@0: return 0; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return cam; nuclear@0: } nuclear@0: nuclear@0: static bool parse_env(char **argv, Scene *scn) nuclear@0: { nuclear@0: char *endp; nuclear@0: nuclear@0: TextureCube *env_tex = 0; nuclear@0: TextureCube *conv_tex = 0; nuclear@0: nuclear@0: float fog_start = -1; nuclear@0: float fog_end = -1; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-color") == 0) { nuclear@0: Color bgcolor; nuclear@0: if(!parse_vec(argv + i + 1, &bgcolor)) { nuclear@0: fprintf(stderr, "failed to parse environment color\n"); nuclear@0: return false; nuclear@0: } nuclear@0: i += 3; nuclear@0: scn->set_background_color(bgcolor); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-fog-start") == 0) { nuclear@0: fog_start = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse environment fog start\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-fog-end") == 0) { nuclear@0: fog_end = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse environment fog end\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-texture") == 0 || strcmp(argv[i], "-texture-conv") == 0) { nuclear@0: Texture *tex = load_texture(argv[++i]); nuclear@0: if(!tex || !dynamic_cast(tex)) { nuclear@0: fprintf(stderr, "failed to load environment cubemap: %s\n", argv[i]); nuclear@0: delete tex; nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if(strstr(argv[i - 1], "-conv")) { nuclear@0: conv_tex = (TextureCube*)tex; nuclear@0: } else { nuclear@0: env_tex = (TextureCube*)tex; nuclear@0: } nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid environment option: %s\n", argv[i]); nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(env_tex || conv_tex) { nuclear@0: scn->set_environment_map(env_tex, conv_tex); nuclear@0: } nuclear@0: nuclear@0: if(fog_start > 0.0 && fog_end > 0.0) { nuclear@0: scn->set_fog(fog_start, fog_end); nuclear@0: } nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static bool parse_xform(char **argv, Scene *scn) nuclear@0: { nuclear@0: char *endp, *name = 0; nuclear@0: Vector3 pos, rot_axis, scale; nuclear@0: float rot_angle = 0; nuclear@0: long tm = 0; nuclear@0: Extrap extrap = EXTRAP_REPEAT; nuclear@0: nuclear@0: bool have_pos = false; nuclear@0: bool have_rot_axis = false; nuclear@0: bool have_rot_angle = false; nuclear@0: bool have_scale = false; nuclear@0: bool have_extrap = false; nuclear@0: nuclear@0: for(int i=0; argv[i]; i++) { nuclear@0: if(strcmp(argv[i], "-name") == 0) { nuclear@0: name = argv[++i]; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-pos") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &pos)) { nuclear@0: fprintf(stderr, "failed to parse xform position\n"); nuclear@0: return false; nuclear@0: } nuclear@0: have_pos = true; nuclear@0: i += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-rot-axis") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &rot_axis)) { nuclear@0: fprintf(stderr, "failed to parse xform rotation axis\n"); nuclear@0: return false; nuclear@0: } nuclear@0: have_rot_axis = true; nuclear@0: i += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-rot-angle") == 0) { nuclear@0: rot_angle = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse xform rotation angle\n"); nuclear@0: return false; nuclear@0: } nuclear@0: rot_angle = M_PI * rot_angle / 180.0; nuclear@0: have_rot_angle = true; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-scale") == 0) { nuclear@0: if(!parse_vec(argv + i + 1, &scale)) { nuclear@0: fprintf(stderr, "failed to parse xform scale\n"); nuclear@0: return false; nuclear@0: } nuclear@0: have_scale = true; nuclear@0: i += 3; nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-time") == 0) { nuclear@0: float tm_sec = strtod(argv[++i], &endp); nuclear@0: if(endp == argv[i]) { nuclear@0: fprintf(stderr, "failed to parse xform time\n"); nuclear@0: return false; nuclear@0: } nuclear@0: tm = (long)(tm_sec * 1000.0f); nuclear@0: nuclear@0: } else if(strcmp(argv[i], "-extrapolation") == 0) { nuclear@0: if(strcmp(argv[++i], "extend") == 0) { nuclear@0: extrap = EXTRAP_EXTEND; nuclear@0: } else if(strcmp(argv[i], "clamp") == 0) { nuclear@0: extrap = EXTRAP_CLAMP; nuclear@0: } else if(strcmp(argv[i], "repeat") == 0) { nuclear@0: extrap = EXTRAP_REPEAT; nuclear@0: } else if(strcmp(argv[i], "pingpong") == 0) { nuclear@0: extrap = EXTRAP_PINGPONG; nuclear@0: } else { nuclear@0: fprintf(stderr, "failed to parse xform extrapolation, invalid mode: %s\n", argv[i]); nuclear@0: return false; nuclear@0: } nuclear@0: have_extrap = true; nuclear@0: nuclear@0: } else { nuclear@0: fprintf(stderr, "invalid xform option: %s\n", argv[i]); nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(!name) { nuclear@0: fprintf(stderr, "invalid xform command, missing -name option\n"); nuclear@0: return false; nuclear@0: } nuclear@0: if(have_rot_angle != have_rot_axis) { nuclear@0: fprintf(stderr, "invalid xform command, must have both -rot-angle and -rot-axis or neither\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: Object *obj = 0; nuclear@0: nuclear@0: int nobj = scn->get_object_count(); nuclear@0: for(int i=0; iget_object(i); nuclear@0: if(strcmp(tmp->get_name(), name) == 0) { nuclear@0: obj = tmp; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(!obj) { nuclear@0: fprintf(stderr, "invalid xform, refers to nonexistent object: %s\n", name); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: if(have_pos) { nuclear@0: obj->set_position(pos, tm); nuclear@0: } nuclear@0: if(have_rot_angle) { nuclear@0: obj->set_rotation(Quaternion(rot_axis, rot_angle), tm); nuclear@0: } nuclear@0: if(have_scale) { nuclear@0: obj->set_scaling(scale, tm); nuclear@0: } nuclear@0: nuclear@0: if(have_extrap) { nuclear@0: obj->set_extrapolator(extrap); nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: static bool parse_vec(char **argv, Vector3 *vptr) nuclear@0: { nuclear@0: char *endp; nuclear@0: nuclear@0: vptr->x = strtod(argv[0], &endp); nuclear@0: if(endp == argv[0]) nuclear@0: return false; nuclear@0: vptr->y = strtod(argv[1], &endp); nuclear@0: if(endp == argv[1]) nuclear@0: return false; nuclear@0: vptr->z = strtod(argv[2], &endp); nuclear@0: if(endp == argv[2]) nuclear@0: return false; nuclear@0: nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: static char *strip_space(char *s) nuclear@0: { nuclear@0: while(*s && isspace(*s)) s++; nuclear@0: nuclear@0: if(!*s) nuclear@0: return s; nuclear@0: nuclear@0: char *endp = s + strlen(s) - 1; nuclear@0: while(isspace(*endp)) endp--; nuclear@0: endp[1] = 0; nuclear@0: nuclear@0: if((endp = strrchr(s, '#'))) { nuclear@0: *endp = 0; nuclear@0: } nuclear@0: nuclear@0: return s; nuclear@0: } nuclear@0: nuclear@0: static char **split_args(char *args) nuclear@0: { nuclear@0: static std::vector argv; nuclear@0: char *tok = 0; nuclear@0: nuclear@0: argv.clear(); nuclear@0: nuclear@0: while((tok = strtok(tok ? 0 : args, " \t\v\n\r"))) { nuclear@0: argv.push_back(tok); nuclear@0: } nuclear@0: argv.push_back(0); nuclear@0: nuclear@0: return &argv[0]; nuclear@0: }