2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your 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.
15 /*---------------------------------------------------------------------------*/
18 #pragma comment(lib, "SDL_image.lib")
19 #pragma comment(lib, "SDL_mixer.lib")
20 #pragma comment(lib, "SDL.lib")
21 #pragma comment(lib, "SDLmain.lib")
22 #pragma comment(lib, "glu32.lib")
23 #pragma comment(lib, "opengl32.lib")
26 /*---------------------------------------------------------------------------*/
29 #include <SDL_image.h>
46 * The overall design of this map converter is very stupid, but very
47 * simple. It begins by assuming that every mtrl, vert, edge, side,
48 * and texc in the map is unique. It then makes an optimizing pass
49 * that discards redundant information. The result is optimal, though
50 * the process is terribly inefficient.
53 /*---------------------------------------------------------------------------*/
55 /* Ohhhh... arbitrary! */
77 static void init_file(struct s_file
*fp
)
99 fp
->mv
= (struct s_mtrl
*) calloc(MAXM
, sizeof (struct s_mtrl
));
100 fp
->vv
= (struct s_vert
*) calloc(MAXV
, sizeof (struct s_vert
));
101 fp
->ev
= (struct s_edge
*) calloc(MAXE
, sizeof (struct s_edge
));
102 fp
->sv
= (struct s_side
*) calloc(MAXS
, sizeof (struct s_side
));
103 fp
->tv
= (struct s_texc
*) calloc(MAXT
, sizeof (struct s_texc
));
104 fp
->gv
= (struct s_geom
*) calloc(MAXG
, sizeof (struct s_geom
));
105 fp
->lv
= (struct s_lump
*) calloc(MAXL
, sizeof (struct s_lump
));
106 fp
->nv
= (struct s_node
*) calloc(MAXN
, sizeof (struct s_node
));
107 fp
->pv
= (struct s_path
*) calloc(MAXP
, sizeof (struct s_path
));
108 fp
->bv
= (struct s_body
*) calloc(MAXB
, sizeof (struct s_body
));
109 fp
->cv
= (struct s_coin
*) calloc(MAXC
, sizeof (struct s_coin
));
110 fp
->zv
= (struct s_goal
*) calloc(MAXZ
, sizeof (struct s_goal
));
111 fp
->jv
= (struct s_jump
*) calloc(MAXJ
, sizeof (struct s_jump
));
112 fp
->xv
= (struct s_swch
*) calloc(MAXX
, sizeof (struct s_swch
));
113 fp
->rv
= (struct s_bill
*) calloc(MAXR
, sizeof (struct s_bill
));
114 fp
->uv
= (struct s_ball
*) calloc(MAXU
, sizeof (struct s_ball
));
115 fp
->wv
= (struct s_view
*) calloc(MAXW
, sizeof (struct s_view
));
116 fp
->av
= (char *) calloc(MAXA
, sizeof (char));
117 fp
->iv
= (short *) calloc(MAXI
, sizeof (short));
120 /*---------------------------------------------------------------------------*/
123 * The following is a small symbol table data structure. Symbols and
124 * their integer values are collected in symv and valv. References
125 * and pointers to their unsatisfied integer values are collected in
126 * refv and pntv. The resolve procedure matches references to symbols
127 * and fills waiting ints with the proper values.
132 static char symv
[MAXSYM
][MAXSTR
];
133 static short valv
[MAXSYM
];
135 static char refv
[MAXSYM
][MAXSTR
];
136 static short *pntv
[MAXSYM
];
141 static void make_sym(const char *s
, short v
)
143 strncpy(symv
[strc
], s
, MAXSTR
- 1);
148 static void make_ref(const char *r
, short *p
)
150 strncpy(refv
[refc
], r
, MAXSTR
- 1);
155 static void resolve(void)
159 for (i
= 0; i
< refc
; i
++)
160 for (j
= 0; j
< strc
; j
++)
161 if (strncmp(refv
[i
], symv
[j
], MAXSTR
) == 0)
163 *(pntv
[i
]) = valv
[j
];
168 /*---------------------------------------------------------------------------*/
171 * The following globals are used to cache target_positions. They are
172 * targeted by various entities and must be resolved in a second pass.
175 static float targ_p
[MAXW
][3];
176 static short targ_wi
[MAXW
];
177 static short targ_ji
[MAXW
];
180 static void targets(struct s_file
*fp
)
184 for (i
= 0; i
< fp
->wc
; i
++)
185 v_cpy(fp
->wv
[i
].q
, targ_p
[targ_wi
[i
]]);
187 for (i
= 0; i
< fp
->jc
; i
++)
188 v_cpy(fp
->jv
[i
].q
, targ_p
[targ_ji
[i
]]);
191 /*---------------------------------------------------------------------------*/
194 * The following code caches image sizes. Textures are referenced by
195 * name, but their sizes are necessary when computing texture
196 * coordinates. This code allows each file to be accessed only once
197 * regardless of the number of surfaces refering to it.
200 static char *image_s
[MAXM
];
201 static int image_w
[MAXM
];
202 static int image_h
[MAXM
];
205 static int size_load(const char *file
, int *w
, int *h
)
209 if ((S
= IMG_Load(file
)))
221 static void size_image(const char *name
, int *w
, int *h
)
228 for (i
= 0; i
< image_n
; i
++)
229 if (strncmp(image_s
[i
], name
, MAXSTR
) == 0)
240 strcpy(jpg
, name
); strcat(jpg
, ".jpg");
241 strcpy(tga
, name
); strcat(tga
, ".tga");
242 strcpy(png
, name
); strcat(png
, ".png");
244 if (size_load(config_data(png
), w
, h
) ||
245 size_load(config_data(tga
), w
, h
) ||
246 size_load(config_data(jpg
), w
, h
))
248 image_s
[image_n
] = (char *) calloc(strlen(name
) + 1, 1);
249 image_w
[image_n
] = *w
;
250 image_h
[image_n
] = *h
;
252 strcpy(image_s
[image_n
], name
);
257 /*---------------------------------------------------------------------------*/
259 /* Read the given material file, adding a new material to the solid. */
261 static int read_mtrl(struct s_file
*fp
, const char *name
)
267 for (mi
= 0; mi
< fp
->mc
; mi
++)
268 if (strncmp(name
, fp
->mv
[mi
].f
, MAXSTR
) == 0)
271 mp
= fp
->mv
+ fp
->mc
++;
273 strncpy(mp
->f
, name
, PATHMAX
- 1);
275 mp
->a
[0] = mp
->a
[1] = mp
->a
[2] = mp
->a
[3] = 1.0f
;
276 mp
->d
[0] = mp
->d
[1] = mp
->d
[2] = mp
->d
[3] = 1.0f
;
277 mp
->s
[0] = mp
->s
[1] = mp
->s
[2] = mp
->s
[3] = 1.0f
;
278 mp
->e
[0] = mp
->e
[1] = mp
->e
[2] = mp
->e
[3] = 1.0f
;
282 if ((fin
= fopen(config_data(name
), "r")))
290 mp
->d
, mp
->d
+ 1, mp
->d
+ 2, mp
->d
+ 3,
291 mp
->a
, mp
->a
+ 1, mp
->a
+ 2, mp
->a
+ 3,
292 mp
->s
, mp
->s
+ 1, mp
->s
+ 2, mp
->s
+ 3,
293 mp
->e
, mp
->e
+ 1, mp
->e
+ 2, mp
->e
+ 3,
301 /*---------------------------------------------------------------------------*/
304 * All bodies with an associated path are assumed to be positioned at
305 * the beginning of that path. These bodies must be moved to the
306 * origin in order for their path transforms to behave correctly.
307 * This is how we get away with defining func_trains with no origin
311 static void move_side(struct s_side
*sp
, const float p
[3])
313 sp
->d
-= v_dot(sp
->n
, p
);
316 static void move_vert(struct s_vert
*vp
, const float p
[3])
318 v_sub(vp
->p
, vp
->p
, p
);
321 static void move_lump(struct s_file
*fp
,
322 struct s_lump
*lp
, const float p
[3])
326 for (i
= 0; i
< lp
->sc
; i
++)
327 move_side(fp
->sv
+ fp
->iv
[lp
->s0
+ i
], p
);
328 for (i
= 0; i
< lp
->vc
; i
++)
329 move_vert(fp
->vv
+ fp
->iv
[lp
->v0
+ i
], p
);
332 static void move_body(struct s_file
*fp
,
337 for (i
= 0; i
< bp
->lc
; i
++)
338 move_lump(fp
, fp
->lv
+ bp
->l0
+ i
, fp
->pv
[bp
->pi
].p
);
341 static void move_file(struct s_file
*fp
)
345 for (i
= 0; i
< fp
->bc
; i
++)
346 if (fp
->bv
[i
].pi
>= 0)
347 move_body(fp
, fp
->bv
+ i
);
350 /*---------------------------------------------------------------------------*/
352 static void read_vt(struct s_file
*fp
, const char *line
)
354 struct s_texc
*tp
= fp
->tv
+ fp
->tc
++;
356 sscanf(line
, "%f %f", tp
->u
, tp
->u
+ 1);
359 static void read_vn(struct s_file
*fp
, const char *line
)
361 struct s_side
*sp
= fp
->sv
+ fp
->sc
++;
363 sscanf(line
, "%f %f %f", sp
->n
, sp
->n
+ 1, sp
->n
+ 2);
366 static void read_v(struct s_file
*fp
, const char *line
)
368 struct s_vert
*vp
= fp
->vv
+ fp
->vc
++;
370 sscanf(line
, "%f %f %f", vp
->p
, vp
->p
+ 1, vp
->p
+ 2);
373 static void read_f(struct s_file
*fp
, const char *line
,
374 short v0
, short t0
, short s0
, short mi
)
376 struct s_geom
*gp
= fp
->gv
+ fp
->gc
++;
382 * FIXME: All faces must be triangles and must include a normal
383 * and texture coordinate.
386 sscanf(line
, "%hd%c%hd%c%hd %hd%c%hd%c%hd %hd%c%hd%c%hd",
387 &gp
->vi
, &c1
, &gp
->ti
, &c2
, &gp
->si
,
388 &gp
->vj
, &c1
, &gp
->tj
, &c2
, &gp
->sj
,
389 &gp
->vk
, &c1
, &gp
->tk
, &c2
, &gp
->sk
);
404 static void read_obj(struct s_file
*fp
, const char *name
)
415 if ((fin
= fopen(config_data(name
), "r")))
417 while (fgets(line
, MAXSTR
, fin
))
419 if (strncmp(line
, "usemtl", 6) == 0)
421 sscanf(line
+ 6, "%s", mtrl
);
422 mi
= read_mtrl(fp
, mtrl
);
425 else if (strncmp(line
, "f", 1) == 0)
427 if (fp
->mv
[mi
].d
[3] > 0)
428 read_f(fp
, line
+ 1, v0
, t0
, s0
, mi
);
431 else if (strncmp(line
, "vt", 2) == 0) read_vt(fp
, line
+ 2);
432 else if (strncmp(line
, "vn", 2) == 0) read_vn(fp
, line
+ 2);
433 else if (strncmp(line
, "v", 1) == 0) read_v (fp
, line
+ 1);
439 /*---------------------------------------------------------------------------*/
441 static float plane_d
[MAXS
];
442 static float plane_n
[MAXS
][3];
443 static float plane_p
[MAXS
][3];
444 static float plane_u
[MAXS
][3];
445 static float plane_v
[MAXS
][3];
446 static short plane_f
[MAXS
];
447 static short plane_m
[MAXS
];
449 static void make_plane(short pi
, short x0
, short y0
, short z0
,
450 short x1
, short y1
, short z1
,
451 short x2
, short y2
, short z2
,
452 short tu
, short tv
, short r
,
453 float su
, float sv
, int fl
, const char *s
)
455 static const float base
[6][3][3] = {
456 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
457 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
458 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
459 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
460 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
461 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
465 float p0
[3], p1
[3], p2
[3];
466 float u
[3], v
[3], p
[3];
471 size_image(s
, &w
, &h
);
473 plane_f
[pi
] = fl
? L_DETAIL
: 0;
475 p0
[0] = +(float) x0
/ SCALE
;
476 p0
[1] = +(float) z0
/ SCALE
;
477 p0
[2] = -(float) y0
/ SCALE
;
479 p1
[0] = +(float) x1
/ SCALE
;
480 p1
[1] = +(float) z1
/ SCALE
;
481 p1
[2] = -(float) y1
/ SCALE
;
483 p2
[0] = +(float) x2
/ SCALE
;
484 p2
[1] = +(float) z2
/ SCALE
;
485 p2
[2] = -(float) y2
/ SCALE
;
490 v_crs(plane_n
[pi
], u
, v
);
491 v_nrm(plane_n
[pi
], plane_n
[pi
]);
493 plane_d
[pi
] = v_dot(plane_n
[pi
], p1
);
495 for (i
= 0; i
< 6; i
++)
496 if ((k
= v_dot(plane_n
[pi
], base
[i
][0])) >= d
)
506 m_rot(R
, base
[n
][0], V_RAD(r
));
508 v_mad(p
, p
, base
[n
][1], su
* tu
/ SCALE
);
509 v_mad(p
, p
, base
[n
][2], sv
* tv
/ SCALE
);
511 m_vxfm(plane_u
[pi
], R
, base
[n
][1]);
512 m_vxfm(plane_v
[pi
], R
, base
[n
][2]);
513 m_vxfm(plane_p
[pi
], R
, p
);
515 v_scl(plane_u
[pi
], plane_u
[pi
], 64.f
/ w
);
516 v_scl(plane_v
[pi
], plane_v
[pi
], 64.f
/ h
);
518 v_scl(plane_u
[pi
], plane_u
[pi
], 1.f
/ su
);
519 v_scl(plane_v
[pi
], plane_v
[pi
], 1.f
/ sv
);
522 /*---------------------------------------------------------------------------*/
531 static int map_token(FILE *fin
, short pi
, char key
[MAXSTR
], char val
[MAXSTR
])
535 if (fgets(buf
, MAXSTR
, fin
))
545 /* Scan the beginning or end of a block. */
547 if (buf
[0] == '{') return T_BEG
;
548 if (buf
[0] == '}') return T_END
;
550 /* Scan a key-value pair. */
554 strcpy(key
, strtok(buf
, "\""));
555 (void) strtok(NULL
, "\"");
556 strcpy(val
, strtok(NULL
, "\""));
567 "%s %hd %hd %hd %f %f %d",
568 &c
, &x0
, &y0
, &z0
, &c
,
569 &c
, &x1
, &y1
, &z1
, &c
,
570 &c
, &x2
, &y2
, &z2
, &c
,
571 key
, &tu
, &tv
, &r
, &su
, &sv
, &fl
) == 22)
573 make_plane(pi
, x0
, y0
, z0
,
576 tu
, tv
, r
, su
, sv
, fl
, key
);
580 /* If it's not recognized, it must be uninteresting. */
587 /*---------------------------------------------------------------------------*/
589 /* Parse a lump from the given file and add it to the solid. */
591 static void read_lump(struct s_file
*fp
, FILE *fin
)
597 struct s_lump
*lp
= fp
->lv
+ fp
->lc
++;
601 while ((t
= map_token(fin
, fp
->sc
, k
, v
)))
605 fp
->sv
[fp
->sc
].n
[0] = plane_n
[fp
->sc
][0];
606 fp
->sv
[fp
->sc
].n
[1] = plane_n
[fp
->sc
][1];
607 fp
->sv
[fp
->sc
].n
[2] = plane_n
[fp
->sc
][2];
608 fp
->sv
[fp
->sc
].d
= plane_d
[fp
->sc
];
610 plane_m
[fp
->sc
] = read_mtrl(fp
, k
);
612 fp
->iv
[fp
->ic
] = fp
->sc
;
622 /*---------------------------------------------------------------------------*/
624 static void make_path(struct s_file
*fp
,
626 char v
[][MAXSTR
], short c
)
628 short i
, pi
= fp
->pc
++;
630 struct s_path
*pp
= fp
->pv
+ pi
;
639 for (i
= 0; i
< c
; i
++)
641 if (strcmp(k
[i
], "targetname") == 0)
644 if (strcmp(k
[i
], "target") == 0)
645 make_ref(v
[i
], &pp
->pi
);
647 if (strcmp(k
[i
], "state") == 0)
650 if (strcmp(k
[i
], "speed") == 0)
651 sscanf(v
[i
], "%f", &pp
->t
);
653 if (strcmp(k
[i
], "origin") == 0)
655 short x
= 0, y
= 0, z
= 0;
657 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
659 pp
->p
[0] = +(float) x
/ SCALE
;
660 pp
->p
[1] = +(float) z
/ SCALE
;
661 pp
->p
[2] = -(float) y
/ SCALE
;
666 static void make_body(struct s_file
*fp
,
668 char v
[][MAXSTR
], short c
, short l0
)
670 short i
, bi
= fp
->bc
++;
681 struct s_body
*bp
= fp
->bv
+ bi
;
687 for (i
= 0; i
< c
; i
++)
689 if (strcmp(k
[i
], "targetname") == 0)
692 if (strcmp(k
[i
], "target") == 0)
693 make_ref(v
[i
], &bp
->pi
);
695 if (strcmp(k
[i
], "model") == 0)
698 if (strcmp(k
[i
], "origin") == 0)
699 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
701 if (strcmp(k
[i
], "message") == 0)
703 strcpy(fp
->av
, v
[i
]);
704 fp
->ac
= (short) (strlen(v
[i
]) + 1);
709 bp
->lc
= fp
->lc
- l0
;
711 bp
->gc
= fp
->gc
- g0
;
713 for (i
= 0; i
< bp
->gc
; i
++)
714 fp
->iv
[fp
->ic
++] = g0
++;
716 p
[0] = +(float) x
/ SCALE
;
717 p
[1] = +(float) z
/ SCALE
;
718 p
[2] = -(float) y
/ SCALE
;
720 for (i
= v0
; i
< fp
->vc
; i
++)
721 v_add(fp
->vv
[i
].p
, fp
->vv
[i
].p
, p
);
724 static void make_coin(struct s_file
*fp
,
726 char v
[][MAXSTR
], short c
)
728 short i
, ci
= fp
->cc
++;
730 struct s_coin
*cp
= fp
->cv
+ ci
;
737 for (i
= 0; i
< c
; i
++)
739 if (strcmp(k
[i
], "light") == 0)
740 sscanf(v
[i
], "%hd", &cp
->n
);
742 if (strcmp(k
[i
], "origin") == 0)
744 short x
= 0, y
= 0, z
= 0;
746 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
748 cp
->p
[0] = +(float) x
/ SCALE
;
749 cp
->p
[1] = +(float) z
/ SCALE
;
750 cp
->p
[2] = -(float) y
/ SCALE
;
755 static void make_bill(struct s_file
*fp
,
757 char v
[][MAXSTR
], short c
)
759 short i
, ri
= fp
->rc
++;
761 struct s_bill
*rp
= fp
->rv
+ ri
;
763 memset(rp
, 0, sizeof (struct s_bill
));
766 for (i
= 0; i
< c
; i
++)
768 if (strcmp(k
[i
], "width") == 0)
769 sscanf(v
[i
], "%f %f %f", rp
->w
, rp
->w
+ 1, rp
->w
+ 2);
770 if (strcmp(k
[i
], "height") == 0)
771 sscanf(v
[i
], "%f %f %f", rp
->h
, rp
->h
+ 1, rp
->h
+ 2);
773 if (strcmp(k
[i
], "xrot") == 0)
774 sscanf(v
[i
], "%f %f %f", rp
->rx
, rp
->rx
+ 1, rp
->rx
+ 2);
775 if (strcmp(k
[i
], "yrot") == 0)
776 sscanf(v
[i
], "%f %f %f", rp
->ry
, rp
->ry
+ 1, rp
->ry
+ 2);
777 if (strcmp(k
[i
], "zrot") == 0)
778 sscanf(v
[i
], "%f %f %f", rp
->rz
, rp
->rz
+ 1, rp
->rz
+ 2);
780 if (strcmp(k
[i
], "time") == 0)
781 sscanf(v
[i
], "%f", &rp
->t
);
782 if (strcmp(k
[i
], "dist") == 0)
783 sscanf(v
[i
], "%f", &rp
->d
);
784 if (strcmp(k
[i
], "flag") == 0)
785 sscanf(v
[i
], "%hd", &rp
->fl
);
787 if (strcmp(k
[i
], "image") == 0)
789 rp
->mi
= read_mtrl(fp
, v
[i
]);
790 fp
->mv
[rp
->mi
].fl
|= M_CLAMPED
;
793 if (strcmp(k
[i
], "origin") == 0)
795 short x
= 0, y
= 0, z
= 0;
798 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
800 p
[0] = +(float) x
/ SCALE
;
801 p
[1] = +(float) z
/ SCALE
;
802 p
[2] = -(float) y
/ SCALE
;
805 rp
->rx
[0] = V_DEG(fatan2f(+p
[1], rp
->d
));
806 rp
->ry
[0] = V_DEG(fatan2f(+p
[0], -p
[2]));
810 if (rp
->fl
& B_ADDITIVE
)
811 fp
->mv
[rp
->mi
].fl
|= M_ADDITIVE
;
814 static void make_goal(struct s_file
*fp
,
816 char v
[][MAXSTR
], short c
)
818 short i
, zi
= fp
->zc
++;
820 struct s_goal
*zp
= fp
->zv
+ zi
;
827 for (i
= 0; i
< c
; i
++)
829 if (strcmp(k
[i
], "radius") == 0)
830 sscanf(v
[i
], "%f", &zp
->r
);
832 if (strcmp(k
[i
], "origin") == 0)
834 short x
= 0, y
= 0, z
= 0;
836 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
838 zp
->p
[0] = +(float) (x
) / SCALE
;
839 zp
->p
[1] = +(float) (z
- 24) / SCALE
;
840 zp
->p
[2] = -(float) (y
) / SCALE
;
845 static void make_view(struct s_file
*fp
,
847 char v
[][MAXSTR
], short c
)
849 short i
, wi
= fp
->wc
++;
851 struct s_view
*wp
= fp
->wv
+ wi
;
860 for (i
= 0; i
< c
; i
++)
862 if (strcmp(k
[i
], "target") == 0)
863 make_ref(v
[i
], targ_wi
+ wi
);
865 if (strcmp(k
[i
], "origin") == 0)
867 short x
= 0, y
= 0, z
= 0;
869 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
871 wp
->p
[0] = +(float) x
/ SCALE
;
872 wp
->p
[1] = +(float) z
/ SCALE
;
873 wp
->p
[2] = -(float) y
/ SCALE
;
878 static void make_jump(struct s_file
*fp
,
880 char v
[][MAXSTR
], short c
)
882 short i
, ji
= fp
->jc
++;
884 struct s_jump
*jp
= fp
->jv
+ ji
;
894 for (i
= 0; i
< c
; i
++)
896 if (strcmp(k
[i
], "radius") == 0)
897 sscanf(v
[i
], "%f", &jp
->r
);
899 if (strcmp(k
[i
], "target") == 0)
900 make_ref(v
[i
], targ_ji
+ ji
);
902 if (strcmp(k
[i
], "origin") == 0)
904 short x
= 0, y
= 0, z
= 0;
906 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
908 jp
->p
[0] = +(float) x
/ SCALE
;
909 jp
->p
[1] = +(float) z
/ SCALE
;
910 jp
->p
[2] = -(float) y
/ SCALE
;
915 static void make_swch(struct s_file
*fp
,
917 char v
[][MAXSTR
], short c
)
919 short i
, xi
= fp
->xc
++;
921 struct s_swch
*xp
= fp
->xv
+ xi
;
933 for (i
= 0; i
< c
; i
++)
935 if (strcmp(k
[i
], "radius") == 0)
936 sscanf(v
[i
], "%f", &xp
->r
);
938 if (strcmp(k
[i
], "target") == 0)
939 make_ref(v
[i
], &xp
->pi
);
941 if (strcmp(k
[i
], "timer") == 0)
942 sscanf(v
[i
], "%f", &xp
->t0
);
944 if (strcmp(k
[i
], "state") == 0)
947 if (strcmp(k
[i
], "origin") == 0)
949 short x
= 0, y
= 0, z
= 0;
951 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
953 xp
->p
[0] = +(float) x
/ SCALE
;
954 xp
->p
[1] = +(float) z
/ SCALE
;
955 xp
->p
[2] = -(float) y
/ SCALE
;
960 static void make_targ(struct s_file
*fp
,
962 char v
[][MAXSTR
], short c
)
966 targ_p
[targ_n
][0] = 0.f
;
967 targ_p
[targ_n
][1] = 0.f
;
968 targ_p
[targ_n
][3] = 0.f
;
970 for (i
= 0; i
< c
; i
++)
972 if (strcmp(k
[i
], "targetname") == 0)
973 make_sym(v
[i
], targ_n
);
975 if (strcmp(k
[i
], "origin") == 0)
977 short x
= 0, y
= 0, z
= 0;
979 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
981 targ_p
[targ_n
][0] = +(float) x
/ SCALE
;
982 targ_p
[targ_n
][1] = +(float) z
/ SCALE
;
983 targ_p
[targ_n
][2] = -(float) y
/ SCALE
;
990 static void make_ball(struct s_file
*fp
,
992 char v
[][MAXSTR
], short c
)
994 short i
, ui
= fp
->uc
++;
996 struct s_ball
*up
= fp
->uv
+ ui
;
1020 for (i
= 0; i
< c
; i
++)
1022 if (strcmp(k
[i
], "radius") == 0)
1023 sscanf(v
[i
], "%f", &up
->r
);
1025 if (strcmp(k
[i
], "origin") == 0)
1027 short x
= 0, y
= 0, z
= 0;
1029 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
1031 up
->p
[0] = +(float) (x
) / SCALE
;
1032 up
->p
[1] = +(float) (z
- 24) / SCALE
;
1033 up
->p
[2] = -(float) (y
) / SCALE
;
1037 up
->p
[1] += up
->r
+ SMALL
;
1040 /*---------------------------------------------------------------------------*/
1042 static void read_ent(struct s_file
*fp
, FILE *fin
)
1044 char k
[MAXKEY
][MAXSTR
];
1045 char v
[MAXKEY
][MAXSTR
];
1046 short t
, i
= 0, c
= 0;
1050 while ((t
= map_token(fin
, -1, k
[c
], v
[c
])))
1054 if (strcmp(k
[c
], "classname") == 0)
1058 if (t
== T_BEG
) read_lump(fp
, fin
);
1059 if (t
== T_END
) break;
1062 if (!strcmp(v
[i
], "light")) make_coin(fp
, k
, v
, c
);
1063 if (!strcmp(v
[i
], "info_camp")) make_swch(fp
, k
, v
, c
);
1064 if (!strcmp(v
[i
], "info_null")) make_bill(fp
, k
, v
, c
);
1065 if (!strcmp(v
[i
], "path_corner")) make_path(fp
, k
, v
, c
);
1066 if (!strcmp(v
[i
], "info_player_start")) make_ball(fp
, k
, v
, c
);
1067 if (!strcmp(v
[i
], "info_player_intermission")) make_view(fp
, k
, v
, c
);
1068 if (!strcmp(v
[i
], "info_player_deathmatch")) make_goal(fp
, k
, v
, c
);
1069 if (!strcmp(v
[i
], "target_teleporter")) make_jump(fp
, k
, v
, c
);
1070 if (!strcmp(v
[i
], "target_position")) make_targ(fp
, k
, v
, c
);
1071 if (!strcmp(v
[i
], "worldspawn")) make_body(fp
, k
, v
, c
, l0
);
1072 if (!strcmp(v
[i
], "func_train")) make_body(fp
, k
, v
, c
, l0
);
1073 if (!strcmp(v
[i
], "misc_model")) make_body(fp
, k
, v
, c
, l0
);
1076 static void read_map(struct s_file
*fp
, FILE *fin
)
1082 while ((t
= map_token(fin
, -1, k
, v
)))
1087 /*---------------------------------------------------------------------------*/
1089 /* Test the location of a point with respect to a side plane. */
1091 static int fore_side(const float p
[3], const struct s_side
*sp
)
1093 return (v_dot(p
, sp
->n
) - sp
->d
> +SMALL
) ? 1 : 0;
1096 static int on_side(const float p
[3], const struct s_side
*sp
)
1098 float d
= v_dot(p
, sp
->n
) - sp
->d
;
1100 return (-SMALL
< d
&& d
< +SMALL
) ? 1 : 0;
1103 /*---------------------------------------------------------------------------*/
1105 * Confirm that the addition of a vert would not result in degenerate
1109 static int ok_vert(const struct s_file
*fp
,
1110 const struct s_lump
*lp
, const float p
[3])
1115 for (i
= 0; i
< lp
->vc
; i
++)
1117 float *q
= fp
->vv
[fp
->iv
[lp
->v0
+ i
]].p
;
1121 if (v_len(r
) < SMALL
)
1127 /*---------------------------------------------------------------------------*/
1130 * The following functions take the set of planes defining a lump and
1131 * find the verts, edges, and geoms that describe its boundaries. To
1132 * do this, they first find the verts, and then search these verts for
1133 * valid edges and geoms. It may be more efficient to compute edges
1134 * and geoms directly by clipping down infinite line segments and
1135 * planes, but this would be more complex and prone to numerical
1140 * Given 3 side planes, compute the point of intersection, if any.
1141 * Confirm that this point falls within the current lump, and that it
1142 * is unique. Add it as a vert of the solid.
1144 static void clip_vert(struct s_file
*fp
,
1145 struct s_lump
*lp
, short si
, short sj
, short sk
)
1147 float M
[16], X
[16], I
[16];
1151 d
[0] = fp
->sv
[si
].d
;
1152 d
[1] = fp
->sv
[sj
].d
;
1153 d
[2] = fp
->sv
[sk
].d
;
1155 m_basis(M
, fp
->sv
[si
].n
, fp
->sv
[sj
].n
, fp
->sv
[sk
].n
);
1162 for (i
= 0; i
< lp
->sc
; i
++)
1164 short si
= fp
->iv
[lp
->s0
+ i
];
1166 if (fore_side(p
, fp
->sv
+ si
))
1170 if (ok_vert(fp
, lp
, p
))
1172 v_cpy(fp
->vv
[fp
->vc
].p
, p
);
1174 fp
->iv
[fp
->ic
] = fp
->vc
;
1183 * Given two side planes, find an edge along their intersection by
1184 * finding a pair of vertices that fall on both planes. Add it to the
1187 static void clip_edge(struct s_file
*fp
,
1188 struct s_lump
*lp
, short si
, short sj
)
1192 for (i
= 1; i
< lp
->vc
; i
++)
1193 for (j
= 0; j
< i
; j
++)
1195 short vi
= fp
->iv
[lp
->v0
+ i
];
1196 short vj
= fp
->iv
[lp
->v0
+ j
];
1198 if (on_side(fp
->vv
[vi
].p
, fp
->sv
+ si
) &&
1199 on_side(fp
->vv
[vj
].p
, fp
->sv
+ si
) &&
1200 on_side(fp
->vv
[vi
].p
, fp
->sv
+ sj
) &&
1201 on_side(fp
->vv
[vj
].p
, fp
->sv
+ sj
))
1203 fp
->ev
[fp
->ec
].vi
= vi
;
1204 fp
->ev
[fp
->ec
].vj
= vj
;
1206 fp
->iv
[fp
->ic
] = fp
->ec
;
1216 * Find all verts that lie on the given side of the lump. Sort these
1217 * verts to have a counter-clockwise winding about the plane normal.
1218 * Create geoms to tessalate the resulting convex polygon.
1220 static void clip_geom(struct s_file
*fp
,
1221 struct s_lump
*lp
, short si
)
1223 short m
[256], t
[256], d
, i
, j
, n
= 0;
1228 struct s_side
*sp
= fp
->sv
+ si
;
1232 for (i
= 0; i
< lp
->vc
; i
++)
1234 short vi
= fp
->iv
[lp
->v0
+ i
];
1236 if (on_side(fp
->vv
[vi
].p
, sp
))
1241 v_add(v
, fp
->vv
[vi
].p
, plane_p
[si
]);
1243 fp
->tv
[t
[n
]].u
[0] = v_dot(v
, plane_u
[si
]);
1244 fp
->tv
[t
[n
]].u
[1] = v_dot(v
, plane_v
[si
]);
1252 for (i
= 1; i
< n
; i
++)
1253 for (j
= i
+ 1; j
< n
; j
++)
1255 v_sub(u
, fp
->vv
[m
[i
]].p
, fp
->vv
[m
[0]].p
);
1256 v_sub(v
, fp
->vv
[m
[j
]].p
, fp
->vv
[m
[0]].p
);
1259 if (v_dot(w
, sp
->n
) < 0.f
)
1273 for (i
= 0; i
< n
- 2; i
++)
1275 fp
->gv
[fp
->gc
].mi
= plane_m
[si
];
1277 fp
->gv
[fp
->gc
].ti
= t
[0];
1278 fp
->gv
[fp
->gc
].tj
= t
[i
+ 1];
1279 fp
->gv
[fp
->gc
].tk
= t
[i
+ 2];
1281 fp
->gv
[fp
->gc
].si
= si
;
1282 fp
->gv
[fp
->gc
].sj
= si
;
1283 fp
->gv
[fp
->gc
].sk
= si
;
1285 fp
->gv
[fp
->gc
].vi
= m
[0];
1286 fp
->gv
[fp
->gc
].vj
= m
[i
+ 1];
1287 fp
->gv
[fp
->gc
].vk
= m
[i
+ 2];
1289 fp
->iv
[fp
->ic
] = fp
->gc
;
1297 * Iterate the sides of the lump, attemping to generate a new vert for
1298 * each trio of planes, a new edge for each pair of planes, and a new
1299 * set of geom for each visible plane.
1301 static void clip_lump(struct s_file
*fp
, struct s_lump
*lp
)
1308 for (i
= 2; i
< lp
->sc
; i
++)
1309 for (j
= 1; j
< i
; j
++)
1310 for (k
= 0; k
< j
; k
++)
1314 fp
->iv
[lp
->s0
+ k
]);
1319 for (i
= 1; i
< lp
->sc
; i
++)
1320 for (j
= 0; j
< i
; j
++)
1323 fp
->iv
[lp
->s0
+ j
]);
1328 for (i
= 0; i
< lp
->sc
; i
++)
1329 if (fp
->mv
[plane_m
[fp
->iv
[lp
->s0
+ i
]]].d
[3] > 0)
1331 fp
->iv
[lp
->s0
+ i
]);
1333 for (i
= 0; i
< lp
->sc
; i
++)
1334 if (plane_f
[fp
->iv
[lp
->s0
+ i
]])
1338 static void clip_file(struct s_file
*fp
)
1342 for (i
= 0; i
< fp
->lc
; i
++)
1343 clip_lump(fp
, fp
->lv
+ i
);
1346 /*---------------------------------------------------------------------------*/
1349 * For each body element type, determine if element 'p' is equivalent
1350 * to element 'q'. This is more than a simple memory compare. It
1351 * effectively snaps mtrls and verts togather, and may reverse the
1352 * winding of an edge or a geom. This is done in order to maximize
1353 * the number of elements that can be eliminated.
1356 static int comp_mtrl(const struct s_mtrl
*mp
, const struct s_mtrl
*mq
)
1358 if (fabs(mp
->d
[0] - mq
->d
[0]) > SMALL
) return 0;
1359 if (fabs(mp
->d
[1] - mq
->d
[1]) > SMALL
) return 0;
1360 if (fabs(mp
->d
[2] - mq
->d
[2]) > SMALL
) return 0;
1361 if (fabs(mp
->d
[3] - mq
->d
[3]) > SMALL
) return 0;
1363 if (fabs(mp
->a
[0] - mq
->a
[0]) > SMALL
) return 0;
1364 if (fabs(mp
->a
[1] - mq
->a
[1]) > SMALL
) return 0;
1365 if (fabs(mp
->a
[2] - mq
->a
[2]) > SMALL
) return 0;
1366 if (fabs(mp
->a
[3] - mq
->a
[3]) > SMALL
) return 0;
1368 if (fabs(mp
->s
[0] - mq
->s
[0]) > SMALL
) return 0;
1369 if (fabs(mp
->s
[1] - mq
->s
[1]) > SMALL
) return 0;
1370 if (fabs(mp
->s
[2] - mq
->s
[2]) > SMALL
) return 0;
1371 if (fabs(mp
->s
[3] - mq
->s
[3]) > SMALL
) return 0;
1373 if (fabs(mp
->e
[0] - mq
->e
[0]) > SMALL
) return 0;
1374 if (fabs(mp
->e
[1] - mq
->e
[1]) > SMALL
) return 0;
1375 if (fabs(mp
->e
[2] - mq
->e
[2]) > SMALL
) return 0;
1376 if (fabs(mp
->e
[3] - mq
->e
[3]) > SMALL
) return 0;
1378 if (fabs(mp
->h
[0] - mq
->h
[0]) > SMALL
) return 0;
1380 if (strncmp(mp
->f
, mq
->f
, PATHMAX
)) return 0;
1385 static int comp_vert(const struct s_vert
*vp
, const struct s_vert
*vq
)
1387 if (fabs(vp
->p
[0] - vq
->p
[0]) > SMALL
) return 0;
1388 if (fabs(vp
->p
[1] - vq
->p
[1]) > SMALL
) return 0;
1389 if (fabs(vp
->p
[2] - vq
->p
[2]) > SMALL
) return 0;
1394 static int comp_edge(const struct s_edge
*ep
, const struct s_edge
*eq
)
1396 if (ep
->vi
!= eq
->vi
&& ep
->vi
!= eq
->vj
) return 0;
1397 if (ep
->vj
!= eq
->vi
&& ep
->vj
!= eq
->vj
) return 0;
1402 static int comp_side(const struct s_side
*sp
, const struct s_side
*sq
)
1404 if (fabs(sp
->d
- sq
->d
) > SMALL
) return 0;
1405 if (v_dot(sp
->n
, sq
->n
) < 0.99999) return 0;
1410 static int comp_texc(const struct s_texc
*tp
, const struct s_texc
*tq
)
1412 if (fabs(tp
->u
[0] - tq
->u
[0]) > SMALL
) return 0;
1413 if (fabs(tp
->u
[1] - tq
->u
[1]) > SMALL
) return 0;
1418 static int comp_geom(const struct s_geom
*gp
, const struct s_geom
*gq
)
1420 if (gp
->mi
!= gq
->mi
) return 0;
1422 if (gp
->ti
!= gq
->ti
) return 0;
1423 if (gp
->si
!= gq
->si
) return 0;
1424 if (gp
->vi
!= gq
->vi
) return 0;
1426 if (gp
->tj
!= gq
->tj
) return 0;
1427 if (gp
->sj
!= gq
->sj
) return 0;
1428 if (gp
->vj
!= gq
->vj
) return 0;
1430 if (gp
->tk
!= gq
->tk
) return 0;
1431 if (gp
->sk
!= gq
->sk
) return 0;
1432 if (gp
->vk
!= gq
->vk
) return 0;
1437 /*---------------------------------------------------------------------------*/
1440 * For each file element type, replace all references to element 'i'
1441 * with a reference to element 'j'. These are used when optimizing
1442 * and sorting the file.
1445 static void swap_mtrl(struct s_file
*fp
, short mi
, short mj
)
1449 for (i
= 0; i
< fp
->gc
; i
++)
1450 if (fp
->gv
[i
].mi
== mi
) fp
->gv
[i
].mi
= mj
;
1451 for (i
= 0; i
< fp
->rc
; i
++)
1452 if (fp
->rv
[i
].mi
== mi
) fp
->rv
[i
].mi
= mj
;
1455 static void swap_vert(struct s_file
*fp
, short vi
, short vj
)
1459 for (i
= 0; i
< fp
->ec
; i
++)
1461 if (fp
->ev
[i
].vi
== vi
) fp
->ev
[i
].vi
= vj
;
1462 if (fp
->ev
[i
].vj
== vi
) fp
->ev
[i
].vj
= vj
;
1465 for (i
= 0; i
< fp
->gc
; i
++)
1467 if (fp
->gv
[i
].vi
== vi
) fp
->gv
[i
].vi
= vj
;
1468 if (fp
->gv
[i
].vj
== vi
) fp
->gv
[i
].vj
= vj
;
1469 if (fp
->gv
[i
].vk
== vi
) fp
->gv
[i
].vk
= vj
;
1472 for (i
= 0; i
< fp
->lc
; i
++)
1473 for (j
= 0; j
< fp
->lv
[i
].vc
; j
++)
1474 if (fp
->iv
[fp
->lv
[i
].v0
+ j
] == vi
)
1475 fp
->iv
[fp
->lv
[i
].v0
+ j
] = vj
;
1478 static void swap_edge(struct s_file
*fp
, short ei
, short ej
)
1482 for (i
= 0; i
< fp
->lc
; i
++)
1483 for (j
= 0; j
< fp
->lv
[i
].ec
; j
++)
1484 if (fp
->iv
[fp
->lv
[i
].e0
+ j
] == ei
)
1485 fp
->iv
[fp
->lv
[i
].e0
+ j
] = ej
;
1488 static void swap_side(struct s_file
*fp
, short si
, short sj
)
1492 for (i
= 0; i
< fp
->gc
; i
++)
1494 if (fp
->gv
[i
].si
== si
) fp
->gv
[i
].si
= sj
;
1495 if (fp
->gv
[i
].sj
== si
) fp
->gv
[i
].sj
= sj
;
1496 if (fp
->gv
[i
].sk
== si
) fp
->gv
[i
].sk
= sj
;
1498 for (i
= 0; i
< fp
->nc
; i
++)
1499 if (fp
->nv
[i
].si
== si
) fp
->nv
[i
].si
= sj
;
1501 for (i
= 0; i
< fp
->lc
; i
++)
1502 for (j
= 0; j
< fp
->lv
[i
].sc
; j
++)
1503 if (fp
->iv
[fp
->lv
[i
].s0
+ j
] == si
)
1504 fp
->iv
[fp
->lv
[i
].s0
+ j
] = sj
;
1507 static void swap_texc(struct s_file
*fp
, short ti
, short tj
)
1511 for (i
= 0; i
< fp
->gc
; i
++)
1513 if (fp
->gv
[i
].ti
== ti
) fp
->gv
[i
].ti
= tj
;
1514 if (fp
->gv
[i
].tj
== ti
) fp
->gv
[i
].tj
= tj
;
1515 if (fp
->gv
[i
].tk
== ti
) fp
->gv
[i
].tk
= tj
;
1520 static void swap_geom(struct s_file
*fp
, short gi
, short gj
)
1524 for (i
= 0; i
< fp
->lc
; i
++)
1525 for (j
= 0; j
< fp
->lv
[i
].gc
; j
++)
1526 if (fp
->iv
[fp
->lv
[i
].g0
+ j
] == gi
)
1527 fp
->iv
[fp
->lv
[i
].g0
+ j
] = gj
;
1529 for (i
= 0; i
< fp
->bc
; i
++)
1530 for (j
= 0; j
< fp
->bv
[i
].gc
; j
++)
1531 if (fp
->iv
[fp
->bv
[i
].g0
+ j
] == gi
)
1532 fp
->iv
[fp
->bv
[i
].g0
+ j
] = gj
;
1535 /*---------------------------------------------------------------------------*/
1537 static void uniq_mtrl(struct s_file
*fp
)
1541 for (i
= 0; i
< fp
->mc
; i
++)
1543 for (j
= 0; j
< i
; j
++)
1544 if (comp_mtrl(fp
->mv
+ i
, fp
->mv
+ j
))
1546 swap_mtrl(fp
, i
, j
);
1554 fp
->mv
[k
] = fp
->mv
[i
];
1555 swap_mtrl(fp
, i
, k
);
1564 static void uniq_vert(struct s_file
*fp
)
1568 for (i
= 0; i
< fp
->vc
; i
++)
1570 for (j
= 0; j
< i
; j
++)
1571 if (comp_vert(fp
->vv
+ i
, fp
->vv
+ j
))
1573 swap_vert(fp
, i
, j
);
1581 fp
->vv
[k
] = fp
->vv
[i
];
1582 swap_vert(fp
, i
, k
);
1591 static void uniq_edge(struct s_file
*fp
)
1595 for (i
= 0; i
< fp
->ec
; i
++)
1597 for (j
= 0; j
< i
; j
++)
1598 if (comp_edge(fp
->ev
+ i
, fp
->ev
+ j
))
1600 swap_edge(fp
, i
, j
);
1608 fp
->ev
[k
] = fp
->ev
[i
];
1609 swap_edge(fp
, i
, k
);
1618 static void uniq_geom(struct s_file
*fp
)
1622 for (i
= 0; i
< fp
->gc
; i
++)
1624 for (j
= 0; j
< i
; j
++)
1625 if (comp_geom(fp
->gv
+ i
, fp
->gv
+ j
))
1627 swap_geom(fp
, i
, j
);
1635 fp
->gv
[k
] = fp
->gv
[i
];
1636 swap_geom(fp
, i
, k
);
1645 static void uniq_texc(struct s_file
*fp
)
1649 for (i
= 0; i
< fp
->tc
; i
++)
1651 for (j
= 0; j
< i
; j
++)
1652 if (comp_texc(fp
->tv
+ i
, fp
->tv
+ j
))
1654 swap_texc(fp
, i
, j
);
1662 fp
->tv
[k
] = fp
->tv
[i
];
1663 swap_texc(fp
, i
, k
);
1672 static void uniq_side(struct s_file
*fp
)
1676 for (i
= 0; i
< fp
->sc
; i
++)
1678 for (j
= 0; j
< i
; j
++)
1679 if (comp_side(fp
->sv
+ i
, fp
->sv
+ j
))
1681 swap_side(fp
, i
, j
);
1689 fp
->sv
[k
] = fp
->sv
[i
];
1690 swap_side(fp
, i
, k
);
1699 static void uniq_file(struct s_file
*fp
)
1709 /*---------------------------------------------------------------------------*/
1711 static void sort_file(struct s_file
*fp
)
1715 /* Sort billboards farthest to nearest. */
1717 for (i
= 0; i
< fp
->rc
; i
++)
1718 for (j
= i
+ 1; j
< fp
->rc
; j
++)
1719 if (fp
->rv
[j
].d
> fp
->rv
[i
].d
)
1724 fp
->rv
[i
] = fp
->rv
[j
];
1728 /* Ensure the first vertex is the lowest. */
1730 for (i
= 0; i
< fp
->vc
; i
++)
1731 if (fp
->vv
[0].p
[1] > fp
->vv
[i
].p
[1])
1736 fp
->vv
[0] = fp
->vv
[i
];
1739 swap_vert(fp
, 0, -1);
1740 swap_vert(fp
, i
, 0);
1741 swap_vert(fp
, -1, i
);
1745 /*---------------------------------------------------------------------------*/
1747 static int test_lump_side(const struct s_file
*fp
,
1748 const struct s_lump
*lp
,
1749 const struct s_side
*sp
)
1757 /* If the given side is part of the given lump, then the lump is behind. */
1759 for (si
= 0; si
< lp
->sc
; si
++)
1760 if (fp
->sv
+ fp
->iv
[lp
->s0
+ si
] == sp
)
1763 /* Check if each lump vertex is in front of, behind, on the side. */
1765 for (vi
= 0; vi
< lp
->vc
; vi
++)
1767 float d
= v_dot(fp
->vv
[fp
->iv
[lp
->v0
+ vi
]].p
, sp
->n
) - sp
->d
;
1773 /* If no verts are behind, the lump is in front, and vice versa. */
1775 if (f
> 0 && b
== 0) return +1;
1776 if (b
> 0 && f
== 0) return -1;
1778 /* Else, the lump crosses the side. */
1783 static int node_node(struct s_file
*fp
, short l0
, short lc
)
1787 /* Base case. Dump all given lumps into a leaf node. */
1789 fp
->nv
[fp
->nc
].si
= -1;
1790 fp
->nv
[fp
->nc
].ni
= -1;
1791 fp
->nv
[fp
->nc
].nj
= -1;
1792 fp
->nv
[fp
->nc
].l0
= l0
;
1793 fp
->nv
[fp
->nc
].lc
= lc
;
1803 short li
= 0, lic
= 0;
1804 short lj
= 0, ljc
= 0;
1805 short lk
= 0, lkc
= 0;
1808 /* Find the side that most evenly splits the given lumps. */
1810 for (si
= 0; si
< fp
->sc
; si
++)
1816 for (li
= 0; li
< lc
; li
++)
1817 if ((k
= test_lump_side(fp
, fp
->lv
+ l0
+ li
, fp
->sv
+ si
)))
1824 if ((d
< sjd
) || (d
== sjd
&& o
< sjo
))
1832 /* Flag each lump with its position WRT the side. */
1834 for (li
= 0; li
< lc
; li
++)
1835 switch (test_lump_side(fp
, fp
->lv
+ l0
+ li
, fp
->sv
+ sj
))
1837 case +1: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x10; break;
1838 case 0: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x20; break;
1839 case -1: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x40; break;
1842 /* Sort all lumps in the range by their flag values. */
1844 for (li
= 1; li
< lc
; li
++)
1845 for (lj
= 0; lj
< li
; lj
++)
1846 if (fp
->lv
[l0
+ li
].fl
< fp
->lv
[l0
+ lj
].fl
)
1850 l
= fp
->lv
[l0
+ li
];
1851 fp
->lv
[l0
+ li
] = fp
->lv
[l0
+ lj
];
1852 fp
->lv
[l0
+ lj
] = l
;
1855 /* Establish the in-front, on, and behind lump ranges. */
1861 for (i
= lc
- 1; i
>= 0; i
--)
1862 switch (fp
->lv
[l0
+ i
].fl
& 0xf0)
1864 case 0x10: li
= l0
+ i
; lic
++; break;
1865 case 0x20: lj
= l0
+ i
; ljc
++; break;
1866 case 0x40: lk
= l0
+ i
; lkc
++; break;
1869 /* Add the lumps on the side to the node. */
1874 fp
->nv
[i
].ni
= node_node(fp
, li
, lic
);
1876 fp
->nv
[i
].nj
= node_node(fp
, lk
, lkc
);
1884 static void node_file(struct s_file
*fp
)
1888 /* Sort the lumps of each body into BSP nodes. */
1890 for (bi
= 0; bi
< fp
->bc
; bi
++)
1891 fp
->bv
[bi
].ni
= node_node(fp
, fp
->bv
[bi
].l0
, fp
->bv
[bi
].lc
);
1894 /*---------------------------------------------------------------------------*/
1896 static void dump_file(struct s_file
*p
, const char *name
)
1901 int m
= p
->rc
+ p
->cc
* 128 + (p
->zc
* p
->jc
+ p
->xc
) * 32;
1903 /* Count the number of solid lumps. */
1905 for (i
= 0; i
< p
->lc
; i
++)
1906 if ((p
->lv
[i
].fl
& 1) == 0)
1909 /* Count the number of visible geoms. */
1911 for (i
= 0; i
< p
->bc
; i
++)
1913 for (j
= 0; j
< p
->bv
[i
].lc
; j
++)
1914 m
+= p
->lv
[p
->bv
[i
].l0
+ j
].gc
;
1918 /* Count the total value of all coins. */
1920 for (i
= 0; i
< p
->cc
; i
++)
1923 printf("%s (%d/%d/$%d)\n"
1924 " mtrl vert edge side texc"
1925 " geom lump path node body\n"
1926 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
1927 " coin goal view jump swch"
1928 " bill ball char indx\n"
1929 "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
1931 p
->mc
, p
->vc
, p
->ec
, p
->sc
, p
->tc
,
1932 p
->gc
, p
->lc
, p
->pc
, p
->nc
, p
->bc
,
1933 p
->cc
, p
->zc
, p
->wc
, p
->jc
, p
->xc
,
1934 p
->rc
, p
->uc
, p
->ac
, p
->ic
);
1937 int main(int argc
, char *argv
[])
1946 if (config_data_path(argv
[2], NULL
))
1948 strncpy(src
, argv
[1], MAXSTR
);
1949 strncpy(dst
, argv
[1], MAXSTR
);
1951 if (strcmp(dst
+ strlen(dst
) - 4, ".map") == 0)
1952 strcpy(dst
+ strlen(dst
) - 4, ".sol");
1954 strcat(dst
, ".sol");
1956 if ((fin
= fopen(src
, "r")))
1976 else fprintf(stderr
, "Failure to establish data directory\n");
1978 else fprintf(stderr
, "Usage: %s <map> [data]\n", argv
[0]);