- Update to ZDoom r2613

* addition of textured automap. (not active for GL renderer yet!)



git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@909 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
Christoph Oelckers 2010-08-27 17:42:01 +00:00
parent 2934a611c9
commit af753ebe37
58 changed files with 2040 additions and 2253 deletions

View file

@ -804,6 +804,10 @@
RelativePath=".\src\p_floor.cpp" RelativePath=".\src\p_floor.cpp"
> >
</File> </File>
<File
RelativePath=".\src\p_glnodes.cpp"
>
</File>
<File <File
RelativePath=".\src\p_interaction.cpp" RelativePath=".\src\p_interaction.cpp"
> >
@ -6541,6 +6545,10 @@
<Filter <Filter
Name="GL Renderer" Name="GL Renderer"
> >
<File
RelativePath=".\src\gl\gl_functions.h"
>
</File>
<Filter <Filter
Name="System" Name="System"
> >
@ -6864,10 +6872,6 @@
RelativePath=".\src\gl\data\gl_data.h" RelativePath=".\src\gl\data\gl_data.h"
> >
</File> </File>
<File
RelativePath=".\src\gl\data\gl_nodes.cpp"
>
</File>
<File <File
RelativePath=".\src\gl\data\gl_portaldata.cpp" RelativePath=".\src\gl\data\gl_portaldata.cpp"
> >

View file

@ -697,6 +697,7 @@ add_executable( zdoom WIN32
p_effect.cpp p_effect.cpp
p_enemy.cpp p_enemy.cpp
p_floor.cpp p_floor.cpp
p_glnodes.cpp
p_interaction.cpp p_interaction.cpp
p_lights.cpp p_lights.cpp
p_linkedsectors.cpp p_linkedsectors.cpp

View file

@ -774,6 +774,7 @@ public:
fixed_t pitch, roll; fixed_t pitch, roll;
FBlockNode *BlockNode; // links in blocks (if needed) FBlockNode *BlockNode; // links in blocks (if needed)
struct sector_t *Sector; struct sector_t *Sector;
subsector_t * subsector;
fixed_t floorz, ceilingz; // closest together of contacted secs fixed_t floorz, ceilingz; // closest together of contacted secs
fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors. fixed_t dropoffz; // killough 11/98: the lowest floor over all contacted Sectors.
@ -948,13 +949,11 @@ public:
return GetClass()->ActorInfo->FindState(2, names, exact); return GetClass()->ActorInfo->FindState(2, names, exact);
} }
bool HasSpecialDeathStates () const; bool HasSpecialDeathStates () const;
TArray<TObjPtr<AActor> > dynamiclights; TArray<TObjPtr<AActor> > dynamiclights;
void * lightassociations; void * lightassociations;
bool hasmodel; bool hasmodel;
subsector_t * subsector;
size_t PropagateMark(); size_t PropagateMark();
}; };

View file

@ -36,6 +36,9 @@
#include "r_translate.h" #include "r_translate.h"
#include "d_event.h" #include "d_event.h"
#include "gi.h" #include "gi.h"
#include "r_bsp.h"
#include "p_setup.h"
#include "c_bind.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "i_system.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); 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); 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 #define AM_NUMMARKPOINTS 10
// player radius for automap checking // 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 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 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_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) 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_rotatePoint (fixed_t *x, fixed_t *y);
void AM_rotate (fixed_t *x, fixed_t *y, angle_t an); void AM_rotate (fixed_t *x, fixed_t *y, angle_t an);
void AM_doFollowPlayer (); 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 // 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 // segment in map coordinates (with the upright y-axis n' all) so
@ -775,11 +832,19 @@ void AM_initVariables ()
automapactive = true; 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; f_oldloc.x = FIXED_MAX;
amclock = 0; amclock = 0;
m_paninc.x = m_paninc.y = 0; m_paninc.x = m_paninc.y = 0;
ftom_zoommul = MAPUNIT;
mtof_zoommul = MAPUNIT; mtof_zoommul = MAPUNIT;
m_w = FTOM(SCREENWIDTH); 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; if (automapactive && (ev->type == EV_KeyDown || ev->type == EV_KeyUp))
static int cheatstate = 0;
static int bigstate = 0;
rc = false;
if (automapactive && ev->type == EV_KeyDown)
{ {
rc = true; if (followplayer)
switch (ev->data1)
{ {
case AM_PANRIGHTKEY: // pan right // check for am_pan* and ignore in follow mode
if (!followplayer) const char *defbind = AutomapBindings.GetBind(ev->data1);
m_paninc.x = FTOM(F_PANINC); if (!strnicmp(defbind, "+am_pan", 7)) return false;
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;
}
} }
}
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 () 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 // Change the scaling multipliers
scale_mtof = MapMul(scale_mtof, mtof_zoommul); scale_mtof = MapMul(scale_mtof, mtof_zoommul);
scale_ftom = MapDiv(MAPUNIT, scale_mtof); 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 // Updates on Game Tick
@ -1361,10 +1319,20 @@ void AM_Ticker ()
amclock++; amclock++;
if (followplayer) if (followplayer)
{
AM_doFollowPlayer(); 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 // Change the zoom if necessary
if (ftom_zoommul != MAPUNIT) if (Button_AM_ZoomIn.bDown || Button_AM_ZoomOut.bDown)
AM_changeWindowScale(); AM_changeWindowScale();
// Change x,y location // 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) 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, // Use more correct info if we have GL nodes available
flip, mark->scaleX, mark->scaleY, mark->Translation, INTBOOL drawn = hasglnodes?
mark->alpha, mark->fillcolor, mark->RenderStyle); 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; marked = mark->args[0] != 0 ? it.Next() : NULL;
} }
@ -2291,6 +2353,9 @@ void AM_Drawer ()
} }
AM_activateNewScale(); AM_activateNewScale();
if (am_textured && hasglnodes && textured)
AM_drawSubsectors();
if (grid) if (grid)
AM_drawGrid(GridColor); AM_drawGrid(GridColor);

View file

@ -26,7 +26,7 @@ struct event_t;
class FArchive; class FArchive;
// Called by main loop. // Called by main loop.
bool AM_Responder (event_t* ev); bool AM_Responder (event_t* ev, bool last);
// Called by main loop. // Called by main loop.
void AM_Ticker (void); void AM_Ticker (void);

View file

@ -309,6 +309,8 @@ GLOBAL R_DrawSpanP_ASM
; edi: dest ; edi: dest
; ebp: scratch ; ebp: scratch
; esi: count ; esi: count
; [esp]: xstep
; [esp+4]: ystep
align 16 align 16
@ -324,6 +326,7 @@ R_DrawSpanP_ASM:
push edi push edi
push ebp push ebp
push esi push esi
sub esp, 8
mov edi,ecx mov edi,ecx
add edi,[dc_destorg] add edi,[dc_destorg]
@ -335,13 +338,13 @@ dsy1: shl edx,6
dsy3: shr ebp,26 dsy3: shr ebp,26
xor ebx,ebx xor ebx,ebx
lea esi,[eax+1] lea esi,[eax+1]
mov [ds_xstep],edx mov [esp],edx
mov edx,[ds_ystep] mov edx,[ds_ystep]
mov ecx,[ds_xfrac] mov ecx,[ds_xfrac]
dsy4: shr ecx,26 dsy4: shr ecx,26
dsm8: and edx,0xffffffc0 dsm8: and edx,0xffffffc0
or ebp,edx or ebp,edx
mov [ds_ystep],ebp mov [esp+4],ebp
mov ebp,[ds_yfrac] mov ebp,[ds_yfrac]
mov edx,[ds_xfrac] mov edx,[ds_xfrac]
dsy2: shl edx,6 dsy2: shl edx,6
@ -355,8 +358,8 @@ dsm9: and ebp,0xffffffc0
mov ebp,ecx mov ebp,ecx
dsx1: rol ebp,6 dsx1: rol ebp,6
dsm1: and ebp,0xfff dsm1: and ebp,0xfff
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
spreada mov bl,[ebp+SPACEFILLER4] spreada mov bl,[ebp+SPACEFILLER4]
spmapa mov bl,[ebx+SPACEFILLER4] spmapa mov bl,[ebx+SPACEFILLER4]
mov [edi],bl mov [edi],bl
@ -367,13 +370,13 @@ dseven1 shr esi,1
; do two more pixels ; do two more pixels
mov ebp,ecx mov ebp,ecx
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
dsm2: and ebp,0xfc00003f dsm2: and ebp,0xfc00003f
dsx2: rol ebp,6 dsx2: rol ebp,6
mov eax,ecx mov eax,ecx
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
spreadb mov bl,[ebp+SPACEFILLER4] ;read texel1 spreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
dsx3: rol eax,6 dsx3: rol eax,6
dsm6: and eax,0xfff dsm6: and eax,0xfff
@ -392,13 +395,13 @@ dsrest test esi,esi
align 16 align 16
dsloop mov ebp,ecx dsloop mov ebp,ecx
spstep1d add edx,[ds_xstep] spstep1d add edx,[esp]
spstep2d adc ecx,[ds_ystep] spstep2d adc ecx,[esp+4]
dsm3: and ebp,0xfc00003f dsm3: and ebp,0xfc00003f
dsx4: rol ebp,6 dsx4: rol ebp,6
mov eax,ecx mov eax,ecx
spstep1e add edx,[ds_xstep] spstep1e add edx,[esp]
spstep2e adc ecx,[ds_ystep] spstep2e adc ecx,[esp+4]
spreadd mov bl,[ebp+SPACEFILLER4] ;read texel1 spreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
dsx5: rol eax,6 dsx5: rol eax,6
dsm5: and eax,0xfff dsm5: and eax,0xfff
@ -406,8 +409,8 @@ spmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
mov [edi],bl ;store texel1 mov [edi],bl ;store texel1
mov ebp,ecx mov ebp,ecx
spreade mov bl,[eax+SPACEFILLER4] ;read texel2 spreade mov bl,[eax+SPACEFILLER4] ;read texel2
spstep1f add edx,[ds_xstep] spstep1f add edx,[esp]
spstep2f adc ecx,[ds_ystep] spstep2f adc ecx,[esp+4]
dsm4: and ebp,0xfc00003f dsm4: and ebp,0xfc00003f
dsx6: rol ebp,6 dsx6: rol ebp,6
spmape mov bl,[ebx+SPACEFILLER4] ;map texel2 spmape mov bl,[ebx+SPACEFILLER4] ;map texel2
@ -420,14 +423,15 @@ dsx7: rol eax,6
dsm7: and eax,0xfff dsm7: and eax,0xfff
mov [edi-2],bl ;store texel3 mov [edi-2],bl ;store texel3
spreadg mov bl,[eax+SPACEFILLER4] ;read texel4 spreadg mov bl,[eax+SPACEFILLER4] ;read texel4
spstep1g add edx,[ds_xstep] spstep1g add edx,[esp]
spstep2g adc ecx,[ds_ystep] spstep2g adc ecx,[esp+4]
spmapg mov bl,[ebx+SPACEFILLER4] ;map texel4 spmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
dec esi dec esi
mov [edi-1],bl ;store texel4 mov [edi-1],bl ;store texel4
jnz near dsloop jnz near dsloop
dsdone pop esi dsdone add esp,8
pop esi
pop ebp pop ebp
pop edi pop edi
pop ebx pop ebx
@ -448,6 +452,8 @@ GLOBAL R_DrawSpanMaskedP_ASM
; edi: dest ; edi: dest
; ebp: scratch ; ebp: scratch
; esi: count ; esi: count
; [esp]: xstep
; [esp+4]: ystep
align 16 align 16
@ -463,6 +469,7 @@ R_DrawSpanMaskedP_ASM:
push edi push edi
push ebp push ebp
push esi push esi
sub esp,8
mov edi,ecx mov edi,ecx
add edi,[dc_destorg] add edi,[dc_destorg]
@ -474,13 +481,13 @@ dmsy1: shl edx,6
dmsy3: shr ebp,26 dmsy3: shr ebp,26
xor ebx,ebx xor ebx,ebx
lea esi,[eax+1] lea esi,[eax+1]
mov [ds_xstep],edx mov [esp],edx
mov edx,[ds_ystep] mov edx,[ds_ystep]
mov ecx,[ds_xfrac] mov ecx,[ds_xfrac]
dmsy4: shr ecx,26 dmsy4: shr ecx,26
dmsm8: and edx,0xffffffc0 dmsm8: and edx,0xffffffc0
or ebp,edx or ebp,edx
mov [ds_ystep],ebp mov [esp+4],ebp
mov ebp,[ds_yfrac] mov ebp,[ds_yfrac]
mov edx,[ds_xfrac] mov edx,[ds_xfrac]
dmsy2: shl edx,6 dmsy2: shl edx,6
@ -494,8 +501,8 @@ dmsm9: and ebp,0xffffffc0
mov ebp,ecx mov ebp,ecx
dmsx1: rol ebp,6 dmsx1: rol ebp,6
dmsm1: and ebp,0xfff dmsm1: and ebp,0xfff
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
mspreada mov bl,[ebp+SPACEFILLER4] mspreada mov bl,[ebp+SPACEFILLER4]
cmp bl,0 cmp bl,0
je mspskipa je mspskipa
@ -508,13 +515,13 @@ dmseven1 shr esi,1
; do two more pixels ; do two more pixels
mov ebp,ecx mov ebp,ecx
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
dmsm2: and ebp,0xfc00003f dmsm2: and ebp,0xfc00003f
dmsx2: rol ebp,6 dmsx2: rol ebp,6
mov eax,ecx mov eax,ecx
add edx,[ds_xstep] add edx,[esp]
adc ecx,[ds_ystep] adc ecx,[esp+4]
mspreadb mov bl,[ebp+SPACEFILLER4] ;read texel1 mspreadb mov bl,[ebp+SPACEFILLER4] ;read texel1
dmsx3: rol eax,6 dmsx3: rol eax,6
dmsm6: and eax,0xfff dmsm6: and eax,0xfff
@ -537,13 +544,13 @@ dmsrest test esi,esi
align 16 align 16
dmsloop mov ebp,ecx dmsloop mov ebp,ecx
mspstep1d add edx,[ds_xstep] mspstep1d add edx,[esp]
mspstep2d adc ecx,[ds_ystep] mspstep2d adc ecx,[esp+4]
dmsm3: and ebp,0xfc00003f dmsm3: and ebp,0xfc00003f
dmsx4: rol ebp,6 dmsx4: rol ebp,6
mov eax,ecx mov eax,ecx
mspstep1e add edx,[ds_xstep] mspstep1e add edx,[esp]
mspstep2e adc ecx,[ds_ystep] mspstep2e adc ecx,[esp+4]
mspreadd mov bl,[ebp+SPACEFILLER4] ;read texel1 mspreadd mov bl,[ebp+SPACEFILLER4] ;read texel1
dmsx5: rol eax,6 dmsx5: rol eax,6
dmsm5: and eax,0xfff dmsm5: and eax,0xfff
@ -553,8 +560,8 @@ dmsm5: and eax,0xfff
mspmapd mov bl,[ebx+SPACEFILLER4] ;map texel1 mspmapd mov bl,[ebx+SPACEFILLER4] ;map texel1
mov [edi],bl ;store texel1 mov [edi],bl ;store texel1
mspreade mov bl,[eax+SPACEFILLER4] ;read texel2 mspreade mov bl,[eax+SPACEFILLER4] ;read texel2
mspstep1f add edx,[ds_xstep] mspstep1f add edx,[esp]
mspstep2f adc ecx,[ds_ystep] mspstep2f adc ecx,[esp+4]
dmsm4: and ebp,0xfc00003f dmsm4: and ebp,0xfc00003f
dmsx6: rol ebp,6 dmsx6: rol ebp,6
cmp bl,0 cmp bl,0
@ -571,8 +578,8 @@ dmsm7: and eax,0xfff
mspmapf mov bl,[ebx+SPACEFILLER4] ;map texel3 mspmapf mov bl,[ebx+SPACEFILLER4] ;map texel3
mov [edi-2],bl ;store texel3 mov [edi-2],bl ;store texel3
mspreadg mov bl,[eax+SPACEFILLER4] ;read texel4 mspreadg mov bl,[eax+SPACEFILLER4] ;read texel4
mspstep1g add edx,[ds_xstep] mspstep1g add edx,[esp]
mspstep2g adc ecx,[ds_ystep] mspstep2g adc ecx,[esp+4]
cmp bl,0 cmp bl,0
je mspskipg je mspskipg
mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4 mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
@ -580,7 +587,8 @@ mspmapg mov bl,[ebx+SPACEFILLER4] ;map texel4
mspskipg dec esi mspskipg dec esi
jnz near dmsloop jnz near dmsloop
dmsdone pop esi dmsdone add esp,8
pop esi
pop ebp pop ebp
pop edi pop edi
pop ebx pop ebx

View file

@ -47,12 +47,6 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
struct FBinding
{
const char *Key;
const char *Bind;
};
/* Default keybindings for Doom (and all other games) /* Default keybindings for Doom (and all other games)
*/ */
static const FBinding DefBindings[] = static const FBinding DefBindings[] =
@ -178,6 +172,27 @@ static const FBinding DefStrifeBindings[] =
// h - use health // 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] = const char *KeyNames[NUM_KEYS] =
{ {
// This array is dependant on the particular keyboard input // 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" "pad_a", "pad_b", "pad_x", "pad_y"
}; };
static FString Bindings[NUM_KEYS]; FKeyBindings Bindings;
static FString DoubleBindings[NUM_KEYS]; FKeyBindings DoubleBindings;
FKeyBindings AutomapBindings;
static unsigned int DClickTime[NUM_KEYS]; static unsigned int DClickTime[NUM_KEYS];
static BYTE DClicked[(NUM_KEYS+7)/8]; static BYTE DClicked[(NUM_KEYS+7)/8];
//=============================================================================
//
//
//
//=============================================================================
static int GetKeyFromName (const char *name) static int GetKeyFromName (const char *name)
{ {
int i; int i;
@ -302,380 +325,15 @@ static int GetKeyFromName (const char *name)
return 0; 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) int keynum = GetKeyFromName(key);
{
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);
if (keynum == 0) if (keynum == 0)
{ {
if (stricmp (key, "LeftBracket") == 0) if (stricmp (key, "LeftBracket") == 0)
@ -695,32 +353,55 @@ void C_DoBind (const char *key, const char *bind, bool dodouble)
keynum = GetKeyFromName ("kp="); keynum = GetKeyFromName ("kp=");
} }
} }
if (keynum != 0) return keynum;
{
(dodouble ? DoubleBindings : Bindings)[keynum] = bind;
}
} }
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) mysnprintf (name, countof(name), "#%d", key);
{ return name;
if (stricmp (cmd, Bindings[i]) == 0)
{
if (c++ == 0)
*first = i;
else
*second = i;
}
i++;
}
return c;
} }
//=============================================================================
//
//
//
//=============================================================================
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) void C_NameKeys (char *str, int first, int second)
{ {
int c = 0; int c = 0;
@ -744,28 +425,471 @@ void C_NameKeys (char *str, int first, int second)
*str = '\0'; *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; int i;
for (i = 0; i < NUM_KEYS; 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__ #ifndef __C_BINDINGS_H__
#define __C_BINDINGS_H__ #define __C_BINDINGS_H__
#include "doomdef.h"
struct event_t; struct event_t;
class FConfigFile; class FConfigFile;
class FCommandLine;
bool C_DoKey (event_t *ev); void C_NameKeys (char *str, int first, int second);
void C_ArchiveBindings (FConfigFile *f, bool dodouble, const char *matchcmd=NULL);
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 // 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_SetDefaultBindings ();
void C_UnbindAll (); void C_UnbindAll ();
// Returns string bound to given key (NULL if none)
const char *C_GetBinding (int key);
extern const char *KeyNames[]; extern const char *KeyNames[];
#endif //__C_BINDINGS_H__ #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_Forward, Button_Right, Button_Left, Button_MoveDown,
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
Button_Zoom, Button_Reload, 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; bool ParsingKeyConf;
@ -131,13 +133,16 @@ bool ParsingKeyConf;
FActionMap ActionMaps[] = FActionMap ActionMaps[] =
{ {
{ 0x0d52d67b, &Button_AM_PanLeft, "am_panleft"},
{ 0x125f5226, &Button_User2, "user2" }, { 0x125f5226, &Button_User2, "user2" },
{ 0x1eefa611, &Button_Jump, "jump" }, { 0x1eefa611, &Button_Jump, "jump" },
{ 0x201f1c55, &Button_Right, "right" }, { 0x201f1c55, &Button_Right, "right" },
{ 0x20ccc4d5, &Button_Zoom, "zoom" }, { 0x20ccc4d5, &Button_Zoom, "zoom" },
{ 0x23a99cd7, &Button_Back, "back" }, { 0x23a99cd7, &Button_Back, "back" },
{ 0x41df90c2, &Button_AM_ZoomIn, "am_zoomin"},
{ 0x426b69e7, &Button_Reload, "reload" }, { 0x426b69e7, &Button_Reload, "reload" },
{ 0x4463f43a, &Button_LookDown, "lookdown" }, { 0x4463f43a, &Button_LookDown, "lookdown" },
{ 0x51f7a334, &Button_AM_ZoomOut, "am_zoomout"},
{ 0x534c30ee, &Button_User4, "user4" }, { 0x534c30ee, &Button_User4, "user4" },
{ 0x5622bf42, &Button_Attack, "attack" }, { 0x5622bf42, &Button_Attack, "attack" },
{ 0x577712d0, &Button_User1, "user1" }, { 0x577712d0, &Button_User1, "user1" },
@ -147,12 +152,15 @@ FActionMap ActionMaps[] =
{ 0x676885b8, &Button_AltAttack, "altattack" }, { 0x676885b8, &Button_AltAttack, "altattack" },
{ 0x6fa41b84, &Button_MoveLeft, "moveleft" }, { 0x6fa41b84, &Button_MoveLeft, "moveleft" },
{ 0x818f08e6, &Button_MoveRight, "moveright" }, { 0x818f08e6, &Button_MoveRight, "moveright" },
{ 0x8197097b, &Button_AM_PanRight, "am_panright"},
{ 0x8d89955e, &Button_AM_PanUp, "am_panup"} ,
{ 0xa2b62d8b, &Button_Mlook, "mlook" }, { 0xa2b62d8b, &Button_Mlook, "mlook" },
{ 0xab2c3e71, &Button_Crouch, "crouch" }, { 0xab2c3e71, &Button_Crouch, "crouch" },
{ 0xb000b483, &Button_Left, "left" }, { 0xb000b483, &Button_Left, "left" },
{ 0xb62b1e49, &Button_LookUp, "lookup" }, { 0xb62b1e49, &Button_LookUp, "lookup" },
{ 0xb6f8fe92, &Button_User3, "user3" }, { 0xb6f8fe92, &Button_User3, "user3" },
{ 0xb7e6a54b, &Button_Strafe, "strafe" }, { 0xb7e6a54b, &Button_Strafe, "strafe" },
{ 0xce301c81, &Button_AM_PanDown, "am_pandown"},
{ 0xd5897c73, &Button_ShowScores, "showscores" }, { 0xd5897c73, &Button_ShowScores, "showscores" },
{ 0xe0ccb317, &Button_Speed, "speed" }, { 0xe0ccb317, &Button_Speed, "speed" },
{ 0xe0cfc260, &Button_Use, "use" }, { 0xe0cfc260, &Button_Use, "use" },
@ -160,6 +168,7 @@ FActionMap ActionMaps[] =
}; };
#define NUM_ACTIONS countof(ActionMaps) #define NUM_ACTIONS countof(ActionMaps)
// PRIVATE DATA DEFINITIONS ------------------------------------------------ // PRIVATE DATA DEFINITIONS ------------------------------------------------
static const char *KeyConfCommands[] = 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 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. bool ReleaseKey (int keynum); // Returns true if this key is no longer pressed.
void ResetTriggers () { bWentDown = bWentUp = false; } void ResetTriggers () { bWentDown = bWentUp = false; }
void Reset () { bDown = bWentDown = bWentUp = false; }
}; };
extern FButtonStatus Button_Mlook, Button_Klook, Button_Use, Button_AltAttack, 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_Forward, Button_Right, Button_Left, Button_MoveDown,
Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch, Button_MoveUp, Button_Jump, Button_ShowScores, Button_Crouch,
Button_Zoom, Button_Reload, 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; extern bool ParsingKeyConf;
void ResetButtonTriggers (); // Call ResetTriggers for all buttons void ResetButtonTriggers (); // Call ResetTriggers for all buttons

View file

@ -2,10 +2,14 @@
#ifdef _WIN32 #ifdef _WIN32
#include <direct.h> #include <direct.h>
#include <io.h>
#else #else
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <pwd.h> #include <pwd.h>
#if !defined(__sun)
#include <fts.h>
#endif
#endif #endif
#include "doomtype.h" #include "doomtype.h"
#include "cmdlib.h" #include "cmdlib.h"
@ -885,3 +889,153 @@ FString NicePath(const char *path)
return where; return where;
#endif #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 ExpandEnvVars(const char *searchpathstring);
FString NicePath(const char *path); FString NicePath(const char *path);
struct FFileList
{
FString Filename;
bool isDirectory;
};
void ScanDirectory(TArray<FFileList> &list, const char *dirpath);
#endif #endif

View file

@ -2294,6 +2294,14 @@ void FStartupScreen::AppendStatusLine(const char *status)
// //
//========================================================================== //==========================================================================
//==========================================================================
//
// STAT fps
//
// Displays statistics about rendering times
//
//==========================================================================
ADD_STAT (fps) ADD_STAT (fps)
{ {
FString out; FString out;
@ -2302,6 +2310,24 @@ ADD_STAT (fps)
return out; 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 // STAT wallcycles

View file

@ -723,7 +723,7 @@ bool F_CastResponder (event_t* ev)
if (ev->type != EV_KeyDown) if (ev->type != EV_KeyDown)
return false; return false;
const char *cmd = C_GetBinding (ev->data1); const char *cmd = Bindings.GetBind (ev->data1);
if (cmd != NULL && !stricmp (cmd, "toggleconsole")) if (cmd != NULL && !stricmp (cmd, "toggleconsole"))
return false; return false;

View file

@ -879,7 +879,7 @@ bool G_Responder (event_t *ev)
if (gameaction == ga_nothing && if (gameaction == ga_nothing &&
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL)) (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) if (ev->type == EV_KeyDown)
{ {
@ -902,11 +902,11 @@ bool G_Responder (event_t *ev)
} }
else else
{ {
return C_DoKey (ev); return C_DoKey (ev, &Bindings, &DoubleBindings);
} }
} }
if (cmd && cmd[0] == '+') if (cmd && cmd[0] == '+')
return C_DoKey (ev); return C_DoKey (ev, &Bindings, &DoubleBindings);
return false; return false;
} }
@ -918,7 +918,7 @@ bool G_Responder (event_t *ev)
{ {
if (ST_Responder (ev)) if (ST_Responder (ev))
return true; // status window ate it return true; // status window ate it
if (!viewactive && AM_Responder (ev)) if (!viewactive && AM_Responder (ev, false))
return true; // automap ate it return true; // automap ate it
} }
else if (gamestate == GS_FINALE) else if (gamestate == GS_FINALE)
@ -930,12 +930,12 @@ bool G_Responder (event_t *ev)
switch (ev->type) switch (ev->type)
{ {
case EV_KeyDown: case EV_KeyDown:
if (C_DoKey (ev)) if (C_DoKey (ev, &Bindings, &DoubleBindings))
return true; return true;
break; break;
case EV_KeyUp: case EV_KeyUp:
C_DoKey (ev); C_DoKey (ev, &Bindings, &DoubleBindings);
break; break;
// [RH] mouse buttons are sent as key up/down events // [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. // the events *last* so that any bound keys get precedence.
if (gamestate == GS_LEVEL && viewactive) if (gamestate == GS_LEVEL && viewactive)
return AM_Responder (ev); return AM_Responder (ev, true);
return (ev->type == EV_KeyDown || return (ev->type == EV_KeyDown ||
ev->type == EV_Mouse); ev->type == EV_Mouse);

View file

@ -1464,8 +1464,8 @@ void G_SerializeLevel (FArchive &arc, bool hubLoad)
P_SerializeThinkers (arc, hubLoad); P_SerializeThinkers (arc, hubLoad);
P_SerializeWorld (arc); P_SerializeWorld (arc);
P_SerializePolyobjs (arc); P_SerializePolyobjs (arc);
P_SerializeSubsectors(arc);
StatusBar->Serialize (arc); StatusBar->Serialize (arc);
//SerializeInterpolations (arc);
arc << level.total_monsters << level.total_items << level.total_secrets; arc << level.total_monsters << level.total_items << level.total_secrets;

View file

@ -399,29 +399,38 @@ void FGameConfigFile::DoGameSetup (const char *gamename)
ReadCVars (0); ReadCVars (0);
} }
strncpy (subsection, "Bindings", sublen); if (!bMigrating)
if (!SetSection (section))
{ // Config has no bindings for the given game
if (!bMigrating)
{
C_SetDefaultBindings ();
}
}
else
{ {
C_UnbindAll (); C_SetDefaultBindings ();
}
strncpy (subsection, "Bindings", sublen);
if (SetSection (section))
{
Bindings.UnbindAll();
while (NextInSection (key, value)) while (NextInSection (key, value))
{ {
C_DoBind (key, value, false); Bindings.DoBind (key, value);
} }
} }
strncpy (subsection, "DoubleBindings", sublen); strncpy (subsection, "DoubleBindings", sublen);
if (SetSection (section)) if (SetSection (section))
{ {
DoubleBindings.UnbindAll();
while (NextInSection (key, value)) 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"); strcpy (subsection, "Bindings");
SetSection (section, true); SetSection (section, true);
C_ArchiveBindings (this, false); Bindings.ArchiveBindings (this);
strncpy (subsection, "DoubleBindings", sublen); strncpy (subsection, "DoubleBindings", sublen);
SetSection (section, true); SetSection (section, true);
C_ArchiveBindings (this, true); DoubleBindings.ArchiveBindings (this);
strncpy (subsection, "AutomapBindings", sublen);
SetSection (section, true);
AutomapBindings.ArchiveBindings (this);
} }
void FGameConfigFile::ArchiveGlobalData () void FGameConfigFile::ArchiveGlobalData ()

File diff suppressed because it is too large Load diff

View file

@ -51,6 +51,7 @@
#include "sc_man.h" #include "sc_man.h"
#include "w_wad.h" #include "w_wad.h"
#include "gi.h" #include "gi.h"
#include "p_setup.h"
#include "g_level.h" #include "g_level.h"
#include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_renderer.h"
@ -108,91 +109,28 @@ static void SpreadHackedFlag(subsector_t * sub)
} }
static bool PointOnLine (int x, int y, int x1, int y1, int dx, int dy)
{
const double SIDE_EPSILON = 6.5536;
// For most cases, a simple dot product is enough.
double d_dx = double(dx);
double d_dy = double(dy);
double d_x = double(x);
double d_y = double(y);
double d_x1 = double(x1);
double d_y1 = double(y1);
double s_num = (d_y1-d_y)*d_dx - (d_x1-d_x)*d_dy;
if (fabs(s_num) < 17179869184.0) // 4<<32
{
// Either the point is very near the line, or the segment defining
// the line is very short: Do a more expensive test to determine
// just how far from the line the point is.
double l = sqrt(d_dx*d_dx+d_dy*d_dy);
double dist = fabs(s_num)/l;
if (dist < SIDE_EPSILON)
{
return true;
}
}
return false;
}
static void PrepareSectorData() static void PrepareSectorData()
{ {
int i; int i;
DWORD j;
size_t /*ii,*/ jj; size_t /*ii,*/ jj;
TArray<subsector_t *> undetermined; TArray<subsector_t *> undetermined;
subsector_t * ss; subsector_t * ss;
// The GL node builder produces screwed output when two-sided walls overlap with one-sides ones! // Account for ZDoom space optimizations that cannot be done for GL
for(i=0;i<numsegs;i++) for(i=0;i<numsegs;i++)
{ {
int partner= int(segs[i].PartnerSeg-segs); unsigned int partner= glsegextras[i].PartnerSeg;
if (partner < numsegs) segs[i].PartnerSeg = &segs[partner];
if (partner<0 || partner>=numsegs || &segs[partner]!=segs[i].PartnerSeg) else segs[i].PartnerSeg = NULL;
{ segs[i].Subsector = glsegextras[i].Subsector;
segs[i].PartnerSeg=NULL;
}
// glbsp creates such incorrect references for Strife.
if (segs[i].linedef && segs[i].PartnerSeg && !segs[i].PartnerSeg->linedef)
{
segs[i].PartnerSeg = segs[i].PartnerSeg->PartnerSeg = NULL;
}
}
for(i=0;i<numsegs;i++)
{
if (segs[i].PartnerSeg && segs[i].PartnerSeg->PartnerSeg!=&segs[i])
{
//Printf("Warning: seg %d (sector %d)'s partner seg is incorrect!\n", i, segs[i].frontsector-sectors);
segs[i].PartnerSeg=NULL;
}
} }
// look up sector number for each subsector // look up sector number for each subsector
for (i = 0; i < numsubsectors; i++) for (i = 0; i < numsubsectors; i++)
{ {
// For rendering pick the sector from the first seg that is a sector boundary
// this takes care of self-referencing sectors
ss = &subsectors[i]; ss = &subsectors[i];
seg_t *seg = ss->firstline; seg_t *seg = ss->firstline;
// Check for one-dimensional subsectors. These aren't rendered and should not be
// subject to filling areas with bleeding flats
ss->degenerate=true;
for(jj=2; jj<ss->numlines; jj++)
{
if (!PointOnLine(seg[jj].v1->x, seg[jj].v1->y, seg->v1->x, seg->v1->y, seg->v2->x-seg->v1->x, seg->v2->y-seg->v1->y))
{
// Not on the same line
ss->degenerate=false;
break;
}
}
seg = ss->firstline;
M_ClearBox(ss->bbox); M_ClearBox(ss->bbox);
for(jj=0; jj<ss->numlines; jj++) for(jj=0; jj<ss->numlines; jj++)
{ {
@ -200,59 +138,6 @@ static void PrepareSectorData()
seg->Subsector = ss; seg->Subsector = ss;
seg++; seg++;
} }
seg = ss->firstline;
for(j=0; j<ss->numlines; j++)
{
if(seg->sidedef && (!seg->PartnerSeg || seg->sidedef->sector!=seg->PartnerSeg->sidedef->sector))
{
ss->render_sector = seg->sidedef->sector;
break;
}
seg++;
}
if(ss->render_sector == NULL)
{
undetermined.Push(ss);
}
}
// assign a vaild render sector to all subsectors which haven't been processed yet.
while (undetermined.Size())
{
bool deleted=false;
for(i=undetermined.Size()-1;i>=0;i--)
{
ss=undetermined[i];
seg_t * seg = ss->firstline;
for(j=0; j<ss->numlines; j++)
{
if (seg->PartnerSeg && seg->PartnerSeg->Subsector)
{
sector_t * backsec = seg->PartnerSeg->Subsector->render_sector;
if (backsec)
{
ss->render_sector=backsec;
undetermined.Delete(i);
deleted=1;
break;
}
}
seg++;
}
}
if (!deleted && undetermined.Size())
{
// This only happens when a subsector is off the map.
// Don't bother and just assign the real sector for rendering
for(i=undetermined.Size()-1;i>=0;i--)
{
ss=undetermined[i];
ss->render_sector=ss->sector;
}
break;
}
} }
// now group the subsectors by sector // now group the subsectors by sector
@ -708,28 +593,6 @@ void gl_PreprocessLevel()
gl_InitData(); gl_InitData();
} }
// Nasty: I can't rely upon the sidedef assignments because older ZDBSPs liked to screw them up
// if the sidedefs are compressed and both sides are the same.
for(i=0;i<numsegs;i++)
{
seg_t * seg=&segs[i];
if (seg->backsector == seg->frontsector && seg->linedef)
{
fixed_t d1=P_AproxDistance(seg->v1->x-seg->linedef->v1->x,seg->v1->y-seg->linedef->v1->y);
fixed_t d2=P_AproxDistance(seg->v2->x-seg->linedef->v1->x,seg->v2->y-seg->linedef->v1->y);
if (d2<d1) // backside
{
seg->sidedef = seg->linedef->sidedef[1];
}
else // front side
{
seg->sidedef = seg->linedef->sidedef[0];
}
}
}
PrepareSegs(); PrepareSegs();
PrepareSectorData(); PrepareSectorData();
InitVertexData(); InitVertexData();

View file

@ -4,20 +4,6 @@
#include "v_palette.h" #include "v_palette.h"
class AActor; class AActor;
struct MapData;
struct node_t;
struct subsector_t;
// These are the original nodes that are preserved because
// P_PointInSubsector should use the original data if possible.
extern node_t * gamenodes;
extern int numgamenodes;
extern subsector_t * gamesubsectors;
extern int numgamesubsectors;
// External entry points for the GL renderer // External entry points for the GL renderer
void gl_PreprocessLevel(); void gl_PreprocessLevel();
@ -28,8 +14,6 @@ void gl_DeleteAllAttachedLights();
void gl_RecreateAllAttachedLights(); void gl_RecreateAllAttachedLights();
void gl_ParseDefs(); void gl_ParseDefs();
void gl_SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog); void gl_SetFogParams(int _fogdensity, PalEntry _outsidefogcolor, int _outsidefogdensity, int _skyfog);
bool gl_CheckNodes(MapData * map, bool rebuilt, int buildtime);
bool gl_LoadGLNodes(MapData * map);

View file

@ -100,7 +100,7 @@ static void AddLine (seg_t *seg,sector_t * sector)
{ {
clipper.SafeAddClipRange(startAngle, endAngle); clipper.SafeAddClipRange(startAngle, endAngle);
} }
else if (!seg->bPolySeg) // Two-sided polyobjects never obstruct the view else if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) // Two-sided polyobjects never obstruct the view
{ {
if (sector->sectornum == seg->backsector->sectornum) if (sector->sectornum == seg->backsector->sectornum)
{ {
@ -134,9 +134,9 @@ static void AddLine (seg_t *seg,sector_t * sector)
seg->linedef->flags |= ML_MAPPED; seg->linedef->flags |= ML_MAPPED;
if (seg->linedef->validcount!=validcount || seg->bPolySeg) if ((seg->sidedef->Flags & WALLF_POLYOBJ) || seg->linedef->validcount!=validcount)
{ {
if (!seg->bPolySeg) seg->linedef->validcount=validcount; if (!(seg->sidedef->Flags & WALLF_POLYOBJ)) seg->linedef->validcount=validcount;
if (gl_render_walls) if (gl_render_walls)
{ {
@ -229,8 +229,6 @@ static void AddPolyobjs(subsector_t *sub, sector_t *sector)
for(unsigned i=0; i < sub->BSP->Segs.Size(); i++) for(unsigned i=0; i < sub->BSP->Segs.Size(); i++)
{ {
sub->BSP->Segs[i].Subsector = sub; sub->BSP->Segs[i].Subsector = sub;
if (sub->BSP->Segs[i].sidedef && sub->BSP->Segs[i].sidedef->Flags & WALLF_POLYOBJ)
sub->BSP->Segs[i].bPolySeg = true; // The GL renderer needs this.
} }
} }
fakesector = sector; fakesector = sector;
@ -267,7 +265,7 @@ static inline void AddLines(subsector_t * sub, sector_t * sector)
{ {
if (line->linedef) if (line->linedef)
{ {
if (!line->bPolySeg) AddLine (line, sector); if (!(line->sidedef->Flags & WALLF_POLYOBJ)) AddLine (line, sector);
} }
line++; line++;
} }

View file

@ -590,7 +590,7 @@ void GLFlat::ProcessSector(sector_t * frontsector, subsector_t * sub)
gl_drawinfo->ss_renderflags[sub-subsectors]|=SSRF_PROCESSED; gl_drawinfo->ss_renderflags[sub-subsectors]|=SSRF_PROCESSED;
if (sub->hacked&1) gl_drawinfo->AddHackedSubsector(sub); if (sub->hacked&1) gl_drawinfo->AddHackedSubsector(sub);
if (sub->degenerate) return; if (sub->flags & SSECF_DEGENERATE) return;
byte * srf = &gl_drawinfo->sectorrenderflags[sector->sectornum]; byte * srf = &gl_drawinfo->sectorrenderflags[sector->sectornum];

View file

@ -669,7 +669,7 @@ void FDrawInfo::DrawUnhandledMissingTextures()
//if (seg->frontsector->ceilingpic==skyflatnum) continue; //if (seg->frontsector->ceilingpic==skyflatnum) continue;
// FIXME: The check for degenerate subsectors should be more precise // FIXME: The check for degenerate subsectors should be more precise
if (seg->PartnerSeg && seg->PartnerSeg->Subsector->degenerate) continue; if (seg->PartnerSeg && (seg->PartnerSeg->Subsector->flags & SSECF_DEGENERATE)) continue;
if (seg->backsector->transdoor) continue; if (seg->backsector->transdoor) continue;
if (seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum) continue; if (seg->backsector->GetTexture(sector_t::ceiling)==skyflatnum) continue;
if (seg->backsector->CeilingSkyBox && seg->backsector->CeilingSkyBox->bAlways) continue; if (seg->backsector->CeilingSkyBox && seg->backsector->CeilingSkyBox->bAlways) continue;
@ -742,7 +742,7 @@ bool FDrawInfo::CheckAnchorFloor(subsector_t * sub)
{ {
// This subsector has a one sided wall and can be used. // This subsector has a one sided wall and can be used.
if (sub->hacked==3) return true; if (sub->hacked==3) return true;
if (sub->degenerate) return false; if (sub->flags & SSECF_DEGENERATE) return false;
for(DWORD j=0;j<sub->numlines;j++) for(DWORD j=0;j<sub->numlines;j++)
{ {
@ -752,7 +752,7 @@ bool FDrawInfo::CheckAnchorFloor(subsector_t * sub)
subsector_t * backsub = seg->PartnerSeg->Subsector; subsector_t * backsub = seg->PartnerSeg->Subsector;
// Find a linedef with a different visplane on the other side. // Find a linedef with a different visplane on the other side.
if (!backsub->degenerate && seg->linedef && if (!(backsub->flags & SSECF_DEGENERATE) && seg->linedef &&
(sub->render_sector != backsub->render_sector && sub->sector != backsub->sector)) (sub->render_sector != backsub->render_sector && sub->sector != backsub->sector))
{ {
// I'm ignoring slopes, scaling and rotation here. The likelihood of ZDoom maps // I'm ignoring slopes, scaling and rotation here. The likelihood of ZDoom maps
@ -790,7 +790,7 @@ bool FDrawInfo::CollectSubsectorsFloor(subsector_t * sub, sector_t * anchor)
// We must collect any subsector that either is connected to this one with a miniseg // We must collect any subsector that either is connected to this one with a miniseg
// or has the same visplane. // or has the same visplane.
// We must not collect any subsector that has the anchor's visplane! // We must not collect any subsector that has the anchor's visplane!
if (!sub->degenerate) if (!(sub->flags & SSECF_DEGENERATE))
{ {
// Is not being rendered so don't bother. // Is not being rendered so don't bother.
if (!(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return true; if (!(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return true;
@ -848,7 +848,7 @@ bool FDrawInfo::CheckAnchorCeiling(subsector_t * sub)
{ {
// This subsector has a one sided wall and can be used. // This subsector has a one sided wall and can be used.
if (sub->hacked==3) return true; if (sub->hacked==3) return true;
if (sub->degenerate) return false; if (sub->flags & SSECF_DEGENERATE) return false;
for(DWORD j=0;j<sub->numlines;j++) for(DWORD j=0;j<sub->numlines;j++)
{ {
@ -858,7 +858,7 @@ bool FDrawInfo::CheckAnchorCeiling(subsector_t * sub)
subsector_t * backsub = seg->PartnerSeg->Subsector; subsector_t * backsub = seg->PartnerSeg->Subsector;
// Find a linedef with a different visplane on the other side. // Find a linedef with a different visplane on the other side.
if (!backsub->degenerate && seg->linedef && if (!(backsub->flags & SSECF_DEGENERATE) && seg->linedef &&
(sub->render_sector != backsub->render_sector && sub->sector != backsub->sector)) (sub->render_sector != backsub->render_sector && sub->sector != backsub->sector))
{ {
// I'm ignoring slopes, scaling and rotation here. The likelihood of ZDoom maps // I'm ignoring slopes, scaling and rotation here. The likelihood of ZDoom maps
@ -892,7 +892,7 @@ bool FDrawInfo::CollectSubsectorsCeiling(subsector_t * sub, sector_t * anchor)
// We must collect any subsector that either is connected to this one with a miniseg // We must collect any subsector that either is connected to this one with a miniseg
// or has the same visplane. // or has the same visplane.
// We must not collect any subsector that has the anchor's visplane! // We must not collect any subsector that has the anchor's visplane!
if (!sub->degenerate) if (!(sub->flags & SSECF_DEGENERATE))
{ {
// Is not being rendererd so don't bother. // Is not being rendererd so don't bother.
if (!(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return true; if (!(ss_renderflags[DWORD(sub-subsectors)]&SSRF_PROCESSED)) return true;

View file

@ -63,7 +63,7 @@ extern int vertexcount;
void GLWall::SplitUpperEdge(texcoord * tcs, bool glow) void GLWall::SplitUpperEdge(texcoord * tcs, bool glow)
{ {
if (seg == NULL || seg->bPolySeg || seg->sidedef == NULL || seg->sidedef->numsegs == 1) return; if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
side_t *sidedef = seg->sidedef; side_t *sidedef = seg->sidedef;
float polyw = glseg.fracright - glseg.fracleft; float polyw = glseg.fracright - glseg.fracleft;
@ -98,7 +98,7 @@ void GLWall::SplitUpperEdge(texcoord * tcs, bool glow)
void GLWall::SplitLowerEdge(texcoord * tcs, bool glow) void GLWall::SplitLowerEdge(texcoord * tcs, bool glow)
{ {
if (seg == NULL || seg->bPolySeg || seg->sidedef == NULL || seg->sidedef->numsegs == 1) return; if (seg == NULL || seg->sidedef == NULL || (seg->sidedef->Flags & WALLF_POLYOBJ) || seg->sidedef->numsegs == 1) return;
side_t *sidedef = seg->sidedef; side_t *sidedef = seg->sidedef;
float polyw = glseg.fracright - glseg.fracleft; float polyw = glseg.fracright - glseg.fracleft;

View file

@ -157,9 +157,13 @@ void GLWall::PutWall(bool translucent)
{ {
if (gl_lights && !gl_dynlight_shader) if (gl_lights && !gl_dynlight_shader)
{ {
if (!seg->bPolySeg) if (seg->sidedef == NULL)
{ {
light = (seg->sidedef != NULL && seg->sidedef->lighthead[0] != NULL); light = false;
}
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
{
light = seg->sidedef->lighthead[0] != NULL;
} }
else if (sub) else if (sub)
{ {
@ -1439,10 +1443,12 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
#endif #endif
#endif #endif
// note: we always have a valid sidedef and linedef reference when getting here.
this->seg = seg; this->seg = seg;
this->sub =seg->Subsector; this->sub =seg->Subsector;
if (seg->bPolySeg && seg->backsector) if ((seg->sidedef->Flags & WALLF_POLYOBJ) && seg->backsector)
{ {
// Textures on 2-sided polyobjects are aligned to the actual seg's sectors // Textures on 2-sided polyobjects are aligned to the actual seg's sectors
realfront = seg->frontsector; realfront = seg->frontsector;
@ -1466,7 +1472,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
v2=seg->linedef->v1; v2=seg->linedef->v1;
} }
if (!seg->bPolySeg) if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
{ {
glseg.fracleft=0; glseg.fracleft=0;
glseg.fracright=1; glseg.fracright=1;
@ -1631,7 +1637,7 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
fch1,fch2,bch1a,bch2a,0); fch1,fch2,bch1a,bch2a,0);
} }
} }
else if (!seg->bPolySeg) else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
{ {
gl_drawinfo->AddUpperMissingTexture(seg, bch1a); gl_drawinfo->AddUpperMissingTexture(seg, bch1a);
} }
@ -1694,7 +1700,8 @@ void GLWall::Process(seg_t *seg, sector_t * frontsector, sector_t * backsector)
bfh1,bfh2,ffh1,ffh2, realfront->GetPlaneTexZ(sector_t::floor)-realfront->GetPlaneTexZ(sector_t::ceiling)); bfh1,bfh2,ffh1,ffh2, realfront->GetPlaneTexZ(sector_t::floor)-realfront->GetPlaneTexZ(sector_t::ceiling));
} }
} }
else if (backsector->GetTexture(sector_t::floor)!=skyflatnum && !seg->bPolySeg) else if (backsector->GetTexture(sector_t::floor)!=skyflatnum &&
!(seg->sidedef->Flags & WALLF_POLYOBJ))
{ {
gl_drawinfo->AddLowerMissingTexture(seg, bfh1); gl_drawinfo->AddLowerMissingTexture(seg, bfh1);
} }

View file

@ -133,22 +133,22 @@ void GLWall::SetupLights()
for(int i=0;i<2;i++) for(int i=0;i<2;i++)
{ {
FLightNode *node; FLightNode *node;
if (!seg->bPolySeg) if (seg->sidedef == NULL)
{ {
// Iterate through all dynamic lights which touch this wall and render them node = NULL;
if (seg->sidedef) }
{ else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
node = seg->sidedef->lighthead[i]; {
} node = seg->sidedef->lighthead[i];
else node = NULL;
} }
else if (sub) else if (sub)
{ {
// To avoid constant rechecking for polyobjects use the subsector's lightlist instead // Polobject segs cannot be checked per sidedef so use the subsector instead.
node = sub->lighthead[i]; node = sub->lighthead[i];
} }
else node = NULL; else node = NULL;
// Iterate through all dynamic lights which touch this wall and render them
while (node) while (node)
{ {
if (!(node->lightsource->flags2&MF2_DORMANT)) if (!(node->lightsource->flags2&MF2_DORMANT))
@ -224,7 +224,7 @@ void GLWall::RenderWall(int textured, float * color2, ADynamicLight * light)
{ {
texcoord tcs[4]; texcoord tcs[4];
bool glowing; bool glowing;
bool split = (gl_seamless && !(textured&4) && !seg->bPolySeg); bool split = (gl_seamless && !(textured&4) && seg->sidedef != NULL && !(seg->sidedef->Flags & WALLF_POLYOBJ));
if (!light) if (!light)
{ {
@ -526,14 +526,14 @@ void GLWall::Draw(int pass)
if (!(flags&GLWF_FOGGY)) gl_SetFog((255+lightlevel)>>1, 0, NULL, false); if (!(flags&GLWF_FOGGY)) gl_SetFog((255+lightlevel)>>1, 0, NULL, false);
else gl_SetFog(lightlevel, 0, &Colormap, true); else gl_SetFog(lightlevel, 0, &Colormap, true);
if (!seg->bPolySeg) if (seg->sidedef == NULL)
{
node = NULL;
}
else if (!(seg->sidedef->Flags & WALLF_POLYOBJ))
{ {
// Iterate through all dynamic lights which touch this wall and render them // Iterate through all dynamic lights which touch this wall and render them
if (seg->sidedef) node = seg->sidedef->lighthead[pass==GLPASS_LIGHT_ADDITIVE];
{
node = seg->sidedef->lighthead[pass==GLPASS_LIGHT_ADDITIVE];
}
else node = NULL;
} }
else if (sub) else if (sub)
{ {

View file

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

View file

@ -96,15 +96,6 @@ EXTERN_CVAR (Bool, vid_vsync)
EXTERN_CVAR(Int, displaynametags) EXTERN_CVAR(Int, displaynametags)
EXTERN_CVAR (Int, snd_channels) EXTERN_CVAR (Int, snd_channels)
void StartGLMenu (void);
EXTERN_CVAR(Int, vid_renderer)
static value_t Renderers[] = {
{ 0.0, "Software" },
{ 1.0, "OpenGL" },
};
EXTERN_CVAR (Float, vid_brightness)
EXTERN_CVAR (Float, vid_contrast)
// //
// defaulted values // defaulted values
// //
@ -213,6 +204,7 @@ static menu_t ConfirmMenu = {
* *
*=======================================*/ *=======================================*/
static void StartAutomapMenu (void);
static void CustomizeControls (void); static void CustomizeControls (void);
static void GameplayOptions (void); static void GameplayOptions (void);
static void CompatibilityOptions (void); static void CompatibilityOptions (void);
@ -237,6 +229,7 @@ static menuitem_t OptionItems[] =
{ more, "Player Setup", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)M_PlayerSetup} }, { 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, "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, "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, "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, "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} }, { more, "Set video mode", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)SetVidMode} },
@ -428,13 +421,13 @@ menu_t ControlsMenu =
2, 2,
}; };
/*======================================= /*=======================================
* *
* Display Options Menu * Display Options Menu
* *
*=======================================*/ *=======================================*/
static void StartMessagesMenu (void); static void StartMessagesMenu (void);
static void StartAutomapMenu (void);
static void StartScoreboardMenu (void); static void StartScoreboardMenu (void);
static void InitCrosshairsList(); static void InitCrosshairsList();
@ -453,6 +446,15 @@ EXTERN_CVAR (Int, r_fakecontrast)
static TArray<valuestring_t> Crosshairs; static TArray<valuestring_t> Crosshairs;
void StartGLMenu (void);
EXTERN_CVAR(Int, vid_renderer)
static value_t Renderers[] = {
{ 0.0, "Software" },
{ 1.0, "OpenGL" },
};
EXTERN_CVAR (Float, vid_brightness)
EXTERN_CVAR (Float, vid_contrast)
static value_t ColumnMethods[] = { static value_t ColumnMethods[] = {
{ 0.0, "Original" }, { 0.0, "Original" },
{ 1.0, "Optimized" } { 1.0, "Optimized" }
@ -505,7 +507,6 @@ static value_t DisplayTagsTypes[] = {
static menuitem_t VideoItems[] = { static menuitem_t VideoItems[] = {
{ more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} }, { more, "Message Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartMessagesMenu} },
{ more, "OpenGL Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartGLMenu} }, { more, "OpenGL Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartGLMenu} },
{ 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} }, { more, "Scoreboard Options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)StartScoreboardMenu} },
{ redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ slider, "Screen size", {&screenblocks}, {3.0}, {12.0}, {1.0}, {NULL} }, { slider, "Screen size", {&screenblocks}, {3.0}, {12.0}, {1.0}, {NULL} },
@ -533,7 +534,7 @@ static menuitem_t VideoItems[] = {
{ discrete, "Display nametags", {&displaynametags}, {4.0}, {0.0}, {0.0}, {DisplayTagsTypes} }, { discrete, "Display nametags", {&displaynametags}, {4.0}, {0.0}, {0.0}, {DisplayTagsTypes} },
}; };
#define CROSSHAIR_INDEX 10 #define CROSSHAIR_INDEX 9
menu_t VideoMenu = menu_t VideoMenu =
{ {
@ -550,6 +551,7 @@ menu_t VideoMenu =
* *
*=======================================*/ *=======================================*/
static void StartMapColorsMenu (void); static void StartMapColorsMenu (void);
static void StartMapControlsMenu (void);
EXTERN_CVAR (Int, am_rotate) EXTERN_CVAR (Int, am_rotate)
EXTERN_CVAR (Int, am_overlay) EXTERN_CVAR (Int, am_overlay)
@ -560,6 +562,7 @@ EXTERN_CVAR (Bool, am_showtime)
EXTERN_CVAR (Int, am_map_secrets) EXTERN_CVAR (Int, am_map_secrets)
EXTERN_CVAR (Bool, am_showtotaltime) EXTERN_CVAR (Bool, am_showtotaltime)
EXTERN_CVAR (Bool, am_drawmapback) EXTERN_CVAR (Bool, am_drawmapback)
EXTERN_CVAR (Bool, am_textured)
static value_t MapColorTypes[] = { static value_t MapColorTypes[] = {
{ 0, "Custom" }, { 0, "Custom" },
@ -589,9 +592,11 @@ static value_t OverlayTypes[] = {
static menuitem_t AutomapItems[] = { static menuitem_t AutomapItems[] = {
{ discrete, "Map color set", {&am_colorset}, {4.0}, {0.0}, {0.0}, {MapColorTypes} }, { 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, "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} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ discrete, "Rotate automap", {&am_rotate}, {3.0}, {0.0}, {0.0}, {RotateTypes} }, { 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, "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} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} },
{ discrete, "Show item counts", {&am_showitems}, {2.0}, {0.0}, {0.0}, {OnOff} }, { 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} }, { discrete, "Show monster counts", {&am_showmonsters}, {2.0}, {0.0}, {0.0}, {OnOff} },
@ -612,6 +617,37 @@ menu_t AutomapMenu =
AutomapItems, 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 * Map Colors Menu
@ -1549,7 +1585,9 @@ void M_BuildKeyList (menuitem_t *item, int numitems)
for (i = 0; i < numitems; i++, item++) for (i = 0; i < numitems; i++, item++)
{ {
if (item->type == control) 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);
} }
} }
@ -1838,7 +1876,7 @@ void M_OptDrawer ()
default: default:
x = indent - width; 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; ? CR_YELLOW : LabelColor;
break; break;
} }
@ -1996,6 +2034,7 @@ void M_OptDrawer ()
break; break;
case control: case control:
case mapcontrol:
{ {
char description[64]; char description[64];
@ -2178,7 +2217,14 @@ void M_OptResponder(event_t *ev)
{ {
if (ev->data1 != KEY_ESCAPE) 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); M_BuildKeyList(CurrentMenu->items, CurrentMenu->numitems);
} }
menuactive = MENU_On; menuactive = MENU_On;
@ -2825,7 +2871,12 @@ void M_OptButtonHandler(EMenuKey key, bool repeat)
case MKEY_Clear: case MKEY_Clear:
if (item->type == control) 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; item->b.key1 = item->c.key2 = 0;
} }
break; break;
@ -2893,7 +2944,7 @@ void M_OptButtonHandler(EMenuKey key, bool repeat)
S_Sound (CHAN_VOICE | CHAN_UI, "menu/change", snd_menuvolume, ATTN_NONE); 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; menuactive = MENU_WaitKey;
OldMessage = CurrentMenu->items[0].label; OldMessage = CurrentMenu->items[0].label;
@ -3013,6 +3064,12 @@ static void StartMapColorsMenu (void)
M_SwitchMenu (&MapColorsMenu); M_SwitchMenu (&MapColorsMenu);
} }
static void StartMapControlsMenu (void)
{
M_BuildKeyList (MapControlsMenu.items, MapControlsMenu.numitems);
M_SwitchMenu (&MapControlsMenu);
}
CCMD (menu_mapcolors) CCMD (menu_mapcolors)
{ {
M_StartControlPanel (true); M_StartControlPanel (true);
@ -3657,12 +3714,14 @@ void M_LoadKeys (const char *modname, bool dbl)
mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname, mysnprintf (section, countof(section), "%s.%s%sBindings", GameNames[gameinfo.gametype], modname,
dbl ? ".Double" : "."); dbl ? ".Double" : ".");
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
if (GameConfig->SetSection (section)) if (GameConfig->SetSection (section))
{ {
const char *key, *value; const char *key, *value;
while (GameConfig->NextInSection (key, value)) while (GameConfig->NextInSection (key, value))
{ {
C_DoBind (key, value, dbl); bindings->DoBind (key, value);
} }
} }
} }
@ -3673,12 +3732,13 @@ int M_DoSaveKeys (FConfigFile *config, char *section, int i, bool dbl)
config->SetSection (section, true); config->SetSection (section, true);
config->ClearCurrentSection (); config->ClearCurrentSection ();
FKeyBindings *bindings = dbl? &DoubleBindings : &Bindings;
for (++i; i < most; ++i) for (++i; i < most; ++i)
{ {
menuitem_t *item = &CustomControlsItems[i]; menuitem_t *item = &CustomControlsItems[i];
if (item->type == control) if (item->type == control)
{ {
C_ArchiveBindings (config, dbl, item->e.command); bindings->ArchiveBindings (config, item->e.command);
continue; continue;
} }
break; break;
@ -3724,7 +3784,7 @@ void FreeKeySections()
for (i = numStdControls; i < CustomControlsItems.Size(); ++i) for (i = numStdControls; i < CustomControlsItems.Size(); ++i)
{ {
menuitem_t *item = &CustomControlsItems[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) if (item->label != NULL)
{ {

View file

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

View file

@ -111,6 +111,12 @@ class FNodeBuilder
bool Forward; bool Forward;
}; };
struct glseg_t : public seg_t
{
DWORD Partner;
};
// Like a blockmap, but for vertices instead of lines // Like a blockmap, but for vertices instead of lines
class IVertexMap class IVertexMap
{ {
@ -200,7 +206,7 @@ public:
~FNodeBuilder (); ~FNodeBuilder ();
void Extract (node_t *&nodes, int &nodeCount, 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, subsector_t *&ssecs, int &subCount,
vertex_t *&verts, int &vertCount); vertex_t *&verts, int &vertCount);
@ -282,10 +288,10 @@ private:
DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg); DWORD AddMiniseg (int v1, int v2, DWORD partner, DWORD seg1, DWORD splitseg);
void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const; void SetNodeFromSeg (node_t &node, const FPrivSeg *pseg) const;
int CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *outVerts); int CloseSubsector (TArray<glseg_t> &segs, int subsector, vertex_t *outVerts);
DWORD PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts); DWORD PushGLSeg (TArray<glseg_t> &segs, const FPrivSeg *seg, vertex_t *outVerts);
void PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vertex_t *v1, vertex_t *v2); void PushConnectingGLSeg (int subsector, TArray<glseg_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 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); static int STACK_ARGS SortSegs (const void *a, const void *b);

View file

@ -54,7 +54,7 @@
#endif #endif
void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount, 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, subsector_t *&outSubs, int &subCount,
vertex_t *&outVerts, int &vertCount) vertex_t *&outVerts, int &vertCount)
{ {
@ -99,7 +99,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
if (GLNodes) if (GLNodes)
{ {
TArray<seg_t> segs (Segs.Size()*5/4); TArray<glseg_t> segs (Segs.Size()*5/4);
for (i = 0; i < subCount; ++i) for (i = 0; i < subCount; ++i)
{ {
@ -110,14 +110,12 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
segCount = segs.Size (); segCount = segs.Size ();
outSegs = new seg_t[segCount]; outSegs = new seg_t[segCount];
memcpy (outSegs, &segs[0], segCount*sizeof(seg_t)); outSegExtras = new glsegextra_t[segCount];
for (i = 0; i < segCount; ++i) for (i = 0; i < segCount; ++i)
{ {
if (outSegs[i].PartnerSeg != NULL) outSegs[i] = *(seg_t *)&segs[i];
{ outSegExtras[i].PartnerSeg = segs[i].Partner;
outSegs[i].PartnerSeg = &outSegs[Segs[(unsigned int)(size_t)outSegs[i].PartnerSeg-1].storedseg];
}
} }
} }
else else
@ -125,6 +123,7 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
memcpy (outSubs, &Subsectors[0], subCount*sizeof(subsector_t)); memcpy (outSubs, &Subsectors[0], subCount*sizeof(subsector_t));
segCount = Segs.Size (); segCount = Segs.Size ();
outSegs = new seg_t[segCount]; outSegs = new seg_t[segCount];
outSegExtras = NULL;
for (i = 0; i < segCount; ++i) for (i = 0; i < segCount; ++i)
{ {
const FPrivSeg *org = &Segs[SegList[i].SegNum]; const FPrivSeg *org = &Segs[SegList[i].SegNum];
@ -138,8 +137,6 @@ void FNodeBuilder::Extract (node_t *&outNodes, int &nodeCount,
out->frontsector = org->frontsector; out->frontsector = org->frontsector;
out->linedef = Level.Lines + org->linedef; out->linedef = Level.Lines + org->linedef;
out->sidedef = Level.Sides + org->sidedef; out->sidedef = Level.Sides + org->sidedef;
out->PartnerSeg = NULL;
out->bPolySeg = false;
} }
} }
for (i = 0; i < subCount; ++i) for (i = 0; i < subCount; ++i)
@ -194,19 +191,17 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
if (GLNodes) if (GLNodes)
{ {
TArray<glseg_t> glsegs;
for (i = 0; i < Subsectors.Size(); ++i) 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].numlines = numsegs;
bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs]; bsp->Subsectors[i].firstline = &bsp->Segs[bsp->Segs.Size() - numsegs];
} }
bsp->Segs.Resize(glsegs.Size());
for (i = 0; i < Segs.Size(); ++i) for (i = 0; i < glsegs.Size(); ++i)
{ {
if (bsp->Segs[i].PartnerSeg != NULL) bsp->Segs[i] = *(seg_t *)&glsegs[i];
{
bsp->Segs[i].PartnerSeg = &bsp->Segs[Segs[(unsigned int)(size_t)bsp->Segs[i].PartnerSeg-1].storedseg];
}
} }
} }
else else
@ -234,8 +229,6 @@ void FNodeBuilder::ExtractMini (FMiniBSP *bsp)
out->linedef = NULL; out->linedef = NULL;
out->sidedef = NULL; out->sidedef = NULL;
} }
out->PartnerSeg = NULL;
out->bPolySeg = false;
} }
for (i = 0; i < bsp->Subsectors.Size(); ++i) 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; FPrivSeg *seg, *prev;
angle_t prevAngle; angle_t prevAngle;
@ -406,7 +399,7 @@ int FNodeBuilder::CloseSubsector (TArray<seg_t> &segs, int subsector, vertex_t *
return count; 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 }; static const double bestinit[2] = { -DBL_MAX, DBL_MAX };
FPrivSeg *seg; FPrivSeg *seg;
@ -473,9 +466,9 @@ int FNodeBuilder::OutputDegenerateSubsector (TArray<seg_t> &segs, int subsector,
return count; 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.v1 = outVerts + seg->v1;
newseg.v2 = outVerts + seg->v2; newseg.v2 = outVerts + seg->v2;
@ -491,14 +484,13 @@ DWORD FNodeBuilder::PushGLSeg (TArray<seg_t> &segs, const FPrivSeg *seg, vertex_
newseg.linedef = NULL; newseg.linedef = NULL;
newseg.sidedef = NULL; newseg.sidedef = NULL;
} }
newseg.PartnerSeg = (seg_t *)(seg->partner == DWORD_MAX ? 0 : (size_t)seg->partner + 1); newseg.Partner = seg->partner;
newseg.bPolySeg = false;
return (DWORD)segs.Push (newseg); 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.v1 = v1;
newseg.v2 = v2; newseg.v2 = v2;
@ -506,7 +498,6 @@ void FNodeBuilder::PushConnectingGLSeg (int subsector, TArray<seg_t> &segs, vert
newseg.frontsector = NULL; newseg.frontsector = NULL;
newseg.linedef = NULL; newseg.linedef = NULL;
newseg.sidedef = NULL; newseg.sidedef = NULL;
newseg.PartnerSeg = NULL; newseg.Partner = DWORD_MAX;
newseg.bPolySeg = false;
segs.Push (newseg); segs.Push (newseg);
} }

View file

@ -5097,7 +5097,7 @@ int DLevelScript::RunScript ()
{ {
int key1 = 0, key2 = 0; int key1 = 0, key2 = 0;
C_GetKeysForCommand ((char *)lookup, &key1, &key2); Bindings.GetKeysForCommand ((char *)lookup, &key1, &key2);
if (key2) if (key2)
work << KeyNames[key1] << " or " << KeyNames[key2]; work << KeyNames[key1] << " or " << KeyNames[key2];

View file

@ -813,7 +813,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang
toSay = GStrings[dlgtext]; toSay = GStrings[dlgtext];
if (toSay == NULL) if (toSay == NULL)
{ {
toSay = GStrings("TXT_GOAWAY"); // Ok, it's lame - but it doesn't look like an error to the player. ;) toSay = "Go away!"; // Ok, it's lame - but it doesn't look like an error to the player. ;)
} }
} }
else else

View file

@ -40,7 +40,6 @@
#include "r_state.h" #include "r_state.h"
#include "templates.h" #include "templates.h"
#include "po_man.h" #include "po_man.h"
#include "gl/gl_functions.h"
static AActor *RoughBlockCheck (AActor *mo, int index, void *); static AActor *RoughBlockCheck (AActor *mo, int index, void *);
@ -303,7 +302,7 @@ void AActor::LinkToWorld (bool buggy)
// link into subsector // link into subsector
sector_t *sec; sector_t *sec;
if (!buggy || numnodes == 0) if (!buggy || numgamenodes == 0)
{ {
sec = P_PointInSector (x, y); sec = P_PointInSector (x, y);
} }

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 // don't splash above the object
if (checkabove && z > thing->z + (thing->height >> 1)) return false; 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 #ifdef _3DFLOORS
for(unsigned int i=0;i<sec->e->XFloor.ffloors.Size();i++) 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 thing->flags6 &= ~MF6_ARMED; // Disarm
P_DamageMobj (thing, NULL, NULL, thing->health, NAME_Crush, DMG_FORCED); // kill object 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) if (thing->flags2 & MF2_FLOATBOB || thing->flags3 & MF3_DONTSPLASH)

View file

@ -47,6 +47,7 @@
#include "r_interpolate.h" #include "r_interpolate.h"
#include "g_level.h" #include "g_level.h"
#include "po_man.h" #include "po_man.h"
#include "p_setup.h"
static void CopyPlayer (player_t *dst, player_t *src, const char *name); static void CopyPlayer (player_t *dst, player_t *src, const char *name);
static void ReadOnePlayer (FArchive &arc, bool skipload); static void ReadOnePlayer (FArchive &arc, bool skipload);
@ -543,3 +544,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 < 2609)
{
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_SerializeWorld (FArchive &arc);
void P_SerializeThinkers (FArchive &arc, bool); void P_SerializeThinkers (FArchive &arc, bool);
void P_SerializePolyobjs (FArchive &arc); void P_SerializePolyobjs (FArchive &arc);
void P_SerializeSubsectors(FArchive &arc);
void P_SerializeSounds (FArchive &arc); void P_SerializeSounds (FArchive &arc);
void P_ReadACSDefereds (PNGHandle *png); void P_ReadACSDefereds (PNGHandle *png);

View file

@ -87,6 +87,8 @@ void P_ParseTextMap(MapData *map);
extern int numinterpolations; extern int numinterpolations;
extern unsigned int R_OldBlend; extern unsigned int R_OldBlend;
EXTERN_CVAR(Bool, am_textured)
CVAR (Bool, genblockmap, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG); CVAR (Bool, genblockmap, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG);
CVAR (Bool, gennodes, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG); CVAR (Bool, gennodes, false, CVAR_SERVERINFO|CVAR_GLOBALCONFIG);
CVAR (Bool, genglnodes, false, CVAR_SERVERINFO); CVAR (Bool, genglnodes, false, CVAR_SERVERINFO);
@ -107,6 +109,7 @@ vertex_t* vertexes;
int numsegs; int numsegs;
seg_t* segs; seg_t* segs;
glsegextra_t* glsegextras;
int numsectors; int numsectors;
sector_t* sectors; sector_t* sectors;
@ -126,6 +129,14 @@ side_t* sides;
int numzones; int numzones;
zone_t* zones; zone_t* zones;
node_t * gamenodes;
int numgamenodes;
subsector_t * gamesubsectors;
int numgamesubsectors;
bool hasglnodes;
FExtraLight* ExtraLights; FExtraLight* ExtraLights;
FLightStack* LightStacks; FLightStack* LightStacks;
@ -136,8 +147,6 @@ sidei_t *sidetemp;
TArray<int> linemap; TArray<int> linemap;
bool UsingGLNodes;
// BLOCKMAP // BLOCKMAP
// Created from axis aligned bounding box // Created from axis aligned bounding box
// of the map, a rectangular array of // of the map, a rectangular array of
@ -158,7 +167,6 @@ fixed_t bmaporgy;
FBlockNode** blocklinks; // for thing chains FBlockNode** blocklinks; // for thing chains
// REJECT // REJECT
// For fast sight rejection. // For fast sight rejection.
// Speeds up enemy AI by skipping detailed // Speeds up enemy AI by skipping detailed
@ -830,7 +838,6 @@ void P_LoadZSegs (FileReaderBase &data)
segs[i].v2 = &vertexes[v2]; segs[i].v2 = &vertexes[v2];
segs[i].linedef = ldef = &lines[line]; segs[i].linedef = ldef = &lines[line];
segs[i].sidedef = ldef->sidedef[side]; segs[i].sidedef = ldef->sidedef[side];
segs[i].PartnerSeg = NULL;
segs[i].frontsector = ldef->sidedef[side]->sector; segs[i].frontsector = ldef->sidedef[side]->sector;
if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != NULL) if (ldef->flags & ML_TWOSIDED && ldef->sidedef[side^1] != NULL)
{ {
@ -886,14 +893,7 @@ void P_LoadGLZSegs (FileReaderBase &data, int type)
{ {
seg[-1].v2 = seg->v1; seg[-1].v2 = seg->v1;
} }
if (partner == 0xFFFFFFFF) glsegextras[seg - segs].PartnerSeg = partner;
{
seg->PartnerSeg = NULL;
}
else
{
seg->PartnerSeg = &segs[partner];
}
if (line != 0xFFFFFFFF) if (line != 0xFFFFFFFF)
{ {
line_t *ldef; line_t *ldef;
@ -996,6 +996,7 @@ void LoadZNodes(FileReaderBase &data, int glnodes)
numsegs = numSegs; numsegs = numSegs;
segs = new seg_t[numsegs]; segs = new seg_t[numsegs];
memset (segs, 0, numsegs*sizeof(seg_t)); memset (segs, 0, numsegs*sizeof(seg_t));
glsegextras = NULL;
for (i = 0; i < numSubs; ++i) for (i = 0; i < numSubs; ++i)
{ {
@ -1008,6 +1009,7 @@ void LoadZNodes(FileReaderBase &data, int glnodes)
} }
else else
{ {
glsegextras = new glsegextra_t[numsegs];
P_LoadGLZSegs (data, glnodes); P_LoadGLZSegs (data, glnodes);
} }
@ -1202,7 +1204,6 @@ void P_LoadSegs (MapData * map)
li->v1 = &vertexes[vnum1]; li->v1 = &vertexes[vnum1];
li->v2 = &vertexes[vnum2]; li->v2 = &vertexes[vnum2];
li->PartnerSeg = NULL;
segangle = (WORD)LittleShort(ml->angle); segangle = (WORD)LittleShort(ml->angle);
@ -2945,6 +2946,16 @@ static void P_GroupLines (bool buildmap)
{ {
subsectors[i].sector = subsectors[i].firstline->sidedef->sector; 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(); times[0].Unclock();
// count number of lines in each sector // count number of lines in each sector
@ -3381,6 +3392,11 @@ void P_FreeLevelData ()
delete[] segs; delete[] segs;
segs = NULL; segs = NULL;
} }
if (glsegextras != NULL)
{
delete[] glsegextras;
glsegextras = NULL;
}
if (sectors != NULL) if (sectors != NULL)
{ {
delete[] sectors[0].e; delete[] sectors[0].e;
@ -3388,6 +3404,18 @@ void P_FreeLevelData ()
sectors = NULL; sectors = NULL;
numsectors = 0; // needed for the pointer cleanup code 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) if (subsectors != NULL)
{ {
for (int i = 0; i < numsubsectors; ++i) for (int i = 0; i < numsubsectors; ++i)
@ -3522,6 +3550,10 @@ void P_SetupLevel (char *lumpname, int position)
int i; int i;
bool buildmap; bool buildmap;
// This is motivated as follows:
bool RequireGLNodes = true; // The GL renderer requires GL nodes
for (i = 0; i < (int)countof(times); ++i) for (i = 0; i < (int)countof(times); ++i)
{ {
times[i].Reset(); times[i].Reset();
@ -3579,6 +3611,7 @@ void P_SetupLevel (char *lumpname, int position)
// find map num // find map num
level.lumpnum = map->lumpnum; level.lumpnum = map->lumpnum;
hasglnodes = false;
// [RH] Support loading Build maps (because I felt like it. :-) // [RH] Support loading Build maps (because I felt like it. :-)
buildmap = false; buildmap = false;
@ -3707,23 +3740,23 @@ void P_SetupLevel (char *lumpname, int position)
{ {
ForceNodeBuild = true; ForceNodeBuild = true;
} }
bool reloop = false;
UsingGLNodes = true; // There really is no point in building non-GL nodes
if (!ForceNodeBuild) if (!ForceNodeBuild)
{ {
// Check for compressed nodes first, then uncompressed nodes // Check for compressed nodes first, then uncompressed nodes
FWadLump test; FWadLump test;
DWORD id = MAKE_ID('X','x','X','x'), idcheck = 0, idcheck2 = 0, idcheck3 = 0, idcheck4 = 0; 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); map->Seek(ML_ZNODES);
idcheck = MAKE_ID('Z','N','O','D'); idcheck = MAKE_ID('Z','N','O','D');
idcheck2 = MAKE_ID('X','N','O','D'); idcheck2 = MAKE_ID('X','N','O','D');
} }
else if (map->MapLumps[ML_GLZNODES].Size != 0) else if (map->MapLumps[ML_GLZNODES].Size != 0)
{ {
// If normal nodes are not present but GL nodes are, use them.
map->Seek(ML_GLZNODES); map->Seek(ML_GLZNODES);
idcheck = MAKE_ID('Z','G','L','N'); idcheck = MAKE_ID('Z','G','L','N');
idcheck2 = MAKE_ID('Z','G','L','2'); idcheck2 = MAKE_ID('Z','G','L','2');
@ -3802,13 +3835,21 @@ void P_SetupLevel (char *lumpname, int position)
// If loading the regular nodes failed try GL nodes before considering a rebuild // If loading the regular nodes failed try GL nodes before considering a rebuild
if (ForceNodeBuild) if (ForceNodeBuild)
{ {
if (gl_LoadGLNodes(map)) ForceNodeBuild=false; if (P_LoadGLNodes(map))
{
ForceNodeBuild=false;
reloop = true;
}
} }
} }
else reloop = true;
unsigned int startTime=0, endTime=0; unsigned int startTime=0, endTime=0;
bool BuildGLNodes;
if (ForceNodeBuild) if (ForceNodeBuild)
{ {
BuildGLNodes = true; //am_textured || multiplayer || demoplayback || demorecording || genglnodes;
startTime = I_FPSTime (); startTime = I_FPSTime ();
TArray<FNodeBuilder::FPolyStart> polyspots, anchors; TArray<FNodeBuilder::FPolyStart> polyspots, anchors;
@ -3820,20 +3861,69 @@ void P_SetupLevel (char *lumpname, int position)
lines, numlines lines, numlines
}; };
leveldata.FindMapBounds (); leveldata.FindMapBounds ();
UsingGLNodes |= genglnodes; // We need GL nodes if am_textured is on.
FNodeBuilder builder (leveldata, polyspots, anchors, UsingGLNodes); // In case a sync critical game mode is started, also build GL nodes to avoid problems
// if the different machines' am_textured setting differs.
FNodeBuilder builder (leveldata, polyspots, anchors, BuildGLNodes);
delete[] vertexes; delete[] vertexes;
builder.Extract (nodes, numnodes, builder.Extract (nodes, numnodes,
segs, numsegs, segs, glsegextras, numsegs,
subsectors, numsubsectors, subsectors, numsubsectors,
vertexes, numvertexes); vertexes, numvertexes);
endTime = I_FPSTime (); endTime = I_FPSTime ();
DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs); DPrintf ("BSP generation took %.3f sec (%d segs)\n", (endTime - startTime) * 0.001, numsegs);
reloop = true;
}
else
{
BuildGLNodes = false;
// Older ZDBSPs had problems with compressed sidedefs and assigned wrong sides to the segs if both sides were the same sidedef.
for(i=0;i<numsegs;i++)
{
seg_t * seg=&segs[i];
if (seg->backsector == seg->frontsector && seg->linedef)
{
fixed_t d1=P_AproxDistance(seg->v1->x-seg->linedef->v1->x,seg->v1->y-seg->linedef->v1->y);
fixed_t d2=P_AproxDistance(seg->v2->x-seg->linedef->v1->x,seg->v2->y-seg->linedef->v1->y);
if (d2<d1) // backside
{
seg->sidedef = seg->linedef->sidedef[1];
}
else // front side
{
seg->sidedef = seg->linedef->sidedef[0];
}
}
}
} }
// If the nodes being loaded are not GL nodes the GL renderer needs to create a second set of nodes. // Copy pointers to the old nodes so that R_PointInSubsector can use them
// The originals have to be kept for use by P_PointInSubsector. if (nodes && subsectors)
ForceNodeBuild |= gl_CheckNodes(map, ForceNodeBuild, endTime - startTime); {
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, BuildGLNodes, endTime - startTime);
hasglnodes = true;
}
else
{
hasglnodes = P_CheckForGLNodes();
}
times[10].Clock(); times[10].Clock();
P_LoadBlockMap (map); P_LoadBlockMap (map);
@ -3851,6 +3941,11 @@ void P_SetupLevel (char *lumpname, int position)
P_FloodZones (); P_FloodZones ();
times[13].Unclock(); times[13].Unclock();
if (hasglnodes)
{
P_SetRenderSector();
}
bodyqueslot = 0; bodyqueslot = 0;
// phares 8/10/98: Clear body queue so the corpses from previous games are // phares 8/10/98: Clear body queue so the corpses from previous games are
// not assumed to be from this one. // not assumed to be from this one.
@ -3901,9 +3996,7 @@ void P_SetupLevel (char *lumpname, int position)
gl_PreprocessLevel(); gl_PreprocessLevel();
times[16].Clock(); times[16].Clock();
// Screw it! I have no desire to track down all cases where this is necessary just to save a few if (reloop) P_LoopSidedefs (false);
// microseconds in the case the second P_LoopSidedefs call is not needed.
/*if (ForceNodeBuild)*/ P_LoopSidedefs (false);
PO_Init (); // Initialize the polyobjs PO_Init (); // Initialize the polyobjs
times[16].Unclock(); times[16].Unclock();
@ -4001,6 +4094,12 @@ void P_SetupLevel (char *lumpname, int position)
} }
} }
MapThingsConverted.Clear(); 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); int GetUDMFInt(int type, int index, const char *key);
fixed_t GetUDMFFixed(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 struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init
{ {
union union
@ -133,5 +139,7 @@ struct sidei_t // [RH] Only keep BOOM sidedef init stuff around for init
}; };
}; };
extern sidei_t *sidetemp; extern sidei_t *sidetemp;
extern bool hasglnodes;
extern struct glsegextra_t *glsegextras;
#endif #endif

View file

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

View file

@ -1827,12 +1827,6 @@ void PO_Init (void)
// [RH] Don't need the seg lists anymore // [RH] Don't need the seg lists anymore
KillSideLists (); 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++) for(int i=0;i<numnodes;i++)
{ {
node_t *no = &nodes[i]; node_t *no = &nodes[i];

View file

@ -36,6 +36,7 @@
#include "i_system.h" #include "i_system.h"
#include "p_lnspec.h" #include "p_lnspec.h"
#include "p_setup.h"
#include "r_main.h" #include "r_main.h"
#include "r_plane.h" #include "r_plane.h"
@ -112,6 +113,8 @@ TArray<size_t> WallMirrors;
static FNodeBuilder::FLevel PolyNodeLevel; static FNodeBuilder::FLevel PolyNodeLevel;
static FNodeBuilder PolyNodeBuilder(PolyNodeLevel); static FNodeBuilder PolyNodeBuilder(PolyNodeLevel);
static subsector_t *InSubsector;
CVAR (Bool, r_drawflat, false, 0) // [RH] Don't texture segs? 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; cliprange_t *next, *start;
int i, j; int i, j;
bool res = false;
// Find the first range that touches the range // Find the first range that touches the range
// (adjacent pixels are touching). // (adjacent pixels are touching).
@ -180,6 +184,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
if (first < start->first) if (first < start->first)
{ {
res = true;
if (last <= start->first) if (last <= start->first)
{ {
// Post is entirely visible (above start). // Post is entirely visible (above start).
@ -205,7 +210,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
next->last = last; next->last = last;
} }
} }
return; return true;
} }
// There is a fragment above *start. // There is a fragment above *start.
@ -220,7 +225,7 @@ void R_ClipWallSegment (int first, int last, bool solid)
// Bottom contained in start? // Bottom contained in start?
if (last <= start->last) if (last <= start->last)
return; return res;
next = start; next = start;
while (last >= (next+1)->first) while (last >= (next+1)->first)
@ -257,6 +262,31 @@ crunch:
newend = start+i; 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 (line->linedef == NULL)
{ {
if (R_CheckClipWallSegment (WallSX1, WallSX2))
{
InSubsector->flags |= SSECF_DRAWN;
}
return; return;
} }
@ -792,6 +826,16 @@ void R_AddLine (seg_t *line)
// Reject empty lines used for triggers and special events. // Reject empty lines used for triggers and special events.
// Identical floor and ceiling on both sides, identical light levels // Identical floor and ceiling on both sides, identical light levels
// on both sides, and no middle texture. // 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; return;
} }
} }
@ -827,7 +871,10 @@ void R_AddLine (seg_t *line)
#endif #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 sector_t tempsec; // killough 3/7/98: deep water hack
int floorlightlevel; // killough 3/16/98: set floor lightlevel int floorlightlevel; // killough 3/16/98: set floor lightlevel
int ceilinglightlevel; // killough 4/11/98 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 #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); I_Error ("R_Subsector: ss %ti with numss = %i", sub - subsectors, numsubsectors);
#endif
#endif #endif
assert(sub->sector != NULL); assert(sub->sector != NULL);
@ -1109,6 +1165,10 @@ void R_Subsector (subsector_t *sub)
if (sub->polys) if (sub->polys)
{ // Render the polyobjs in the subsector first { // Render the polyobjs in the subsector first
R_AddPolyobjs(sub); R_AddPolyobjs(sub);
if (outersubsector)
{
InSubsector = NULL;
}
return; return;
} }
@ -1190,12 +1250,16 @@ void R_Subsector (subsector_t *sub)
while (count--) while (count--)
{ {
if (!line->bPolySeg) if (!outersubsector || line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
{ {
R_AddLine (line); R_AddLine (line);
} }
line++; line++;
} }
if (outersubsector)
{
InSubsector = NULL;
}
} }
// //

View file

@ -338,6 +338,7 @@ enum
SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater SECF_FORCEDUNDERWATER= 64, // sector is forced to be underwater
SECF_UNDERWATERMASK = 32+64, SECF_UNDERWATERMASK = 32+64,
SECF_DRAWN = 128, // sector has been drawn at least once SECF_DRAWN = 128, // sector has been drawn at least once
SECF_HIDDEN = 256, // Do not draw on textured automap
}; };
enum enum
@ -1042,32 +1043,43 @@ struct seg_t
seg_t* PartnerSeg; seg_t* PartnerSeg;
BITFIELD bPolySeg:1;
subsector_t* Subsector; subsector_t* Subsector;
float sidefrac; // relative position of seg's ending vertex on owning sidedef float sidefrac; // relative position of seg's ending vertex on owning sidedef
}; };
struct glsegextra_t
{
DWORD PartnerSeg;
subsector_t *Subsector;
};
// //
// A SubSector. // A SubSector.
// References a Sector. // References a Sector.
// Basically, this is a list of LineSegs indicating the visible walls that // Basically, this is a list of LineSegs indicating the visible walls that
// define (all or some) sides of a convex BSP leaf. // define (all or some) sides of a convex BSP leaf.
// //
enum
{
SSECF_DEGENERATE = 1,
SSECF_DRAWN = 2,
};
struct subsector_t struct subsector_t
{ {
sector_t *sector; sector_t *sector;
FPolyNode *polys; FPolyNode *polys;
FMiniBSP *BSP; FMiniBSP *BSP;
seg_t *firstline; seg_t *firstline;
sector_t *render_sector;
DWORD numlines; DWORD numlines;
int flags;
// subsector related GL data // subsector related GL data
FLightNode * lighthead[2]; // Light nodes (blended and additive) FLightNode * lighthead[2]; // Light nodes (blended and additive)
sector_t * render_sector; // The sector this belongs to for rendering
fixed_t bbox[4]; // Bounding box fixed_t bbox[4]; // Bounding box
int validcount; int validcount;
bool degenerate;
char hacked; // 1: is part of a render hack char hacked; // 1: is part of a render hack
// 2: has one-sided walls // 2: has one-sided walls
}; };

View file

@ -1000,6 +1000,77 @@ const BYTE* ds_source;
// just for profiling // just for profiling
int dscount; 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. // Green/Red/Blue/Indigo shirts.
extern void (*R_DrawTranslatedColumn)(void); 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); 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. // Span drawing for masked textures.
extern void (*R_DrawSpanMasked)(void); 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. { // Don't waste time on a masked texture if it isn't really masked.
masked = false; masked = false;
} }
tex->GetWidth (); R_SetupSpanBits(tex);
ds_xbits = tex->WidthBits;
ds_ybits = tex->HeightBits;
if ((1 << ds_xbits) > tex->GetWidth())
{
ds_xbits--;
}
if ((1 << ds_ybits) > tex->GetHeight())
{
ds_ybits--;
}
pl->xscale = MulScale16 (pl->xscale, tex->xScale); pl->xscale = MulScale16 (pl->xscale, tex->xScale);
pl->yscale = MulScale16 (pl->yscale, tex->yScale); pl->yscale = MulScale16 (pl->yscale, tex->yScale);
#ifdef X86_ASM
R_SetSpanSize_ASM (ds_xbits, ds_ybits);
#endif
ds_source = tex->GetPixels (); ds_source = tex->GetPixels ();
basecolormap = pl->colormap; basecolormap = pl->colormap;

View file

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

View file

@ -1485,7 +1485,7 @@ void RP_Subsector (subsector_t *sub)
while (count--) while (count--)
{ {
if (!line->bPolySeg) if (line->sidedef == NULL || !(line->sidedef->Flags & WALLF_POLYOBJ))
{ {
RP_AddLine (line); RP_AddLine (line);
} }

View file

@ -77,6 +77,13 @@ extern side_t* sides;
extern int numzones; extern int numzones;
extern zone_t* zones; extern zone_t* zones;
extern node_t * gamenodes;
extern int numgamenodes;
extern subsector_t * gamesubsectors;
extern int numgamesubsectors;
extern FExtraLight* ExtraLights; extern FExtraLight* ExtraLights;
extern FLightStack* LightStacks; extern FLightStack* LightStacks;

View file

@ -1534,7 +1534,7 @@ static void SetCustomLoopPts(FMOD::Sound *sound)
FMOD_MODE mode; FMOD_MODE mode;
if (FMOD_OK == (sound->getMode(&mode))) if (FMOD_OK == (sound->getMode(&mode)))
{ {
sound->setMode(mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL) | FMOD_LOOP_BIDI); sound->setMode((mode & ~(FMOD_LOOP_OFF | FMOD_LOOP_NORMAL)) | FMOD_LOOP_BIDI);
} }
} }
} }

View file

@ -125,7 +125,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMIDIDevice type)
// Read the remainder of the song. // Read the remainder of the song.
len = int(len - start); len = int(len - start);
if (len < sizeof(MusHeader)) if (len < (int)sizeof(MusHeader))
{ // It's too short. { // It's too short.
return; return;
} }

View file

@ -3,5 +3,5 @@
// This file was automatically generated by the // This file was automatically generated by the
// updaterevision tool. Do not edit by hand. // updaterevision tool. Do not edit by hand.
#define ZD_SVN_REVISION_STRING "2601" #define ZD_SVN_REVISION_STRING "2613"
#define ZD_SVN_REVISION_NUMBER 2601 #define ZD_SVN_REVISION_NUMBER 2613

View file

@ -62,6 +62,9 @@ int CleanWidth, CleanHeight;
// Above minus 1 (or 1, if they are already 1) // Above minus 1 (or 1, if they are already 1)
int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_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); CVAR (Bool, hud_scale, false, CVAR_ARCHIVE);
// For routines that take RGB colors, cache the previous lookup in case there // 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 int LastPal = -1;
static uint32 LastRGB; static uint32 LastRGB;
static int PalFromRGB(uint32 rgb) static int PalFromRGB(uint32 rgb)
{ {
if (LastPal >= 0 && LastRGB == 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; double iyscale = 1 / yscale;
spryscale = FLOAT2FIXED(yscale); spryscale = FLOAT2FIXED(yscale);
assert(spryscale > 2);
#if 0 #if 0
// Fix precision errors that are noticeable at some resolutions // Fix precision errors that are noticeable at some resolutions
if ((y0 + parms.destheight) > (y0 + yscale * img->GetHeight())) 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 */ /* Other miscellaneous routines */

View file

@ -133,6 +133,7 @@ enum
class FFont; class FFont;
struct FRemapTable; struct FRemapTable;
class player_t; class player_t;
typedef uint32 angle_t;
// //
// VIDEO // VIDEO
@ -175,6 +176,11 @@ public:
// Fill an area with a texture // Fill an area with a texture
virtual void FlatFill (int left, int top, int right, int bottom, FTexture *src, bool local_origin=false); 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 // Set an area to a specified color
virtual void Clear (int left, int top, int right, int bottom, int palcolor, uint32 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; GatheringWipeScreen = false;
ScreenWipe = NULL; ScreenWipe = NULL;
InScene = false; InScene = false;
QuadExtra = new BufferedQuad[MAX_QUAD_BATCH]; QuadExtra = new BufferedTris[MAX_QUAD_BATCH];
Packs = NULL; Packs = NULL;
PixelDoubling = 0; PixelDoubling = 0;
SkipAt = -1; SkipAt = -1;
@ -1865,7 +1865,7 @@ void D3DFB::DrawPackedTextures(int packnum)
CheckQuadBatch(); CheckQuadBatch();
BufferedQuad *quad = &QuadExtra[QuadBatchPos]; BufferedTris *quad = &QuadExtra[QuadBatchPos];
FBVERTEX *vert = &VertexData[VertexPos]; FBVERTEX *vert = &VertexData[VertexPos];
quad->Group1 = 0; quad->Group1 = 0;
@ -1881,6 +1881,8 @@ void D3DFB::DrawPackedTextures(int packnum)
} }
quad->Palette = NULL; quad->Palette = NULL;
quad->Texture = pack->Tex; quad->Texture = pack->Tex;
quad->NumVerts = 4;
quad->NumTris = 2;
float x0 = float(x) - 0.5f; float x0 = float(x) - 0.5f;
float y0 = float(y) - 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; parms.bilinear = false;
D3DCOLOR color0, color1; D3DCOLOR color0, color1;
if (!SetStyle(tex, parms, color0, color1, QuadExtra[QuadBatchPos])) BufferedTris *quad = &QuadExtra[QuadBatchPos];
if (!SetStyle(tex, parms, color0, color1, *quad))
{ {
return; return;
} }
QuadExtra[QuadBatchPos].Texture = tex->Box->Owner->Tex; quad->Texture = tex->Box->Owner->Tex;
if (parms.bilinear) 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; 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(); CheckQuadBatch();
BufferedQuad *quad = &QuadExtra[QuadBatchPos]; BufferedTris *quad = &QuadExtra[QuadBatchPos];
FBVERTEX *vert = &VertexData[VertexPos]; FBVERTEX *vert = &VertexData[VertexPos];
quad->Group1 = 0; 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->Palette = NULL;
quad->Texture = tex->Box->Owner->Tex; quad->Texture = tex->Box->Owner->Tex;
quad->NumVerts = 4;
quad->NumTris = 2;
vert[0].x = x0; vert[0].x = x0;
vert[0].y = y0; vert[0].y = y0;
@ -3217,6 +3225,128 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
IndexPos += 6; 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 // 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) void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color)
{ {
BufferedQuad *quad; BufferedTris *quad;
FBVERTEX *verts; FBVERTEX *verts;
CheckQuadBatch(); CheckQuadBatch();
@ -3247,6 +3377,8 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR
} }
quad->Palette = NULL; quad->Palette = NULL;
quad->Texture = NULL; quad->Texture = NULL;
quad->NumVerts = 4;
quad->NumTris = 2;
verts[0].x = x; verts[0].x = x;
verts[0].y = y; verts[0].y = y;
@ -3300,17 +3432,19 @@ void D3DFB::AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR
// //
// D3DFB :: CheckQuadBatch // 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) if (BatchType == BATCH_Lines)
{ {
EndLineBatch(); EndLineBatch();
} }
else if (QuadBatchPos == MAX_QUAD_BATCH) else if (QuadBatchPos == MAX_QUAD_BATCH ||
VertexPos + numverts > NUM_VERTS ||
IndexPos + numtris * 3 > NUM_INDEXES)
{ {
EndQuadBatch(); EndQuadBatch();
} }
@ -3371,23 +3505,33 @@ void D3DFB::EndQuadBatch()
D3DDevice->SetIndices(IndexBuffer); D3DDevice->SetIndices(IndexBuffer);
bool uv_wrapped = false; bool uv_wrapped = false;
bool uv_should_wrap; bool uv_should_wrap;
int indexpos, vertpos;
indexpos = vertpos = 0;
for (int i = 0; i < QuadBatchPos; ) for (int i = 0; i < QuadBatchPos; )
{ {
const BufferedQuad *quad = &QuadExtra[i]; const BufferedTris *quad = &QuadExtra[i];
int j; 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 // Quads with matching parameters should be done with a single
// DrawPrimitive call. // DrawPrimitive call.
for (j = i + 1; j < QuadBatchPos; ++j) for (j = i + 1; j < QuadBatchPos; ++j)
{ {
const BufferedQuad *q2 = &QuadExtra[j]; const BufferedTris *q2 = &QuadExtra[j];
if (quad->Texture != q2->Texture || if (quad->Texture != q2->Texture ||
quad->Group1 != q2->Group1 || quad->Group1 != q2->Group1 ||
quad->Palette != q2->Palette) quad->Palette != q2->Palette)
{ {
break; break;
} }
indexpos += q2->NumTris * 3;
vertpos += q2->NumVerts;
} }
// Set the palette (if one) // Set the palette (if one)
@ -3467,7 +3611,12 @@ void D3DFB::EndQuadBatch()
} }
// Draw the quad // 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; i = j;
} }
if (uv_wrapped) 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(); D3DFORMAT fmt = tex->GetTexFormat();
FRenderStyle style = parms.style; FRenderStyle style = parms.style;

View file

@ -466,7 +466,7 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
{ {
fb->CheckQuadBatch(); fb->CheckQuadBatch();
BufferedQuad *quad = &fb->QuadExtra[fb->QuadBatchPos]; BufferedTris *quad = &fb->QuadExtra[fb->QuadBatchPos];
FBVERTEX *vert = &fb->VertexData[fb->VertexPos]; FBVERTEX *vert = &fb->VertexData[fb->VertexPos];
WORD *index = &fb->IndexData[fb->IndexPos]; WORD *index = &fb->IndexData[fb->IndexPos];
@ -475,6 +475,8 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb)
quad->ShaderNum = BQS_Plain; quad->ShaderNum = BQS_Plain;
quad->Palette = NULL; quad->Palette = NULL;
quad->Texture = fb->InitialWipeScreen; quad->Texture = fb->InitialWipeScreen;
quad->NumVerts = 4;
quad->NumTris = 2;
// Fill the vertex buffer. // Fill the vertex buffer.
float u0 = rect.left / float(fb->FBWidth); 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 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 DrawLine(int x0, int y0, int x1, int y1, int palColor, uint32 realcolor);
void DrawPixel(int x, int y, int palcolor, uint32 rgbcolor); 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); bool WipeStartScreen(int type);
void WipeEndScreen(); void WipeEndScreen();
bool WipeDo(int ticks); bool WipeDo(int ticks);
@ -278,7 +281,7 @@ private:
}; };
#define D3DFVF_FBVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1) #define D3DFVF_FBVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1)
struct BufferedQuad struct BufferedTris
{ {
union union
{ {
@ -293,6 +296,8 @@ private:
}; };
D3DPal *Palette; D3DPal *Palette;
IDirect3DTexture9 *Texture; IDirect3DTexture9 *Texture;
WORD NumVerts; // Number of _unique_ vertices used by this set.
WORD NumTris; // Number of triangles used by this set.
}; };
enum enum
@ -355,12 +360,12 @@ private:
void DrawPackedTextures(int packnum); void DrawPackedTextures(int packnum);
void DrawLetterbox(); void DrawLetterbox();
void Draw3DPart(bool copy3d); 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 D3DBLEND GetStyleAlpha(int type);
static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1); static void SetColorOverlay(DWORD color, float alpha, D3DCOLOR &color0, D3DCOLOR &color1);
void DoWindowedGamma(); void DoWindowedGamma();
void AddColorOnlyQuad(int left, int top, int width, int height, D3DCOLOR color); 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 BeginQuadBatch();
void EndQuadBatch(); void EndQuadBatch();
void BeginLineBatch(); void BeginLineBatch();
@ -433,7 +438,7 @@ private:
FBVERTEX *VertexData; FBVERTEX *VertexData;
IDirect3DIndexBuffer9 *IndexBuffer; IDirect3DIndexBuffer9 *IndexBuffer;
WORD *IndexData; WORD *IndexData;
BufferedQuad *QuadExtra; BufferedTris *QuadExtra;
int VertexPos; int VertexPos;
int IndexPos; int IndexPos;
int QuadBatchPos; int QuadBatchPos;

View file

@ -268,6 +268,8 @@ AMSTR_FOLLOWON = "Follow Mode ON";
AMSTR_FOLLOWOFF = "Follow Mode OFF"; AMSTR_FOLLOWOFF = "Follow Mode OFF";
AMSTR_GRIDON = "Grid ON"; AMSTR_GRIDON = "Grid ON";
AMSTR_GRIDOFF = "Grid OFF"; AMSTR_GRIDOFF = "Grid OFF";
AMSTR_TEXON = "Texture Mode ON";
AMSTR_TEXOFF = "Texture Mode OFF";
AMSTR_MARKEDSPOT = "Marked Spot"; AMSTR_MARKEDSPOT = "Marked Spot";
AMSTR_MARKSCLEARED = "All Marks Cleared"; AMSTR_MARKSCLEARED = "All Marks Cleared";
STSTR_MUS = "Music Change"; STSTR_MUS = "Music Change";
@ -1477,7 +1479,6 @@ TXT_RANDOMGOODBYE_1 = "Bye!";
TXT_RANDOMGOODBYE_2 = "Thanks, bye!"; TXT_RANDOMGOODBYE_2 = "Thanks, bye!";
TXT_RANDOMGOODBYE_3 = "See you later!"; TXT_RANDOMGOODBYE_3 = "See you later!";
TXT_HAVEENOUGH = "You seem to have enough!"; TXT_HAVEENOUGH = "You seem to have enough!";
TXT_GOAWAY = "Go away!";
// Skills: // Skills: