2 * Copyright (C) 2003 Robert Kooima
4 * SUPER EMPTY BALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
16 * I'm not particularly proud of this chunk of code. It was not so much
17 * designed as it was accumulated.
21 #include <SDL/SDL_image.h>
34 #define SMALL 0.0000000005
37 * The overall design of this map converter is very stupid, but very simple
38 * It begins by assuming that every mtrl, vert, edge, side, and texc in the
39 * map is unique. It then makes an optimizing pass that discards redundant
40 * information. The result is optimal, though the process is terribly
44 /*---------------------------------------------------------------------------*/
46 /* Arbitrary limits woo! */
62 static void init_file(struct s_file
*fp
)
78 fp
->mv
= (struct s_mtrl
*) calloc(MAXM
, sizeof (struct s_mtrl
));
79 fp
->vv
= (struct s_vert
*) calloc(MAXV
, sizeof (struct s_vert
));
80 fp
->ev
= (struct s_edge
*) calloc(MAXE
, sizeof (struct s_edge
));
81 fp
->sv
= (struct s_side
*) calloc(MAXS
, sizeof (struct s_side
));
82 fp
->tv
= (struct s_texc
*) calloc(MAXT
, sizeof (struct s_texc
));
83 fp
->gv
= (struct s_geom
*) calloc(MAXG
, sizeof (struct s_geom
));
84 fp
->lv
= (struct s_lump
*) calloc(MAXL
, sizeof (struct s_lump
));
85 fp
->nv
= (struct s_node
*) calloc(MAXN
, sizeof (struct s_node
));
86 fp
->pv
= (struct s_path
*) calloc(MAXP
, sizeof (struct s_path
));
87 fp
->bv
= (struct s_body
*) calloc(MAXB
, sizeof (struct s_body
));
88 fp
->cv
= (struct s_coin
*) calloc(MAXC
, sizeof (struct s_coin
));
89 fp
->uv
= (struct s_ball
*) calloc(MAXU
, sizeof (struct s_ball
));
90 fp
->iv
= (int *) calloc(MAXI
, sizeof (int));
93 /*---------------------------------------------------------------------------*/
96 * The following is a small symbol table data structure. Symbols and their
97 * integer values are collected in symv and valv. References and pointers to
98 * their unsatisfied integer values are collected in refv and pntv. The
99 * resolve procedure matches references to symbols and fills waiting ints
100 * with the proper values.
105 static char symv
[MAXSYM
][MAXSTR
];
106 static int valv
[MAXSYM
];
108 static char refv
[MAXSYM
][MAXSTR
];
109 static int *pntv
[MAXSYM
];
114 static void make_sym(const char *s
, int v
)
116 strcpy(symv
[strc
], s
);
121 static void make_ref(const char *r
, int *p
)
123 strcpy(refv
[refc
], r
);
128 static void resolve(void)
132 for (i
= 0; i
< refc
; i
++)
133 for (j
= 0; j
< strc
; j
++)
134 if (strcmp(refv
[i
], symv
[j
]) == 0)
136 *(pntv
[i
]) = valv
[j
];
141 /*---------------------------------------------------------------------------*/
143 static void size_image(const char *s
, int *w
, int *h
)
145 SDL_Surface
*S
= IMG_Load(s
);
161 /*---------------------------------------------------------------------------*/
163 static int path_0
= -1;
165 static double plane_d
[MAXS
];
166 static double plane_n
[MAXS
][3];
167 static double plane_p
[MAXS
][3];
168 static double plane_u
[MAXS
][3];
169 static double plane_v
[MAXS
][3];
170 static int plane_f
[MAXS
];
172 static void make_plane(int pi
, int x0
, int y0
, int z0
,
173 int x1
, int y1
, int z1
,
174 int x2
, int y2
, int z2
,
175 int tu
, int tv
, int r
,
176 float su
, float sv
, int fl
, const char *s
)
178 static const double base
[6][3][3] = {
179 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
180 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
181 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
182 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
183 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
184 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
188 double p0
[3], p1
[3], p2
[3];
189 double u
[3], v
[3], p
[3];
192 char filename
[MAXSTR
];
195 strcat(filename
, ".jpg");
197 size_image(filename
, &w
, &h
);
201 p0
[0] = +(double) x0
/ SCALE
;
202 p0
[1] = +(double) z0
/ SCALE
;
203 p0
[2] = -(double) y0
/ SCALE
;
205 p1
[0] = +(double) x1
/ SCALE
;
206 p1
[1] = +(double) z1
/ SCALE
;
207 p1
[2] = -(double) y1
/ SCALE
;
209 p2
[0] = +(double) x2
/ SCALE
;
210 p2
[1] = +(double) z2
/ SCALE
;
211 p2
[2] = -(double) y2
/ SCALE
;
216 v_crs(plane_n
[pi
], u
, v
);
217 v_nrm(plane_n
[pi
], plane_n
[pi
]);
219 plane_d
[pi
] = v_dot(plane_n
[pi
], p1
);
221 for (i
= 0; i
< 6; i
++)
222 if ((k
= v_dot(plane_n
[pi
], base
[i
][0])) > d
)
232 m_rot(R
, base
[n
][0], V_RAD(r
));
234 v_mad(p
, p
, base
[n
][1], su
* tu
/ SCALE
);
235 v_mad(p
, p
, base
[n
][2], sv
* tv
/ SCALE
);
237 m_vxfm(plane_u
[pi
], R
, base
[n
][1]);
238 m_vxfm(plane_v
[pi
], R
, base
[n
][2]);
239 m_vxfm(plane_p
[pi
], R
, p
);
241 v_scl(plane_u
[pi
], plane_u
[pi
], SCALE
/ w
);
242 v_scl(plane_v
[pi
], plane_v
[pi
], SCALE
/ h
);
244 v_scl(plane_u
[pi
], plane_u
[pi
], 1.0 / su
);
245 v_scl(plane_v
[pi
], plane_v
[pi
], 1.0 / sv
);
248 /*---------------------------------------------------------------------------*/
257 static int map_token(FILE *fin
, int pi
, char key
[MAXSTR
],
262 if (fgets(buf
, MAXSTR
, fin
))
271 /* Scan the beginning or end of a block. */
273 if (buf
[0] == '{') return T_BEG
;
274 if (buf
[0] == '}') return T_END
;
276 /* Scan a key-value pair. */
280 strcpy(key
, strtok(buf
, "\""));
281 (void) strtok(NULL
, "\"");
282 strcpy(val
, strtok(NULL
, "\""));
289 if (sscanf(buf
, "%c %d %d %d %c "
292 "%s %d %d %d %f %f %d",
293 &c
, &x0
, &y0
, &z0
, &c
,
294 &c
, &x1
, &y1
, &z1
, &c
,
295 &c
, &x2
, &y2
, &z2
, &c
,
296 key
, &tu
, &tv
, &r
, &su
, &sv
, &fl
) == 22)
298 make_plane(pi
, x0
, y0
, z0
,
301 tu
, tv
, r
, su
, sv
, fl
, key
);
305 /* If it's not recognized, it must be uninteresting. */
312 /*---------------------------------------------------------------------------*/
314 /* Read the given material file, adding a new material to the solid. */
316 static void read_mtrl(struct s_file
*fp
, const char *s
)
318 struct s_mtrl
*mp
= fp
->mv
+ fp
->mc
++;
321 if ((fin
= fopen(s
, "r")))
323 fscanf(fin
, "%f %f %f %f "
328 mp
->d
, mp
->d
+ 1, mp
->d
+ 2, mp
->d
+ 3,
329 mp
->a
, mp
->a
+ 1, mp
->a
+ 2, mp
->a
+ 3,
330 mp
->s
, mp
->s
+ 1, mp
->s
+ 2, mp
->s
+ 3,
331 mp
->e
, mp
->e
+ 1, mp
->e
+ 2, mp
->e
+ 3,
335 strcpy(mp
->f
, "data/");
337 strcat(mp
->f
, ".jpg");
342 * Parse a lump from the given file and add it to the solid. Note a small
343 * hack here in mapping materials onto sides. Material indices cannot be
344 * assigned until faces are computed, so for now there is assumed to be one
345 * material per side, and that a side index equals that side's material
346 * index. See clip_lump and clip_geom.
348 static void read_lump(struct s_file
*fp
, FILE *fin
)
354 struct s_lump
*lp
= fp
->lv
+ fp
->lc
++;
358 while ((t
= map_token(fin
, fp
->sc
, k
, v
)))
362 fp
->sv
[fp
->sc
].n
[0] = plane_n
[fp
->sc
][0];
363 fp
->sv
[fp
->sc
].n
[1] = plane_n
[fp
->sc
][1];
364 fp
->sv
[fp
->sc
].n
[2] = plane_n
[fp
->sc
][2];
365 fp
->sv
[fp
->sc
].d
= plane_d
[fp
->sc
];
369 fp
->iv
[fp
->ic
] = fp
->sc
;
379 /*---------------------------------------------------------------------------*/
381 static void make_path(struct s_file
*fp
,
383 char v
[][MAXSTR
], int c
)
385 int i
, pi
= fp
->pc
++;
387 struct s_path
*pp
= fp
->pv
+ pi
;
395 for (i
= 0; i
< c
; i
++)
397 if (!strcmp(k
[i
], "targetname"))
400 if (!strcmp(k
[i
], "target"))
401 make_ref(v
[i
], &pp
->pi
);
403 if (!strcmp(k
[i
], "speed"))
404 sscanf(v
[i
], "%lf", &pp
->t
);
406 if (!strcmp(k
[i
], "origin"))
408 int x
= 0, y
= 0, z
= 0;
410 sscanf(v
[i
], "%d %d %d", &x
, &y
, &z
);
412 pp
->p
[0] = +(double) x
/ SCALE
;
413 pp
->p
[1] = +(double) z
/ SCALE
;
414 pp
->p
[2] = -(double) y
/ SCALE
;
419 static void make_body(struct s_file
*fp
,
421 char v
[][MAXSTR
], int c
, int l0
)
423 int i
, bi
= fp
->bc
++;
425 struct s_body
*bp
= fp
->bv
+ bi
;
431 bp
->lc
= fp
->lc
- l0
;
433 for (i
= 0; i
< c
; i
++)
434 if (strcmp(k
[i
], "target") == 0)
435 make_ref(v
[i
], &bp
->pi
);
438 static void make_coin(struct s_file
*fp
,
440 char v
[][MAXSTR
], int c
)
442 int i
, ci
= fp
->cc
++;
444 struct s_coin
*cp
= fp
->cv
+ ci
;
451 for (i
= 0; i
< c
; i
++)
453 if (strcmp(k
[i
], "light") == 0)
454 sscanf(v
[i
], "%d", &cp
->n
);
456 if (strcmp(k
[i
], "origin") == 0)
458 int x
= 0, y
= 0, z
= 0;
460 sscanf(v
[i
], "%d %d %d", &x
, &y
, &z
);
462 cp
->p
[0] = +(double) x
/ SCALE
;
463 cp
->p
[1] = +(double) z
/ SCALE
;
464 cp
->p
[2] = -(double) y
/ SCALE
;
469 static void make_ball(struct s_file
*fp
,
471 char v
[][MAXSTR
], int c
)
473 int i
, ui
= fp
->uc
++;
475 struct s_ball
*up
= fp
->uv
+ ui
;
499 for (i
= 0; i
< c
; i
++)
501 if (strcmp(k
[i
], "radius") == 0)
502 sscanf(v
[i
], "%lf", &up
->r
);
504 if (!strcmp(k
[i
], "target"))
505 make_ref(v
[i
], &path_0
);
507 if (strcmp(k
[i
], "origin") == 0)
509 int x
= 0, y
= 0, z
= 0;
511 sscanf(v
[i
], "%d %d %d", &x
, &y
, &z
);
513 up
->p
[0] = +(double) (x
) / SCALE
;
514 up
->p
[1] = +(double) (z
- 24) / SCALE
;
515 up
->p
[2] = -(double) (y
) / SCALE
;
519 up
->p
[1] += up
->r
+ SMALL
;
522 /*---------------------------------------------------------------------------*/
524 static void read_ent(struct s_file
*fp
, FILE *fin
)
526 char k
[MAXKEY
][MAXSTR
];
527 char v
[MAXKEY
][MAXSTR
];
532 while ((t
= map_token(fin
, -1, k
[c
], v
[c
])))
536 if (strcmp(k
[c
], "classname") == 0)
546 if (!strcmp(v
[i
], "light")) make_coin(fp
, k
, v
, c
);
547 if (!strcmp(v
[i
], "path_corner")) make_path(fp
, k
, v
, c
);
548 if (!strcmp(v
[i
], "info_player_start")) make_ball(fp
, k
, v
, c
);
550 if (!strcmp(v
[i
], "worldspawn")) make_body(fp
, k
, v
, c
, l0
);
551 if (!strcmp(v
[i
], "func_train")) make_body(fp
, k
, v
, c
, l0
);
554 static void read_map(struct s_file
*fp
, FILE *fin
)
560 while ((t
= map_token(fin
, -1, k
, v
)))
565 /*---------------------------------------------------------------------------*/
568 * All bodies with an associated path are assumed to be positioned at the
569 * beginning of that path. These bodies must be moved to the origin in order
570 * for their path transforms to behave correctly. This is how we get away
571 * with defining func_trains with no origin specification.
574 static void move_side(struct s_side
*sp
, const double p
[3])
576 sp
->d
-= v_dot(sp
->n
, p
);
579 static void move_lump(struct s_file
*fp
,
580 struct s_lump
*lp
, const double p
[3])
584 for (i
= 0; i
< lp
->sc
; i
++)
585 move_side(fp
->sv
+ fp
->iv
[lp
->s0
+ i
], p
);
588 static void move_body(struct s_file
*fp
,
593 for (i
= 0; i
< bp
->lc
; i
++)
594 move_lump(fp
, fp
->lv
+ bp
->l0
+ i
, fp
->pv
[bp
->pi
].p
);
597 static void move_file(struct s_file
*fp
)
601 for (i
= 0; i
< fp
->bc
; i
++)
602 if (fp
->bv
[i
].pi
>= 0)
603 move_body(fp
, fp
->bv
+ i
);
606 /*---------------------------------------------------------------------------*/
608 /* Test the location of a point with respect to a side plane. */
610 static int fore_side(const double p
[3], const struct s_side
*sp
)
612 return (v_dot(p
, sp
->n
) - sp
->d
> +SMALL
) ? 1 : 0;
615 static int on_side(const double p
[3], const struct s_side
*sp
)
617 double d
= v_dot(p
, sp
->n
) - sp
->d
;
619 return (-SMALL
< d
&& d
< +SMALL
) ? 1 : 0;
622 /*---------------------------------------------------------------------------*/
624 * Confirm that the addition of a vert would not result in degenerate
628 static int ok_vert(const struct s_file
*fp
,
629 const struct s_lump
*lp
, const double p
[3])
634 for (i
= 0; i
< lp
->vc
; i
++)
636 double *q
= fp
->vv
[fp
->iv
[lp
->v0
+ i
]].p
;
640 if (v_len(r
) < SMALL
)
646 /*---------------------------------------------------------------------------*/
649 * The following functions take the set of planes defining a lump and find
650 * the verts, edges, and geoms that describe its boundaries. To do this,
651 * they first find the verts, and then search these verts for valid edges and
652 * geoms. It may be more efficient to compute edges and geoms directly by
653 * clipping down infinite line segments and planes, but this would be more
654 * complex and prone to numerical error.
658 * Given 3 side planes, compute the point of intersection, if any. Confirm
659 * that this point falls within the current lump, and that it is unique. Add
660 * it as a vert of the solid.
662 static void clip_vert(struct s_file
*fp
,
663 struct s_lump
*lp
, int si
, int sj
, int sk
)
665 double M
[16], X
[16], I
[16];
673 m_basis(M
, fp
->sv
[si
].n
, fp
->sv
[sj
].n
, fp
->sv
[sk
].n
);
680 for (i
= 0; i
< lp
->sc
; i
++)
682 int si
= fp
->iv
[lp
->s0
+ i
];
684 if (fore_side(p
, fp
->sv
+ si
))
688 if (ok_vert(fp
, lp
, p
))
690 v_cpy(fp
->vv
[fp
->vc
].p
, p
);
692 fp
->iv
[fp
->ic
] = fp
->vc
;
701 * Given two side planes, find an edge along their intersection by finding a
702 * pair of vertices that fall on both planes. Add it to the solid.
704 static void clip_edge(struct s_file
*fp
,
705 struct s_lump
*lp
, int si
, int sj
)
709 for (i
= 1; i
< lp
->vc
; i
++)
710 for (j
= 0; j
< i
; j
++)
712 int vi
= fp
->iv
[lp
->v0
+ i
];
713 int vj
= fp
->iv
[lp
->v0
+ j
];
715 if (on_side(fp
->vv
[vi
].p
, fp
->sv
+ si
) &&
716 on_side(fp
->vv
[vj
].p
, fp
->sv
+ si
) &&
717 on_side(fp
->vv
[vi
].p
, fp
->sv
+ sj
) &&
718 on_side(fp
->vv
[vj
].p
, fp
->sv
+ sj
))
720 fp
->ev
[fp
->ec
].vi
= vi
;
721 fp
->ev
[fp
->ec
].vj
= vj
;
723 fp
->iv
[fp
->ic
] = fp
->ec
;
733 * Find all verts that lie on the given side of the lump. Sort these verts
734 * to have a counter-clockwise winding about the plane normal. Create geoms
735 * to tessalate the resulting convex polygon.
737 static void clip_geom(struct s_file
*fp
,
738 struct s_lump
*lp
, int si
)
740 int m
[16], t
[16], d
, i
, j
, n
= 0;
745 struct s_side
*sp
= fp
->sv
+ si
;
749 for (i
= 0; i
< lp
->vc
; i
++)
751 int vi
= fp
->iv
[lp
->v0
+ i
];
753 if (on_side(fp
->vv
[vi
].p
, sp
))
758 v_add(v
, fp
->vv
[vi
].p
, plane_p
[si
]);
760 fp
->tv
[t
[n
]].u
[0] = v_dot(v
, plane_u
[si
]);
761 fp
->tv
[t
[n
]].u
[1] = v_dot(v
, plane_v
[si
]);
769 for (i
= 1; i
< n
; i
++)
770 for (j
= i
+ 1; j
< n
; j
++)
772 v_sub(u
, fp
->vv
[m
[i
]].p
, fp
->vv
[m
[0]].p
);
773 v_sub(v
, fp
->vv
[m
[j
]].p
, fp
->vv
[m
[0]].p
);
776 if (v_dot(w
, sp
->n
) < 0.0)
790 for (i
= 0; i
< n
- 2; i
++)
792 fp
->gv
[fp
->gc
].si
= si
;
793 fp
->gv
[fp
->gc
].mi
= si
;
795 fp
->gv
[fp
->gc
].ti
= t
[0];
796 fp
->gv
[fp
->gc
].tj
= t
[i
+ 1];
797 fp
->gv
[fp
->gc
].tk
= t
[i
+ 2];
799 fp
->gv
[fp
->gc
].vi
= m
[0];
800 fp
->gv
[fp
->gc
].vj
= m
[i
+ 1];
801 fp
->gv
[fp
->gc
].vk
= m
[i
+ 2];
803 fp
->iv
[fp
->ic
] = fp
->gc
;
811 * Iterate the sides of the lump, attemping to generate a new vert for each
812 * trio of planes, a new edge for each pair of planes, and a new set of geom
813 * for each visible plane.
815 static void clip_lump(struct s_file
*fp
, struct s_lump
*lp
)
822 for (i
= 2; i
< lp
->sc
; i
++)
823 for (j
= 1; j
< i
; j
++)
824 for (k
= 0; k
< j
; k
++)
833 for (i
= 1; i
< lp
->sc
; i
++)
834 for (j
= 0; j
< i
; j
++)
842 for (i
= 0; i
< lp
->sc
; i
++)
843 if (fp
->mv
[fp
->iv
[lp
->s0
+ i
]].d
[3] > 0)
847 for (i
= 0; i
< lp
->sc
; i
++)
848 lp
->fl
|= (plane_f
[fp
->iv
[lp
->s0
+ i
]] ? 1 : 0);
851 static void clip_file(struct s_file
*fp
)
855 for (i
= 0; i
< fp
->lc
; i
++)
856 clip_lump(fp
, fp
->lv
+ i
);
859 /*---------------------------------------------------------------------------*/
862 * For each body element type, determine if element 'p' is equivalent to
863 * element 'q'. This is more than a simple memory compare. It effectively
864 * snaps mtrls and verts togather, and may reverse the winding of an edge or
865 * a geom. This is done in order to maximize the number of elements that can
869 static int comp_mtrl(const struct s_mtrl
*mp
, const struct s_mtrl
*mq
)
871 if (fabs(mp
->d
[0] - mq
->d
[0]) > SMALL
) return 0;
872 if (fabs(mp
->d
[1] - mq
->d
[1]) > SMALL
) return 0;
873 if (fabs(mp
->d
[2] - mq
->d
[2]) > SMALL
) return 0;
874 if (fabs(mp
->d
[3] - mq
->d
[3]) > SMALL
) return 0;
876 if (fabs(mp
->a
[0] - mq
->a
[0]) > SMALL
) return 0;
877 if (fabs(mp
->a
[1] - mq
->a
[1]) > SMALL
) return 0;
878 if (fabs(mp
->a
[2] - mq
->a
[2]) > SMALL
) return 0;
879 if (fabs(mp
->a
[3] - mq
->a
[3]) > SMALL
) return 0;
881 if (fabs(mp
->s
[0] - mq
->s
[0]) > SMALL
) return 0;
882 if (fabs(mp
->s
[1] - mq
->s
[1]) > SMALL
) return 0;
883 if (fabs(mp
->s
[2] - mq
->s
[2]) > SMALL
) return 0;
884 if (fabs(mp
->s
[3] - mq
->s
[3]) > SMALL
) return 0;
886 if (fabs(mp
->e
[0] - mq
->e
[0]) > SMALL
) return 0;
887 if (fabs(mp
->e
[1] - mq
->e
[1]) > SMALL
) return 0;
888 if (fabs(mp
->e
[2] - mq
->e
[2]) > SMALL
) return 0;
889 if (fabs(mp
->e
[3] - mq
->e
[3]) > SMALL
) return 0;
891 if (fabs(mp
->h
[0] - mq
->h
[0]) > SMALL
) return 0;
893 if (strcmp(mp
->f
, mq
->f
)) return 0;
898 static int comp_vert(const struct s_vert
*vp
, const struct s_vert
*vq
)
900 if (fabs(vp
->p
[0] - vq
->p
[0]) > SMALL
) return 0;
901 if (fabs(vp
->p
[1] - vq
->p
[1]) > SMALL
) return 0;
902 if (fabs(vp
->p
[2] - vq
->p
[2]) > SMALL
) return 0;
907 static int comp_edge(const struct s_edge
*ep
, const struct s_edge
*eq
)
909 if (ep
->vi
!= eq
->vi
&& ep
->vi
!= eq
->vj
) return 0;
910 if (ep
->vj
!= eq
->vi
&& ep
->vj
!= eq
->vj
) return 0;
915 static int comp_side(const struct s_side
*sp
, const struct s_side
*sq
)
917 if (fabs(sp
->d
- sq
->d
) > SMALL
) return 0;
918 if (v_dot(sp
->n
, sq
->n
) < 1.0 - SMALL
) return 0;
923 static int comp_texc(const struct s_texc
*tp
, const struct s_texc
*tq
)
925 if (fabs(tp
->u
[0] - tq
->u
[0]) > SMALL
) return 0;
926 if (fabs(tp
->u
[1] - tq
->u
[1]) > SMALL
) return 0;
931 static int comp_geom(const struct s_geom
*gp
, const struct s_geom
*gq
)
933 if (gp
->si
!= gq
->si
) return 0;
934 if (gp
->mi
!= gq
->mi
) return 0;
941 /*---------------------------------------------------------------------------*/
944 * For each file element type, replace all references to element 'i' with a
945 * reference to element 'j'. These are used when optimizing and sorting the
949 static void swap_mtrl(struct s_file
*fp
, int mi
, int mj
)
953 for (i
= 0; i
< fp
->gc
; i
++)
954 if (fp
->gv
[i
].mi
== mi
) fp
->gv
[i
].mi
= mj
;
957 static void swap_vert(struct s_file
*fp
, int vi
, int vj
)
961 for (i
= 0; i
< fp
->ec
; i
++)
963 if (fp
->ev
[i
].vi
== vi
) fp
->ev
[i
].vi
= vj
;
964 if (fp
->ev
[i
].vj
== vi
) fp
->ev
[i
].vj
= vj
;
967 for (i
= 0; i
< fp
->gc
; i
++)
969 if (fp
->gv
[i
].vi
== vi
) fp
->gv
[i
].vi
= vj
;
970 if (fp
->gv
[i
].vj
== vi
) fp
->gv
[i
].vj
= vj
;
971 if (fp
->gv
[i
].vk
== vi
) fp
->gv
[i
].vk
= vj
;
974 for (i
= 0; i
< fp
->lc
; i
++)
975 for (j
= 0; j
< fp
->lv
[i
].vc
; j
++)
976 if (fp
->iv
[fp
->lv
[i
].v0
+ j
] == vi
)
977 fp
->iv
[fp
->lv
[i
].v0
+ j
] = vj
;
980 static void swap_edge(struct s_file
*fp
, int ei
, int ej
)
984 for (i
= 0; i
< fp
->lc
; i
++)
985 for (j
= 0; j
< fp
->lv
[i
].ec
; j
++)
986 if (fp
->iv
[fp
->lv
[i
].e0
+ j
] == ei
)
987 fp
->iv
[fp
->lv
[i
].e0
+ j
] = ej
;
990 static void swap_side(struct s_file
*fp
, int si
, int sj
)
994 for (i
= 0; i
< fp
->gc
; i
++)
995 if (fp
->gv
[i
].si
== si
) fp
->gv
[i
].si
= sj
;
996 for (i
= 0; i
< fp
->nc
; i
++)
997 if (fp
->nv
[i
].si
== si
) fp
->nv
[i
].si
= sj
;
999 for (i
= 0; i
< fp
->lc
; i
++)
1000 for (j
= 0; j
< fp
->lv
[i
].sc
; j
++)
1001 if (fp
->iv
[fp
->lv
[i
].s0
+ j
] == si
)
1002 fp
->iv
[fp
->lv
[i
].s0
+ j
] = sj
;
1005 static void swap_texc(struct s_file
*fp
, int ti
, int tj
)
1009 for (i
= 0; i
< fp
->gc
; i
++)
1011 if (fp
->gv
[i
].ti
== ti
) fp
->gv
[i
].ti
= tj
;
1012 if (fp
->gv
[i
].tj
== ti
) fp
->gv
[i
].tj
= tj
;
1013 if (fp
->gv
[i
].tk
== ti
) fp
->gv
[i
].tk
= tj
;
1017 static void swap_geom(struct s_file
*fp
, int gi
, int gj
)
1021 for (i
= 0; i
< fp
->lc
; i
++)
1022 for (j
= 0; j
< fp
->lv
[i
].gc
; j
++)
1023 if (fp
->iv
[fp
->lv
[i
].g0
+ j
] == gi
)
1024 fp
->iv
[fp
->lv
[i
].g0
+ j
] = gj
;
1027 static void swap_path(struct s_file
*fp
, int pi
, int pj
)
1031 for (i
= 0; i
< fp
->pc
; i
++)
1032 if (fp
->pv
[i
].pi
== pi
) fp
->pv
[i
].pi
= pj
;
1034 for (i
= 0; i
< fp
->bc
; i
++)
1035 if (fp
->bv
[i
].pi
== pi
) fp
->bv
[i
].pi
= pj
;
1038 /*---------------------------------------------------------------------------*/
1040 static void uniq_mtrl(struct s_file
*fp
)
1044 for (i
= 0; i
< fp
->mc
; i
++)
1046 for (j
= 0; j
< i
; j
++)
1047 if (comp_mtrl(fp
->mv
+ i
, fp
->mv
+ j
))
1049 swap_mtrl(fp
, i
, j
);
1055 fp
->mv
[k
] = fp
->mv
[i
];
1056 swap_mtrl(fp
, i
, k
);
1064 static void uniq_vert(struct s_file
*fp
)
1068 for (i
= 0; i
< fp
->vc
; i
++)
1070 for (j
= 0; j
< i
; j
++)
1071 if (comp_vert(fp
->vv
+ i
, fp
->vv
+ j
))
1073 swap_vert(fp
, i
, j
);
1079 fp
->vv
[k
] = fp
->vv
[i
];
1080 swap_vert(fp
, i
, k
);
1088 static void uniq_edge(struct s_file
*fp
)
1092 for (i
= 0; i
< fp
->ec
; i
++)
1094 for (j
= 0; j
< i
; j
++)
1095 if (comp_edge(fp
->ev
+ i
, fp
->ev
+ j
))
1097 swap_edge(fp
, i
, j
);
1103 fp
->ev
[k
] = fp
->ev
[i
];
1104 swap_edge(fp
, i
, k
);
1112 static void uniq_geom(struct s_file
*fp
)
1116 for (i
= 0; i
< fp
->gc
; i
++)
1118 for (j
= 0; j
< i
; j
++)
1119 if (comp_geom(fp
->gv
+ i
, fp
->gv
+ j
))
1121 swap_geom(fp
, i
, j
);
1127 fp
->gv
[k
] = fp
->gv
[i
];
1128 swap_geom(fp
, i
, k
);
1136 static void uniq_texc(struct s_file
*fp
)
1140 for (i
= 0; i
< fp
->tc
; i
++)
1142 for (j
= 0; j
< i
; j
++)
1143 if (comp_texc(fp
->tv
+ i
, fp
->tv
+ j
))
1145 swap_texc(fp
, i
, j
);
1150 fp
->tv
[k
] = fp
->tv
[i
];
1151 swap_texc(fp
, i
, k
);
1159 static void uniq_side(struct s_file
*fp
)
1163 for (i
= 0; i
< fp
->sc
; i
++)
1165 for (j
= 0; j
< i
; j
++)
1166 if (comp_side(fp
->sv
+ i
, fp
->sv
+ j
))
1168 swap_side(fp
, i
, j
);
1173 fp
->sv
[k
] = fp
->sv
[i
];
1174 swap_side(fp
, i
, k
);
1182 static void uniq_file(struct s_file
*fp
)
1192 /*---------------------------------------------------------------------------*/
1194 static void sort_file(struct s_file
*fp
)
1203 * Sort the geoms in order of material index. This was originally an
1204 * important state transition reduction hack, but is now merely cute.
1206 for (i
= 1; i
< fp
->gc
; i
++)
1207 for (j
= 0; j
< i
; j
++)
1208 if (fp
->gv
[i
].mi
> fp
->gv
[j
].mi
)
1211 fp
->gv
[i
] = fp
->gv
[j
];
1214 swap_geom(fp
, i
, -1);
1215 swap_geom(fp
, j
, i
);
1216 swap_geom(fp
, -1, j
);
1220 * Sort the sides so that the most "floorish" side is 0. Then any geoms
1221 * referring to side 0 may be given special treatment as "floor" geoms.
1223 for (j
= 1; j
< fp
->sc
; j
++)
1224 if (fp
->sv
[j
].n
[1] >= fp
->sv
[0].n
[1] &&
1225 fabs(fp
->sv
[j
].d
) <= fabs(fp
->sv
[0].d
))
1228 fp
->sv
[0] = fp
->sv
[j
];
1231 swap_side(fp
, 0, -1);
1232 swap_side(fp
, j
, 0);
1233 swap_side(fp
, -1, j
);
1237 * If path_0 is not -1, ensure that the path it refers to is 0.
1239 if (path_0
> 0 && fp
->pc
> 0)
1244 fp
->pv
[0] = fp
->pv
[j
];
1247 swap_path(fp
, 0, -2);
1248 swap_path(fp
, j
, 0);
1249 swap_path(fp
, -2, j
);
1253 /*---------------------------------------------------------------------------*/
1255 static void dump_head(void)
1257 printf(" mtrl vert edge side texc geom lump"
1258 " node path body coin ball indx\n");
1261 static void dump_file(struct s_file
*fp
)
1263 printf("%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
1264 fp
->mc
, fp
->vc
, fp
->ec
, fp
->sc
, fp
->tc
, fp
->gc
, fp
->lc
,
1265 fp
->nc
, fp
->pc
, fp
->bc
, fp
->cc
, fp
->uc
, fp
->ic
);
1268 int main(int argc
, char *argv
[])
1275 if ((fin
= fopen(argv
[1], "r")))
1290 sol_stor(&f
, argv
[2]);