Update to ZDoom r898:

- Replaced P_PathTraverse with an FPathTraverse class, rewrote all code using
  P_PathTraverse and got rid of a lot of global variables in the process.
- Simplified the use of the checkarray in FBlockThingsIterator: Since the entire
  game runs single threaded there is no need for multiple check arrays if 
  recursive use occurs. Using the same array with a higher start index is 
  sufficient if the size is reset after finishing using the iterator.

April 9, 2008 (SBarInfo Update #17)
- Fixed: SBarInfo tried to calculate scaled offsets on unscaled status bars.
- Added: createpopup to SBarInfo.  No we don't have custom popups yet.  It only
  defines the transition effect.  Currently none or slideinbottom.
- Made the first argument of DrawMugShot optional (think of it as an overloaded
  function).  The use of the first argument is deprecated due to the event of
  per player class faces.
- More changes from DrawImage to screen->DrawTexture().  I guess I didn't get
  them all just yet.

- Added the FCriticalSection class in critsec.h to make it easier to
  use critical sections in other places besides the OPL player.
- Reimplemented snd_midiprecache, now for MIDI as well as MUS, and
  defaulting to false. 

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@89 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
Christoph Oelckers 2008-04-10 08:09:21 +00:00
parent 700adbf82f
commit b75a6dcea6
28 changed files with 1685 additions and 1262 deletions

View file

@ -1791,6 +1791,10 @@
RelativePath=".\src\win32\boing8.ico" RelativePath=".\src\win32\boing8.ico"
> >
</File> </File>
<File
RelativePath=".\src\win32\critsec.h"
>
</File>
<File <File
RelativePath=".\src\win32\cursor1.cur" RelativePath=".\src\win32\cursor1.cur"
> >
@ -2976,6 +2980,10 @@
/> />
</FileConfiguration> </FileConfiguration>
</File> </File>
<File
RelativePath=".\src\sdl\critsec.h"
>
</File>
<File <File
RelativePath=".\src\sdl\dikeys.h" RelativePath=".\src\sdl\dikeys.h"
> >

View file

@ -25,98 +25,87 @@
static FRandom pr_botdofire ("BotDoFire"); static FRandom pr_botdofire ("BotDoFire");
//Used with Reachable().
static AActor *looker;
static AActor *rtarget;
static bool reachable;
static fixed_t last_z;
static sector_t *last_s;
static fixed_t estimated_dist;
static bool PTR_Reachable (intercept_t *in) //Checks TRUE reachability from
//one looker to another. First mobj (looker) is looker.
bool FCajunMaster::Reachable (AActor *looker, AActor *rtarget)
{ {
fixed_t hitx, hity; if (looker == rtarget)
fixed_t frac; return false;
line_t *line;
AActor *thing;
fixed_t dist;
sector_t *s;
frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST); if ((rtarget->Sector->ceilingplane.ZatPoint (rtarget->x, rtarget->y) -
dist = FixedMul (frac, MAX_TRAVERSE_DIST); rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y))
< looker->height) //Where rtarget is, looker can't be.
return false;
hitx = trace.x + FixedMul (looker->momx, frac); sector_t *last_s = looker->Sector;
hity = trace.y + FixedMul (looker->momy, frac); fixed_t last_z = last_s->floorplane.ZatPoint (looker->x, looker->y);
fixed_t estimated_dist = P_AproxDistance (looker->x - rtarget->x, looker->y - rtarget->y);
bool reachable = true;
if (in->isaline) FPathTraverse it(looker->x+looker->momx, looker->y+looker->momy, rtarget->x, rtarget->y, PT_ADDLINES|PT_ADDTHINGS);
intercept_t *in;
while ((in = it.Next()))
{ {
line = in->d.line; fixed_t hitx, hity;
fixed_t frac;
line_t *line;
AActor *thing;
fixed_t dist;
sector_t *s;
if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS))) frac = in->frac - FixedDiv (4*FRACUNIT, MAX_TRAVERSE_DIST);
{ dist = FixedMul (frac, MAX_TRAVERSE_DIST);
return (reachable = false); //Cannot continue.
}
else
{
//Determine if going to use backsector/frontsector.
s = (line->backsector == last_s) ? line->frontsector : line->backsector;
fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity);
if (!bglobal.IsDangerous (s) && //Any nukage/lava? hitx = it.Trace().x + FixedMul (looker->momx, frac);
(floorheight <= (last_z+MAXMOVEHEIGHT) hity = it.Trace().y + FixedMul (looker->momy, frac);
&& ((ceilingheight == floorheight && line->special)
|| (ceilingheight - floorheight) >= looker->height))) //Does it fit? if (in->isaline)
{
line = in->d.line;
if (!(line->flags & ML_TWOSIDED) || (line->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING|ML_BLOCK_PLAYERS)))
{ {
last_z = floorheight; return false; //Cannot continue.
last_s = s;
return true;
} }
else else
{ {
return (reachable = false); //Determine if going to use backsector/frontsector.
s = (line->backsector == last_s) ? line->frontsector : line->backsector;
fixed_t ceilingheight = s->ceilingplane.ZatPoint (hitx, hity);
fixed_t floorheight = s->floorplane.ZatPoint (hitx, hity);
if (!bglobal.IsDangerous (s) && //Any nukage/lava?
(floorheight <= (last_z+MAXMOVEHEIGHT)
&& ((ceilingheight == floorheight && line->special)
|| (ceilingheight - floorheight) >= looker->height))) //Does it fit?
{
last_z = floorheight;
last_s = s;
continue;
}
else
{
return false;
}
} }
} }
if (dist > estimated_dist)
{
return true;
}
thing = in->d.thing;
if (thing == looker) //Can't reach self in this case.
continue;
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
{
return true;
}
reachable = false;
} }
if (dist > estimated_dist)
{
reachable = true;
return false; //Don't need to continue.
}
thing = in->d.thing;
if (thing == looker) //Can't reach self in this case.
return true;
if (thing == rtarget && (rtarget->Sector->floorplane.ZatPoint (rtarget->x, rtarget->y) <= (last_z+MAXMOVEHEIGHT)))
{
reachable = true;
return false;
}
reachable = false;
return true;
}
//Checks TRUE reachability from
//one actor to another. First mobj (actor) is looker.
bool FCajunMaster::Reachable (AActor *actor, AActor *target)
{
if (actor == target)
return false;
if ((target->Sector->ceilingplane.ZatPoint (target->x, target->y) -
target->Sector->floorplane.ZatPoint (target->x, target->y))
< actor->height) //Where target is, looker can't be.
return false;
looker = actor;
rtarget = target;
last_s = actor->Sector;
last_z = last_s->floorplane.ZatPoint (actor->x, actor->y);
reachable = true;
estimated_dist = P_AproxDistance (actor->x - target->x, actor->y - target->y);
P_PathTraverse (actor->x+actor->momx, actor->y+actor->momy, target->x, target->y, PT_ADDLINES|PT_ADDTHINGS, PTR_Reachable);
return reachable; return reachable;
} }

View file

@ -40,6 +40,7 @@
#include "v_collection.h" #include "v_collection.h"
#define NUMHUDS 9 #define NUMHUDS 9
#define NUMPOPUPS 3
class FBarTexture; class FBarTexture;
class FScanner; class FScanner;
@ -47,6 +48,35 @@ class FScanner;
struct SBarInfoCommand; //we need to be able to use this before it is defined. struct SBarInfoCommand; //we need to be able to use this before it is defined.
struct MugShotState; struct MugShotState;
//Popups!
enum PopupTransition
{
TRANSITION_NONE,
TRANSITION_SLIDEINBOTTOM,
};
struct Popup
{
PopupTransition transition;
bool opened;
bool moving;
int height;
int width;
int speed;
int x;
int y;
Popup();
void init();
void tick();
void open();
void close();
bool isDoneMoving();
int getXOffset();
int getYOffset();
};
//SBarInfo
struct SBarInfoBlock struct SBarInfoBlock
{ {
TArray<SBarInfoCommand> commands; TArray<SBarInfoCommand> commands;
@ -82,6 +112,7 @@ struct SBarInfo
{ {
TArray<FString> Images; TArray<FString> Images;
SBarInfoBlock huds[NUMHUDS]; SBarInfoBlock huds[NUMHUDS];
Popup popups[NUMPOPUPS];
bool automapbar; bool automapbar;
bool interpolateHealth; bool interpolateHealth;
bool interpolateArmor; bool interpolateArmor;
@ -276,6 +307,7 @@ enum //Key words
SBARINFO_LOWERHEALTHCAP, SBARINFO_LOWERHEALTHCAP,
SBARINFO_STATUSBAR, SBARINFO_STATUSBAR,
SBARINFO_MUGSHOT, SBARINFO_MUGSHOT,
SBARINFO_CREATEPOPUP,
}; };
enum //Bar types enum //Bar types
@ -340,7 +372,7 @@ public:
void ShowPop(int popnum); void ShowPop(int popnum);
void SetMugShotState(const char* stateName, bool waitTillDone=false); void SetMugShotState(const char* stateName, bool waitTillDone=false);
private: private:
void doCommands(SBarInfoBlock &block); void doCommands(SBarInfoBlock &block, int xOffset=0, int yOffset=0);
void DrawGraphic(FTexture* texture, int x, int y, int flags=0); void DrawGraphic(FTexture* texture, int x, int y, int flags=0);
void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0); void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0);
void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0, bool fillzeros=false); void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0, bool fillzeros=false);
@ -366,6 +398,7 @@ private:
int mugshotHealth; int mugshotHealth;
int chainWiggle; int chainWiggle;
int artiflash; int artiflash;
int pendingPopup;
int currentPopup; int currentPopup;
unsigned int invBarOffset; unsigned int invBarOffset;
FBarShader shader_horz_normal; FBarShader shader_horz_normal;

View file

