mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
2272 lines
52 KiB
C++
2272 lines
52 KiB
C++
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This source is available for distribution and/or modification
|
|
// only under the terms of the DOOM Source Code License as
|
|
// published by id Software. All rights reserved.
|
|
//
|
|
// The source is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
|
// for more details.
|
|
//
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION: the automap code
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "doomdef.h"
|
|
#include "templates.h"
|
|
#include "g_level.h"
|
|
#include "doomdef.h"
|
|
#include "st_stuff.h"
|
|
#include "p_local.h"
|
|
#include "p_lnspec.h"
|
|
#include "w_wad.h"
|
|
|
|
#include "m_cheat.h"
|
|
#include "i_system.h"
|
|
#include "c_dispatch.h"
|
|
|
|
// Needs access to LFB.
|
|
#include "v_video.h"
|
|
|
|
#include "v_text.h"
|
|
|
|
// State.
|
|
#include "doomstat.h"
|
|
#include "r_state.h"
|
|
|
|
// Data.
|
|
#include "gstrings.h"
|
|
|
|
#include "am_map.h"
|
|
#include "a_artifacts.h"
|
|
|
|
static int Background, YourColor, WallColor, TSWallColor,
|
|
FDWallColor, CDWallColor, ThingColor,
|
|
ThingColor_Item, ThingColor_Monster, ThingColor_Friend,
|
|
SecretWallColor, GridColor, XHairColor,
|
|
NotSeenColor,
|
|
LockedColor,
|
|
AlmostBackground,
|
|
IntraTeleportColor, InterTeleportColor,
|
|
SecretSectorColor;
|
|
|
|
static int DoomColors[11];
|
|
static byte DoomPaletteVals[11*3] =
|
|
{
|
|
0x00,0x00,0x00, 0xff,0xff,0xff, 0x10,0x10,0x10,
|
|
0xfc,0x00,0x00, 0x80,0x80,0x80, 0xbc,0x78,0x48,
|
|
0xfc,0xfc,0x00, 0x74,0xfc,0x6c, 0x4c,0x4c,0x4c,
|
|
0x80,0x80,0x80, 0x6c,0x6c,0x6c
|
|
};
|
|
|
|
#define MAPBITS 12
|
|
#define MapDiv SafeDivScale12
|
|
#define MapMul MulScale12
|
|
#define MAPUNIT (1<<MAPBITS)
|
|
#define FRACTOMAPBITS (FRACBITS-MAPBITS)
|
|
|
|
// scale on entry
|
|
#define INITSCALEMTOF (.2*MAPUNIT)
|
|
// used by MTOF to scale from map-to-frame-buffer coords
|
|
static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
|
|
// used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
|
|
static fixed_t scale_ftom;
|
|
|
|
// translates between frame-buffer and map distances
|
|
inline fixed_t FTOM(fixed_t x)
|
|
{
|
|
return x * scale_ftom;
|
|
}
|
|
|
|
inline fixed_t MTOF(fixed_t x)
|
|
{
|
|
return MulScale24 (x, scale_mtof);
|
|
}
|
|
|
|
static int WeightingScale;
|
|
|
|
CVAR (Bool, am_rotate, false, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_overlay, false, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_showsecrets, true, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_showmonsters, true, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_showitems, false, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_showtime, true, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_showtotaltime, false, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_usecustomcolors, true, CVAR_ARCHIVE);
|
|
CVAR (Float, am_ovtrans, 1.f, CVAR_ARCHIVE);
|
|
CVAR (Color, am_backcolor, 0x6c5440, CVAR_ARCHIVE);
|
|
CVAR (Color, am_yourcolor, 0xfce8d8, CVAR_ARCHIVE);
|
|
CVAR (Color, am_wallcolor, 0x2c1808, CVAR_ARCHIVE);
|
|
CVAR (Color, am_secretwallcolor, 0x000000, CVAR_ARCHIVE);
|
|
CVAR (Color, am_tswallcolor, 0x888888, CVAR_ARCHIVE);
|
|
CVAR (Color, am_fdwallcolor, 0x887058, CVAR_ARCHIVE);
|
|
CVAR (Color, am_cdwallcolor, 0x4c3820, CVAR_ARCHIVE);
|
|
CVAR (Color, am_thingcolor, 0xfcfcfc, CVAR_ARCHIVE);
|
|
CVAR (Color, am_gridcolor, 0x8b5a2b, CVAR_ARCHIVE);
|
|
CVAR (Color, am_xhaircolor, 0x808080, CVAR_ARCHIVE);
|
|
CVAR (Color, am_notseencolor, 0x6c6c6c, CVAR_ARCHIVE);
|
|
CVAR (Color, am_lockedcolor, 0x007800, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovyourcolor, 0xfce8d8, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovwallcolor, 0x00ff00, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovthingcolor, 0xe88800, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovotherwallscolor, 0x008844, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovunseencolor, 0x00226e, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovtelecolor, 0xffff00, CVAR_ARCHIVE);
|
|
CVAR (Color, am_intralevelcolor, 0x0000ff, CVAR_ARCHIVE);
|
|
CVAR (Color, am_interlevelcolor, 0xff0000, CVAR_ARCHIVE);
|
|
CVAR (Color, am_secretsectorcolor, 0xff00ff, CVAR_ARCHIVE);
|
|
CVAR (Int, am_map_secrets, 1, CVAR_ARCHIVE);
|
|
CVAR (Bool, am_drawmapback, true, CVAR_ARCHIVE);
|
|
CVAR (Color, am_thingcolor_friend, 0xfcfcfc, CVAR_ARCHIVE);
|
|
CVAR (Color, am_thingcolor_monster, 0xfcfcfc, CVAR_ARCHIVE);
|
|
CVAR (Color, am_thingcolor_item, 0xfcfcfc, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovthingcolor_friend, 0xe88800, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovthingcolor_monster, 0xe88800, CVAR_ARCHIVE);
|
|
CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE);
|
|
|
|
// drawing stuff
|
|
#define AM_PANDOWNKEY KEY_DOWNARROW
|
|
#define AM_PANUPKEY KEY_UPARROW
|
|
#define AM_PANRIGHTKEY KEY_RIGHTARROW
|
|
#define AM_PANLEFTKEY KEY_LEFTARROW
|
|
#define AM_ZOOMINKEY KEY_EQUALS
|
|
#define AM_ZOOMINKEY2 0x4e // DIK_ADD
|
|
#define AM_ZOOMOUTKEY KEY_MINUS
|
|
#define AM_ZOOMOUTKEY2 0x4a // DIK_SUBTRACT
|
|
#define AM_GOBIGKEY 0x0b // DIK_0
|
|
#define AM_FOLLOWKEY 'f'
|
|
#define AM_GRIDKEY 'g'
|
|
#define AM_MARKKEY 'm'
|
|
#define AM_CLEARMARKKEY 'c'
|
|
|
|
#define AM_NUMMARKPOINTS 10
|
|
|
|
// player radius for automap checking
|
|
#define PLAYERRADIUS 16*MAPUNIT
|
|
|
|
// how much the automap moves window per tic in frame-buffer coordinates
|
|
// moves 140 pixels at 320x200 in 1 second
|
|
#define F_PANINC (140/TICRATE)
|
|
// how much zoom-in per tic
|
|
// goes to 2x in 1 second
|
|
#define M_ZOOMIN ((int) (1.02*MAPUNIT))
|
|
// how much zoom-out per tic
|
|
// pulls out to 0.5x in 1 second
|
|
#define M_ZOOMOUT ((int) (MAPUNIT/1.02))
|
|
|
|
// translates between frame-buffer and map coordinates
|
|
#define CXMTOF(x) (MTOF((x)-m_x)/* - f_x*/)
|
|
#define CYMTOF(y) (f_h - MTOF((y)-m_y)/* + f_y*/)
|
|
|
|
typedef struct {
|
|
int x, y;
|
|
} fpoint_t;
|
|
|
|
typedef struct {
|
|
fpoint_t a, b;
|
|
} fline_t;
|
|
|
|
typedef struct {
|
|
fixed_t x,y;
|
|
} mpoint_t;
|
|
|
|
typedef struct {
|
|
mpoint_t a, b;
|
|
} mline_t;
|
|
|
|
typedef struct {
|
|
fixed_t slp, islp;
|
|
} islope_t;
|
|
|
|
|
|
|
|
//
|
|
// The vector graphics for the automap.
|
|
// A line drawing of the player pointing right,
|
|
// starting from the middle.
|
|
//
|
|
#define R ((8*PLAYERRADIUS)/7)
|
|
mline_t player_arrow[] = {
|
|
{ { -R+R/8, 0 }, { R, 0 } }, // -----
|
|
{ { R, 0 }, { R-R/2, R/4 } }, // ----->
|
|
{ { R, 0 }, { R-R/2, -R/4 } },
|
|
{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
|
|
{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
|
|
{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
|
|
{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
|
|
};
|
|
#undef R
|
|
#define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
|
|
|
|
#define R ((8*PLAYERRADIUS)/7)
|
|
mline_t cheat_player_arrow[] = {
|
|
{ { -R+R/8, 0 }, { R, 0 } }, // -----
|
|
{ { R, 0 }, { R-R/2, R/6 } }, // ----->
|
|
{ { R, 0 }, { R-R/2, -R/6 } },
|
|
{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
|
|
{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
|
|
{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
|
|
{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
|
|
{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
|
|
{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
|
|
{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
|
|
{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
|
|
{ { -R/6, -R/6 }, { 0, -R/6 } },
|
|
{ { 0, -R/6 }, { 0, R/4 } },
|
|
{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
|
|
{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
|
|
{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
|
|
};
|
|
#undef R
|
|
#define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
|
|
|
|
#define R (MAPUNIT)
|
|
// [RH] Avoid lots of warnings without compiler-specific #pragmas
|
|
#define L(a,b,c,d) { {(fixed_t)((a)*R),(fixed_t)((b)*R)}, {(fixed_t)((c)*R),(fixed_t)((d)*R)} }
|
|
mline_t triangle_guy[] = {
|
|
L (-.867,-.5, .867,-.5),
|
|
L (.867,-.5, 0,1),
|
|
L (0,1, -.867,-.5)
|
|
};
|
|
#define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
|
|
|
|
mline_t thintriangle_guy[] = {
|
|
L (-.5,-.7, 1,0),
|
|
L (1,0, -.5,.7),
|
|
L (-.5,.7, -.5,-.7)
|
|
};
|
|
#undef L
|
|
#undef R
|
|
#define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
|
|
|
|
|
|
|
|
EXTERN_CVAR (Bool, sv_cheats)
|
|
CUSTOM_CVAR (Int, am_cheat, 0, 0)
|
|
{
|
|
// No automap cheat in net games when cheats are disabled!
|
|
if (netgame && !sv_cheats && self != 0)
|
|
{
|
|
self = 0;
|
|
}
|
|
}
|
|
|
|
static int grid = 0;
|
|
|
|
static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
|
|
|
|
bool automapactive = false;
|
|
|
|
// location of window on screen
|
|
static int f_x;
|
|
static int f_y;
|
|
|
|
// size of window on screen
|
|
static int f_w;
|
|
static int f_h;
|
|
static int f_p; // [RH] # of bytes from start of a line to start of next
|
|
|
|
static byte *fb; // pseudo-frame buffer
|
|
static int amclock;
|
|
|
|
static mpoint_t m_paninc; // how far the window pans each tic (map coords)
|
|
static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
|
|
static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
|
|
|
|
static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
|
|
static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
|
|
|
|
//
|
|
// width/height of window on map (map coords)
|
|
//
|
|
static fixed_t m_w;
|
|
static fixed_t m_h;
|
|
|
|
// based on level size
|
|
static fixed_t min_x, min_y, max_x, max_y;
|
|
|
|
static fixed_t max_w; // max_x-min_x,
|
|
static fixed_t max_h; // max_y-min_y
|
|
|
|
// based on player size
|
|
static fixed_t min_w;
|
|
static fixed_t min_h;
|
|
|
|
|
|
static fixed_t min_scale_mtof; // used to tell when to stop zooming out
|
|
static fixed_t max_scale_mtof; // used to tell when to stop zooming in
|
|
|
|
// old stuff for recovery later
|
|
static fixed_t old_m_w, old_m_h;
|
|
static fixed_t old_m_x, old_m_y;
|
|
|
|
// old location used by the Follower routine
|
|
static mpoint_t f_oldloc;
|
|
|
|
static int marknums[10]; // numbers used for marking by the automap
|
|
static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
|
|
static int markpointnum = 0; // next point to be assigned
|
|
|
|
static int followplayer = 1; // specifies whether to follow the player around
|
|
|
|
class FAutomapTexture : public FTexture
|
|
{
|
|
public:
|
|
FAutomapTexture (int lumpnum);
|
|
~FAutomapTexture ();
|
|
|
|
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
|
const BYTE *GetPixels ();
|
|
void Unload ();
|
|
void MakeTexture ();
|
|
|
|
private:
|
|
BYTE *Pixels;
|
|
Span DummySpan[2];
|
|
int LumpNum;
|
|
};
|
|
|
|
static FAutomapTexture *mapback; // the automap background
|
|
static fixed_t mapystart=0; // y-value for the start of the map bitmap...used in the parallax stuff.
|
|
static fixed_t mapxstart=0; //x-value for the bitmap.
|
|
|
|
static BOOL stopped = true;
|
|
|
|
|
|
#define NUMALIASES 3
|
|
#define WALLCOLORS -1
|
|
#define FDWALLCOLORS -2
|
|
#define CDWALLCOLORS -3
|
|
|
|
#define WEIGHTBITS 6
|
|
#define WEIGHTSHIFT (16-WEIGHTBITS)
|
|
#define NUMWEIGHTS (1<<WEIGHTBITS)
|
|
#define WEIGHTMASK (NUMWEIGHTS-1)
|
|
static byte antialias[NUMALIASES][NUMWEIGHTS];
|
|
|
|
|
|
|
|
void AM_rotatePoint (fixed_t *x, fixed_t *y);
|
|
void AM_rotate (fixed_t *x, fixed_t *y, angle_t an);
|
|
|
|
void DrawWuLine (int X0, int Y0, int X1, int Y1, byte *BaseColor);
|
|
void DrawTransWuLine (int X0, int Y0, int X1, int Y1, byte BaseColor);
|
|
|
|
// Calculates the slope and slope according to the x-axis of a line
|
|
// segment in map coordinates (with the upright y-axis n' all) so
|
|
// that it can be used with the brain-dead drawing stuff.
|
|
|
|
// Ripped out for Heretic
|
|
/*
|
|
void AM_getIslope (mline_t *ml, islope_t *is)
|
|
{
|
|
int dx, dy;
|
|
|
|
dy = ml->a.y - ml->b.y;
|
|
dx = ml->b.x - ml->a.x;
|
|
if (!dy) is->islp = (dx<0?-MAXINT:MAXINT);
|
|
else is->islp = FixedDiv(dx, dy);
|
|
if (!dx) is->slp = (dy<0?-MAXINT:MAXINT);
|
|
else is->slp = FixedDiv(dy, dx);
|
|
}
|
|
*/
|
|
|
|
void AM_GetPosition(fixed_t & x, fixed_t & y)
|
|
{
|
|
x = (m_x + m_w/2) << FRACTOMAPBITS;
|
|
y = (m_y + m_h/2) << FRACTOMAPBITS;
|
|
}
|
|
//
|
|
//
|
|
//
|
|
void AM_activateNewScale ()
|
|
{
|
|
m_x += m_w/2;
|
|
m_y += m_h/2;
|
|
m_w = FTOM(f_w);
|
|
m_h = FTOM(f_h);
|
|
m_x -= m_w/2;
|
|
m_y -= m_h/2;
|
|
m_x2 = m_x + m_w;
|
|
m_y2 = m_y + m_h;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_saveScaleAndLoc ()
|
|
{
|
|
old_m_x = m_x;
|
|
old_m_y = m_y;
|
|
old_m_w = m_w;
|
|
old_m_h = m_h;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_restoreScaleAndLoc ()
|
|
{
|
|
m_w = old_m_w;
|
|
m_h = old_m_h;
|
|
if (!followplayer)
|
|
{
|
|
m_x = old_m_x;
|
|
m_y = old_m_y;
|
|
}
|
|
else
|
|
{
|
|
m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2;
|
|
m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS)- m_h/2;
|
|
}
|
|
m_x2 = m_x + m_w;
|
|
m_y2 = m_y + m_h;
|
|
|
|
// Change the scaling multipliers
|
|
scale_mtof = MapDiv(f_w<<MAPBITS, m_w);
|
|
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
|
}
|
|
|
|
//
|
|
// adds a marker at the current location
|
|
//
|
|
bool AM_addMark ()
|
|
{
|
|
if (marknums[0] != -1)
|
|
{
|
|
markpoints[markpointnum].x = m_x + m_w/2;
|
|
markpoints[markpointnum].y = m_y + m_h/2;
|
|
markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Determines bounding box of all vertices,
|
|
// sets global variables controlling zoom range.
|
|
//
|
|
static void AM_findMinMaxBoundaries ()
|
|
{
|
|
int i;
|
|
fixed_t a;
|
|
fixed_t b;
|
|
|
|
min_x = min_y = FIXED_MAX;
|
|
max_x = max_y = FIXED_MIN;
|
|
|
|
for (i = 0; i < numvertexes; i++)
|
|
{
|
|
if (vertexes[i].x < min_x)
|
|
min_x = vertexes[i].x;
|
|
else if (vertexes[i].x > max_x)
|
|
max_x = vertexes[i].x;
|
|
|
|
if (vertexes[i].y < min_y)
|
|
min_y = vertexes[i].y;
|
|
else if (vertexes[i].y > max_y)
|
|
max_y = vertexes[i].y;
|
|
}
|
|
|
|
max_w = (max_x >>= FRACTOMAPBITS) - (min_x >>= FRACTOMAPBITS);
|
|
max_h = (max_y >>= FRACTOMAPBITS) - (min_y >>= FRACTOMAPBITS);
|
|
|
|
min_w = 2*PLAYERRADIUS; // const? never changed?
|
|
min_h = 2*PLAYERRADIUS;
|
|
|
|
a = MapDiv (SCREENWIDTH << MAPBITS, max_w);
|
|
b = MapDiv (::ST_Y << MAPBITS, max_h);
|
|
|
|
min_scale_mtof = a < b ? a : b;
|
|
max_scale_mtof = MapDiv (SCREENHEIGHT << MAPBITS, 2*PLAYERRADIUS);
|
|
}
|
|
|
|
static void AM_ClipRotatedExtents ()
|
|
{
|
|
fixed_t rmin_x, rmin_y, rmax_x, rmax_y;
|
|
|
|
if (!am_rotate)
|
|
{
|
|
rmin_x = min_x;
|
|
rmin_y = min_y;
|
|
rmax_x = max_x;
|
|
rmax_y = max_y;
|
|
}
|
|
else
|
|
{
|
|
fixed_t xs[4], ys[4];
|
|
int i;
|
|
|
|
xs[0] = min_x; ys[0] = min_y;
|
|
xs[1] = max_x; ys[1] = min_y;
|
|
xs[2] = max_x; ys[2] = max_y;
|
|
xs[3] = min_x; ys[3] = max_y;
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
AM_rotatePoint (&xs[i], &ys[i]);
|
|
}
|
|
rmin_x = rmin_y = FIXED_MAX;
|
|
rmax_x = rmax_y = FIXED_MIN;
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
if (xs[i] < rmin_x) rmin_x = xs[i];
|
|
if (xs[i] > rmax_x) rmax_x = xs[i];
|
|
if (ys[i] < rmin_y) rmin_y = ys[i];
|
|
if (ys[i] > rmax_y) rmax_y = ys[i];
|
|
}
|
|
}
|
|
if (m_x + m_w/2 > rmax_x)
|
|
m_x = rmax_x - m_w/2;
|
|
else if (m_x + m_w/2 < rmin_x)
|
|
m_x = rmin_x - m_w/2;
|
|
|
|
if (m_y + m_h/2 > rmax_y)
|
|
m_y = rmax_y - m_h/2;
|
|
else if (m_y + m_h/2 < rmin_y)
|
|
m_y = rmin_y - m_h/2;
|
|
|
|
m_x2 = m_x + m_w;
|
|
m_y2 = m_y + m_h;
|
|
}
|
|
|
|
static void AM_ScrollParchment (fixed_t dmapx, fixed_t dmapy)
|
|
{
|
|
mapxstart -= MulScale12 (dmapx, scale_mtof);
|
|
mapystart -= MulScale12 (dmapy, scale_mtof);
|
|
|
|
if (mapback != NULL)
|
|
{
|
|
int pwidth = mapback->GetWidth() << MAPBITS;
|
|
int pheight = mapback->GetHeight() << MAPBITS;
|
|
|
|
while(mapxstart > 0)
|
|
mapxstart -= pwidth;
|
|
while(mapxstart <= -pwidth)
|
|
mapxstart += pwidth;
|
|
while(mapystart > 0)
|
|
mapystart -= pheight;
|
|
while(mapystart <= -pheight)
|
|
mapystart += pheight;
|
|
}
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_changeWindowLoc ()
|
|
{
|
|
if (0 != (m_paninc.x | m_paninc.y))
|
|
{
|
|
followplayer = 0;
|
|
f_oldloc.x = FIXED_MAX;
|
|
}
|
|
|
|
int oldmx = m_x, oldmy = m_y;
|
|
|
|
m_x += Scale (m_paninc.x, SCREENWIDTH, 320);
|
|
m_y += Scale (m_paninc.y, SCREENHEIGHT, 200);
|
|
|
|
AM_ClipRotatedExtents ();
|
|
AM_ScrollParchment (m_x-oldmx, oldmy-m_y);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_initVariables ()
|
|
{
|
|
int pnum;
|
|
|
|
automapactive = true;
|
|
|
|
f_oldloc.x = FIXED_MAX;
|
|
amclock = 0;
|
|
|
|
m_paninc.x = m_paninc.y = 0;
|
|
ftom_zoommul = MAPUNIT;
|
|
mtof_zoommul = MAPUNIT;
|
|
|
|
m_w = FTOM(SCREENWIDTH);
|
|
m_h = FTOM(SCREENHEIGHT);
|
|
|
|
// find player to center on initially
|
|
if (!playeringame[pnum = consoleplayer])
|
|
for (pnum=0;pnum<MAXPLAYERS;pnum++)
|
|
if (playeringame[pnum])
|
|
break;
|
|
|
|
m_x = (players[pnum].camera->x >> FRACTOMAPBITS) - m_w/2;
|
|
m_y = (players[pnum].camera->y >> FRACTOMAPBITS) - m_h/2;
|
|
AM_changeWindowLoc();
|
|
|
|
// for saving & restoring
|
|
old_m_x = m_x;
|
|
old_m_y = m_y;
|
|
old_m_w = m_w;
|
|
old_m_h = m_h;
|
|
}
|
|
|
|
static void GetComponents (int color, DWORD *palette, float &r, float &g, float &b)
|
|
{
|
|
if (palette)
|
|
color = palette[color];
|
|
|
|
r = (float)RPART(color);
|
|
g = (float)GPART(color);
|
|
b = (float)BPART(color);
|
|
}
|
|
|
|
static void AM_initColors (BOOL overlayed)
|
|
{
|
|
static DWORD *lastpal = NULL;
|
|
static int lastback = -1;
|
|
DWORD *palette;
|
|
|
|
palette = (DWORD *)GPalette.BaseColors;
|
|
|
|
if (lastpal != palette)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = j = 0; i < 11; i++, j += 3)
|
|
{
|
|
DoomColors[i] = palette
|
|
? ColorMatcher.Pick (DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2])
|
|
: MAKERGB(DoomPaletteVals[j], DoomPaletteVals[j+1], DoomPaletteVals[j+2]);
|
|
}
|
|
}
|
|
|
|
if (overlayed)
|
|
{
|
|
YourColor = am_ovyourcolor.GetIndex ();
|
|
SecretSectorColor = SecretWallColor = WallColor = am_ovwallcolor.GetIndex ();
|
|
ThingColor_Item = am_ovthingcolor_item.GetIndex();
|
|
ThingColor_Friend = am_ovthingcolor_friend.GetIndex();
|
|
ThingColor_Monster = am_ovthingcolor_monster.GetIndex();
|
|
ThingColor = am_ovthingcolor.GetIndex ();
|
|
FDWallColor = CDWallColor = LockedColor = am_ovotherwallscolor.GetIndex ();
|
|
NotSeenColor = TSWallColor = am_ovunseencolor.GetIndex ();
|
|
IntraTeleportColor = InterTeleportColor = am_ovtelecolor.GetIndex ();
|
|
}
|
|
else if (am_usecustomcolors)
|
|
{
|
|
/* Use the custom colors in the am_* cvars */
|
|
Background = am_backcolor.GetIndex ();
|
|
YourColor = am_yourcolor.GetIndex ();
|
|
SecretWallColor = am_secretwallcolor.GetIndex ();
|
|
WallColor = am_wallcolor.GetIndex ();
|
|
TSWallColor = am_tswallcolor.GetIndex ();
|
|
FDWallColor = am_fdwallcolor.GetIndex ();
|
|
CDWallColor = am_cdwallcolor.GetIndex ();
|
|
ThingColor_Item = am_thingcolor_item.GetIndex();
|
|
ThingColor_Friend = am_thingcolor_friend.GetIndex();
|
|
ThingColor_Monster = am_thingcolor_monster.GetIndex();
|
|
ThingColor = am_thingcolor.GetIndex ();
|
|
GridColor = am_gridcolor.GetIndex ();
|
|
XHairColor = am_xhaircolor.GetIndex ();
|
|
NotSeenColor = am_notseencolor.GetIndex ();
|
|
LockedColor = am_lockedcolor.GetIndex ();
|
|
InterTeleportColor = am_interlevelcolor.GetIndex ();
|
|
IntraTeleportColor = am_intralevelcolor.GetIndex ();
|
|
SecretSectorColor = am_secretsectorcolor.GetIndex ();
|
|
|
|
DWORD ba = am_backcolor;
|
|
|
|
int r = RPART(ba) - 16;
|
|
int g = GPART(ba) - 16;
|
|
int b = BPART(ba) - 16;
|
|
|
|
if (r < 0)
|
|
r += 32;
|
|
if (g < 0)
|
|
g += 32;
|
|
if (b < 0)
|
|
b += 32;
|
|
|
|
AlmostBackground = ColorMatcher.Pick (r, g, b);
|
|
}
|
|
else
|
|
{ // Use colors corresponding to the original Doom's
|
|
Background = DoomColors[0];
|
|
YourColor = DoomColors[1];
|
|
AlmostBackground = DoomColors[2];
|
|
SecretSectorColor =
|
|
SecretWallColor =
|
|
WallColor = DoomColors[3];
|
|
TSWallColor = DoomColors[4];
|
|
FDWallColor = DoomColors[5];
|
|
LockedColor =
|
|
CDWallColor = DoomColors[6];
|
|
ThingColor_Item =
|
|
ThingColor_Friend =
|
|
ThingColor_Monster =
|
|
ThingColor = DoomColors[7];
|
|
GridColor = DoomColors[8];
|
|
XHairColor = DoomColors[9];
|
|
NotSeenColor = DoomColors[10];
|
|
}
|
|
|
|
// initialize the anti-aliased lines
|
|
static struct
|
|
{
|
|
int *color;
|
|
int prevcolor;
|
|
int falseColor;
|
|
} aliasedLines[3] = {
|
|
{ &WallColor, -1, WALLCOLORS },
|
|
{ &FDWallColor, -1, FDWALLCOLORS },
|
|
{ &CDWallColor, -1, CDWALLCOLORS }
|
|
};
|
|
float backRed, backGreen, backBlue;
|
|
|
|
GetComponents (Background, palette, backRed, backGreen, backBlue);
|
|
|
|
for (int alias = 0; alias < NUMALIASES; alias++)
|
|
{
|
|
if (aliasedLines[alias].prevcolor != *(aliasedLines[alias].color) ||
|
|
lastpal != palette || lastback != Background)
|
|
{
|
|
float foreRed, foreGreen, foreBlue;
|
|
|
|
aliasedLines[alias].prevcolor = *(aliasedLines[alias].color);
|
|
GetComponents (*(aliasedLines[alias].color), palette, foreRed, foreGreen, foreBlue);
|
|
|
|
for (int i = 0; i < NUMWEIGHTS; i++)
|
|
{
|
|
float step = (float)i;
|
|
float fore = (NUMWEIGHTS-1 - step) / (NUMWEIGHTS-1);
|
|
float back = step / (NUMWEIGHTS-1);
|
|
int red = (int)(backRed * back + foreRed * fore);
|
|
int green = (int)(backGreen * back + foreGreen * fore);
|
|
int blue = (int)(backGreen * back + foreBlue * fore);
|
|
if (palette)
|
|
antialias[alias][i] = ColorMatcher.Pick (red, green, blue);
|
|
else
|
|
antialias[alias][i] = MAKERGB(red, green, blue);
|
|
}
|
|
*(aliasedLines[alias].color) = aliasedLines[alias].falseColor;
|
|
}
|
|
}
|
|
lastpal = palette;
|
|
lastback = Background;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_loadPics ()
|
|
{
|
|
int i;
|
|
char namebuf[9];
|
|
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
sprintf (namebuf, "AMMNUM%d", i);
|
|
marknums[i] = TexMan.CheckForTexture (namebuf, FTexture::TEX_MiscPatch);
|
|
}
|
|
|
|
if (mapback == NULL)
|
|
{
|
|
i = Wads.CheckNumForName ("AUTOPAGE");
|
|
if (i >= 0)
|
|
{
|
|
mapback = new FAutomapTexture (i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AM_unloadPics ()
|
|
{
|
|
if (mapback != NULL)
|
|
{
|
|
delete mapback;
|
|
mapback = NULL;
|
|
}
|
|
}
|
|
|
|
bool AM_clearMarks ()
|
|
{
|
|
for (int i = AM_NUMMARKPOINTS-1; i >= 0; i--)
|
|
markpoints[i].x = -1; // means empty
|
|
markpointnum = 0;
|
|
return marknums[0] != -1;
|
|
}
|
|
|
|
//
|
|
// should be called at the start of every level
|
|
// right now, i figure it out myself
|
|
//
|
|
void AM_LevelInit ()
|
|
{
|
|
leveljuststarted = 0;
|
|
|
|
AM_clearMarks();
|
|
|
|
AM_findMinMaxBoundaries();
|
|
scale_mtof = MapDiv(min_scale_mtof, (int) (0.7*MAPUNIT));
|
|
if (scale_mtof > max_scale_mtof)
|
|
scale_mtof = min_scale_mtof;
|
|
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_Stop ()
|
|
{
|
|
AM_unloadPics ();
|
|
automapactive = false;
|
|
stopped = true;
|
|
BorderNeedRefresh = screen->GetPageCount ();
|
|
viewactive = true;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_Start ()
|
|
{
|
|
static char lastmap[sizeof(level.mapname)] = "";
|
|
|
|
if (!stopped) AM_Stop();
|
|
stopped = false;
|
|
if (strcmp (lastmap, level.mapname))
|
|
{
|
|
AM_LevelInit();
|
|
strcpy (lastmap, level.mapname);
|
|
}
|
|
AM_initVariables();
|
|
AM_loadPics();
|
|
}
|
|
|
|
//
|
|
// set the window scale to the maximum size
|
|
//
|
|
void AM_minOutWindowScale ()
|
|
{
|
|
scale_mtof = min_scale_mtof;
|
|
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
|
}
|
|
|
|
//
|
|
// set the window scale to the minimum size
|
|
//
|
|
void AM_maxOutWindowScale ()
|
|
{
|
|
scale_mtof = max_scale_mtof;
|
|
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
|
}
|
|
|
|
|
|
CCMD (togglemap)
|
|
{
|
|
gameaction = ga_togglemap;
|
|
}
|
|
|
|
void AM_ToggleMap ()
|
|
{
|
|
if (gamestate != GS_LEVEL)
|
|
return;
|
|
|
|
SB_state = screen->GetPageCount ();
|
|
if (!automapactive)
|
|
{
|
|
AM_Start ();
|
|
viewactive = (am_overlay != 0.f);
|
|
}
|
|
else
|
|
{
|
|
if (am_overlay && viewactive)
|
|
{
|
|
viewactive = false;
|
|
SB_state = screen->GetPageCount ();
|
|
}
|
|
else
|
|
{
|
|
AM_Stop ();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle events (user inputs) in automap mode
|
|
//
|
|
BOOL AM_Responder (event_t *ev)
|
|
{
|
|
int rc;
|
|
static int cheatstate = 0;
|
|
static int bigstate = 0;
|
|
|
|
rc = false;
|
|
|
|
if (automapactive && ev->type == EV_KeyDown)
|
|
{
|
|
rc = true;
|
|
switch (ev->data1)
|
|
{
|
|
case AM_PANRIGHTKEY: // pan right
|
|
if (!followplayer)
|
|
m_paninc.x = FTOM(F_PANINC);
|
|
else
|
|
rc = false;
|
|
break;
|
|
case AM_PANLEFTKEY: // pan left
|
|
if (!followplayer)
|
|
m_paninc.x = -FTOM(F_PANINC);
|
|
else
|
|
rc = false;
|
|
break;
|
|
case AM_PANUPKEY: // pan up
|
|
if (!followplayer)
|
|
m_paninc.y = FTOM(F_PANINC);
|
|
else
|
|
rc = false;
|
|
break;
|
|
case AM_PANDOWNKEY: // pan down
|
|
if (!followplayer)
|
|
m_paninc.y = -FTOM(F_PANINC);
|
|
else
|
|
rc = false;
|
|
break;
|
|
case AM_ZOOMOUTKEY: // zoom out
|
|
case AM_ZOOMOUTKEY2:
|
|
mtof_zoommul = M_ZOOMOUT;
|
|
ftom_zoommul = M_ZOOMIN;
|
|
break;
|
|
case AM_ZOOMINKEY: // zoom in
|
|
case AM_ZOOMINKEY2:
|
|
mtof_zoommul = M_ZOOMIN;
|
|
ftom_zoommul = M_ZOOMOUT;
|
|
break;
|
|
case AM_GOBIGKEY:
|
|
bigstate = !bigstate;
|
|
if (bigstate)
|
|
{
|
|
AM_saveScaleAndLoc();
|
|
AM_minOutWindowScale();
|
|
}
|
|
else
|
|
AM_restoreScaleAndLoc();
|
|
break;
|
|
default:
|
|
switch (ev->data2)
|
|
{
|
|
case AM_FOLLOWKEY:
|
|
followplayer = !followplayer;
|
|
f_oldloc.x = FIXED_MAX;
|
|
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
|
|
break;
|
|
case AM_GRIDKEY:
|
|
grid = !grid;
|
|
Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF"));
|
|
break;
|
|
case AM_MARKKEY:
|
|
if (AM_addMark())
|
|
{
|
|
Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum);
|
|
}
|
|
else
|
|
{
|
|
rc = false;
|
|
}
|
|
break;
|
|
case AM_CLEARMARKKEY:
|
|
if (AM_clearMarks())
|
|
{
|
|
Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED"));
|
|
}
|
|
else
|
|
{
|
|
rc = false;
|
|
}
|
|
break;
|
|
default:
|
|
cheatstate = 0;
|
|
rc = false;
|
|
}
|
|
}
|
|
}
|
|
else if (ev->type == EV_KeyUp)
|
|
{
|
|
rc = false;
|
|
switch (ev->data1)
|
|
{
|
|
case AM_PANRIGHTKEY:
|
|
if (!followplayer) m_paninc.x = 0;
|
|
break;
|
|
case AM_PANLEFTKEY:
|
|
if (!followplayer) m_paninc.x = 0;
|
|
break;
|
|
case AM_PANUPKEY:
|
|
if (!followplayer) m_paninc.y = 0;
|
|
break;
|
|
case AM_PANDOWNKEY:
|
|
if (!followplayer) m_paninc.y = 0;
|
|
break;
|
|
case AM_ZOOMOUTKEY:
|
|
case AM_ZOOMOUTKEY2:
|
|
case AM_ZOOMINKEY:
|
|
case AM_ZOOMINKEY2:
|
|
mtof_zoommul = MAPUNIT;
|
|
ftom_zoommul = MAPUNIT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
//
|
|
// Zooming
|
|
//
|
|
void AM_changeWindowScale ()
|
|
{
|
|
// Change the scaling multipliers
|
|
scale_mtof = MapMul(scale_mtof, mtof_zoommul);
|
|
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
|
|
|
if (scale_mtof < min_scale_mtof)
|
|
AM_minOutWindowScale();
|
|
else if (scale_mtof > max_scale_mtof)
|
|
AM_maxOutWindowScale();
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
void AM_doFollowPlayer ()
|
|
{
|
|
fixed_t sx, sy;
|
|
|
|
if (players[consoleplayer].camera != NULL &&
|
|
(f_oldloc.x != players[consoleplayer].camera->x ||
|
|
f_oldloc.y != players[consoleplayer].camera->y))
|
|
{
|
|
m_x = (players[consoleplayer].camera->x >> FRACTOMAPBITS) - m_w/2;
|
|
m_y = (players[consoleplayer].camera->y >> FRACTOMAPBITS) - m_h/2;
|
|
m_x2 = m_x + m_w;
|
|
m_y2 = m_y + m_h;
|
|
|
|
// do the parallax parchment scrolling.
|
|
sx = (players[consoleplayer].camera->x - f_oldloc.x) >> FRACTOMAPBITS;
|
|
sy = (f_oldloc.y - players[consoleplayer].camera->y) >> FRACTOMAPBITS;
|
|
if (am_rotate)
|
|
{
|
|
AM_rotate (&sx, &sy, players[consoleplayer].camera->angle - ANG90);
|
|
}
|
|
AM_ScrollParchment (sx, sy);
|
|
|
|
f_oldloc.x = players[consoleplayer].camera->x;
|
|
f_oldloc.y = players[consoleplayer].camera->y;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Updates on Game Tick
|
|
//
|
|
void AM_Ticker ()
|
|
{
|
|
if (!automapactive)
|
|
return;
|
|
|
|
amclock++;
|
|
|
|
if (followplayer)
|
|
AM_doFollowPlayer();
|
|
|
|
// Change the zoom if necessary
|
|
if (ftom_zoommul != MAPUNIT)
|
|
AM_changeWindowScale();
|
|
|
|
// Change x,y location
|
|
//if (m_paninc.x || m_paninc.y)
|
|
AM_changeWindowLoc();
|
|
}
|
|
|
|
|
|
//
|
|
// Clear automap frame buffer.
|
|
//
|
|
void AM_clearFB (int color)
|
|
{
|
|
if (mapback == NULL || !am_drawmapback)
|
|
{
|
|
screen->Clear (0, 0, f_w, f_h, color);
|
|
}
|
|
else
|
|
{
|
|
int pwidth = mapback->GetWidth();
|
|
int pheight = mapback->GetHeight();
|
|
int x, y;
|
|
|
|
//blit the automap background to the screen.
|
|
for (y = mapystart >> MAPBITS; y < f_h; y += pheight)
|
|
{
|
|
for (x = mapxstart >> MAPBITS; x < f_w; x += pwidth)
|
|
{
|
|
screen->DrawTexture (mapback, x, y, DTA_ClipBottom, f_h, TAG_DONE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Automap clipping of lines.
|
|
//
|
|
// Based on Cohen-Sutherland clipping algorithm but with a slightly
|
|
// faster reject and precalculated slopes. If the speed is needed,
|
|
// use a hash algorithm to handle the common cases.
|
|
//
|
|
BOOL AM_clipMline (mline_t *ml, fline_t *fl)
|
|
{
|
|
enum {
|
|
LEFT =1,
|
|
RIGHT =2,
|
|
BOTTOM =4,
|
|
TOP =8
|
|
};
|
|
|
|
register int outcode1 = 0;
|
|
register int outcode2 = 0;
|
|
register int outside;
|
|
|
|
fpoint_t tmp;
|
|
int dx;
|
|
int dy;
|
|
|
|
#define DOOUTCODE(oc, mx, my) \
|
|
(oc) = 0; \
|
|
if ((my) < 0) (oc) |= TOP; \
|
|
else if ((my) >= f_h) (oc) |= BOTTOM; \
|
|
if ((mx) < 0) (oc) |= LEFT; \
|
|
else if ((mx) >= f_w) (oc) |= RIGHT;
|
|
|
|
// do trivial rejects and outcodes
|
|
if (ml->a.y > m_y2)
|
|
outcode1 = TOP;
|
|
else if (ml->a.y < m_y)
|
|
outcode1 = BOTTOM;
|
|
|
|
if (ml->b.y > m_y2)
|
|
outcode2 = TOP;
|
|
else if (ml->b.y < m_y)
|
|
outcode2 = BOTTOM;
|
|
|
|
if (outcode1 & outcode2)
|
|
return false; // trivially outside
|
|
|
|
if (ml->a.x < m_x)
|
|
outcode1 |= LEFT;
|
|
else if (ml->a.x > m_x2)
|
|
outcode1 |= RIGHT;
|
|
|
|
if (ml->b.x < m_x)
|
|
outcode2 |= LEFT;
|
|
else if (ml->b.x > m_x2)
|
|
outcode2 |= RIGHT;
|
|
|
|
if (outcode1 & outcode2)
|
|
return false; // trivially outside
|
|
|
|
// transform to frame-buffer coordinates.
|
|
fl->a.x = CXMTOF(ml->a.x);
|
|
fl->a.y = CYMTOF(ml->a.y);
|
|
fl->b.x = CXMTOF(ml->b.x);
|
|
fl->b.y = CYMTOF(ml->b.y);
|
|
|
|
DOOUTCODE(outcode1, fl->a.x, fl->a.y);
|
|
DOOUTCODE(outcode2, fl->b.x, fl->b.y);
|
|
|
|
if (outcode1 & outcode2)
|
|
return false;
|
|
|
|
while (outcode1 | outcode2) {
|
|
// may be partially inside box
|
|
// find an outside point
|
|
if (outcode1)
|
|
outside = outcode1;
|
|
else
|
|
outside = outcode2;
|
|
|
|
// clip to each side
|
|
if (outside & TOP)
|
|
{
|
|
dy = fl->a.y - fl->b.y;
|
|
dx = fl->b.x - fl->a.x;
|
|
tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
|
|
tmp.y = 0;
|
|
}
|
|
else if (outside & BOTTOM)
|
|
{
|
|
dy = fl->a.y - fl->b.y;
|
|
dx = fl->b.x - fl->a.x;
|
|
tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
|
|
tmp.y = f_h-1;
|
|
}
|
|
else if (outside & RIGHT)
|
|
{
|
|
dy = fl->b.y - fl->a.y;
|
|
dx = fl->b.x - fl->a.x;
|
|
tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
|
|
tmp.x = f_w-1;
|
|
}
|
|
else if (outside & LEFT)
|
|
{
|
|
dy = fl->b.y - fl->a.y;
|
|
dx = fl->b.x - fl->a.x;
|
|
tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
|
|
tmp.x = 0;
|
|
}
|
|
|
|
if (outside == outcode1)
|
|
{
|
|
fl->a = tmp;
|
|
DOOUTCODE(outcode1, fl->a.x, fl->a.y);
|
|
}
|
|
else
|
|
{
|
|
fl->b = tmp;
|
|
DOOUTCODE(outcode2, fl->b.x, fl->b.y);
|
|
}
|
|
|
|
if (outcode1 & outcode2)
|
|
return false; // trivially outside
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#undef DOOUTCODE
|
|
|
|
|
|
//
|
|
// Classic Bresenham w/ whatever optimizations needed for speed
|
|
//
|
|
void AM_drawFline (fline_t *fl, int color)
|
|
{
|
|
fl->a.x += f_x;
|
|
fl->b.x += f_x;
|
|
fl->a.y += f_y;
|
|
fl->b.y += f_y;
|
|
|
|
switch (color)
|
|
{
|
|
case WALLCOLORS:
|
|
DrawWuLine (fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[0][0]);
|
|
break;
|
|
case FDWALLCOLORS:
|
|
DrawWuLine (fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[1][0]);
|
|
break;
|
|
case CDWALLCOLORS:
|
|
DrawWuLine (fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[2][0]);
|
|
break;
|
|
default:
|
|
DrawTransWuLine (fl->a.x, fl->a.y, fl->b.x, fl->b.y, color);
|
|
break;
|
|
#if 0
|
|
{
|
|
register int x;
|
|
register int y;
|
|
register int dx;
|
|
register int dy;
|
|
register int sx;
|
|
register int sy;
|
|
register int ax;
|
|
register int ay;
|
|
register int d;
|
|
|
|
#define PUTDOTP(xx,yy,cc) fb[(yy)*f_p+(xx)]=(cc)
|
|
|
|
dx = fl->b.x - fl->a.x;
|
|
ax = 2 * (dx<0 ? -dx : dx);
|
|
sx = dx<0 ? -1 : 1;
|
|
|
|
dy = fl->b.y - fl->a.y;
|
|
ay = 2 * (dy<0 ? -dy : dy);
|
|
sy = dy<0 ? -1 : 1;
|
|
|
|
x = fl->a.x;
|
|
y = fl->a.y;
|
|
|
|
if (ax > ay) {
|
|
d = ay - ax/2;
|
|
for (;;) {
|
|
PUTDOTP(x,y,(byte)color);
|
|
if (x == fl->b.x)
|
|
return;
|
|
if (d>=0) {
|
|
y += sy;
|
|
d -= ax;
|
|
}
|
|
x += sx;
|
|
d += ay;
|
|
}
|
|
} else {
|
|
d = ax - ay/2;
|
|
for (;;) {
|
|
PUTDOTP(x, y, (byte)color);
|
|
if (y == fl->b.y)
|
|
return;
|
|
if (d >= 0) {
|
|
x += sx;
|
|
d -= ay;
|
|
}
|
|
y += sy;
|
|
d += ax;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* Wu antialiased line drawer.
|
|
* (X0,Y0),(X1,Y1) = line to draw
|
|
* BaseColor = color # of first color in block used for antialiasing, the
|
|
* 100% intensity version of the drawing color
|
|
* NumLevels = size of color block, with BaseColor+NumLevels-1 being the
|
|
* 0% intensity version of the drawing color
|
|
* IntensityBits = log base 2 of NumLevels; the # of bits used to describe
|
|
* the intensity of the drawing color. 2**IntensityBits==NumLevels
|
|
*/
|
|
void PUTDOT (int xx, int yy,byte *cc, byte *cm)
|
|
{
|
|
static int oldyy;
|
|
static int oldyyshifted;
|
|
byte *oldcc=cc;
|
|
|
|
#if 0
|
|
if(xx < 32)
|
|
cc += 7-(xx>>2);
|
|
else if(xx > (finit_width - 32))
|
|
cc += 7-((finit_width-xx) >> 2);
|
|
// if(cc==oldcc) //make sure that we don't double fade the corners.
|
|
// {
|
|
if(yy < 32)
|
|
cc += 7-(yy>>2);
|
|
else if(yy > (finit_height - 32))
|
|
cc += 7-((finit_height-yy) >> 2);
|
|
// }
|
|
#endif
|
|
if (cm != NULL && cc > cm)
|
|
{
|
|
cc = cm;
|
|
}
|
|
else if (cc > oldcc+6) // don't let the color escape from the fade table...
|
|
{
|
|
cc=oldcc+6;
|
|
}
|
|
if (yy == oldyy+1)
|
|
{
|
|
oldyy++;
|
|
oldyyshifted += SCREENPITCH;
|
|
}
|
|
else if (yy == oldyy-1)
|
|
{
|
|
oldyy--;
|
|
oldyyshifted -= SCREENPITCH;
|
|
}
|
|
else if (yy != oldyy)
|
|
{
|
|
oldyy = yy;
|
|
oldyyshifted = yy*SCREENPITCH;
|
|
}
|
|
fb[oldyyshifted+xx] = *(cc);
|
|
}
|
|
|
|
void DrawWuLine (int x0, int y0, int x1, int y1, byte *baseColor)
|
|
{
|
|
int deltaX, deltaY, xDir;
|
|
|
|
if (viewactive)
|
|
{
|
|
// If the map is overlayed, use the translucent line drawer
|
|
// code to avoid nasty discolored spots along the edges of
|
|
// the lines. Otherwise, use this one to avoid reading from
|
|
// the framebuffer.
|
|
DrawTransWuLine (x0, y0, x1, y1, *baseColor);
|
|
return;
|
|
}
|
|
|
|
// Make sure the line runs top to bottom
|
|
if (y0 > y1)
|
|
{
|
|
int temp = y0; y0 = y1; y1 = temp;
|
|
temp = x0; x0 = x1; x1 = temp;
|
|
}
|
|
|
|
// Draw the initial pixel, which is always exactly intersected by
|
|
// the line and so needs no weighting
|
|
PUTDOT (x0, y0, &baseColor[0], NULL);
|
|
|
|
if ((deltaX = x1 - x0) >= 0)
|
|
{
|
|
xDir = 1;
|
|
}
|
|
else
|
|
{
|
|
xDir = -1;
|
|
deltaX = -deltaX; // make deltaX positive
|
|
}
|
|
// Special-case horizontal, vertical, and diagonal lines, which
|
|
// require no weighting because they go right through the center of
|
|
// every pixel
|
|
if ((deltaY = y1 - y0) == 0)
|
|
{ // horizontal line
|
|
while (deltaX-- != 0)
|
|
{
|
|
x0 += xDir;
|
|
PUTDOT (x0, y0, &baseColor[0], NULL);
|
|
}
|
|
return;
|
|
}
|
|
if (deltaX == 0)
|
|
{ // vertical line
|
|
do
|
|
{
|
|
y0++;
|
|
PUTDOT (x0, y0, &baseColor[0], NULL);
|
|
} while (--deltaY != 0);
|
|
return;
|
|
}
|
|
if (deltaX == deltaY)
|
|
{ // diagonal line.
|
|
do
|
|
{
|
|
x0 += xDir;
|
|
y0++;
|
|
PUTDOT (x0, y0, &baseColor[0], NULL);
|
|
} while (--deltaY != 0);
|
|
return;
|
|
}
|
|
|
|
// Line is not horizontal, diagonal, or vertical
|
|
fixed_t errorAcc = 0; // initialize the line error accumulator to 0
|
|
|
|
// Is this an X-major or Y-major line?
|
|
if (deltaY > deltaX)
|
|
{
|
|
// Y-major line; calculate 16-bit fixed-point fractional part of a
|
|
// pixel that X advances each time Y advances 1 pixel, truncating the
|
|
// result so that we won't overrun the endpoint along the X axis
|
|
fixed_t errorAdj = ((DWORD) deltaX << 16) / (DWORD) deltaY & 0xffff;
|
|
|
|
// Draw all pixels other than the first and last
|
|
if (xDir < 0)
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++; // Y-major, so always advance Y
|
|
|
|
// The most significant bits of ErrorAcc give us the intensity
|
|
// weighting for this pixel, and the complement of the weighting
|
|
// for the paired pixel
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTDOT (x0 - (errorAcc >> 16), y0, &baseColor[weighting], &baseColor[NUMWEIGHTS-1]);
|
|
PUTDOT (x0 - (errorAcc >> 16) - 1, y0,
|
|
&baseColor[WEIGHTMASK - weighting], &baseColor[NUMWEIGHTS-1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++; // Y-major, so always advance Y
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTDOT (x0 + (errorAcc >> 16), y0, &baseColor[weighting], &baseColor[NUMWEIGHTS-1]);
|
|
PUTDOT (x0 + (errorAcc >> 16) + 1, y0,
|
|
&baseColor[WEIGHTMASK - weighting], &baseColor[NUMWEIGHTS-1]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It's an X-major line; calculate 16-bit fixed-point fractional part of a
|
|
// pixel that Y advances each time X advances 1 pixel, truncating the
|
|
// result to avoid overrunning the endpoint along the X axis
|
|
fixed_t errorAdj = ((DWORD) deltaY << 16) / (DWORD) deltaX;
|
|
|
|
// Draw all pixels other than the first and last
|
|
while (--deltaX)
|
|
{
|
|
errorAcc += errorAdj;
|
|
x0 += xDir; // X-major, so always advance X
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTDOT (x0, y0 + (errorAcc >> 16), &baseColor[weighting], &baseColor[NUMWEIGHTS-1]);
|
|
PUTDOT (x0, y0 + (errorAcc >> 16) + 1,
|
|
&baseColor[WEIGHTMASK - weighting], &baseColor[NUMWEIGHTS-1]);
|
|
}
|
|
}
|
|
|
|
// Draw the final pixel, which is always exactly intersected by the line
|
|
// and so needs no weighting
|
|
PUTDOT (x1, y1, &baseColor[0], NULL);
|
|
}
|
|
|
|
void PUTTRANSDOT (int xx, int yy, int basecolor, int level)
|
|
{
|
|
static int oldyy;
|
|
static int oldyyshifted;
|
|
|
|
#if 0
|
|
if(xx < 32)
|
|
cc += 7-(xx>>2);
|
|
else if(xx > (finit_width - 32))
|
|
cc += 7-((finit_width-xx) >> 2);
|
|
// if(cc==oldcc) //make sure that we don't double fade the corners.
|
|
// {
|
|
if(yy < 32)
|
|
cc += 7-(yy>>2);
|
|
else if(yy > (finit_height - 32))
|
|
cc += 7-((finit_height-yy) >> 2);
|
|
// }
|
|
if(cc > cm && cm != NULL)
|
|
{
|
|
cc = cm;
|
|
}
|
|
else if(cc > oldcc+6) // don't let the color escape from the fade table...
|
|
{
|
|
cc=oldcc+6;
|
|
}
|
|
#endif
|
|
if (yy == oldyy+1)
|
|
{
|
|
oldyy++;
|
|
oldyyshifted += SCREENPITCH;
|
|
}
|
|
else if (yy == oldyy-1)
|
|
{
|
|
oldyy--;
|
|
oldyyshifted -= SCREENPITCH;
|
|
}
|
|
else if (yy != oldyy)
|
|
{
|
|
oldyy = yy;
|
|
oldyyshifted = yy*SCREENPITCH;
|
|
}
|
|
|
|
byte *spot = fb + oldyyshifted + xx;
|
|
DWORD *bg2rgb = Col2RGB8[1+level];
|
|
DWORD *fg2rgb = Col2RGB8[63-level];
|
|
DWORD fg = fg2rgb[basecolor];
|
|
DWORD bg = bg2rgb[*spot];
|
|
bg = (fg+bg) | 0x1f07c1f;
|
|
*spot = RGB32k[0][0][bg&(bg>>15)];
|
|
}
|
|
|
|
void DrawTransWuLine (int x0, int y0, int x1, int y1, byte baseColor)
|
|
{
|
|
int deltaX, deltaY, xDir;
|
|
|
|
if (y0 > y1)
|
|
{
|
|
int temp = y0; y0 = y1; y1 = temp;
|
|
temp = x0; x0 = x1; x1 = temp;
|
|
}
|
|
|
|
PUTTRANSDOT (x0, y0, baseColor, 0);
|
|
|
|
if ((deltaX = x1 - x0) >= 0)
|
|
{
|
|
xDir = 1;
|
|
}
|
|
else
|
|
{
|
|
xDir = -1;
|
|
deltaX = -deltaX;
|
|
}
|
|
|
|
if ((deltaY = y1 - y0) == 0)
|
|
{ // horizontal line
|
|
if (x0 > x1)
|
|
{
|
|
swap (x0, x1);
|
|
}
|
|
memset (screen->GetBuffer() + y0*screen->GetPitch() + x0, baseColor, deltaX+1);
|
|
return;
|
|
}
|
|
if (deltaX == 0)
|
|
{ // vertical line
|
|
byte *spot = screen->GetBuffer() + y0*screen->GetPitch() + x0;
|
|
int pitch = screen->GetPitch ();
|
|
do
|
|
{
|
|
*spot = baseColor;
|
|
spot += pitch;
|
|
} while (--deltaY != 0);
|
|
return;
|
|
}
|
|
if (deltaX == deltaY)
|
|
{ // diagonal line.
|
|
byte *spot = screen->GetBuffer() + y0*screen->GetPitch() + x0;
|
|
int advance = screen->GetPitch() + xDir;
|
|
do
|
|
{
|
|
*spot = baseColor;
|
|
spot += advance;
|
|
} while (--deltaY != 0);
|
|
return;
|
|
}
|
|
|
|
// line is not horizontal, diagonal, or vertical
|
|
fixed_t errorAcc = 0;
|
|
|
|
if (deltaY > deltaX)
|
|
{ // y-major line
|
|
fixed_t errorAdj = (((unsigned)deltaX << 16) / (unsigned)deltaY) & 0xffff;
|
|
if (xDir < 0)
|
|
{
|
|
if (WeightingScale == 0)
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++;
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0 - (errorAcc >> 16), y0, baseColor, weighting);
|
|
PUTTRANSDOT (x0 - (errorAcc >> 16) - 1, y0,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++;
|
|
int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0 - (errorAcc >> 16), y0, baseColor, weighting);
|
|
PUTTRANSDOT (x0 - (errorAcc >> 16) - 1, y0,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (WeightingScale == 0)
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++;
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0 + (errorAcc >> 16), y0, baseColor, weighting);
|
|
PUTTRANSDOT (x0 + (errorAcc >> 16) + xDir, y0,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (--deltaY)
|
|
{
|
|
errorAcc += errorAdj;
|
|
y0++;
|
|
int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0 + (errorAcc >> 16), y0, baseColor, weighting);
|
|
PUTTRANSDOT (x0 + (errorAcc >> 16) + xDir, y0,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // x-major line
|
|
fixed_t errorAdj = (((DWORD) deltaY << 16) / (DWORD) deltaX) & 0xffff;
|
|
|
|
if (WeightingScale == 0)
|
|
{
|
|
while (--deltaX)
|
|
{
|
|
errorAcc += errorAdj;
|
|
x0 += xDir;
|
|
int weighting = (errorAcc >> WEIGHTSHIFT) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0, y0 + (errorAcc >> 16), baseColor, weighting);
|
|
PUTTRANSDOT (x0, y0 + (errorAcc >> 16) + 1,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (--deltaX)
|
|
{
|
|
errorAcc += errorAdj;
|
|
x0 += xDir;
|
|
int weighting = ((errorAcc * WeightingScale) >> (WEIGHTSHIFT+8)) & WEIGHTMASK;
|
|
PUTTRANSDOT (x0, y0 + (errorAcc >> 16), baseColor, weighting);
|
|
PUTTRANSDOT (x0, y0 + (errorAcc >> 16) + 1,
|
|
baseColor, WEIGHTMASK - weighting);
|
|
}
|
|
}
|
|
}
|
|
|
|
PUTTRANSDOT (x1, y1, baseColor, 0);
|
|
}
|
|
|
|
//
|
|
// Clip lines, draw visible parts of lines.
|
|
//
|
|
void AM_drawMline (mline_t *ml, int color)
|
|
{
|
|
static fline_t fl;
|
|
|
|
if (AM_clipMline (ml, &fl))
|
|
AM_drawFline (&fl, color); // draws it on frame buffer using fb coords
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Draws flat (floor/ceiling tile) aligned grid lines.
|
|
//
|
|
void AM_drawGrid (int color)
|
|
{
|
|
fixed_t x, y;
|
|
fixed_t start, end;
|
|
mline_t ml;
|
|
fixed_t minlen, extx, exty;
|
|
fixed_t minx, miny;
|
|
|
|
// [RH] Calculate a minimum for how long the grid lines should be so that
|
|
// they cover the screen at any rotation.
|
|
minlen = (fixed_t)sqrtf ((float)m_w*(float)m_w + (float)m_h*(float)m_h);
|
|
extx = (minlen - m_w) / 2;
|
|
exty = (minlen - m_h) / 2;
|
|
|
|
minx = m_x;
|
|
miny = m_y;
|
|
|
|
// Figure out start of vertical gridlines
|
|
start = minx - extx;
|
|
if ((start-bmaporgx)%(MAPBLOCKUNITS<<MAPBITS))
|
|
start += (MAPBLOCKUNITS<<MAPBITS)
|
|
- ((start-bmaporgx)%(MAPBLOCKUNITS<<MAPBITS));
|
|
end = minx + minlen - extx;
|
|
|
|
// draw vertical gridlines
|
|
for (x = start; x < end; x += (MAPBLOCKUNITS<<MAPBITS))
|
|
{
|
|
ml.a.x = x;
|
|
ml.b.x = x;
|
|
ml.a.y = miny - exty;
|
|
ml.b.y = ml.a.y + minlen;
|
|
if (am_rotate)
|
|
{
|
|
AM_rotatePoint (&ml.a.x, &ml.a.y);
|
|
AM_rotatePoint (&ml.b.x, &ml.b.y);
|
|
}
|
|
AM_drawMline(&ml, color);
|
|
}
|
|
|
|
// Figure out start of horizontal gridlines
|
|
start = miny - exty;
|
|
if ((start-bmaporgy)%(MAPBLOCKUNITS<<MAPBITS))
|
|
start += (MAPBLOCKUNITS<<MAPBITS)
|
|
- ((start-bmaporgy)%(MAPBLOCKUNITS<<MAPBITS));
|
|
end = miny + minlen - exty;
|
|
|
|
// draw horizontal gridlines
|
|
for (y=start; y<end; y+=(MAPBLOCKUNITS<<MAPBITS))
|
|
{
|
|
ml.a.x = minx - extx;
|
|
ml.b.x = ml.a.x + minlen;
|
|
ml.a.y = y;
|
|
ml.b.y = y;
|
|
if (am_rotate)
|
|
{
|
|
AM_rotatePoint (&ml.a.x, &ml.a.y);
|
|
AM_rotatePoint (&ml.b.x, &ml.b.y);
|
|
}
|
|
AM_drawMline (&ml, color);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determines visible lines, draws them.
|
|
// This is LineDef based, not LineSeg based.
|
|
//
|
|
void AM_drawWalls (bool allmap)
|
|
{
|
|
int i;
|
|
static mline_t l;
|
|
|
|
for (i = 0; i < numlines; i++)
|
|
{
|
|
l.a.x = lines[i].v1->x >> FRACTOMAPBITS;
|
|
l.a.y = lines[i].v1->y >> FRACTOMAPBITS;
|
|
l.b.x = lines[i].v2->x >> FRACTOMAPBITS;
|
|
l.b.y = lines[i].v2->y >> FRACTOMAPBITS;
|
|
|
|
if (am_rotate)
|
|
{
|
|
AM_rotatePoint (&l.a.x, &l.a.y);
|
|
AM_rotatePoint (&l.b.x, &l.b.y);
|
|
}
|
|
|
|
if (am_cheat != 0 || (lines[i].flags & ML_MAPPED))
|
|
{
|
|
if ((lines[i].flags & ML_DONTDRAW) && am_cheat == 0)
|
|
continue;
|
|
|
|
if (!lines[i].backsector)
|
|
{
|
|
if (lines[i].frontsector->oldspecial &&
|
|
(am_map_secrets==2 || (am_map_secrets==1 && !(lines[i].frontsector->special&SECRET_MASK))))
|
|
{
|
|
// map secret sectors like Boom
|
|
AM_drawMline(&l, SecretSectorColor);
|
|
}
|
|
else
|
|
{
|
|
AM_drawMline(&l, WallColor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((lines[i].special == Teleport ||
|
|
lines[i].special == Teleport_NoFog ||
|
|
lines[i].special == Teleport_Line) &&
|
|
GET_SPAC(lines[i].flags) != SPAC_MCROSS &&
|
|
am_usecustomcolors)
|
|
{ // intra-level teleporters
|
|
AM_drawMline(&l, IntraTeleportColor);
|
|
}
|
|
else if ((lines[i].special == Teleport_NewMap ||
|
|
lines[i].special == Teleport_EndGame ||
|
|
lines[i].special == Exit_Normal ||
|
|
lines[i].special == Exit_Secret) &&
|
|
am_usecustomcolors)
|
|
{ // inter-level/game-ending teleporters
|
|
AM_drawMline(&l, InterTeleportColor);
|
|
}
|
|
else if (lines[i].flags & ML_SECRET)
|
|
{ // secret door
|
|
if (am_cheat != 0)
|
|
AM_drawMline(&l, SecretWallColor);
|
|
else
|
|
AM_drawMline(&l, WallColor);
|
|
}
|
|
else if (lines[i].special == Door_LockedRaise ||
|
|
lines[i].special == ACS_LockedExecute ||
|
|
(lines[i].special == Generic_Door && lines[i].args[4]!=0))
|
|
{
|
|
if (am_usecustomcolors)
|
|
{
|
|
int P_GetMapColorForLock(int lock);
|
|
int lock;
|
|
|
|
|
|
if (lines[i].special==Door_LockedRaise) lock=lines[i].args[3];
|
|
else lock=lines[i].args[4];
|
|
|
|
int color = P_GetMapColorForLock(lock);
|
|
|
|
if (color > 0)
|
|
{
|
|
color = ColorMatcher.Pick(RPART(color), GPART(color), BPART(color));
|
|
}
|
|
else color = LockedColor;
|
|
|
|
AM_drawMline (&l, color);
|
|
}
|
|
else
|
|
AM_drawMline (&l, LockedColor); // locked special
|
|
}
|
|
else if (lines[i].backsector->floorplane
|
|
!= lines[i].frontsector->floorplane)
|
|
{
|
|
AM_drawMline(&l, FDWallColor); // floor level change
|
|
}
|
|
else if (lines[i].backsector->ceilingplane
|
|
!= lines[i].frontsector->ceilingplane)
|
|
{
|
|
AM_drawMline(&l, CDWallColor); // ceiling level change
|
|
}
|
|
else if (am_cheat != 0)
|
|
{
|
|
AM_drawMline(&l, TSWallColor);
|
|
}
|
|
}
|
|
}
|
|
else if (allmap)
|
|
{
|
|
if (!(lines[i].flags & ML_DONTDRAW))
|
|
AM_drawMline(&l, NotSeenColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Rotation in 2D.
|
|
// Used to rotate player arrow line character.
|
|
//
|
|
void AM_rotate (fixed_t *x, fixed_t *y, angle_t a)
|
|
{
|
|
fixed_t tmpx;
|
|
|
|
a >>= ANGLETOFINESHIFT;
|
|
tmpx = DMulScale16 (*x,finecosine[a],*y,-finesine[a]);
|
|
*y = DMulScale16 (*x,finesine[a],*y,finecosine[a]);
|
|
*x = tmpx;
|
|
}
|
|
|
|
void AM_rotatePoint (fixed_t *x, fixed_t *y)
|
|
{
|
|
*x -= players[consoleplayer].camera->x >> FRACTOMAPBITS;
|
|
*y -= players[consoleplayer].camera->y >> FRACTOMAPBITS;
|
|
AM_rotate (x, y, ANG90 - players[consoleplayer].camera->angle);
|
|
*x += players[consoleplayer].camera->x >> FRACTOMAPBITS;
|
|
*y += players[consoleplayer].camera->y >> FRACTOMAPBITS;
|
|
}
|
|
|
|
void
|
|
AM_drawLineCharacter
|
|
( const mline_t *lineguy,
|
|
int lineguylines,
|
|
fixed_t scale,
|
|
angle_t angle,
|
|
int color,
|
|
fixed_t x,
|
|
fixed_t y )
|
|
{
|
|
int i;
|
|
mline_t l;
|
|
|
|
for (i=0;i<lineguylines;i++) {
|
|
l.a.x = lineguy[i].a.x;
|
|
l.a.y = lineguy[i].a.y;
|
|
|
|
if (scale) {
|
|
l.a.x = MapMul(scale, l.a.x);
|
|
l.a.y = MapMul(scale, l.a.y);
|
|
}
|
|
|
|
if (angle)
|
|
AM_rotate(&l.a.x, &l.a.y, angle);
|
|
|
|
l.a.x += x;
|
|
l.a.y += y;
|
|
|
|
l.b.x = lineguy[i].b.x;
|
|
l.b.y = lineguy[i].b.y;
|
|
|
|
if (scale) {
|
|
l.b.x = MapMul(scale, l.b.x);
|
|
l.b.y = MapMul(scale, l.b.y);
|
|
}
|
|
|
|
if (angle)
|
|
AM_rotate(&l.b.x, &l.b.y, angle);
|
|
|
|
l.b.x += x;
|
|
l.b.y += y;
|
|
|
|
AM_drawMline(&l, color);
|
|
}
|
|
}
|
|
|
|
void AM_drawPlayers ()
|
|
{
|
|
angle_t angle;
|
|
int i;
|
|
|
|
if (!multiplayer)
|
|
{
|
|
if (am_rotate)
|
|
angle = ANG90;
|
|
else
|
|
angle = players[consoleplayer].camera->angle;
|
|
|
|
if (am_cheat != 0)
|
|
AM_drawLineCharacter
|
|
(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
|
|
angle, YourColor, players[consoleplayer].camera->x >> FRACTOMAPBITS, players[consoleplayer].camera->y >> FRACTOMAPBITS);
|
|
else
|
|
AM_drawLineCharacter
|
|
(player_arrow, NUMPLYRLINES, 0, angle,
|
|
YourColor, players[consoleplayer].camera->x >> FRACTOMAPBITS, players[consoleplayer].camera->y >> FRACTOMAPBITS);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < MAXPLAYERS; i++)
|
|
{
|
|
player_t *p = &players[i];
|
|
int color;
|
|
mpoint_t pt;
|
|
|
|
if (!playeringame[i] || p->mo == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (deathmatch && !demoplayback &&
|
|
!p->mo->IsTeammate (players[consoleplayer].mo) &&
|
|
p != players[consoleplayer].camera->player)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (p->mo->alpha < OPAQUE)
|
|
{
|
|
color = AlmostBackground;
|
|
}
|
|
else
|
|
{
|
|
float h, s, v, r, g, b;
|
|
|
|
D_GetPlayerColor (i, &h, &s, &v);
|
|
HSVtoRGB (&r, &g, &b, h, s, v);
|
|
|
|
color = ColorMatcher.Pick (clamp (int(r*255.f),0,255),
|
|
clamp (int(g*255.f),0,255), clamp (int(b*255.f),0,255));
|
|
}
|
|
|
|
if (p->mo != NULL)
|
|
{
|
|
pt.x = p->mo->x >> FRACTOMAPBITS;
|
|
pt.y = p->mo->y >> FRACTOMAPBITS;
|
|
angle = p->mo->angle;
|
|
|
|
if (am_rotate)
|
|
{
|
|
AM_rotatePoint (&pt.x, &pt.y);
|
|
angle -= players[consoleplayer].camera->angle - ANG90;
|
|
}
|
|
|
|
AM_drawLineCharacter
|
|
(player_arrow, NUMPLYRLINES, 0, angle,
|
|
color, pt.x, pt.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AM_drawThings (int _color)
|
|
{
|
|
int color;
|
|
int i;
|
|
AActor* t;
|
|
mpoint_t p;
|
|
angle_t angle;
|
|
|
|
for (i=0;i<numsectors;i++)
|
|
{
|
|
t = sectors[i].thinglist;
|
|
while (t)
|
|
{
|
|
p.x = t->x >> FRACTOMAPBITS;
|
|
p.y = t->y >> FRACTOMAPBITS;
|
|
angle = t->angle;
|
|
|
|
if (am_rotate)
|
|
{
|
|
AM_rotatePoint (&p.x, &p.y);
|
|
angle += ANG90 - players[consoleplayer].camera->angle;
|
|
}
|
|
|
|
color = ThingColor;
|
|
|
|
// use separate colors for special thing types
|
|
if (t->flags3&MF3_ISMONSTER && !(t->flags&MF_CORPSE))
|
|
{
|
|
if (t->flags & MF_FRIENDLY || !(t->flags & MF_COUNTKILL)) color = ThingColor_Friend;
|
|
else color = ThingColor_Monster;
|
|
}
|
|
else if (t->flags&MF_SPECIAL) color = ThingColor_Item;
|
|
|
|
AM_drawLineCharacter
|
|
(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
|
|
16<<MAPBITS, angle, color, p.x, p.y);
|
|
|
|
if (am_cheat >= 3)
|
|
{
|
|
static const mline_t box[4] =
|
|
{
|
|
{ { -MAPUNIT, -MAPUNIT }, { MAPUNIT, -MAPUNIT } },
|
|
{ { MAPUNIT, -MAPUNIT }, { MAPUNIT, MAPUNIT } },
|
|
{ { MAPUNIT, MAPUNIT }, { -MAPUNIT, MAPUNIT } },
|
|
{ { -MAPUNIT, MAPUNIT }, { -MAPUNIT, -MAPUNIT } },
|
|
};
|
|
|
|
AM_drawLineCharacter (box, 4, t->radius >> FRACTOMAPBITS, angle - t->angle, color, p.x, p.y);
|
|
}
|
|
t = t->snext;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AM_drawMarks ()
|
|
{
|
|
int i, fx, fy, w, h;
|
|
mpoint_t pt;
|
|
|
|
for (i = 0; i < AM_NUMMARKPOINTS; i++)
|
|
{
|
|
if (markpoints[i].x != -1)
|
|
{
|
|
// w = TileSizes[i].width;
|
|
// h = TileSizes[i].height;
|
|
w = 5; // because something's wrong with the wad, i guess
|
|
h = 6; // because something's wrong with the wad, i guess
|
|
|
|
pt.x = markpoints[i].x;
|
|
pt.y = markpoints[i].y;
|
|
|
|
if (am_rotate)
|
|
AM_rotatePoint (&pt.x, &pt.y);
|
|
|
|
fx = CXMTOF(pt.x);
|
|
fy = CYMTOF(pt.y) - 3;
|
|
|
|
if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h && marknums[i] != -1)
|
|
screen->DrawTexture (TexMan(marknums[i]), fx, fy, DTA_CleanNoMove, true, TAG_DONE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AM_drawCrosshair (int color)
|
|
{
|
|
fb[f_p*((f_h+1)/2)+(f_w/2)] = (byte)color; // single point for now
|
|
}
|
|
|
|
void AM_Drawer ()
|
|
{
|
|
if (!automapactive)
|
|
return;
|
|
|
|
bool allmap = (level.flags & LEVEL_ALLMAP) != 0;
|
|
bool allthings = allmap && players[consoleplayer].mo->FindInventory<APowerScanner>() != NULL;
|
|
|
|
AM_initColors (viewactive);
|
|
|
|
fb = screen->GetBuffer ();
|
|
if (!viewactive)
|
|
{
|
|
// [RH] Set f_? here now to handle automap overlaying
|
|
// and view size adjustments.
|
|
f_x = f_y = 0;
|
|
f_w = screen->GetWidth ();
|
|
f_h = ST_Y;
|
|
f_p = screen->GetPitch ();
|
|
WeightingScale = 0;
|
|
|
|
AM_clearFB(Background);
|
|
}
|
|
else
|
|
{
|
|
f_x = viewwindowx;
|
|
f_y = viewwindowy;
|
|
f_w = realviewwidth;
|
|
f_h = realviewheight;
|
|
f_p = screen->GetPitch ();
|
|
WeightingScale = (int)(am_ovtrans * 256.f);
|
|
if (WeightingScale < 0 || WeightingScale >= 256)
|
|
{
|
|
WeightingScale = 0;
|
|
}
|
|
}
|
|
AM_activateNewScale();
|
|
|
|
if (grid)
|
|
AM_drawGrid(GridColor);
|
|
|
|
AM_drawWalls(allmap);
|
|
AM_drawPlayers();
|
|
if (am_cheat >= 2 || allthings)
|
|
AM_drawThings(ThingColor);
|
|
|
|
if (!viewactive)
|
|
AM_drawCrosshair(XHairColor);
|
|
|
|
AM_drawMarks();
|
|
}
|
|
|
|
FAutomapTexture::FAutomapTexture (int lumpnum)
|
|
: Pixels(NULL), LumpNum(lumpnum)
|
|
{
|
|
UseType = TEX_MiscPatch;
|
|
Width = 320;
|
|
Height = Wads.LumpLength(lumpnum) / 320;
|
|
CalcBitSize ();
|
|
|
|
DummySpan[0].TopOffset = 0;
|
|
DummySpan[0].Length = Height;
|
|
DummySpan[1].TopOffset = 0;
|
|
DummySpan[1].Length = 0;
|
|
}
|
|
|
|
FAutomapTexture::~FAutomapTexture ()
|
|
{
|
|
Unload ();
|
|
}
|
|
|
|
void FAutomapTexture::Unload ()
|
|
{
|
|
if (Pixels != NULL)
|
|
{
|
|
delete[] Pixels;
|
|
Pixels = NULL;
|
|
}
|
|
}
|
|
|
|
void FAutomapTexture::MakeTexture ()
|
|
{
|
|
int x, y;
|
|
FMemLump data = Wads.ReadLump (LumpNum);
|
|
const BYTE *indata = (const BYTE *)data.GetMem();
|
|
|
|
Pixels = new BYTE[Width * Height];
|
|
|
|
for (x = 0; x < Width; ++x)
|
|
{
|
|
for (y = 0; y < Height; ++y)
|
|
{
|
|
Pixels[x*Height+y] = indata[x+320*y];
|
|
}
|
|
}
|
|
}
|
|
|
|
const BYTE *FAutomapTexture::GetPixels ()
|
|
{
|
|
if (Pixels == NULL)
|
|
{
|
|
MakeTexture ();
|
|
}
|
|
return Pixels;
|
|
}
|
|
|
|
const BYTE *FAutomapTexture::GetColumn (unsigned int column, const Span **spans_out)
|
|
{
|
|
if (Pixels == NULL)
|
|
{
|
|
MakeTexture ();
|
|
}
|
|
if ((unsigned)column >= (unsigned)Width)
|
|
{
|
|
column %= Width;
|
|
}
|
|
if (spans_out != NULL)
|
|
{
|
|
*spans_out = DummySpan;
|
|
}
|
|
return Pixels + column*Height;
|
|
}
|