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