- merged automap branch into trunk.

SVN r2609 (trunk)
This commit is contained in:
Christoph Oelckers 2010-08-27 15:20:05 +00:00
parent 9102200771
commit 9a4abe0915
47 changed files with 3497 additions and 751 deletions

View file

@ -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

View file

@ -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.

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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__

View file

@ -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[] =

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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 ()

View file

@ -116,6 +116,7 @@ typedef enum {
joy_slider,
joy_map,
joy_inverter,
mapcontrol,
} itemtype;
struct IJoystickConfig;

View file

@ -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)
{

View file

@ -442,6 +442,7 @@ xx(nofakecontrast)
xx(smoothlighting)
xx(blockprojectiles)
xx(blockuse)
xx(hidden)
xx(Renderstyle)

View file

@ -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);

View file

@ -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);
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;
}
//

View file

@ -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
{

View file

@ -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)

View file

@ -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;
}
}
}
}
}
}

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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

View file

@ -1227,6 +1227,10 @@ public:
sec->seqType = -1;
continue;
case NAME_hidden:
sec->MoreFlags |= SECF_HIDDEN;
break;
default:
break;
}

View file

@ -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];

View file

@ -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;
}
}
//

View file

@ -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;
};

View file

@ -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
}
//

View file

@ -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);

View file

@ -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;

View file

@ -110,5 +110,4 @@ bool R_PlaneInitData (void);
extern visplane_t* floorplane;
extern visplane_t* ceilingplane;
#endif // __R_PLANE_H__

View file

@ -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);
}

View file

@ -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;

View file

@ -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 */

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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";

View file

@ -804,6 +804,10 @@
RelativePath=".\src\p_floor.cpp"
>
</File>
<File
RelativePath=".\src\p_glnodes.cpp"
>
</File>
<File
RelativePath=".\src\p_interaction.cpp"
>