#include #include #include #include #include #include #include "3d.h" #include "model.h" extern const char *__progname; typedef struct arg ARG; typedef struct map MAP; typedef struct xform XFORM; /* * [x y z] -> [x' y' z'] * * [ Mxx Mxy Mxz 0 ] * [ x' y' z' 1 ] = [ x y z 1 ] [ Myx Myy Myz 0 ] * [ Mzx Mzy Mzz 0 ] * [ Sx Sy Sz 1 ] */ struct xform { double Mxx; double Mxy; double Mxz; double Myx; double Myy; double Myz; double Mzx; double Mzy; double Mzz; double Sx; double Sy; double Sz; } ; struct map { int n; int a; int *m; char *s; } ; struct arg { ARG *link; char *filename; XFORM xform; MODEL *model; } ; static ARG *args = 0; static MODEL *out; static XYZ xform(XYZ, XFORM) __attribute__((__const__)); static XYZ xform(XYZ v, XFORM m) { return((XYZ){ .x = (v.x * m.Mxx) + (v.y * m.Myx) + (v.z * m.Mzx) + m.Sx, .y = (v.x * m.Mxy) + (v.y * m.Myy) + (v.z * m.Mzy) + m.Sy, .z = (v.x * m.Mxz) + (v.y * m.Myz) + (v.z * m.Mzz) + m.Sz }); } #if 0 /* * C = A B, or, in individual-component form, * * [ c.Mxx c.Mxy c.Mxz 0 ] [ a.Mxx a.Mxy a.Mxz 0 ] [ b.Mxx b.Mxy b.Mxz 0 ] * [ c.Myx c.Myy c.Myz 0 ] = [ a.Myx a.Myy a.Myz 0 ] [ b.Myx b.Myy b.Myz 0 ] * [ c.Mzx c.Mzy c.Mzz 0 ] [ a.Mzx a.Mzy a.Mzz 0 ] [ b.Mzx b.Mzy b.Mzz 0 ] * [ c.Sx c.Sy c.Sz 1 ] [ a.Sx a.Sy a.Sz 1 ] [ b.Sx b.Sy b.Sz 1 ] */ static XFORM compound(XFORM, XFORM) __attribute__((__const__)); static XFORM compound(XFORM a, XFORM b) { return((XFORM){ .Mxx = (a.Mxx * b.Mxx) + (a.Mxy * b.Myx) + (a.Mxz * b.Mzx), .Mxy = (a.Mxx * b.Mxy) + (a.Mxy * b.Myy) + (a.Mxz * b.Mzy), .Mxz = (a.Mxx * b.Mxz) + (a.Mxy * b.Myz) + (a.Mxz * b.Mzz), .Myx = (a.Myx * b.Mxx) + (a.Myy * b.Myx) + (a.Myz * b.Mzx), .Myy = (a.Myx * b.Mxy) + (a.Myy * b.Myy) + (a.Myz * b.Mzy), .Myz = (a.Myx * b.Mxz) + (a.Myy * b.Myz) + (a.Myz * b.Mzz), .Mzx = (a.Mzx * b.Mxx) + (a.Mzy * b.Myx) + (a.Mzz * b.Mzx), .Mzy = (a.Mzx * b.Mxy) + (a.Mzy * b.Myy) + (a.Mzz * b.Mzy), .Mzz = (a.Mzx * b.Mxz) + (a.Mzy * b.Myz) + (a.Mzz * b.Mzz), .Sx = (a.Sx * b.Mxx) + (a.Sy * b.Myx) + (a.Sz * b.Mzx) + b.Sx, .Sy = (a.Sy * b.Mxy) + (a.Sy * b.Myy) + (a.Sz * b.Mzy) + b.Sy, .Sz = (a.Sz * b.Mxz) + (a.Sy * b.Myz) + (a.Sz * b.Mzz) + b.Sz }); } #endif static const XFORM xf_identity = { .Mxx = 1, .Mxy = 0, .Mxz = 0, .Myx = 0, .Myy = 1, .Myz = 0, .Mzx = 0, .Mzy = 0, .Mzz = 1, .Sx = 0, .Sy = 0, .Sz = 0 }; static XFORM xf_shift(XYZ) __attribute__((__const__)); static XFORM xf_shift(XYZ v) { return((XFORM){ .Mxx = 1, .Mxy = 0, .Mxz = 0, .Myx = 0, .Myy = 1, .Myz = 0, .Mzx = 0, .Mzy = 0, .Mzz = 1, .Sx = v.x, .Sy = v.y, .Sz = v.z }); } static void add_arg(char *fn, XFORM xform) { ARG *a; a = malloc(sizeof(ARG)); a->filename = fn; a->xform = xform; a->link = args; args = a; } static void handleargs(int ac, char **av) { int skip; int errs; XFORM xform; xform = xf_identity; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { add_arg(*av,xform); xform = xf_identity; 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")) { XYZ shift; WANTARG(); shift.x = atof(av[skip]); WANTARG(); shift.y = atof(av[skip]); WANTARG(); shift.z = atof(av[skip]); xform = xf_shift(shift); continue; } if (!strcmp(*av,"-xform")) { WANTARG(); xform.Mxx = atof(av[skip]); WANTARG(); xform.Mxy = atof(av[skip]); WANTARG(); xform.Mxz = atof(av[skip]); WANTARG(); xform.Myx = atof(av[skip]); WANTARG(); xform.Myy = atof(av[skip]); WANTARG(); xform.Myz = atof(av[skip]); WANTARG(); xform.Mzx = atof(av[skip]); WANTARG(); xform.Mzy = atof(av[skip]); WANTARG(); xform.Mzz = atof(av[skip]); WANTARG(); xform.Sx = atof(av[skip]); WANTARG(); xform.Sy = atof(av[skip]); WANTARG(); xform.Sz = atof(av[skip]); continue; } if (!strcmp(*av,"-file")) { WANTARG(); add_arg(av[skip],xform); xform = xf_identity; 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 = xform(get_location(a->model,i)->l,a->xform); for (j=n_locations(out)-1;j>=0;j--) { if (same_xyz(l,get_location(out,j)->l)) { map_set(l_map,i,j); continue <"l">; } } j = new_location(out); get_location(out,j)->l = 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 = xform(get_location(a->model,p->loc)->l,a->xform); 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)->l)) 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 <"m"> (i=n_marks(a->model)-1;i>=0;i--) { MARK *o; MARK *n; o = get_mark(a->model,i); j = new_mark(out); n = get_mark(out,j); n->at = map_map(l_map,i); n->text = strdup(o->text); } } } 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); }