#include #include #include #include #include #include #include "model.h" extern const char *__progname; typedef struct arg ARG; typedef struct map MAP; struct map { int n; int a; int *m; char *s; } ; struct arg { ARG *link; char *filename; XYZ shift; MODEL *model; } ; static ARG *args = 0; static MODEL *out; static XYZ add3(XYZ, XYZ) __attribute__((__const__)); static XYZ add3(XYZ a, XYZ b) { return((XYZ){a.x+b.x,a.y+b.y,a.z+b.z}); } static void add_arg(char *fn, XYZ shift) { ARG *a; a = malloc(sizeof(ARG)); a->filename = fn; a->shift = shift; a->link = args; args = a; } static void handleargs(int ac, char **av) { int skip; int errs; XYZ shift; shift = (XYZ) { 0, 0, 0 }; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { add_arg(*av,shift); shift = (XYZ) { 0, 0, 0 }; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-shift")) { WANTARG(); shift.x = atof(av[skip]); WANTARG(); shift.y = atof(av[skip]); WANTARG(); shift.z = atof(av[skip]); continue; } if (!strcmp(*av,"-file")) { WANTARG(); add_arg(av[skip],shift); shift = (XYZ) { 0, 0, 0 }; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static void read_models(void) { ARG *a; FILE *f; static void errf(const char *s) { const char *nl; while (1) { nl = index(s,'\n'); if (! nl) break; fprintf(stderr,"%s: %s [offset %lu]: %.*s\n",__progname,a->filename,ftell(f),(int)(nl-s),s); s = nl + 1; } if (s[0]) { fprintf(stderr,"%s: %s [offset %lu]: %s\n",__progname,a->filename,ftell(f),s); } } for (a=args;a;a=a->link) { f = fopen(a->filename,"r"); if (f == 0) { fprintf(stderr,"%s: %s: %s\n",__progname,a->filename,strerror(errno)); exit(1); } a->model = load_model(f,&errf); if (! a->model) exit(1); fclose(f); } } static MAP *map_init(void) { MAP *m; m = malloc(sizeof(MAP)); m->n = 0; m->a = 0; m->m = 0; m->s = 0; return(m); } static void map_reset(MAP *m) { m->n = 0; } static void map_set(MAP *m, int inx, int val) { if (inx < 0) abort(); if (inx >= m->n) { if (inx >= m->a) { m->a = inx + 8; m->m = realloc(m->m,m->a*sizeof(*m->m)); m->s = realloc(m->s,m->a*sizeof(*m->s)); } while (m->n <= inx) m->s[m->n++] = 0; } m->s[inx] = 1; m->m[inx] = val; } static int map_map(MAP *m, int inx) { if ((inx < 0) || (inx >= m->n) || !m->s[inx]) abort(); return(m->m[inx]); } static int same_material(MATERIAL *a, MATERIAL *b) { if (fabs(a->selflum.r-b->selflum.r) > 1e-4) return(0); if (fabs(a->selflum.g-b->selflum.g) > 1e-4) return(0); if (fabs(a->selflum.b-b->selflum.b) > 1e-4) return(0); if (fabs(a->reflect.r-b->reflect.r) > 1e-4) return(0); if (fabs(a->reflect.g-b->reflect.g) > 1e-4) return(0); if (fabs(a->reflect.b-b->reflect.b) > 1e-4) return(0); if (fabs(a->spec_exp-b->spec_exp) > 1e-4) return(0); if (fabs(a->spec_mul-b->spec_mul) > 1e-4) return(0); return(1); } static int same_xyz(XYZ a, XYZ b) { return( (fabs(a.x-b.x) < 1e-4) && (fabs(a.y-b.y) < 1e-4) && (fabs(a.z-b.z) < 1e-4) ); } static void merge(void) { ARG *a; MAP *m_map; MAP *l_map; MAP *p_map; MAP *t_map; MAP *o_map; int i; int j; m_map = map_init(); l_map = map_init(); p_map = map_init(); t_map = map_init(); o_map = map_init(); out = new_model(); for (a=args;a;a=a->link) { map_reset(m_map); map_reset(l_map); map_reset(p_map); map_reset(t_map); map_reset(o_map); for <"m"> (i=n_materials(a->model)-1;i>=0;i--) { MATERIAL *m; m = get_material(a->model,i); for (j=n_materials(out)-1;j>=0;j--) { if (same_material(m,get_material(out,j))) { map_set(m_map,i,j); continue <"m">; } } j = new_material(out); *get_material(out,j) = *m; map_set(m_map,i,j); } for <"l"> (i=n_locations(a->model)-1;i>=0;i--) { XYZ l; l = add3(*get_location(a->model,i),a->shift); for (j=n_locations(out)-1;j>=0;j--) { if (same_xyz(l,*get_location(out,j))) { map_set(l_map,i,j); continue <"l">; } } j = new_location(out); *get_location(out,j) = l; map_set(l_map,i,j); } for <"p"> (i=n_points(a->model)-1;i>=0;i--) { POINT *p; POINT *p2; XYZ pl; p = get_point(a->model,i); pl = add3(*get_location(a->model,p->loc),a->shift); for (j=n_points(out)-1;j>=0;j--) { p2 = get_point(out,j); if (p->type != p2->type) continue; if (! same_xyz(pl,*get_location(out,p2->loc))) continue; if ((p->type == PT_SURFACE) && !same_xyz(p->normal,p2->normal)) continue; map_set(p_map,i,j); continue <"p">; } j = new_point(out); p2 = get_point(out,j); p2->loc = map_map(l_map,p->loc); p2->type = p->type; if (p->type == PT_SURFACE) p2->normal = p->normal; map_set(p_map,i,j); } for <"t"> (i=n_triangles(a->model)-1;i>=0;i--) { TRIANGLE *t; TRIANGLE *n; t = get_triangle(a->model,i); j = new_triangle(out); n = get_triangle(out,j); n->material = map_map(m_map,t->material); n->corner[0] = map_map(p_map,t->corner[0]); n->corner[1] = map_map(p_map,t->corner[1]); n->corner[2] = map_map(p_map,t->corner[2]); map_set(t_map,i,j); } for <"o"> (i=n_objects(a->model)-1;i>=0;i--) { OBJECT *o; OBJECT *n; int k; o = get_object(a->model,i); j = new_object(out); n = get_object(out,j); n->ntriangles = o->ntriangles; free(n->triangles); n->triangles = malloc(n->ntriangles*sizeof(int)); for (k=n->ntriangles-1;k>=0;k--) { n->triangles[k] = map_map(t_map,o->triangles[k]); } map_set(o_map,i,j); } } } static void write_output(void) { save_model(out,stdout); } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); read_models(); merge(); write_output(); return(0); }