@ -267,6 +267,8 @@ DSBarInfo::DSBarInfo () : DBaseStatusBar (SBarInfoScript->height),
chainWiggle = 0; chainWiggle = 0;
artiflash = 4; artiflash = 4;
currentState = NULL; currentState = NULL;
currentPopup = POP_None;
pendingPopup = POP_None;
} }
DSBarInfo::~DSBarInfo () DSBarInfo::~DSBarInfo ()
@ -320,11 +322,11 @@ void DSBarInfo::Draw (EHudState state)
if(currentPopup != POP_None) if(currentPopup != POP_None)
{ {
if(currentPopup == POP_Log) if(currentPopup == POP_Log)
doCommands(SBarInfoScript->huds[STBAR_POPUPLOG]); doCommands(SBarInfoScript->huds[STBAR_POPUPLOG], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
else if(currentPopup == POP_Keys) else if(currentPopup == POP_Keys)
doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS]); doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
else if(currentPopup == POP_Status) else if(currentPopup == POP_Status)
doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS]); doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS], SBarInfoScript->popups[currentPopup].getXOffset(), SBarInfoScript->popups[currentPopup].getYOffset());
} }
} }
@ -410,6 +412,16 @@ void DSBarInfo::Tick ()
rampageTimer = 0; rampageTimer = 0;
} }
mugshotHealth = CPlayer->health; mugshotHealth = CPlayer->health;
if(currentPopup != POP_None)
{
SBarInfoScript->popups[currentPopup].tick();
if(SBarInfoScript->popups[currentPopup].opened == false && SBarInfoScript->popups[currentPopup].isDoneMoving())
{
currentPopup = pendingPopup;
if(currentPopup != POP_None)
SBarInfoScript->popups[currentPopup].open();
}
}
} }
void DSBarInfo::ReceivedWeapon (AWeapon *weapon) void DSBarInfo::ReceivedWeapon (AWeapon *weapon)
@ -426,9 +438,20 @@ void DSBarInfo::ShowPop(int popnum)
{ {
DBaseStatusBar::ShowPop(popnum); DBaseStatusBar::ShowPop(popnum);
if(popnum != currentPopup) if(popnum != currentPopup)
currentPopup = popnum; {
pendingPopup = popnum;
}
else else
currentPopup = POP_None; pendingPopup = POP_None;
if(currentPopup != POP_None)
SBarInfoScript->popups[currentPopup].close();
else
{
currentPopup = pendingPopup;
pendingPopup = POP_None;
if(currentPopup != POP_None)
SBarInfoScript->popups[currentPopup].open();
}
} }
//Public so it can be called by ACS //Public so it can be called by ACS
@ -447,7 +470,7 @@ void DSBarInfo::SetMugShotState(const char* stateName, bool waitTillDone)
} }
} }
void DSBarInfo::doCommands(SBarInfoBlock &block) void DSBarInfo::doCommands(SBarInfoBlock &block, int xOffset, int yOffset)
{ {
//prepare ammo counts //prepare ammo counts
AAmmo *ammo1, *ammo2; AAmmo *ammo1, *ammo2;
@ -467,6 +490,8 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
for(unsigned int i = 0;i < block.commands.Size();i++) for(unsigned int i = 0;i < block.commands.Size();i++)
{ {
SBarInfoCommand& cmd = block.commands[i]; SBarInfoCommand& cmd = block.commands[i];
cmd.x += xOffset;
cmd.y += yOffset;
switch(cmd.type) //read and execute all the commands switch(cmd.type) //read and execute all the commands
{ {
case SBARINFO_DRAWSWITCHABLEIMAGE: //draw the alt image if we don't have the item else this is like a normal drawimage case SBARINFO_DRAWSWITCHABLEIMAGE: //draw the alt image if we don't have the item else this is like a normal drawimage
@ -712,7 +737,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
} }
else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY)) else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY))
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
break; break;
case SBARINFO_DRAWINVENTORYBAR: case SBARINFO_DRAWINVENTORYBAR:
@ -1063,7 +1088,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
((cmd.flags & GAMETYPE_COOPERATIVE) && multiplayer && !deathmatch) || ((cmd.flags & GAMETYPE_COOPERATIVE) && multiplayer && !deathmatch) ||
((cmd.flags & GAMETYPE_TEAMGAME) && teamplay)) ((cmd.flags & GAMETYPE_TEAMGAME) && teamplay))
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
break; break;
case SBARINFO_PLAYERCLASS: case SBARINFO_PLAYERCLASS:
@ -1072,14 +1097,14 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
int spawnClass = CPlayer->cls->ClassIndex; int spawnClass = CPlayer->cls->ClassIndex;
if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass) if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass)
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
break; break;
} }
case SBARINFO_ASPECTRATIO: case SBARINFO_ASPECTRATIO:
if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value) if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value)
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
break; break;
case SBARINFO_ISSELECTED: case SBARINFO_ISSELECTED:
@ -1090,16 +1115,16 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(weapon2 != NULL) if(weapon2 != NULL)
{ {
if((cmd.flags & SBARINFOEVENT_NOT) && (weapon1 != CPlayer->ReadyWeapon->GetSpecies() && weapon2 != CPlayer->ReadyWeapon->GetSpecies())) if((cmd.flags & SBARINFOEVENT_NOT) && (weapon1 != CPlayer->ReadyWeapon->GetSpecies() && weapon2 != CPlayer->ReadyWeapon->GetSpecies()))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
else if(!(cmd.flags & SBARINFOEVENT_NOT) && (weapon1 == CPlayer->ReadyWeapon->GetSpecies() || weapon2 == CPlayer->ReadyWeapon->GetSpecies())) else if(!(cmd.flags & SBARINFOEVENT_NOT) && (weapon1 == CPlayer->ReadyWeapon->GetSpecies() || weapon2 == CPlayer->ReadyWeapon->GetSpecies()))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
else else
{ {
if(!(cmd.flags & SBARINFOEVENT_NOT) && weapon1 == CPlayer->ReadyWeapon->GetSpecies()) if(!(cmd.flags & SBARINFOEVENT_NOT) && weapon1 == CPlayer->ReadyWeapon->GetSpecies())
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
else if((cmd.flags & SBARINFOEVENT_NOT) && weapon1 != CPlayer->ReadyWeapon->GetSpecies()) else if((cmd.flags & SBARINFOEVENT_NOT) && weapon1 != CPlayer->ReadyWeapon->GetSpecies())
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
} }
break; break;
@ -1115,7 +1140,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
bool usesammo2 = (AmmoType2 != NULL); bool usesammo2 = (AmmoType2 != NULL);
if(!(cmd.flags & SBARINFOEVENT_NOT) && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble. if(!(cmd.flags & SBARINFOEVENT_NOT) && !usesammo1 && !usesammo2) //if the weapon doesn't use ammo don't go though the trouble.
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
break; break;
} }
//Or means only 1 ammo type needs to match and means both need to match. //Or means only 1 ammo type needs to match and means both need to match.
@ -1126,11 +1151,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(((cmd.flags & SBARINFOEVENT_OR) && (match1 || match2)) || ((cmd.flags & SBARINFOEVENT_AND) && (match1 && match2))) if(((cmd.flags & SBARINFOEVENT_OR) && (match1 || match2)) || ((cmd.flags & SBARINFOEVENT_AND) && (match1 && match2)))
{ {
if(!(cmd.flags & SBARINFOEVENT_NOT)) if(!(cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
else if(cmd.flags & SBARINFOEVENT_NOT) else if(cmd.flags & SBARINFOEVENT_NOT)
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
} }
else //Every thing here could probably be one long if statement but then it would be more confusing. else //Every thing here could probably be one long if statement but then it would be more confusing.
@ -1138,11 +1163,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if((usesammo1 && (AmmoType1 == IfAmmo1)) || (usesammo2 && (AmmoType2 == IfAmmo1))) if((usesammo1 && (AmmoType1 == IfAmmo1)) || (usesammo2 && (AmmoType2 == IfAmmo1)))
{ {
if(!(cmd.flags & SBARINFOEVENT_NOT)) if(!(cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
else if(cmd.flags & SBARINFOEVENT_NOT) else if(cmd.flags & SBARINFOEVENT_NOT)
{ {
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
} }
} }
@ -1154,24 +1179,26 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
if(cmd.flags & SBARINFOEVENT_AND) if(cmd.flags & SBARINFOEVENT_AND)
{ {
if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
else if(cmd.flags & SBARINFOEVENT_OR) else if(cmd.flags & SBARINFOEVENT_OR)
{ {
if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
} }
else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT)) else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT)) else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
doCommands(cmd.subBlock); doCommands(cmd.subBlock, xOffset, yOffset);
break; break;
} }
} }
cmd.x -= xOffset;
cmd.y -= yOffset;
} }
} }
@ -1191,7 +1218,8 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
y += ST_Y; y += ST_Y;
int w = texture->GetScaledWidth(); int w = texture->GetScaledWidth();
int h = texture->GetScaledHeight() + y; int h = texture->GetScaledHeight() + y;
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); if(Scaled)
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
h -= y; h -= y;
if((flags & DRAWIMAGE_TRANSLATABLE)) if((flags & DRAWIMAGE_TRANSLATABLE))
{ {
@ -1238,7 +1266,8 @@ void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translatio
int ry = y + ST_Y; int ry = y + ST_Y;
int rw = character->GetScaledWidth(); int rw = character->GetScaledWidth();
int rh = character->GetScaledHeight(); int rh = character->GetScaledHeight();
screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true); if(Scaled)
screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true);
screen->DrawTexture(character, rx, ry, screen->DrawTexture(character, rx, ry,
DTA_DestWidth, rw, DTA_DestWidth, rw,
DTA_DestHeight, rh, DTA_DestHeight, rh,
@ -1297,7 +1326,8 @@ void DSBarInfo::DrawFace(FString &defaultFace, int accuracy, bool xdth, bool ani
y += ST_Y; y += ST_Y;
int w = face->GetScaledWidth(); int w = face->GetScaledWidth();
int h = face->GetScaledHeight(); int h = face->GetScaledHeight();
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); if(Scaled)
screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
screen->DrawTexture(face, x, y, screen->DrawTexture(face, x, y,
DTA_DestWidth, w, DTA_DestWidth, w,
DTA_DestHeight, h, DTA_DestHeight, h,
@ -1492,10 +1522,10 @@ void DSBarInfo::DrawGem(FTexture* chain, FTexture* gem, int value, int x, int y,
int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value); int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value);
if(chain != NULL) if(chain != NULL)
{ {
DrawImage(chain, x+(offset%chainsize), y); DrawGraphic(chain, x+(offset%chainsize), y);
} }
if(gem != NULL) if(gem != NULL)
DrawImage(gem, x+padleft+offset, y, translate ? getTranslation() : NULL); DrawGraphic(gem, x+padleft+offset, y, translate ? DRAWIMAGE_TRANSLATABLE : 0);
} }
FRemapTable* DSBarInfo::getTranslation() FRemapTable* DSBarInfo::getTranslation()

View file

@ -60,6 +60,7 @@ static const char *SBarInfoTopLevel[] =
"lowerhealthcap", "lowerhealthcap",
"statusbar", "statusbar",
"mugshot", "mugshot",
"createpopup",
NULL NULL
}; };
@ -305,6 +306,43 @@ void SBarInfo::ParseSBarInfo(int lump)
MugShotStates.Push(state); MugShotStates.Push(state);
break; break;
} }
case SBARINFO_CREATEPOPUP:
{
int pop = 0;
sc.MustGetToken(TK_Identifier);
if(sc.Compare("keys"))
pop = 0;
else if(sc.Compare("log"))
pop = 1;
else if(sc.Compare("status"))
pop = 2;
else
sc.ScriptError("Unkown popup: '%s'", sc.String);
Popup &popup = popups[pop];
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
popup.width = sc.Number;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
popup.height = sc.Number;
sc.MustGetToken(',');
if(!sc.CheckToken(TK_None))
{
sc.MustGetToken(TK_Identifier);
if(sc.Compare("slideinbottom"))
{
popup.transition = TRANSITION_SLIDEINBOTTOM;
sc.MustGetToken(',');
sc.MustGetToken(TK_IntConst);
popup.speed = sc.Number;
}
else
sc.ScriptError("Unkown transition type: '%s'", sc.String);
}
popup.init();
sc.MustGetToken(';');
break;
}
} }
} }
} }
@ -553,9 +591,11 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
sc.MustGetToken(';'); sc.MustGetToken(';');
break; break;
case SBARINFO_DRAWMUGSHOT: case SBARINFO_DRAWMUGSHOT:
sc.MustGetToken(TK_StringConst); if(sc.CheckToken(TK_StringConst))
cmd.setString(sc, sc.String, 0, 3, true); {
sc.MustGetToken(','); cmd.setString(sc, sc.String, 0, 3, true);
sc.MustGetToken(',');
}
sc.MustGetToken(TK_IntConst); //accuracy sc.MustGetToken(TK_IntConst); //accuracy
if(sc.Number < 1 || sc.Number > 9) if(sc.Number < 1 || sc.Number > 9)
sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number); sc.ScriptError("Expected a number between 1 and 9, got %d instead.", sc.Number);
@ -1237,6 +1277,88 @@ const MugShotState *FindMugShotState(FString state)
return NULL; return NULL;
} }
//Popup
Popup::Popup()
{
transition = TRANSITION_NONE;
height = 320;
width = 200;
speed = 0;
x = 320;
y = 200;
opened = false;
moving = false;
}
void Popup::init()
{
x = width;
y = height;
if(transition == TRANSITION_SLIDEINBOTTOM)
{
x = 0;
}
}
void Popup::tick()
{
if(transition == TRANSITION_SLIDEINBOTTOM)
{
if(moving)
{
if(opened)
y -= clamp(height + (y - height), 1, speed);
else
y += clamp(height - y, 1, speed);
}
if(y != 0 && y != height)
moving = true;
else
moving = false;
}
else
{
moving = false;
if(opened)
{
y = 0;
x = 0;
}
else
{
y = height;
x = width;
}
}
}
bool Popup::isDoneMoving()
{
return !moving;
}
int Popup::getXOffset()
{
return x;
}
int Popup::getYOffset()
{
return y;
}
void Popup::open()
{
opened = true;
moving = true;
}
void Popup::close()
{
opened = false;
moving = true;
}
//Used to allow replacements of states //Used to allow replacements of states
int FindMugShotStateIndex(FName state) int FindMugShotStateIndex(FName state)
{ {

View file

@ -70,6 +70,8 @@ EXTERN_CVAR (Bool, snd_pitched)
EXTERN_CVAR (Color, am_wallcolor) EXTERN_CVAR (Color, am_wallcolor)
EXTERN_CVAR (Color, am_fdwallcolor) EXTERN_CVAR (Color, am_fdwallcolor)
EXTERN_CVAR (Color, am_cdwallcolor) EXTERN_CVAR (Color, am_cdwallcolor)
EXTERN_CVAR (Float, spc_amp)
EXTERN_CVAR (Bool, snd_midiprecache)
FString WeaponSection; FString WeaponSection;
@ -297,14 +299,15 @@ void FGameConfigFile::DoGlobalSetup ()
} }
if (last < 206) if (last < 206)
{ // spc_amp is now a float, not an int. { // spc_amp is now a float, not an int.
FBaseCVar *amp = FindCVar ("spc_amp", NULL); if (spc_amp > 16)
if (amp != NULL)
{ {
UCVarValue val = amp->GetGenericRep(CVAR_Float); spc_amp = spc_amp / 16.f;
val.Float /= 16.f;
amp->SetGenericRep(val, CVAR_Float);
} }
} }
if (last < 207)
{ // Now that snd_midiprecache works again, you probably don't want it on.
snd_midiprecache = false;
}
} }
} }
} }

