1 //----------------------------------------------------------------------------
2 // EDGE Automap Functions
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2010 The EDGE Team.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 // Based on the DOOM source code, released by Id Software under the
20 // following copyright:
21 //
22 // Copyright (C) 1993-1996 by id Software, Inc.
23 //
24 //----------------------------------------------------------------------------
25
26 #include "i_defs.h"
27 #include "i_defs_gl.h"
28
29 #include "con_main.h"
30 #include "e_input.h"
31 #include "hu_draw.h"
32 #include "hu_style.h"
33 #include "m_argv.h"
34 #include "m_bbox.h"
35 #include "m_cheat.h"
36 #include "m_misc.h"
37 #include "n_network.h"
38 #include "p_local.h"
39 #include "am_map.h"
40 #include "r_draw.h"
41 #include "r_colormap.h"
42 #include "r_modes.h"
43
44 #include <stdio.h>
45 #include <float.h>
46 #include <math.h>
47
48 #define DEBUG_TRUEBSP 0
49 #define DEBUG_COLLIDE 0
50
51 // Automap colors
52
53 // NOTE: this order must match the one in the COAL API script
54 static rgbcol_t am_colors[AM_NUM_COLORS] =
55 {
56 RGB_MAKE( 40, 40,112), // AMCOL_Grid
57 RGB_MAKE(112,112,112), // AMCOL_Allmap
58 RGB_MAKE(255, 0, 0), // AMCOL_Wall
59 RGB_MAKE(192,128, 80), // AMCOL_Step
60 RGB_MAKE(192,128, 80), // AMCOL_Ledge
61 RGB_MAKE(220,220, 0), // AMCOL_Ceil
62 RGB_MAKE( 0,200,200), // AMCOL_Secret
63
64 RGB_MAKE(255,255,255), // AMCOL_Player
65 RGB_MAKE( 0,255, 0), // AMCOL_Monster
66 RGB_MAKE(220, 0, 0), // AMCOL_Corpse
67 RGB_MAKE( 0, 0,255), // AMCOL_Item
68 RGB_MAKE(255,188, 0), // AMCOL_Missile
69 RGB_MAKE(120, 60, 30) // AMCOL_Scenery
70 };
71
72
73 // Automap keys
74 // Ideally these would be configurable...
75
76 int key_am_up;
77 int key_am_down;
78 int key_am_left;
79 int key_am_right;
80
81 int key_am_zoomin;
82 int key_am_zoomout;
83
84 int key_am_follow;
85 int key_am_grid;
86 int key_am_mark;
87 int key_am_clear;
88
89 #define AM_NUMMARKPOINTS 9
90
91 //
92 // NOTE:
93 // `F' in the names here means `Framebuffer', i.e. on-screen coords.
94 // `M' in the names means `Map', i.e. coordinates in the level.
95 //
96
97 // scale on entry
98 #define INIT_MSCALE (4.0f)
99 #define MAX_MSCALE (200.0f)
100
101 // how much the automap moves window per tic in frame-buffer coordinates
102 // moves a whole screen-width in 1.5 seconds
103 #define F_PANINC 6.1
104
105 // how much zoom-in per tic
106 // goes to 3x in 1 second
107 #define M_ZOOMIN 1.03f
108
109 // how much zoom-in for each mouse-wheel click
110 // goes to 3x in 4 clicks
111 #define WHEEL_ZOOMIN 1.32f
112
113
114 bool automapactive = false;
115
116 cvar_c am_smoothing;
117 cvar_c am_gridsize;
118
119 static int cheating = 0;
120 static int grid = 0;
121
122 static bool show_things = false;
123 static bool show_walls = false;
124 static bool show_allmap = false;
125
126
127 // location and size of window on screen
128 static float f_x, f_y;
129 static float f_w, f_h;
130
131 // scale value which makes the whole map fit into the on-screen area
132 // (multiplying map coords by this value).
133 static float f_scale;
134
135 static mobj_t *f_focus;
136
137
138 // location on map which the map is centred on
139 static float m_cx, m_cy;
140
141 // relative scaling: 1.0 = map fits the on-screen area,
142 // 2.0 = map is twice as big
143 // 8.0 = map is eight times as big
144 static float m_scale;
145
146
147 // translates between frame-buffer and map distances
148 #define MTOF(xx) ( (int)((xx) * m_scale * f_scale))
149 #define FTOM(xx) ((float)((xx) / m_scale / f_scale))
150
151 // translates between frame-buffer and map coordinates
152 #define CXMTOF(xx) (f_x + f_w*0.5 + MTOF((xx) - m_cx))
153 #define CYMTOF(yy) (f_y + f_h*0.5 - MTOF((yy) - m_cy))
154
155
156 // largest size of map along X or Y axis
157 static float map_size;
158
159 static float map_min_x;
160 static float map_min_y;
161 static float map_max_x;
162 static float map_max_y;
163
164
165 // how far the window pans each tic (map coords)
166 static float panning_x = 0;
167 static float panning_y = 0;
168
169 // how far the window zooms in each tic (map coords)
170 static float zooming = -1;
171
172
173 // where the points are
174 static mpoint_t markpoints[AM_NUMMARKPOINTS];
175
176 #define NO_MARK_X (-777)
177
178 // next point to be assigned
179 static int markpointnum = 0;
180
181 // specifies whether to follow the player around
182 static bool followplayer = true;
183
184
185 cheatseq_t cheat_amap = {0, 0};
186
187 static bool stopped = true;
188
189 bool rotatemap = false;
190
191 extern style_c *automap_style; // FIXME: put in header
192
193
194 //
195 // adds a marker at the current location
196 //
AddMark(void)197 static void AddMark(void)
198 {
199 markpoints[markpointnum].x = m_cx;
200 markpoints[markpointnum].y = m_cy;
201
202 markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
203 }
204
205 //
206 // Determines bounding box of all vertices,
207 // sets global variables controlling zoom range.
208 //
FindMinMaxBoundaries(void)209 static void FindMinMaxBoundaries(void)
210 {
211 map_min_x = +9e9;
212 map_min_y = +9e9;
213
214 map_max_x = -9e9;
215 map_max_y = -9e9;
216
217 for (int i = 0; i < numvertexes; i++)
218 {
219 map_min_x = MIN(map_min_x, vertexes[i].x);
220 map_max_x = MAX(map_max_x, vertexes[i].x);
221
222 map_min_y = MIN(map_min_y, vertexes[i].y);
223 map_max_y = MAX(map_max_y, vertexes[i].y);
224 }
225
226 float map_w = map_max_x - map_min_x;
227 float map_h = map_max_y - map_min_y;
228
229 map_size = MAX(map_w, map_h);
230
231 m_cx = (map_min_x + map_max_x) / 2.0;
232 m_cy = (map_min_y + map_max_y) / 2.0;
233 }
234
235
ClearMarks(void)236 static void ClearMarks(void)
237 {
238 for (int i = 0; i < AM_NUMMARKPOINTS; i++)
239 markpoints[i].x = NO_MARK_X;
240
241 markpointnum = 0;
242 }
243
244
AM_InitLevel(void)245 void AM_InitLevel(void)
246 {
247 if (!cheat_amap.sequence)
248 {
249 cheat_amap.sequence = language["iddt"];
250 }
251
252 ClearMarks();
253
254 FindMinMaxBoundaries();
255
256 m_scale = INIT_MSCALE;
257 }
258
259
AM_Stop(void)260 void AM_Stop(void)
261 {
262 automapactive = false;
263 stopped = true;
264
265 panning_x = 0;
266 panning_y = 0;
267 zooming = -1;
268 }
269
AM_Hide(void)270 static void AM_Hide(void)
271 {
272 automapactive = false;
273
274 panning_x = 0;
275 panning_y = 0;
276 zooming = -1;
277 }
278
AM_Show(void)279 static void AM_Show(void)
280 {
281 automapactive = true;
282
283 if (! stopped)
284 /// AM_Stop();
285 return;
286
287 AM_InitLevel();
288
289 stopped = false;
290
291 panning_x = 0;
292 panning_y = 0;
293 zooming = -1;
294 }
295
296
297 //
298 // Zooming
299 //
ChangeWindowScale(float factor)300 static void ChangeWindowScale(float factor)
301 {
302 m_scale *= factor;
303
304 m_scale = MAX(m_scale, 1.0);
305 m_scale = MIN(m_scale, MAX_MSCALE);
306 }
307
308
309 //
310 // Handle events (user inputs) in automap mode
311 //
AM_Responder(event_t * ev)312 bool AM_Responder(event_t * ev)
313 {
314 int sym = ev->value.key.sym;
315
316 // check the enable/disable key
317 if (ev->type == ev_keydown && E_MatchesKey(key_map, sym))
318 {
319 if (automapactive)
320 AM_Hide();
321 else
322 AM_Show();
323 return true;
324 }
325
326 if (! automapactive)
327 return false;
328
329 // --- handle key releases ---
330
331 if (ev->type == ev_keyup)
332 {
333 if (E_MatchesKey(key_am_left, sym) || E_MatchesKey(key_am_right, sym))
334 panning_x = 0;
335
336 if (E_MatchesKey(key_am_up, sym) || E_MatchesKey(key_am_down, sym))
337 panning_y = 0;
338
339 if (E_MatchesKey(key_am_zoomin, sym) || E_MatchesKey(key_am_zoomout, sym))
340 zooming = -1;
341
342 return false;
343 }
344
345 // --- handle key presses ---
346
347 if (ev->type != ev_keydown)
348 return false;
349
350 if (! followplayer)
351 {
352 if (E_MatchesKey(key_am_left, sym))
353 {
354 panning_x = -FTOM(F_PANINC);
355 return true;
356 }
357 else if (E_MatchesKey(key_am_right, sym))
358 {
359 panning_x = FTOM(F_PANINC);
360 return true;
361 }
362 else if (E_MatchesKey(key_am_up, sym))
363 {
364 panning_y = FTOM(F_PANINC);
365 return true;
366 }
367 else if (E_MatchesKey(key_am_down, sym))
368 {
369 panning_y = -FTOM(F_PANINC);
370 return true;
371 }
372 }
373
374 if (E_MatchesKey(key_am_zoomin, sym))
375 {
376 zooming = M_ZOOMIN;
377 return true;
378 }
379 else if (E_MatchesKey(key_am_zoomout, sym))
380 {
381 zooming = 1.0 / M_ZOOMIN;
382 return true;
383 }
384
385 if (E_MatchesKey(key_am_follow, sym))
386 {
387 followplayer = !followplayer;
388
389 // -ACB- 1998/08/10 Use DDF Lang Reference
390 if (followplayer)
391 CON_PlayerMessageLDF(consoleplayer, "AutoMapFollowOn");
392 else
393 CON_PlayerMessageLDF(consoleplayer, "AutoMapFollowOff");
394
395 return true;
396 }
397
398 if (E_MatchesKey(key_am_grid, sym))
399 {
400 grid = !grid;
401 // -ACB- 1998/08/10 Use DDF Lang Reference
402 if (grid)
403 CON_PlayerMessageLDF(consoleplayer, "AutoMapGridOn");
404 else
405 CON_PlayerMessageLDF(consoleplayer, "AutoMapGridOff");
406
407 return true;
408 }
409
410 if (E_MatchesKey(key_am_mark, sym))
411 {
412 // -ACB- 1998/08/10 Use DDF Lang Reference
413 CON_PlayerMessage(consoleplayer, "%s %d",
414 language["AutoMapMarkedSpot"], markpointnum);
415 AddMark();
416 return true;
417 }
418
419 if (E_MatchesKey(key_am_clear, sym))
420 {
421 // -ACB- 1998/08/10 Use DDF Lang Reference
422 CON_PlayerMessageLDF(consoleplayer, "AutoMapMarksClear");
423 ClearMarks();
424 return true;
425 }
426
427 // -AJA- 2007/04/18: mouse-wheel support
428 if (sym == KEYD_WHEEL_DN)
429 {
430 ChangeWindowScale(1.0 / WHEEL_ZOOMIN);
431 return true;
432 }
433 else if (sym == KEYD_WHEEL_UP)
434 {
435 ChangeWindowScale(WHEEL_ZOOMIN);
436 return true;
437 }
438
439 // -ACB- 1999/09/28 Proper casting
440 if (!DEATHMATCH() && M_CheckCheat(&cheat_amap, (char)sym))
441 {
442 cheating = (cheating + 1) % 3;
443
444 show_things = (cheating == 2) ? true : false;
445 show_walls = (cheating >= 1) ? true : false;
446 }
447
448 return false;
449 }
450
451
452 //
453 // Updates on game tick
454 //
AM_Ticker(void)455 void AM_Ticker(void)
456 {
457 if (! automapactive)
458 return;
459
460 // Change x,y location
461 if (! followplayer)
462 {
463 m_cx += panning_x;
464 m_cy += panning_y;
465
466 // limit position, don't go outside of the map
467 m_cx = MIN(m_cx, map_max_x);
468 m_cx = MAX(m_cx, map_min_x);
469
470 m_cy = MIN(m_cy, map_max_y);
471 m_cy = MAX(m_cy, map_min_y);
472 }
473
474 // Change the zoom if necessary
475 if (zooming > 0)
476 ChangeWindowScale(zooming);
477 }
478
479 //
480 // Rotation in 2D.
481 // Used to rotate player arrow line character.
482 //
Rotate(float * x,float * y,angle_t a)483 static inline void Rotate(float * x, float * y, angle_t a)
484 {
485 float new_x = *x * M_Cos(a) - *y * M_Sin(a);
486 float new_y = *x * M_Sin(a) + *y * M_Cos(a);
487
488 *x = new_x;
489 *y = new_y;
490 }
491
GetRotatedCoords(float sx,float sy,float * dx,float * dy)492 static inline void GetRotatedCoords(float sx, float sy, float *dx, float *dy)
493 {
494 *dx = sx;
495 *dy = sy;
496
497 if (rotatemap)
498 {
499 // rotate coordinates so they are on the map correctly
500 *dx -= f_focus->x;
501 *dy -= f_focus->y;
502
503 Rotate(dx, dy, ANG90 - f_focus->angle);
504
505 *dx += f_focus->x;
506 *dy += f_focus->y;
507 }
508 }
509
GetRotatedAngle(angle_t src)510 static inline angle_t GetRotatedAngle(angle_t src)
511 {
512 if (rotatemap)
513 return src + ANG90 - f_focus->angle;
514
515 return src;
516 }
517
518
519 //
520 // Draw visible parts of lines.
521 //
DrawMLine(mline_t * ml,rgbcol_t rgb,bool thick=true)522 static void DrawMLine(mline_t * ml, rgbcol_t rgb, bool thick = true)
523 {
524 if (! am_smoothing.d)
525 thick = false;
526
527 float x1 = f_x + f_w*0.5 + MTOF(ml->a.x);
528 float y1 = f_y + f_h*0.5 - MTOF(ml->a.y);
529
530 float x2 = f_x + f_w*0.5 + MTOF(ml->b.x);
531 float y2 = f_y + f_h*0.5 - MTOF(ml->b.y);
532
533 float dx = MTOF(- m_cx);
534 float dy = MTOF(- m_cy);
535
536 HUD_SolidLine(x1, y1, x2, y2, rgb, thick, thick, dx, dy);
537 }
538
539
540 //
541 // Draws flat (floor/ceiling tile) aligned grid lines.
542 //
DrawGrid()543 static void DrawGrid()
544 {
545 mline_t ml;
546
547 int grid_size = MAX(4, am_gridsize.d);
548
549 int mx0 = int(m_cx);
550 int my0 = int(m_cy);
551
552 if (mx0 < 0) mx0 -= -(-mx0 % grid_size); else mx0 -= mx0 % grid_size;
553 if (my0 < 0) my0 -= -(-my0 % grid_size); else my0 -= my0 % grid_size;
554
555 for (int j = 1; j < 1024; j++)
556 {
557 int jx = ((j & ~1) >> 1);
558
559 // stop when both lines are off the screen
560 float x1 = CXMTOF(mx0 - jx * grid_size);
561 float x2 = CXMTOF(mx0 + jx * grid_size);
562
563 if (x1 < f_x && x2 >= f_x + f_w)
564 break;
565
566 ml.a.x = mx0 + jx * ((j & 1) ? -grid_size : grid_size);
567 ml.b.x = ml.a.x;
568
569 ml.a.y = -40000;
570 ml.b.y = +40000;
571
572 DrawMLine(&ml, am_colors[AMCOL_Grid], false);
573 }
574
575 for (int k = 1; k < 1024; k++)
576 {
577 int ky = ((k & ~1) >> 1);
578
579 // stop when both lines are off the screen
580 float y1 = CYMTOF(my0 + ky * grid_size);
581 float y2 = CYMTOF(my0 - ky * grid_size);
582
583 if (y1 < f_y && y2 >= f_y + f_h)
584 break;
585
586 ml.a.x = -40000;
587 ml.b.x = +40000;
588
589 ml.a.y = my0 + ky * ((k & 1) ? -grid_size : grid_size);
590 ml.b.y = ml.a.y;
591
592 DrawMLine(&ml, am_colors[AMCOL_Grid], false);
593 }
594 }
595
596
597 //
598 // Checks whether the two sectors' regions are similiar. If they are
599 // different enough, a line will be drawn on the automap.
600 //
601 // -AJA- 1999/12/07: written.
602 //
CheckSimiliarRegions(sector_t * front,sector_t * back)603 static bool CheckSimiliarRegions(sector_t *front, sector_t *back)
604 {
605 extrafloor_t *F, *B;
606
607 if (front->tag == back->tag)
608 return true;
609
610 // Note: doesn't worry about liquids
611
612 F = front->bottom_ef;
613 B = back->bottom_ef;
614
615 while (F && B)
616 {
617 if (F->top_h != B->top_h)
618 return false;
619
620 if (F->bottom_h != B->bottom_h)
621 return false;
622
623 F = F->higher;
624 B = B->higher;
625 }
626
627 return (F || B) ? false : true;
628 }
629
630
631 //
632 // Determines visible lines, draws them.
633 //
634 // -AJA- This is now *lineseg* based, not linedef.
635 //
AM_WalkSeg(seg_t * seg)636 static void AM_WalkSeg(seg_t *seg)
637 {
638 mline_t l;
639 line_t *line;
640
641 sector_t *front = seg->frontsector;
642 sector_t *back = seg->backsector;
643
644 if (seg->miniseg)
645 {
646 #if (DEBUG_TRUEBSP == 1)
647 if (seg->partner && seg > seg->partner)
648 return;
649
650 GetRotatedCoords(seg->v1->x, seg->v1->y, &l.a.x, &l.a.y);
651 GetRotatedCoords(seg->v2->x, seg->v2->y, &l.b.x, &l.b.y);
652
653 DrawMLine(&l, RGB_MAKE(0,0,128), false);
654 #endif
655 return;
656 }
657
658 line = seg->linedef;
659 SYS_ASSERT(line);
660
661 // only draw segs on the _right_ side of linedefs
662 if (line->side[1] == seg->sidedef)
663 return;
664
665 GetRotatedCoords(seg->v1->x, seg->v1->y, &l.a.x, &l.a.y);
666 GetRotatedCoords(seg->v2->x, seg->v2->y, &l.b.x, &l.b.y);
667
668 if ((line->flags & MLF_Mapped) || show_walls)
669 {
670 if ((line->flags & MLF_DontDraw) && !show_walls)
671 return;
672
673 if (!front || !back)
674 {
675 DrawMLine(&l, am_colors[AMCOL_Wall]);
676 }
677 else
678 {
679 if (line->flags & MLF_Secret)
680 {
681 // secret door
682 if (show_walls)
683 DrawMLine(&l, am_colors[AMCOL_Secret]);
684 else
685 DrawMLine(&l, am_colors[AMCOL_Wall]);
686 }
687 else if (back->f_h != front->f_h)
688 {
689 float diff = fabs(back->f_h - front->f_h);
690
691 // floor level change
692 if (diff > 24)
693 DrawMLine(&l, am_colors[AMCOL_Ledge]);
694 else
695 DrawMLine(&l, am_colors[AMCOL_Step]);
696 }
697 else if (back->c_h != front->c_h)
698 {
699 // ceiling level change
700 DrawMLine(&l, am_colors[AMCOL_Ceil]);
701 }
702 else if ((front->exfloor_used > 0 || back->exfloor_used > 0) &&
703 (front->exfloor_used != back->exfloor_used ||
704 ! CheckSimiliarRegions(front, back)))
705 {
706 // -AJA- 1999/10/09: extra floor change.
707 DrawMLine(&l, am_colors[AMCOL_Ledge]);
708 }
709 else if (show_walls)
710 {
711 DrawMLine(&l, am_colors[AMCOL_Allmap]);
712 }
713 }
714 }
715 else if (f_focus->player && (show_allmap || f_focus->player->powers[PW_AllMap] != 0))
716 {
717 if (! (line->flags & MLF_DontDraw))
718 DrawMLine(&l, am_colors[AMCOL_Allmap]);
719 }
720 }
721
722
DrawLineCharacter(mline_t * lineguy,int lineguylines,float radius,angle_t angle,rgbcol_t rgb,float x,float y)723 static void DrawLineCharacter(mline_t *lineguy, int lineguylines,
724 float radius, angle_t angle,
725 rgbcol_t rgb, float x, float y)
726 {
727 float cx, cy;
728
729 GetRotatedCoords(x, y, &cx, &cy);
730
731 cx = CXMTOF(cx);
732 cy = CYMTOF(cy);
733
734 radius = MTOF(radius);
735
736 if (radius < 2)
737 radius = 2;
738
739 angle = GetRotatedAngle(angle);
740
741 for (int i = 0; i < lineguylines; i++)
742 {
743 float ax = lineguy[i].a.x * radius;
744 float ay = lineguy[i].a.y * radius;
745
746 if (angle)
747 Rotate(&ax, &ay, angle);
748
749 float bx = lineguy[i].b.x * radius;
750 float by = lineguy[i].b.y * radius;
751
752 if (angle)
753 Rotate(&bx, &by, angle);
754
755 HUD_SolidLine(cx+ax, cy-ay, cx+bx, cy-by, rgb);
756 }
757 }
758
759
760 #if (DEBUG_COLLIDE == 1)
DrawObjectBounds(mobj_t * mo,rgbcol_t rgb)761 static void DrawObjectBounds(mobj_t *mo, rgbcol_t rgb)
762 {
763 float R = mo->radius;
764
765 if (R < 2)
766 R = 2;
767
768 float lx = mo->x - R;
769 float ly = mo->y - R;
770 float hx = mo->x + R;
771 float hy = mo->y + R;
772
773 mline_t ml;
774
775 GetRotatedCoords(lx, ly, &ml.a.x, &ml.a.y);
776 GetRotatedCoords(lx, hy, &ml.b.x, &ml.b.y);
777 DrawMLine(&ml, rgb);
778
779 GetRotatedCoords(lx, hy, &ml.a.x, &ml.a.y);
780 GetRotatedCoords(hx, hy, &ml.b.x, &ml.b.y);
781 DrawMLine(&ml, rgb);
782
783 GetRotatedCoords(hx, hy, &ml.a.x, &ml.a.y);
784 GetRotatedCoords(hx, ly, &ml.b.x, &ml.b.y);
785 DrawMLine(&ml, rgb);
786
787 GetRotatedCoords(hx, ly, &ml.a.x, &ml.a.y);
788 GetRotatedCoords(lx, ly, &ml.b.x, &ml.b.y);
789 DrawMLine(&ml, rgb);
790 }
791 #endif
792
793
794 static rgbcol_t player_colors[8] =
795 {
796 RGB_MAKE( 5,255, 5), // GREEN,
797 RGB_MAKE( 80, 80, 80), // GRAY + GRAY_LEN*2/3,
798 RGB_MAKE(160,100, 50), // BROWN,
799 RGB_MAKE(255,255,255), // RED + RED_LEN/2,
800 RGB_MAKE(255,176, 5), // ORANGE,
801 RGB_MAKE(170,170,170), // GRAY + GRAY_LEN*1/3,
802 RGB_MAKE(255, 5, 5), // RED,
803 RGB_MAKE(255,185,225), // PINK
804 };
805
806 //
807 // The vector graphics for the automap.
808 //
809 // A line drawing of the player pointing right, starting from the
810 // middle.
811
812 static mline_t player_arrow[] =
813 {
814 {{-0.875f, 0.0f}, {1.0f, 0.0f}}, // -----
815
816 {{1.0f, 0.0f}, {0.5f, 0.25f}}, // ----->
817 {{1.0f, 0.0f}, {0.5f, -0.25f}},
818
819 {{-0.875f, 0.0f}, {-1.125f, 0.25f}}, // >---->
820 {{-0.875f, 0.0f}, {-1.125f, -0.25f}},
821
822 {{-0.625f, 0.0f}, {-0.875f, 0.25f}}, // >>--->
823 {{-0.625f, 0.0f}, {-0.875f, -0.25f}}
824 };
825
826 #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
827
828 static mline_t cheat_player_arrow[] =
829 {
830 {{-0.875f, 0.0f}, {1.0f, 0.0f}}, // -----
831
832 {{1.0f, 0.0f}, {0.5f, 0.167f}}, // ----->
833 {{1.0f, 0.0f}, {0.5f, -0.167f}},
834
835 {{-0.875f, 0.0f}, {-1.125f, 0.167f}}, // >----->
836 {{-0.875f, 0.0f}, {-1.125f, -0.167f}},
837
838 {{-0.625f, 0.0f}, {-0.875f, 0.167f}}, // >>----->
839 {{-0.625f, 0.0f}, {-0.875f, -0.167f}},
840
841 {{-0.5f, 0.0f}, {-0.5f, -0.167f}}, // >>-d--->
842 {{-0.5f, -0.167f}, {-0.5f + 0.167f, -0.167f}},
843 {{-0.5f + 0.167f, -0.167f}, {-0.5f + 0.167f, 0.25f}},
844
845 {{-0.167f, 0.0f}, {-0.167f, -0.167f}}, // >>-dd-->
846 {{-0.167f, -0.167f}, {0.0f, -0.167f}},
847 {{0.0f, -0.167f}, {0.0f, 0.25f}},
848
849 {{0.167f, 0.25f}, {0.167f, -0.143f}}, // >>-ddt->
850 {{0.167f, -0.143f}, {0.167f + 0.031f, -0.143f - 0.031f}},
851 {{0.167f + 0.031f, -0.143f - 0.031f}, {0.167f + 0.1f, -0.143f}}
852 };
853
854 #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
855
856 static mline_t thin_triangle_guy[] =
857 {
858 {{-0.5f, -0.7f}, {1.0f, 0.0f}},
859 {{1.0f, 0.0f}, {-0.5f, 0.7f}},
860 {{-0.5f, 0.7f}, {-0.5f, -0.7f}}
861 };
862
863 #define NUMTHINTRIANGLEGUYLINES (sizeof(thin_triangle_guy)/sizeof(mline_t))
864
AM_DrawPlayer(mobj_t * mo)865 static void AM_DrawPlayer(mobj_t *mo)
866 {
867 #if (DEBUG_COLLIDE == 1)
868 DrawObjectBounds(mo, am_colors[AMCOL_Player]);
869 #endif
870
871 if (!netgame)
872 {
873 if (cheating)
874 DrawLineCharacter(cheat_player_arrow, NUMCHEATPLYRLINES,
875 mo->radius, mo->angle,
876 am_colors[AMCOL_Player], mo->x, mo->y);
877 else
878 DrawLineCharacter(player_arrow, NUMPLYRLINES,
879 mo->radius, mo->angle,
880 am_colors[AMCOL_Player], mo->x, mo->y);
881
882 return;
883 }
884
885 #if 0 //!!!! TEMP DISABLED, NETWORK DEBUGGING
886 if ((DEATHMATCH() && !singledemo) && mo->player != p)
887 return;
888 #endif
889
890 DrawLineCharacter(player_arrow, NUMPLYRLINES,
891 mo->radius, mo->angle,
892 player_colors[mo->player->pnum & 0x07],
893 mo->x, mo->y);
894 }
895
896
AM_WalkThing(mobj_t * mo)897 static void AM_WalkThing(mobj_t *mo)
898 {
899 int index = AMCOL_Scenery;
900
901 if (mo->player && mo->player->mo == mo)
902 {
903 AM_DrawPlayer(mo);
904 return;
905 }
906
907 if (! show_things)
908 return;
909
910 // -AJA- more colourful things
911 if (mo->flags & MF_SPECIAL)
912 index = AMCOL_Item;
913 else if (mo->flags & MF_MISSILE)
914 index = AMCOL_Missile;
915 else if (mo->extendedflags & EF_MONSTER && mo->health <= 0)
916 index = AMCOL_Corpse;
917 else if (mo->extendedflags & EF_MONSTER)
918 index = AMCOL_Monster;
919
920 #if (DEBUG_COLLIDE == 1)
921 DrawObjectBounds(mo, am_colors[index]);
922 return;
923 #endif
924
925 DrawLineCharacter(
926 thin_triangle_guy, NUMTHINTRIANGLEGUYLINES,
927 mo->radius, mo->angle, am_colors[index], mo->x, mo->y);
928 }
929
930
931 //
932 // Visit a subsector and draw everything.
933 //
AM_WalkSubsector(unsigned int num)934 static void AM_WalkSubsector(unsigned int num)
935 {
936 subsector_t *sub = &subsectors[num];
937
938 // handle each seg
939 for (seg_t *seg = sub->segs; seg; seg = seg->sub_next)
940 {
941 AM_WalkSeg(seg);
942 }
943
944 // handle each thing
945 for (mobj_t *mo = sub->thinglist; mo; mo = mo->snext)
946 {
947 AM_WalkThing(mo);
948 }
949 }
950
951
952 //
953 // Checks BSP node/subtree bounding box.
954 // Returns true if some part of the bbox might be visible.
955 //
AM_CheckBBox(float * bspcoord)956 static bool AM_CheckBBox(float *bspcoord)
957 {
958 float xl = bspcoord[BOXLEFT];
959 float yt = bspcoord[BOXTOP];
960 float xr = bspcoord[BOXRIGHT];
961 float yb = bspcoord[BOXBOTTOM];
962
963 // TODO: improve this quick'n'dirty hack
964 if (rotatemap)
965 return true;
966
967 float x1 = CXMTOF(xl);
968 float x2 = CXMTOF(xr);
969
970 float y1 = CYMTOF(yt);
971 float y2 = CYMTOF(yb);
972
973 // some part of bbox is visible?
974 return HUD_ScissorTest(x1, y1, x2, y2);
975 }
976
977
978 //
979 // Walks all subsectors below a given node, traversing subtree
980 // recursively. Just call with BSP root.
981 //
AM_WalkBSPNode(unsigned int bspnum)982 static void AM_WalkBSPNode(unsigned int bspnum)
983 {
984 node_t *node;
985 int side;
986
987 // Found a subsector?
988 if (bspnum & NF_V5_SUBSECTOR)
989 {
990 AM_WalkSubsector(bspnum & (~NF_V5_SUBSECTOR));
991 return;
992 }
993
994 node = &nodes[bspnum];
995 side = 0;
996
997 // Recursively divide right space
998 if (AM_CheckBBox(node->bbox[0]))
999 AM_WalkBSPNode(node->children[side]);
1000
1001 // Recursively divide back space
1002 if (AM_CheckBBox(node->bbox[side ^ 1]))
1003 AM_WalkBSPNode(node->children[side ^ 1]);
1004 }
1005
1006
DrawMarks(void)1007 static void DrawMarks(void)
1008 {
1009 font_c *am_font = automap_style->fonts[0];
1010
1011 HUD_SetFont(am_font);
1012 HUD_SetAlignment(0, 0); // centre the characters
1013
1014 char buffer[4];
1015
1016 for (int i = 0; i < AM_NUMMARKPOINTS; i++)
1017 {
1018 if (markpoints[i].x == NO_MARK_X)
1019 continue;
1020
1021 float mx, my;
1022
1023 GetRotatedCoords(markpoints[i].x, markpoints[i].y, &mx, &my);
1024
1025 buffer[0] = ('1' + i);
1026 buffer[1] = 0;
1027
1028 HUD_DrawText(CXMTOF(mx), CYMTOF(my), buffer);
1029 }
1030
1031 HUD_SetFont();
1032 HUD_SetAlignment();
1033 }
1034
1035
AM_RenderScene(void)1036 static void AM_RenderScene(void)
1037 {
1038 HUD_PushScissor(f_x, f_y, f_x+f_w, f_y+f_h, true);
1039
1040 // walk the bsp tree
1041 AM_WalkBSPNode(root_node);
1042
1043 HUD_PopScissor();
1044 }
1045
1046
AM_Drawer(float x,float y,float w,float h,mobj_t * focus)1047 void AM_Drawer(float x, float y, float w, float h, mobj_t *focus)
1048 {
1049 f_x = x;
1050 f_y = y;
1051 f_w = w;
1052 f_h = h;
1053
1054 f_scale = MAX(f_w, f_h) / map_size / 2.0f;
1055 f_focus = focus;
1056
1057 if (followplayer)
1058 {
1059 m_cx = f_focus->x;
1060 m_cy = f_focus->y;
1061 }
1062
1063 SYS_ASSERT(automap_style);
1064
1065 if (grid && !rotatemap)
1066 DrawGrid();
1067
1068 AM_RenderScene();
1069
1070 DrawMarks();
1071 }
1072
1073
AM_SetColor(int which,rgbcol_t color)1074 void AM_SetColor(int which, rgbcol_t color)
1075 {
1076 SYS_ASSERT(0 <= which && which < AM_NUM_COLORS);
1077
1078 am_colors[which] = color;
1079 }
1080
1081
AM_GetState(int * state,float * zoom)1082 void AM_GetState(int *state, float *zoom)
1083 {
1084 *state = 0;
1085
1086 if (grid)
1087 *state |= AMST_Grid;
1088
1089 if (followplayer)
1090 *state |= AMST_Follow;
1091
1092 if (rotatemap)
1093 *state |= AMST_Rotate;
1094
1095 if (show_things)
1096 *state |= AMST_Things;
1097
1098 if (show_walls)
1099 *state |= AMST_Walls;
1100
1101 // nothing required for AMST_Allmap flag (no actual state)
1102
1103 *zoom = m_scale;
1104 }
1105
1106
AM_SetState(int state,float zoom)1107 void AM_SetState(int state, float zoom)
1108 {
1109 grid = (state & AMST_Grid) ? true : false;
1110 followplayer = (state & AMST_Follow) ? true : false;
1111 rotatemap = (state & AMST_Rotate) ? true : false;
1112
1113 show_things = (state & AMST_Things) ? true : false;
1114 show_walls = (state & AMST_Walls) ? true : false;
1115 show_allmap = (state & AMST_Allmap) ? true : false;
1116
1117 m_scale = zoom;
1118 }
1119
1120 //--- editor settings ---
1121 // vi:ts=4:sw=4:noexpandtab
1122