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.lib")
20 #pragma comment(lib, "SDLmain.lib")
21 #pragma comment(lib, "glu32.lib")
22 #pragma comment(lib, "opengl32.lib")
25 /*---------------------------------------------------------------------------*/
28 #include <SDL_image.h>
43 static char path
[MAXSTR
];
44 static char src
[MAXSTR
];
45 static char dst
[MAXSTR
];
48 * The overall design of this map converter is very stupid, but very
49 * simple. It begins by assuming that every mtrl, vert, edge, side,
50 * and texc in the map is unique. It then makes an optimizing pass
51 * that discards redundant information. The result is optimal, though
52 * the process is terribly inefficient.
55 /*---------------------------------------------------------------------------*/
57 /* Ohhhh... arbitrary! */
79 static void init_file(struct s_file
*fp
)
101 fp
->mv
= (struct s_mtrl
*) calloc(MAXM
, sizeof (struct s_mtrl
));
102 fp
->vv
= (struct s_vert
*) calloc(MAXV
, sizeof (struct s_vert
));
103 fp
->ev
= (struct s_edge
*) calloc(MAXE
, sizeof (struct s_edge
));
104 fp
->sv
= (struct s_side
*) calloc(MAXS
, sizeof (struct s_side
));
105 fp
->tv
= (struct s_texc
*) calloc(MAXT
, sizeof (struct s_texc
));
106 fp
->gv
= (struct s_geom
*) calloc(MAXG
, sizeof (struct s_geom
));
107 fp
->lv
= (struct s_lump
*) calloc(MAXL
, sizeof (struct s_lump
));
108 fp
->nv
= (struct s_node
*) calloc(MAXN
, sizeof (struct s_node
));
109 fp
->pv
= (struct s_path
*) calloc(MAXP
, sizeof (struct s_path
));
110 fp
->bv
= (struct s_body
*) calloc(MAXB
, sizeof (struct s_body
));
111 fp
->cv
= (struct s_coin
*) calloc(MAXC
, sizeof (struct s_coin
));
112 fp
->zv
= (struct s_goal
*) calloc(MAXZ
, sizeof (struct s_goal
));
113 fp
->jv
= (struct s_jump
*) calloc(MAXJ
, sizeof (struct s_jump
));
114 fp
->xv
= (struct s_swch
*) calloc(MAXX
, sizeof (struct s_swch
));
115 fp
->rv
= (struct s_bill
*) calloc(MAXR
, sizeof (struct s_bill
));
116 fp
->uv
= (struct s_ball
*) calloc(MAXU
, sizeof (struct s_ball
));
117 fp
->wv
= (struct s_view
*) calloc(MAXW
, sizeof (struct s_view
));
118 fp
->av
= (char *) calloc(MAXA
, sizeof (char));
119 fp
->iv
= (short *) calloc(MAXI
, sizeof (short));
122 /*---------------------------------------------------------------------------*/
124 static void strapp(char *dest
,
127 const char *extn
, size_t n
)
129 size_t p
= strlen(path
);
130 size_t r
= strlen(path
);
132 strncpy(dest
, path
, n
- 1);
133 strncat(dest
, "/", n
- p
- 1);
134 strncat(dest
, root
, n
- p
- 2);
135 strncat(dest
, extn
, n
- p
- r
- 2);
138 /*---------------------------------------------------------------------------*/
141 * The following is a small symbol table data structure. Symbols and
142 * their integer values are collected in symv and valv. References
143 * and pointers to their unsatisfied integer values are collected in
144 * refv and pntv. The resolve procedure matches references to symbols
145 * and fills waiting ints with the proper values.
150 static char symv
[MAXSYM
][MAXSTR
];
151 static short valv
[MAXSYM
];
153 static char refv
[MAXSYM
][MAXSTR
];
154 static short *pntv
[MAXSYM
];
159 static void make_sym(const char *s
, short v
)
161 strncpy(symv
[strc
], s
, MAXSTR
- 1);
166 static void make_ref(const char *r
, short *p
)
168 strncpy(refv
[refc
], r
, MAXSTR
- 1);
173 static void resolve(void)
177 for (i
= 0; i
< refc
; i
++)
178 for (j
= 0; j
< strc
; j
++)
179 if (strncmp(refv
[i
], symv
[j
], MAXSTR
) == 0)
181 *(pntv
[i
]) = valv
[j
];
186 /*---------------------------------------------------------------------------*/
189 * The following globals are used to cache target_positions. They are
190 * targeted by various entities and must be resolved in a second pass.
193 static float targ_p
[MAXW
][3];
194 static short targ_wi
[MAXW
];
195 static short targ_ji
[MAXW
];
198 static void targets(struct s_file
*fp
)
202 for (i
= 0; i
< fp
->wc
; i
++)
203 v_cpy(fp
->wv
[i
].q
, targ_p
[targ_wi
[i
]]);
205 for (i
= 0; i
< fp
->jc
; i
++)
206 v_cpy(fp
->jv
[i
].q
, targ_p
[targ_ji
[i
]]);
209 /*---------------------------------------------------------------------------*/
212 * The following code caches image sizes. Textures are referenced by
213 * name, but their sizes are necessary when computing texture
214 * coordinates. This code allows each file to be accessed only once
215 * regardless of the number of surfaces refering to it.
218 static char *image_s
[MAXM
];
219 static int image_w
[MAXM
];
220 static int image_h
[MAXM
];
223 static int size_load(const char *file
, int *w
, int *h
)
227 if ((S
= IMG_Load(file
)))
239 static void size_image(const char *name
, int *w
, int *h
)
246 for (i
= 0; i
< image_n
; i
++)
247 if (strncmp(image_s
[i
], name
, MAXSTR
) == 0)
258 strapp(jpg
, path
, name
, ".jpg", MAXSTR
);
259 strapp(tga
, path
, name
, ".tga", MAXSTR
);
260 strapp(png
, path
, name
, ".png", MAXSTR
);
262 if (size_load(png
, w
, h
) || size_load(tga
, w
, h
) || size_load(jpg
, w
, h
))
264 image_s
[image_n
] = (char *) calloc(strlen(name
) + 1, 1);
265 image_w
[image_n
] = *w
;
266 image_h
[image_n
] = *h
;
268 strcpy(image_s
[image_n
], name
);
273 /*---------------------------------------------------------------------------*/
275 /* Read the given material file, adding a new material to the solid. */
277 static int read_mtrl(struct s_file
*fp
, const char *name
)
284 strapp(file
, path
, name
, "", MAXSTR
);
286 for (mi
= 0; mi
< fp
->mc
; mi
++)
287 if (strncmp(name
, fp
->mv
[mi
].f
, MAXSTR
) == 0)
290 mp
= fp
->mv
+ fp
->mc
++;
292 if ((fin
= fopen(file
, "r")))
300 mp
->d
, mp
->d
+ 1, mp
->d
+ 2, mp
->d
+ 3,
301 mp
->a
, mp
->a
+ 1, mp
->a
+ 2, mp
->a
+ 3,
302 mp
->s
, mp
->s
+ 1, mp
->s
+ 2, mp
->s
+ 3,
303 mp
->e
, mp
->e
+ 1, mp
->e
+ 2, mp
->e
+ 3,
307 strncpy(mp
->f
, name
, PATHMAX
- 1);
313 /*---------------------------------------------------------------------------*/
316 * All bodies with an associated path are assumed to be positioned at
317 * the beginning of that path. These bodies must be moved to the
318 * origin in order for their path transforms to behave correctly.
319 * This is how we get away with defining func_trains with no origin
323 static void move_side(struct s_side
*sp
, const float p
[3])
325 sp
->d
-= v_dot(sp
->n
, p
);
328 static void move_vert(struct s_vert
*vp
, const float p
[3])
330 v_sub(vp
->p
, vp
->p
, p
);
333 static void move_lump(struct s_file
*fp
,
334 struct s_lump
*lp
, const float p
[3])
338 for (i
= 0; i
< lp
->sc
; i
++)
339 move_side(fp
->sv
+ fp
->iv
[lp
->s0
+ i
], p
);
340 for (i
= 0; i
< lp
->vc
; i
++)
341 move_vert(fp
->vv
+ fp
->iv
[lp
->v0
+ i
], p
);
344 static void move_body(struct s_file
*fp
,
349 for (i
= 0; i
< bp
->lc
; i
++)
350 move_lump(fp
, fp
->lv
+ bp
->l0
+ i
, fp
->pv
[bp
->pi
].p
);
353 static void move_file(struct s_file
*fp
)
357 for (i
= 0; i
< fp
->bc
; i
++)
358 if (fp
->bv
[i
].pi
>= 0)
359 move_body(fp
, fp
->bv
+ i
);
362 /*---------------------------------------------------------------------------*/
364 static void read_vt(struct s_file
*fp
, const char *line
)
366 struct s_texc
*tp
= fp
->tv
+ fp
->tc
++;
368 sscanf(line
, "%f %f", tp
->u
, tp
->u
+ 1);
371 static void read_vn(struct s_file
*fp
, const char *line
)
373 struct s_side
*sp
= fp
->sv
+ fp
->sc
++;
375 sscanf(line
, "%f %f %f", sp
->n
, sp
->n
+ 1, sp
->n
+ 2);
378 static void read_v(struct s_file
*fp
, const char *line
)
380 struct s_vert
*vp
= fp
->vv
+ fp
->vc
++;
382 sscanf(line
, "%f %f %f", vp
->p
, vp
->p
+ 1, vp
->p
+ 2);
385 static void read_f(struct s_file
*fp
, const char *line
,
386 short v0
, short t0
, short s0
, short mi
)
388 struct s_geom
*gp
= fp
->gv
+ fp
->gc
++;
394 * FIXME: All faces must be triangles and must include a normal
395 * and texture coordinate.
398 sscanf(line
, "%hd%c%hd%c%hd %hd%c%hd%c%hd %hd%c%hd%c%hd",
399 &gp
->vi
, &c1
, &gp
->ti
, &c2
, &gp
->si
,
400 &gp
->vj
, &c1
, &gp
->tj
, &c2
, &gp
->sj
,
401 &gp
->vk
, &c1
, &gp
->tk
, &c2
, &gp
->sk
);
416 static void read_obj(struct s_file
*fp
, const char *name
)
428 strapp(file
, path
, name
, "", MAXSTR
);
430 if ((fin
= fopen(file
, "r")))
432 while (fgets(line
, MAXSTR
, fin
))
434 if (strncmp(line
, "usemtl", 6) == 0)
436 sscanf(line
+ 6, "%s", mtrl
);
437 mi
= read_mtrl(fp
, mtrl
);
440 else if (strncmp(line
, "f", 1) == 0)
442 if (fp
->mv
[mi
].d
[3] > 0)
443 read_f(fp
, line
+ 1, v0
, t0
, s0
, mi
);
446 else if (strncmp(line
, "vt", 2) == 0) read_vt(fp
, line
+ 2);
447 else if (strncmp(line
, "vn", 2) == 0) read_vn(fp
, line
+ 2);
448 else if (strncmp(line
, "v", 1) == 0) read_v (fp
, line
+ 1);
454 /*---------------------------------------------------------------------------*/
456 static float plane_d
[MAXS
];
457 static float plane_n
[MAXS
][3];
458 static float plane_p
[MAXS
][3];
459 static float plane_u
[MAXS
][3];
460 static float plane_v
[MAXS
][3];
461 static short plane_f
[MAXS
];
462 static short plane_m
[MAXS
];
464 static void make_plane(short pi
, short x0
, short y0
, short z0
,
465 short x1
, short y1
, short z1
,
466 short x2
, short y2
, short z2
,
467 short tu
, short tv
, short r
,
468 float su
, float sv
, int fl
, const char *s
)
470 static const float base
[6][3][3] = {
471 {{ 0, 0, 1 }, { 1, 0, 0 }, { 0, -1, 0 }},
472 {{ 0, 0, -1 }, { 1, 0, 0 }, { 0, -1, 0 }},
473 {{ 1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
474 {{ -1, 0, 0 }, { 0, 0, -1 }, { 0, -1, 0 }},
475 {{ 0, 1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
476 {{ 0, -1, 0 }, { 1, 0, 0 }, { 0, 0, 1 }},
480 float p0
[3], p1
[3], p2
[3];
481 float u
[3], v
[3], p
[3];
486 size_image(s
, &w
, &h
);
488 plane_f
[pi
] = fl
? L_DETAIL
: 0;
490 p0
[0] = +(float) x0
/ SCALE
;
491 p0
[1] = +(float) z0
/ SCALE
;
492 p0
[2] = -(float) y0
/ SCALE
;
494 p1
[0] = +(float) x1
/ SCALE
;
495 p1
[1] = +(float) z1
/ SCALE
;
496 p1
[2] = -(float) y1
/ SCALE
;
498 p2
[0] = +(float) x2
/ SCALE
;
499 p2
[1] = +(float) z2
/ SCALE
;
500 p2
[2] = -(float) y2
/ SCALE
;
505 v_crs(plane_n
[pi
], u
, v
);
506 v_nrm(plane_n
[pi
], plane_n
[pi
]);
508 plane_d
[pi
] = v_dot(plane_n
[pi
], p1
);
510 for (i
= 0; i
< 6; i
++)
511 if ((k
= v_dot(plane_n
[pi
], base
[i
][0])) >= d
)
521 m_rot(R
, base
[n
][0], V_RAD(r
));
523 v_mad(p
, p
, base
[n
][1], su
* tu
/ SCALE
);
524 v_mad(p
, p
, base
[n
][2], sv
* tv
/ SCALE
);
526 m_vxfm(plane_u
[pi
], R
, base
[n
][1]);
527 m_vxfm(plane_v
[pi
], R
, base
[n
][2]);
528 m_vxfm(plane_p
[pi
], R
, p
);
530 v_scl(plane_u
[pi
], plane_u
[pi
], 64.f
/ w
);
531 v_scl(plane_v
[pi
], plane_v
[pi
], 64.f
/ h
);
533 v_scl(plane_u
[pi
], plane_u
[pi
], 1.f
/ su
);
534 v_scl(plane_v
[pi
], plane_v
[pi
], 1.f
/ sv
);
537 /*---------------------------------------------------------------------------*/
546 static int map_token(FILE *fin
, short pi
, char key
[MAXSTR
], char val
[MAXSTR
])
550 if (fgets(buf
, MAXSTR
, fin
))
560 /* Scan the beginning or end of a block. */
562 if (buf
[0] == '{') return T_BEG
;
563 if (buf
[0] == '}') return T_END
;
565 /* Scan a key-value pair. */
569 strcpy(key
, strtok(buf
, "\""));
570 (void) strtok(NULL
, "\"");
571 strcpy(val
, strtok(NULL
, "\""));
582 "%s %hd %hd %hd %f %f %d",
583 &c
, &x0
, &y0
, &z0
, &c
,
584 &c
, &x1
, &y1
, &z1
, &c
,
585 &c
, &x2
, &y2
, &z2
, &c
,
586 key
, &tu
, &tv
, &r
, &su
, &sv
, &fl
) == 22)
588 make_plane(pi
, x0
, y0
, z0
,
591 tu
, tv
, r
, su
, sv
, fl
, key
);
595 /* If it's not recognized, it must be uninteresting. */
602 /*---------------------------------------------------------------------------*/
604 /* Parse a lump from the given file and add it to the solid. */
606 static void read_lump(struct s_file
*fp
, FILE *fin
)
612 struct s_lump
*lp
= fp
->lv
+ fp
->lc
++;
616 while ((t
= map_token(fin
, fp
->sc
, k
, v
)))
620 fp
->sv
[fp
->sc
].n
[0] = plane_n
[fp
->sc
][0];
621 fp
->sv
[fp
->sc
].n
[1] = plane_n
[fp
->sc
][1];
622 fp
->sv
[fp
->sc
].n
[2] = plane_n
[fp
->sc
][2];
623 fp
->sv
[fp
->sc
].d
= plane_d
[fp
->sc
];
625 plane_m
[fp
->sc
] = read_mtrl(fp
, k
);
627 fp
->iv
[fp
->ic
] = fp
->sc
;
637 /*---------------------------------------------------------------------------*/
639 static void make_path(struct s_file
*fp
,
641 char v
[][MAXSTR
], short c
)
643 short i
, pi
= fp
->pc
++;
645 struct s_path
*pp
= fp
->pv
+ pi
;
654 for (i
= 0; i
< c
; i
++)
656 if (strcmp(k
[i
], "targetname") == 0)
659 if (strcmp(k
[i
], "target") == 0)
660 make_ref(v
[i
], &pp
->pi
);
662 if (strcmp(k
[i
], "state") == 0)
665 if (strcmp(k
[i
], "speed") == 0)
666 sscanf(v
[i
], "%f", &pp
->t
);
668 if (strcmp(k
[i
], "origin") == 0)
670 short x
= 0, y
= 0, z
= 0;
672 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
674 pp
->p
[0] = +(float) x
/ SCALE
;
675 pp
->p
[1] = +(float) z
/ SCALE
;
676 pp
->p
[2] = -(float) y
/ SCALE
;
681 static void make_body(struct s_file
*fp
,
683 char v
[][MAXSTR
], short c
, short l0
)
685 short i
, bi
= fp
->bc
++;
696 struct s_body
*bp
= fp
->bv
+ bi
;
702 for (i
= 0; i
< c
; i
++)
704 if (strcmp(k
[i
], "targetname") == 0)
707 if (strcmp(k
[i
], "target") == 0)
708 make_ref(v
[i
], &bp
->pi
);
710 if (strcmp(k
[i
], "model") == 0)
713 if (strcmp(k
[i
], "origin") == 0)
714 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
716 if (strcmp(k
[i
], "message") == 0)
718 strcpy(fp
->av
, v
[i
]);
719 fp
->ac
= (short) (strlen(v
[i
]) + 1);
724 bp
->lc
= fp
->lc
- l0
;
726 bp
->gc
= fp
->gc
- g0
;
728 for (i
= 0; i
< bp
->gc
; i
++)
729 fp
->iv
[fp
->ic
++] = g0
++;
731 p
[0] = +(float) x
/ SCALE
;
732 p
[1] = +(float) z
/ SCALE
;
733 p
[2] = -(float) y
/ SCALE
;
735 for (i
= v0
; i
< fp
->vc
; i
++)
736 v_add(fp
->vv
[i
].p
, fp
->vv
[i
].p
, p
);
739 static void make_coin(struct s_file
*fp
,
741 char v
[][MAXSTR
], short c
)
743 short i
, ci
= fp
->cc
++;
745 struct s_coin
*cp
= fp
->cv
+ ci
;
752 for (i
= 0; i
< c
; i
++)
754 if (strcmp(k
[i
], "light") == 0)
755 sscanf(v
[i
], "%hd", &cp
->n
);
757 if (strcmp(k
[i
], "origin") == 0)
759 short x
= 0, y
= 0, z
= 0;
761 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
763 cp
->p
[0] = +(float) x
/ SCALE
;
764 cp
->p
[1] = +(float) z
/ SCALE
;
765 cp
->p
[2] = -(float) y
/ SCALE
;
770 static void make_bill(struct s_file
*fp
,
772 char v
[][MAXSTR
], short c
)
774 short i
, ri
= fp
->rc
++;
776 struct s_bill
*rp
= fp
->rv
+ ri
;
785 for (i
= 0; i
< c
; i
++)
787 if (strcmp(k
[i
], "angle") == 0)
788 sscanf(v
[i
], "%f", &rp
->z
);
790 if (strcmp(k
[i
], "radius") == 0)
792 sscanf(v
[i
], "%f", &rp
->w
);
793 sscanf(v
[i
], "%f", &rp
->h
);
796 if (strcmp(k
[i
], "width") == 0)
797 sscanf(v
[i
], "%f", &rp
->w
);
799 if (strcmp(k
[i
], "height") == 0)
800 sscanf(v
[i
], "%f", &rp
->h
);
802 if (strcmp(k
[i
], "image") == 0)
803 rp
->mi
= read_mtrl(fp
, v
[i
]);
805 if (strcmp(k
[i
], "origin") == 0)
807 short x
= 0, y
= 0, z
= 0;
809 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
811 rp
->p
[0] = +(float) x
/ SCALE
;
812 rp
->p
[1] = +(float) z
/ SCALE
;
813 rp
->p
[2] = -(float) y
/ SCALE
;
818 static void make_goal(struct s_file
*fp
,
820 char v
[][MAXSTR
], short c
)
822 short i
, zi
= fp
->zc
++;
824 struct s_goal
*zp
= fp
->zv
+ zi
;
831 for (i
= 0; i
< c
; i
++)
833 if (strcmp(k
[i
], "radius") == 0)
834 sscanf(v
[i
], "%f", &zp
->r
);
836 if (strcmp(k
[i
], "origin") == 0)
838 short x
= 0, y
= 0, z
= 0;
840 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
842 zp
->p
[0] = +(float) (x
) / SCALE
;
843 zp
->p
[1] = +(float) (z
- 24) / SCALE
;
844 zp
->p
[2] = -(float) (y
) / SCALE
;
849 static void make_view(struct s_file
*fp
,
851 char v
[][MAXSTR
], short c
)
853 short i
, wi
= fp
->wc
++;
855 struct s_view
*wp
= fp
->wv
+ wi
;
864 for (i
= 0; i
< c
; i
++)
866 if (strcmp(k
[i
], "target") == 0)
867 make_ref(v
[i
], targ_wi
+ wi
);
869 if (strcmp(k
[i
], "origin") == 0)
871 short x
= 0, y
= 0, z
= 0;
873 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
875 wp
->p
[0] = +(float) x
/ SCALE
;
876 wp
->p
[1] = +(float) z
/ SCALE
;
877 wp
->p
[2] = -(float) y
/ SCALE
;
882 static void make_jump(struct s_file
*fp
,
884 char v
[][MAXSTR
], short c
)
886 short i
, ji
= fp
->jc
++;
888 struct s_jump
*jp
= fp
->jv
+ ji
;
898 for (i
= 0; i
< c
; i
++)
900 if (strcmp(k
[i
], "radius") == 0)
901 sscanf(v
[i
], "%f", &jp
->r
);
903 if (strcmp(k
[i
], "target") == 0)
904 make_ref(v
[i
], targ_ji
+ ji
);
906 if (strcmp(k
[i
], "origin") == 0)
908 short x
= 0, y
= 0, z
= 0;
910 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
912 jp
->p
[0] = +(float) x
/ SCALE
;
913 jp
->p
[1] = +(float) z
/ SCALE
;
914 jp
->p
[2] = -(float) y
/ SCALE
;
919 static void make_swch(struct s_file
*fp
,
921 char v
[][MAXSTR
], short c
)
923 short i
, xi
= fp
->xc
++;
925 struct s_swch
*xp
= fp
->xv
+ xi
;
937 for (i
= 0; i
< c
; i
++)
939 if (strcmp(k
[i
], "radius") == 0)
940 sscanf(v
[i
], "%f", &xp
->r
);
942 if (strcmp(k
[i
], "target") == 0)
943 make_ref(v
[i
], &xp
->pi
);
945 if (strcmp(k
[i
], "timer") == 0)
946 sscanf(v
[i
], "%f", &xp
->t0
);
948 if (strcmp(k
[i
], "state") == 0)
951 if (strcmp(k
[i
], "origin") == 0)
953 short x
= 0, y
= 0, z
= 0;
955 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
957 xp
->p
[0] = +(float) x
/ SCALE
;
958 xp
->p
[1] = +(float) z
/ SCALE
;
959 xp
->p
[2] = -(float) y
/ SCALE
;
964 static void make_targ(struct s_file
*fp
,
966 char v
[][MAXSTR
], short c
)
970 targ_p
[targ_n
][0] = 0.f
;
971 targ_p
[targ_n
][1] = 0.f
;
972 targ_p
[targ_n
][3] = 0.f
;
974 for (i
= 0; i
< c
; i
++)
976 if (strcmp(k
[i
], "targetname") == 0)
977 make_sym(v
[i
], targ_n
);
979 if (strcmp(k
[i
], "origin") == 0)
981 short x
= 0, y
= 0, z
= 0;
983 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
985 targ_p
[targ_n
][0] = +(float) x
/ SCALE
;
986 targ_p
[targ_n
][1] = +(float) z
/ SCALE
;
987 targ_p
[targ_n
][2] = -(float) y
/ SCALE
;
994 static void make_ball(struct s_file
*fp
,
996 char v
[][MAXSTR
], short c
)
998 short i
, ui
= fp
->uc
++;
1000 struct s_ball
*up
= fp
->uv
+ ui
;
1024 for (i
= 0; i
< c
; i
++)
1026 if (strcmp(k
[i
], "radius") == 0)
1027 sscanf(v
[i
], "%f", &up
->r
);
1029 if (strcmp(k
[i
], "origin") == 0)
1031 short x
= 0, y
= 0, z
= 0;
1033 sscanf(v
[i
], "%hd %hd %hd", &x
, &y
, &z
);
1035 up
->p
[0] = +(float) (x
) / SCALE
;
1036 up
->p
[1] = +(float) (z
- 24) / SCALE
;
1037 up
->p
[2] = -(float) (y
) / SCALE
;
1041 up
->p
[1] += up
->r
+ SMALL
;
1044 /*---------------------------------------------------------------------------*/
1046 static void read_ent(struct s_file
*fp
, FILE *fin
)
1048 char k
[MAXKEY
][MAXSTR
];
1049 char v
[MAXKEY
][MAXSTR
];
1050 short t
, i
= 0, c
= 0;
1054 while ((t
= map_token(fin
, -1, k
[c
], v
[c
])))
1058 if (strcmp(k
[c
], "classname") == 0)
1062 if (t
== T_BEG
) read_lump(fp
, fin
);
1063 if (t
== T_END
) break;
1066 if (!strcmp(v
[i
], "light")) make_coin(fp
, k
, v
, c
);
1067 if (!strcmp(v
[i
], "info_camp")) make_swch(fp
, k
, v
, c
);
1068 if (!strcmp(v
[i
], "info_null")) make_bill(fp
, k
, v
, c
);
1069 if (!strcmp(v
[i
], "path_corner")) make_path(fp
, k
, v
, c
);
1070 if (!strcmp(v
[i
], "info_player_start")) make_ball(fp
, k
, v
, c
);
1071 if (!strcmp(v
[i
], "info_player_intermission")) make_view(fp
, k
, v
, c
);
1072 if (!strcmp(v
[i
], "info_player_deathmatch")) make_goal(fp
, k
, v
, c
);
1073 if (!strcmp(v
[i
], "target_teleporter")) make_jump(fp
, k
, v
, c
);
1074 if (!strcmp(v
[i
], "target_position")) make_targ(fp
, k
, v
, c
);
1075 if (!strcmp(v
[i
], "worldspawn")) make_body(fp
, k
, v
, c
, l0
);
1076 if (!strcmp(v
[i
], "func_train")) make_body(fp
, k
, v
, c
, l0
);
1077 if (!strcmp(v
[i
], "misc_model")) make_body(fp
, k
, v
, c
, l0
);
1080 static void read_map(struct s_file
*fp
, FILE *fin
)
1086 while ((t
= map_token(fin
, -1, k
, v
)))
1091 /*---------------------------------------------------------------------------*/
1093 /* Test the location of a point with respect to a side plane. */
1095 static int fore_side(const float p
[3], const struct s_side
*sp
)
1097 return (v_dot(p
, sp
->n
) - sp
->d
> +SMALL
) ? 1 : 0;
1100 static int on_side(const float p
[3], const struct s_side
*sp
)
1102 float d
= v_dot(p
, sp
->n
) - sp
->d
;
1104 return (-SMALL
< d
&& d
< +SMALL
) ? 1 : 0;
1107 /*---------------------------------------------------------------------------*/
1109 * Confirm that the addition of a vert would not result in degenerate
1113 static int ok_vert(const struct s_file
*fp
,
1114 const struct s_lump
*lp
, const float p
[3])
1119 for (i
= 0; i
< lp
->vc
; i
++)
1121 float *q
= fp
->vv
[fp
->iv
[lp
->v0
+ i
]].p
;
1125 if (v_len(r
) < SMALL
)
1131 /*---------------------------------------------------------------------------*/
1134 * The following functions take the set of planes defining a lump and
1135 * find the verts, edges, and geoms that describe its boundaries. To
1136 * do this, they first find the verts, and then search these verts for
1137 * valid edges and geoms. It may be more efficient to compute edges
1138 * and geoms directly by clipping down infinite line segments and
1139 * planes, but this would be more complex and prone to numerical
1144 * Given 3 side planes, compute the point of intersection, if any.
1145 * Confirm that this point falls within the current lump, and that it
1146 * is unique. Add it as a vert of the solid.
1148 static void clip_vert(struct s_file
*fp
,
1149 struct s_lump
*lp
, short si
, short sj
, short sk
)
1151 float M
[16], X
[16], I
[16];
1155 d
[0] = fp
->sv
[si
].d
;
1156 d
[1] = fp
->sv
[sj
].d
;
1157 d
[2] = fp
->sv
[sk
].d
;
1159 m_basis(M
, fp
->sv
[si
].n
, fp
->sv
[sj
].n
, fp
->sv
[sk
].n
);
1166 for (i
= 0; i
< lp
->sc
; i
++)
1168 short si
= fp
->iv
[lp
->s0
+ i
];
1170 if (fore_side(p
, fp
->sv
+ si
))
1174 if (ok_vert(fp
, lp
, p
))
1176 v_cpy(fp
->vv
[fp
->vc
].p
, p
);
1178 fp
->iv
[fp
->ic
] = fp
->vc
;
1187 * Given two side planes, find an edge along their intersection by
1188 * finding a pair of vertices that fall on both planes. Add it to the
1191 static void clip_edge(struct s_file
*fp
,
1192 struct s_lump
*lp
, short si
, short sj
)
1196 for (i
= 1; i
< lp
->vc
; i
++)
1197 for (j
= 0; j
< i
; j
++)
1199 short vi
= fp
->iv
[lp
->v0
+ i
];
1200 short vj
= fp
->iv
[lp
->v0
+ j
];
1202 if (on_side(fp
->vv
[vi
].p
, fp
->sv
+ si
) &&
1203 on_side(fp
->vv
[vj
].p
, fp
->sv
+ si
) &&
1204 on_side(fp
->vv
[vi
].p
, fp
->sv
+ sj
) &&
1205 on_side(fp
->vv
[vj
].p
, fp
->sv
+ sj
))
1207 fp
->ev
[fp
->ec
].vi
= vi
;
1208 fp
->ev
[fp
->ec
].vj
= vj
;
1210 fp
->iv
[fp
->ic
] = fp
->ec
;
1220 * Find all verts that lie on the given side of the lump. Sort these
1221 * verts to have a counter-clockwise winding about the plane normal.
1222 * Create geoms to tessalate the resulting convex polygon.
1224 static void clip_geom(struct s_file
*fp
,
1225 struct s_lump
*lp
, short si
)
1227 short m
[256], t
[256], d
, i
, j
, n
= 0;
1232 struct s_side
*sp
= fp
->sv
+ si
;
1236 for (i
= 0; i
< lp
->vc
; i
++)
1238 short vi
= fp
->iv
[lp
->v0
+ i
];
1240 if (on_side(fp
->vv
[vi
].p
, sp
))
1245 v_add(v
, fp
->vv
[vi
].p
, plane_p
[si
]);
1247 fp
->tv
[t
[n
]].u
[0] = v_dot(v
, plane_u
[si
]);
1248 fp
->tv
[t
[n
]].u
[1] = v_dot(v
, plane_v
[si
]);
1256 for (i
= 1; i
< n
; i
++)
1257 for (j
= i
+ 1; j
< n
; j
++)
1259 v_sub(u
, fp
->vv
[m
[i
]].p
, fp
->vv
[m
[0]].p
);
1260 v_sub(v
, fp
->vv
[m
[j
]].p
, fp
->vv
[m
[0]].p
);
1263 if (v_dot(w
, sp
->n
) < 0.f
)
1277 for (i
= 0; i
< n
- 2; i
++)
1279 fp
->gv
[fp
->gc
].mi
= plane_m
[si
];
1281 fp
->gv
[fp
->gc
].ti
= t
[0];
1282 fp
->gv
[fp
->gc
].tj
= t
[i
+ 1];
1283 fp
->gv
[fp
->gc
].tk
= t
[i
+ 2];
1285 fp
->gv
[fp
->gc
].si
= si
;
1286 fp
->gv
[fp
->gc
].sj
= si
;
1287 fp
->gv
[fp
->gc
].sk
= si
;
1289 fp
->gv
[fp
->gc
].vi
= m
[0];
1290 fp
->gv
[fp
->gc
].vj
= m
[i
+ 1];
1291 fp
->gv
[fp
->gc
].vk
= m
[i
+ 2];
1293 fp
->iv
[fp
->ic
] = fp
->gc
;
1301 * Iterate the sides of the lump, attemping to generate a new vert for
1302 * each trio of planes, a new edge for each pair of planes, and a new
1303 * set of geom for each visible plane.
1305 static void clip_lump(struct s_file
*fp
, struct s_lump
*lp
)
1312 for (i
= 2; i
< lp
->sc
; i
++)
1313 for (j
= 1; j
< i
; j
++)
1314 for (k
= 0; k
< j
; k
++)
1318 fp
->iv
[lp
->s0
+ k
]);
1323 for (i
= 1; i
< lp
->sc
; i
++)
1324 for (j
= 0; j
< i
; j
++)
1327 fp
->iv
[lp
->s0
+ j
]);
1332 for (i
= 0; i
< lp
->sc
; i
++)
1333 if (fp
->mv
[plane_m
[fp
->iv
[lp
->s0
+ i
]]].d
[3] > 0)
1335 fp
->iv
[lp
->s0
+ i
]);
1337 for (i
= 0; i
< lp
->sc
; i
++)
1338 if (plane_f
[fp
->iv
[lp
->s0
+ i
]])
1342 static void clip_file(struct s_file
*fp
)
1346 for (i
= 0; i
< fp
->lc
; i
++)
1347 clip_lump(fp
, fp
->lv
+ i
);
1350 /*---------------------------------------------------------------------------*/
1353 * For each body element type, determine if element 'p' is equivalent
1354 * to element 'q'. This is more than a simple memory compare. It
1355 * effectively snaps mtrls and verts togather, and may reverse the
1356 * winding of an edge or a geom. This is done in order to maximize
1357 * the number of elements that can be eliminated.
1360 static int comp_mtrl(const struct s_mtrl
*mp
, const struct s_mtrl
*mq
)
1362 if (fabs(mp
->d
[0] - mq
->d
[0]) > SMALL
) return 0;
1363 if (fabs(mp
->d
[1] - mq
->d
[1]) > SMALL
) return 0;
1364 if (fabs(mp
->d
[2] - mq
->d
[2]) > SMALL
) return 0;
1365 if (fabs(mp
->d
[3] - mq
->d
[3]) > SMALL
) return 0;
1367 if (fabs(mp
->a
[0] - mq
->a
[0]) > SMALL
) return 0;
1368 if (fabs(mp
->a
[1] - mq
->a
[1]) > SMALL
) return 0;
1369 if (fabs(mp
->a
[2] - mq
->a
[2]) > SMALL
) return 0;
1370 if (fabs(mp
->a
[3] - mq
->a
[3]) > SMALL
) return 0;
1372 if (fabs(mp
->s
[0] - mq
->s
[0]) > SMALL
) return 0;
1373 if (fabs(mp
->s
[1] - mq
->s
[1]) > SMALL
) return 0;
1374 if (fabs(mp
->s
[2] - mq
->s
[2]) > SMALL
) return 0;
1375 if (fabs(mp
->s
[3] - mq
->s
[3]) > SMALL
) return 0;
1377 if (fabs(mp
->e
[0] - mq
->e
[0]) > SMALL
) return 0;
1378 if (fabs(mp
->e
[1] - mq
->e
[1]) > SMALL
) return 0;
1379 if (fabs(mp
->e
[2] - mq
->e
[2]) > SMALL
) return 0;
1380 if (fabs(mp
->e
[3] - mq
->e
[3]) > SMALL
) return 0;
1382 if (fabs(mp
->h
[0] - mq
->h
[0]) > SMALL
) return 0;
1384 if (strncmp(mp
->f
, mq
->f
, PATHMAX
)) return 0;
1389 static int comp_vert(const struct s_vert
*vp
, const struct s_vert
*vq
)
1391 if (fabs(vp
->p
[0] - vq
->p
[0]) > SMALL
) return 0;
1392 if (fabs(vp
->p
[1] - vq
->p
[1]) > SMALL
) return 0;
1393 if (fabs(vp
->p
[2] - vq
->p
[2]) > SMALL
) return 0;
1398 static int comp_edge(const struct s_edge
*ep
, const struct s_edge
*eq
)
1400 if (ep
->vi
!= eq
->vi
&& ep
->vi
!= eq
->vj
) return 0;
1401 if (ep
->vj
!= eq
->vi
&& ep
->vj
!= eq
->vj
) return 0;
1406 static int comp_side(const struct s_side
*sp
, const struct s_side
*sq
)
1408 if (fabs(sp
->d
- sq
->d
) > SMALL
) return 0;
1409 if (v_dot(sp
->n
, sq
->n
) < 0.99999) return 0;
1414 static int comp_texc(const struct s_texc
*tp
, const struct s_texc
*tq
)
1416 if (fabs(tp
->u
[0] - tq
->u
[0]) > SMALL
) return 0;
1417 if (fabs(tp
->u
[1] - tq
->u
[1]) > SMALL
) return 0;
1422 static int comp_geom(const struct s_geom
*gp
, const struct s_geom
*gq
)
1424 if (gp
->mi
!= gq
->mi
) return 0;
1426 if (gp
->ti
!= gq
->ti
) return 0;
1427 if (gp
->si
!= gq
->si
) return 0;
1428 if (gp
->vi
!= gq
->vi
) return 0;
1430 if (gp
->tj
!= gq
->tj
) return 0;
1431 if (gp
->sj
!= gq
->sj
) return 0;
1432 if (gp
->vj
!= gq
->vj
) return 0;
1434 if (gp
->tk
!= gq
->tk
) return 0;
1435 if (gp
->sk
!= gq
->sk
) return 0;
1436 if (gp
->vk
!= gq
->vk
) return 0;
1441 /*---------------------------------------------------------------------------*/
1444 * For each file element type, replace all references to element 'i'
1445 * with a reference to element 'j'. These are used when optimizing
1446 * and sorting the file.
1449 static void swap_mtrl(struct s_file
*fp
, short mi
, short mj
)
1453 for (i
= 0; i
< fp
->gc
; i
++)
1454 if (fp
->gv
[i
].mi
== mi
) fp
->gv
[i
].mi
= mj
;
1455 for (i
= 0; i
< fp
->rc
; i
++)
1456 if (fp
->rv
[i
].mi
== mi
) fp
->rv
[i
].mi
= mj
;
1459 static void swap_vert(struct s_file
*fp
, short vi
, short vj
)
1463 for (i
= 0; i
< fp
->ec
; i
++)
1465 if (fp
->ev
[i
].vi
== vi
) fp
->ev
[i
].vi
= vj
;
1466 if (fp
->ev
[i
].vj
== vi
) fp
->ev
[i
].vj
= vj
;
1469 for (i
= 0; i
< fp
->gc
; i
++)
1471 if (fp
->gv
[i
].vi
== vi
) fp
->gv
[i
].vi
= vj
;
1472 if (fp
->gv
[i
].vj
== vi
) fp
->gv
[i
].vj
= vj
;
1473 if (fp
->gv
[i
].vk
== vi
) fp
->gv
[i
].vk
= vj
;
1476 for (i
= 0; i
< fp
->lc
; i
++)
1477 for (j
= 0; j
< fp
->lv
[i
].vc
; j
++)
1478 if (fp
->iv
[fp
->lv
[i
].v0
+ j
] == vi
)
1479 fp
->iv
[fp
->lv
[i
].v0
+ j
] = vj
;
1482 static void swap_edge(struct s_file
*fp
, short ei
, short ej
)
1486 for (i
= 0; i
< fp
->lc
; i
++)
1487 for (j
= 0; j
< fp
->lv
[i
].ec
; j
++)
1488 if (fp
->iv
[fp
->lv
[i
].e0
+ j
] == ei
)
1489 fp
->iv
[fp
->lv
[i
].e0
+ j
] = ej
;
1492 static void swap_side(struct s_file
*fp
, short si
, short sj
)
1496 for (i
= 0; i
< fp
->gc
; i
++)
1498 if (fp
->gv
[i
].si
== si
) fp
->gv
[i
].si
= sj
;
1499 if (fp
->gv
[i
].sj
== si
) fp
->gv
[i
].sj
= sj
;
1500 if (fp
->gv
[i
].sk
== si
) fp
->gv
[i
].sk
= sj
;
1502 for (i
= 0; i
< fp
->nc
; i
++)
1503 if (fp
->nv
[i
].si
== si
) fp
->nv
[i
].si
= sj
;
1505 for (i
= 0; i
< fp
->lc
; i
++)
1506 for (j
= 0; j
< fp
->lv
[i
].sc
; j
++)
1507 if (fp
->iv
[fp
->lv
[i
].s0
+ j
] == si
)
1508 fp
->iv
[fp
->lv
[i
].s0
+ j
] = sj
;
1511 static void swap_texc(struct s_file
*fp
, short ti
, short tj
)
1515 for (i
= 0; i
< fp
->gc
; i
++)
1517 if (fp
->gv
[i
].ti
== ti
) fp
->gv
[i
].ti
= tj
;
1518 if (fp
->gv
[i
].tj
== ti
) fp
->gv
[i
].tj
= tj
;
1519 if (fp
->gv
[i
].tk
== ti
) fp
->gv
[i
].tk
= tj
;
1524 static void swap_geom(struct s_file
*fp
, short gi
, short gj
)
1528 for (i
= 0; i
< fp
->lc
; i
++)
1529 for (j
= 0; j
< fp
->lv
[i
].gc
; j
++)
1530 if (fp
->iv
[fp
->lv
[i
].g0
+ j
] == gi
)
1531 fp
->iv
[fp
->lv
[i
].g0
+ j
] = gj
;
1533 for (i
= 0; i
< fp
->bc
; i
++)
1534 for (j
= 0; j
< fp
->bv
[i
].gc
; j
++)
1535 if (fp
->iv
[fp
->bv
[i
].g0
+ j
] == gi
)
1536 fp
->iv
[fp
->bv
[i
].g0
+ j
] = gj
;
1539 /*---------------------------------------------------------------------------*/
1541 static void uniq_mtrl(struct s_file
*fp
)
1545 for (i
= 0; i
< fp
->mc
; i
++)
1547 for (j
= 0; j
< i
; j
++)
1548 if (comp_mtrl(fp
->mv
+ i
, fp
->mv
+ j
))
1550 swap_mtrl(fp
, i
, j
);
1556 fp
->mv
[k
] = fp
->mv
[i
];
1557 swap_mtrl(fp
, i
, k
);
1565 static void uniq_vert(struct s_file
*fp
)
1569 for (i
= 0; i
< fp
->vc
; i
++)
1571 for (j
= 0; j
< i
; j
++)
1572 if (comp_vert(fp
->vv
+ i
, fp
->vv
+ j
))
1574 swap_vert(fp
, i
, j
);
1580 fp
->vv
[k
] = fp
->vv
[i
];
1581 swap_vert(fp
, i
, k
);
1589 static void uniq_edge(struct s_file
*fp
)
1593 for (i
= 0; i
< fp
->ec
; i
++)
1595 for (j
= 0; j
< i
; j
++)
1596 if (comp_edge(fp
->ev
+ i
, fp
->ev
+ j
))
1598 swap_edge(fp
, i
, j
);
1604 fp
->ev
[k
] = fp
->ev
[i
];
1605 swap_edge(fp
, i
, k
);
1613 static void uniq_geom(struct s_file
*fp
)
1617 for (i
= 0; i
< fp
->gc
; i
++)
1619 for (j
= 0; j
< i
; j
++)
1620 if (comp_geom(fp
->gv
+ i
, fp
->gv
+ j
))
1622 swap_geom(fp
, i
, j
);
1628 fp
->gv
[k
] = fp
->gv
[i
];
1629 swap_geom(fp
, i
, k
);
1637 static void uniq_texc(struct s_file
*fp
)
1641 for (i
= 0; i
< fp
->tc
; i
++)
1643 for (j
= 0; j
< i
; j
++)
1644 if (comp_texc(fp
->tv
+ i
, fp
->tv
+ j
))
1646 swap_texc(fp
, i
, j
);
1651 fp
->tv
[k
] = fp
->tv
[i
];
1652 swap_texc(fp
, i
, k
);
1660 static void uniq_side(struct s_file
*fp
)
1664 for (i
= 0; i
< fp
->sc
; i
++)
1666 for (j
= 0; j
< i
; j
++)
1667 if (comp_side(fp
->sv
+ i
, fp
->sv
+ j
))
1669 swap_side(fp
, i
, j
);
1674 fp
->sv
[k
] = fp
->sv
[i
];
1675 swap_side(fp
, i
, k
);
1683 static void uniq_file(struct s_file
*fp
)
1693 /*---------------------------------------------------------------------------*/
1695 static int test_lump_side(const struct s_file
*fp
,
1696 const struct s_lump
*lp
,
1697 const struct s_side
*sp
)
1705 /* If the given side is part of the given lump, then the lump is behind. */
1707 for (si
= 0; si
< lp
->sc
; si
++)
1708 if (fp
->sv
+ fp
->iv
[lp
->s0
+ si
] == sp
)
1711 /* Check if each lump vertex is in front of, behind, on the side. */
1713 for (vi
= 0; vi
< lp
->vc
; vi
++)
1715 float d
= v_dot(fp
->vv
[fp
->iv
[lp
->v0
+ vi
]].p
, sp
->n
) - sp
->d
;
1721 /* If no verts are behind, the lump is in front, and vice versa. */
1723 if (f
> 0 && b
== 0) return +1;
1724 if (b
> 0 && f
== 0) return -1;
1726 /* Else, the lump crosses the side. */
1731 static int node_node(struct s_file
*fp
, short l0
, short lc
)
1735 /* Base case. Dump all given lumps into a leaf node. */
1737 fp
->nv
[fp
->nc
].si
= -1;
1738 fp
->nv
[fp
->nc
].ni
= -1;
1739 fp
->nv
[fp
->nc
].nj
= -1;
1740 fp
->nv
[fp
->nc
].l0
= l0
;
1741 fp
->nv
[fp
->nc
].lc
= lc
;
1751 short li
= 0, lic
= 0;
1752 short lj
= 0, ljc
= 0;
1753 short lk
= 0, lkc
= 0;
1756 /* Find the side that most evenly splits the given lumps. */
1758 for (si
= 0; si
< fp
->sc
; si
++)
1764 for (li
= 0; li
< lc
; li
++)
1765 if ((k
= test_lump_side(fp
, fp
->lv
+ l0
+ li
, fp
->sv
+ si
)))
1772 if ((d
< sjd
) || (d
== sjd
&& o
< sjo
))
1780 /* Flag each lump with its position WRT the side. */
1782 for (li
= 0; li
< lc
; li
++)
1783 switch (test_lump_side(fp
, fp
->lv
+ l0
+ li
, fp
->sv
+ sj
))
1785 case +1: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x10; break;
1786 case 0: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x20; break;
1787 case -1: fp
->lv
[l0
+li
].fl
= (fp
->lv
[l0
+li
].fl
& 1) | 0x40; break;
1790 /* Sort all lumps in the range by their flag values. */
1792 for (li
= 1; li
< lc
; li
++)
1793 for (lj
= 0; lj
< li
; lj
++)
1794 if (fp
->lv
[l0
+ li
].fl
< fp
->lv
[l0
+ lj
].fl
)
1798 l
= fp
->lv
[l0
+ li
];
1799 fp
->lv
[l0
+ li
] = fp
->lv
[l0
+ lj
];
1800 fp
->lv
[l0
+ lj
] = l
;
1803 /* Establish the in-front, on, and behind lump ranges. */
1809 for (i
= lc
- 1; i
>= 0; i
--)
1810 switch (fp
->lv
[l0
+ i
].fl
& 0xf0)
1812 case 0x10: li
= l0
+ i
; lic
++; break;
1813 case 0x20: lj
= l0
+ i
; ljc
++; break;
1814 case 0x40: lk
= l0
+ i
; lkc
++; break;
1817 /* Add the lumps on the side to the node. */
1822 fp
->nv
[i
].ni
= node_node(fp
, li
, lic
);
1824 fp
->nv
[i
].nj
= node_node(fp
, lk
, lkc
);
1832 static void node_file(struct s_file
*fp
)
1836 /* Sort the lumps of each body into BSP nodes. */
1838 for (bi
= 0; bi
< fp
->bc
; bi
++)
1839 fp
->bv
[bi
].ni
= node_node(fp
, fp
->bv
[bi
].l0
, fp
->bv
[bi
].lc
);
1842 /*---------------------------------------------------------------------------*/
1844 static void dump_file(struct s_file
*p
, const char *name
)
1849 int m
= p
->rc
+ p
->cc
* 128 + (p
->zc
* p
->jc
+ p
->xc
) * 32;
1851 /* Count the number of solid lumps. */
1853 for (i
= 0; i
< p
->lc
; i
++)
1854 if ((p
->lv
[i
].fl
& 1) == 0)
1857 /* Count the number of visible geoms. */
1859 for (i
= 0; i
< p
->bc
; i
++)
1861 for (j
= 0; j
< p
->bv
[i
].lc
; j
++)
1862 m
+= p
->lv
[p
->bv
[i
].l0
+ j
].gc
;
1866 /* Count the total value of all coins. */
1868 for (i
= 0; i
< p
->cc
; i
++)
1871 printf("%s (%d/%d/$%d)\n"
1872 " mtrl vert edge side texc"
1873 " geom lump path node body\n"
1874 "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
1875 " coin goal view jump swch"
1876 " bill ball char indx\n"
1877 "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
1879 p
->mc
, p
->vc
, p
->ec
, p
->sc
, p
->tc
,
1880 p
->gc
, p
->lc
, p
->pc
, p
->nc
, p
->bc
,
1881 p
->cc
, p
->zc
, p
->wc
, p
->jc
, p
->xc
,
1882 p
->rc
, p
->uc
, p
->ac
, p
->ic
);
1885 int main(int argc
, char *argv
[])
1892 strncpy(src
, argv
[1], MAXSTR
);
1893 strncpy(dst
, argv
[1], MAXSTR
);
1894 strncpy(path
, argv
[2], MAXSTR
);
1896 if (strcmp(dst
+ strlen(dst
) - 4, ".map") == 0)
1897 strcpy(dst
+ strlen(dst
) - 4, ".sol");
1899 strcat(dst
, ".sol");
1901 if ((fin
= fopen(src
, "r")))
1921 fprintf(stderr
, "Usage: %s <map> <data>\n", argv
[0]);