mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 14:51:40 +00:00
- merged automap branch into trunk.
SVN r2609 (trunk)
This commit is contained in:
parent
9102200771
commit
9a4abe0915
47 changed files with 3497 additions and 751 deletions
|
@ -679,6 +679,7 @@ add_executable( zdoom WIN32
|
|||
p_effect.cpp
|
||||
p_enemy.cpp
|
||||
p_floor.cpp
|
||||
p_glnodes.cpp
|
||||
p_interaction.cpp
|
||||
p_lights.cpp
|
||||
p_linkedsectors.cpp
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "r_blend.h"
|
||||
#include "s_sound.h"
|
||||
|
||||
struct subsector_t;
|
||||
//
|
||||
// NOTES: AActor
|
||||
//
|
||||
|
@ -773,6 +774,7 @@ public:
|
|||
fixed_t pitch, roll;
|
||||
FBlockNode *BlockNode; // links in blocks (if needed)
|
||||
struct sector_t *Sector;
|
||||
subsector_t * subsector;
|
||||
fixed_t floorz, ceilingz; // closest together of contacted secs
|
||||
fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors.
|
||||
|
||||
|
|
369
src/am_map.cpp
369
src/am_map.cpp
|
@ -36,6 +36,9 @@
|
|||
#include "r_translate.h"
|
||||
#include "d_event.h"
|
||||
#include "gi.h"
|
||||
#include "r_bsp.h"
|
||||
#include "p_setup.h"
|
||||
#include "c_bind.h"
|
||||
|
||||
#include "m_cheat.h"
|
||||
#include "i_system.h"
|
||||
|
@ -183,6 +186,14 @@ CVAR (Color, am_ovthingcolor_item, 0xe88800, CVAR_ARCHIVE);
|
|||
CVAR (Color, am_ovthingcolor_citem, 0xe88800, CVAR_ARCHIVE);
|
||||
|
||||
|
||||
static int bigstate = 0;
|
||||
static bool textured = 1; // internal toggle for texture mode
|
||||
|
||||
CUSTOM_CVAR(Bool, am_textured, false, CVAR_ARCHIVE)
|
||||
{
|
||||
textured |= self;
|
||||
}
|
||||
|
||||
CVAR(Int, am_showsubsector, -1, 0);
|
||||
|
||||
|
||||
|
@ -225,21 +236,6 @@ CUSTOM_CVAR (Int, am_showalllines, -1, 0) // This is a cheat so don't save it.
|
|||
}
|
||||
|
||||
|
||||
// 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
|
||||
|
@ -417,7 +413,6 @@ 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)
|
||||
|
@ -466,7 +461,69 @@ static void AM_calcMinMaxMtoF();
|
|||
void AM_rotatePoint (fixed_t *x, fixed_t *y);
|
||||
void AM_rotate (fixed_t *x, fixed_t *y, angle_t an);
|
||||
void AM_doFollowPlayer ();
|
||||
static void AM_ToggleFollowPlayer();
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// map functions
|
||||
//
|
||||
//=============================================================================
|
||||
bool AM_addMark ();
|
||||
bool AM_clearMarks ();
|
||||
void AM_saveScaleAndLoc ();
|
||||
void AM_restoreScaleAndLoc ();
|
||||
void AM_minOutWindowScale ();
|
||||
|
||||
|
||||
CCMD(am_togglefollow)
|
||||
{
|
||||
followplayer = !followplayer;
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
|
||||
}
|
||||
|
||||
CCMD(am_togglegrid)
|
||||
{
|
||||
grid = !grid;
|
||||
Printf ("%s\n", GStrings(grid ? "AMSTR_GRIDON" : "AMSTR_GRIDOFF"));
|
||||
}
|
||||
|
||||
CCMD(am_toggletexture)
|
||||
{
|
||||
if (am_textured && hasglnodes)
|
||||
{
|
||||
textured = !textured;
|
||||
Printf ("%s\n", GStrings(textured ? "AMSTR_TEXON" : "AMSTR_TEXOFF"));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_setmark)
|
||||
{
|
||||
if (AM_addMark())
|
||||
{
|
||||
Printf ("%s %d\n", GStrings("AMSTR_MARKEDSPOT"), markpointnum);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_clearmarks)
|
||||
{
|
||||
if (AM_clearMarks())
|
||||
{
|
||||
Printf ("%s\n", GStrings("AMSTR_MARKSCLEARED"));
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(am_gobig)
|
||||
{
|
||||
bigstate = !bigstate;
|
||||
if (bigstate)
|
||||
{
|
||||
AM_saveScaleAndLoc();
|
||||
AM_minOutWindowScale();
|
||||
}
|
||||
else
|
||||
AM_restoreScaleAndLoc();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -775,11 +832,19 @@ void AM_initVariables ()
|
|||
|
||||
automapactive = true;
|
||||
|
||||
// Reset AM buttons
|
||||
Button_AM_PanLeft.Reset();
|
||||
Button_AM_PanRight.Reset();
|
||||
Button_AM_PanUp.Reset();
|
||||
Button_AM_PanDown.Reset();
|
||||
Button_AM_ZoomIn.Reset();
|
||||
Button_AM_ZoomOut.Reset();
|
||||
|
||||
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
amclock = 0;
|
||||
|
||||
m_paninc.x = m_paninc.y = 0;
|
||||
ftom_zoommul = MAPUNIT;
|
||||
mtof_zoommul = MAPUNIT;
|
||||
|
||||
m_w = FTOM(SCREENWIDTH);
|
||||
|
@ -1158,127 +1223,28 @@ void AM_ToggleMap ()
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
bool AM_Responder (event_t *ev)
|
||||
bool AM_Responder (event_t *ev, bool last)
|
||||
{
|
||||
bool rc;
|
||||
static int cheatstate = 0;
|
||||
static int bigstate = 0;
|
||||
|
||||
rc = false;
|
||||
|
||||
if (automapactive && ev->type == EV_KeyDown)
|
||||
if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
|
||||
{
|
||||
rc = true;
|
||||
switch (ev->data1)
|
||||
if (followplayer)
|
||||
{
|
||||
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:
|
||||
AM_ToggleFollowPlayer();
|
||||
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;
|
||||
}
|
||||
// check for am_pan* and ignore in follow mode
|
||||
const char *defbind = AutomapBindings.GetBind(ev->data1);
|
||||
if (!strnicmp(defbind, "+am_pan", 7)) return 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;
|
||||
bool res = C_DoKey(ev, &AutomapBindings, NULL);
|
||||
if (res && ev->type == EV_KeyUp && !last)
|
||||
{
|
||||
// If this is a release event we also need to check if it released a button in the main Bindings
|
||||
// so that that button does not get stuck.
|
||||
const char *defbind = Bindings.GetBind(ev->data1);
|
||||
return (defbind[0] != '+'); // Let G_Responder handle button releases
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1290,6 +1256,11 @@ bool AM_Responder (event_t *ev)
|
|||
|
||||
void AM_changeWindowScale ()
|
||||
{
|
||||
int mtof_zoommul;
|
||||
|
||||
if (Button_AM_ZoomIn.bDown) mtof_zoommul = M_ZOOMIN;
|
||||
else if (Button_AM_ZoomOut.bDown) mtof_zoommul = M_ZOOMOUT;
|
||||
|
||||
// Change the scaling multipliers
|
||||
scale_mtof = MapMul(scale_mtof, mtof_zoommul);
|
||||
scale_ftom = MapDiv(MAPUNIT, scale_mtof);
|
||||
|
@ -1334,19 +1305,6 @@ void AM_doFollowPlayer ()
|
|||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static void AM_ToggleFollowPlayer()
|
||||
{
|
||||
followplayer = !followplayer;
|
||||
f_oldloc.x = FIXED_MAX;
|
||||
Printf ("%s\n", GStrings(followplayer ? "AMSTR_FOLLOWON" : "AMSTR_FOLLOWOFF"));
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Updates on Game Tick
|
||||
|
@ -1361,10 +1319,20 @@ void AM_Ticker ()
|
|||
amclock++;
|
||||
|
||||
if (followplayer)
|
||||
{
|
||||
AM_doFollowPlayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_paninc.x = m_paninc.y = 0;
|
||||
if (Button_AM_PanLeft.bDown) m_paninc.x -= FTOM(F_PANINC);
|
||||
if (Button_AM_PanRight.bDown) m_paninc.x += FTOM(F_PANINC);
|
||||
if (Button_AM_PanUp.bDown) m_paninc.y += FTOM(F_PANINC);
|
||||
if (Button_AM_PanDown.bDown) m_paninc.y -= FTOM(F_PANINC);
|
||||
}
|
||||
|
||||
// Change the zoom if necessary
|
||||
if (ftom_zoommul != MAPUNIT)
|
||||
if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown)
|
||||
AM_changeWindowScale();
|
||||
|
||||
// Change x,y location
|
||||
|
@ -1622,6 +1590,92 @@ void AM_drawGrid (const AMColor &color)
|
|||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// AM_drawSubsectors
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_drawSubsectors()
|
||||
{
|
||||
static TArray<FVector2> points;
|
||||
float scale = float(scale_mtof);
|
||||
angle_t rotation;
|
||||
sector_t tempsec;
|
||||
int floorlight, ceilinglight;
|
||||
double originx, originy;
|
||||
FDynamicColormap *colormap;
|
||||
|
||||
|
||||
for (int i = 0; i < numsubsectors; ++i)
|
||||
{
|
||||
if ((!(subsectors[i].flags & SSECF_DRAWN) || (subsectors[i].render_sector->MoreFlags & SECF_HIDDEN)) && am_cheat == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Fill the points array from the subsector.
|
||||
points.Resize(subsectors[i].numlines);
|
||||
for (DWORD j = 0; j < subsectors[i].numlines; ++j)
|
||||
{
|
||||
mpoint_t pt = { subsectors[i].firstline[j].v1->x >> FRACTOMAPBITS,
|
||||
subsectors[i].firstline[j].v1->y >> FRACTOMAPBITS };
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
AM_rotatePoint(&pt.x, &pt.y);
|
||||
}
|
||||
points[j].X = f_x + ((pt.x - m_x) * scale / float(1 << 24));
|
||||
points[j].Y = f_y + (f_h - (pt.y - m_y) * scale / float(1 << 24));
|
||||
}
|
||||
// For lighting and texture determination
|
||||
sector_t *sec = R_FakeFlat (subsectors[i].render_sector, &tempsec, &floorlight,
|
||||
&ceilinglight, false);
|
||||
// Find texture origin.
|
||||
mpoint_t originpt = { -sec->GetXOffset(sector_t::floor) >> FRACTOMAPBITS,
|
||||
sec->GetYOffset(sector_t::floor) >> FRACTOMAPBITS };
|
||||
rotation = 0 - sec->GetAngle(sector_t::floor);
|
||||
// Apply the floor's rotation to the texture origin.
|
||||
if (rotation != 0)
|
||||
{
|
||||
AM_rotate(&originpt.x, &originpt.y, rotation);
|
||||
}
|
||||
// Apply the automap's rotation to the texture origin.
|
||||
if (am_rotate == 1 || (am_rotate == 2 && viewactive))
|
||||
{
|
||||
rotation += ANG90 - players[consoleplayer].camera->angle;
|
||||
AM_rotatePoint(&originpt.x, &originpt.y);
|
||||
}
|
||||
originx = f_x + ((originpt.x - m_x) * scale / float(1 << 24));
|
||||
originy = f_y + (f_h - (originpt.y - m_y) * scale / float(1 << 24));
|
||||
// Coloring for the polygon
|
||||
colormap = sec->ColorMap;
|
||||
// If this subsector has not actually been seen yet (because you are cheating
|
||||
// to see it on the map), tint and desaturate it.
|
||||
if (!(subsectors[i].flags & SSECF_DRAWN))
|
||||
{
|
||||
colormap = GetSpecialLights(
|
||||
MAKERGB(
|
||||
(colormap->Color.r + 255) / 2,
|
||||
(colormap->Color.g + 200) / 2,
|
||||
(colormap->Color.b + 160) / 2),
|
||||
colormap->Fade,
|
||||
255 - (255 - colormap->Desaturate) / 4);
|
||||
floorlight = (floorlight + 200*15) / 16;
|
||||
}
|
||||
|
||||
// Draw the polygon.
|
||||
screen->FillSimplePoly(
|
||||
TexMan(sec->GetTexture(sector_t::floor)),
|
||||
&points[0], points.Size(),
|
||||
originx, originy,
|
||||
scale / (FIXED2FLOAT(sec->GetXScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
scale / (FIXED2FLOAT(sec->GetYScale(sector_t::floor)) * float(1 << MAPBITS)),
|
||||
rotation,
|
||||
colormap,
|
||||
floorlight
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
|
@ -2232,11 +2286,19 @@ void AM_drawAuthorMarkers ()
|
|||
|
||||
while (marked != NULL)
|
||||
{
|
||||
if (mark->args[1] == 0 || (mark->args[1] == 1 && marked->Sector->MoreFlags & SECF_DRAWN))
|
||||
if (mark->args[1] == 0 || (mark->args[1] == 1))
|
||||
{
|
||||
DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0,
|
||||
flip, mark->scaleX, mark->scaleY, mark->Translation,
|
||||
mark->alpha, mark->fillcolor, mark->RenderStyle);
|
||||
// Use more correct info if we have GL nodes available
|
||||
INTBOOL drawn = hasglnodes?
|
||||
marked->subsector->flags & SSECF_DRAWN :
|
||||
marked->Sector->MoreFlags & SECF_DRAWN;
|
||||
|
||||
if (drawn)
|
||||
{
|
||||
DrawMarker (tex, marked->x >> FRACTOMAPBITS, marked->y >> FRACTOMAPBITS, 0,
|
||||
flip, mark->scaleX, mark->scaleY, mark->Translation,
|
||||
mark->alpha, mark->fillcolor, mark->RenderStyle);
|
||||
}
|
||||
}
|
||||
marked = mark->args[0] != 0 ? it.Next() : NULL;
|
||||
}
|
||||
|
@ -2291,6 +2353,9 @@ void AM_Drawer ()
|
|||
}
|
||||
AM_activateNewScale();
|
||||
|
||||
if (am_textured && hasglnodes && textured)
|
||||
AM_drawSubsectors();
|
||||
|
||||
if (grid)
|
||||
AM_drawGrid(GridColor);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ struct event_t;
|
|||
class FArchive;
|
||||
|
||||
// Called by main loop.
|
||||
bool AM_Responder (event_t* ev);
|
||||
bool AM_Responder (event_t* ev, bool last);
|
||||
|
||||
// Called by main loop.
|
||||
void AM_Ticker (void);
|
||||
|
|
|
@ -309,6 +309,8 @@ GLOBAL R_DrawSpanP_ASM
|
|||
; edi: dest
|
||||
; ebp: scratch
|
||||
; esi: count
|
||||
; [esp]: xstep
|
||||
; [esp+4]: ystep
|
||||
|
||||
align 16
|
||||
|
||||
|
@ -324,6 +326,7 @@ R_DrawSpanP_ASM:
|
|||
push edi
|
||||
push ebp
|
||||
push esi
|
||||
sub esp, 8
|
||||
|
||||
mov edi,ecx
|
||||
add edi,[dc_destorg]
|
||||
|
@ -335,13 +338,13 @@ dsy1: shl edx,6
|
|||
dsy3: shr ebp,26
|
||||
xor ebx,ebx
|
||||
lea esi,[eax+1]
|
||||
mov [ds_xstep],edx
|
||||
mov [esp],edx
|
||||
mov edx,[ds_ystep]
|
||||
mov ecx,[ds_xfrac]
|
||||
dsy4: shr ecx,26
|
||||
dsm8: and edx,0xffffffc0
|
||||
or ebp,edx
|
||||
mov [ds_ystep],ebp
|
||||
mov [esp+4],ebp
|
||||
mov ebp,[ds_yfrac]
|
||||
mov edx,[ds_xfrac]
|
||||
dsy2: shl edx,6
|
||||
|
@ -355,8 +358,8 @@ dsm9: and ebp,0xffffffc0
|
|||
mov ebp,ecx
|
||||
dsx1: rol ebp,6
|
||||
dsm1: and ebp,0xfff
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
spreada mov bl,[ebp+SPACEFILLER4]
|
||||
spmapa mov bl,[ebx+SPACEFILLER4]
|
||||
mov [edi],bl
|
||||
|
@ -367,13 +370,13 @@ dseven1 shr esi,1
|
|||
|
||||
; do two more pixels
|
||||
mov ebp,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
dsm2: and ebp,0xfc00003f
|
||||
dsx2: rol ebp,6
|
||||
mov eax,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
spreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dsx3: rol eax,6
|
||||
dsm6: and eax,0xfff
|
||||
|
@ -392,13 +395,13 @@ dsrest test esi,esi
|
|||
align 16
|
||||
|
||||
dsloop mov ebp,ecx
|
||||
spstep1d add edx,[ds_xstep]
|
||||
spstep2d adc ecx,[ds_ystep]
|
||||
spstep1d add edx,[esp]
|
||||
spstep2d adc ecx,[esp+4]
|
||||
dsm3: and ebp,0xfc00003f
|
||||
dsx4: rol ebp,6
|
||||
mov eax,ecx
|
||||
spstep1e add edx,[ds_xstep]
|
||||
spstep2e adc ecx,[ds_ystep]
|
||||
spstep1e add edx,[esp]
|
||||
spstep2e adc ecx,[esp+4]
|
||||
spreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dsx5: rol eax,6
|
||||
dsm5: and eax,0xfff
|
||||
|
@ -406,8 +409,8 @@ spmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
|
|||
mov [edi],bl ;store texel1
|
||||
mov ebp,ecx
|
||||
spreade mov bl,[eax+SPACEFILLER4] ;read texel2
|
||||
spstep1f add edx,[ds_xstep]
|
||||
spstep2f adc ecx,[ds_ystep]
|
||||
spstep1f add edx,[esp]
|
||||
spstep2f adc ecx,[esp+4]
|
||||
dsm4: and ebp,0xfc00003f
|
||||
dsx6: rol ebp,6
|
||||
spmape mov bl,[ebx+SPACEFILLER4] ;map texel2
|
||||
|
@ -420,14 +423,15 @@ dsx7: rol eax,6
|
|||
dsm7: and eax,0xfff
|
||||
mov [edi-2],bl ;store texel3
|
||||
spreadg mov bl,[eax+SPACEFILLER4] ;read texel4
|
||||
spstep1g add edx,[ds_xstep]
|
||||
spstep2g adc ecx,[ds_ystep]
|
||||
spstep1g add edx,[esp]
|
||||
spstep2g adc ecx,[esp+4]
|
||||
spmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
||||
dec esi
|
||||
mov [edi-1],bl ;store texel4
|
||||
jnz near dsloop
|
||||
|
||||
dsdone pop esi
|
||||
dsdone add esp,8
|
||||
pop esi
|
||||
pop ebp
|
||||
pop edi
|
||||
pop ebx
|
||||
|
@ -448,6 +452,8 @@ GLOBAL R_DrawSpanMaskedP_ASM
|
|||
; edi: dest
|
||||
; ebp: scratch
|
||||
; esi: count
|
||||
; [esp]: xstep
|
||||
; [esp+4]: ystep
|
||||
|
||||
align 16
|
||||
|
||||
|
@ -463,6 +469,7 @@ R_DrawSpanMaskedP_ASM:
|
|||
push edi
|
||||
push ebp
|
||||
push esi
|
||||
sub esp,8
|
||||
|
||||
mov edi,ecx
|
||||
add edi,[dc_destorg]
|
||||
|
@ -474,13 +481,13 @@ dmsy1: shl edx,6
|
|||
dmsy3: shr ebp,26
|
||||
xor ebx,ebx
|
||||
lea esi,[eax+1]
|
||||
mov [ds_xstep],edx
|
||||
mov [esp],edx
|
||||
mov edx,[ds_ystep]
|
||||
mov ecx,[ds_xfrac]
|
||||
dmsy4: shr ecx,26
|
||||
dmsm8: and edx,0xffffffc0
|
||||
or ebp,edx
|
||||
mov [ds_ystep],ebp
|
||||
mov [esp+4],ebp
|
||||
mov ebp,[ds_yfrac]
|
||||
mov edx,[ds_xfrac]
|
||||
dmsy2: shl edx,6
|
||||
|
@ -494,8 +501,8 @@ dmsm9: and ebp,0xffffffc0
|
|||
mov ebp,ecx
|
||||
dmsx1: rol ebp,6
|
||||
dmsm1: and ebp,0xfff
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
mspreada mov bl,[ebp+SPACEFILLER4]
|
||||
cmp bl,0
|
||||
je mspskipa
|
||||
|
@ -508,13 +515,13 @@ dmseven1 shr esi,1
|
|||
|
||||
; do two more pixels
|
||||
mov ebp,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
dmsm2: and ebp,0xfc00003f
|
||||
dmsx2: rol ebp,6
|
||||
mov eax,ecx
|
||||
add edx,[ds_xstep]
|
||||
adc ecx,[ds_ystep]
|
||||
add edx,[esp]
|
||||
adc ecx,[esp+4]
|
||||
mspreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dmsx3: rol eax,6
|
||||
dmsm6: and eax,0xfff
|
||||
|
@ -537,13 +544,13 @@ dmsrest test esi,esi
|
|||
align 16
|
||||
|
||||
dmsloop mov ebp,ecx
|
||||
mspstep1d add edx,[ds_xstep]
|
||||
mspstep2d adc ecx,[ds_ystep]
|
||||
mspstep1d add edx,[esp]
|
||||
mspstep2d adc ecx,[esp+4]
|
||||
dmsm3: and ebp,0xfc00003f
|
||||
dmsx4: rol ebp,6
|
||||
mov eax,ecx
|
||||
mspstep1e add edx,[ds_xstep]
|
||||
mspstep2e adc ecx,[ds_ystep]
|
||||
mspstep1e add edx,[esp]
|
||||
mspstep2e adc ecx,[esp+4]
|
||||
mspreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
|
||||
dmsx5: rol eax,6
|
||||
dmsm5: and eax,0xfff
|
||||
|
@ -553,8 +560,8 @@ dmsm5: and eax,0xfff
|
|||
mspmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
|
||||
mov [edi],bl ;store texel1
|
||||
mspreade mov bl,[eax+SPACEFILLER4] ;read texel2
|
||||
mspstep1f add edx,[ds_xstep]
|
||||
mspstep2f adc ecx,[ds_ystep]
|
||||
mspstep1f add edx,[esp]
|
||||
mspstep2f adc ecx,[esp+4]
|
||||
dmsm4: and ebp,0xfc00003f
|
||||
dmsx6: rol ebp,6
|
||||
cmp bl,0
|
||||
|
@ -571,8 +578,8 @@ dmsm7: and eax,0xfff
|
|||
mspmapf mov bl,[ebx+SPACEFILLER4] ;map texel3
|
||||
mov [edi-2],bl ;store texel3
|
||||
mspreadg mov bl,[eax+SPACEFILLER4] ;read texel4
|
||||
mspstep1g add edx,[ds_xstep]
|
||||
mspstep2g adc ecx,[ds_ystep]
|
||||
mspstep1g add edx,[esp]
|
||||
mspstep2g adc ecx,[esp+4]
|
||||
cmp bl,0
|
||||
je mspskipg
|
||||
mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
||||
|
@ -580,7 +587,8 @@ mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
|
|||
mspskipg dec esi
|
||||
jnz near dmsloop
|
||||
|
||||
dmsdone pop esi
|
||||
dmsdone add esp,8
|
||||
pop esi
|
||||
pop ebp
|
||||
pop edi
|
||||
pop ebx
|
||||
|
|
932
src/c_bind.cpp
932
src/c_bind.cpp
|
@ -47,12 +47,6 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct FBinding
|
||||
{
|
||||
const char *Key;
|
||||
const char *Bind;
|
||||
};
|
||||
|
||||
/* Default keybindings for Doom (and all other games)
|
||||
*/
|
||||
static const FBinding DefBindings[] =
|
||||
|
@ -178,6 +172,27 @@ static const FBinding DefStrifeBindings[] =
|
|||
// h - use health
|
||||
};
|
||||
|
||||
static const FBinding DefAutomapBindings[] =
|
||||
{
|
||||
{ "f", "am_togglefollow" },
|
||||
{ "g", "am_togglegrid" },
|
||||
{ "t", "am_toggletexture" },
|
||||
{ "m", "am_setmark" },
|
||||
{ "c", "am_clearmarks" },
|
||||
{ "0", "am_gobig" },
|
||||
{ "rightarrow", "+am_panright" },
|
||||
{ "leftarrow", "+am_panleft" },
|
||||
{ "uparrow", "+am_panup" },
|
||||
{ "downarrow", "+am_pandown" },
|
||||
{ "-", "+am_zoomout" },
|
||||
{ "=", "+am_zoomin" },
|
||||
{ "kp-", "+am_zoomout" },
|
||||
{ "kp+", "+am_zoomin" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
|
||||
const char *KeyNames[NUM_KEYS] =
|
||||
{
|
||||
// This array is dependant on the particular keyboard input
|
||||
|
@ -278,11 +293,19 @@ const char *KeyNames[NUM_KEYS] =
|
|||
"pad_a", "pad_b", "pad_x", "pad_y"
|
||||
};
|
||||
|
||||
static FString Bindings[NUM_KEYS];
|
||||
static FString DoubleBindings[NUM_KEYS];
|
||||
FKeyBindings Bindings;
|
||||
FKeyBindings DoubleBindings;
|
||||
FKeyBindings AutomapBindings;
|
||||
|
||||
static unsigned int DClickTime[NUM_KEYS];
|
||||
static BYTE DClicked[(NUM_KEYS+7)/8];
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static int GetKeyFromName (const char *name)
|
||||
{
|
||||
int i;
|
||||
|
@ -302,380 +325,15 @@ static int GetKeyFromName (const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const char *KeyName (int key)
|
||||
{
|
||||
static char name[5];
|
||||
|
||||
if (KeyNames[key])
|
||||
return KeyNames[key];
|
||||
|
||||
mysnprintf (name, countof(name), "#%d", key);
|
||||
return name;
|
||||
}
|
||||
|
||||
void C_UnbindAll ()
|
||||
{
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
Bindings[i] = "";
|
||||
DoubleBindings[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (unbindall)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
}
|
||||
|
||||
CCMD (unbind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
if ( (i = GetKeyFromName (argv[1])) )
|
||||
{
|
||||
Bindings[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (bind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], Bindings[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Bindings[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Current key bindings:\n");
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!Bindings[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), Bindings[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//=============================================================================
|
||||
//
|
||||
// CCMD defaultbind
|
||||
//
|
||||
// Binds a command to a key if that key is not already bound and if
|
||||
// that command is not already bound to another key.
|
||||
//
|
||||
//==========================================================================
|
||||
//=============================================================================
|
||||
|
||||
CCMD (defaultbind)
|
||||
static int GetConfigKeyFromName (const char *key)
|
||||
{
|
||||
if (argv.argc() < 3)
|
||||
{
|
||||
Printf ("Usage: defaultbind <key> <command>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int key = GetKeyFromName (argv[1]);
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (!Bindings[key].IsEmpty())
|
||||
{ // This key is already bound.
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
if (!Bindings[i].IsEmpty() && stricmp (Bindings[i], argv[2]) == 0)
|
||||
{ // This command is already bound to a key.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// It is safe to do the bind, so do it.
|
||||
Bindings[key] = argv[2];
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (undoublebind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
if ( (i = GetKeyFromName (argv[1])) )
|
||||
{
|
||||
DoubleBindings[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (doublebind)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], DoubleBindings[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
DoubleBindings[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Current key doublebindings:\n");
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!DoubleBindings[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), DoubleBindings[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (rebind)
|
||||
{
|
||||
FString *bindings;
|
||||
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Rebind cannot be used from the console\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (key & KEY_DBLCLICKED)
|
||||
{
|
||||
bindings = DoubleBindings;
|
||||
key &= KEY_DBLCLICKED-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bindings = Bindings;
|
||||
}
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
bindings[key] = argv[1];
|
||||
}
|
||||
}
|
||||
|
||||
static void SetBinds (const FBinding *array)
|
||||
{
|
||||
while (array->Key)
|
||||
{
|
||||
C_DoBind (array->Key, array->Bind, false);
|
||||
array++;
|
||||
}
|
||||
}
|
||||
|
||||
void C_BindDefaults ()
|
||||
{
|
||||
SetBinds (DefBindings);
|
||||
|
||||
if (gameinfo.gametype & (GAME_Raven|GAME_Strife))
|
||||
{
|
||||
SetBinds (DefRavenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
SetBinds (DefHereticBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
SetBinds (DefHexenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
SetBinds (DefStrifeBindings);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(binddefaults)
|
||||
{
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
void C_SetDefaultBindings ()
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
bool C_DoKey (event_t *ev)
|
||||
{
|
||||
FString binding;
|
||||
bool dclick;
|
||||
int dclickspot;
|
||||
BYTE dclickmask;
|
||||
|
||||
if (ev->type != EV_KeyDown && ev->type != EV_KeyUp)
|
||||
return false;
|
||||
|
||||
if ((unsigned int)ev->data1 >= NUM_KEYS)
|
||||
return false;
|
||||
|
||||
dclickspot = ev->data1 >> 3;
|
||||
dclickmask = 1 << (ev->data1 & 7);
|
||||
dclick = false;
|
||||
|
||||
// This used level.time which didn't work outside a level.
|
||||
if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown)
|
||||
{
|
||||
// Key pressed for a double click
|
||||
binding = DoubleBindings[ev->data1];
|
||||
DClicked[dclickspot] |= dclickmask;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{ // Key pressed for a normal press
|
||||
binding = Bindings[ev->data1];
|
||||
DClickTime[ev->data1] = I_MSTime() + 571;
|
||||
}
|
||||
else if (DClicked[dclickspot] & dclickmask)
|
||||
{ // Key released from a double click
|
||||
binding = DoubleBindings[ev->data1];
|
||||
DClicked[dclickspot] &= ~dclickmask;
|
||||
DClickTime[ev->data1] = 0;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{ // Key released from a normal press
|
||||
binding = Bindings[ev->data1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (binding.IsEmpty())
|
||||
{
|
||||
binding = Bindings[ev->data1];
|
||||
dclick = false;
|
||||
}
|
||||
|
||||
if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256))
|
||||
{
|
||||
if (ev->type == EV_KeyUp && binding[0] != '+')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char *copy = binding.LockBuffer();
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
copy[0] = '-';
|
||||
}
|
||||
|
||||
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *C_ConfigKeyName(int keynum)
|
||||
{
|
||||
const char *name = KeyName(keynum);
|
||||
if (name[1] == 0) // Make sure given name is config-safe
|
||||
{
|
||||
if (name[0] == '[')
|
||||
return "LeftBracket";
|
||||
else if (name[0] == ']')
|
||||
return "RightBracket";
|
||||
else if (name[0] == '=')
|
||||
return "Equals";
|
||||
else if (strcmp (name, "kp=") == 0)
|
||||
return "KP-Equals";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// This function is first called for functions in custom key sections.
|
||||
// In this case, matchcmd is non-NULL, and only keys bound to that command
|
||||
// are stored. If a match is found, its binding is set to "\1".
|
||||
// After all custom key sections are saved, it is called one more for the
|
||||
// normal Bindings and DoubleBindings sections for this game. In this case
|
||||
// matchcmd is NULL and all keys will be stored. The config section was not
|
||||
// previously cleared, so all old bindings are still in place. If the binding
|
||||
// for a key is empty, the corresponding key in the config is removed as well.
|
||||
// If a binding is "\1", then the binding itself is cleared, but nothing
|
||||
// happens to the entry in the config.
|
||||
void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd)
|
||||
{
|
||||
FString *bindings;
|
||||
int i;
|
||||
|
||||
bindings = dodouble ? DoubleBindings : Bindings;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (bindings[i].IsEmpty())
|
||||
{
|
||||
if (matchcmd == NULL)
|
||||
{
|
||||
f->ClearKey(C_ConfigKeyName(i));
|
||||
}
|
||||
}
|
||||
else if (matchcmd == NULL || stricmp(bindings[i], matchcmd) == 0)
|
||||
{
|
||||
if (bindings[i][0] == '\1')
|
||||
{
|
||||
bindings[i] = "";
|
||||
continue;
|
||||
}
|
||||
f->SetValueForKey(C_ConfigKeyName(i), bindings[i]);
|
||||
if (matchcmd != NULL)
|
||||
{ // If saving a specific command, set a marker so that
|
||||
// it does not get saved in the general binding list.
|
||||
bindings[i] = "\1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_DoBind (const char *key, const char *bind, bool dodouble)
|
||||
{
|
||||
int keynum = GetKeyFromName (key);
|
||||
int keynum = GetKeyFromName(key);
|
||||
if (keynum == 0)
|
||||
{
|
||||
if (stricmp (key, "LeftBracket") == 0)
|
||||
|
@ -695,32 +353,55 @@ void C_DoBind (const char *key, const char *bind, bool dodouble)
|
|||
keynum = GetKeyFromName ("kp=");
|
||||
}
|
||||
}
|
||||
if (keynum != 0)
|
||||
{
|
||||
(dodouble ? DoubleBindings : Bindings)[keynum] = bind;
|
||||
}
|
||||
return keynum;
|
||||
}
|
||||
|
||||
int C_GetKeysForCommand (char *cmd, int *first, int *second)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static const char *KeyName (int key)
|
||||
{
|
||||
int c, i;
|
||||
static char name[5];
|
||||
|
||||
*first = *second = c = i = 0;
|
||||
if (KeyNames[key])
|
||||
return KeyNames[key];
|
||||
|
||||
while (i < NUM_KEYS && c < 2)
|
||||
{
|
||||
if (stricmp (cmd, Bindings[i]) == 0)
|
||||
{
|
||||
if (c++ == 0)
|
||||
*first = i;
|
||||
else
|
||||
*second = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return c;
|
||||
mysnprintf (name, countof(name), "#%d", key);
|
||||
return name;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
static const char *ConfigKeyName(int keynum)
|
||||
{
|
||||
const char *name = KeyName(keynum);
|
||||
if (name[1] == 0) // Make sure given name is config-safe
|
||||
{
|
||||
if (name[0] == '[')
|
||||
return "LeftBracket";
|
||||
else if (name[0] == ']')
|
||||
return "RightBracket";
|
||||
else if (name[0] == '=')
|
||||
return "Equals";
|
||||
else if (strcmp (name, "kp=") == 0)
|
||||
return "KP-Equals";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_NameKeys (char *str, int first, int second)
|
||||
{
|
||||
int c = 0;
|
||||
|
@ -744,28 +425,471 @@ void C_NameKeys (char *str, int first, int second)
|
|||
*str = '\0';
|
||||
}
|
||||
|
||||
void C_UnbindACommand (char *str)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::DoBind (const char *key, const char *bind)
|
||||
{
|
||||
int keynum = GetConfigKeyFromName (key);
|
||||
if (keynum != 0)
|
||||
{
|
||||
Binds[keynum] = bind;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::SetBinds(const FBinding *binds)
|
||||
{
|
||||
while (binds->Key)
|
||||
{
|
||||
DoBind (binds->Key, binds->Bind);
|
||||
binds++;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindAll ()
|
||||
{
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindKey(const char *key)
|
||||
{
|
||||
int i;
|
||||
|
||||
if ( (i = GetKeyFromName (key)) )
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::PerformBind(FCommandLine &argv, const char *msg)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
i = GetKeyFromName (argv[1]);
|
||||
if (!i)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
if (argv.argc() == 2)
|
||||
{
|
||||
Printf ("\"%s\" = \"%s\"\n", argv[1], Binds[i].GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
Binds[i] = argv[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("%s:\n", msg);
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!Binds[i].IsEmpty())
|
||||
Printf ("%s \"%s\"\n", KeyName (i), Binds[i].GetChars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// This function is first called for functions in custom key sections.
|
||||
// In this case, matchcmd is non-NULL, and only keys bound to that command
|
||||
// are stored. If a match is found, its binding is set to "\1".
|
||||
// After all custom key sections are saved, it is called one more for the
|
||||
// normal Bindings and DoubleBindings sections for this game. In this case
|
||||
// matchcmd is NULL and all keys will be stored. The config section was not
|
||||
// previously cleared, so all old bindings are still in place. If the binding
|
||||
// for a key is empty, the corresponding key in the config is removed as well.
|
||||
// If a binding is "\1", then the binding itself is cleared, but nothing
|
||||
// happens to the entry in the config.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::ArchiveBindings(FConfigFile *f, const char *matchcmd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!stricmp (str, Bindings[i]))
|
||||
if (Binds[i].IsEmpty())
|
||||
{
|
||||
Bindings[i] = "";
|
||||
if (matchcmd == NULL)
|
||||
{
|
||||
f->ClearKey(ConfigKeyName(i));
|
||||
}
|
||||
}
|
||||
else if (matchcmd == NULL || stricmp(Binds[i], matchcmd) == 0)
|
||||
{
|
||||
if (Binds[i][0] == '\1')
|
||||
{
|
||||
Binds[i] = "";
|
||||
continue;
|
||||
}
|
||||
f->SetValueForKey(ConfigKeyName(i), Binds[i]);
|
||||
if (matchcmd != NULL)
|
||||
{ // If saving a specific command, set a marker so that
|
||||
// it does not get saved in the general binding list.
|
||||
Binds[i] = "\1";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_ChangeBinding (const char *str, int newone)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
int FKeyBindings::GetKeysForCommand (char *cmd, int *first, int *second)
|
||||
{
|
||||
if ((unsigned int)newone < NUM_KEYS)
|
||||
int c, i;
|
||||
|
||||
*first = *second = c = i = 0;
|
||||
|
||||
while (i < NUM_KEYS && c < 2)
|
||||
{
|
||||
Bindings[newone] = str;
|
||||
if (stricmp (cmd, Binds[i]) == 0)
|
||||
{
|
||||
if (c++ == 0)
|
||||
*first = i;
|
||||
else
|
||||
*second = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::UnbindACommand (char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_KEYS; i++)
|
||||
{
|
||||
if (!stricmp (str, Binds[i]))
|
||||
{
|
||||
Binds[i] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *C_GetBinding (int key)
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void FKeyBindings::DefaultBind(const char *keyname, const char *cmd)
|
||||
{
|
||||
return (unsigned int)key < NUM_KEYS ? Bindings[key].GetChars() : NULL;
|
||||
int key = GetKeyFromName (keyname);
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Unknown key \"%s\"\n", keyname);
|
||||
return;
|
||||
}
|
||||
if (!Binds[key].IsEmpty())
|
||||
{ // This key is already bound.
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < NUM_KEYS; ++i)
|
||||
{
|
||||
if (!Binds[i].IsEmpty() && stricmp (Binds[i], cmd) == 0)
|
||||
{ // This command is already bound to a key.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// It is safe to do the bind, so do it.
|
||||
Binds[key] = cmd;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_UnbindAll ()
|
||||
{
|
||||
Bindings.UnbindAll();
|
||||
DoubleBindings.UnbindAll();
|
||||
AutomapBindings.UnbindAll();
|
||||
}
|
||||
|
||||
CCMD (unbindall)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (unbind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
Bindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (undoublebind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
DoubleBindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
CCMD (unmapbind)
|
||||
{
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
AutomapBindings.UnbindKey(argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (bind)
|
||||
{
|
||||
Bindings.PerformBind(argv, "Current key bindings");
|
||||
}
|
||||
|
||||
CCMD (doublebind)
|
||||
{
|
||||
DoubleBindings.PerformBind(argv, "Current key doublebindings");
|
||||
}
|
||||
|
||||
CCMD (mapbind)
|
||||
{
|
||||
AutomapBindings.PerformBind(argv, "Current automap key bindings");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD defaultbind
|
||||
//
|
||||
// Binds a command to a key if that key is not already bound and if
|
||||
// that command is not already bound to another key.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
CCMD (defaultbind)
|
||||
{
|
||||
if (argv.argc() < 3)
|
||||
{
|
||||
Printf ("Usage: defaultbind <key> <command>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Bindings.DefaultBind(argv[1], argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
CCMD (rebind)
|
||||
{
|
||||
FKeyBindings *bindings;
|
||||
|
||||
if (key == 0)
|
||||
{
|
||||
Printf ("Rebind cannot be used from the console\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (key & KEY_DBLCLICKED)
|
||||
{
|
||||
bindings = &DoubleBindings;
|
||||
key &= KEY_DBLCLICKED-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bindings = &Bindings;
|
||||
}
|
||||
|
||||
if (argv.argc() > 1)
|
||||
{
|
||||
bindings->SetBind(key, argv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
void C_BindDefaults ()
|
||||
{
|
||||
Bindings.SetBinds (DefBindings);
|
||||
|
||||
if (gameinfo.gametype & (GAME_Raven|GAME_Strife))
|
||||
{
|
||||
Bindings.SetBinds (DefRavenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Heretic)
|
||||
{
|
||||
Bindings.SetBinds (DefHereticBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Hexen)
|
||||
{
|
||||
Bindings.SetBinds (DefHexenBindings);
|
||||
}
|
||||
|
||||
if (gameinfo.gametype == GAME_Strife)
|
||||
{
|
||||
Bindings.SetBinds (DefStrifeBindings);
|
||||
}
|
||||
|
||||
AutomapBindings.SetBinds(DefAutomapBindings);
|
||||
}
|
||||
|
||||
CCMD(binddefaults)
|
||||
{
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
void C_SetDefaultBindings ()
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_BindDefaults ();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds)
|
||||
{
|
||||
FString binding;
|
||||
bool dclick;
|
||||
int dclickspot;
|
||||
BYTE dclickmask;
|
||||
|
||||
if (ev->type != EV_KeyDown && ev->type != EV_KeyUp)
|
||||
return false;
|
||||
|
||||
if ((unsigned int)ev->data1 >= NUM_KEYS)
|
||||
return false;
|
||||
|
||||
dclickspot = ev->data1 >> 3;
|
||||
dclickmask = 1 << (ev->data1 & 7);
|
||||
dclick = false;
|
||||
|
||||
// This used level.time which didn't work outside a level.
|
||||
if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown)
|
||||
{
|
||||
// Key pressed for a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] |= dclickmask;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ev->type == EV_KeyDown)
|
||||
{ // Key pressed for a normal press
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
DClickTime[ev->data1] = I_MSTime() + 571;
|
||||
}
|
||||
else if (DClicked[dclickspot] & dclickmask)
|
||||
{ // Key released from a double click
|
||||
if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1);
|
||||
DClicked[dclickspot] &= ~dclickmask;
|
||||
DClickTime[ev->data1] = 0;
|
||||
dclick = true;
|
||||
}
|
||||
else
|
||||
{ // Key released from a normal press
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (binding.IsEmpty())
|
||||
{
|
||||
binding = binds->GetBinding(ev->data1);
|
||||
dclick = false;
|
||||
}
|
||||
|
||||
if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256))
|
||||
{
|
||||
if (ev->type == EV_KeyUp && binding[0] != '+')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char *copy = binding.LockBuffer();
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
copy[0] = '-';
|
||||
}
|
||||
|
||||
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
60
src/c_bind.h
60
src/c_bind.h
|
@ -34,25 +34,65 @@
|
|||
#ifndef __C_BINDINGS_H__
|
||||
#define __C_BINDINGS_H__
|
||||
|
||||
#include "doomdef.h"
|
||||
|
||||
struct event_t;
|
||||
class FConfigFile;
|
||||
class FCommandLine;
|
||||
|
||||
bool C_DoKey (event_t *ev);
|
||||
void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd=NULL);
|
||||
void C_NameKeys (char *str, int first, int second);
|
||||
|
||||
struct FBinding
|
||||
{
|
||||
const char *Key;
|
||||
const char *Bind;
|
||||
};
|
||||
|
||||
class FKeyBindings
|
||||
{
|
||||
FString Binds[NUM_KEYS];
|
||||
|
||||
public:
|
||||
void PerformBind(FCommandLine &argv, const char *msg);
|
||||
void SetBinds(const FBinding *binds);
|
||||
bool DoKey(event_t *ev);
|
||||
void ArchiveBindings(FConfigFile *F, const char *matchcmd = NULL);
|
||||
int GetKeysForCommand (char *cmd, int *first, int *second);
|
||||
void UnbindACommand (char *str);
|
||||
void UnbindAll ();
|
||||
void UnbindKey(const char *key);
|
||||
void DoBind (const char *key, const char *bind);
|
||||
void DefaultBind(const char *keyname, const char *cmd);
|
||||
|
||||
void SetBind(unsigned int key, const char *bind)
|
||||
{
|
||||
if (key < NUM_KEYS) Binds[key] = bind;
|
||||
}
|
||||
|
||||
const FString &GetBinding(unsigned int index) const
|
||||
{
|
||||
return Binds[index];
|
||||
}
|
||||
|
||||
const char *GetBind(unsigned int index) const
|
||||
{
|
||||
if (index < NUM_KEYS) return Binds[index];
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
extern FKeyBindings Bindings;
|
||||
extern FKeyBindings DoubleBindings;
|
||||
extern FKeyBindings AutomapBindings;
|
||||
|
||||
|
||||
bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds);
|
||||
|
||||
// Stuff used by the customize controls menu
|
||||
int C_GetKeysForCommand (char *cmd, int *first, int *second);
|
||||
void C_NameKeys (char *str, int first, int second);
|
||||
void C_UnbindACommand (char *str);
|
||||
void C_ChangeBinding (const char *str, int newone);
|
||||
void C_DoBind (const char *key, const char *bind, bool doublebind);
|
||||
void C_SetDefaultBindings ();
|
||||
void C_UnbindAll ();
|
||||
|
||||
// Returns string bound to given key (NULL if none)
|
||||
const char *C_GetBinding (int key);
|
||||
|
||||
extern const char *KeyNames[];
|
||||
|
||||
#endif //__C_BINDINGS_H__
|
||||
|
|
|
@ -119,7 +119,9 @@ FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
|||
Button_Forward, Button_Right, Button_Left, Button_MoveDown,
|
||||
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
|
||||
Button_Zoom, Button_Reload,
|
||||
Button_User1, Button_User2, Button_User3, Button_User4;
|
||||
Button_User1, Button_User2, Button_User3, Button_User4,
|
||||
Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp,
|
||||
Button_AM_ZoomIn, Button_AM_ZoomOut;
|
||||
|
||||
bool ParsingKeyConf;
|
||||
|
||||
|
@ -131,13 +133,16 @@ bool ParsingKeyConf;
|
|||
|
||||
FActionMap ActionMaps[] =
|
||||
{
|
||||
{ 0x0d52d67b, &Button_AM_PanLeft, "am_panleft"},
|
||||
{ 0x125f5226, &Button_User2, "user2" },
|
||||
{ 0x1eefa611, &Button_Jump, "jump" },
|
||||
{ 0x201f1c55, &Button_Right, "right" },
|
||||
{ 0x20ccc4d5, &Button_Zoom, "zoom" },
|
||||
{ 0x23a99cd7, &Button_Back, "back" },
|
||||
{ 0x41df90c2, &Button_AM_ZoomIn, "am_zoomin"},
|
||||
{ 0x426b69e7, &Button_Reload, "reload" },
|
||||
{ 0x4463f43a, &Button_LookDown, "lookdown" },
|
||||
{ 0x51f7a334, &Button_AM_ZoomOut, "am_zoomout"},
|
||||
{ 0x534c30ee, &Button_User4, "user4" },
|
||||
{ 0x5622bf42, &Button_Attack, "attack" },
|
||||
{ 0x577712d0, &Button_User1, "user1" },
|
||||
|
@ -147,12 +152,15 @@ FActionMap ActionMaps[] =
|
|||
{ 0x676885b8, &Button_AltAttack, "altattack" },
|
||||
{ 0x6fa41b84, &Button_MoveLeft, "moveleft" },
|
||||
{ 0x818f08e6, &Button_MoveRight, "moveright" },
|
||||
{ 0x8197097b, &Button_AM_PanRight, "am_panright"},
|
||||
{ 0x8d89955e, &Button_AM_PanUp, "am_panup"} ,
|
||||
{ 0xa2b62d8b, &Button_Mlook, "mlook" },
|
||||
{ 0xab2c3e71, &Button_Crouch, "crouch" },
|
||||
{ 0xb000b483, &Button_Left, "left" },
|
||||
{ 0xb62b1e49, &Button_LookUp, "lookup" },
|
||||
{ 0xb6f8fe92, &Button_User3, "user3" },
|
||||
{ 0xb7e6a54b, &Button_Strafe, "strafe" },
|
||||
{ 0xce301c81, &Button_AM_PanDown, "am_pandown"},
|
||||
{ 0xd5897c73, &Button_ShowScores, "showscores" },
|
||||
{ 0xe0ccb317, &Button_Speed, "speed" },
|
||||
{ 0xe0cfc260, &Button_Use, "use" },
|
||||
|
@ -160,6 +168,7 @@ FActionMap ActionMaps[] =
|
|||
};
|
||||
#define NUM_ACTIONS countof(ActionMaps)
|
||||
|
||||
|
||||
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
||||
|
||||
static const char *KeyConfCommands[] =
|
||||
|
|
|
@ -146,6 +146,7 @@ struct FButtonStatus
|
|||
bool PressKey (int keynum); // Returns true if this key caused the button to be pressed.
|
||||
bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed.
|
||||
void ResetTriggers () { bWentDown = bWentUp = false; }
|
||||
void Reset () { bDown = bWentDown = bWentUp = false; }
|
||||
};
|
||||
|
||||
extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
||||
|
@ -154,7 +155,9 @@ extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack,
|
|||
Button_Forward, Button_Right, Button_Left, Button_MoveDown,
|
||||
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
|
||||
Button_Zoom, Button_Reload,
|
||||
Button_User1, Button_User2, Button_User3, Button_User4;
|
||||
Button_User1, Button_User2, Button_User3, Button_User4,
|
||||
Button_AM_PanLeft, Button_AM_PanRight, Button_AM_PanDown, Button_AM_PanUp,
|
||||
Button_AM_ZoomIn, Button_AM_ZoomOut;
|
||||
extern bool ParsingKeyConf;
|
||||
|
||||
void ResetButtonTriggers (); // Call ResetTriggers for all buttons
|
||||
|
|
154
src/cmdlib.cpp
154
src/cmdlib.cpp
|
@ -2,10 +2,14 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#if !defined(__sun)
|
||||
#include <fts.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "doomtype.h"
|
||||
#include "cmdlib.h"
|
||||
|
@ -885,3 +889,153 @@ FString NicePath(const char *path)
|
|||
return where;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
struct _finddata_t fileinfo;
|
||||
intptr_t handle;
|
||||
FString dirmatch;
|
||||
|
||||
dirmatch << dirpath << "*";
|
||||
|
||||
if ((handle = _findfirst(dirmatch, &fileinfo)) == -1)
|
||||
{
|
||||
I_Error("Could not scan '%s': %s\n", dirpath, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
if (fileinfo.attrib & _A_HIDDEN)
|
||||
{
|
||||
// Skip hidden files and directories. (Prevents SVN bookkeeping
|
||||
// info from being included.)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileinfo.attrib & _A_SUBDIR)
|
||||
{
|
||||
if (fileinfo.name[0] == '.' &&
|
||||
(fileinfo.name[1] == '\0' ||
|
||||
(fileinfo.name[1] == '.' && fileinfo.name[2] == '\0')))
|
||||
{
|
||||
// Do not record . and .. directories.
|
||||
continue;
|
||||
}
|
||||
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << fileinfo.name;
|
||||
fl->isDirectory = true;
|
||||
FString newdir = fl->Filename;
|
||||
newdir << "/";
|
||||
ScanDirectory(list, newdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << fileinfo.name;
|
||||
fl->isDirectory = false;
|
||||
}
|
||||
}
|
||||
while (_findnext(handle, &fileinfo) == 0);
|
||||
_findclose(handle);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__sun) || defined(linux)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
// Solaris version
|
||||
//
|
||||
// Given NULL-terminated array of directory paths, create trees for them.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
DIR *directory = opendir(dirpath);
|
||||
if(directory == NULL)
|
||||
return;
|
||||
|
||||
struct dirent *file;
|
||||
while((file = readdir(directory)) != NULL)
|
||||
{
|
||||
if(file->d_name[0] == '.') //File is hidden or ./.. directory so ignore it.
|
||||
continue;
|
||||
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename << dirpath << file->d_name;
|
||||
|
||||
struct stat fileStat;
|
||||
stat(fl->Filename, &fileStat);
|
||||
fl->isDirectory = S_ISDIR(fileStat.st_mode);
|
||||
|
||||
if(fl->isDirectory)
|
||||
{
|
||||
FString newdir = fl->Filename;
|
||||
newdir += "/";
|
||||
ScanDirectory(list, newdir);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(directory);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ScanDirectory
|
||||
// 4.4BSD version
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath)
|
||||
{
|
||||
const char **argv[] = {dirpath, NULL };
|
||||
FTS *fts;
|
||||
FTSENT *ent;
|
||||
|
||||
fts = fts_open(argv, FTS_LOGICAL, NULL);
|
||||
if (fts == NULL)
|
||||
{
|
||||
I_Error("Failed to start directory traversal: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
while ((ent = fts_read(fts)) != NULL)
|
||||
{
|
||||
if (ent->fts_info == FTS_D && ent->fts_name[0] == '.')
|
||||
{
|
||||
// Skip hidden directories. (Prevents SVN bookkeeping
|
||||
// info from being included.)
|
||||
fts_set(fts, ent, FTS_SKIP);
|
||||
}
|
||||
if (ent->fts_info == FTS_D && ent->fts_level == 0)
|
||||
{
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename = ent->fts_path;
|
||||
fl->isDirectory = true;
|
||||
}
|
||||
if (ent->fts_info == FTS_F)
|
||||
{
|
||||
// We're only interested in remembering files.
|
||||
FFileList *fl = &list[list.Reserve(1)];
|
||||
fl->Filename = ent->fts_path;
|
||||
fl->isDirectory = false;
|
||||
}
|
||||
}
|
||||
fts_close(fts);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -54,4 +54,12 @@ void CreatePath(const char * fn);
|
|||
FString ExpandEnvVars(const char *searchpathstring);
|
||||
FString NicePath(const char *path);
|
||||
|
||||
struct FFileList
|
||||
{
|
||||
FString Filename;
|
||||
bool isDirectory;
|
||||
};
|
||||
|
||||
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2294,6 +2294,14 @@ void FStartupScreen::AppendStatusLine(const char *status)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// STAT fps
|
||||
//
|
||||
// Displays statistics about rendering times
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ADD_STAT (fps)
|
||||
{
|
||||
FString out;
|
||||
|
@ -2302,6 +2310,24 @@ ADD_STAT (fps)
|
|||
return out;
|
||||
}
|
||||
|
||||
|
||||
static double f_acc, w_acc,p_acc,m_acc;
|
||||
static int acc_c;
|
||||
|
||||
ADD_STAT (fps_accumulated)
|
||||
{
|
||||
f_acc += FrameCycles.TimeMS();
|
||||
w_acc += WallCycles.TimeMS();
|
||||
p_acc += PlaneCycles.TimeMS();
|
||||
m_acc += MaskedCycles.TimeMS();
|
||||
acc_c++;
|
||||
FString out;
|
||||
out.Format("frame=%04.1f ms walls=%04.1f ms planes=%04.1f ms masked=%04.1f ms %d counts",
|
||||
f_acc/acc_c, w_acc/acc_c, p_acc/acc_c, m_acc/acc_c, acc_c);
|
||||
Printf(PRINT_LOG, "%s\n", out.GetChars());
|
||||
return out;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// STAT wallcycles
|
||||
|
|
|
@ -723,7 +723,7 @@ bool F_CastResponder (event_t* ev)
|
|||
if (ev->type != EV_KeyDown)
|
||||
return false;
|
||||
|
||||
const char *cmd = C_GetBinding (ev->data1);
|
||||
const char *cmd = Bindings.GetBind (ev->data1);
|
||||
|
||||
if (cmd != NULL && !stricmp (cmd, "toggleconsole"))
|
||||
return false;
|
||||
|
|
|
@ -879,7 +879,7 @@ bool G_Responder (event_t *ev)
|
|||
if (gameaction == ga_nothing &&
|
||||
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL))
|
||||
{
|
||||
const char *cmd = C_GetBinding (ev->data1);
|
||||
const char *cmd = Bindings.GetBind (ev->data1);
|
||||
|
||||
if (ev->type == EV_KeyDown)
|
||||
{
|
||||
|
@ -902,11 +902,11 @@ bool G_Responder (event_t *ev)
|
|||
}
|
||||
else
|
||||
{
|
||||
return C_DoKey (ev);
|
||||
return C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
}
|
||||
}
|
||||
if (cmd && cmd[0] == '+')
|
||||
return C_DoKey (ev);
|
||||
return C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -918,7 +918,7 @@ bool G_Responder (event_t *ev)
|
|||
{
|
||||
if (ST_Responder (ev))
|
||||
return true; // status window ate it
|
||||
if (!viewactive && AM_Responder (ev))
|
||||
if (!viewactive && AM_Responder (ev, false))
|
||||
return true; // automap ate it
|
||||
}
|
||||
else if (gamestate == GS_FINALE)
|
||||
|
@ -930,12 +930,12 @@ bool G_Responder (event_t *ev)
|
|||
switch (ev->type)
|
||||
{
|
||||
case EV_KeyDown:
|
||||
if (C_DoKey (ev))
|
||||
if (C_DoKey (ev, &Bindings, &DoubleBindings))
|
||||
return true;
|
||||
break;
|
||||
|
||||
case EV_KeyUp:
|
||||
C_DoKey (ev);
|
||||
C_DoKey (ev, &Bindings, &DoubleBindings);
|
||||
break;
|
||||
|
||||
// [RH] mouse buttons are sent as key up/down events
|
||||
|
@ -949,7 +949,7 @@ bool G_Responder (event_t *ev)
|
|||
// the events *last* so that any bound keys get precedence.
|
||||
|
||||
if (gamestate == GS_LEVEL && viewactive)
|
||||
return AM_Responder (ev);
|
||||
return AM_Responder (ev, true);
|
||||
|
||||
return (ev->type == EV_KeyDown ||
|
||||
ev->type == EV_Mouse);
|
||||
|
|
|
@ -1464,8 +1464,8 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
|
|||
P_SerializeThinkers (arc, hubLoad);
|
||||
P_SerializeWorld (arc);
|
||||
P_SerializePolyobjs (arc);
|
||||
P_SerializeSubsectors(arc);
|
||||
StatusBar->Serialize (arc);
|
||||
//SerializeInterpolations (arc);
|
||||
|
||||
arc << level.total_monsters << level.total_items << level.total_secrets;
|
||||
|
||||
|
|
|
@ -399,29 +399,38 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
|
|||
ReadCVars (0);
|
||||
}
|
||||
|
||||
strncpy (subsection, "Bindings", sublen);
|
||||
if (!SetSection (section))
|
||||
{ // Config has no bindings for the given game
|
||||
if (!bMigrating)
|
||||
{
|
||||
C_SetDefaultBindings ();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!bMigrating)
|
||||
{
|
||||
C_UnbindAll ();
|
||||
C_SetDefaultBindings ();
|
||||
}
|
||||
|
||||
strncpy (subsection, "Bindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
Bindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
C_DoBind (key, value, false);
|
||||
Bindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (subsection, "DoubleBindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
DoubleBindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
C_DoBind (key, value, true);
|
||||
DoubleBindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (subsection, "AutomapBindings", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
AutomapBindings.UnbindAll();
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
AutomapBindings.DoBind (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -512,11 +521,15 @@ void FGameConfigFile::ArchiveGameData (const char *gamename)
|
|||
|
||||
strcpy (subsection, "Bindings");
|
||||
SetSection (section, true);
|
||||
C_ArchiveBindings (this, false);
|
||||
Bindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "DoubleBindings", sublen);
|
||||
SetSection (section, true);
|
||||
C_ArchiveBindings (this, true);
|
||||
DoubleBindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "AutomapBindings", sublen);
|
||||
SetSection (section, true);
|
||||
AutomapBindings.ArchiveBindings (this);
|
||||
}
|
||||
|
||||
void FGameConfigFile::ArchiveGlobalData ()
|
||||
|
|
|
@ -116,6 +116,7 @@ typedef enum {
|
|||
joy_slider,
|
||||
joy_map,
|
||||
joy_inverter,
|
||||
mapcontrol,
|
||||
} itemtype;
|
||||
|
||||
struct IJoystickConfig;
|
||||
|
|
|
@ -204,6 +204,7 @@ static menu_t ConfirmMenu = {
|
|||
*
|
||||
*=======================================*/
|
||||
|
||||
static void StartAutomapMenu (void);
|
||||
static void CustomizeControls (void);
|
||||
static void GameplayOptions (void);
|
||||
static void CompatibilityOptions (void);
|
||||
|
@ -228,6 +229,7 @@ static menuitem_t OptionItems[] =
|
|||
{ more, "Player Setup", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)M_PlayerSetup} },
|
||||
{ more, "Gameplay Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)GameplayOptions} },
|
||||
{ more, "Compatibility Options",{NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)CompatibilityOptions} },
|
||||
{ more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} },
|
||||
{ more, "Sound Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)SoundOptions} },
|
||||
{ more, "Display Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)VideoOptions} },
|
||||
{ more, "Set video mode", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)SetVidMode} },
|
||||
|
@ -419,13 +421,13 @@ menu_t ControlsMenu =
|
|||
2,
|
||||
};
|
||||
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Display Options Menu
|
||||
*
|
||||
*=======================================*/
|
||||
static void StartMessagesMenu (void);
|
||||
static void StartAutomapMenu (void);
|
||||
static void StartScoreboardMenu (void);
|
||||
static void InitCrosshairsList();
|
||||
|
||||
|
@ -495,7 +497,6 @@ static value_t DisplayTagsTypes[] = {
|
|||
|
||||
static menuitem_t VideoItems[] = {
|
||||
{ more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} },
|
||||
{ more, "Automap Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartAutomapMenu} },
|
||||
{ more, "Scoreboard Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartScoreboardMenu} },
|
||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ slider, "Screen size", {&screenblocks}, {3.0}, {12.0}, {1.0}, {NULL} },
|
||||
|
@ -538,6 +539,7 @@ menu_t VideoMenu =
|
|||
*
|
||||
*=======================================*/
|
||||
static void StartMapColorsMenu (void);
|
||||
static void StartMapControlsMenu (void);
|
||||
|
||||
EXTERN_CVAR (Int, am_rotate)
|
||||
EXTERN_CVAR (Int, am_overlay)
|
||||
|
@ -548,6 +550,7 @@ EXTERN_CVAR (Bool, am_showtime)
|
|||
EXTERN_CVAR (Int, am_map_secrets)
|
||||
EXTERN_CVAR (Bool, am_showtotaltime)
|
||||
EXTERN_CVAR (Bool, am_drawmapback)
|
||||
EXTERN_CVAR (Bool, am_textured)
|
||||
|
||||
static value_t MapColorTypes[] = {
|
||||
{ 0, "Custom" },
|
||||
|
@ -577,9 +580,11 @@ static value_t OverlayTypes[] = {
|
|||
static menuitem_t AutomapItems[] = {
|
||||
{ discrete, "Map color set", {&am_colorset}, {4.0}, {0.0}, {0.0}, {MapColorTypes} },
|
||||
{ more, "Set custom colors", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t*)StartMapColorsMenu} },
|
||||
{ more, "Customize map controls", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t*)StartMapControlsMenu} },
|
||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ discrete, "Rotate automap", {&am_rotate}, {3.0}, {0.0}, {0.0}, {RotateTypes} },
|
||||
{ discrete, "Overlay automap", {&am_overlay}, {3.0}, {0.0}, {0.0}, {OverlayTypes} },
|
||||
{ discrete, "Enable textured display", {&am_textured}, {3.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ discrete, "Show item counts", {&am_showitems}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
{ discrete, "Show monster counts", {&am_showmonsters}, {2.0}, {0.0}, {0.0}, {OnOff} },
|
||||
|
@ -600,6 +605,37 @@ menu_t AutomapMenu =
|
|||
AutomapItems,
|
||||
};
|
||||
|
||||
menuitem_t MapControlsItems[] =
|
||||
{
|
||||
{ redtext,"ENTER to change, BACKSPACE to clear", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ whitetext,"Map Controls", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
|
||||
{ mapcontrol, "Pan left", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panleft"} },
|
||||
{ mapcontrol, "Pan right", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panright"} },
|
||||
{ mapcontrol, "Pan up", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_panup"} },
|
||||
{ mapcontrol, "Pan down", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_pandown"} },
|
||||
{ mapcontrol, "Zoom in", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_zoomin"} },
|
||||
{ mapcontrol, "Zoom out", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"+am_zoomout"} },
|
||||
{ mapcontrol, "Toggle zoom", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_gobig"} },
|
||||
{ mapcontrol, "Toggle follow", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_togglefollow"} },
|
||||
{ mapcontrol, "Toggle grid", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_togglegrid"} },
|
||||
{ mapcontrol, "Toggle texture", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_toggletexture"} },
|
||||
{ mapcontrol, "Set mark", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_setmark"} },
|
||||
{ mapcontrol, "Clear mark", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)"am_clearmarks"} },
|
||||
};
|
||||
|
||||
menu_t MapControlsMenu =
|
||||
{
|
||||
"CUSTOMIZE MAP CONTROLS",
|
||||
3,
|
||||
countof(MapControlsItems),
|
||||
0,
|
||||
MapControlsItems,
|
||||
2,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Map Colors Menu
|
||||
|
@ -1536,7 +1572,9 @@ void M_BuildKeyList (menuitem_t *item, int numitems)
|
|||
for (i = 0; i < numitems; i++, item++)
|
||||
{
|
||||
if (item->type == control)
|
||||
C_GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2);
|
||||
Bindings.GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2);
|
||||
else if (item->type == mapcontrol)
|
||||
AutomapBindings.GetKeysForCommand (item->e.command, &item->b.key1, &item->c.key2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1825,7 +1863,7 @@ void M_OptDrawer ()
|
|||
|
||||
default:
|
||||
x = indent - width;
|
||||
color = (item->type == control && menuactive == MENU_WaitKey && i == CurrentItem)
|
||||
color = ((item->type == control || item->type == mapcontrol) && menuactive == MENU_WaitKey && i == CurrentItem)
|
||||
? CR_YELLOW : LabelColor;
|
||||
break;
|
||||
}
|
||||
|
@ -1983,6 +2021,7 @@ void M_OptDrawer ()
|
|||
break;
|
||||
|
||||
case control:
|
||||
case mapcontrol:
|
||||
{
|
||||
char description[64];
|
||||
|
||||
|
@ -2165,7 +2204,14 @@ void M_OptResponder(event_t *ev)
|
|||
{
|
||||
if (ev->data1 != KEY_ESCAPE)
|
||||
{
|
||||
C_ChangeBinding(item->e.command, ev->data1);
|
||||
if (item->type == control)
|
||||
{
|
||||
Bindings.SetBind(ev->data1, item->e.command);
|
||||
}
|
||||
else if (item->type == mapcontrol)
|
||||
{
|
||||
AutomapBindings.SetBind(ev->data1, item->e.command);
|
||||
}
|
||||
M_BuildKeyList(CurrentMenu->items, CurrentMenu->numitems);
|
||||
}
|
||||
menuactive = MENU_On;
|
||||
|
@ -2812,7 +2858,12 @@ void M_OptButtonHandler(EMenuKey key, bool repeat)
|
|||
case MKEY_Clear:
|
||||
if (item->type == control)
|
||||
{
|
||||
C_UnbindACommand (item->e.command);
|
||||
Bindings.UnbindACommand (item->e.command);
|
||||
item->b.key1 = item->c.key2 = 0;
|
||||
}
|
||||
else if (item->type == mapcontrol)
|
||||
{
|
||||
AutomapBindings.UnbindACommand (item->e.command);
|
||||
item->b.key1 = item->c.key2 = 0;
|
||||
}
|
||||
break;
|
||||
|
@ -2880,7 +2931,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat)
|
|||
|
||||
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE);
|
||||
}
|
||||
else if (item->type == control)
|
||||
else if (item->type == control || item->type == mapcontrol)
|
||||
{
|
||||
menuactive = MENU_WaitKey;
|
||||
OldMessage = CurrentMenu->items[0].label;
|
||||
|
@ -3000,6 +3051,12 @@ static void StartMapColorsMenu (void)
|
|||
M_SwitchMenu (&MapColorsMenu);
|
||||
}
|
||||
|
||||
static void StartMapControlsMenu (void)
|
||||
{
|
||||
M_BuildKeyList (MapControlsMenu.items, MapControlsMenu.numitems);
|
||||
M_SwitchMenu (&MapControlsMenu);
|
||||
}
|
||||
|
||||
CCMD (menu_mapcolors)
|
||||
{
|
||||
M_StartControlPanel (true);
|
||||
|
@ -3644,12 +3701,14 @@ void M_LoadKeys (const char *modname, bool dbl)
|
|||
|
||||
mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname,
|
||||
dbl ? ".Double" : ".");
|
||||
|
||||
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
|
||||
if (GameConfig->SetSection (section))
|
||||
{
|
||||
const char *key, *value;
|
||||
while (GameConfig->NextInSection (key, value))
|
||||
{
|
||||
C_DoBind (key, value, dbl);
|
||||
bindings->DoBind (key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3660,12 +3719,13 @@ int M_DoSaveKeys (FConfigFile *config, char *section, int i, bool dbl)
|
|||
|
||||
config->SetSection (section, true);
|
||||
config->ClearCurrentSection ();
|
||||
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
|
||||
for (++i; i < most; ++i)
|
||||
{
|
||||
menuitem_t *item = &CustomControlsItems[i];
|
||||
if (item->type == control)
|
||||
{
|
||||
C_ArchiveBindings (config, dbl, item->e.command);
|
||||
bindings->ArchiveBindings (config, item->e.command);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
@ -3711,7 +3771,7 @@ void FreeKeySections()
|
|||
for (i = numStdControls; i < CustomControlsItems.Size(); ++i)
|
||||
{
|
||||
menuitem_t *item = &CustomControlsItems[i];
|
||||
if (item->type == whitetext || item->type == control)
|
||||
if (item->type == whitetext || item->type == control || item->type == mapcontrol)
|
||||
{
|
||||
if (item->label != NULL)
|
||||
{
|
||||
|
|
|
@ -442,6 +442,7 @@ xx(nofakecontrast)
|
|||
xx(smoothlighting)
|
||||
xx(blockprojectiles)
|
||||
xx(blockuse)
|
||||
xx(hidden)
|
||||
|
||||
xx(Renderstyle)
|
||||
|
||||
|
|
|
@ -111,6 +111,12 @@ class FNodeBuilder
|
|||
bool Forward;
|
||||
};
|
||||
|
||||
struct glseg_t : public seg_t
|
||||
{
|
||||
DWORD Partner;
|
||||
};
|
||||
|
||||
|
||||
// Like a blockmap, but for vertices instead of lines
|
||||
class IVertexMap
|
||||
{
|
||||
|
@ -200,7 +206,7 @@ public:
|
|||
~FNodeBuilder ();
|
||||
|
||||
void Extract (node_t *&nodes, int &nodeCount,
|
||||
seg_t *&segs, int &segCount,
|
||||
seg_t *&segs, glsegextra_t *&glsegextras, int &segCount,
|
||||
subsector_t *&ssecs, int &subCount,
|
||||
vertex_t *&verts, int &vertCount);
|
||||
|
||||
|
@ -282,10 +288,10 @@ private:
|
|||
DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg);
|
||||
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
|
||||
|
||||
int CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
DWORD PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
int CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts);
|
||||
DWORD PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
|
||||
void PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2);
|
||||
int OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts);
|
||||
|
||||
static int STACK_ARGS SortSegs (const void *a, const void *b);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
#endif
|
||||
|
||||
void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
||||
seg_t *&outSegs, int &segCount,
|
||||
seg_t *&outSegs, glsegextra_t *&outSegExtras, int &segCount,
|
||||
subsector_t *&outSubs, int &subCount,
|
||||
vertex_t *&outVerts, int &vertCount)
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
|
||||
if (GLNodes)
|
||||
{
|
||||
TArray<seg_t> segs (Segs.Size()*5/4);
|
||||
TArray<glseg_t> segs (Segs.Size()*5/4);
|
||||
|
||||
for (i = 0; i < subCount; ++i)
|
||||
{
|
||||
|
@ -110,14 +110,12 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
|
||||
segCount = segs.Size ();
|
||||
outSegs = new seg_t[segCount];
|
||||
memcpy (outSegs, &segs[0], segCount*sizeof(seg_t));
|
||||
outSegExtras = new glsegextra_t[segCount];
|
||||
|
||||
for (i = 0; i < segCount; ++i)
|
||||
{
|
||||
if (outSegs[i].PartnerSeg != NULL)
|
||||
{
|
||||
outSegs[i].PartnerSeg = &outSegs[Segs[(unsigned int)(size_t)outSegs[i].PartnerSeg-1].storedseg];
|
||||
}
|
||||
outSegs[i] = *(seg_t *)&segs[i];
|
||||
outSegExtras[i].PartnerSeg = segs[i].Partner;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -125,6 +123,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
memcpy (outSubs, &Subsectors[0], subCount*sizeof(subsector_t));
|
||||
segCount = Segs.Size ();
|
||||
outSegs = new seg_t[segCount];
|
||||
outSegExtras = NULL;
|
||||
for (i = 0; i < segCount; ++i)
|
||||
{
|
||||
const FPrivSeg *org = &Segs[SegList[i].SegNum];
|
||||
|
@ -138,8 +137,6 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
|
|||
out->frontsector = org->frontsector;
|
||||
out->linedef = Level.Lines + org->linedef;
|
||||
out->sidedef = Level.Sides + org->sidedef;
|
||||
out->PartnerSeg = NULL;
|
||||
out->bPolySeg = false;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < subCount; ++i)
|
||||
|
@ -194,19 +191,17 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
|
|||
|
||||
if (GLNodes)
|
||||
{
|
||||
TArray<glseg_t> glsegs;
|
||||
for (i = 0; i < Subsectors.Size(); ++i)
|
||||
{
|
||||
DWORD numsegs = CloseSubsector (bsp->Segs, i, &bsp->Verts[0]);
|
||||
DWORD numsegs = CloseSubsector (glsegs, i, &bsp->Verts[0]);
|
||||
bsp->Subsectors[i].numlines = numsegs;
|
||||
bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs];
|
||||
}
|
||||
|
||||
for (i = 0; i < Segs.Size(); ++i)
|
||||
bsp->Segs.Resize(glsegs.Size());
|
||||
for (i = 0; i < glsegs.Size(); ++i)
|
||||
{
|
||||
if (bsp->Segs[i].PartnerSeg != NULL)
|
||||
{
|
||||
bsp->Segs[i].PartnerSeg = &bsp->Segs[Segs[(unsigned int)(size_t)bsp->Segs[i].PartnerSeg-1].storedseg];
|
||||
}
|
||||
bsp->Segs[i] = *(seg_t *)&glsegs[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -234,8 +229,6 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
|
|||
out->linedef = NULL;
|
||||
out->sidedef = NULL;
|
||||
}
|
||||
out->PartnerSeg = NULL;
|
||||
out->bPolySeg = false;
|
||||
}
|
||||
for (i = 0; i < bsp->Subsectors.Size(); ++i)
|
||||
{
|
||||
|
@ -244,7 +237,7 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
|
|||
}
|
||||
}
|
||||
|
||||
int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts)
|
||||
int FNodeBuilder::CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts)
|
||||
{
|
||||
FPrivSeg *seg, *prev;
|
||||
angle_t prevAngle;
|
||||
|
@ -406,7 +399,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
|
|||
return count;
|
||||
}
|
||||
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
int FNodeBuilder::OutputDegenerateSubsector (TArray<glseg_t> &segs, int subsector, bool bForward, double lastdot, FPrivSeg *&prev, vertex_t *outVerts)
|
||||
{
|
||||
static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
|
||||
FPrivSeg *seg;
|
||||
|
@ -473,9 +466,9 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
|
|||
return count;
|
||||
}
|
||||
|
||||
DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
DWORD FNodeBuilder::PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts)
|
||||
{
|
||||
seg_t newseg;
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = outVerts + seg->v1;
|
||||
newseg.v2 = outVerts + seg->v2;
|
||||
|
@ -491,14 +484,13 @@ DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_
|
|||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
}
|
||||
newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1);
|
||||
newseg.bPolySeg = false;
|
||||
newseg.Partner = seg->partner;
|
||||
return (DWORD)segs.Push (newseg);
|
||||
}
|
||||
|
||||
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2)
|
||||
void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<glseg_t> &segs, vertex_t *v1, vertex_t *v2)
|
||||
{
|
||||
seg_t newseg;
|
||||
glseg_t newseg;
|
||||
|
||||
newseg.v1 = v1;
|
||||
newseg.v2 = v2;
|
||||
|
@ -506,7 +498,6 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vert
|
|||
newseg.frontsector = NULL;
|
||||
newseg.linedef = NULL;
|
||||
newseg.sidedef = NULL;
|
||||
newseg.PartnerSeg = NULL;
|
||||
newseg.bPolySeg = false;
|
||||
newseg.Partner = DWORD_MAX;
|
||||
segs.Push (newseg);
|
||||
}
|
||||
|
|
|
@ -5097,7 +5097,7 @@ int DLevelScript::RunScript ()
|
|||
{
|
||||
int key1 = 0, key2 = 0;
|
||||
|
||||
C_GetKeysForCommand ((char *)lookup, &key1, &key2);
|
||||
Bindings.GetKeysForCommand ((char *)lookup, &key1, &key2);
|
||||
|
||||
if (key2)
|
||||
work << KeyNames[key1] << " or " << KeyNames[key2];
|
||||
|
|
1537
src/p_glnodes.cpp
Normal file
1537
src/p_glnodes.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -456,9 +456,10 @@ const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymo
|
|||
// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.)
|
||||
//
|
||||
//----------------------------------------------------------------------------------
|
||||
subsector_t *P_PointInSubsector (fixed_t x, fixed_t y);
|
||||
inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
|
||||
{
|
||||
return R_PointInSubsector(x,y)->sector;
|
||||
return P_PointInSubsector(x,y)->sector;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -302,7 +302,7 @@ void AActor::LinkToWorld (bool buggy)
|
|||
// link into subsector
|
||||
sector_t *sec;
|
||||
|
||||
if (!buggy || numnodes == 0)
|
||||
if (!buggy || numgamenodes == 0)
|
||||
{
|
||||
sec = P_PointInSector (x, y);
|
||||
}
|
||||
|
@ -322,6 +322,7 @@ void AActor::LinkToWorld (sector_t *sec)
|
|||
return;
|
||||
}
|
||||
Sector = sec;
|
||||
subsector = R_PointInSubsector(x, y); // this is from the rendering nodes, not the gameplay nodes!
|
||||
|
||||
if ( !(flags & MF_NOSECTOR) )
|
||||
{
|
||||
|
@ -460,7 +461,7 @@ static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
|
|||
|
||||
sector_t *AActor::LinkToWorldForMapThing ()
|
||||
{
|
||||
node_t *node = nodes + numnodes - 1;
|
||||
node_t *node = gamenodes + numgamenodes - 1;
|
||||
|
||||
do
|
||||
{
|
||||
|
|
|
@ -4705,6 +4705,20 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
|
|||
// don't splash above the object
|
||||
if (checkabove && z > thing->z + (thing->height >> 1)) return false;
|
||||
|
||||
#if 0 // needs some rethinking before activation
|
||||
|
||||
// This avoids spawning splashes on invisible self referencing sectors.
|
||||
// For network consistency do this only in single player though because
|
||||
// it is not guaranteed that all players have GL nodes loaded.
|
||||
if (!multiplayer && thing->subsector->sector != thing->subsector->render_sector)
|
||||
{
|
||||
fixed_t zs = thing->subsector->sector->floorplane.ZatPoint(x, y);
|
||||
fixed_t zr = thing->subsector->render_sector->floorplane.ZatPoint(x, y);
|
||||
|
||||
if (zs > zr && thing->z >= zs) return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _3DFLOORS
|
||||
for(unsigned int i=0;i<sec->e->XFloor.ffloors.Size();i++)
|
||||
{
|
||||
|
@ -4823,7 +4837,7 @@ bool P_HitFloor (AActor *thing)
|
|||
{
|
||||
thing->flags6 &= ~MF6_ARMED; // Disarm
|
||||
P_DamageMobj (thing, NULL, NULL, thing->health, NAME_Crush, DMG_FORCED); // kill object
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thing->flags2 & MF2_FLOATBOB || thing->flags3 & MF3_DONTSPLASH)
|
||||
|
|
106
src/p_saveg.cpp
106
src/p_saveg.cpp
|
@ -47,6 +47,7 @@
|
|||
#include "r_interpolate.h"
|
||||
#include "g_level.h"
|
||||
#include "po_man.h"
|
||||
#include "p_setup.h"
|
||||
|
||||
static void CopyPlayer (player_t *dst, player_t *src, const char *name);
|
||||
static void ReadOnePlayer (FArchive &arc, bool skipload);
|
||||
|
@ -542,3 +543,108 @@ void P_SerializePolyobjs (FArchive &arc)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// RecalculateDrawnSubsectors
|
||||
//
|
||||
// In case the subsector data is unusable this function tries to reconstruct
|
||||
// if from the linedefs' ML_MAPPED info.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void RecalculateDrawnSubsectors()
|
||||
{
|
||||
for(int i=0;i<numsubsectors;i++)
|
||||
{
|
||||
subsector_t *sub = &subsectors[i];
|
||||
for(unsigned int j=0;j<sub->numlines;j++)
|
||||
{
|
||||
if (sub->firstline[j].linedef != NULL &&
|
||||
(sub->firstline[j].linedef->flags & ML_MAPPED))
|
||||
{
|
||||
sub->flags |= SSECF_DRAWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ArchiveSubsectors
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void P_SerializeSubsectors(FArchive &arc)
|
||||
{
|
||||
int num_verts, num_subs, num_nodes;
|
||||
BYTE by;
|
||||
|
||||
if (arc.IsStoring())
|
||||
{
|
||||
if (hasglnodes)
|
||||
{
|
||||
arc << numvertexes << numsubsectors << numnodes; // These are only for verification
|
||||
for(int i=0;i<numsubsectors;i+=8)
|
||||
{
|
||||
by = 0;
|
||||
for(int j=0;j<8;j++)
|
||||
{
|
||||
if ((subsectors[i+j].flags & SSECF_DRAWN) && i+j<numsubsectors)
|
||||
{
|
||||
by |= (1<<j);
|
||||
}
|
||||
}
|
||||
arc << by;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int v = 0;
|
||||
arc << v << v << v;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SaveVersion < 2500)
|
||||
{
|
||||
if (hasglnodes)
|
||||
{
|
||||
RecalculateDrawnSubsectors();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
arc << num_verts << num_subs << num_nodes;
|
||||
if (num_verts != numvertexes ||
|
||||
num_subs != numsubsectors ||
|
||||
num_nodes != numnodes)
|
||||
{
|
||||
// Nodes don't match - we can't use this info
|
||||
for(int i=0;i<num_subs;i+=8)
|
||||
{
|
||||
// Skip the subsector info.
|
||||
arc << by;
|
||||
}
|
||||
if (hasglnodes)
|
||||
{
|
||||
RecalculateDrawnSubsectors();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i=0;i<numsubsectors;i+=8)
|
||||
{
|
||||
arc << by;
|
||||
for(int j=0;j<8;j++)
|
||||
{
|
||||
if ((by & (1<<j)) && i+j<numsubsectors)
|
||||
{
|
||||
subsectors[i+j].flags |= SSECF_DRAWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ void P_SerializePlayers (FArchive &arc, bool fakeload);
|
|||
void P_SerializeWorld (FArchive &arc);
|
||||
void P_SerializeThinkers (FArchive &arc, bool);
|
||||
void P_SerializePolyobjs (FArchive &arc);
|
||||
void P_SerializeSubsectors(FArchive &arc);
|
||||
void P_SerializeSounds (FArchive &arc);
|
||||
|
||||
void P_ReadACSDefereds (PNGHandle *png);
|
||||
|
|
133
src/p_setup.cpp
133
src/p_setup.cpp
|
@ -83,6 +83,8 @@ void P_ParseTextMap(MapData *map);
|
|||
extern int numinterpolations;
|
||||
extern unsigned int R_OldBlend;
|
||||
|
||||
EXTERN_CVAR(Bool, am_textured)
|
||||
|
||||
CVAR (Bool, genblockmap, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, gennodes, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG);
|
||||
CVAR (Bool, genglnodes, false, CVAR_SERVERINFO);
|
||||
|
@ -103,6 +105,7 @@ vertex_t* vertexes;
|
|||
|
||||
int numsegs;
|
||||
seg_t* segs;
|
||||
glsegextra_t* glsegextras;
|
||||
|
||||
int numsectors;
|
||||
sector_t* sectors;
|
||||
|
@ -122,6 +125,14 @@ side_t* sides;
|
|||
int numzones;
|
||||
zone_t* zones;
|
||||
|
||||
node_t * gamenodes;
|
||||
int numgamenodes;
|
||||
|
||||
subsector_t * gamesubsectors;
|
||||
int numgamesubsectors;
|
||||
|
||||
bool hasglnodes;
|
||||
|
||||
FExtraLight* ExtraLights;
|
||||
FLightStack* LightStacks;
|
||||
|
||||
|
@ -132,8 +143,6 @@ sidei_t *sidetemp;
|
|||
|
||||
TArray<int> linemap;
|
||||
|
||||
bool UsingGLNodes;
|
||||
|
||||
// BLOCKMAP
|
||||
// Created from axis aligned bounding box
|
||||
// of the map, a rectangular array of
|
||||
|
@ -152,7 +161,6 @@ fixed_t bmaporgx; // origin of block map
|
|||
fixed_t bmaporgy;
|
||||
|
||||
FBlockNode** blocklinks; // for thing chains
|
||||
|
||||
|
||||
|
||||
// REJECT
|
||||
|
@ -790,7 +798,6 @@ void P_LoadZSegs (FileReaderBase &data)
|
|||
segs[i].v2 = &vertexes[v2];
|
||||
segs[i].linedef = ldef = &lines[line];
|
||||
segs[i].sidedef = ldef->sidedef[side];
|
||||
segs[i].PartnerSeg = NULL;
|
||||
segs[i].frontsector = ldef->sidedef[side]->sector;
|
||||
if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != NULL)
|
||||
{
|
||||
|
@ -846,14 +853,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
|
|||
{
|
||||
seg[-1].v2 = seg->v1;
|
||||
}
|
||||
if (partner == 0xFFFFFFFF)
|
||||
{
|
||||
seg->PartnerSeg = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
seg->PartnerSeg = &segs[partner];
|
||||
}
|
||||
glsegextras[seg - segs].PartnerSeg = partner;
|
||||
if (line != 0xFFFFFFFF)
|
||||
{
|
||||
line_t *ldef;
|
||||
|
@ -887,7 +887,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
static void LoadZNodes(FileReaderBase &data, int glnodes)
|
||||
void LoadZNodes(FileReaderBase &data, int glnodes)
|
||||
{
|
||||
// Read extra vertices added during node building
|
||||
DWORD orgVerts, newVerts;
|
||||
|
@ -956,6 +956,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
|||
numsegs = numSegs;
|
||||
segs = new seg_t[numsegs];
|
||||
memset (segs, 0, numsegs*sizeof(seg_t));
|
||||
glsegextras = NULL;
|
||||
|
||||
for (i = 0; i < numSubs; ++i)
|
||||
{
|
||||
|
@ -968,6 +969,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
|||
}
|
||||
else
|
||||
{
|
||||
glsegextras = new glsegextra_t[numsegs];
|
||||
P_LoadGLZSegs (data, glnodes);
|
||||
}
|
||||
|
||||
|
@ -1014,7 +1016,7 @@ static void LoadZNodes(FileReaderBase &data, int glnodes)
|
|||
}
|
||||
|
||||
|
||||
static void P_LoadZNodes (FileReader &dalump, DWORD id)
|
||||
void P_LoadZNodes (FileReader &dalump, DWORD id)
|
||||
{
|
||||
int type;
|
||||
bool compressed;
|
||||
|
@ -1162,7 +1164,6 @@ void P_LoadSegs (MapData * map)
|
|||
|
||||
li->v1 = &vertexes[vnum1];
|
||||
li->v2 = &vertexes[vnum2];
|
||||
li->PartnerSeg = NULL;
|
||||
|
||||
segangle = (WORD)LittleShort(ml->angle);
|
||||
|
||||
|
@ -2904,6 +2905,16 @@ static void P_GroupLines (bool buildmap)
|
|||
{
|
||||
subsectors[i].sector = subsectors[i].firstline->sidedef->sector;
|
||||
}
|
||||
if (glsegextras != NULL)
|
||||
{
|
||||
for (i = 0; i < numsubsectors; i++)
|
||||
{
|
||||
for (jj = 0; jj < subsectors[i].numlines; ++jj)
|
||||
{
|
||||
glsegextras[subsectors[i].firstline - segs + jj].Subsector = &subsectors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
times[0].Unclock();
|
||||
|
||||
// count number of lines in each sector
|
||||
|
@ -3339,6 +3350,11 @@ void P_FreeLevelData ()
|
|||
delete[] segs;
|
||||
segs = NULL;
|
||||
}
|
||||
if (glsegextras != NULL)
|
||||
{
|
||||
delete[] glsegextras;
|
||||
glsegextras = NULL;
|
||||
}
|
||||
if (sectors != NULL)
|
||||
{
|
||||
delete[] sectors[0].e;
|
||||
|
@ -3346,6 +3362,18 @@ void P_FreeLevelData ()
|
|||
sectors = NULL;
|
||||
numsectors = 0; // needed for the pointer cleanup code
|
||||
}
|
||||
if (gamenodes && gamenodes!=nodes)
|
||||
{
|
||||
delete [] gamenodes;
|
||||
gamenodes = NULL;
|
||||
numgamenodes = 0;
|
||||
}
|
||||
if (gamesubsectors && gamesubsectors!=subsectors)
|
||||
{
|
||||
delete [] gamesubsectors;
|
||||
gamesubsectors = NULL;
|
||||
numgamesubsectors = 0;
|
||||
}
|
||||
if (subsectors != NULL)
|
||||
{
|
||||
for (int i = 0; i < numsubsectors; ++i)
|
||||
|
@ -3480,6 +3508,9 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
int i;
|
||||
bool buildmap;
|
||||
|
||||
// This is motivated as follows:
|
||||
bool RequireGLNodes = am_textured;
|
||||
|
||||
for (i = 0; i < (int)countof(times); ++i)
|
||||
{
|
||||
times[i].Reset();
|
||||
|
@ -3537,6 +3568,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
|
||||
// find map num
|
||||
level.lumpnum = map->lumpnum;
|
||||
hasglnodes = false;
|
||||
|
||||
// [RH] Support loading Build maps (because I felt like it. :-)
|
||||
buildmap = false;
|
||||
|
@ -3665,23 +3697,23 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
{
|
||||
ForceNodeBuild = true;
|
||||
}
|
||||
bool reloop = false;
|
||||
|
||||
UsingGLNodes = false;
|
||||
if (!ForceNodeBuild)
|
||||
{
|
||||
// Check for compressed nodes first, then uncompressed nodes
|
||||
FWadLump test;
|
||||
DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0;
|
||||
|
||||
if (map->MapLumps[ML_ZNODES].Size != 0 && !UsingGLNodes)
|
||||
if (map->MapLumps[ML_ZNODES].Size != 0)
|
||||
{
|
||||
// Test normal nodes first
|
||||
map->Seek(ML_ZNODES);
|
||||
idcheck = MAKE_ID('Z','N','O','D');
|
||||
idcheck2 = MAKE_ID('X','N','O','D');
|
||||
}
|
||||
else if (map->MapLumps[ML_GLZNODES].Size != 0)
|
||||
{
|
||||
// If normal nodes are not present but GL nodes are, use them.
|
||||
map->Seek(ML_GLZNODES);
|
||||
idcheck = MAKE_ID('Z','G','L','N');
|
||||
idcheck2 = MAKE_ID('Z','G','L','2');
|
||||
|
@ -3756,10 +3788,23 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
else ForceNodeBuild = true;
|
||||
}
|
||||
else ForceNodeBuild = true;
|
||||
|
||||
// If loading the regular nodes failed try GL nodes before considering a rebuild
|
||||
if (ForceNodeBuild)
|
||||
{
|
||||
if (P_LoadGLNodes(map))
|
||||
{
|
||||
ForceNodeBuild=false;
|
||||
reloop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else reloop = true;
|
||||
|
||||
unsigned int startTime=0, endTime=0;
|
||||
|
||||
if (ForceNodeBuild)
|
||||
{
|
||||
unsigned int startTime, endTime;
|
||||
|
||||
startTime = I_FPSTime ();
|
||||
TArray<FNodeBuilder::FPolyStart> polyspots, anchors;
|
||||
|
@ -3771,15 +3816,46 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
lines, numlines
|
||||
};
|
||||
leveldata.FindMapBounds ();
|
||||
UsingGLNodes |= genglnodes;
|
||||
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes);
|
||||
// We need GL nodes if am_textured is on.
|
||||
// In case a sync critical game mode is started, also build GL nodes to avoid problems
|
||||
// if the different machines' am_textured setting differs.
|
||||
bool BuildGLNodes = am_textured || multiplayer || demoplayback || demorecording || genglnodes;
|
||||
FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes);
|
||||
delete[] vertexes;
|
||||
builder.Extract (nodes, numnodes,
|
||||
segs, numsegs,
|
||||
segs, glsegextras, numsegs,
|
||||
subsectors, numsubsectors,
|
||||
vertexes, numvertexes);
|
||||
endTime = I_FPSTime ();
|
||||
DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs);
|
||||
reloop = true;
|
||||
}
|
||||
|
||||
// Copy pointers to the old nodes so that R_PointInSubsector can use them
|
||||
if (nodes && subsectors)
|
||||
{
|
||||
gamenodes = nodes;
|
||||
numgamenodes = numnodes;
|
||||
gamesubsectors = subsectors;
|
||||
numgamesubsectors = numsubsectors;
|
||||
}
|
||||
else
|
||||
{
|
||||
gamenodes=NULL;
|
||||
}
|
||||
|
||||
if (RequireGLNodes)
|
||||
{
|
||||
// Build GL nodes if we want a textured automap or GL nodes are forced to be built.
|
||||
// If the original nodes being loaded are not GL nodes they will be kept around for
|
||||
// use in P_PointInSubsector to avoid problems with maps that depend on the specific
|
||||
// nodes they were built with (P:AR E1M3 is a good example for a map where this is the case.)
|
||||
reloop |= P_CheckNodes(map, ForceNodeBuild, endTime - startTime);
|
||||
hasglnodes = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasglnodes = P_CheckForGLNodes();
|
||||
}
|
||||
|
||||
times[10].Clock();
|
||||
|
@ -3798,6 +3874,11 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
P_FloodZones ();
|
||||
times[13].Unclock();
|
||||
|
||||
if (hasglnodes)
|
||||
{
|
||||
P_SetRenderSector();
|
||||
}
|
||||
|
||||
bodyqueslot = 0;
|
||||
// phares 8/10/98: Clear body queue so the corpses from previous games are
|
||||
// not assumed to be from this one.
|
||||
|
@ -3845,7 +3926,7 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
P_SpawnSpecials ();
|
||||
|
||||
times[16].Clock();
|
||||
if (ForceNodeBuild) P_LoopSidedefs (false);
|
||||
if (reloop) P_LoopSidedefs (false);
|
||||
PO_Init (); // Initialize the polyobjs
|
||||
times[16].Unclock();
|
||||
|
||||
|
@ -3922,6 +4003,12 @@ void P_SetupLevel (char *lumpname, int position)
|
|||
}
|
||||
}
|
||||
MapThingsConverted.Clear();
|
||||
|
||||
if (glsegextras != NULL)
|
||||
{
|
||||
delete[] glsegextras;
|
||||
glsegextras = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -111,6 +111,12 @@ int P_TranslateSectorSpecial (int);
|
|||
int GetUDMFInt(int type, int index, const char *key);
|
||||
fixed_t GetUDMFFixed(int type, int index, const char *key);
|
||||
|
||||
bool P_LoadGLNodes(MapData * map);
|
||||
bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime);
|
||||
bool P_CheckForGLNodes();
|
||||
void P_SetRenderSector();
|
||||
|
||||
|
||||
struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init
|
||||
{
|
||||
union
|
||||
|
@ -133,5 +139,7 @@ struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init
|
|||
};
|
||||
};
|
||||
extern sidei_t *sidetemp;
|
||||
extern bool hasglnodes;
|
||||
extern struct glsegextra_t *glsegextras;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1227,6 +1227,10 @@ public:
|
|||
sec->seqType = -1;
|
||||
continue;
|
||||
|
||||
case NAME_hidden:
|
||||
sec->MoreFlags |= SECF_HIDDEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1827,12 +1827,6 @@ void PO_Init (void)
|
|||
// [RH] Don't need the seg lists anymore
|
||||
KillSideLists ();
|
||||
|
||||
// We still need to flag the segs of the polyobj's sidedefs so that they are excluded from rendering.
|
||||
for(int i=0;i<numsegs;i++)
|
||||
{
|
||||
segs[i].bPolySeg = (segs[i].sidedef != NULL && segs[i].sidedef->Flags & WALLF_POLYOBJ);
|
||||
}
|
||||
|
||||
for(int i=0;i<numnodes;i++)
|
||||
{
|
||||
node_t *no = &nodes[i];
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "i_system.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "p_setup.h"
|
||||
|
||||
#include "r_main.h"
|
||||
#include "r_plane.h"
|
||||
|
@ -112,6 +113,8 @@ TArray<size_t> WallMirrors;
|
|||
static FNodeBuilder::FLevel PolyNodeLevel;
|
||||
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
|
||||
|
||||
static subsector_t *InSubsector;
|
||||
|
||||
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs?
|
||||
|
||||
|
||||
|
@ -167,10 +170,11 @@ static cliprange_t solidsegs[MAXWIDTH/2+2];
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_ClipWallSegment (int first, int last, bool solid)
|
||||
bool R_ClipWallSegment (int first, int last, bool solid)
|
||||
{
|
||||
cliprange_t *next, *start;
|
||||
int i, j;
|
||||
bool res = false;
|
||||
|
||||
// Find the first range that touches the range
|
||||
// (adjacent pixels are touching).
|
||||
|
@ -180,6 +184,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
|
|||
|
||||
if (first < start->first)
|
||||
{
|
||||
res = true;
|
||||
if (last <= start->first)
|
||||
{
|
||||
// Post is entirely visible (above start).
|
||||
|
@ -205,7 +210,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
|
|||
next->last = last;
|
||||
}
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// There is a fragment above *start.
|
||||
|
@ -220,7 +225,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
|
|||
|
||||
// Bottom contained in start?
|
||||
if (last <= start->last)
|
||||
return;
|
||||
return res;
|
||||
|
||||
next = start;
|
||||
while (last >= (next+1)->first)
|
||||
|
@ -257,6 +262,31 @@ crunch:
|
|||
newend = start+i;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool R_CheckClipWallSegment (int first, int last)
|
||||
{
|
||||
cliprange_t *start;
|
||||
|
||||
// Find the first range that touches the range
|
||||
// (adjacent pixels are touching).
|
||||
start = solidsegs;
|
||||
while (start->last < first)
|
||||
start++;
|
||||
|
||||
if (first < start->first)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bottom contained in start?
|
||||
if (last > start->last)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -626,6 +656,10 @@ void R_AddLine (seg_t *line)
|
|||
|
||||
if (line->linedef == NULL)
|
||||
{
|
||||
if (R_CheckClipWallSegment (WallSX1, WallSX2))
|
||||
{
|
||||
InSubsector->flags |= SSECF_DRAWN;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -792,6 +826,16 @@ void R_AddLine (seg_t *line)
|
|||
// Reject empty lines used for triggers and special events.
|
||||
// Identical floor and ceiling on both sides, identical light levels
|
||||
// on both sides, and no middle texture.
|
||||
|
||||
// When using GL nodes, do a clipping test for these lines so we can
|
||||
// mark their subsectors as visible for automap texturing.
|
||||
if (hasglnodes && !(InSubsector->flags & SSECF_DRAWN))
|
||||
{
|
||||
if (R_CheckClipWallSegment(WallSX1, WallSX2))
|
||||
{
|
||||
InSubsector->flags |= SSECF_DRAWN;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -827,7 +871,10 @@ void R_AddLine (seg_t *line)
|
|||
#endif
|
||||
}
|
||||
|
||||
R_ClipWallSegment (WallSX1, WallSX2, solid);
|
||||
if (R_ClipWallSegment (WallSX1, WallSX2, solid))
|
||||
{
|
||||
InSubsector->flags |= SSECF_DRAWN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1096,12 +1143,21 @@ void R_Subsector (subsector_t *sub)
|
|||
sector_t tempsec; // killough 3/7/98: deep water hack
|
||||
int floorlightlevel; // killough 3/16/98: set floor lightlevel
|
||||
int ceilinglightlevel; // killough 4/11/98
|
||||
bool outersubsector;
|
||||
|
||||
if (InSubsector != NULL)
|
||||
{ // InSubsector is not NULL. This means we are rendering from a mini-BSP.
|
||||
outersubsector = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
outersubsector = true;
|
||||
InSubsector = sub;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef RANGECHECK
|
||||
if (sub - subsectors >= (ptrdiff_t)numsubsectors)
|
||||
if (outersubsector && sub - subsectors >= (ptrdiff_t)numsubsectors)
|
||||
I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
assert(sub->sector != NULL);
|
||||
|
@ -1109,6 +1165,10 @@ void R_Subsector (subsector_t *sub)
|
|||
if (sub->polys)
|
||||
{ // Render the polyobjs in the subsector first
|
||||
R_AddPolyobjs(sub);
|
||||
if (outersubsector)
|
||||
{
|
||||
InSubsector = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1190,12 +1250,16 @@ void R_Subsector (subsector_t *sub)
|
|||
|
||||
while (count--)
|
||||
{
|
||||
if (!line->bPolySeg)
|
||||
if (!outersubsector || line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
R_AddLine (line);
|
||||
}
|
||||
line++;
|
||||
}
|
||||
if (outersubsector)
|
||||
{
|
||||
InSubsector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
18
src/r_defs.h
18
src/r_defs.h
|
@ -319,6 +319,7 @@ enum
|
|||
SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater
|
||||
SECF_UNDERWATERMASK = 32+64,
|
||||
SECF_DRAWN = 128, // sector has been drawn at least once
|
||||
SECF_HIDDEN = 256, // Do not draw on textured automap
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -942,10 +943,12 @@ struct seg_t
|
|||
// Sector references. Could be retrieved from linedef, too.
|
||||
sector_t* frontsector;
|
||||
sector_t* backsector; // NULL for one-sided lines
|
||||
};
|
||||
|
||||
seg_t* PartnerSeg;
|
||||
|
||||
BITFIELD bPolySeg:1;
|
||||
struct glsegextra_t
|
||||
{
|
||||
DWORD PartnerSeg;
|
||||
subsector_t *Subsector;
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -954,13 +957,22 @@ struct seg_t
|
|||
// Basically, this is a list of LineSegs indicating the visible walls that
|
||||
// define (all or some) sides of a convex BSP leaf.
|
||||
//
|
||||
|
||||
enum
|
||||
{
|
||||
SSECF_DEGENERATE = 1,
|
||||
SSECF_DRAWN = 2,
|
||||
};
|
||||
|
||||
struct subsector_t
|
||||
{
|
||||
sector_t *sector;
|
||||
FPolyNode *polys;
|
||||
FMiniBSP *BSP;
|
||||
seg_t *firstline;
|
||||
sector_t *render_sector;
|
||||
DWORD numlines;
|
||||
int flags;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1000,6 +1000,77 @@ const BYTE* ds_source;
|
|||
|
||||
// just for profiling
|
||||
int dscount;
|
||||
|
||||
#ifdef X86_ASM
|
||||
extern "C" void R_SetSpanSource_ASM (const BYTE *flat);
|
||||
extern "C" void STACK_ARGS R_SetSpanSize_ASM (int xbits, int ybits);
|
||||
extern "C" void R_SetSpanColormap_ASM (BYTE *colormap);
|
||||
extern "C" BYTE *ds_curcolormap, *ds_cursource, *ds_curtiltedsource;
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetSpanSource
|
||||
//
|
||||
// Sets the source bitmap for the span drawing routines.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_SetSpanSource(const BYTE *pixels)
|
||||
{
|
||||
ds_source = pixels;
|
||||
#ifdef X86_ASM
|
||||
if (ds_cursource != ds_source)
|
||||
{
|
||||
R_SetSpanSource_ASM(pixels);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetSpanColormap
|
||||
//
|
||||
// Sets the colormap for the span drawing routines.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_SetSpanColormap(BYTE *colormap)
|
||||
{
|
||||
ds_colormap = colormap;
|
||||
#ifdef X86_ASM
|
||||
if (ds_colormap != ds_curcolormap)
|
||||
{
|
||||
R_SetSpanColormap_ASM (ds_colormap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// R_SetupSpanBits
|
||||
//
|
||||
// Sets the texture size for the span drawing routines.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void R_SetupSpanBits(FTexture *tex)
|
||||
{
|
||||
tex->GetWidth ();
|
||||
ds_xbits = tex->WidthBits;
|
||||
ds_ybits = tex->HeightBits;
|
||||
if ((1 << ds_xbits) > tex->GetWidth())
|
||||
{
|
||||
ds_xbits--;
|
||||
}
|
||||
if ((1 << ds_ybits) > tex->GetHeight())
|
||||
{
|
||||
ds_ybits--;
|
||||
}
|
||||
#ifdef X86_ASM
|
||||
R_SetSpanSize_ASM (ds_xbits, ds_ybits);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -91,8 +91,11 @@ extern void (*R_DrawShadedColumn)(void);
|
|||
// Green/Red/Blue/Indigo shirts.
|
||||
extern void (*R_DrawTranslatedColumn)(void);
|
||||
|
||||
// Span drawing for rows, floor/ceiling. No Sepctre effect needed.
|
||||
// Span drawing for rows, floor/ceiling. No Spectre effect needed.
|
||||
extern void (*R_DrawSpan)(void);
|
||||
void R_SetupSpanBits(FTexture *tex);
|
||||
void R_SetSpanColormap(BYTE *colormap);
|
||||
void R_SetSpanSource(const BYTE *pixels);
|
||||
|
||||
// Span drawing for masked textures.
|
||||
extern void (*R_DrawSpanMasked)(void);
|
||||
|
|
|
@ -991,22 +991,9 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool masked)
|
|||
{ // Don't waste time on a masked texture if it isn't really masked.
|
||||
masked = false;
|
||||
}
|
||||
tex->GetWidth ();
|
||||
ds_xbits = tex->WidthBits;
|
||||
ds_ybits = tex->HeightBits;
|
||||
if ((1 << ds_xbits) > tex->GetWidth())
|
||||
{
|
||||
ds_xbits--;
|
||||
}
|
||||
if ((1 << ds_ybits) > tex->GetHeight())
|
||||
{
|
||||
ds_ybits--;
|
||||
}
|
||||
R_SetupSpanBits(tex);
|
||||
pl->xscale = MulScale16 (pl->xscale, tex->xScale);
|
||||
pl->yscale = MulScale16 (pl->yscale, tex->yScale);
|
||||
#ifdef X86_ASM
|
||||
R_SetSpanSize_ASM (ds_xbits, ds_ybits);
|
||||
#endif
|
||||
ds_source = tex->GetPixels ();
|
||||
|
||||
basecolormap = pl->colormap;
|
||||
|
|
|
@ -110,5 +110,4 @@ bool R_PlaneInitData (void);
|
|||
extern visplane_t* floorplane;
|
||||
extern visplane_t* ceilingplane;
|
||||
|
||||
|
||||
#endif // __R_PLANE_H__
|
||||
|
|
|
@ -1485,7 +1485,7 @@ void RP_Subsector (subsector_t *sub)
|
|||
|
||||
while (count--)
|
||||
{
|
||||
if (!line->bPolySeg)
|
||||
if (line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
|
||||
{
|
||||
RP_AddLine (line);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,13 @@ extern side_t* sides;
|
|||
extern int numzones;
|
||||
extern zone_t* zones;
|
||||
|
||||
extern node_t * gamenodes;
|
||||
extern int numgamenodes;
|
||||
|
||||
extern subsector_t * gamesubsectors;
|
||||
extern int numgamesubsectors;
|
||||
|
||||
|
||||
extern FExtraLight* ExtraLights;
|
||||
extern FLightStack* LightStacks;
|
||||
|
||||
|
|
172
src/v_draw.cpp
172
src/v_draw.cpp
|
@ -62,6 +62,9 @@ int CleanWidth, CleanHeight;
|
|||
// Above minus 1 (or 1, if they are already 1)
|
||||
int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
|
||||
|
||||
// FillSimplePoly uses this
|
||||
extern "C" short spanend[MAXHEIGHT];
|
||||
|
||||
CVAR (Bool, hud_scale, false, CVAR_ARCHIVE);
|
||||
|
||||
// For routines that take RGB colors, cache the previous lookup in case there
|
||||
|
@ -69,6 +72,7 @@ CVAR (Bool, hud_scale, false, CVAR_ARCHIVE);
|
|||
static int LastPal = -1;
|
||||
static uint32 LastRGB;
|
||||
|
||||
|
||||
static int PalFromRGB(uint32 rgb)
|
||||
{
|
||||
if (LastPal >= 0 && LastRGB == rgb)
|
||||
|
@ -186,7 +190,7 @@ void STACK_ARGS DCanvas::DrawTextureV(FTexture *img, double x, double y, uint32
|
|||
double iyscale = 1 / yscale;
|
||||
|
||||
spryscale = FLOAT2FIXED(yscale);
|
||||
|
||||
assert(spryscale > 2);
|
||||
#if 0
|
||||
// Fix precision errors that are noticeable at some resolutions
|
||||
if ((y0 + parms.destheight) > (y0 + yscale * img->GetHeight()))
|
||||
|
@ -1091,6 +1095,172 @@ void DCanvas::Clear (int left, int top, int right, int bottom, int palcolor, uin
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DCanvas :: FillSimplePoly
|
||||
//
|
||||
// Fills a simple polygon with a texture. Here, "simple" means that a
|
||||
// horizontal scanline at any vertical position within the polygon will
|
||||
// not cross it more than twice.
|
||||
//
|
||||
// The originx, originy, scale, and rotation parameters specify
|
||||
// transformation of the filling texture, not of the points.
|
||||
//
|
||||
// The points must be specified in clockwise order.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley, angle_t rotation,
|
||||
FDynamicColormap *colormap, int lightlevel)
|
||||
{
|
||||
// Use an equation similar to player sprites to determine shade
|
||||
fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT;
|
||||
float topy, boty, leftx, rightx;
|
||||
int toppt, botpt, pt1, pt2;
|
||||
int i;
|
||||
int y1, y2, y;
|
||||
fixed_t x;
|
||||
double rot = rotation * M_PI / double(1u << 31);
|
||||
bool dorotate = rot != 0;
|
||||
double cosrot, sinrot;
|
||||
|
||||
if (--npoints < 2 || Buffer == NULL)
|
||||
{ // not a polygon or we're not locked
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the extents of the polygon, in particular the highest and lowest points.
|
||||
for (botpt = toppt = 0, boty = topy = points[0].Y, leftx = rightx = points[0].X, i = 1; i <= npoints; ++i)
|
||||
{
|
||||
if (points[i].Y < topy)
|
||||
{
|
||||
topy = points[i].Y;
|
||||
toppt = i;
|
||||
}
|
||||
if (points[i].Y > boty)
|
||||
{
|
||||
boty = points[i].Y;
|
||||
botpt = i;
|
||||
}
|
||||
if (points[i].X < leftx)
|
||||
{
|
||||
leftx = points[i].X;
|
||||
}
|
||||
if (points[i].X > rightx)
|
||||
{
|
||||
rightx = points[i].X;
|
||||
}
|
||||
}
|
||||
if (topy >= Height || // off the bottom of the screen
|
||||
boty <= 0 || // off the top of the screen
|
||||
leftx >= Width || // off the right of the screen
|
||||
rightx <= 0) // off the left of the screen
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cosrot = cos(rot);
|
||||
sinrot = sin(rot);
|
||||
|
||||
// Setup constant texture mapping parameters.
|
||||
R_SetupSpanBits(tex);
|
||||
R_SetSpanColormap(colormap != NULL ? &colormap->Maps[clamp(shade >> FRACBITS, 0, NUMCOLORMAPS-1) * 256] : identitymap);
|
||||
R_SetSpanSource(tex->GetPixels());
|
||||
scalex = double(1u << (32 - ds_xbits)) / scalex;
|
||||
scaley = double(1u << (32 - ds_ybits)) / scaley;
|
||||
ds_xstep = xs_RoundToInt(cosrot * scalex);
|
||||
ds_ystep = xs_RoundToInt(sinrot * scaley);
|
||||
|
||||
// Travel down the right edge and create an outline of that edge.
|
||||
pt1 = toppt;
|
||||
pt2 = toppt + 1; if (pt2 > npoints) pt2 = 0;
|
||||
y1 = xs_RoundToInt(points[pt1].Y + 0.5f);
|
||||
do
|
||||
{
|
||||
x = FLOAT2FIXED(points[pt1].X + 0.5f);
|
||||
y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
|
||||
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
|
||||
int y3 = MIN(y2, Height);
|
||||
if (y1 < 0)
|
||||
{
|
||||
x += xinc * -y1;
|
||||
y1 = 0;
|
||||
}
|
||||
for (y = y1; y < y3; ++y)
|
||||
{
|
||||
spanend[y] = clamp<short>(x >> FRACBITS, -1, Width);
|
||||
x += xinc;
|
||||
}
|
||||
}
|
||||
y1 = y2;
|
||||
pt1 = pt2;
|
||||
pt2++; if (pt2 > npoints) pt2 = 0;
|
||||
} while (pt1 != botpt);
|
||||
|
||||
// Travel down the left edge and fill it in.
|
||||
pt1 = toppt;
|
||||
pt2 = toppt - 1; if (pt2 < 0) pt2 = npoints;
|
||||
y1 = xs_RoundToInt(points[pt1].Y + 0.5f);
|
||||
do
|
||||
{
|
||||
x = FLOAT2FIXED(points[pt1].X + 0.5f);
|
||||
y2 = xs_RoundToInt(points[pt2].Y + 0.5f);
|
||||
if (y1 >= y2 || (y1 < 0 && y2 < 0) || (y1 >= Height && y2 >= Height))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_t xinc = FLOAT2FIXED((points[pt2].X - points[pt1].X) / (points[pt2].Y - points[pt1].Y));
|
||||
int y3 = MIN(y2, Height);
|
||||
if (y1 < 0)
|
||||
{
|
||||
x += xinc * -y1;
|
||||
y1 = 0;
|
||||
}
|
||||
for (y = y1; y < y3; ++y)
|
||||
{
|
||||
int x1 = x >> FRACBITS;
|
||||
int x2 = spanend[y];
|
||||
if (x2 > x1 && x2 > 0 && x1 < Width)
|
||||
{
|
||||
x1 = MAX(x1, 0);
|
||||
x2 = MIN(x2, Width);
|
||||
#if 0
|
||||
memset(this->Buffer + y * this->Pitch + x1, (int)tex, x2 - x1);
|
||||
#else
|
||||
ds_y = y;
|
||||
ds_x1 = x1;
|
||||
ds_x2 = x2 - 1;
|
||||
|
||||
TVector2<double> tex(x1 - originx, y - originy);
|
||||
if (dorotate)
|
||||
{
|
||||
double t = tex.X;
|
||||
tex.X = t * cosrot - tex.Y * sinrot;
|
||||
tex.Y = tex.Y * cosrot + t * sinrot;
|
||||
}
|
||||
ds_xfrac = xs_RoundToInt(tex.X * scalex);
|
||||
ds_yfrac = xs_RoundToInt(tex.Y * scaley);
|
||||
|
||||
R_DrawSpan();
|
||||
#endif
|
||||
}
|
||||
x += xinc;
|
||||
}
|
||||
}
|
||||
y1 = y2;
|
||||
pt1 = pt2;
|
||||
pt2--; if (pt2 < 0) pt2 = npoints;
|
||||
} while (pt1 != botpt);
|
||||
}
|
||||
|
||||
|
||||
/********************************/
|
||||
/* */
|
||||
/* Other miscellaneous routines */
|
||||
|
|
|
@ -133,6 +133,7 @@ enum
|
|||
class FFont;
|
||||
struct FRemapTable;
|
||||
class player_t;
|
||||
typedef uint32 angle_t;
|
||||
|
||||
//
|
||||
// VIDEO
|
||||
|
@ -175,6 +176,11 @@ public:
|
|||
// Fill an area with a texture
|
||||
virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false);
|
||||
|
||||
// Fill a simple polygon with a texture
|
||||
virtual void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley, angle_t rotation,
|
||||
struct FDynamicColormap *colormap, int lightlevel);
|
||||
|
||||
// Set an area to a specified color
|
||||
virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 color);
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ D3DFB::D3DFB (UINT adapter, int width, int height, bool fullscreen)
|
|||
GatheringWipeScreen = false;
|
||||
ScreenWipe = NULL;
|
||||
InScene = false;
|
||||
QuadExtra = new BufferedQuad[MAX_QUAD_BATCH];
|
||||
QuadExtra = new BufferedTris[MAX_QUAD_BATCH];
|
||||
Packs = NULL;
|
||||
PixelDoubling = 0;
|
||||
SkipAt = -1;
|
||||
|
@ -1865,7 +1865,7 @@ void D3DFB::DrawPackedTextures(int packnum)
|
|||
|
||||
CheckQuadBatch();
|
||||
|
||||
BufferedQuad *quad = &QuadExtra[QuadBatchPos];
|
||||
BufferedTris *quad = &QuadExtra[QuadBatchPos];
|
||||
FBVERTEX *vert = &VertexData[VertexPos];
|
||||
|
||||
quad->Group1 = 0;
|
||||
|
@ -1881,6 +1881,8 @@ void D3DFB::DrawPackedTextures(int packnum)
|
|||
}
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = pack->Tex;
|
||||
quad->NumVerts = 4;
|
||||
quad->NumTris = 2;
|
||||
|
||||
float x0 = float(x) - 0.5f;
|
||||
float y0 = float(y) - 0.5f;
|
||||
|
@ -3021,16 +3023,20 @@ void STACK_ARGS D3DFB::DrawTextureV (FTexture *img, double x, double y, uint32 t
|
|||
parms.bilinear = false;
|
||||
|
||||
D3DCOLOR color0, color1;
|
||||
if (!SetStyle(tex, parms, color0, color1, QuadExtra[QuadBatchPos]))
|
||||
BufferedTris *quad = &QuadExtra[QuadBatchPos];
|
||||
|
||||
if (!SetStyle(tex, parms, color0, color1, *quad))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QuadExtra[QuadBatchPos].Texture = tex->Box->Owner->Tex;
|
||||
quad->Texture = tex->Box->Owner->Tex;
|
||||
if (parms.bilinear)
|
||||
{
|
||||
QuadExtra[QuadBatchPos].Flags |= BQF_Bilinear;
|
||||
quad->Flags |= BQF_Bilinear;
|
||||
}
|
||||
quad->NumTris = 2;
|
||||
quad->NumVerts = 4;
|
||||
|
||||
float yoffs = GatheringWipeScreen ? 0.5f : 0.5f - LBOffset;
|
||||
|
||||
|
@ -3152,7 +3158,7 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
|
|||
|
||||
CheckQuadBatch();
|
||||
|
||||
BufferedQuad *quad = &QuadExtra[QuadBatchPos];
|
||||
BufferedTris *quad = &QuadExtra[QuadBatchPos];
|
||||
FBVERTEX *vert = &VertexData[VertexPos];
|
||||
|
||||
quad->Group1 = 0;
|
||||
|
@ -3168,6 +3174,8 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
|
|||
}
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = tex->Box->Owner->Tex;
|
||||
quad->NumVerts = 4;
|
||||
quad->NumTris = 2;
|
||||
|
||||
vert[0].x = x0;
|
||||
vert[0].y = y0;
|
||||
|
@ -3217,6 +3225,128 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
|
|||
IndexPos += 6;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: FillSimplePoly
|
||||
//
|
||||
// Here, "simple" means that a simple triangle fan can draw it.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel)
|
||||
{
|
||||
// Use an equation similar to player sprites to determine shade
|
||||
fixed_t shade = LIGHT2SHADE(lightlevel) - 12*FRACUNIT;
|
||||
BufferedTris *quad;
|
||||
FBVERTEX *verts;
|
||||
D3DTex *tex;
|
||||
float yoffs, uscale, vscale;
|
||||
int i, ipos;
|
||||
D3DCOLOR color0, color1;
|
||||
float ox, oy;
|
||||
float cosrot, sinrot;
|
||||
float rot = float(rotation * M_PI / float(1u << 31));
|
||||
bool dorotate = rot != 0;
|
||||
|
||||
if (npoints < 3)
|
||||
{ // This is no polygon.
|
||||
return;
|
||||
}
|
||||
if (In2D < 2)
|
||||
{
|
||||
Super::FillSimplePoly(texture, points, npoints, originx, originy, scalex, scaley, rotation, colormap, lightlevel);
|
||||
return;
|
||||
}
|
||||
if (!InScene)
|
||||
{
|
||||
return;
|
||||
}
|
||||
tex = static_cast<D3DTex *>(texture->GetNative(true));
|
||||
if (tex == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cosrot = cos(rot);
|
||||
sinrot = sin(rot);
|
||||
|
||||
CheckQuadBatch(npoints - 2, npoints);
|
||||
quad = &QuadExtra[QuadBatchPos];
|
||||
verts = &VertexData[VertexPos];
|
||||
|
||||
color0 = 0;
|
||||
color1 = 0xFFFFFFFF;
|
||||
|
||||
quad->Group1 = 0;
|
||||
if (tex->GetTexFormat() == D3DFMT_L8 && !tex->IsGray)
|
||||
{
|
||||
quad->Flags = BQF_WrapUV | BQF_GamePalette | BQF_DisableAlphaTest;
|
||||
quad->ShaderNum = BQS_PalTex;
|
||||
if (colormap != NULL)
|
||||
{
|
||||
if (colormap->Desaturate != 0)
|
||||
{
|
||||
quad->Flags |= BQF_Desaturated;
|
||||
}
|
||||
quad->ShaderNum = BQS_InGameColormap;
|
||||
color0 = D3DCOLOR_ARGB(colormap->Desaturate,
|
||||
colormap->Color.r, colormap->Color.g, colormap->Color.b);
|
||||
double fadelevel = clamp(shade / (NUMCOLORMAPS * 65536.0), 0.0, 1.0);
|
||||
color1 = D3DCOLOR_ARGB(DWORD((1 - fadelevel) * 255),
|
||||
DWORD(colormap->Fade.r * fadelevel),
|
||||
DWORD(colormap->Fade.g * fadelevel),
|
||||
DWORD(colormap->Fade.b * fadelevel));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
quad->Flags = BQF_WrapUV | BQF_DisableAlphaTest;
|
||||
quad->ShaderNum = BQS_Plain;
|
||||
}
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = tex->Box->Owner->Tex;
|
||||
quad->NumVerts = npoints;
|
||||
quad->NumTris = npoints - 2;
|
||||
|
||||
yoffs = GatheringWipeScreen ? 0 : LBOffset;
|
||||
uscale = float(1.f / (texture->GetWidth() * scalex));
|
||||
vscale = float(1.f / (texture->GetHeight() * scaley));
|
||||
ox = float(originx);
|
||||
oy = float(originy);
|
||||
|
||||
for (i = 0; i < npoints; ++i)
|
||||
{
|
||||
verts[i].x = points[i].X;
|
||||
verts[i].y = points[i].Y + yoffs;
|
||||
verts[i].z = 0;
|
||||
verts[i].rhw = 1;
|
||||
verts[i].color0 = color0;
|
||||
verts[i].color1 = color1;
|
||||
float u = points[i].X - 0.5f - ox;
|
||||
float v = points[i].Y - 0.5f - oy;
|
||||
if (dorotate)
|
||||
{
|
||||
float t = u;
|
||||
u = t * cosrot - v * sinrot;
|
||||
v = v * cosrot + t * sinrot;
|
||||
}
|
||||
verts[i].tu = u * uscale;
|
||||
verts[i].tv = v * vscale;
|
||||
}
|
||||
for (ipos = IndexPos, i = 2; i < npoints; ++i, ipos += 3)
|
||||
{
|
||||
IndexData[ipos ] = VertexPos;
|
||||
IndexData[ipos + 1] = VertexPos + i - 1;
|
||||
IndexData[ipos + 2] = VertexPos + i;
|
||||
}
|
||||
|
||||
QuadBatchPos++;
|
||||
VertexPos += npoints;
|
||||
IndexPos = ipos;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// D3DFB :: AddColorOnlyQuad
|
||||
|
@ -3227,7 +3357,7 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
|
|||
|
||||
void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color)
|
||||
{
|
||||
BufferedQuad *quad;
|
||||
BufferedTris *quad;
|
||||
FBVERTEX *verts;
|
||||
|
||||
CheckQuadBatch();
|
||||
|
@ -3247,6 +3377,8 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR
|
|||
}
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = NULL;
|
||||
quad->NumVerts = 4;
|
||||
quad->NumTris = 2;
|
||||
|
||||
verts[0].x = x;
|
||||
verts[0].y = y;
|
||||
|
@ -3300,17 +3432,19 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR
|
|||
//
|
||||
// D3DFB :: CheckQuadBatch
|
||||
//
|
||||
// Make sure there's enough room in the batch for one more quad.
|
||||
// Make sure there's enough room in the batch for one more set of triangles.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void D3DFB::CheckQuadBatch()
|
||||
void D3DFB::CheckQuadBatch(int numtris, int numverts)
|
||||
{
|
||||
if (BatchType == BATCH_Lines)
|
||||
{
|
||||
EndLineBatch();
|
||||
}
|
||||
else if (QuadBatchPos == MAX_QUAD_BATCH)
|
||||
else if (QuadBatchPos == MAX_QUAD_BATCH ||
|
||||
VertexPos + numverts > NUM_VERTS ||
|
||||
IndexPos + numtris * 3 > NUM_INDEXES)
|
||||
{
|
||||
EndQuadBatch();
|
||||
}
|
||||
|
@ -3371,23 +3505,33 @@ void D3DFB::EndQuadBatch()
|
|||
D3DDevice->SetIndices(IndexBuffer);
|
||||
bool uv_wrapped = false;
|
||||
bool uv_should_wrap;
|
||||
int indexpos, vertpos;
|
||||
|
||||
indexpos = vertpos = 0;
|
||||
for (int i = 0; i < QuadBatchPos; )
|
||||
{
|
||||
const BufferedQuad *quad = &QuadExtra[i];
|
||||
const BufferedTris *quad = &QuadExtra[i];
|
||||
int j;
|
||||
|
||||
int startindex = indexpos;
|
||||
int startvertex = vertpos;
|
||||
|
||||
indexpos += quad->NumTris * 3;
|
||||
vertpos += quad->NumVerts;
|
||||
|
||||
// Quads with matching parameters should be done with a single
|
||||
// DrawPrimitive call.
|
||||
for (j = i + 1; j < QuadBatchPos; ++j)
|
||||
{
|
||||
const BufferedQuad *q2 = &QuadExtra[j];
|
||||
const BufferedTris *q2 = &QuadExtra[j];
|
||||
if (quad->Texture != q2->Texture ||
|
||||
quad->Group1 != q2->Group1 ||
|
||||
quad->Palette != q2->Palette)
|
||||
{
|
||||
break;
|
||||
}
|
||||
indexpos += q2->NumTris * 3;
|
||||
vertpos += q2->NumVerts;
|
||||
}
|
||||
|
||||
// Set the palette (if one)
|
||||
|
@ -3467,7 +3611,12 @@ void D3DFB::EndQuadBatch()
|
|||
}
|
||||
|
||||
// Draw the quad
|
||||
D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4 * i, 4 * (j - i), 6 * i, 2 * (j - i));
|
||||
D3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0,
|
||||
startvertex, // MinIndex
|
||||
vertpos - startvertex, // NumVertices
|
||||
startindex, // StartIndex
|
||||
(indexpos - startindex) / 3 // PrimitiveCount
|
||||
/*4 * i, 4 * (j - i), 6 * i, 2 * (j - i)*/);
|
||||
i = j;
|
||||
}
|
||||
if (uv_wrapped)
|
||||
|
@ -3508,7 +3657,7 @@ void D3DFB::EndBatch()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedQuad &quad)
|
||||
bool D3DFB::SetStyle(D3DTex *tex, DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedTris &quad)
|
||||
{
|
||||
D3DFORMAT fmt = tex->GetTexFormat();
|
||||
FRenderStyle style = parms.style;
|
||||
|
|
|
@ -466,7 +466,7 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
|
|||
{
|
||||
fb->CheckQuadBatch();
|
||||
|
||||
BufferedQuad *quad = &fb->QuadExtra[fb->QuadBatchPos];
|
||||
BufferedTris *quad = &fb->QuadExtra[fb->QuadBatchPos];
|
||||
FBVERTEX *vert = &fb->VertexData[fb->VertexPos];
|
||||
WORD *index = &fb->IndexData[fb->IndexPos];
|
||||
|
||||
|
@ -475,6 +475,8 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
|
|||
quad->ShaderNum = BQS_Plain;
|
||||
quad->Palette = NULL;
|
||||
quad->Texture = fb->InitialWipeScreen;
|
||||
quad->NumVerts = 4;
|
||||
quad->NumTris = 2;
|
||||
|
||||
// Fill the vertex buffer.
|
||||
float u0 = rect.left / float(fb->FBWidth);
|
||||
|
|
|
@ -257,6 +257,9 @@ public:
|
|||
void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin);
|
||||
void DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor);
|
||||
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor);
|
||||
void FillSimplePoly(FTexture *tex, FVector2 *points, int npoints,
|
||||
double originx, double originy, double scalex, double scaley,
|
||||
angle_t rotation, FDynamicColormap *colormap, int lightlevel);
|
||||
bool WipeStartScreen(int type);
|
||||
void WipeEndScreen();
|
||||
bool WipeDo(int ticks);
|
||||
|
@ -278,7 +281,7 @@ private:
|
|||
};
|
||||
#define D3DFVF_FBVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1)
|
||||
|
||||
struct BufferedQuad
|
||||
struct BufferedTris
|
||||
{
|
||||
union
|
||||
{
|
||||
|
@ -293,6 +296,8 @@ private:
|
|||
};
|
||||
D3DPal *Palette;
|
||||
IDirect3DTexture9 *Texture;
|
||||
WORD NumVerts; // Number of _unique_ vertices used by this set.
|
||||
WORD NumTris; // Number of triangles used by this set.
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -355,12 +360,12 @@ private:
|
|||
void DrawPackedTextures(int packnum);
|
||||
void DrawLetterbox();
|
||||
void Draw3DPart(bool copy3d);
|
||||
bool SetStyle(D3DTex *tex, DCanvas::DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedQuad &quad);
|
||||
bool SetStyle(D3DTex *tex, DCanvas::DrawParms &parms, D3DCOLOR &color0, D3DCOLOR &color1, BufferedTris &quad);
|
||||
static D3DBLEND GetStyleAlpha(int type);
|
||||
static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1);
|
||||
void DoWindowedGamma();
|
||||
void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color);
|
||||
void CheckQuadBatch();
|
||||
void CheckQuadBatch(int numtris=2, int numverts=4);
|
||||
void BeginQuadBatch();
|
||||
void EndQuadBatch();
|
||||
void BeginLineBatch();
|
||||
|
@ -433,7 +438,7 @@ private:
|
|||
FBVERTEX *VertexData;
|
||||
IDirect3DIndexBuffer9 *IndexBuffer;
|
||||
WORD *IndexData;
|
||||
BufferedQuad *QuadExtra;
|
||||
BufferedTris *QuadExtra;
|
||||
int VertexPos;
|
||||
int IndexPos;
|
||||
int QuadBatchPos;
|
||||
|
|
|
@ -268,6 +268,8 @@ AMSTR_FOLLOWON = "Follow Mode ON";
|
|||
AMSTR_FOLLOWOFF = "Follow Mode OFF";
|
||||
AMSTR_GRIDON = "Grid ON";
|
||||
AMSTR_GRIDOFF = "Grid OFF";
|
||||
AMSTR_TEXON = "Texture Mode ON";
|
||||
AMSTR_TEXOFF = "Texture Mode OFF";
|
||||
AMSTR_MARKEDSPOT = "Marked Spot";
|
||||
AMSTR_MARKSCLEARED = "All Marks Cleared";
|
||||
STSTR_MUS = "Music Change";
|
||||
|
|
|
@ -804,6 +804,10 @@
|
|||
RelativePath=".\src\p_floor.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_glnodes.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\p_interaction.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue