1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * FrClip.c
21  *
22  * $Source: r:/prj/cit/src/RCS/frclip.c $
23  * $Revision: 1.12 $
24  * $Author: dc $
25  * $Date: 1994/09/10 00:30:09 $
26  *
27  * Citadel Renderer
28  *  various clippers for terrain, including basic cone clip and the later day
29  *   tile based clipper
30  *
31  * $Log: frclip.c $
32  * Revision 1.12  1994/09/10  00:30:09  dc
33  * this time i really think i fixed the malloc's
34  *
35  * Revision 1.11  1994/09/06  03:14:58  dc
36  * do cspace a little more correctly, eh?
37  *
38  * Revision 1.10  1994/09/05  08:33:35  dc
39  * hey how about not forgetting about cyberspace this time, eh?
40  *
41  * Revision 1.9  1994/09/05  06:43:26  dc
42  * span parse fixes, clear as we go
43  *
44  * Revision 1.8  1994/08/30  05:51:01  dc
45  * fix vanish if home square not drawn bug, othe rstuff
46  *
47  * Revision 1.7  1994/08/21  03:10:06  dc
48  * duh.
49  *
50  * Revision 1.6  1994/08/21  03:06:55  dc
51  * parameterize spawn_check, save a bit of code space
52  *
53  * Revision 1.5  1994/07/28  05:53:42  dc
54  * protection from span clip nightmare, what is cone doing...
55  *
56  * Revision 1.4  1994/03/13  17:18:04  dc
57  * doors take 38, still doesnt do minimal inclusion clips right
58  *
59  * Revision 1.3  1994/03/10  00:11:03  dc
60  * better door stuff, still need some stuff, though....
61  *
62  * Revision 1.2  1994/01/22  18:57:39  dc
63  * fix objclip to set correct bits of subclip, next switch it to flick_qclip
64  */
65 
66 #define __FRCLIP_SRC
67 
68 #include <stdlib.h>
69 #include <string.h>
70 
71 #include "frintern.h"
72 #include "frspans.h"
73 #include "frtables.h"
74 #include "fr3d.h"
75 #include "frquad.h"
76 #include "frflags.h"
77 #include "frparams.h"
78 #include "frsubclp.h"
79 #include "frshipm.h"
80 
81 #include "cone.h"
82 
83 #include "map.h"
84 #include "mapflags.h"
85 #include "tilename.h"
86 
87 // pre prototyping
88 static void _fr_rebuild_nVecWork(void);
89 static void _fr_init_vecwork(void);
90 static void clear_clip_bits(void);
91 
92 // for the subtile clipper
93 ushort sc_reg[NUM_SUBCLIP][SC_VEC_COUNT];
94 ushort *cur_sc_ptr;
95 uint cur_sc_reg;
96 
97 // Prototypes
98 void _fr_sclip_line(MapElem *sp_base, int len, int val);
99 void _fr_sclip_line_check_solid(MapElem *sp_base, int len, int val);
100 void fr_span_parse(void);
101 void span_fixup(void);
102 int fr_clip_show_all(void);
103 // uchar _fr_move_ccv_x(struct _nVecWork *nvp);
104 void _fr_move_along_dcode(int dircode);
105 
106 #ifndef MAP_RESIZING
107 static uchar real_x_spans[(1 << DEFAULT_YSHF) * SPAN_MEM];
108 static uchar real_cone_spans[(1 << DEFAULT_YSHF) * 2];
109 #endif
110 
fr_clip_freemem(void)111 int fr_clip_freemem(void) {
112     if (x_span_lists != NULL)
113         free(x_span_lists);
114     _fr_ret;
115 }
116 
fr_clip_resize(int x,int y)117 int fr_clip_resize(int x, int y) // x, y
118 {
119     int i;
120 #ifdef MAP_RESIZING
121     if (x_span_lists != NULL)
122         free(x_span_lists);
123     if (cone_span_list != NULL)
124         free(cone_span_list);
125     x_span_lists = (uchar *)malloc(y * SPAN_MEM * sizeof(uchar));
126     cone_span_list = (uchar *)malloc(y * 2 * sizeof(uchar));
127 #else
128     x_span_lists = &real_x_spans[0];
129     cone_span_list = &real_cone_spans[0];
130 #endif
131     _fr_rebuild_nVecWork();
132     _fr_init_vecwork();
133     _fr_dbg(if (x_span_lists == NULL) _fr_ret_val(FR_NOMEM));
134     _fr_dbg(if (cone_span_list == NULL) _fr_ret_val(FR_NOMEM));
135     for (i = 0; i < fr_map_y; i++)
136         span_count(i) = 0;
137     _fr_ret;
138 }
139 
fr_clip_frame_start(void)140 int fr_clip_frame_start(void) {
141     // setup real span lists
142     // setup real obj stack
143     //   _fr_init_vecwork();
144     // hmm... is this really necessary????
145     LG_memset(cone_span_list, 0xff, fr_map_y * 2 * sizeof(uchar));
146     _fr_sdbg(SANITY, _fr_init_vecwork()); // hey, why not?
147     _fr_ret;
148 }
149 
fr_clip_frame_end(void)150 int fr_clip_frame_end(void) {
151 #ifndef CLEAR_AS_WE_GO
152     clear_clip_bits();
153 #endif
154     _fr_ret;
155 }
156 
157 // cradle every word the falls
158 // into the arms of failure
store_x_span(int y,int lx,int rx)159 void store_x_span(int y, int lx, int rx) {
160     int c_span;
161 
162     c_span = span_count(y)++;
163     if (c_span >= MAX_SPANS) {
164         //      Warning(("HEY too many spans!!! y %d from %d to %d\n",y,lx,rx));  // should probably solve the problem
165         span_count(y)--;
166         c_span--;
167         span_right(y, c_span) = rx; // just add a new right edge
168     } else {
169         span_left(y, c_span) = lx;
170         span_right(y, c_span) = rx;
171     }
172     _fr_sdbg(VECSPEW, mprintf("Put %d->%d at span %d of %d\n", lx, rx, c_span, y));
173 
174 #ifdef _FR_TILEMAP
175     if (fr_highlights) {
176         LGPoint p;
177         for (p.x = lx, p.y = y; p.x <= rx; p.x++)
178             TileMapSetHighlight(NULL, p, 0, TRUE);
179     }
180 #endif // _FR_TILEMAP
181 }
182 
_fr_sclip_line(MapElem * sp_base,int len,int val)183 void _fr_sclip_line(MapElem *sp_base, int len, int val) {
184     _fr_sdbg(SPAN_PARSE, mprintf("yep, at %x, len %x, val %x\n", sp_base, len, val));
185     for (; len > 0; len--, sp_base++)
186         me_subclip(sp_base) = val;
187 }
188 
_fr_sclip_line_check_solid(MapElem * sp_base,int len,int val)189 void _fr_sclip_line_check_solid(MapElem *sp_base, int len, int val) {
190     _fr_sdbg(SPAN_PARSE, mprintf("yep, at %x, len %x, val %x\n", sp_base, len, val));
191     for (; len > 0; len--, sp_base++)
192         if (me_tiletype(sp_base) == TILE_SOLID)
193             me_subclip(sp_base) = SUBCLIP_OUT_OF_CONE;
194         else
195             me_subclip(sp_base) = val;
196 }
197 
198 // compute bounding box as well
199 extern MapElem *fr_map_base;
200 ushort frpipe_dist;
fr_span_parse(void)201 void fr_span_parse(void) {
202     int y, dist;
203     MapElem *cur_span = fr_map_base;
204     uchar *cur_span_cnt = &(span_count(0)), *cur_cone_span = &cone_span_list[0];
205 
206     frpipe_dist = 0;
207     for (y = 0; y < fr_map_y; y++, cur_span += fr_map_x, cur_span_cnt += (1 << SPAN_SHIFT), cur_cone_span += 2)
208         if (*cur_span_cnt) {
209             if ((*cur_span_cnt) == 1) {
210                 _fr_sdbg(SPAN_PARSE, mprintf("sc 1 at %x, going from %x to %x and %x to %x\n", y, *cur_cone_span,
211                                              span_left(y, 0), span_right(y, 0) + 1, *(cur_cone_span + 1)));
212                 _fr_sclip_line(cur_span + (*cur_cone_span), span_left(y, 0) - *cur_cone_span, SUBCLIP_OUT_OF_CONE);
213                 _fr_sclip_line(cur_span + span_right(y, 0) + 1, (*(cur_cone_span + 1)) - (span_right(y, 0) + 1) + 1,
214                                SUBCLIP_OUT_OF_CONE);
215             } else { // first merge wacky scenes....
216                 int cur_l, cur_r, span_id = 0, off_l;
217                 _fr_sdbg(SPAN_PARSE, for (cur_l = 0; cur_l < *cur_span_cnt; cur_l++)
218                                          mprintf("at %x MultiSpan %d from %x to %x\n", y, cur_l, span_left(y, cur_l),
219                                                  span_right(y, cur_l)));
220                 cur_l = span_left(y, 0);
221                 cur_r = span_right(y, 0);
222                 off_l = *cur_cone_span;
223                 while (++span_id < (*cur_span_cnt)) {
224                     if (span_left(y, span_id) <=
225                         cur_r) { // merge the spans into 1, but sclip clean any overlap pass first
226                         _fr_sdbg(SPAN_PARSE, mprintf("at %x Cleanup from %x to %x\n", y, span_left(y, span_id), cur_r));
227                         _fr_sclip_line(cur_span + span_left(y, span_id), cur_r - span_left(y, span_id) + 1,
228                                        SUBCLIP_FULL_TILE); // set them to no subclip
229                         if (cur_r < span_right(y, span_id)) {
230                             _fr_sdbg(SPAN_PARSE,
231                                      mprintf("span merge right to %x from %x\n", span_right(y, span_id), cur_r));
232                             cur_r = span_right(y, span_id);
233                         }
234                     } else {
235                         _fr_sdbg(SPAN_PARSE, mprintf("sent old span %x from %x to %x\n", y, off_l, cur_l));
236                         _fr_sclip_line(cur_span + off_l, cur_l - off_l, SUBCLIP_OUT_OF_CONE);
237                         off_l = cur_r + 1;
238                         cur_l = span_left(y, span_id);
239                         cur_r = span_right(y, span_id);
240                     }
241                 }
242                 _fr_sdbg(SPAN_PARSE, mprintf("loop done at %x, now sending %x -> %x and %x -> %x\n", y, off_l, cur_l,
243                                              cur_r + 1, *(cur_cone_span + 1)));
244                 _fr_sclip_line(cur_span + off_l, cur_l - off_l, SUBCLIP_OUT_OF_CONE);
245                 _fr_sclip_line(cur_span + cur_r + 1, (*(cur_cone_span + 1)) - (cur_r + 1) + 1, SUBCLIP_OUT_OF_CONE);
246             }
247             dist = abs(y - _fr_y_cen);
248             if ((dist + abs(span_left(y, 0) - _fr_x_cen)) > frpipe_dist)
249                 frpipe_dist = dist + abs(span_left(y, 0) - _fr_x_cen);
250             if ((dist + abs(span_right(y, (*cur_span_cnt) - 1) - _fr_x_cen)) > frpipe_dist)
251                 frpipe_dist = dist + abs(span_right(y, (*cur_span_cnt) - 1) - _fr_x_cen);
252 #ifdef CLEAR_AS_WE_GO
253             *cur_span_cnt = 0;
254 #endif
255         } else if (*cur_cone_span != 0xff) {
256             _fr_sdbg(SPAN_PARSE, mprintf("Cleaning up %x from %x to %x\n", y, *cur_cone_span, *(cur_cone_span + 1)));
257             _fr_sclip_line(cur_span + (*cur_cone_span), (*(cur_cone_span + 1)) - (*(cur_cone_span)) + 1,
258                            SUBCLIP_OUT_OF_CONE);
259         } // note the ()'s are right, it is (right edge) - (left edge) + 1
260 }
261 
span_fixup(void)262 void span_fixup(void) {
263     _fr_sdbg(VECSPEW,
264              mprintf("Center was %d spans, %d -> %d and %d -> %d\n", span_count(_fr_y_cen), span_left(_fr_y_cen, 0),
265                      span_right(_fr_y_cen, 0), span_left(_fr_y_cen, 1), span_right(_fr_y_cen, 1)));
266     if (span_count(_fr_y_cen) > 1) {
267         span_count(_fr_y_cen)--;
268         span_left(_fr_y_cen, 0) = lg_min(span_left(_fr_y_cen, 0), span_left(_fr_y_cen, 1));
269         span_right(_fr_y_cen, 0) = lg_max(span_right(_fr_y_cen, 0), span_right(_fr_y_cen, 1));
270     } else
271         WARN("%s: Only one span at y center", __FUNCTION__);
272     fr_span_parse();
273 #if _fr_defdbg(VECSPEW)
274     if (_fr_dbgflg_chk(VECSPEW)) {
275         int i, j, lc;
276         mprintf("At %d %d\n", _fr_x_cen, _fr_y_cen);
277         for (i = 0, lc = -1; i < fr_map_y; i++) {
278             if (span_count(i) == 0) {
279                 if (lc == -1)
280                     lc = i;
281             } else {
282                 if (lc != -1) {
283                     mprintf("y %d-%d have none\n", lc, i);
284                     lc = -1;
285                 }
286                 mprintf("y%d c%d: ", i, span_count(i));
287                 for (j = 0; j < span_count(i); j++)
288                     mprintf(" %d->%d", span_left(i, j), span_right(i, j));
289                 mprintf("\n");
290             }
291         }
292         if (lc != -1)
293             mprintf("y %d-%d have none\n", lc, i - 1);
294     }
295 #endif
296 }
297 
298 #define STAY_ON_MAP
cone_span_set(int y,int l,int r)299 void cone_span_set(int y, int l, int r) {
300     cone_span_list[y + y] = l;
301     cone_span_list[y + y + 1] = r;
302 }
303 
304 #ifndef CLEAR_AS_WE_GO
clear_clip_bits(void)305 static void clear_clip_bits(void) {
306     int i, j;
307     MapElem *mbptr = MAP_MAP, *mptr;
308     for (i = 0; i < fr_map_y; i++, mbptr += fr_map_x)
309         if (cone_span_left(i) != 0xff)
310             for (j = cone_span_left(i), mptr = mbptr + j; j <= cone_span_right(i); j++, mptr++)
311                 _me_subclip(mptr) = SUBCLIP_OUT_OF_CONE;
312 }
313 #endif
314 
set_clip_bits(void)315 static void set_clip_bits(void) {
316     int i;
317     MapElem *mbptr = MAP_MAP, *mptr, *rptr;
318     for (i = 0; i < fr_map_y; i++, mbptr += fr_map_x)
319         if (cone_span_left(i) != 0xff)
320             for (mptr = mbptr + cone_span_left(i), rptr = mbptr + cone_span_right(i); mptr <= rptr; mptr++)
321                 _me_subclip(mptr) = SUBCLIP_FULL_TILE;
322 }
323 
324 #if _fr_defdbg(NO_CONE)
set_full_cone(void)325 void set_full_cone(void) {}
326 #endif
327 
328 // satan got her tongue
329 // now, it's undone
fr_clip_cone(void)330 int fr_clip_cone(void) {
331     simple_cone_clip_pass();
332     //   _fr_ndbg(NO_CONE,simple_cone_clip_pass());
333     //   _fr_sdbg(NO_CONE,set_full_cone());
334     set_clip_bits();
335 
336 #if _fr_defdbg(VECSPEW)
337     if (_fr_dbgflg_chk(VECSPEW)) {
338         int i, lc;
339         mprintf("Cone from %d %d\n", _fr_x_cen, _fr_y_cen);
340         for (i = 0, lc = -1; i < fr_map_y; i++) {
341             if (cone_span_left(i) == 0xff) {
342                 if (lc == -1)
343                     lc = i;
344             } else {
345                 if (lc != -1) {
346                     mprintf("y %d-%d have none\n", lc, i);
347                     lc = -1;
348                 }
349                 mprintf("y%d: %d->%d\n", i, cone_span_left(i), cone_span_right(i));
350             }
351         }
352         if (lc != -1)
353             mprintf("y %d-%d have none\n", lc, i - 1);
354         mprintf("left (%x,%x), right (%x,%x)\n", span_intersect[0], span_intersect[1], span_intersect[2],
355                 span_intersect[3]);
356         mprintf("vec tl (%x,%x), vec tr (%x,%x)\n", span_lines[2], span_lines[3], span_lines[4], span_lines[5]);
357         mprintf("vec bl (%x,%x), vec br (%x,%x)\n", span_lines[0], span_lines[1], span_lines[6], span_lines[7]);
358         mprintf("Note eye @ %x %x, ang %x %x %x\n", coor(EYE_X), coor(EYE_Y), coor(EYE_H), coor(EYE_P), coor(EYE_B));
359     }
360 #endif
361     _fr_ret;
362 }
363 
364 // these two are a little unstoked at the moment
fr_clip_show_all(void)365 int fr_clip_show_all(void) {
366     MapElem *cur_span = fr_map_base;
367 #ifndef REALLY_ALL
368     uchar *cur_cone_span = &cone_span_left(0);
369     int i, dist;
370     for (i = 0; i < fr_map_y; i++, cur_span += fr_map_x, cur_cone_span += 2)
371         if ((*cur_cone_span) != 0xff) {
372 #ifndef CLEAR_AS_WE_GO
373             store_x_span(i, *cur_cone_span, *(cur_cone_span + 1));
374 #endif
375             _fr_sclip_line_check_solid(cur_span + (*cur_cone_span), *(cur_cone_span + 1) - *(cur_cone_span) + 1,
376                                        SUBCLIP_FULL_TILE);
377             dist = abs(i - _fr_y_cen);
378             if ((dist + abs(*cur_cone_span - _fr_x_cen)) > frpipe_dist)
379                 frpipe_dist = dist + abs(*cur_cone_span - _fr_x_cen);
380             if ((dist + abs(*(cur_cone_span + 1) - _fr_x_cen)) > frpipe_dist)
381                 frpipe_dist = dist + abs(*(cur_cone_span - 1) - _fr_x_cen);
382         }
383 #else
384     int y;
385     for (y = 0; y < fr_map_y; y++) {
386 #ifndef CLEAR_AS_WE_GO
387         store_x_span(y, 0, fr_map_x - 1);
388 #endif
389         _fr_sclip_line_check_solid(cur_span + (*cur_cone_span), *(cur_cone_span + 1) - *(cur_cone_span) + 1,
390                                    SUBCLIP_FULL_TILE);
391     }
392     if (_fr_x_cen < (fr_map_x >> 1))
393         dist = fr_map_x - _fr_x_cen;
394     else
395         dist = _fr_x_cen - fr_map_x;
396     if (_fr_y_cen < (fr_map_y >> 1))
397         dist += fr_map_y - _fr_y_cen;
398     else
399         dist = _fr_y_cen - fr_map_y;
400 #endif
401     _fr_ret;
402 }
403 
404 // when i hear the word security, i reach for my shotgun
405 typedef struct {
406     fix loc[3];    // current location of vector
407     fix deltas[3]; // current steps for vector
408     MapElem *mptr; // current map pointer
409     uchar flags;   // inuse, LR, pointer to self
410     uchar nxtv;    // for now, points to next
411     fix oldx;      // x at last y crossing
412     fix len;       // current vector length
413 } FrClipVec;
414 
415 struct _nVecWork {
416     fix remx;         // how far to go in x
417     short mapstep[2]; // how to move in map when going by x, y
418     uchar inface[2];  // inface for x and y
419     fix stepy;        // how far to go in y for a remx
420     uchar move_x;     // do we move in x?
421     uchar dircode;    // so we can get back out
422 };
423 
424 #define nVW_XDIR 2
425 #define nVW_YDIR 1
426 
427 #define nVW_NXNY 0
428 #define nVW_NXPY 1
429 #define nVW_PXNY 2
430 #define nVW_PXPY 3
431 
432 #define _fixp1 (fix_make(1, 0))
433 #define _fixn1 (-fix_make(1, 0))
434 static fix locstep[4][2] = {{_fixn1, _fixn1}, {_fixn1, _fixp1}, {_fixp1, _fixn1}, {_fixp1, _fixp1}};
435 static fix edgestep[4][2] = {{0, 0}, {0, _fixp1 - 1}, {_fixp1 - 1, 0}, {_fixp1 - 1, _fixp1 - 1}};
436 static char rmmod[4] = {-1, -1, 1, 1};       /* mod to rem to get to next full square */
437 static short new_del_mapstep[2] = {-32, 32}; /* wants to be wall_adds[2] and then wall_adds[0] */
438 static MapElem *eye_mptr;
439 
440 #define FRVECSELF 0x3F
441 #define FRVECMASK 0x3F
442 #define FRVECUSE  0x80
443 #define FRVECL    0x40
444 #define FRVECR    0x00
445 #define FRVECDIR  0x40
446 
447 #define MS_X 0
448 #define MS_Y 1
449 
450 #define MAX_CLIP_VEC 16
451 static FrClipVec allclipv[MAX_CLIP_VEC];
452 static FrClipVec *ccv;
453 static char vechead = 0, ffreevec = 0, lastvec = -1, endvec = MAX_CLIP_VEC - 1;
454 
455 struct _nVecWork _nVP[4] = {{0xdeadbeef, -1, -64, 3, 2, 0xdeadbeef, 0xff, nVW_NXNY},
456                             {0xdeadbeef, -1, 64, 3, 0, 0xdeadbeef, 0xff, nVW_NXPY},
457                             {0xdeadbeef, 1, -64, 1, 2, 0xdeadbeef, 0xff, nVW_PXNY},
458                             {0xdeadbeef, 1, 64, 1, 0, 0xdeadbeef, 0xff, nVW_PXPY}};
459 
460 // this is a gross way to do this...
461 #define _fr_build_clip_vec(cv, org, ray, aflags)               \
462     (cv)->len = 0;                                             \
463     (cv)->flags = ((cv)->flags & FRVECMASK) + aflags;          \
464     (cv)->mptr = MAP_GET_XY(fix_int(org[0]), fix_int(org[1])); \
465     (cv)->loc[0] = org[0];                                     \
466     (cv)->loc[1] = org[1];                                     \
467     (cv)->loc[2] = org[2];                                     \
468     cv->oldx = org[0];                                         \
469     (cv)->deltas[0] = ray[0];                                  \
470     (cv)->deltas[1] = ray[1];                                  \
471     (cv)->deltas[2] = ray[2]
472 
473 // More prototypes
474 uchar _fr_skip_solid_right_n_back(FrClipVec *cv, fix max_loc, int y_map_step);
475 uchar _fr_skip_space_right_n_back(FrClipVec *cv, fix max_loc, int y_map_step);
476 uchar _fr_skip_solid_left_n_back(FrClipVec *cv, fix min_loc, int y_map_step);
477 void _fr_del_compute(FrClipVec *v1, FrClipVec *v2);
478 void _fr_spawn_check_one(FrClipVec *lv, FrClipVec *rv, uchar northward);
479 uchar _fr_move_new_dels(FrClipVec *lv, FrClipVec *rv, uchar northward);
480 void _fr_kill_pair(FrClipVec *lv, FrClipVec *rv);
481 uchar _fr_setup_first_pair(uchar headnorth);
482 
483 // these dont really work, the *org, *ray doesnt move all 3
484 // (*((cv)->loc))=*org; (*((cv)->deltas))=*ray;
485 // this gets a missing lvalue stupidity
486 // (cv)->loc=org; (cv)->deltas=ray;
487 
_fr_rebuild_nVecWork(void)488 static void _fr_rebuild_nVecWork(void) {
489     _nVP[nVW_NXNY].mapstep[MS_X] = _nVP[nVW_NXPY].mapstep[MS_X] = wall_adds[3];
490     _nVP[nVW_PXNY].mapstep[MS_X] = _nVP[nVW_PXPY].mapstep[MS_X] = wall_adds[1];
491     _nVP[nVW_NXNY].mapstep[MS_Y] = _nVP[nVW_PXNY].mapstep[MS_Y] = wall_adds[2];
492     _nVP[nVW_NXPY].mapstep[MS_Y] = _nVP[nVW_PXPY].mapstep[MS_Y] = wall_adds[0];
493     new_del_mapstep[0] = wall_adds[2];
494     new_del_mapstep[1] = wall_adds[0];
495 }
496 
_fr_init_vecwork(void)497 static void _fr_init_vecwork(void) {
498     int i;
499     for (i = 0; i < MAX_CLIP_VEC; i++) // point at self and next
500     {
501         allclipv[i].flags = i;
502         allclipv[i].nxtv = (i + 1) & (MAX_CLIP_VEC - 1);
503     }
504     vechead = 0;
505     ffreevec = 0;
506     lastvec = -1;
507     endvec = MAX_CLIP_VEC - 1;
508 }
509 
510 #if _fr_defdbg(VECSPEW)
print_nvp(struct _nVecWork * nvp)511 void print_nvp(struct _nVecWork *nvp) {
512     static char *nvm_str[4] = {"nxny", "nxpy", "pxny", "pxpy"};
513     static char ifc_str[4] = {'n', 'e', 's', 'w'};
514     mprintf(" _nVP xrem %x stepy %x. move_x %d std %s %c%c %d %d\n", nvp->remx, nvp->stepy, nvp->move_x,
515             nvm_str[nvp->dircode], ifc_str[nvp->inface[0]], ifc_str[nvp->inface[1]], nvp->mapstep[0], nvp->mapstep[1]);
516 }
517 
print_fcv(FrClipVec * _ccv,int dim)518 void print_fcv(FrClipVec *_ccv, int dim) {
519     if (dim == 3)
520         mprintf(" _ccv @(%x,%x,%x),d(%x,%x,%x)..", _ccv->loc[0], _ccv->loc[1], _ccv->loc[2], _ccv->deltas[0],
521                 _ccv->deltas[1], _ccv->deltas[2]);
522     else
523         mprintf(" _ccv @(%x,%x),d(%x,%x)..", _ccv->loc[0], _ccv->loc[1], _ccv->deltas[0], _ccv->deltas[1]);
524     mprintf("ox%x mp%x fl%xnx%x\n", _ccv->oldx, _ccv->mptr, _ccv->flags, _ccv->nxtv);
525 }
526 #else
527 #define print_nvp(a)
528 #define print_fcv(a, b)
529 #endif
530 
531 static uchar *_face_curedge, *_face_nxtedge;
532 static uchar _face_curmask, _face_nxtmask;
533 static uchar _face_topmask, _face_botmask;
534 
535 //#define out_of_cone (me_bits_seen_p(mp)==0)
536 #define out_of_cone(mp) (me_subclip(mp) == SUBCLIP_OUT_OF_CONE)
537 
538 // indexed by (vecside)+(dircode<<2)+xdir/ydir, with do nothings for second at Y
539 static uchar _sclip_major_mask[9][2] = {{FMK_SW, FMK_EW}, {FMK_SW, FMK_WW}, {FMK_NW, FMK_EW},
540                                         {FMK_NW, FMK_WW}, {FMK_NW, FMK_WW}, {FMK_NW, FMK_EW},
541                                         {FMK_SW, FMK_WW}, {FMK_SW, FMK_EW}, {0, 0}};
542 
543 static uchar _sclip_door_mask[9][2] = {{FMK_INT_NW, FMK_INT_EW}, {FMK_INT_NW, FMK_INT_WW}, {FMK_INT_SW, FMK_INT_EW},
544                                        {FMK_INT_SW, FMK_INT_WW}, {FMK_INT_SW, FMK_INT_WW}, {FMK_INT_SW, FMK_INT_EW},
545                                        {FMK_INT_NW, FMK_INT_WW}, {FMK_INT_NW, FMK_INT_EW}, {0, 0}};
546 
547 static uchar *_sclip_mask, *_sclip_door;
548 
549 // assumes ccv is us
550 // moves until next y span is hit, i guess
551 // perhaps will have to learn about it's partner vector?
552 // strip the gloss from a beauty queen
_fr_move_ccv_x(struct _nVecWork * nvp)553 uchar _fr_move_ccv_x(struct _nVecWork *nvp) {
554     int tt, oflow;
555     uchar move_in_y = TRUE, move_in_x = TRUE;
556 
557     // should be saving off texture cuts some day!!
558     ccv->loc[1] += nvp->stepy;
559     tt = me_tiletype(ccv->mptr);
560     if (fr_obj_block(ccv->mptr, _sclip_door, (int *)ccv->loc) ||
561         ((_face_curedge[tt << 2] == 0xff) ||
562          (me_clearsolid(ccv->mptr) &
563           _face_curmask))) { // these really have to get wacky and learn about partial obscuration
564         move_in_x = move_in_y = FALSE;
565         _fr_sdbg(VECSPEW, mprintf("move_x(top): hit our tile\n"));
566     } else {
567         _fr_sdbg(VECSPEW, mprintf("move_x(top): sub_clip or %x, old %x\n", _sclip_mask[0], me_subclip(ccv->mptr)));
568         _me_subclip(ccv->mptr) |= _sclip_mask[0];
569         ccv->mptr += nvp->mapstep[0];
570         tt = me_tiletype(ccv->mptr);
571         if ((_face_nxtedge[tt << 2] == 0xff) || (me_clearsolid(ccv->mptr) & _face_nxtmask) ||
572             out_of_cone(ccv->mptr)) { // these really have to get wacky and learn about partial obscuration
573             move_in_x = move_in_y = FALSE;
574             ccv->mptr -= nvp->mapstep[0];
575             _fr_sdbg(VECSPEW, mprintf("move_x top: hit other tile\n"));
576         } else { // correct for new setup
577             ccv->loc[0] += nvp->remx + rmmod[nvp->dircode];
578             nvp->remx = locstep[nvp->dircode][0];
579             nvp->stepy = fix_mul_div(ccv->deltas[1], nvp->remx, ccv->deltas[0]);
580             _fr_sdbg(VECSPEW, mprintf("move_x top: move and recompute step\n"));
581         }
582     }
583     _fr_sdbg(VECSPEW, {
584         mprintf("move_x top:\n");
585         print_fcv(ccv, 2);
586         print_nvp(nvp);
587     });
588 
589     oflow = ccv->loc[1] & 0xffff;
590     while (move_in_x) {
591         oflow += nvp->stepy;
592         if (oflow & 0xffff0000) { // perhaps should get more elegant, but i mean really, how could it?
593             move_in_x = FALSE;
594             move_in_y = TRUE;
595             _fr_sdbg(VECSPEW, mprintf("move_x(while): reached y\n"));
596         } else {
597             ccv->loc[1] += nvp->stepy;
598             // can we leave the square there?
599             tt = me_tiletype(ccv->mptr);
600             // no matter what, we can get out of ourselves?
601             if (fr_obj_block(ccv->mptr, _sclip_door, (int *)ccv->loc) ||
602                 ((_face_curedge[tt << 2] == 0xff) ||
603                  (me_clearsolid(ccv->mptr) &
604                   _face_curmask))) { // these really have to get wacky and learn about partial obscuration
605                 move_in_x = move_in_y = FALSE;
606                 _fr_sdbg(VECSPEW, mprintf("move_x(while): hit our tile\n"));
607             } else {
608                 _fr_sdbg(VECSPEW,
609                          mprintf("move_x(while): sub_clip or %x, old %x\n", _sclip_mask[0], me_subclip(ccv->mptr)));
610                 _me_subclip(ccv->mptr) |= _sclip_mask[0];
611                 ccv->mptr += nvp->mapstep[0];
612                 tt = me_tiletype(ccv->mptr);
613                 if ((_face_nxtedge[tt << 2] == 0xff) || (me_clearsolid(ccv->mptr) & _face_nxtmask) ||
614                     out_of_cone(ccv->mptr)) { // these really have to get wacky and learn about partial obscuration
615                     move_in_x = move_in_y = FALSE;
616                     ccv->mptr -= nvp->mapstep[0];
617                     _fr_sdbg(VECSPEW, mprintf("move_x(while): hit other tile\n"));
618                 } else {
619                     ccv->loc[0] += locstep[nvp->dircode][0];
620                     _fr_sdbg(VECSPEW, mprintf("move_x: moving ccv\n"));
621                 }
622             }
623         }
624         _fr_sdbg(VECSPEW, {
625             mprintf("move_x(while):\n");
626             print_fcv(ccv, 2);
627             print_nvp(nvp);
628         });
629     }
630 
631     // should go back to this, it should add to oflow, non add to loc[1] in loop, then do loc[1]|=(oflow-stepy)
632     //   if (move_in_y) ccv->loc[1]-=nvp->stepy;      // undo the step that went too far(tm)
633 
634     return move_in_y;
635     // compute intersection
636     // if not clear internally, migrate to clear point, recompute
637     //   if now clear internally, move mptr and vec to next square
638     //   if not, backup pointers, return FALSE
639     // check crossin clear, if clear return TRUE
640     // if not clear, migrate to next clear point, recompute
641     //   if now clear, return TRUE
642     //   if not, backup pointers if appropriate, return FALSE
643 }
644 
_fr_move_along_dcode(int dircode)645 void _fr_move_along_dcode(int dircode) {
646     uchar move_in_y = TRUE;
647     struct _nVecWork *nvp = &_nVP[dircode];
648 
649     if (dircode & nVW_XDIR)
650         nvp->remx = _fixp1 - 1 - fix_frac(ccv->loc[0]);
651     else
652         nvp->remx = -fix_frac(ccv->loc[0]);
653 
654     if (ccv->deltas[1] == 0) // no y delta
655     {
656         nvp->move_x = TRUE;
657         nvp->stepy = 0;
658     }                             // lets do the flat line thing
659     else if (ccv->deltas[0] == 0) // just do a single y step
660         nvp->move_x = FALSE;      // no need to set step or anything
661     else                          // replace with wacky table neg?
662     {                             // get the signs right, as it were
663         if (nvp->remx)
664             switch (dircode) { // these just arent right
665             case nVW_NXNY:
666                 nvp->move_x = (-nvp->remx * ccv->deltas[1] > (fix_frac(ccv->loc[1])) * (ccv->deltas[0]));
667                 break; // flip sign for --
668             case nVW_NXPY:
669                 nvp->move_x = (nvp->remx * ccv->deltas[1] > (_fixp1 - 1 - fix_frac(ccv->loc[1])) * (ccv->deltas[0]));
670                 break; // flip xd, sign
671             case nVW_PXNY:
672                 nvp->move_x = (-nvp->remx * ccv->deltas[1] < (fix_frac(ccv->loc[1])) * ccv->deltas[0]);
673                 break; // flip yd, sign
674             case nVW_PXPY:
675                 nvp->move_x = (nvp->remx * ccv->deltas[1] < (_fixp1 - 1 - fix_frac(ccv->loc[1])) * ccv->deltas[0]);
676                 break; // all things good
677             }
678         else
679             nvp->move_x = TRUE;
680         if (nvp->move_x)
681             nvp->stepy = fix_mul_div(nvp->remx, ccv->deltas[1], ccv->deltas[0]);
682     }
683 
684     // this is dumb, we want the second to be based on primary
685     if (ccv->mptr == eye_mptr) // ( () &&((nvp->dircode&nVW_YDIR)==0))
686     {
687         _sclip_mask = &_sclip_major_mask[8][0];
688         //      _sclip_door=&_sclip_door_mask[8][0];
689     } else {
690         _sclip_mask = (&_sclip_major_mask[0][0]) + ((ccv->flags & FRVECDIR) >> 3) + (dircode + dircode);
691         //      _sclip_door=(&_sclip_door_mask[0][0])+((ccv->flags&FRVECDIR)>>3)+(dircode+dircode);
692     }
693     _sclip_door = (&_sclip_door_mask[0][0]) + ((ccv->flags & FRVECDIR) >> 3) + (dircode + dircode);
694 
695     _fr_sdbg(VECSPEW, {
696         mprintf("move_along(new_vec): sclip offs %d d%d (%d,%d)\n", _sclip_mask - _sclip_major_mask, dircode,
697                 *_sclip_mask, *(_sclip_mask + 1));
698         print_fcv(ccv, 2);
699         print_nvp(nvp);
700     });
701 
702     if (nvp->move_x) {
703         if (dircode & nVW_XDIR) {
704             _face_curedge = &face_obstruct[0][1];
705             _face_nxtedge = &face_obstruct[0][3];
706             _face_curmask = FMK_INT_EW;
707             _face_nxtmask = FMK_INT_WW;
708         } else {
709             _face_curedge = &face_obstruct[0][3];
710             _face_nxtedge = &face_obstruct[0][1];
711             _face_curmask = FMK_INT_WW;
712             _face_nxtmask = FMK_INT_EW;
713         }
714         move_in_y = _fr_move_ccv_x(nvp);
715     }
716 
717     // the more he likes me, the more i drink
718     // i think the more i drink the more he likes me
719     if (move_in_y) { // actually move in y
720         fix nstp;
721         if (dircode & nVW_YDIR)
722             nstp = _fixp1 - 1 - fix_frac(ccv->loc[1]);
723         else
724             nstp = -fix_frac(ccv->loc[1]);
725         nstp = fix_mul_div(nstp, ccv->deltas[0], ccv->deltas[1]);
726         ccv->loc[0] += nstp;
727         ccv->loc[1] &= 0xffff0000; // this will go away in asm, as all we need to do is set the bottom
728         ccv->loc[1] += edgestep[dircode][1];
729         _fr_sdbg(VECSPEW, mprintf("move_y(if): sub_clip or %x, old %x\n", _sclip_mask[1], me_subclip(ccv->mptr)));
730         _me_subclip(ccv->mptr) |= _sclip_mask[1];
731         _fr_sdbg(VECSPEW, {
732             mprintf("move_y(if): nstp %x\n", nstp);
733             print_fcv(ccv, 2);
734         });
735     } else { // pop up to top of square, for now, no f_o usage
736         // wow this is a slow dumb way to do this, eh?
737         ccv->loc[1] &= 0xffff0000; // the ands go away in assembler, as we need only set the bottom
738         ccv->loc[0] &= 0xffff0000;
739         ccv->loc[0] += edgestep[dircode][0];
740         ccv->loc[1] += edgestep[dircode][1];
741 #ifdef SWITCH_IS_FASTER_MAYBE
742         switch (dircode) {
743         case nVW_NXNY:
744             ccv->loc[0] &= 0xffff0000;
745             ccv->loc[1] &= 0xffff0000;
746             break;
747         case nVW_NXPY:
748             ccv->loc[0] &= 0xffff0000;
749             ccv->loc[1] |= 0x0000ffff;
750             break;
751         case nVW_PXNY:
752             ccv->loc[0] |= 0x0000ffff;
753             ccv->loc[1] &= 0xffff0000;
754             break;
755         case nVW_PXPY:
756             ccv->loc[0] |= 0x0000ffff;
757             ccv->loc[1] |= 0x0000ffff;
758             break;
759         }
760 #endif
761 #ifdef ANOTHER_WACKY_WAY
762         if (dircode & nVW_XDIR)
763             ccv->loc[0] |= 0x0000ffff;
764         else
765             ccv->loc[0] &= 0xffff0000;
766         if (dircode & nVW_YDIR)
767             ccv->loc[1] |= 0x0000ffff;
768         else
769             ccv->loc[1] &= 0xffff0000;
770 #endif
771         _fr_sdbg(VECSPEW, mprintf("move_y(else): sub_clip or %x, old %x\n", _sclip_mask[0], me_subclip(ccv->mptr)));
772         _me_subclip(ccv->mptr) |= _sclip_mask[0];
773         _fr_sdbg(VECSPEW, {
774             mprintf("move_y(else):\n");
775             print_fcv(ccv, 2);
776         });
777     }
778     _fr_sdbg(VECSPEW, {
779         mprintf("move_along(end):\n");
780         print_fcv(ccv, 2);
781         print_nvp(nvp);
782     });
783 }
784 
785 #define _fr_move_along_hn_p(x) _fr_move_along_dcode(((ccv->deltas[0] > 0) ? nVW_XDIR : 0) + x)
786 
787 static uchar *_face_topedge, *_face_botedge;
788 
789 // partial tiles? who knows when
790 
791 // note fullwise, at the moment the subclip&face_topmask in middle gets doors, whereas the
792 //  subclip==SUBCLIP_OUT_OF_CONE gets itself, though in reality and face_botmask would do same thing, i think
793 
794 // wow is this a total mess, goddamn
795 #define is_solid()                                                                                                     \
796     ((_face_topedge[(me_tiletype(cv->mptr) << 2)] == 0xff) || (me_clearsolid(cv->mptr) & _face_topmask) ||             \
797      (me_subclip(cv->mptr) & _face_topmask) || (_face_botedge[(me_tiletype((cv->mptr + y_map_step)) << 2)] == 0xff) || \
798      (me_clearsolid((cv->mptr + y_map_step)) & _face_botmask) ||                                                       \
799      (me_subclip(cv->mptr + y_map_step) == SUBCLIP_OUT_OF_CONE))
800 
801 #define is_space()                                                                                                \
802     ((_face_topedge[(me_tiletype(cv->mptr) << 2)] != 0xff) && ((me_clearsolid(cv->mptr) & _face_topmask) == 0) && \
803      ((me_subclip(cv->mptr) & _face_topmask) == 0) &&                                                             \
804      (_face_botedge[(me_tiletype((cv->mptr + y_map_step)) << 2)] != 0xff) &&                                      \
805      ((me_clearsolid((cv->mptr + y_map_step)) & _face_botmask) == 0))
806 
807 // note how pretty this looks till you look at the is_solid macro
_fr_skip_solid_right_n_back(FrClipVec * cv,fix max_loc,int y_map_step)808 uchar _fr_skip_solid_right_n_back(FrClipVec *cv, fix max_loc, int y_map_step) {
809     if (is_solid()) {
810         cv->loc[0] &= 0xffff0000;
811         cv->loc[0] += _fixp1;
812         cv->mptr += 1;
813         while (is_solid() && (cv->loc[0] < max_loc)) {
814             cv->loc[0] += _fixp1;
815             cv->mptr += 1;
816         }
817     }
818     return (cv->loc[0] >= max_loc);
819 }
820 
_fr_skip_space_right_n_back(FrClipVec * cv,fix max_loc,int y_map_step)821 uchar _fr_skip_space_right_n_back(FrClipVec *cv, fix max_loc, int y_map_step) {
822     if (is_space()) {
823         cv->loc[0] &= 0xffff0000;
824         cv->loc[0] += _fixp1;
825         cv->mptr += 1;
826         while (is_space() && (cv->loc[0] < max_loc)) {
827             cv->loc[0] += _fixp1;
828             cv->mptr += 1;
829         }
830     }
831     return (cv->loc[0] >= max_loc);
832 }
833 
_fr_skip_solid_left_n_back(FrClipVec * cv,fix min_loc,int y_map_step)834 uchar _fr_skip_solid_left_n_back(FrClipVec *cv, fix min_loc, int y_map_step) {
835     if (is_solid()) {
836         cv->loc[0] |= 0x0000ffff;
837         cv->loc[0] += _fixn1;
838         cv->mptr += -1;
839         while (is_solid() && (min_loc < cv->loc[0])) {
840             cv->loc[0] += _fixn1;
841             cv->mptr += -1;
842         }
843     }
844     return (cv->loc[0] <= min_loc);
845 }
846 
847 #define DT_SHFT (8)
848 #define DT_FAKE ((1 << DT_SHFT) - 1)
849 #define fixup_delta(dlta)                     \
850     if ((dlta) > 0)                           \
851         dlta = ((dlta) + DT_FAKE) >> DT_SHFT; \
852     else                                      \
853         (dlta) = ((dlta)-DT_FAKE) >> DT_SHFT;
854 
_fr_del_compute(FrClipVec * v1,FrClipVec * v2)855 void _fr_del_compute(FrClipVec *v1, FrClipVec *v2) {
856     v1->deltas[0] = v1->loc[0] - coor(EYE_X);
857     v1->deltas[1] = v1->loc[1] - coor(EYE_Y);
858     fixup_delta(v1->deltas[0]);
859     fixup_delta(v1->deltas[1]);
860     v2->deltas[0] = v2->loc[0] - coor(EYE_X);
861     v2->deltas[1] = v2->loc[1] - coor(EYE_Y);
862     fixup_delta(v2->deltas[0]);
863     fixup_delta(v2->deltas[1]);
864     v1->oldx = v1->loc[0];
865     v2->oldx = v2->loc[0];
866 }
867 
_fr_spawn_check_one(FrClipVec * lv,FrClipVec * rv,uchar northward)868 void _fr_spawn_check_one(FrClipVec *lv, FrClipVec *rv, uchar northward) {
869     FrClipVec *tmpr, *tmpl;
870     short cur_mapstep = new_del_mapstep[northward];
871     int nxts;
872 
873     while (1) // really, run till we find the right edge
874     {
875         tmpr = allclipv + ffreevec;
876         nxts = tmpr->nxtv;
877         *tmpr = *lv; // perhaps should back up a mapstep and check for other half tiles first
878         tmpr->nxtv = nxts;
879         tmpr->flags = ffreevec;                                          // fixup next and self
880         if (!_fr_skip_space_right_n_back(tmpr, rv->loc[0], cur_mapstep)) // really should do render bit setup here...
881         { // ok lv->rv->?, and tmpr->tmpl->vecx, ffreevec->tmpr... we want lv->tmpr->tmpl->rv, ffreevec->vecx
882             _fr_sdbg(VECSPEW, {
883                 mprintf("new_dels(spawn): found ");
884                 print_fcv(tmpr, 2);
885             });
886             tmpl = allclipv + nxts; // tmpl is next free vec, as nxts is tmpr->nxtv and tmpr was ffreevec
887             ffreevec = tmpl->nxtv;  // point ffreevec at tmpl's old next, as tmpl and tmpr are from free list
888             *tmpl = *tmpr;
889             tmpl->nxtv = lv->nxtv;  // point tmpl->rv, lv's old friend
890             lv->nxtv = tmpr->flags; // we havent or'red in real flag data, so flags is currently just self for tmpr
891             tmpl->flags =
892                 tmpr->nxtv; // tmpr->nxtv never changes, it is always pointing at tmpl, so tmpl can self set with it
893 #if _fr_defdbg(SANITY)
894             if (_fr_skip_solid_right_n_back(tmpl, rv->loc[0], cur_mapstep)) // this is true
895                 mprintf("new_dels(spawn) ERR: found middle with no right edge\n");
896 #else
897             _fr_skip_solid_right_n_back(tmpl, rv->loc[0], cur_mapstep);
898 #endif
899             tmpr->loc[0]--;
900             tmpr->mptr--; // note that tmpl is a-ok
901             if (northward) {
902                 tmpr->flags |= FRVECUSE | FRVECL;
903                 tmpl->flags |= FRVECUSE | FRVECR;
904             } else {
905                 tmpl->flags |= FRVECUSE | FRVECL;
906                 tmpr->flags |= FRVECUSE | FRVECR;
907             }
908             _fr_sdbg(VECSPEW, {
909                 mprintf("new_dels(spawn): generated\n");
910                 print_fcv(tmpr, 2);
911                 print_fcv(tmpl, 2);
912             });
913             (allclipv + lastvec)->nxtv = ffreevec;
914             _fr_del_compute(tmpl, tmpr);
915             lv = tmpl; // move scan start over appropriately
916         } else
917             return;
918     }
919 }
920 
921 // returns FALSE if there are no vectors left in this branch, else true
922 // ok. northward is done super grossly at the moment
923 // really, this has to spawn new vectors as well
924 
925 // i want no part of their death culture
926 // i just want to go the beach
_fr_move_new_dels(FrClipVec * lv,FrClipVec * rv,uchar northward)927 uchar _fr_move_new_dels(FrClipVec *lv, FrClipVec *rv, uchar northward) {
928     int lm, rm;
929 
930     lm = lg_min(lv->oldx, lv->loc[0]);
931     rm = lg_max(rv->oldx, rv->loc[0]);
932     store_x_span(fix_int(lv->loc[1]), fix_int(lm), fix_int(rm));
933     _fr_sdbg(VECSPEW, mprintf("new_dels: setting span %d to %x,%x - o: %x %x c: x %x %x y %x %x m %x\n",
934                               span_count(fix_int(lv->loc[1])), lm, rm, lv->oldx, rv->oldx, lv->loc[0], rv->loc[0],
935                               lv->loc[1], rv->loc[1], lv->mptr));
936 
937     if (_fr_skip_solid_right_n_back(lv, rv->loc[0], new_del_mapstep[northward]))
938         return FALSE;
939     if (_fr_skip_solid_left_n_back(rv, lv->loc[0], new_del_mapstep[northward])) {
940         _fr_sdbg(SANITY, mprintf("new_dels ERR: closure from right\n"));
941         return FALSE;
942     }
943 
944     lv->loc[1] += rmmod[northward + 1]; // if we are keeping the vectors, move their y coordinates appropriately
945     rv->loc[1] += rmmod[northward + 1];
946     _fr_del_compute(lv, rv);
947 
948     //   (*_fr_spawn_check)(lv,rv);
949     _fr_spawn_check_one(lv, rv, northward);
950 
951     lm = lv->flags & FRVECSELF; // now move everyones map coordinates
952     rm = rv->nxtv;
953     for (; lm != rm; lm = (allclipv + lm)->nxtv)
954         (allclipv + lm)->mptr += new_del_mapstep[northward];
955     return TRUE;
956 }
957 
958 // remembering you fallen into my arms
959 // crying for the death of your heart
960 // you were stone white so delicate lost in the cold
961 // you were always so lost in the dark
_fr_kill_pair(FrClipVec * lv,FrClipVec * rv)962 void _fr_kill_pair(FrClipVec *lv, FrClipVec *rv) {
963     int lft_self = lv->flags & FRVECSELF, lft_pt = vechead;
964     // should sanity check for too many vectors here and in spawn code
965     if (vechead == lft_self) {
966         if (rv->nxtv != ffreevec) {
967             vechead = rv->nxtv; // if not, leave vechead at base for simplicities sake, i guess?
968             allclipv[endvec].nxtv = vechead;
969         } else
970             lastvec = -1;
971     } else {
972         while ((lft_pt != ffreevec) && (allclipv[lft_pt].nxtv != lft_self))
973             lft_pt = allclipv[lft_pt].nxtv; // go find who points at lv
974         _fr_sdbg(SANITY, if (lft_pt == ffreevec) mprintf("kill_pair(lft_pt) ERR: no lft pt\n"));
975         allclipv[lft_pt].nxtv = rv->nxtv;
976         if (lastvec == lv->nxtv)
977             lastvec = lft_pt;
978     }
979     rv->nxtv = ffreevec;
980     ffreevec = lv->flags & FRVECMASK;
981     rv->flags &= FRVECSELF;
982     lv->flags &= FRVECSELF;
983     if (lastvec != -1)
984         (allclipv + lastvec)->nxtv = ffreevec;
985 }
986 
987 // it's a wonderful world, with a lot of strange men
988 // who are standing around, and they're all wearing towels
_fr_setup_first_pair(uchar headnorth)989 uchar _fr_setup_first_pair(uchar headnorth) {
990     fix org[3], ray[3];
991     int flags;
992 
993     _fr_sdbg(VECSPEW, mprintf("setup_first_pair: note vh %d ff %d\n", vechead, ffreevec));
994 #define FULL_360_VECTORS
995 #ifdef FULL_360_VECTORS
996     org[0] = coor(EYE_X);
997     org[1] = coor(EYE_Y);
998     org[2] = coor(EYE_Z);
999     ray[1] = fix_make(0, 0);
1000     ray[2] = fix_make(0, 0);
1001     //   ray[0]=fix_make((headnorth)?-1:1,0);
1002     ray[0] = fix_make(-1, 0);
1003     ccv = allclipv + ffreevec;
1004     flags = FRVECUSE;
1005     flags |= headnorth ? FRVECR : FRVECL;
1006     _fr_build_clip_vec(ccv, org, ray, flags);
1007     ccv = allclipv + ccv->nxtv;
1008     ray[0] = fix_make(1, 0);
1009     //   ray[0]=fix_make((headnorth)?1:-1,0);
1010     flags = FRVECUSE;
1011     flags |= headnorth ? FRVECL : FRVECR;
1012     _fr_build_clip_vec(ccv, org, ray, flags);
1013     ffreevec = ccv->nxtv;
1014     lastvec = ccv->flags & FRVECSELF;
1015 #else
1016     if (headnorth) {
1017         if (span_lines[3] < 0)
1018             return FALSE;
1019         ray[0] = span_lines[2];
1020         ray[1] = span_lines[3];
1021     } else {
1022         if (span_lines[1] > 0)
1023             return FALSE;
1024         ray[0] = span_lines[0];
1025         ray[1] = span_lines[1];
1026     }
1027     org[2] = coor(EYE_Z); // these are constant
1028     ray[2] = fix_make(0, 0);
1029     org[0] = span_intersect[0]; // these are true for both north and south left vecs
1030     org[1] = span_intersect[1];
1031 
1032     ccv = allclipv + ffreevec;
1033     flags = FRVECUSE;
1034     flags |= headnorth ? FRVECR : FRVECL;
1035     _fr_build_clip_vec(ccv, org, ray, flags);
1036     ccv = allclipv + ccv->nxtv;
1037 
1038     if (headnorth) {
1039         ray[0] = span_lines[4];
1040         ray[1] = span_lines[5];
1041     } else {
1042         ray[0] = span_lines[6];
1043         ray[1] = span_lines[7];
1044     }
1045 
1046     org[0] = span_intersect[2];
1047     org[1] = span_intersect[3];
1048 
1049     flags = FRVECUSE;
1050     flags |= headnorth ? FRVECL : FRVECR;
1051     _fr_build_clip_vec(ccv, org, ray, flags);
1052     ffreevec = ccv->nxtv;
1053     lastvec = ccv->flags & FRVECSELF;
1054 #endif
1055 
1056     // setup various revectorings
1057     if (headnorth) {
1058         _face_topedge = &face_obstruct[0][0];
1059         _face_botedge = &face_obstruct[0][2];
1060         _face_topmask = FMK_INT_NW;
1061         _face_botmask = FMK_INT_SW;
1062     } else {
1063         _face_topedge = &face_obstruct[0][2];
1064         _face_botedge = &face_obstruct[0][0];
1065         _face_topmask = FMK_INT_SW;
1066         _face_botmask = FMK_INT_NW;
1067     }
1068     fr_clip_start(headnorth);
1069     return TRUE;
1070 }
1071 
1072 #if _fr_defdbg(VECTRACK)
_fr_show_veclist(void)1073 void _fr_show_veclist(void) {
1074     int i, cv;
1075     mprintf("Vec(ff%d): ", ffreevec);
1076     for (i = 0, cv = vechead; i < MAX_CLIP_VEC; i++, cv = allclipv[cv].nxtv)
1077         mprintf("%1.1X%c%c ", cv, (allclipv[cv].flags & FRVECUSE) ? 'U' : 'x',
1078                 (allclipv[cv].flags & FRVECL) ? 'L' : 'R');
1079     if (cv != vechead)
1080         mprintf("ERROR %d!%d\n", cv, vechead);
1081     else
1082         mprintf("\n");
1083 }
1084 #else
1085 #define _fr_show_veclist()
1086 #endif
1087 
1088 // stains on the carpet and stains on the memory
1089 // and both of us know, how the end always is
fr_clip_tile(void)1090 int fr_clip_tile(void) {
1091     FrClipVec *_v1, *_v2;
1092     int northward, nxtvec;
1093     // also have to do exact correct reverse order, so obj_stack works, so go north first, then south
1094     // sadly, new render order invalidates this
1095 
1096     // Just draw everything if physics is disabled
1097     if (global_fullmap->cyber) {
1098         fr_clip_show_all();
1099         _fr_ret;
1100     }
1101 
1102     // next, do each direction
1103     if (_fr_curflags & FR_SHOWALL_MASK) {
1104         fr_clip_show_all();
1105         _fr_ret;
1106     } // fill in all things
1107     _fr_sdbg(VECSPEW, mprintf("Frame start at %x %x\n", coor(EYE_X), coor(EYE_Y)));
1108     eye_mptr = MAP_GET_XY(_fr_x_cen, _fr_y_cen);
1109 
1110     for (northward = 1; northward >= 0; northward--) {
1111         // set up the initial vectors and list
1112         if (!_fr_setup_first_pair(northward))
1113             continue;
1114         _fr_sdbg(VECSPEW, mprintf("clip_tile(for): heading %d\n", northward));
1115         // for each line
1116         do {
1117             _v1 = ccv = allclipv + vechead;
1118             while (ccv->flags & FRVECUSE) {
1119                 // move out left vector
1120                 _fr_move_along_hn_p(northward);
1121                 // at each square, code objects
1122                 // keep a right edge for internal? ick!
1123 
1124                 // move out right vector
1125                 _v2 = ccv = allclipv + ccv->nxtv;
1126                 nxtvec = ccv->nxtv; // so if we new_dels more vecs, or kill our vec, we have the next ptr ready, eh?
1127                 _fr_move_along_hn_p(northward); // do same things, but in reverse
1128 
1129                 if (!_fr_move_new_dels(_v1, _v2, northward)) // kill off the vectors
1130                 {                                            // wow, can we do multiple here... i guess so
1131                     _fr_sdbg(VECSPEW, {
1132                         mprintf("clip_tile(while): killing vector pair\n");
1133                         print_fcv(_v1, 2);
1134                         print_fcv(_v2, 2);
1135                     });
1136                     _fr_kill_pair(_v1, _v2);
1137                 } else {
1138                     nxtvec = _v2->nxtv; // could have changed
1139                     _fr_sdbg(VECSPEW, {
1140                         mprintf("clip_tile(while): moving on to %d after pair\n", nxtvec);
1141                         print_fcv(_v1, 2);
1142                         print_fcv(_v2, 2);
1143                     });
1144                 }
1145 #if _fr_defdbg(VECTRACK)
1146                 _fr_sdbg(VECTRACK, _fr_show_veclist());
1147 #endif
1148                 // store off new base span
1149                 // spawn/collect vectors
1150                 // move to next span line
1151                 _v1 = ccv = allclipv + nxtvec;
1152             }
1153         } while (ffreevec != vechead);
1154     }
1155     // hit the fucking road
1156     span_fixup();
1157     _fr_ret;
1158 }
1159 
1160 // can you see?
1161 // see into the back of a long black car
1162 // pulling away from a funeral of flowers
1163 // with my hand, between your legs
1164 // melting
1165 
1166 // fills dst with a wall hit by a ray cast from orig along ray
1167 // a len!=0 is stopped at, 0 goes forever or until page fault
1168 // each fix* is assumed to be a 3 element array
1169 #ifdef WE_WERE_COOL
fr_ray_cast(fix * org,fix * ray,fix * dst,fix len)1170 fix *fr_ray_cast(fix *org, fix *ray, fix *dst, fix len) {
1171     MapElem *cur_us;
1172 
1173     _fr_build_clip_vec(&scratchvec, org, ray, len);
1174 }
1175 #endif
1176