View file

@ -40,12 +40,59 @@ void FBoundingBox::AddToBox (fixed_t x, fixed_t y)
m_Box[BOXTOP] = y; m_Box[BOXTOP] = y;
} }
//==========================================================================
//
// FBoundingBox :: BoxOnLineSide
//
// Considers the line to be infinite
// Returns side 0 or 1, -1 if box crosses the line.
//
//==========================================================================
int FBoundingBox::BoxOnLineSide (const line_t *ld) const int FBoundingBox::BoxOnLineSide (const line_t *ld) const
{ {
return P_BoxOnLineSide(m_Box, ld); int p1;
int p2;
switch (ld->slopetype)
{
case ST_HORIZONTAL:
p1 = m_Box[BOXTOP] > ld->v1->y;
p2 = m_Box[BOXBOTTOM] > ld->v1->y;
if (ld->dx < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_VERTICAL:
p1 = m_Box[BOXRIGHT] < ld->v1->x;
p2 = m_Box[BOXLEFT] < ld->v1->x;
if (ld->dy < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_POSITIVE:
p1 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXTOP], ld);
p2 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXBOTTOM], ld);
break;
case ST_NEGATIVE:
default: // Just to assure GCC that p1 and p2 really do get initialized
p1 = P_PointOnLineSide (m_Box[BOXRIGHT], m_Box[BOXTOP], ld);
p2 = P_PointOnLineSide (m_Box[BOXLEFT], m_Box[BOXBOTTOM], ld);
break;
}
return (p1 == p2) ? p1 : -1;
} }

View file

@ -71,6 +71,7 @@ typedef struct
WORD NumSecondaryChans; WORD NumSecondaryChans;
WORD NumInstruments; WORD NumInstruments;
WORD Pad; WORD Pad;
// WORD UsedInstruments[NumInstruments];
} MUSHeader; } MUSHeader;
bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile); bool ProduceMIDI (const BYTE *musBuf, TArray<BYTE> &outFile);

View file

@ -261,9 +261,9 @@ void OPLMIDIDevice::Stop()
int OPLMIDIDevice::StreamOutSync(MIDIHDR *header) int OPLMIDIDevice::StreamOutSync(MIDIHDR *header)
{ {
Serialize(); ChipAccess.Enter();
StreamOut(header); StreamOut(header);
Unserialize(); ChipAccess.Leave();
return 0; return 0;
} }

View file

@ -28,59 +28,22 @@ OPLmusicBlock::OPLmusicBlock()
TwoChips = !opl_onechip; TwoChips = !opl_onechip;
Looping = false; Looping = false;
io = NULL; io = NULL;
#ifdef _WIN32
InitializeCriticalSection (&ChipAccess);
#else
ChipAccess = SDL_CreateMutex ();
if (ChipAccess == NULL)
{
return;
}
#endif
io = new OPLio; io = new OPLio;
} }
OPLmusicBlock::~OPLmusicBlock() OPLmusicBlock::~OPLmusicBlock()
{ {
BlockForStats = NULL; BlockForStats = NULL;
#ifdef _WIN32
DeleteCriticalSection (&ChipAccess);
#else
if (ChipAccess != NULL)
{
SDL_DestroyMutex (ChipAccess);
ChipAccess = NULL;
}
#endif
delete io; delete io;
} }
void OPLmusicBlock::Serialize()
{
#ifdef _WIN32
EnterCriticalSection (&ChipAccess);
#else
if (SDL_mutexP (ChipAccess) != 0)
return;
#endif
}
void OPLmusicBlock::Unserialize()
{
#ifdef _WIN32
LeaveCriticalSection (&ChipAccess);
#else
SDL_mutexV (ChipAccess);
#endif
}
void OPLmusicBlock::ResetChips () void OPLmusicBlock::ResetChips ()
{ {
TwoChips = !opl_onechip; TwoChips = !opl_onechip;
Serialize(); ChipAccess.Enter();
io->OPLdeinit (); io->OPLdeinit ();
io->OPLinit (TwoChips + 1); io->OPLinit (TwoChips + 1);
Unserialize(); ChipAccess.Leave();
} }
void OPLmusicBlock::Restart() void OPLmusicBlock::Restart()
@ -237,7 +200,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
samples1 = samples; samples1 = samples;
memset(buff, 0, numbytes); memset(buff, 0, numbytes);
Serialize(); ChipAccess.Enter();
while (numsamples > 0) while (numsamples > 0)
{ {
double ticky = NextTickIn; double ticky = NextTickIn;
@ -294,7 +257,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes)
} }
} }
} }
Unserialize(); ChipAccess.Leave();
return res; return res;
} }

View file

@ -1,11 +1,4 @@
#ifdef _WIN32 #include "critsec.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define USE_WINDOWS_DWORD
#else
#include <SDL.h>
#endif
#include "muslib.h" #include "muslib.h"
#include "files.h" #include "files.h"
@ -23,19 +16,12 @@ public:
protected: protected:
virtual int PlayTick() = 0; virtual int PlayTick() = 0;
void Serialize();
void Unserialize();
double NextTickIn; double NextTickIn;
double SamplesPerTick; double SamplesPerTick;
bool TwoChips; bool TwoChips;
bool Looping; bool Looping;
#ifdef _WIN32 FCriticalSection ChipAccess;
CRITICAL_SECTION ChipAccess;
#else
SDL_mutex *ChipAccess;
#endif
}; };
class OPLmusicFile : public OPLmusicBlock class OPLmusicFile : public OPLmusicBlock

View file

@ -61,7 +61,6 @@
#define BASETHRESHOLD 100 #define BASETHRESHOLD 100
// //
// P_PSPR // P_PSPR
// //
@ -161,6 +160,7 @@ typedef struct
{ {
fixed_t frac; // along trace line fixed_t frac; // along trace line
bool isaline; bool isaline;
bool done;
union { union {
AActor *thing; AActor *thing;
line_t *line; line_t *line;
@ -216,7 +216,6 @@ inline void P_MakeDivline (const line_t *li, divline_t *dl)
} }
fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1);
int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld);
struct FLineOpening struct FLineOpening
{ {
@ -256,10 +255,7 @@ public:
class FBlockThingsIterator class FBlockThingsIterator
{ {
typedef TArray<AActor *> BTChecked; static TArray<AActor *> CheckArray;
static TDeletingArray< BTChecked* > FreeBTChecked;
int minx, maxx; int minx, maxx;
int miny, maxy; int miny, maxy;
@ -267,21 +263,24 @@ class FBlockThingsIterator
int curx, cury; int curx, cury;
bool dontfreecheck; bool dontfreecheck;
BTChecked *checkarray; int checkindex;
FBlockNode *block; FBlockNode *block;
BTChecked *GetCheckArray();
void FreeCheckArray();
void StartBlock(int x, int y); void StartBlock(int x, int y);
// The following 3 functions are only for use in the path traverser
// and therefore declared private.
static int GetCheckIndex();
static void SetCheckIndex(int newvalue);
FBlockThingsIterator(int x, int y, int checkindex);
friend class FPathTraverse;
public: public:
FBlockThingsIterator(int minx, int miny, int maxx, int maxy, TArray<AActor *> *check = NULL); FBlockThingsIterator(int minx, int miny, int maxx, int maxy);
FBlockThingsIterator(const FBoundingBox &box); FBlockThingsIterator(const FBoundingBox &box);
~FBlockThingsIterator() ~FBlockThingsIterator();
{
if (!dontfreecheck) FreeCheckArray();
}
AActor *Next(); AActor *Next();
void Reset() { StartBlock(minx, miny); } void Reset() { StartBlock(minx, miny); }
}; };
@ -294,20 +293,31 @@ public:
AActor *Next(); AActor *Next();
}; };
class FPathTraverse
{
static TArray<intercept_t> intercepts;
divline_t trace;
unsigned int intercept_index;
unsigned int intercept_count;
fixed_t maxfrac;
unsigned int count;
void AddLineIntercepts(int bx, int by);
void AddThingIntercepts(int bx, int by, int checkindex);
public:
intercept_t *Next();
FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags);
~FPathTraverse();
const divline_t &Trace() const { return trace; }
};
#define PT_ADDLINES 1 #define PT_ADDLINES 1
#define PT_ADDTHINGS 2 #define PT_ADDTHINGS 2
extern divline_t trace;
bool
P_PathTraverse
( fixed_t x1,
fixed_t y1,
fixed_t x2,
fixed_t y2,
int flags,
bool (*trav) (intercept_t *));
AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int)); AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int));
AActor *P_RoughMonsterSearch (AActor *mo, int distance); AActor *P_RoughMonsterSearch (AActor *mo, int distance);
@ -386,9 +396,7 @@ bool P_CheckMissileSpawn (AActor *missile);
void P_PlaySpawnSound(AActor *missile, AActor *spawner); void P_PlaySpawnSound(AActor *missile, AActor *spawner);
// [RH] Position the chasecam // [RH] Position the chasecam
void P_AimCamera (AActor *t1); void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec);
extern fixed_t CameraX, CameraY, CameraZ;
extern sector_t *CameraSector;
// [RH] Means of death // [RH] Means of death
void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, bool hurtSelf, bool dodamage=true); void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, bool hurtSelf, bool dodamage=true);
@ -434,9 +442,7 @@ extern FBlockNode** blocklinks; // for thing chains
// P_INTER // P_INTER
// //
void P_TouchSpecialThing (AActor *special, AActor *toucher); void P_TouchSpecialThing (AActor *special, AActor *toucher);
void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0);
bool P_GiveBody (AActor *actor, int num); bool P_GiveBody (AActor *actor, int num);
void P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); void P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison);
void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound);

File diff suppressed because it is too large Load diff

View file

@ -59,57 +59,6 @@ fixed_t P_AproxDistance (fixed_t dx, fixed_t dy)
return (dx < dy) ? dx+dy-(dx>>1) : dx+dy-(dy>>1); return (dx < dy) ? dx+dy-(dx>>1) : dx+dy-(dy>>1);
} }
//==========================================================================
//
// P_BoxOnLineSide
//
// Considers the line to be infinite
// Returns side 0 or 1, -1 if box crosses the line.
//
//==========================================================================
int P_BoxOnLineSide (const fixed_t *tmbox, const line_t *ld)
{
int p1;
int p2;
switch (ld->slopetype)
{
case ST_HORIZONTAL:
p1 = tmbox[BOXTOP] > ld->v1->y;
p2 = tmbox[BOXBOTTOM] > ld->v1->y;
if (ld->dx < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_VERTICAL:
p1 = tmbox[BOXRIGHT] < ld->v1->x;
p2 = tmbox[BOXLEFT] < ld->v1->x;
if (ld->dy < 0)
{
p1 ^= 1;
p2 ^= 1;
}
break;
case ST_POSITIVE:
p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
break;
case ST_NEGATIVE:
default: // Just to assure GCC that p1 and p2 really do get initialized
p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
break;
}
return (p1 == p2) ? p1 : -1;
}
//========================================================================== //==========================================================================
// //
// P_InterceptVector // P_InterceptVector
@ -270,6 +219,7 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
// THING POSITION SETTING // THING POSITION SETTING
// //
//==========================================================================
// //
// P_UnsetThingPosition // P_UnsetThingPosition
// Unlinks a thing from block map and sectors. // Unlinks a thing from block map and sectors.
@ -277,6 +227,8 @@ void P_LineOpening (FLineOpening &open, AActor *actor, const line_t *linedef,
// lookups maintaining lists of things inside // lookups maintaining lists of things inside
// these structures need to be updated. // these structures need to be updated.
// //
//==========================================================================
void AActor::UnlinkFromWorld () void AActor::UnlinkFromWorld ()
{ {
sector_list = NULL; sector_list = NULL;
@ -332,11 +284,14 @@ void AActor::UnlinkFromWorld ()
} }
//==========================================================================
// //
// P_SetThingPosition // P_SetThingPosition
// Links a thing into both a block and a subsector based on it's x y. // Links a thing into both a block and a subsector based on it's x y.
// Sets thing->sector properly // Sets thing->sector properly
// //
//==========================================================================
void AActor::LinkToWorld (bool buggy) void AActor::LinkToWorld (bool buggy)
{ {
// link into subsector // link into subsector
@ -440,12 +395,15 @@ void AActor::LinkToWorld (sector_t *sec)
} }
} }
//==========================================================================
// //
// [RH] LinkToWorldForMapThing // [RH] LinkToWorldForMapThing
// //
// Emulate buggy PointOnLineSide and fix actors that lie on // Emulate buggy PointOnLineSide and fix actors that lie on
// lines to compensate for some IWAD maps. // lines to compensate for some IWAD maps.
// //
//==========================================================================
static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node) static int R_PointOnSideSlow (fixed_t x, fixed_t y, node_t *node)
{ {
// [RH] This might have been faster than two multiplies and an // [RH] This might have been faster than two multiplies and an
@ -549,7 +507,6 @@ sector_t *AActor::LinkToWorldForMapThing ()
} }
} }
#if 1
// Not inside the line's bounding box // Not inside the line's bounding box
if (x + radius <= ldef->bbox[BOXLEFT] if (x + radius <= ldef->bbox[BOXLEFT]
|| x - radius >= ldef->bbox[BOXRIGHT] || x - radius >= ldef->bbox[BOXRIGHT]
@ -593,39 +550,6 @@ sector_t *AActor::LinkToWorldForMapThing ()
y += FixedMul(distance, finesine[finean]); y += FixedMul(distance, finesine[finean]);
return P_PointInSector (x, y); return P_PointInSector (x, y);
} }
#else
if (DMulScale32 (y - ldef->v1->y, ldef->dx, ldef->v1->x - x, ldef->dy) == 0)
{
// It touches the infinite line; now make sure it touches the linedef
SQWORD num, den;
den = (SQWORD)ldef->dx*ldef->dx + (SQWORD)ldef->dy*ldef->dy;
if (den != 0)
{
num = (SQWORD)(x-ldef->v1->x)*ldef->dx+(SQWORD)(y-ldef->v1->y)*ldef->dy;
if (num >= 0 && num <= den)
{
DPrintf ("%s at (%d,%d) lies directly on %s line %d\n",
this->GetClass()->TypeName.GetChars(), x>>FRACBITS, y>>FRACBITS,
ldef->dx == 0? "vertical" : ldef->dy == 0? "horizontal" : "diagonal",
ldef-lines);
angle_t finean = R_PointToAngle2 (0, 0, ldef->dx, ldef->dy);
if (ldef->backsector != NULL && ldef->backsector == ssec->sector)
{
finean += ANGLE_90;
}
else
{
finean -= ANGLE_90;
}
finean >>= ANGLETOFINESHIFT;
x += finecosine[finean]) >> 2;
y += finesine[finean]) >> 2;
break;
}
}
}
#endif
} }
} }
} }
@ -815,34 +739,20 @@ line_t *FBlockLinesIterator::Next()
//=========================================================================== //===========================================================================
// //
// FBlockThingsIterator :: GetCheckArray // FBlockThingsIterator :: CheckArray
// //
//=========================================================================== //===========================================================================
TDeletingArray< FBlockThingsIterator::BTChecked* > FBlockThingsIterator::FreeBTChecked; TArray<AActor *> FBlockThingsIterator::CheckArray(32);
FBlockThingsIterator::BTChecked *FBlockThingsIterator::GetCheckArray() int FBlockThingsIterator::GetCheckIndex()
{ {
dontfreecheck = false; return CheckArray.Size();
if (FreeBTChecked.Size() != 0)
{
BTChecked *ret;
FreeBTChecked.Pop(ret);
ret->Clear();
return ret;
}
return new BTChecked();
} }
//=========================================================================== void FBlockThingsIterator::SetCheckIndex(int newvalue)
//
// FBlockThingsIterator :: FreeCheckArray
//
//===========================================================================
void FBlockThingsIterator::FreeCheckArray()
{ {
FreeBTChecked.Push(checkarray); CheckArray.Resize(newvalue);
} }
//=========================================================================== //===========================================================================
@ -851,17 +761,19 @@ void FBlockThingsIterator::FreeCheckArray()
// //
//=========================================================================== //===========================================================================
FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy, TArray<AActor *> *Check) FBlockThingsIterator::FBlockThingsIterator(int x, int y, int check)
{ {
if (Check != NULL) checkindex = check;
{ dontfreecheck = true;
checkarray = Check; minx = maxx = x;
dontfreecheck = true; miny = maxy = y;
} Reset();
else }
{
checkarray = GetCheckArray(); FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int _maxy)
} {
checkindex = CheckArray.Size();
dontfreecheck = false;
minx = _minx; minx = _minx;
maxx = _maxx; maxx = _maxx;
miny = _miny; miny = _miny;
@ -871,7 +783,8 @@ FBlockThingsIterator::FBlockThingsIterator(int _minx, int _miny, int _maxx, int
FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box) FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
{ {
checkarray = GetCheckArray(); checkindex = CheckArray.Size();
dontfreecheck = false;
maxy = (box.Top() - bmaporgy) >> MAPBLOCKSHIFT; maxy = (box.Top() - bmaporgy) >> MAPBLOCKSHIFT;
miny = (box.Bottom() - bmaporgy) >> MAPBLOCKSHIFT; miny = (box.Bottom() - bmaporgy) >> MAPBLOCKSHIFT;
maxx = (box.Right() - bmaporgx) >> MAPBLOCKSHIFT; maxx = (box.Right() - bmaporgx) >> MAPBLOCKSHIFT;
@ -879,6 +792,17 @@ FBlockThingsIterator::FBlockThingsIterator(const FBoundingBox &box)
Reset(); Reset();
} }
//===========================================================================
//
// FBlockThingsIterator :: FreeCheckArray
//
//===========================================================================
FBlockThingsIterator::~FBlockThingsIterator()
{
if (!dontfreecheck) CheckArray.Resize(checkindex);
}
//=========================================================================== //===========================================================================
// //
// FBlockThingsIterator :: StartBlock // FBlockThingsIterator :: StartBlock
@ -917,16 +841,16 @@ AActor *FBlockThingsIterator::Next()
block = block->NextActor; block = block->NextActor;
// Don't recheck things that were already checked // Don't recheck things that were already checked
for (i = (int)checkarray->Size() - 1; i >= 0; --i) for (i = (int)CheckArray.Size() - 1; i >= checkindex; --i)
{ {
if ((*checkarray)[i] == me) if (CheckArray[i] == me)
{ {
break; break;
} }
} }
if (i < 0) if (i < checkindex)
{ {
checkarray->Push (me); CheckArray.Push (me);
return me; return me;
} }
} }
@ -974,16 +898,18 @@ AActor *FRadiusThingsIterator::Next()
} }
//===========================================================================
// //
// INTERCEPT ROUTINES // FPathTraverse :: Intercepts
// //
TArray<intercept_t> intercepts (128); //===========================================================================
divline_t trace; TArray<intercept_t> FPathTraverse::intercepts(128);
int ptflags;
//===========================================================================
// //
// PIT_AddLineIntercepts. // FPathTraverse :: AddLineIntercepts.
// Looks for lines in the given block // Looks for lines in the given block
// that intercept the given trace // that intercept the given trace
// to add to the intercepts list. // to add to the intercepts list.
@ -991,7 +917,9 @@ int ptflags;
// A line is crossed if its endpoints // A line is crossed if its endpoints
// are on opposite sides of the trace. // are on opposite sides of the trace.
// //
void P_AddLineIntercepts(int bx, int by) //===========================================================================
void FPathTraverse::AddLineIntercepts(int bx, int by)
{ {
FBlockLinesIterator it(bx, by, bx, by, true); FBlockLinesIterator it(bx, by, bx, by, true);
line_t *ld; line_t *ld;
@ -1030,18 +958,22 @@ void P_AddLineIntercepts(int bx, int by)
newintercept.frac = frac; newintercept.frac = frac;
newintercept.isaline = true; newintercept.isaline = true;
newintercept.done = false;
newintercept.d.line = ld; newintercept.d.line = ld;
intercepts.Push (newintercept); intercepts.Push (newintercept);
} }
} }
//===========================================================================
// //
// PIT_AddThingIntercepts // FPathTraverse :: AddThingIntercepts
// //
void P_AddThingIntercepts (int bx, int by, TArray<AActor*> &checkbt) //===========================================================================
void FPathTraverse::AddThingIntercepts (int bx, int by, int checkindex)
{ {
FBlockThingsIterator it(bx, by, bx, by, &checkbt); FBlockThingsIterator it(bx, by, checkindex);
AActor *thing; AActor *thing;
while ((thing = it.Next())) while ((thing = it.Next()))
@ -1106,6 +1038,7 @@ void P_AddThingIntercepts (int bx, int by, TArray<AActor*> &checkbt)
intercept_t newintercept; intercept_t newintercept;
newintercept.frac = frac; newintercept.frac = frac;
newintercept.isaline = false; newintercept.isaline = false;
newintercept.done = false;
newintercept.d.thing = thing; newintercept.d.thing = thing;
intercepts.Push (newintercept); intercepts.Push (newintercept);
continue; continue;
@ -1120,6 +1053,7 @@ void P_AddThingIntercepts (int bx, int by, TArray<AActor*> &checkbt)
intercept_t newintercept; intercept_t newintercept;
newintercept.frac = 0; newintercept.frac = 0;
newintercept.isaline = false; newintercept.isaline = false;
newintercept.done = false;
newintercept.d.thing = thing; newintercept.d.thing = thing;
intercepts.Push (newintercept); intercepts.Push (newintercept);
} }
@ -1127,60 +1061,41 @@ void P_AddThingIntercepts (int bx, int by, TArray<AActor*> &checkbt)
} }
//===========================================================================
// //
// P_TraverseIntercepts // FPathTraverse :: Next
// Returns true if the traverser function returns true
// for all lines.
// //
bool P_TraverseIntercepts (traverser_t func, fixed_t maxfrac) //===========================================================================
intercept_t *FPathTraverse::Next()
{ {
unsigned int count;
fixed_t dist;
unsigned int scanpos;
intercept_t *scan;
intercept_t *in = NULL; intercept_t *in = NULL;
count = intercepts.Size (); fixed_t dist = FIXED_MAX;
for (unsigned scanpos = intercept_index; scanpos < intercepts.Size (); scanpos++)
while (count--)
{ {
dist = FIXED_MAX; intercept_t *scan = &intercepts[scanpos];
for (scanpos = 0; scanpos < intercepts.Size (); scanpos++) if (scan->frac < dist && !scan->done)
{ {
scan = &intercepts[scanpos]; dist = scan->frac;
if (scan->frac < dist) in = scan;
{
dist = scan->frac;
in = scan;
}
} }
if (dist > maxfrac || in == NULL)
return true; // checked everything in range
if (!func (in))
return false; // don't bother going farther
in->frac = FIXED_MAX;
} }
return true; // everything was traversed if (dist > maxfrac || in == NULL) return NULL; // checked everything in range
in->done = true;
return in;
} }
//===========================================================================
// //
// P_PathTraverse // FPathTraverse
// Traces a line from x1,y1 to x2,y2, // Traces a line from x1,y1 to x2,y2,
// calling the traverser function for each.
// Returns true if the traverser function returns true
// for all lines.
// //
bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags, bool (*trav) (intercept_t *)) //===========================================================================
{
static TArray<AActor *> pathbt;
FPathTraverse::FPathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags)
{
fixed_t xt1; fixed_t xt1;
fixed_t yt1; fixed_t yt1;
fixed_t xt2; fixed_t xt2;
@ -1203,8 +1118,7 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
int count; int count;
validcount++; validcount++;
intercepts.Clear (); intercept_index = intercepts.Size();
pathbt.Clear ();
if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0) if ( ((x1-bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
x1 += FRACUNIT; // don't side exactly on a line x1 += FRACUNIT; // don't side exactly on a line
@ -1295,16 +1209,18 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
mapx = xt1; mapx = xt1;
mapy = yt1; mapy = yt1;
// we want to use one list of checked actors for the entire operation
int BTI_CheckIndex = FBlockThingsIterator::GetCheckIndex();
for (count = 0 ; count < 100 ; count++) for (count = 0 ; count < 100 ; count++)
{ {
if (flags & PT_ADDLINES) if (flags & PT_ADDLINES)
{ {
P_AddLineIntercepts(mapx, mapy); AddLineIntercepts(mapx, mapy);
} }
if (flags & PT_ADDTHINGS) if (flags & PT_ADDTHINGS)
{ {
P_AddThingIntercepts(mapx, mapy, pathbt); AddThingIntercepts(mapx, mapy, BTI_CheckIndex);
} }
if (mapx == xt2 && mapy == yt2) if (mapx == xt2 && mapy == yt2)
@ -1336,14 +1252,14 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
// be checked. // be checked.
if (flags & PT_ADDLINES) if (flags & PT_ADDLINES)
{ {
P_AddLineIntercepts(mapx + mapxstep, mapy); AddLineIntercepts(mapx + mapxstep, mapy);
P_AddLineIntercepts(mapx, mapy + mapystep); AddLineIntercepts(mapx, mapy + mapystep);
} }
if (flags & PT_ADDTHINGS) if (flags & PT_ADDTHINGS)
{ {
P_AddThingIntercepts(mapx + mapxstep, mapy, pathbt); AddThingIntercepts(mapx + mapxstep, mapy, BTI_CheckIndex);
P_AddThingIntercepts(mapx, mapy + mapystep, pathbt); AddThingIntercepts(mapx, mapy + mapystep, BTI_CheckIndex);
} }
xintercept += xstep; xintercept += xstep;
yintercept += ystep; yintercept += ystep;
@ -1352,10 +1268,16 @@ bool P_PathTraverse (fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags,
break; break;
} }
} }
// go through the sorted list FBlockThingsIterator::SetCheckIndex(BTI_CheckIndex);
return P_TraverseIntercepts ( trav, FRACUNIT ); maxfrac = FRACUNIT;
} }
FPathTraverse::~FPathTraverse()
{
intercepts.Resize(intercept_index);
}
//=========================================================================== //===========================================================================
// //
// P_RoughMonsterSearch // P_RoughMonsterSearch

View file

@ -80,7 +80,6 @@ static void PlayerLandedOnThing (AActor *mo, AActor *onmobj);
extern cycle_t BotSupportCycles; extern cycle_t BotSupportCycles;
extern cycle_t BotWTG; extern cycle_t BotWTG;
extern fixed_t attackrange;
EXTERN_CVAR (Bool, r_drawfuzz); EXTERN_CVAR (Bool, r_drawfuzz);
EXTERN_CVAR (Int, cl_rockettrails) EXTERN_CVAR (Int, cl_rockettrails)

View file

@ -43,8 +43,7 @@ static int sightcounts[6];
static cycle_t SightCycles; static cycle_t SightCycles;
static cycle_t MaxSightCycles; static cycle_t MaxSightCycles;
// we might as well use the global intercepts array instead of creating a new one static TArray<intercept_t> intercepts (128);
extern TArray<intercept_t> intercepts;
class SightCheck class SightCheck
{ {

View file

@ -36,70 +36,73 @@
#include "p_local.h" #include "p_local.h"
#include "i_system.h" #include "i_system.h"
static fixed_t StartZ; struct FTraceInfo
static fixed_t Vx, Vy, Vz; {
static DWORD ActorMask, WallMask; fixed_t StartX, StartY, StartZ;
static AActor *IgnoreThis; fixed_t Vx, Vy, Vz;
static FTraceResults *Results; DWORD ActorMask, WallMask;
static sector_t *CurSector; AActor *IgnoreThis;
static fixed_t MaxDist; FTraceResults *Results;
static fixed_t EnterDist; sector_t *CurSector;
static bool (*TraceCallback)(FTraceResults &res); fixed_t MaxDist;
static DWORD TraceFlags; fixed_t EnterDist;
bool (*TraceCallback)(FTraceResults &res);
DWORD TraceFlags;
// These are required for 3D-floor checking // These are required for 3D-floor checking
// to create a fake sector with a floor // to create a fake sector with a floor
// or ceiling plane coming from a 3D-floor // or ceiling plane coming from a 3D-floor
static sector_t DummySector[2]; sector_t DummySector[2];
static int sectorsel; int sectorsel;
bool TraceTraverse (int ptflags);
bool CheckSectorPlane (const sector_t *sector, bool checkFloor);
};
static bool PTR_TraceIterator (intercept_t *);
static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t & trace);
static bool EditTraceResult (DWORD flags, FTraceResults &res); static bool EditTraceResult (DWORD flags, FTraceResults &res);
bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector, bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist, fixed_t vx, fixed_t vy, fixed_t vz, fixed_t maxDist,
DWORD actorMask, DWORD wallMask, AActor *ignore, DWORD actorMask, DWORD wallMask, AActor *ignore,
FTraceResults &res, FTraceResults &res,
DWORD flags, bool (*callback)(FTraceResults &res)) DWORD flags, bool (*callback)(FTraceResults &res))
{ {
// Under extreme circumstances ADecal::DoTrace can call this from inside a linespecial call!
static bool recursion;
if (recursion) return false;
recursion=true;
int ptflags; int ptflags;
FTraceInfo inf;
ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES; ptflags = actorMask ? PT_ADDLINES|PT_ADDTHINGS : PT_ADDLINES;
StartZ = z; inf.StartX = x;
Vx = vx; inf.StartY = y;
Vy = vy; inf.StartZ = z;
Vz = vz; inf.Vx = vx;
ActorMask = actorMask; inf.Vy = vy;
WallMask = wallMask; inf.Vz = vz;
IgnoreThis = ignore; inf.ActorMask = actorMask;
CurSector = sector; inf.WallMask = wallMask;
MaxDist = maxDist; inf.IgnoreThis = ignore;
EnterDist = 0; inf.CurSector = sector;
TraceCallback = callback; inf.MaxDist = maxDist;
TraceFlags = flags; inf.EnterDist = 0;
inf.TraceCallback = callback;
inf.TraceFlags = flags;
res.CrossedWater = NULL; res.CrossedWater = NULL;
Results = &res; inf.Results = &res;
res.HitType = TRACE_HitNone; res.HitType = TRACE_HitNone;
// Do a 3D floor check in the starting sector // Do a 3D floor check in the starting sector
res.ffloor=NULL; res.ffloor=NULL;
sectorsel=0; inf.sectorsel=0;
TDeletingArray<F3DFloor*> &ff = sector->e->XFloor.ffloors; TDeletingArray<F3DFloor*> &ff = sector->e->XFloor.ffloors;
if (ff.Size()) if (ff.Size())
{ {
memcpy(&DummySector[0],sector,sizeof(sector_t)); memcpy(&inf.DummySector[0],sector,sizeof(sector_t));
CurSector=sector=&DummySector[0]; inf.CurSector=sector=&inf.DummySector[0];
sectorsel=1; inf.sectorsel=1;
fixed_t bf = sector->floorplane.ZatPoint (x, y); fixed_t bf = sector->floorplane.ZatPoint (x, y);
fixed_t bc = sector->ceilingplane.ZatPoint (x, y); fixed_t bc = sector->ceilingplane.ZatPoint (x, y);
@ -141,11 +144,11 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
if (xd>SQWORD(32767)*FRACUNIT) if (xd>SQWORD(32767)*FRACUNIT)
{ {
maxDist=FixedDiv(FIXED_MAX-x,vx); maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-x,vx);
} }
else if (xd<-SQWORD(32767)*FRACUNIT) else if (xd<-SQWORD(32767)*FRACUNIT)
{ {
maxDist=FixedDiv(FIXED_MIN-x,vx); maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-x,vx);
} }
@ -153,40 +156,34 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
if (yd>SQWORD(32767)*FRACUNIT) if (yd>SQWORD(32767)*FRACUNIT)
{ {
maxDist=FixedDiv(FIXED_MAX-y,vy); maxDist = inf.MaxDist=FixedDiv(FIXED_MAX-y,vy);
} }
else if (yd<-SQWORD(32767)*FRACUNIT) else if (yd<-SQWORD(32767)*FRACUNIT)
{ {
maxDist=FixedDiv(FIXED_MIN-y,vy); maxDist = inf.MaxDist=FixedDiv(FIXED_MIN-y,vy);
} }
// recalculate the trace's end points for robustness // recalculate the trace's end points for robustness
if (P_PathTraverse (x, y, x + FixedMul (vx, maxDist), y + FixedMul (vy, maxDist), if (inf.TraceTraverse (ptflags))
ptflags, PTR_TraceIterator))
{ // check for intersection with floor/ceiling { // check for intersection with floor/ceiling
res.Sector = CurSector; res.Sector = inf.CurSector;
divline_t trace;
trace.x=x; if (inf.CheckSectorPlane (inf.CurSector, true))
trace.y=y;
if (CheckSectorPlane (CurSector, true, trace))
{ {
res.HitType = TRACE_HitFloor; res.HitType = TRACE_HitFloor;
if (res.CrossedWater == NULL && if (res.CrossedWater == NULL &&
CurSector->heightsec != NULL && inf.CurSector->heightsec != NULL &&
CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z) inf.CurSector->heightsec->floorplane.ZatPoint (res.X, res.Y) >= res.Z)
{ {
res.CrossedWater = CurSector; res.CrossedWater = inf.CurSector;
} }
} }
else if (CheckSectorPlane (CurSector, false, trace)) else if (inf.CheckSectorPlane (inf.CurSector, false))
{ {
res.HitType = TRACE_HitCeiling; res.HitType = TRACE_HitCeiling;
} }
} }
recursion=false;
if (res.HitType != TRACE_HitNone) if (res.HitType != TRACE_HitNone)
{ {
if (flags) if (flags)
@ -210,339 +207,343 @@ bool Trace (fixed_t x, fixed_t y, fixed_t z, sector_t *sector,
} }
} }
static bool PTR_TraceIterator (intercept_t *in) bool FTraceInfo::TraceTraverse (int ptflags)
{ {
fixed_t hitx, hity, hitz; FPathTraverse it(StartX, StartY, StartX + FixedMul (Vx, MaxDist), StartY + FixedMul (Vy, MaxDist), ptflags);
fixed_t dist; intercept_t *in;
if (in->isaline) while ((in = it.Next()))
{ {
int lineside; fixed_t hitx, hity, hitz;
sector_t *entersector; fixed_t dist;
dist = FixedMul (MaxDist, in->frac); if (in->isaline)
hitx = trace.x + FixedMul (Vx, dist);
hity = trace.y + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
fixed_t ff, fc, bf = 0, bc = 0;
// CurSector may be a copy so we must compare the sector number, not the index!
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
{ {
lineside = 0; int lineside;
} sector_t *entersector;
else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
{ dist = FixedMul (MaxDist, in->frac);
lineside = 1; hitx = StartX + FixedMul (Vx, dist);
} hity = StartY + FixedMul (Vy, dist);
else hitz = StartZ + FixedMul (Vz, dist);
{ // Dammit. Why does Doom have to allow non-closed sectors?
if (in->d.line->backsector == NULL) fixed_t ff, fc, bf = 0, bc = 0;
// CurSector may be a copy so we must compare the sector number, not the index!
if (in->d.line->frontsector->sectornum == CurSector->sectornum)
{ {
lineside = 0; lineside = 0;
CurSector = in->d.line->frontsector; }
else if (in->d.line->backsector && in->d.line->backsector->sectornum == CurSector->sectornum)
{
lineside = 1;
} }
else else
{ { // Dammit. Why does Doom have to allow non-closed sectors?
lineside = P_PointOnLineSide (trace.x, trace.y, in->d.line); if (in->d.line->backsector == NULL)
CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
}
}
if (!(in->d.line->flags & ML_TWOSIDED))
{
entersector = NULL;
}
else
{
entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
// For backwards compatibility: Ignore lines with the same sector on both sides.
// This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it.
if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
{
return true;
}
}
ff = CurSector->floorplane.ZatPoint (hitx, hity);
fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
if (entersector != NULL)
{
bf = entersector->floorplane.ZatPoint (hitx, hity);
bc = entersector->ceilingplane.ZatPoint (hitx, hity);
}
if (Results->CrossedWater == NULL &&
CurSector->heightsec &&
!(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
//CurSector->heightsec->waterzone &&
hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity))
{
// hit crossed a water plane
Results->CrossedWater = CurSector;
}
if (hitz <= ff)
{ // hit floor in front of wall
Results->HitType = TRACE_HitFloor;
}
else if (hitz >= fc)
{ // hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling;
}
else if (entersector == NULL ||
hitz <= bf || hitz >= bc ||
in->d.line->flags & WallMask)
{ // hit the wall
Results->HitType = TRACE_HitWall;
Results->Tier =
entersector == NULL ? TIER_Middle :
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
if (TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
}
else
{ // made it past the wall
// check for 3D floors first
if (entersector->e->XFloor.ffloors.Size())
{
memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
entersector=&DummySector[sectorsel];
sectorsel^=1;
for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
{ {
F3DFloor * rover=entersector->e->XFloor.ffloors[i]; lineside = 0;
CurSector = in->d.line->frontsector;
if (rover->flags&FF_SOLID && rover->flags&FF_EXISTS)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
// clip to the part of the sector we are in
if (hitz>ff_top)
{
// above
if (bf<ff_top)
{
entersector->floorplane=*rover->top.plane;
entersector->floorpic=*rover->top.texture;
bf=ff_top;
}
}
else if (hitz<ff_bottom)
{
//below
if (bc>ff_bottom)
{
entersector->ceilingplane=*rover->bottom.plane;
entersector->ceilingpic=*rover->bottom.texture;
bc=ff_bottom;
}
}
else
{
//hit the edge - equivalent to hitting the wall
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_FFloor;
Results->ffloor = rover;
if ((TraceFlags & TRACE_Impact) && in->d.line->special)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
goto cont;
}
}
}
}
Results->HitType = TRACE_HitNone;
if (TraceFlags & TRACE_PCross)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS);
}
if (TraceFlags & TRACE_Impact)
{ // This is incorrect for "impact", but Hexen did this, so
// we need to as well, for compatibility
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
}
cont:
if (Results->HitType != TRACE_HitNone)
{
// We hit something, so figure out where exactly
Results->Sector = CurSector;
if (Results->HitType != TRACE_HitWall &&
!CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor, trace))
{ // trace is parallel to the plane (or right on it)
if (entersector == NULL)
{
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_Middle;
} }
else else
{ {
if (hitz <= bf || hitz >= bc) lineside = P_PointOnLineSide (StartX, StartY, in->d.line);
CurSector = lineside ? in->d.line->backsector : in->d.line->frontsector;
}
}
if (!(in->d.line->flags & ML_TWOSIDED))
{
entersector = NULL;
}
else
{
entersector = (lineside == 0) ? in->d.line->backsector : in->d.line->frontsector;
// For backwards compatibility: Ignore lines with the same sector on both sides.
// This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 need it.
if (i_compatflags & COMPATF_TRACE && in->d.line->backsector == in->d.line->frontsector)
{
continue;
}
}
ff = CurSector->floorplane.ZatPoint (hitx, hity);
fc = CurSector->ceilingplane.ZatPoint (hitx, hity);
if (entersector != NULL)
{
bf = entersector->floorplane.ZatPoint (hitx, hity);
bc = entersector->ceilingplane.ZatPoint (hitx, hity);
}
if (Results->CrossedWater == NULL &&
CurSector->heightsec &&
!(CurSector->MoreFlags & SECF_IGNOREHEIGHTSEC) &&
//CurSector->heightsec->waterzone &&
hitz <= CurSector->heightsec->floorplane.ZatPoint (hitx, hity))
{
// hit crossed a water plane
Results->CrossedWater = CurSector;
}
if (hitz <= ff)
{ // hit floor in front of wall
Results->HitType = TRACE_HitFloor;
}
else if (hitz >= fc)
{ // hit ceiling in front of wall
Results->HitType = TRACE_HitCeiling;
}
else if (entersector == NULL ||
hitz <= bf || hitz >= bc ||
in->d.line->flags & WallMask)
{ // hit the wall
Results->HitType = TRACE_HitWall;
Results->Tier =
entersector == NULL ? TIER_Middle :
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
if (TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
}
else
{ // made it past the wall
// check for 3D floors first
if (entersector->e->XFloor.ffloors.Size())
{
memcpy(&DummySector[sectorsel],entersector,sizeof(sector_t));
entersector=&DummySector[sectorsel];
sectorsel^=1;
for(unsigned int i=0;i<entersector->e->XFloor.ffloors.Size();i++)
{
F3DFloor * rover=entersector->e->XFloor.ffloors[i];
if (rover->flags&FF_SOLID && rover->flags&FF_EXISTS)
{
fixed_t ff_bottom=rover->bottom.plane->ZatPoint(hitx, hity);
fixed_t ff_top=rover->top.plane->ZatPoint(hitx, hity);
// clip to the part of the sector we are in
if (hitz>ff_top)
{
// above
if (bf<ff_top)
{
entersector->floorplane=*rover->top.plane;
entersector->floorpic=*rover->top.texture;
bf=ff_top;
}
}
else if (hitz<ff_bottom)
{
//below
if (bc>ff_bottom)
{
entersector->ceilingplane=*rover->bottom.plane;
entersector->ceilingpic=*rover->bottom.texture;
bc=ff_bottom;
}
}
else
{
//hit the edge - equivalent to hitting the wall
Results->HitType = TRACE_HitWall;
Results->Tier = TIER_FFloor;
Results->ffloor = rover;
if ((TraceFlags & TRACE_Impact) && in->d.line->special)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
goto cont;
}
}
}
}
Results->HitType = TRACE_HitNone;
if (TraceFlags & TRACE_PCross)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_PCROSS);
}
if (TraceFlags & TRACE_Impact)
{ // This is incorrect for "impact", but Hexen did this, so
// we need to as well, for compatibility
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
}
}
cont:
if (Results->HitType != TRACE_HitNone)
{
// We hit something, so figure out where exactly
Results->Sector = CurSector;
if (Results->HitType != TRACE_HitWall &&
!CheckSectorPlane (CurSector, Results->HitType == TRACE_HitFloor))
{ // trace is parallel to the plane (or right on it)
if (entersector == NULL)
{ {
Results->HitType = TRACE_HitWall; Results->HitType = TRACE_HitWall;
Results->Tier = Results->Tier = TIER_Middle;
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
} }
else else
{ {
Results->HitType = TRACE_HitNone; if (hitz <= bf || hitz >= bc)
{
Results->HitType = TRACE_HitWall;
Results->Tier =
hitz <= bf ? TIER_Lower :
hitz >= bc ? TIER_Upper : TIER_Middle;
}
else
{
Results->HitType = TRACE_HitNone;
}
}
if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
{
P_ActivateLine (in->d.line, IgnoreThis, lineside, SPAC_IMPACT);
} }
} }
if (Results->HitType == TRACE_HitWall && TraceFlags & TRACE_Impact)
if (Results->HitType == TRACE_HitWall)
{ {
P_ActivateLine(in->d.line, IgnoreThis, lineside, SPAC_IMPACT); Results->X = hitx;
Results->Y = hity;
Results->Z = hitz;
Results->Distance = dist;
Results->Fraction = in->frac;
Results->Line = in->d.line;
Results->Side = lineside;
} }
} }
if (Results->HitType == TRACE_HitWall) if (Results->HitType == TRACE_HitNone)
{ {
Results->X = hitx; CurSector = entersector;
Results->Y = hity; EnterDist = dist;
Results->Z = hitz; continue;
Results->Distance = dist; }
Results->Fraction = in->frac;
Results->Line = in->d.line; if (TraceCallback != NULL)
Results->Side = lineside; {
if (!TraceCallback (*Results)) return false;
}
else
{
return false;
} }
} }
if (Results->HitType == TRACE_HitNone) // Encountered an actor
if (!(in->d.thing->flags & ActorMask) ||
in->d.thing == IgnoreThis)
{ {
CurSector = entersector; continue;
EnterDist = dist;
return true;
} }
if (TraceCallback != NULL) dist = FixedMul (MaxDist, in->frac);
{ hitx = StartX + FixedMul (Vx, dist);
return TraceCallback (*Results); hity = StartY + FixedMul (Vy, dist);
}
else
{
return false;
}
}
// Encountered an actor
if (!(in->d.thing->flags & ActorMask) ||
in->d.thing == IgnoreThis)
{
return true;
}
dist = FixedMul (MaxDist, in->frac);
hitx = trace.x + FixedMul (Vx, dist);
hity = trace.y + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist);
if (hitz > in->d.thing->z + in->d.thing->height)
{ // trace enters above actor
if (Vz >= 0) return true; // Going up: can't hit
// Does it hit the top of the actor?
dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz);
if (dist > MaxDist) return true;
in->frac = FixedDiv(dist, MaxDist);
hitx = trace.x + FixedMul (Vx, dist);
hity = trace.y + FixedMul (Vy, dist);
hitz = StartZ + FixedMul (Vz, dist); hitz = StartZ + FixedMul (Vz, dist);
// calculated coordinate is outside the actor's bounding box if (hitz > in->d.thing->z + in->d.thing->height)
if (abs(hitx - in->d.thing->x) > in->d.thing->radius || { // trace enters above actor
abs(hity - in->d.thing->y) > in->d.thing->radius) return true; if (Vz >= 0) continue; // Going up: can't hit
}
else if (hitz < in->d.thing->z) // Does it hit the top of the actor?
{ // trace enters below actor dist = FixedDiv(in->d.thing->z + in->d.thing->height - StartZ, Vz);
if (Vz <= 0) return true; // Going down: can't hit
// Does it hit the bottom of the actor?
dist = FixedDiv(in->d.thing->z - StartZ, Vz);
if (dist > MaxDist) return true;
in->frac = FixedDiv(dist, MaxDist);
hitx = trace.x + FixedMul (Vx, dist); if (dist > MaxDist) continue;
hity = trace.y + FixedMul (Vy, dist); in->frac = FixedDiv(dist, MaxDist);
hitz = StartZ + FixedMul (Vz, dist);
// calculated coordinate is outside the actor's bounding box hitx = StartX + FixedMul (Vx, dist);
if (abs(hitx - in->d.thing->x) > in->d.thing->radius || hity = StartY + FixedMul (Vy, dist);
abs(hity - in->d.thing->y) > in->d.thing->radius) return true; hitz = StartZ + FixedMul (Vz, dist);
}
// check for extrafloors first // calculated coordinate is outside the actor's bounding box
if (CurSector->e->XFloor.ffloors.Size()) if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
{ abs(hity - in->d.thing->y) > in->d.thing->radius) continue;
fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
if (hitz>ff_ceiling) // actor is hit above the current ceiling
{
Results->HitType=TRACE_HitCeiling;
} }
else if (hitz<ff_floor) // actor is hit below the current floor else if (hitz < in->d.thing->z)
{ { // trace enters below actor
Results->HitType=TRACE_HitFloor; if (Vz <= 0) continue; // Going down: can't hit
}
else goto cont1; // Does it hit the bottom of the actor?
dist = FixedDiv(in->d.thing->z - StartZ, Vz);
if (dist > MaxDist) continue;
in->frac = FixedDiv(dist, MaxDist);
// the trace hit a 3D-floor before the thing. hitx = StartX + FixedMul (Vx, dist);
// Calculate an intersection and abort. hity = StartY + FixedMul (Vy, dist);
Results->Sector = CurSector; hitz = StartZ + FixedMul (Vz, dist);
if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor, trace))
{
Results->HitType=TRACE_HitNone;
}
if (TraceCallback != NULL)
{
return TraceCallback (*Results);
}
else
{
return false;
}
}
// calculated coordinate is outside the actor's bounding box
if (abs(hitx - in->d.thing->x) > in->d.thing->radius ||
abs(hity - in->d.thing->y) > in->d.thing->radius) continue;
}
// check for extrafloors first
if (CurSector->e->XFloor.ffloors.Size())
{
fixed_t ff_floor=CurSector->floorplane.ZatPoint(hitx, hity);
fixed_t ff_ceiling=CurSector->ceilingplane.ZatPoint(hitx, hity);
if (hitz>ff_ceiling) // actor is hit above the current ceiling
{
Results->HitType=TRACE_HitCeiling;
}
else if (hitz<ff_floor) // actor is hit below the current floor
{
Results->HitType=TRACE_HitFloor;
}
else goto cont1;
// the trace hit a 3D-floor before the thing.
// Calculate an intersection and abort.
Results->Sector = CurSector;
if (!CheckSectorPlane(CurSector, Results->HitType==TRACE_HitFloor))
{
Results->HitType=TRACE_HitNone;
}
if (TraceCallback != NULL)
{
return TraceCallback (*Results);
}
else
{
return false;
}
}
cont1: cont1:
Results->HitType = TRACE_HitActor; Results->HitType = TRACE_HitActor;
Results->X = hitx; Results->X = hitx;
Results->Y = hity; Results->Y = hity;
Results->Z = hitz; Results->Z = hitz;
Results->Distance = dist; Results->Distance = dist;
Results->Fraction = in->frac; Results->Fraction = in->frac;
Results->Actor = in->d.thing; Results->Actor = in->d.thing;
if (TraceCallback != NULL) if (TraceCallback != NULL)
{ {
return TraceCallback (*Results); if (!TraceCallback (*Results)) return false;
} }
else else
{ {
return false; return false;
}
} }
return true;
} }
static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t & trace) bool FTraceInfo::CheckSectorPlane (const sector_t *sector, bool checkFloor)
{ {
secplane_t plane; secplane_t plane;
@ -559,16 +560,16 @@ static bool CheckSectorPlane (const sector_t *sector, bool checkFloor, divline_t
if (den != 0) if (den != 0)
{ {
fixed_t num = TMulScale16 (plane.a, trace.x, fixed_t num = TMulScale16 (plane.a, StartX,
plane.b, trace.y, plane.b, StartY,
plane.c, StartZ) + plane.d; plane.c, StartZ) + plane.d;
fixed_t hitdist = FixedDiv (-num, den); fixed_t hitdist = FixedDiv (-num, den);
if (hitdist > EnterDist && hitdist < MaxDist) if (hitdist > EnterDist && hitdist < MaxDist)
{ {
Results->X = trace.x + FixedMul (Vx, hitdist); Results->X = StartX + FixedMul (Vx, hitdist);
Results->Y = trace.y + FixedMul (Vy, hitdist); Results->Y = StartY + FixedMul (Vy, hitdist);
Results->Z = StartZ + FixedMul (Vz, hitdist); Results->Z = StartZ + FixedMul (Vz, hitdist);
Results->Distance = hitdist; Results->Distance = hitdist;
Results->Fraction = FixedDiv (hitdist, MaxDist); Results->Fraction = FixedDiv (hitdist, MaxDist);

View file

@ -1134,11 +1134,7 @@ void R_SetupFrame (AActor *actor)
camera->sprite != 0) // Sprite 0 is always TNT1 camera->sprite != 0) // Sprite 0 is always TNT1
{ {
// [RH] Use chasecam view // [RH] Use chasecam view
P_AimCamera (camera); P_AimCamera (camera, iview->nviewx, iview->nviewy, iview->nviewz, viewsector);
iview->nviewx = CameraX;
iview->nviewy = CameraY;
iview->nviewz = CameraZ;
viewsector = CameraSector;
r_showviewer = true; r_showviewer = true;
} }
else else

48
src/sdl/critsec.h Normal file
View file

@ -0,0 +1,48 @@
// Wraps an SDL mutex object. (A critical section is a Windows synchronization
// object similar to a mutex but optimized for access by threads belonging to
// only one process, hence the class name.)
#ifndef CRITSEC_H
#define CRITSEC_H
#include "SDL.h"
#include "SDL_thread.h"
#include "i_system.h"
class FCriticalSection
{
public:
FCriticalSection()
{
CritSec = SDL_CreateMutex();
if (CritSec == NULL)
{
I_FatalError("Failed to create a critical section mutex.");
}
}
~FCriticalSection()
{
if (CritSec != NULL)
{
SDL_DestroyMutex(CritSec);
}
}
void Enter()
{
if (SDL_mutexP(CritSec) != 0)
{
I_FatalError("Failed entering a critical section.");
}
}
void Leave()
{
if (SDL_mutexV(CritSec) != 0)
{
I_FatalError("Failed to leave a critical section.");
}
}
private:
SDL_mutex *CritSec;
};
#endif

View file

@ -112,6 +112,7 @@ public:
virtual bool FakeVolume() = 0; virtual bool FakeVolume() = 0;
virtual bool Pause(bool paused) = 0; virtual bool Pause(bool paused) = 0;
virtual bool NeedThreadedCallback() = 0; virtual bool NeedThreadedCallback() = 0;
virtual void PrecacheInstruments(const BYTE *instruments, int count);
}; };
// WinMM implementation of a MIDI output device ----------------------------- // WinMM implementation of a MIDI output device -----------------------------
@ -137,6 +138,7 @@ public:
bool FakeVolume(); bool FakeVolume();
bool NeedThreadedCallback(); bool NeedThreadedCallback();
bool Pause(bool paused); bool Pause(bool paused);
void PrecacheInstruments(const BYTE *instruments, int count);
protected: protected:
static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD); static void CALLBACK CallbackFunc(HMIDIOUT, UINT, DWORD_PTR, DWORD, DWORD);
@ -236,6 +238,7 @@ protected:
virtual void DoInitialSetup() = 0; virtual void DoInitialSetup() = 0;
virtual void DoRestart() = 0; virtual void DoRestart() = 0;
virtual bool CheckDone() = 0; virtual bool CheckDone() = 0;
virtual void Precache() = 0;
virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0; virtual DWORD *MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time) = 0;
enum enum
@ -294,6 +297,7 @@ protected:
void DoInitialSetup(); void DoInitialSetup();
void DoRestart(); void DoRestart();
bool CheckDone(); bool CheckDone();
void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time); DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
MUSHeader *MusHeader; MUSHeader *MusHeader;
@ -319,6 +323,7 @@ protected:
void DoInitialSetup(); void DoInitialSetup();
void DoRestart(); void DoRestart();
bool CheckDone(); bool CheckDone();
void Precache();
DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time); DWORD *MakeEvents(DWORD *events, DWORD *max_events_p, DWORD max_time);
void AdvanceTracks(DWORD time); void AdvanceTracks(DWORD time);

View file

@ -12,8 +12,6 @@ static bool nummididevicesset;
#ifdef _WIN32 #ifdef _WIN32
UINT mididevice; UINT mididevice;
CVAR (Bool, snd_midiprecache, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{ {
UINT oldmididev = mididevice; UINT oldmididev = mididevice;
@ -155,8 +153,9 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps; MIDIOUTCAPS caps;
MMRESULT res; MMRESULT res;
PrintMidiDevice (-2, "TiMidity++", 0, 0); PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0);
PrintMidiDevice (-1, "FMOD", 0, 0); PrintMidiDevice (-2, "TiMidity++", 0, MOD_WAVETABLE | MOD_SWSYNTH);
PrintMidiDevice (-1, "FMOD", 0, MOD_WAVETABLE | MOD_SWSYNTH);
if (nummididevices != 0) if (nummididevices != 0)
{ {
for (id = 0; id < nummididevices; ++id) for (id = 0; id < nummididevices; ++id)
@ -206,6 +205,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues)
CCMD (snd_listmididevices) CCMD (snd_listmididevices)
{ {
Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : ""); Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : "");
Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : ""); Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : "");
} }

View file

@ -754,6 +754,96 @@ void MIDISong2::SetTempo(int new_tempo)
} }
} }
//==========================================================================
//
// MIDISong2 :: Precache
//
// Scans each track for program change events on normal channels and note on
// events on channel 10. Does not care about bank selects, since they're
// unlikely to appear in a song aimed at Doom.
//
//==========================================================================
void MIDISong2::Precache()
{
int i, j;
// This array keeps track of instruments that are used. The first 128
// entries are for melodic instruments. The second 128 are for
// percussion.
BYTE found_instruments[256] = { 0, };
DoRestart();
for (i = 0; i < NumTracks; ++i)
{
TrackInfo *track = &Tracks[i];
BYTE running_status = 0;
BYTE ev, data1, data2, command, channel;
int len;
while (track->TrackP < track->MaxTrackP)
{
ev = track->TrackBegin[track->TrackP++];
command = ev & 0xF0;
if (command == MIDI_SYSEX || command == MIDI_SYSEXEND)
{
len = track->ReadVarLen();
track->TrackP += len;
}
else if (command == MIDI_META)
{
track->TrackP++;
len = track->ReadVarLen();
track->TrackP += len;
}
else if ((command & 0xF0) == 0xF0)
{
track->TrackP += CommonLengths[ev & 0xF];
}
else
{
if ((ev & 0x80) == 0)
{ // Use running status.
data1 = ev;
ev = running_status;
}
else
{ // Store new running status.
running_status = ev;
data1 = track->TrackBegin[track->TrackP++];
}
command = ev & 0x70;
channel = ev & 0x0F;
if (EventLengths[command >> 4] == 2)
{
data2 = track->TrackBegin[track->TrackP++];
}
if (channel != 9 && command == (MIDI_PRGMCHANGE & 0x70))
{
found_instruments[data1 & 127] = 1;
}
else if (channel == 9 && command == (MIDI_NOTEON & 0x70) && data2 != 0)
{
found_instruments[data1 | 128] = 1;
}
track->ReadVarLen(); // Skip delay.
}
}
}
DoRestart();
// Now pack everything into a contiguous region for the PrecacheInstruments call().
for (i = j = 0; i < 256; ++i)
{
if (found_instruments[i])
{
found_instruments[j++] = i;
}
}
MIDI->PrecacheInstruments(found_instruments, j);
}
//========================================================================== //==========================================================================
// //
// MIDISong2 :: GetOPLDumper // MIDISong2 :: GetOPLDumper

View file

@ -221,6 +221,7 @@ void MIDIStreamer::Play(bool looping)
} }
CheckCaps(); CheckCaps();
Precache();
// Set time division and tempo. // Set time division and tempo.
if (0 != MIDI->SetTimeDiv(Division) || if (0 != MIDI->SetTimeDiv(Division) ||
@ -301,7 +302,8 @@ void MIDIStreamer::Play(bool looping)
// MIDIStreamer :: Pause // MIDIStreamer :: Pause
// //
// "Pauses" the song by setting it to zero volume and filling subsequent // "Pauses" the song by setting it to zero volume and filling subsequent
// buffers with NOPs until the song is unpaused. // buffers with NOPs until the song is unpaused. A MIDI device that
// supports real pauses will return true from its Pause() method.
// //
//========================================================================== //==========================================================================
@ -711,3 +713,22 @@ MIDIDevice::MIDIDevice()
MIDIDevice::~MIDIDevice() MIDIDevice::~MIDIDevice()
{ {
} }
//==========================================================================
//
// MIDIDevice :: PrecacheInstruments
//
// The MIDIStreamer calls this method between device open and the first
// buffered stream with a list of instruments known to be used by the song.
// If the device can benefit from preloading the instruments, it can do so
// now.
//
// For each entry, bit 7 set indicates that the instrument is percussion and
// the lower 7 bits contain the note number to use on MIDI channel 10,
// otherwise it is melodic and the lower 7 bits are the program number.
//
//==========================================================================
void MIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
{
}

View file

@ -179,6 +179,34 @@ bool MUSSong2::CheckDone()
return MusP >= MaxMusP; return MusP >= MaxMusP;
} }
//==========================================================================
//
// MUSSong2 :: Precache
//
// MUS songs contain information in their header for exactly this purpose.
//
//==========================================================================
void MUSSong2::Precache()
{
BYTE *work = (BYTE *)alloca(MusHeader->NumInstruments);
const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / 2;
int i, j;
for (i = j = 0; i < MusHeader->NumInstruments; ++i)
{
if (used[i] < 128)
{
work[j++] = (BYTE)used[i];
}
else if (used[i] >= 135 && used[i] <= 181)
{ // Percussions are 100-based, not 128-based, eh?
work[j++] = (used[i] - 100) | 0x80;
}
}
MIDI->PrecacheInstruments(&work[0], j);
}
//========================================================================== //==========================================================================
// //
// MUSSong2 :: MakeEvents // MUSSong2 :: MakeEvents

View file

@ -55,6 +55,8 @@
// PUBLIC DATA DEFINITIONS ------------------------------------------------- // PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR (Bool, snd_midiprecache, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
//========================================================================== //==========================================================================
@ -203,6 +205,61 @@ void WinMIDIDevice::Stop()
} }
} }
//==========================================================================
//
// WinMIDIDevice :: PrecacheInstruments
//
// For each entry, bit 7 set indicates that the instrument is percussion and
// the lower 7 bits contain the note number to use on MIDI channel 10,
// otherwise it is melodic and the lower 7 bits are the program number.
//
// My old GUS PnP needed the instruments to be preloaded, or it would miss
// some notes the first time through the song. I doubt any modern
// hardware has this problem, but since I'd already written the code for
// ZDoom 1.22 and below, I'm resurrecting it now for completeness, since I'm
// using preloading for the internal Timidity.
//
//==========================================================================
void WinMIDIDevice::PrecacheInstruments(const BYTE *instruments, int count)
{
// Setting snd_midiprecache to false disables this precaching, since it
// does involve sleeping for more than a miniscule amount of time.
if (!snd_midiprecache)
{
return;
}
for (int i = 0, chan = 0; i < count; ++i)
{
if (instruments[i] & 0x80)
{ // Percussion
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | 9 | ((instruments[i] & 0x7f) << 8) | (1 << 16));
}
else
{ // Melodic
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_PRGMCHANGE | chan | (instruments[i] << 8));
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_NOTEON | chan | (60 << 8) | (1 << 16));
if (++chan == 9)
{ // Skip the percussion channel
chan = 10;
}
}
// Once we've got an instrument playing on each melodic channel, sleep to give
// the driver time to load the instruments. Also do this for the final batch
// of instruments.
if (chan == 16 || i == count - 1)
{
Sleep(250);
for (chan = 15; chan-- != 0; )
{
// Turn all notes off
midiOutShortMsg((HMIDIOUT)MidiOut, MIDI_CTRLCHANGE | chan | (123 << 8));
}
// And now chan is back at 0, ready to start the cycle over.
}
}
}
//========================================================================== //==========================================================================
// //
// WinMIDIDevice :: Pause // WinMIDIDevice :: Pause

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 "894" #define ZD_SVN_REVISION_STRING "898"
#define ZD_SVN_REVISION_NUMBER 894 #define ZD_SVN_REVISION_NUMBER 898

View file

@ -56,12 +56,12 @@
// Version identifier for network games. // Version identifier for network games.
// Bump it every time you do a release unless you're certain you // Bump it every time you do a release unless you're certain you
// didn't change anything that will affect sync. // didn't change anything that will affect sync.
#define NETGAMEVERSION 215 #define NETGAMEVERSION 216
// Version stored in the ini's [LastRun] section. // Version stored in the ini's [LastRun] section.
// Bump it if you made some configuration change that you want to // Bump it if you made some configuration change that you want to
// be able to migrate in FGameConfigFile::DoGlobalSetup(). // be able to migrate in FGameConfigFile::DoGlobalSetup().
#define LASTRUNVERSION "206" #define LASTRUNVERSION "207"
// Protocol version used in demos. // Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones. // Bump it if you change existing DEM_ commands or add new ones.

42
src/win32/critsec.h Normal file
View file

@ -0,0 +1,42 @@
// Wraps a Windows critical section object.
#ifndef CRITSEC_H
#define CRITSEC_H
#ifndef _WINNT_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define USE_WINDOWS_DWORD
#endif
class FCriticalSection
{
public:
FCriticalSection()
{
InitializeCriticalSection(&CritSec);
}
~FCriticalSection()
{
DeleteCriticalSection(&CritSec);
}
void Enter()
{
EnterCriticalSection(&CritSec);
}
void Leave()
{
LeaveCriticalSection(&CritSec);
}
#if 0
// SDL has no equivalent functionality, so better not use it on Windows.
bool TryEnter()
{
return TryEnterCriticalSection(&CritSec) != 0;
}
#endif
private:
CRITICAL_SECTION CritSec;
};
#endif